--- title: "16-优化封装" created: 2025-12-02 tags: - 项目 aliases: - 优化封装 --- # 优化封装 ## qian封装通用返回对象 给对象补充一些信息 告诉前端这个请求在业务层面上是成功还是失败 ```json { “name":"Zwww" } 变成 { "code": 0 //业务状态码 "data":{ "name":"Zwww" }, "message":"ok" } ``` ### 通用返回类 ![[image-0b1cfe59.png]] ```java package com.zwnsyw.bankend.common; import lombok.Data; import java.io.Serializable; /** * 通用返回类 * * @author Zwww */ @Data public class BaseResponse implements Serializable { /** * 状态码 */ private int code; /** * 数据 */ private T data; /** * 消息 */ private String message; /** * 描述 */ private String description; public BaseResponse(int code, T data, String message, String description) { this.code = code; this.data = data; this.message = message; this.description = description; } public BaseResponse(int code, T data, String message) { this(code, data, message, ""); } public BaseResponse(int code, T data) { this(code, data, "", ""); } public BaseResponse(ErrorCode errorCode) { this(errorCode.getCode(), null, errorCode.getMessage(), errorCode.getDescription()); } } ``` ### 返回工具类 ![[image-0b1cfe59.png]] 以免每次调用都要传一堆参数 这里再做一层封装 帮助填这些参数 ```java package com.zwnsyw.bankend.common; /** * 返回工具类 * * @author Zwww */ public class ResultUtils { /** * 成功 * * @param data * @param * @return */ public static BaseResponse success(T data) { return new BaseResponse<>(0, data, "ok"); } /** * 失败 * * @param errorCode * @return */ public static BaseResponse error(ErrorCode errorCode) { return new BaseResponse<>(errorCode); } /** * 失败 * * @param code * @param message * @param description * @return */ public static BaseResponse error(int code, String message, String description) { return new BaseResponse(code, null, message, description); } /** * 失败 * * @param errorCode * @return */ public static BaseResponse error(ErrorCode errorCode, String message, String description) { return new BaseResponse(errorCode.getCode(), null, message, description); } /** * 失败 * * @param errorCode * @return */ public static BaseResponse error(ErrorCode errorCode, String description) { return new BaseResponse(errorCode.getCode(), errorCode.getMessage(), description); } } ``` ## 封装全局异常处理 业务逻辑中 之前遇到判定为错误后 都是返回-1或者false 其实是不明确的 加上一些通用的错误码 ![[image-ce1d6341.png]] ```java package com.zwnsyw.bankend.common; /** * 错误码 * * @author Zwww */ public enum ErrorCode { SUCCESS(0, "ok", ""), PARAMS_ERROR(40000, "请求参数错误", ""), NULL_ERROR(40001, "请求数据为空", ""), NOT_LOGIN(40100, "未登录", ""), NO_AUTH(40101, "无权限", ""), SYSTEM_ERROR(50000, "系统内部异常", ""); private final int code; /** * 状态码信息 */ private final String message; /** * 状态码描述(详情) */ private final String description; ErrorCode(int code, String message, String description) { this.code = code; this.message = message; this.description = description; } public int getCode() { return code; } public String getMessage() { return message; } public String getDescription() { return description; } } ``` ## 全局异常处理 定义一个东西来捕获整个业务中的异常 统一处理 ![[image-f214b3a9.png]] ### 自定义异常类 相较于java的异常类 扩充更多字段 自定义构造函数 更灵活快捷设置字段 ```java package com.zwnsyw.bankend.exception; import com.zwnsyw.bankend.common.ErrorCode; /** * 自定义异常类 * * @author Zwww */ public class BusinessException extends RuntimeException { /** * 异常码 */ private final int code; /** * 描述 */ private final String description; public BusinessException(String message, int code, String description) { super(message); this.code = code; this.description = description; } public BusinessException(ErrorCode errorCode) { super(errorCode.getMessage()); this.code = errorCode.getCode(); this.description = errorCode.getDescription(); } public BusinessException(ErrorCode errorCode, String description) { super(errorCode.getMessage()); this.code = errorCode.getCode(); this.description = description; } public int getCode() { return code; } public String getDescription() { return description; } } ``` ### 全局异常处理器 捕获代码中所有的异常 集中处理 让前端感知更详细的业务报错/信息 ```java package com.zwnsyw.bankend.exception; import com.zwnsyw.bankend.common.BaseResponse; import com.zwnsyw.bankend.common.ErrorCode; import com.zwnsyw.bankend.common.ResultUtils; import lombok.extern.slf4j.Slf4j; import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.bind.annotation.RestControllerAdvice; /** * 全局异常处理器 * * @author Zwww */ @RestControllerAdvice @Slf4j public class GlobalExceptionHandler { @ExceptionHandler(BusinessException.class) public BaseResponse businessExceptionHandler(BusinessException e) { log.error("businessException: " + e.getMessage(), e); return ResultUtils.error(e.getCode(), e.getMessage(), e.getDescription()); } @ExceptionHandler(RuntimeException.class) public BaseResponse runtimeExceptionHandler(RuntimeException e) { log.error("runtimeException", e); return ResultUtils.error(ErrorCode.SYSTEM_ERROR, e.getMessage(), ""); } } ``` ## 前端对应接口 ![[image-56a9e883.png]] api.ts ```javascript import request from '@/plugins/globalRequest'; /** 获取当前的用户 GET /api/user/current */ export async function currentUser(options?: { [key: string]: any }) { return request>('/api/user/current', { method: 'GET', ...(options || {}), }); } /** 退出登录接口 POST /api/user/logout */ export async function outLogin(options?: { [key: string]: any }) { return request>('/api/user/logout', { method: 'POST', ...(options || {}), }); } /** 登录接口 POST /api/user/login */ export async function login(body: API.LoginParams, options?: { [key: string]: any }) { return request>('/api/user/login', { method: 'POST', headers: { 'Content-Type': 'application/json', }, data: body, ...(options || {}), }); } /** 注册接口 POST /api/user/register */ export async function register(body: API.RegisterParams, options?: { [key: string]: any }) { return request>('/api/user/register', { method: 'POST', headers: { 'Content-Type': 'application/json', }, data: body, ...(options || {}), }); } /** 搜索用户 GET /api/user/search */ export async function searchUsers(options?: { [key: string]: any }) { return request>('/api/user/search', { method: 'GET', ...(options || {}), }); } ``` ![[image-00c5f3c3.png]] ```javascript /** * request 网络请求工具 * 更详细的 api 文档: https://github.com/umijs/umi-request */ import {extend} from 'umi-request'; import {message} from "antd"; import {history} from "@@/core/history"; import {stringify} from "querystring"; /** * 配置request请求时的默认参数 */ const request = extend({ credentials: 'include', // 默认请求是否带上cookie prefix: process.env.NODE_ENV === 'production' ? 'http://user-backend.code-nav.cn' : undefined // requestType: 'form', }); /** * 所以请求拦截器 */ request.interceptors.request.use((url, options): any => { console.log(`do request url = ${url}`) return { url, options: { ...options, headers: {}, }, }; }); /** * 所有响应拦截器 */ request.interceptors.response.use(async (response, options): Promise => { const res = await response.clone().json(); if (res.code === 0) { return res.data; } if (res.code === 40100) { message.error('请先登录'); history.replace({ pathname: '/user/login', search: stringify({ redirect: location.pathname, }), }); } else { message.error(res.description) } return res.data; }); export default request; ``` --- **项目分区导航**:⬅️ [[15-逻辑删除mybatis-plus配置原理|15-逻辑删除mybatis-plus配置原理]] | 16-优化封装 | ➡️ [[17-部署|17-部署]]