前言

Github:https://github.com/HealerJean

博客:http://blog.healerjean.com

一、常用类

1、枚举

1)CodeEnum

package com.healerjean.proj.common.enums;


import lombok.AllArgsConstructor;
import lombok.Getter;

/**
 * CodeEnum
 *
 * @author zhangyujin
 * @date 2023/6/12  10:41.
 */
public interface CodeEnum {


    @Getter
    @AllArgsConstructor
    enum ErrorCodeEnum implements CodeEnum {

        ERROR_CODE_SUCCESS("00000", "成功"),
        ERROR_CODE_PARAMS_ERROR("10000", "参数错误"),
        ERROR_CODE_BUSINESS_ERROR("20000", "业务处理失败"),
        ERROR_CODE_PRC_ERROR("30000", "RPC处理失败"),
        ERROR_CODE_RUNTIME_ERROR("40000", "运行时失败"),
        ERROR_CODE_FAIL("99999", "系统太火爆了,请稍后重试!"),
        ;
        private final String code;
        private final String msg;

    }



    @Getter
    @AllArgsConstructor
    enum BusinessErrorEnum implements CodeEnum {

        ERROR_CODE_20000("20000", "业务处理失败", "系统太火爆了,请稍后重试!"),
        ERROR_CODE_20001("20001", "订单创建失败", "您有一个订单正在创建,请稍后查看"),
        ERROR_CODE_20002("20002", "付款失败,存在创建中的订单", "您的订单付款失败,请稍后查看"),
        ERROR_CODE_20003("20003", "付款失败,存在未支付的订单", "您的订单付款失败,请稍后查看"),

        ;
        private final String code;

        private final String msg;

        private final String showMsg;
    }


    @Getter
    @AllArgsConstructor
    enum ParamsErrorEnum implements CodeEnum {

        ERROR_CODE_10000("10000", "参数错误"),
        ERROR_CODE_10001("10001", "不支持的请求方式"),
        ERROR_CODE_10002("10002", "参数格式异常"),

        ;
        private final String code;

        private final String msg;


    }


    @Getter
    @AllArgsConstructor
    enum RpcErrorEnum implements CodeEnum {

        /**
         * 系统_失败分类(请求0、返回1)_业务_方法_调用方CODE码(代码补齐)
         */
        ERROR_CODE_USER_0_30001_0001("USER_0_30001_0001", "RPC异常-USER-用户信息-查询单个用户信息-接口调用失败"),
        ERROR_CODE_USER_1_30001_0001("USER_1_30001_0001", "RPC异常-USER-用户信息-查询单个用户信息-接口返回失败"),
        ERROR_CODE_USER_1_30001_0002("USER_1_30001_0002", "RPC异常-USER-用户信息-分页查询用户信息-接口返回失败"),
        ;
        private final String code;
        private final String msg;
    }


    @Getter
    @AllArgsConstructor
    enum PlatformErrorEnum implements CodeEnum {

        ERROR_CODE_40000("40000", "运行时失败"),
        ERROR_CODE_40001("40001", "路由消息处理失败"),

        ;
        private final String code;

        private final String msg;

    }



}

2、实体

1)入参 PageReq

package com.healerjean.proj.common.data.req;

import com.healerjean.proj.common.data.dto.PageQueryDTO;
import lombok.Data;

import java.io.Serializable;


/**
 * PageReq
 *
 * @author zhangyujin
 * @date 2023/6/14  14:24
 */
@Data
public class PageReq<T> implements Serializable {

    /**
     * serialVersionUID
     */
    private static final long serialVersionUID = 467204528695545241L;

    /**
     * 条件对象
     */
    private T data;

    /**
     * pageQuery
     */
    private PageQueryDTO pageQuery;
}

package com.healerjean.proj.common.data.dto;

import lombok.Data;
import lombok.experimental.Accessors;

import java.io.Serializable;

/**
 * @author zhangyujin
 * @date 2023/6/14  14:26.
 */
@Accessors(chain = true)
@Data
public class PageQueryDTO implements Serializable {

    /**
     * serialVersionUID
     */
    private static final long serialVersionUID = -6352246288500328255L;

    /**
     * 当前页数
     */
    private Long currPage;

    /**
     * 分页
     */
    private Long pageSize;


    /**
     * 默认分页参数
     */
    public PageQueryDTO() {
        this.currPage = 1L;
        this.pageSize = 10L;
    }
}

2)出参 BaseRes

package com.healerjean.proj.common.data.bo;


import com.healerjean.proj.common.enums.CodeEnum;
import lombok.Data;
import lombok.experimental.Accessors;

/**
 * 返回对象
 */
