Spring3.2新注解@ControllerAdvice @InitBinder

@ControllerAdvice,是spring3.2提供的新注解,从名字上可以看出大体意思是控制器增强。

@ControllerAdvice是@Component注解的一个延伸注解,Spring会自动扫描并检测被@ControllerAdvice所标注的类。@ControllerAdvice需要和@ExceptionHandler、@InitBinder以及@ModelAttribute注解搭配使用,主要是用来处理控制器所抛出的异常信息。首先,我们需要定义一个被@ControllerAdvice所标注的类,在该类中,定义一个用于处理具体异常的方法,并使用@ExceptionHandler注解进行标记。此外,在有必要的时候,可以使用@InitBinder在类中进行全局的配置,还可以使用@ModelAttribute配置与视图相关的参数。使用@ControllerAdvice注解,就可以快速的创建统一的,自定义的异常处理类。

让我们先看看@ControllerAdvice的实现:

@Target(ElementType.TYPE)  
@Retention(RetentionPolicy.RUNTIME)  
@Documented  
@Component  
public @interface ControllerAdvice {  
  
}

使用 @ControllerAdvice,不用任何的配置,只要把这个类放在项目中,Spring能扫描到的地方。就可以实现全局异常的回调。

 没什么特别之处,该注解使用@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
*/
  • @ControllerAdvice是一个@Component,用于定义@ExceptionHandler,@InitBinder和@ModelAttribute方法,适用于所有使用@RequestMapping方法。

  • Spring4之前,@ControllerAdvice在同一调度的Servlet中协助所有控制器。Spring4已经改变:@ControllerAdvice支持配置控制器的子集,而默认的行为仍然可以利用。

  • 在Spring4中, @ControllerAdvice通过annotations(), basePackageClasses(), basePackages() 方法定制用于选择控制器子集。

即把@ControllerAdvice注解内部使用@ExceptionHandler、@InitBinder、@ModelAttribute注解的方法应用到所有的 @RequestMapping注解的方法。非常简单,不过只有当使用@ExceptionHandler最有用,另外两个用处不大。

 先看一个示例:

定义一个业务异常,这个异常交给@ControllerAdvice中的@ExceptionHandler处理。

package com.dxz.web.controller.excepion;

/**
 * 业务异常
 */
public class BusinessException extends Exception {

    private static final long serialVersionUID = 1L;

    // 业务类型
    private String bizType;
    // 业务代码
    private int bizCode;
    // 错误信息
    private String message;

    public BusinessException(String bizType, int bizCode, String message) {
        super(message);
        this.bizType = bizType;
        this.bizCode = bizCode;
        this.message = message;
    }

    public BusinessException(String message) {
        super(message);
        this.bizType = "";
        this.bizCode = -1;
        this.message = message;
    }

    public BusinessException(String bizType, String message) {
        super(message);
        this.bizType = bizType;
        this.bizCode = -1;
        this.message = message;
    }

    public BusinessException(int bizCode, String message) {
        super(message);
        this.bizType = "";
        this.bizCode = bizCode;
        this.message = message;
    }

    public String getBizType() {
        return bizType;
    }

    public void setBizType(String bizType) {
        this.bizType = bizType;
    }

    public int getBizCode() {
        return bizCode;
    }

    public void setBizCode(int bizCode) {
        this.bizCode = bizCode;
    }

    public String getMessage() {
        return message;
    }

    public void setMessage(String message) {
        this.message = message;
    }

}

用@ControllerAdvice为@RequestMapping注解的方法的提供@ExceptionHandler、@InitBinder、@ModelAttribute的功能。

package com.dxz.web.controller.excepion;

import java.beans.PropertyEditor;
import java.sql.SQLException;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;

import javax.servlet.http.HttpServletRequest;

import org.springframework.beans.propertyeditors.CustomDateEditor;
import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.InitBinder;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.servlet.ModelAndView;

import com.dxz.web.model.User;

