JSR-303提供了一些注解,将其放到属性上,可以限制这些属性的值。
参考:Spring MVC学习笔记——JSR303介绍及最佳实践
校验放在DTO层上,不要和数据库交互的model层混用
关于model,VO等的区别,参考:Spring MVC学习笔记——POJO和DispatcherServlet
如何赋值,参考:优雅的使用BeanUtils对List集合的操作
DTO和DO的转换,可以使用BeanUtils
,参考:设计之道-controller层的设计
也可以使用ModelMapper,参考:Spring Boot DTO示例:实体到DTO的转换
如果使用的springboot版本大于2.3.x,需要额外引用依赖
1 2 3 4 5 6
| <dependency> <groupId>org.hibernate</groupId> <artifactId>hibernate-validator</artifactId> <version>6.0.1.Final</version> </dependency>
|
参考:使用SpringBoot进行优雅的数据验证
定义dto层或者vo层,添加 @NotEmpty注解 和 @Size注解,并设置分组校验,即在Post请求或者Put请求的时候进行校验
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
| import com.example.demo.core.valid.Post; import com.example.demo.core.valid.Put; import com.example.demo.model.User; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; import org.springframework.beans.BeanUtils;
import javax.validation.constraints.NotEmpty; import javax.validation.constraints.Size;
@Data @AllArgsConstructor @NoArgsConstructor public class UserDTO {
@NotEmpty(groups = Post.class, message = "注册时username字段不能为空") @Size(groups = {Post.class, Put.class}, min = 3, max = 120) private String username;
private String password;
public static User convert(UserDTO dto) { User user = new User(); BeanUtils.copyProperties(dto, user); return user; }
public static UserDTO convertDTO(User user) { UserDTO dto = new UserDTO(); BeanUtils.copyProperties(user, dto); return dto; }
}
|
定义Post分组接口
1 2 3 4 5
| package com.example.demo.core.valid;
public interface Post { }
|
定义Put分组接口
1 2 3 4 5
| package com.example.demo.core.valid;
public interface Put { }
|
设置全局异常处理
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| @ResponseStatus(HttpStatus.BAD_REQUEST) @ExceptionHandler(MethodArgumentNotValidException.class) public ControllerResponseT methodArgumentNotValidException(MethodArgumentNotValidException e) { String message = ResultCode.METHOD_ARGUMENT_NOT_VALID.getMessage(); log.error("参数验证失败 => {}", e.getMessage()); BindingResult bindingResult = e.getBindingResult(); List<ObjectError> allErrors = bindingResult.getAllErrors(); return new ControllerResponseT<>(ResultCode.METHOD_ARGUMENT_NOT_VALID.getCode(), message, allErrors); }
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR) @ExceptionHandler({SQLException.class, DataAccessException.class}) public ControllerResponseT databaseException(final Throwable e) { String message = ResultCode.DATABASE_ERROR.getMessage(); log.error("数据库错误 => {}", e.getMessage()); return ControllerResponseT.ofFail(ResultCode.DATABASE_ERROR.getCode(), message, e.getMessage()); }
|
controller层
1 2 3 4 5 6 7 8
| @ApiImplicitParams({ @ApiImplicitParam(paramType = "body", dataType = "UserDTO", name = "userDTO", value = "用户", required = true) }) @RequestMapping(path = "/user", method = RequestMethod.POST) public ControllerResponseT create(@Validated({Post.class}) @RequestBody UserDTO userDTO) { int result = userService.save(UserDTO.convert(userDTO)); return ControllerResponseT.ofSuccess("success"); }
|
如果参数验证错误,则接口返回结果如下