1、會話
- 會話過程中要解決的一些問題?
例如:用戶點擊超鏈接通過一個servlet購買了一個商品,程序應該想辦法保存用戶購買的商品,以便於用戶點結帳servlet時,結帳servlet可以得到用戶購買的商品爲用戶結帳。
保存會話數據的兩種技術:
- Cookie
- Session
2、cookie API
- public Cookie(String name,String value)
- setValue與getValue方法
- setMaxAge與getMaxAge方法 :沒有設置的話,關閉瀏覽器cookie就失效了,存於緩存。設置了寫入硬盤
- setPath與getPath方法 /day06:訪問day06的時候帶cookie
- setDomain與getDomain方法:域方法:https://www.taobao.com/這是主機名 .taobao.com是域名!
- getName方法 :cookie名稱
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
response.setContentType("text/html;charset=UTF-8");
PrintWriter out = response.getWriter();
out.write("這是網站首頁!<br>");
out.write("您上次訪問時間是:");
//得到上次訪問時間
Cookie[] cookies = request.getCookies();
if (cookies == null) {
out.write("初次訪問");
} else {
for (int i = 0; i < cookies.length; i++) {
if(cookies[i].getName().equals("LastAccessTime")){
Long time = Long.parseLong(cookies[i].getValue());
Date date = new Date(time);
out.write(date.toLocaleString());
}
}
}
//將訪問時間寫入cookie中
Cookie cookie = new Cookie("LastAccessTime",System.currentTimeMillis()+"");
cookie.setMaxAge(3600);
response.addCookie(cookie);
}
- 一個Cookie只能標識一種信息,它至少含有一個標識該信息的名稱(NAME)和設置值(VALUE)。
- 一個WEB站點可以給一個WEB瀏覽器發送多個Cookie,一個WEB瀏覽器也可以存儲多個WEB站點提供的Cookie。
- 瀏覽器一般只允許存放300個Cookie,每個站點最多存放20個Cookie,每個Cookie的大小限制爲4KB。
- 如果創建了一個cookie,並將他發送到瀏覽器,默認情況下它是一個會話級別的cookie(即存儲在瀏覽器的內存中),用戶退出瀏覽器之後即被刪除。若希望瀏覽器將該cookie存儲在磁盤上,則需要使用maxAge,並給出一個以秒爲單位的時間。將最大時效設爲0則是命令瀏覽器刪除該cookie。
- 注意,刪除cookie時,path必須一致,否則不會刪除
Cookie cookie = new Cookie("LastAccessTime",System.currentTimeMillis()+"");
cookie.setMaxAge(0);
response.addCookie(cookie);
必須設置 地址一致實例:最近瀏覽過的商品
//首頁
public class CookieDemo3 extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
response.setContentType("text/html;charset=UTF-8");
PrintWriter out = response.getWriter();
//1.顯示網站所有商品
out.write("本網站有如下書籍:<br><br>");
Set<Map.Entry<String, Book>> set = DB.getAll().entrySet();
for(Map.Entry<String, Book> me : set){
Book book = me.getValue();
out.write("<a href='/day07/servlet/CookieDemo4?id="+book.getId()+"' target='_blank'>"+book.getName()+"</a>");
out.write("<br/>");
}
//2.顯示用戶曾經瀏覽過的商品
out.write("<br/><br/>您曾經瀏覽過的商品:<br/>" );
Cookie cookies[] = request.getCookies();
for(int i=0;cookies!=null && i<cookies.length;i++){
Cookie cookie = cookies[i];
if(cookie.getName().equals("bookHistory")){
String bookHistory = cookie.getValue(); // 2_3
String ids[] = bookHistory.split("\\_"); //[2,3]
for(String id: ids){
Book book = (Book) DB.getAll().get(id);
out.write(book.getName() + "<br/>");
}
}
}
}
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doGet(request, response);
}
}
class DB
{
private static Map<String,Book> map = new LinkedHashMap();
static{
map.put("1", new Book("1","javaweb開發","老張","一本好書"));
map.put("2", new Book("2","spring開發","老黎","一本好書"));
map.put("3", new Book("3","hibernate開發","老佟","一本好書"));
map.put("4", new Book("4","struts開發","老畢","一本好書"));
map.put("5", new Book("5","ajax開發","老張","一本好書"));
}
public static Map getAll(){
return map;
}
}
class Book{
private String id;
private String name;
private String author;
private String description;
public Book() {
super();
// TODO Auto-generated constructor stub
}
public Book(String id, String name, String author, String description) {
super();
this.id = id;
this.name = name;
this.author = author;
this.description = description;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getAuthor() {
return author;
}
public void setAuthor(String author) {
this.author = author;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
}
cookie4:ublic class CookieDemo4 extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
response.setContentType("text/html;charset=UTF-8");
PrintWriter out = response.getWriter();
//1.根據用戶帶過來的id號,顯示商品的詳細信息
String id = request.getParameter("id");
Book book = (Book) DB.getAll().get(id);
out.write("您要查看的書的詳細信息如下:<br/><br/>");
out.write(book.getId() + "<br/>");
out.write(book.getName() + "<br/>");
out.write(book.getAuthor() + "<br/>");
out.write(book.getDescription() + "<br/>");
//2.給用戶回送包含當前商品id的cookie
String bookHistory = makeHistory(request,id); // 3_2
Cookie cookie = new Cookie("bookHistory",bookHistory);
cookie.setMaxAge(1*30*24*3600);
response.addCookie(cookie);
}
private String makeHistory(HttpServletRequest request, String id) {
String bookHistory = null;
Cookie cookies[] = request.getCookies();
for(int i=0;cookies!=null&&i<cookies.length;i++){
if(cookies[i].getName().equals("bookHistory")){
bookHistory = cookies[i].getValue();
}
}
// bookHistory=null 1 bookHistory=1
// bookHistory=3_1_5 1 bookHistory=1_3_5
// bookHistory=3_2_5 1 bookHistory=1_3_2
// bookHistory=3_2 1 bookHistory=1_3_2
// bookHistory=null 1 bookHistory=1
if(bookHistory==null){
return id;
}
List l = Arrays.asList(bookHistory.split("\\_")); //[3,4] //數組 鏈接
LinkedList<String> list = new LinkedList();
list.addAll(l);
if(list.contains(id)){
// bookHistory=3_1_5 1 bookHistory=1_3_5
list.remove(id);
list.addFirst(id);
}else{
if(list.size()>=3){
// bookHistory=3_2_5 1 bookHistory=1_3_2
list.removeLast();
list.addFirst(id);
}else{
// bookHistory=3_2 1 bookHistory=1_3_2
list.addFirst(id);
}
}
StringBuffer sb = new StringBuffer(); //2_3_4
for(String lid: list){
sb.append(lid + "_");
}
return sb.deleteCharAt(sb.length()-1).toString();
}
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doGet(request, response);
}
}
3、session
Session和Cookie的主要區別在於:
- Cookie是把用戶的數據寫給用戶的瀏覽器。存於用戶,客戶端技術
- Session技術把用戶的數據寫到用戶獨佔的session中。存於服務器,服務器技術
購物車實例:
書類如上:response.setContentType("text/html;charset=UTF-8");
PrintWriter out = response.getWriter();
request.getSession();
out.write("本網站有如下書:<br/>");
Set<Map.Entry<String,Book>> set = DB.getAll().entrySet();
for(Map.Entry<String,Book> me : set){
Book book = me.getValue();
String url = "/day07/servlet/BuyServlet?id=" + book.getId();
url = response.encodeURL(url);
out.println(book.getName() + " <a href='"+url+"'>購買</a><br/>");
}
buy:String id = request.getParameter("id");
Book book = (Book) DB.getAll().get(id); //得到用戶想買的書
HttpSession session = request.getSession();
/*Cookie cookie = new Cookie("JSESSIONID",session.getId());
cookie.setMaxAge(30*60);
cookie.setPath("/day07");
response.addCookie(cookie);*/
List list = (List) session.getAttribute("list"); //得到用戶用於保存所有書的容器
if(list==null){
list = new ArrayList();
session.setAttribute("list", list);
}
list.add(book);
//request.getRequestDispatcher("/servlet/ListCartServlet").forward(request, response);
String url = response.encodeRedirectURL("/day07/servlet/ListCartServlet");
System.out.println(url);
response.sendRedirect(url);
ListCartServlet:response.setContentType("text/html;charset=UTF-8");
PrintWriter out = response.getWriter();
HttpSession session = request.getSession();
List<Book> list = (List) session.getAttribute("list");
if(list==null || list.size()==0){
out.write("對不起,您還沒有購買任何商品!!");
return;
}
//顯示用戶買過的商品
out.write("您買過如下商品:<br>");
for(Book book : list){
out.write(book.getName() + "<br/>");
}
服務器是如何實現一個session爲一個用戶瀏覽器服務的?
瀏覽器第一次getsession的時候,服務器創建一個session對象,服務器會給每個session一個固定的ID號碼,通過cookie的形式保存到用戶硬盤上,由於沒有設置有效時間,因此,當關閉瀏覽器這個cookie就失效了,那麼這個session就結束了。
因此要實現關閉了瀏覽器,session對象還在,那麼就需要對保存session的ID號碼的cookie對象設置有效時間(由於畢竟是session對象,服務器默認該session如果30分鐘內沒人使用自動銷燬,因此自己設置的cookie有效期不應該30分鐘)
String id = session.getId();
Cookie cookie = new Cookie("JSESSIONID",id);
cookie.setMaxAge(1800);//不應該超過30分鐘
cookie.setPath("/");
response.addCookie(cookie);
cookie.setPath("/");
應用於所有工程下的servlet!禁用Cookie後servlet共享數據導致的問題:URL重寫
response. encodeRedirectURL(java.lang.String url)
用於對sendRedirect方法後的url地址進行重寫。
response. encodeURL(java.lang.String url)
用於對錶單action和超鏈接的url地址進行重寫
response.setContentType("text/html;charset=UTF-8");
PrintWriter out = response.getWriter();
request.getSession();
out.write("本網站有如下圖書:<br>");
Set<Map.Entry<String,Book>> set = DB.getAll().entrySet();
for (Map.Entry<String,Book> me:set){
Book book = me.getValue();
String url = response.encodeRedirectURL("/Buy?id=" + book.getID());
out.write(book.getName()+" <a href='"+ url +"'>購買</a><br>");
}
buy:String url = response.encodeRedirectURL("/ListCart");
response.sendRedirect(url);
1.1 服務器創建session出來後,會把 session的id號,以cookie的形式回寫給客戶機,這樣,只要客戶機的瀏覽器不關,再
去訪問服務器時,都會帶着session 的id號去,服務器發現客戶機帶session id過來了,就會使用內存中與之對應的
session爲之服務
2、如何做到一個session爲多個瀏覽器服務
2.1 服務器第一次創建session,程序員把session id號,手工以cookie的形式回送給瀏覽器,並設置cookie的有效期這樣,即使用戶的瀏覽器關了,開新瀏覽器時,還會帶着session id找服務器,服務器從而就可以用內存中與之對應的session爲第二個瀏覽器窗口服務
3、如何做用戶禁用cookie後,session還能爲多次請求而服務
3.1 把用戶可能點的每一個超鏈接後面,都跟上用戶的session id號
4、session對象的創建和銷燬時機
4.1 用戶第一次request.getSession時4.2 session對象默認30分鐘沒有使用,則服務器會自動銷燬session,
4.2.1 用戶在web.xml文件中手工配置session的失效時間:session-config timeout4.2.2 用戶可以手工調用session.invalidate方法,摧毀session
4、session案例
(1)、使用Session完成用戶登錄
<body>
歡迎您:<br>
<%
User user = (User) session.getAttribute("user");
if (user != null)
out.write(user.getUsername());
%>
<a href="login.jsp">登錄</a>
</body>
response.setContentType("text/html;charset=UTF-8");
PrintWriter out = response.getWriter();
String username = request.getParameter("username");
String password = request.getParameter("password");
User user = DB.find(username, password);
if(user == null){
out.write("用戶名或密碼錯誤");
return;
}
request.getSession().setAttribute("user",user);
response.sendRedirect("/index.jsp");
<body>
<form action="/Login" method="post">
用戶名:<input type="text" name="username"><br>
密碼:<input type="password" name="password"><br>
<input type="submit" value="登錄">
</form>
</body>
(2)、防止表單重複提交
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title></title>
</head>
<script type="text/javascript">
function dosubmit(){
var submit = document.getElementById("submit");
submit.disabled="disabled";
return true;
}
</script>
<body>
<form action="FormTest" method="post" οnsubmit="return dosubmit()">
<input type="text" name="username"><br>
<input type="submit" value="提交" id="submit">
</form>
</body>
</html>
發佈表單的同時發佈一個隨機數,如果隨機數一致了,錄入信息,並將session中的隨機數清除,再提交的時候由於隨機數銷燬了,就不會一致了防止了表單的重複提交。
單態設計模式:一個類只生成一個實體對象
*1、把類的構造函數私有*2、自己創建一個類的對象
*3、對外提供一個公共的方法,返回類的對象
class TokenProcess{
//單態模式,原子模式,單例模式
/*
*單態設計模式(保證類的對象在內存中只有一個)
*1、把類的構造函數私有
*2、自己創建一個類的對象
*3、對外提供一個公共的方法,返回類的對象
*
*/
private TokenProcess(){}
private static final TokenProcess instance = new TokenProcess();
public static TokenProcess getInstance(){
return instance;
}
//形成隨機數
public String makeToken(){
String token = (System.currentTimeMillis() + new Random().nextInt(999999999)) + "";
//數據指紋 128位長 16個字節 md5
try {
MessageDigest md5 = MessageDigest.getInstance("md5");
byte[] digest = md5.digest(token.getBytes());
BASE64Encoder encoder = new BASE64Encoder();
return encoder.encode(digest);
} catch (NoSuchAlgorithmException e) {
throw new RuntimeException(e);
}
}
try {
MessageDigest md5 = MessageDigest.getInstance("md5");
byte[] digest = md5.digest(token.getBytes());
BASE64Encoder encoder = new BASE64Encoder();
return encoder.encode(digest);
} catch (NoSuchAlgorithmException e) {
throw new RuntimeException(e);
}