SpringMVC 全局异常处理

(一)、SpringMVC全局异常快速入门 

 

 

 

 (二)、Spring及SpringMVC扫描包隔离及配置文件优化 

          1、删除applicationContext-datasource.xml文件里context:component-scan        

 <context:component-scan base-package="com.mmall" annotation-config="true"/>

          2、applicationContext.xml文件          

<!-- 扫描com.mmall包下的注解,就可以很方便的在类中进行注入-->
    <!-- 排除controller注解-->
    <!-- ApplicationContext.xml  是spring 全局配置文件,用来控制spring 特性的-->
    <!-- dispatcher-servlet.xml 是spring mvc里面的,控制器、拦截uri转发view  Controller扫描放到这里,其他扫描放到ApplicationContext.xml-->

    <context:component-scan base-package="com.mmall" annotation-config="true">
        <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
    </context:component-scan>

           3、dispatcher-servlet.xml文件

           

<!--  只扫描controller注解,其他bean的applicationContext.xml  扫描放到 只要有方法使用了@Controller,就会扫描到-->
    <!-- use-default-filter 关闭默认扫描-->
    <context:component-scan base-package="com.mmall.controller" annotation-config="true" use-default-filters="false">
        <context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
    </context:component-scan>

 

备注:

转载地址:https://www.cnblogs.com/parryyang/p/5783399.html

applicationContext.xml和dispatcher-servlet.xml的区别

在SpringMVC项目中我们一般会引入applicationContext.xml和dispatcher-servlet.xml两个配置文件,这两个配置文件具体的区别是什么呢?

  Spring 官方文档介绍如下:

Spring lets you define multiple contexts in a parent-child hierarchy.  
    The applicationContext.xml defines the beans for the "root webapp context", i.e. the context associated with the webapp.  
    The spring-servlet.xml (or whatever else you call it) defines the beans for one servlet's app context. There can be many of these in a webapp, one per Spring servlet (e.g. spring1-servlet.xml for servlet spring1, spring2-servlet.xml for servlet spring2).  
    Beans in spring-servlet.xml can reference beans in applicationContext.xml, but not vice versa.  
    All Spring MVC controllers must go in the spring-servlet.xml context.  
    In most simple cases, the applicationContext.xml context is unnecessary. It is generally used to contain beans that are shared between all servlets in a webapp. If you only have one servlet, then there's not really much point, unless you have a specific use for it.

可见, applicationContext.xml 和 dispatch-servlet.xml形成了两个父子关系的上下文。

  1) 一个bean如果在两个文件中都被定义了(比如两个文件中都定义了component scan扫描相同的package), spring会在application context和 servlet context中都生成一个实例,他们处于不同的上下文空间中,他们的行为方式是有可能不一样的。

  2) 如果在application context和 servlet context中都存在同一个 @Service 的实例, controller(在servlet context中) 通过 @Resource引用时, 会优先选择servlet context中的实例。

  不过最好的方法是:在applicationContext和dispatcher-servlet定义的bean最好不要重复, dispatcher-servlet最好只是定义controller类型的bean。

  ----------------------------------------------------------------------------------------------------------------------------------------

  applicationContext.xml  是spring 全局配置文件,用来控制spring 特性的

  dispatcher-servlet.xml 是spring mvc里面的,控制器、拦截uri转发view

 

Contronller bean放在dispatcher-servlet.xml,其他bean放在applicationContext.xml 

(三)、 SpringMVC全局异常实战

         新建ExceptionResolver文件

          

@Slf4j
@Component
public class ExceptionResolver implements HandlerExceptionResolver {
    @Override
    public ModelAndView resolveException(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) {
        // 必须加e,不然在控制台不会输出完整的错误
        log.error("{} Exception", httpServletRequest.getRequestURI(), e);

        // 当使用jackjson2.x的时候使用MappingJackson2JsonView,课程中使用的是1.9,所以使用MappingJacksonJsonView
        // MappingJacksonJsonView是为了将model转换成json
        ModelAndView modelAndView = new ModelAndView(new MappingJacksonJsonView());
        modelAndView.addObject("status", ResponseCode.ERROR.getCode());
        modelAndView.addObject("msg", "接口异常,详细请查看服务端日志的异常信息");
        modelAndView.addObject("data", e.toString());
        return modelAndView;
    }
}

 

 

   (四)、上面的全局异常用的是HandlerExceptionResolver,实际中还有一种方法,是用 @ExceptionHandler和@controlleradvice 

     转载:https://www.cnblogs.com/xiang--liu/p/11422504.html     

