servlet生命周期
生命周期包括四个阶段
1.实例化
当用户第一次访问servl时,由容器调用servlet的构造器创建具体的servlet
的对象。也可以在容器启动后立刻创建实例。使用以下代码就可以设置servlet是
否在服务器启动时就创建:
<load-on-startup>1</load-on-startup>
注意只执行一次
2.初始化
在初始化阶段,init()会被调用。这个方法在javax.servlet.Servlet接口
中定义。其中,方法以一个ServletConfig类型的对象做参数。
init()方法就被执行一次
3.服务
当客户端有一个请求时,容器就会将请求ServletRequest与响应
ServletResponse对象转给servlet,以参数方式传递给service。
此方法会执行多次
4.销毁
当servlet容器停止或者重新启动都会销毁servlet对象并调用destroy方法
destroy方法只执行一次
servlet特性
** 线程安全问题**
servlet在访问之后,会执行实例化操作,创建一个servlet对象。而Tomcat容器可
以同时多个线程并访问同一个servlet,如果在方法中对成员变量做修改操作,就
会有线程安全问题。
如何避免线程安全问题
使用局部变量
状态管理
现有问题
* Http协议是无状态的,不能每次保存提交的信息。
* 如果用户发送一个新的请求,服务器无法知道它是否与上次的请求有联系
* 对于那些需要多次提交才能完成的web操作,会出现问题
概念
将浏览器与web服务器的多次交互当作一个整体来处理,并且将多次交互所涉及
的数据保存下来
状态管理分类
客户端状态管理技术:将状态保存在客户端。——>Cookie技术
服务端状态管理技术:将状态保存在服务端。——>session技术(服务器传递
sessionID时需要使用Cookie方式和application)
Cookie的使用
什么是Cookie
* Cookie是浏览器访问服务器某个资源时,由Web服务器在Http响应消息头中附带
传送给浏览器的一小段数据。
* 一旦web浏览器保存了某个Cookie,那么它在以后访问web服务器时,都会将
这个cookie传送给Web服务器
* 一个Cookie主要由标识该信息的名称和值组成。
//1. 服务端创建Cookie对象
Cookie cookie=new Cookie("username","feng");
//1.1设置cookie的访问路径
cookie.setPath("/WebProject_war_exploded/get");
//1.2设置cookie的生命周期
cookie.setMaxAge(60*60);
//将cookie响应给客户端
resp.addCookie(cookie);
获取cookie
//1.通过request对象获取所有的cookie
Cookie[] cookies=req.getCookies();
//2.遍历所有的cookie
if(cookies!=null)
{
for(Cookie cookie:cookies)
{
System.out.println(cookie.getName()+":"+cookie.getValue);
}
}
Cookie 的修改
只有当name是一样时并且setPath的路径也一样,那么就可以修改;
Cookie cookie=new Cookie("username","feng");
cookie.setPath("/WebProject_war_exploded/get");
Cookie cookie=new Cookie("username","man");
cookie.setPath("/WebProject_war_exploded/get");
之后的结果输出数据username变成man;
Cookie的编码与解码
cookie默认不支持中文,只能包括ASCII字符,所以cookie需要对Unicode字符
进行编码,否则会出现乱码
编码使用java.net.URLEncoder类的encode(String str,String encoding)方法
解码使用java.net.URLDecoder类的decode(String str,String encoding)方法
cookie可以自己配置到期时间,在到期时间到来之前cookie的数据在客户端一直存在。
Session对象
session概述
session用于记录用户的状态。session指的是在一段时间内,单个客户端与
服务端一连串的交互过程。
在一个session内,客户可能会多次请求访问同一个资源,也有可能访问各种
不同服务器资源。
session原理
* 服务器会为每一次会话分配一个session对象
* 同一个浏览器发起的多次请求,同属于一个会话
* 首次使用session时, 服务器会自动创建session,并创建cookie存储
sessionld发送回客户端
session使用
session作用域:拥有存储数据的空间,作用范围是一次会话有效
* 一次会话是使用同一浏览器的多次请求,一旦浏览器关闭,则会话结束
* 可以将数据存入session中,在一次会话任意位置获取
* 可以传递任何数据类型
1.获取session
Httpsession session=req.getSession();
2.保存数据
session.setAttribute("key",value);
获取数据
session.getAttribute("key");//通过string类型的key访问
object的value,需要做数据类型强转
移除数据
session.removeAttribute("key");
session与request的区别
* session同一次会话有效,浏览器改变,session改变
* request一次请求有效,请求改变,request改变
session的生命周期
开始:第一次使用到session的请求,则创建session
结束:
* 浏览器关闭,失效
* 超时,失效
session.setMaxInactiveInterval(seconds);//设置最大时长
* 手工销毁失效
ServletContext对象
ServletContext描述
* 全局对象,也拥有作用域,对应一个Tomcat的web应用
* 当web服务器启动时,会为每一个web应用创建一块共享的存储区域
(ServletContext)
* ServletContext在web服务器启动时创建,关闭时销毁
获取servletcontext对象
* GenericServlet提供getServletContext()方法,(推荐)this.getServletContext()
* HttpServletRequest 提供了getServletContext()方法,(推荐)
* HttpSession 提供了getServletContext()方法
ServletContext作用
获取当前项目在服务器发布的真实路径
String getPath=servletContext.getRealPath("/");
获取项目的上下文路径
servletContext.getContextPath();
全局容器:
servletContext拥有作用域,可以将数据存储到全局容器中
* 存储数据:servletContext.setAttribute("name",value)
* 获得数据:servletContext.getAttribute("name")
* 移除数据:servletContext.removeAttribute("name")
servletContext特点
唯一性:一个应用对应一个上下文
生命周期:只要容器不关闭,servlet上下文就一直存在
过滤器概述及基本实现
在编写多个servlet时,会有沉冗的代码,而这些代码写在过滤器中,再调用就可以节约资源和时间。
概念
过滤器是处于客户端和服务端之间的一道过滤技术。
过滤器的实现是客户端发送请求先经过过滤器,过滤器进行操作再传给服务端,
服务端响应后再传给过滤器,过滤器再传给服务端。(而过滤器中的操作可以是多个
servlet共享的代码)
过滤器作用
* 执行地位在servlet之前,客户端发送请求时,会先经过Filter再到达目标
servlet中。响应时,会执行流程再次方向执行Filter
* 可以解决多个servlet共性沉冗代码的问题
编写过滤器
Servlet API中提供一个Filter接口,开发人员编写一个java类实现这个接口,
而这个javalei就被称为过滤器。
实现过程
* 编写javalei实现filter接口
* 在doFilter方法中编写拦截逻辑
* 设置拦截路径
* 注意需要写代码将请求向下传递,这样请求才会到达servlet中
filterChain.doFilter(servletRequest,servletResponse);
@WebFilter(value = "/t")
public class MyFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
System.out.println("--Filter--");
filterChain.doFilter(servletRequest,servletResponse);
}
@Override
public void destroy() {
}
}
过滤器配置
注解配置
在自定义的Filter上使用注解@WebFilter(value = "/t")
xml配置
<filter>
<filter-name>xml</filter-name>
<filter-class>com.feng.filter.XmlFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>xml</filter-name>
<url-pattern>/test</url-pattern>
</filter-mapping>
拦截路径
过滤器拦截路径有三种:
精确拦截匹配:/myservlet1 /index.jsp
后缀拦截匹配:*.jsp *.html
通配符拦截:/* 表示拦截所有
过滤器链和优先级
过滤器链
* 客户端对服务器请求后,服务器调用servlet之前会执行一组过滤器
(多个过滤器),这一组过滤器就被成为过滤器链。
* 每个过滤器会实现某个特定的功能,当第一个Filter的doFilter()方法
被调用时,web服务器会创建一个代表Filter链的FilterChain对象传递
给该方法。在doFilter(),开发人员如果调用FilterChain的doFilter()
,则web服务器会检查FilterChain对象中是否还有filter,如果有,
则调用第二个,如果没有,调用目标资源
过滤器优先级
在一个web应用中可以开发多个Filter,这些Filter组合起来被称为Filter链
优先级:
* 如果注解的话,按类的全名称的字符串顺序决定作用顺序
* 如果web.xml,按照顺序,从上到下
* web.xml顺序高于注解
* 如果注解和web.xml同时运用,会创建多个过滤器对象,多次过滤
过滤器典型应用
过滤器解决编码
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
//统一处理乱码
servletRequest.setCharacterEncoding("UTF-8");
servletResponse.setContentType("text/html;charset=utf-8");
filterChain.doFilter(servletRequest, servletResponse);
}
权限验证
因为servletRequest不是基于http协议,需要转换
//权限验证,验证管理员是否登录
HttpServletRequest request=(HttpServletRequest) servletRequest;
HttpServletResponse response=(HttpServletResponse) servletResponse;
HttpSession session=request.getSession();
Manager manager=(Manager) session.getAttribute("mgr");
if(manager!=null)
{
filterChain.doFilter(request,response);
}
else
{
response.sendRedirect("/WebProject_war_exploded/loginMgr.html");
}