@Accessors(chain = true)
@Data
public class BaseRes<T> {

    public BaseRes() {
    }

    /**
     * 是否成功
     */
    private Boolean success;
    /**
     * 返回结果
     */
    private T data;

    /**
     * msg
     */
    private String msg = "";

    /**
     * Code
     */
    private String code;


    /**
     * buildSuccess
     *
     * @param <T> <T>
     * @return ResponseBean
     */
    public static <T> BaseRes<T> buildSuccess() {
        BaseRes<T> baseRes = new BaseRes<>();
        baseRes.setSuccess(true);
        baseRes.setCode(CodeEnum.ErrorCodeEnum.ERROR_CODE_SUCCESS.getCode());
        return baseRes;
    }

    /**
     * buildSuccess
     *
     * @param data data
     * @param <T>  <T>
     * @return ResponseBean
     */
    public static <T> BaseRes<T> buildSuccess(T data) {
        BaseRes<T> baseRes = new BaseRes<>();
        baseRes.setSuccess(true);
        baseRes.setCode(CodeEnum.ErrorCodeEnum.ERROR_CODE_SUCCESS.getCode());
        baseRes.setData(data);
        return baseRes;
    }

    /**
     * buildSuccess
     *
     * @param <T> <T>
     * @return ResponseBean
     */
    public static <T> BaseRes<T> buildSuccess(T data, String msg) {
        BaseRes<T> baseRes = new BaseRes<>();
        baseRes.setSuccess(true);
        baseRes.setData(data);
        baseRes.setCode(CodeEnum.ErrorCodeEnum.ERROR_CODE_SUCCESS.getCode());
        baseRes.setMsg(msg);
        return baseRes;
    }

    /**
     * buildFailure
     *
     * @return ResponseBean
     */
    public static <T> BaseRes<T> buildFailure() {
        BaseRes<T> baseRes = new BaseRes<>();
        baseRes.setSuccess(false);
        baseRes.setCode(CodeEnum.ErrorCodeEnum.ERROR_CODE_FAIL.getCode());
        return baseRes;
    }


    /**
     * parameterErrorEnum
     *
     * @param msg msg
     * @param <T> <T>
     * @return ResponseBean
     */
    public static <T> BaseRes<T> buildParamsFailure(String msg) {
        BaseRes<T> baseRes = new BaseRes<>();
        baseRes.setSuccess(false);
        baseRes.setCode(CodeEnum.ErrorCodeEnum.ERROR_CODE_PARAMS_ERROR.getCode());
        baseRes.setMsg(msg);
        return baseRes;
    }

    /**
     * parameterErrorEnum
     *
     * @param codeEnum codeEnum
     * @param <T>      <T>
     * @return ResponseBean
     */
    public static <T> BaseRes<T> buildFailure(CodeEnum codeEnum) {
        BaseRes<T> baseRes = new BaseRes<>();
        baseRes.setSuccess(false);
        if (codeEnum instanceof CodeEnum.ErrorCodeEnum) {
            CodeEnum.ErrorCodeEnum errorEnum = (CodeEnum.ErrorCodeEnum) codeEnum;
            baseRes.setCode(errorEnum.getCode());
            baseRes.setMsg(errorEnum.getMsg());
            return baseRes;
        }
        if (codeEnum instanceof CodeEnum.BusinessErrorEnum) {
            CodeEnum.BusinessErrorEnum errorEnum = (CodeEnum.BusinessErrorEnum) codeEnum;
            baseRes.setCode(errorEnum.getCode());
            baseRes.setMsg(errorEnum.getMsg());
            return baseRes;
        }
        return baseRes;
    }

    /**
     * @param code code
     * @param msg  msg
     * @param <T>  <T>
     * @return ResponseBean
     */
    public static <T> BaseRes<T> buildFailure(String code, String msg) {
        BaseRes<T> baseRes = new BaseRes<>();
        baseRes.setSuccess(false);
        baseRes.setCode(code);
        baseRes.setMsg(msg);
        return baseRes;
    }

}

3)出参分页返回 PageVO

package com.healerjean.proj.common.data.vo;

import lombok.Data;

import java.io.Serializable;
import java.util.Collections;
import java.util.List;

/**
* PageBO
*
* @author zhangyujin
* @date 2023/6/14  11:54.
*/
@Data
public class PageVO<T> implements Serializable {

  /**
   * serialVersionUID
   */
  private static final long serialVersionUID = 1817973891205894329L;

  /**
   * 总记录数
   */
  private Long totalCount;
  /**
   * 每页记录数
   */
  private Long pageSize;
  /**
   * 总页数
   */
  private Long totalPage;
  /**
   * 当前页数
   */
  private Long currPage;
  /**
   * 列表数据
   */
  private List<T> list;


