ICode9

精准搜索请尝试: 精确搜索
首页 > 编程语言> 文章详细

Java 过滤器Filter 监听器Listener 拦截器Interceptor 异常处理Exception 详解

2021-09-26 23:34:14  阅读:498  来源: 互联网

标签:拦截器 http 登录 javax Listener 监听器 import servlet public


过滤器 (Filter)

1. 主要内容

在这里插入图片描述

2. 过滤器

2.1 介绍

  • Filter即为过滤,用于在Servlet之外对Request或者Response进行修改。它主要用于对用户请求进行预处理,也可以对HttpServletResponse进行后处理。使用Fiter的完整流程: Filter对用户请求进行预处理,接着将请求交给Servlet进行处理并生成响应,最后Filter再对服务器响应进行后处理。在一个web应用中,可以开发编写多个Filter,这些Filter组合起来称之为一个Fiter链。
    在这里插入图片描述
    在这里插入图片描述

若是一个过滤器链:先配置先执行(请求时的执行顺序);响应时:以相反的顺序执行。

  • 在HttpServletRequest 到达 Servlet之前,拦截客户的HttpServletRequest。根据需要检查 HttpServletRequest,也可以修改HttpServletRequest头和数据。
  • 在HttpServletResponse到达客户端之前,拦截HttpServletResponse,根据需要检查 HttpServletResponse,也可以修改HttpServletResponse头和数据。

2.2 实现

  • 可以通过实现一个叫做javax.servlet.Fileter的接口来实现一个过滤器,其中定义了三个方法, inito() , doFilter(), destroy() 分别在相应的时机执行。后期观察生命周期。
  • Filter的实现只需要两步:
    • step1:编写java类实现Fiter接口,并实现其doFiter方法。
    • Step2:通过@WebFilter注解设置它所能拦截的资源。
  • 过滤器1
package com.liu.filter;

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

/**
 * @author lms
 * @date 2021-09-25 - 15:02
 */
// /* 表示拦截所有的请求
@WebFilter("/*")
public class Filter03 implements Filter {
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        
    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
		// 业务逻辑的过滤操作
        // 选择性放行,否则请求无法到达处理器
        filterChain.doFilter(servletRequest, servletResponse);
    }

    @Override
    public void destroy() {

    }
}

  • 控制器
package com.liu.servlet;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

/**
 * @author lms
 * @date 2021-09-25 - 15:08
 */
//表示  "/ser01"  的请求将会由当前的这个处理器进行处理请求服务
//@WebServlet("/ser01")
public class Servlet01 extends HttpServlet {
    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        System.out.println("ser01正在被处理请求信息。。。。。。。。。。");
    }
}

2.3 用户非法访问拦截

  • 目标:
    • 只有当用户登录之后,才能访问其他的资源信息,非法访问直接跳转至登录页面。
  • 过滤器2
package com.liu.filter;

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

/**
 * @author lms
 * @date 2021-09-25 - 17:25
 *
 * 过滤器实现的登录拦截:
 *
 * 模拟登录拦截器:用户未登录,禁止访问指定的资源
 *  非法访问拦截:
 *      拦截的资源: 拦截所有的资源 /*
 *      需要放行的资源:
 *          1.指定页面进行放行(无需登录就可以访问的页面,例如:登录页面,注册页面等)
 *          2.静态资源需要放行(比如:images,js,css文件)
 *          3.指定操作,放行(无需登录即可执行的操作,例如:登录操作,注册操作)
 *          4.如果当前是登录状态,放行(通过判断session中的用户信息是否为空)
 *          
 *     如果上面的状态都不执行,就拦截让其重定向到登录页面
 */
