Skip to content

通用项目代码

约 1404 字大约 5 分钟

通用代码

2025-07-30

后端

常用依赖

Lombok

<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
  	<version>1.18.36</version>
    <optional>true</optional>
</dependency>

Hutool工具类 常见的Java工具类库,包含了常用的工具类,例如字符串处理、日期处理、文件处理、文件加密等等。它节省了开发人员对项目中公用类和公用工具方法的封装时间。

<dependency>
    <groupId>cn.hutool</groupId>
    <artifactId>hutool-all</artifactId>
    <version>5.8.38</version>
</dependency>

Knife4j Knife4j 是基于Swagger接口文档的增强工具,提供了更加友好的API文档界面和功能扩展,例如动态参数调试、分组文 档等。它适合用于Spring Boot项目中,能够通过简单的配置自动生成接口文档,让开发者和前端快速了解和调试接口, 提高协作效率。

<dependency>
    <groupId>com.github.xiaoymin</groupId>
    <artifactId>knife4j-openapi3-jakarta-spring-boot-starter</artifactId>
    <version>4.4.0</version>
</dependency>

AOP切面

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-aop</artifactId>
</dependency>

使用@EnableAspectJAutoProxy(exposeProxy = true): 通过Spring AOP提供当前代理对象的访问,可以在业务逻辑中访问当前的代理对象。

通用基础代码

统一异常错误码

统一错误码,便于前端处理。

@Getter
public enum ErrorCode {

    SUCCESS(0, "ok"),
    PARAMS_ERROR(40000, "请求参数错误"),
    NOT_LOGIN_ERROR(40100, "未登录"),
    NO_AUTH_ERROR(40101, "无权限"),
    NOT_FOUND_ERROR(40400, "请求数据不存在"),
    FORBIDDEN_ERROR(40300, "禁止访问"),
    SYSTEM_ERROR(50000, "系统内部异常"),
    OPERATION_ERROR(50001, "操作失败");

    /**
     * 状态码
     */
    private final int code;

    /**
     * 信息
     */
    private final String message;

    ErrorCode(int code, String message) {
        this.code = code;
        this.message = message;
    }
}

自定义异常

继承RuntimeException异常,可以实现自己的异常处理

@Getter
public class BusinessException extends RuntimeException {

    /**
     * 错误码
     */
    private final int code;

    public BusinessException(int code, String message) {
        super(message);
        this.code = code;
    }

    public BusinessException(ErrorCode errorCode) {
        super(errorCode.getMessage());
        this.code = errorCode.getCode();
    }

    public BusinessException(ErrorCode errorCode, String message) {
        super(message);
        this.code = errorCode.getCode();
    }
}

响应包装类

@Data
public class BaseResponse<T> implements Serializable {

    private int code;

    private T data;

    private String message;

    public BaseResponse(int code, T data, String message) {
        this.code = code;
        this.data = data;
        this.message = message;
    }

    public BaseResponse(int code, T data) {
        this(code, data, "");
    }

    public BaseResponse(ErrorCode errorCode) {
        this(errorCode.getCode(), null, errorCode.getMessage());
    }
}

通用返回响应类

public class ResultUtils {

    /**
     * 成功
     *
     * @param data 数据
     * @param <T>  数据类型
     * @return 响应
     */
    public static <T> BaseResponse<T> 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 错误信息
     * @return 响应
     */
    public static BaseResponse<?> error(int code, String message) {
        return new BaseResponse<>(code, null, message);
    }

    /**
     * 失败
     *
     * @param errorCode 错误码
     * @return 响应
     */
    public static BaseResponse<?> error(ErrorCode errorCode, String message) {
        return new BaseResponse<>(errorCode.getCode(), null, message);
    }
}

全局异常处理器

使用AOP拦截异常

@Hidden
@RestControllerAdvice
@Slf4j
public class GlobalExceptionHandler {

    @ExceptionHandler(BusinessException.class)
    public BaseResponse<?> businessExceptionHandler(BusinessException e) {
        log.error("BusinessException", e);
        return ResultUtils.error(e.getCode(), e.getMessage());
    }

    @ExceptionHandler(RuntimeException.class)
    public BaseResponse<?> runtimeExceptionHandler(RuntimeException e) {
        log.error("RuntimeException", e);
        return ResultUtils.error(ErrorCode.SYSTEM_ERROR, "系统错误");
    }
}

请求包装类

@Data
public class DeleteRequest implements Serializable {

    /**
     * id
     */
    private Long id;

