@ControllerAdvice 统一管理异常/错误

@ControllerAdvice 统一管理异常/错误

一、注意事项

1. 如果校验注解不指定 message 属性 ,会返回默认消息, 这些消息是配置在
ValidationMessages_zh_CN.properties 文件中的, 这个文件是框架提供的(如图)
2. 写完验证注解后, 不要忘了在控制器开启校验, 将 @Validated 写在要校验的 Entity前, 否则不会生效
3. @NotNull 注解可以接受任意类型, @NotBlank(String) 和@ NotEmpty(数组、集合) 都有要求, 具体看源码即可

二、统一管理异常/错误的好处

1. 如果每一个 Controller 都分别写对数据校验异常的处理代码,非常繁琐,扩展性不高
2. 我们可以使用@ControllerAdvice 统一管理异常/错误

三、代码实现

1. 普通方法

实体类BrandEntity.java

package com.xjz.xjzliving.commodity.entity;

import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;

import java.io.Serializable;
import java.util.Date;
import lombok.Data;
import org.hibernate.validator.constraints.URL;

import javax.validation.constraints.Min;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Pattern;

/**
 * 家居品牌
 *
 * @author xjz
 * @email xjz@gmail.com
 * @date 2024-02-20 19:03:08
 */
@Data
@TableName("commodity_brand")
public class BrandEntity implements Serializable {
	private static final long serialVersionUID = 1L;

	/**
	 * id
	 */
	@TableId
	private Long id;
	/**
	 * 品牌名
		 * 代码解读
		 * 1. @NotBlank 表示 name 必须包括一个非空字符
		 * 2. message = "品牌名不能为空" 是我指定的一个校验消息
		 * 3. 如果不指定 message = " 品牌名不能为空" ,会返回默认消息
		 * 	  javax.validation.constraints.NotBlank.message
		 *  4. 这个消息是配置在 ValidationMessages_zh_CN.properties 文件中的
		 *  5. 下面其它的校验注解规则一样,也很好理解
	 */
	@NotBlank(message = "品牌名不能为空")
	private String name;
	/**
	 * logo
	 * 1. @NotBlank 和 @URL 同时修饰 logo 是两个校验注解都要满足
	 */
	@NotBlank(message = "logo不能为空")
	@URL(message = "logo不是一个合法的URL")
	private String logo;
	/**
	 * 说明
	 */
	private String description;
	/**
	 * 显示
		 * 代码解读
		 * 1.这里使用了@NotNull 注解,该注解可以接受任意类型
		 * 2.如果使用@NotBlank 注解,会报错,因为@NotBlank 不支持校验 Integer
		 * 3.在开发时,要注解注解可以接受哪些类型,直接看注解源码即可
		 * 4.如果是数字类型,不支持@Pattern, 后面再想办法
	 */
	@NotNull(message = "显示状态不能为空")
	private Integer isshow;
	/**
	 * 检索首字母
		 * 代码解读
		 * 1. @Pattern 是使用自己写的正则表达式来校验, 非常有用
	 */
	@NotBlank(message = "检索字母不能为空")
	@Pattern(regexp = "^[a-zA-Z]$",message = "检索字母必须是a-z或者A-Z")
	private String firstLetter;
	/**
	 * 排序
		 * 代码解读
		 * 1. @Min(value = 0) 表示 sort 这个字段最小值为 0
	 */
	@NotNull(message = "排序值不能为空")
	@Min(value = 0,message = "排序值要求大于等于0")
	private Integer sort;

}

控制层BrandController

/**
 * @author xjz_2002
 */
@RestController
@RequestMapping("commodity/brand")
public class BrandController {
    @Autowired
    private BrandService brandService;
    
	/**
     * 保存
     * 代码解读
     * 1. @Validated 标注在 这里表示启用对 BrandEntity 字段的校验
     * 2. 注意: 如果不写 @Validated 即使在 BrandEntity 写了校验注解, 也不会生效
     * 3. BindingResult result: springboot 会将校验的结果 放入到 result
     * 4. 程序员可以通过 BindingResult result 取出自己关系的错误信息
     */
    @RequestMapping("/save")
    public R save(@Validated @RequestBody BrandEntity brand,
                  BindingResult result) {

        if (result.hasErrors()) {
            Map<String, String> map = new HashMap<>();
            //1. 获取校验的错误结果
            result.getFieldErrors().forEach((item) -> {
                //2. FieldError 获取到错误提示
                String message = item.getDefaultMessage();
                //3. 获取错误的属性的名字
                String field = item.getField();
                //4. 放入map
                map.put(field, message);
            });
            return R.error(400, "品牌表单数据不合法").put("data", map);

        } else { //没有校验错误,则正常入库
            brandService.save(brand);
            return R.ok();
        }
    }

}