//拦截所有的请求路径
@WebFilter("/*")
public class LoginFilter implements Filter {

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

    }

    // 在这里设置需要被放行的路径信息(即不同登录也可以访问的资源/页面)
    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        // 基于http请求
        HttpServletRequest request = (HttpServletRequest) servletRequest;
        HttpServletResponse response = (HttpServletResponse) servletResponse;

        // 获取用户访问的路径
        String uri = request.getRequestURI();
        System.out.println("uri = " + uri);

        // 1.指定页面进行放行(无需登录就可以访问的页面,例如:登录页面,注册页面等)
        if (uri.contains("/login.jsp")){
            filterChain.doFilter(request, response);
            return;
        }

        // 2.静态资源需要放行(比如:images,js,css文件)
        if (uri.contains("/js") || uri.contains("/css") || uri.contains("/images")){
            filterChain.doFilter(request, response);
            return;
        }

        // 3.指定操作,放行(无需登录即可执行的操作,例如:登录操作,注册操作)
        if (uri.contains("/login")){
            filterChain.doFilter(request, response);
            return;
        }

        // 4.是登录状态,放行(判断session中的用户信息是否为空)
        // 从session中获取保存的域对象信息
        String user = (String) request.getSession().getAttribute("user");
        // 判断user对象是否为空,不为空,这说明已经是登录状态,则放行
        if (user != null){
            filterChain.doFilter(request, response);
            return;
        }

        // 当用户未登录时,所有的非法访问拦截请求都会被重定向跳转到登录页面,登录之后才能访问其他资源
        response.sendRedirect("login.jsp");
    }

    @Override
    public void destroy() {

    }
}
  • 控制器
package com.liu.servlet;

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;

/**
 * @author lms
 * @date 2021-09-25 - 17:30
 * 处理用户请求
 */
@WebServlet("/login")
public class LoginServlet extends HttpServlet {

    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        System.out.println("用户登录中.............");
        String name = req.getParameter("name");
        System.out.println("name = " + name);

        // 此时在登录页面,如果登录的用户是admin,则表示登录成功,重定向至登录成功的页面,否则登陆失败,请求转发到登录页面
        if ("admin".equals(name)){
            req.getSession().setAttribute("user", name);
            // 重定向到首页
            resp.sendRedirect("index.jsp");
        }else {
            // 转发到登录页面
            req.getRequestDispatcher("login.jsp").forward(req, resp);
        }
    }
}
  • index.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
  <head>
    <title>首页</title>
  </head>
  <body>
    <h3>${user}, 登录成功</h3>
  </body>
</html>
  • login.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>登录</title>
    <script type="text/javascript" src="js/jquery-3.4.1.js"></script>
    <script type="text/javascript">
        // 判断用户名是否为空
        function login() {
            var name = $("#name").val();
            console.log(name);
            if (name != null && name.trim() != ''){
                // 用户名不为空,则进行表单提交,提交到指定的路径上
                $("#formData").submit();
            }
        }
    </script>
</head>
<body>
    <form action="login" id="formData">
       用户名: <input type="text" name="name" id="name"><br>
        <button type="button" onclick="login()">登录</button>
    </form>
</body>
</html>

监听器 (Listener)

1. 介绍

  • Web 监听器是Servlet中一种的特殊的类,能帮助开发者监听web中的特定事件,比如 ServletContext,HttpSession,ServletRequest的创建和销毁;变量的创建、销毁和修改等。可以在某些动作前后增加处理,实现监控。例如可以用来统计在线人数等

2. 实现

  • 常用的监听器(监听生命周期)
    • ServletRequestListener
    • HttpSessionListener
    • ServletContextListener

2.1 解析

  • 监听器
package com.liu.listener;

import javax.servlet.annotation.WebListener;
import javax.servlet.http.HttpSessionEvent;
import javax.servlet.http.HttpSessionListener;
/**
 * @author lms
 * @date 2021-09-25 - 16:27
 * 开启监听器,并设置监听的对象
 */
@WebListener
public class Listener01 implements HttpSessionListener {

    @Override
    public void sessionCreated(HttpSessionEvent httpSessionEvent) {
        System.out.println("监听器被创建了。。。。。。。。。");
    }

    @Override
    public void sessionDestroyed(HttpSessionEvent httpSessionEvent) {
        System.out.println("监听器被销毁了。。。。。。。。。");
    }
}
  • 控制器
package com.liu.servlet;

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 javax.servlet.http.HttpSession;
import java.io.IOException;

/**
 * @author lms
 * @date 2021-09-25 - 16:29
 */
//创建session
@WebServlet("/ser01")
public class Servlet01 extends HttpServlet {
    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        System.out.println("servlet01 被调用了......");
        // 创建session
        HttpSession session = req.getSession();

    }
}
package com.liu.servlet;

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;

