ServletContext和Filter

晨考

1 请求转发的特点

  • 地址栏没有变化
  • 服务器动作
  • 一次请求
  • 可以当做域对象存储数据,在一次请求中共享

2 重定向的特点

  • 地址栏会改变
  • 浏览器行为
  • 两次请求
  • 请求域中的数据,重定向后取不出

3 如何创建一个cookie并返回给浏览器

Cookie ck = new Cookie(name,value);

resp.addCookie(ck);

4 如何获得session对象

// 从请求对象获得的session

HttpSession session = req.getSession();

5 session域和request域存储数据的区别

请求域:存储数据,只有在一次请求中共享

session域: 存储数据,只要session没有销毁,无论是请求转发还是重定向都可以取出session的数据

回顾

​ 请求转发 req.getRequestDispatcher(“/ok”).forward(req,resp);

​ 响应重定向 resp.sendRedirect(“/ok”);

注意事项:

​ - 请求转发时路径从/开始,那么就是服务器根路径开始,

​ 即从项目名开始http://localhost:8080/day41/ok

​ - 重定向时路径从/开始,那么就是从浏览器的根路径开始,

​ 即从端口开始http://localhost:8080/ok

  • 所以在重定向时,建议手动加上项目名,以防止丢失项目名

    • req.getContextPath()
  • 请求转发,重定向就是用来转发页面或者跳转页面,就是一种控制行为.


Cookie,Session是一种会话技术,都是用来保存会话过程中的数据.

Cookie是浏览器技术

​ 将数据直接存储在浏览器,直接可用查看,相对不安全,存储数据量小4kb

Session是服务器技术

​ 将数据存储在服务器,安全,可靠,数据量大

登录权限认证

在某个系统中,需要先登录才能操作.不登录直接通过url进行操作增删改操作.这样不科学!

LoginServlet 登录,登录成功加入session

DeleteServlet 删除

AddServlet 添加

LogoutServlet 退出

详见代码,自己画图

Servlet的线程安全问题(了解)

  • Servlet实例是单实例
  • 并发请求时会有线程安全问题
  • 加锁synchronized
  • 推荐最简单方案
    • 可以将一些全局变量变成局部变量

ServletContext

  • ServletContext是域对象,对于整个web应用有效
  • 服务器启动时创建,关闭时销毁
  • 一个web应用只会创建一个ServletContext
  • 域对象,也可以像request域,session域一样,存储数据

获得ServletContext

// 从请求中获得
ServletContext servletContext1 = req.getServletContext( );

// 从session获得
HttpSession session = req.getSession( );
ServletContext servletContext2 = session.getServletContext( );

作用

  • 获得当前项目名(掌握)
    • servletContext.getContextPath()
    • 与请求域的方法类似
      • req.getContextPath();
  • 获得当前项目的真实路径(了解)
    • servletContext.getRealPath(“/”)
  • 当做域存取数据(了解)
    • 存储 servletContext.setAttribute(key,value)
    • 取出 servletContext.getAttribute(key)
    • 这个域对象存储的数据是整个应用程序内有效,服务器不关闭,就会一直存在
    • 可以主动删除 servletContext.removeAttribute(key)
// 作用3: 当做域,存取数据
servletContext1.setAttribute("username","laowangba");
String username = (String) servletContext1.getAttribute("username");

System.out.println("自存自取: " + username );
@WebServlet("/aaa")
public class AAAServlet extends HttpServlet {
    
    

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    
    
        // 获得对象
        ServletContext servletContext = req.getServletContext( );

        // 获得数据
        String username = (String) servletContext.getAttribute("username");


        System.out.println("AAA类获得 " + username );
    }
}  

销毁

服务器宕机,或者应用从服务器卸载ServletContext对象就会销毁

Filter(过滤器,拦截器)

为什么需要?