  /**
   * 默认
   */
  private PageVO() {
  }

  /**
   * 构造器
   *
   * @param totalCount 条数
   * @param pageSize   size
   * @param totalPage  current
   * @param currPage   cur
   * @param list       list
   */
  public PageVO(Long totalCount, Long pageSize, Long totalPage, Long currPage, List<T> list) {
      this.totalCount = totalCount;
      this.pageSize = pageSize;
      this.totalPage = totalPage;
      this.currPage = currPage;
      this.list = list;
  }


  /**
   * 无数据
   */
  public static <T> PageVO<T> none(Long pageSize, Long currenPage) {
      return new PageVO<>(0L, pageSize, 0L, currenPage, Collections.emptyList());
  }
}

4) 业务分页返回 PageBO

package com.healerjean.proj.common.data.bo;

import lombok.Data;

import java.io.Serializable;
import java.util.Collections;
import java.util.List;

/**
 * PageBO
 *
 * @author zhangyujin
 * @date 2023/6/14  11:54.
 */
@Data
public class PageBO<T> implements Serializable {

    /**
     * serialVersionUID
     */
    private static final long serialVersionUID = 1411218404349777400L;

    /**
     * 总记录数
     */
    private Long totalCount;
    /**
     * 每页记录数
     */
    private Long pageSize;
    /**
     * 总页数
     */
    private Long totalPage;

    /**
     * 当前页数
     */
    private Long currPage;

    /**
     * 列表数据
     */
    private List<T> list;


    /**
     * 默认
     */
    private PageBO() {
    }

    /**
     * 构造器
     *
     * @param totalCount 条数
     * @param pageSize   size
     * @param totalPage  current
     * @param currPage   cur
     * @param list       list
     */
    public PageBO(Long totalCount, Long pageSize, Long totalPage, Long currPage, List<T> list) {
        this.totalCount = totalCount;
        this.pageSize = pageSize;
        this.totalPage = totalPage;
        this.currPage = currPage;
        this.list = list;
    }


    /**
     * 无数据
     */
    public static <T> PageBO<T> none(Long pageSize, Long currenPage) {
        return new PageBO<>(0L, pageSize, 0L, currenPage, Collections.emptyList());
    }
}

5)业务分页查询 PageQueryBO

package com.healerjean.proj.common.data.bo;

import lombok.Data;
import lombok.experimental.Accessors;

import java.io.Serializable;

/**
 * @author zhangyujin
 * @date 2023/6/14  14:14.
 */
@Accessors(chain = true)
@Data
public class PageQueryBO<T> implements Serializable {
    /**
     * serialVersionUID
     */
    private static final long serialVersionUID = 3015419757742187536L;

    /**
     * 当前页数
     */
    private Long currPage;

    /**
     * 分页
     */
    private Long pageSize;

    /**
     * 是否进行 count 查询
     * 默认不需要
     */
    private Boolean searchCountFlag;


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

    /**
     * 默认分页参数
     */
    public PageQueryBO() {
        this.currPage = 1L;
        this.pageSize = 10L;
        this.searchCountFlag = true;
    }
}

6)业务排序 OrderByBO

package com.healerjean.proj.common.data.bo;

import lombok.Data;
import lombok.experimental.Accessors;

import java.io.Serializable;

/**
 * OrderByBO
 *
 * @author zhangyujin
 * @date 2023/6/14  17:40.
 */
@Accessors(chain = true)
@Data
public class OrderByBO implements Serializable {

    /**
     * serialVersionUID
     */
    private static final long serialVersionUID = 160148478613404512L;
    /**
     * 排序属性
     */
    private String property;
    /**
     * 排序方向
     */
    private String direction;

}

7)对象转化 PageConverter

package com.healerjean.proj.common.data.convert;

import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.healerjean.proj.common.data.bo.OrderByBO;
import com.healerjean.proj.common.data.bo.PageBO;
import com.healerjean.proj.common.data.bo.PageQueryBO;
import com.healerjean.proj.common.data.dto.OrderByDTO;
import com.healerjean.proj.common.data.dto.PageQueryDTO;
import com.healerjean.proj.common.data.vo.PageVO;
import org.mapstruct.Mapper;
import org.mapstruct.factory.Mappers;
import org.springframework.util.CollectionUtils;

import java.util.Collections;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

/**
* @author zhangyujin
* @date 2023/6/14  13:56.
*/
@Mapper
public interface PageConverter {

  /**
   * 实例
   */
  PageConverter INSTANCE = Mappers.getMapper(PageConverter.class);