/**
 * @author lms
 * @date 2021-09-25 - 16:31
 */

//销毁session
@WebServlet("/ser02")
public class Servlet02 extends HttpServlet {

    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        System.out.println("servlet02 被调用了......");
        // 将session设置为过期
        req.getSession().invalidate();
    }
}

2.2 在线人数统计

  • 监听器
package com.liu.listener;

import javax.servlet.annotation.WebListener;
import javax.servlet.http.HttpSessionEvent;
import javax.servlet.http.HttpSessionListener;

/**
 * @author lms
 * @date 2021-09-25 - 16:48
 * 实现在线人数的统计
 */

@WebListener
public class OnlineListener implements HttpSessionListener {

    // 记录在线的人数统计
    private Integer onlineNum = 0;

    // 通过判断session的创建和销毁来判断人数登录和退出的统计
    // 登录
    @Override
    public void sessionCreated(HttpSessionEvent httpSessionEvent) {
        onlineNum++;
        // 为了让别的地方能够获取到onlineNum对象,将其设置在session域对象中
        // session的作用域比较小,得让所有的浏览器都能看到互相的改变,所以设置在更大的作用域Context中
//        HttpSession session = httpSessionEvent.getSession();
//        session.setAttribute("onlineNum", onlineNum);


        httpSessionEvent.getSession().getServletContext().setAttribute("onlineNum", onlineNum);

    }

    // 退出
    @Override
    public void sessionDestroyed(HttpSessionEvent httpSessionEvent) {
        onlineNum--;
        // 为了让别的地方能够获取到onlineNum对象,将其设置在session域对象中
//        HttpSession session = httpSessionEvent.getSession();
//        session.setAttribute("onlineNum", onlineNum);

//        理由同上
        httpSessionEvent.getSession().getServletContext().setAttribute("onlineNum", onlineNum);
    }
}
  • 控制器
package com.liu.servlet;

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 javax.servlet.http.HttpSession;
import java.io.IOException;

/**
 * @author lms
 * @date 2021-09-25 - 16:52
 */
@WebServlet("/online")
public class OnlineServlet extends HttpServlet {

    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        // 设置字符编码格式
        resp.setContentType("text/html;charset=UTF-8");
        // 通过session获取当前在线的人数
        HttpSession session = req.getSession();

        // 退出的人数
        String key = req.getParameter("key");
        if (key != null && "logout".equalsIgnoreCase(key)){
            session.invalidate();
            return;
        }

        // 登录
        Integer onlineNum = (Integer) session.getServletContext().getAttribute("onlineNum");

        // 通过响应流字符流将在线人数输出到页面显示
        // 如果online请求携带有参数,则表示退出的操作,没有携带为登录操作
        resp.getWriter().write("<h3>当前在线的人数为: " + onlineNum + "</h3><br>" +
                "<a href='online?key=logout'>退出</a>");
    }
}

拦截器 (Interceptor)

1. 介绍

  • SpringMVC中的Interceptor拦截器也是相当重要和相当有用的,它的主要作用是拦截用户的请求并进行相应的处理。比如通过它来进行权限验证,或者是来判断用户是否登陆等操作。
  • 原理:和过滤器原理相同
  • 对于SpringMVC拦截器的定义方式有两种:
    • 实现接口org.springframework.web.servlet.HandlerInterceptor
    • 继承适配器org.springframework.web.servlet.handler.HandlerInterceptorAdapter
      • 其间接实现了HandlerInterceptor接口
  • HandlerInterceptor
public interface HandlerInterceptor {
    default boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        // true: 表示允许目标方法(handler)(类似于过滤器的放行操作)
        // false:禁止目标方法的执行
        return true;
    }

    // 目标方法(请求)执行之后,还没有生成视图之前,执行该方法
    default void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable ModelAndView modelAndView) throws Exception {
    }

     // 目标方法(请求)执行之后,生成视图之后,执行该方法
    default void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable Exception ex) throws Exception {
    }
}
  • HandlerInterceptorAdapter(间接实现了HandlerInterceptor接口)
- public abstract class HandlerInterceptorAdapter implements AsyncHandlerInterceptor
    - public interface AsyncHandlerInterceptor extends HandlerInterceptor

2. 拦截器的实现

