系统学习JavaWeb之八Session篇

来源:互联网 发布:网络光端机价格 编辑:程序博客网 时间:2024/05/21 10:35

    我们都会有这样的体验,就比如说我们上CSDN上写博客,只要我们第一次登陆了,之后我们跳转到网站的任何其他的部分都不用再登陆了(除非你对你的浏览器作了特殊设置或者网站本身有相关设置)。这是为什么呢?其实CSDN管理了您的Session。

    Session可以保持我们登陆的状态,保持状态的方法有4个:网址重写、隐藏域、cookie及HttpSession。


网址重写

这是一种Session追踪技术,需要将一个或多个token作为查询字符串添加到URL中。token的格式就是键值对

url?key=value&key1=value1...

下面看个例子:

package com.liuyc.sysframe.action;import java.io.IOException;import java.io.PrintWriter;import java.util.ArrayList;import java.util.List;import javax.servlet.ServletException;import javax.servlet.annotation.WebServlet;import javax.servlet.http.HttpServlet;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;@WebServlet(name="top5Servlet",urlPatterns={ "/top5"})public class SessionDemoServlet extends HttpServlet {private static final long serialVersionUID = 1L;private List<String> londonAttractions = new ArrayList<String>();private List<String> parisAttractions = new ArrayList<String>();@Overridepublic void init() throws ServletException {londonAttractions = new ArrayList<String>();londonAttractions.add("London Eye");londonAttractions.add("Buckingham Palace");londonAttractions.add("2012 Olympic Park");londonAttractions.add("Big Ben");londonAttractions.add("Tower of London");londonAttractions.add("2012 Olympic Park");parisAttractions = new ArrayList<String>();parisAttractions.add("Eiffel Tower");parisAttractions.add("Notre Name");parisAttractions.add("Les Invalides");parisAttractions.add("Musee d'Orsay");parisAttractions.add("Montmarte");parisAttractions.add("Arc de Triomphe");}@Overrideprotected void doGet(HttpServletRequest req, HttpServletResponse resp)throws ServletException, IOException {String city = req.getParameter("city");if (city != null && ("London".equals(city) || "Paris".equals(city))) {showAttractions(req, resp , city);} else {showMainPage(req, resp);}}private void showMainPage(HttpServletRequest req, HttpServletResponse resp)throws ServletException, IOException {resp.setContentType("text/html");PrintWriter writer = resp.getWriter();writer.println("<html><head></head><body><h1>Please Select a City:</h1>"+ "</br><a href='?city=London' >London</a>"+ "</br><a href='?city=Paris' >Paris</a>"+ "</body></html>");}private void showAttractions(HttpServletRequest req, HttpServletResponse resp, String city) throws ServletException, IOException {int page = 1;String pageParameter = req.getParameter("page");try {page = Integer.parseInt(pageParameter);} catch (NumberFormatException e) {}if (page > 2) {page = 1; }List<String> attractions = null;if ("London".equals(city)) {attractions = londonAttractions;}else {attractions = parisAttractions;}resp.setContentType("text/html");PrintWriter writer = resp.getWriter();writer.println("<html><head><title>Top 5 Tourist Attractions</title></head><body>");writer.println("<a href='top5'>Select City</a>");writer.println("<hr/> Page " + page + "<hr/>");int start = page * 3 - 3;for (int i = start; i < start + 3; i++) {writer.println(attractions.get(i) + "<br/>");}writer.println("<hr style='color:blue'/><a href='?city=" + city +"&page=1'>Page 1</a>");writer.println("  <a href='?city=" + city +"&page=2'>Page 2</a>");writer.println("</body></html>");}}

    第一次发送请求的时候,默认是通过HTTP的get方法发送,所以调用的是servlet的doGet方法,由于首次没有带参数所以servlet返回的是一个城市的主页面。在主页面的时候,点击城市名称的超链接<ahref='?city=Paris' >Paris</a>,看到href的属性里的?号了吗?后面接的就是token,这个href的属性是一个相对的url,任何相对的url都是相对于当前页面的URL,换句话说点击一个超链接之后,那么url就变成:

http://127.0.0.1:8080/jtable/top5?city=London或者http://127.0.0.1:8080/jtable/top5?city=Paris

一旦用户点击一个超链接之后,doGet方法就可以获取city参数,并调用showAttractions()方法。至于下面的page参数也是同样的道理,就不赘述了。


隐藏域

利用隐藏域保持状态,跟网址重写技术类似,但是隐藏域不是将值加到url后面,而是将参数值放在HTML表单的隐藏域中。当用户提交表单时,隐藏域的值也被提交到服务器。

下面来看一个实例:

