forked from gin/simple-template
feat: initial commit
This commit is contained in:
+16
@@ -0,0 +1,16 @@
|
||||
package com.agileboot.infrastructure;
|
||||
|
||||
import org.springframework.boot.web.servlet.support.SpringBootServletInitializer;
|
||||
|
||||
/**
|
||||
* 对于Spring Boot应用,我们一般会打成jar包使用内置容器运行,但是有时候我们想要像使用传统spring web项目一样,
|
||||
* 将Spring Boot应用打成WAR包,然后部署到外部容器运行,那么我们传统的使用Main类启动的方式稍显蹩脚,
|
||||
* 因为外部容器无法识别到应用启动类,需要在应用中继承SpringBootServletInitializer类,然后重写config方法,
|
||||
* 将其指向应用启动类。
|
||||
* @author valarchie
|
||||
*/
|
||||
public class WarDeploymentInitializer extends SpringBootServletInitializer {
|
||||
// protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
|
||||
// return application.sources(AgileBootApplication.class);
|
||||
// }
|
||||
}
|
||||
+122
@@ -0,0 +1,122 @@
|
||||
package com.agileboot.infrastructure.annotations.ratelimit;
|
||||
|
||||
import cn.hutool.extra.servlet.ServletUtil;
|
||||
import com.agileboot.common.exception.ApiException;
|
||||
import com.agileboot.common.exception.error.ErrorCode;
|
||||
import com.agileboot.common.utils.ServletHolderUtil;
|
||||
import com.agileboot.infrastructure.user.AuthenticationUtils;
|
||||
import com.agileboot.infrastructure.user.app.AppLoginUser;
|
||||
import com.agileboot.infrastructure.user.web.SystemLoginUser;
|
||||
import java.lang.annotation.Documented;
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* 限流注解
|
||||
*
|
||||
* @author valarchie
|
||||
*/
|
||||
@Target(ElementType.METHOD)
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Documented
|
||||
public @interface RateLimit {
|
||||
|
||||
/**
|
||||
* 限流key
|
||||
*/
|
||||
String key() default "None";
|
||||
|
||||
/**
|
||||
* 限流时间,单位秒
|
||||
*/
|
||||
int time() default 60;
|
||||
|
||||
/**
|
||||
* 限流次数
|
||||
*/
|
||||
int maxCount() default 100;
|
||||
|
||||
/**
|
||||
* 限流条件类型
|
||||
*/
|
||||
LimitType limitType() default LimitType.GLOBAL;
|
||||
|
||||
/**
|
||||
* 限流使用的缓存类型
|
||||
*/
|
||||
CacheType cacheType() default CacheType.REDIS;
|
||||
|
||||
|
||||
|
||||
enum LimitType {
|
||||
/**
|
||||
* 默认策略全局限流 不区分IP和用户
|
||||
*/
|
||||
GLOBAL{
|
||||
@Override
|
||||
public String generateCombinedKey(RateLimit rateLimiter) {
|
||||
return rateLimiter.key() + this.name();
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* 根据请求者IP进行限流
|
||||
*/
|
||||
IP {
|
||||
@Override
|
||||
public String generateCombinedKey(RateLimit rateLimiter) {
|
||||
String clientIP = ServletUtil.getClientIP(ServletHolderUtil.getRequest());
|
||||
return rateLimiter.key() + clientIP;
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* 按Web用户限流
|
||||
*/
|
||||
SYSTEM_USER {
|
||||
@Override
|
||||
public String generateCombinedKey(RateLimit rateLimiter) {
|
||||
SystemLoginUser loginUser = AuthenticationUtils.getSystemLoginUser();
|
||||
if (loginUser == null) {
|
||||
throw new ApiException(ErrorCode.Client.COMMON_NO_AUTHORIZATION);
|
||||
}
|
||||
return rateLimiter.key() + loginUser.getUsername();
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* 按App用户限流
|
||||
*/
|
||||
APP_USER {
|
||||
@Override
|
||||
public String generateCombinedKey(RateLimit rateLimiter) {
|
||||
AppLoginUser loginUser = AuthenticationUtils.getAppLoginUser();
|
||||
if (loginUser == null) {
|
||||
throw new ApiException(ErrorCode.Client.COMMON_NO_AUTHORIZATION);
|
||||
}
|
||||
return rateLimiter.key() + loginUser.getUsername();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
public abstract String generateCombinedKey(RateLimit rateLimiter);
|
||||
|
||||
}
|
||||
|
||||
enum CacheType {
|
||||
|
||||
/**
|
||||
* 使用redis做缓存
|
||||
*/
|
||||
REDIS,
|
||||
|
||||
/**
|
||||
* 使用map做缓存
|
||||
*/
|
||||
Map
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
+17
@@ -0,0 +1,17 @@
|
||||
package com.agileboot.infrastructure.annotations.ratelimit;
|
||||
|
||||
/**
|
||||
* 限流key
|
||||
* @author valarchie
|
||||
*/
|
||||
public class RateLimitKey {
|
||||
|
||||
public static final String PREFIX = "Rate-Limit:";
|
||||
|
||||
public static final String LOGIN_CAPTCHA_KEY = PREFIX + "Login-Captcha:";
|
||||
|
||||
public static final String TEST_KEY = PREFIX + "Test:";
|
||||
|
||||
private RateLimitKey() {
|
||||
}
|
||||
}
|
||||
+51
@@ -0,0 +1,51 @@
|
||||
package com.agileboot.infrastructure.annotations.ratelimit;
|
||||
|
||||
import com.agileboot.infrastructure.annotations.ratelimit.implementation.MapRateLimitChecker;
|
||||
import com.agileboot.infrastructure.annotations.ratelimit.implementation.RedisRateLimitChecker;
|
||||
import java.lang.reflect.Method;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.aspectj.lang.JoinPoint;
|
||||
import org.aspectj.lang.annotation.Aspect;
|
||||
import org.aspectj.lang.annotation.Before;
|
||||
import org.aspectj.lang.reflect.MethodSignature;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* 限流切面处理
|
||||
*
|
||||
* @author valarchie
|
||||
*/
|
||||
@Aspect
|
||||
@Component
|
||||
@Slf4j
|
||||
@ConditionalOnExpression("'${agileboot.embedded.redis}' != 'true'")
|
||||
@RequiredArgsConstructor
|
||||
public class RateLimiterAspect {
|
||||
|
||||
private final RedisRateLimitChecker redisRateLimitChecker;
|
||||
|
||||
private final MapRateLimitChecker mapRateLimitChecker;
|
||||
|
||||
|
||||
@Before("@annotation(rateLimiter)")
|
||||
public void doBefore(JoinPoint point, RateLimit rateLimiter) {
|
||||
MethodSignature signature = (MethodSignature) point.getSignature();
|
||||
Method method = signature.getMethod();
|
||||
log.info("当前限流方法:" + method.toGenericString());
|
||||
|
||||
switch (rateLimiter.cacheType()) {
|
||||
case REDIS:
|
||||
redisRateLimitChecker.check(rateLimiter);
|
||||
break;
|
||||
case Map:
|
||||
mapRateLimitChecker.check(rateLimiter);
|
||||
return;
|
||||
default:
|
||||
redisRateLimitChecker.check(rateLimiter);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
+17
@@ -0,0 +1,17 @@
|
||||
package com.agileboot.infrastructure.annotations.ratelimit.implementation;
|
||||
|
||||
import com.agileboot.infrastructure.annotations.ratelimit.RateLimit;
|
||||
|
||||
/**
|
||||
* @author valarchie
|
||||
*/
|
||||
public abstract class AbstractRateLimitChecker {
|
||||
|
||||
/**
|
||||
* 检查是否超出限流
|
||||
*
|
||||
* @param rateLimiter RateLimit
|
||||
*/
|
||||
public abstract void check(RateLimit rateLimiter);
|
||||
|
||||
}
|
||||
+42
@@ -0,0 +1,42 @@
|
||||
package com.agileboot.infrastructure.annotations.ratelimit.implementation;
|
||||
|
||||
import cn.hutool.cache.impl.LRUCache;
|
||||
import com.agileboot.common.exception.ApiException;
|
||||
import com.agileboot.common.exception.error.ErrorCode;
|
||||
import com.agileboot.infrastructure.annotations.ratelimit.RateLimit;
|
||||
import com.google.common.util.concurrent.RateLimiter;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* @author valarchie
|
||||
*/
|
||||
@SuppressWarnings("UnstableApiUsage")
|
||||
@Component
|
||||
@RequiredArgsConstructor
|
||||
@Slf4j
|
||||
public class MapRateLimitChecker extends AbstractRateLimitChecker{
|
||||
|
||||
/**
|
||||
* 最大仅支持4096个key 超出这个key 限流将可能失效
|
||||
*/
|
||||
private final LRUCache<String, RateLimiter> cache = new LRUCache<>(4096);
|
||||
|
||||
|
||||
@Override
|
||||
public void check(RateLimit rateLimit) {
|
||||
String combinedKey = rateLimit.limitType().generateCombinedKey(rateLimit);
|
||||
|
||||
RateLimiter rateLimiter = cache.get(combinedKey,
|
||||
() -> RateLimiter.create((double) rateLimit.maxCount() / rateLimit.time())
|
||||
);
|
||||
|
||||
if (!rateLimiter.tryAcquire()) {
|
||||
throw new ApiException(ErrorCode.Client.COMMON_REQUEST_TOO_OFTEN);
|
||||
}
|
||||
|
||||
log.info("限制请求key:{}, combined key:{}", rateLimit.key(), combinedKey);
|
||||
}
|
||||
|
||||
}
|
||||
+67
@@ -0,0 +1,67 @@
|
||||
package com.agileboot.infrastructure.annotations.ratelimit.implementation;
|
||||
|
||||
import cn.hutool.core.collection.ListUtil;
|
||||
import com.agileboot.common.exception.ApiException;
|
||||
import com.agileboot.common.exception.error.ErrorCode;
|
||||
import com.agileboot.infrastructure.annotations.ratelimit.RateLimit;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.data.redis.core.RedisTemplate;
|
||||
import org.springframework.data.redis.core.script.DefaultRedisScript;
|
||||
import org.springframework.data.redis.core.script.RedisScript;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* @author valarchie
|
||||
*/
|
||||
@Component
|
||||
@RequiredArgsConstructor
|
||||
@Slf4j
|
||||
public class RedisRateLimitChecker extends AbstractRateLimitChecker{
|
||||
|
||||
private final RedisTemplate<Object, Object> redisTemplate;
|
||||
|
||||
private final RedisScript<Long> limitScript = new DefaultRedisScript<>(limitScriptText(), Long.class);
|
||||
|
||||
@Override
|
||||
public void check(RateLimit rateLimiter) {
|
||||
int maxCount = rateLimiter.maxCount();
|
||||
String combineKey = rateLimiter.limitType().generateCombinedKey(rateLimiter);
|
||||
|
||||
Long currentCount;
|
||||
try {
|
||||
currentCount = redisTemplate.execute(limitScript, ListUtil.of(combineKey), maxCount, rateLimiter.time());
|
||||
log.info("限制请求:{}, 当前请求次数:{}, 缓存key:{}", combineKey, currentCount, rateLimiter.key());
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException("redis限流器异常,请确保redis启动正常");
|
||||
}
|
||||
|
||||
if (currentCount == null) {
|
||||
throw new RuntimeException("redis限流器异常,请稍后再试");
|
||||
}
|
||||
|
||||
if (currentCount.intValue() > maxCount) {
|
||||
throw new ApiException(ErrorCode.Client.COMMON_REQUEST_TOO_OFTEN);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 限流脚本
|
||||
*/
|
||||
private static String limitScriptText() {
|
||||
return "local key = KEYS[1]\n" +
|
||||
"local count = tonumber(ARGV[1])\n" +
|
||||
"local time = tonumber(ARGV[2])\n" +
|
||||
"local current = redis.call('get', key);\n" +
|
||||
"if current and tonumber(current) > count then\n" +
|
||||
" return tonumber(current);\n" +
|
||||
"end\n" +
|
||||
"current = redis.call('incr', key)\n" +
|
||||
"if tonumber(current) == 1 then\n" +
|
||||
" redis.call('expire', key, time)\n" +
|
||||
"end\n" +
|
||||
"return tonumber(current);";
|
||||
}
|
||||
|
||||
}
|
||||
+95
@@ -0,0 +1,95 @@
|
||||
package com.agileboot.infrastructure.annotations.unrepeatable;
|
||||
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.agileboot.infrastructure.user.AuthenticationUtils;
|
||||
import com.agileboot.infrastructure.user.app.AppLoginUser;
|
||||
import com.agileboot.infrastructure.user.web.SystemLoginUser;
|
||||
import java.lang.annotation.Documented;
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Inherited;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
import java.lang.reflect.Method;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
/**
|
||||
* 自定义注解防止表单重复提交
|
||||
* 仅生效于有RequestBody注解的参数 因为使用RequestBodyAdvice来实现
|
||||
* @author valarchie
|
||||
*/
|
||||
@Inherited
|
||||
@Target(ElementType.METHOD)
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Documented
|
||||
public @interface Unrepeatable {
|
||||
|
||||
/**
|
||||
* 间隔时间(s),小于此时间视为重复提交
|
||||
*/
|
||||
int interval() default 5;
|
||||
|
||||
// TODO改成和rate limit一样 可以选择类型
|
||||
|
||||
/**
|
||||
* 检测条件类型
|
||||
*/
|
||||
CheckType checkType() default CheckType.SYSTEM_USER;
|
||||
|
||||
@Slf4j
|
||||
enum CheckType {
|
||||
/**
|
||||
* 按App用户
|
||||
*/
|
||||
APP_USER {
|
||||
@Override
|
||||
public String generateResubmitRedisKey(Method method) {
|
||||
String username;
|
||||
|
||||
try {
|
||||
AppLoginUser loginUser = AuthenticationUtils.getAppLoginUser();
|
||||
username = loginUser.getUsername();
|
||||
} catch (Exception e) {
|
||||
username = NO_LOGIN;
|
||||
log.error("could not find the related user to check repeatable submit.");
|
||||
}
|
||||
|
||||
return StrUtil.format(RESUBMIT_REDIS_KEY,
|
||||
this.name(),
|
||||
method.getDeclaringClass().getName(),
|
||||
method.getName(),
|
||||
username);
|
||||
}
|
||||
},
|
||||
/**
|
||||
* 按Web用户
|
||||
*/
|
||||
SYSTEM_USER {
|
||||
@Override
|
||||
public String generateResubmitRedisKey(Method method) {
|
||||
String username;
|
||||
|
||||
try {
|
||||
SystemLoginUser loginUser = AuthenticationUtils.getSystemLoginUser();
|
||||
username = loginUser.getUsername();
|
||||
} catch (Exception e) {
|
||||
username = NO_LOGIN;
|
||||
log.error("could not find the related user to check repeatable submit.");
|
||||
}
|
||||
|
||||
return StrUtil.format(RESUBMIT_REDIS_KEY,
|
||||
this.name(),
|
||||
method.getDeclaringClass().getName(),
|
||||
method.getName(),
|
||||
username);
|
||||
}
|
||||
};
|
||||
|
||||
public static final String NO_LOGIN = "Anonymous";
|
||||
public static final String RESUBMIT_REDIS_KEY = "resubmit:{}:{}:{}:{}";
|
||||
|
||||
public abstract String generateResubmitRedisKey(Method method);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
+67
@@ -0,0 +1,67 @@
|
||||
package com.agileboot.infrastructure.annotations.unrepeatable;
|
||||
|
||||
import cn.hutool.json.JSONUtil;
|
||||
import com.agileboot.common.exception.ApiException;
|
||||
import com.agileboot.common.exception.error.ErrorCode;
|
||||
import com.agileboot.infrastructure.cache.RedisUtil;
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.Objects;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.springframework.core.MethodParameter;
|
||||
import org.springframework.http.HttpInputMessage;
|
||||
import org.springframework.http.converter.HttpMessageConverter;
|
||||
import org.springframework.web.bind.annotation.ControllerAdvice;
|
||||
import org.springframework.web.servlet.mvc.method.annotation.RequestBodyAdviceAdapter;
|
||||
|
||||
/**
|
||||
* 重复提交拦截器 如果涉及前后端加解密的话 也可以通过继承RequestBodyAdvice来实现
|
||||
*
|
||||
* @author valarchie
|
||||
*/
|
||||
@ControllerAdvice(basePackages = "com.agileboot")
|
||||
@Slf4j
|
||||
@RequiredArgsConstructor
|
||||
public class UnrepeatableInterceptor extends RequestBodyAdviceAdapter {
|
||||
|
||||
private final RedisUtil redisUtil;
|
||||
|
||||
@Override
|
||||
public boolean supports(MethodParameter methodParameter, Type targetType,
|
||||
Class<? extends HttpMessageConverter<?>> converterType) {
|
||||
return methodParameter.hasMethodAnnotation(Unrepeatable.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param body 仅获取有RequestBody注解的参数
|
||||
*/
|
||||
@NotNull
|
||||
@Override
|
||||
public Object afterBodyRead(Object body, HttpInputMessage inputMessage, MethodParameter parameter, Type targetType,
|
||||
Class<? extends HttpMessageConverter<?>> converterType) {
|
||||
// 仅获取有RequestBody注解的参数
|
||||
String currentRequest = JSONUtil.toJsonStr(body);
|
||||
|
||||
Unrepeatable resubmitAnno = parameter.getMethodAnnotation(Unrepeatable.class);
|
||||
if (resubmitAnno != null) {
|
||||
String redisKey = resubmitAnno.checkType().generateResubmitRedisKey(parameter.getMethod());
|
||||
|
||||
log.info("请求重复提交拦截,当前key:{}, 当前参数:{}", redisKey, currentRequest);
|
||||
|
||||
String preRequest = redisUtil.getCacheObject(redisKey);
|
||||
if (preRequest != null) {
|
||||
boolean isSameRequest = Objects.equals(currentRequest, preRequest);
|
||||
|
||||
if (isSameRequest) {
|
||||
throw new ApiException(ErrorCode.Client.COMMON_REQUEST_RESUBMIT);
|
||||
}
|
||||
}
|
||||
redisUtil.setCacheObject(redisKey, currentRequest, resubmitAnno.interval(), TimeUnit.SECONDS);
|
||||
}
|
||||
|
||||
return body;
|
||||
}
|
||||
|
||||
}
|
||||
Vendored
+210
@@ -0,0 +1,210 @@
|
||||
package com.agileboot.infrastructure.cache;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.data.redis.core.BoundSetOperations;
|
||||
import org.springframework.data.redis.core.HashOperations;
|
||||
import org.springframework.data.redis.core.RedisTemplate;
|
||||
import org.springframework.data.redis.core.ValueOperations;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* spring redis 工具类
|
||||
*
|
||||
* @author valarchie
|
||||
**/
|
||||
@SuppressWarnings(value = {"unchecked", "rawtypes"})
|
||||
@Component
|
||||
@RequiredArgsConstructor
|
||||
public class RedisUtil {
|
||||
|
||||
public final RedisTemplate redisTemplate;
|
||||
|
||||
/**
|
||||
* 缓存基本的对象,Integer、String、实体类等
|
||||
*
|
||||
* @param key 缓存的键值
|
||||
* @param value 缓存的值
|
||||
*/
|
||||
public <T> void setCacheObject(final String key, final T value) {
|
||||
redisTemplate.opsForValue().set(key, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* 缓存基本的对象,Integer、String、实体类等
|
||||
*
|
||||
* @param key 缓存的键值
|
||||
* @param value 缓存的值
|
||||
* @param timeout 时间
|
||||
* @param timeUnit 时间颗粒度
|
||||
*/
|
||||
public <T> void setCacheObject(final String key, final T value, final Integer timeout, final TimeUnit timeUnit) {
|
||||
redisTemplate.opsForValue().set(key, value, timeout, timeUnit);
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置有效时间
|
||||
*
|
||||
* @param key Redis键
|
||||
* @param timeout 超时时间
|
||||
* @return true=设置成功;false=设置失败
|
||||
*/
|
||||
public boolean expire(final String key, final long timeout) {
|
||||
return expire(key, timeout, TimeUnit.SECONDS);
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置有效时间
|
||||
*
|
||||
* @param key Redis键
|
||||
* @param timeout 超时时间
|
||||
* @param unit 时间单位
|
||||
* @return true=设置成功;false=设置失败
|
||||
*/
|
||||
public Boolean expire(final String key, final long timeout, final TimeUnit unit) {
|
||||
return redisTemplate.expire(key, timeout, unit);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获得缓存的基本对象。
|
||||
*
|
||||
* @param key 缓存键值
|
||||
* @return 缓存键值对应的数据
|
||||
*/
|
||||
public <T> T getCacheObject(final String key) {
|
||||
ValueOperations<String, T> operation = redisTemplate.opsForValue();
|
||||
return operation.get(key);
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除单个对象
|
||||
*/
|
||||
public void deleteObject(final String key) {
|
||||
redisTemplate.delete(key);
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除集合对象
|
||||
*
|
||||
* @param collection 多个对象
|
||||
*/
|
||||
public Long deleteObject(final Collection collection) {
|
||||
return redisTemplate.delete(collection);
|
||||
}
|
||||
|
||||
/**
|
||||
* 缓存List数据
|
||||
*
|
||||
* @param key 缓存的键值
|
||||
* @param dataList 待缓存的List数据
|
||||
* @return 缓存的对象
|
||||
*/
|
||||
public <T> long setCacheList(final String key, final List<T> dataList) {
|
||||
Long count = redisTemplate.opsForList().rightPushAll(key, dataList);
|
||||
return count == null ? 0 : count;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获得缓存的list对象
|
||||
*
|
||||
* @param key 缓存的键值
|
||||
* @return 缓存键值对应的数据
|
||||
*/
|
||||
public <T> List<T> getCacheList(final String key) {
|
||||
return redisTemplate.opsForList().range(key, 0, -1);
|
||||
}
|
||||
|
||||
/**
|
||||
* 缓存Set
|
||||
*
|
||||
* @param key 缓存键值
|
||||
* @param dataSet 缓存的数据
|
||||
* @return 缓存数据的对象
|
||||
*/
|
||||
public <T> BoundSetOperations<String, T> setCacheSet(final String key, final Set<T> dataSet) {
|
||||
BoundSetOperations<String, T> setOperation = redisTemplate.boundSetOps(key);
|
||||
for (T t : dataSet) {
|
||||
setOperation.add(t);
|
||||
}
|
||||
return setOperation;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获得缓存的set
|
||||
*/
|
||||
public <T> Set<T> getCacheSet(final String key) {
|
||||
return redisTemplate.opsForSet().members(key);
|
||||
}
|
||||
|
||||
/**
|
||||
* 缓存Map
|
||||
*/
|
||||
public <T> void setCacheMap(final String key, final Map<String, T> dataMap) {
|
||||
if (dataMap != null) {
|
||||
redisTemplate.opsForHash().putAll(key, dataMap);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获得缓存的Map
|
||||
*/
|
||||
public <T> Map<String, T> getCacheMap(final String key) {
|
||||
return redisTemplate.opsForHash().entries(key);
|
||||
}
|
||||
|
||||
/**
|
||||
* 往Hash中存入数据
|
||||
*
|
||||
* @param key Redis键
|
||||
* @param hKey Hash键
|
||||
* @param value 值
|
||||
*/
|
||||
public <T> void setCacheMapValue(final String key, final String hKey, final T value) {
|
||||
redisTemplate.opsForHash().put(key, hKey, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取Hash中的数据
|
||||
*
|
||||
* @param key Redis键
|
||||
* @param hKey Hash键
|
||||
* @return Hash中的对象
|
||||
*/
|
||||
public <T> T getCacheMapValue(final String key, final String hKey) {
|
||||
HashOperations<String, String, T> opsForHash = redisTemplate.opsForHash();
|
||||
return opsForHash.get(key, hKey);
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除Hash中的数据
|
||||
*/
|
||||
public void delCacheMapValue(final String key, final String hKey) {
|
||||
HashOperations hashOperations = redisTemplate.opsForHash();
|
||||
hashOperations.delete(key, hKey);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取多个Hash中的数据
|
||||
*
|
||||
* @param key Redis键
|
||||
* @param hKeys Hash键集合
|
||||
* @return Hash对象集合
|
||||
*/
|
||||
public <T> List<T> getMultiCacheMapValue(final String key, final Collection<Object> hKeys) {
|
||||
return redisTemplate.opsForHash().multiGet(key, hKeys);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获得缓存的基本对象列表
|
||||
*
|
||||
* @param pattern 字符串前缀
|
||||
* @return 对象列表
|
||||
*/
|
||||
public Collection<String> keys(final String pattern) {
|
||||
return redisTemplate.keys(pattern);
|
||||
}
|
||||
}
|
||||
+14
@@ -0,0 +1,14 @@
|
||||
package com.agileboot.infrastructure.cache.aop;
|
||||
|
||||
/**
|
||||
* @author valarchie
|
||||
*/
|
||||
public class CacheNameConstants {
|
||||
|
||||
public static final String GUAVA = "guava";
|
||||
|
||||
public static final String REDIS = "redis";
|
||||
|
||||
private CacheNameConstants() {
|
||||
}
|
||||
}
|
||||
+91
@@ -0,0 +1,91 @@
|
||||
package com.agileboot.infrastructure.cache.aop;
|
||||
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.google.common.cache.CacheBuilder;
|
||||
import java.util.Objects;
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import javax.annotation.PostConstruct;
|
||||
import org.springframework.cache.Cache;
|
||||
import org.springframework.cache.support.SimpleValueWrapper;
|
||||
/**
|
||||
* @author valarchie
|
||||
*/
|
||||
//@Component
|
||||
public class GuavaCacheBean implements Cache {
|
||||
|
||||
/**
|
||||
* 缓存仓库
|
||||
*/
|
||||
private com.google.common.cache.Cache<Object, Object> storage;
|
||||
|
||||
@PostConstruct
|
||||
private void init() {
|
||||
storage = CacheBuilder.newBuilder()
|
||||
// 设置缓存的容量为100
|
||||
.maximumSize(100)
|
||||
// 设置初始容量为16
|
||||
.initialCapacity(16)
|
||||
// 设置过期时间为写入缓存后10分钟过期
|
||||
.refreshAfterWrite(10, TimeUnit.MINUTES)
|
||||
.build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return CacheNameConstants.GUAVA;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@Override
|
||||
public ValueWrapper get(Object key) {
|
||||
if (Objects.isNull(key)) {
|
||||
return null;
|
||||
}
|
||||
Object ifPresent = storage.getIfPresent(key.toString());
|
||||
return Objects.isNull(ifPresent) ? null : new SimpleValueWrapper(ifPresent);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void put(Object key, Object value) {
|
||||
if (StrUtil.isEmpty((CharSequence) key)) {
|
||||
return;
|
||||
}
|
||||
storage.put(key, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void evict(Object key) {
|
||||
if (key == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
storage.invalidate(key);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*-----------------------暂时不用实现的方法-----------------*/
|
||||
|
||||
|
||||
@Override
|
||||
public <T> T get(Object key, Class<T> type) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T get(Object key, Callable<T> valueLoader) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clear() {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getNativeCache() {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
+70
@@ -0,0 +1,70 @@
|
||||
package com.agileboot.infrastructure.cache.aop;
|
||||
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.agileboot.infrastructure.cache.RedisUtil;
|
||||
import java.util.concurrent.Callable;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.cache.Cache;
|
||||
import org.springframework.cache.support.SimpleValueWrapper;
|
||||
|
||||
/**
|
||||
* @author valarchie
|
||||
*/
|
||||
//@Component
|
||||
@RequiredArgsConstructor
|
||||
public class RedisCacheBean implements Cache {
|
||||
|
||||
/**
|
||||
* 缓存仓库
|
||||
*/
|
||||
private final RedisUtil redisUtil;
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return CacheNameConstants.REDIS;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void put(Object key, Object value) {
|
||||
if (StrUtil.isNotEmpty((CharSequence) key)) {
|
||||
redisUtil.setCacheObject((String) key, value);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void evict(Object key) {
|
||||
if (StrUtil.isNotEmpty((CharSequence) key)) {
|
||||
redisUtil.deleteObject((String) key);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public ValueWrapper get(Object key) {
|
||||
return key == null ? null : new SimpleValueWrapper(redisUtil.getCacheObject((String) key));
|
||||
}
|
||||
|
||||
|
||||
/*-----------------------暂时不用实现的方法-----------------*/
|
||||
|
||||
|
||||
@Override
|
||||
public <T> T get(Object key, Class<T> type) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T get(Object key, Callable<T> valueLoader) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getNativeCache() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clear() {
|
||||
|
||||
}
|
||||
}
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
package com.agileboot.infrastructure.cache.aop;
|
||||
|
||||
/**
|
||||
* 本来想通过注解的形式 @cacheable来实现缓存
|
||||
* 但是MybatisPlus 生成的Service类 里面是空的 不好打注解
|
||||
* 并且本项目借鉴CQRS的想法,所有写相关的操作,都放置在domainService当中,而查询可以通过
|
||||
* mybatis plus普通的service进行查询。
|
||||
* 查询和操作 分别在两个地方 如果用@cacheable注解的话, 在两个地方进行分别注解 很容易疏漏出问题
|
||||
* 所以最终还是想采用手动操作缓存的方式
|
||||
* 利用三级缓存 map-> guava -> redis 的形式
|
||||
*/
|
||||
+107
@@ -0,0 +1,107 @@
|
||||
package com.agileboot.infrastructure.cache.guava;
|
||||
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.google.common.base.Ticker;
|
||||
import com.google.common.cache.CacheBuilder;
|
||||
import com.google.common.cache.CacheLoader;
|
||||
import com.google.common.cache.LoadingCache;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
/**
|
||||
* 缓存接口实现类 二级缓存
|
||||
* @author valarchie
|
||||
*/
|
||||
@Slf4j
|
||||
public abstract class AbstractGuavaCacheTemplate<T> {
|
||||
|
||||
private final LoadingCache<String, Optional<T>> guavaCache = CacheBuilder.newBuilder()
|
||||
// 基于容量回收。缓存的最大数量。超过就取MAXIMUM_CAPACITY = 1 << 30。依靠LRU队列recencyQueue来进行容量淘汰
|
||||
.maximumSize(1024)
|
||||
// 基于容量回收。但这是统计占用内存大小,maximumWeight与maximumSize不能同时使用。设置最大总权重
|
||||
// .maximumWeight(1000)
|
||||
// 设置权重(可当成每个缓存占用的大小)
|
||||
// .weigher((o, o2) -> 5)
|
||||
// 软弱引用(引用强度顺序:强软弱虚)
|
||||
// -- 弱引用key
|
||||
// .weakKeys()
|
||||
// -- 弱引用value
|
||||
// .weakValues()
|
||||
// -- 软引用value
|
||||
// .softValues()
|
||||
// 过期失效回收
|
||||
// -- 没读写访问下,超过5秒会失效(非自动失效,需有任意get put方法才会扫描过期失效数据)
|
||||
// .expireAfterAccess(5L, TimeUnit.MINUTES)
|
||||
// -- 没写访问下,超过5秒会失效(非自动失效,需有任意put get方法才会扫描过期失效数据)
|
||||
// .expireAfterWrite(5L, TimeUnit.MINUTES)
|
||||
// 没写访问下,超过5秒会失效(非自动失效,需有任意put get方法才会扫描过期失效数据。但区别是会开一个异步线程进行刷新,刷新过程中访问返回旧数据)
|
||||
.refreshAfterWrite(5L, TimeUnit.MINUTES)
|
||||
// 移除监听事件
|
||||
.removalListener(removal -> {
|
||||
// 可做一些删除后动作,比如上报删除数据用于统计
|
||||
log.info("触发删除动作,删除的key={}, value={}", removal.getKey(), removal.getValue());
|
||||
})
|
||||
// 并行等级。决定segment数量的参数,concurrencyLevel与maxWeight共同决定
|
||||
.concurrencyLevel(16)
|
||||
// 开启缓存统计。比如命中次数、未命中次数等
|
||||
.recordStats()
|
||||
// 所有segment的初始总容量大小
|
||||
.initialCapacity(128)
|
||||
// 用于测试,可任意改变当前时间。参考:https://www.geek-share.com/detail/2689756248.html
|
||||
// 大坑 设置ticket为0 会导致缓存不会失效 定时刷新也不会触发,因为距离上次刷新时刻(永远是0)不会超过refreshAfterWrite定义的间隔。
|
||||
// 所以可以总结,这个Ticker直接返回0,会导致Cache的所有基于时间的过期和刷新策略都无法正常工作。Cache内容也不会按预期失效或刷新。
|
||||
// .ticker(new Ticker() {
|
||||
// @Override
|
||||
// public long read() {
|
||||
// return 0;
|
||||
// }
|
||||
// })
|
||||
.build(new CacheLoader<String, Optional<T>>() {
|
||||
@Override
|
||||
public Optional<T> load(String key) {
|
||||
T cacheObject = getObjectFromDb(key);
|
||||
log.debug("find the local guava cache of key: {} is {}", key, cacheObject);
|
||||
return Optional.ofNullable(cacheObject);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
|
||||
public T get(String key) {
|
||||
try {
|
||||
if (StrUtil.isEmpty(key)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
Optional<T> optional = guavaCache.get(key);
|
||||
return optional.orElse(null);
|
||||
} catch (ExecutionException e) {
|
||||
log.error("get cache object from guava cache failed.", e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void invalidate(String key) {
|
||||
if (StrUtil.isEmpty(key)) {
|
||||
return;
|
||||
}
|
||||
|
||||
guavaCache.invalidate(key);
|
||||
}
|
||||
|
||||
public void invalidateAll() {
|
||||
guavaCache.invalidateAll();
|
||||
}
|
||||
|
||||
/**
|
||||
* 从数据库加载数据
|
||||
*
|
||||
* @param id id
|
||||
* @return T
|
||||
*/
|
||||
public abstract T getObjectFromDb(Object id);
|
||||
|
||||
}
|
||||
+46
@@ -0,0 +1,46 @@
|
||||
package com.agileboot.infrastructure.cache.redis;
|
||||
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
* @author valarchie
|
||||
*/
|
||||
public enum CacheKeyEnum {
|
||||
|
||||
/**
|
||||
* Redis各类缓存集合
|
||||
*/
|
||||
CAPTCHAT("captcha_codes:", 2, TimeUnit.MINUTES),
|
||||
LOGIN_USER_KEY("login_tokens:", 30, TimeUnit.MINUTES),
|
||||
RATE_LIMIT_KEY("rate_limit:", 60, TimeUnit.SECONDS),
|
||||
USER_ENTITY_KEY("user_entity:", 60, TimeUnit.MINUTES),
|
||||
ROLE_ENTITY_KEY("role_entity:", 60, TimeUnit.MINUTES),
|
||||
POST_ENTITY_KEY("post_entity:", 60, TimeUnit.MINUTES),
|
||||
ROLE_MODEL_INFO_KEY("role_model_info:", 60, TimeUnit.MINUTES),
|
||||
|
||||
;
|
||||
|
||||
|
||||
CacheKeyEnum(String key, int expiration, TimeUnit timeUnit) {
|
||||
this.key = key;
|
||||
this.expiration = expiration;
|
||||
this.timeUnit = timeUnit;
|
||||
}
|
||||
|
||||
private final String key;
|
||||
private final int expiration;
|
||||
private final TimeUnit timeUnit;
|
||||
|
||||
public String key() {
|
||||
return key;
|
||||
}
|
||||
|
||||
public int expiration() {
|
||||
return expiration;
|
||||
}
|
||||
|
||||
public TimeUnit timeUnit() {
|
||||
return timeUnit;
|
||||
}
|
||||
|
||||
}
|
||||
+127
@@ -0,0 +1,127 @@
|
||||
package com.agileboot.infrastructure.cache.redis;
|
||||
|
||||
import com.agileboot.infrastructure.cache.RedisUtil;
|
||||
import com.google.common.cache.CacheBuilder;
|
||||
import com.google.common.cache.CacheLoader;
|
||||
import com.google.common.cache.LoadingCache;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
/**
|
||||
* 缓存接口实现类 三级缓存
|
||||
* @author valarchie
|
||||
*/
|
||||
@Slf4j
|
||||
public class RedisCacheTemplate<T> {
|
||||
|
||||
private final RedisUtil redisUtil;
|
||||
private final CacheKeyEnum redisRedisEnum;
|
||||
private final LoadingCache<String, Optional<T>> guavaCache;
|
||||
|
||||
public RedisCacheTemplate(RedisUtil redisUtil, CacheKeyEnum redisRedisEnum) {
|
||||
this.redisUtil = redisUtil;
|
||||
this.redisRedisEnum = redisRedisEnum;
|
||||
this.guavaCache = CacheBuilder.newBuilder()
|
||||
// 基于容量回收。缓存的最大数量。超过就取MAXIMUM_CAPACITY = 1 << 30。依靠LRU队列recencyQueue来进行容量淘汰
|
||||
.maximumSize(1024)
|
||||
.softValues()
|
||||
// 没写访问下,超过5秒会失效(非自动失效,需有任意put get方法才会扫描过期失效数据。
|
||||
// 但区别是会开一个异步线程进行刷新,刷新过程中访问返回旧数据)
|
||||
.expireAfterWrite(redisRedisEnum.expiration(), TimeUnit.MINUTES)
|
||||
// 并行等级。决定segment数量的参数,concurrencyLevel与maxWeight共同决定
|
||||
.concurrencyLevel(64)
|
||||
// 所有segment的初始总容量大小
|
||||
.initialCapacity(128)
|
||||
.build(new CacheLoader<String, Optional<T>>() {
|
||||
@Override
|
||||
public Optional<T> load(String cachedKey) {
|
||||
T cacheObject = redisUtil.getCacheObject(cachedKey);
|
||||
log.debug("find the redis cache of key: {} is {}", cachedKey, cacheObject);
|
||||
return Optional.ofNullable(cacheObject);
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 从缓存中获取对象 如果获取不到的话 从DB层面获取
|
||||
*
|
||||
* @param id id
|
||||
*/
|
||||
public T getObjectById(Object id) {
|
||||
String cachedKey = generateKey(id);
|
||||
try {
|
||||
Optional<T> optional = guavaCache.get(cachedKey);
|
||||
// log.debug("find the guava cache of key: {}", cachedKey);
|
||||
|
||||
if (!optional.isPresent()) {
|
||||
T objectFromDb = getObjectFromDb(id);
|
||||
set(id, objectFromDb);
|
||||
return objectFromDb;
|
||||
}
|
||||
|
||||
return optional.get();
|
||||
} catch (ExecutionException e) {
|
||||
log.error("从缓存中获取对象失败", e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 从缓存中获取 对象, 即使找不到的话 也不从DB中找
|
||||
* @param id id
|
||||
*/
|
||||
public T getObjectOnlyInCacheById(Object id) {
|
||||
String cachedKey = generateKey(id);
|
||||
try {
|
||||
Optional<T> optional = guavaCache.get(cachedKey);
|
||||
log.debug("find the guava cache of key: {}", cachedKey);
|
||||
return optional.orElse(null);
|
||||
} catch (ExecutionException e) {
|
||||
log.error("从缓存中获取对象失败", e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 从缓存中获取 对象, 即使找不到的话 也不从DB中找
|
||||
* @param cachedKey 直接通过redis的key来搜索
|
||||
*/
|
||||
public T getObjectOnlyInCacheByKey(String cachedKey) {
|
||||
try {
|
||||
Optional<T> optional = guavaCache.get(cachedKey);
|
||||
log.debug("find the guava cache of key: {}", cachedKey);
|
||||
return optional.orElse(null);
|
||||
} catch (ExecutionException e) {
|
||||
log.error("从缓存中获取对象失败", e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void set(Object id, T obj) {
|
||||
redisUtil.setCacheObject(generateKey(id), obj, redisRedisEnum.expiration(), redisRedisEnum.timeUnit());
|
||||
guavaCache.refresh(generateKey(id));
|
||||
}
|
||||
|
||||
public void delete(Object id) {
|
||||
redisUtil.deleteObject(generateKey(id));
|
||||
guavaCache.refresh(generateKey(id));
|
||||
}
|
||||
|
||||
public void refresh(Object id) {
|
||||
redisUtil.expire(generateKey(id), redisRedisEnum.expiration(), redisRedisEnum.timeUnit());
|
||||
guavaCache.refresh(generateKey(id));
|
||||
}
|
||||
|
||||
public String generateKey(Object id) {
|
||||
return redisRedisEnum.key() + id;
|
||||
}
|
||||
|
||||
public T getObjectFromDb(Object id) {
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
+21
@@ -0,0 +1,21 @@
|
||||
package com.agileboot.infrastructure.config;
|
||||
|
||||
import org.mybatis.spring.annotation.MapperScan;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.EnableAspectJAutoProxy;
|
||||
import org.springframework.scheduling.annotation.EnableScheduling;
|
||||
|
||||
/**
|
||||
* 程序注解配置
|
||||
* 注解EnableAspectJAutoProxy 表示通过aop框架暴露该代理对象,AopContext能够访问
|
||||
* 注解MapperScan 指定要扫描的Mapper类的包的路径
|
||||
* @author valarchie
|
||||
*/
|
||||
@Configuration
|
||||
@EnableAspectJAutoProxy(exposeProxy = true)
|
||||
@EnableScheduling
|
||||
// 因为如果直接指定db包 service也会被扫描到 所以通过markerInterface 进行限定
|
||||
@MapperScan(value = "com.agileboot.**.db", markerInterface = com.baomidou.mybatisplus.core.mapper.BaseMapper.class)
|
||||
public class ApplicationConfig {
|
||||
|
||||
}
|
||||
+80
@@ -0,0 +1,80 @@
|
||||
package com.agileboot.infrastructure.config;
|
||||
|
||||
import com.agileboot.infrastructure.exception.GlobalExceptionFilter;
|
||||
import com.agileboot.infrastructure.filter.TestFilter;
|
||||
import com.agileboot.infrastructure.filter.TraceIdFilter;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.boot.web.servlet.FilterRegistrationBean;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.core.Ordered;
|
||||
import org.springframework.web.cors.CorsConfiguration;
|
||||
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
|
||||
import org.springframework.web.filter.CorsFilter;
|
||||
|
||||
/**
|
||||
* Filter配置
|
||||
* @author valarchie
|
||||
*/
|
||||
@Configuration
|
||||
public class FilterConfig {
|
||||
|
||||
// TODO 后续统一到一个properties 类中比较好
|
||||
@Value("${agileboot.traceRequestIdKey}")
|
||||
private String requestIdKey;
|
||||
|
||||
|
||||
@Bean
|
||||
public FilterRegistrationBean<TestFilter> testFilterRegistrationBean() {
|
||||
FilterRegistrationBean<TestFilter> registration = new FilterRegistrationBean<>();
|
||||
registration.setFilter(new TestFilter());
|
||||
registration.addUrlPatterns("/*");
|
||||
registration.setName("testFilter");
|
||||
registration.setOrder(2);
|
||||
return registration;
|
||||
}
|
||||
|
||||
@Bean
|
||||
public FilterRegistrationBean<TraceIdFilter> traceIdFilterRegistrationBean() {
|
||||
FilterRegistrationBean<TraceIdFilter> registration = new FilterRegistrationBean<>();
|
||||
registration.setFilter(new TraceIdFilter(requestIdKey));
|
||||
registration.addUrlPatterns("/*");
|
||||
registration.setName("traceIdFilter");
|
||||
registration.setOrder(Ordered.HIGHEST_PRECEDENCE);
|
||||
return registration;
|
||||
}
|
||||
|
||||
@Bean
|
||||
public FilterRegistrationBean<GlobalExceptionFilter> exceptionFilterRegistrationBean() {
|
||||
FilterRegistrationBean<GlobalExceptionFilter> registration = new FilterRegistrationBean<>();
|
||||
registration.setFilter(new GlobalExceptionFilter());
|
||||
registration.addUrlPatterns("/*");
|
||||
registration.setName("exceptionFilter");
|
||||
registration.setOrder(Ordered.HIGHEST_PRECEDENCE);
|
||||
return registration;
|
||||
}
|
||||
|
||||
/**
|
||||
* 跨域配置
|
||||
*/
|
||||
@Bean
|
||||
public CorsFilter corsFilter() {
|
||||
CorsConfiguration config = new CorsConfiguration();
|
||||
config.setAllowCredentials(true);
|
||||
// 设置访问源地址
|
||||
config.addAllowedOriginPattern("*");
|
||||
// 设置访问源请求头
|
||||
config.addAllowedHeader("*");
|
||||
// 设置访问源请求方法
|
||||
config.addAllowedMethod("*");
|
||||
// 有效期 1800秒
|
||||
config.setMaxAge(1800L);
|
||||
// 添加映射路径,拦截一切请求
|
||||
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
|
||||
source.registerCorsConfiguration("/**", config);
|
||||
// 返回新的CorsFilter
|
||||
return new CorsFilter(source);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
+108
@@ -0,0 +1,108 @@
|
||||
package com.agileboot.infrastructure.config;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.aop.Advisor;
|
||||
import org.springframework.aop.aspectj.AspectJExpressionPointcut;
|
||||
import org.springframework.aop.support.DefaultPointcutAdvisor;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.transaction.TransactionDefinition;
|
||||
import org.springframework.transaction.TransactionManager;
|
||||
import org.springframework.transaction.interceptor.NameMatchTransactionAttributeSource;
|
||||
import org.springframework.transaction.interceptor.RollbackRuleAttribute;
|
||||
import org.springframework.transaction.interceptor.RuleBasedTransactionAttribute;
|
||||
import org.springframework.transaction.interceptor.TransactionInterceptor;
|
||||
|
||||
/**
|
||||
* 全局事务管理器
|
||||
* @author valarchie
|
||||
*/
|
||||
@Configuration
|
||||
@RequiredArgsConstructor
|
||||
public class GlobalTransactionConfig {
|
||||
|
||||
/**
|
||||
* 配置全局事务的切点为service层的所有方法 AOP切面表达式 可参考(<a
|
||||
* href="https://blog.csdn.net/ycf921244819/article/details/106599489">https://blog.csdn.net/ycf921244819/article/details/106599489</a>)
|
||||
* 本项目设置在 applicationService层
|
||||
*/
|
||||
private static final String POINTCUT_EXPRESSION = "execution(public * com.agileboot.domain..*.*ApplicationService.*(..))";
|
||||
|
||||
|
||||
/**
|
||||
* 注入事务管理器
|
||||
*/
|
||||
private final TransactionManager transactionManager;
|
||||
|
||||
/**
|
||||
* 配置事务拦截器
|
||||
*
|
||||
* @return TransactionInterceptor
|
||||
*/
|
||||
@Bean
|
||||
public TransactionInterceptor txAdvice() {
|
||||
RuleBasedTransactionAttribute txAttrRequired = new RuleBasedTransactionAttribute();
|
||||
txAttrRequired.setName("REQUIRED事务");
|
||||
|
||||
//设置事务传播机制,默认是PROPAGATION_REQUIRED:如果当前存在事务,则加入该事务;如果当前没有事务,则创建一个新的事务
|
||||
txAttrRequired.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
|
||||
//设置异常回滚为Exception 默认是RuntimeException
|
||||
List<RollbackRuleAttribute> rollbackRuleAttributes = new ArrayList<>();
|
||||
rollbackRuleAttributes.add(new RollbackRuleAttribute(Exception.class));
|
||||
txAttrRequired.setRollbackRules(rollbackRuleAttributes);
|
||||
|
||||
|
||||
RuleBasedTransactionAttribute txAttrRequiredReadOnly = new RuleBasedTransactionAttribute();
|
||||
txAttrRequiredReadOnly.setName("SUPPORTS事务");
|
||||
//设置事务传播机制,PROPAGATION_SUPPORTS:如果当前存在事务,则加入该事务;如果当前没有事务,则以非事务的方式继续运行
|
||||
txAttrRequiredReadOnly.setPropagationBehavior(TransactionDefinition.PROPAGATION_SUPPORTS);
|
||||
//设置异常回滚为Exception 默认是RuntimeException
|
||||
txAttrRequiredReadOnly.setRollbackRules(rollbackRuleAttributes);
|
||||
txAttrRequiredReadOnly.setReadOnly(true);
|
||||
|
||||
// 事务管理规则,声明具备事务管理的方法名
|
||||
NameMatchTransactionAttributeSource source = new NameMatchTransactionAttributeSource();
|
||||
// 方法名规则限制,必须以下列开头才会加入事务管理当中
|
||||
// 新增
|
||||
source.addTransactionalMethod("add*", txAttrRequired);
|
||||
source.addTransactionalMethod("save*", txAttrRequired);
|
||||
source.addTransactionalMethod("create*", txAttrRequired);
|
||||
source.addTransactionalMethod("insert*", txAttrRequired);
|
||||
// 修改
|
||||
source.addTransactionalMethod("submit*", txAttrRequired);
|
||||
source.addTransactionalMethod("edit*", txAttrRequired);
|
||||
source.addTransactionalMethod("update*", txAttrRequired);
|
||||
source.addTransactionalMethod("modify*", txAttrRequired);
|
||||
source.addTransactionalMethod("exec*", txAttrRequired);
|
||||
source.addTransactionalMethod("set*", txAttrRequired);
|
||||
// 删除
|
||||
source.addTransactionalMethod("del*", txAttrRequired);
|
||||
source.addTransactionalMethod("remove*", txAttrRequired);
|
||||
|
||||
//对于查询方法,根据实际情况添加事务管理 可能存在查询多个数据时,已查询出来的数据刚好被改变的情况
|
||||
source.addTransactionalMethod("get*", txAttrRequiredReadOnly);
|
||||
source.addTransactionalMethod("select*", txAttrRequiredReadOnly);
|
||||
source.addTransactionalMethod("query*", txAttrRequiredReadOnly);
|
||||
source.addTransactionalMethod("find*", txAttrRequiredReadOnly);
|
||||
source.addTransactionalMethod("list*", txAttrRequiredReadOnly);
|
||||
source.addTransactionalMethod("count*", txAttrRequiredReadOnly);
|
||||
source.addTransactionalMethod("is*", txAttrRequiredReadOnly);
|
||||
|
||||
return new TransactionInterceptor(transactionManager, source);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 设置切面
|
||||
* @return Advisor
|
||||
*/
|
||||
@Bean
|
||||
public Advisor txAdviceAdvisor() {
|
||||
AspectJExpressionPointcut pointcut = new AspectJExpressionPointcut();
|
||||
pointcut.setExpression(POINTCUT_EXPRESSION);
|
||||
return new DefaultPointcutAdvisor(pointcut, txAdvice());
|
||||
}
|
||||
|
||||
}
|
||||
+31
@@ -0,0 +1,31 @@
|
||||
package com.agileboot.infrastructure.config;
|
||||
|
||||
import com.agileboot.infrastructure.security.xss.JsonHtmlXssTrimSerializer;
|
||||
import java.util.TimeZone;
|
||||
import org.springframework.boot.autoconfigure.jackson.Jackson2ObjectMapperBuilderCustomizer;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder;
|
||||
|
||||
/**
|
||||
* @author valarchie
|
||||
*/
|
||||
@Configuration
|
||||
public class JacksonConfig implements Jackson2ObjectMapperBuilderCustomizer{
|
||||
|
||||
// 这种配置方式会覆盖 yml中的jackson配置, 使用下面的customize配置则不会
|
||||
// @Bean
|
||||
// Jackson2ObjectMapperBuilder objectMapperBuilder() {
|
||||
// Jackson2ObjectMapperBuilder builder = new Jackson2ObjectMapperBuilder();
|
||||
// builder.deserializers(new JsonHtmlXssTrimSerializer());
|
||||
// return builder;
|
||||
// }
|
||||
|
||||
@Override
|
||||
public void customize(Jackson2ObjectMapperBuilder jacksonObjectMapperBuilder) {
|
||||
// 防XSS脚本注入
|
||||
jacksonObjectMapperBuilder.deserializers(new JsonHtmlXssTrimSerializer());
|
||||
// 默认时区配置
|
||||
jacksonObjectMapperBuilder.timeZone(TimeZone.getDefault());
|
||||
}
|
||||
|
||||
}
|
||||
+37
@@ -0,0 +1,37 @@
|
||||
package com.agileboot.infrastructure.config;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.DbType;
|
||||
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
|
||||
import com.baomidou.mybatisplus.extension.plugins.inner.BlockAttackInnerInterceptor;
|
||||
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
|
||||
import javax.sql.DataSource;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
|
||||
import org.springframework.transaction.annotation.EnableTransactionManagement;
|
||||
|
||||
/**
|
||||
* Mybatis支持*匹配扫描包
|
||||
*
|
||||
* @author valarchie
|
||||
*/
|
||||
@Configuration
|
||||
@EnableTransactionManagement
|
||||
public class MyBatisConfig {
|
||||
|
||||
@Bean
|
||||
public MybatisPlusInterceptor mybatisPlusInterceptor() {
|
||||
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
|
||||
interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
|
||||
interceptor.addInnerInterceptor(new BlockAttackInnerInterceptor());
|
||||
return interceptor;
|
||||
}
|
||||
|
||||
@Bean
|
||||
public DataSourceTransactionManager transactionManager(DataSource dataSource) {
|
||||
DataSourceTransactionManager transactionManager = new DataSourceTransactionManager();
|
||||
transactionManager.setDataSource(dataSource);
|
||||
return transactionManager;
|
||||
}
|
||||
|
||||
}
|
||||
+27
@@ -0,0 +1,27 @@
|
||||
package com.agileboot.infrastructure.config;
|
||||
|
||||
import com.agileboot.common.config.AgileBootConfig;
|
||||
import com.agileboot.common.constant.Constants;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
|
||||
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
|
||||
|
||||
/**
|
||||
* 通用配置
|
||||
*
|
||||
* @author valarchie
|
||||
*/
|
||||
@Configuration
|
||||
@RequiredArgsConstructor
|
||||
public class ResourcesConfig implements WebMvcConfigurer {
|
||||
|
||||
@Override
|
||||
public void addResourceHandlers(ResourceHandlerRegistry registry) {
|
||||
/* 本地文件上传路径 */
|
||||
registry.addResourceHandler("/" + Constants.RESOURCE_PREFIX + "/**")
|
||||
.addResourceLocations("file:" + AgileBootConfig.getFileBaseDir() + "/");
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
+29
@@ -0,0 +1,29 @@
|
||||
package com.agileboot.infrastructure.config;
|
||||
|
||||
import io.swagger.v3.oas.models.ExternalDocumentation;
|
||||
import io.swagger.v3.oas.models.OpenAPI;
|
||||
import io.swagger.v3.oas.models.info.Info;
|
||||
import io.swagger.v3.oas.models.info.License;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
/**
|
||||
* @author valarchie
|
||||
* SpringDoc API文档相关配置
|
||||
*/
|
||||
@Configuration
|
||||
public class SpringDocConfig {
|
||||
|
||||
@Bean
|
||||
public OpenAPI agileBootApi() {
|
||||
return new OpenAPI()
|
||||
.info(new Info().title("Agileboot后台管理系统")
|
||||
.description("Agileboot API 演示")
|
||||
.version("v1.8.0")
|
||||
.license(new License().name("MIT 3.0").url("https://github.com/valarchie/AgileBoot-Back-End")))
|
||||
.externalDocs(new ExternalDocumentation()
|
||||
.description("Agileboot后台管理系统接口文档")
|
||||
.url("https://juejin.cn/column/7159946528827080734"));
|
||||
}
|
||||
|
||||
}
|
||||
+97
@@ -0,0 +1,97 @@
|
||||
package com.agileboot.infrastructure.config.captcha;
|
||||
|
||||
import static com.google.code.kaptcha.Constants.KAPTCHA_BORDER;
|
||||
import static com.google.code.kaptcha.Constants.KAPTCHA_BORDER_COLOR;
|
||||
import static com.google.code.kaptcha.Constants.KAPTCHA_IMAGE_HEIGHT;
|
||||
import static com.google.code.kaptcha.Constants.KAPTCHA_IMAGE_WIDTH;
|
||||
import static com.google.code.kaptcha.Constants.KAPTCHA_NOISE_COLOR;
|
||||
import static com.google.code.kaptcha.Constants.KAPTCHA_NOISE_IMPL;
|
||||
import static com.google.code.kaptcha.Constants.KAPTCHA_OBSCURIFICATOR_IMPL;
|
||||
import static com.google.code.kaptcha.Constants.KAPTCHA_SESSION_CONFIG_KEY;
|
||||
import static com.google.code.kaptcha.Constants.KAPTCHA_TEXTPRODUCER_CHAR_LENGTH;
|
||||
import static com.google.code.kaptcha.Constants.KAPTCHA_TEXTPRODUCER_CHAR_SPACE;
|
||||
import static com.google.code.kaptcha.Constants.KAPTCHA_TEXTPRODUCER_FONT_COLOR;
|
||||
import static com.google.code.kaptcha.Constants.KAPTCHA_TEXTPRODUCER_FONT_NAMES;
|
||||
import static com.google.code.kaptcha.Constants.KAPTCHA_TEXTPRODUCER_FONT_SIZE;
|
||||
import static com.google.code.kaptcha.Constants.KAPTCHA_TEXTPRODUCER_IMPL;
|
||||
|
||||
import com.google.code.kaptcha.impl.DefaultKaptcha;
|
||||
import com.google.code.kaptcha.util.Config;
|
||||
import java.util.Properties;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
/**
|
||||
* 验证码配置
|
||||
*
|
||||
* @author ruoyi
|
||||
*/
|
||||
@Configuration
|
||||
public class CaptchaConfig {
|
||||
|
||||
@Bean(name = "captchaProducer")
|
||||
public DefaultKaptcha getCaptchaBean() {
|
||||
DefaultKaptcha defaultKaptcha = new DefaultKaptcha();
|
||||
Properties properties = new Properties();
|
||||
// 是否有边框 默认为true 我们可以自己设置yes,no
|
||||
properties.setProperty(KAPTCHA_BORDER, "yes");
|
||||
// 验证码文本字符颜色 默认为Color.BLACK
|
||||
properties.setProperty(KAPTCHA_TEXTPRODUCER_FONT_COLOR, "black");
|
||||
// 验证码图片宽度 默认为200
|
||||
properties.setProperty(KAPTCHA_IMAGE_WIDTH, "160");
|
||||
// 验证码图片高度 默认为50
|
||||
properties.setProperty(KAPTCHA_IMAGE_HEIGHT, "60");
|
||||
// 验证码文本字符大小 默认为40
|
||||
properties.setProperty(KAPTCHA_TEXTPRODUCER_FONT_SIZE, "38");
|
||||
// KAPTCHA_SESSION_KEY
|
||||
properties.setProperty(KAPTCHA_SESSION_CONFIG_KEY, "kaptchaCode");
|
||||
// 验证码文本字符长度 默认为5
|
||||
properties.setProperty(KAPTCHA_TEXTPRODUCER_CHAR_LENGTH, "4");
|
||||
// 验证码文本字体样式 默认为new Font("Arial", 1, fontSize), new Font("Courier", 1, fontSize)
|
||||
properties.setProperty(KAPTCHA_TEXTPRODUCER_FONT_NAMES, "Arial,Courier");
|
||||
// 图片样式 水纹com.google.code.kaptcha.impl.WaterRipple 鱼眼com.google.code.kaptcha.impl.FishEyeGimpy
|
||||
// 阴影com.google.code.kaptcha.impl.ShadowGimpy
|
||||
properties.setProperty(KAPTCHA_OBSCURIFICATOR_IMPL, "com.google.code.kaptcha.impl.ShadowGimpy");
|
||||
Config config = new Config(properties);
|
||||
defaultKaptcha.setConfig(config);
|
||||
return defaultKaptcha;
|
||||
}
|
||||
|
||||
@Bean(name = "captchaProducerMath")
|
||||
public DefaultKaptcha getKaptchaBeanMath() {
|
||||
DefaultKaptcha defaultKaptcha = new DefaultKaptcha();
|
||||
Properties properties = new Properties();
|
||||
// 是否有边框 默认为true 我们可以自己设置yes,no
|
||||
properties.setProperty(KAPTCHA_BORDER, "yes");
|
||||
// 边框颜色 默认为Color.BLACK
|
||||
properties.setProperty(KAPTCHA_BORDER_COLOR, "105,179,90");
|
||||
// 验证码文本字符颜色 默认为Color.BLACK
|
||||
properties.setProperty(KAPTCHA_TEXTPRODUCER_FONT_COLOR, "blue");
|
||||
// 验证码图片宽度 默认为200
|
||||
properties.setProperty(KAPTCHA_IMAGE_WIDTH, "160");
|
||||
// 验证码图片高度 默认为50
|
||||
properties.setProperty(KAPTCHA_IMAGE_HEIGHT, "60");
|
||||
// 验证码文本字符大小 默认为40
|
||||
properties.setProperty(KAPTCHA_TEXTPRODUCER_FONT_SIZE, "35");
|
||||
// KAPTCHA_SESSION_KEY
|
||||
properties.setProperty(KAPTCHA_SESSION_CONFIG_KEY, "kaptchaCodeMath");
|
||||
// 验证码文本生成器 需要填 文本生成器类的全限定包名
|
||||
properties.setProperty(KAPTCHA_TEXTPRODUCER_IMPL, "com.agileboot.infrastructure.config.captcha.CaptchaMathTextCreator");
|
||||
// 验证码文本字符间距 默认为2
|
||||
properties.setProperty(KAPTCHA_TEXTPRODUCER_CHAR_SPACE, "3");
|
||||
// 验证码文本字符长度 默认为5
|
||||
properties.setProperty(KAPTCHA_TEXTPRODUCER_CHAR_LENGTH, "6");
|
||||
// 验证码文本字体样式 默认为new Font("Arial", 1, fontSize), new Font("Courier", 1, fontSize)
|
||||
properties.setProperty(KAPTCHA_TEXTPRODUCER_FONT_NAMES, "Arial,Courier");
|
||||
// 验证码噪点颜色 默认为Color.BLACK
|
||||
properties.setProperty(KAPTCHA_NOISE_COLOR, "white");
|
||||
// 干扰实现类
|
||||
properties.setProperty(KAPTCHA_NOISE_IMPL, "com.google.code.kaptcha.impl.NoNoise");
|
||||
// 图片样式 水纹com.google.code.kaptcha.impl.WaterRipple 鱼眼com.google.code.kaptcha.impl.FishEyeGimpy
|
||||
// 阴影com.google.code.kaptcha.impl.ShadowGimpy
|
||||
properties.setProperty(KAPTCHA_OBSCURIFICATOR_IMPL, "com.google.code.kaptcha.impl.ShadowGimpy");
|
||||
Config config = new Config(properties);
|
||||
defaultKaptcha.setConfig(config);
|
||||
return defaultKaptcha;
|
||||
}
|
||||
}
|
||||
+75
@@ -0,0 +1,75 @@
|
||||
package com.agileboot.infrastructure.config.captcha;
|
||||
|
||||
import cn.hutool.core.util.EnumUtil;
|
||||
import cn.hutool.core.util.RandomUtil;
|
||||
import com.google.code.kaptcha.text.impl.DefaultTextCreator;
|
||||
|
||||
/**
|
||||
* verification code of math Generator
|
||||
*
|
||||
* @author valarchie
|
||||
*/
|
||||
public class CaptchaMathTextCreator extends DefaultTextCreator {
|
||||
|
||||
@Override
|
||||
public String getText() {
|
||||
int x = RandomUtil.randomInt(13);
|
||||
int y = RandomUtil.randomInt(13);
|
||||
Operand randomOperand = EnumUtil.getEnumAt(Operand.class, RandomUtil.randomInt(4));
|
||||
|
||||
StringBuilder mathExpression = new StringBuilder();
|
||||
int result = randomOperand.generateMathExpression(x, y, mathExpression);
|
||||
|
||||
mathExpression.append("=?@").append(result);
|
||||
return mathExpression.toString();
|
||||
}
|
||||
|
||||
enum Operand {
|
||||
/**
|
||||
* 加减乘除操作 用来生成验证码的图片表达式
|
||||
*/
|
||||
ADD {
|
||||
@Override
|
||||
public int generateMathExpression(int x, int y, StringBuilder expression) {
|
||||
expression.append(x);
|
||||
expression.append("+");
|
||||
expression.append(y);
|
||||
return x + y;
|
||||
}
|
||||
},
|
||||
MINUS {
|
||||
@Override
|
||||
public int generateMathExpression(int x, int y, StringBuilder expression) {
|
||||
expression.append(Math.max(x, y));
|
||||
expression.append("-");
|
||||
expression.append(Math.min(x, y));
|
||||
return Math.abs(x - y);
|
||||
}
|
||||
},
|
||||
MULTIPLE {
|
||||
@Override
|
||||
public int generateMathExpression(int x, int y, StringBuilder expression) {
|
||||
expression.append(x);
|
||||
expression.append("*");
|
||||
expression.append(y);
|
||||
return x * y;
|
||||
}
|
||||
},
|
||||
DIVIDE {
|
||||
@Override
|
||||
public int generateMathExpression(int x, int y, StringBuilder expression) {
|
||||
// Judge whether an integer can be divided
|
||||
if (x != 0 && y % x == 0) {
|
||||
expression.append(y);
|
||||
expression.append("/");
|
||||
expression.append(x);
|
||||
return y / x;
|
||||
} else {
|
||||
// use add addition instead
|
||||
return Operand.ADD.generateMathExpression(x, y, expression);
|
||||
}
|
||||
}
|
||||
};
|
||||
public abstract int generateMathExpression(int x, int y, StringBuilder expression);
|
||||
}
|
||||
}
|
||||
+38
@@ -0,0 +1,38 @@
|
||||
package com.agileboot.infrastructure.config.redis;
|
||||
|
||||
import javax.annotation.PostConstruct;
|
||||
import javax.annotation.PreDestroy;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import redis.embedded.RedisServer;
|
||||
|
||||
/**
|
||||
* @author valarchie
|
||||
*/
|
||||
@Configuration
|
||||
@ConditionalOnExpression("'${agileboot.embedded.redis}' == 'true'")
|
||||
public class EmbeddedRedisConfig {
|
||||
|
||||
@Value("${spring.redis.port}")
|
||||
private Integer port;
|
||||
|
||||
private RedisServer redisServer;
|
||||
|
||||
|
||||
@PostConstruct
|
||||
public void postConstruct() {
|
||||
RedisServer redisServer = RedisServer.builder().port(port)
|
||||
.setting("maxheap 32M")
|
||||
.setting("daemonize no")
|
||||
.setting("appendonly no").build();
|
||||
this.redisServer = redisServer;
|
||||
redisServer.start();
|
||||
}
|
||||
|
||||
@PreDestroy
|
||||
public void preDestroy() {
|
||||
redisServer.stop();
|
||||
}
|
||||
|
||||
}
|
||||
+61
@@ -0,0 +1,61 @@
|
||||
package com.agileboot.infrastructure.config.redis;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonAutoDetect;
|
||||
import com.fasterxml.jackson.annotation.JsonTypeInfo;
|
||||
import com.fasterxml.jackson.annotation.PropertyAccessor;
|
||||
import com.fasterxml.jackson.databind.DeserializationFeature;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.fasterxml.jackson.databind.SerializationFeature;
|
||||
import com.fasterxml.jackson.databind.jsontype.impl.LaissezFaireSubTypeValidator;
|
||||
import com.fasterxml.jackson.databind.module.SimpleModule;
|
||||
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
|
||||
import org.springframework.cache.annotation.CachingConfigurerSupport;
|
||||
import org.springframework.cache.annotation.EnableCaching;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.data.redis.connection.RedisConnectionFactory;
|
||||
import org.springframework.data.redis.core.RedisTemplate;
|
||||
import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer;
|
||||
import org.springframework.data.redis.serializer.StringRedisSerializer;
|
||||
|
||||
/**
|
||||
* redis配置
|
||||
*
|
||||
* @author valarchie
|
||||
*/
|
||||
@Configuration
|
||||
@EnableCaching
|
||||
public class RedisConfig extends CachingConfigurerSupport {
|
||||
|
||||
@Bean
|
||||
public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory connectionFactory) {
|
||||
RedisTemplate<Object, Object> template = new RedisTemplate<>();
|
||||
template.setConnectionFactory(connectionFactory);
|
||||
|
||||
ObjectMapper objectMapper = new ObjectMapper();
|
||||
objectMapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
|
||||
objectMapper.registerModule(new JavaTimeModule());
|
||||
objectMapper.registerModule((new SimpleModule()));
|
||||
//有属性不能映射的时候不报错
|
||||
objectMapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
|
||||
//对象为空时不抛异常
|
||||
objectMapper.disable(SerializationFeature.FAIL_ON_EMPTY_BEANS);
|
||||
objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
|
||||
objectMapper.activateDefaultTyping(LaissezFaireSubTypeValidator.instance, ObjectMapper.DefaultTyping.NON_FINAL,
|
||||
JsonTypeInfo.As.PROPERTY);
|
||||
|
||||
GenericJackson2JsonRedisSerializer serializer = new GenericJackson2JsonRedisSerializer(objectMapper);
|
||||
|
||||
template.setKeySerializer(new StringRedisSerializer());
|
||||
template.setValueSerializer(serializer);
|
||||
|
||||
// Hash的key也采用StringRedisSerializer的序列化方式
|
||||
template.setHashKeySerializer(new StringRedisSerializer());
|
||||
template.setHashValueSerializer(serializer);
|
||||
|
||||
template.afterPropertiesSet();
|
||||
return template;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
+73
@@ -0,0 +1,73 @@
|
||||
package com.agileboot.infrastructure.exception;
|
||||
|
||||
import cn.hutool.core.map.MapUtil;
|
||||
import com.agileboot.common.exception.ApiException;
|
||||
import com.agileboot.common.exception.error.ErrorCode.Internal;
|
||||
import java.sql.SQLException;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.ibatis.exceptions.PersistenceException;
|
||||
import org.aspectj.lang.ProceedingJoinPoint;
|
||||
import org.aspectj.lang.annotation.Around;
|
||||
import org.aspectj.lang.annotation.Aspect;
|
||||
import org.aspectj.lang.annotation.Pointcut;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
|
||||
/**
|
||||
* @author valarchie
|
||||
*/
|
||||
@Aspect
|
||||
@Component
|
||||
@Slf4j
|
||||
public class DbExceptionAspect {
|
||||
|
||||
|
||||
@Pointcut("execution(* com.agileboot..db..*(..))")
|
||||
public void dbException() {
|
||||
}
|
||||
|
||||
/**
|
||||
* 包装成ApiException 再交给globalExceptionHandler处理
|
||||
*
|
||||
* @param joinPoint joinPoint
|
||||
* @return object
|
||||
*/
|
||||
@Around("dbException()")
|
||||
public Object aroundDbException(ProceedingJoinPoint joinPoint) throws Throwable {
|
||||
Object proceed;
|
||||
try {
|
||||
// 将应用层的数据库错误 捕获并进行转换 主要捕获 sql形式的异常
|
||||
proceed = joinPoint.proceed();
|
||||
} catch (ApiException apiException) {
|
||||
throw apiException;
|
||||
} catch (Exception sqlException) {
|
||||
ApiException wrapException = new ApiException(sqlException, Internal.DB_INTERNAL_ERROR);
|
||||
wrapException.setPayload(MapUtil.of("detail", sqlException.getMessage()));
|
||||
throw wrapException;
|
||||
}
|
||||
return proceed;
|
||||
}
|
||||
|
||||
@Pointcut("bean(*ApplicationService)")
|
||||
public void applicationDbException() {
|
||||
}
|
||||
|
||||
@Around("applicationDbException()")
|
||||
public Object aroundApplicationDbException(ProceedingJoinPoint joinPoint) throws Throwable {
|
||||
Object proceed;
|
||||
try {
|
||||
// 将应用层的数据库错误 捕获并进行转换 主要捕获 jpa形式的 insert save 等模型抛出的错误
|
||||
proceed = joinPoint.proceed();
|
||||
} catch (ApiException ae) {
|
||||
throw ae;
|
||||
} catch (SQLException | PersistenceException sqlException) {
|
||||
ApiException wrapException = new ApiException(sqlException, Internal.DB_INTERNAL_ERROR);
|
||||
wrapException.setPayload(MapUtil.of("detail", sqlException.getMessage()));
|
||||
throw wrapException;
|
||||
}
|
||||
|
||||
return proceed;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
+58
@@ -0,0 +1,58 @@
|
||||
package com.agileboot.infrastructure.exception;
|
||||
|
||||
|
||||
import cn.hutool.json.JSONUtil;
|
||||
import com.agileboot.common.core.dto.ResponseDTO;
|
||||
import com.agileboot.common.exception.ApiException;
|
||||
import com.agileboot.common.exception.error.ErrorCode.Internal;
|
||||
import java.io.IOException;
|
||||
import javax.servlet.Filter;
|
||||
import javax.servlet.FilterChain;
|
||||
import javax.servlet.FilterConfig;
|
||||
import javax.servlet.ServletRequest;
|
||||
import javax.servlet.ServletResponse;
|
||||
import javax.servlet.annotation.WebFilter;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
|
||||
/**
|
||||
* 异常过滤器,因为配置的全局异常捕获器只能捕获MVC框架的异常
|
||||
* 不能捕获filter的异常
|
||||
* @author valarchie
|
||||
*/
|
||||
@Slf4j
|
||||
@WebFilter(filterName = "ExceptionFilter", urlPatterns = "/*")
|
||||
public class GlobalExceptionFilter implements Filter {
|
||||
|
||||
@Override
|
||||
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException {
|
||||
try {
|
||||
chain.doFilter(request, response);
|
||||
} catch (ApiException ex) {
|
||||
log.error("global filter exceptions", ex);
|
||||
String resultJson = JSONUtil.toJsonStr(ResponseDTO.fail(ex));
|
||||
writeToResponse(response, resultJson);
|
||||
} catch (Exception e) {
|
||||
log.error("global filter exceptions, unknown error:", e);
|
||||
ResponseDTO<Object> responseDTO = ResponseDTO.fail(new ApiException(Internal.INTERNAL_ERROR, e.getMessage()));
|
||||
String resultJson = JSONUtil.toJsonStr(responseDTO);
|
||||
writeToResponse(response, resultJson);
|
||||
}
|
||||
}
|
||||
|
||||
private void writeToResponse(ServletResponse response, String resultJson) throws IOException {
|
||||
response.setContentType("application/json");
|
||||
response.setCharacterEncoding("UTF-8");
|
||||
response.getWriter().write(resultJson);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init(FilterConfig filterConfig) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void destroy() {
|
||||
|
||||
}
|
||||
}
|
||||
+106
@@ -0,0 +1,106 @@
|
||||
package com.agileboot.infrastructure.exception;
|
||||
|
||||
import com.agileboot.common.core.dto.ResponseDTO;
|
||||
import com.agileboot.common.exception.ApiException;
|
||||
import com.agileboot.common.exception.error.ErrorCode;
|
||||
import com.agileboot.common.exception.error.ErrorCode.Business;
|
||||
import com.agileboot.common.exception.error.ErrorCode.Client;
|
||||
import com.agileboot.common.exception.error.ErrorCode.Internal;
|
||||
import com.google.common.util.concurrent.UncheckedExecutionException;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.security.access.AccessDeniedException;
|
||||
import org.springframework.validation.BindException;
|
||||
import org.springframework.web.HttpRequestMethodNotSupportedException;
|
||||
import org.springframework.web.bind.MethodArgumentNotValidException;
|
||||
import org.springframework.web.bind.annotation.ExceptionHandler;
|
||||
import org.springframework.web.bind.annotation.RestControllerAdvice;
|
||||
|
||||
/**
|
||||
* 全局异常处理器
|
||||
*
|
||||
* @author valarchie
|
||||
*/
|
||||
@RestControllerAdvice
|
||||
@Slf4j
|
||||
public class GlobalExceptionInterceptor {
|
||||
|
||||
/**
|
||||
* 权限校验异常
|
||||
*/
|
||||
@ExceptionHandler(AccessDeniedException.class)
|
||||
public ResponseDTO<?> handleAccessDeniedException(AccessDeniedException e, HttpServletRequest request) {
|
||||
log.error("请求地址'{}',权限校验失败'{}'", request.getRequestURI(), e.getMessage());
|
||||
return ResponseDTO.fail(new ApiException(Business.PERMISSION_NOT_ALLOWED_TO_OPERATE));
|
||||
}
|
||||
|
||||
/**
|
||||
* 请求方式不支持
|
||||
*/
|
||||
@ExceptionHandler(HttpRequestMethodNotSupportedException.class)
|
||||
public ResponseDTO<?> handleHttpRequestMethodNotSupported(HttpRequestMethodNotSupportedException e,
|
||||
HttpServletRequest request) {
|
||||
log.error("请求地址'{}',不支持'{}'请求", request.getRequestURI(), e.getMethod());
|
||||
return ResponseDTO.fail(new ApiException(Client.COMMON_REQUEST_METHOD_INVALID, e.getMethod()));
|
||||
}
|
||||
|
||||
/**
|
||||
* 业务异常
|
||||
*/
|
||||
@ExceptionHandler(ApiException.class)
|
||||
public ResponseDTO<?> handleServiceException(ApiException e) {
|
||||
log.error(e.getMessage(), e);
|
||||
return ResponseDTO.fail(e, e.getPayload());
|
||||
}
|
||||
|
||||
/**
|
||||
* 捕获缓存类当中的错误
|
||||
*/
|
||||
@ExceptionHandler(UncheckedExecutionException.class)
|
||||
public ResponseDTO<?> handleServiceException(UncheckedExecutionException e) {
|
||||
log.error(e.getMessage(), e);
|
||||
return ResponseDTO.fail(new ApiException(Internal.GET_CACHE_FAILED, e.getMessage()));
|
||||
}
|
||||
|
||||
/**
|
||||
* 拦截未知的运行时异常
|
||||
*/
|
||||
@ExceptionHandler(RuntimeException.class)
|
||||
public ResponseDTO<?> handleRuntimeException(RuntimeException e, HttpServletRequest request) {
|
||||
String errorMsg = String.format("请求地址'%s',发生未知异常.", request.getRequestURI());
|
||||
log.error(errorMsg, e);
|
||||
return ResponseDTO.fail(new ApiException(Internal.INTERNAL_ERROR, e.getMessage()));
|
||||
}
|
||||
|
||||
/**
|
||||
* 系统异常
|
||||
*/
|
||||
@ExceptionHandler(Exception.class)
|
||||
public ResponseDTO<?> handleException(Exception e, HttpServletRequest request) {
|
||||
String errorMsg = String.format("请求地址'%s',发生未知异常.", request.getRequestURI());
|
||||
log.error(errorMsg, e);
|
||||
return ResponseDTO.fail(new ApiException(Internal.INTERNAL_ERROR, e.getMessage()));
|
||||
}
|
||||
|
||||
/**
|
||||
* 自定义验证异常
|
||||
*/
|
||||
@ExceptionHandler(BindException.class)
|
||||
public ResponseDTO<?> handleBindException(BindException e) {
|
||||
log.error(e.getMessage(), e);
|
||||
String message = e.getAllErrors().get(0).getDefaultMessage();
|
||||
return ResponseDTO.fail(new ApiException(ErrorCode.Client.COMMON_REQUEST_PARAMETERS_INVALID, message));
|
||||
}
|
||||
|
||||
/**
|
||||
* 自定义验证异常
|
||||
*/
|
||||
@ExceptionHandler(MethodArgumentNotValidException.class)
|
||||
public ResponseDTO<?> handleMethodArgumentNotValidException(MethodArgumentNotValidException e) {
|
||||
log.error(e.getMessage(), e);
|
||||
String message = e.getBindingResult().getFieldError().getDefaultMessage();
|
||||
return ResponseDTO.fail(new ApiException(ErrorCode.Client.COMMON_REQUEST_PARAMETERS_INVALID, message));
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
+33
@@ -0,0 +1,33 @@
|
||||
package com.agileboot.infrastructure.filter;
|
||||
|
||||
import java.io.IOException;
|
||||
import javax.servlet.Filter;
|
||||
import javax.servlet.FilterChain;
|
||||
import javax.servlet.FilterConfig;
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.ServletRequest;
|
||||
import javax.servlet.ServletResponse;
|
||||
|
||||
/**
|
||||
* 过滤器模板代码
|
||||
* @author valarchie
|
||||
*/
|
||||
public class TestFilter implements Filter {
|
||||
|
||||
@Override
|
||||
public void init(FilterConfig filterConfig) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
|
||||
throws IOException, ServletException {
|
||||
// 实现你的逻辑
|
||||
chain.doFilter(request, response);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void destroy() {
|
||||
|
||||
}
|
||||
}
|
||||
+61
@@ -0,0 +1,61 @@
|
||||
package com.agileboot.infrastructure.filter;
|
||||
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import java.io.IOException;
|
||||
import java.util.UUID;
|
||||
import javax.servlet.Filter;
|
||||
import javax.servlet.FilterChain;
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.ServletRequest;
|
||||
import javax.servlet.ServletResponse;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.slf4j.MDC;
|
||||
|
||||
/**
|
||||
* 给每一个线程分配一个uuid 以便日志可以可以精准查询一条请求的所有日志
|
||||
* 过滤器
|
||||
* @author valarchie
|
||||
*/
|
||||
@AllArgsConstructor
|
||||
@Slf4j
|
||||
public class TraceIdFilter implements Filter {
|
||||
|
||||
private String requestIdKey;
|
||||
|
||||
@Override
|
||||
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
|
||||
try {
|
||||
// 生成UUID并存储在MDC中 然后在日志中打印出来
|
||||
String uuid = UUID.randomUUID().toString();
|
||||
if (StrUtil.isNotEmpty(requestIdKey)) {
|
||||
MDC.put(requestIdKey, uuid);
|
||||
if (request instanceof HttpServletRequest) {
|
||||
HttpServletResponse httpResponse = (HttpServletResponse) response;
|
||||
// 把RequestId放到response的header中去方便追踪
|
||||
httpResponse.setHeader(requestIdKey, uuid);
|
||||
}
|
||||
} else {
|
||||
// 如果requestIdKey为空的话 说明配置有问题
|
||||
log.error("traceRequestIdKey 为null, 请检查项目yml中traceRequestIdKey的配置是否正确。");
|
||||
}
|
||||
|
||||
// 继续处理请求
|
||||
chain.doFilter(request, response);
|
||||
} finally {
|
||||
// 清除MDC中的UUID
|
||||
removeRequestIdSafely(requestIdKey);
|
||||
}
|
||||
}
|
||||
|
||||
public void removeRequestIdSafely(String requestIdKey) {
|
||||
try {
|
||||
MDC.remove(requestIdKey);
|
||||
} catch (Exception e) {
|
||||
log.error("traceRequestIdKey 为null, 请检查项目yml中traceRequestIdKey的配置是否正确。", e);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
+52
@@ -0,0 +1,52 @@
|
||||
package com.agileboot.infrastructure.i18n;
|
||||
|
||||
import cn.hutool.core.convert.Convert;
|
||||
import cn.hutool.core.util.ArrayUtil;
|
||||
import com.agileboot.common.exception.error.ErrorCode;
|
||||
import com.agileboot.common.exception.error.ErrorCodeInterface;
|
||||
import com.agileboot.common.utils.i18n.MessageUtils;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.boot.ApplicationArguments;
|
||||
import org.springframework.boot.ApplicationRunner;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* 检测 未添加到i18n文件(messages.properties)中的message
|
||||
* @author valarchie
|
||||
*/
|
||||
@Component
|
||||
@Slf4j
|
||||
public class MessageI18nCheckerRunner implements ApplicationRunner {
|
||||
|
||||
@Value("agileboot.checkI18nKey")
|
||||
private String checkI18nKey;
|
||||
|
||||
public static Object[] allErrorCodes = ArrayUtil.addAll(
|
||||
ErrorCode.Internal.values(),
|
||||
ErrorCode.External.values(),
|
||||
ErrorCode.Client.values(),
|
||||
ErrorCode.Business.values());
|
||||
|
||||
@Override
|
||||
public void run(ApplicationArguments args) {
|
||||
if (Convert.toBool(checkI18nKey)) {
|
||||
checkEveryMessage();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 如果想支持i18n, 请把对应的错误码描述填到 /resources/i18n/messages.properties 文件中
|
||||
*/
|
||||
public void checkEveryMessage() {
|
||||
for (Object errorCode : allErrorCodes) {
|
||||
ErrorCodeInterface errorInterface = (ErrorCodeInterface) errorCode;
|
||||
try {
|
||||
MessageUtils.message(errorInterface.i18nKey());
|
||||
} catch (Exception e) {
|
||||
log.warn("could not find i18n message for:{} in the file /resources/i18n/messages.properties.",
|
||||
errorInterface.i18nKey());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+85
@@ -0,0 +1,85 @@
|
||||
package com.agileboot.infrastructure.log;
|
||||
|
||||
import cn.hutool.json.JSONUtil;
|
||||
import com.agileboot.common.utils.jackson.JacksonUtil;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.aspectj.lang.JoinPoint;
|
||||
import org.aspectj.lang.ProceedingJoinPoint;
|
||||
import org.aspectj.lang.annotation.AfterThrowing;
|
||||
import org.aspectj.lang.annotation.Around;
|
||||
import org.aspectj.lang.annotation.Aspect;
|
||||
import org.aspectj.lang.annotation.Pointcut;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
|
||||
/**
|
||||
* @author valarchie
|
||||
*/
|
||||
@Aspect
|
||||
@Component
|
||||
@Slf4j
|
||||
public class MethodLogAspect {
|
||||
|
||||
@Pointcut("execution(public * com.agileboot..db.*Service.*(..))")
|
||||
public void dbService() {
|
||||
}
|
||||
|
||||
@Around("dbService()")
|
||||
public Object aroundDbService(ProceedingJoinPoint joinPoint) throws Throwable {
|
||||
Object proceed = joinPoint.proceed();
|
||||
log.info("DB SERVICE : {} ; REQUEST:{} ; RESPONSE : {}", joinPoint.getSignature().toShortString(),
|
||||
safeToJson(joinPoint.getArgs()), safeToJson(proceed));
|
||||
return proceed;
|
||||
}
|
||||
|
||||
@AfterThrowing(value = "dbService()", throwing = "e")
|
||||
public void afterDbServiceThrow(JoinPoint joinPoint, Exception e) {
|
||||
log.error("DB SERVICE : {} ; REQUEST:{} ; EXCEPTION : {}", joinPoint.getSignature().toShortString(),
|
||||
safeToJson(joinPoint.getArgs()), e.getMessage());
|
||||
}
|
||||
|
||||
|
||||
@Pointcut("bean(*ApplicationService)")
|
||||
public void applicationServiceLog() {
|
||||
}
|
||||
|
||||
@Around("applicationServiceLog()")
|
||||
public Object aroundApplicationService(ProceedingJoinPoint joinPoint) throws Throwable {
|
||||
Object proceed = joinPoint.proceed();
|
||||
log.info("APPLICATION SERVICE : {} ; REQUEST:{} ; RESPONSE : {}", joinPoint.getSignature().toShortString(),
|
||||
safeToJson(joinPoint.getArgs()), safeToJson(proceed));
|
||||
return proceed;
|
||||
}
|
||||
|
||||
@AfterThrowing(value = "applicationServiceLog()", throwing = "e")
|
||||
public void afterApplicationServiceThrow(JoinPoint joinPoint, Exception e) {
|
||||
log.error("APPLICATION SERVICE : {} ; REQUEST:{} ; EXCEPTION : {}", joinPoint.getSignature().toShortString(),
|
||||
safeToJson(joinPoint.getArgs()), e.getMessage());
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 安全的打印出Json字符串 因为Jackson的Json格式化要求比较高,可能会报错
|
||||
* 如果报错的话 使用Hutool的JSON工具 如果还是报错,直接使用对象的toString方法即可
|
||||
* 目的只是为了打印参数和返回值
|
||||
* 逻辑上不用太严格
|
||||
*/
|
||||
private String safeToJson(Object o) {
|
||||
if (o == null) {
|
||||
return "null";
|
||||
}
|
||||
String json = null;
|
||||
try {
|
||||
json = JacksonUtil.to(o);
|
||||
} catch (Exception e) {
|
||||
json = JSONUtil.toJsonStr(o);
|
||||
} finally {
|
||||
if (json == null) {
|
||||
json = o.toString();
|
||||
}
|
||||
}
|
||||
return json;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
+258
@@ -0,0 +1,258 @@
|
||||
package com.agileboot.infrastructure.mybatisplus;
|
||||
|
||||
import cn.hutool.core.io.resource.ResourceUtil;
|
||||
import cn.hutool.json.JSON;
|
||||
import cn.hutool.json.JSONUtil;
|
||||
import com.agileboot.common.core.base.BaseController;
|
||||
import com.agileboot.common.core.base.BaseEntity;
|
||||
import com.baomidou.mybatisplus.annotation.FieldFill;
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.generator.FastAutoGenerator;
|
||||
import com.baomidou.mybatisplus.generator.config.DataSourceConfig.Builder;
|
||||
import com.baomidou.mybatisplus.generator.config.OutputFile;
|
||||
import com.baomidou.mybatisplus.generator.config.StrategyConfig;
|
||||
import com.baomidou.mybatisplus.generator.config.TemplateType;
|
||||
import com.baomidou.mybatisplus.generator.config.builder.Entity;
|
||||
import com.baomidou.mybatisplus.generator.config.converts.MySqlTypeConvert;
|
||||
import com.baomidou.mybatisplus.generator.config.querys.MySqlQuery;
|
||||
import com.baomidou.mybatisplus.generator.config.rules.DateType;
|
||||
import com.baomidou.mybatisplus.generator.config.rules.NamingStrategy;
|
||||
import com.baomidou.mybatisplus.generator.engine.VelocityTemplateEngine;
|
||||
import com.baomidou.mybatisplus.generator.fill.Column;
|
||||
import com.baomidou.mybatisplus.generator.fill.Property;
|
||||
import com.baomidou.mybatisplus.generator.keywords.MySqlKeyWordsHandler;
|
||||
import java.util.Collections;
|
||||
import lombok.Data;
|
||||
import org.yaml.snakeyaml.Yaml;
|
||||
|
||||
/**
|
||||
* @author valarchie
|
||||
*/
|
||||
@Data
|
||||
@lombok.Builder
|
||||
public class CodeGenerator {
|
||||
|
||||
private String author;
|
||||
private String module;
|
||||
private String tableName;
|
||||
private String databaseUrl;
|
||||
private String username;
|
||||
private String password;
|
||||
private String parentPackage;
|
||||
private Boolean isExtendsFromBaseEntity;
|
||||
|
||||
/**
|
||||
* 避免覆盖掉原有生成的类 生成的类 放在orm子模块下的/target/generated-code目录底下
|
||||
* 有需要更新的实体自己在手动覆盖 或者 挪动过去
|
||||
*/
|
||||
public static void main(String[] args) {
|
||||
// 默认读取application-dev yml中的master数据库配置
|
||||
// JSON ymlJson = JSONUtil.parse(new Yaml().load(ResourceUtil.getStream("application-dev.yml")));
|
||||
|
||||
String databaseUrl = "jdbc:mysql://localhost:33067/agileboot-pure";
|
||||
String username = "root";
|
||||
String password = "12345";
|
||||
|
||||
CodeGenerator generator = CodeGenerator.builder()
|
||||
.databaseUrl(databaseUrl)
|
||||
.username(username)
|
||||
.password(password)
|
||||
.author("valarchie")
|
||||
//生成的类 放在orm子模块下的/target/generated-code目录底下
|
||||
.module("/agileboot-orm/target/generated-code")
|
||||
.parentPackage("com.agileboot")
|
||||
.tableName("sys_menu")
|
||||
// 决定是否继承基类
|
||||
.isExtendsFromBaseEntity(true)
|
||||
.build();
|
||||
|
||||
generator.generateCode();
|
||||
}
|
||||
|
||||
public void generateCode() {
|
||||
FastAutoGenerator generator = FastAutoGenerator.create(
|
||||
new Builder(databaseUrl, username, password)
|
||||
// .schema("mybatis-plus")
|
||||
// all these three options
|
||||
.dbQuery(new MySqlQuery())
|
||||
.typeConvert(new MySqlTypeConvert())
|
||||
.keyWordsHandler(new MySqlKeyWordsHandler()));
|
||||
|
||||
globalConfig(generator);
|
||||
packageConfig(generator);
|
||||
// templateConfig(generator);
|
||||
injectionConfig(generator);
|
||||
strategyConfig(generator);
|
||||
// 默认的是Velocity引擎模板
|
||||
generator.templateEngine(new VelocityTemplateEngine());
|
||||
generator.execute();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 为了避免 覆盖掉service中的方法
|
||||
* @param generator 生成器
|
||||
*/
|
||||
private void globalConfig(FastAutoGenerator generator) {
|
||||
generator.globalConfig(
|
||||
builder -> builder
|
||||
// override old code of file
|
||||
.fileOverride()
|
||||
.outputDir(System.getProperty("user.dir") + module + "/src/main/java")
|
||||
// use date type under package of java utils
|
||||
.dateType(DateType.ONLY_DATE)
|
||||
// 配置生成文件中的author
|
||||
.author(author)
|
||||
// .enableKotlin()
|
||||
// generate swagger annotations.
|
||||
.enableSwagger()
|
||||
// 注释日期的格式
|
||||
.commentDate("yyyy-MM-dd")
|
||||
.build());
|
||||
}
|
||||
|
||||
|
||||
private void packageConfig(FastAutoGenerator generator) {
|
||||
generator.packageConfig(builder -> builder
|
||||
// parent package name
|
||||
.parent(parentPackage)
|
||||
.moduleName("orm")
|
||||
.entity("entity")
|
||||
.service("service")
|
||||
.serviceImpl("service.impl")
|
||||
.mapper("mapper")
|
||||
.xml("mapper.xml")
|
||||
.controller("controller")
|
||||
.other("other")
|
||||
// define dir related to OutputFileType(entity,mapper,service,controller,mapper.xml)
|
||||
.pathInfo(Collections.singletonMap(OutputFile.mapperXml, System.getProperty("user.dir") + module
|
||||
+ "/src/main/resources/mapper/system/test"))
|
||||
.build());
|
||||
}
|
||||
|
||||
private void templateConfig(FastAutoGenerator generator) {
|
||||
// customization code template. disable if you don't have specific requirement.
|
||||
generator.templateConfig(builder -> builder
|
||||
.disable(TemplateType.ENTITY)
|
||||
.entity("/templates/entity.java")
|
||||
.service("/templates/service.java")
|
||||
.serviceImpl("/templates/serviceImpl.java")
|
||||
.mapper("/templates/mapper.java")
|
||||
.mapperXml("/templates/mapper.xml")
|
||||
.controller("/templates/controller.java")
|
||||
.build());
|
||||
}
|
||||
|
||||
private void injectionConfig(FastAutoGenerator generator) {
|
||||
// customization code template. disable if you don't have specific requirement.
|
||||
generator.injectionConfig(builder -> {
|
||||
// Customization
|
||||
builder.beforeOutputFile((tableInfo, objectMap) -> System.out.println("tableInfo: " +
|
||||
tableInfo.getEntityName() + " objectMap: " + objectMap.size()))
|
||||
// .customMap(Collections.singletonMap("test", "baomidou"))
|
||||
// .customFile(Collections.singletonMap("test.txt", "/templates/test.vm"))
|
||||
.build();
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
private void strategyConfig(FastAutoGenerator generator) {
|
||||
// customization code template. disable if you don't have specific requirement.
|
||||
generator.strategyConfig(builder -> {
|
||||
builder
|
||||
// Global Configuration
|
||||
.enableCapitalMode()
|
||||
// does not generate view
|
||||
.enableSkipView()
|
||||
.disableSqlFilter()
|
||||
// filter which tables need to be generated
|
||||
// .likeTable(new LikeTable("USER"))
|
||||
// .addInclude("t_simple")
|
||||
// .addTablePrefix("t_", "c_")
|
||||
// .addFieldSuffix("_flag")
|
||||
.addInclude(tableName);
|
||||
|
||||
entityConfig(builder);
|
||||
controllerConfig(builder);
|
||||
serviceConfig(builder);
|
||||
mapperConfig(builder);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
private void entityConfig(StrategyConfig.Builder builder) {
|
||||
Entity.Builder entityBuilder = builder.entityBuilder();
|
||||
|
||||
entityBuilder
|
||||
// .superClass(BaseEntity.class)
|
||||
// .disableSerialVersionUID()
|
||||
// .enableChainModel()
|
||||
.enableLombok()
|
||||
// boolean field
|
||||
// .enableRemoveIsPrefix()
|
||||
.enableTableFieldAnnotation()
|
||||
// operate entity like JPA.
|
||||
.enableActiveRecord()
|
||||
// .versionColumnName("version")
|
||||
// .versionPropertyName("version")
|
||||
// deleted的字段设置成tinyint 长度为1
|
||||
.logicDeleteColumnName("deleted")
|
||||
// .logicDeletePropertyName("deleteFlag")
|
||||
.naming(NamingStrategy.underline_to_camel)
|
||||
.columnNaming(NamingStrategy.underline_to_camel)
|
||||
// 如果不需要BaseEntity 请注释掉以下两行
|
||||
// .superClass(BaseEntity.class)
|
||||
// .addSuperEntityColumns("creator_id", "create_time", "creator_name", "updater_id", "update_time", "updater_name", "deleted")
|
||||
// .addIgnoreColumns("age")
|
||||
// 两种配置方式 都可以
|
||||
.addTableFills(new Column("create_time", FieldFill.INSERT))
|
||||
.addTableFills(new Column("creator_id", FieldFill.INSERT))
|
||||
.addTableFills(new Property("updateTime", FieldFill.INSERT_UPDATE))
|
||||
.addTableFills(new Property("updaterId", FieldFill.INSERT_UPDATE))
|
||||
// ID strategy AUTO, NONE, INPUT, ASSIGN_ID, ASSIGN_UUID;
|
||||
.idType(IdType.AUTO)
|
||||
.formatFileName("%sEntity");
|
||||
|
||||
if (isExtendsFromBaseEntity) {
|
||||
entityBuilder
|
||||
.superClass(BaseEntity.class)
|
||||
.addSuperEntityColumns("creator_id", "create_time", "creator_name", "updater_id", "update_time",
|
||||
"updater_name", "deleted");
|
||||
}
|
||||
|
||||
entityBuilder.build();
|
||||
}
|
||||
|
||||
|
||||
private void controllerConfig(StrategyConfig.Builder builder) {
|
||||
builder.controllerBuilder()
|
||||
.superClass(BaseController.class)
|
||||
.enableHyphenStyle()
|
||||
.enableRestStyle()
|
||||
.formatFileName("%sController")
|
||||
.build();
|
||||
}
|
||||
|
||||
private void serviceConfig(StrategyConfig.Builder builder) {
|
||||
builder.serviceBuilder()
|
||||
// .superServiceClass(BaseService.class)
|
||||
// .superServiceImplClass(BaseServiceImpl.class)
|
||||
.formatServiceFileName("%sService")
|
||||
.formatServiceImplFileName("%sServiceImpl")
|
||||
.build();
|
||||
}
|
||||
|
||||
private void mapperConfig(StrategyConfig.Builder builder) {
|
||||
builder.mapperBuilder()
|
||||
// .superClass(BaseMapper.class)
|
||||
// .enableMapperAnnotation()
|
||||
// .enableBaseResultMap()
|
||||
// .enableBaseColumnList()
|
||||
// .cache(MyMapperCache.class)
|
||||
.formatMapperFileName("%sMapper")
|
||||
.formatXmlFileName("%sMapper")
|
||||
.build();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
+62
@@ -0,0 +1,62 @@
|
||||
package com.agileboot.infrastructure.mybatisplus;
|
||||
|
||||
import com.agileboot.infrastructure.user.AuthenticationUtils;
|
||||
import com.agileboot.infrastructure.user.web.SystemLoginUser;
|
||||
import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler;
|
||||
import java.util.Date;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.ibatis.reflection.MetaObject;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* Mybatis Plus允许在插入或者更新的时候
|
||||
* 自定义设定值
|
||||
* @author valarchie
|
||||
*/
|
||||
@Component
|
||||
@Slf4j
|
||||
public class CustomMetaObjectHandler implements MetaObjectHandler {
|
||||
|
||||
public static final String CREATE_TIME_FIELD = "createTime";
|
||||
public static final String CREATOR_ID_FIELD = "creatorId";
|
||||
|
||||
public static final String UPDATE_TIME_FIELD = "updateTime";
|
||||
public static final String UPDATER_ID_FIELD = "updaterId";
|
||||
|
||||
|
||||
@Override
|
||||
public void insertFill(MetaObject metaObject) {
|
||||
if (metaObject.hasSetter(CREATE_TIME_FIELD)) {
|
||||
this.setFieldValByName(CREATE_TIME_FIELD, new Date(), metaObject);
|
||||
}
|
||||
|
||||
Long userId = getUserIdSafely();
|
||||
if (metaObject.hasSetter(CREATOR_ID_FIELD) && userId != null) {
|
||||
this.strictInsertFill(metaObject, CREATOR_ID_FIELD, Long.class, getUserIdSafely());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateFill(MetaObject metaObject) {
|
||||
if (metaObject.hasSetter(UPDATE_TIME_FIELD)) {
|
||||
this.setFieldValByName(UPDATE_TIME_FIELD, new Date(), metaObject);
|
||||
}
|
||||
|
||||
Long userId = getUserIdSafely();
|
||||
if (metaObject.hasSetter(UPDATER_ID_FIELD) && userId != null) {
|
||||
this.strictUpdateFill(metaObject, UPDATER_ID_FIELD, Long.class, getUserIdSafely());
|
||||
}
|
||||
}
|
||||
|
||||
public Long getUserIdSafely() {
|
||||
Long userId = null;
|
||||
try {
|
||||
SystemLoginUser loginUser = AuthenticationUtils.getSystemLoginUser();
|
||||
userId = loginUser.getUserId();
|
||||
} catch (Exception e) {
|
||||
log.warn("can not find user in current thread.");
|
||||
}
|
||||
return userId;
|
||||
}
|
||||
|
||||
}
|
||||
+30
@@ -0,0 +1,30 @@
|
||||
package com.agileboot.infrastructure.mybatisplus;
|
||||
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 由于H2不支持大部分Mysql的函数 所以要自己实现
|
||||
* 在H2的初始化 h2sql/agileboot_schema.sql加上这句
|
||||
* CREATE ALIAS FIND_IN_SET FOR "com.agileboot.infrastructure.mybatisplus.MySqlFunction.find_in_set";
|
||||
*
|
||||
* @author valarchie
|
||||
*/
|
||||
public class MySqlFunction {
|
||||
|
||||
private MySqlFunction() {
|
||||
}
|
||||
|
||||
public static boolean findInSet(String target, String setString) {
|
||||
if (setString == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
List<String> split = StrUtil.split(setString, ",");
|
||||
|
||||
return CollUtil.contains(split, target);
|
||||
}
|
||||
|
||||
}
|
||||
+61
@@ -0,0 +1,61 @@
|
||||
package com.agileboot.infrastructure.schedule;
|
||||
|
||||
import cn.hutool.core.date.DateUtil;
|
||||
import java.util.Date;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.scheduling.annotation.Scheduled;
|
||||
|
||||
/**
|
||||
* 如果想开启定时任务 请不要注释@Component注解
|
||||
* @author valarchie
|
||||
*/
|
||||
//@Component
|
||||
@Slf4j
|
||||
public class ScheduleJobManager {
|
||||
|
||||
/**
|
||||
* fixedRate:固定速率执行。每60秒执行一次。
|
||||
*/
|
||||
@Scheduled(fixedRate = 60000)
|
||||
public void reportCurrentTimeWithFixedRate() {
|
||||
log.info("Current Thread : {}, Fixed Rate Task : The time is now {}",
|
||||
Thread.currentThread().getName(), DateUtil.formatTime(new Date()));
|
||||
}
|
||||
|
||||
/**
|
||||
* fixedDelay:固定延迟执行。距离上一次调用成功后30秒才执。
|
||||
*/
|
||||
@Scheduled(fixedDelay = 30000)
|
||||
public void reportCurrentTimeWithFixedDelay() {
|
||||
try {
|
||||
TimeUnit.SECONDS.sleep(60);
|
||||
log.info("Current Thread : {}, Fixed Delay Task : The time is now {}",
|
||||
Thread.currentThread().getName(), DateUtil.formatTime(new Date()));
|
||||
} catch (InterruptedException e) {
|
||||
log.error("计划任务执行失败", e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* initialDelay:初始延迟。任务的第一次执行将延迟30秒,然后将以60秒的固定间隔执行。
|
||||
*/
|
||||
@Scheduled(initialDelay = 30000, fixedRate = 60000)
|
||||
public void reportCurrentTimeWithInitialDelay() {
|
||||
log.info("Current Thread : {}, Fixed Rate Task with Initial Delay : The time is now {}",
|
||||
Thread.currentThread().getName(), DateUtil.formatTime(new Date()));
|
||||
}
|
||||
|
||||
/**
|
||||
* cron:使用Cron表达式。 每分钟的1,2秒运行
|
||||
* <a href="https://cron.qqe2.com/">https://cron.qqe2.com/</a>
|
||||
* cron表达式 在线解析
|
||||
*/
|
||||
@Scheduled(cron = "1-2 * * * * ? ")
|
||||
public void reportCurrentTimeWithCronExpression() {
|
||||
log.info("Current Thread : {}, Cron Expression: The time is now {}",
|
||||
Thread.currentThread().getName(), DateUtil.formatTime(new Date()));
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
+23
@@ -0,0 +1,23 @@
|
||||
package com.agileboot.infrastructure.security;
|
||||
|
||||
import cn.hutool.crypto.SecureUtil;
|
||||
import cn.hutool.crypto.asymmetric.RSA;
|
||||
|
||||
/**
|
||||
* Rsa key生成
|
||||
* @author valarchie
|
||||
*/
|
||||
public class RsaKeyPairGenerator {
|
||||
|
||||
public static void main(String[] args) {
|
||||
RSA rsa = SecureUtil.rsa();
|
||||
|
||||
String privateKeyBase64 = rsa.getPrivateKeyBase64();
|
||||
String publicKeyBase64 = rsa.getPublicKeyBase64();
|
||||
|
||||
System.out.println(privateKeyBase64);
|
||||
System.out.println(publicKeyBase64);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
+34
@@ -0,0 +1,34 @@
|
||||
package com.agileboot.infrastructure.security.xss;
|
||||
|
||||
import cn.hutool.http.HtmlUtil;
|
||||
import com.fasterxml.jackson.core.JsonParser;
|
||||
import com.fasterxml.jackson.databind.DeserializationContext;
|
||||
import com.fasterxml.jackson.databind.JsonDeserializer;
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* 直接将html标签去掉
|
||||
* @author valarchie
|
||||
*/
|
||||
public class JsonHtmlXssTrimSerializer extends JsonDeserializer<String> {
|
||||
|
||||
public JsonHtmlXssTrimSerializer() {
|
||||
super();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String deserialize(JsonParser p, DeserializationContext context) throws IOException {
|
||||
String value = p.getValueAsString();
|
||||
if( value != null) {
|
||||
// 去除掉html标签 如果想要转义的话 可使用 HtmlUtil.escape()
|
||||
return HtmlUtil.cleanHtmlTag(value);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<String> handledType() {
|
||||
return String.class;
|
||||
}
|
||||
|
||||
}
|
||||
+32
@@ -0,0 +1,32 @@
|
||||
package com.agileboot.infrastructure.thread;
|
||||
|
||||
import javax.annotation.PreDestroy;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* 确保应用退出时能关闭后台线程
|
||||
*
|
||||
* @author ruoyi
|
||||
*/
|
||||
@Component
|
||||
@Slf4j
|
||||
public class ShutdownHook {
|
||||
|
||||
@PreDestroy
|
||||
public void destroy() {
|
||||
shutdownAllThreadPool();
|
||||
}
|
||||
|
||||
/**
|
||||
* 停止异步执行任务
|
||||
*/
|
||||
private void shutdownAllThreadPool() {
|
||||
try {
|
||||
log.info("close thread pool");
|
||||
ThreadPoolManager.shutdown();
|
||||
} catch (Exception e) {
|
||||
log.error(e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
}
|
||||
+23
@@ -0,0 +1,23 @@
|
||||
package com.agileboot.infrastructure.thread;
|
||||
|
||||
/**
|
||||
* @author valarchie
|
||||
*/
|
||||
public class ThreadConfig {
|
||||
|
||||
public static final int CORE_POOL_SIZE = 50;
|
||||
|
||||
public static final int MAX_POOL_SIZE = 200;
|
||||
|
||||
public static final int QUEUE_CAPACITY = 1000;
|
||||
|
||||
public static final int KEEP_ALIVE_SECONDS = 300;
|
||||
|
||||
/**
|
||||
* 操作延迟10毫秒
|
||||
*/
|
||||
public static final int OPERATE_DELAY_TIME = 10;
|
||||
|
||||
private ThreadConfig() {
|
||||
}
|
||||
}
|
||||
+72
@@ -0,0 +1,72 @@
|
||||
package com.agileboot.infrastructure.thread;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.lang3.concurrent.BasicThreadFactory;
|
||||
|
||||
import java.util.TimerTask;
|
||||
import java.util.concurrent.*;
|
||||
|
||||
/**
|
||||
* 异步任务管理器
|
||||
*
|
||||
* @author valarchie
|
||||
*/
|
||||
@Slf4j
|
||||
public class ThreadPoolManager {
|
||||
|
||||
private static final ThreadPoolExecutor THREAD_EXECUTOR = new ThreadPoolExecutor(
|
||||
ThreadConfig.CORE_POOL_SIZE, ThreadConfig.MAX_POOL_SIZE,
|
||||
ThreadConfig.KEEP_ALIVE_SECONDS, TimeUnit.SECONDS,
|
||||
new SynchronousQueue<>(), new ThreadPoolExecutor.CallerRunsPolicy());
|
||||
private static final ScheduledExecutorService SCHEDULED_EXECUTOR = new ScheduledThreadPoolExecutor(
|
||||
ThreadConfig.CORE_POOL_SIZE,
|
||||
new BasicThreadFactory.Builder().namingPattern("schedule-pool-%d").daemon(true).build(),
|
||||
new ThreadPoolExecutor.CallerRunsPolicy()) {
|
||||
@Override
|
||||
protected void afterExecute(Runnable r, Throwable t) {
|
||||
if (t == null && r instanceof Future<?>) {
|
||||
try {
|
||||
Future<?> future = (Future<?>) r;
|
||||
if (future.isDone()) {
|
||||
future.get();
|
||||
}
|
||||
} catch (CancellationException ce) {
|
||||
t = ce;
|
||||
} catch (ExecutionException ee) {
|
||||
t = ee.getCause();
|
||||
} catch (InterruptedException ie) {
|
||||
Thread.currentThread().interrupt();
|
||||
}
|
||||
}
|
||||
if (t != null) {
|
||||
log.error(t.getMessage(), t);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
private ThreadPoolManager() {
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 执行schedule任务
|
||||
*/
|
||||
public static void schedule(TimerTask task) {
|
||||
SCHEDULED_EXECUTOR.schedule(task, ThreadConfig.OPERATE_DELAY_TIME, TimeUnit.MILLISECONDS);
|
||||
}
|
||||
|
||||
/**
|
||||
* 执行异步任务任务
|
||||
*/
|
||||
public static void execute(Runnable task) {
|
||||
THREAD_EXECUTOR.execute(task);
|
||||
}
|
||||
|
||||
/**
|
||||
* 停止任务线程池
|
||||
*/
|
||||
public static void shutdown() {
|
||||
THREAD_EXECUTOR.shutdown();
|
||||
SCHEDULED_EXECUTOR.shutdown();
|
||||
}
|
||||
}
|
||||
+85
@@ -0,0 +1,85 @@
|
||||
package com.agileboot.infrastructure.user;
|
||||
|
||||
|
||||
import com.agileboot.common.exception.ApiException;
|
||||
import com.agileboot.common.exception.error.ErrorCode;
|
||||
import com.agileboot.infrastructure.user.app.AppLoginUser;
|
||||
import com.agileboot.infrastructure.user.web.SystemLoginUser;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.context.SecurityContextHolder;
|
||||
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
|
||||
|
||||
/**
|
||||
* 安全服务工具类
|
||||
*
|
||||
* @author valarchie
|
||||
*/
|
||||
public class AuthenticationUtils {
|
||||
|
||||
private AuthenticationUtils() {}
|
||||
|
||||
/**
|
||||
* 用户ID
|
||||
**/
|
||||
public static Long getUserId() {
|
||||
try {
|
||||
return getSystemLoginUser().getUserId();
|
||||
} catch (Exception e) {
|
||||
throw new ApiException(ErrorCode.Business.USER_FAIL_TO_GET_USER_ID);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取系统用户
|
||||
**/
|
||||
public static SystemLoginUser getSystemLoginUser() {
|
||||
try {
|
||||
return (SystemLoginUser) getAuthentication().getPrincipal();
|
||||
} catch (Exception e) {
|
||||
throw new ApiException(ErrorCode.Business.USER_FAIL_TO_GET_USER_INFO);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取App用户
|
||||
**/
|
||||
public static AppLoginUser getAppLoginUser() {
|
||||
try {
|
||||
return (AppLoginUser) getAuthentication().getPrincipal();
|
||||
} catch (Exception e) {
|
||||
throw new ApiException(ErrorCode.Business.USER_FAIL_TO_GET_USER_INFO);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取Authentication
|
||||
*/
|
||||
public static Authentication getAuthentication() {
|
||||
return SecurityContextHolder.getContext().getAuthentication();
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成BCryptPasswordEncoder密码
|
||||
*
|
||||
* @param password 密码
|
||||
* @return 加密字符串
|
||||
*/
|
||||
public static String encryptPassword(String password) {
|
||||
BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
|
||||
return passwordEncoder.encode(password);
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断密码是否相同
|
||||
*
|
||||
* @param rawPassword 真实密码
|
||||
* @param encodedPassword 加密后字符
|
||||
* @return 结果
|
||||
*/
|
||||
public static boolean matchesPassword(String rawPassword, String encodedPassword) {
|
||||
BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
|
||||
return passwordEncoder.matches(rawPassword, encodedPassword);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
+27
@@ -0,0 +1,27 @@
|
||||
package com.agileboot.infrastructure.user.app;
|
||||
|
||||
import com.agileboot.infrastructure.user.base.BaseLoginUser;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
/**
|
||||
* 登录用户身份权限
|
||||
* @author valarchie
|
||||
*/
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
public class AppLoginUser extends BaseLoginUser {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private boolean isVip;
|
||||
|
||||
|
||||
public AppLoginUser(Long userId, Boolean isVip, String cachedKey) {
|
||||
this.cachedKey = cachedKey;
|
||||
this.userId = userId;
|
||||
this.isVip = isVip;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
+129
@@ -0,0 +1,129 @@
|
||||
package com.agileboot.infrastructure.user.base;
|
||||
|
||||
import cn.hutool.extra.servlet.ServletUtil;
|
||||
import com.agileboot.common.utils.ServletHolderUtil;
|
||||
import com.agileboot.common.utils.ip.IpRegionUtil;
|
||||
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||
import eu.bitwalker.useragentutils.UserAgent;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
import org.springframework.security.core.GrantedAuthority;
|
||||
import org.springframework.security.core.authority.SimpleGrantedAuthority;
|
||||
import org.springframework.security.core.userdetails.UserDetails;
|
||||
|
||||
/**
|
||||
* 登录用户身份权限
|
||||
* @author valarchie
|
||||
*/
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
public class BaseLoginUser implements UserDetails {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
protected Long userId;
|
||||
|
||||
/**
|
||||
* 用户唯一标识,缓存的key
|
||||
*/
|
||||
protected String cachedKey;
|
||||
|
||||
protected String username;
|
||||
|
||||
protected String password;
|
||||
|
||||
protected List<GrantedAuthority> authorities = new ArrayList<>();
|
||||
/**
|
||||
* 登录信息
|
||||
*/
|
||||
protected final LoginInfo loginInfo = new LoginInfo();
|
||||
|
||||
|
||||
public BaseLoginUser(Long userId, String username, String password) {
|
||||
this.userId = userId;
|
||||
this.username = username;
|
||||
this.password = password;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置用户代理信息
|
||||
*
|
||||
*/
|
||||
public void fillLoginInfo() {
|
||||
UserAgent userAgent = UserAgent.parseUserAgentString(ServletHolderUtil.getRequest().getHeader("User-Agent"));
|
||||
String ip = ServletUtil.getClientIP(ServletHolderUtil.getRequest());
|
||||
|
||||
this.getLoginInfo().setIpAddress(ip);
|
||||
this.getLoginInfo().setLocation(IpRegionUtil.getBriefLocationByIp(ip));
|
||||
this.getLoginInfo().setBrowser(userAgent.getBrowser().getName());
|
||||
this.getLoginInfo().setOperationSystem(userAgent.getOperatingSystem().getName());
|
||||
this.getLoginInfo().setLoginTime(System.currentTimeMillis());
|
||||
}
|
||||
|
||||
public void grantAppPermission(String appName) {
|
||||
authorities.add(new SimpleGrantedAuthority(appName));
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public String getUsername() {
|
||||
return this.username;
|
||||
}
|
||||
|
||||
|
||||
@JsonIgnore
|
||||
@Override
|
||||
public String getPassword() {
|
||||
return this.password;
|
||||
}
|
||||
|
||||
/**
|
||||
* 账户是否未过期,过期无法验证
|
||||
* 未实现此功能
|
||||
*/
|
||||
@JsonIgnore
|
||||
@Override
|
||||
public boolean isAccountNonExpired() {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 指定用户是否解锁,锁定的用户无法进行身份验证
|
||||
* 未实现此功能
|
||||
*/
|
||||
@JsonIgnore
|
||||
@Override
|
||||
public boolean isAccountNonLocked() {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 指示是否已过期的用户的凭据(密码),过期的凭据防止认证
|
||||
* 未实现此功能
|
||||
*/
|
||||
@JsonIgnore
|
||||
@Override
|
||||
public boolean isCredentialsNonExpired() {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否可用 ,禁用的用户不能身份验证
|
||||
* 未实现此功能
|
||||
*/
|
||||
@Override
|
||||
public boolean isEnabled() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@JsonIgnore
|
||||
@Override
|
||||
public Collection<? extends GrantedAuthority> getAuthorities() {
|
||||
return authorities;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
+36
@@ -0,0 +1,36 @@
|
||||
package com.agileboot.infrastructure.user.base;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* @author valarchie
|
||||
*/
|
||||
@Data
|
||||
public class LoginInfo {
|
||||
|
||||
/**
|
||||
* 登录IP地址
|
||||
*/
|
||||
private String ipAddress;
|
||||
|
||||
/**
|
||||
* 登录地点
|
||||
*/
|
||||
private String location;
|
||||
|
||||
/**
|
||||
* 浏览器类型
|
||||
*/
|
||||
private String browser;
|
||||
|
||||
/**
|
||||
* 操作系统
|
||||
*/
|
||||
private String operationSystem;
|
||||
|
||||
/**
|
||||
* 登录时间
|
||||
*/
|
||||
private Long loginTime;
|
||||
|
||||
}
|
||||
+42
@@ -0,0 +1,42 @@
|
||||
package com.agileboot.infrastructure.user.web;
|
||||
|
||||
import com.agileboot.common.enums.BasicEnum;
|
||||
|
||||
/**
|
||||
* 对应sys_role表的data_scope字段
|
||||
* @author valarchie
|
||||
*/
|
||||
public enum DataScopeEnum implements BasicEnum<Integer> {
|
||||
|
||||
/**
|
||||
* 数据权限范围
|
||||
*/
|
||||
ALL(1, "所有数据权限"),
|
||||
CUSTOM_DEFINE(2, "自定义数据权限"),
|
||||
SINGLE_DEPT(3, "本部门数据权限"),
|
||||
DEPT_TREE(4, "本部门以及子孙部门数据权限"),
|
||||
ONLY_SELF(5, "仅本人数据权限");
|
||||
|
||||
private final int value;
|
||||
private final String description;
|
||||
|
||||
DataScopeEnum(int value, String description) {
|
||||
this.value = value;
|
||||
this.description = description;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String description() {
|
||||
return description;
|
||||
}
|
||||
|
||||
public String getDescription() {
|
||||
return description;
|
||||
}
|
||||
|
||||
}
|
||||
+44
@@ -0,0 +1,44 @@
|
||||
package com.agileboot.infrastructure.user.web;
|
||||
|
||||
import java.util.Set;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
import org.apache.commons.collections4.SetUtils;
|
||||
|
||||
/**
|
||||
* @author valarchie
|
||||
*/
|
||||
@Data
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
public class RoleInfo {
|
||||
|
||||
public static final RoleInfo EMPTY_ROLE = new RoleInfo();
|
||||
public static final long ADMIN_ROLE_ID = -1;
|
||||
public static final String ADMIN_ROLE_KEY = "admin";
|
||||
public static final String ALL_PERMISSIONS = "*:*:*";
|
||||
|
||||
public static final Set<String> ADMIN_PERMISSIONS = SetUtils.hashSet(ALL_PERMISSIONS);
|
||||
|
||||
|
||||
public RoleInfo(Long roleId, String roleKey, DataScopeEnum dataScope, Set<Long> deptIdSet,
|
||||
Set<String> menuPermissions, Set<Long> menuIds) {
|
||||
this.roleId = roleId;
|
||||
this.roleKey = roleKey;
|
||||
this.dataScope = dataScope;
|
||||
this.deptIdSet = deptIdSet;
|
||||
this.menuPermissions = menuPermissions != null ? menuPermissions : SetUtils.emptySet();
|
||||
this.menuIds = menuIds != null ? menuIds : SetUtils.emptySet();
|
||||
}
|
||||
|
||||
|
||||
private Long roleId;
|
||||
private String roleName;
|
||||
private DataScopeEnum dataScope;
|
||||
private Set<Long> deptIdSet;
|
||||
private String roleKey;
|
||||
private Set<String> menuPermissions;
|
||||
private Set<Long> menuIds;
|
||||
|
||||
}
|
||||
+52
@@ -0,0 +1,52 @@
|
||||
package com.agileboot.infrastructure.user.web;
|
||||
|
||||
import com.agileboot.infrastructure.user.base.BaseLoginUser;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
/**
|
||||
* 登录用户身份权限
|
||||
* @author valarchie
|
||||
*/
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
public class SystemLoginUser extends BaseLoginUser {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private boolean isAdmin;
|
||||
|
||||
private Long deptId;
|
||||
|
||||
private RoleInfo roleInfo;
|
||||
|
||||
/**
|
||||
* 当超过这个时间 则触发刷新缓存时间
|
||||
*/
|
||||
private Long autoRefreshCacheTime;
|
||||
|
||||
|
||||
public SystemLoginUser(Long userId, Boolean isAdmin, String username, String password, RoleInfo roleInfo,
|
||||
Long deptId) {
|
||||
this.userId = userId;
|
||||
this.isAdmin = isAdmin;
|
||||
this.username = username;
|
||||
this.password = password;
|
||||
this.roleInfo = roleInfo;
|
||||
this.deptId = deptId;
|
||||
}
|
||||
|
||||
public RoleInfo getRoleInfo() {
|
||||
return roleInfo;
|
||||
}
|
||||
|
||||
public Long getRoleId() {
|
||||
return getRoleInfo().getRoleId();
|
||||
}
|
||||
|
||||
public Long getDeptId() {
|
||||
return deptId;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,129 @@
|
||||
# 基础公用的配置参数放置在这份yml中
|
||||
# 项目相关配置
|
||||
agileboot:
|
||||
# 名称
|
||||
name: AgileBoot
|
||||
# 版本
|
||||
version: 1.8.0
|
||||
# 版权年份
|
||||
copyright-year: 2022
|
||||
# 实例演示开关
|
||||
demo-enabled: true
|
||||
# 获取ip地址开关
|
||||
addressEnabled: false
|
||||
# 验证码类型 math 数组计算 char 字符验证
|
||||
captchaType: math
|
||||
# 对应的公钥放在前端项目中的utils/rsaUtils类中
|
||||
rsaPrivateKey: MIICdQIBADANBgkqhkiG9w0BAQEFAASCAl8wggJbAgEAAoGBAKHoeQr6sIzfsUDMIdXK2FNzqnG+vnnUrTsJGF1f82MJ10cC5Aw53/ntHl+IjCBU0R8KwPVwjJLoDwhaPgO0ktHa3b0l6E+mqIVIniE20Nws3E0mJhFwJC/IxB7JAg8TkuNzflzvZjAO1ACwgkKGxq7Iutz4TocLeCfUkObXwc1fAgMBAAECgYAWwCzqDwnp8bDdkxGaEhPNvi4QJ6ZqRilFZ2TGEiqIGyTl9JEI6sT/QIOJFw3hqSltfDxbAMKwDe221b9rE9+hZhE2rrpwcTKuehob9Z8CObYeUHR9HG7Qb2tYRElvSCWo74iz2zajXAvJLjIE4MPuPYqXC5zOabH+EJ/eaOzVwQJBANmRkMlb+qzp1GWuqFMHP+5MeYhFwUHVX7fxKNA24oHldX8zjPIZ6d3vaRfliTvxOaz1T80acvJkkb7zHBmaW38CQQC+gfF8Lg+nvBY/S3wfOPL8FcntP16jdFhNNZmbOxq72ZmCfl5Zk5cYNBc4rDSrd9Sj4TkLLug+wrK6Wr117P4hAkBOVxnZR2NVy8SM8HzvmJauiZ7hMKzLtbcHlrBpeLnKqALM0JUZv7b0EPa4ghAOI2fvHU2kvrdRDGFmbkdZ+LilAkBnX8eT5MKl+A/yZJmDr7laRNB/poVKGNXZf55Md3P4Pwlnn/6+iLHSdmGrZPZnnOyLyKjVgqyPccLeEGMCXIlBAkAt2OMwss16OH2x79OcfBrabU5iCVbDHg56JYGbWP8KcPfvspxtL/4TdACRsa+yCMcI6L29Q4wn791SEEnE834a
|
||||
# 是否检查 i18n 资源文件(messages.properties)是否都有对应的键值对
|
||||
checkI18nKey: false
|
||||
traceRequestIdKey: AG-RequestId
|
||||
|
||||
|
||||
|
||||
## 开发环境配置
|
||||
#server:
|
||||
# # 服务器的HTTP端口,默认为8080
|
||||
# port: 8080
|
||||
# servlet:
|
||||
# # 应用的访问路径
|
||||
# context-path: /
|
||||
# tomcat:
|
||||
# # tomcat的URI编码
|
||||
# uri-encoding: UTF-8
|
||||
# # 连接数满后的排队数,默认为100
|
||||
# accept-count: 1000
|
||||
# threads:
|
||||
# # tomcat最大线程数,默认为200
|
||||
# max: 800
|
||||
# # Tomcat启动初始化的线程数,默认值10
|
||||
# min-spare: 100
|
||||
|
||||
# 日志配置
|
||||
logging:
|
||||
level:
|
||||
# 记得配置到包名
|
||||
com.agileboot: debug
|
||||
org.springframework: info
|
||||
pattern:
|
||||
console: "%date requestId:%X{${agileboot.traceRequestIdKey}} %thread %green(%level) [%cyan(%logger{10}):%magenta(%line)] %red(%method) | %msg%n"
|
||||
|
||||
|
||||
# Spring配置
|
||||
spring:
|
||||
# 资源信息
|
||||
messages:
|
||||
# 国际化资源文件路径
|
||||
basename: i18n/messages
|
||||
# 有些版本的 IDEA 会自动设置properties的编码为IOS-8859-1 请在IDEA配置里设置成UTF8
|
||||
encoding: UTF-8
|
||||
|
||||
# 文件上传
|
||||
servlet:
|
||||
multipart:
|
||||
# 单个文件大小
|
||||
max-file-size: 10MB
|
||||
# 设置总上传的文件大小
|
||||
max-request-size: 20MB
|
||||
# 服务模块
|
||||
devtools:
|
||||
restart:
|
||||
# 热部署开关 线上记得关闭
|
||||
enabled: false
|
||||
# compatible with swagger
|
||||
mvc:
|
||||
pathmatch:
|
||||
matching-strategy: ANT_PATH_MATCHER
|
||||
jackson:
|
||||
deserialization:
|
||||
fail-on-unknown-properties: false
|
||||
serialization:
|
||||
write-dates-as-timestamps: false
|
||||
date-format: yyyy-MM-dd HH:mm:ss
|
||||
|
||||
|
||||
|
||||
# token配置
|
||||
token:
|
||||
# 令牌自定义标识
|
||||
header: Authorization
|
||||
# 令牌密钥 TODO 记得更换
|
||||
secret: sdhfkjshBN6rr32df38
|
||||
# 自动刷新token的时间
|
||||
autoRefreshTime: 20
|
||||
|
||||
# MyBatis配置
|
||||
mybatis-plus:
|
||||
# 搜索指定包别名 使用简短的类型名称来代替完整的类型名称
|
||||
# typeAliasesPackage: com.agileboot.orm.*
|
||||
# 配置mapper的扫描,找到所有的mapper.xml映射文件
|
||||
mapperLocations: classpath*:mapper/**/*Mapper.xml
|
||||
# 加载全局的配置文件
|
||||
configuration:
|
||||
cacheEnabled: true
|
||||
useGeneratedKeys: true
|
||||
defaultExecutorType: SIMPLE
|
||||
logImpl: org.apache.ibatis.logging.slf4j.Slf4jImpl
|
||||
global-config:
|
||||
refresh: true
|
||||
|
||||
|
||||
# PageHelper分页插件
|
||||
pagehelper:
|
||||
helperDialect: mysql
|
||||
supportMethodsArguments: true
|
||||
params: count=countSql
|
||||
|
||||
springdoc:
|
||||
api-docs:
|
||||
enabled: true
|
||||
path: /v3/api-docs
|
||||
groups:
|
||||
enabled: true
|
||||
# 配置需要生成接口文档的扫描包
|
||||
packages-to-scan: com.agileboot
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
Application Version: ${revision}
|
||||
Spring Boot Version: ${spring-boot.version}
|
||||
_ _ _ ____ _
|
||||
/ \ __ _ (_)| | ___ | __ ) ___ ___ | |_
|
||||
/ _ \ / _` || || | / _ \| _ \ / _ \ / _ \ | __|
|
||||
/ ___ \| (_| || || || __/| |_) || (_) || (_) || |_
|
||||
/_/ \_\\__, ||_||_| \___||____/ \___/ \___/ \__|
|
||||
|___/
|
||||
@@ -0,0 +1,225 @@
|
||||
/*
|
||||
Navicat MySQL Data Transfer
|
||||
|
||||
Source Server : Local-Mysql
|
||||
Source Server Version : 80029
|
||||
Source Host : localhost:33066
|
||||
Source Database : agileboot
|
||||
|
||||
Target Server Type : MYSQL
|
||||
Target Server Version : 80029
|
||||
File Encoding : 65001
|
||||
|
||||
Date: 2022-10-07 16:05:40
|
||||
*/
|
||||
|
||||
-- SET FOREIGN_KEY_CHECKS=0;
|
||||
|
||||
|
||||
-- ----------------------------
|
||||
-- Records of sys_config
|
||||
-- ----------------------------
|
||||
INSERT INTO `sys_config` VALUES ('1', '主框架页-默认皮肤样式名称', 'sys.index.skinName', '["skin-blue","skin-green","skin-purple","skin-red","skin-yellow"]', 'skin-blue', '1', null, null, '2022-08-28 22:12:19', '2022-05-21 08:30:55', '蓝色 skin-blue、绿色 skin-green、紫色 skin-purple、红色 skin-red、黄色 skin-yellow', '0');
|
||||
INSERT INTO `sys_config` VALUES ('2', '用户管理-账号初始密码', 'sys.user.initPassword', '', '1234567', '1', null, null, '2022-08-28 21:54:19', '2022-05-21 08:30:55', '初始化密码 123456', '0');
|
||||
INSERT INTO `sys_config` VALUES ('3', '主框架页-侧边栏主题', 'sys.index.sideTheme', '["theme-dark","theme-light"]', 'theme-dark', '1', null, null, '2022-08-28 22:12:15', '2022-08-20 08:30:55', '深色主题theme-dark,浅色主题theme-light', '0');
|
||||
INSERT INTO `sys_config` VALUES ('4', '账号自助-验证码开关', 'sys.account.captchaOnOff', '["true","false"]', 'false', '0', null, null, '2022-08-28 22:03:37', '2022-05-21 08:30:55', '是否开启验证码功能(true开启,false关闭)', '0');
|
||||
INSERT INTO `sys_config` VALUES ('5', '账号自助-是否开启用户注册功能', 'sys.account.registerUser', '["true","false"]', 'true', '0', null, '1', '2022-10-05 22:18:57', '2022-05-21 08:30:55', '是否开启注册用户功能(true开启,false关闭)', '0');
|
||||
|
||||
|
||||
-- ----------------------------
|
||||
-- Records of sys_dept
|
||||
-- ----------------------------
|
||||
INSERT INTO `sys_dept` VALUES ('1', '0', '0', 'AgileBoot科技', '0', null, 'valarchie', '15888888888', 'valarchie@163.com', '1', null, '2022-05-21 08:30:54', null, null, '0');
|
||||
INSERT INTO `sys_dept` VALUES ('2', '1', '0,1', '深圳总公司', '1', null, 'valarchie', '15888888888', 'valarchie@163.com', '1', null, '2022-05-21 08:30:54', null, null, '0');
|
||||
INSERT INTO `sys_dept` VALUES ('3', '1', '0,1', '长沙分公司', '2', null, 'valarchie', '15888888888', 'valarchie@163.com', '1', null, '2022-05-21 08:30:54', null, null, '0');
|
||||
INSERT INTO `sys_dept` VALUES ('4', '2', '0,1,2', '研发部门', '1', null, 'valarchie', '15888888888', 'valarchie@163.com', '1', null, '2022-05-21 08:30:54', null, null, '0');
|
||||
INSERT INTO `sys_dept` VALUES ('5', '2', '0,1,2', '市场部门', '2', null, 'valarchie', '15888888888', 'valarchie@163.com', '1', null, '2022-05-21 08:30:54', null, null, '0');
|
||||
INSERT INTO `sys_dept` VALUES ('6', '2', '0,1,2', '测试部门', '3', null, 'valarchie', '15888888888', 'valarchie@163.com', '1', null, '2022-05-21 08:30:54', null, null, '0');
|
||||
INSERT INTO `sys_dept` VALUES ('7', '2', '0,1,2', '财务部门', '4', null, 'valarchie', '15888888888', 'valarchie@163.com', '1', null, '2022-05-21 08:30:54', null, null, '0');
|
||||
INSERT INTO `sys_dept` VALUES ('8', '2', '0,1,2', '运维部门', '5', null, 'valarchie', '15888888888', 'valarchie@163.com', '1', null, '2022-05-21 08:30:54', null, null, '0');
|
||||
INSERT INTO `sys_dept` VALUES ('9', '3', '0,1,3', '市场部门', '1', null, 'valarchie', '15888888888', 'valarchie@163.com', '1', null, '2022-05-21 08:30:54', null, null, '0');
|
||||
INSERT INTO `sys_dept` VALUES ('10', '3', '0,1,3', '财务部门', '2', null, 'valarchie', '15888888888', 'valarchie@163.com', '0', null, '2022-05-21 08:30:54', null, null, '0');
|
||||
|
||||
|
||||
|
||||
-- ----------------------------
|
||||
-- Records of sys_login_info
|
||||
-- ----------------------------
|
||||
|
||||
-- ----------------------------
|
||||
-- Records of sys_menu
|
||||
-- ----------------------------
|
||||
INSERT INTO sys_menu VALUES (1, '系统管理', 2, '', 0, '/system', 0, '', '{"title":"系统管理","icon":"ep:management","showParent":1,"rank":1}', 1, '系统管理目录', 0, '2022-05-21 08:30:54', 1, '2023-08-14 23:08:50', 0);
|
||||
INSERT INTO sys_menu VALUES (2, '系统监控', 2, '', 0, '/monitor', 0, '', '{"title":"系统监控","icon":"ep:monitor","showParent":1,"rank":3}', 1, '系统监控目录', 0, '2022-05-21 08:30:54', 1, '2023-08-14 23:09:15', 0);
|
||||
INSERT INTO sys_menu VALUES (3, '系统工具', 2, '', 0, '/tool', 0, '', '{"title":"系统工具","icon":"ep:tools","showParent":1,"rank":2}', 1, '系统工具目录', 0, '2022-05-21 08:30:54', 1, '2023-08-14 23:09:03', 0);
|
||||
INSERT INTO sys_menu VALUES (4, 'AgileBoot官网', 3, 'AgileBootguanwangIframeRouter', 0, '/AgileBootguanwangIframeLink', 0, '', '{"title":"AgileBoot官网","icon":"ep:link","showParent":1,"frameSrc":"https://element-plus.org/zh-CN/","rank":8}', 1, 'Agileboot官网地址', 0, '2022-05-21 08:30:54', 1, '2023-08-14 23:09:40', 0);
|
||||
INSERT INTO sys_menu VALUES (5, '用户管理', 1, 'SystemUser', 1, '/system/user/index', 0, 'system:user:list', '{"title":"用户管理","icon":"ep:user-filled","showParent":1}', 1, '用户管理菜单', 0, '2022-05-21 08:30:54', 1, '2023-08-14 23:16:13', 0);
|
||||
INSERT INTO sys_menu VALUES (6, '角色管理', 1, 'SystemRole', 1, '/system/role/index', 0, 'system:role:list', '{"title":"角色管理","icon":"ep:user","showParent":1}', 1, '角色管理菜单', 0, '2022-05-21 08:30:54', 1, '2023-08-14 23:16:23', 0);
|
||||
INSERT INTO sys_menu VALUES (7, '菜单管理', 1, 'MenuManagement', 1, '/system/menu/index', 0, 'system:menu:list', '{"title":"菜单管理","icon":"ep:menu","showParent":1}', 1, '菜单管理菜单', 0, '2022-05-21 08:30:54', 1, '2023-08-14 23:15:41', 0);
|
||||
INSERT INTO sys_menu VALUES (8, '部门管理', 1, 'Department', 1, '/system/dept/index', 0, 'system:dept:list', '{"title":"部门管理","icon":"fa-solid:code-branch","showParent":1}', 1, '部门管理菜单', 0, '2022-05-21 08:30:54', 1, '2023-08-14 23:15:35', 0);
|
||||
INSERT INTO sys_menu VALUES (9, '岗位管理', 1, 'Post', 1, '/system/post/index', 0, 'system:post:list', '{"title":"岗位管理","icon":"ep:postcard","showParent":1}', 1, '岗位管理菜单', 0, '2022-05-21 08:30:54', 1, '2023-08-14 23:15:11', 0);
|
||||
INSERT INTO sys_menu VALUES (10, '参数设置', 1, 'Config', 1, '/system/config/index', 0, 'system:config:list', '{"title":"参数设置","icon":"ep:setting","showParent":1}', 1, '参数设置菜单', 0, '2022-05-21 08:30:54', 1, '2023-08-14 23:15:03', 0);
|
||||
INSERT INTO sys_menu VALUES (11, '通知公告', 1, 'SystemNotice', 1, '/system/notice/index', 0, 'system:notice:list', '{"title":"通知公告","icon":"ep:notification","showParent":1}', 1, '通知公告菜单', 0, '2022-05-21 08:30:54', 1, '2023-08-14 23:14:56', 0);
|
||||
INSERT INTO sys_menu VALUES (12, '日志管理', 1, 'LogManagement', 1, '/system/logd', 0, '', '{"title":"日志管理","icon":"ep:document","showParent":1}', 1, '日志管理菜单', 0, '2022-05-21 08:30:54', 1, '2023-08-14 23:14:47', 0);
|
||||
INSERT INTO sys_menu VALUES (13, '在线用户', 1, 'OnlineUser', 2, '/system/monitor/onlineUser/index', 0, 'monitor:online:list', '{"title":"在线用户","icon":"fa-solid:users","showParent":1}', 1, '在线用户菜单', 0, '2022-05-21 08:30:54', 1, '2023-08-14 23:13:13', 0);
|
||||
INSERT INTO sys_menu VALUES (14, '数据监控', 1, 'DataMonitor', 2, '/system/monitor/druid/index', 0, 'monitor:druid:list', '{"title":"数据监控","icon":"fa:database","showParent":1,"frameSrc":"/druid/login.html","isFrameSrcInternal":1}', 1, '数据监控菜单', 0, '2022-05-21 08:30:54', 1, '2023-08-14 23:13:25', 0);
|
||||
INSERT INTO sys_menu VALUES (15, '服务监控', 1, 'ServerInfo', 2, '/system/monitor/server/index', 0, 'monitor:server:list', '{"title":"服务监控","icon":"fa:server","showParent":1}', 1, '服务监控菜单', 0, '2022-05-21 08:30:54', 1, '2023-08-14 23:13:34', 0);
|
||||
INSERT INTO sys_menu VALUES (16, '缓存监控', 1, 'CacheInfo', 2, '/system/monitor/cache/index', 0, 'monitor:cache:list', '{"title":"缓存监控","icon":"ep:reading","showParent":1}', 1, '缓存监控菜单', 0, '2022-05-21 08:30:54', 1, '2023-08-14 23:12:59', 0);
|
||||
INSERT INTO sys_menu VALUES (17, '系统接口', 1, 'SystemAPI', 3, '/tool/swagger/index', 0, 'tool:swagger:list', '{"title":"系统接口","icon":"ep:document-remove","showParent":1,"frameSrc":"/swagger-ui/index.html","isFrameSrcInternal":1}', 1, '系统接口菜单', 0, '2022-05-21 08:30:54', 1, '2023-08-14 23:14:01', 0);
|
||||
INSERT INTO sys_menu VALUES (18, '操作日志', 1, 'OperationLog', 12, '/system/log/operationLog/index', 0, 'monitor:operlog:list', '{"title":"操作日志"}', 1, '操作日志菜单', 0, '2022-05-21 08:30:54', null, null, 0);
|
||||
INSERT INTO sys_menu VALUES (19, '登录日志', 1, 'LoginLog', 12, '/system/log/loginLog/index', 0, 'monitor:logininfor:list', '{"title":"登录日志"}', 1, '登录日志菜单', 0, '2022-05-21 08:30:54', null, null, 0);
|
||||
INSERT INTO sys_menu VALUES (20, '用户查询', 0, ' ', 5, '', 1, 'system:user:query', '{"title":"用户查询"}', 1, '', 0, '2022-05-21 08:30:54', null, null, 0);
|
||||
INSERT INTO sys_menu VALUES (21, '用户新增', 0, ' ', 5, '', 1, 'system:user:add', '{"title":"用户新增"}', 1, '', 0, '2022-05-21 08:30:54', null, null, 0);
|
||||
INSERT INTO sys_menu VALUES (22, '用户修改', 0, ' ', 5, '', 1, 'system:user:edit', '{"title":"用户修改"}', 1, '', 0, '2022-05-21 08:30:54', null, null, 0);
|
||||
INSERT INTO sys_menu VALUES (23, '用户删除', 0, ' ', 5, '', 1, 'system:user:remove', '{"title":"用户删除"}', 1, '', 0, '2022-05-21 08:30:54', null, null, 0);
|
||||
INSERT INTO sys_menu VALUES (24, '用户导出', 0, ' ', 5, '', 1, 'system:user:export', '{"title":"用户导出"}', 1, '', 0, '2022-05-21 08:30:54', null, null, 0);
|
||||
INSERT INTO sys_menu VALUES (25, '用户导入', 0, ' ', 5, '', 1, 'system:user:import', '{"title":"用户导入"}', 1, '', 0, '2022-05-21 08:30:54', null, null, 0);
|
||||
INSERT INTO sys_menu VALUES (26, '重置密码', 0, ' ', 5, '', 1, 'system:user:resetPwd', '{"title":"重置密码"}', 1, '', 0, '2022-05-21 08:30:54', null, null, 0);
|
||||
INSERT INTO sys_menu VALUES (27, '角色查询', 0, ' ', 6, '', 1, 'system:role:query', '{"title":"角色查询"}', 1, '', 0, '2022-05-21 08:30:54', null, null, 0);
|
||||
INSERT INTO sys_menu VALUES (28, '角色新增', 0, ' ', 6, '', 1, 'system:role:add', '{"title":"角色新增"}', 1, '', 0, '2022-05-21 08:30:54', null, null, 0);
|
||||
INSERT INTO sys_menu VALUES (29, '角色修改', 0, ' ', 6, '', 1, 'system:role:edit', '{"title":"角色修改"}', 1, '', 0, '2022-05-21 08:30:54', null, null, 0);
|
||||
INSERT INTO sys_menu VALUES (30, '角色删除', 0, ' ', 6, '', 1, 'system:role:remove', '{"title":"角色删除"}', 1, '', 0, '2022-05-21 08:30:54', null, null, 0);
|
||||
INSERT INTO sys_menu VALUES (31, '角色导出', 0, ' ', 6, '', 1, 'system:role:export', '{"title":"角色导出"}', 1, '', 0, '2022-05-21 08:30:54', null, null, 0);
|
||||
INSERT INTO sys_menu VALUES (32, '菜单查询', 0, ' ', 7, '', 1, 'system:menu:query', '{"title":"菜单查询"}', 1, '', 0, '2022-05-21 08:30:54', null, null, 0);
|
||||
INSERT INTO sys_menu VALUES (33, '菜单新增', 0, ' ', 7, '', 1, 'system:menu:add', '{"title":"菜单新增"}', 1, '', 0, '2022-05-21 08:30:54', null, null, 0);
|
||||
INSERT INTO sys_menu VALUES (34, '菜单修改', 0, ' ', 7, '', 1, 'system:menu:edit', '{"title":"菜单修改"}', 1, '', 0, '2022-05-21 08:30:54', null, null, 0);
|
||||
INSERT INTO sys_menu VALUES (35, '菜单删除', 0, ' ', 7, '', 1, 'system:menu:remove', '{"title":"菜单删除"}', 1, '', 0, '2022-05-21 08:30:54', null, null, 0);
|
||||
INSERT INTO sys_menu VALUES (36, '部门查询', 0, ' ', 8, '', 1, 'system:dept:query', '{"title":"部门查询"}', 1, '', 0, '2022-05-21 08:30:54', null, null, 0);
|
||||
INSERT INTO sys_menu VALUES (37, '部门新增', 0, ' ', 8, '', 1, 'system:dept:add', '{"title":"部门新增"}', 1, '', 0, '2022-05-21 08:30:54', null, null, 0);
|
||||
INSERT INTO sys_menu VALUES (38, '部门修改', 0, ' ', 8, '', 1, 'system:dept:edit', '{"title":"部门修改"}', 1, '', 0, '2022-05-21 08:30:54', null, null, 0);
|
||||
INSERT INTO sys_menu VALUES (39, '部门删除', 0, ' ', 8, '', 1, 'system:dept:remove', '{"title":"部门删除"}', 1, '', 0, '2022-05-21 08:30:54', null, null, 0);
|
||||
INSERT INTO sys_menu VALUES (40, '岗位查询', 0, ' ', 9, '', 1, 'system:post:query', '{"title":"岗位查询"}', 1, '', 0, '2022-05-21 08:30:54', null, null, 0);
|
||||
INSERT INTO sys_menu VALUES (41, '岗位新增', 0, ' ', 9, '', 1, 'system:post:add', '{"title":"岗位新增"}', 1, '', 0, '2022-05-21 08:30:54', null, null, 0);
|
||||
INSERT INTO sys_menu VALUES (42, '岗位修改', 0, ' ', 9, '', 1, 'system:post:edit', '{"title":"岗位修改"}', 1, '', 0, '2022-05-21 08:30:54', null, null, 0);
|
||||
INSERT INTO sys_menu VALUES (43, '岗位删除', 0, ' ', 9, '', 1, 'system:post:remove', '{"title":"岗位删除"}', 1, '', 0, '2022-05-21 08:30:54', null, null, 0);
|
||||
INSERT INTO sys_menu VALUES (44, '岗位导出', 0, ' ', 9, '', 1, 'system:post:export', '{"title":"岗位导出"}', 1, '', 0, '2022-05-21 08:30:54', null, null, 0);
|
||||
INSERT INTO sys_menu VALUES (45, '参数查询', 0, ' ', 10, '', 1, 'system:config:query', '{"title":"参数查询"}', 1, '', 0, '2022-05-21 08:30:54', null, null, 0);
|
||||
INSERT INTO sys_menu VALUES (46, '参数新增', 0, ' ', 10, '', 1, 'system:config:add', '{"title":"参数新增"}', 1, '', 0, '2022-05-21 08:30:54', null, null, 0);
|
||||
INSERT INTO sys_menu VALUES (47, '参数修改', 0, ' ', 10, '', 1, 'system:config:edit', '{"title":"参数修改"}', 1, '', 0, '2022-05-21 08:30:54', null, null, 0);
|
||||
INSERT INTO sys_menu VALUES (48, '参数删除', 0, ' ', 10, '', 1, 'system:config:remove', '{"title":"参数删除"}', 1, '', 0, '2022-05-21 08:30:54', null, null, 0);
|
||||
INSERT INTO sys_menu VALUES (49, '参数导出', 0, ' ', 10, '', 1, 'system:config:export', '{"title":"参数导出"}', 1, '', 0, '2022-05-21 08:30:54', null, null, 0);
|
||||
INSERT INTO sys_menu VALUES (50, '公告查询', 0, ' ', 11, '', 1, 'system:notice:query', '{"title":"公告查询"}', 1, '', 0, '2022-05-21 08:30:54', null, null, 0);
|
||||
INSERT INTO sys_menu VALUES (51, '公告新增', 0, ' ', 11, '', 1, 'system:notice:add', '{"title":"公告新增"}', 1, '', 0, '2022-05-21 08:30:54', null, null, 0);
|
||||
INSERT INTO sys_menu VALUES (52, '公告修改', 0, ' ', 11, '', 1, 'system:notice:edit', '{"title":"公告修改"}', 1, '', 0, '2022-05-21 08:30:54', null, null, 0);
|
||||
INSERT INTO sys_menu VALUES (53, '公告删除', 0, ' ', 11, '', 1, 'system:notice:remove', '{"title":"公告删除"}', 1, '', 0, '2022-05-21 08:30:54', null, null, 0);
|
||||
INSERT INTO sys_menu VALUES (54, '操作查询', 0, ' ', 18, '', 1, 'monitor:operlog:query', '{"title":"操作查询"}', 1, '', 0, '2022-05-21 08:30:54', null, null, 0);
|
||||
INSERT INTO sys_menu VALUES (55, '操作删除', 0, ' ', 18, '', 1, 'monitor:operlog:remove', '{"title":"操作删除"}', 1, '', 0, '2022-05-21 08:30:54', null, null, 0);
|
||||
INSERT INTO sys_menu VALUES (56, '日志导出', 0, ' ', 18, '', 1, 'monitor:operlog:export', '{"title":"日志导出"}', 1, '', 0, '2022-05-21 08:30:54', null, null, 0);
|
||||
INSERT INTO sys_menu VALUES (57, '登录查询', 0, ' ', 19, '', 1, 'monitor:logininfor:query', '{"title":"登录查询"}', 1, '', 0, '2022-05-21 08:30:54', null, null, 0);
|
||||
INSERT INTO sys_menu VALUES (58, '登录删除', 0, ' ', 19, '', 1, 'monitor:logininfor:remove', '{"title":"登录删除"}', 1, '', 0, '2022-05-21 08:30:54', null, null, 0);
|
||||
INSERT INTO sys_menu VALUES (59, '日志导出', 0, ' ', 19, '', 1, 'monitor:logininfor:export', '{"title":"日志导出","rank":22}', 1, '', 0, '2022-05-21 08:30:54', 1, '2023-07-22 17:02:28', 0);
|
||||
INSERT INTO sys_menu VALUES (60, '在线查询', 0, ' ', 13, '', 1, 'monitor:online:query', '{"title":"在线查询"}', 1, '', 0, '2022-05-21 08:30:54', null, null, 0);
|
||||
INSERT INTO sys_menu VALUES (61, '批量强退', 0, ' ', 13, '', 1, 'monitor:online:batchLogout', '{"title":"批量强退"}', 1, '', 0, '2022-05-21 08:30:54', null, null, 0);
|
||||
INSERT INTO sys_menu VALUES (62, '单条强退', 0, ' ', 13, '', 1, 'monitor:online:forceLogout', '{"title":"单条强退"}', 1, '', 0, '2022-05-21 08:30:54', null, null, 0);
|
||||
INSERT INTO sys_menu VALUES (63, 'AgileBoot Github地址', 4, 'https://github.com/valarchie/AgileBoot-Back-End', 0, '/external', 0, '', '{"title":"AgileBoot Github地址","icon":"fa-solid:external-link-alt","showParent":1,"rank":9}', 1, 'Agileboot github地址', 0, '2022-05-21 08:30:54', 1, '2023-08-14 23:12:13', 0);
|
||||
INSERT INTO sys_menu VALUES (64, '首页', 2, '', 0, '/global', 0, '121212', '{"title":"首页","showParent":1,"rank":3}', 1, '', 1, '2023-07-24 22:36:03', 1, '2023-07-24 22:38:37', 1);
|
||||
INSERT INTO sys_menu VALUES (65, '个人中心', 1, 'PersonalCenter', 2053, '/system/user/profile', 0, '434sdf', '{"title":"个人中心","showParent":1,"rank":3}', 1, '', 1, '2023-07-24 22:36:55', null, null, 1);
|
||||
|
||||
|
||||
-- ----------------------------
|
||||
-- Records of sys_notice
|
||||
-- ----------------------------
|
||||
INSERT INTO `sys_notice` VALUES ('1', '温馨提醒:2018-07-01 AgileBoot新版本发布啦', '2', '新版本内容~~~~~~~~~~', '1', '1', '2022-05-21 08:30:55', '1', '2022-08-29 20:12:37', '管理员', '0');
|
||||
INSERT INTO `sys_notice` VALUES ('2', '维护通知:2018-07-01 AgileBoot系统凌晨维护', '1', '维护内容', '1', '1', '2022-05-21 08:30:55', null, null, '管理员', '0');
|
||||
|
||||
|
||||
-- ----------------------------
|
||||
-- Records of sys_operation_log
|
||||
-- ----------------------------
|
||||
|
||||
|
||||
|
||||
-- ----------------------------
|
||||
-- Records of sys_post
|
||||
-- ----------------------------
|
||||
INSERT INTO `sys_post` VALUES ('1', 'ceo', '董事长', '1', '1', '', null, '2022-05-21 08:30:54', null, null, '0');
|
||||
INSERT INTO `sys_post` VALUES ('2', 'se', '项目经理', '2', '1', '', null, '2022-05-21 08:30:54', null, null, '0');
|
||||
INSERT INTO `sys_post` VALUES ('3', 'hr', '人力资源', '3', '1', '', null, '2022-05-21 08:30:54', null, null, '0');
|
||||
INSERT INTO `sys_post` VALUES ('4', 'user', '普通员工', '5', '0', '', null, '2022-05-21 08:30:54', null, null, '0');
|
||||
|
||||
|
||||
-- ----------------------------
|
||||
-- Records of sys_role
|
||||
-- ----------------------------
|
||||
INSERT INTO `sys_role` VALUES ('1', '超级管理员', 'admin', '1', '1', '', '1', null, '2022-05-21 08:30:54', null, null, '超级管理员', '0');
|
||||
INSERT INTO `sys_role` VALUES ('2', '普通角色', 'common', '3', '2', '', '1', null, '2022-05-21 08:30:54', null, null, '普通角色', '0');
|
||||
INSERT INTO `sys_role` VALUES ('3', '闲置角色', 'unused', '4', '2', '', '0', null, '2022-05-21 08:30:54', null, null, '未使用的角色', '0');
|
||||
|
||||
|
||||
|
||||
-- ----------------------------
|
||||
-- Records of sys_role_menu
|
||||
-- ----------------------------
|
||||
INSERT INTO `sys_role_menu` VALUES ('2', '1');
|
||||
INSERT INTO `sys_role_menu` VALUES ('2', '2');
|
||||
INSERT INTO `sys_role_menu` VALUES ('2', '3');
|
||||
INSERT INTO `sys_role_menu` VALUES ('2', '4');
|
||||
INSERT INTO `sys_role_menu` VALUES ('2', '5');
|
||||
INSERT INTO `sys_role_menu` VALUES ('2', '6');
|
||||
INSERT INTO `sys_role_menu` VALUES ('2', '7');
|
||||
INSERT INTO `sys_role_menu` VALUES ('2', '8');
|
||||
INSERT INTO `sys_role_menu` VALUES ('2', '9');
|
||||
INSERT INTO `sys_role_menu` VALUES ('2', '10');
|
||||
INSERT INTO `sys_role_menu` VALUES ('2', '11');
|
||||
INSERT INTO `sys_role_menu` VALUES ('2', '12');
|
||||
INSERT INTO `sys_role_menu` VALUES ('2', '13');
|
||||
INSERT INTO `sys_role_menu` VALUES ('2', '14');
|
||||
INSERT INTO `sys_role_menu` VALUES ('2', '15');
|
||||
INSERT INTO `sys_role_menu` VALUES ('2', '16');
|
||||
INSERT INTO `sys_role_menu` VALUES ('2', '17');
|
||||
INSERT INTO `sys_role_menu` VALUES ('2', '18');
|
||||
INSERT INTO `sys_role_menu` VALUES ('2', '19');
|
||||
INSERT INTO `sys_role_menu` VALUES ('2', '20');
|
||||
INSERT INTO `sys_role_menu` VALUES ('2', '21');
|
||||
INSERT INTO `sys_role_menu` VALUES ('2', '22');
|
||||
INSERT INTO `sys_role_menu` VALUES ('2', '23');
|
||||
INSERT INTO `sys_role_menu` VALUES ('2', '24');
|
||||
INSERT INTO `sys_role_menu` VALUES ('2', '25');
|
||||
INSERT INTO `sys_role_menu` VALUES ('2', '26');
|
||||
INSERT INTO `sys_role_menu` VALUES ('2', '27');
|
||||
INSERT INTO `sys_role_menu` VALUES ('2', '28');
|
||||
INSERT INTO `sys_role_menu` VALUES ('2', '29');
|
||||
INSERT INTO `sys_role_menu` VALUES ('2', '30');
|
||||
INSERT INTO `sys_role_menu` VALUES ('2', '31');
|
||||
INSERT INTO `sys_role_menu` VALUES ('2', '32');
|
||||
INSERT INTO `sys_role_menu` VALUES ('2', '33');
|
||||
INSERT INTO `sys_role_menu` VALUES ('2', '34');
|
||||
INSERT INTO `sys_role_menu` VALUES ('2', '35');
|
||||
INSERT INTO `sys_role_menu` VALUES ('2', '36');
|
||||
INSERT INTO `sys_role_menu` VALUES ('2', '37');
|
||||
INSERT INTO `sys_role_menu` VALUES ('2', '38');
|
||||
INSERT INTO `sys_role_menu` VALUES ('2', '39');
|
||||
INSERT INTO `sys_role_menu` VALUES ('2', '40');
|
||||
INSERT INTO `sys_role_menu` VALUES ('2', '41');
|
||||
INSERT INTO `sys_role_menu` VALUES ('2', '42');
|
||||
INSERT INTO `sys_role_menu` VALUES ('2', '43');
|
||||
INSERT INTO `sys_role_menu` VALUES ('2', '44');
|
||||
INSERT INTO `sys_role_menu` VALUES ('2', '45');
|
||||
INSERT INTO `sys_role_menu` VALUES ('2', '46');
|
||||
INSERT INTO `sys_role_menu` VALUES ('2', '47');
|
||||
INSERT INTO `sys_role_menu` VALUES ('2', '48');
|
||||
INSERT INTO `sys_role_menu` VALUES ('2', '49');
|
||||
INSERT INTO `sys_role_menu` VALUES ('2', '50');
|
||||
INSERT INTO `sys_role_menu` VALUES ('2', '51');
|
||||
INSERT INTO `sys_role_menu` VALUES ('2', '52');
|
||||
INSERT INTO `sys_role_menu` VALUES ('2', '53');
|
||||
INSERT INTO `sys_role_menu` VALUES ('2', '54');
|
||||
INSERT INTO `sys_role_menu` VALUES ('2', '55');
|
||||
INSERT INTO `sys_role_menu` VALUES ('2', '56');
|
||||
INSERT INTO `sys_role_menu` VALUES ('2', '57');
|
||||
INSERT INTO `sys_role_menu` VALUES ('2', '58');
|
||||
INSERT INTO `sys_role_menu` VALUES ('2', '59');
|
||||
INSERT INTO `sys_role_menu` VALUES ('2', '60');
|
||||
INSERT INTO `sys_role_menu` VALUES ('2', '61');
|
||||
-- roleId = 2的权限 特地少一个 方便测试
|
||||
INSERT INTO `sys_role_menu` VALUES ('3', '1');
|
||||
|
||||
|
||||
|
||||
|
||||
-- ----------------------------
|
||||
-- Records of sys_user
|
||||
-- ----------------------------
|
||||
INSERT INTO `sys_user` VALUES ('1', '1', '1', '4', 'admin', 'valarchie1', '0', 'agileboot@163.com', '15888888889', '0', '', '$2a$10$rb1wRoEIkLbIknREEN1LH.FGs4g0oOS5t6l5LQ793nRaFO.SPHDHy', '1', '127.0.0.1', '2022-10-06 17:00:06', 1, null, '2022-05-21 08:30:54', '1', '2022-10-06 17:00:06', '管理员', '0');
|
||||
INSERT INTO `sys_user` VALUES ('2', '2', '2', '5', 'ag1', 'valarchie2', '0', 'agileboot1@qq.com', '15666666666', '1', '', '$2a$10$7JB720yubVSZvUI0rEqK/.VqGOZTH.ulu33dHOiBE8ByOhJIrdAu2', '1', '127.0.0.1', '2022-05-21 08:30:54', 0, null, '2022-05-21 08:30:54', null, null, '测试员1', '0');
|
||||
INSERT INTO `sys_user` VALUES ('3', '2', '0', '5', 'ag2', 'valarchie3', '0', 'agileboot2@qq.com', '15666666667', '1', '', '$2a$10$7JB720yubVSZvUI0rEqK/.VqGOZTH.ulu33dHOiBE8ByOhJIrdAu2', '1', '127.0.0.1', '2022-05-21 08:30:54', 0, null, '2022-05-21 08:30:54', null, null, '测试员2', '0');
|
||||
@@ -0,0 +1,184 @@
|
||||
|
||||
--- int后面不能带数字, 索引相关的语句也不允许, 保留最简单原始的语句即可
|
||||
create sequence if not exists sys_config_seq start with 6 increment by 1;
|
||||
create table sys_config
|
||||
(
|
||||
config_id int default next value for sys_config_seq,
|
||||
config_name varchar(128) default '' not null comment '配置名称',
|
||||
config_key varchar(128) default '' not null comment '配置键名',
|
||||
config_options varchar(1024) default '' not null comment '可选的选项',
|
||||
config_value varchar(256) default '' not null comment '配置值',
|
||||
is_allow_change int not null comment '是否允许修改',
|
||||
creator_id int null comment '创建者ID',
|
||||
updater_id int null comment '更新者ID',
|
||||
update_time datetime null comment '更新时间',
|
||||
create_time datetime null comment '创建时间',
|
||||
remark varchar(128) null comment '备注',
|
||||
deleted int default 0 not null comment '逻辑删除'
|
||||
);
|
||||
|
||||
create sequence if not exists sys_dept_seq start with 11 increment by 1;
|
||||
create table sys_dept
|
||||
(
|
||||
dept_id int default next value for sys_dept_seq,
|
||||
parent_id bigint default 0 not null comment '父部门id',
|
||||
ancestors text not null comment '祖级列表',
|
||||
dept_name varchar(64) default '' not null comment '部门名称',
|
||||
order_num int default 0 not null comment '显示顺序',
|
||||
leader_id bigint null,
|
||||
leader_name varchar(64) null comment '负责人',
|
||||
phone varchar(16) null comment '联系电话',
|
||||
email varchar(128) null comment '邮箱',
|
||||
status smallint default 0 not null comment '部门状态(0正常 1停用)',
|
||||
creator_id bigint null comment '创建者ID',
|
||||
create_time datetime null comment '创建时间',
|
||||
updater_id bigint null comment '更新者ID',
|
||||
update_time datetime null comment '更新时间',
|
||||
deleted tinyint default 0 not null comment '逻辑删除'
|
||||
);
|
||||
|
||||
create sequence if not exists sys_login_info_seq start with 1 increment by 1;
|
||||
create table sys_login_info
|
||||
(
|
||||
info_id bigint default next value for sys_login_info_seq,
|
||||
username varchar(50) default '' not null comment '用户账号',
|
||||
ip_address varchar(128) default '' not null comment '登录IP地址',
|
||||
login_location varchar(255) default '' not null comment '登录地点',
|
||||
browser varchar(50) default '' not null comment '浏览器类型',
|
||||
operation_system varchar(50) default '' not null comment '操作系统',
|
||||
status smallint default 0 not null comment '登录状态(1成功 0失败)',
|
||||
msg varchar(255) default '' not null comment '提示消息',
|
||||
login_time datetime null comment '访问时间',
|
||||
deleted tinyint default 0 not null comment '逻辑删除'
|
||||
);
|
||||
|
||||
create sequence if not exists sys_menu_seq start with 63 increment by 1;
|
||||
create table sys_menu
|
||||
(
|
||||
menu_id bigint auto_increment comment '菜单ID'
|
||||
primary key,
|
||||
menu_name varchar(64) not null comment '菜单名称',
|
||||
menu_type smallint default 0 not null comment '菜单的类型(1为普通菜单2为目录3为内嵌iFrame4为外链跳转)',
|
||||
router_name varchar(255) default '' not null comment '路由名称(需保持和前端对应的vue文件中的name保持一致defineOptions方法中设置的name)',
|
||||
parent_id bigint default 0 not null comment '父菜单ID',
|
||||
path varchar(255) null comment '组件路径(对应前端项目view文件夹中的路径)',
|
||||
is_button tinyint(1) default 0 not null comment '是否按钮',
|
||||
permission varchar(128) null comment '权限标识',
|
||||
meta_info varchar(1024) default '{}' not null comment '路由元信息(前端根据这个信息进行逻辑处理)',
|
||||
status smallint default 0 not null comment '菜单状态(1启用 0停用)',
|
||||
remark varchar(256) default '' null comment '备注',
|
||||
creator_id bigint null comment '创建者ID',
|
||||
create_time datetime null comment '创建时间',
|
||||
updater_id bigint null comment '更新者ID',
|
||||
update_time datetime null comment '更新时间',
|
||||
deleted tinyint(1) default 0 not null comment '逻辑删除'
|
||||
);
|
||||
|
||||
create sequence if not exists sys_notice_seq start with 3 increment by 1;
|
||||
create table sys_notice
|
||||
(
|
||||
notice_id int default next value for sys_notice_seq,
|
||||
notice_title varchar(64) not null comment '公告标题',
|
||||
notice_type smallint not null comment '公告类型(1通知 2公告)',
|
||||
notice_content text null comment '公告内容',
|
||||
status smallint default 0 not null comment '公告状态(1正常 0关闭)',
|
||||
creator_id bigint not null comment '创建者ID',
|
||||
create_time datetime null comment '创建时间',
|
||||
updater_id bigint null comment '更新者ID',
|
||||
update_time datetime null comment '更新时间',
|
||||
remark varchar(255) default '' not null comment '备注',
|
||||
deleted tinyint default 0 not null comment '逻辑删除'
|
||||
);
|
||||
|
||||
create sequence if not exists sys_operation_log_seq start with 1 increment by 1;
|
||||
create table sys_operation_log
|
||||
(
|
||||
operation_id bigint default next value for sys_operation_log_seq,
|
||||
business_type smallint default 0 not null comment '业务类型(0其它 1新增 2修改 3删除)',
|
||||
request_method smallint default 0 not null comment '请求方式',
|
||||
request_module varchar(64) default '' not null comment '请求模块',
|
||||
request_url varchar(256) default '' not null comment '请求URL',
|
||||
called_method varchar(128) default '' not null comment '调用方法',
|
||||
operator_type smallint default 0 not null comment '操作类别(0其它 1后台用户 2手机端用户)',
|
||||
user_id bigint default 0 null comment '用户ID',
|
||||
username varchar(32) default '' null comment '操作人员',
|
||||
operator_ip varchar(128) default '' null comment '操作人员ip',
|
||||
operator_location varchar(256) default '' null comment '操作地点',
|
||||
dept_id bigint default 0 null comment '部门ID',
|
||||
dept_name varchar(64) null comment '部门名称',
|
||||
operation_param varchar(2048) default '' null comment '请求参数',
|
||||
operation_result varchar(2048) default '' null comment '返回参数',
|
||||
status smallint default 1 not null comment '操作状态(1正常 0异常)',
|
||||
error_stack varchar(2048) default '' null comment '错误消息',
|
||||
operation_time datetime not null comment '操作时间',
|
||||
deleted tinyint default 0 not null comment '逻辑删除'
|
||||
);
|
||||
|
||||
create sequence if not exists sys_post_seq start with 5 increment by 1;
|
||||
create table sys_post
|
||||
(
|
||||
post_id bigint default next value for sys_post_seq,
|
||||
post_code varchar(64) not null comment '岗位编码',
|
||||
post_name varchar(64) not null comment '岗位名称',
|
||||
post_sort int not null comment '显示顺序',
|
||||
status smallint not null comment '状态(1正常 0停用)',
|
||||
remark varchar(512) null comment '备注',
|
||||
creator_id bigint null,
|
||||
create_time datetime null comment '创建时间',
|
||||
updater_id bigint null,
|
||||
update_time datetime null comment '更新时间',
|
||||
deleted tinyint default 0 not null comment '逻辑删除'
|
||||
);
|
||||
|
||||
create sequence if not exists sys_role_seq start with 4 increment by 1;
|
||||
create table sys_role
|
||||
(
|
||||
role_id bigint default next value for sys_role_seq,
|
||||
role_name varchar(32) not null comment '角色名称',
|
||||
role_key varchar(128) not null comment '角色权限字符串',
|
||||
role_sort int not null comment '显示顺序',
|
||||
data_scope smallint default 1 null comment '数据范围(1:全部数据权限 2:自定数据权限 3: 本部门数据权限 4: 本部门及以下数据权限 5: 本人权限)',
|
||||
dept_id_set varchar(1024) default '' null comment '角色所拥有的部门数据权限',
|
||||
status smallint not null comment '角色状态(1正常 0停用)',
|
||||
creator_id bigint null comment '创建者ID',
|
||||
create_time datetime null comment '创建时间',
|
||||
updater_id bigint null comment '更新者ID',
|
||||
update_time datetime null comment '更新时间',
|
||||
remark varchar(512) null comment '备注',
|
||||
deleted tinyint default 0 not null comment '删除标志(0代表存在 1代表删除)'
|
||||
);
|
||||
|
||||
create table sys_role_menu
|
||||
(
|
||||
role_id bigint auto_increment not null comment '角色ID',
|
||||
menu_id bigint auto_increment not null comment '菜单ID'
|
||||
);
|
||||
|
||||
create sequence if not exists sys_user_seq start with 4 increment by 1;
|
||||
create table sys_user
|
||||
(
|
||||
user_id bigint default next value for sys_user_seq,
|
||||
post_id bigint null comment '职位id',
|
||||
role_id bigint null comment '角色id',
|
||||
dept_id bigint null comment '部门ID',
|
||||
username varchar(64) not null comment '用户账号',
|
||||
nickname varchar(32) not null comment '用户昵称',
|
||||
user_type smallint default 0 null comment '用户类型(00系统用户)',
|
||||
email varchar(128) default '' null comment '用户邮箱',
|
||||
phone_number varchar(18) default '' null comment '手机号码',
|
||||
sex smallint default 0 null comment '用户性别(0男 1女 2未知)',
|
||||
avatar varchar(512) default '' null comment '头像地址',
|
||||
password varchar(128) default '' not null comment '密码',
|
||||
status smallint default 0 not null comment '帐号状态(1正常 2停用 3冻结)',
|
||||
login_ip varchar(128) default '' null comment '最后登录IP',
|
||||
login_date datetime null comment '最后登录时间',
|
||||
is_admin tinyint default 0 not null comment '超级管理员标志(1是,0否)',
|
||||
creator_id bigint null comment '更新者ID',
|
||||
create_time datetime null comment '创建时间',
|
||||
updater_id bigint null comment '更新者ID',
|
||||
update_time datetime null comment '更新时间',
|
||||
remark varchar(512) null comment '备注',
|
||||
deleted tinyint default 0 not null comment '删除标志(0代表存在 1代表删除)'
|
||||
);
|
||||
|
||||
CREATE ALIAS FIND_IN_SET FOR "com.agileboot.infrastructure.mybatisplus.MySqlFunction.findInSet";
|
||||
@@ -0,0 +1,10 @@
|
||||
#错误消息 有些版本的 IDEA 会自动设置properties的编码为IOS-8859-1 请设置成UTF8
|
||||
SUCCESS=操作成功
|
||||
FAIL=操作失败
|
||||
|
||||
Business.LOGIN_WRONG_USER_PASSWORD=用户不存在/密码错误
|
||||
|
||||
Business.LOGIN_CAPTCHA_CODE_WRONG=验证码错误
|
||||
Business.LOGIN_CAPTCHA_CODE_EXPIRE=验证码过期
|
||||
|
||||
Client.COMMON_REQUEST_TOO_OFTEN=调用太过频繁,请稍后再试
|
||||
@@ -0,0 +1,122 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<configuration>
|
||||
|
||||
<!-- 日志存放路径 在xml文件夹中 -->
|
||||
<springProperty name="log.path" source="logging.file.path"/>
|
||||
|
||||
<springProperty name="console.pattern" source="logging.pattern.console"/>
|
||||
|
||||
<!-- 日志输出格式 -->
|
||||
<property name="log.pattern" value="%d{HH:mm:ss.SSS} [%thread] %-5level %logger{20} - [%method,%line] - %msg%n"/>
|
||||
|
||||
<!-- 控制台输出 -->
|
||||
<appender name="console" class="ch.qos.logback.core.ConsoleAppender">
|
||||
<encoder>
|
||||
<pattern>${console.pattern}</pattern>
|
||||
</encoder>
|
||||
</appender>
|
||||
|
||||
<!-- 系统日志输出 -->
|
||||
<appender name="info_log" class="ch.qos.logback.core.rolling.RollingFileAppender">
|
||||
<file>${log.path}/sys-info.log</file>
|
||||
<!-- 循环政策:基于时间创建日志文件 -->
|
||||
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
|
||||
<!-- 日志文件名格式 -->
|
||||
<fileNamePattern>${log.path}/sys-info.%d{yyyy-MM-dd}.log</fileNamePattern>
|
||||
<!-- 日志最大的历史 60天 -->
|
||||
<maxHistory>60</maxHistory>
|
||||
</rollingPolicy>
|
||||
<encoder>
|
||||
<pattern>${log.pattern}</pattern>
|
||||
</encoder>
|
||||
<filter class="ch.qos.logback.classic.filter.LevelFilter">
|
||||
<!-- 过滤的级别 -->
|
||||
<level>INFO</level>
|
||||
<!-- 匹配时的操作:接收(记录) -->
|
||||
<onMatch>ACCEPT</onMatch>
|
||||
<!-- 不匹配时的操作:拒绝(不记录) -->
|
||||
<onMismatch>DENY</onMismatch>
|
||||
</filter>
|
||||
</appender>
|
||||
|
||||
<appender name="error_log" class="ch.qos.logback.core.rolling.RollingFileAppender">
|
||||
<file>${log.path}/sys-error.log</file>
|
||||
<!-- 循环政策:基于时间创建日志文件 -->
|
||||
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
|
||||
<!-- 日志文件名格式 -->
|
||||
<fileNamePattern>${log.path}/sys-error.%d{yyyy-MM-dd}.log</fileNamePattern>
|
||||
<!-- 日志最大的历史 60天 -->
|
||||
<maxHistory>60</maxHistory>
|
||||
</rollingPolicy>
|
||||
<encoder>
|
||||
<pattern>${log.pattern}</pattern>
|
||||
</encoder>
|
||||
<filter class="ch.qos.logback.classic.filter.LevelFilter">
|
||||
<!-- 过滤的级别 -->
|
||||
<level>ERROR</level>
|
||||
<!-- 匹配时的操作:接收(记录) -->
|
||||
<onMatch>ACCEPT</onMatch>
|
||||
<!-- 不匹配时的操作:拒绝(不记录) -->
|
||||
<onMismatch>DENY</onMismatch>
|
||||
</filter>
|
||||
</appender>
|
||||
|
||||
<!-- debug日志输出 -->
|
||||
<appender name="debug_log" class="ch.qos.logback.core.rolling.RollingFileAppender">
|
||||
<file>${log.path}/sys-debug.log</file>
|
||||
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
|
||||
<!-- 按天回滚 daily -->
|
||||
<fileNamePattern>${log.path}/sys-debug.%d{yyyy-MM-dd}.log</fileNamePattern>
|
||||
<!-- 日志最大的历史 60天 -->
|
||||
<maxHistory>60</maxHistory>
|
||||
</rollingPolicy>
|
||||
<encoder>
|
||||
<pattern>${log.pattern}</pattern>
|
||||
</encoder>
|
||||
</appender>
|
||||
|
||||
<!-- 异步输出 -->
|
||||
<appender name="async_info_log" class="ch.qos.logback.classic.AsyncAppender">
|
||||
<!-- 不丢失日志.默认的,如果队列的80%已满,则会丢弃TRACT、DEBUG、INFO级别的日志 -->
|
||||
<discardingThreshold>0</discardingThreshold>
|
||||
<!-- 更改默认的队列的深度,该值会影响性能.默认值为256 -->
|
||||
<queueSize>256</queueSize>
|
||||
<!-- 添加附加的appender,最多只能添加一个 -->
|
||||
<appender-ref ref="info_log"/>
|
||||
<!-- %class%line中没有显示正确的值,而是两个问号? 解决办法:一般出现在AsyncAppender中,需要添加属性 -->
|
||||
<includeCallerData>true</includeCallerData>
|
||||
</appender>
|
||||
|
||||
<!-- 异步输出 -->
|
||||
<appender name="async_error_log" class="ch.qos.logback.classic.AsyncAppender">
|
||||
<!-- 不丢失日志.默认的,如果队列的80%已满,则会丢弃TRACT、DEBUG、INFO级别的日志 -->
|
||||
<discardingThreshold>0</discardingThreshold>
|
||||
<!-- 更改默认的队列的深度,该值会影响性能.默认值为256 -->
|
||||
<queueSize>256</queueSize>
|
||||
<!-- 添加附加的appender,最多只能添加一个 -->
|
||||
<appender-ref ref="error_log"/>
|
||||
<includeCallerData>true</includeCallerData>
|
||||
</appender>
|
||||
|
||||
<!-- 异步输出 -->
|
||||
<appender name="async_debug_log" class="ch.qos.logback.classic.AsyncAppender">
|
||||
<!-- 不丢失日志.默认的,如果队列的80%已满,则会丢弃TRACT、DEBUG、INFO级别的日志 -->
|
||||
<discardingThreshold>256</discardingThreshold>
|
||||
<!-- 更改默认的队列的深度,该值会影响性能.默认值为256 -->
|
||||
<queueSize>1024</queueSize>
|
||||
<!-- 添加附加的appender,最多只能添加一个 -->
|
||||
<appender-ref ref="debug_log"/>
|
||||
<includeCallerData>true</includeCallerData>
|
||||
</appender>
|
||||
|
||||
|
||||
<root level="info">
|
||||
<appender-ref ref="console"/>
|
||||
<appender-ref ref="async_info_log"/>
|
||||
<appender-ref ref="async_error_log"/>
|
||||
<appender-ref ref="async_debug_log"/>
|
||||
</root>
|
||||
|
||||
|
||||
|
||||
</configuration>
|
||||
@@ -0,0 +1,195 @@
|
||||
|
||||
|
||||
INSERT INTO app.sys_config (config_id, config_name, config_key, config_options, config_value, is_allow_change, creator_id, updater_id, update_time, create_time, remark, deleted) VALUES (1, '主框架页-默认皮肤样式名称', 'sys.index.skinName', '["skin-blue","skin-green","skin-purple","skin-red","skin-yellow"]', 'skin-blue', true, null, null, '2022-08-28 22:12:19', '2022-05-21 08:30:55', '蓝色 skin-blue、绿色 skin-green、紫色 skin-purple、红色 skin-red、黄色 skin-yellow', 0);
|
||||
INSERT INTO app.sys_config (config_id, config_name, config_key, config_options, config_value, is_allow_change, creator_id, updater_id, update_time, create_time, remark, deleted) VALUES (2, '用户管理-账号初始密码', 'sys.user.initPassword', '', '123456', true, null, 1, '2023-07-20 14:42:08', '2022-05-21 08:30:55', '初始化密码 123456', 0);
|
||||
INSERT INTO app.sys_config (config_id, config_name, config_key, config_options, config_value, is_allow_change, creator_id, updater_id, update_time, create_time, remark, deleted) VALUES (3, '主框架页-侧边栏主题', 'sys.index.sideTheme', '["theme-dark","theme-light"]', 'theme-dark', true, null, null, '2022-08-28 22:12:15', '2022-08-20 08:30:55', '深色主题theme-dark,浅色主题theme-light', 0);
|
||||
INSERT INTO app.sys_config (config_id, config_name, config_key, config_options, config_value, is_allow_change, creator_id, updater_id, update_time, create_time, remark, deleted) VALUES (4, '账号自助-验证码开关', 'sys.account.captchaOnOff', '["true","false"]', 'false', false, null, 1, '2023-07-20 14:39:36', '2022-05-21 08:30:55', '是否开启验证码功能(true开启,false关闭)', 0);
|
||||
INSERT INTO app.sys_config (config_id, config_name, config_key, config_options, config_value, is_allow_change, creator_id, updater_id, update_time, create_time, remark, deleted) VALUES (5, '账号自助-是否开启用户注册功能', 'sys.account.registerUser', '["true","false"]', 'true', false, null, 1, '2022-10-05 22:18:57', '2022-05-21 08:30:55', '是否开启注册用户功能(true开启,false关闭)', 0);
|
||||
|
||||
|
||||
INSERT INTO app.sys_dept (dept_id, parent_id, ancestors, dept_name, order_num, leader_id, leader_name, phone, email, status, creator_id, create_time, updater_id, update_time, deleted) VALUES (1, 0, '0', 'AgileBoot科技', 0, null, 'valarchie', '15888888888', 'valarchie@163.com', 1, null, '2022-05-21 08:30:54', null, null, 0);
|
||||
INSERT INTO app.sys_dept (dept_id, parent_id, ancestors, dept_name, order_num, leader_id, leader_name, phone, email, status, creator_id, create_time, updater_id, update_time, deleted) VALUES (2, 1, '0,1', '深圳总公司', 1, null, 'valarchie', '15888888888', 'valarchie@163.com', 1, null, '2022-05-21 08:30:54', null, null, 0);
|
||||
INSERT INTO app.sys_dept (dept_id, parent_id, ancestors, dept_name, order_num, leader_id, leader_name, phone, email, status, creator_id, create_time, updater_id, update_time, deleted) VALUES (3, 1, '0,1', '长沙分公司', 2, null, 'valarchie', '15888888888', 'valarchie@163.com', 1, null, '2022-05-21 08:30:54', null, null, 0);
|
||||
INSERT INTO app.sys_dept (dept_id, parent_id, ancestors, dept_name, order_num, leader_id, leader_name, phone, email, status, creator_id, create_time, updater_id, update_time, deleted) VALUES (4, 2, '0,1,2', '研发部门', 1, null, 'valarchie', '15888888888', 'valarchie@163.com', 1, null, '2022-05-21 08:30:54', null, null, 0);
|
||||
INSERT INTO app.sys_dept (dept_id, parent_id, ancestors, dept_name, order_num, leader_id, leader_name, phone, email, status, creator_id, create_time, updater_id, update_time, deleted) VALUES (5, 2, '0,1,2', '市场部门', 2, null, 'valarchie', '15888888888', 'valarchie@163.com', 0, null, '2022-05-21 08:30:54', 1, '2023-07-20 22:46:41', 0);
|
||||
INSERT INTO app.sys_dept (dept_id, parent_id, ancestors, dept_name, order_num, leader_id, leader_name, phone, email, status, creator_id, create_time, updater_id, update_time, deleted) VALUES (6, 2, '0,1,2', '测试部门', 3, null, 'valarchie', '15888888888', 'valarchie@163.com', 1, null, '2022-05-21 08:30:54', null, null, 0);
|
||||
INSERT INTO app.sys_dept (dept_id, parent_id, ancestors, dept_name, order_num, leader_id, leader_name, phone, email, status, creator_id, create_time, updater_id, update_time, deleted) VALUES (7, 2, '0,1,2', '财务部门', 4, null, 'valarchie', '15888888888', 'valarchie@163.com', 1, null, '2022-05-21 08:30:54', null, null, 0);
|
||||
INSERT INTO app.sys_dept (dept_id, parent_id, ancestors, dept_name, order_num, leader_id, leader_name, phone, email, status, creator_id, create_time, updater_id, update_time, deleted) VALUES (8, 2, '0,1,2', '运维部门', 5, null, 'valarchie', '15888888888', 'valarchie@163.com', 1, null, '2022-05-21 08:30:54', null, null, 0);
|
||||
INSERT INTO app.sys_dept (dept_id, parent_id, ancestors, dept_name, order_num, leader_id, leader_name, phone, email, status, creator_id, create_time, updater_id, update_time, deleted) VALUES (9, 3, '0,1,3', '市场部!', 1, null, 'valarchie!!', '15888188888', 'valarc1hie@163.com', 0, null, '2022-05-21 08:30:54', 1, '2023-07-20 22:33:31', 0);
|
||||
INSERT INTO app.sys_dept (dept_id, parent_id, ancestors, dept_name, order_num, leader_id, leader_name, phone, email, status, creator_id, create_time, updater_id, update_time, deleted) VALUES (10, 3, '0,1,3', '财务部门', 2, null, 'valarchie', '15888888888', 'valarchie@163.com', 0, null, '2022-05-21 08:30:54', null, null, 0);
|
||||
|
||||
|
||||
INSERT INTO app.sys_login_info (info_id, username, ip_address, login_location, browser, operation_system, status, msg, login_time, deleted) VALUES (415, 'admin', '127.0.0.1', '内网IP', 'Chrome 11', 'Mac OS X', 1, '登录成功', '2023-06-29 22:49:37', 0);
|
||||
INSERT INTO app.sys_login_info (info_id, username, ip_address, login_location, browser, operation_system, status, msg, login_time, deleted) VALUES (416, 'admin', '127.0.0.1', '内网IP', 'Chrome 11', 'Mac OS X', 1, '登录成功', '2023-07-02 22:12:30', 0);
|
||||
INSERT INTO app.sys_login_info (info_id, username, ip_address, login_location, browser, operation_system, status, msg, login_time, deleted) VALUES (417, 'admin', '127.0.0.1', '内网IP', 'Chrome 11', 'Mac OS X', 0, '验证码过期', '2023-07-02 22:16:06', 0);
|
||||
|
||||
|
||||
INSERT INTO app.sys_menu (menu_id, menu_name, menu_type, router_name, parent_id, path, is_button, permission, meta_info, status, remark, creator_id, create_time, updater_id, update_time, deleted) VALUES (1, '系统管理', 2, '', 0, '/system', false, '', '{"title":"系统管理","icon":"ep:management","showParent":true,"rank":1}', 1, '系统管理目录', 0, '2022-05-21 08:30:54', 1, '2023-08-14 23:08:50', 0);
|
||||
INSERT INTO app.sys_menu (menu_id, menu_name, menu_type, router_name, parent_id, path, is_button, permission, meta_info, status, remark, creator_id, create_time, updater_id, update_time, deleted) VALUES (2, '系统监控', 2, '', 0, '/monitor', false, '', '{"title":"系统监控","icon":"ep:monitor","showParent":true,"rank":3}', 1, '系统监控目录', 0, '2022-05-21 08:30:54', 1, '2023-08-14 23:09:15', 0);
|
||||
INSERT INTO app.sys_menu (menu_id, menu_name, menu_type, router_name, parent_id, path, is_button, permission, meta_info, status, remark, creator_id, create_time, updater_id, update_time, deleted) VALUES (3, '系统工具', 2, '', 0, '/tool', false, '', '{"title":"系统工具","icon":"ep:tools","showParent":true,"rank":2}', 1, '系统工具目录', 0, '2022-05-21 08:30:54', 1, '2023-08-14 23:09:03', 0);
|
||||
INSERT INTO app.sys_menu (menu_id, menu_name, menu_type, router_name, parent_id, path, is_button, permission, meta_info, status, remark, creator_id, create_time, updater_id, update_time, deleted) VALUES (4, 'AgileBoot官网', 3, 'AgileBootguanwangIframeRouter', 0, '/AgileBootguanwangIframeLink', false, '', '{"title":"AgileBoot官网","icon":"ep:link","showParent":true,"frameSrc":"https://element-plus.org/zh-CN/","rank":8}', 1, 'Agileboot官网地址', 0, '2022-05-21 08:30:54', 1, '2023-08-14 23:09:40', 0);
|
||||
INSERT INTO app.sys_menu (menu_id, menu_name, menu_type, router_name, parent_id, path, is_button, permission, meta_info, status, remark, creator_id, create_time, updater_id, update_time, deleted) VALUES (5, '用户管理', 1, 'SystemUser', 1, '/system/user/index', false, 'system:user:list', '{"title":"用户管理","icon":"ep:user-filled","showParent":true}', 1, '用户管理菜单', 0, '2022-05-21 08:30:54', 1, '2023-08-14 23:16:13', 0);
|
||||
INSERT INTO app.sys_menu (menu_id, menu_name, menu_type, router_name, parent_id, path, is_button, permission, meta_info, status, remark, creator_id, create_time, updater_id, update_time, deleted) VALUES (6, '角色管理', 1, 'SystemRole', 1, '/system/role/index', false, 'system:role:list', '{"title":"角色管理","icon":"ep:user","showParent":true}', 1, '角色管理菜单', 0, '2022-05-21 08:30:54', 1, '2023-08-14 23:16:23', 0);
|
||||
INSERT INTO app.sys_menu (menu_id, menu_name, menu_type, router_name, parent_id, path, is_button, permission, meta_info, status, remark, creator_id, create_time, updater_id, update_time, deleted) VALUES (7, '菜单管理', 1, 'MenuManagement', 1, '/system/menu/index', false, 'system:menu:list', '{"title":"菜单管理","icon":"ep:menu","showParent":true}', 1, '菜单管理菜单', 0, '2022-05-21 08:30:54', 1, '2023-08-14 23:15:41', 0);
|
||||
INSERT INTO app.sys_menu (menu_id, menu_name, menu_type, router_name, parent_id, path, is_button, permission, meta_info, status, remark, creator_id, create_time, updater_id, update_time, deleted) VALUES (8, '部门管理', 1, 'Department', 1, '/system/dept/index', false, 'system:dept:list', '{"title":"部门管理","icon":"fa-solid:code-branch","showParent":true}', 1, '部门管理菜单', 0, '2022-05-21 08:30:54', 1, '2023-08-14 23:15:35', 0);
|
||||
INSERT INTO app.sys_menu (menu_id, menu_name, menu_type, router_name, parent_id, path, is_button, permission, meta_info, status, remark, creator_id, create_time, updater_id, update_time, deleted) VALUES (9, '岗位管理', 1, 'Post', 1, '/system/post/index', false, 'system:post:list', '{"title":"岗位管理","icon":"ep:postcard","showParent":true}', 1, '岗位管理菜单', 0, '2022-05-21 08:30:54', 1, '2023-08-14 23:15:11', 0);
|
||||
INSERT INTO app.sys_menu (menu_id, menu_name, menu_type, router_name, parent_id, path, is_button, permission, meta_info, status, remark, creator_id, create_time, updater_id, update_time, deleted) VALUES (10, '参数设置', 1, 'Config', 1, '/system/config/index', false, 'system:config:list', '{"title":"参数设置","icon":"ep:setting","showParent":true}', 1, '参数设置菜单', 0, '2022-05-21 08:30:54', 1, '2023-08-14 23:15:03', 0);
|
||||
INSERT INTO app.sys_menu (menu_id, menu_name, menu_type, router_name, parent_id, path, is_button, permission, meta_info, status, remark, creator_id, create_time, updater_id, update_time, deleted) VALUES (11, '通知公告', 1, 'SystemNotice', 1, '/system/notice/index', false, 'system:notice:list', '{"title":"通知公告","icon":"ep:notification","showParent":true}', 1, '通知公告菜单', 0, '2022-05-21 08:30:54', 1, '2023-08-14 23:14:56', 0);
|
||||
INSERT INTO app.sys_menu (menu_id, menu_name, menu_type, router_name, parent_id, path, is_button, permission, meta_info, status, remark, creator_id, create_time, updater_id, update_time, deleted) VALUES (12, '日志管理', 1, 'LogManagement', 1, '/system/logd', false, '', '{"title":"日志管理","icon":"ep:document","showParent":true}', 1, '日志管理菜单', 0, '2022-05-21 08:30:54', 1, '2023-08-14 23:14:47', 0);
|
||||
INSERT INTO app.sys_menu (menu_id, menu_name, menu_type, router_name, parent_id, path, is_button, permission, meta_info, status, remark, creator_id, create_time, updater_id, update_time, deleted) VALUES (13, '在线用户', 1, 'OnlineUser', 2, '/system/monitor/onlineUser/index', false, 'monitor:online:list', '{"title":"在线用户","icon":"fa-solid:users","showParent":true}', 1, '在线用户菜单', 0, '2022-05-21 08:30:54', 1, '2023-08-14 23:13:13', 0);
|
||||
INSERT INTO app.sys_menu (menu_id, menu_name, menu_type, router_name, parent_id, path, is_button, permission, meta_info, status, remark, creator_id, create_time, updater_id, update_time, deleted) VALUES (14, '数据监控', 1, 'DataMonitor', 2, '/system/monitor/druid/index', false, 'monitor:druid:list', '{"title":"数据监控","icon":"fa:database","showParent":true,"frameSrc":"/druid/login.html","isFrameSrcInternal":true}', 1, '数据监控菜单', 0, '2022-05-21 08:30:54', 1, '2023-08-14 23:13:25', 0);
|
||||
INSERT INTO app.sys_menu (menu_id, menu_name, menu_type, router_name, parent_id, path, is_button, permission, meta_info, status, remark, creator_id, create_time, updater_id, update_time, deleted) VALUES (15, '服务监控', 1, 'ServerInfo', 2, '/system/monitor/server/index', false, 'monitor:server:list', '{"title":"服务监控","icon":"fa:server","showParent":true}', 1, '服务监控菜单', 0, '2022-05-21 08:30:54', 1, '2023-08-14 23:13:34', 0);
|
||||
INSERT INTO app.sys_menu (menu_id, menu_name, menu_type, router_name, parent_id, path, is_button, permission, meta_info, status, remark, creator_id, create_time, updater_id, update_time, deleted) VALUES (16, '缓存监控', 1, 'CacheInfo', 2, '/system/monitor/cache/index', false, 'monitor:cache:list', '{"title":"缓存监控","icon":"ep:reading","showParent":true}', 1, '缓存监控菜单', 0, '2022-05-21 08:30:54', 1, '2023-08-14 23:12:59', 0);
|
||||
INSERT INTO app.sys_menu (menu_id, menu_name, menu_type, router_name, parent_id, path, is_button, permission, meta_info, status, remark, creator_id, create_time, updater_id, update_time, deleted) VALUES (17, '系统接口', 1, 'SystemAPI', 3, '/tool/swagger/index', false, 'tool:swagger:list', '{"title":"系统接口","icon":"ep:document-remove","showParent":true,"frameSrc":"/swagger-ui/index.html","isFrameSrcInternal":true}', 1, '系统接口菜单', 0, '2022-05-21 08:30:54', 1, '2023-08-14 23:14:01', 0);
|
||||
INSERT INTO app.sys_menu (menu_id, menu_name, menu_type, router_name, parent_id, path, is_button, permission, meta_info, status, remark, creator_id, create_time, updater_id, update_time, deleted) VALUES (18, '操作日志', 1, 'OperationLog', 12, '/system/log/operationLog/index', false, 'monitor:operlog:list', '{"title":"操作日志"}', 1, '操作日志菜单', 0, '2022-05-21 08:30:54', null, null, 0);
|
||||
INSERT INTO app.sys_menu (menu_id, menu_name, menu_type, router_name, parent_id, path, is_button, permission, meta_info, status, remark, creator_id, create_time, updater_id, update_time, deleted) VALUES (19, '登录日志', 1, 'LoginLog', 12, '/system/log/loginLog/index', false, 'monitor:logininfor:list', '{"title":"登录日志"}', 1, '登录日志菜单', 0, '2022-05-21 08:30:54', null, null, 0);
|
||||
INSERT INTO app.sys_menu (menu_id, menu_name, menu_type, router_name, parent_id, path, is_button, permission, meta_info, status, remark, creator_id, create_time, updater_id, update_time, deleted) VALUES (20, '用户查询', 0, ' ', 5, '', true, 'system:user:query', '{"title":"用户查询"}', 1, '', 0, '2022-05-21 08:30:54', null, null, 0);
|
||||
INSERT INTO app.sys_menu (menu_id, menu_name, menu_type, router_name, parent_id, path, is_button, permission, meta_info, status, remark, creator_id, create_time, updater_id, update_time, deleted) VALUES (21, '用户新增', 0, ' ', 5, '', true, 'system:user:add', '{"title":"用户新增"}', 1, '', 0, '2022-05-21 08:30:54', null, null, 0);
|
||||
INSERT INTO app.sys_menu (menu_id, menu_name, menu_type, router_name, parent_id, path, is_button, permission, meta_info, status, remark, creator_id, create_time, updater_id, update_time, deleted) VALUES (22, '用户修改', 0, ' ', 5, '', true, 'system:user:edit', '{"title":"用户修改"}', 1, '', 0, '2022-05-21 08:30:54', null, null, 0);
|
||||
INSERT INTO app.sys_menu (menu_id, menu_name, menu_type, router_name, parent_id, path, is_button, permission, meta_info, status, remark, creator_id, create_time, updater_id, update_time, deleted) VALUES (23, '用户删除', 0, ' ', 5, '', true, 'system:user:remove', '{"title":"用户删除"}', 1, '', 0, '2022-05-21 08:30:54', null, null, 0);
|
||||
INSERT INTO app.sys_menu (menu_id, menu_name, menu_type, router_name, parent_id, path, is_button, permission, meta_info, status, remark, creator_id, create_time, updater_id, update_time, deleted) VALUES (24, '用户导出', 0, ' ', 5, '', true, 'system:user:export', '{"title":"用户导出"}', 1, '', 0, '2022-05-21 08:30:54', null, null, 0);
|
||||
INSERT INTO app.sys_menu (menu_id, menu_name, menu_type, router_name, parent_id, path, is_button, permission, meta_info, status, remark, creator_id, create_time, updater_id, update_time, deleted) VALUES (25, '用户导入', 0, ' ', 5, '', true, 'system:user:import', '{"title":"用户导入"}', 1, '', 0, '2022-05-21 08:30:54', null, null, 0);
|
||||
INSERT INTO app.sys_menu (menu_id, menu_name, menu_type, router_name, parent_id, path, is_button, permission, meta_info, status, remark, creator_id, create_time, updater_id, update_time, deleted) VALUES (26, '重置密码', 0, ' ', 5, '', true, 'system:user:resetPwd', '{"title":"重置密码"}', 1, '', 0, '2022-05-21 08:30:54', null, null, 0);
|
||||
INSERT INTO app.sys_menu (menu_id, menu_name, menu_type, router_name, parent_id, path, is_button, permission, meta_info, status, remark, creator_id, create_time, updater_id, update_time, deleted) VALUES (27, '角色查询', 0, ' ', 6, '', true, 'system:role:query', '{"title":"角色查询"}', 1, '', 0, '2022-05-21 08:30:54', null, null, 0);
|
||||
INSERT INTO app.sys_menu (menu_id, menu_name, menu_type, router_name, parent_id, path, is_button, permission, meta_info, status, remark, creator_id, create_time, updater_id, update_time, deleted) VALUES (28, '角色新增', 0, ' ', 6, '', true, 'system:role:add', '{"title":"角色新增"}', 1, '', 0, '2022-05-21 08:30:54', null, null, 0);
|
||||
INSERT INTO app.sys_menu (menu_id, menu_name, menu_type, router_name, parent_id, path, is_button, permission, meta_info, status, remark, creator_id, create_time, updater_id, update_time, deleted) VALUES (29, '角色修改', 0, ' ', 6, '', true, 'system:role:edit', '{"title":"角色修改"}', 1, '', 0, '2022-05-21 08:30:54', null, null, 0);
|
||||
INSERT INTO app.sys_menu (menu_id, menu_name, menu_type, router_name, parent_id, path, is_button, permission, meta_info, status, remark, creator_id, create_time, updater_id, update_time, deleted) VALUES (30, '角色删除', 0, ' ', 6, '', true, 'system:role:remove', '{"title":"角色删除"}', 1, '', 0, '2022-05-21 08:30:54', null, null, 0);
|
||||
INSERT INTO app.sys_menu (menu_id, menu_name, menu_type, router_name, parent_id, path, is_button, permission, meta_info, status, remark, creator_id, create_time, updater_id, update_time, deleted) VALUES (31, '角色导出', 0, ' ', 6, '', true, 'system:role:export', '{"title":"角色导出"}', 1, '', 0, '2022-05-21 08:30:54', null, null, 0);
|
||||
INSERT INTO app.sys_menu (menu_id, menu_name, menu_type, router_name, parent_id, path, is_button, permission, meta_info, status, remark, creator_id, create_time, updater_id, update_time, deleted) VALUES (32, '菜单查询', 0, ' ', 7, '', true, 'system:menu:query', '{"title":"菜单查询"}', 1, '', 0, '2022-05-21 08:30:54', null, null, 0);
|
||||
INSERT INTO app.sys_menu (menu_id, menu_name, menu_type, router_name, parent_id, path, is_button, permission, meta_info, status, remark, creator_id, create_time, updater_id, update_time, deleted) VALUES (33, '菜单新增', 0, ' ', 7, '', true, 'system:menu:add', '{"title":"菜单新增"}', 1, '', 0, '2022-05-21 08:30:54', null, null, 0);
|
||||
INSERT INTO app.sys_menu (menu_id, menu_name, menu_type, router_name, parent_id, path, is_button, permission, meta_info, status, remark, creator_id, create_time, updater_id, update_time, deleted) VALUES (34, '菜单修改', 0, ' ', 7, '', true, 'system:menu:edit', '{"title":"菜单修改"}', 1, '', 0, '2022-05-21 08:30:54', null, null, 0);
|
||||
INSERT INTO app.sys_menu (menu_id, menu_name, menu_type, router_name, parent_id, path, is_button, permission, meta_info, status, remark, creator_id, create_time, updater_id, update_time, deleted) VALUES (35, '菜单删除', 0, ' ', 7, '', true, 'system:menu:remove', '{"title":"菜单删除"}', 1, '', 0, '2022-05-21 08:30:54', null, null, 0);
|
||||
INSERT INTO app.sys_menu (menu_id, menu_name, menu_type, router_name, parent_id, path, is_button, permission, meta_info, status, remark, creator_id, create_time, updater_id, update_time, deleted) VALUES (36, '部门查询', 0, ' ', 8, '', true, 'system:dept:query', '{"title":"部门查询"}', 1, '', 0, '2022-05-21 08:30:54', null, null, 0);
|
||||
INSERT INTO app.sys_menu (menu_id, menu_name, menu_type, router_name, parent_id, path, is_button, permission, meta_info, status, remark, creator_id, create_time, updater_id, update_time, deleted) VALUES (37, '部门新增', 0, ' ', 8, '', true, 'system:dept:add', '{"title":"部门新增"}', 1, '', 0, '2022-05-21 08:30:54', null, null, 0);
|
||||
INSERT INTO app.sys_menu (menu_id, menu_name, menu_type, router_name, parent_id, path, is_button, permission, meta_info, status, remark, creator_id, create_time, updater_id, update_time, deleted) VALUES (38, '部门修改', 0, ' ', 8, '', true, 'system:dept:edit', '{"title":"部门修改"}', 1, '', 0, '2022-05-21 08:30:54', null, null, 0);
|
||||
INSERT INTO app.sys_menu (menu_id, menu_name, menu_type, router_name, parent_id, path, is_button, permission, meta_info, status, remark, creator_id, create_time, updater_id, update_time, deleted) VALUES (39, '部门删除', 0, ' ', 8, '', true, 'system:dept:remove', '{"title":"部门删除"}', 1, '', 0, '2022-05-21 08:30:54', null, null, 0);
|
||||
INSERT INTO app.sys_menu (menu_id, menu_name, menu_type, router_name, parent_id, path, is_button, permission, meta_info, status, remark, creator_id, create_time, updater_id, update_time, deleted) VALUES (40, '岗位查询', 0, ' ', 9, '', true, 'system:post:query', '{"title":"岗位查询"}', 1, '', 0, '2022-05-21 08:30:54', null, null, 0);
|
||||
INSERT INTO app.sys_menu (menu_id, menu_name, menu_type, router_name, parent_id, path, is_button, permission, meta_info, status, remark, creator_id, create_time, updater_id, update_time, deleted) VALUES (41, '岗位新增', 0, ' ', 9, '', true, 'system:post:add', '{"title":"岗位新增"}', 1, '', 0, '2022-05-21 08:30:54', null, null, 0);
|
||||
INSERT INTO app.sys_menu (menu_id, menu_name, menu_type, router_name, parent_id, path, is_button, permission, meta_info, status, remark, creator_id, create_time, updater_id, update_time, deleted) VALUES (42, '岗位修改', 0, ' ', 9, '', true, 'system:post:edit', '{"title":"岗位修改"}', 1, '', 0, '2022-05-21 08:30:54', null, null, 0);
|
||||
INSERT INTO app.sys_menu (menu_id, menu_name, menu_type, router_name, parent_id, path, is_button, permission, meta_info, status, remark, creator_id, create_time, updater_id, update_time, deleted) VALUES (43, '岗位删除', 0, ' ', 9, '', true, 'system:post:remove', '{"title":"岗位删除"}', 1, '', 0, '2022-05-21 08:30:54', null, null, 0);
|
||||
INSERT INTO app.sys_menu (menu_id, menu_name, menu_type, router_name, parent_id, path, is_button, permission, meta_info, status, remark, creator_id, create_time, updater_id, update_time, deleted) VALUES (44, '岗位导出', 0, ' ', 9, '', true, 'system:post:export', '{"title":"岗位导出"}', 1, '', 0, '2022-05-21 08:30:54', null, null, 0);
|
||||
INSERT INTO app.sys_menu (menu_id, menu_name, menu_type, router_name, parent_id, path, is_button, permission, meta_info, status, remark, creator_id, create_time, updater_id, update_time, deleted) VALUES (45, '参数查询', 0, ' ', 10, '', true, 'system:config:query', '{"title":"参数查询"}', 1, '', 0, '2022-05-21 08:30:54', null, null, 0);
|
||||
INSERT INTO app.sys_menu (menu_id, menu_name, menu_type, router_name, parent_id, path, is_button, permission, meta_info, status, remark, creator_id, create_time, updater_id, update_time, deleted) VALUES (46, '参数新增', 0, ' ', 10, '', true, 'system:config:add', '{"title":"参数新增"}', 1, '', 0, '2022-05-21 08:30:54', null, null, 0);
|
||||
INSERT INTO app.sys_menu (menu_id, menu_name, menu_type, router_name, parent_id, path, is_button, permission, meta_info, status, remark, creator_id, create_time, updater_id, update_time, deleted) VALUES (47, '参数修改', 0, ' ', 10, '', true, 'system:config:edit', '{"title":"参数修改"}', 1, '', 0, '2022-05-21 08:30:54', null, null, 0);
|
||||
INSERT INTO app.sys_menu (menu_id, menu_name, menu_type, router_name, parent_id, path, is_button, permission, meta_info, status, remark, creator_id, create_time, updater_id, update_time, deleted) VALUES (48, '参数删除', 0, ' ', 10, '', true, 'system:config:remove', '{"title":"参数删除"}', 1, '', 0, '2022-05-21 08:30:54', null, null, 0);
|
||||
INSERT INTO app.sys_menu (menu_id, menu_name, menu_type, router_name, parent_id, path, is_button, permission, meta_info, status, remark, creator_id, create_time, updater_id, update_time, deleted) VALUES (49, '参数导出', 0, ' ', 10, '', true, 'system:config:export', '{"title":"参数导出"}', 1, '', 0, '2022-05-21 08:30:54', null, null, 0);
|
||||
INSERT INTO app.sys_menu (menu_id, menu_name, menu_type, router_name, parent_id, path, is_button, permission, meta_info, status, remark, creator_id, create_time, updater_id, update_time, deleted) VALUES (50, '公告查询', 0, ' ', 11, '', true, 'system:notice:query', '{"title":"公告查询"}', 1, '', 0, '2022-05-21 08:30:54', null, null, 0);
|
||||
INSERT INTO app.sys_menu (menu_id, menu_name, menu_type, router_name, parent_id, path, is_button, permission, meta_info, status, remark, creator_id, create_time, updater_id, update_time, deleted) VALUES (51, '公告新增', 0, ' ', 11, '', true, 'system:notice:add', '{"title":"公告新增"}', 1, '', 0, '2022-05-21 08:30:54', null, null, 0);
|
||||
INSERT INTO app.sys_menu (menu_id, menu_name, menu_type, router_name, parent_id, path, is_button, permission, meta_info, status, remark, creator_id, create_time, updater_id, update_time, deleted) VALUES (52, '公告修改', 0, ' ', 11, '', true, 'system:notice:edit', '{"title":"公告修改"}', 1, '', 0, '2022-05-21 08:30:54', null, null, 0);
|
||||
INSERT INTO app.sys_menu (menu_id, menu_name, menu_type, router_name, parent_id, path, is_button, permission, meta_info, status, remark, creator_id, create_time, updater_id, update_time, deleted) VALUES (53, '公告删除', 0, ' ', 11, '', true, 'system:notice:remove', '{"title":"公告删除"}', 1, '', 0, '2022-05-21 08:30:54', null, null, 0);
|
||||
INSERT INTO app.sys_menu (menu_id, menu_name, menu_type, router_name, parent_id, path, is_button, permission, meta_info, status, remark, creator_id, create_time, updater_id, update_time, deleted) VALUES (54, '操作查询', 0, ' ', 18, '', true, 'monitor:operlog:query', '{"title":"操作查询"}', 1, '', 0, '2022-05-21 08:30:54', null, null, 0);
|
||||
INSERT INTO app.sys_menu (menu_id, menu_name, menu_type, router_name, parent_id, path, is_button, permission, meta_info, status, remark, creator_id, create_time, updater_id, update_time, deleted) VALUES (55, '操作删除', 0, ' ', 18, '', true, 'monitor:operlog:remove', '{"title":"操作删除"}', 1, '', 0, '2022-05-21 08:30:54', null, null, 0);
|
||||
INSERT INTO app.sys_menu (menu_id, menu_name, menu_type, router_name, parent_id, path, is_button, permission, meta_info, status, remark, creator_id, create_time, updater_id, update_time, deleted) VALUES (56, '日志导出', 0, ' ', 18, '', true, 'monitor:operlog:export', '{"title":"日志导出"}', 1, '', 0, '2022-05-21 08:30:54', null, null, 0);
|
||||
INSERT INTO app.sys_menu (menu_id, menu_name, menu_type, router_name, parent_id, path, is_button, permission, meta_info, status, remark, creator_id, create_time, updater_id, update_time, deleted) VALUES (57, '登录查询', 0, ' ', 19, '', true, 'monitor:logininfor:query', '{"title":"登录查询"}', 1, '', 0, '2022-05-21 08:30:54', null, null, 0);
|
||||
INSERT INTO app.sys_menu (menu_id, menu_name, menu_type, router_name, parent_id, path, is_button, permission, meta_info, status, remark, creator_id, create_time, updater_id, update_time, deleted) VALUES (58, '登录删除', 0, ' ', 19, '', true, 'monitor:logininfor:remove', '{"title":"登录删除"}', 1, '', 0, '2022-05-21 08:30:54', null, null, 0);
|
||||
INSERT INTO app.sys_menu (menu_id, menu_name, menu_type, router_name, parent_id, path, is_button, permission, meta_info, status, remark, creator_id, create_time, updater_id, update_time, deleted) VALUES (59, '日志导出', 0, ' ', 19, '', true, 'monitor:logininfor:export', '{"title":"日志导出","rank":22}', 1, '', 0, '2022-05-21 08:30:54', 1, '2023-07-22 17:02:28', 0);
|
||||
INSERT INTO app.sys_menu (menu_id, menu_name, menu_type, router_name, parent_id, path, is_button, permission, meta_info, status, remark, creator_id, create_time, updater_id, update_time, deleted) VALUES (60, '在线查询', 0, ' ', 13, '', true, 'monitor:online:query', '{"title":"在线查询"}', 1, '', 0, '2022-05-21 08:30:54', null, null, 0);
|
||||
INSERT INTO app.sys_menu (menu_id, menu_name, menu_type, router_name, parent_id, path, is_button, permission, meta_info, status, remark, creator_id, create_time, updater_id, update_time, deleted) VALUES (61, '批量强退', 0, ' ', 13, '', true, 'monitor:online:batchLogout', '{"title":"批量强退"}', 1, '', 0, '2022-05-21 08:30:54', null, null, 0);
|
||||
INSERT INTO app.sys_menu (menu_id, menu_name, menu_type, router_name, parent_id, path, is_button, permission, meta_info, status, remark, creator_id, create_time, updater_id, update_time, deleted) VALUES (62, '单条强退', 0, ' ', 13, '', true, 'monitor:online:forceLogout', '{"title":"单条强退"}', 1, '', 0, '2022-05-21 08:30:54', null, null, 0);
|
||||
INSERT INTO app.sys_menu (menu_id, menu_name, menu_type, router_name, parent_id, path, is_button, permission, meta_info, status, remark, creator_id, create_time, updater_id, update_time, deleted) VALUES (63, 'AgileBoot Github地址', 4, 'https://github.com/valarchie/AgileBoot-Back-End', 0, '/external', false, '', '{"title":"AgileBoot Github地址","icon":"fa-solid:external-link-alt","showParent":true,"rank":9}', 1, 'Agileboot github地址', 0, '2022-05-21 08:30:54', 1, '2023-08-14 23:12:13', 0);
|
||||
INSERT INTO app.sys_menu (menu_id, menu_name, menu_type, router_name, parent_id, path, is_button, permission, meta_info, status, remark, creator_id, create_time, updater_id, update_time, deleted) VALUES (64, '首页', 2, '', 0, '/global', false, '121212', '{"title":"首页","showParent":true,"rank":3}', 1, '', 1, '2023-07-24 22:36:03', 1, '2023-07-24 22:38:37', 1);
|
||||
INSERT INTO app.sys_menu (menu_id, menu_name, menu_type, router_name, parent_id, path, is_button, permission, meta_info, status, remark, creator_id, create_time, updater_id, update_time, deleted) VALUES (65, '个人中心', 1, 'PersonalCenter', 2053, '/system/user/profile', false, '434sdf', '{"title":"个人中心","showParent":true,"rank":3}', 1, '', 1, '2023-07-24 22:36:55', null, null, 1);
|
||||
|
||||
|
||||
|
||||
INSERT INTO app.sys_notice (notice_id, notice_title, notice_type, notice_content, status, creator_id, create_time, updater_id, update_time, remark, deleted) VALUES (1, '温馨提醒:2018-07-01 AgileBoot新版本发布啦', 2, '新版本内容~~~~~~~~~~', 1, 1, '2022-05-21 08:30:55', 1, '2022-08-29 20:12:37', '管理员', 0);
|
||||
INSERT INTO app.sys_notice (notice_id, notice_title, notice_type, notice_content, status, creator_id, create_time, updater_id, update_time, remark, deleted) VALUES (2, '维护通知:2018-07-01 AgileBoot系统凌晨维护', 1, '维护内容', 1, 1, '2022-05-21 08:30:55', null, null, '管理员', 0);
|
||||
|
||||
|
||||
|
||||
INSERT INTO app.sys_operation_log (operation_id, business_type, request_method, request_module, request_url, called_method, operator_type, user_id, username, operator_ip, operator_location, dept_id, dept_name, operation_param, operation_result, status, error_stack, operation_time, deleted) VALUES (561, 1, 2, '菜单管理', '/system/menus', 'it.upos.builder.admin.controller.system.SysMenuController.add()', 1, 0, 'admin', '127.0.0.1', '内网IP', 0, null, '{"menuName":"","permission":"","parentId":2035,"path":"","isButton":false,"routerName":"","meta":{"showParent":true,"rank":0},"status":1},', '', 1, '', '2023-07-22 17:06:57', 0);
|
||||
|
||||
|
||||
|
||||
INSERT INTO app.sys_post (post_id, post_code, post_name, post_sort, status, remark, creator_id, create_time, updater_id, update_time, deleted) VALUES (1, 'ceo', '董事长', 1, 1, '', null, '2022-05-21 08:30:54', null, null, 0);
|
||||
INSERT INTO app.sys_post (post_id, post_code, post_name, post_sort, status, remark, creator_id, create_time, updater_id, update_time, deleted) VALUES (2, 'se', '项目经理', 2, 1, '', null, '2022-05-21 08:30:54', null, null, 0);
|
||||
INSERT INTO app.sys_post (post_id, post_code, post_name, post_sort, status, remark, creator_id, create_time, updater_id, update_time, deleted) VALUES (3, 'hr', '人力资源', 3, 1, '', null, '2022-05-21 08:30:54', null, null, 0);
|
||||
INSERT INTO app.sys_post (post_id, post_code, post_name, post_sort, status, remark, creator_id, create_time, updater_id, update_time, deleted) VALUES (4, 'user', '普通员工', 5, 0, '', null, '2022-05-21 08:30:54', null, null, 0);
|
||||
|
||||
|
||||
|
||||
INSERT INTO app.sys_role (role_id, role_name, role_key, role_sort, data_scope, dept_id_set, status, creator_id, create_time, updater_id, update_time, remark, deleted) VALUES (1, '超级管理员', 'admin', 1, 1, '', 1, null, '2022-05-21 08:30:54', null, null, '超级管理员', 0);
|
||||
INSERT INTO app.sys_role (role_id, role_name, role_key, role_sort, data_scope, dept_id_set, status, creator_id, create_time, updater_id, update_time, remark, deleted) VALUES (2, '普通角色', 'common', 3, 2, '', 1, null, '2022-05-21 08:30:54', null, null, '普通角色', 0);
|
||||
INSERT INTO app.sys_role (role_id, role_name, role_key, role_sort, data_scope, dept_id_set, status, creator_id, create_time, updater_id, update_time, remark, deleted) VALUES (3, '闲置角色', 'unused', 4, 2, '', 0, null, '2022-05-21 08:30:54', null, null, '未使用的角色', 0);
|
||||
|
||||
|
||||
|
||||
INSERT INTO app.sys_role_menu (role_id, menu_id) VALUES (2, 1);
|
||||
INSERT INTO app.sys_role_menu (role_id, menu_id) VALUES (2, 2);
|
||||
INSERT INTO app.sys_role_menu (role_id, menu_id) VALUES (2, 3);
|
||||
INSERT INTO app.sys_role_menu (role_id, menu_id) VALUES (2, 4);
|
||||
INSERT INTO app.sys_role_menu (role_id, menu_id) VALUES (2, 5);
|
||||
INSERT INTO app.sys_role_menu (role_id, menu_id) VALUES (2, 6);
|
||||
INSERT INTO app.sys_role_menu (role_id, menu_id) VALUES (2, 7);
|
||||
INSERT INTO app.sys_role_menu (role_id, menu_id) VALUES (2, 8);
|
||||
INSERT INTO app.sys_role_menu (role_id, menu_id) VALUES (2, 9);
|
||||
INSERT INTO app.sys_role_menu (role_id, menu_id) VALUES (2, 10);
|
||||
INSERT INTO app.sys_role_menu (role_id, menu_id) VALUES (2, 11);
|
||||
INSERT INTO app.sys_role_menu (role_id, menu_id) VALUES (2, 12);
|
||||
INSERT INTO app.sys_role_menu (role_id, menu_id) VALUES (2, 13);
|
||||
INSERT INTO app.sys_role_menu (role_id, menu_id) VALUES (2, 14);
|
||||
INSERT INTO app.sys_role_menu (role_id, menu_id) VALUES (2, 15);
|
||||
INSERT INTO app.sys_role_menu (role_id, menu_id) VALUES (2, 16);
|
||||
INSERT INTO app.sys_role_menu (role_id, menu_id) VALUES (2, 17);
|
||||
INSERT INTO app.sys_role_menu (role_id, menu_id) VALUES (2, 18);
|
||||
INSERT INTO app.sys_role_menu (role_id, menu_id) VALUES (2, 19);
|
||||
INSERT INTO app.sys_role_menu (role_id, menu_id) VALUES (2, 20);
|
||||
INSERT INTO app.sys_role_menu (role_id, menu_id) VALUES (2, 21);
|
||||
INSERT INTO app.sys_role_menu (role_id, menu_id) VALUES (2, 22);
|
||||
INSERT INTO app.sys_role_menu (role_id, menu_id) VALUES (2, 23);
|
||||
INSERT INTO app.sys_role_menu (role_id, menu_id) VALUES (2, 24);
|
||||
INSERT INTO app.sys_role_menu (role_id, menu_id) VALUES (2, 25);
|
||||
INSERT INTO app.sys_role_menu (role_id, menu_id) VALUES (2, 26);
|
||||
INSERT INTO app.sys_role_menu (role_id, menu_id) VALUES (2, 27);
|
||||
INSERT INTO app.sys_role_menu (role_id, menu_id) VALUES (2, 28);
|
||||
INSERT INTO app.sys_role_menu (role_id, menu_id) VALUES (2, 29);
|
||||
INSERT INTO app.sys_role_menu (role_id, menu_id) VALUES (2, 30);
|
||||
INSERT INTO app.sys_role_menu (role_id, menu_id) VALUES (2, 31);
|
||||
INSERT INTO app.sys_role_menu (role_id, menu_id) VALUES (2, 32);
|
||||
INSERT INTO app.sys_role_menu (role_id, menu_id) VALUES (2, 33);
|
||||
INSERT INTO app.sys_role_menu (role_id, menu_id) VALUES (2, 34);
|
||||
INSERT INTO app.sys_role_menu (role_id, menu_id) VALUES (2, 35);
|
||||
INSERT INTO app.sys_role_menu (role_id, menu_id) VALUES (2, 36);
|
||||
INSERT INTO app.sys_role_menu (role_id, menu_id) VALUES (2, 37);
|
||||
INSERT INTO app.sys_role_menu (role_id, menu_id) VALUES (2, 38);
|
||||
INSERT INTO app.sys_role_menu (role_id, menu_id) VALUES (2, 39);
|
||||
INSERT INTO app.sys_role_menu (role_id, menu_id) VALUES (2, 40);
|
||||
INSERT INTO app.sys_role_menu (role_id, menu_id) VALUES (2, 41);
|
||||
INSERT INTO app.sys_role_menu (role_id, menu_id) VALUES (2, 42);
|
||||
INSERT INTO app.sys_role_menu (role_id, menu_id) VALUES (2, 43);
|
||||
INSERT INTO app.sys_role_menu (role_id, menu_id) VALUES (2, 44);
|
||||
INSERT INTO app.sys_role_menu (role_id, menu_id) VALUES (2, 45);
|
||||
INSERT INTO app.sys_role_menu (role_id, menu_id) VALUES (2, 46);
|
||||
INSERT INTO app.sys_role_menu (role_id, menu_id) VALUES (2, 47);
|
||||
INSERT INTO app.sys_role_menu (role_id, menu_id) VALUES (2, 48);
|
||||
INSERT INTO app.sys_role_menu (role_id, menu_id) VALUES (2, 49);
|
||||
INSERT INTO app.sys_role_menu (role_id, menu_id) VALUES (2, 50);
|
||||
INSERT INTO app.sys_role_menu (role_id, menu_id) VALUES (2, 51);
|
||||
INSERT INTO app.sys_role_menu (role_id, menu_id) VALUES (2, 52);
|
||||
INSERT INTO app.sys_role_menu (role_id, menu_id) VALUES (2, 53);
|
||||
INSERT INTO app.sys_role_menu (role_id, menu_id) VALUES (2, 54);
|
||||
INSERT INTO app.sys_role_menu (role_id, menu_id) VALUES (2, 55);
|
||||
INSERT INTO app.sys_role_menu (role_id, menu_id) VALUES (2, 56);
|
||||
INSERT INTO app.sys_role_menu (role_id, menu_id) VALUES (2, 57);
|
||||
INSERT INTO app.sys_role_menu (role_id, menu_id) VALUES (2, 58);
|
||||
INSERT INTO app.sys_role_menu (role_id, menu_id) VALUES (2, 59);
|
||||
INSERT INTO app.sys_role_menu (role_id, menu_id) VALUES (2, 60);
|
||||
INSERT INTO app.sys_role_menu (role_id, menu_id) VALUES (2, 61);
|
||||
INSERT INTO app.sys_role_menu (role_id, menu_id) VALUES (3, 1);
|
||||
INSERT INTO app.sys_role_menu (role_id, menu_id) VALUES (111, 1);
|
||||
|
||||
|
||||
INSERT INTO app.sys_user (user_id, post_id, role_id, dept_id, username, nickname, user_type, email, phone_number, sex, avatar, password, status, login_ip, login_date, is_admin, creator_id, create_time, updater_id, update_time, remark, deleted) VALUES (1, 1, 1, 4, 'admin', 'valarchie1', 0, 'agileboot@163.com', '15888888883', 0, '/profile/avatar/20230725164110_blob_6b7a989b1cdd4dd396665d2cfd2addc5.png', '$2a$10$o55UFZAtyWnDpRV6dvQe8.c/MjlFacC49ASj2usNXm9BY74SYI/uG', 1, '127.0.0.1', '2023-08-14 23:07:03', true, null, '2022-05-21 08:30:54', 1, '2023-08-14 23:07:03', '管理员', 0);
|
||||
INSERT INTO app.sys_user (user_id, post_id, role_id, dept_id, username, nickname, user_type, email, phone_number, sex, avatar, password, status, login_ip, login_date, is_admin, creator_id, create_time, updater_id, update_time, remark, deleted) VALUES (2, 2, 2, 5, 'ag1', 'valarchie2', 0, 'agileboot1@qq.com', '15666666666', 1, '/profile/avatar/20230725114818_avatar_b5bf400732bb43369b4df58802049b22.png', '$2a$10$7JB720yubVSZvUI0rEqK/.VqGOZTH.ulu33dHOiBE8ByOhJIrdAu2', 1, '127.0.0.1', '2022-05-21 08:30:54', false, null, '2022-05-21 08:30:54', null, null, '测试员1', 0);
|
||||
INSERT INTO app.sys_user (user_id, post_id, role_id, dept_id, username, nickname, user_type, email, phone_number, sex, avatar, password, status, login_ip, login_date, is_admin, creator_id, create_time, updater_id, update_time, remark, deleted) VALUES (3, 2, 0, 5, 'ag2', 'valarchie3', 0, 'agileboot2@qq.com', '15666666667', 1, '/profile/avatar/20230725114818_avatar_b5bf400732bb43369b4df58802049b22.png', '$2a$10$7JB720yubVSZvUI0rEqK/.VqGOZTH.ulu33dHOiBE8ByOhJIrdAu2', 1, '127.0.0.1', '2022-05-21 08:30:54', false, null, '2022-05-21 08:30:54', null, null, '测试员2', 0);
|
||||
|
||||
-- 序列更新
|
||||
select setval('app.sys_config_config_id_seq',COALESCE(max(config_id),1)) from app.sys_config;
|
||||
select setval('app.sys_dept_dept_id_seq',COALESCE(max(dept_id),1)) from app.sys_dept;
|
||||
select setval('app.sys_login_info_info_id_seq',COALESCE(max(info_id),1)) from app.sys_login_info;
|
||||
select setval('app.sys_menu_menu_id_seq',COALESCE(max(menu_id),1)) from app.sys_menu;
|
||||
select setval('app.sys_notice_notice_id_seq',COALESCE(max(notice_id),1)) from app.sys_notice;
|
||||
select setval('app.sys_operation_log_operation_id_seq',COALESCE(max(operation_id),1)) from app.sys_operation_log;
|
||||
select setval('app.sys_post_post_id_seq',COALESCE(max(post_id),1)) from app.sys_post;
|
||||
select setval('app.sys_role_role_id_seq',COALESCE(max(role_id),1)) from app.sys_role;
|
||||
select setval('app.sys_user_user_id_seq',COALESCE(max(user_id),1)) from app.sys_user;
|
||||
@@ -0,0 +1,174 @@
|
||||
-- 创建表 sys_config 参数配置表
|
||||
CREATE TABLE app.sys_config (
|
||||
config_id serial8 PRIMARY KEY NOT NULL, -- 参数主键
|
||||
config_name VARCHAR(128) NOT NULL DEFAULT '', -- 配置名称
|
||||
config_key VARCHAR(128) NOT NULL, -- 配置键名
|
||||
config_options VARCHAR(1024) NOT NULL DEFAULT '', -- 可选的选项
|
||||
config_value VARCHAR(256) NOT NULL DEFAULT '', -- 配置值
|
||||
is_allow_change bool NOT NULL, -- 是否允许修改
|
||||
creator_id int8, -- 创建者ID
|
||||
updater_id int8, -- 更新者ID
|
||||
update_time TIMESTAMPTZ, -- 更新时间
|
||||
create_time TIMESTAMPTZ, -- 创建时间
|
||||
remark VARCHAR(128), -- 备注
|
||||
deleted int2 DEFAULT 0 NOT NULL -- 逻辑删除
|
||||
);
|
||||
|
||||
-- 创建表 sys_dept 部门表
|
||||
CREATE TABLE app.sys_dept (
|
||||
dept_id serial8 PRIMARY KEY NOT NULL, -- 部门id
|
||||
parent_id int8 NOT NULL DEFAULT 0, -- 父部门id
|
||||
ancestors TEXT NOT NULL, -- 祖级列表
|
||||
dept_name VARCHAR(64) NOT NULL DEFAULT '', -- 部门名称
|
||||
order_num INT NOT NULL DEFAULT 0, -- 显示顺序
|
||||
leader_id int8, -- 负责人
|
||||
leader_name VARCHAR(64), -- 负责人姓名
|
||||
phone VARCHAR(16), -- 联系电话
|
||||
email VARCHAR(128), -- 邮箱
|
||||
status SMALLINT NOT NULL DEFAULT 0, -- 部门状态(0停用 1启用)
|
||||
creator_id int8, -- 创建者ID
|
||||
create_time TIMESTAMPTZ, -- 创建时间
|
||||
updater_id int8, -- 更新者ID
|
||||
update_time TIMESTAMPTZ, -- 更新时间
|
||||
deleted int2 DEFAULT 0 NOT NULL -- 逻辑删除
|
||||
);
|
||||
|
||||
-- 创建表 sys_login_info 系统访问记录
|
||||
CREATE TABLE app.sys_login_info (
|
||||
info_id serial8 PRIMARY KEY NOT NULL, -- 访问ID
|
||||
username VARCHAR(50) NOT NULL DEFAULT '', -- 用户账号
|
||||
ip_address VARCHAR(128) NOT NULL DEFAULT '', -- 登录IP地址
|
||||
login_location VARCHAR(255) NOT NULL DEFAULT '', -- 登录地点
|
||||
browser VARCHAR(50) NOT NULL DEFAULT '', -- 浏览器类型
|
||||
operation_system VARCHAR(50) NOT NULL DEFAULT '', -- 操作系统
|
||||
status int2 NOT NULL DEFAULT 0, -- 登录状态(1成功 0失败)
|
||||
msg VARCHAR(255) NOT NULL DEFAULT '', -- 提示消息
|
||||
login_time TIMESTAMPTZ, -- 访问时间
|
||||
deleted int2 DEFAULT 0 NOT NULL -- 逻辑删除
|
||||
);
|
||||
|
||||
|
||||
-- 创建表 sys_notice 通知公告表
|
||||
CREATE TABLE app.sys_notice (
|
||||
notice_id serial8 PRIMARY KEY NOT NULL, -- 公告ID
|
||||
notice_title VARCHAR(64) NOT NULL, -- 公告标题
|
||||
notice_type int2 NOT NULL, -- 公告类型(1通知 2公告)
|
||||
notice_content TEXT, -- 公告内容
|
||||
status int2 NOT NULL DEFAULT 0, -- 公告状态(1正常 0关闭)
|
||||
creator_id int8 NOT NULL, -- 创建者ID
|
||||
create_time TIMESTAMPTZ, -- 创建时间
|
||||
updater_id int8, -- 更新者ID
|
||||
update_time TIMESTAMPTZ, -- 更新时间
|
||||
remark VARCHAR(255) NOT NULL DEFAULT '', -- 备注
|
||||
deleted int2 DEFAULT 0 NOT NULL -- 逻辑删除
|
||||
);
|
||||
|
||||
-- 创建表 sys_operation_log 操作日志记录
|
||||
CREATE TABLE app.sys_operation_log (
|
||||
operation_id serial8 PRIMARY KEY NOT NULL, -- 日志主键
|
||||
business_type int2 NOT NULL DEFAULT 0, -- 业务类型(0其它 1新增 2修改 3删除)
|
||||
request_method int2 NOT NULL DEFAULT 0, -- 请求方式
|
||||
request_module VARCHAR(64) NOT NULL DEFAULT '', -- 请求模块
|
||||
request_url VARCHAR(256) NOT NULL DEFAULT '', -- 请求URL
|
||||
called_method VARCHAR(128) NOT NULL DEFAULT '', -- 调用方法
|
||||
operator_type int2 NOT NULL DEFAULT 0, -- 操作类别(0其它 1后台用户 2手机端用户)
|
||||
user_id int8, -- 用户ID
|
||||
username VARCHAR(32), -- 操作人员
|
||||
operator_ip VARCHAR(128), -- 操作人员ip
|
||||
operator_location VARCHAR(256), -- 操作地点
|
||||
dept_id int8, -- 部门ID
|
||||
dept_name VARCHAR(64), -- 部门名称
|
||||
operation_param VARCHAR(2048), -- 请求参数
|
||||
operation_result VARCHAR(2048), -- 返回参数
|
||||
status int2 NOT NULL DEFAULT 1, -- 操作状态(1正常 0异常)
|
||||
error_stack VARCHAR(2048), -- 错误消息
|
||||
operation_time TIMESTAMPTZ NOT NULL, -- 操作时间
|
||||
deleted int2 DEFAULT 0 NOT NULL -- 逻辑删除
|
||||
);
|
||||
|
||||
-- 创建表 sys_post 岗位信息表
|
||||
CREATE TABLE app.sys_post (
|
||||
post_id serial8 PRIMARY KEY NOT NULL, -- 岗位ID
|
||||
post_code VARCHAR(64) NOT NULL, -- 岗位编码
|
||||
post_name VARCHAR(64) NOT NULL, -- 岗位名称
|
||||
post_sort INT NOT NULL, -- 显示顺序
|
||||
status int2 NOT NULL, -- 状态(1正常 0停用)
|
||||
remark VARCHAR(512), -- 备注
|
||||
creator_id int8, -- 创建者ID
|
||||
create_time TIMESTAMPTZ, -- 创建时间
|
||||
updater_id int8, -- 更新者ID
|
||||
update_time TIMESTAMPTZ, -- 更新时间
|
||||
deleted int2 DEFAULT 0 NOT NULL -- 逻辑删除
|
||||
);
|
||||
|
||||
|
||||
-- 创建表 sys_menu 菜单权限表
|
||||
CREATE TABLE app.sys_menu (
|
||||
menu_id serial8 PRIMARY KEY NOT NULL, -- 菜单ID
|
||||
menu_name VARCHAR(64) NOT NULL, -- 菜单名称
|
||||
menu_type int2 NOT NULL DEFAULT 0, -- 菜单的类型(1为普通菜单2为目录3为内嵌iFrame4为外链跳转)
|
||||
router_name VARCHAR(255) NOT NULL DEFAULT '', -- 路由名称
|
||||
parent_id int8 NOT NULL DEFAULT 0, -- 父菜单ID
|
||||
path VARCHAR(255), -- 组件路径
|
||||
is_button bool NOT NULL DEFAULT false, -- 是否按钮
|
||||
permission VARCHAR(128), -- 权限标识
|
||||
meta_info VARCHAR(1024) NOT NULL DEFAULT '{}', -- 路由元信息
|
||||
status int2 NOT NULL DEFAULT 0, -- 菜单状态(1启用 0停用)
|
||||
remark VARCHAR(256), -- 备注
|
||||
creator_id int8, -- 创建者ID
|
||||
create_time TIMESTAMPTZ, -- 创建时间
|
||||
updater_id int8, -- 更新者ID
|
||||
update_time TIMESTAMPTZ, -- 更新时间
|
||||
deleted int2 DEFAULT 0 NOT NULL -- 逻辑删除
|
||||
);
|
||||
|
||||
-- 创建表 sys_role 角色信息表
|
||||
CREATE TABLE app.sys_role (
|
||||
role_id serial8 PRIMARY KEY NOT NULL, -- 角色ID
|
||||
role_name VARCHAR(32) NOT NULL, -- 角色名称
|
||||
role_key VARCHAR(128) NOT NULL, -- 角色权限字符串
|
||||
role_sort INT NOT NULL, -- 显示顺序
|
||||
data_scope int2, -- 数据范围
|
||||
dept_id_set VARCHAR(1024) DEFAULT '', -- 角色所拥有的部门数据权限
|
||||
status int2 NOT NULL, -- 角色状态(1正常 0停用)
|
||||
creator_id int8, -- 创建者ID
|
||||
create_time TIMESTAMPTZ, -- 创建时间
|
||||
updater_id int8, -- 更新者ID
|
||||
update_time TIMESTAMPTZ, -- 更新时间
|
||||
remark VARCHAR(512), -- 备注
|
||||
deleted int2 DEFAULT 0 NOT NULL -- 删除标志(0代表存在 1代表删除)
|
||||
);
|
||||
|
||||
-- 创建表 sys_role_menu 角色和菜单关联表
|
||||
CREATE TABLE app.sys_role_menu (
|
||||
role_id int8 NOT NULL, -- 角色ID
|
||||
menu_id int8 NOT NULL, -- 菜单ID
|
||||
PRIMARY KEY (role_id, menu_id) -- 设置复合主键
|
||||
);
|
||||
|
||||
|
||||
-- 创建表 sys_user 用户信息表
|
||||
CREATE TABLE app.sys_user (
|
||||
user_id serial8 PRIMARY KEY NOT NULL, -- 用户ID
|
||||
post_id int8, -- 职位id
|
||||
role_id int8, -- 角色id
|
||||
dept_id int8, -- 部门ID
|
||||
username VARCHAR(64) NOT NULL, -- 用户账号
|
||||
nickname VARCHAR(32) NOT NULL, -- 用户昵称
|
||||
user_type int2 DEFAULT 0, -- 用户类型(00系统用户)
|
||||
email VARCHAR(128), -- 用户邮箱
|
||||
phone_number VARCHAR(18), -- 手机号码
|
||||
sex int2, -- 用户性别(0男 1女 2未知)
|
||||
avatar VARCHAR(512), -- 头像地址
|
||||
password VARCHAR(128) NOT NULL, -- 密码
|
||||
status int2 NOT NULL, -- 帐号状态(1正常 2停用 3冻结)
|
||||
login_ip VARCHAR(128), -- 最后登录IP
|
||||
login_date TIMESTAMPTZ, -- 最后登录时间
|
||||
is_admin bool DEFAULT false NOT NULL, -- 超级管理员标志(1是,0否)
|
||||
creator_id int8, -- 更新者ID
|
||||
create_time TIMESTAMPTZ, -- 创建时间
|
||||
updater_id int8, -- 更新者ID
|
||||
update_time TIMESTAMPTZ, -- 更新时间
|
||||
remark VARCHAR(512), -- 备注
|
||||
deleted int2 DEFAULT 0 NOT NULL -- 删除标志(0代表存在 1代表删除)
|
||||
);
|
||||
+27
@@ -0,0 +1,27 @@
|
||||
package com.agileboot.framework.config;
|
||||
|
||||
import cn.hutool.core.convert.Convert;
|
||||
import cn.hutool.core.math.Calculator;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.agileboot.infrastructure.config.captcha.CaptchaMathTextCreator;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
public class CaptchaMathTextCreatorTest {
|
||||
|
||||
@Test
|
||||
public void test() {
|
||||
CaptchaMathTextCreator captchaMathTextCreator = new CaptchaMathTextCreator();
|
||||
for (int i = 0; i < 50; i++) {
|
||||
validateExpressionAndResult(captchaMathTextCreator.getText());
|
||||
}
|
||||
}
|
||||
|
||||
private void validateExpressionAndResult(String expression) {
|
||||
String[] expressionAndResult = expression.split("@");
|
||||
Assert.assertEquals(expressionAndResult.length, 2);
|
||||
System.out.println(expressionAndResult[0] + " answer is " + expressionAndResult[1]);
|
||||
String safeExpression = StrUtil.removeSuffix(expressionAndResult[0], "=?");
|
||||
Assert.assertEquals(Convert.toInt(Calculator.conversion(safeExpression)) + "", expressionAndResult[1]);
|
||||
}
|
||||
}
|
||||
+23
@@ -0,0 +1,23 @@
|
||||
package com.agileboot.infrastructure.annotations;
|
||||
|
||||
import com.agileboot.infrastructure.annotations.ratelimit.RateLimit;
|
||||
import com.agileboot.infrastructure.annotations.ratelimit.RateLimit.LimitType;
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
class RateLimitTypeTest {
|
||||
|
||||
@Test
|
||||
void testCombinedKey() {
|
||||
RateLimit mockLimit = mock(RateLimit.class);
|
||||
when(mockLimit.key()).thenReturn("Test");
|
||||
|
||||
String combinedKey = LimitType.GLOBAL.generateCombinedKey(mockLimit);
|
||||
|
||||
Assertions.assertEquals("Test-GLOBAL", combinedKey);
|
||||
}
|
||||
|
||||
}
|
||||
+17
@@ -0,0 +1,17 @@
|
||||
package com.agileboot.infrastructure.mybatisplus;
|
||||
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
class MySqlFunctionTest {
|
||||
|
||||
@Test
|
||||
void find_in_set() {
|
||||
String searchStr = ",2,4,5,9";
|
||||
|
||||
Assertions.assertTrue(MySqlFunction.findInSet("2", searchStr));
|
||||
Assertions.assertTrue(MySqlFunction.findInSet("5", searchStr));
|
||||
Assertions.assertTrue(MySqlFunction.findInSet("9", searchStr));
|
||||
}
|
||||
|
||||
}
|
||||
+27
@@ -0,0 +1,27 @@
|
||||
package com.agileboot.infrastructure.web.util;
|
||||
|
||||
import com.agileboot.infrastructure.user.AuthenticationUtils;
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
class AuthenticationUtilsTest {
|
||||
|
||||
@Test
|
||||
void testMatchesPassword() {
|
||||
// 每次加密散列后的密码是不同的 但是代表的是同一份密码
|
||||
String password = "admin123";
|
||||
String encryptPassword1 = "$2a$10$vh0eep5P2Rj2x.mjjOSq/O1LT645Qwmohp.ciOA0.6E261rlOVSSO";
|
||||
String encryptPassword2 = "$2a$10$rb1wRoEIkLbIknREEN1LH.FGs4g0oOS5t6l5LQ793nRaFO.SPHDHy";
|
||||
|
||||
Assertions.assertTrue(AuthenticationUtils.matchesPassword(password,encryptPassword1));
|
||||
Assertions.assertTrue(AuthenticationUtils.matchesPassword(password,encryptPassword2));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testEncryptPassword() {
|
||||
String encrypt1 = AuthenticationUtils.encryptPassword("admin123");
|
||||
String encrypt2 = AuthenticationUtils.encryptPassword("admin123");
|
||||
|
||||
Assertions.assertNotEquals(encrypt1, encrypt2);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user