`
m635674608
  • 浏览: 5032596 次
  • 性别: Icon_minigender_1
  • 来自: 南京
社区版块
存档分类
最新评论

spring mvc统一异常处理(@ControllerAdvice + @ExceptionHandler)

    博客分类:
  • java
 
阅读更多

v一、前言

  项目刚刚开发的时候,并没有做好充足的准备。开发到一定程度的时候才会想到还有一些问题没有解决。就比如今天我要说的一个问题:异常的处理。写程序的时候一般都会通过try...catch...finally对异常进行处理,但是我们真的能在写程序的时候处理掉所有可能发生的异常吗? 以及发生异常的时候执行什么逻辑,返回什么提示信息,跳转到什么页面,这些都是要考虑到的。

v二、基于@ControllerAdvice(加强的控制器)的异常处理

  参考文档:http://jinnianshilongnian.iteye.com/blog/1866350

  @ControllerAdvice注解内部使用@ExceptionHandler、@InitBinder、@ModelAttribute注解的方法应用到所有的 @RequestMapping注解的方法。本例子中使用ExceptionHandler应用到所有@RequestMapping注解的方法,处理发生的异常。

  示例代码:

复制代码
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;

import com.hjz.exception.ServiceException;
import com.hjz.exception.utils.ExceptionUtils;

@ResponseBody
public class ExceptionAdvice {
    private static final Logger LOGGER = LoggerFactory.getLogger(ExceptionAdvice.class);

    /**
     * 拦截web层异常,记录异常日志,并返回友好信息到前端
     * 目前只拦截Exception,是否要拦截Error需再做考虑
     *
     * @param e 异常对象
     * @return 异常提示
     */
    @ExceptionHandler(Exception.class)
    public ResponseEntity<String> handleException(Exception e) {
        //不需要再记录ServiceException,因为在service异常切面中已经记录过
        if (!(e instanceof ServiceException)) {
            LOGGER.error(ExceptionUtils.getExcTrace(e));
        }

        HttpHeaders headers = new HttpHeaders();
        headers.set("Content-type", "text/plain;charset=UTF-8");
        headers.add("icop-content-type", "exception");
        String message = StringUtils.isEmpty(e.getMessage()) ? "系统异常!!" : e.getMessage();
        return new ResponseEntity<>(message, headers, HttpStatus.OK);
    }
}
复制代码

  如果不起作用,请检查 spring-mvc的配置文件,是否有ControllerAdvice的如下配置

<context:component-scan base-package="com.sishuok.es" use-default-filters="false">  
       <context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/>  
       <context:include-filter type="annotation" expression="org.springframework.web.bind.annotation.ControllerAdvice"/>  
   </context:component-scan>  

 

v三、基于AOP的异常处理

  1.处理controller层的异常 WebExceptionAspect.java

复制代码
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import com.hjz.exception.ServiceException;
import com.hjz.exception.utils.ExceptionUtils;

import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;

/**
 * web异常切面
 * 默认spring aop不会拦截controller层,使用该类需要在spring公共配置文件中注入改bean,
 * 另外需要配置<aop:aspectj-autoproxy proxy-target-class="true"/>
 */
@Aspect
public class WebExceptionAspect {
    private static final Logger LOGGER = LoggerFactory.getLogger(WebExceptionAspect.class);

    @Pointcut("@annotation(org.springframework.web.bind.annotation.RequestMapping)")
    private void webPointcut() {}

    /**
     * 拦截web层异常,记录异常日志,并返回友好信息到前端
     * 目前只拦截Exception,是否要拦截Error需再做考虑
     *
     * @param e 异常对象
     */
    @AfterThrowing(pointcut = "webPointcut()", throwing = "e")
    public void handleThrowing(Exception e) {
        //不需要再记录ServiceException,因为在service异常切面中已经记录过
        if (!(e instanceof ServiceException)) {
            LOGGER.error(ExceptionUtils.getExcTrace(e));
        }

        String errorMsg = StringUtils.isEmpty(e.getMessage()) ? "系统异常" : e.getMessage();
        writeContent(errorMsg);
    }

    /**
     * 将内容输出到浏览器
     *
     * @param content 输出内容
     */
    private void writeContent(String content) {
        HttpServletResponse response = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getResponse();
        response.reset();
        response.setCharacterEncoding("UTF-8");
        response.setHeader("Content-Type", "text/plain;charset=UTF-8");
        response.setHeader("icop-content-type", "exception");
        PrintWriter writer = null;
        try {
            writer = response.getWriter();
        } catch (IOException e) {
            e.printStackTrace();
        }
        writer.print(content);
        writer.flush();
        writer.close();
    }
}
复制代码

  2.处理service层的异常ServiceExceptionAspect .java

复制代码
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;

import com.hjz.exception.ServiceException;
import com.hjz.exception.utils.ExceptionUtils;

@Aspect
public class ServiceExceptionAspect {
    private static final Logger LOGGER = LoggerFactory.getLogger(ServiceExceptionAspect.class);

    /**
     * @within(org.springframework.stereotype.Service),拦截带有 @Service 注解的类的所有方法
     * @annotation(org.springframework.web.bind.annotation.RequestMapping),拦截带有@RquestMapping的注解方法
     */
    @Pointcut("@within(org.springframework.stereotype.Service) && execution(public * *(..))")
    private void servicePointcut() {}

    /**
     * 拦截service层异常,记录异常日志,并设置对应的异常信息
     * 目前只拦截Exception,是否要拦截Error需再做考虑
     *
     * @param e 异常对象
     */
    @AfterThrowing(pointcut = "servicePointcut()", throwing = "e")
    public void handle(JoinPoint point, Exception e) {
        LOGGER.error(ExceptionUtils.getExcTrace(e));

        String signature = point.getSignature().toString();
        String errorMsg = getMessage(signature) == null ? (StringUtils.isEmpty(e.getMessage()) ? "服务异常" : e.getMessage()) : getMessage(signature);
        throw new ServiceException(errorMsg, e);
    }

    /**
     * 获取方法签名对应的提示消息
     *
     * @param signature 方法签名
     * @return 提示消息
     */
    private String getMessage(String signature) {
        return null;
    }
}
复制代码

   3.使用方式,在spring的公共配置文件中加入如下配置:

<aop:aspectj-autoproxy proxy-target-class="true" />
<bean class="com.hjz.exception.aspect.ServiceExceptionAspect" />
<bean class="com.hjz.exception.aspect.WebExceptionAspect" />

  或者 自定义一个 注册类,ServiceExceptionAspect.java和WebExceptionAspect.java都加入@Component注解

复制代码
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;

/**
 * 异常相关bean注册类
 */
@Configuration
@EnableAspectJAutoProxy
@ComponentScan("com.hjz.exception.aspect")
public class ExceptionConfig {

}
复制代码

  注:spring 公共配置文件中的配置 改成 <bean class="com.hjz.exception.config.ExceptionConfig"/>,如果controller层的异常无法拦截,请将配置换到springmvc的配置文件中,原因请见(SpringMVC关于AOP拦截controller的注意事项

复制代码
@Aspect
@Component
public class WebExceptionAspect {
   ..........  
}


@Aspect
@Component
public class ServiceExceptionAspect {
   .........
}
复制代码

v四、疑惑

   @within(org.springframework.stereotype.Service),拦截带有 @Service 注解的类的所有方法
   @annotation(org.springframework.web.bind.annotation.RequestMapping),拦截带有@RquestMapping的注解方法

v五、测试

  分别编写controller层和service层的异常测试类。这个很简单,在方法里简单的抛一下异常就可以了。最后验证一下,异常发生的时候有没有 执行 @AfterThrowing对应的方法就好了。具体还是看我写的demo吧,嘿嘿嘿!!!

  完整项目下载地址:https://github.com/hjzgg/Spring-annotation-AOP-Exception_handling

 

http://www.cnblogs.com/hujunzheng/p/6255463.html

分享到:
评论

相关推荐

    spring mvc统一处理异常

    spring mvc统一处理异常,通过@ControllerAdvice+@ExceptionHandler

    ControllerAdvice spring mvc 3.2 错误统一控制

    通过`@ExceptionHandler`标注的方法`handleException`,我们可以定义当发生异常时,如何处理异常并返回对应的视图。 具体到给出的内容: ```jsp jsp/error.jsp &lt;%@taglib prefix="spring" uri="***"%&gt; ${message}...

    spring mvc异常简单处理

    确保正确配置这些依赖,是构建一个能够正常处理异常的Spring MVC项目的基础。 在`src`目录下,可能包含了Java源代码、配置文件等。通常,异常处理相关的类会放在`com.example.yourpackage.controller.advice`这样的...

    spring mvc异常处理

    Spring MVC 提供了一种统一的方式来处理应用程序中抛出的异常。它通过`@ExceptionHandler`注解、`@ControllerAdvice`注解和`HandlerExceptionResolver`接口来实现这一目标,使得我们可以定制化错误页面,提供友好的...

    spring mvc 4.0

    11. **错误处理**:通过@ControllerAdvice和@ExceptionHandler,可以全局处理异常,提供统一的错误页面或API响应。 12. **整合WebSocket**:Spring MVC 4.0开始支持WebSocket协议,允许实现实时通信,如聊天应用、...

    spring2.0MVC+spring2.5MVC+portletMVC

    5. **异常处理**:Spring 2.0提供了@ControllerAdvice和@ExceptionHandler注解,使得全局异常处理更加简洁和高效。 接下来,Spring 2.5进一步扩展了这些特性,包括: 1. **@RequestMapping**:这是一个关键注解,...

    springmvc 异常统一处理的三种方式详解.docx

    本篇文章将详细探讨Spring MVC处理异常的三种主要方法:SimpleMappingExceptionResolver、自定义HandlerExceptionResolver以及@ExceptionHandler注解。 1. SimpleMappingExceptionResolver Spring MVC提供了内置的...

    最全最经典spring-mvc教程

    错误处理和异常处理也是Spring MVC中的重要部分,通过@ControllerAdvice和@ExceptionHandler可以全局处理异常,提供统一的错误页面。 最后,测试是任何应用程序开发的重要环节。Spring MVC提供了MockMVC,可以在不...

    spring mvc + mybitis + mysql集成例子,带数据库

    7. **错误和异常处理**:使用Spring的@ControllerAdvice和@ExceptionHandler注解可以全局处理错误和异常,提高用户体验。 通过这个集成例子,开发者可以学习到如何将这三个组件有效地整合在一起,创建一个功能完善...

    springMVCDemo+maven

    - 可以通过@ControllerAdvice 和 @ExceptionHandler 注解进行全局异常处理,提高代码的健壮性。 11. **视图技术** - Spring MVC 兼容多种视图技术,如 JSP、Freemarker、Thymeleaf 等,可以根据项目需求选择合适...

    最全的Spring MVC注解例子,异步请求,错误处理

    - `@ControllerAdvice`:这是一个全局的异常处理注解,它可以跨越多个控制器,统一处理异常。 - `@ResponseStatus`:用于设置HTTP状态码,配合`@ExceptionHandler`一起使用,可以自定义错误响应的状态码。 - `...

    SpringMVC异常处理知识点总结

    SpringMVC 异常处理是 Spring MVC 框架中的一个重要机制,通过使用 @ExceptionHandler 注解和 @ControllerAdvice 注解,可以实现统一的异常处理机制。在实际开发中,需要根据不同的业务需求来设计和实现异常处理机制...

    Spring MVC 使用注解的示例讲解

    Spring MVC允许我们使用@ControllerAdvice和@ExceptionHandler注解定义全局的异常处理器。这样,任何Controller中抛出的异常都可以被统一捕获和处理。 6. **验证** 使用JSR-303/JSR-349提供的@NotNull、@Size等...

    Spring MVC与MYBatis企业应用实战.pdf

    - 异常处理:通过@ControllerAdvice和@ExceptionHandler全局处理异常。 - 单元测试:使用JUnit和Mockito测试Controller、Service和DAO层的功能。 总之,《Spring MVC与MYBatis企业应用实战》将引导读者深入理解这...

    Spring MVC中异常处理的三种方式

    Spring MVC 框架为我们提供了三种方式来处理异常,分别是实现 HandlerExceptionResolver、使用 @ControllerAdvice 和 @ExceptionHandler 注解、使用 ErrorController。下面我们将详细介绍这三种方式。 1. 实现 ...

    精通Spring MVC4

    Spring MVC提供了一种优雅的异常处理机制,可以使用@ControllerAdvice和@ExceptionHandler注解定义全局异常处理器。此外,还可以自定义错误页面,提高用户体验。 8. **数据绑定和验证** Spring MVC支持自动的数据...

    spring MVC_快速入门

    可以使用@ControllerAdvice和@ExceptionHandler全局处理异常,为整个应用提供统一的错误页面或提示。 8. **拦截器(Interceptor)** 拦截器允许在请求处理前后执行自定义逻辑,比如登录检查、日志记录等。通过...

    spring mvc 整合包

    13. **异常处理**:通过@ControllerAdvice和@ExceptionHandler注解,可以全局处理异常,提供统一的错误页面。 14. **RESTful风格**:Spring MVC支持创建RESTful API,通过HTTP方法(GET、POST、PUT、DELETE等)和...

    Mastering Spring MVC 3中文版

    6. **异常处理**:通过@ControllerAdvice和@ExceptionHandler注解实现全局异常处理。 7. **拦截器**:自定义Interceptor,实现请求前后的预处理和后处理,如权限控制、日志记录等。 8. **RESTful支持**:通过@...

    spring mvc

    13. **异常处理**: 通过@ControllerAdvice和@ExceptionHandler,可以全局捕获并处理应用程序中的异常,提供统一的错误页面或JSON响应。 14. **Internationalization (i18n) & Localization (l10n)**: Spring MVC ...

Global site tag (gtag.js) - Google Analytics