👨💻个人主页: 才疏学浅的木子 🙇♂️ 本人也在学习阶段如若发现问题,请告知非常感谢 🙇♂️ 📒 本文来自专栏: 常用工具类以及常见问题处理方法 🌈 每日一语:越努力越幸运 🌈
写多个if来判断条件
实体类
@Data
public class User {
private String username;
private String password;
private String email;
}
@PostMapping("/loginUser")
public void loginUser(@RequestBody User user) throws Exception {
if(StringUtils.isBlank(user.getUsername())){
throw new Exception("用户名不能为空");
}
if (StringUtils.isBlank(user.getPassword())){
throw new Exception("密码不能为空");
}
if (StringUtils.isBlank(user.getEmail())){
throw new Exception("邮箱不能为空");
}
System.out.println(user);
}
StringUtils的依赖包
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.12.0</version>
</dependency>
实体类
@Data
public class User {
@NotBlank(message = "用户名不能为空")
private String username;
@NotBlank(message = "密码不能为空")
private String password;
@Email(message = "邮箱格式错误")
private String email;
}
@PostMapping("/loginUser")
public void loginUser(@Validated @RequestBody User user) throws Exception {
System.out.println(user);
}
引入依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>
踩坑过后的建议
字符串建议用@NotBlank不要用@NotNull
@NotNull:用在基本类型上 不能为null但是可以为空字符串
@NotEmpty:用在集合类上 不能为空并且长度必须大于0
@NotBlank:只能作用在String上 不能为null并且调用trim()后长度必须大于0
由上面可以看出抛出了MethodArgumentNotValidException异常
而MethodArgumentNotValidException继承了BindException
@RestControllerAdvice
public class ControllerAdvice {
@ExceptionHandler(BindException.class)
public R MethodArgumentNotValidExceptionHandler(BindException e){
//获取到错误信息
String objectError = e.getBindingResult().getAllErrors().get(0).getDefaultMessage();
return new R().setFlag(false).setMessage(objectError);
}
}
@PostMapping("/getUser")
public User getUser(){
return new User();
}
但是要进行和前端的交互,为了和前端妹子打好关系所以我们通常需要对数据进行包装一下,增加一下状态码,状态信息
@Data
@Accessors(chain = true)
public class R {
private boolean flag;
private String message;
private Object data;
}
@GetMapping("/getUser")
public R getUser(){
return new R().setFlag(true).setMessage("获取用户成功").setData(new User());
}
这里面可以封装状态码信息等我只是简单封装
每次返回都要new R()并且设置flag很麻烦所以提供一个静态方法
@Data
@Accessors(chain = true)
public class R {
private boolean flag;
private String message;
private Object data;
public static R ok(){
return new R().setFlag(true);
}
public static R error(){
return new R().setFlag(false);
}
}
@GetMapping("/getUser")
public R getUser(){
return R.ok().setMessage("获取用户成功").setData(new User());
}
AOP拦截所有Controller
@RestControllerAdvice(basePackages = {"com.example.quickspringboot.controller"})
public class ControllerResponseAdvice implements ResponseBodyAdvice<Object> {
//判断这个类型是不是已经是 R 是了就不用封装,如果不是就会调用 beforeBodyWrite
@Override
public boolean supports(MethodParameter returnType, Class<? extends HttpMessageConverter<?>> converterType) {
return !returnType.getParameterType().isAssignableFrom(R.class);
}
@SneakyThrows
@Override
public Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType, Class<? extends HttpMessageConverter<?>> selectedConverterType, ServerHttpRequest request, ServerHttpResponse response) {
// String类型不能直接包装
if (returnType.getGenericParameterType().equals(String.class)) {
ObjectMapper objectMapper = new ObjectMapper();
try {
// 将数据包装在ResultVo里后转换为json串进行返回
return objectMapper.writeValueAsString(new R().setData(body));
} catch (JsonProcessingException e) {
throw new Exception("ControllerResponseAdvice String 封装失败");
}
}
// 否则直接包装成ResultVo返回
return new R().setData(body);
}
}
@GetMapping("/getUser")
public User getUser(){
return new User();
}
但是这个只是对数据,这种可以设置成功的案列因为flag和message如果成功可以设置为默认
假如有需求返回结果不要R类型需要String类型或者其他类型,那么第一种封装就可以很快直接返回就行而使用AOP不能,所以我们可以自定义一个注解
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface NotControllerResponseAdvice {
}
@Override
public boolean supports(MethodParameter returnType, Class<? extends HttpMessageConverter<?>> converterType) {
return !returnType.getParameterType().isAssignableFrom(R.class)
&& returnType.hasMethodAnnotation(NotControllerResponseAdvice.class);
}
说明注解修饰的对象范围,枚举规定了范围
// 用于描述类、接口等
TYPE,
//用于描述域
FIELD,
//用于描述方法
METHOD,
//用于描述参数
PARAMETER,
//用于描述构造器
CONSTRUCTOR,
//用于描述局部变量
LOCAL_VARIABLE,
//注解变量
ANNOTATION_TYPE,
//用于描述包
PACKAGE,
TYPE_PARAMETER,
TYPE_USE
定义该注解被保留时间长短
//在源文件有效
SOURCE,
//在class文件中有效
CLASS,
//运行时
RUNTIME
@Inherited 元注解是一个标记注解,@Inherited阐述了某个被标注的类型是被继承的。如果一个使用了@Inherited修饰的annotation类型被用于一个class,则这个annotation将被用于该class的子类。
@Documented用于描述其它类型的annotation应该被作为被标注的程序成员的公共API,因此可以被例如javadoc此类的工具文档化。Documented是一个标记注解,没有成员
首先继承异常类
@Data
public class MyException extends RuntimeException{
private int code;
private String msg;
}
@RestControllerAdvice
public class ControllerAdvice {
@ExceptionHandler(BindException.class)
public R MethodArgumentNotValidExceptionHandler(BindException e){
//获取到错误信息
String objectError = e.getBindingResult().getAllErrors().get(0).getDefaultMessage();
return new R().setFlag(false).setMessage(objectError);
}
@ExceptionHandler(MyException.class)
public void test(Exception e){
System.out.println(e.getMessage());
}
}