Springboot优雅实现对接口返回统一封装

前端在调用后端接口时往往不同的接口返回的数据是不一样的,但是通常我们会与前端约定一个固定的返回格式,通过固定的格式告诉他们什么时候接口是返回成功,什么时候返回失败,返回成功后他们如何拿到接口返回的数据去渲染前端页面。
在不对接口统一包装时,你可能会这样的返回如一个查询接口

    @PostMapping(value = "/list")
    public List<Map<String, Object>> list() {
        List<Map<String, Object>> mapList = new ArrayList<>();
        HashMap<String, Object> map = new HashMap<>();
        map.put("dazhi", "大智");
        map.put("zhangsan", "张三");
        map.put("laoliu", "老六");
        mapList.add(map);
        return mapList;
    }

接口返回

又或者这样的如一个删除接口

    @PostMapping(value = "/delete")
    public String delete() {
        return "删除完毕";
    }

接口返回

像这些情况如果你和前端开发人员联调接口她们就会很懵逼,由于我们没有给他一个统一的格式,前端人员不知道如何处理返回值。所以我们需要定义一个统一的标准返回格式的。
一个标准的返回格式至少包含3部分:
code 状态码:统一定义各种返回结果的状态码。
msg 描述:接口调用的结果描述。
data 数据:返回的数据。

{
    "code": "S000",
    "msg": "操作成功!",
    "data": "数据更新成功!"
}

我们使用@RestControllerAdvice注解并且实现ResponseBodyAdvice接口来实现统一返回格式的封装,关于使用@RestControllerAdvice实现全局异常处理可以看我以前的文章《Springboot全局异常处理从配置文件中读取自定义异常信息》,接下来展示一下大概的代码

定义一个标准的统一返回实体

package com.yx.limit.base.vo;

import com.yx.limit.base.enums.ResponseEnum;
import lombok.Data;

/**
 * 统一响应实体
 */
@Data
public class ResponseVo<T> {

    /**
     * 响应编码
     */
    private String code;
    /**
     * 消息内容
     */
    private String msg;
    /**
     * 响应数据
     */
    private T data;

    private ResponseVo() {
    }

    private enum Singleton{
        INSTANCE;
        private ResponseVo responseVo;
        Singleton(){
            if (responseVo == null){
                responseVo = new ResponseVo();
            }
        }
        public ResponseVo getInstance(){
            return responseVo;
        }
    }

    public static <T> ResponseVo<T> success() {
        return success(null);
    }

    public static <T> ResponseVo<T> success(T data) {
        ResponseVo<T> responseVo = Singleton.INSTANCE.getInstance();
        responseVo.setCode(ResponseEnum.SUCCESS.getResultCode());
        responseVo.setMsg(ResponseEnum.SUCCESS.getResultMsg());
        responseVo.setData(data);
        return responseVo;
    }

    public static <T> ResponseVo<T> error(String code, String msg) {
        ResponseVo<T> responseVo = Singleton.INSTANCE.getInstance();
        responseVo.setCode(code);
        responseVo.setMsg(msg);
        responseVo.setData(null);
        return responseVo;
    }

    public static <T> ResponseVo<T> error(String msg) {
        ResponseVo<T> responseVo = Singleton.INSTANCE.getInstance();
        responseVo.setCode(ResponseEnum.ERROR.getResultCode());
        responseVo.setMsg(ResponseEnum.ERROR.getResultMsg());
        responseVo.setData(null);
        return responseVo;
    }
}


定义一个状态码枚举

package com.yx.limit.base.enums;

import lombok.AllArgsConstructor;
import lombok.Getter;

/**
 * 响应编码枚举
 */
@AllArgsConstructor
public enum ResponseEnum {

    /**
     * 数据操作错误定义
     */
    SUCCESS("S000","操作成功!"),
    ERROR("E000","操作失败!"),
    SIGNATURE_NOT_MATCH("E001","请求的数字签名不匹配!"),
    BODY_NOT_MATCH("E002","请求的数据格式不符!"),
    INTERNAL_SERVER_ERROR("E003", "服务器内部错误!");

    /**
     * 错误码
     */
    @Getter
    private String resultCode;
    /**
     * 错误描述
     */
    @Getter
    private String resultMsg;
}


