🎶 文章简介:木字楠后台管理系统(1):SpringBoot项目初始化并引入基础文件
💡 创作目的:为了带大家完整的体验木字楠后台管理系统模版的开发流程
☀️ 今日天气:天气☁️很好。太阳晒在身上暖暖的
📝 每日一言:多情却被无情恼,今夜还如昨夜长。
🚗 1、新建一个SpringBoot项目
- 使用IDEA编辑器新建一个 SpringBoot 项目
- 项目名称自定义(eg:MuZiNan-Template)
- Jdk 版本使用 1.8 的版本
- SpringBoot版本选择默认,创建成功之后会在 pom文件 中修改为 2.5.5 版本
- 依赖引入选择Web依赖即可
这样我们就已经成功新建了一个SpringBoot项目了。
接下来我们对SpriingBoot 的部分配置信息进行修改。
- SpringBoot 版本
- 项目基础描述信息(版本、描述信息大家可自定定义)
🚕 2、项目结构完善
🚙 2-1、基础依赖引入
首先我们需要引入项目中所必须的一些基础依赖,eg: Mysql 、Lombok、FastJson…
<!--============== 项目版本号规定 ===============-->
<properties>
<java.version>1.8</java.version>
<!--============== 数据库依赖 ==================-->
<mysql.version>8.0.29</mysql.version>
<!--============== 工具依赖 ==================-->
<lombok.version>1.18.24</lombok.version>
<fastjson.version>2.0.7</fastjson.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!--================== 数据库依赖 =======================-->
<!-- mysql8 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>${mysql.version}</version>
</dependency>
<!--================== 工具依赖 =======================-->
<!--Lombok-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>${lombok.version}</version>
</dependency>
<!-- 阿里JSON解析器 -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>${fastjson.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
🏎️ 2-2、常用结果枚举类
在项目中经常会返回一些统一的结果(比如:操作成功,操作失败…),我们可以将这些信息定义在常用的枚举类中,方便后续使用。我们的常用结果枚举类也会结合结果集处理器、自定义异常类、全局异常处理类进行使用。
注意:枚举类中不需要setter方法,我们仅提供getter方法即可。
/**
* @author 木字楠
* @version 1.0
* @date 2022/11/24
* @description 常用结果枚举类
*/
@Getter
@AllArgsConstructor
public enum HttpCodeEnum {
//==================== 登录相关枚举 ======================
/**
* 登陆超时
*/
USER_LOGIN_TIME_OUT(100, "登陆超时"),
/**
* 用户未登录
*/
USER_NOT_LOGIN(101, "用户未登录,请先进行登录"),
/**
* 账户被禁用,请联系管理员解决
*/
ACCOUNT_IS_DISABLED(102, "账户被禁用,请联系管理员解决"),
/**
* 用户信息加载失败
*/
USER_INFO_LOAD_FAIL(103, "用户信息加载失败"),
/**
* 用户身份信息获取失败
*/
USER_IDENTITY_LOAD_FAIL(104, "用户身份信息获取失败"),
/**
* 用户名不能为空
*/
USERNAME_CAN_NOT_BE_EMPTY(105, "用户名不能为空"),
/**
* 用户名或密码错误
*/
USERNAME_OR_PASSWORD_ERROR(106, "用户名或密码错误"),
/**
* 用户登录成功
*/
USER_LOGIN_SUCCESS(108, "用户登录成功"),
/**
* 用户注销成功
*/
USER_LOGOUT_SUCCESS(109, "用户注销成功"),
//==================== 注册相关枚举 ======================
/**
* 验证码错误
*/
CAPTCHA_ERROR(300, "验证码错误"),
/**
* 验证码过期
*/
CAPTCHA_ALREADY_EXPIRE(301, "验证码已过期"),
/**
* 用户名已存在
*/
USERNAME_ALREADY_EXISTED(302, "用户名已存在"),
/**
* 参数格式不合法
*/
PARAMETER_VALID_ERROR(600, "参数格式不合法"),
//======================= 其他枚举 ==============================
/**
* 没有权限
*/
PERMISSION_NOT_DEFINED(403, "您没有操作权限"),
/**
* 操作成功
*/
OPERATOR_IS_SUCCESS(200, "操作成功"),
/**
* 操作失败
*/
OPERATOR_IS_FAILED(500, "操作失败"),
/**
* 未知异常
*/
UNKNOWN_ERROR(600, "未知异常");
/**
* 状态码
*/
private final int code;
/**
* 返回信息
*/
private final String message;
}
🚐 2-3、统一结果集处理类
在前后端分离项目中,前端开发同学 与 后端开发同学 会约定好接口返回结果的数据结构。这样方便前端开发童鞋对于网络请求结果的判断以及设置统一的数据接受方式。
至于这里使用到了泛型,这是为了方便返回data数据类型的规定,当我们所需要的返回对象是什么类型,只需要提前规定即可。
但是我们也会发现一个问题,我们的统一结果集处理类确实可以返回对象数据和列表数据,但是返回的结果中没有总条数数据,这样对我们进行分页查询时就会很麻烦,所以我又新增了一个分页结果处理类。
# 本项目中呢我们所约定的数据结构如下:
{
code: 200,
success: true,
message: "返回提示信息",
data:{}
}
/**
* @author: MuZiNan
* @createDate: 2022/11/24
* @description: 统一结果集处理器
* @version: 1.0
*/
@Data
public class ResponseResult<T> {
/**
* 请求状态
*/
private Boolean success;
/**
* 状态码
*/
private Integer code;
/**
* 状态信息
*/
private String message;
/**
* 数据信息
*/
private T data;
/**
* 私有构造
*
* @param success 请求状态
* @param code 状态码
* @param message 状态信息
* @param data 数据
* @param <T> 泛型数据
* @return 结果集处理器
*/
private static <T> ResponseResult<T> response(Boolean success, Integer code, String message, T data) {
ResponseResult<T> result = new ResponseResult<>();
result.setSuccess(success);
result.setCode(code);
result.setMessage(message);
result.setData(data);
return result;
}
/**
* 请求成功返回(一)
*
* @param code 状态码
* @param message 状态信息
* @param data 数据
* @param <T> 泛型数据
* @return 结果集处理器
*/
public static <T> ResponseResult<T> success(Integer code, String message, T data) {
return response(true, code, message, data);
}
/**
* 请求成功返回(二)
*
* @param message 状态信息
* @param data 数据
* @param <T> 泛型数据
* @return 结果集处理器
*/
public static <T> ResponseResult<T> success(String message, T data) {
return response(true, HttpCodeEnum.OPERATOR_IS_SUCCESS.getCode(), message, data);
}
/**
* 请求成功返回(三)
*
* @param message 状态信息
* @param <T> 泛型数据
* @return 结果集处理器
*/
public static <T> ResponseResult<T> success(String message) {
return response(true, HttpCodeEnum.OPERATOR_IS_SUCCESS.getCode(), message, null);
}
/**
* 请求成功返回(四)
*
* @param httpCodeEnum 状态枚举
* @param <T> 泛型数据
* @return 结果集处理器
*/
public static <T> ResponseResult<T> success(HttpCodeEnum httpCodeEnum) {
return response(true, httpCodeEnum.getCode(), httpCodeEnum.getMessage(), null);
}
/**
* 请求成功返回(五)
*
* @param httpCodeEnum 状态枚举
* @param data 数据
* @param <T> 泛型数据
* @return 结果集处理器
*/
public static <T> ResponseResult<T> success(HttpCodeEnum httpCodeEnum, T data) {
return response(true, httpCodeEnum.getCode(), httpCodeEnum.getMessage(), data);
}
/**
* 请求成功返回(六)
* @param data 数据
* @return 结果集处理器
* @param <T> 泛型数据
*/
public static <T> ResponseResult<T> success( T data) {
return response(true, HttpCodeEnum.OPERATOR_IS_SUCCESS.getCode(),HttpCodeEnum.OPERATOR_IS_SUCCESS.getMessage(), data);
}
/**
* 请求失败返回(一)
*
* @param code 状态码
* @param message 状态信息
* @param data 数据
* @param <T> 泛型数据
* @return 结果集处理器
*/
public static <T> ResponseResult<T> fail(Integer code, String message, T data) {
return response(false, code, message, data);
}
/**
* 请求失败返回(二)
*
* @param message 状态信息
* @param data 数据
* @param <T> 泛型数据
* @return 结果集处理器
*/
public static <T> ResponseResult<T> fail(String message, T data) {
return response(false, HttpCodeEnum.OPERATOR_IS_FAILED.getCode(), message, data);
}
/**
* 请求失败返回(三)
*
* @param message 状态信息
* @param <T> 泛型数据
* @return 结果集处理器
*/
public static <T> ResponseResult<T> fail(String message) {
return response(false, HttpCodeEnum.OPERATOR_IS_FAILED.getCode(), message, null);
}
/**
* 请求失败返回(四)
*
* @param httpCodeEnum 状态枚举
* @param <T> 泛型数据
* @return 结果集处理器
*/
public static <T> ResponseResult<T> fail(HttpCodeEnum httpCodeEnum) {
return response(false, httpCodeEnum.getCode(), httpCodeEnum.getMessage(), null);
}
}
分页结果处理类也是用到了泛型,效果同上。当我们需要处理分页查询的时候可以将PageResult整个对象返回出去即可。
/**
* @author 木字楠
* @version 1.0
* @description 分页结果处理类
* @date 2022/11/24
*/
@Data
@AllArgsConstructor
public class PageResult<T> {
/**
* 总数据量
*/
private long totalCount;
/**
* 数据列表
*/
private List<T> dataList;
}
🚌 2-4、统一异常处理类
统一异常处理的目的是为了防止直接将后台的报错信息返回给前端,这样对于前端的同学并不友好,而且对于后端同学的排错也不方便。
- 自定义异常类
- 全局异常处理类
/**
* @author 木字楠
* @version 1.0
* @date 2022/11/24
* @description 基础异常处理类
*/
@Getter
public class BaseException extends RuntimeException {
/**
* 状态码
*/
private final Integer code;
/**
* 报错信息
*/
private final String message;
/**
* 全参构造方法
*
* @param code 状态码
* @param message 报错信息
*/
public BaseException(Integer code, String message) {
this.code = code;
this.message = message;
}
/**
* 构造方法
*
* @param message 报错信息
*/
public BaseException(String message) {
this(HttpCodeEnum.OPERATOR_IS_FAILED.getCode(), message);
}
/**
* 构造方法
* @param httpCodeEnum http枚举类
*/
public BaseException(HttpCodeEnum httpCodeEnum) {
this(httpCodeEnum.getCode(), httpCodeEnum.getMessage());
}
}
统一异常信息处理类:
- 被**@RestControllerAdvice**注解可以使用 @ExceptionHandler,@InitBinder和@ModelAttribute这些注解
- **@ExceptionHandler(Exception.class)**可以捕获到所传入的异常类型,例如NullPointerException、FileNotFoundException等异常(比如下述代码中,第一个可以捕获所有的异常,Exception是所有异常的父类。第二个尽可以捕获BaseException类型的异常)
- 捕获到异常之后我们选择使用统一结果集类进行返回提示系统出现异常
/**
* @author: MuZiNan
* @createDate: 2022/11/24
* @description: 统一异常信息处理
* @version: 1.0
*/
@Slf4j
@RestControllerAdvice
public class GlobalException {
/**
* 全局异常处理
*
* @param e 异常信息
* @return 错误信息
*/
@ExceptionHandler(Exception.class)
public ResponseResult<?> globalException(Exception e) {
log.error("异常信息 => {}", e.getMessage());
e.printStackTrace();
return ResponseResult.fail(HttpCodeEnum.OPERATOR_IS_FAILED.getMessage());
}
/**
* 基础异常处理
*
* @param baseException 基础异常信息类
* @return 错误结果
*/
@ExceptionHandler(BaseException.class)
public ResponseResult<?> baseException(BaseException baseException) {
log.error("异常信息 => {}", baseException.getMessage());
return ResponseResult.fail(baseException.getMessage());
}
}
🚎 2-5、统一日志信息处理
我们这里使用Log4j2来进行日志的打印,首先我们引入Log4fj2的依赖,因为我们的父工程是springboot项目,不设置版本默认使用父工程的版本(即:2.5.5版本)
<!--============== SpringBoot相关依赖 ===============-->
<!-- web -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- Log4j2 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-log4j2</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
我们需要在resources目录下引入 log4j2.xml 文件,大家默认使用如下内容即可。(切记 文件名称不能输错必须为log4j2.xml )
<?xml version="1.0" encoding="UTF-8"?>
<!-- status:用来指定log4j本身的打印日志级别,monitorInterval:指定log4j自动重新配置的监测间隔时间 -->
<configuration status="WARN" monitorInterval="30">
<!-- 自己设置属性,后面通过${}来访问 -->
<properties>
<!--<property name="LOG_HOME">${web:rootDir}/logs</property>-->
<property name="LOG_HOME">/opt/logs</property>
<!--日志名称-->
<property name="LOG_NAME">nanjustar-server-logs</property>
<!--日志格式-->
<property name="LOG_FORMAT">[%d{yyyy-MM-dd HH:mm:ss.SSS}] %p %t %c[%L] - %m %n</property>
<property name="LOG_FORMAT_CONSOLE">%d{yyyy-MM-dd HH:mm:ss.SSS} %highlight{%-5level} [%t] %highlight{%c{1.}.%M(%L)}: %msg%n%throwable</property>
<!--备份目录- 根据年月建立文件夹 -->
<property name="BACKUP_HOME">${LOG_HOME}/$${date:yyyy-MM}</property>
<!--备份频率-->
<property name="BACK_HZ">%d{yyyy-MM-dd}</property>
</properties>
<appenders>
<!--控制台日志-->
<console name="console" target="SYSTEM_OUT">
<!--输出日志的格式-->
<PatternLayout pattern="${LOG_FORMAT_CONSOLE}" disableAnsi="false" noConsoleNoAnsi="false"/>
</console>
</appenders>
<loggers>
<!--根日志配置-->
<root level="info">
<appender-ref ref="console"/>
<appender-ref ref="infoLog"/>
<appender-ref ref="warnLog"/>
<appender-ref ref="errorLog"/>
</root>
</loggers>
</configuration>
引入之后我们会发现项目启动的时候会出现依赖冲突的问题,这是由于Springboot web模块自带logback与log4j2冲突问题及配置,解决方法呢是我们将web模块中的logback模块进行排除,不再使用web模块中的logback。
排除需要使用到
<exclusions></exclusions>
<!--============== SpringBoot相关依赖 ===============-->
<!-- web -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<exclusions>
<exclusion>
<artifactId>logback-classic</artifactId>
<groupId>ch.qos.logback</groupId>
</exclusion>
<exclusion>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-to-slf4j</artifactId>
</exclusion>
</exclusions>
</dependency>
至此,我们的基础配置已经全部完成。