  /**
   * covertPageBoToVo
   *
   * @param pageBo pageBo
   * @param <T>    <T>
   * @return PageVO
   */
  default <T> PageVO<T> covertPageBoToVo(PageBO<?> pageBo, List<T> list) {
      return new PageVO<>(pageBo.getTotalCount(), pageBo.getPageSize(), pageBo.getTotalPage(), pageBo.getCurrPage(), list);
  }


  /**
   * covertPageBoToVo
   *
   * @param iPage iPage
   * @param list  list
   * @param <T>   <T>
   * @return PageVO
   */
  default <T> PageBO<T> covertPageBoToBo(Page<?> iPage, List<T> list) {
      return new PageBO<>(iPage.getTotal(), iPage.getSize(), iPage.getPages(), iPage.getCurrent(), list);
  }


  /**
   * pageQueryDtoToBo
   *
   * @param pageQuery pageQuery
   * @return PageQueryBO
   */
  default <T> PageQueryBO<T> pageQueryDtoToBo(PageQueryDTO pageQuery) {
      if (Objects.isNull(pageQuery)) {
          pageQuery = new PageQueryDTO();
      }
      PageQueryBO<T> result = new PageQueryBO<>();
      if (Objects.nonNull(pageQuery.getCurrPage())) {
          result.setCurrPage(pageQuery.getCurrPage());
      }
      if (Objects.nonNull(pageQuery.getPageSize())) {
          result.setPageSize(pageQuery.getPageSize());
      }
      return result;
  }


  /**
   * coverOrderByDtoToBo
   *
   * @param orderByBo orderByBo
   * @return PageQueryBO.OrderByBO
   */
  default OrderByBO coverOrderByDtoToBo(OrderByDTO orderByBo) {
      OrderByBO orderByBO = new OrderByBO();
      orderByBO.setProperty(orderByBo.getProperty());
      orderByBO.setDirection(orderByBo.getDirection());
      return orderByBO;
  }

  /**
   * coverOrderByDtoToBoList
   *
   * @param orderByBos orderByBos
   * @return List<PageQueryBO.OrderByBO>
   */
  default List<OrderByBO> coverOrderByDtoToBoList(List<OrderByDTO> orderByBos) {
      if (CollectionUtils.isEmpty(orderByBos)) {
          return Collections.emptyList();
      }
      return orderByBos.stream().map(this::coverOrderByDtoToBo).collect(Collectors.toList());
  }

}

3、Exception

1)业务异常 BusinessException

@Getter
public class BusinessException extends RuntimeException {

    /**
     * serialVersionUID
     */
    private static final long serialVersionUID = 799633539625676004L;

    /**
     * 返回错误码
     */
    private final String code;

    /**
     * 展示信息
     */
    private final String showMsg;


    /**
     * BusinessException
     *
     * @param businessErrorEnum businessErrorEnum
     */
    public BusinessException(CodeEnum.BusinessErrorEnum businessErrorEnum) {
        super(businessErrorEnum.getMsg());
        this.code = businessErrorEnum.getCode();
        this.showMsg = businessErrorEnum.getShowMsg();

    }

    /**
     * BusinessException
     *
     * @param message message
     */
    public BusinessException(String message) {
        super(message);
        this.code = CodeEnum.ErrorCodeEnum.ERROR_CODE_BUSINESS_ERROR.getCode();
        this.showMsg = message;
    }

}

2)参数异常类:ParameterException

@Getter
public class ParameterException extends RuntimeException {


    /**
     * serialVersionUID
     */
    private static final long serialVersionUID = -6114625076221233075L;
    /**
     * 返回错误码
     */
    private final String code;


    /**
     * BusinessException
     *
     * @param paramErrorEnum paramErrorEnum
     */
    public ParameterException(CodeEnum.ParamsErrorEnum paramErrorEnum) {
        super(paramErrorEnum.getMsg());
        this.code = paramErrorEnum.getCode();
    }

    /**
     * ParameterErrorException
     *
     * @param message message
     */
    public ParameterException(String message) {
        super(message);
        this.code = CodeEnum.ErrorCodeEnum.ERROR_CODE_PARAMS_ERROR.getCode();
    }

}

3)接口异常类 RpcException

@Getter
public class RpcException extends RuntimeException {

    /**
     * serialVersionUID
     */
    private static final long serialVersionUID = 799633539625676004L;

    /**
     * 返回错误码
     */
    private final String code;

    /**
     * 展示信息
     */
    private final String showMsg;

