springboot项目脚手架
序言
根据以下上版本,搭建springboot项目,集成mybatis,统一异常处理,日志打印,响应体
- springboot 2.7.1
- jdk1.8
- mybatis2.3.0
- druid1.1.13
- mysql8
- 开发工具 idea
1.idea 新建springboot项目
2 maven依赖
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.7.1</version>
<relativePath/>
</parent>
<groupId>com.gz</groupId>
<artifactId>gz-login-spring-boot-starter</artifactId>
<version>1.0.0-SNAPSHOT</version>
<name>gz-login-spring-boot-starter</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
<mybatis.version>2.3.0</mybatis.version>
<druid-version>1.1.13</druid-version>
<aspectj.version>1.9.6</aspectj.version>
<commons-lang3.version>3.12.0</commons-lang3.version>
<pageHelper-version>5.2.0</pageHelper-version>
<lombok-version>1.18.24</lombok-version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>${mybatis.version}</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>${druid-version}</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>${aspectj.version}</version>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>${commons-lang3.version}</version>
</dependency>
<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper</artifactId>
<version>${pageHelper-version}</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>${lombok-version}</version>
<scope>compile</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.mybatis.generator</groupId>
<artifactId>mybatis-generator-maven-plugin</artifactId>
<version>1.3.7</version>
<configuration>
<configurationFile>
src/main/resources/mapper/generatorConfig.xml
</configurationFile>
<overwrite>true</overwrite>
<verbose>true</verbose>
</configuration>
<dependencies>
<!-- mysql的JDBC驱动 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.29</version>
</dependency>
</dependencies>
</plugin>
</plugins>
</build>
</project>
3.项目结构
4.统一异常处理
package com.gz.gzloginspringbootstarter.exception;
import com.gz.gzloginspringbootstarter.pojo.webRes.WebResponse;
import com.gz.gzloginspringbootstarter.pojo.webRes.WebResponseBuilder;
import com.gz.gzloginspringbootstarter.pojo.enums.WebResponseEnum;
import lombok.extern.slf4j.Slf4j;
import org.springframework.validation.ObjectError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import java.net.SocketTimeoutException;
/**
* @author GZ
* 全局异常
*/
@RestControllerAdvice
@Slf4j
public class GlobalExceptionHandlerAdvice {
@ExceptionHandler(MethodArgumentNotValidException.class)
public WebResponse methodArgumentNotValidException(MethodArgumentNotValidException e) {
log.error("method argument not valid exception:", e);
ObjectError objectError = e.getBindingResult().getFieldError();
return WebResponseBuilder.fail(WebResponseEnum.PARAMETER_INVALID.getCode(), objectError.getDefaultMessage());
}
@ExceptionHandler(IllegalArgumentException.class)
public WebResponse illegalArgumentException(IllegalArgumentException e) {
log.error("illegal argument exception:", e);
return WebResponseBuilder.fail(WebResponseEnum.PARAMETER_INVALID.getCode(), e.getMessage());
}
@ExceptionHandler(SocketTimeoutException.class)
public WebResponse socketTimeoutException(SocketTimeoutException e) {
log.error("socket timeout exception:", e);
return WebResponseBuilder.fail(WebResponseEnum.CONNECT_TIMEOUT.getCode(), WebResponseEnum.CONNECT_TIMEOUT.getMsg());
}
@ExceptionHandler(ServiceException.class)
public WebResponse serviceException(ServiceException e) {
log.error("service exception:", e);
return WebResponseBuilder.fail(WebResponseEnum.INTERNAL_SERVER_ERROR.getCode(), e.getMessage());
}
@ExceptionHandler(Exception.class)
public WebResponse exception(Exception e) {
log.error("system error:", e);
return WebResponseBuilder.fail(WebResponseEnum.INTERNAL_SERVER_ERROR.getCode(), WebResponseEnum.INTERNAL_SERVER_ERROR.getMsg());
}
}
5.统一日志处理
package com.gz.gzloginspringbootstarter.interceptor;
import com.gz.gzloginspringbootstarter.util.JacksonUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.lang.reflect.Method;
/**
* @author GZ
* 请求参数拦截器打印
*/
@Component
@Aspect
@Slf4j
public class ParameterInterceptor {
/**
* Pointcut
*/
@Pointcut(value = "execution (* com.gz.gzloginspringbootstarter.controller.*.*(..))")
private void pointcut() {
}
/**
*
* @param proceedingJoinPoint
* @return
*/
@Around(value = "pointcut()")
public Object around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
if (log.isInfoEnabled()) {
Object[] args = proceedingJoinPoint.getArgs();
if (args.length == 0) {
return proceedingJoinPoint.proceed();
}
Signature sig = proceedingJoinPoint.getSignature();
MethodSignature methodSignature = (MethodSignature) sig;
Object target = proceedingJoinPoint.getTarget();
Method currentMethod = target.getClass().getMethod(methodSignature.getName(), methodSignature.getParameterTypes());
log.info("{}.{} request parameter is: {}",
currentMethod.getDeclaringClass().getName(),
currentMethod.getName(),
isFilter(args[0]) ? StringUtils.EMPTY : JacksonUtil.toJsonString(args[0]));
}
return proceedingJoinPoint.proceed();
}
/**
* Filter
*
* @param args
* @return
*/
private boolean isFilter(Object args) {
return args instanceof MultipartFile || args instanceof HttpServletRequest || args instanceof HttpServletResponse;
}
}
6.统一响应体
package com.gz.gzloginspringbootstarter.pojo.webRes;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* @author GuoZhong
* @description
* @date 2023/2/7 22:05
*/
@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class WebResponse<T> {
/**
* 响应码
*/
@JsonProperty
private String code;
/**
* 响应消息
*/
@JsonProperty
private String msg;
/**
* 是否处理成功
*/
@JsonProperty
private Boolean success = true;
/**
* 响应数据
*/
@JsonProperty
private T data;
}
package com.gz.gzloginspringbootstarter.pojo.webRes;
import com.gz.gzloginspringbootstarter.pojo.enums.WebResponseEnum;
import com.gz.gzloginspringbootstarter.pojo.webRes.WebResponse;
/**
* @author GuoZhong
* @description
* @date 2023/2/7 22:06
*/
public class WebResponseBuilder {
/**
* 构建处理成功请求
* @param data
* @param <T>
* @return
*/
public static <T> WebResponse success(T data){
WebResponseEnum success = WebResponseEnum.SUCCESS;
return WebResponse.builder().success(true).code(success.getCode())
.msg(success.getMsg()).data(data).build();
}
/**
* 构建处理成功请求
* @param code 响应代码
* @param msg 响应消息
* @param data 响应数据
* @return
*/
public static <T> WebResponse success(String code, String msg, T data){
return WebResponse.builder().success(true).code(code)
.msg(msg).data(data).build();
}
/**
* 构建处理失败请求
* @param
* @param <T>
* @return
*/
public static <T> WebResponse fail(){
WebResponseEnum fail = WebResponseEnum.FAIL;
return WebResponse.builder().success(false).code(fail.getCode())
.msg(fail.getMsg()).build();
}
/**
* 构建自定义参数的处理失败请求
* @param code 响应代码
* @param msg 响应消息
* @return
*/
public static <T> WebResponse fail(String code, String msg){
return WebResponse.builder().success(false).code(code)
.msg(msg).build();
}
}
package com.gz.gzloginspringbootstarter.pojo.enums;
import lombok.Getter;
/**
* @author GuoZhong
* @description
* @date 2023/2/7 22:07
*/
@Getter
public enum WebResponseEnum {
/**
* 处理成功
*/
SUCCESS("S00000","处理成功"),
/**
* 处理失败
*/
FAIL("E00001","处理失败"),
/**
* 请求参数错误
*/
PARAMETER_INVALID("E00400", "请求参数错误"),
/**
* 业务服务异常统一编码
*/
INTERNAL_SERVER_ERROR("E00010", "服务器内部错误"),
/**
* 服务不可用错误编码
*/
SERVICE_UNAVAILABLE("E00011", "服务不可用"),
/**
* 未知异常
*/
UNKNOWN("E00012", "未知异常!"),
/**
* 请求超时
*/
CONNECT_TIMEOUT("E00013", "请求超时");
private String code;
private String msg;
WebResponseEnum(String code, String msg){
this.code = code;
this.msg = msg;
}
}
7.application.yml
spring:
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://192.168.200.129:3306/login_auth?serverTimezone=GMT%2B8&useSSL=true
username: root
password: BUG150983
type: com.alibaba.druid.pool.DruidDataSource
druid:
initial-size: 5
min-idle: 5
max-active: 20
max-wait: 60000
time-between-eviction-runs-millis: 60000
min-evictable-idle-time-millis: 300000
mybatis:
mapper-locations: classpath:mapper/xml/ext/*.xml
configuration:
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
8.mybatis自动生成mapper 实体插件配置
generatorConfig.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE generatorConfiguration
PUBLIC "-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN"
"http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd">
<generatorConfiguration>
<!-- 数据库驱动:选择你的本地硬盘上面的数据库驱动包-->
<properties resource="mapper/generator.properties"/>
<context id="MyBatis" targetRuntime="MyBatis3">
<plugin type="org.mybatis.generator.plugins.UnmergeableXmlMappersPlugin"/>
<commentGenerator>
<property name="suppressDate" value="true"/>
<!-- 是否去除自动生成的注释 true:是 : false:否 -->
<property name="suppressAllComments" value="false"/>
</commentGenerator>
<!--数据库链接 URL,用户名、密码 -->
<jdbcConnection driverClass="${driverClass}" connectionURL="${connectionURL}"
userId="${userId}" password="${password}">
<!--解决连接到别的数据库表的问题-->
<property name="nullCatalogMeansCurrent" value="true"/>
</jdbcConnection>
<javaTypeResolver>
<property name="forceBigDecimals" value="false"/>
<property name="useJSR310Types" value="false"/>
</javaTypeResolver>
<!-- 生成模型的包名和位置-->
<javaModelGenerator targetPackage="com.gz.gzloginspringbootstarter.mapper.entity"
targetProject="src/main/java">
<property name="enableSubPackages" value="true"/>
<property name="trimStrings" value="true"/>
</javaModelGenerator>
<!-- 生成映射文件的包名和位置-->
<sqlMapGenerator targetPackage="mapper/xml"
targetProject="src/main/resources">
<property name="enableSubPackages" value="true"/>
</sqlMapGenerator>
<!-- 生成 DAO 的包名和位置-->
<javaClientGenerator type="XMLMAPPER" targetPackage="com.gz.gzloginspringbootstarter.mapper"
targetProject="src/main/java">
<property name="enableSubPackages" value="true"/>
</javaClientGenerator>
<!-- 要生成的表 tableName 是数据库中的表名或视图名 domainObjectName 是实体类名-->
<table tableName="t_account" domainObjectName="Account"
enableCountByExample="false"
enableUpdateByExample="false" enableDeleteByExample="false" enableSelectByExample="false"
selectByExampleQueryId="false">
</table>
</context>
</generatorConfiguration>
generator.properties
driverClass=com.mysql.cj.jdbc.Driver
connectionURL=jdbc:mysql://192.168.200.129:3306/login_auth
userId=root
password=BUG150983