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
共同学习,写下你的评论
评论加载中...
作者其他优质文章