Servlet--会话管理

默认情况下,一个Web服务器是无法区分一个HTTP请求是否为第一次访问.

例如,一个Web邮件应用要求用户登录后才能查看邮件,因此,当用户输入了相应的用户名和密码后,应用不应该再次提示需要用户登录,应用必须记住哪些用户已经登录.即应用必须能管理用户的会话.

这里阐述四种不同的状态保持技术:URL重写,隐藏域,cookies和HTTPSession对象.

URL重写

URL重写是一种会话跟踪技术,它将一个或多个token添加到URL的查询字符串中,每个token通常为key=value形式,如: url?key_1 = value_1&key_2 = value_2 .

注意,URL和token间用问号(?)隔开,token间用与号(&).

URL重写使用于tokens无需在太多的URL间传递的情况下,然而它有如下的限制:

  • URL在某些浏览器上最大长度为2000字符.
  • 若要传递值到下一个资源时,需要将值插入到链接中,换句话说,静态页面很难传值.
  • URL重写需要在服务端上完成,所有的链接必须带值,因此当以个页面存在很多链接时,处理过程会是一个不小的挑战.
  • 某些字符,例如空格,与和问号等必须用base64编码.
  • 所有的信息都是可见的,某些情况下不太合适.

因此存在如上限制,URL重写仅适用于信息仅在少量页面间传递,且信息本身不隐藏.

示例:

import com.sun.deploy.net.HttpResponse;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.WriteAbortedException;
import java.util.ArrayList;
import java.util.List;

@WebServlet(name = "CityServletDemo",urlPatterns = "/c")
public class CityServletDemo extends HttpServlet {
    private List londonList,parisList;
    @Override
    public void init() throws ServletException {
        londonList = new ArrayList();
        londonList.add("London Eye");
        londonList.add("Big Ben");
        londonList.add("Tower of London");

        parisList = new ArrayList();
        parisList.add("Eiffel Tower");
        parisList.add("The Louvre");
        parisList.add("Champs Elysees");
    }

    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        String city = request.getParameter("city");
        System.out.println(city);
        try {
            if(!city.isEmpty() &&(city.equals("London")||city .equals("Paris"))){
                showCity(response,city);
            }else{
                showMain(response);
            }
        }catch (NullPointerException e){
            showMain(response);
        }

    }

    private void showMain(HttpServletResponse response) {
        try {
            response.setContentType("text/html;charset=utf-8");
            PrintWriter writer = response.getWriter();
            writer.print("\n" +
                    "\n" +
                    "\n" +
                    "    \n" +
                    "\n" +
                    "\n" +
                    "    

Please select a city:

\n"
+ "

London

\n"
+ "

Paris

\n"
+ "\n" + ""); writer.close(); } catch (IOException e) { e.printStackTrace(); }finally { } } private void showCity(HttpServletResponse response,String city) { List list = null; if (city.equals("London") ){ list = londonList; }else{ list = parisList; } try { PrintWriter writer = response.getWriter(); writer.print("\n" + "\n" + "\n" + " \n" + "\n" + "\n" + "

Top 10 Tourist Attractions:

\n"
); for (String s : list) { writer.print("

"+s+"

"
); } writer.print( " \n" + "\n" + ""); writer.close(); } catch (IOException e) { e.printStackTrace(); } } }

隐藏域

使用隐藏域来保护状态类似于URL重写技术,但不是将值附加到URL上,而是放到HTML表单的隐藏域中.当表单提交时,隐藏域的值也同时提交到服务器端.隐藏域技术仅当网页有表单时有效.该技术相对于URL重写的优势在于:没有字符数限制,同时无须额外的编码.但该技术同URL重写一样,不适合跨越多个界面.

Cookies

URL重写和隐藏域仅适合保存无需跨越太多页面的消息.如果需要在多个页面间传递信息,则以上两种技术实现成本高昂,因为你不得不在每个页面都进行相应的处理.幸运的是Cookies技术可以帮助我们.

Cookies是一个很少的信息片段,可自动地在浏览器和Web服务器间交互,因此cookies可存储在多个页面间传递的信息.Cookie作为HTTP header的一部分,其传输由HTTP协议控制.此外,你可以控制cookies的有效时间.浏览器通常支持每个网站高达20个cookies.

Cookies的问题在于用户可以通过改变其浏览器设置来拒绝接受cookies.

