Java封装统一结果集

问题背景

一个用户的操作,比如登录,就可能会有很多种情况,用户层面的:账号错误、密码错误;服务器层面的:数据库错误等等情况。但是我们正常的是直接把一个对象解析成json对象返回给前端,那我们如何去判断是哪一种情况,并给用户一个反馈信息呢?前端就犯难了。这时候,我们就想出了一个方法,既然都是对象,那我能不能嵌套对象,一个对象包含状态码,提示信息,和返回值呢,这时候统一结果集就孕育而生了。

解决思路

首先我们定义一下我们的对象格式,格式如下所示:

  • code:自定义请求状态码,前端判断的依据

  • msg:用户提示信息,前端就可以直接弹出

  • data:后台真正返回的数据,比如说token、查询列表等。

image-20230521005753518

结果集V1

很简单的一个思路,即我们要返回前端的一般都是一个json对象,那么我们只需要把我们真正需要返回前端的对象,嵌套进另一个对象即可。那么可以写出这样的代码。

package cn.stopyc.constant;

/**
 * @program: return-project
 * @description: 返回值包装
 * @author: stop.yc
 * @create: 2022-04-01 12:24
 **/
public class Result<T> {
    /**
     * 编号
     */
    private Integer code;
    /**
     * 信息
     */
    private String msg;

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

    public Result() {
        super();
    }

    public Result(Integer code, String msg, T data) {
        this.code = code;
        this.msg = msg;
        this.data = data;
    }

    public Result(Integer code, String msg) {
        this.code = code;
        this.msg = msg;
    }

    public Integer getCode() {
        return code;
    }

    public void setCode(Integer code) {
        this.code = code;
    }

    public String getMsg() {
        return msg;
    }

    public void setMsg(String msg) {
        this.msg = msg;
    }

    public T getData() {
        return data;
    }

    public void setData(T data) {
        this.data = data;
    }

    @Override
    public String toString() {
        return "Result{" +
                "code=" + code +
                ", msg='" + msg + '\'' +
                ", data=" + data +
                '}';
    }
}

通过泛型的定义,我们可以直接把需要返回前端的对象,返进data里面即可。但是,实践中发现,状态码、响应信息等都是直接硬编码在代码里面,没办法形成统一等风格。那么,我们就可以维护一个枚举类,统一编码,然后前后端也更容易协调。

package cn.stopyc.constant;

/**
* @Description: 结果集枚举
* @Param:
* @return:
* @Author: stop.yc
* @Date: 2022/4/28
*/
public enum ResultEnum {
    //自定义
    //通用
    UNKNOWN_ERROR(-1,"未知错误"),
    SUCCESS(200,"成功"),
    SERVER_INTERNAL_ERROR(500,"服务器内部错误"),
    RESOURCE_NOT_FOUND(404,"资源未找到"),
    PARAMETER_NOT_VALID(400,"参数不合法"),
    DATABASE_ERROR(600,"数据库操作错误"),
    //用户模块 5002XX
    PASSWORD_FAILED(500200,"密码错误"),
    REPEAT_NAME(500210,"用户名重复"),
    FIND_USER_FAILED(500220,"用户名不存在"),
    CHECK_CODE_ERROR(500230,"验证码错误"),
    //任务模块 6002XX
    NO_TASK(600200,"当前没有任务"),
    //.......

    ;
    /**
     * 编号
     */
    private Integer code;
    /**
     * 信息
     */
    private String msg;

    ResultEnum(Integer code, String msg) {
        this.code = code;
        this.msg = msg;
    }

    public Integer getCode() {
        return code;
    }

    public String getMsg() {
        return msg;
    }
}

经过这样的改进,我们最后controller返回信息的时候,只需要这样书写即可。

return new Result<>(ResultEnum.SUCCESS.getCode(), ResultEnum.SUCCESS.getMsg(), data);

结果集V2

看到第一版的代码,似乎已经很不错了,但是可以看到,最后返回的代码中,出现了两次类似的东西,ResultEnum,而且调用的枚举还是同一个,所以,是不是可以考虑把这两部分抽象一下,然后Result对象内部自己组装code和msg呢?所以,这里我们对Result对象实例化的时候的传参,使用了一个StatusCode接口。代码如下。

//接口
public interface StatusCode {

    int getCode();

    String getMsg();
}
//结果集类
public class Result {
    /**编号*/
    private int code;
    /**信息*/
    private String msg;

