使用Spring MVC的@ControllerAdvice注解做Json的异常处理
2016-07-19 10:07
411 查看
一,本文介绍Spring MVC的自定义异常处理,即在Controller中抛出自定义的异常时,客户端收到更友好的JSON格式的提示。而不是常见的报错页面。
二,场景描述:实现公用API,验证API key的逻辑,放在拦截器中判断(等同于在Controller中)并抛出异常,用户收到类似下图的提示:
其中,Http状态Code也能自由控制。
三,解决方案:
1,在RateLimitInterceptor.java拦截器中抛出异常:
[java] view
plain copy
public class RateLimitInterceptor extends HandlerInterceptorAdapter{
@Autowired private RedisService rs;
/**
* 流量控制检查入口
*/
@Override
public boolean preHandle(HttpServletRequest request,
HttpServletResponse response, Object handler) throws RequiredParameterException, SignException, RateLimitException,Exception {
super.preHandle(request, response, handler);
String appKey = request.getParameter("appKey");
//判断appKey是否为空或是否合法
if(appKey == null){
throw new RequiredParameterException("");
}else if(AppKeyUtils.isFormatCorrect(appKey) || !rs.isExist(appKey)){
throw new SignException();
}else {
try {
AppCall appCall = AppCall.create(appKey, AppKeyUtils.getPlanDetails(appKey));
appCall.decrease();
rs.save(appCall);
System.out.println("RateLimitInterceptor pass.");
} catch (RateLimitException e) {
//抛出超限异常
throw new RateLimitException();
}
}
return true;
}
}
当代码走到(具体怎样走到,需考虑具体业务逻辑,上述代码使用AppCall类来封装,这是后话)
[java] view
plain copy
throw new SignException();
时,Spring将自动捕获这个异常。然后做一些处理。这是正常的流程。那么Spring如何自动不火
2,使用Spring MVC的@ControllerAdvice,在GlobalExceptionHandler.java类中实现全局的异常处理类:
[java] view
plain copy
@ControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(SQLException.class)
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
@ResponseBody
public ExceptionResponse handleSQLException(HttpServletRequest request, Exception ex) {
String message = ex.getMessage();
return ExceptionResponse.create(HttpStatus.INTERNAL_SERVER_ERROR.value(), message);
}
@ResponseStatus(value=HttpStatus.NOT_FOUND, reason="IOException occured")
@ExceptionHandler(IOException.class)
@ResponseBody
public void handleIOException(){
//returning 404 error code
}
@ResponseStatus(HttpStatus.BAD_REQUEST)
@ResponseBody
@ExceptionHandler(SignException.class)
public ExceptionResponse signException(SignException ex) {
return ex.getEr();
}
}
在方法的头上注解:
[java] view
plain copy
@ExceptionHandler(SignException.class)
即表示让Spring捕获到所有抛出的SignException异常,并交由这个被注解的方法处理。
注解:
[java] view
plain copy
@ResponseBody
即表示返回的对象,Spring会自动把该对象进行json转化,最后写入到Response中。
注解:
[java] view
plain copy
@ResponseStatus(HttpStatus.BAD_REQUEST)
表示设置状态码。如果应用级别的错误,此处其实永远返回200也是可以接受的,但是要在你自定义的异常串和异常码中做好交代。
本文的方案自定义了一个ExceptionResponse.java类,如下:
[java] view
plain copy
/**
* 返回的json数据
* @author craig
*
*/
public class ExceptionResponse {
private String message;
private Integer code;
/**
* Construction Method
* @param code
* @param message
*/
public ExceptionResponse(Integer code, String message){
this.message = message;
this.code = code;
}
public static ExceptionResponse create(Integer code, String message){
return new ExceptionResponse(code, message);
}
public Integer getCode() {
return code;
}
public String getMessage() {
return message;
}
}
如你所知,这个类就是最后传到用户面前的一个异常类,code和message根据业务定义并让用户知晓。而自定义的SignException.java实际上起到了一个桥梁的作用。Spring把SignException对象捕获到,转成相应的ExceptionResponse对象,剩下的就是如何优雅实现的问题了。 如下是SignException.java的实现:
[java] view
plain copy
/**
* 签名异常
* @author tuxiao.czz
*
*/
public class SignException extends Exception {
private static final long serialVersionUID = 4714113994147018010L;
private String message = "AppKey is not correct, please check.";
private Integer code = 10002;
private ExceptionResponse er;
public SignException() {
er = ExceptionResponse.create(code, message);
}
public ExceptionResponse getEr() {
return er;
}
}
所有关于这个异常的code和message都写在这个类里,个人感觉还是可以接受。当然还有另外一种实现,就是只拦截、定义一种Exception类,然后传不同的code和message进去,然后做相应的处理。这些都是比较灵活的。
以上便是实现“自定义异常json化处理”的相关代码和说明。
二,场景描述:实现公用API,验证API key的逻辑,放在拦截器中判断(等同于在Controller中)并抛出异常,用户收到类似下图的提示:
其中,Http状态Code也能自由控制。
三,解决方案:
1,在RateLimitInterceptor.java拦截器中抛出异常:
[java] view
plain copy
public class RateLimitInterceptor extends HandlerInterceptorAdapter{
@Autowired private RedisService rs;
/**
* 流量控制检查入口
*/
@Override
public boolean preHandle(HttpServletRequest request,
HttpServletResponse response, Object handler) throws RequiredParameterException, SignException, RateLimitException,Exception {
super.preHandle(request, response, handler);
String appKey = request.getParameter("appKey");
//判断appKey是否为空或是否合法
if(appKey == null){
throw new RequiredParameterException("");
}else if(AppKeyUtils.isFormatCorrect(appKey) || !rs.isExist(appKey)){
throw new SignException();
}else {
try {
AppCall appCall = AppCall.create(appKey, AppKeyUtils.getPlanDetails(appKey));
appCall.decrease();
rs.save(appCall);
System.out.println("RateLimitInterceptor pass.");
} catch (RateLimitException e) {
//抛出超限异常
throw new RateLimitException();
}
}
return true;
}
}
当代码走到(具体怎样走到,需考虑具体业务逻辑,上述代码使用AppCall类来封装,这是后话)
[java] view
plain copy
throw new SignException();
时,Spring将自动捕获这个异常。然后做一些处理。这是正常的流程。那么Spring如何自动不火
2,使用Spring MVC的@ControllerAdvice,在GlobalExceptionHandler.java类中实现全局的异常处理类:
[java] view
plain copy
@ControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(SQLException.class)
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
@ResponseBody
public ExceptionResponse handleSQLException(HttpServletRequest request, Exception ex) {
String message = ex.getMessage();
return ExceptionResponse.create(HttpStatus.INTERNAL_SERVER_ERROR.value(), message);
}
@ResponseStatus(value=HttpStatus.NOT_FOUND, reason="IOException occured")
@ExceptionHandler(IOException.class)
@ResponseBody
public void handleIOException(){
//returning 404 error code
}
@ResponseStatus(HttpStatus.BAD_REQUEST)
@ResponseBody
@ExceptionHandler(SignException.class)
public ExceptionResponse signException(SignException ex) {
return ex.getEr();
}
}
在方法的头上注解:
[java] view
plain copy
@ExceptionHandler(SignException.class)
即表示让Spring捕获到所有抛出的SignException异常,并交由这个被注解的方法处理。
注解:
[java] view
plain copy
@ResponseBody
即表示返回的对象,Spring会自动把该对象进行json转化,最后写入到Response中。
注解:
[java] view
plain copy
@ResponseStatus(HttpStatus.BAD_REQUEST)
表示设置状态码。如果应用级别的错误,此处其实永远返回200也是可以接受的,但是要在你自定义的异常串和异常码中做好交代。
本文的方案自定义了一个ExceptionResponse.java类,如下:
[java] view
plain copy
/**
* 返回的json数据
* @author craig
*
*/
public class ExceptionResponse {
private String message;
private Integer code;
/**
* Construction Method
* @param code
* @param message
*/
public ExceptionResponse(Integer code, String message){
this.message = message;
this.code = code;
}
public static ExceptionResponse create(Integer code, String message){
return new ExceptionResponse(code, message);
}
public Integer getCode() {
return code;
}
public String getMessage() {
return message;
}
}
如你所知,这个类就是最后传到用户面前的一个异常类,code和message根据业务定义并让用户知晓。而自定义的SignException.java实际上起到了一个桥梁的作用。Spring把SignException对象捕获到,转成相应的ExceptionResponse对象,剩下的就是如何优雅实现的问题了。 如下是SignException.java的实现:
[java] view
plain copy
/**
* 签名异常
* @author tuxiao.czz
*
*/
public class SignException extends Exception {
private static final long serialVersionUID = 4714113994147018010L;
private String message = "AppKey is not correct, please check.";
private Integer code = 10002;
private ExceptionResponse er;
public SignException() {
er = ExceptionResponse.create(code, message);
}
public ExceptionResponse getEr() {
return er;
}
}
所有关于这个异常的code和message都写在这个类里,个人感觉还是可以接受。当然还有另外一种实现,就是只拦截、定义一种Exception类,然后传不同的code和message进去,然后做相应的处理。这些都是比较灵活的。
以上便是实现“自定义异常json化处理”的相关代码和说明。
相关文章推荐
- (转)java中Executor、ExecutorService、ThreadPoolExecutor介绍
- Java设计模式—策略模式
- WebService-CXF_配置文件篇
- Java四种线程池的使用
- Java设计模式—策略模式
- spring中AOP编程
- 按照列表中的某个字段的属性进行排序
- Spring中基于Java的配置@Configuration和@Bean用法
- java并发编程之CountDownLatch
- (原)java中对象复制、==、equals
- JNI:在java和c之间进行数据传递
- Spring注解@Component、@Repository、@Service、@Controller区别
- Spring中@Controller和@RestController之间的区别
- 二叉树<一> — — 3种方式的遍历
- Spring入门
- spring整合JUnit4
- Spring mvc的参数究竟是如何绑定的
- Arrays类asList()方法遇到的问题
- java9*9乘法
- eclipse启动时报错jvm找不到,No java virtual machine was found