项目结构调整 x 15 : 将 web、security、operatelog 等组件拆分出去

This commit is contained in:
YunaiV
2021-05-02 00:41:21 +08:00
parent 750ce01ecd
commit 20066bc864
151 changed files with 575 additions and 313 deletions

View File

@@ -13,6 +13,11 @@
<module>yudao-common</module>
<module>yudao-framework-all</module>
<module>yudao-spring-boot-starter-mybatis</module>
<module>yudao-spring-boot-starter-web</module>
<module>yudao-spring-boot-starter-security</module>
<module>yudao-spring-boot-starter-monitor</module>
<module>yudao-spring-boot-starter-protection</module>
<module>yudao-spring-boot-starter-operatelog</module>
</modules>
<artifactId>yudao-framework</artifactId>

View File

@@ -57,6 +57,12 @@
<scope>provided</scope> <!-- 设置为 provided主要是 PageParam 使用到 -->
</dependency>
<!-- 监控相关 -->
<dependency>
<groupId>org.apache.skywalking</groupId>
<artifactId>apm-toolkit-trace</artifactId>
</dependency>
<!-- 工具类相关 -->
<dependency>
<groupId>org.projectlombok</groupId>

View File

@@ -1,11 +1,13 @@
package cn.iocoder.dashboard.framework.web.core.enums;
package cn.iocoder.yudao.framework.common.enums;
/**
* 过滤器顺序的枚举类保证过滤器按照符合我们的预期
* Web 过滤器顺序的枚举类保证过滤器按照符合我们的预期
*
* 考虑到每个 starter 都需要用到该工具类所以放到 common 模块下的 util 包下
*
* @author 芋道源码
*/
public interface FilterOrderEnum {
public interface WebFilterOrderEnum {
int CORS_FILTER = Integer.MIN_VALUE;

View File

@@ -1,10 +1,12 @@
package cn.iocoder.dashboard.framework.tracer.core.util;
package cn.iocoder.yudao.framework.util.monitor;
import org.apache.skywalking.apm.toolkit.trace.TraceContext;
/**
* 链路追踪工具类
*
* 考虑到每个 starter 都需要用到该工具类所以放到 common 模块下的 util 包下
*
* @author 芋道源码
*/
public class TracerUtils {

View File

@@ -24,35 +24,7 @@
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
<!-- Web 相关 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>
<dependency>
<groupId>com.github.xiaoymin</groupId>
<artifactId>knife4j-spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>io.swagger</groupId>
<artifactId>swagger-annotations</artifactId>
</dependency>
<!-- DB 相关 -->
<dependency>

View File

@@ -1,9 +0,0 @@
package cn.iocoder.dashboard.framework.captcha.config;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Configuration;
@Configuration
@EnableConfigurationProperties(CaptchaProperties.class)
public class CaptchaConfig {
}

View File

@@ -1,31 +0,0 @@
package cn.iocoder.dashboard.framework.captcha.config;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.validation.annotation.Validated;
import javax.validation.constraints.NotNull;
import java.time.Duration;
@ConfigurationProperties(prefix = "yudao.captcha")
@Validated
@Data
public class CaptchaProperties {
/**
* 验证码的过期时间
*/
@NotNull(message = "验证码的过期时间不为空")
private Duration timeout;
/**
* 验证码的高度
*/
@NotNull(message = "验证码的高度不能为空")
private Integer height;
/**
* 验证码的宽度
*/
@NotNull(message = "验证码的宽度不能为空")
private Integer width;
}

View File

@@ -1,4 +0,0 @@
/**
* 基于 Hutool captcha 库,实现验证码功能
*/
package cn.iocoder.dashboard.framework.captcha;

View File

@@ -1,9 +0,0 @@
package cn.iocoder.dashboard.framework.codegen.config;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Configuration;
@Configuration
@EnableConfigurationProperties(CodegenProperties.class)
public class CodegenConfiguration {
}

View File

@@ -1,28 +0,0 @@
package cn.iocoder.dashboard.framework.codegen.config;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.validation.annotation.Validated;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.NotNull;
import java.util.Collection;
@ConfigurationProperties(prefix = "yudao.codegen")
@Validated
@Data
public class CodegenProperties {
/**
* 生成的 Java 代码的基础包
*/
@NotNull(message = "Java 代码的基础包不能为空")
private String basePackage;
/**
* 数据库名数组
*/
@NotEmpty(message = "数据库不能为空")
private Collection<String> dbSchemas;
}

View File

@@ -1,4 +0,0 @@
/**
* 代码生成器
*/
package cn.iocoder.dashboard.framework.codegen;

View File

@@ -1,36 +0,0 @@
package cn.iocoder.dashboard.framework.errorcode.config;
import cn.iocoder.dashboard.framework.errorcode.core.generator.ErrorCodeAutoGenerator;
import cn.iocoder.dashboard.framework.errorcode.core.loader.ErrorCodeLoader;
import cn.iocoder.dashboard.framework.errorcode.core.service.ErrorCodeFrameworkService;
import cn.iocoder.dashboard.framework.errorcode.core.loader.ErrorCodeLoaderImpl;
import cn.iocoder.dashboard.framework.errorcode.core.generator.ErrorCodeAutoGeneratorImpl;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.EnableScheduling;
/**
* 错误码配置类
*/
@Configuration
@EnableConfigurationProperties(ErrorCodeProperties.class)
@EnableScheduling // 开启调度任务的功能,因为 ErrorCodeRemoteLoader 通过定时刷新错误码
public class ErrorCodeConfiguration {
@Bean
public ErrorCodeAutoGenerator errorCodeAutoGenerator(@Value("${spring.application.name}") String applicationName,
ErrorCodeProperties errorCodeProperties,
ErrorCodeFrameworkService errorCodeFrameworkService) {
return new ErrorCodeAutoGeneratorImpl(applicationName, errorCodeProperties.getConstantsClassList(),
errorCodeFrameworkService);
}
@Bean
public ErrorCodeLoader errorCodeLoader(@Value("${spring.application.name}") String applicationName,
ErrorCodeFrameworkService errorCodeFrameworkService) {
return new ErrorCodeLoaderImpl(applicationName, errorCodeFrameworkService);
}
}

View File

@@ -1,26 +0,0 @@
package cn.iocoder.dashboard.framework.errorcode.config;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.validation.annotation.Validated;
import javax.validation.constraints.NotNull;
import java.util.List;
/**
* 错误码的配置属性类
*
* @author dlyan
*/
@ConfigurationProperties("yudao.error-code")
@Data
@Validated
public class ErrorCodeProperties {
/**
* 错误码枚举类
*/
@NotNull(message = "错误码枚举类不能为空")
private List<String> constantsClassList;
}

View File

@@ -1,34 +0,0 @@
package cn.iocoder.dashboard.framework.errorcode.core.dto;
import lombok.Data;
import lombok.experimental.Accessors;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.NotNull;
/**
* 错误码自动生成 DTO
*
* @author dylan
*/
@Data
@Accessors(chain = true)
public class ErrorCodeAutoGenerateReqDTO {
/**
* 应用名
*/
@NotNull(message = "应用名不能为空")
private String applicationName;
/**
* 错误码编码
*/
@NotNull(message = "错误码编码不能为空")
private Integer code;
/**
* 错误码错误提示
*/
@NotEmpty(message = "错误码错误提示不能为空")
private String message;
}

View File

@@ -1,28 +0,0 @@
package cn.iocoder.dashboard.framework.errorcode.core.dto;
import lombok.Data;
import java.util.Date;
/**
* 错误码的 Response DTO
*
* @author 芋道源码
*/
@Data
public class ErrorCodeRespDTO {
/**
* 错误码编码
*/
private Integer code;
/**
* 错误码错误提示
*/
private String message;
/**
* 更新时间
*/
private Date updateTime;
}

View File

@@ -1,15 +0,0 @@
package cn.iocoder.dashboard.framework.errorcode.core.generator;
/**
* 错误码的自动生成器
*
* @author dylan
*/
public interface ErrorCodeAutoGenerator {
/**
* 将配置类到错误码写入数据库
*/
void execute();
}

View File

@@ -1,98 +0,0 @@
package cn.iocoder.dashboard.framework.errorcode.core.generator;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ClassUtil;
import cn.hutool.core.util.ReflectUtil;
import cn.iocoder.yudao.framework.common.exception.ErrorCode;
import cn.iocoder.dashboard.framework.errorcode.core.dto.ErrorCodeAutoGenerateReqDTO;
import cn.iocoder.dashboard.framework.errorcode.core.service.ErrorCodeFrameworkService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.context.event.ApplicationReadyEvent;
import org.springframework.context.event.EventListener;
import org.springframework.scheduling.annotation.Async;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
/**
* ErrorCodeAutoGenerator 的实现类
* 目的是,扫描指定的 {@link #constantsClassList} 类,写入到 system 服务中
*
* @author dylan
*/
@RequiredArgsConstructor
@Slf4j
public class ErrorCodeAutoGeneratorImpl implements ErrorCodeAutoGenerator {
/**
* 应用分组
*/
private final String applicationName;
/**
* 错误码枚举类
*/
private final List<String> constantsClassList;
/**
* 错误码 Service
*/
private final ErrorCodeFrameworkService errorCodeService;
@Override
@EventListener(ApplicationReadyEvent.class)
@Async // 异步,保证项目的启动过程,毕竟非关键流程
public void execute() {
// 第一步,解析错误码
List<ErrorCodeAutoGenerateReqDTO> autoGenerateDTOs = parseErrorCode();
log.info("[execute][解析到错误码数量为 ({}) 个]", autoGenerateDTOs.size());
// 第二步,写入到 system 服务
errorCodeService.autoGenerateErrorCodes(autoGenerateDTOs);
log.info("[execute][写入到 system 组件完成]");
}
/**
* 解析 constantsClassList 变量,转换成错误码数组
*
* @return 错误码数组
*/
private List<ErrorCodeAutoGenerateReqDTO> parseErrorCode() {
// 校验 errorCodeConstantsClass 参数
if (CollUtil.isEmpty(constantsClassList)) {
log.info("[execute][未配置 yudao.error-code.constants-class-list 配置项,不进行自动写入到 system 服务中]");
return new ArrayList<>();
}
// 解析错误码
List<ErrorCodeAutoGenerateReqDTO> autoGenerateDTOs = new ArrayList<>();
constantsClassList.forEach(constantsClass -> {
// 解析错误码枚举类
Class<?> errorCodeConstantsClazz = ClassUtil.loadClass(constantsClass);
// 解析错误码
autoGenerateDTOs.addAll(parseErrorCode(errorCodeConstantsClazz));
});
return autoGenerateDTOs;
}
/**
* 解析错误码类,获得错误码数组
*
* @return 错误码数组
*/
private List<ErrorCodeAutoGenerateReqDTO> parseErrorCode(Class<?> constantsClass) {
List<ErrorCodeAutoGenerateReqDTO> autoGenerateDTOs = new ArrayList<>();
Arrays.stream(constantsClass.getFields()).forEach(field -> {
if (field.getType() != ErrorCode.class) {
return;
}
// 转换成 ErrorCodeAutoGenerateReqDTO 对象
ErrorCode errorCode = (ErrorCode) ReflectUtil.getFieldValue(constantsClass, field);
autoGenerateDTOs.add(new ErrorCodeAutoGenerateReqDTO().setApplicationName(applicationName)
.setCode(errorCode.getCode()).setMessage(errorCode.getMsg()));
});
return autoGenerateDTOs;
}
}

View File

@@ -1,24 +0,0 @@
package cn.iocoder.dashboard.framework.errorcode.core.loader;
import cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil;
/**
* 错误码加载器
*
* 注意,错误码最终加载到 {@link ServiceExceptionUtil} 的 MESSAGES 变量中!
*
* @author dlyan
*/
public interface ErrorCodeLoader {
/**
* 添加错误码
*
* @param code 错误码的编号
* @param msg 错误码的提示
*/
default void putErrorCode(Integer code, String msg) {
ServiceExceptionUtil.put(code, msg);
}
}

View File

@@ -1,73 +0,0 @@
package cn.iocoder.dashboard.framework.errorcode.core.loader;
import cn.hutool.core.collection.CollUtil;
import cn.iocoder.dashboard.framework.errorcode.core.dto.ErrorCodeRespDTO;
import cn.iocoder.dashboard.framework.errorcode.core.service.ErrorCodeFrameworkService;
import cn.iocoder.yudao.framework.util.date.DateUtils;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.context.event.ApplicationReadyEvent;
import org.springframework.context.event.EventListener;
import org.springframework.scheduling.annotation.Scheduled;
import java.util.Date;
import java.util.List;
/**
* ErrorCodeLoader 的实现类,从 infra 的数据库中,加载错误码。
*
* 考虑到错误码会刷新,所以按照 {@link #REFRESH_ERROR_CODE_PERIOD} 频率,增量加载错误码。
*
* @author dlyan
*/
@RequiredArgsConstructor
@Slf4j
public class ErrorCodeLoaderImpl implements ErrorCodeLoader {
/**
* 刷新错误码的频率,单位:毫秒
*/
private static final int REFRESH_ERROR_CODE_PERIOD = 60 * 1000;
/**
* 应用分组
*/
private final String applicationName;
/**
* 错误码 Service
*/
private final ErrorCodeFrameworkService errorCodeService;
/**
* 缓存错误码的最大更新时间,用于后续的增量轮询,判断是否有更新
*/
private Date maxUpdateTime;
@EventListener(ApplicationReadyEvent.class)
public void loadErrorCodes() {
this.loadErrorCodes0();
}
@Scheduled(fixedDelay = REFRESH_ERROR_CODE_PERIOD, initialDelay = REFRESH_ERROR_CODE_PERIOD)
public void refreshErrorCodes() {
this.loadErrorCodes0();
}
private void loadErrorCodes0() {
// 加载错误码
List<ErrorCodeRespDTO> errorCodeRespDTOs = errorCodeService.getErrorCodeList(applicationName, maxUpdateTime);
if (CollUtil.isEmpty(errorCodeRespDTOs)) {
return;
}
log.info("[loadErrorCodes0][加载到 ({}) 个错误码]", errorCodeRespDTOs.size());
// 刷新错误码的缓存
errorCodeRespDTOs.forEach(errorCodeRespDTO -> {
// 写入到错误码的缓存
putErrorCode(errorCodeRespDTO.getCode(), errorCodeRespDTO.getMessage());
// 记录下更新时间,方便增量更新
maxUpdateTime = DateUtils.max(maxUpdateTime, errorCodeRespDTO.getUpdateTime());
});
}
}

View File

@@ -1,35 +0,0 @@
package cn.iocoder.dashboard.framework.errorcode.core.service;
import cn.iocoder.dashboard.framework.errorcode.core.dto.ErrorCodeAutoGenerateReqDTO;
import cn.iocoder.dashboard.framework.errorcode.core.dto.ErrorCodeRespDTO;
import javax.validation.Valid;
import java.util.Date;
import java.util.List;
/**
* 错误码 Framework Service 接口
*
* @author 芋道源码
*/
public interface ErrorCodeFrameworkService {
/**
* 自动创建错误码
*
* @param autoGenerateDTOs 错误码信息
*/
void autoGenerateErrorCodes(@Valid List<ErrorCodeAutoGenerateReqDTO> autoGenerateDTOs);
/**
* 增量获得错误码数组
*
* 如果 minUpdateTime 为空时,则获取所有错误码
*
* @param applicationName 应用名
* @param minUpdateTime 最小更新时间
* @return 错误码数组
*/
List<ErrorCodeRespDTO> getErrorCodeList(String applicationName, Date minUpdateTime);
}

View File

@@ -1,6 +0,0 @@
/**
* 错误码组件
*
* 将错误码缓存在内存中,同时通过定时器每 n 分钟更新
*/
package cn.iocoder.dashboard.framework.errorcode;

View File

@@ -1,12 +0,0 @@
package cn.iocoder.dashboard.framework.file.config;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Configuration;
/**
* 文件 配置类
*/
@Configuration
@EnableConfigurationProperties(FileProperties.class)
public class FileConfiguration {
}

View File

@@ -1,22 +0,0 @@
package cn.iocoder.dashboard.framework.file.config;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.validation.annotation.Validated;
import javax.validation.constraints.NotNull;
@ConfigurationProperties(prefix = "yudao.file")
@Validated
@Data
public class FileProperties {
/**
* 对应 InfFileController 的 getFile 方法
*/
@NotNull(message = "基础文件路径不能为空")
private String basePath;
// TODO 七牛、等等
}

View File

@@ -1,16 +0,0 @@
/**
* 文件的存储,推荐使用七牛、阿里云、华为云、腾讯云等文件服务
*
* 在不采用云服务的情况下,我们有几种技术选型:
* 方案 1. 使用自建的文件服务,例如说 minIO、FastDFS 等等
* 方案 2. 使用服务器的文件系统存储
* 方案 3. 使用数据库进行存储
*
* 如果考虑额外在搭建服务,推荐方案 1。
* 对于方案 2 来说,如果要实现文件存储的高可用,需要多台服务器之间做实时同步,可以基于 rsync + inotify 来做
* 对于方案 3 的话,实现起来最简单,但是数据库本身不适合存储海量的文件
*
* 综合考虑,暂时使用方案 3 的方式,比较适合这样一个 all in one 的项目。
* 随着文件的量级大了之后,还是推荐采用云服务。
*/
package cn.iocoder.dashboard.framework.file;

View File

@@ -1 +0,0 @@
package cn.iocoder.dashboard.framework.logger.operatelog.core;

View File

@@ -1,10 +0,0 @@
/**
* 日志组件,包括:
*
* 1. 用户操作日志:记录用户的操作,用于对用户的操作的审计与追溯,永久保存。
* 2. API 日志:包含两类
* 2.1 API 访问日志:记录用户访问 API 的访问日志,定期归档历史日志。
* 2.2 API 异常日志:记录用户访问 API 的系统异常,方便日常排查问题与告警。
* 3. 通用 Logger 日志:将 {@link org.slf4j.Logger} 打印的日志,只满足大于等于配置的 {@link org.slf4j.event.Level} 进行持久化,可以理解成简易的“日志中心”。
*/
package cn.iocoder.dashboard.framework.logger;

View File

@@ -2,7 +2,7 @@ package cn.iocoder.dashboard.framework.tracer.config;
import cn.iocoder.dashboard.framework.tracer.core.aop.BizTraceAspect;
import cn.iocoder.dashboard.framework.tracer.core.filter.TraceFilter;
import cn.iocoder.dashboard.framework.web.core.enums.FilterOrderEnum;
import cn.iocoder.yudao.framework.common.enums.WebFilterOrderEnum;
import io.opentracing.Tracer;
import org.apache.skywalking.apm.toolkit.opentracing.SkywalkingTracer;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
@@ -49,7 +49,7 @@ public class TracerAutoConfiguration {
public FilterRegistrationBean<TraceFilter> traceFilter() {
FilterRegistrationBean<TraceFilter> registrationBean = new FilterRegistrationBean<>();
registrationBean.setFilter(new TraceFilter());
registrationBean.setOrder(FilterOrderEnum.TRACE_FILTER);
registrationBean.setOrder(WebFilterOrderEnum.TRACE_FILTER);
return registrationBean;
}

View File

@@ -1,6 +1,6 @@
package cn.iocoder.dashboard.framework.tracer.core.filter;
import cn.iocoder.dashboard.framework.tracer.core.util.TracerUtils;
import cn.iocoder.yudao.framework.util.monitor.TracerUtils;
import org.springframework.web.filter.OncePerRequestFilter;
import javax.servlet.FilterChain;

View File

@@ -0,0 +1,18 @@
<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<groupId>cn.iocoder.boot</groupId>
<artifactId>yudao-framework</artifactId>
<version>${revision}</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>yudao-spring-boot-starter-monitor</artifactId>
<packaging>jar</packaging>
<name>${artifactId}</name>
<description>服务监控,提供链路追踪、日志服务、指标收集等等功能</description>
<url>https://github.com/YunaiV/ruoyi-vue-pro</url>
</project>

View File

@@ -28,16 +28,16 @@
<!-- Web 相关 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<groupId>cn.iocoder.boot</groupId>
<artifactId>yudao-spring-boot-starter-web</artifactId>
<scope>provided</scope> <!-- 设置为 provided只有 OncePerRequestFilter 使用到 -->
</dependency>
<dependency>
<groupId>jakarta.servlet</groupId>
<artifactId>jakarta.servlet-api</artifactId>
<scope>provided</scope> <!-- 设置为 provided只有 OncePerRequestFilter 使用到 -->
</dependency>
<!-- <dependency>-->
<!-- <groupId>jakarta.servlet</groupId>-->
<!-- <artifactId>jakarta.servlet-api</artifactId>-->
<!-- <scope>provided</scope> &lt;!&ndash; 设置为 provided只有 OncePerRequestFilter 使用到 &ndash;&gt;-->
<!-- </dependency>-->
<!-- DB 相关 -->
<dependency>

View File

@@ -1,8 +1,7 @@
package cn.iocoder.yudao.framework.mybatis.core.handler;
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
import cn.iocoder.dashboard.framework.security.core.LoginUser;
import cn.iocoder.dashboard.framework.security.core.util.SecurityFrameworkUtils;
import cn.iocoder.yudao.framework.web.core.util.WebFrameworkUtils;
import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler;
import org.apache.ibatis.reflection.MetaObject;
@@ -21,10 +20,9 @@ public class DefaultDBFieldHandler implements MetaObjectHandler {
@Override
public void insertFill(MetaObject metaObject) {
if (Objects.nonNull(metaObject) && metaObject.getOriginalObject() instanceof BaseDO) {
LoginUser loginUser = SecurityFrameworkUtils.getLoginUser();
BaseDO baseDO = (BaseDO) metaObject.getOriginalObject();
Date current = new Date();
Date current = new Date();
// 创建时间为空,则以当前时间为插入时间
if (Objects.isNull(baseDO.getCreateTime())) {
baseDO.setCreateTime(current);
@@ -33,31 +31,32 @@ public class DefaultDBFieldHandler implements MetaObjectHandler {
if (Objects.isNull(baseDO.getUpdateTime())) {
baseDO.setUpdateTime(current);
}
Long userId = WebFrameworkUtils.getLoginUserId();
// 当前登录用户不为空,创建人为空,则当前登录用户为创建人
if (Objects.nonNull(loginUser) && Objects.isNull(baseDO.getCreator())) {
baseDO.setCreator(loginUser.getId().toString());
if (Objects.nonNull(userId) && Objects.isNull(baseDO.getCreator())) {
baseDO.setCreator(userId.toString());
}
// 当前登录用户不为空,更新人为空,则当前登录用户为更新人
if (Objects.nonNull(loginUser) && Objects.isNull(baseDO.getUpdater())) {
baseDO.setUpdater(loginUser.getId().toString());
if (Objects.nonNull(userId) && Objects.isNull(baseDO.getUpdater())) {
baseDO.setUpdater(userId.toString());
}
}
}
@Override
public void updateFill(MetaObject metaObject) {
Object modifyTime = getFieldValByName("updateTime", metaObject);
Object modifier = getFieldValByName("updater", metaObject);
// 获取登录用户信息
LoginUser loginUser = SecurityFrameworkUtils.getLoginUser();
// 更新时间为空,则以当前时间为更新时间
Object modifyTime = getFieldValByName("updateTime", metaObject);
if (Objects.isNull(modifyTime)) {
setFieldValByName("updateTime", new Date(), metaObject);
}
// 当前登录用户不为空,更新人为空,则当前登录用户为更新人
if (Objects.nonNull(loginUser) && Objects.isNull(modifier)) {
setFieldValByName("updater", loginUser.getId().toString(), metaObject);
Object modifier = getFieldValByName("updater", metaObject);
Long userId = WebFrameworkUtils.getLoginUserId();
if (Objects.nonNull(userId) && Objects.isNull(modifier)) {
setFieldValByName("updater", userId.toString(), metaObject);
}
}
}

View File

@@ -0,0 +1,44 @@
<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<groupId>cn.iocoder.boot</groupId>
<artifactId>yudao-framework</artifactId>
<version>${revision}</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>yudao-spring-boot-starter-operatelog</artifactId>
<packaging>jar</packaging>
<name>${artifactId}</name>
<description>操作日志</description>
<url>https://github.com/YunaiV/ruoyi-vue-pro</url>
<dependencies>
<dependency>
<groupId>cn.iocoder.boot</groupId>
<artifactId>yudao-common</artifactId>
</dependency>
<!-- Spring 核心 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
<!-- Web 相关 -->
<dependency>
<groupId>cn.iocoder.boot</groupId>
<artifactId>yudao-spring-boot-starter-web</artifactId>
<scope>provided</scope>
</dependency>
<!-- 工具类相关 -->
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
</dependency>
</dependencies>
</project>

View File

@@ -1,11 +1,11 @@
package cn.iocoder.dashboard.framework.logger.operatelog.config;
package cn.iocoder.yudao.framework.operatelog.config;
import cn.iocoder.dashboard.framework.logger.operatelog.core.aop.OperateLogAspect;
import cn.iocoder.yudao.framework.operatelog.core.aop.OperateLogAspect;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class OperateLogConfiguration {
public class YudaoOperateLogAutoConfiguration {
@Bean
public OperateLogAspect operateLogAspect() {

View File

@@ -1,6 +1,6 @@
package cn.iocoder.dashboard.framework.logger.operatelog.core.annotations;
package cn.iocoder.yudao.framework.operatelog.core.annotations;
import cn.iocoder.dashboard.framework.logger.operatelog.core.enums.OperateTypeEnum;
import cn.iocoder.yudao.framework.operatelog.core.enums.OperateTypeEnum;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;

View File

@@ -1,18 +1,18 @@
package cn.iocoder.dashboard.framework.logger.operatelog.core.aop;
package cn.iocoder.yudao.framework.operatelog.core.aop;
import cn.hutool.core.exceptions.ExceptionUtil;
import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.extra.servlet.ServletUtil;
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.dashboard.framework.logger.operatelog.core.annotations.OperateLog;
import cn.iocoder.dashboard.framework.logger.operatelog.core.dto.OperateLogCreateReqDTO;
import cn.iocoder.dashboard.framework.logger.operatelog.core.enums.OperateTypeEnum;
import cn.iocoder.dashboard.framework.logger.operatelog.core.service.OperateLogFrameworkService;
import cn.iocoder.dashboard.framework.security.core.util.SecurityFrameworkUtils;
import cn.iocoder.dashboard.framework.tracer.core.util.TracerUtils;
import cn.iocoder.yudao.framework.operatelog.core.annotations.OperateLog;
import cn.iocoder.yudao.framework.operatelog.core.dto.OperateLogCreateReqDTO;
import cn.iocoder.yudao.framework.operatelog.core.enums.OperateTypeEnum;
import cn.iocoder.yudao.framework.operatelog.core.service.OperateLogFrameworkService;
import cn.iocoder.yudao.framework.util.monitor.TracerUtils;
import cn.iocoder.yudao.framework.util.json.JsonUtils;
import cn.iocoder.yudao.framework.util.servlet.ServletUtils;
import cn.iocoder.yudao.framework.web.core.util.WebFrameworkUtils;
import com.google.common.collect.Maps;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
@@ -148,7 +148,7 @@ public class OperateLogAspect {
}
private static void fillUserFields(OperateLogCreateReqDTO operateLogDTO) {
operateLogDTO.setUserId(SecurityFrameworkUtils.getLoginUserId());
operateLogDTO.setUserId(WebFrameworkUtils.getLoginUserId());
}
private static void fillModuleFields(OperateLogCreateReqDTO operateLogDTO,

View File

@@ -1,4 +1,4 @@
package cn.iocoder.dashboard.framework.logger.operatelog.core.dto;
package cn.iocoder.yudao.framework.operatelog.core.dto;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;

View File

@@ -1,6 +1,6 @@
package cn.iocoder.dashboard.framework.logger.operatelog.core.enums;
package cn.iocoder.yudao.framework.operatelog.core.enums;
import cn.iocoder.dashboard.framework.logger.operatelog.core.annotations.OperateLog;
import cn.iocoder.yudao.framework.operatelog.core.annotations.OperateLog;
import lombok.AllArgsConstructor;
import lombok.Getter;

View File

@@ -0,0 +1 @@
package cn.iocoder.yudao.framework.operatelog.core;

View File

@@ -1,6 +1,6 @@
package cn.iocoder.dashboard.framework.logger.operatelog.core.service;
package cn.iocoder.yudao.framework.operatelog.core.service;
import cn.iocoder.dashboard.framework.logger.operatelog.core.dto.OperateLogCreateReqDTO;
import cn.iocoder.yudao.framework.operatelog.core.dto.OperateLogCreateReqDTO;
import java.util.concurrent.Future;

View File

@@ -1,6 +1,6 @@
package cn.iocoder.dashboard.framework.logger.operatelog.core.util;
package cn.iocoder.yudao.framework.operatelog.core.util;
import cn.iocoder.dashboard.framework.logger.operatelog.core.aop.OperateLogAspect;
import cn.iocoder.yudao.framework.operatelog.core.aop.OperateLogAspect;
/**
* 操作日志工具类

View File

@@ -0,0 +1,6 @@
/**
* 用户操作日志:记录用户的操作,用于对用户的操作的审计与追溯,永久保存。
*
* @author 芋道源码
*/
package cn.iocoder.yudao.framework.operatelog;

View File

@@ -0,0 +1,18 @@
<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<groupId>cn.iocoder.boot</groupId>
<artifactId>yudao-framework</artifactId>
<version>${revision}</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>yudao-spring-boot-starter-protection</artifactId>
<packaging>jar</packaging>
<name>${artifactId}</name>
<description>服务保证,提供分布式锁、幂等、限流、熔断等等功能</description>
<url>https://github.com/YunaiV/ruoyi-vue-pro</url>
</project>

View File

@@ -0,0 +1,38 @@
<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<groupId>cn.iocoder.boot</groupId>
<artifactId>yudao-framework</artifactId>
<version>${revision}</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>yudao-spring-boot-starter-security</artifactId>
<packaging>jar</packaging>
<name>${artifactId}</name>
<description>用户的认证、权限的校验</description>
<url>https://github.com/YunaiV/ruoyi-vue-pro</url>
<dependencies>
<dependency>
<groupId>cn.iocoder.boot</groupId>
<artifactId>yudao-common</artifactId>
<version>${revision}</version>
</dependency>
<!-- Web 相关 -->
<dependency>
<groupId>cn.iocoder.boot</groupId>
<artifactId>yudao-spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
</dependencies>
</project>

View File

@@ -1,4 +1,4 @@
package cn.iocoder.dashboard.framework.security.config;
package cn.iocoder.yudao.framework.security.config;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;

View File

@@ -1,9 +1,9 @@
package cn.iocoder.dashboard.framework.security.config;
package cn.iocoder.yudao.framework.security.config;
import cn.iocoder.dashboard.framework.security.core.filter.JwtAuthenticationTokenFilter;
import cn.iocoder.dashboard.framework.security.core.handler.LogoutSuccessHandlerImpl;
import cn.iocoder.dashboard.framework.web.config.WebProperties;
import de.codecentric.boot.admin.server.config.AdminServerProperties;
import cn.iocoder.yudao.framework.security.core.filter.JwtAuthenticationTokenFilter;
import cn.iocoder.yudao.framework.security.core.handler.LogoutSuccessHandlerImpl;
import cn.iocoder.yudao.framework.web.config.WebProperties;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
@@ -30,7 +30,7 @@ import javax.annotation.Resource;
*/
@EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true)
@EnableConfigurationProperties(SecurityProperties.class)
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
public class YudaoSecurityConfiguration extends WebSecurityConfigurerAdapter {
/**
* 自定义用户认证逻辑
@@ -62,8 +62,9 @@ public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
@Resource
private WebProperties webProperties;
@Resource
private AdminServerProperties adminServerProperties;
@Value("${spring.boot.admin.context-path:''}")
private String adminSeverContextPath;
/**
* 由于 Spring Security 创建 AuthenticationManager 对象时没声明 @Bean 注解导致无法被注入
@@ -129,7 +130,7 @@ public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
.authorizeRequests()
// 登陆的接口可匿名访问
.antMatchers(api("/login")).anonymous()
// 通用的接口可匿名访问
// 通用的接口可匿名访问 TODO 芋艿需要抽象出去
.antMatchers(api("/system/captcha/**")).anonymous()
// 静态资源可匿名访问
.antMatchers(HttpMethod.GET, "/*.html", "/**/*.html", "/**/*.css", "/**/*.js").permitAll()
@@ -140,15 +141,15 @@ public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
.antMatchers("/swagger-resources/**").anonymous()
.antMatchers("/webjars/**").anonymous()
.antMatchers("/*/api-docs").anonymous()
// Spring Boot Admin Server 的安全配置
.antMatchers(adminServerProperties.getContextPath()).anonymous()
.antMatchers(adminServerProperties.getContextPath() + "/**").anonymous()
// Spring Boot Admin Server 的安全配置 TODO 芋艿需要抽象出去
.antMatchers(adminSeverContextPath).anonymous()
.antMatchers(adminSeverContextPath + "/**").anonymous()
// Spring Boot Actuator 的安全配置
.antMatchers("/actuator").anonymous()
.antMatchers("/actuator/**").anonymous()
// Druid 监控
// Druid 监控 TODO 芋艿需要抽象出去
.antMatchers("/druid/**").anonymous()
// 短信回调 API
// 短信回调 API TODO 芋艿需要抽象出去
.antMatchers(api("/system/sms/callback/**")).anonymous()
// 除上面外的所有请求全部需要鉴权认证
.anyRequest().authenticated()

View File

@@ -1,4 +1,4 @@
package cn.iocoder.dashboard.framework.security.core;
package cn.iocoder.yudao.framework.security.core;
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
import com.fasterxml.jackson.annotation.JsonIgnore;

View File

@@ -1,4 +1,4 @@
package cn.iocoder.dashboard.framework.security.core.enums;
package cn.iocoder.yudao.framework.security.core.enums;
import lombok.AllArgsConstructor;
import lombok.Getter;

View File

@@ -1,12 +1,12 @@
package cn.iocoder.dashboard.framework.security.core.filter;
package cn.iocoder.yudao.framework.security.core.filter;
import cn.hutool.core.util.StrUtil;
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.dashboard.framework.security.config.SecurityProperties;
import cn.iocoder.dashboard.framework.security.core.LoginUser;
import cn.iocoder.dashboard.framework.security.core.service.SecurityAuthFrameworkService;
import cn.iocoder.dashboard.framework.security.core.util.SecurityFrameworkUtils;
import cn.iocoder.dashboard.framework.web.core.handler.GlobalExceptionHandler;
import cn.iocoder.yudao.framework.security.config.SecurityProperties;
import cn.iocoder.yudao.framework.security.core.LoginUser;
import cn.iocoder.yudao.framework.security.core.service.SecurityAuthFrameworkService;
import cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils;
import cn.iocoder.yudao.framework.web.core.handler.GlobalExceptionHandler;
import cn.iocoder.yudao.framework.util.servlet.ServletUtils;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;

View File

@@ -1,8 +1,8 @@
package cn.iocoder.dashboard.framework.security.core.handler;
package cn.iocoder.yudao.framework.security.core.handler;
import cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeConstants;
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.dashboard.framework.security.core.util.SecurityFrameworkUtils;
import cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils;
import cn.iocoder.yudao.framework.util.servlet.ServletUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.access.AccessDeniedException;

View File

@@ -1,4 +1,4 @@
package cn.iocoder.dashboard.framework.security.core.handler;
package cn.iocoder.yudao.framework.security.core.handler;
import cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeConstants;
import cn.iocoder.yudao.framework.common.pojo.CommonResult;

View File

@@ -1,10 +1,10 @@
package cn.iocoder.dashboard.framework.security.core.handler;
package cn.iocoder.yudao.framework.security.core.handler;
import cn.hutool.core.util.StrUtil;
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.dashboard.framework.security.config.SecurityProperties;
import cn.iocoder.dashboard.framework.security.core.service.SecurityAuthFrameworkService;
import cn.iocoder.dashboard.framework.security.core.util.SecurityFrameworkUtils;
import cn.iocoder.yudao.framework.security.config.SecurityProperties;
import cn.iocoder.yudao.framework.security.core.service.SecurityAuthFrameworkService;
import cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils;
import cn.iocoder.yudao.framework.util.servlet.ServletUtils;
import org.springframework.security.core.Authentication;
import org.springframework.security.web.authentication.logout.LogoutSuccessHandler;
@@ -39,4 +39,5 @@ public class LogoutSuccessHandlerImpl implements LogoutSuccessHandler {
// 返回成功
ServletUtils.writeJSON(response, CommonResult.success(null));
}
}

View File

@@ -1,6 +1,6 @@
package cn.iocoder.dashboard.framework.security.core.service;
package cn.iocoder.yudao.framework.security.core.service;
import cn.iocoder.dashboard.framework.security.core.LoginUser;
import cn.iocoder.yudao.framework.security.core.LoginUser;
import org.springframework.security.core.userdetails.UserDetailsService;
/**

View File

@@ -1,4 +1,4 @@
package cn.iocoder.dashboard.framework.security.core.service;
package cn.iocoder.yudao.framework.security.core.service;
/**
* Security 框架 Permission Service 接口定义 security 组件需要的功能

View File

@@ -1,7 +1,7 @@
package cn.iocoder.dashboard.framework.security.core.util;
package cn.iocoder.yudao.framework.security.core.util;
import cn.iocoder.dashboard.framework.security.core.LoginUser;
import cn.iocoder.dashboard.framework.web.core.util.WebFrameworkUtils;
import cn.iocoder.yudao.framework.security.core.LoginUser;
import cn.iocoder.yudao.framework.web.core.util.WebFrameworkUtils;
import org.springframework.lang.Nullable;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;

View File

@@ -0,0 +1,59 @@
<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<groupId>cn.iocoder.boot</groupId>
<artifactId>yudao-framework</artifactId>
<version>${revision}</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>yudao-spring-boot-starter-web</artifactId>
<packaging>jar</packaging>
<name>${artifactId}</name>
<description>用户的认证、权限的校验</description>
<url>https://github.com/YunaiV/ruoyi-vue-pro</url>
<dependencies>
<dependency>
<groupId>cn.iocoder.boot</groupId>
<artifactId>yudao-common</artifactId>
</dependency>
<!-- Web 相关 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>com.github.xiaoymin</groupId>
<artifactId>knife4j-spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>io.swagger</groupId>
<artifactId>swagger-annotations</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-core</artifactId>
<scope>provided</scope> <!-- 设置为 provided主要是 GlobalExceptionHandler 使用 -->
</dependency>
<!-- 服务保障相关 -->
<dependency>
<groupId>io.github.resilience4j</groupId>
<artifactId>resilience4j-ratelimiter</artifactId>
<scope>provided</scope> <!-- 设置为 provided主要是 GlobalExceptionHandler 使用 -->
</dependency>
</dependencies>
</project>

View File

@@ -1,10 +1,12 @@
package cn.iocoder.dashboard.framework.logger.apilog.config;
package cn.iocoder.yudao.framework.apilog.config;
import cn.iocoder.dashboard.framework.logger.apilog.core.filter.ApiAccessLogFilter;
import cn.iocoder.dashboard.framework.logger.apilog.core.service.ApiAccessLogFrameworkService;
import cn.iocoder.dashboard.framework.web.config.WebProperties;
import cn.iocoder.dashboard.framework.web.core.enums.FilterOrderEnum;
import cn.iocoder.yudao.framework.apilog.core.filter.ApiAccessLogFilter;
import cn.iocoder.yudao.framework.apilog.core.service.ApiAccessLogFrameworkService;
import cn.iocoder.yudao.framework.web.config.WebProperties;
import cn.iocoder.yudao.framework.web.config.YudaoWebAutoConfiguration;
import cn.iocoder.yudao.framework.common.enums.WebFilterOrderEnum;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@@ -12,7 +14,8 @@ import org.springframework.context.annotation.Configuration;
import javax.servlet.Filter;
@Configuration
public class ApiLogConfiguration {
@AutoConfigureAfter(YudaoWebAutoConfiguration.class)
public class YudaoApiLogAutoConfiguration {
/**
* 创建 ApiAccessLogFilter Bean记录 API 请求日志
@@ -22,7 +25,7 @@ public class ApiLogConfiguration {
@Value("${spring.application.name}") String applicationName,
ApiAccessLogFrameworkService apiAccessLogFrameworkService) {
ApiAccessLogFilter filter = new ApiAccessLogFilter(webProperties, applicationName, apiAccessLogFrameworkService);
return createFilterBean(filter, FilterOrderEnum.API_ACCESS_LOG_FILTER);
return createFilterBean(filter, WebFilterOrderEnum.API_ACCESS_LOG_FILTER);
}
private static <T extends Filter> FilterRegistrationBean<T> createFilterBean(T filter, Integer order) {

View File

@@ -1,15 +1,15 @@
package cn.iocoder.dashboard.framework.logger.apilog.core.filter;
package cn.iocoder.yudao.framework.apilog.core.filter;
import cn.hutool.core.exceptions.ExceptionUtil;
import cn.hutool.core.map.MapUtil;
import cn.hutool.extra.servlet.ServletUtil;
import cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeConstants;
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.dashboard.framework.logger.apilog.core.service.ApiAccessLogFrameworkService;
import cn.iocoder.dashboard.framework.logger.apilog.core.service.dto.ApiAccessLogCreateDTO;
import cn.iocoder.dashboard.framework.tracer.core.util.TracerUtils;
import cn.iocoder.dashboard.framework.web.config.WebProperties;
import cn.iocoder.dashboard.framework.web.core.util.WebFrameworkUtils;
import cn.iocoder.yudao.framework.apilog.core.service.ApiAccessLogFrameworkService;
import cn.iocoder.yudao.framework.apilog.core.service.dto.ApiAccessLogCreateDTO;
import cn.iocoder.yudao.framework.util.monitor.TracerUtils;
import cn.iocoder.yudao.framework.web.config.WebProperties;
import cn.iocoder.yudao.framework.web.core.util.WebFrameworkUtils;
import cn.iocoder.yudao.framework.util.date.DateUtils;
import cn.iocoder.yudao.framework.util.json.JsonUtils;
import cn.iocoder.yudao.framework.util.servlet.ServletUtils;

View File

@@ -1,6 +1,6 @@
package cn.iocoder.dashboard.framework.logger.apilog.core.service;
package cn.iocoder.yudao.framework.apilog.core.service;
import cn.iocoder.dashboard.framework.logger.apilog.core.service.dto.ApiAccessLogCreateDTO;
import cn.iocoder.yudao.framework.apilog.core.service.dto.ApiAccessLogCreateDTO;
import javax.validation.Valid;
import java.util.concurrent.Future;

View File

@@ -1,6 +1,6 @@
package cn.iocoder.dashboard.framework.logger.apilog.core.service;
package cn.iocoder.yudao.framework.apilog.core.service;
import cn.iocoder.dashboard.framework.logger.apilog.core.service.dto.ApiErrorLogCreateDTO;
import cn.iocoder.yudao.framework.apilog.core.service.dto.ApiErrorLogCreateDTO;
import javax.validation.Valid;
import java.util.concurrent.Future;

View File

@@ -1,4 +1,4 @@
package cn.iocoder.dashboard.framework.logger.apilog.core.service.dto;
package cn.iocoder.yudao.framework.apilog.core.service.dto;
import lombok.Data;
import lombok.experimental.Accessors;

View File

@@ -0,0 +1,8 @@
/**
* API 日志:包含两类
* 1. API 访问日志:记录用户访问 API 的访问日志,定期归档历史日志。
* 2. 异常日志:记录用户访问 API 的系统异常,方便日常排查问题与告警。
*
* @author 芋道源码
*/
package cn.iocoder.yudao.framework.apilog;

View File

@@ -1,7 +1,7 @@
package cn.iocoder.dashboard.framework.jackson.config;
package cn.iocoder.yudao.framework.jackson.config;
import cn.iocoder.dashboard.framework.jackson.deser.LocalDateTimeDeserializer;
import cn.iocoder.dashboard.framework.jackson.ser.LocalDateTimeSerializer;
import cn.iocoder.yudao.framework.jackson.core.databind.LocalDateTimeDeserializer;
import cn.iocoder.yudao.framework.jackson.core.databind.LocalDateTimeSerializer;
import cn.iocoder.yudao.framework.util.json.JsonUtils;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.module.SimpleModule;
@@ -11,7 +11,7 @@ import org.springframework.context.annotation.Configuration;
import java.time.LocalDateTime;
@Configuration
public class JacksonConfig {
public class YudaoJacksonAutoConfiguration {
@Bean
@SuppressWarnings("InstantiationOfUtilityClass")

View File

@@ -1,4 +1,4 @@
package cn.iocoder.dashboard.framework.jackson.deser;
package cn.iocoder.yudao.framework.jackson.core.databind;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonProcessingException;

View File

@@ -1,4 +1,4 @@
package cn.iocoder.dashboard.framework.jackson.ser;
package cn.iocoder.yudao.framework.jackson.core.databind;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.JsonSerializer;

View File

@@ -0,0 +1 @@
package cn.iocoder.yudao.framework.jackson.core;

View File

@@ -0,0 +1 @@
package cn.iocoder.yudao.framework;

View File

@@ -1,4 +1,4 @@
package cn.iocoder.dashboard.framework.swagger.config;
package cn.iocoder.yudao.framework.swagger.config;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;

View File

@@ -1,4 +1,4 @@
package cn.iocoder.dashboard.framework.swagger.config;
package cn.iocoder.yudao.framework.swagger.config;
import com.github.xiaoymin.knife4j.spring.annotations.EnableKnife4j;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
@@ -38,7 +38,7 @@ import static springfox.documentation.builders.RequestHandlerSelectors.basePacka
@ConditionalOnProperty(prefix = "yudao.swagger", value = "enable", matchIfMissing = true)
// 允许使用 swagger.enable=false 禁用 Swagger
@EnableConfigurationProperties(SwaggerProperties.class)
public class SwaggerAutoConfiguration {
public class YudaoSwaggerAutoConfiguration {
@Bean
@ConditionalOnMissingBean

View File

@@ -3,4 +3,4 @@
*
* @author 芋道源码
*/
package cn.iocoder.dashboard.framework.swagger;
package cn.iocoder.yudao.framework.swagger;

View File

@@ -1,4 +1,4 @@
package cn.iocoder.dashboard.framework.web.config;
package cn.iocoder.yudao.framework.web.config;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
@@ -19,7 +19,7 @@ public class WebProperties {
* 意义通过该前缀避免 SwaggerActuator 意外通过 Nginx 暴露出来给外部带来安全性问题
* 这样Nginx 只需要配置转发到 /api/* 的所有接口即可
*
* @see WebConfiguration#configurePathMatch(PathMatchConfigurer)
* @see YudaoWebAutoConfiguration#configurePathMatch(PathMatchConfigurer)
*/
@NotNull(message = "API 前缀不能为空")
private String apiPrefix;

View File

@@ -1,4 +1,4 @@
package cn.iocoder.dashboard.framework.web.config;
package cn.iocoder.yudao.framework.web.config;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;

View File

@@ -1,9 +1,9 @@
package cn.iocoder.dashboard.framework.web.config;
package cn.iocoder.yudao.framework.web.config;
import cn.iocoder.dashboard.framework.web.core.enums.FilterOrderEnum;
import cn.iocoder.dashboard.framework.web.core.filter.CacheRequestBodyFilter;
import cn.iocoder.dashboard.framework.web.core.filter.DemoFilter;
import cn.iocoder.dashboard.framework.web.core.filter.XssFilter;
import cn.iocoder.yudao.framework.common.enums.WebFilterOrderEnum;
import cn.iocoder.yudao.framework.web.core.filter.CacheRequestBodyFilter;
import cn.iocoder.yudao.framework.web.core.filter.DemoFilter;
import cn.iocoder.yudao.framework.web.core.filter.XssFilter;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
@@ -22,7 +22,7 @@ import javax.servlet.Filter;
@Configuration
@EnableConfigurationProperties({WebProperties.class, XssProperties.class})
public class WebConfiguration implements WebMvcConfigurer {
public class YudaoWebAutoConfiguration implements WebMvcConfigurer {
@Resource
private WebProperties webProperties;
@@ -51,7 +51,7 @@ public class WebConfiguration implements WebMvcConfigurer {
// 创建 UrlBasedCorsConfigurationSource 对象
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", config); // 对接口配置跨域设置
return createFilterBean(new CorsFilter(source), FilterOrderEnum.CORS_FILTER);
return createFilterBean(new CorsFilter(source), WebFilterOrderEnum.CORS_FILTER);
}
/**
@@ -59,7 +59,7 @@ public class WebConfiguration implements WebMvcConfigurer {
*/
@Bean
public FilterRegistrationBean<CacheRequestBodyFilter> requestBodyCacheFilter() {
return createFilterBean(new CacheRequestBodyFilter(), FilterOrderEnum.REQUEST_BODY_CACHE_FILTER);
return createFilterBean(new CacheRequestBodyFilter(), WebFilterOrderEnum.REQUEST_BODY_CACHE_FILTER);
}
/**
@@ -67,7 +67,7 @@ public class WebConfiguration implements WebMvcConfigurer {
*/
@Bean
public FilterRegistrationBean<XssFilter> xssFilter(XssProperties properties, PathMatcher pathMatcher) {
return createFilterBean(new XssFilter(properties, pathMatcher), FilterOrderEnum.XSS_FILTER);
return createFilterBean(new XssFilter(properties, pathMatcher), WebFilterOrderEnum.XSS_FILTER);
}
/**
@@ -76,7 +76,7 @@ public class WebConfiguration implements WebMvcConfigurer {
@Bean
@ConditionalOnProperty(value = "yudao.demo", havingValue = "true")
public FilterRegistrationBean<DemoFilter> demoFilter() {
return createFilterBean(new DemoFilter(), FilterOrderEnum.DEMO_FILTER);
return createFilterBean(new DemoFilter(), WebFilterOrderEnum.DEMO_FILTER);
}
private static <T extends Filter> FilterRegistrationBean<T> createFilterBean(T filter, Integer order) {

View File

@@ -1,4 +1,4 @@
package cn.iocoder.dashboard.framework.web.core.filter;
package cn.iocoder.yudao.framework.web.core.filter;
import cn.iocoder.yudao.framework.util.servlet.ServletUtils;
import org.springframework.web.filter.OncePerRequestFilter;

View File

@@ -1,4 +1,4 @@
package cn.iocoder.dashboard.framework.web.core.filter;
package cn.iocoder.yudao.framework.web.core.filter;
import cn.hutool.extra.servlet.ServletUtil;

View File

@@ -1,9 +1,9 @@
package cn.iocoder.dashboard.framework.web.core.filter;
package cn.iocoder.yudao.framework.web.core.filter;
import cn.hutool.core.util.StrUtil;
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.dashboard.framework.security.core.util.SecurityFrameworkUtils;
import cn.iocoder.yudao.framework.util.servlet.ServletUtils;
import cn.iocoder.yudao.framework.web.core.util.WebFrameworkUtils;
import org.springframework.web.filter.OncePerRequestFilter;
import javax.servlet.FilterChain;
@@ -23,7 +23,7 @@ public class DemoFilter extends OncePerRequestFilter {
protected boolean shouldNotFilter(HttpServletRequest request) {
String method = request.getMethod();
return !StrUtil.equalsAnyIgnoreCase(method, "POST", "PUT", "DELETE") // 写操作时不进行过滤率
|| SecurityFrameworkUtils.getLoginUser() == null; // 非登陆用户时不进行过滤
|| WebFrameworkUtils.getLoginUserId(request) == null; // 非登陆用户时不进行过滤
}
@Override

View File

@@ -1,6 +1,6 @@
package cn.iocoder.dashboard.framework.web.core.filter;
package cn.iocoder.yudao.framework.web.core.filter;
import cn.iocoder.dashboard.framework.web.config.XssProperties;
import cn.iocoder.yudao.framework.web.config.XssProperties;
import lombok.AllArgsConstructor;
import org.springframework.util.PathMatcher;
import org.springframework.web.filter.OncePerRequestFilter;

View File

@@ -1,4 +1,4 @@
package cn.iocoder.dashboard.framework.web.core.filter;
package cn.iocoder.yudao.framework.web.core.filter;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.io.IoUtil;

View File

@@ -1,15 +1,14 @@
package cn.iocoder.dashboard.framework.web.core.handler;
package cn.iocoder.yudao.framework.web.core.handler;
import cn.hutool.core.exceptions.ExceptionUtil;
import cn.hutool.core.map.MapUtil;
import cn.hutool.extra.servlet.ServletUtil;
import cn.iocoder.yudao.framework.common.exception.ServiceException;
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.dashboard.framework.logger.apilog.core.service.ApiErrorLogFrameworkService;
import cn.iocoder.dashboard.framework.logger.apilog.core.service.dto.ApiErrorLogCreateDTO;
import cn.iocoder.dashboard.framework.security.core.util.SecurityFrameworkUtils;
import cn.iocoder.dashboard.framework.tracer.core.util.TracerUtils;
import cn.iocoder.dashboard.framework.web.core.util.WebFrameworkUtils;
import cn.iocoder.yudao.framework.apilog.core.service.ApiErrorLogFrameworkService;
import cn.iocoder.yudao.framework.apilog.core.service.dto.ApiErrorLogCreateDTO;
import cn.iocoder.yudao.framework.util.monitor.TracerUtils;
import cn.iocoder.yudao.framework.web.core.util.WebFrameworkUtils;
import cn.iocoder.yudao.framework.util.json.JsonUtils;
import cn.iocoder.yudao.framework.util.servlet.ServletUtils;
import io.github.resilience4j.ratelimiter.RequestNotPermitted;
@@ -202,7 +201,7 @@ public class GlobalExceptionHandler {
*/
@ExceptionHandler(value = AccessDeniedException.class)
public CommonResult<?> accessDeniedExceptionHandler(HttpServletRequest req, AccessDeniedException ex) {
log.warn("[accessDeniedExceptionHandler][userId({}) 无法访问 url({})]", SecurityFrameworkUtils.getLoginUserId(),
log.warn("[accessDeniedExceptionHandler][userId({}) 无法访问 url({})]", WebFrameworkUtils.getLoginUserId(req),
req.getRequestURL(), ex);
return CommonResult.error(FORBIDDEN);
}

View File

@@ -1,7 +1,7 @@
package cn.iocoder.dashboard.framework.web.core.handler;
package cn.iocoder.yudao.framework.web.core.handler;
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.dashboard.framework.web.core.util.WebFrameworkUtils;
import cn.iocoder.yudao.framework.web.core.util.WebFrameworkUtils;
import org.springframework.core.MethodParameter;
import org.springframework.http.MediaType;
import org.springframework.http.server.ServerHttpRequest;
@@ -18,7 +18,7 @@ import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;
* 原因是GlobalResponseBodyHandler 本质上是 AOP它不应该改变 Controller 返回的数据结构
*
* 目前GlobalResponseBodyHandler 的主要作用是记录 Controller 的返回结果
* 方便 {@link cn.iocoder.dashboard.framework.logger.apilog.core.filter.ApiAccessLogFilter} 记录访问日志
* 方便 {@link cn.iocoder.yudao.framework.apilog.core.filter.ApiAccessLogFilter} 记录访问日志
*/
@ControllerAdvice
public class GlobalResponseBodyHandler implements ResponseBodyAdvice {

View File

@@ -1,7 +1,10 @@
package cn.iocoder.dashboard.framework.web.core.util;
package cn.iocoder.yudao.framework.web.core.util;
import cn.iocoder.yudao.framework.common.enums.UserTypeEnum;
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import javax.servlet.ServletRequest;
import javax.servlet.http.HttpServletRequest;
@@ -28,9 +31,17 @@ public class WebFrameworkUtils {
* @return 用户编号
*/
public static Long getLoginUserId(HttpServletRequest request) {
if (request == null) {
return null;
}
return (Long) request.getAttribute(REQUEST_ATTRIBUTE_LOGIN_USER_ID);
}
public static Long getLoginUserId() {
HttpServletRequest request = getRequest();
return getLoginUserId(request);
}
public static Integer getUserType(HttpServletRequest request) {
return UserTypeEnum.ADMIN.getValue(); // TODO 芋艿等后续优化
}
@@ -43,4 +54,13 @@ public class WebFrameworkUtils {
return (CommonResult<?>) request.getAttribute(REQUEST_ATTRIBUTE_COMMON_RESULT);
}
private static HttpServletRequest getRequest() {
RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
if (!(requestAttributes instanceof ServletRequestAttributes)) {
return null;
}
ServletRequestAttributes servletRequestAttributes = (ServletRequestAttributes) requestAttributes;
return servletRequestAttributes.getRequest();
}
}

View File

@@ -1,4 +1,4 @@
/**
* 针对 SpringMVC 的基础封装
*/
package cn.iocoder.dashboard.framework.web;
package cn.iocoder.yudao.framework.web;