package com.liuyc.sysframe.action;public class Customer {private Integer custId;private String name;private String city;public Customer() {}public Integer getCustId() {return custId;}public void setCustId(Integer custId) {this.custId = custId;}public String getName() {return name;}public void setName(String name) {this.name = name;}public String getCity() {return city;}public void setCity(String city) {this.city = city;}}
Customer是一个实体类,用户封装我们的消费者对象。

package com.liuyc.sysframe.action;import java.io.IOException;import java.io.PrintWriter;import java.util.ArrayList;import java.util.List;import javax.servlet.ServletException;import javax.servlet.annotation.WebServlet;import javax.servlet.http.HttpServlet;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;@WebServlet(name="CustomerServlet" , urlPatterns = {"/customer","/editCustomer","/updateCustomer"})public class CustomerServlet extends HttpServlet{private static final long serialVersionUID = 1L;private List<Customer> customers = new ArrayList<Customer>();@Overridepublic void init() throws ServletException {Customer c1 = new Customer();c1.setCustId(1);c1.setName("LinKon");c1.setCity("NewYork");Customer c2 = new Customer();c2.setCustId(2);c2.setName("Mac");c2.setCity("London");customers.add(c1);customers.add(c2);}@Overrideprotected void doGet(HttpServletRequest req, HttpServletResponse resp)throws ServletException, IOException {String uri = req.getRequestURI();if (uri.endsWith("/customer")) {sendCustomerList(resp);}else if(uri.endsWith("/editCustomer")){sendEditCustomerForm(req , resp);}}@Overrideprotected void doPost(HttpServletRequest req, HttpServletResponse resp)throws ServletException, IOException {int customerId = 0;try {customerId = Integer.parseInt(req.getParameter("custId"));} catch (Exception e) {}Customer customer = getCustomer(customerId);if (customer != null) {customer.setName(req.getParameter("name"));customer.setCity(req.getParameter("city"));}else{System.out.println("No Found Customer!");}sendCustomerList(resp);}private Customer getCustomer(int customerId) {Customer cust = null;for (Customer customer : customers) {if (customer.getCustId() == customerId) {cust = customer;}}return cust;}private void sendEditCustomerForm(HttpServletRequest req,HttpServletResponse resp) throws IOException{resp.setContentType("text/html");PrintWriter writer = resp.getWriter();int custId = 0;try {custId = Integer.parseInt(req.getParameter("custId"));} catch (NumberFormatException e) {}Customer customer = getCustomer(custId);if (customer != null) {writer.println("<html><head><title>Edit Customer</title></head>"+ "<body>"+ "<h2>Edit Customer</h2>"+ "<form method='post' action='updateCustomer'><input type='hidden' name='custId' value='"+ custId + "'/>"+ "<table>"+ "<tr><td>Name:</td><td><input name='name' value='"+ customer.getName().replaceAll("'", "'") + "'/></td></tr>"+ "<tr><td>Name:</td><td><input name='city' value='"+ customer.getCity().replaceAll("'", "'") + "'/></td></tr>"+ "<tr><td colspan='2' style='text-align:right'><input type='submit' value='Update' /></td></tr>"+ "<tr><td colspan='2' style='text-align:right'><a href='customer'>Customer List</a></td></tr>"+ "</table>"+ "</form>"+ "</body></html>");}else{writer.println("No Customer Found!");}}private void sendCustomerList(HttpServletResponse resp) throws IOException{resp.setContentType("text/html");PrintWriter writer = resp.getWriter();writer.println("<html><head><title>Edit Customer</title></head><body><h2>Customers</h2>");writer.println("<ul>");for (Customer customer : customers) {writer.println("<li>"+ customer.getName() +"("+ customer.getCity()+")("+ "<a href='editCustomer?custId="+ customer.getCustId() +"'>edit</a>)"+ "</li>");}writer.println("</ul></body></html>");}}

CustomerServlet是我们的Servlet类,init方法做了初始化数据的工作,实例化了两个Customer对象,这相当于我们做JavaWeb应用时的数据源。首次发送请求的时候,没有带参数,/customer是作为Servlet的入口,返回一个customer的列表页面。点击edit,页面跳转到一个form表单的修改页面,custId值放在隐藏域中,当表单提交后custId值也会被提交到服务器,从而服务器通过custId就能找到要被修改的customer对象了。


cookie

网址重写和隐藏域都是只适用于保持那些不需要跨越多个页面的信息,因为跨越多个页面的话,你就要管理每个页面的信息,而网址重写和隐藏域只能保持前一页面的信息。

cookie能解决跨越多个页面的信息保持的问题,cookie是自动地在web服务器和web浏览器之间来回传递的一小块信息。cookie是作为HTTP标头嵌入的,因此cookie的传输过程是HTTP协议处理。对于web浏览器而言,每台web服务器最多可以支持20个cookie。

要想很好使用cookie,就要熟悉javax.servlet.http.Cookie类。

