Servlet
重定向
重定向作用在客户端,客户端将请求发送给服务端后,服务器响应给客户端一个新的请求地址,客户端重新发送新请求。
页面跳转
在调用业务逻辑的Servlet中,编写一下代码
- response.sendRedirect(“目标URL”);(不建议使用)
数据传输
sendRedirect跳转时,地址栏改变,代表客户端重新发送的请求,属于二次请求
- response没有作用域,两次response请求中的数据无法共享
- 传递数据:通过URL的拼接进行数据传递(“/webProject/b?username=tom”);
- 获取数据:request.getParameter(“username”);
重定向特点
- 重定向是客户端行为
- 重定向是浏览器做了至少两次的访问请求
- 重定向浏览器地址改变
- 重定向两次跳转之间传输的信息会丢失(request范围)
- 重定向可以指向任何的资源,包括当前应用程序中的其他资源,同一个站点上的其他应用程序中的资源,其他站点的资源。
Servlet生命周期四个阶段
实体化
当用户第一次访问Servlet时,由容器调用Servlet的构造器创建具体的Servlet对象,也可以在容器启动之后立刻创建实例,使用如下代码可以设置Servlet是否在服务器启动时就创建。
(load-on-startup)1(/load-on-startup)
- 注意:只执行一次
初始化
在初始化阶段,init()方法会被调用。这个方法在javax.servlet.Servlet接口中定义。其中,方法以一个ServletConfig类型的对象作为参数。
- 注意:init()方法只被执行一次
服务
当客户端有一个请求时,容器就会将请求ServletRequest与响应ServletResponse对象转给Servlet,以参数的形式传给Servlet方法。
- 此方法会执行多次
销毁
当Servlet容器停止或者重新启动都会引起销毁Servlet对象并调用destroy方法。
- destroy方法执行一次
Servlet特性
线程安全问题
Servlet在访问之后,会执行实例化操作,创建一个Servlet对象,而我们Tomcat容器可以同时多线程并发访问同一个Servlet,如果在方法中对成员变量做修改操作,就会有线程安全问题。
保证线程安全
- synchronized
将存在线程安全问题的代码放到同步代码块中- 实现SingleThreadMode接口
Servlet实现SingleThreadMode接口后,每个线程都会创建Servlet实例,这样每个客户端请求就不存在共享资源问题,但是Servlet响应客户端请求的效率太低,所以已经淘汰。- 尽可能使用局部变量
状态管理
现有问题
- HTTP协议量无状态的,不能保存每次提交的信息
- 如果用户发来一个新的请求,服务器无法知道他是否与上次的请求有联系。
- 对于那些需要多次提交数据才能完成的web操作,比如登录来说,就成问题了。
概念
将浏览器与web服务器之间多次交互当作一个整体来处理,并且将多次交互所涉及的数据(即状态)保存下来。
状态管理分类
- 客户端状态管理技术:将状态保存在客户端,代表性的是Cookie技术。
- 服务器状态管理技术:将状态保存在服务器端。代表性分是session技术(服务器传递session是需要使用Cookie方式和application)
Cookie的使用
什么是Cookie
- Cookie是在浏览器访问服务端的某个资源时,由Web服务器在HTTP响应消息头中附带传送给浏览器的一小段数据。
- 一旦web浏览器保存了某个Cookie,那么他在以后每次访问该web服务器时,都应在HTTP请求头中将这个Cookie回传给Web服务器。
- 一个Cookie主要由标识该信息的名称(name)和值(value)组成。
获取Cookie
Cookie cookie = new Cookie("username","aaron");
cookie.setPath("/WebProject_war_exploded/get");
cookie.setMaxAge(60*60*24*7);
resp.addCookie(cookie);
修改Cookie
只要保证cookie的名称和路径一致即可改变
Cookie cookie = new Cookie("username","Gavin");
cookie.setPath("/WebProject_war_exploded/get");
cookie.setMaxAge(60*60);
resp.addCookie(cookie);
Cookie编码与解码
Cookie默认不支持中文,只能包含ASCLL字符,所以Cookie需要对Unicode字符进行编码,否则会出现乱码。
- 编码可以使用java.net.URLEncoder类的encode(String str,String encoding)方法
- 解码使用java.net.URLDecoder类的decode(String str,String encoding)方法
创建带中文Cookie
Cookie cookie = new Cookie(URLEncoder.encode("姓名","UTF-8"),URLEncoder.encode("张三","UTF-8"));
cookie.setPath("/WebProject_war_exploded/get");
cookie.setMaxAge(600);
resp.addCookie(cookie);
for (Cookie cookie: cookies) {
System.out.println(URLDecoder.decode(cookie.getName(),"UTF-8") +":"+URLDecoder.decode(cookie.getValue(),"UTF-8"));
}
Cookie优点和缺点
优点
- 可配置到期规则
- 简单性:Cookie是一种基于文本的轻量结构,包含简单的键值对。
- 数据持久性:Cookie默认在过期之前是可以一直存在客户端浏览器上的。
缺点
- 大小受到限制:大多数浏览器对Cookie的大小有4k,8k字节的限制。
- 用户配置为禁用:有些用户禁用了浏览器或客户端设备接收Cookie的能力,因此限制了这一项功能。
- 潜在的安全风险:Cookie可能会被篡改,会对安全性造成潜在风险或者导致依赖于Cookie的应用程序失败。
Session
session概述
- Session用于记录用户的状态,Session指的是在一段时间内,单个客户端与web服务器的一连串相关的交互过程。
- 在一个Session中,客户可能会多次请求访问同一个资源,也有可能请求访问不同的服务器资源。
Session原理
服务器会为每一次话分配一个Session对象
- 同一个浏览器发起的多次请求,同属于一次会话(session)
- 首先使用到Session时,服务器会自动创建Session,开创建Cookie存储SessionId发送回客户端
注意:Session是由服务端创建的。
Session使用
- Session作用域:拥有存储数据的空间。作用范围是一次会话有效
- 一次会话是使用同一浏览器发送的多次请求,一旦浏览器关闭,则结束会话
- 可以将数据存入Session中,在一次会话的任意位置进行获取
- 可传递任何数据(基本类型,对象,集合数组)
获取Session
//1.通过request对象获取Session对象
HttpSession session = request.getSession();
System.out.println(session.getId());
Session保存数据
setAttribute(属性名,Object)保存到Session中
session.setAttribute("username","gavin");
Session获取数据
getAttribute(属性名);获取session中数据
session.getAttribute("username");
Session移除数据
removeAttribute(属性名);从session中删除数据
session.removeAttribute("username");
Session和Request应用区别
- request是一次请求有效,请求改变,则request改变
- Session是一次会话有效,浏览器改变,则Session改变。
Session的生命周期
- 开始:第一次使用则Session的请求产生,则创建Session
- 结束:
—浏览器关闭,则失效
—Session超时,则失效
——session.getMaxInactiveInterval();//设置最大有效时间(单位为毫秒)
—手工销毁,则失效
——session.invalidate();//立即失效
ServletContext对象
ServletContext概述
- 全局对象,也拥有作用域,对应一个Tomcat中的web应用
- 当web服务器启动时,会为每一个web应用程序创建一块共享的存储区域(ServletContext)。
- ServletContext在web服务器启动时创建,服务器关闭时销毁。
获取ServletContext对象
- GenericServlet提供了getServletContext()方法。(推荐)this.getServletContext();
- HttpServletRequest提供了getServletContext()方法。(推荐)
- HTTPSession提供了getServletCon()方法。
ServletContext作用
获取项目真实路径
获取当前项目在服务器发布的真实路径
获取项目上下文路径
获取项目上下文路径(应用程序名称)
全局容器
ServletContext拥有作用域,可以存储数据到全局容器中
- 存储数据: servletContext.setAttribute(“name”,value);
- 获取数据:servletContext.getAttribute(“name”);
- 移除数据:servletContext.removeAttribute(“name”);
ServletContext特点
- 唯一性:一个应用对应一个ServletContext。
- 生命周期:只要容器不关闭或者应用不卸载,ServletContext就一直存在。
作用域总结
- HttpServletRequest:一次请求,请求响应之前有效(临时数据的传递使用)
- HttpSession:一次会话开始,浏览器不关闭或不超时之前有效(保存登录状态,权限验证使用)
- ServletContext:服务器启动开始,服务器停止之前有效(全局容器状态:如计数器使用)
过滤器
现有问题
在以往Servlet中,有没有冗余的代码,多个Servlet都要进行编写。
概念
过滤器(Filter)是处于客户端与服务器目标资源之间的一道过滤技术。
过滤器作用
- 执行地位在Servlet之前,客户端发送请求时,会经过Filter,再到达目标Servlet中;响应时,会根据执行流程再次反向执行filter
- 可以解决多个Servlet共性代码的冗余问题(例如:乱码处理,登录验证)
编写过滤器
Servlet API中提供了一个filter接口,开发人员编写一个Java类实现了这个接口即可,这个Java类称之为过滤器(filter)
实现过程
- 编写Java类实现Filter接口
- 在doFilter方法中编写拦截逻辑
- 设置拦截路径
注解配置
在自定义的Filter类上使用注解@WebFilter(value = “/过滤目标资源”)
过滤器链和优先级
过滤器链
客户端对服务器请求之后,服务器调用Servlet之前会执行一组过滤器(多个过滤器),那么这组过滤器就称为一条过滤器链。
每个过滤器实现某个特定的功能,当第一个Filter的doFilter方法被调用时,Web服务器会创建一个代表Filter链的FilterChain对象传递给该方法,在doFilter方法中,开发人员如果调用了FilterChain对象的doFilter方法,则Web服务器会检查FilterChain对象中是否还有Filter,如果有,则调用第2个Filter,如果没有,则调用目标资源。
过滤器优先级
在一个web应用中,可以开发编写多个Filter,这些Filter组合起来称之为一个Filter链。
优先级
- 如果为注解的话,是按照类全名称的字符串顺序决定作用顺序
- 如果web.xml,按照Filter.mapping注册顺序,从上往下
- web.xml配置高于注解方式
- 如果注解和web.xml同时配置,会创建多个过滤器对象,造成过滤多次。
过滤器典型应用
过滤器解决编码