    /**
     * RpcException-处理未知的异常
     *
     *
     * @param rpcErrorEnum rpcErrorEnum
     */
    public RpcException(CodeEnum.RpcErrorEnum rpcErrorEnum) {
        super(rpcErrorEnum.getMsg());
        this.code = rpcErrorEnum.getCode();
        this.showMsg = CodeEnum.ErrorCodeEnum.ERROR_CODE_FAIL.getMsg();
    }

    /**
     * RpcException 处理已知的异常
     *
     * @param rpcErrorEnum rpcErrorEnum
     * @param code         code
     * @param showMsg      showMsg
     */
    public RpcException(CodeEnum.RpcErrorEnum rpcErrorEnum, String code, String showMsg) {
        super(rpcErrorEnum.getMsg());
        this.code = rpcErrorEnum.getCode() + "_" + code;
        this.showMsg = showMsg;
    }

    /**
     * RpcException 处理已知的异常
     *
     * @param rpcErrorEnum rpcErrorEnum
     * @param code         code
     * @param showMsg      showMsg
     */
    public RpcException(CodeEnum.RpcErrorEnum rpcErrorEnum, String code, String msg, String showMsg) {
        super(msg);
        this.code = rpcErrorEnum.getCode() + "_" + code;
        this.showMsg = showMsg;
    }

}

4、运行异常类:PlatformException

package com.healerjean.proj.exceptions;

import com.healerjean.proj.common.enums.CodeEnum;
import lombok.Getter;

/**
 * PlatformException
 *
 * @author zhangyujin
 * @date 2024/1/3
 */
@Getter
public class PlatformException extends RuntimeException {

    private static final long serialVersionUID = 5535821215702463243L;
    /**
     * 返回错误码
     */
    private final String code;

    /**
     * 展示信息
     */
    private final String showMsg;

    /**
     * PlatformException
     *
     * @param platformErrorEnum platformErrorEnum
     */
    public PlatformException(CodeEnum.PlatformErrorEnum platformErrorEnum) {
        super(platformErrorEnum.getMsg());
        this.code = platformErrorEnum.getCode();
        this.showMsg = CodeEnum.ErrorCodeEnum.ERROR_CODE_FAIL.getMsg();

    }
}

4、控制层

1)ControllerHandleConfig

package com.healerjean.proj.controller;

import com.healerjean.proj.common.data.bo.BaseRes;
import com.healerjean.proj.common.enums.CodeEnum;
import com.healerjean.proj.exceptions.BusinessException;
import com.healerjean.proj.exceptions.ParameterException;
import com.healerjean.proj.exceptions.PlatformException;
import com.healerjean.proj.exceptions.RpcException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.converter.HttpMessageConversionException;
import org.springframework.validation.BindException;
import org.springframework.web.HttpRequestMethodNotSupportedException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.method.annotation.MethodArgumentTypeMismatchException;

import javax.servlet.http.HttpServletResponse;
import javax.validation.UnexpectedTypeException;

/**
 * ControllerHandleConfig
 *
 * @author zhangyujin
 * @date 2023/6/15  10:55.
 */
@Slf4j
@ControllerAdvice
public class ControllerHandleConfig {

    /**
     * 不支持的请求方始
     */
    @ExceptionHandler(value = HttpRequestMethodNotSupportedException.class)
    @ResponseStatus(value = HttpStatus.METHOD_NOT_ALLOWED)
    public BaseRes<?> methodNotSupportExceptionHandler(HttpRequestMethodNotSupportedException e) {
        log.error("不支持的请求方式", e);
        return BaseRes.buildFailure(CodeEnum.ParamsErrorEnum.ERROR_CODE_10001.getCode(), e.getMessage());
    }


    /**
     * 参数类型错误
     * 1、(BindException : 比如 Integer 传入String  )
     * Field error in object 'demoDTO' on field 'age': rejected value [fasdf]; codes [typeMismatch.demoDTO.age,typeMismatch.age,typeMismatch.java.lang.Integer,typeMismatch]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [demoDTO.age,age]; arguments []; default message [age]]; default message [Failed to convert property value of type 'java.lang.String' to required type 'java.lang.Integer' for property 'age'; nested exception is java.lang.NumberFormatException: For input string: "fasdf"]
     */
    @ExceptionHandler(value = {BindException.class})
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    @ResponseBody
    public BaseRes<?> bindExceptionHandler(BindException e) {
        log.error("====参数类型错误===", e);
        return BaseRes.buildFailure(CodeEnum.ParamsErrorEnum.ERROR_CODE_10000);
    }


    /**
     * 参数格式问题
     */
    @ExceptionHandler(value = {MethodArgumentTypeMismatchException.class, HttpMessageConversionException.class, UnexpectedTypeException.class})
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    @ResponseBody
    public BaseRes<?> httpMessageConversionExceptionHandler(Exception e) {
        log.error("====参数格式异常===", e);
        return BaseRes.buildFailure(CodeEnum.ParamsErrorEnum.ERROR_CODE_10002);
    }