2.1 实现HandlerInterceptor接口

package com.liu.springmvc.interceptor;

import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * @author lms
 * @date 2021-09-25 - 19:36
 * 实现拦截器HandlerInterceptor的接口,并重写3个方法
 */

public class MyInterceptor01 implements HandlerInterceptor {
    /**
     * 在目标(handler)方法执行前  执行
     * @param request
     * @param response
     * @param handler
     * @return true:执行handler(目标)方法,也就是放行
     *         false:禁止目标方法的执行
     * @throws Exception
     */
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        System.out.println("MyInterceptor01 ==> 目标方法之前执行了 ---> preHandle........");
        return true;
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        System.out.println("目标方法执行之后,视图生成之前,执行了 ---> postHandle........");
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        System.out.println("目标方法执行之后,视图生成之后,执行了 ---> afterCompletion........");
    }
}

web.xml

  • 配置拦截器
  • 方式1
<!--        配置拦截器,方式一:拦截所有的请求,表示哪些路径下的请求会被拦截-->
<mvc:interceptors>
    <!--
            使用bean标签定义一个Interceptor拦截器
            如果直接定义在mvc:interceptors标签中,表示项目下的所有的请求都会被拦截器进行拦截,等价于 /*
        -->
    <bean class="com.liu.springmvc.interceptor.MyInterceptor01"/>
</mvc:interceptors>
  • 方式2
<!-- 配置拦截器:方式二:拦截部分请求,放行部分请求   -->
<mvc:interceptors>
    <!--
        在标签<mvc:interceptor>中,可以自定义需要被拦截和不被拦截的请求
        可以定义多个拦截器
        如果有多个拦截器,则会根据配置的先后顺序来执行
   -->
    <mvc:interceptor>
        <!--  通过<mvc:mapping标签配置需要被拦截的资源,支持通配符,可以配置多个          -->
        <!--  path="/**" 表示拦截所有的请求 -->
        <mvc:mapping path="/**"/>
        <!--  通过<mvc:exclude-mapping标签配置不需要拦截的资源,支持通配符,可配置多个         -->
        <!--  path="/model/*" 表示model下的所有请求 -->
        <mvc:exclude-mapping path="/model/*"/>
        <bean class="com.liu.springmvc.interceptor.MyInterceptor01"/>
    </mvc:interceptor>
</mvc:interceptors>

  • 测试类1
package com.liu.springmvc.controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;

/**
 * @author lms
 * @date 2021-09-25 - 9:23
 */
@Controller
public class HelloController {

    @RequestMapping("/hello")
    public ModelAndView hello(){

        // 模拟异常(全局异常处理)
        //        int i = 1 / 0;

        // 抛出自定义的异常信息
        //        if (1 == 1){
        //            // 参数异常
                     throw new ParamsException();
        //            // 业务异常
        //            throw new BusinessException();
        //        }

        System.out.println("hello请求被拦截了.........");
        ModelAndView modelAndView = new ModelAndView();
        // 设置数据信息
        modelAndView.addObject("name", "zhangsan");
        // 设置跳转的视图
        modelAndView.setViewName("hello");
        return modelAndView;
    }
}
  • 测试类2
package com.liu.springmvc.controller;

import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import java.util.Map;

/**
 * @author lms
 * @date 2021-09-25 - 11:40
 *
 * 请求域对象的设置方式(五种):
 *
 */
@Controller
@RequestMapping("model")
public class ModelController {

    /**
     * ModelAndView设置域对象
     * @return
     */
    @RequestMapping("/test01")
    public ModelAndView test01(){
        ModelAndView modelAndView = new ModelAndView();
        // 设置请求域对象
        modelAndView.addObject("name", "hello model-1");
        // 设置视图
        modelAndView.setViewName("hello");
        return modelAndView;
    }

    /**
     * Model设置域对象
     * @return
     */
    @RequestMapping("/test02")
    public String test02(Model model){
        // 设置请求域对象
        model.addAttribute("name", "hello model-2");
        // 设置视图
        return "hello";
    }

    /**
     * ModelMap设置域对象
     * @return
     */
    @RequestMapping("/test03")
    public String test03(ModelMap model){
        // 设置请求域对象
        model.addAttribute("name", "hello model-3");
        // 设置视图
        return "hello";
    }

