1.Cookie和Session
在JavaWeb基础(五)中,我们分享了.Servlet规范、Servlet生命周期、Servlet请求流程、Servlet初始化参数、Servlet继承体系结构和设计原因。
今天我主要来分享下Cookie和Session, Cookie和Session使用起来其实很简单, 主要用来解决多个request之间的数据共享问题。先说下我这篇博客会分享的内容.
Servlet3.0的注解、Http协议存的问题、Cookie技术、Session技术、总结下使用场景
1.1 Servlet3.0新增的注解
之前的编码中,我们每次增加一个Servlet。都需要到WEB-INF下配置web.xml.我们需要注册Servlet并关联资源名.
而从J2EE6规范起, 我们就可以用注解的方式来配置这些信息.这个版本的Servlet即Servlet3.0, 对应着J2EE6的规范和Tomcat7.*.
为什么引入Servlet配置注解方式
每个新技术的引入都是有一定应用场景, Servlet注解的引入主要是为了解决配置xml的繁琐和臃肿.因为随着Sevlet的增加, web.xml里的配置会爆炸性的增长, 这时候对于修改和维护该配置文件效率往往会非常低.
web.xml中的metadata-complete属性
该属性表示元数据的完整性.即xml是用来描述Servlet的,我们也可以把XML看成是描述Servlet的一种元数据.
如果我们声明其为true。表示xml描述信息是完整的,那么这时候tomcat就不会再去解析Servlet的注解信息.如果我们声明其为false。表示xml描述信息是不完整的,那么这时候tomcat机会再去解析Servlet的注解信息, 这时候我们使用注解替代web.xml才会生效.
代码演示
我们之前分享的中,提到最多的配置是资源名称映射到Servlet配置和Servlet初始化参数配置.我们就来看下如何使用注解来配置.首先这两个配置对应的是@WebServlet注解和@WebInitParam注解.以下是其源代码, 我们只列出部分常见属性.
@Target(ElementType.TYPE)@Retention(RetentionPolicy.RUNTIME)@Documentedpublic @interface WebServlet { String name() default "";
String[] value() default {};
String[] urlPatterns() default {}; int loadOnStartup() default -1;
WebInitParam[] initParams() default {};
}@Target(ElementType.TYPE)@Retention(RetentionPolicy.RUNTIME)@Documentedpublic @interface WebInitParam { String name(); String value();
}@WebServlet有name、value、urlPatterns、loadOnStartup、initParams五个常用属性.
value和urlPatterns作用一样, 只是因为value是默认属性,所以我们可以不用写Key
initParams属性是一个数组, 元素类型是@WebInitParams注解, 其属性为name和value,name确定key值, value确定对应key的值。
并且这些注解的生命周期都是能存储到运行时.所以其原理就是利用运行时在确定要
资源名要关联的Servlet.
如下代码,使用Servlet注解
package com.sweetcs.web.servlet.servlet3_0;import java.io.IOException;import java.util.Arrays;import javax.jws.soap.InitParam;import javax.servlet.ServletException;import javax.servlet.annotation.WebInitParam;import javax.servlet.annotation.WebServlet;import javax.servlet.http.HttpServlet;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;@WebServlet(
value={"/annotation_servlet"},
initParams={ @WebInitParam(name = "enocding", value ="UTF-8")
})public class AnnotationServlet extends HttpServlet {
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// 使用反射读取配置初始化参数
Class<AnnotationServlet> clazz = null; try {
clazz = (Class<AnnotationServlet>) Class.forName("com.sweetcs.web.servlet.servlet3_0.AnnotationServlet");
WebServlet annOfWebServlet = clazz.getAnnotation(WebServlet.class);
System.out.println(Arrays.toString(annOfWebServlet.value()));
System.out.println(Arrays.toString(annOfWebServlet.urlPatterns()));
System.out.println(Arrays.toString(annOfWebServlet.initParams()));
} catch (ClassNotFoundException e) { // TODO Auto-generated catch block
e.printStackTrace();
}
}
}启动浏览器, 输入http://127.0.0.1:8080/annotation_servlet. 运行输出如下.注解能在运行时成功读取到,其中value和urlpattern属性作用是一样,但是如果我们只配置其中一个,其只能读取到其中一个的值.
web.xml和注解的选择
XML和注解区别
XML使得配置和Java相分离, 维护性较高。注解和Java代码耦合, 维护性低.
XML维护繁琐, 配置文件臃肿, 开发效率低。注解使得开发效率高, 方便快速定位.
选择
一般在企业级开发中, 我们当然要尽量的选择其优点, 所以我们在xml中做通用配置。个别的Servlet配置才用注解。
1.2 Http协议无状态带来的问题
一次会话
从打开浏览器,到关闭浏览器过程中的操作可以称为一次会话.我们把一次会话也称为Session。而一次会话中我们可以发送多次的请求Request.
Http协议的问题
http协议是一种无状态连接的协议.导致了服务端无法让多个请求共享数据.
说白话就是
服务端不知道上一次是哪个客户端请求了自己。
一次会话中可以发送多次请求, 但是服务器却不知道这多次请求是来自同一个客户端。
问题:这也就导致了服务端无法让多个请求共享数据.为了解决这个问题就引入了参数传递机制、Cookie技术和Session技术
举个栗子
客户端例子
学过移动端开发的同学都知道, 对于同一个用户, 我们需要在多个页面之前传递数据.而因为Http协议的
无状态连接问题导致我们无法在多个页面之前传递数据.这只是在客户端之前的一个例子, 并不准确。
服务端例子
在服务端开发中,涉及到网络通信,所以可以理解为
多个请求无法标识,导致了服务端无法有效的利用之前的数据在多个请求前实现共享.这也就是导致了你发次请求过来,下次我就不知道是你了,如果有很多页面需要做权限控制,那么每次页面一跳转,由于Http协议的健忘性.你又得重新登入做权限验证
1.3 参数传递机制
为了解决服务端无法识别请求。我们可以在请求中自己附加参数,用来标记请求,这是最原始的解决方案。如下代码使用参数传递来解决数据共享问题.
登入界面
登入界面
LoginServlet
@WebServlet(urlPatterns={"/login"})public class LoginServlet extends HttpServlet {
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
req.setCharacterEncoding("UTF-8");
resp.setContentType("text/html;charset=UTF-8");
String username = req.getParameter("username");
String password = req.getParameter("password");
System.out.println("username = " + username +"password = " + password);
IUserDAO userDAO = new UserDAOImpl();
User user = userDAO.loginReturnUserOrNull(username, password);
PrintWriter printWriter = resp.getWriter();
if (null == user) {
printWriter.write("login failed");
}else {
resp.sendRedirect("/get?username=" + username);
}
}
}GetServlet
负责显示邮件箱
@WebServlet(urlPatterns={"/get"})public class GetServlet extends HttpServlet{ @Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
req.setCharacterEncoding("UTF-8");
resp.setContentType("text/html;charset=UTF-8");
PrintWriter pw = resp.getWriter();
String username = req.getParameter("username");
pw.write("用户:" + username + "<br />"); for (int i = 0; i < 6; i++) {
pw.write("<a href="+"'/content?username="+ username +"'>第(" + i +")封邮件</a> <br />");
}
}
}邮箱界面, 显示邮件
作者:sixleaves
链接:https://www.jianshu.com/p/c904e5116c9b