    /**
     * 参数错误
     */
    @ExceptionHandler(value = ParameterException.class)
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    @ResponseBody
    public BaseRes<?> parameterErrorExceptionHandler(ParameterException e) {
        log.error("====参数异常:code:{},msg:{}", e.getCode(), e.getMessage(), e);
        return BaseRes.buildFailure(e.getCode(), e.getMessage());
    }


    /**
     * 业务异常,给前台返回异常数据
     */
    @ExceptionHandler(value = BusinessException.class)
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    @ResponseBody
    public BaseRes<?> businessExceptionHandler(BusinessException e) {
        log.error("====业务异常:code:{},msg:{},showMsg:{}", e.getCode(), e.getMessage(), e.getShowMsg(), e);
        return BaseRes.buildFailure(e.getCode(), e.getShowMsg());
    }


    /**
     * RPC,给前台返回异常数据
     */
    @ExceptionHandler(value = RpcException.class)
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    @ResponseBody
    public BaseRes<?> rpcExceptionHandler(RpcException e) {
        log.error("====RPC异常:code:{},msg:{},showMsg:{}", e.getCode(), e.getMessage(), e.getShowMsg(), e);
        return BaseRes.buildFailure(e.getCode(), e.getShowMsg());
    }

    /**
     * 运行异常,给前台返回异常数据
     */
    @ExceptionHandler(value = PlatformException.class)
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    @ResponseBody
    public BaseRes<?> rpcExceptionHandler(PlatformException e) {
        log.error("====运行异常:code:{},msg:{},showMsg:{}", e.getCode(), e.getMessage(), e.getShowMsg(), e);
        return BaseRes.buildFailure(e.getCode(), e.getShowMsg());
    }


    /**
     * 所有异常报错
     */
    @ExceptionHandler
    @ResponseBody
    public HttpEntity<BaseRes<?>> allExceptionHandler(HttpServletResponse response, Exception e) {
        log.error("====系统错误===", e);
        response.setStatus(500);
        return returnMessage(BaseRes.buildFailure(CodeEnum.ErrorCodeEnum.ERROR_CODE_FAIL));
    }

    /**
     * returnMessage
     *
     * @param baseRes baseRes
     * @return HttpEntity<BaseRes < ?>>
     */
    private HttpEntity<BaseRes<?>> returnMessage(BaseRes<?> baseRes) {
        HttpHeaders header = new HttpHeaders();
        header.add("Content-Type", "application/json");
        header.add("Charset", "UTF-8");
        return new HttpEntity<>(baseRes, header);
    }


    /**
     * 参数非法
     * 1、(BindException : 比如 Integer 传入abc  )
     */
    // @ExceptionHandler(value = {MethodArgumentTypeMismatchException.class, HttpRequestMethodNotSupportedException.class, HttpMessageConversionException.class, BindException.class, UnexpectedTypeException.class})
    // @ResponseBody
    // public HttpEntity<ResponseBean> httpMessageConversionExceptionHandler(HttpServletResponse response, Exception e) {
    //     log.error("====参数格式异常===", e);
    //     // 等同于 @ResponseStatus(HttpStatus.BAD_REQUEST)
    //     // 但是setStatus 不能比随便设置,最好一般情况下不要和HttpStatus 有重复的,这样有可能会造成没有输出Response body
    //     response.setStatus(ResponseEnum.参数格式异常.code);
    //     return returnMessage(ResponseBean.buildFailure(ResponseEnum.参数格式异常));
    // }
    // @ExceptionHandler(value ={HttpMessageConversionException.class, BindException.class} )
    // @ResponseBody
    // public HttpEntity<ResponseBean> httpMessageConversionExceptionHandler(Exception e) {
    //     log.error("====参数格式异常===", e);
    //     return new ResponseEntity<>(ResponseBean.buildFailure(ResponseEnum.参数格式异常),HttpStatus.BAD_REQUEST);
    // }

}

2)验证

package com.healerjean.proj.controller;

import com.healerjean.proj.common.anno.LogIndex;
import com.healerjean.proj.common.data.bo.BaseRes;
import com.healerjean.proj.common.enums.CodeEnum;
import com.healerjean.proj.data.vo.UserDemoVO;
import com.healerjean.proj.exceptions.BusinessException;
import com.healerjean.proj.exceptions.ParameterException;
import com.healerjean.proj.exceptions.PlatformException;
import com.healerjean.proj.exceptions.RpcException;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;

import java.util.List;

