SpringBoot项目自定义统一响应体设计_附上完整测试代码

目录

1. 介绍

2. 示例

​3. 自定义响应类和响应码枚举类设计

3.1 响应类Result

3.2 响应码枚举类

4. 数据库以及Java代码

4.1 数据库示例

4.1.1 数据库列展示

4.1.2 数据库建表DDL

4.2 实体类PO

4.3 Controller

4.4 Service

4.5 ServiceImpl

4.6 Mapper

5. 调接口测试

5.1 保存订单

5.2 根据订单id查询一条订单数据

6. 更新预告--->全局异常处理

6.1 更新全局异常处理

​6.2 国际化

6.3 自动根据请求头注入用户会话信息

6.3.1 Controller

6.3.2 ServiceImpl

6.3.3 控制台


1. 介绍

自定义响应类是指在开发中,根据业务需求自定义的用于封装接口响应数据的类。通常情况下,一个自定义响应类包含了接口返回的相关信息,如状态码、消息、数据等。

自定义响应类的设计灵活多样,可以根据具体的业务需求进行定义。一般来说,一个自定义响应类应该包括以下属性或方法:

  1. 状态码(Code):表示接口调用的状态,如成功、失败、错误等。
  2. 消息(Message):对接口调用结果的描述信息,可以是成功或失败的提示信息。
  3. 数据(Data):接口返回的具体数据。

作用

通过自定义响应类,可以将接口响应数据按照统一的格式进行封装和返回,方便前端或其他调用方解析和处理。同时,自定义响应类也可以提供更多的灵活性,可以根据具体的业务场景进行定制,满足不同的需求。

2. 示例

我们这里以 根据订单id查询一条订单数据为例:

如下所示:返回了一个响应体:包括响应码, 具体消息, 以及具体的响应数据:


3. 自定义响应类和响应码枚举类设计

3.1 响应类Result

注意类设计泛型, 这样无论什么类型的返回数据(String、Boolean、Integer、List)都可以。

响应类Result通常是依赖于响应码枚举类ResultCodeEnum, 而非独立存在

package com.rehse.common;

import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;

/**
 * @author: Rehse
 * @description: Result
 * @date: 2025/8/14
 */
@Data
@Builder
@AllArgsConstructor
// <T> 为泛型, 可以代表任意数据类型
public class Result<T> {
    private String code;
    private String message;
    private T data;

    public Result(){
    }
    public Result(ResultCodeEnum codeEnum) {
        this.code = codeEnum.getCode();
        this.message = codeEnum.getMessage();
    }

    public Result(ResultCodeEnum codeEnum, T data) {
        this.code = codeEnum.getCode();
        this.message = codeEnum.getMessage();
        this.data = data;
    }

    public static <T> Result<T> success() {
        Result<T> response = new Result<>();
        response.setCode(ResultCodeEnum.SUCCESS.getCode());
        response.setMessage("成功");
        return response;
    }

    // 用得最多的就是这个
    public static <T> Result<T> success(T data) {
        Result<T> response = new Result<>();
        response.setCode(ResultCodeEnum.SUCCESS.getCode());
        response.setMessage("成功");
        response.setData(data);
        return response;
    }

    public static <T> Result<T> fail(String msg) {
        Result<T> response = new Result<>();
        response.setCode(ResultCodeEnum.FAIL.getCode());
        response.setMessage(msg);
        return response;
    }

    public static <T> Result<T> fail(String code, String message) {
        Result<T> response = new Result<>();
        response.setCode(code);
        response.setMessage(message);
        return response;
    }


}

看似那么多, 其实返回成功时候, 主要只是用 传参为数据的这个方法

 // 用得最多的就是这个
    public static <T> Result<T> success(T data) {
        Result<T> response = new Result<>();
        response.setCode(ResultCodeEnum.SUCCESS.getCode());
        response.setMessage("成功");
        response.setData(data);
        return response;
    }

3.2 响应码枚举类

package com.rehse.common;
import java.util.Objects;
import java.util.stream.Stream;
/**
 * @author: Rehse
 * @description: ResultCodeEnum
 * @date: 2025/8/13
 */
public enum ResultCodeEnum {
    SUCCESS("10000", "成功"),
    FAIL("100001", "失败"),
    BAD_REQUEST("400", "请求错误"),
    UNAUTHORIZED("401", "未授权"),
    METHOD_NOT_ALLOWED("405", "请求方法不允许");


    private String code;            // 状态码
    private String message;          // 消息

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

    public String getCode() {
        return this.code;
    }

    public String getMessage() {
        return this.message;
    }

    public static ResultCodeEnum valueof(String code) {
        return Stream.of(values())
                .filter(option -> Objects.equals(option.code, code))
                .findFirst()
                .orElseThrow(() -> new IllegalArgumentException("No matching enum value for [" + code + "]"));
    }

}

4. 数据库以及Java代码

4.1 数据库示例

4.1.1 数据库列展示

4.1.2 数据库建表DDL

