【代码规范】统一参数校验、结果返回

发布时间:2023年12月21日

统一参数校验:

? ? ? ? 在编写Controller层的代码时,时常会有这种情况出现

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

    
    @Resource
    private UserService userService;


    @PostMapping("register")
    public String register(@RequestBody UserDto userDto){
        if (StringUtils.isEmpty(userDto.getName())) {
            return "用户名不能为空";
        }

        if(StringUtils.isEmpty(userDto.getPhone())){
            return "手机号不能为空";
        }

        if(userDto.getPhone().length() != 11){
            return "手机号格式不正确";
        }

        if(StringUtils.isEmpty(userDto.getEmail())){
            return "邮箱不能为空";
        }

        userService.register();
        
        return "注册成功";
    }


    @PutMapping("update")
    public String updateInfo(@RequestBody UserDto userDto){
        if (StringUtils.isEmpty(userDto.getName())) {
            return "用户名不能为空";
        }

        if(StringUtils.isEmpty(userDto.getPhone())){
            return "手机号不能为空";
        }

        if(userDto.getPhone().length() != 11){
            return "手机号格式不正确";
        }


        if(StringUtils.isEmpty(userDto.getEmail())){
            return "邮箱不能为空";
        }

        userService.updateInfo();
        
        return "修改成功";
    }
}

? ? ? ?在编写业务层组件实现真正的业务处理逻辑前,需要编写一大堆的参数校验逻辑。controller层可能有多个接口都需要进行参数校验,这样使得开发工作量加大、代码也不简洁。

解决方案:?

? ? ? ? (1)pom文件中引入spring-boot-starter-validation依赖

<dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-validation</artifactId>
        </dependency>

? ? ? ? (2)给实体类字段加上@NotNull注解

@AllArgsConstructor
@NoArgsConstructor
@Data
public class UserDto {

    @NotNull(message = "用户名不能为空")
    private String name;

    @NotNull(message = "手机号不能为空")
    @Pattern(regexp = "^[1][3,4,5,6,7,8,9][0-9]{9}$", message = "手机号格式不正确")
    private String phone;


    @NotNull(message = "邮箱不能为空")
    private String email;

    private Integer id;

    private Integer role;
    
}

? ? ? ? @NotNull字段不能为null,但可以是空(如"")。
? ? ? ? @Pattern^表示字符串的开头,1表示手机号码的开头数字是1,[3-9]表示第二位数字是3到9之间的数字,\d表示匹配一个数字,{9}表示匹配9个数字,$表示字符串的结尾。不符合正则表达式的手机号都会被视为格式不正确。

? ? ? ? (3)在controller层给数据传输对象(xxxDto)加上@Validated注解

@Resource
    private UserService userService;


@PostMapping("register")
    public String register(@RequestBody @Validated UserDto userDto,
                           BindingResult result){
        //如果校验不通过,则error对象不为空
        //返回错误信息即可
        for (ObjectError error : result.getAllErrors()) {
            return error.getDefaultMessage();
        }

        userService.add();

        return "注册成功";
    }

? ? ? ? 当客户端调用此接口时,Validator会自动校验数据传输对象UserDto的参数,并将错误信息封装到BingdingResult对象中。getAllErrors()方法会返回一个元素是ObjectError的List集合,如果List集合不为空,说明有参数没有通过校验,返回错误信息即可。

? ? ? ? 测试

? ? ? ? 1、email为空

? ? ? ? 我们可以发现,返回的错误信息其实就是我们在使用@NotNull注解时配置的message属性。

? ? ? ? 2、手机号格式错误

? ? ? ? 这里手机号是以数字2开头,而正则表达式规定了手机号只能以数字1开头。

统一结果返回:

? ? ? ? controller层返回请求处理结果时,会出现如下场景

@GetMapping("getString")
    public String getString(){
        
        return "hello world";
    }

    @GetMapping("getInfo")
    public UserDto getUserInfo(){
        UserDto response = new UserDto(3, "zhangsan", "15798403197", "hutu@163.com", 0);
        return response;
    }

? ? ? ? 可以看到有些接口返回String字符串,有些接口返回数据传输对象(xxxDto),接口返回给前端的结果不统一,导致前端不能高效的处理响应数据。

解决方案

????????标准的响应对象中应该包含响应状态码(code)处理结果描述(message)响应数据(data)等信息。

? ? ? ? (1)定义一个ProcessResult枚举类

public enum ProcessResult {

    SUCCESS("3333","操作成功"),

    FAIL("9999","操作失败"),

    SYSTEM_ERROR("6666","服务正忙,请稍后访问");


    private String code;

    private String message;


    ProcessResult(String code, String message) {
        this.code = code;
        this.message = message;
    }

    public String getCode() {
        return code;
    }

    public String getMessage() {
        return message;
    }
}

? ? ? ? (2)定义响应类BaseResponseVO

@Data
public class BaseResponseVO<T> {

    /**
     * 响应状态码
     * 3333:操作成功
     * 6666:系统错误
     * 9999:操作失败
     */
    private String code;


    /**
     * 处理结果描述
     */
    private String message;


    /**
     * 响应数据
     */
    private T data;


    /**
     * 成功返回
     * @param data:接口需要响应给前端的数据
     * @param <T>
     * @return
     */
    public static <T> BaseResponseVO<T> success(T data){
        BaseResponseVO<T> resp = success();
        resp.setData(data);
        return resp;
    }

    /**
     * 成功返回,但没有返回数据
     * @param <T>
     * @return
     */
    public static <T> BaseResponseVO<T> success(){
        BaseResponseVO resp = new BaseResponseVO();

        resp.setCode(ProcessResult.SUCCESS.getCode());
        resp.setMessage(ProcessResult.SUCCESS.getMessage());

        return resp;
    }

    /**
     * 失败返回
     * @param code:失败状态码
     * @param message:处理结果描述
     * @param <T>
     * @return
     */
    public static <T> BaseResponseVO<T> fail(String code,String message){
        BaseResponseVO resp = new BaseResponseVO();

        resp.setCode(code);
        resp.setMessage(message);

        return resp;
    }
}

? ? ? ? 1、枚举类ProcessResult包含了响应状态码、处理结果描述等信息,我们如果需要多个不同的响应码及响应信息,可直接在枚举类中扩展。

? ? ? ? 2、我们不能确定返回数据的类型,因此使用泛型来声明返回数据。

? ? ? ?3、 响应类BaseResponseVO提供了多个静态方法,我们可以根据处理结果调用相应的方法进行返回(成功且有返回数据:success(T data);成功但无返回数据:success();失败:fail(String code,String message))。

? ? ? ? (3)修改controller层代码

@GetMapping("getString")
    public BaseResponseVO<String> getString(){
        return BaseResponseVO.success("hello world");
    }

    @GetMapping("getInfo")
    public BaseResponseVO<UserDto> getUserInfo(){
        UserDto response = new UserDto(3, "zhangsan", "15798403197", "hutu@163.com", 0);
        return BaseResponseVO.success(response);
    }

? ? ? ? 测试

? ? ? ? (1)getString接口

? ? ? ? (2)getInfo接口

文章来源:https://blog.csdn.net/Annancqxxx/article/details/135139116
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。