分布式医疗挂号系统(四) | 统一返回结果、异常处理、日志处理到通用模块

本系列文章介绍从0开始搭建一个基于分布式的医疗挂号系统。本次四篇文章完成了医院设置微服务模块的后端接口,为了方便开发,对接口的返回结果全局异常全局日志进行了统一处理。 同时,为了方便进行访问测试,还整合了Swagger2工具,这些通用的模块中,除了全局日志被放在医院设置微服务模块的配置资源中,其余都统一被抽取在common模块中。具体实现可参考下面文章:

  • 医院设置微服务 | 模块搭建
  • 医院设置微服务 | 接口开发
  • 通用模块 | 整合Swagger2
  • 通用模块 | 统一返回结果、统一异常处理、统一日志处理

作者:Hudie
微信公众号/CSDN博客:编程一只蝶
项目已开源至gitee:https://gitee.com/guo-qianliang/yygh_parent
项目已开源至github:https://github.com/Guoqianliang/yygh_parent


一、统一返回结果

在实际开发中,是一个后端团队一起开发,每个人做不同的模块,开发不同的接口,最终进行调用进而显示。因此可以把所有返回结果做一个统一的约定。让所有的接口都返回相同的数据格式,这样利于前端的显示与解析

统一返回结果类的运用

上图这一操作需要通过统一返回结果类统一返回结果状态信息类 来实现。

1.统一返回结果类

/**
 * 全局统一返回结果类
 */
@Data
@ApiModel(value = "全局统一返回结果")
public class Result {
    @ApiModelProperty(value = "返回码")
    private Integer code;

    @ApiModelProperty(value = "返回消息")
    private String message;

    @ApiModelProperty(value = "返回数据")
    private T data;

    public Result() {
    }

    protected static  Result build(T data) {
        Result result = new Result();
        if (data != null) {
            result.setData(data);
        }
        return result;
    }

    public static  Result build(T body, ResultCodeEnum resultCodeEnum) {
        Result result = build(body);
        result.setCode(resultCodeEnum.getCode());
        result.setMessage(resultCodeEnum.getMessage());
        return result;
    }

    public static  Result build(Integer code, String message) {
        Result result = build(null);
        result.setCode(code);
        result.setMessage(message);
        return result;
    }

    public static  Result ok() {
        return Result.ok(null);
    }

    /**
     * 操作成功
     * @param data
     * @param 
     * @return
     */
    public static  Result ok(T data) {
        Result result = build(data);
        return build(data, ResultCodeEnum.SUCCESS);
    }

    public static  Result fail() {
        return Result.fail(null);
    }

    /**
     * 操作失败
     * @param data
     * @param 
     * @return
     */
    public static  Result fail(T data) {
        Result result = build(data);
        return build(data, ResultCodeEnum.FAIL);
    }

    public Result message(String msg) {
        this.setMessage(msg);
        return this;
    }

    public Result code(Integer code) {
        this.setCode(code);
        return this;
    }

    public boolean isOk() {
        if (this.getCode().intValue() == ResultCodeEnum.SUCCESS.getCode().intValue()) {
            return true;
        }
        return false;
    }
}

2.统一返回状态信息类

/**
 * 统一返回结果状态信息类
 */
@Getter
public enum ResultCodeEnum {

    SUCCESS(200, "成功"),
    FAIL(201, "失败"),
    PARAM_ERROR(202, "参数不正确"),
    SERVICE_ERROR(203, "服务异常"),
    DATA_ERROR(204, "数据异常"),
    DATA_UPDATE_ERROR(205, "数据版本异常"),

    LOGIN_AUTH(208, "未登陆"),
    PERMISSION(209, "没有权限"),

    CODE_ERROR(210, "验证码错误"),
    //    LOGIN_MOBLE_ERROR(211, "账号不正确"),
    LOGIN_DISABLED_ERROR(212, "改用户已被禁用"),
    REGISTER_MOBLE_ERROR(213, "手机号已被使用"),
    LOGIN_AURH(214, "需要登录"),
    LOGIN_ACL(215, "没有权限"),

    URL_ENCODE_ERROR(216, "URL编码失败"),
    ILLEGAL_CALLBACK_REQUEST_ERROR(217, "非法回调请求"),
    FETCH_ACCESSTOKEN_FAILD(218, "获取accessToken失败"),
    FETCH_USERINFO_ERROR(219, "获取用户信息失败"),
    //LOGIN_ERROR( 23005, "登录失败"),