要使用cookies,需要熟悉javax.servlet.http.Cookie类以及HttpServletRequeset和HttpServletResponse两个接口.

可以通过传递name和value两个参数给Cookie类的构造函数来创建一个cookies:

Cookie cookie = new Cookie(name,value);

创建完一个Cookie对象后,你可以设置domain,path和maxAge属性.其中maxAge属性决定cookie何时过期.

要讲cookie发送到浏览器,需要调用HttpServletResponse的add方法:

response.addCookie(cookie);

浏览器在访问统一Web浏览器时,会将之前收到的cookie一并发送.

此外,cookies也可以通过客户端的javascript脚本创建和删除.

服务器端若要读取浏览器提交的cookie,可以通过HttpServletRequest接口的getCookies方法,该方法返回一个Cookie数组,若没有cookies则返回null.如下是查询一个名为maxRecords的cookie的示例:

Cookie maxRecordsCookie = null;
 Cookie[] cookies = request.getCookies();
 if (cookies != null){
     for (Cookie cookie : cookies) {
         if (cookie.getName().equals("maxRecords")){
             maxRecordsCookie = cookie;
             break;
         }
     }
 }

目前,还没有类似于getCookieByName的这样的方法来帮助简化工作.此外也没有直接的方法来删除一个cookie,你只能创建一个同名的cookie,并将maxAge属性设置为0,并添加到HttpServletResquest接口中.如:

Cookie cookie = new Cookie("name","");
cookie.setMaxAge(0);
response.addCookie(cookie);

HttpSession对象

在所有的会话跟踪技术中,HttpSession对象是最强大的和最通用的.一个用户可以有且最多有一个HttpSession,并且不会被其他用户访问到.

HttpSession对象在用户第一次访问网站的时候自动被创建,你可以通过调用HttpServletRequest的getSession方法获取该对象.getSession有两个重载方法:

HttpSession getSession();//返回当前的HttpSession,若当前没有则创建一个新的返回.
HttpSession getSession(boolean var1);//false:返回当前HttpSession,若不存在则,返回null;true与无参数时一样.

可以通过HttpSession的setAttribute方法将值放入HttpSession

void setAttribute(String var1, Object var2);//若传入的name参数此前已用过则会用新值覆盖旧值

请注意,不同于URL重写,隐藏域或cookie,放入到HttpSession的值,是存储在内存中,因此不要网HttpSession中放入太多的对象或大对象.尽管现代的Servlet容器在内存不够用的时候会将保存在HttpSession的对象转储到二级存储上,但这样有性能问题,因此小心存储.

此外,放到HttpSession的值,不限于String类型,可以是任意实现java.io.Serializable的java对象,当然也可以将不支持序列化的对象放入HttpSession,只是这样,当Servlet容器视图序列化的时候会失败并报错.

void setAttribute(String var1, Object var2);//返回之前放入的对像.
Enumeration getAttributeNames(); //迭代访问保存在HttpSession中的所有值

注意,所有保存在HttpSession的数据不会发送到客户端,不同于其他会话管理技术,Servlet容器为每个HttpSession生成唯一标识,并将该标识发送给服务器,或创建一个名为JSEEIONID的cookie,或者在URL后加一个名为jsessionid的参数.在后续的请求中,浏览器会将标识提交给服务器,这样服务器就可以识别该请求是由哪个用户发起.Servlet容器自动选择一种方式传递会话标识.

String getId();//可以通过HttpSession的getId方法来读取该标识

此外,HttpSession还定义了一个invalidate的方法.该方法强制会话过期,并清空其保存的对象.默认情况下,HttpSession会在用户不活动一段时间后自动过期,该时间可以通过部署描述符的session-timeout元素配置,若设置为30,则绘画对象会在用户最后一次访问30分钟后过期,如果部署描述符没有配置,则该值取决于Servlet容器的设定.大部分情况下,应该主动销毁无用的HttpSession,以便释放响应内存.

可以调用HttpSession的getMaxInactiveInterval方法查看会话多久会过期.该方法返回一个数字类型,单位为秒.调用setMaxInactiveInterval方法来单独对某个HttpSession设定其超时时间.

void setMaxInactiveInterval(int var1); //若var1=0,则永不过期,这样HttpSession所占用的内存将永不释放,直到应用重加载或Servlet容器关闭.

你可能感兴趣的:(servlet)