/**
 * ExceltionController
 *
 * @author zhangyujin
 * @date 2024/1/3
 */
@RestController
@RequestMapping("hlj/exception")
@Api(tags = "Exception-控制器")
@Slf4j
public class ExceptionController {


    @ApiOperation("parameterExceptionEnum")
    @LogIndex
    @GetMapping("parameterExceptionEnum")
    @ResponseBody
    public BaseRes<List<UserDemoVO>> parameterExceptionEnum() {
        throw new ParameterException(CodeEnum.ParamsErrorEnum.ERROR_CODE_10002);
    }


    @ApiOperation("parameterExceptionMsg")
    @LogIndex
    @GetMapping("parameterExceptionMsg")
    @ResponseBody
    public BaseRes<List<UserDemoVO>> parameterExceptionMsg() {
        throw new ParameterException("用户Id不能为空");
    }



    @ApiOperation("businessExceptionEnum")
    @LogIndex
    @GetMapping("businessExceptionEnum")
    @ResponseBody
    public BaseRes<List<UserDemoVO>> businessExceptionEnum() {
        throw new BusinessException(CodeEnum.BusinessErrorEnum.ERROR_CODE_20001);
    }

    @ApiOperation("businessExceptionMsg")
    @LogIndex
    @GetMapping("businessExceptionMsg")
    @ResponseBody
    public BaseRes<List<UserDemoVO>> businessExceptionMsg() {
        throw new BusinessException("用户创建失败");
    }



    @ApiOperation("rpcExceptionDefaultEnum")
    @LogIndex
    @GetMapping("rpcExceptionDefaultEnum")
    @ResponseBody
    public BaseRes<List<UserDemoVO>> rpcExceptionDefaultEnum() {
        throw new RpcException(CodeEnum.RpcErrorEnum.ERROR_CODE_USER_0_30001_0001);
    }


    @ApiOperation("rpcExceptionEnumShowMsg")
    @LogIndex
    @GetMapping("rpcExceptionEnumShowMsg")
    @ResponseBody
    public BaseRes<List<UserDemoVO>> rpcExceptionEnumShowMsg() {
        throw new RpcException(CodeEnum.RpcErrorEnum.ERROR_CODE_USER_1_30001_0001, "1000", "用户不存在");
    }


    @ApiOperation("rpcExceptionEnumMsg")
    @LogIndex
    @GetMapping("rpcExceptionEnumMsg")
    @ResponseBody
    public BaseRes<List<UserDemoVO>> rpcExceptionEnumMsg() {
        throw new RpcException(CodeEnum.RpcErrorEnum.ERROR_CODE_USER_1_30001_0001, "1000", "底层结构异常", "用户不存在");
    }



    @ApiOperation("platformException")
    @LogIndex
    @GetMapping("platformException")
    @ResponseBody
    public BaseRes<List<UserDemoVO>> platformException() {
        throw new PlatformException(CodeEnum.PlatformErrorEnum.ERROR_CODE_40001);
    }
}

二、常见规范

1、注释规范

/**
     * 根据合同模板生成合同初始pdf文件,讲合同状态设置为待确认状态
     * 1、数据校验
     *  1.1、基本数据校验
     *  1.2、校验合同模板是否存在
     *  1.3、校验签署人是否完整
     *  1.4、校验签署方是否真实有效
     * 2、把合同签署各方的信息和模板取出,将变量更替,生成word和pdf
     * 4、保存签署人信息
     * 5、合同初始化日志保存
     * 6、删除临时文件
     */
void createContractByTeamplate(ContractDTO contractDTO) 

2、POJO( DTOVOBOPODO)、Query

POJO 的定义是无规则简单的对象,在日常的代码分层中 pojo 会被分为VOBOPODTO

1)VOView Object)显示层对象

VOView Object):显示层对象,通常是 Web 向模板渲染引擎层传输的对象

1、前端展示的数据,在接口数据返回给前端的时候需要转成VO

2、个人理解使用场景,接口层服务中,将DTO转成VO,返回给前台

public List<UserVO> getUserVOs(UserQuery userQuery){
    
   //DTO转VO
    BeanUils.dtoToUserVO(userservice.getUserDTOs());
}

2)BOBusiness Object)业务层对象

业务对象。 由 Service 层输出的封装业务逻辑的对象。

1、主要在服务内部使用的业务对象

2、可以包含多个对象,可以用于对象的聚合操作

3、个人理解使用场景,在服务层服务中,由 DTO 转成 BO 然后进行业务处理后,转成DTO返回到接口层

Service内部的私有代码 
List<UserBO> getUserBOs(UserQuery userQuery){

   //DO转BO
    BeanUils.doToUserBO(userdao.getUserDOs());
}

