默认情况下,一个Web服务器是无法区分一个HTTP请求是否为第一次访问.
例如,一个Web邮件应用要求用户登录后才能查看邮件,因此,当用户输入了相应的用户名和密码后,应用不应该再次提示需要用户登录,应用必须记住哪些用户已经登录.即应用必须能管理用户的会话.
这里阐述四种不同的状态保持技术:URL重写,隐藏域,cookies和HTTPSession对象.
URL重写是一种会话跟踪技术,它将一个或多个token添加到URL的查询字符串中,每个token通常为key=value形式,如: url?key_1 = value_1&key_2 = value_2 ⋯ ⋯ .
注意,URL和token间用问号(?)隔开,token间用与号(&).
URL重写使用于tokens无需在太多的URL间传递的情况下,然而它有如下的限制:
因此存在如上限制,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" +
" \n" +
" \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重写一样,不适合跨越多个界面.
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对象在用户第一次访问网站的时候自动被创建,你可以通过调用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容器关闭.