定义一个忽略自动包装返回功能的注解

package com.yx.limit.base.annotations;

import java.lang.annotation.*;

/**
 * 忽略自动返回构造注解
 */
@Documented
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface IgnoreAutoResponse {
}


统一响应结果通知类 

package com.yx.light.element.mybatis.advice;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.yx.limit.base.annotations.IgnoreAutoResponse;
import com.yx.limit.base.vo.ResponseVo;
import lombok.SneakyThrows;
import org.springframework.core.MethodParameter;
import org.springframework.http.MediaType;
import org.springframework.http.converter.HttpMessageConverter;
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<Object> {

    private final ObjectMapper objectMapper;

    public ResponseAdvice(ObjectMapper objectMapper) {
        this.objectMapper = objectMapper;
    }

    @Override
    public boolean supports(MethodParameter methodParameter, Class<? extends HttpMessageConverter<?>> aClass) {
        return !methodParameter.hasMethodAnnotation(IgnoreAutoResponse.class);
    }

    @SneakyThrows
    @Override
    public Object beforeBodyWrite(Object o, MethodParameter methodParameter, MediaType mediaType, Class<? extends HttpMessageConverter<?>> aClass, ServerHttpRequest serverHttpRequest, ServerHttpResponse serverHttpResponse) {
        // 判断当前请求是否是 Swagger 相关的请求
        if (serverHttpRequest.getURI().getPath().startsWith("/swagger") || serverHttpRequest.getURI().getPath().startsWith("/v2/api-docs")) {
            return o;
        }
        //SpringBoot的Controller中的方法返回值是String时会直接返回
        if (o instanceof String) {
            return objectMapper.writeValueAsString(ResponseVo.success(o));
        }
        //全局异常处理的结果直接返回即可
        if (o instanceof ResponseVo) {
            return o;
        }
        return ResponseVo.success(o);
    }
}

 这个时候我们再来请求原来的两个方法查看返回结果
list方法:

delete方法:

我们发现delete的方法返回的json格式没有格式化,我们只需要稍加改造一下delete方法就能正常返回格式化的数据

    @PostMapping(value = "/delete", produces = "application/json; charset=UTF-8")
    public String delete() {
        return "删除完毕";
    }

 

对于一些不想返回固定包装的方法可以在方法上加上@IgnoreAutoResponse注解即可返回原始的格式

    @PostMapping(value = "/original")
    @IgnoreAutoResponse
    public String original() {
        return "原始字符串";
    }

 

  • 8
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Spring Boot是一个用于构建独立的、生产级别的Spring应用程序的框架,它提供了丰富的功能和特性,方便开发人员快速搭建和开发项目。 在Spring Boot中使用AOP(面向切面编程)可以实现将一些公共的功能逻辑代码从业务逻辑代码中解耦出来,提高代码的复用性和可维护性。通过AOP可以在方法的前后注入一些通用的逻辑,例如日志记录、异常处理、权限校验等。 其中,使用AOP进行结果的统一封装是很常见的需求。通过AOP可以在方法执行后对返回的结果进行封装统一处理返回结果的格式,并可以对结果进行一些统一的处理操作,例如添加统一返回码、返回信息、返回时间等。 在Spring Boot中使用AOP进行结果的统一封装可以按照以下步骤进行: 1. 创建一个切面(Aspect),通过在切面类上加上@Aspect注解标识该类是一个切面类。 2. 在切面类中定义一个切点(Pointcut),通过定义一个方法并添加@Pointcut注解来指定切入点。 3. 在切面类中定义一个通知(Advice),通过@Before、@After、@Around等注解来指定通知类型,并在通知方法中编写需要执行的逻辑。 4. 在通知方法中获取方法的返回结果,并进行相应的封装和处理。 5. 在Spring Boot的配置类中添加@EnableAspectJAutoProxy注解来启用AOP。 使用以上步骤可以实现对方法返回结果的统一封装,使得返回结果具有统一的格式和处理逻辑。这样可以提高代码的重用性和可维护性,并且可以在一处对结果进行集中处理,减少了代码的重复性,提高了开发效率。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值