3)DTOData Transfer Object)数据传输对象

数据传输对象,ServiceManager 向外传输的对象

1、在服务间的调用中,传输的数据对象

2、个人理解,DTO 是可以存在于各层服务中(接口、服务、数据库等等)服务间的交互使用DTO来解耦

 List<UserDTO> getUserDTOs(UserQuery userQuery){
     
      //BO转DTO,也可能DO转DTO
    BeanUils.boToUserDTO(userservice.getUserBOs());
 }

4)POpersistent object)持久对象

1、出现位置为数据库数据,用来存储数据库提取的数据

2、只存储数据,不包含数据操作

3、个人理解使用场景,在数据库层中,获取的数据库数据存储到PO中,然后转为DTO返回到服务层中

List<UserDO> getUsers(UserQuery userQuery);

5)DOData Object)领域实体对象

DOData Object)这个等同于上面的PO

List<UserDO> getUsers(UserQuery userQuery);

3、RPC 命名

1)提供者 ` DemoProvider`

2)消费者

3)接入层 RpcProxy

直接包装外部接口,无业务数据

package com.healerjean.proj.rpc.consumer.proxy.impl;

import com.healerjean.proj.common.anno.LogIndex;
import com.healerjean.proj.rpc.provider.DemoPrcResource;
import com.healerjean.proj.rpc.consumer.proxy.DemoRpcProxy;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;

/**
 * DemoRpcProxy
 *
 * @author zhangyujin
 * @date 2023/6/15  21:23.
 */
@Slf4j
@Service("demoRpcProxy")
public class DemoRpcProxyImpl implements DemoRpcProxy {


    @Resource
    private DemoPrcResource demoPrcResource;

    /**
     * Rpc调用
     *
     * @param reqString reqString
     * @return String
     */
    @LogIndex
    @Override
    public String rpcInvoke(String reqString) {
        return demoPrcResource.rpcInvoke(reqString);
    }
}

4)适配层 RpcAdapter

适配消费者,用于适配外部数据和聚合同类型的接口

/**
 * DemoAdapterImpl
 *
 * @author zhangyujin
 * @date 2023/7/14
 */
@Slf4j
@Service
public class DemoRpcAdapterImpl implements DemoRpcAdapter {

    @Resource
    private DemoRpcProxy demoRpcProxy;


    /**
     * Rpc调用
     *
     * @param msg msg
     * @return String String
     */
    String rpcInvoke(String msg) {
        try {
            return demoRpcProxy.rpcInvoke(msg);
        } catch (Exception e) {
            log.info("[DemoAdapter#rpcInvoke] msg", msg, e);
            return null;
        }
    }
}

4、返回码规范

以 HTTP 状态码为例,为了更加清晰的表述和区分状态码的含义,HTTP 状态做了分段。

image-20230612103909823

参考 HTTP 状态码的思路,我们对错误码进行分段,如上 CodeEnum

image-20230612103924970

5、接口文档

1)角色列表查询

说明

  • 测试调用地址:/api/roles
  • 调用方式:GET

请求参数

参数名称 参数类型 参数长度 是否必需 说明 备注
pageSize 整数   每页显示数量 默认10
pageNo 整数   当前查看页码 默认1
roleName 字符串 64 角色名称  
systemCode 字符串 32 系统CODE  
isPage 布尔 4 是否分页 true/false

请求报文样例

{
    "pageSize": 1,
    "pageNo": 1,
    "roleName": "",
    "systemCode": "scf-manager",
    "isPage": true
}

响应参数

参数名称 参数类型 参数长度 是否必需 说明 备注
msg 字符串 255 返回结果  
total 数字   总数  
pageNo 数字   页数  
totalPage 数字   总页数  
pageSize 数字   每页数量  
datas Role数组   返回的数据信息  

Role 数据结构

参数名称 参数类型 参数长度 是否必需 说明 备注
id 数字 16 id  
roleName 字符串 64 角色名称  
systemCode 字符串 64 系统CODE  
status 字符串 8 状态  
desc 字符串 255 描述  

响应报文样例

{
    "msg": "角色列表查询成功",
    "total": 2,
    "pageNo": 1,
    "totalPage": 1,
    "datas": [
        {
            "id": 1,
            "roleName": "后台管理员",
            "systemCode": "scf-manager",
            "status": "10"
        },
        {
            "id": 4,
            "roleName": "测试角色哦",
            "systemCode": "scf-manager",
            "status": "10",
            "desc": "真的是测试"
        }
    ],
    "pageSize": 10
}

返回码解析

返回码 含义 备注
200 成功  

ContactAuthor