首頁>技術>

2.3 @ControllerAdvice

@ControllerAdvice註解一個特殊的Bean元件,顧名思義它負責所有控制器共享的功能,如異常處理(配合@ExceptionHandler)、資料繫結(配合@InitBinder)等。@ControllerAdvice透過屬性指定起效的控制器範圍:

透過註解限制:

@ControllerAdvice(annotations = RestController.class) public class someControllerAdvice{}

透過包名指定:

@ControllerAdvice("top.wisely.learningspringmvc.controller")public class someControllerAdvice{}

指定控制器:

@ControllerAdvice(assignableTypes = {PeopleController.class, DemoController.class})public class someControllerAdvice{}
2.3.1 異常處理

我們使用@ExceptionHandler組合@ControllerAdvice處理所有控制器的異常,當然@ExceptionHandler也可以註解在@Controller(包含@RestController)內,異常處理只對當前控制器有效。

我們先自定義個異常:

@Getter@Setter@AllArgsConstructor@NoArgsConstructorpublic class PersonNameNotFoundException extends RuntimeException{    private String name;}

我們定義異常處理類:

@ControllerAdvicepublic class ExceptionHandlerAdvice {    @ExceptionHandler(PersonNameNotFoundException.class) //    public ResponseEntity<String> customExceptionHandler(PersonNameNotFoundException exception){        return ResponseEntity.status(HttpStatus.NOT_FOUND)                .body(exception.getName() + "沒有找到!");    }    }

我們在控制器中,手動丟擲異常:

@GetMapping("/exceptions")public void exceptions(String name)  {    throw new PersonNameNotFoundException(name);}

異常被ExceptionHandlerAdvice的exceptionHandler方法處理。

2.3.2 初始化資料繫結

使用@InitBinder註解組合@ControllerAdvice實現初始化資料繫結。所謂出具繫結資料繫結,即在web請求在進入控制器方法處理之前,對web請求引數(不包含請求體@RequestBody,它使用下節的RequestBodyAdvice處理)進行預先的初始化處理,這個處理是透過WebDataBinder物件來做的。這些請求引數包括來自於@RequestParam、@PathVariable、ServletRequest、ServletReponse等,也就是這些引數都可以在@InitBinder註解的方法中進行先處理,該方法沒有返回值。如我們將引數1-wyf-35轉成一個Person物件。@InitBinder也可以用在@Controller內,只對使用的控制器有效。

我們先定義一個屬性編輯器將接收到的格式為id-name-age轉換成物件:

public class PersonEditor extends PropertyEditorSupport {    @Override    public void setAsText(String text) throws IllegalArgumentException {        String[] personStr = text.split("-"); // 將1-wyf-35分割成字串陣列        Long id = Long.valueOf(personStr[0]);        String name = personStr[1];        Integer age = Integer.valueOf(personStr[2]);        setValue(new Person(id, name, age)); //利用字串陣列建立Person物件    }}

我們使用@InitBinder來註冊這個屬性編輯器:

@ControllerAdvice@Slf4jpublic class InitBinderAdvice {    @InitBinder    public void registerPersonEditor(WebDataBinder binder, @RequestBody String person){        log.info("在InitBinder中為字串:" + person);        binder.registerCustomEditor(Person.class, new PersonEditor());    }}

未經WebDataBinder註冊PersonEditor轉換前,從請求引數裡拿到的只是字串person,此處的字串引數只是為了大家加深理解需要,我們開發時不需要這個引數。

我們用控制器來驗證:

@GetMapping("/propertyEditor")public Person propertyEditor(@RequestParam Person person){//支援的引數型別@RequetParam    log.info("經過InitBinder註冊的PropertyEditor轉換後為物件:" + person);    return person;    return person;}

控制檯顯示:

我們正確地將字串1-wyf-35轉成了Person物件。

2.3.3 自定義Validator

我們在“引數校驗”一節演示了預設的校驗方式,若有特殊的校驗需求,也可以透過實org.springframework.validation.Validator介面來完全控制校驗行為:

public class PersonValidator implements Validator {    @Override    public boolean supports(Class<?> clazz) {        return Person.class.isAssignableFrom(clazz); //只支援Person類    }    @Override    public void validate(Object target, Errors errors) {        Person person = (Person) target;        validateId(person, errors); //校驗id        validateName(person, errors); //校驗name        validateAge(person, errors); //校驗age    }    private void validateId(Person person, Errors errors){        ValidationUtils.rejectIfEmpty(errors,"id", "person.code", "id不能為空-自定義");    }    private void validateName(Person person, Errors errors){        int nameLength = person.getName().length();        if (nameLength < 3 || nameLength > 5)            errors.rejectValue("name", "person.name", "name在3到5個字元之間-自定義");    }    private void validateAge(Person person, Errors errors){        if (person.getAge() < 18)            errors.rejectValue("age", "person.age", "age不能低於18歲-自定義");    }}

在InitBinderAdvice類中的@InitBinder方法中註冊:

@ControllerAdvicepublic class InitBinderAdvice {    @InitBinder    public void setPersonValidator(WebDataBinder binder){        binder.setValidator(new PersonValidator());    }}

我們還是使用前面的校驗控制器方法請求:

12
  • BSA-TRITC(10mg/ml) TRITC-BSA 牛血清白蛋白改性標記羅丹明
  • 神經網路解析|CNN