本文参考地址:http://blog.youkuaiyun.com/wuhenzhangxing/article/details/46459853
@ControllerAdvice是spring3.2提供的新注解,从名字上可以看出大体意思是控制器增强。让我们先看看 @ControllerAdvice的源码实现如下:
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
public @interface ControllerAdvice {
}
注解使用@Component注解,这样的话当我们使用<context:component-scan>扫描时也能扫描到,其 javadoc定义如下:
/**
* Indicates the annotated class assists a "Controller".
*
* <p>Serves as a specialization of {@link Component @Component}, allowing for
* implementation classes to be autodetected through classpath scanning.
*
* <p>It is typically used to define {@link ExceptionHandler @ExceptionHandler},
* {@link InitBinder @InitBinder}, and {@link ModelAttribute @ModelAttribute}
* methods that apply to all {@link RequestMapping @RequestMapping} methods.
*
* @author Rossen Stoyanchev
* @since 3.2
*/
由javadoc可以看出在@ControllerAdvice注解内部我们可以使用@ExceptionHandler、@InitBinder、 @ModelAttribute共3个注解,使用方式如下:
@ControllerAdvice
public class ControllerAdviceTest {
@ModelAttribute
public User newUser() {
System.out.println("============应用到所有@RequestMapping注解方法,在其执行之前把返回值放入Model");
return new User();
}
@InitBinder
public void initBinder(WebDataBinder binder) {
System.out.println("============应用到所有@RequestMapping注解方法,在其执行之前初始化数据绑定器");
}
@ExceptionHandler(UnauthenticatedException.class)
@ResponseStatus(HttpStatus.UNAUTHORIZED)
public String processUnauthenticatedException(NativeWebRequest request, UnauthenticatedException e) {
System.out.println("===========应用到所有@RequestMapping注解的方法,在其抛出UnauthenticatedException异常时执行");
return "viewName"; //返回一个逻辑视图名
}
}
以上代码可以看出@ModelAttribute、@initBinder和@ExceptionHandler对所有使用@RequestMapping的方法起作用,但@ModelAttribute和@initBinder在设置全局数据时比较有用,使用较少, @ExceptionHandler异常处理器,当注解的方法发生定义的异常时产生作用,使用较多。例如遇 到RuntimeException时做JSON的异常处理。
如果你的spring-mvc配置文件使用如下方式扫描bean
<context:component-scan base-package="com.jshi.es" use-default-filters="false">
<context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
</context:component-scan>
需要把@ControllerAdvice包含进来,否则不起作用:
<context:component-scan base-package="com.jshi.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>
项目中的场景应用:使用@ControllerAdvice注解做Json的异常处理,代码如下,FieldValidationError是自 定义的错误信息,RemoteResponse是自定义的返回数据结构,RespEnum是自定义的响应码
/**
* 通用的exception的handler的定义
* @author jshi
* @date 2016-6-5
*/
@ControllerAdvice
public class ExceptionAdvice {
/**
* 数据校验失败
* @param ex
* @return
*/
@ExceptionHandler(MethodArgumentNotValidException.class)
// @ResponseStatus(value = HttpStatus.BAD_REQUEST)
@ResponseBody
public RemoteResponse handleMethodArgumentNotValidException(MethodArgumentNotValidException ex) {
BindingResult bindingResult = ex.getBindingResult();
List<FieldValidationError> errorList=new LinkedList<FieldValidationError>();
for (FieldError fieldError : bindingResult.getFieldErrors()) {
errorList.add(new FieldValidationError( fieldError.getField(),fieldError.getDefaultMessage()));
}
return new RemoteResponse(RespEnum.COM_ARGUMENT_NOT_VALID, errorList);
}
/**
* 数据校验失败
* @param ex
* @return
*/
@ExceptionHandler(BindException.class)
@ResponseBody
public RemoteResponse handleBindException(BindException ex) {
BindingResult bindingResult = ex.getBindingResult();
List<FieldValidationError> errorList=new LinkedList<FieldValidationError>();
for (FieldError fieldError : bindingResult.getFieldErrors()) {
errorList.add(new FieldValidationError( fieldError.getField(),fieldError.getDefaultMessage()));
}
return new RemoteResponse(RespEnum.COM_ARGUMENT_NOT_VALID, errorList);
}
/**
* 400 - Bad Request
*/
@ResponseStatus(HttpStatus.BAD_REQUEST)
@ExceptionHandler(HttpMessageNotReadableException.class)
@ResponseBody
public RemoteResponse handleHttpMessageNotReadableException(HttpMessageNotReadableException e) {
Loggers.demoLogger.error("参数解析失败", e);
return new RemoteResponse(RespEnum.COM_ARGUMENT_NOT_READARABLE);
}
/**
* 400 - Bad Request
*/
// @ResponseStatus(HttpStatus.BAD_REQUEST)
@ExceptionHandler(JSONException.class)
@ResponseBody
public RemoteResponse handleJSONException(JSONException e) {
Loggers.demoLogger.error("json读取失败", e);
return new RemoteResponse(RespEnum.COM_ARGUMENT_NOT_READARABLE);
}
/**
* 405 - Method Not Allowed
*/
@ExceptionHandler(HttpRequestMethodNotSupportedException.class)
@ResponseBody
public RemoteResponse handleHttpRequestMethodNotSupportedException(HttpRequestMethodNotSupportedException e) {
Loggers.demoLogger.error("不支持当前请求方法", e);
return new RemoteResponse(RespEnum.COM_METHOD_NOT_SUPPORT);
}
/**
* 415 - Unsupported Media Type
*/
@ExceptionHandler(HttpMediaTypeNotSupportedException.class)
@ResponseBody
public RemoteResponse handleHttpMediaTypeNotSupportedException(Exception e) {
Loggers.demoLogger.error("不支持当前媒体类型", e);
return new RemoteResponse(RespEnum.COM_MEDIA_NOT_SUPPORT);
}
/**
* 数据库操作失败
*/
@ExceptionHandler(SQLException.class)
@ResponseBody
public RemoteResponse handleSQLException(SQLException e) {
Loggers.demoLogger.error("数据库异常", e);
return new RemoteResponse(RespEnum.COM_DB_OPERATION_FAILED);
}
/**
* 数据库操作失败
*/
@ExceptionHandler(MaxUploadSizeExceededException.class)
@ResponseBody
public RemoteResponse handleMaxUploadSizeExceededException(MaxUploadSizeExceededException e) {
Loggers.demoLogger.error("上传文件过大,上传失败,最大只能上传2M", e);
return new RemoteResponse(RespEnum.UPLOAD_FILE_EXCEEDED_MAXSIZE);
}
/**
* 500 - Internal Server Error
*/
@ExceptionHandler(Exception.class)
@ResponseBody
public RemoteResponse handleException(Exception e) {
Loggers.demoLogger.error("服务运行异常", e);
return new RemoteResponse(RespEnum.COM_INTERNAL_ERROR);
}
}
/**
* 定义在字段的数据校验不通过的情况,返回的错误信息的结构
* @author jshi
* @date 2016-6-5
*/
public class FieldValidationError {
private String field;
private String msg;
public FieldValidationError(String field,String msg)
{
this.field=field;
this.msg=msg;
}
public String getField() {
return field;
}
public void setField(String field) {
this.field = field;
}
public String getMsg() {
return msg;
}
public void setMsg(String msg) {
this.msg = msg;
}
}
/**
* rest接口,返回的json结构
* @author jshi
*/
public class RemoteResponse {
private int code;//code =0表示成功; code !=0 表示失败
private String message;
private Object data;
public RemoteResponse(RespEnum resp)
{
this.code=resp.getValue();
this.message= I18nUtil.getMessage(resp.getName());
}
public RemoteResponse(RespEnum resp,String...args)
{
this.code=resp.getValue();
this.message= I18nUtil.getMessage(resp.getName(),args);
}
public RemoteResponse(RespEnum resp,String msg)
{
this.code=resp.getValue();
this.message=msg;
}
public RemoteResponse(RespEnum resp,Object data)
{
this.code=resp.getValue();
this.message= I18nUtil.getMessage(resp.getName());
this.data=data;
}
public RemoteResponse(RespEnum resp,Object data,String...agrs)
{
this.code=resp.getValue();
this.message= I18nUtil.getMessage(resp.getName(),agrs);
this.data=data;
}
public RemoteResponse(RespInfo resp)
{
this.code=resp.getCode();
this.message=resp.getMessage();
this.data=resp.getModel();
}
protected void success()
{
code=0;
}
protected RemoteResponse success(String msg)
{
code=RespEnum.SUCCESS_RESULT.getValue();
this.message=msg;
return this;
}
protected RemoteResponse failure(String msg)
{
code= RespEnum.COM_ERROR.getValue();
this.message=msg;
return this;
}
public RemoteResponse failure(int code ,String msg)
{
this.code=code;
this.message=msg;
return this;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
public Object getData() {
return data;
}
public void setData(Object data) {
this.data = data;
}
public int getCode() {
return code;
}
public void setCode(int code) {
this.code = code;
}
}
1824

被折叠的 条评论
为什么被折叠?



