0
点赞
收藏
分享

微信扫一扫

第五节 SpringBoot统一全局响应

独兜曲 2022-07-27 阅读 108


一、基础响应

        前后端分离一定会设计到数据传输。因此,每个项目必定都有一个基础的响应类。

        我就以我个人的经验编写这个类吧。定义基础:响应码code、响应信息message、传输的数据data、总记录数。

        定义两个基础的构造函数,再定义两个通过枚举的构造函数。

package com.zhoutianyu.learnspringboot.response;

import lombok.Data;

@Data
public class BaseResponse<T> {

private int code;

private String message;

private T data;
private Long total;

public BaseResponse(int code, String message) {
this.code = code;
this.message = message;
this.data = null;
}

public BaseResponse(int code, String message, T data) {
this.code = code;
this.message = message;
this.data = data;
}

public BaseResponse(StatusCodeEnum statusCodeEnum) {
this.code = statusCodeEnum.getCode();
this.message = statusCodeEnum.getMessage();
this.data = null;
}

public BaseResponse(StatusCodeEnum statusCodeEnum, T data) {
this.code = statusCodeEnum.getCode();
this.message = statusCodeEnum.getMessage();
this.data = data;
}
}

        响应码枚举类,封装一些常用的响应码与响应信息。

package com.zhoutianyu.learnspringboot.response;

import lombok.Getter;

@Getter
public enum StatusCodeEnum {

SUCCESS(200, "SUCCESS"), ERROR(500, "Business Exception"), INVALID(-1, "Illegal Argument");

private int code;

private String message;

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

        我们的目标就是让前端同事,收到传给他们的的code、message、data 数据。

        编写如下测试类。

package com.zhoutianyu.learnspringboot.test;

import com.zhoutianyu.learnspringboot.exception.FieldInvalidException;
import com.zhoutianyu.learnspringboot.response.BaseResponse;
import com.zhoutianyu.learnspringboot.response.StatusCodeEnum;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class SomethingController {

private static final Logger LOGGER = LoggerFactory.getLogger(SomethingController.class);

@GetMapping(value = "/response/test")
public BaseResponse buy(String param) {
LOGGER.info("paramType is {}", param);
return new BaseResponse<>(StatusCodeEnum.SUCCESS, param);
}
}

        重启项目并访问:​​http://localhost:8081/study/springboot/response/test?param=abc​​

        可以访问到上述方法。方法按照预期的响应。

第五节  SpringBoot统一全局响应_spring

二、统一响应模板

        刚才编写的方法,返回的就是一个BaseResponse对象。但是,如果某个方法返回的是一个字符串,那么这不符合前端接收的规则。为了减少与前端同事不必要的撕逼,我们后端应该对这些单个返回的数据进行处理。

        让数据从 "我是数据" 这种格式 ,修改为 { code : 200 , message : SUCCESS , data : 我是数据 }。

        比如现在有如下方法,在浏览器访问:

        ​​http://localhost:8081/study/springboot/response/test/string?param=l_am_data​​

@GetMapping(value = "/response/test/string")
public String buyTwo(String param) {
LOGGER.info("paramType is {}", param);
return param;
}

         

第五节  SpringBoot统一全局响应_ide_02

          如何处理呢。这里用到了AOP的思想。在返回给前端之前,用切面对返回值做一次数据处理。

          SpringBoot对切面的支持真的非常的友好。我们这个需求只需要实现一个叫做ResponseBodyAdvice的接口。Advice结尾就知道是一个AOP的通知。@ResponseBody注解的功能就是将返回数据映射成JSON格式。而我们就在他映射之前,修改掉返回数据。

          下面的代码的大致思路是:看看后台返回的数据,是不是符合标准响应(BaseResponse或者是ExceptionResponse)。如果是标准响应,那么就不做处理。如果不是上述的标准响应,那么就将返回数据处理成标准响应。

package com.zhoutianyu.learnspringboot.response;

import org.springframework.core.MethodParameter;
import org.springframework.http.MediaType;
import org.springframework.http.server.ServerHttpRequest;
import org.springframework.http.server.ServerHttpResponse;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;

@RestControllerAdvice
public class ResponseAdvice implements ResponseBodyAdvice {

@Override
public boolean supports(MethodParameter methodParameter, Class aClass) {
return true;
}

@Override
public Object beforeBodyWrite(Object data, MethodParameter methodParameter,
MediaType mediaType, Class aClass,
ServerHttpRequest serverHttpRequest, ServerHttpResponse serverHttpResponse) {

if (isResponseType(data)) {
return data;
}

return new BaseResponse<>(StatusCodeEnum.SUCCESS, data);
}

private boolean isResponseType(Object data) {
return data instanceof BaseResponse;
}
}

        还需要为系统添加一个配置,否则上述切面无法正常工作。原因不详:我搜集到的参考链接:

​​https://www.jianshu.com/p/ed55bbf676fb​​​

package com.zhoutianyu.learnspringboot.config;

import com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter;
import org.springframework.boot.autoconfigure.http.HttpMessageConverters;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

@Configuration
public class CustomWebConfigure implements WebMvcConfigurer {

@Bean
public HttpMessageConverters customConverters() {
return new HttpMessageConverters(new FastJsonHttpMessageConverter());
}
}


<!-- fast json-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.54</version>
</dependency>

         还会有乱码的问题。在application.yml中加入下面的参数即可。

spring:
http:
encoding:
charset: UTF-8
force: true
enabled: true
messages:
encoding: UTF-8
banner:
charset: UTF-8

        最后的测试:​​http://localhost:8081/study/springboot/response/test/string?param=​​

第五节  SpringBoot统一全局响应_ide_03

第五节  SpringBoot统一全局响应_spring_04

三、源码下载

        本章节项目源码:​​点我下载源代码​​

    ​

2020年1月4日适配分页

package com.zhoutianyu.learnspringboot.response;

import com.zhoutianyu.learnspringboot.interceptor.PageHelperThreadLocal;
import org.springframework.core.MethodParameter;
import org.springframework.http.MediaType;
import org.springframework.http.server.ServerHttpRequest;
import org.springframework.http.server.ServerHttpResponse;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;

@RestControllerAdvice
public class ResponseAdvice implements ResponseBodyAdvice {

@Override
public boolean supports(MethodParameter methodParameter, Class aClass) {
return true;
}

@Override
public Object beforeBodyWrite(Object data, MethodParameter methodParameter,
MediaType mediaType, Class aClass,
ServerHttpRequest serverHttpRequest, ServerHttpResponse serverHttpResponse) {

if (isResponseType(data)) {
return data;
}
//构造适配数据
BaseResponse response = new BaseResponse<>(StatusCodeEnum.SUCCESS, data);
//适配数量
if (null != PageInfo.getRowBounds().getTotal()) {
response.setTotal(PageInfo.getRowBounds().getTotal());
}
return response;
}

private boolean isResponseType(Object data) {
return data instanceof BaseResponse || data instanceof ExceptionResponse;
}
}

 

举报

相关推荐

0 条评论