    /**
     * ModelMap设置域对象
     * @return
     */
    @RequestMapping("/test04")
    public String test04(Map model){
        // 设置请求域对象
        model.put("name", "hello model-4");
        // 设置视图
        return "hello";
    }

    /**
     * ModelMap设置域对象
     * @return
     */
    @RequestMapping("/test05")
    public String test05(HttpServletRequest request){
        // 设置请求域对象
        request.setAttribute("name", "hello model-5");
        // 设置视图
        return "hello";
    }
}

2.2 继承HandlerInterceptorAdapter

package com.liu.springmvc.interceptor;

import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * @author lms
 * @date 2021-09-25 - 20:33
 */

public class MyInterceptor02 extends HandlerInterceptorAdapter {
    /**
     * 在目标方法(handler)执行前  执行
     *
     * @param request
     * @param response
     * @param handler
     * @return true:执行handler(目标)方法,也就是放行
     * false:禁止目标方法的执行
     * @throws Exception
     */
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        System.out.println("MyInterceptor02 ==> 目标方法执行之前执行了 ---> preHandle........");
        return true;
    }
}
  • 配置拦截器

  • 方式1

<mvc:interceptors>
    <mvc:interceptor>
        <!--    被拦截的请求        -->
        <mvc:mapping path="/**"/>
        <!--    拦截器不拦截的请求(放行的请求)       -->
        <mvc:exclude-mapping path="/model/test01"/>
        <mvc:exclude-mapping path="/model/test02"/>
        <!--   使用的拦截器         -->
        <bean class="com.liu.springmvc.interceptor.MyInterceptor02"/>
    </mvc:interceptor>
</mvc:interceptors>
  • 方式2
<mvc:interceptors>
    <!-- 
		拦截所有的请求,拦截器链(多个拦截器构成)按照先后的顺序执行拦截操作  
		先配置的拦截器的preHandler()方法先执行
		先配置的拦截器的postHandler(),afterCompletion()方法后执行
	-->
    <mvc:interceptor>
        
        <mvc:mapping path="/**"/>
        <bean class="com.liu.springmvc.interceptor.MyInterceptor01"/>
    </mvc:interceptor>
    <mvc:interceptor>
        <mvc:mapping path="/**"/>
         <!-- MyInterceptor02 在下面  -->
        <bean class="com.liu.springmvc.interceptor.MyInterceptor02"/>
    </mvc:interceptor>
</mvc:interceptors>
  • 测试类同上

3. 拦截器的应用:非法请求拦截

  • 使用拦截器完成用户是否登录的请求验证功能
  • 用户控制器
  • 注意:当前的模拟登陆是直接通过在地址栏中输入: http://localhost:8080/项目名/userInfo/login
package com.liu.springmvc.controller;

import com.liu.springmvc.bean.User;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpSession;

/**
 * @author lms
 * @date 2021-09-25 - 21:26
 * 非法请求拦截的模拟实现
 * login:登录不拦截(不需要登录即可访问)
 * add:  未登录就拦截(访问前需要登录)
 * update:未登录就拦截(访问前需要登录)
 */

@Controller
@RequestMapping("userInfo")
public class LoginController {

    @RequestMapping("login")
    public ModelAndView login(HttpSession session) {
        ModelAndView modelAndView = new ModelAndView();
        User user = new User();
        user.setId(1);
        user.setName("admin");
        user.setAge(20);
        // 将当前登录用户的信息设置在session中
        session.setAttribute("user", user);
        modelAndView.setViewName("success");
        return modelAndView;
    }


    @RequestMapping("add")
    public ModelAndView add() {
        ModelAndView modelAndView = new ModelAndView();
        modelAndView.setViewName("success");
        return modelAndView;
    }

    @RequestMapping("update")
    public ModelAndView update() {
        ModelAndView modelAndView = new ModelAndView();
        modelAndView.setViewName("success");
        return modelAndView;
    }
}

  • success.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
    <h3>登录成功!</h3>
</body>
</html>
  • 登录界面(未登录跳转至当前页面)
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
    <h3>登录页面!</h3>
</body>
</html>
  • 登陆拦截器
package com.liu.springmvc.interceptor;