2. 统一管理@ControllerAdvice

统一管理数据异常工具类

package com.xjz.xjzliving.commodity.exception;

import com.xjz.common.utils.R;
import lombok.extern.slf4j.Slf4j;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;

import java.util.HashMap;
import java.util.Map;

/**
 * @author xjz_2002
 * @version 1.0
 */

/**
 * 代码解读
 * 1. @ResponseBody 都以 json 格式返回数据
 * 2. @ControllerAdvice
 * (basePackages = "com.xjz.xjzliving.commodity.controller")统一接管
 * com.xjz.xjzliving.commodity.controller 包下 抛出的异常
 */
@Slf4j
@ResponseBody
@ControllerAdvice(basePackages = "com.xjz.xjzliving.commodity.controller")
public class XjzlivingExceptionControllerAdvice {

    /**
     * 代码解读
     * 1. 数据校验错误属于 MethodArgumentNotValidException
     * 2. 可 以 通 过 log.error(" 数 据 校 验 出 现 问 题 {} , 异 常 类 型 :
     * {}",e.getMessage(),e.getClass()); 得到
     * 3. 异常匹配的规则是先精确匹配,然后匹配范围更大的异常类型
     * 4. 写清楚精确匹配的异常后,我们可以更加准确的定制提示异常信息
     */
    @ExceptionHandler(value = MethodArgumentNotValidException.class)
    public R handleVaildException(MethodArgumentNotValidException e) {

        log.error("数据校验出现问题{},异常类型:{}",e.getMessage(),e.getClass());
        BindingResult bindingResult = e.getBindingResult();
        Map<String , String> errorMap = new HashMap<>();
        bindingResult.getFieldErrors().forEach(fieldError -> {
            errorMap.put(fieldError.getField(), fieldError.getDefaultMessage());
        });
        return R.error(400,"方法参数异常").put("data",errorMap);
    }

    /**
     * 这里再写一个处理 Throwable 类型的异常的方法, * 没有精确匹配到的异常, 走这里
     */
    @ExceptionHandler(value = Throwable.class)
    public R handleException(Throwable throwable){
        return R.error(40000,"系统未知错误");
    }
}

3. PostMan测试结果

数据校验异常
在这里插入图片描述![

其他异常
在这里插入图片描述

  • 15
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
注册的Controller层代码应该包含以下几个方面: 1.引入相关的包和类 ```java import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RequestParam; import com.xxxx.entity.User; import com.xxxx.service.UserService; ``` 2.声明Controller类 ```java @Controller @RequestMapping("/user") public class UserController { // 注入UserService对象 @Autowired private UserService userService; //处理注册请求 @RequestMapping(value = "/register", method = RequestMethod.POST) public String register(@RequestParam("username") String username, @RequestParam("password") String password, Model model) { // 创建User对象,封装注册信息 User user = new User(); user.setUsername(username); user.setPassword(password); // 调用UserService的register方法,执行注册操作 boolean result = userService.register(user); if (result) { // 注册成功,跳转到登录页面 return "redirect:/user/login"; } else { // 注册失败,返回注册页面,并提示错误信息 model.addAttribute("errorMsg", "注册失败,请重新注册!"); return "register"; } } } ``` 3.在Controller中注入UserService对象 在上述代码中,我们使用了@Autowired注解将UserService对象注入到UserController类中,这样就可以在Controller中调用UserService中的方法来处理业务逻辑。 ```java @Autowired private UserService userService; ``` 4.编写注册方法 在UserController中,我们需要编写一个register方法来处理用户的注册请求。该方法使用@RequestMapping注解来指定注册请求的URL和请求方法类型。在方法中,我们首先从请求参数中获取到用户名和密码,并使用User对象来封装注册信息。然后,调用UserService的register方法来执行注册操作。如果注册成功,我们就重定向到登录页面;如果注册失败,我们就返回注册页面,并在页面中提示错误信息。 ```java @RequestMapping(value = "/register", method = RequestMethod.POST) public String register(@RequestParam("username") String username, @RequestParam("password") String password, Model model) { // 创建User对象,封装注册信息 User user = new User(); user.setUsername(username); user.setPassword(password); // 调用UserService的register方法,执行注册操作 boolean result = userService.register(user); if (result) { // 注册成功,跳转到登录页面 return "redirect:/user/login"; } else { // 注册失败,返回注册页面,并提示错误信息 model.addAttribute("errorMsg", "注册失败,请重新注册!"); return "register"; } } ``` 以上就是一个简单的注册Controller层代码,具体实现可能因为业务需求而不同。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

xjz_2002

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值