【Spring Boot】【前后端分离】后端接口返回结果统一封装

最近在尝试使用前后端分离的模式写一个简单的个人博客,遇到接口数据返回结构的问题,在网上查了一圈,发现了一个很好用的方法,在复现的过程中也遇到了不少坑点,特意在这记录下。

创建 SpringBoot 项目

导入下面依赖

<dependencies>
    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
        <optional>true</optional>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
        <scope>test</scope>
    </dependency>
</dependencies>

封装返回结果

新建 result 包,和结果封装相关的类都放在这个包里,创建 ReturnCode 枚举类,因为是演示所以就写了两个返回值,实际使用过程中应该不止这两个类型

@Getter
public enum ReturnCode {
    
    
    RC200(200, "success"),
    RC400(400, "fail");
    private final int code;
    private final String msg;
    ReturnCode(int code, String msg){
    
    
        this.code = code;
        this.msg = msg;
    }
}

创建 ResultData 类,作为统一返回类型的封装

@Data
public class ResultData<T> {
    
    
    private int code;
    private String msg;
    private T data;
    public static <T> ResultData<T> success(T data) {
    
    
        ResultData<T> resultData = new ResultData<>();
        resultData.setCode(ReturnCode.RC200.getCode());
        resultData.setMsg(ReturnCode.RC200.getMsg());
        resultData.setData(data);
        return resultData;
    }
    public static <T> ResultData<T> fail(int code, String msg) {
    
    
        ResultData<T> resultData = new ResultData<>();
        resultData.setCode(code);
        resultData.setMsg(msg);
        return resultData;
    }
}

实现返回对象的自动封装

每次使用的时候都要 return Result.success() 太麻烦了,可以使用 SpringBoot 实现返回对象的自动封装,创建 ResponseAdvice ,实现 ResponseBodyAdvice<T> 接口

@RestControllerAdvice
public class ResponseAdvice implements ResponseBodyAdvice<Object> {
    
    
    @Autowired
    private ObjectMapper objectMapper;
    @Override
    public boolean supports(MethodParameter methodParameter, Class<? extends HttpMessageConverter<?>> aClass) {
    
    
        return true;
    }
    @SneakyThrows
    @Override
    public Object beforeBodyWrite(Object o, MethodParameter methodParameter, MediaType mediaType,
                                  Class<? extends HttpMessageConverter<?>> aClass,
                                  ServerHttpRequest serverHttpRequest, ServerHttpResponse serverHttpResponse) {
    
    
        if (o instanceof String) {
    
    
            return objectMapper.writeValueAsString(ResultData.success(o));
        }
        if (o instanceof ResultData) {
    
    
            return o;
        }
        return ResultData.success(o);
    }
}

处理异常

这个时候如果发生异常还没办法处理,我们可以由全局异常处理器统一捕获,使用全局异常处理器最大的便利就是写代码时不再需要手写 try...catch ,新建一个 error 包,下包下创建全局异常处理器 RestExceptionHandler

@Slf4j
@RestControllerAdvice
public class RestExceptionHandler {
    
    
    @ExceptionHandler(Exception.class)
    @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
    public ResultData<String> exception(Exception e) {
    
    
        log.error("全局异常信息 ex={}", e.getMessage(), e);
        return ResultData.fail(ReturnCode.RC400.getCode(), e.getMessage());
    }
}

测试

接下来写一个测试控制器,写两个方法测试是否正确工作

@RestController
public class TestController {
    
    
    @GetMapping("/right")
    public String hello() {
    
    
        return "Hello, SpringBoot!";
    }
    @GetMapping("/error")
    public int error() {
    
    
        return 9 / 0;
    }
}

使用 postman 接口测试工具,分别测试两个接口,可以得到预期的结果。

猜你喜欢

转载自blog.csdn.net/wji15/article/details/126650045