把 @ExceptionHandler、HandlerExceptionResolver、@controlleradvice 三兄弟放在一起来写更有比较性。这三个东西都是用来处理异常的,但是它们使用的场景都不一样。看本文给你详细的讲解,再也不怕面试被问到了!

这三个注解都是来自于 SpringMVC 的,都能进行异常处理。

Java 程序员都非常的痛恨异常,很多人讨厌 Java 就是因为它的异常处理机制。到处的 try-catch-finally,再不是就是到处抛出异常。

所以 Spring 深知 Java 的疼点,推出了:@ExceptionHandler、HandlerExceptionResolver、@controlleradvice 来方便我们处理一些异常!

@ExceptionHandler 注解

用于局部方法捕获,与抛出异常的方法处于同一个 Controller 类。源码如下:

@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface ExceptionHandler {
    Class<? extends Throwable>[] value() default {};
}

从源码中可以看出,@ExceptionHandler 注解只能作用为对象的方法上,并且在运行时有效,value() 可以指定异常类。由该注解注释的方法可以具有灵活的输入参数。

异常参数可以包括一般的异常或特定的异常(即自定义异常),如果注解没有指定异常类,会默认进行映射。

用法代码如下:

@Controller
public class XttblogController {
    @ExceptionHandler({NullPointerException.class})
    public String exception(NullPointerException e) {
        System.out.println(e.getMessage());
        e.printStackTrace();
        return "null pointer exception";
    }
    @RequestMapping("test")
    public void test() {
        throw new NullPointerException("出错了!");
    }
}

上面这段代码只会捕获 XttblogController 类中的 NullPointerException 异常。

HandlerExceptionResolver 接口

HandlerExceptionResolver 是 Spring 提供的一个接口。它可以用来处理全局异常!

@Component
public class GlobalExceptionResolver implements HandlerExceptionResolver{
    private ObjectMapper objectMapper;
    public CustomMvcExceptionHandler() {
        objectMapper = new ObjectMapper();
    }
    @Override
    public ModelAndView resolveException(HttpServletRequest request, 
        HttpServletResponse response,Object o, Exception ex) {
        response.setStatus(200);
        response.setContentType(MediaType.APPLICATION_JSON_VALUE);
        response.setCharacterEncoding("UTF-8");
        response.setHeader("Cache-Control", "no-cache, must-revalidate");
        Map<String, Object> map = new HashMap<>();
        if (ex instanceof NullPointerException) {
            map.put("code", ResponseCode.NP_EXCEPTION);
        } else if (ex instanceof IndexOutOfBoundsException) {
            map.put("code", ResponseCode.INDEX_OUT_OF_BOUNDS_EXCEPTION);
        } else {
            map.put("code", ResponseCode.CATCH_EXCEPTION);
        }
        try {
            map.put("data", ex.getMessage());
            response.getWriter().write(objectMapper.writeValueAsString(map));
        } catch (Exception e) {
            e.printStackTrace();
        }
        return new ModelAndView();
    }
}

在 Spring 源码中,我们可以看出它会获取一个实现了 HandlerExceptionResolver 接口的列表 List<HandlerExceptionResolver> resolvers; 如果这个列表不为空,则循环处理其中的异常。

HandlerExceptionResolve 虽然能够处理全局异常,但是 Spring 官方不推荐使用它。

@controlleradvice 注解

另外一个能够处理全局异常的就是 @controlleradvice 注解了。

@controlleradvice 注解根据它的源码,我们知道它也只能作用在类上,并且作用于运行时。下面我们来看一个例子。

@ControllerAdvice
public class ExceptionController {
    @ExceptionHandler(RuntimeException.class)
    public ModelAndView handlerRuntimeException(RuntimeException ex) {
        if (ex instanceof MaxUploadSizeExceededException) {
            return new ModelAndView("error").addObject("msg", "文件太大!");
        }
        return new ModelAndView("error").addObject("msg", "未知错误:" + ex);
    }
    @ExceptionHandler(Exception.class)
    public ModelAndView handlerMaxUploadSizeExceededException(Exception ex) {
        if (ex != null) {
            return new ModelAndView("error").addObject("msg", ex);
        }
        return new ModelAndView("error").addObject("msg", "未知错误:" + ex);
    }
}

需要注意的是,@ControllerAdvice 一般是和 @ExceptionHandler 组合在一起使用的。官方也推荐用这种方式处理统一全局异常。

posted @ 2020-04-10 11:59  zhaobao1830  阅读(370)  评论(0编辑  收藏  举报