2021-12-25 Обновление
- Этот проект был загружен на центральный склад, добро пожаловать в использование
<dependency>
<groupId>io.github.chenxuancode</groupId>
<artifactId>base</artifactId>
<version>1.0.0-Release</version>
</dependency>
- Быстро создать проект: выполните следующую команду, чтобы быстро создать проект Springboot, содержащий функции этого проекта.
mvn archetype:generate -DarchetypeGroupId=io.github.chenxuancode -DarchetypeArtifactId=archetype -DarchetypeVersion=1.0.0-Release -DgroupId=io.github.chenxuancode -DartifactId=demo -Dport=8888
Tip:
DgroupId修改为你的groupId,DartifactId修改为你项目的artifactId
命令控制台会确认你项目的groupId、artifactId等信息,如无需修改回车确认即可
- Код этого проекта обновлен доGitHub.com/Chen Xuan код…
last: Отзывы и предложения приветствуются!!!Нелегко кодировать слова, пожалуйста, поставьте лайк и подпишитесь на звездочку~~~
-------------------------------------------------- -----------------------сегментация
текст
При разработке зрелого проекта базовый пакет будет предоставлять некоторые общие функциональные компоненты проекта, чтобы избежать повторения колес для каждого проекта. Этот проект включает в себя основные функции, обычно используемые при разработке проектов Springboot.Единое управление зависимостями,Обработка исключений,Упаковка ответного сообщения,Единое управление журналами,Шифрование и дешифрование конфиденциальных данныхи другие функции. Поддерживайте подключаемый режим, пока вводятся зависимости, доступны вышеуказанные функции.
Вот как это сделать~~~
Единое управление зависимостями
Объединение некоторых часто используемых зависимостей в базовый пакет может облегчить последующее управление компонентами (обновление или исправление ошибок и т.д.) Принцип зависимостей компонентов в базовом пакете - стабильность и минимум зависимостей. В настоящее время в базу входят следующие компоненты, в основном отвечающие основным функциям, разработанным проектом springboot. Зависимости базовых пакетов каждого проекта управляются базой, и нужно вводить только базовый модуль, а пакеты функций вводятся самим каждым проектом. В текущий базовый пакет интегрированы общие базовые компоненты, такие как mybatis-plus swagger.
имя компонента | Версия |
---|---|
spring-boot-starter-validation | 2.3.12.RELEASE |
spring-boot-starter-web | 2.3.12.RELEASE |
spring-boot-starter-test | 2.3.12.RELEASE |
spring-boot-starter-aop | 2.3.12.RELEASE |
mysql-connector-java | 8.0.16 |
mybatis-plus | 3.4.0 |
springfox-swagger2 | 2.8.0 |
springfox-swagger-ui | 2.8.0 |
swagger-bootstrap-ui | 1.8.5 |
lombok | 1.18.20 |
hutool-all | 5.7.14 |
Обработка исключений
Определяется унифицированный глобальный обработчик исключений, который не поощряет захват исключений в бизнес-коде и выбрасывает все исключения на уровнях dao, службы и контроллера на верхний уровень.try-catch对业务代码的侵入性
Если вам нужно вернуть указанное сообщение об ошибке интерфейса, вы можете напрямую создать пользовательское исключение.AiException
throw new ApiException("两次密码输入不一致");
Принцип реализации
использовать@RestControllerAdvice
Включите захват глобальных исключений и настройте метод для использованияExceptionHandler
Аннотируйте, а затем определите тип захваченных исключений для единообразной обработки этих захваченных исключений.
@Slf4j
@RestControllerAdvice
public class ExceptionControllerAdvice {
@ExceptionHandler(ApiException.class)
public ResultVO<String> apiExceptionHandler(ApiException e) {
log.error("接口请求异常:{}{}",e.getResultCode(),e.getMsg());
return new ResultVO<>(e.getResultCode(), e.getMsg());
}
@ExceptionHandler
public ResultVO unknownException(Exception e) {
log.error("发生了未知异常", e);
return new ResultVO<>(ResultCode.ERROR, "系统出现错误, 请联系网站管理员!");
}
@ExceptionHandler(MethodArgumentNotValidException.class)
public ResultVO<String> methodArgumentNotValidExceptionHandler(MethodArgumentNotValidException e) {
// 从异常对象中拿到ObjectError对象
ObjectError objectError = e.getBindingResult().getAllErrors().get(0);
return new ResultVO<>(ResultCode.VALIDATE_FAILED, objectError.getDefaultMessage());
}
}
Другие исключения, не созданные явно, автоматически распознаются внешним обработчиком исключений как неизвестные ошибки и возвращаются во внешний интерфейс.
обработка журнала
В проектах Springboot компоненты журнала обычно используются для управления журналом. Тогда, если каждый сервис будет писать свой конфигурационный файл логбэка, это неизбежно приведет к различным форматам логов и путям логов, которыми сложно управлять, поэтому обработка логов передана в базовый пакет для унифицированной обработки. Обычно при обработке журналов необходимо учитывать несколько моментов: как распечатывать журналы, как разделять журналы и управлять ими, а также как собирать журналы.
Печать входящего и исходящего журнала
Используйте @WebLog в методе контроллера, чтобы распечатать сообщение ответа на запрос.
@PostMapping("/register")
@ApiOperation(value = "注册")
@WebLog
public String register(@RequestBody @Validated RegisterParam param) {
userService.register(param);
return "操作成功";
}
Принцип реализации
Определение аспекта журналаLogAspect
,
public class LogAspect {
@Pointcut("@annotation(com.sleeper.common.base.annotate.WebLog)")
public void webLog() {}
@Before("webLog()")
public void doBefore(JoinPoint joinPoint) throws Throwable {
ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
HttpServletRequest request = attributes.getRequest();
log.info("IP:{} Class Method:{}.{} Request Args: {}",request.getRemoteAddr(),joinPoint.getSignature().getDeclaringTypeName(), joinPoint.getSignature().getName(), new Gson().toJson(joinPoint.getArgs()));
}
@Around("webLog()")
public Object doAround(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
long startTime = System.currentTimeMillis();
Object result = proceedingJoinPoint.proceed();
log.info("Response Args : {} Time-Consuming : {} ms", new Gson().toJson(result),System.currentTimeMillis() - startTime);
return result;
}
}
WebLog
аннотация
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD})
@Documented
public @interface WebLog {
}
сохранение журнала разделения
Разделение и сохранение журнала настраивается с помощью logback. Текущий журнал разделен на журналы ошибок и обычные журналы. Каждый тип файла разделен по дням. Файлы журнала, превышающие 200M в этот день, разделяются путем увеличения числа в имени файла. правила следующие${LOG_ERROR_HOME}/${springAppName}-%d{yyyy-MM-dd}.%i.log ${LOG_INFO_HOME}/${springAppName}-%d{yyyy-MM-dd}.%i.log
|
использоватьAsyncAppender
Журнал выводится в виде асинхронного вывода. Полный журнал журналов см.:
отслеживание ссылок
В настоящее время отслеживание ссылок реализовано через MDC. MDC является важным инструментом для реализации распределенной многопоточной передачи данных журнала в системах журнала, подобных Slf4J. MDC можно использовать для печати некоторых данных контекста времени выполнения. Для ознакомления с MDC см.nuggets.capable/post/690122…
Принцип реализацииПерехватите запрос через перехватчик, сгенерируйте traceId и установите его в THreadLocalMap через интерфейс ввода MDC.
public class LogInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
String traceId = request.getHeader("traceId");
if (traceId == null) {
traceId = IdUtil.getSnowflake().nextIdStr();
}
MDC.put("traceId", traceId);
return true;
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView)
throws Exception {
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
throws Exception {
MDC.remove("TRACE_ID");
}
Добавьте %X{traceId} в logback-spring.xml.
<property name="PATTERN" value="%red(%d{yyyy-MM-dd HH:mm:ss.SSS}) %X{traceId} %yellow(%-5level) %highlight([%t]) %boldMagenta([%C]).%green(%method[%L]): %m%n"/>
Автоматическая инкапсуляция ответного сообщения
Обычно интерфейс нужно возвращать по определенной структуре, включая кодировку результата обработки сервиса, текстовую информацию, соответствующую кодировке, возвращаемое значение и т.д.@RestControllerAdvice
Enhance Controller для реализации автоматической инкапсуляции ответных сообщений
@RestControllerAdvice("com.sleeper")
public class ResponseControllerAdvice implements ResponseBodyAdvice<Object> {
@Override
public boolean supports(MethodParameter returnType, Class<? extends HttpMessageConverter<?>> aClass) {
// 如果接口返回的类型本身就是ResultVO那就没有必要进行额外的操作,返回false
return !returnType.getParameterType().equals(ResultVO.class) || returnType.hasMethodAnnotation(NotResponseWrap.class);
}
@Override
public Object beforeBodyWrite(Object data, MethodParameter returnType, MediaType mediaType, Class<? extends HttpMessageConverter<?>> aClass, ServerHttpRequest request, ServerHttpResponse response) {
// String类型不能直接包装,所以要进行些特别的处理
if (returnType.getGenericParameterType().equals(String.class)) {
ObjectMapper objectMapper = new ObjectMapper();
try {
// 将数据包装在ResultVO里后,再转换为json字符串响应给前端
return objectMapper.writeValueAsString(new ResultVO<>(data));
} catch (JsonProcessingException e) {
throw new ApiException("返回String类型错误");
}
}
// 将原本的数据包装在ResultVO里
return new ResultVO<>(data);
}
}
Для интерфейсов, которые не хотят автоматически инкапсулировать результат, используйте аннотации@NotResponseWrap
поставить отметку на методе
Шифрование и дешифрование конфиденциальных данных
Иногда в процессе разработки необходимо зашифровать определенные данные, такие как номера мобильных телефонов, идентификационные номера и другие данные, когда они хранятся в базе данных, чтобы предотвратить утечку данных. Этот базовый пакет обеспечивает@SensitiveData
(действуя на КЛАССЕ)@SensitiveField
(Он действует на FEILD для реализации операций шифрования и дешифрования, просто добавьте объект объекта данных@SensitiveData
Примечания в конфиденциальных полях плюс@SensitiveField
Могут быть реализованы операции шифрования и дешифрования конфиденциальных данных.
@Data
@SensitiveData
public class SysUser implements Serializable {
private static final long serialVersionUID = 1L;
@TableId(value = "id", type = IdType.AUTO)
private String id;
@SensitiveField
private String mobile;
}
Принцип реализации
Переписать перехватчик mybatisResultSetHandler.handleResultSets
ParameterHandler.setParameters
метод, который идентифицирует аннотации и шифрует поля с помощью AES при настройке параметров запроса, а также идентифицирует аннотации и расшифровывает поля с помощью AES при получении наборов результатов.Подробнее см.GitHub.com/Chen Xuan код…
изящное завершение работы
Если нет корректного завершения работы, сервер в это время отключается напрямую (kill -9), что приведет к прямому сбою бизнеса, работающего в данный момент в контейнере, и созданию грязных данных в некоторых особых сценариях. При включенном изящном завершении работы, когда веб-контейнер завершает работу, веб-сервер больше не будет получать запросы и будет ожидать завершения буфера активных запросов.
Принцип реализацииВерсия Spring Boot 2.3, используемая базовым пакетом, имеет эту встроенную функцию, и нет необходимости расширять пул потоков контейнера для ее обработки. все приложения поддерживают функцию плавного выключения, нужно только настроитьserver.shutdown=graceful
.
Этот базовый пакет по умолчанию включает функцию плавного завершения работы.SPI
Механизм выполняет внедрение конфигурации в службу и объединяет сценарии последующего развертывания для унифицированного управления корректным завершением работы службы.
@Configuration
public class ShutDownConfig {
@Autowired
ServerProperties serverProperties;
@Autowired
LifecycleProperties lifecycleProperties;
@Bean
public void setShutDownConfig() {
serverProperties.setShutdown(Shutdown.GRACEFUL);
lifecycleProperties.setTimeoutPerShutdownPhase(Duration.ofSeconds(20));
}