    /**数据*/
    private Object data;

    /**
     * 无参构造方法(保险)
     */
    public Result() {
        super();
    }

    /**
     * 手动指定状态码
     * @param code :状态码
     * @param msg :信息
     * @param data :数据
     */
    public Result(int code, String msg, Object data) {
        this.code = code;
        this.msg = msg;
        this.data = data;
    }

    /**
     * 没有返回值,
     * @param statusCode :状态
     */
    public Result(StatusCode statusCode) {
        this.code = statusCode.getCode();
        this.msg = statusCode.getMsg();
    }

    /**
     * 有返回值
     * @param statusCode :状态
     * @param data :数据
     */
    public Result(StatusCode statusCode,Object data) {
        this.code = statusCode.getCode();
        this.msg = statusCode.getMsg();
        this.data = data;
    }

    public Result(Object data) {
        this.code = ResultEnum.SUCCESS.getCode();
        this.msg = ResultEnum.SUCCESS.getMsg();
        this.data = data;
    }

    @Override
    public String toString() {
        return "Result{" +
                "code=" + code +
                ", msg='" + msg + '\'' +
                ", data=" + data +
                '}';
    }
}
//状态枚举
public enum ResultEnum implements StatusCode{
    //自定义
    //通用
    UNKNOWN_ERROR(-1,"未知错误"),
    SUCCESS(200,"成功"),
    UNAUTHORIZED(401,"请先登录"),
    FORBIDDEN(403,"权限不足"),
    RESOURCE_NOT_FOUND(404,"资源未找到"),
    PARAMETER_NOT_VALID(400,"参数不合法"),
    SERVER_INTERNAL_ERROR(500,"服务器正在忙碌中,请稍后试试吧"),

    ;
    /**
     * 编号
     */
    private int code;
    /**
     * 信息
     */
    private String msg;

    ResultEnum(Integer code, String msg) {
        this.code = code;
        this.msg = msg;
    }

    public int getCode() {
        return code;
    }

    public String getMsg() {
        return msg;
    }
}
//启动类
public class App {
    public static void main(String[] args) {
        String data = "12345";
        //直接输入数据,默认封装请求成功状态码
        System.out.println(new Result(12345));

        //指定状态码,加数据
        System.out.println(new Result(ResultEnum.CODE_ADD_ERR,data));

        //指定状态码,没有数据
        System.out.println(new Result(ResultEnum.CODE_SELECT_ERR));

        int i = 0;

        System.out.println(new Result((i == 1 ? ResultEnum.CODE_ADD_OK : ResultEnum.CODE_ADD_ERR)));
    }
}

结果集V3

v2的已经挺完美了,但是,在实际的代码书写中,还是会发现一些问题,就是我们频繁的写一个成功的code,也就是200code。那这个能不能变成一个方法进行调用呢?代码如下。

@Data
@NoArgsConstructor
@AllArgsConstructor
@Accessors(chain = true)
public class Result {

    /**编号*/
    private Integer code;

    /**信息*/
    private String msg;

    /**数据*/
    private Object data;

    public static Result ok() {
        return new Result()
                .setCode(ResultEnum.REQUEST_SUCCESS.getCode())
                .setMsg(ResultEnum.REQUEST_SUCCESS.getMsg());
    }

    public static Result ok(Object data) {
        return new Result()
                .setCode(ResultEnum.REQUEST_SUCCESS.getCode())
                .setMsg(ResultEnum.REQUEST_SUCCESS.getMsg())
                .setData(data);
    }

    public static  Result fail(StatusCode statusCode) {
        return new Result()
                .setCode(statusCode.getCode())
                .setMsg(statusCode.getMsg());
    }

    public static  Result fail(StatusCode statusCode,Object data) {
        return new Result()
                .setCode(statusCode.getCode())
                .setMsg(statusCode.getMsg())
                .setData(data);
    }
}

StatusCode接口代码:

public interface StatusCode {

    int getCode();

    String getMsg();
}

使用实例代码:

return Result.ok();
return Result.fail(PHONE_CODE_ERR);
return Result.ok(data);
return Result.fail(PHONE_CODE_ERR,data);

总结

一些代码,总是会遵循一个先完成后优化的规律。随着业务的发展和代码的实践过程中,总是会发现一些问题,那么,我们就需要好好思考,去进行相应的改进,去把他优化、升级,使其更加的优雅,美观。

参考

如何优雅地写controller层代码

redis教程配套代码

暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