Servlet的学习07--状态管理02

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 如何编写过滤器

编写过滤器遵循下列步骤:

  1. 编写一个实现了Filter接口的类

  2. 实现Filter接口的三个方法,过滤逻辑在doFilter方法中实现

  3. 在Web程序中注册过滤器

  4. 把过滤器和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>

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值