zoukankan      html  css  js  c++  java
  • 7.【原创】Spring Mvc自定义DispatcherServlet类,处理404异常

    1.原因:

      自己在写纯接口服务的时候,使用Spring Mvc方式在web.xml中配置拦截器,使用@RestControllerAdvice注解定义了一个全局的异常处理器,在SpringBoot中,它可正常拦截到类似NoHandlerFoundException(404)、500、406等异常,但是在Spring Mvc确无法做到。在使用Spring Mvc时,此框架通过DispatcherServlet类进行转发请求时,例如404此种异常会直接在DispatcherServlet类中抛出,然后由Tomcat捕获进行错误页面的响应处理,并不会转发到Controller层中。也就无法到达@RestControllerAdvice注解的全局异常处理类中处理。

    2.处理:

      2.1.继承DispatcherServlet,自定义转发器,重写noHandlerFound方法处理404异常,因为此方法返回值是void,所以采用抛出自定义的异常,让@RestControllerAdvice的全局异常处理类处理。再重写processHandlerException方法处理其他异常,例如500,406等。

      2.2.在web.xml中将原先的DispatcherServlet替换成自定义的CustomizeDispatcherServlet类即可。话不多说,上代码。

    3.实现:

      3.1.自定义转发器DispatcherServlet重写noHandlerFound和processHandlerException方法

    package cn.drip.dripblog.filter;
    
    import cn.drip.dripblog.constant.consist.DripException;
    import cn.drip.dripblog.constant.enums.ExpStatus;
    import cn.drip.dripblog.model.dto.Result;
    import com.alibaba.fastjson.support.spring.FastJsonJsonView;
    import org.springframework.http.HttpHeaders;
    import org.springframework.http.HttpStatus;
    import org.springframework.web.HttpRequestMethodNotSupportedException;
    import org.springframework.web.servlet.DispatcherServlet;
    import org.springframework.web.servlet.ModelAndView;
    import org.springframework.web.servlet.NoHandlerFoundException;
    
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    import java.util.HashMap;
    import java.util.Map;
    
    /**
     * @Author: Chunhai.Hu
     * @Date: 2020/9/8 0008 15:46
     * @Last Modified by: Chunhai.Hu
     * @Last Modified time: 2020/9/8 0008 15:46
     * @Desc: 自定义DispatcherServlet,重写noHandlerFound方法,处理HTTP通用异常,如404
     */
    public class CustomizeDispatcherServlet extends DispatcherServlet {
    
        // 抛出404的异常:交由GlobalExceptionHandler处理
        @Override
        protected void noHandlerFound(HttpServletRequest request, HttpServletResponse response) throws Exception {
            throw new NoHandlerFoundException(request.getMethod(), request.getRequestURL().toString(), new HttpHeaders());
        }
    
        // 拦截对应异常:拦截除404之外的HTTP异常
        @Override
        protected ModelAndView processHandlerException(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
            // 共用参数
            ModelAndView model = new ModelAndView();
            FastJsonJsonView view = new FastJsonJsonView();
            Map<String, String> map = new HashMap<String, String>();
    
            if (ex instanceof HttpRequestMethodNotSupportedException) {
                // 处理405异常:请求方式不支持
                map.put("status", String.valueOf(HttpStatus.METHOD_NOT_ALLOWED.value()));
                map.put("message", ex.getMessage());
            } else {
           // 不想自定义处理的异常:交还父类处理
    return super.processHandlerException(request, response, handler, ex); } // 设置返回 view.setAttributesMap(map); model.setView(view); return model; } }

    3.2.使用RestControllerAdvice注解定义全局的异常处理器GlobalExceptionHandler

    package cn.drip.dripblog.filter;
    
    import cn.drip.dripblog.constant.consist.DripException;
    import cn.drip.dripblog.constant.enums.ExpStatus;
    import cn.drip.dripblog.model.dto.Result;
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    import org.springframework.http.HttpStatus;
    import org.springframework.web.bind.annotation.*;
    import org.springframework.web.servlet.NoHandlerFoundException;
    
    import javax.servlet.http.HttpServletRequest;
    
    /*
     * @Created with IntelliJ IDEA.
     * @Author: Chunhai.Hu
     * @Date: 2020/6/29 2:38
     * @1.Desc: 全局异常处理,如果使用@RestControllerAdvice 注解则会将返回的数据类型转换成JSON格式
     * @2.在Spring mvc中404,500,505等异常通过DispatcherServlet类抛出被tomcat捕获,
     * @无法到达Controller,也就无法到达@ControllerAdvice
     * @处理方式:声明自定义的CustomizeDispatcherServlet类,重写noHandlerFound和processHandlerException方法处理
     */
    @RestControllerAdvice
    public class GlobalExceptionHandler
    {
        private static final Logger logger = LoggerFactory.getLogger(GlobalExceptionHandler.class);
    
        /**
         * @param req
         * @param e
         * @return
         * @处理: 自定义异常
         */
        @ExceptionHandler(DripException.class)
        public Result DripExceptionHandler(HttpServletRequest req, DripException e)
        {
            e.printStackTrace();
            logger.error("DripException Exception Cause by:{}", e.getMessage());
            return new Result(e.getStatus(), e.getMessage(), e.getExpMsgAttach());
        }
    
        /**
         * @处理404异常
         * @param req
         * @param e
         * @return
         */
        @ExceptionHandler(NoHandlerFoundException.class)
        public Result handlerNoFoundException(HttpServletRequest req, NoHandlerFoundException e) {
            logger.error("NoHandlerFoundException Exception Cause by:{}", e.getMessage());
            return new Result(String.valueOf(HttpStatus.NOT_FOUND.value()), e.getMessage());
        }
    
        /**
         * @param req
         * @param e
         * @return
         * @处理:空指针异常
         */
        @ExceptionHandler(NullPointerException.class)
        public Result nullPointerExceptionHandler(HttpServletRequest req, NullPointerException e)
        {
            e.printStackTrace();
            logger.error("NullPointerException Exception Cause by:{}", e.getMessage());
            return new Result(ExpStatus.SERVICE_BUSY);
        }
    
        /**
         * @param req
         * @param e
         * @return
         * @处理:未涉及的异常
         */
        @ExceptionHandler(Exception.class)
        public Result ExceptionHandler(HttpServletRequest req, Exception e)
        {
            e.printStackTrace();
            logger.error("Exception Cause by:{}", e.getMessage());
            return new Result(ExpStatus.SERVICE_BUSY);
        }
    }

    3.3.将web.xml中将原先的DispatcherServlet替换成自定义的CustomizeDispatcherServlet类

    <?xml version="1.0" encoding="UTF-8"?>
    <web-app xmlns="http://java.sun.com/xml/ns/javaee"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
                        http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
             version="3.0">
    
      <!--1.1:配置Spring监听器,加载spring核心容器配置:默认只加载WEB-INF下的applicationContext.xml文件-->
      <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
      </listener>
    
      <!--1.2:设置Spring配置文件路径-->
      <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>classpath:applicationContext.xml</param-value>
      </context-param>
    
      <!--步骤2.1:配置spring的前端控制器,让所有请求都由其处理(此为自定义的DispatcherServlet)-->
      <servlet>
        <servlet-name>CustomizeDispatcherServlet</servlet-name>
        <servlet-class>cn.drip.dripblog.filter.CustomizeDispatcherServlet</servlet-class>
        <!--配置初始化参数:读取springmvc的配置文件:使用类路径方式-->
        <init-param>
          <param-name>contextConfigLocation</param-name>
          <param-value>classpath:spring-servlet.xml</param-value>
        </init-param>
        <!--配置加载策略:一启动时就加载-->
        <load-on-startup>1</load-on-startup>
      </servlet>
      <!--2.2:配置映射路径及拦截范围-->
      <servlet-mapping>
        <servlet-name>CustomizeDispatcherServlet</servlet-name>
        <url-pattern>/</url-pattern>
      </servlet-mapping>
    </web-app>

    4.注意事项:

      4.1.以上代码中的DripException、ExpStatus、Result和Status类都是我自定义的类,具体使用时,可依情况进行对应替换。

  • 相关阅读:
    集合-ArrayList 源码解析
    >>《配色设计原理.pdf》
    >>《[美国视觉设计学院用书:完成设计(从理论到实践)].(萨马拉).温迪等.扫描版.pdf》
    《Photoshop智能手机APP界面设计.pdf》
    《贴心设计:打造高可用性的移动产品》——5.平板电脑和电子书阅读器
    3H Buy a Ticket —— Dij
    最短路板子
    3E A Simple Problem —— 数论
    3D 城池攻占 —— 左偏树
    3A Least Cost Bracket Sequence —— 贪心
  • 原文地址:https://www.cnblogs.com/Nick-Hu/p/13650453.html
Copyright © 2011-2022 走看看