import com.liu.springmvc.bean.User;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * @author lms
 * @date 2021-09-25 - 21:32
 */

public class LoginInterceptor extends HandlerInterceptorAdapter {
    /**
     * 指定目标方法之前执行该方法
     *
     * @param request
     * @param response
     * @param handler
     * @return
     * @throws Exception
     */
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        // 获取session中的user信息
        User user = (User) request.getSession().getAttribute("user");
        // 未登录
        if (user == null) {
            // 重定向到登录页面
            response.sendRedirect(request.getContextPath() + "/" + "login.jsp");
            // 禁止执行请求
            return false;
        }
        // 否则放行,执行目标方法
        return true;
    }
}
  • 配置拦截器
<!-- 非法访问拦截 拦截器配置   -->
<mvc:interceptors>
    <mvc:interceptor>
        <!--     拦截所有的请求       -->
        <mvc:mapping path="/**"/>
        <!--   不拦截登录请求         -->
        <mvc:exclude-mapping path="/userInfo/login"/>
        <bean class="com.liu.springmvc.interceptor.LoginInterceptor"/>
    </mvc:interceptor>
</mvc:interceptors>

全局异常统一处理(Exception)

1. 介绍

  • 在 JavaEE项目的开发中,不管是对底层的数据库操作过程,还是业务层的处理过程,还是控制层的处理过程,都不可避免会遇到各种可预知的、不可预知的异常需要处理。每个过程都单独处理异常,系统的代码耦合度高,工作量大且不好统一,维护的工作量也很大。
  • SpringMVC对于异常处理这块提供了支持,通过 SpringMVC提供的全局异常处理机制,能够将所有类型的异常处理从各处理过程解耦出来,既保证了相关处理过程的功能较单一,也实现了异常信息的统一处理和维护。
  • 全局异常实现方式 Spring MVC处理异常有3种方式:
    • 使用SpringMVC提供的简单异常处理器SimpleMappingExceptionResolver
      - (需要在SpringMVC配置文件中进行配置,处理的是视图的异常,对于返回的是json数据的异常就会有缺陷,所以不推荐使用)
    • 实现Spring的异常处理接口 HandlerExceptionResolver自定义自己的异常处理器(推荐使用)
    • 使用@ExceptionHandler注解实现异常处理

2. 全局异常处理实现

2.1 方式一:web.xml中配置SimpleMappingExceptionResolver

<!--
        全局异常统一处理(3种)
            1. 使用SpringMVC中提供的简单异常处理器 SimpleMappingExceptionResolver
    -->

<!--        方式1: 使用SpringMVC中提供的简单异常处理器 SimpleMappingExceptionResolver-->
<bean class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver">
    <!--   页面在转发时出现异常,将跳转到error错误页面     -->
    <property name="defaultErrorView" value="error"/>
    <!--    属性exceptionAttribute中包含了出现异常的信息,设置别名为ex    -->
    <property name="exceptionAttribute" value="ex"/>

    <!--   设置自定义异常和该异常对应的处理页面-->
    <property name="exceptionMappings">
        <props>
            <!-- key表示具体的自定义异常的类,标签为出现该自定义异常要跳转到的处理页面  -->
            <prop key="com.liu.springmvc.exception.ParamsException">params_error</prop>
            <prop key="com.liu.springmvc.exception.BusinessException">business_error</prop>
        </props>
    </property>
</bean>
  • 自定义异常处理类
package com.liu.springmvc.exception;

/**
 * @author lms
 * @date 2021-09-26 - 10:34
 */
//自定义参数异常类
public class ParamsException extends RuntimeException {
    private Integer code = 300;
    private String msg = "参数异常";

    public ParamsException() {
        super("参数异常");
    }

    public ParamsException(Integer code) {
        super("参数异常");
        this.code = code;
    }

    public ParamsException(String msg) {
        super(msg);
        this.msg = msg;
    }

    public ParamsException(Integer code, String msg) {
        super(msg);
        this.code = code;
    }
}
package com.liu.springmvc.exception;

/**
 * @author lms
 * @date 2021-09-26 - 10:39
 */
public class BusinessException extends RuntimeException {

    private Integer code = 400;
    private String msg = "业务异常";