目前的情况

  • 在每个servlet为了防止乱码,在进行操作之前,都先设置请求和响应的编码格式.
  • 在web项目中,在每个Servlet中都要对身份进行认证

即在代码中有重复代码

使用过滤器解决

可以拦截指定请求,然后对请求进行设置,设置后放行或者不放行.

过滤器的入门使用

  1. 创建一个类
  2. 实现Filter接口
  3. 重写方法
  4. 在doFilter()方法内写拦截的具体内容
  5. 根据情况决定是否放行
    1. 如果后续有其他拦截器,放行到下个拦截器
    2. 如果后续没有拦截器,放行到对应的servlet
  6. 配置Filter的拦截路径(web.xml)

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-L9YczRDE-1662464405157)(day41_servlet.assets/image-20220906152157215.png)]

package com.qf.servlet.filter;

import javax.servlet.*;
import java.io.IOException;

/**
 * --- 天道酬勤 ---
 *
 * @author QiuShiju
 * @desc
 */
public class MyFilter1 implements Filter {
    
    

    public MyFilter1(){
    
    
        System.out.println("MyFilter1创建" );
    }

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
    
    
        System.out.println("MyFilter1初始" );

    }

    /**
     * @param servletRequest 请求对象,是HttpServletRequest的父类
     * @param servletResponse 响应对象,是HttpServletResponse的父类
     * @param filterChain  过滤器链,项目中可以同时出现多个拦截器,拦截器之间形成链
     *                     多个拦截器的执行顺序
     *                         如果是web.xml配置的,那么就按从上至下
     *                         如果是注解配置,那么就是按照类字母顺序
     *                     通过拦截器链对象,来决定是否放行
     * @throws IOException
     * @throws ServletException
     */
    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
    
    

        System.out.println("拦截器执行了,,,," );

        // 放行,如果没有这行代码,就是不放行
        filterChain.doFilter(servletRequest,servletResponse);

    }

    @Override
    public void destroy() {
    
    
        System.out.println("MyFilter1销毁" );

    }
}
<?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>MyFilter1</filter-name>
        <!-- 过滤器类 -->
        <filter-class>com.qf.servlet.filter.MyFilter1</filter-class>
    </filter>
    <filter-mapping>
        <!-- 名字要与上面的name一致 -->
        <filter-name>MyFilter1</filter-name>
        <!-- 拦截的路径,与servlet中的映射路径写法一样
          支持 绝对路径,模糊匹配,后缀匹配,拦截所有等
         -->
        <url-pattern>/hw/*</url-pattern>
    </filter-mapping>

</web-app>

生命周期

  • 服务器启动,filter创建,只创建一次
  • 随机立即初始化,只初始化一次
  • 每次拦截到都会执行doFilter方法
  • 服务器宕机销毁

拦截器链儿

  • 项目中可以设置多个拦截器
  • 一样创建类,实现接口,重写方法
  • 根据情况放行,放行到下一个拦截
  • 多个拦截器的执行顺序,按照web.xml上下配置顺序

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-9CvYFyKx-1662464405158)(day41_servlet.assets/image-20220906155348311.png)]

<?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>MyFilter3</filter-name>
        <!-- 过滤器类 -->
        <filter-class>com.qf.servlet.filter.MyFilter3</filter-class>
    </filter>
    <filter-mapping>
        <!-- 名字要与上面的name一致 -->
        <filter-name>MyFilter3</filter-name>
        <!-- 拦截的路径,与servlet中的映射路径写法一样
          支持 绝对路径,模糊匹配,后缀匹配,拦截所有等
         -->
        <url-pattern>/hw/*</url-pattern>
    </filter-mapping>

    <filter>
        <filter-name>MyFilter2</filter-name>
        <!-- 过滤器类 -->
        <filter-class>com.qf.servlet.filter.MyFilter2</filter-class>
    </filter>
    <filter-mapping>
        <!-- 名字要与上面的name一致 -->
        <filter-name>MyFilter2</filter-name>
        <!-- 拦截的路径,与servlet中的映射路径写法一样
          支持 绝对路径,模糊匹配,后缀匹配,拦截所有等
         -->
        <url-pattern>/hw/*</url-pattern>
    </filter-mapping>

    <filter>
        <filter-name>MyFilter1</filter-name>
        <!-- 过滤器类 -->
        <filter-class>com.qf.servlet.filter.MyFilter1</filter-class>
    </filter>
    <filter-mapping>
        <!-- 名字要与上面的name一致 -->
        <filter-name>MyFilter1</filter-name>
        <!-- 拦截的路径,与servlet中的映射路径写法一样
          支持 绝对路径,模糊匹配,后缀匹配,拦截所有等
         -->
        <url-pattern>/hw/*</url-pattern>
    </filter-mapping>
</web-app>

注解改造

  • web.xml不再使用,且同一个类不能同时即使用web.xml配置又使用注解
  • 在类上加@WebFilter(“路径”)
@WebFilter("/hw/*")
public class CMyFilter1 implements Filter {
    
    

  ...
}

实战使用[重点]

全局编码格式过滤

以前: 在每个servlet为了防止乱码,在进行操作之前,都先设置请求和响应的编码格式.

现在: 使用拦截器,对所有请求拦截器,设置编码,然后放行


package com.qf.servlet.filter;

import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import java.io.IOException;

/**
 * --- 天道酬勤 ---
 *
 * @author QiuShiju
 * @desc 对所有请求都是设置编码格式
 */
