使用Spring MVC的@ControllerAdvice注解做Json的异常处理

一,本文介绍Spring MVC的自定义异常处理,即在Controller中抛出自定义的异常时,客户端收到更友好的JSON格式的提示。而不是常见的报错页面。

二,场景描述:实现公用API,验证API key的逻辑,放在拦截器中判断(等同于在Controller中)并抛出异常,用户收到类似下图的提示:


其中,Http状态Code也能自由控制。


三,解决方案:

1,在RateLimitInterceptor.java拦截器中抛出异常:

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类来封装,这是后话)

throw new SignException();

时,Spring将自动捕获这个异常。然后做一些处理。这是正常的流程。那么Spring如何自动不火


2,使用Spring MVC的@ControllerAdvice,在GlobalExceptionHandler.java类中实现全局的异常处理类:

@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();
	}

}

在方法的头上注解:
@ExceptionHandler(SignException.class)

即表示让Spring捕获到所有抛出的SignException异常,并交由这个被注解的方法处理。

注解:

@ResponseBody

即表示返回的对象,Spring会自动把该对象进行json转化,最后写入到Response中。

注解:

@ResponseStatus(HttpStatus.BAD_REQUEST)

表示设置状态码。如果应用级别的错误,此处其实永远返回200也是可以接受的,但是要在你自定义的异常串和异常码中做好交代。

本文的方案自定义了一个ExceptionResponse.java类,如下:

/**
 * 返回的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的实现:

/**
 * 签名异常
 * @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化处理”的相关代码和说明。


  • 5
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 5
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值