    PAY_RUN(220, "支付中"),
    CANCEL_ORDER_FAIL(225, "取消订单失败"),
    CANCEL_ORDER_NO(225, "不能取消预约"),

    HOSCODE_EXIST(230, "医院编号已经存在"),
    NUMBER_NO(240, "可预约号不足"),
    TIME_NO(250, "当前时间不可以预约"),

    SIGN_ERROR(300, "签名错误"),
    HOSPITAL_OPEN(310, "医院未开通,暂时不能访问"),
    HOSPITAL_LOCK(320, "医院被锁定,暂时不能访问"),
    ;

    private Integer code;
    private String message;

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

二、统一异常处理

spring boot 默认情况下会将异常映射到 /error 进行异常处理,这样的提示十分不友好,下面使用自定义异常处理,可以提供更友好的展示。

1.自定义异常类

/**
 * 自定义全局异常类
 *
 */
@Data
@ApiModel(value = "自定义全局异常类")
public class YyghException extends RuntimeException {

    @ApiModelProperty(value = "异常状态码")
    private Integer code;

    /**
     * 通过状态码和错误消息创建异常对象
     * @param message
     * @param code
     */
    public YyghException(String message, Integer code) {
        super(message);
        this.code = code;
    }

    /**
     * 接收枚举类型对象
     * @param resultCodeEnum
     */
    public YyghException(ResultCodeEnum resultCodeEnum) {
        super(resultCodeEnum.getMessage());
        this.code = resultCodeEnum.getCode();
    }

    @Override
    public String toString() {
        return "YyghException{" +
                "code=" + code +
                ", message=" + this.getMessage() +
                '}';
    }
}

2.全局异常处理

下面代码中两个方法的@ExceptionHandler注解,分别传入系统异常Exception类自定义异常YyghException类,当出现系统异常时会运行系统的Exception方法,当出现自定义异常时会运行YyghException方法。

/**
 * @Description: 统一异常处理类
 * @author Guoqianliang
 * @date 20:56 - 2021/4/7
 */
@ControllerAdvice
public class GlobalExceptionHandler {

    /**
     * 全局异常处理
     * @param e
     * @return
     */
    @ExceptionHandler(Exception.class)
    @ResponseBody
    public Result error(Exception e) {
        e.printStackTrace();
        return Result.fail();
    }

    /**
     * 自定义异常处理
     * @param e
     * @return
     */
    @ExceptionHandler(YyghException.class)
    @ResponseBody
    public Result error(YyghException e) {
        e.printStackTrace();
        return Result.fail();
    }
}

使用自定义异常时,不会自动调用,需要手动抛出异常,举例如下:


手动抛出异常

三、统一日志处理

日志记录器(Logger)的行为是分等级的,常用的4个级别如下:

  • DEBUG < INFO < WARN < ERROR

级别越高,打印的信息越多。默认情况下,springboot从控制台打印出来的日志级别只有INFO及以上级别,通过:logging.level.root=debug可以修改日志级别。

下面给出一个日志模块,通过此模板可以将日志持久化到本地文件:



    
    
    
    

    logback
    
    

    
    
    
    
    
    
    
    


    
    
        
        
        
            INFO
        
        
            ${CONSOLE_LOG_PATTERN}
            
            UTF-8
        
    


    

    
    
        
        ${log.path}/log_info.log
        
        
            %d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n
            UTF-8
        
        
        
            
            ${log.path}/info/log-info-%d{yyyy-MM-dd}.%i.log
            
                100MB
            
            
            15
        
        
        
            INFO
            ACCEPT
            DENY
        
    

    
    
        
        ${log.path}/log_warn.log
        
        
            %d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n
            UTF-8 
        
        
        
            ${log.path}/warn/log-warn-%d{yyyy-MM-dd}.%i.log
            
                100MB
            
            
            15
        
        
        
            warn
            ACCEPT
            DENY
        
    


    
    
        
        ${log.path}/log_error.log
        
        
            %d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n
            UTF-8 
        
        
        
            ${log.path}/error/log-error-%d{yyyy-MM-dd}.%i.log
            
                100MB
            
            
            15
        
        
        
            ERROR
            ACCEPT
            DENY
        
    

    
    
    
    
        
        

        
        
            
            
            
            
        
    


    
    

        
            
            
            
            
            
        
    



你可能感兴趣的:(分布式医疗挂号系统(四) | 统一返回结果、异常处理、日志处理到通用模块)