7.1 Session状态管理
7.1.1 什么是session
见名知意,是会话的意思。当浏览器访问服务器时,服务器会为每一个浏览器在服务器端的内存中分配空间,单独维护一个Session对象,每个session对象都有一个唯一标识符,叫sessionId。服务器会将sessionId以cookie的方式发给浏览器,浏览器会保存sessionid.
当浏览器再次向服务器发送请求时,会带上sessionId。服务端收到sessionId后,会依据sessionId查找是否有对应的session对象。
7.1.2 如何获取session对象
获取Session对象的方法如下:
HttpSession s = request.getSession(boolean flag);
-
flag = true:先从请求中找找看是否有SID,没有会创建新Session对象,有SID会查找与编号对应的对象,找到匹配的对象则返回,找不到SID对应的对象时则会创建新Session对象。
总结:填写true就一定会得到一个Session对象。要么返回找到的,要么返回新创建的
-
flag = false:不存在SID以及按照SID找不到Session对象时都会返回null,只有根据SID找到对应的对象时会返回具体的Session对象。
总结:填写false时,不会创建新的Session. 要么返回找到的,要么返回null。
如何想要设置flag为true, 可以使用以下重载方法, 相当于设置了flag为true. 提供该方法主要是为了书写代码时更方便,大多数情况下还是希望能够返回一个Session对象的。
HttpSession s = request.getSession(boolean flag);
7.1.3 Session的常用API
Session对象,也是采用name-value对的形式来区分每一组数据。
1)绑定数据的代码:
void session.setAttribute(String name,Object obj)
Session对象可以保存更复杂的对象类型数据了,不像Cookie只能保存字符串。
2)获取绑定数据的代码:
Object obj = session.getAttribute(String name)
3)移除绑定数据的代码
void session.removeAttribute(String name)
4)删除session对象
session.invalidate() //立即失效
该方法会使得服务器端与该客户端对应的Session对象不再被Session容器管理,进入到垃圾回收的状态。对于这种立即删除Session对象的操作主要应用于不再需要身份识别的情况下,如登出操作。
7.1.4 Session的有效时间(超时时间)
Session会以对象的形式占用服务器端的内存,过多的以及长期的消耗内存会降低服务器端的运行效率,所以Session对象存在于内存中时会有默认的时间限制,一旦Session对象存在的时间超过了这个缺省的时间限制则认为是Session超时,Session会失效,不能再继续访问。
Web服务器缺省的超时时间设置一般是30分钟。
如果用户想要自定义session的时间,有如下两种方式,
1)第一种:声明式 (全局)
在web.xml中添加如下配置
<session-config>
<session-timeout>30</session-timeout>
</session-config>
<!-- 注意:单位是分钟 -->
使用声明式来修改缺省时间,那么该应用创建的所有Session对象的生命周期都会应用这个规定的时间,单位为分钟。
2)第二种:编程式 (局部)
在代码中使用session的api进行设置
session.setMaxInactiveInterval(int seconds) //单位是秒
7.1.5 session的优缺点
优点: 安全(状态数据保存到服务器端) session绑定的数据类型更加丰富,cookie只能是字符串 session保存的数据量更大,cookie只能是4kb 缺点: session占服务器的内存。
案例演示:登录验证
需求:如果访问的页面没有经过登录,那么需要立即跳转到登录页面
7.2 Servlet上下文
例 组件和xml代码
package com.shuilidianli.web;
import javax.servlet.ServletConfig;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;
import java.io.PrintWriter;
/**
* 完成统计在线人数的演示
* 利用:ServletContext 这个对象
* 该对象的获取方式:
* 1: GenericServlet的getServletContext()
* 2: ServletConfig的getServletContext()
* 3: HttpSession的getServletContext()
* 4: FilterConfig的getServletContext()
*
* ServletContext:简称Servlet上下文
* 特点:
* 1. 一个应用程序(项目)中只有这一个对象
* 2. 只要容器不管,项目不卸载,该对象就一直存在
* 3. 可以绑定一些数据,供整个应用中的所有组件共享
*/
public class VisitedCount extends HttpServlet {
@Override
protected void service(HttpServletRequest request, HttpServletResponse resp) throws ServletException, IOException {
//获取Servlet上下文对象
// 从this身上获取,即从GenericServlet身上得到
//ServletContext sc1 = getServletContext();
//从ServletConfig身上获取
//ServletConfig scf =getServletConfig();
//ServletContext sc2 = scf.getServletContext();
//从HttpSession身上获取
//ServletContext sc3 = request.getSession().getServletContext();
//从HttpServletRequest身上获取
ServletContext sc = request.getServletContext();
//从sc上,获取绑定的数据, getAttribute(String name):
// 获取访问人数count
Integer count = (Integer)sc.getAttribute("count");
if(count==null){
count=1; //第一次访问
}else{
count+=1; //访问次数+1
}
//重新绑回去
sc.setAttribute("count",count);
//获取流对象
resp.setContentType("text/html;charset=utf8");
PrintWriter pw = resp.getWriter();
pw.println("访问次数:"+count);
pw.close();
}
}
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
version="4.0">
<servlet>
<servlet-name>life</servlet-name>
<servlet-class>com.shuilidianli.web.LifeServlet</servlet-class>
<!-- 设置初始化阶段的一些参数-->
<init-param>
<param-name>school</param-name>
<param-value>shuilidianli</param-value>
</init-param>
<!-- load-on-startup: 容器启动后,就实例化该组件,默认情况下是访问时才实例化-->
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>life</servlet-name>
<url-pattern>/life</url-pattern>
</servlet-mapping>
<servlet>
<servlet-name>count</servlet-name>
<servlet-class>com.shuilidianli.web.VisitedCount</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>count</servlet-name>
<url-pattern>/visited</url-pattern>
</servlet-mapping>
</web-app>
7.3 过滤器
7.3.1 什么是过滤器
过滤器是Servlet2.3规范之中定义的一种小型的,可插入的Web组件,可以用来拦截和处理Servlet容器的请求和响应过程。以便查看,提取或以某种方式操作正在客户端与服务器端之间交换的数据。
例如,对请求的数据是否包含敏感词进行提前筛选过滤,没有必要在下一层(业务层)进行处理。再比如用户没有进行登录,应该跳往登录页面等操作
7.3.2 如何编写过滤器
编写过滤器遵循下列步骤:
-
编写一个实现了Filter接口的类
-
实现Filter接口的三个方法,过滤逻辑在doFilter方法中实现
-
在Web程序中注册过滤器
-
把过滤器和Web应用一起打包部署
7.3.3 过滤器的执行流程
如图所示为过滤器的执行流程。
客户端发来请求后,不会直接将请求送达Servlet,而是先走过滤器1的doFilter方法中的code1,当遇到chain.doFilter()方法时,控制权交到service()方法,执行业务逻辑,但执行结束后并不会立即将响应返回给客户端,而是回到过滤器1的doFilter()方法中code2部分,如果该部分有代码就会执行,执行结束后才会将response对象返回给客户端。
从流程中可以看到,过滤器不仅仅对Servlet的执行前起到过滤作用,对于执行后同样有过滤效果。所以,过滤器是对request和response的检查。
7.3.4 过滤器的优先级
在一个Web应用中,可以有多个过滤器,它们的优先级由位于web.xml文件中的声明顺序决定,具体是按照<filter-mapping>的顺序来决定的。如下代码所示,filter1和filter2都已经注册,执行顺序是filter2 ,然后 filter1 。
<?xml version="1.0" encoding="utf-8"?>
<web-app xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="2.4" xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
<!-- 过滤器 -->
<filter>
<filter-name>filter1</filter-name>
<filter-class/>
</filter>
<filter>
<filter-name>filter2</filter-name>
<filter-class/>
</filter>
<filter-mapping>
<filter-name>filter2</filter-name>
<url-pattern>/comment2</url-pattern>
</filter-mapping>
<filter-mapping>
<filter-name>filter1</filter-name>
<url-pattern>/comment1</url-pattern>
</filter-mapping>
</web-app>
7.3.5 多个过滤器的用法
如图所示,为多个过滤器的执行流程,过滤器1的doFilter的code1 ,然后 过滤器2的doFilter的code1 ,然后再试 service()方法 ,再然后是过滤器2的doFilter的code2 ,之后是 过滤器1的doFilter的code2 ,最后返回给客户端
在这个动作的传递过程中一定要写 chain.doFilter()
7.3.6 过滤器的初始化参数
容器启动之后,会创建过滤器实例。通过init方法来完成过滤器的初始化。初始化时可以添加一些配置,提升动态性。而这些参数通过在web.xml文件中的<init-param>以name-value对的形式存在。
读取这些name-value对需要使用FilterConfig对象,从web.xml文件到FilterConfig对象的过程由容器完成,并通过参数传入到init方法之中,只需要设定一些成员对象保存数值就可以在doFilter方法中使用。
7.3.7 初始化参数的配置
<?xml version="1.0" encoding="utf-8"?>
<web-app xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="2.4" xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
<!-- 过滤器 -->
<filter>
<filter-name>filter1</filter-name>
<filter-class>web.CommentFilter1</filter-class>
<!-- 初始化参数 -->
<init-param>
<param-name>illegalStr</param-name>
<param-value>xxx</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>filter1</filter-name>
<url-pattern>/comment</url-pattern>
</filter-mapping>
</web-app>
7.3.8 读取初始化参数
读取初始化参数使用如下代码:
public class CommentFilter implements Filter{
FilterConfig config = null;
public void init(FilterConfig arg0) throws ServletException {
config = arg0;
}
public void doFilter(ServletRequest arg0,ServletResponse arg1, FilterChain arg2) throws IOException, ServletException {
String illegalStr = config.getInitParameter("illegalStr");
// … …
}
public void destroy() {
// … …
}
}
7.3.9 过滤器的特点
方便增加或减少某个功能模块,需要添加过滤就多部署一个class修改一下web.xml文件,需要减少某个功能只要删除web.xml中对应的声明即可。
方便修改处理逻辑。当把一些功能独立到某个模块时,如果逻辑变了,只修改这一个文件并更新就可以实现功能的改变,而不用修改每一个使用这个插件的组件。
7.3.10 敏感词过滤案例
CommentFilter1类
package com.shuilidianli.filter;
import javax.servlet.*;
import java.io.IOException;
public class CommentFilter1 implements Filter {
//添加全局变量FilterConfig
FilterConfig config = null;
@Override
public void init(FilterConfig filterConfig) throws ServletException {
//给全局变量config赋值
config = filterConfig;
}
@Override
public void doFilter(ServletRequest request,
ServletResponse response,
FilterChain chain) throws IOException, ServletException {
request.setCharacterEncoding("utf-8");
response.setContentType("text/html;charset=utf8");
//使用全局变量config获取一些敏感词
String word1 = config.getInitParameter("word1");
System.out.println("word1:"+word1);
//获取评论内容
String comment = request.getParameter("comment");
if(comment.contains(word1)){
//转发到comment.jsp页面进行提醒
request.setAttribute("message","您输入了敏感词"+word1);
request.getRequestDispatcher("comment.jsp").forward(request,response);
}else{
//继续向下执行
chain.doFilter(request,response);
}
}
@Override
public void destroy() {
}
}
CommentFilter2类
package com.shuilidianli.filter;
import javax.servlet.*;
import java.io.IOException;
public class CommentFilter2 implements Filter {
//添加全局变量FilterConfig
FilterConfig config = null;
@Override
public void init(FilterConfig filterConfig) throws ServletException {
//给全局变量config赋值
config = filterConfig;
}
@Override
public void doFilter(ServletRequest request,
ServletResponse response,
FilterChain chain) throws IOException, ServletException {
request.setCharacterEncoding("utf-8");
response.setContentType("text/html;charset=utf8");
//使用全局变量config获取一些敏感词
String word2 = config.getInitParameter("word2");
//获取评论内容
String comment = request.getParameter("comment");
if(comment.contains(word2)){
//转发到comment.jsp页面进行提醒
request.setAttribute("message","您输入了敏感词"+word2);
request.getRequestDispatcher("comment.jsp").forward(request,response);
}else{
//继续向下执行
chain.doFilter(request,response);
}
}
@Override
public void destroy() {
}
}
CommentServlet类
package com.shuilidianli.web;
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;
@WebServlet("/toComment")
public class CommentServlet extends HttpServlet {
@Override
protected void service(HttpServletRequest request,
HttpServletResponse response) throws ServletException, IOException {
//处理中文乱码问题
request.setCharacterEncoding("utf-8");
response.setContentType("text/html;charset=utf8");
String comment = request.getParameter("comment");
PrintWriter pw = response.getWriter();
pw.println("评论通过,您的评论内容如下:<br>");
pw.println("<p>"+comment+"</p>");
pw.close();
}
}
web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
version="4.0">
<filter>
<filter-name>f1</filter-name>
<filter-class>com.shuilidianli.filter.CommentFilter1</filter-class>
<init-param>
<param-name>word1</param-name>
<param-value>尼玛</param-value>
</init-param>
</filter>
<filter>
<filter-name>f2</filter-name>
<filter-class>com.shuilidianli.filter.CommentFilter2</filter-class>
<init-param>
<param-name>word2</param-name>
<param-value>qusi</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>f2</filter-name>
<url-pattern>/toComment</url-pattern>
</filter-mapping>
<filter-mapping>
<filter-name>f1</filter-name>
<url-pattern>/toComment</url-pattern>
</filter-mapping>
</web-app>