    public BusinessException() {
        super("业务异常");
    }

    public BusinessException(String msg) {
        super(msg);
        this.msg = msg;
    }

    public BusinessException(Integer code) {
        super("业务异常");
        this.code = code;
    }

    public Integer getCode() {
        return code;
    }

    public void setCode(Integer code) {
        this.code = code;
    }

    public String getMsg() {
        return msg;
    }

    public void setMsg(String msg) {
        this.msg = msg;
    }
}
  • params_error.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>参数异常</title>
</head>
<body>
    <h3>异常信息: ${ex}</h3>
</body>
</html>
  • business_error.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>业务异常</title>
</head>
<body>
    <h3>异常信息: ${ex}</h3>
</body>
</html>
  • 控制器
package com.liu.springmvc.controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;

/**
 * @author lms
 * @date 2021-09-25 - 9:23
 */
@Controller
public class HelloController {

    @RequestMapping("/hello")
    public ModelAndView hello(){

        // 模拟异常(全局异常处理)
//        int i = 1 / 0;

        // 抛出自定义的异常信息
//        if (1 == 1){
//            // 参数异常
             throw new ParamsException();
//            // 业务异常
//            throw new BusinessException();
//        }

        System.out.println("hello请求被拦截了.........");
        ModelAndView modelAndView = new ModelAndView();
        // 设置数据信息
        modelAndView.addObject("name", "zhangsan");
        // 设置跳转的视图
        modelAndView.setViewName("hello");
        return modelAndView;
    }
}

  • 使用 SimpleMappingExceptionResolver 进行异常处理,具有集成简单,有良好的的拓展性,对已有的代码没有入侵性等优点,但该方法仅能获取到异常信息,若出现异常时,对需要获取除了异常之外的数据的情况不适用。

2.2 实现接口 HandlerExceptionResolver

  • 配置全局的异常处理类(需要放置在包下)
package com.liu.springmvc;

import com.liu.springmvc.exception.BusinessException;
import com.liu.springmvc.exception.ParamsException;
import org.springframework.web.servlet.HandlerExceptionResolver;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * @author lms
 * @date 2021-09-26 - 11:13
 */
// 为了让当前的全局异常处理类生效,需要将其让IOC容器进行管理
// 方式2: 实现Spring的异常处理接口 HandlerExceptionResolver自定义自己的异常处理器(推荐使用)
// 直接使用注解不生效,不知道为啥,所以需要在SpringMVC的配置文件中进行配置全局异常处理类
//@Component
//@Component("handlerExceptionResolver")
public class GlobalExceptionResolver implements HandlerExceptionResolver {
    @Override
    public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {
        // 设置默认的异常处理页面
        ModelAndView mv = new ModelAndView("error");
        mv.addObject("ex", "默认错误异常信息!");

        // 判断是否是自定义异常信息
        // 参数异常,跳转至参数异常页面
        if (ex instanceof ParamsException) {
            mv.setViewName("params_error");
            // 获取具体的异常信息
            ParamsException e = (ParamsException) ex;
            mv.addObject("ex", e.getMessage());
        }

        // 业务异常,跳转至业务异常页面
        if (ex instanceof BusinessException) {
            mv.setViewName("business_error");
            // 获取具体的异常信息
            BusinessException e = (BusinessException) ex;
            mv.addObject("ex", e.getMessage());
        }
        return mv;
    }
}

  • 配置文件
 <!-- 方式2: 实现Spring的异常处理接口 HandlerExceptionResolver自定义自己的异常处理器(推荐使用)  -->
 <bean id="handlerExceptionResolver" class="com.liu.springmvc.GlobalExceptionResolver"/>

2.3 未捕获异常处理

  • 在web.xml中进行配置
<!--  未捕获的异常信息处理  -->
<error-page>
    <exception-type>java.lang.Throwable</exception-type>
    <location>/500.jsp</location>
</error-page>
<error-page>
    <error-code>500</error-code>
    <location>/500.jsp</location>
</error-page>
<error-page>
    <error-code>404</error-code>
    <location>/404.jsp</location>
</error-page>

标签:拦截器,http,登录,javax,Listener,监听器,import,servlet,public
来源: https://blog.csdn.net/lms18811338696/article/details/120499241

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有