@WebFilter("/*")
public class EncodingFilter implements Filter {
    
    

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
    
     }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
    
    
        // 设置编码格式
        request.setCharacterEncoding("UTF-8");
        response.setContentType("text/html;charset=UTF-8");


        // 放行
        chain.doFilter(request,response);
    }

    @Override
    public void destroy() {
    
     }
}

身份认证拦截器

以前: 在web项目中,在每个Servlet中都要对身份进行认证

现在: 使用拦截器,将身份过滤的代码前置到拦截器,对每个请求先身份认证

package com.qf.servlet.filter;

import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;

/**
 * --- 天道酬勤 ---
 *
 * @author QiuShiju
 * @desc
 */
@WebFilter("/*")
// @WebFilter("/hw/*")
// @WebFilter("*.do")
public class LoginFilter implements Filter {
    
    
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
    
     }

    /**
     * 对请求的身份进行认证
     * 请求中获得session,且session中有登录时存入的数据,说明登录成功,放行
     * 请求中获得session,但是session中没有数据,说明没有登录,重定向到登录页
     */
    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
    
    

        // 获取session
        HttpServletRequest req = (HttpServletRequest) request;
        HttpSession session = req.getSession( );

        String requestURI = req.getRequestURI( );

        /**
         * 因为是拦截所有 /*
         * 所以要放行 静态资源以及第一次登录的请求
         */
        if(requestURI.contains("/login") ||requestURI.contains("html") || requestURI.contains("js") || requestURI.contains("css")) {
    
    
            // 放行
            chain.doFilter(request, response);
        }

        // 从session获得数据
        String username = (String) session.getAttribute("username");

        // 判断
        if (username != null){
    
    
            // 放行
            chain.doFilter(request, response);
        } else {
    
    
            HttpServletResponse resp = (HttpServletResponse) response;
            resp.sendRedirect(req.getContextPath()+"/index.html");
        }

    }

    @Override
    public void destroy() {
    
     }
}
   // 从session获得数据
    String username = (String) session.getAttribute("username");

    // 判断
    if (username != null){
        // 放行
        chain.doFilter(request, response);
    } else {
        HttpServletResponse resp = (HttpServletResponse) response;
        resp.sendRedirect(req.getContextPath()+"/index.html");
    }

}

@Override
public void destroy() { }

}










猜你喜欢

转载自blog.csdn.net/m0_73050509/article/details/126732287