/**
 * @ModelAttribute用于属性注入
 * @InitBinder用于参数的统一处理
 * @ExceptionHandler用于捕获异常统一处理
 */
@ControllerAdvice
public class GlobalExceptionHandler {

    private final static String EXPTION_MSG_KEY = "message";

    @ModelAttribute  
    public User newUser() {  
        System.out.println("============应用到所有@RequestMapping注解方法,在其执行之前把返回值放入Model");  
        return new User();  
    } 
    
    @InitBinder
    public void dataBinder(WebDataBinder binder) {
        DateFormat dateFormat = new SimpleDateFormat("yyyyMMdd");
        PropertyEditor propertyEditor = new CustomDateEditor(dateFormat, true); // 第二个参数表示是否允许为空
        binder.registerCustomEditor(Date.class, propertyEditor);
    }

    @ExceptionHandler(BusinessException.class)
    @ResponseBody
    public void handleBizExp(HttpServletRequest request, Exception ex) {
        System.out.println("Business exception handler  " + ex.getMessage());
        request.getSession(true).setAttribute(EXPTION_MSG_KEY, ex.getMessage());
    }

    @ExceptionHandler(SQLException.class)
    public ModelAndView handSql(Exception ex) {
        System.out.println("SQL Exception " + ex.getMessage());
        ModelAndView mv = new ModelAndView();
        mv.addObject("message", ex.getMessage());
        mv.setViewName("sql_error");
        return mv;
    }

}

测试的controller:

package com.dxz.web.controller;

import java.io.IOException;
import java.io.Writer;
import java.sql.SQLException;
import java.util.Date;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;

import com.dxz.web.controller.excepion.BusinessException;

@Controller
@RequestMapping("/user")
public class UserController {

    @RequestMapping("login")
    public String login() {
        return "login";
    }

    @RequestMapping("login2")
    public String login2() throws Exception {
        throw new SQLException("数据库出错");
    }

    @RequestMapping("login3")
    public String login3() throws Exception {
        throw new BusinessException("业务执行异常");
    }

    @RequestMapping("dataBinder/{date}")
    public void testDate(@PathVariable Date date, Writer writer) throws IOException {
        System.out.println("date:" + date);
        writer.write(String.valueOf(date.getTime()));
    }

    // 此方法抛出的异常不是由GlobalExceptionHandler处理
    // 而是在catch块处理
    @RequestMapping("login4")
    public String login4() {
        try {
            throw new BusinessException("业务执行异常");
        } catch (BusinessException e) {
            System.out.println("自己消化异常");
        }
        return "login";
    }

}

@ExceptionHandler演示,分别访问:

http://localhost:8080/SpringWebTraining/user/login4.do

http://localhost:8080/SpringWebTraining/user/login3.do

http://localhost:8080/SpringWebTraining/user/login2.do

测试结果:

 @InitBinder演示,分别访问:

http://localhost:8080/SpringWebTraining/user/dataBinder/20171023

 

1、@ModelAttribute注解的方法作用请参考SpringMVC Controller 介绍

2、@InitBinder注解的方法作用请参考SpringMVC Controller 介绍

@InitBinder注解用于标注初始化WebDataBinider的方法,该方法用于对Http请求传递的表单数据进行处理,如时间格式化、字符串处理等。下面是使用此注解的示例:

3、@ExceptionHandler,异常处理器,此注解的作用是当出现其定义的异常时进行处理的方法,其可以使用springmvc提供的数据绑定,比如注入HttpServletRequest等,还可以接受一个当前抛出的Throwable对象。可以参考javadoc或snowolf的Spring 注解学习手札(八)补遗——@ExceptionHandler

 

该注解非常简单,大多数时候其实只@ExceptionHandler比较有用,其他两个用到的场景非常少,这样可以把异常处理器应用到所有控制器,而不是@Controller注解的单个控制器。

posted on 2014-06-17 09:21  duanxz  阅读(5962)  评论(0编辑  收藏  举报