本文将从零开始搭建一个 springboot-starter-kit 脚手架项目,以支持当前主流的前后端分离架构,开箱即用,快速开发!
模块分层
api(controller) –> service –> mapper(dao) –> pojo(entity) –> common
logback 日志处理
在 api 模块的 resources 目录下创建 logback-spring.xml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104
| <?xml version="1.0" encoding="UTF-8"?> <configuration>
<springProperty scope="context" name="logback.dir" source="logging.logback.dir"/>
<conversionRule conversionWord="clr" converterClass="org.springframework.boot.logging.logback.ColorConverter"/> <conversionRule conversionWord="wex" converterClass="org.springframework.boot.logging.logback.WhitespaceThrowableProxyConverter"/> <conversionRule conversionWord="wEx" converterClass="org.springframework.boot.logging.logback.ExtendedWhitespaceThrowableProxyConverter"/>
<property name="CONSOLE_LOG_PATTERN" value="${CONSOLE_LOG_PATTERN:-%clr(%d{${LOG_DATEFORMAT_PATTERN:-HH:mm:ss.SSS}}){faint} %clr(${LOG_LEVEL_PATTERN:-%5p}) %clr(${PID:- }){magenta} %clr(-){faint} %clr([%13.13t]){faint} %clr(%-40.40logger{39}){cyan} %clr(:){faint} %m%n${LOG_EXCEPTION_CONVERSION_WORD:-%wEx}}"/> <property name="FILE_LOG_PATTERN" value="${FILE_LOG_PATTERN:-%d{${LOG_DATEFORMAT_PATTERN:-yyyy-MM-dd HH:mm:ss.SSS}} ${LOG_LEVEL_PATTERN:-%5p} ${PID:- } - [%13.13t] %-40.40logger{39} : %m%n${LOG_EXCEPTION_CONVERSION_WORD:-%wEx}}"/>
<appender name="consoleLog" class="ch.qos.logback.core.ConsoleAppender"> <layout class="ch.qos.logback.classic.PatternLayout"> <pattern> ${CONSOLE_LOG_PATTERN} </pattern> </layout> <filter class="ch.qos.logback.classic.filter.ThresholdFilter"> <level>INFO</level> </filter> </appender>
<appender name="fileInfoLog" class="ch.qos.logback.core.rolling.RollingFileAppender">
<filter class="ch.qos.logback.classic.filter.LevelFilter"> <level>ERROR</level> <onMatch>DENY</onMatch> <onMismatch>ACCEPT</onMismatch> </filter>
<File>${logback.dir}/info.log</File> <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"> <FileNamePattern>${logback.dir}/info.%d{yyyy-MM-dd}.log</FileNamePattern> <maxHistory>90</maxHistory> </rollingPolicy> <encoder> <charset>UTF-8</charset> <pattern>${FILE_LOG_PATTERN}</pattern> </encoder> </appender>
<appender name="fileErrorLog" class="ch.qos.logback.core.rolling.RollingFileAppender"> <filter class="ch.qos.logback.classic.filter.ThresholdFilter"> <level>Error</level> </filter>
<File>${logback.dir}/error.log</File> <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"> <FileNamePattern>${logback.dir}/error.%d{yyyy-MM-dd}.log</FileNamePattern> <maxHistory>90</maxHistory> </rollingPolicy> <encoder> <charset>UTF-8</charset> <pattern>${FILE_LOG_PATTERN}</pattern> </encoder> </appender>
<root level="INFO"> <appender-ref ref="consoleLog"/> <appender-ref ref="fileInfoLog"/> <appender-ref ref="fileErrorLog"/> </root>
</configuration>
|
在 application.yml 中添加日志根目录
1 2 3
| logging: logback: dir: /Users/zhanghao/data/springboot-starter-kit/log
|
统一响应对象
异常对象枚举
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| package org.example.common.enums;
public enum RetEnum {
OK(200, "成功"), BAD_REQUEST(400, "参数错误"), UNAUTHORIZED(401, "您未登录或您的登录信息已过期,请重新登录"), FORBIDDEN(403, "您没有该权限"), NOT_FOUND(404, "您请求的资源未找到"), SERVER_ERROR(500, "服务器异常"), ;
public final int code; public final String msg;
RetEnum(int code, String msg) { this.code = code; this.msg = msg; } }
|
统一响应对象
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67
| package org.example.common;
import lombok.Data; import lombok.experimental.Accessors; import org.example.common.enums.RetEnum;
import java.io.Serializable;
@Data @Accessors(chain = true) public class Ret implements Serializable {
private static final long serialVersionUID = 2665482313176083754L;
private int code; private String msg; private Object data;
public static Ret ok() { return new Ret().setCode(RetEnum.OK.code).setMsg(RetEnum.OK.msg); }
public static Ret ok(Object data) { return Ret.ok().setData(data); }
public static Ret fail(int code, String msg) { return new Ret().setCode(code).setMsg(msg); }
public static Ret fail(String msg) { return Ret.fail(RetEnum.BAD_REQUEST.code, msg); }
public static Ret fail(RetEnum retEnum) { return Ret.fail(retEnum.code, retEnum.msg); }
public static Ret badRequest() { return Ret.fail(RetEnum.BAD_REQUEST); }
public static Ret unauthorized() { return Ret.fail(RetEnum.UNAUTHORIZED); }
public static Ret forbidden() { return Ret.fail(RetEnum.FORBIDDEN); }
public static Ret notFound() { return Ret.fail(RetEnum.NOT_FOUND); }
public static Ret serverError() { return Ret.fail(RetEnum.SERVER_ERROR); }
}
|
业务异常类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
| package org.example.common.exception;
public class ServiceException extends RuntimeException {
private static final long serialVersionUID = -3287961933635362725L;
public ServiceException(String message) {
super(message, null, false, false); }
}
|
全局异常处理
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46
| package org.example.api.configuration;
import lombok.extern.slf4j.Slf4j; import org.example.common.Ret; import org.example.common.exception.ServiceException; import org.springframework.web.bind.annotation.ControllerAdvice; import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.bind.annotation.ResponseBody;
@Slf4j @ControllerAdvice public class ExceptionConfiguration {
@ExceptionHandler(ServiceException.class) @ResponseBody public Ret handler(ServiceException e) { log.info(e.getMessage(), e); return Ret.fail(e.getMessage()); }
@ExceptionHandler(Exception.class) @ResponseBody public Ret handler(Exception e) { log.error(e.getMessage(), e); return Ret.serverError(); }
}
|
全局请求响应参数及耗时记录
异步调用处理
Redis 整合及序列化处理
Knife4j 接口文档整合