package javax.servlet.http;import java.io.Serializable;import java.text.MessageFormat;import java.util.Locale;import java.util.ResourceBundle;public class Cookie  implements Cloneable, Serializable{  private static final long serialVersionUID = 1L;  private static final String LSTRING_FILE = "javax.servlet.http.LocalStrings";  private static ResourceBundle lStrings = ResourceBundle.getBundle("javax.servlet.http.LocalStrings");  private String name;  private String value;  private String comment;  private String domain;  private int maxAge = -1;  private String path;  private boolean secure;  private int version = 0;  private boolean httpOnly;  private static final String tspecials = ",; ";  private static final String tspecials2NoSlash = "()<>@,;:\\\"[]?={} \t";  private static final String tspecials2WithSlash = "()<>@,;:\\\"[]?={} \t/";  private static final String tspecials2;  private static final boolean STRICT_SERVLET_COMPLIANCE = Boolean.parseBoolean(System.getProperty("org.apache.catalina.STRICT_SERVLET_COMPLIANCE", "false"));  private static final boolean FWD_SLASH_IS_SEPARATOR;  private static final boolean STRICT_NAMING;  public Cookie(String name, String value)  {    if ((name == null) || (name.length() == 0)) {      throw new IllegalArgumentException(lStrings.getString("err.cookie_name_blank"));    }    if ((!isToken(name)) || (name.equalsIgnoreCase("Comment")) || (name.equalsIgnoreCase("Discard")) || (name.equalsIgnoreCase("Domain")) || (name.equalsIgnoreCase("Expires")) || (name.equalsIgnoreCase("Max-Age")) || (name.equalsIgnoreCase("Path")) || (name.equalsIgnoreCase("Secure")) || (name.equalsIgnoreCase("Version")) || (name.startsWith("$")))    {      String errMsg = lStrings.getString("err.cookie_name_is_token");      Object[] errArgs = new Object[1];      errArgs[0] = name;      errMsg = MessageFormat.format(errMsg, errArgs);      throw new IllegalArgumentException(errMsg);    }    this.name = name;    this.value = value;  }  public void setComment(String purpose)  {    this.comment = purpose;  }  public String getComment()  {    return this.comment;  }  public void setDomain(String pattern)  {    this.domain = pattern.toLowerCase(Locale.ENGLISH);  }  public String getDomain()  {    return this.domain;  }  public void setMaxAge(int expiry)  {    this.maxAge = expiry;  }  public int getMaxAge()  {    return this.maxAge;  }  public void setPath(String uri)  {    this.path = uri;  }  public String getPath()  {    return this.path;  }  public void setSecure(boolean flag)  {    this.secure = flag;  }  public boolean getSecure()  {    return this.secure;  }  public String getName()  {    return this.name;  }  public void setValue(String newValue)  {    this.value = newValue;  }  public String getValue()  {    return this.value;  }  public int getVersion()  {    return this.version;  }  public void setVersion(int v)  {    this.version = v;  }  private boolean isToken(String possibleToken)  {    int len = possibleToken.length();    for (int i = 0; i < len; i++) {      char c = possibleToken.charAt(i);      if ((c < ' ') || (c >= '') || (",; ".indexOf(c) != -1) || ((STRICT_NAMING) && (tspecials2.indexOf(c) != -1)))      {        return false;      }    }    return true;  }  public Object clone()  {    try    {      return super.clone();    } catch (CloneNotSupportedException e) {      throw new RuntimeException(e.getMessage());    }  }  public void setHttpOnly(boolean httpOnly)  {    this.httpOnly = httpOnly;  }  public boolean isHttpOnly()  {    return this.httpOnly;  }  static  {    String fwdSlashIsSeparator = System.getProperty("org.apache.tomcat.util.http.ServerCookie.FWD_SLASH_IS_SEPARATOR");    if (fwdSlashIsSeparator == null)      FWD_SLASH_IS_SEPARATOR = STRICT_SERVLET_COMPLIANCE;    else {      FWD_SLASH_IS_SEPARATOR = Boolean.parseBoolean(fwdSlashIsSeparator);    }    if (FWD_SLASH_IS_SEPARATOR)      tspecials2 = "()<>@,;:\\\"[]?={} \t/";    else {      tspecials2 = "()<>@,;:\\\"[]?={} \t";    }    String strictNaming = System.getProperty("org.apache.tomcat.util.http.ServerCookie.STRICT_NAMING");    if (strictNaming == null)      STRICT_NAMING = STRICT_SERVLET_COMPLIANCE;    else      STRICT_NAMING = Boolean.parseBoolean(strictNaming);  }}

可以调用 public Cookie(String name, String value)有参构造器创建cookie:

Cookie c= new Cookie("language", "Chinese");
为了将cookie发送到浏览器,调用HttpServletResponse上调用add方法:

HttpServletResponse.addCookie(cookie);



1 0