    private static final long serialVersionUID = 1L;
}
@Data
public class PageRequest {

    /**
     * 当前页号
     */
    private int pageNum = 1;

    /**
     * 页面大小
     */
    private int pageSize = 10;

    /**
     * 排序字段
     */
    private String sortField;

    /**
     * 排序顺序(默认降序)
     */
    private String sortOrder = "descend";
}

全局跨域配置

@Configuration
public class CorsConfig implements WebMvcConfigurer {

    @Override
    public void addCorsMappings(CorsRegistry registry) {
        // 覆盖所有请求
        registry.addMapping("/**")
                // 允许发送 Cookie
                .allowCredentials(true)
                // 放行哪些域名(必须用 patterns,否则 * 会和 allowCredentials 冲突)
                .allowedOriginPatterns("*")
                .allowedMethods("GET", "POST", "PUT", "DELETE", "OPTIONS")
                .allowedHeaders("*")
                .exposedHeaders("*");
    }
}

yml配置

spring:
  application:
    name: fly-genius
server:
  port: 8100
  servlet:
    context-path: /api
    
# 文档
springdoc:
  api-docs:
    enabled: true
  group-configs:
    - group: 'default'
      paths-to-match:
        - '\**'
      packages-to-scan:
        - com.flycode.flygenius.controller
knife4j:
  enable: true
  setting:
    language: zh_cn

前端配置

全局自定义请求

需要自定义全局请求地址等,参考Axios官方文档,编写请求配置文件request.ts。包括全局接口请求地址、超时时间、自定义请求响应拦截器等。

响应拦截器的应用场景:我们需要对接口的通用响应 进行统一处理,比如从response中取出data;或者根据code去集 中处理错误。这样不用在每个接口请求中都去写相同的逻辑。

比如可以在全局响应拦截器中,读取出结果中的data,并校验code是否合法,如果是未登录状态,则自动登录。

示例代码如下,其中 withCredentials: true 一定要写,否则无法在发请求时携带Cookie,就无法完成登录。

npm install axios

import axios from 'axios'
import { message } from 'ant-design-vue'

// 创建 Axios 实例
const myAxios = axios.create({
  baseURL: 'http://localhost:8100/api',
  timeout: 60000,
  withCredentials: true,
})

// 全局请求拦截器
myAxios.interceptors.request.use(
  function (config) {
    // Do something before request is sent
    return config
  },
  function (error) {
    // Do something with request error
    return Promise.reject(error)
  },
)

// 全局响应拦截器
myAxios.interceptors.response.use(
  function (response) {
    const { data } = response
    // 未登录
    if (data.code === 40100) {
      // 不是获取用户信息的请求,并且用户目前不是已经在用户登录页面,则跳转到登录页面
      if (
        !response.request.responseURL.includes('user/get/login') &&
        !window.location.pathname.includes('/user/login')
      ) {
        message.warning('请先登录')
        window.location.href = `/user/login?redirect=${window.location.href}`
      }
    }
    return response
  },
  function (error) {
    // Any status codes that falls outside the range of 2xx cause this function to trigger
    // Do something with response error
    return Promise.reject(error)
  },
)

export default myAxios

自动生成请求代码

安装openapi

npm i --save-dev @umijs/openapi
npm i --save-dev tslib

创建openapi2ts.config.ts,配置后端地址和生成文件位置

export default {
  requestLibPath: "import request from '@/request'",
  schemaPath: 'http://localhost:8100/api/v3/api-docs',
  serversPath: './src',
}

需要确保package和openapi2ts.config.ts在同一个目录下,不然需要加上对应的文件夹 package.json添加

"openapi2ts": "openapi2ts"

如果是ts环境,生成的代码会报错,但是不影响运行。可以在tsconfig.json中修改

{
  "files": [],
  "compilerOptions": {
    "target": "esnext",
    "module": "esnext",
    "moduleResolution": "node",
    "strict": true,
    "jsx": "preserve",
    "sourceMap": true,
    "resolveJsonModule": true,
    "esModuleInterop": true,
    "skipLibCheck": true,
    "baseUrl": ".",
    "paths": {
      "@/*": [
        "src/*"
      ]
    }
  },
  "include": [
    "src/**/*.ts",
    "src/**/*.tsx",
    "src/**/*.vue"
  ],
  "references": [
    {
      "path": "./tsconfig.node.json"
    },
    {
      "path": "./tsconfig.app.json"
    }
  ]
}

贡献者

  • flycodeuflycodeu

公告板

2025-03-04正式迁移知识库到此项目