统一返回响应

前言

我们为什么要设置统一返回响应

  1. 提高代码的可维护性:通过统一返回请求的格式,可以使代码更加清晰和易于维护,减少重复的代码,提高代码质量。

  2. 便于调试和测试:统一的返回格式使得在调试和测试时更为简单,可以快速定位和解决问题。

  3. 增强系统的可靠性:统一的返回格式有助于保证系统的稳定性和一致性,减少因不同模块返回格式不统一而导致的错误。

  4. 提升用户体验:统一的返回格式使得前端处理更加便捷,提高了响应速度,提升了用户体验。

  5. 便于日志记录和监控:统一的返回格式便于记录和监控系统的运行状态,方便进行故障排查和性能优化。

  6. 简化前后端接口对接:前后端约定统一的返回格式后,接口对接工作会变得更加顺畅,减少沟通成本和开发时间。

  7. 提高扩展性:统一的返回格式有利于系统扩展,当需要新增功能或模块时,只需遵循既定的返回格式,无需大规模修改已有代码。

  8. 保证数据安全:通过统一的返回格式,可以更好地控制返回的数据内容,避免敏感信息的泄露,提高数据安全性。

确定响应实体

我们首先要定义一个公共的接口响应实体,以后所有的接口返回值,都是返回的这个公共响应实体。
这样做的好处是可以统一返回值的风格,编译接口的维护。
需要包含3个关键的成员变量:

  1. 状态码
  2. 返回信息
  3. 数据
/**
 * api请求响应实体
 *
 * @author 
 * @date 
 */
@AllArgsConstructor
@Data
public class ApiResult<T> {

    /**
     * 请求成功状态码
     */
    public static final int OK = HttpStatus.HTTP_OK;

    /**
     * 接口返回码
     */
    private int code;

    /**
     * 接口返回信息
     */
    private String message;

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

确定响应实体工具类

为了更加优雅的创建相应实体类,我们可以增加一个专门的工具类。
这个工具类的职责是创建上面的ApiResult类的实例。
当然有两种情况:

/**
 * api请求响应实体处理工具类
 *

 */
public class ApiResultUtil {

    private ApiResultUtil() {
    }

    /**
     * 请求成功
     *
     * @param data 数据
     * @param <T>  数据类型
     * @return 接口相应实体
     */
    public static <T> ApiResult<T> success(T data) {
        return new ApiResult<>(ApiResult.OK, null, data);
    }

    /**
     * 请求成功
     *
     * @param <T> 数据类型
     * @return 接口相应实体
     */
    public static <T> ApiResult<T> success() {
        return success(null);
    }

    /**
     * 请求成功
     *
     * @param code    返回码
     * @param message 返回信息
     * @param <T>     数据类型
     * @return 接口相应实体
     */
    public static <T> ApiResult<T> error(int code, String message) {
        return new ApiResult<>(code, message, null);
    }
}

ApiResultUtil工具类中包含了两个重载的success方法,主要是处理接口请求成功的情况。
而error方法,主要是为了处理接口请求出现异常的情况。
需要注意的是ApiResultUtil类有一个私有的无参构造方法,是为了防止调用者new这个类的实例对象的一种常规做法,很多JDK源码中都有类似的做法。

业务异常

有了上面公共的响应实体类,我们可以先处理异常了。
但异常有两种:

  1. 系统异常
  2. 业务异常
    系统异常我们在统一处理时,错误码都返回500没问题。
    但如果有些业务异常,错误码都返回500,这种设计不太合理。
    因此,我们需要增加一个专门的业务异常类:BusinessException。
AllArgsConstructor
@Data
public class BusinessException extends RuntimeException {

    public static final long serialVersionUID = -6735897190745766939L;

    /**
     * 异常码
     */
    private int code;

    /**
     * 具体异常信息
     */
    private String message;

    public BusinessException() {
        super();
    }
}

这个异常类继承了RuntimeException类,是一种运行时异常,后面好处理。
包含了两个成员变量:

  1. code:表示异常码
  2. message:表示异常信息
    比如用户添加接口中,出现用户名称相同时,异常信息可以提示:用户名称重复。

全局异常处理

接下来,我们可以统一处理全局异常了。
在Spring MVC中可以通过@RestControllerAdvice注解处理全局异常:

@Slf4j
@RestControllerAdvice
public class GlobalExceptionHandler {

    /**
     * 统一处理异常
     *
     * @param e 异常
     * @return API请求响应实体
     */
    @ExceptionHandler(Throwable.class)
    public ApiResult handleException(Throwable e) {
        if (e instanceof BusinessException) {
            BusinessException businessException = (BusinessException) e;
            log.info("请求出现业务异常:", e);
            return ApiResultUtil.error(businessException.getCode(), businessException.getMessage());
        }
        log.error("请求出现系统异常:", e);
        return ApiResultUtil.error(HttpStatus.INTERNAL_SERVER_ERROR.value(), "服务器内部错误");
    }
}

正常接口响应处理


@ControllerAdvice
public class GlobalApiResultHandler implements ResponseBodyAdvice<Object> {
    @Override
    public boolean supports(MethodParameter returnType, Class<? extends HttpMessageConverter<?>> converterType) {
        ServletRequestAttributes sra = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = sra.getRequest();
        String requestURI = request.getRequestURI();
        return matchUrl(requestURI);
    }

    private boolean matchUrl(String uri) {
        if (StringUtils.isBlank(uri)) {
            return false;
        }
        return uri.contains("/v1");
    }

    @Override
    public Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType, Class<? extends HttpMessageConverter<?>> selectedConverterType, ServerHttpRequest request, ServerHttpResponse response) {
        if (body instanceof ApiResult) {
            return (ApiResult) body;
        }
        return ApiResultUtil.success(body);
    }
}
  • 5
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
牙科就诊管理系统利用当下成熟完善的SSM框架,使用跨平台的可开发大型商业网站的Java语言,以及最受欢迎的RDBMS应用软件之一的Mysql数据库进行程序开发。实现了用户在线查看数据。管理员管理病例管理、字典管理、公告管理、药单管理、药品管理、药品收藏管理、药品评价管理、药品订单管理、牙医管理、牙医收藏管理、牙医评价管理、牙医挂号管理、用户管理、管理员管理等功能。牙科就诊管理系统的开发根据操作人员需要设计的界面简洁美观,在功能模块布局上跟同类型网站保持一致,程序在实现基本要求功能时,也为数据信息面临的安全问题提供了一些实用的解决方案。可以说该程序在帮助管理者高效率地处理工作事务的同时,也实现了数据信息的整体化,规范化与自动化。 管理员在后台主要管理病例管理、字典管理、公告管理、药单管理、药品管理、药品收藏管理、药品评价管理、药品订单管理、牙医管理、牙医收藏管理、牙医评价管理、牙医挂号管理、用户管理、管理员管理等。 牙医列表页面,此页面提供给管理员的功能有:查看牙医、新增牙医、修改牙医、删除牙医等。公告信息管理页面提供的功能操作有:新增公告,修改公告,删除公告操作。公告类型管理页面显示所有公告类型,在此页面既可以让管理员添加新的公告信息类型,也能对已有的公告类型信息执行编辑更新,失效的公告类型信息也能让管理员快速删除。药品管理页面,此页面提供给管理员的功能有:新增药品,修改药品,删除药品。药品类型管理页面,此页面提供给管理员的功能有:新增药品类型,修改药品类型,删除药品类型。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

忘忧记

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值