-- ----------------------------
-- Table structure for t_order
-- ----------------------------
DROP TABLE IF EXISTS `t_order`;
CREATE TABLE `t_order`  (
  `id` int NOT NULL AUTO_INCREMENT,
  `order_id` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,
  `user_id` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,
  `merchant_id` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,
  `status` int NULL DEFAULT NULL,
  `create_time` datetime NULL DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP,
  `update_time` datetime NULL DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = Dynamic;

SET FOREIGN_KEY_CHECKS = 1;

4.2 实体类PO

package com.rehse.po;

import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.Date;

@Data
@AllArgsConstructor
@NoArgsConstructor
@TableName("t_order")
public class Order {

    /**
     * 主键
     */
    @TableId(value = "id")
    private Long id;

    /**
     * 订单id
     */
    private String orderId;

    /**
     * 用户id
     */
    private String userId;

    /**
     * 商家id
     */
    private String merchantId;

    /**
     * 订单状态
     */
    private Integer status;

    /**
     * 创建时间
     */
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    private Date createTime;

    /**
     * 更新时间
     */
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    private Date updateTime;


}

4.3 Controller

package com.rehse.controller;

import com.rehse.common.Result;
import com.rehse.po.Order;
import com.rehse.service.OrderService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

@RestController
@RequestMapping("/rehse/order")
public class OrderController {

    @Autowired
    private OrderService orderService;

    @PostMapping("/saveOrder")
    public Result<Boolean> saveOrder(@RequestBody Order order){
        return Result.success(orderService.saveOrder(order));
    }

    @PostMapping("/selectByOrderId")
    public Result<Order> selectByOrderId(@RequestParam("orderId") String orderId){
        Order order = orderService.selectByOrderId(orderId);
        return Result.success(order);
    }
}

4.4 Service

package com.rehse.service;

import com.baomidou.mybatisplus.extension.service.IService;
import com.rehse.po.Order;

public interface OrderService extends IService<Order> {
    Order selectByOrderId(String orderId);

    Boolean saveOrder(Order order);
}

4.5 ServiceImpl

package com.rehse.service.impl;

import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.rehse.mapper.OrderMapper;
import com.rehse.po.Order;
import com.rehse.service.OrderService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.Date;
import java.util.UUID;

@Slf4j
@Service
public class OrderServiceImpl extends ServiceImpl<OrderMapper, Order> implements OrderService {
    @Autowired
    private OrderMapper orderMapper;


    @Override
    public Boolean saveOrder(Order order) {
        Order orderNew = new Order();
        BeanUtils.copyProperties(order, orderNew);
        orderNew.setOrderId(String.valueOf(UUID.randomUUID()).replace("-", ""));
        orderNew.setCreateTime(new Date());
        orderNew.setUpdateTime(new Date());
        orderNew.setStatus(0);
        return save(orderNew);
    }

    @Override
    public Order selectByOrderId(String orderId) {
        return orderMapper.selectByOrderId(orderId);
    }


}

4.6 Mapper

package com.rehse.mapper;

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.rehse.po.Order;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select;


@Mapper
public interface OrderMapper extends BaseMapper<Order> {

    @Select("select * from t_order where order_id = #{orderId}")
    Order selectByOrderId(@Param("orderId") String orderId);
}

5. 调接口测试

这里用了ApiPost, 比postman好用, 不需要登录:

5.1 保存订单

5.2 根据订单id查询一条订单数据

6. 更新预告--->全局异常处理

感谢宝宝们看完这篇博客, 感觉有帮助的话一键三连么么哒!

25届Java小登已入职, 入职后也要继续提升哇,猪咪将会不定期分享学习笔记!

重铸Java荣光, 我辈义不容辞!

本期博客只是个简单demo, 其中的响应消息为固定死的, 非常不通用。

后续还会进行进一步优化, 请关注跟进吧么么哒!

接下来将会按照顺序依次1.更新全局异常处理->2.国际化->3.自动根据请求头注入用户会话信息

强烈建议这几篇博客一起看, 因为我是一天写完的, 

为了保持CSDN活跃度, 我打算一天一发, 下一篇将会于2025年8月18日00:01:00自动更新:

6.1 更新全局异常处理

比如当调用接口:根据订单id查询一条订单, 如果没有传入订单id,那么肯定会抛出异常的:

示例:


6.2 国际化

根据请求头传入的语言为中文还是英文, 返回不同的响应消息。

示例:

设置请求头中的语言为英文, 当传入订单id为空时, 返回异常为相应的英文。

6.3 自动根据请求头注入用户会话信息

在某个用户在平台上面进行操作的时候, 会存在很多用户会话信息:包括用户id, 用户姓名, 用户邮箱等。

后续将会更新通过一个注解@UserSession, 一步注入用户会话信息

示例:

6.3.1 Controller

在接口里面添加了注解@UserSession

  @PostMapping("/saveOrder")
    public Result<Boolean> saveOrder(@UserSession UserSessionInfo userSessionInfo, @RequestBody Order order){
        return Result.success(orderService.saveOrder(order));
    }

6.3.2 ServiceImpl

@Override
    public Boolean saveOrder(Order order) {
        UserSessionInfo userSessionInfo = SessionThreadLocalUtil.getCurrentUserInfo();
        System.out.println("当前的UserSessionInfo为 : " + userSessionInfo);
        Order orderNew = new Order();
        BeanUtils.copyProperties(order, orderNew);
        orderNew.setUserId(String.valueOf(userSessionInfo.getUserId()));
        orderNew.setOrderId(String.valueOf(UUID.randomUUID()).replace("-", ""));
        orderNew.setCreateTime(new Date());
        orderNew.setUpdateTime(new Date());
        orderNew.setStatus(0);
        return save(orderNew);
    }

6.3.3 控制台

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值