feat: 优化配置和代码结构
1、优化项目结构、优化部分配置 2、优化Redis配置类,缓存需手动指定key生成器 3、新增AnonTagUtils,用于获取匿名接口 4、优化Swagger,排除不需要认证的接口 5、新增BigDecimalUtils,用于BigDecimal类型,+-*/计算,元与分的转换
This commit is contained in:
parent
fc5fbe0c85
commit
eb17ffdfc7
@ -13,7 +13,7 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package me.zhengjie.annotation;
|
||||
package me.zhengjie.annotation.rest;
|
||||
|
||||
import java.lang.annotation.*;
|
||||
|
@ -22,7 +22,6 @@ import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
import me.zhengjie.annotation.AnonymousAccess;
|
||||
import org.springframework.core.annotation.AliasFor;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMethod;
|
||||
|
@ -22,7 +22,6 @@ import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
import me.zhengjie.annotation.AnonymousAccess;
|
||||
import org.springframework.core.annotation.AliasFor;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMethod;
|
||||
|
@ -22,7 +22,6 @@ import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
import me.zhengjie.annotation.AnonymousAccess;
|
||||
import org.springframework.core.annotation.AliasFor;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMethod;
|
||||
|
@ -22,7 +22,6 @@ import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
import me.zhengjie.annotation.AnonymousAccess;
|
||||
import org.springframework.core.annotation.AliasFor;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMethod;
|
||||
|
@ -22,7 +22,6 @@ import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
import me.zhengjie.annotation.AnonymousAccess;
|
||||
import org.springframework.core.annotation.AliasFor;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMethod;
|
||||
|
@ -0,0 +1,75 @@
|
||||
package me.zhengjie.config;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Primary;
|
||||
import java.util.concurrent.*;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
/**
|
||||
* 创建自定义的线程池
|
||||
* @author Zheng Jie
|
||||
* @description
|
||||
* @date 2023-06-08
|
||||
**/
|
||||
@Configuration
|
||||
public class AsyncExecutor {
|
||||
|
||||
public static int corePoolSize;
|
||||
|
||||
public static int maxPoolSize;
|
||||
|
||||
public static int keepAliveSeconds;
|
||||
|
||||
public static int queueCapacity;
|
||||
|
||||
@Value("${task.pool.core-pool-size}")
|
||||
public void setCorePoolSize(int corePoolSize) {
|
||||
AsyncExecutor.corePoolSize = corePoolSize;
|
||||
}
|
||||
|
||||
@Value("${task.pool.max-pool-size}")
|
||||
public void setMaxPoolSize(int maxPoolSize) {
|
||||
AsyncExecutor.maxPoolSize = maxPoolSize;
|
||||
}
|
||||
|
||||
@Value("${task.pool.keep-alive-seconds}")
|
||||
public void setKeepAliveSeconds(int keepAliveSeconds) {
|
||||
AsyncExecutor.keepAliveSeconds = keepAliveSeconds;
|
||||
}
|
||||
|
||||
@Value("${task.pool.queue-capacity}")
|
||||
public void setQueueCapacity(int queueCapacity) {
|
||||
AsyncExecutor.queueCapacity = queueCapacity;
|
||||
}
|
||||
|
||||
/**
|
||||
* 自定义线程池,用法 @Async
|
||||
* @return Executor
|
||||
*/
|
||||
@Bean
|
||||
@Primary
|
||||
public Executor elAsync() {
|
||||
// 自定义工厂
|
||||
ThreadFactory factory = r -> new Thread(r, "el-async-" + new AtomicInteger(1).getAndIncrement());
|
||||
// 自定义线程池
|
||||
return new ThreadPoolExecutor(corePoolSize, maxPoolSize, keepAliveSeconds,
|
||||
TimeUnit.SECONDS, new ArrayBlockingQueue<>(queueCapacity), factory,
|
||||
new ThreadPoolExecutor.CallerRunsPolicy());
|
||||
}
|
||||
|
||||
/**
|
||||
* 自定义线程池,用法 @Async("otherAsync")
|
||||
* @return Executor
|
||||
*/
|
||||
@Bean
|
||||
public Executor otherAsync() {
|
||||
// 自定义工厂
|
||||
ThreadFactory factory = r -> new Thread(r, "tpl-other-" + new AtomicInteger(1).getAndIncrement());
|
||||
// 自定义线程池
|
||||
return new ThreadPoolExecutor(2, 4, keepAliveSeconds,
|
||||
TimeUnit.SECONDS, new ArrayBlockingQueue<>(20), factory,
|
||||
new ThreadPoolExecutor.CallerRunsPolicy());
|
||||
}
|
||||
}
|
@ -15,47 +15,38 @@
|
||||
*/
|
||||
package me.zhengjie.config;
|
||||
|
||||
import cn.hutool.core.lang.Assert;
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import com.alibaba.fastjson.parser.ParserConfig;
|
||||
import com.alibaba.fastjson.serializer.SerializerFeature;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.codec.digest.DigestUtils;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
import org.springframework.boot.autoconfigure.data.redis.RedisProperties;
|
||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||
import org.springframework.cache.Cache;
|
||||
import org.springframework.cache.annotation.CachingConfigurerSupport;
|
||||
import org.springframework.cache.annotation.EnableCaching;
|
||||
import org.springframework.cache.interceptor.CacheErrorHandler;
|
||||
import org.springframework.cache.interceptor.KeyGenerator;
|
||||
import org.springframework.cache.interceptor.SimpleCacheErrorHandler;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.data.redis.cache.RedisCacheConfiguration;
|
||||
import org.springframework.data.redis.cache.RedisCacheManager;
|
||||
import org.springframework.data.redis.connection.RedisConnectionFactory;
|
||||
import org.springframework.data.redis.core.RedisOperations;
|
||||
import org.springframework.data.redis.core.RedisTemplate;
|
||||
import org.springframework.data.redis.serializer.RedisSerializationContext;
|
||||
import org.springframework.data.redis.serializer.RedisSerializer;
|
||||
import reactor.util.annotation.Nullable;
|
||||
import java.nio.charset.Charset;
|
||||
import org.springframework.data.redis.serializer.StringRedisSerializer;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.time.Duration;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
|
||||
/**
|
||||
* @author Zheng Jie
|
||||
* @date 2018-11-24
|
||||
* @date 2025-01-13
|
||||
*/
|
||||
@Slf4j
|
||||
@Configuration
|
||||
@EnableCaching
|
||||
@ConditionalOnClass(RedisOperations.class)
|
||||
@EnableConfigurationProperties(RedisProperties.class)
|
||||
public class RedisConfig extends CachingConfigurerSupport {
|
||||
public class RedisConfiguration {
|
||||
|
||||
/**
|
||||
* 设置 redis 数据默认过期时间,默认2小时
|
||||
@ -70,9 +61,7 @@ public class RedisConfig extends CachingConfigurerSupport {
|
||||
return configuration;
|
||||
}
|
||||
|
||||
@SuppressWarnings("all")
|
||||
@Bean(name = "redisTemplate")
|
||||
@ConditionalOnMissingBean(name = "redisTemplate")
|
||||
public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
|
||||
RedisTemplate<Object, Object> template = new RedisTemplate<>();
|
||||
//序列化
|
||||
@ -96,10 +85,24 @@ public class RedisConfig extends CachingConfigurerSupport {
|
||||
}
|
||||
|
||||
/**
|
||||
* 自定义缓存key生成策略,默认将使用该策略
|
||||
* 缓存管理器
|
||||
* @param redisConnectionFactory /
|
||||
* @return 缓存管理器
|
||||
*/
|
||||
@Bean
|
||||
public RedisCacheManager cacheManager(RedisConnectionFactory redisConnectionFactory) {
|
||||
RedisCacheConfiguration config = redisCacheConfiguration();
|
||||
return RedisCacheManager.builder(redisConnectionFactory)
|
||||
.cacheDefaults(config)
|
||||
.build();
|
||||
}
|
||||
|
||||
/**
|
||||
* 自定义缓存key生成策略,需要在缓存注解中使用keyGenerator才会生效
|
||||
* 默认是使用SimpleKeyGenerator生成的key
|
||||
* 继承 CachingConfigurerSupport 后,才会默认生效这个生成器,暂时没找到其他方式默认生效,如果有请PR,谢谢
|
||||
*/
|
||||
@Bean
|
||||
@Override
|
||||
public KeyGenerator keyGenerator() {
|
||||
return (target, method, params) -> {
|
||||
Map<String,Object> container = new HashMap<>(8);
|
||||
@ -122,101 +125,63 @@ public class RedisConfig extends CachingConfigurerSupport {
|
||||
}
|
||||
|
||||
@Bean
|
||||
@Override
|
||||
@SuppressWarnings("all")
|
||||
public CacheErrorHandler errorHandler() {
|
||||
// 异常处理,当Redis发生异常时,打印日志,但是程序正常走
|
||||
log.info("初始化 -> [{}]", "Redis CacheErrorHandler");
|
||||
return new CacheErrorHandler() {
|
||||
return new SimpleCacheErrorHandler() {
|
||||
@Override
|
||||
public void handleCacheGetError(RuntimeException e, Cache cache, Object key) {
|
||||
log.error("Redis occur handleCacheGetError:key -> [{}]", key, e);
|
||||
public void handleCacheGetError(RuntimeException exception, Cache cache, Object key) {
|
||||
// 处理缓存读取错误
|
||||
log.error("Cache Get Error: {}",exception.getMessage());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleCachePutError(RuntimeException e, Cache cache, Object key, Object value) {
|
||||
log.error("Redis occur handleCachePutError:key -> [{}];value -> [{}]", key, value, e);
|
||||
public void handleCachePutError(RuntimeException exception, Cache cache, Object key, Object value) {
|
||||
// 处理缓存写入错误
|
||||
log.error("Cache Put Error: {}",exception.getMessage());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleCacheEvictError(RuntimeException e, Cache cache, Object key) {
|
||||
log.error("Redis occur handleCacheEvictError:key -> [{}]", key, e);
|
||||
public void handleCacheEvictError(RuntimeException exception, Cache cache, Object key) {
|
||||
// 处理缓存删除错误
|
||||
log.error("Cache Evict Error: {}",exception.getMessage());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleCacheClearError(RuntimeException e, Cache cache) {
|
||||
log.error("Redis occur handleCacheClearError:", e);
|
||||
public void handleCacheClearError(RuntimeException exception, Cache cache) {
|
||||
// 处理缓存清除错误
|
||||
log.error("Cache Clear Error: {}",exception.getMessage());
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
/**
|
||||
* Value 序列化
|
||||
*
|
||||
* @param <T>
|
||||
* @author /
|
||||
*/
|
||||
static class FastJsonRedisSerializer<T> implements RedisSerializer<T> {
|
||||
|
||||
/**
|
||||
* Value 序列化
|
||||
*
|
||||
* @author /
|
||||
* @param <T>
|
||||
*/
|
||||
class FastJsonRedisSerializer<T> implements RedisSerializer<T> {
|
||||
private final Class<T> clazz;
|
||||
|
||||
private final Class<T> clazz;
|
||||
|
||||
FastJsonRedisSerializer(Class<T> clazz) {
|
||||
super();
|
||||
this.clazz = clazz;
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] serialize(T t) {
|
||||
if (t == null) {
|
||||
return new byte[0];
|
||||
FastJsonRedisSerializer(Class<T> clazz) {
|
||||
super();
|
||||
this.clazz = clazz;
|
||||
}
|
||||
return JSON.toJSONString(t, SerializerFeature.WriteClassName).getBytes(StandardCharsets.UTF_8);
|
||||
}
|
||||
|
||||
@Override
|
||||
public T deserialize(byte[] bytes) {
|
||||
if (bytes == null || bytes.length == 0) {
|
||||
return null;
|
||||
@Override
|
||||
public byte[] serialize(T t) {
|
||||
if (t == null) {
|
||||
return new byte[0];
|
||||
}
|
||||
return JSON.toJSONString(t, SerializerFeature.WriteClassName).getBytes(StandardCharsets.UTF_8);
|
||||
}
|
||||
String str = new String(bytes, StandardCharsets.UTF_8);
|
||||
return JSON.parseObject(str, clazz);
|
||||
|
||||
@Override
|
||||
public T deserialize(byte[] bytes) {
|
||||
if (bytes == null || bytes.length == 0) {
|
||||
return null;
|
||||
}
|
||||
String str = new String(bytes, StandardCharsets.UTF_8);
|
||||
return JSON.parseObject(str, clazz);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 重写序列化器
|
||||
*
|
||||
* @author /
|
||||
*/
|
||||
class StringRedisSerializer implements RedisSerializer<Object> {
|
||||
|
||||
private final Charset charset;
|
||||
|
||||
StringRedisSerializer() {
|
||||
this(StandardCharsets.UTF_8);
|
||||
}
|
||||
|
||||
private StringRedisSerializer(Charset charset) {
|
||||
Assert.notNull(charset, "Charset must not be null!");
|
||||
this.charset = charset;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String deserialize(byte[] bytes) {
|
||||
return (bytes == null ? null : new String(bytes, charset));
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable byte[] serialize(Object object) {
|
||||
String string = JSON.toJSONString(object);
|
||||
|
||||
if (org.apache.commons.lang3.StringUtils.isBlank(string)) {
|
||||
return null;
|
||||
}
|
||||
string = string.replace("\"", "");
|
||||
return string.getBytes(charset);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,53 @@
|
||||
package me.zhengjie.config;
|
||||
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import lombok.Data;
|
||||
import org.redisson.Redisson;
|
||||
import org.redisson.api.RedissonClient;
|
||||
import org.redisson.config.Config;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
@Data
|
||||
@Configuration
|
||||
public class RedissonConfiguration {
|
||||
|
||||
@Value("${spring.redis.host}")
|
||||
private String redisHost;
|
||||
|
||||
@Value("${spring.redis.port}")
|
||||
private int redisPort;
|
||||
|
||||
@Value("${spring.redis.database}")
|
||||
private int redisDatabase;
|
||||
|
||||
@Value("${spring.redis.password:}")
|
||||
private String redisPassword;
|
||||
|
||||
@Value("${spring.redis.timeout:5000}")
|
||||
private int timeout;
|
||||
|
||||
@Value("${spring.redis.lettuce.pool.max-active:64}")
|
||||
private int connectionPoolSize;
|
||||
|
||||
@Value("${spring.redis.lettuce.pool.min-idle:16}")
|
||||
private int connectionMinimumIdleSize;
|
||||
|
||||
@Bean
|
||||
public RedissonClient redissonClient() {
|
||||
Config config = new Config();
|
||||
config.useSingleServer()
|
||||
.setAddress("redis://" + redisHost + ":" + redisPort)
|
||||
.setDatabase(redisDatabase)
|
||||
.setTimeout(timeout)
|
||||
.setConnectionPoolSize(connectionPoolSize)
|
||||
.setConnectionMinimumIdleSize(connectionMinimumIdleSize);
|
||||
if(StrUtil.isNotBlank(redisPassword)){
|
||||
config.useSingleServer().setPassword(redisPassword);
|
||||
}
|
||||
return Redisson.create(config);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -13,7 +13,7 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package me.zhengjie.config;
|
||||
package me.zhengjie.config.properties;
|
||||
|
||||
import lombok.Data;
|
||||
import me.zhengjie.utils.ElConstant;
|
@ -13,7 +13,7 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package me.zhengjie.config;
|
||||
package me.zhengjie.config.properties;
|
||||
|
||||
import lombok.Data;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
@ -13,15 +13,17 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package me.zhengjie.config;
|
||||
package me.zhengjie.config.webConfig;
|
||||
|
||||
import com.alibaba.fastjson.serializer.SerializerFeature;
|
||||
import com.alibaba.fastjson.support.config.FastJsonConfig;
|
||||
import com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter;
|
||||
import me.zhengjie.config.properties.FileProperties;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.http.converter.HttpMessageConverter;
|
||||
import org.springframework.http.converter.StringHttpMessageConverter;
|
||||
import org.springframework.web.cors.CorsConfiguration;
|
||||
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
|
||||
import org.springframework.web.filter.CorsFilter;
|
||||
@ -73,16 +75,22 @@ public class ConfigurerAdapter implements WebMvcConfigurer {
|
||||
|
||||
@Override
|
||||
public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
|
||||
// 使用 fastjson 序列化,会导致 @JsonIgnore 失效,可以使用 @JSONField(serialize = false) 替换
|
||||
FastJsonHttpMessageConverter converter = new FastJsonHttpMessageConverter();
|
||||
// 添加默认的 StringHttpMessageConverter
|
||||
converters.add(new StringHttpMessageConverter(StandardCharsets.UTF_8));
|
||||
// 配置 FastJsonHttpMessageConverter
|
||||
FastJsonHttpMessageConverter fastJsonConverter = new FastJsonHttpMessageConverter();
|
||||
List<MediaType> supportMediaTypeList = new ArrayList<>();
|
||||
supportMediaTypeList.add(MediaType.APPLICATION_JSON);
|
||||
FastJsonConfig config = new FastJsonConfig();
|
||||
config.setDateFormat("yyyy-MM-dd HH:mm:ss");
|
||||
config.setSerializerFeatures(SerializerFeature.DisableCircularReferenceDetect);
|
||||
converter.setFastJsonConfig(config);
|
||||
converter.setSupportedMediaTypes(supportMediaTypeList);
|
||||
converter.setDefaultCharset(StandardCharsets.UTF_8);
|
||||
converters.add(converter);
|
||||
config.setSerializerFeatures(
|
||||
SerializerFeature.WriteEnumUsingToString,
|
||||
SerializerFeature.DisableCircularReferenceDetect
|
||||
);
|
||||
fastJsonConverter.setFastJsonConfig(config);
|
||||
fastJsonConverter.setSupportedMediaTypes(supportMediaTypeList);
|
||||
fastJsonConverter.setDefaultCharset(StandardCharsets.UTF_8);
|
||||
// 将 FastJsonHttpMessageConverter 添加到列表末尾
|
||||
converters.add(fastJsonConverter);
|
||||
}
|
||||
}
|
@ -13,7 +13,7 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package me.zhengjie.config.webmvc;
|
||||
package me.zhengjie.config.webConfig;
|
||||
|
||||
import org.springframework.boot.web.servlet.MultipartConfigFactory;
|
||||
import org.springframework.context.annotation.Bean;
|
@ -13,15 +13,18 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package me.zhengjie.config.webmvc;
|
||||
package me.zhengjie.config.webConfig;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import me.zhengjie.utils.AnonTagUtils;
|
||||
import me.zhengjie.utils.StringUtils;
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.beans.factory.config.BeanPostProcessor;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.util.ReflectionUtils;
|
||||
import org.springframework.web.servlet.mvc.method.RequestMappingInfoHandlerMapping;
|
||||
import springfox.documentation.builders.ApiInfoBuilder;
|
||||
import springfox.documentation.builders.PathSelectors;
|
||||
import springfox.documentation.service.ApiInfo;
|
||||
@ -32,11 +35,14 @@ import springfox.documentation.service.SecurityScheme;
|
||||
import springfox.documentation.spi.DocumentationType;
|
||||
import springfox.documentation.spi.service.contexts.SecurityContext;
|
||||
import springfox.documentation.spring.web.plugins.Docket;
|
||||
import springfox.documentation.spring.web.plugins.WebFluxRequestHandlerProvider;
|
||||
import springfox.documentation.spring.web.plugins.WebMvcRequestHandlerProvider;
|
||||
import springfox.documentation.swagger2.annotations.EnableSwagger2;
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.regex.Pattern;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
@ -61,7 +67,6 @@ public class SwaggerConfig {
|
||||
private final ApplicationContext applicationContext;
|
||||
|
||||
@Bean
|
||||
@SuppressWarnings("all")
|
||||
public Docket createRestApi() {
|
||||
return new Docket(DocumentationType.SWAGGER_2)
|
||||
.enable(enabled)
|
||||
@ -119,4 +124,44 @@ public class SwaggerConfig {
|
||||
securityReferences.add(new SecurityReference(tokenHeader, authorizationScopes));
|
||||
return securityReferences;
|
||||
}
|
||||
|
||||
/**
|
||||
* 解决Springfox与SpringBoot集成后,WebMvcRequestHandlerProvider和WebFluxRequestHandlerProvider冲突问题
|
||||
* @return /
|
||||
*/
|
||||
@Bean
|
||||
@SuppressWarnings({"all"})
|
||||
public static BeanPostProcessor springfoxHandlerProviderBeanPostProcessor() {
|
||||
return new BeanPostProcessor() {
|
||||
|
||||
@Override
|
||||
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
|
||||
if (bean instanceof WebMvcRequestHandlerProvider || bean instanceof WebFluxRequestHandlerProvider) {
|
||||
customizeSpringfoxHandlerMappings(getHandlerMappings(bean));
|
||||
}
|
||||
return bean;
|
||||
}
|
||||
|
||||
private <T extends RequestMappingInfoHandlerMapping> void customizeSpringfoxHandlerMappings(List<T> mappings) {
|
||||
List<T> filteredMappings = mappings.stream()
|
||||
.filter(mapping -> mapping.getPatternParser() == null)
|
||||
.collect(Collectors.toList());
|
||||
mappings.clear();
|
||||
mappings.addAll(filteredMappings);
|
||||
}
|
||||
|
||||
private List<RequestMappingInfoHandlerMapping> getHandlerMappings(Object bean) {
|
||||
Field field = ReflectionUtils.findField(bean.getClass(), "handlerMappings");
|
||||
if (field != null) {
|
||||
field.setAccessible(true);
|
||||
try {
|
||||
return (List<RequestMappingInfoHandlerMapping>) field.get(bean);
|
||||
} catch (IllegalAccessException e) {
|
||||
throw new IllegalStateException("Failed to access handlerMappings field", e);
|
||||
}
|
||||
}
|
||||
return Collections.emptyList();
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
@ -13,7 +13,7 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package me.zhengjie.config;
|
||||
package me.zhengjie.config.webConfig;
|
||||
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
@ -15,7 +15,7 @@
|
||||
*/
|
||||
package me.zhengjie.utils;
|
||||
|
||||
import me.zhengjie.annotation.AnonymousAccess;
|
||||
import me.zhengjie.annotation.rest.AnonymousAccess;
|
||||
import me.zhengjie.utils.enums.RequestMethodEnum;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.web.bind.annotation.RequestMethod;
|
||||
|
@ -0,0 +1,143 @@
|
||||
/*
|
||||
* Copyright 2019-2020 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package me.zhengjie.utils;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.math.RoundingMode;
|
||||
|
||||
/**
|
||||
* @author Zheng Jie
|
||||
* @description 计算类
|
||||
* @date 2024-12-27
|
||||
**/
|
||||
public class BigDecimalUtils {
|
||||
|
||||
/**
|
||||
* 将对象转换为 BigDecimal
|
||||
* @param obj 输入对象
|
||||
* @return 转换后的 BigDecimal
|
||||
*/
|
||||
private static BigDecimal toBigDecimal(Object obj) {
|
||||
if (obj instanceof BigDecimal) {
|
||||
return (BigDecimal) obj;
|
||||
} else if (obj instanceof Long) {
|
||||
return BigDecimal.valueOf((Long) obj);
|
||||
} else if (obj instanceof Integer) {
|
||||
return BigDecimal.valueOf((Integer) obj);
|
||||
} else if (obj instanceof Double) {
|
||||
return new BigDecimal(String.valueOf(obj));
|
||||
} else {
|
||||
throw new IllegalArgumentException("Unsupported type");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 加法
|
||||
* @param a 加数
|
||||
* @param b 加数
|
||||
* @return 两个加数的和,保留两位小数
|
||||
*/
|
||||
public static BigDecimal add(Object a, Object b) {
|
||||
BigDecimal bdA = toBigDecimal(a);
|
||||
BigDecimal bdB = toBigDecimal(b);
|
||||
return bdA.add(bdB).setScale(2, RoundingMode.HALF_UP);
|
||||
}
|
||||
|
||||
/**
|
||||
* 减法
|
||||
* @param a 被减数
|
||||
* @param b 减数
|
||||
* @return 两数的差,保留两位小数
|
||||
*/
|
||||
public static BigDecimal subtract(Object a, Object b) {
|
||||
BigDecimal bdA = toBigDecimal(a);
|
||||
BigDecimal bdB = toBigDecimal(b);
|
||||
return bdA.subtract(bdB).setScale(2, RoundingMode.HALF_UP);
|
||||
}
|
||||
|
||||
/**
|
||||
* 乘法
|
||||
* @param a 乘数
|
||||
* @param b 乘数
|
||||
* @return 两个乘数的积,保留两位小数
|
||||
*/
|
||||
public static BigDecimal multiply(Object a, Object b) {
|
||||
BigDecimal bdA = toBigDecimal(a);
|
||||
BigDecimal bdB = toBigDecimal(b);
|
||||
return bdA.multiply(bdB).setScale(2, RoundingMode.HALF_UP);
|
||||
}
|
||||
|
||||
/**
|
||||
* 除法
|
||||
* @param a 被除数
|
||||
* @param b 除数
|
||||
* @return 两数的商,保留两位小数
|
||||
*/
|
||||
public static BigDecimal divide(Object a, Object b) {
|
||||
BigDecimal bdA = toBigDecimal(a);
|
||||
BigDecimal bdB = toBigDecimal(b);
|
||||
return bdA.divide(bdB, 2, RoundingMode.HALF_UP);
|
||||
}
|
||||
|
||||
/**
|
||||
* 除法
|
||||
* @param a 被除数
|
||||
* @param b 除数
|
||||
* @param scale 保留小数位数
|
||||
* @return 两数的商,保留两位小数
|
||||
*/
|
||||
public static BigDecimal divide(Object a, Object b, int scale) {
|
||||
BigDecimal bdA = toBigDecimal(a);
|
||||
BigDecimal bdB = toBigDecimal(b);
|
||||
return bdA.divide(bdB, scale, RoundingMode.HALF_UP);
|
||||
}
|
||||
|
||||
/**
|
||||
* 分转元
|
||||
* @param obj 分的金额
|
||||
* @return 转换后的元,保留两位小数
|
||||
*/
|
||||
public static BigDecimal centsToYuan(Object obj) {
|
||||
BigDecimal cents = toBigDecimal(obj);
|
||||
return cents.divide(BigDecimal.valueOf(100), 2, RoundingMode.HALF_UP);
|
||||
}
|
||||
|
||||
/**
|
||||
* 元转分
|
||||
* @param obj 元的金额
|
||||
* @return 转换后的分
|
||||
*/
|
||||
public static Long yuanToCents(Object obj) {
|
||||
BigDecimal yuan = toBigDecimal(obj);
|
||||
return yuan.multiply(BigDecimal.valueOf(100)).setScale(0, RoundingMode.HALF_UP).longValue();
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
BigDecimal num1 = new BigDecimal("10.123");
|
||||
BigDecimal num2 = new BigDecimal("2.456");
|
||||
|
||||
System.out.println("加法结果: " + add(num1, num2));
|
||||
System.out.println("减法结果: " + subtract(num1, num2));
|
||||
System.out.println("乘法结果: " + multiply(num1, num2));
|
||||
System.out.println("除法结果: " + divide(num1, num2));
|
||||
|
||||
Long cents = 12345L;
|
||||
System.out.println("分转元结果: " + centsToYuan(cents));
|
||||
|
||||
BigDecimal yuan = new BigDecimal("123.45");
|
||||
System.out.println("元转分结果: " + yuanToCents(yuan));
|
||||
}
|
||||
}
|
@ -16,9 +16,9 @@
|
||||
package me.zhengjie.utils;
|
||||
|
||||
/**
|
||||
* @author: liaojinlong
|
||||
* @date: 2020/6/11 15:49
|
||||
* @apiNote: 关于缓存的Key集合
|
||||
* @author liaojinlong
|
||||
* @date 2020/6/11 15:49
|
||||
* @description 关于缓存的Key集合
|
||||
*/
|
||||
public interface CacheKey {
|
||||
|
||||
|
@ -1,43 +0,0 @@
|
||||
/*
|
||||
* Copyright 2019-2020 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package me.zhengjie.utils;
|
||||
|
||||
/**
|
||||
* @author: liaojinlong
|
||||
* @date: 2020/6/9 17:02
|
||||
* @since: 1.0
|
||||
* @see {@link SpringBeanHolder}
|
||||
* 针对某些初始化方法,在SpringContextHolder 初始化前时,<br>
|
||||
* 可提交一个 提交回调任务。<br>
|
||||
* 在SpringContextHolder 初始化后,进行回调使用
|
||||
*/
|
||||
|
||||
public interface CallBack {
|
||||
/**
|
||||
* 回调执行方法
|
||||
*/
|
||||
void executor();
|
||||
|
||||
/**
|
||||
* 本回调任务名称
|
||||
* @return /
|
||||
*/
|
||||
default String getCallBackName() {
|
||||
return Thread.currentThread().getId() + ":" + this.getClass().getName();
|
||||
}
|
||||
}
|
||||
|
@ -19,7 +19,6 @@ import java.io.Closeable;
|
||||
|
||||
/**
|
||||
* @author Zheng Jie
|
||||
* @website https://eladmin.vip
|
||||
* @description 用于关闭各种连接,缺啥补啥
|
||||
* @date 2021-03-05
|
||||
**/
|
||||
|
@ -22,9 +22,9 @@ import java.time.format.DateTimeFormatter;
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* @author: liaojinlong
|
||||
* @date: 2020/6/11 16:28
|
||||
* @apiNote: JDK 8 新日期类 格式化与字符串转换 工具类
|
||||
* @author liaojinlong
|
||||
* @date 2020/6/11 16:28
|
||||
* @description JDK 8 新日期类 格式化与字符串转换 工具类
|
||||
*/
|
||||
public class DateUtil {
|
||||
|
||||
|
@ -37,7 +37,7 @@ public class EncryptUtils {
|
||||
private static final IvParameterSpec IV = new IvParameterSpec(STR_PARAM.getBytes(StandardCharsets.UTF_8));
|
||||
|
||||
private static DESKeySpec getDesKeySpec(String source) throws Exception {
|
||||
if (source == null || source.length() == 0){
|
||||
if (source == null || source.isEmpty()){
|
||||
return null;
|
||||
}
|
||||
cipher = Cipher.getInstance("DES/CBC/PKCS5Padding");
|
||||
|
@ -4,6 +4,12 @@ import lombok.*;
|
||||
import java.io.Serializable;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 分页结果封装类
|
||||
* @author Zheng Jie
|
||||
* @date 2018-11-23
|
||||
* @param <T>
|
||||
*/
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
|
@ -33,7 +33,7 @@ import java.util.stream.Collectors;
|
||||
* @author /
|
||||
*/
|
||||
@Component
|
||||
@SuppressWarnings({"unchecked", "all"})
|
||||
@SuppressWarnings({"all"})
|
||||
public class RedisUtils {
|
||||
private static final Logger log = LoggerFactory.getLogger(RedisUtils.class);
|
||||
|
||||
|
@ -10,7 +10,7 @@ import java.security.spec.PKCS8EncodedKeySpec;
|
||||
import java.security.spec.X509EncodedKeySpec;
|
||||
|
||||
/**
|
||||
* @author https://www.cnblogs.com/nihaorz/p/10690643.html
|
||||
* @author <a href="https://www.cnblogs.com/nihaorz/p/10690643.html">...</a>
|
||||
* @description Rsa 工具类,公钥私钥生成,加解密
|
||||
* @date 2020-05-18
|
||||
**/
|
||||
|
@ -31,6 +31,7 @@ import java.util.List;
|
||||
* @date 2019-01-07
|
||||
*/
|
||||
@Slf4j
|
||||
@SuppressWarnings("all")
|
||||
public class SpringBeanHolder implements ApplicationContextAware, DisposableBean {
|
||||
|
||||
private static ApplicationContext applicationContext = null;
|
||||
@ -55,7 +56,6 @@ public class SpringBeanHolder implements ApplicationContextAware, DisposableBean
|
||||
/**
|
||||
* 从静态变量applicationContext中取得Bean, 自动转型为所赋值对象的类型.
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public static <T> T getBean(String name) {
|
||||
assertContextInjected();
|
||||
return (T) applicationContext.getBean(name);
|
||||
@ -153,4 +153,20 @@ public class SpringBeanHolder implements ApplicationContextAware, DisposableBean
|
||||
return new ArrayList<>(Arrays.asList(applicationContext
|
||||
.getBeanNamesForAnnotation(Service.class)));
|
||||
}
|
||||
|
||||
interface CallBack {
|
||||
|
||||
/**
|
||||
* 回调执行方法
|
||||
*/
|
||||
void executor();
|
||||
|
||||
/**
|
||||
* 本回调任务名称
|
||||
* @return /
|
||||
*/
|
||||
default String getCallBackName() {
|
||||
return Thread.currentThread().getId() + ":" + this.getClass().getName();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -32,7 +32,7 @@ import java.util.*;
|
||||
* 字符串工具类, 继承org.apache.commons.lang3.StringUtils类
|
||||
*/
|
||||
@Slf4j
|
||||
@SuppressWarnings({"unchecked","all"})
|
||||
@SuppressWarnings({"all"})
|
||||
public class StringUtils extends org.apache.commons.lang3.StringUtils {
|
||||
|
||||
private static final char SEPARATOR = '_';
|
||||
|
@ -39,12 +39,6 @@
|
||||
<version>1.1</version>
|
||||
</dependency>
|
||||
|
||||
<!-- Spring boot websocket -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-websocket</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- quartz -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
|
@ -1,31 +0,0 @@
|
||||
/*
|
||||
* Copyright 2019-2023 Zheng Jie
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package me.zhengjie.config;
|
||||
|
||||
import org.apache.catalina.connector.Connector;
|
||||
import org.springframework.boot.web.embedded.tomcat.TomcatConnectorCustomizer;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
/**
|
||||
* @author bearBoy80
|
||||
*/
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
public class RelaxedQueryCharsConnectorCustomizer implements TomcatConnectorCustomizer {
|
||||
@Override
|
||||
public void customize(Connector connector) {
|
||||
connector.setProperty("relaxedQueryChars", "[]{}");
|
||||
}
|
||||
}
|
@ -1,59 +0,0 @@
|
||||
/*
|
||||
* Copyright 2019-2020 Zheng Jie
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package me.zhengjie.config.thread;
|
||||
|
||||
import lombok.Data;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* 线程池配置属性类
|
||||
* @author https://juejin.im/entry/5abb8f6951882555677e9da2
|
||||
* @date 2019年10月31日14:58:18
|
||||
*/
|
||||
@Data
|
||||
@Component
|
||||
public class AsyncTaskProperties {
|
||||
|
||||
public static int corePoolSize;
|
||||
|
||||
public static int maxPoolSize;
|
||||
|
||||
public static int keepAliveSeconds;
|
||||
|
||||
public static int queueCapacity;
|
||||
|
||||
@Value("${task.pool.core-pool-size}")
|
||||
public void setCorePoolSize(int corePoolSize) {
|
||||
AsyncTaskProperties.corePoolSize = corePoolSize;
|
||||
}
|
||||
|
||||
@Value("${task.pool.max-pool-size}")
|
||||
public void setMaxPoolSize(int maxPoolSize) {
|
||||
AsyncTaskProperties.maxPoolSize = maxPoolSize;
|
||||
}
|
||||
|
||||
@Value("${task.pool.keep-alive-seconds}")
|
||||
public void setKeepAliveSeconds(int keepAliveSeconds) {
|
||||
AsyncTaskProperties.keepAliveSeconds = keepAliveSeconds;
|
||||
}
|
||||
|
||||
@Value("${task.pool.queue-capacity}")
|
||||
public void setQueueCapacity(int queueCapacity) {
|
||||
AsyncTaskProperties.queueCapacity = queueCapacity;
|
||||
}
|
||||
}
|
@ -1,52 +0,0 @@
|
||||
package me.zhengjie.config.thread;
|
||||
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Primary;
|
||||
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
|
||||
import java.util.concurrent.Executor;
|
||||
import java.util.concurrent.ThreadPoolExecutor;
|
||||
|
||||
/**
|
||||
* 创建自定义的线程池
|
||||
* @author Zheng Jie
|
||||
* @description
|
||||
* @date 2023-06-08
|
||||
**/
|
||||
@Configuration
|
||||
public class CustomExecutorConfig {
|
||||
|
||||
/**
|
||||
* 自定义线程池,用法 @Async
|
||||
* @return Executor
|
||||
*/
|
||||
@Bean
|
||||
@Primary
|
||||
public Executor elAsync() {
|
||||
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
|
||||
executor.setCorePoolSize(AsyncTaskProperties.corePoolSize);
|
||||
executor.setMaxPoolSize(AsyncTaskProperties.maxPoolSize);
|
||||
executor.setQueueCapacity(AsyncTaskProperties.queueCapacity);
|
||||
executor.setThreadNamePrefix("el-async-");
|
||||
executor.setKeepAliveSeconds(AsyncTaskProperties.keepAliveSeconds);
|
||||
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
|
||||
executor.initialize();
|
||||
return executor;
|
||||
}
|
||||
|
||||
/**
|
||||
* 自定义线程池,用法 @Async("otherAsync")
|
||||
* @return Executor
|
||||
*/
|
||||
@Bean
|
||||
public Executor otherAsync() {
|
||||
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
|
||||
executor.setCorePoolSize(15);
|
||||
executor.setQueueCapacity(50);
|
||||
executor.setKeepAliveSeconds(AsyncTaskProperties.keepAliveSeconds);
|
||||
executor.setThreadNamePrefix("el-task-");
|
||||
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
|
||||
executor.initialize();
|
||||
return executor;
|
||||
}
|
||||
}
|
@ -0,0 +1,134 @@
|
||||
/*
|
||||
* Copyright 2019-2020 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version loginCode.length.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-loginCode.length.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package me.zhengjie.modules.security.config.bean;
|
||||
|
||||
import com.wf.captcha.*;
|
||||
import com.wf.captcha.base.Captcha;
|
||||
import lombok.Data;
|
||||
import lombok.Getter;
|
||||
import me.zhengjie.exception.BadRequestException;
|
||||
import me.zhengjie.utils.StringUtils;
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import java.awt.*;
|
||||
|
||||
/**
|
||||
* 登录验证码配置信息
|
||||
* @author liaojinlong
|
||||
* @date 2025-01-13
|
||||
*/
|
||||
@Data
|
||||
@Configuration
|
||||
@ConfigurationProperties(prefix = "login.code")
|
||||
public class CodeProperties {
|
||||
|
||||
/**
|
||||
* 验证码配置
|
||||
*/
|
||||
@Getter
|
||||
private LoginCodeEnum codeType;
|
||||
|
||||
/**
|
||||
* 验证码有效期 分钟
|
||||
*/
|
||||
private Long expiration = 5L;
|
||||
|
||||
/**
|
||||
* 验证码内容长度
|
||||
*/
|
||||
private int length = 4;
|
||||
|
||||
/**
|
||||
* 验证码宽度
|
||||
*/
|
||||
private int width = 111;
|
||||
|
||||
/**
|
||||
* 验证码高度
|
||||
*/
|
||||
private int height = 36;
|
||||
|
||||
/**
|
||||
* 验证码字体
|
||||
*/
|
||||
private String fontName;
|
||||
|
||||
/**
|
||||
* 字体大小
|
||||
*/
|
||||
private int fontSize = 25;
|
||||
|
||||
/**
|
||||
* 依据配置信息生产验证码
|
||||
* @return /
|
||||
*/
|
||||
public Captcha getCaptcha() {
|
||||
Captcha captcha;
|
||||
switch (codeType) {
|
||||
case ARITHMETIC:
|
||||
// 算术类型 https://gitee.com/whvse/EasyCaptcha
|
||||
captcha = new FixedArithmeticCaptcha(width, height);
|
||||
// 几位数运算,默认是两位
|
||||
captcha.setLen(length);
|
||||
break;
|
||||
case CHINESE:
|
||||
captcha = new ChineseCaptcha(width, height);
|
||||
captcha.setLen(length);
|
||||
break;
|
||||
case CHINESE_GIF:
|
||||
captcha = new ChineseGifCaptcha(width, height);
|
||||
captcha.setLen(length);
|
||||
break;
|
||||
case GIF:
|
||||
captcha = new GifCaptcha(width, height);
|
||||
captcha.setLen(length);
|
||||
break;
|
||||
case SPEC:
|
||||
captcha = new SpecCaptcha(width, height);
|
||||
captcha.setLen(length);
|
||||
break;
|
||||
default:
|
||||
throw new BadRequestException("验证码配置信息错误!正确配置查看 LoginCodeEnum ");
|
||||
}
|
||||
if(StringUtils.isNotBlank(fontName)){
|
||||
captcha.setFont(new Font(fontName, Font.PLAIN, fontSize));
|
||||
}
|
||||
return captcha;
|
||||
}
|
||||
|
||||
static class FixedArithmeticCaptcha extends ArithmeticCaptcha {
|
||||
public FixedArithmeticCaptcha(int width, int height) {
|
||||
super(width, height);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected char[] alphas() {
|
||||
// 生成随机数字和运算符
|
||||
int n1 = num(1, 10), n2 = num(1, 10);
|
||||
int opt = num(3);
|
||||
|
||||
// 计算结果
|
||||
int res = new int[]{n1 + n2, n1 - n2, n1 * n2}[opt];
|
||||
// 转换为字符运算符
|
||||
char optChar = "+-x".charAt(opt);
|
||||
|
||||
this.setArithmeticString(String.format("%s%c%s=?", n1, optChar, n2));
|
||||
this.chars = String.valueOf(res);
|
||||
|
||||
return chars.toCharArray();
|
||||
}
|
||||
}
|
||||
}
|
@ -1,61 +0,0 @@
|
||||
/*
|
||||
* Copyright 2019-2020 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package me.zhengjie.modules.security.config.bean;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* 登录验证码配置信息
|
||||
*
|
||||
* @author liaojinlong
|
||||
* @date 2020/6/10 18:53
|
||||
*/
|
||||
@Data
|
||||
public class LoginCode {
|
||||
|
||||
/**
|
||||
* 验证码配置
|
||||
*/
|
||||
private LoginCodeEnum codeType;
|
||||
/**
|
||||
* 验证码有效期 分钟
|
||||
*/
|
||||
private Long expiration = 2L;
|
||||
/**
|
||||
* 验证码内容长度
|
||||
*/
|
||||
private int length = 2;
|
||||
/**
|
||||
* 验证码宽度
|
||||
*/
|
||||
private int width = 111;
|
||||
/**
|
||||
* 验证码高度
|
||||
*/
|
||||
private int height = 36;
|
||||
/**
|
||||
* 验证码字体
|
||||
*/
|
||||
private String fontName;
|
||||
/**
|
||||
* 字体大小
|
||||
*/
|
||||
private int fontSize = 25;
|
||||
|
||||
public LoginCodeEnum getCodeType() {
|
||||
return codeType;
|
||||
}
|
||||
}
|
@ -15,14 +15,7 @@
|
||||
*/
|
||||
package me.zhengjie.modules.security.config.bean;
|
||||
|
||||
import com.wf.captcha.*;
|
||||
import com.wf.captcha.base.Captcha;
|
||||
import lombok.Data;
|
||||
import lombok.Getter;
|
||||
import me.zhengjie.exception.BadRequestException;
|
||||
import me.zhengjie.utils.StringUtils;
|
||||
import java.awt.*;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* 配置文件读取
|
||||
@ -36,88 +29,7 @@ public class LoginProperties {
|
||||
/**
|
||||
* 账号单用户 登录
|
||||
*/
|
||||
@Getter
|
||||
private boolean singleLogin = false;
|
||||
|
||||
private LoginCode loginCode;
|
||||
|
||||
public static final String cacheKey = "user-login-cache:";
|
||||
|
||||
/**
|
||||
* 获取验证码生产类
|
||||
*
|
||||
* @return /
|
||||
*/
|
||||
public Captcha getCaptcha() {
|
||||
if (Objects.isNull(loginCode)) {
|
||||
loginCode = new LoginCode();
|
||||
if (Objects.isNull(loginCode.getCodeType())) {
|
||||
loginCode.setCodeType(LoginCodeEnum.ARITHMETIC);
|
||||
}
|
||||
}
|
||||
return switchCaptcha(loginCode);
|
||||
}
|
||||
|
||||
/**
|
||||
* 依据配置信息生产验证码
|
||||
*
|
||||
* @param loginCode 验证码配置信息
|
||||
* @return /
|
||||
*/
|
||||
private Captcha switchCaptcha(LoginCode loginCode) {
|
||||
Captcha captcha;
|
||||
switch (loginCode.getCodeType()) {
|
||||
case ARITHMETIC:
|
||||
// 算术类型 https://gitee.com/whvse/EasyCaptcha
|
||||
captcha = new FixedArithmeticCaptcha(loginCode.getWidth(), loginCode.getHeight());
|
||||
// 几位数运算,默认是两位
|
||||
captcha.setLen(loginCode.getLength());
|
||||
break;
|
||||
case CHINESE:
|
||||
captcha = new ChineseCaptcha(loginCode.getWidth(), loginCode.getHeight());
|
||||
captcha.setLen(loginCode.getLength());
|
||||
break;
|
||||
case CHINESE_GIF:
|
||||
captcha = new ChineseGifCaptcha(loginCode.getWidth(), loginCode.getHeight());
|
||||
captcha.setLen(loginCode.getLength());
|
||||
break;
|
||||
case GIF:
|
||||
captcha = new GifCaptcha(loginCode.getWidth(), loginCode.getHeight());
|
||||
captcha.setLen(loginCode.getLength());
|
||||
break;
|
||||
case SPEC:
|
||||
captcha = new SpecCaptcha(loginCode.getWidth(), loginCode.getHeight());
|
||||
captcha.setLen(loginCode.getLength());
|
||||
break;
|
||||
default:
|
||||
throw new BadRequestException("验证码配置信息错误!正确配置查看 LoginCodeEnum ");
|
||||
}
|
||||
if(StringUtils.isNotBlank(loginCode.getFontName())){
|
||||
captcha.setFont(new Font(loginCode.getFontName(), Font.PLAIN, loginCode.getFontSize()));
|
||||
}
|
||||
return captcha;
|
||||
}
|
||||
|
||||
static class FixedArithmeticCaptcha extends ArithmeticCaptcha {
|
||||
public FixedArithmeticCaptcha(int width, int height) {
|
||||
super(width, height);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected char[] alphas() {
|
||||
// 生成随机数字和运算符
|
||||
int n1 = num(1, 10), n2 = num(1, 10);
|
||||
int opt = num(3);
|
||||
|
||||
// 计算结果
|
||||
int res = new int[]{n1 + n2, n1 - n2, n1 * n2}[opt];
|
||||
// 转换为字符运算符
|
||||
char optChar = "+-x".charAt(opt);
|
||||
|
||||
this.setArithmeticString(String.format("%s%c%s=?", n1, optChar, n2));
|
||||
this.chars = String.valueOf(res);
|
||||
|
||||
return chars.toCharArray();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -25,8 +25,9 @@ import me.zhengjie.annotation.Log;
|
||||
import me.zhengjie.annotation.rest.AnonymousDeleteMapping;
|
||||
import me.zhengjie.annotation.rest.AnonymousGetMapping;
|
||||
import me.zhengjie.annotation.rest.AnonymousPostMapping;
|
||||
import me.zhengjie.config.RsaProperties;
|
||||
import me.zhengjie.config.properties.RsaProperties;
|
||||
import me.zhengjie.exception.BadRequestException;
|
||||
import me.zhengjie.modules.security.config.bean.CodeProperties;
|
||||
import me.zhengjie.modules.security.config.bean.LoginCodeEnum;
|
||||
import me.zhengjie.modules.security.config.bean.LoginProperties;
|
||||
import me.zhengjie.modules.security.config.bean.SecurityProperties;
|
||||
@ -47,7 +48,7 @@ import org.springframework.security.core.context.SecurityContextHolder;
|
||||
import org.springframework.security.core.userdetails.UserDetails;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import javax.annotation.Resource;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
@ -63,14 +64,14 @@ import java.util.concurrent.TimeUnit;
|
||||
@RequestMapping("/auth")
|
||||
@RequiredArgsConstructor
|
||||
@Api(tags = "系统:系统授权接口")
|
||||
public class AuthorizationController {
|
||||
public class AuthController {
|
||||
private final SecurityProperties properties;
|
||||
private final RedisUtils redisUtils;
|
||||
private final OnlineUserService onlineUserService;
|
||||
private final TokenProvider tokenProvider;
|
||||
private final AuthenticationManagerBuilder authenticationManagerBuilder;
|
||||
@Resource
|
||||
private LoginProperties loginProperties;
|
||||
private final CodeProperties codeProperties;
|
||||
private final LoginProperties loginProperties;
|
||||
|
||||
@Log("用户登录")
|
||||
@ApiOperation("登录授权")
|
||||
@ -123,7 +124,7 @@ public class AuthorizationController {
|
||||
@AnonymousGetMapping(value = "/code")
|
||||
public ResponseEntity<Object> getCode() {
|
||||
// 获取运算的结果
|
||||
Captcha captcha = loginProperties.getCaptcha();
|
||||
Captcha captcha = codeProperties.getCaptcha();
|
||||
String uuid = properties.getCodeKey() + IdUtil.simpleUUID();
|
||||
//当验证码类型为 arithmetic时且长度 >= 2 时,captcha.text()的结果有几率为浮点型
|
||||
String captchaValue = captcha.text();
|
||||
@ -131,7 +132,7 @@ public class AuthorizationController {
|
||||
captchaValue = captchaValue.split("\\.")[0];
|
||||
}
|
||||
// 保存
|
||||
redisUtils.set(uuid, captchaValue, loginProperties.getLoginCode().getExpiration(), TimeUnit.MINUTES);
|
||||
redisUtils.set(uuid, captchaValue, codeProperties.getExpiration(), TimeUnit.MINUTES);
|
||||
// 验证码信息
|
||||
Map<String, Object> imgResult = new HashMap<String, Object>(2) {{
|
||||
put("img", captcha.toBase64());
|
@ -21,7 +21,7 @@ import io.swagger.annotations.Api;
|
||||
import io.swagger.annotations.ApiOperation;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import me.zhengjie.annotation.Log;
|
||||
import me.zhengjie.config.RsaProperties;
|
||||
import me.zhengjie.config.properties.RsaProperties;
|
||||
import me.zhengjie.modules.system.domain.Dept;
|
||||
import me.zhengjie.modules.system.domain.Role;
|
||||
import me.zhengjie.modules.system.service.DataService;
|
||||
|
@ -35,7 +35,7 @@ import java.util.*;
|
||||
**/
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
@CacheConfig(cacheNames = "data")
|
||||
@CacheConfig(cacheNames = "data", keyGenerator = "keyGenerator")
|
||||
public class DataServiceImpl implements DataService {
|
||||
|
||||
private final RoleService roleService;
|
||||
|
@ -45,7 +45,7 @@ import java.util.stream.Collectors;
|
||||
*/
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
@CacheConfig(cacheNames = "dept")
|
||||
@CacheConfig(cacheNames = "dept", keyGenerator = "keyGenerator")
|
||||
public class DeptServiceImpl extends ServiceImpl<DeptMapper, Dept> implements DeptService {
|
||||
|
||||
private final DeptMapper deptMapper;
|
||||
|
@ -37,7 +37,7 @@ import java.util.List;
|
||||
*/
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
@CacheConfig(cacheNames = "dict")
|
||||
@CacheConfig(cacheNames = "dict", keyGenerator = "keyGenerator")
|
||||
public class DictDetailServiceImpl extends ServiceImpl<DictDetailMapper, DictDetail> implements DictDetailService {
|
||||
|
||||
private final DictMapper dictMapper;
|
||||
|
@ -39,7 +39,7 @@ import java.util.*;
|
||||
*/
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
@CacheConfig(cacheNames = "dict")
|
||||
@CacheConfig(cacheNames = "dict", keyGenerator = "keyGenerator")
|
||||
public class DictServiceImpl extends ServiceImpl<DictMapper, Dict> implements DictService {
|
||||
|
||||
private final DictMapper dictMapper;
|
||||
|
@ -41,7 +41,7 @@ import java.util.*;
|
||||
*/
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
@CacheConfig(cacheNames = "job")
|
||||
@CacheConfig(cacheNames = "job", keyGenerator = "keyGenerator")
|
||||
public class JobServiceImpl extends ServiceImpl<JobMapper, Job> implements JobService {
|
||||
|
||||
private final JobMapper jobMapper;
|
||||
@ -49,6 +49,7 @@ public class JobServiceImpl extends ServiceImpl<JobMapper, Job> implements JobSe
|
||||
private final UserMapper userMapper;
|
||||
|
||||
@Override
|
||||
@Cacheable
|
||||
public PageResult<Job> queryAll(JobQueryCriteria criteria, Page<Object> page) {
|
||||
return PageUtil.toPage(jobMapper.findAll(criteria, page));
|
||||
}
|
||||
|
@ -48,7 +48,7 @@ import java.util.stream.Collectors;
|
||||
*/
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
@CacheConfig(cacheNames = "menu")
|
||||
@CacheConfig(cacheNames = "menu", keyGenerator = "keyGenerator")
|
||||
public class MenuServiceImpl extends ServiceImpl<MenuMapper, Menu> implements MenuService {
|
||||
|
||||
private final MenuMapper menuMapper;
|
||||
|
@ -49,7 +49,7 @@ import java.util.stream.Collectors;
|
||||
*/
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
@CacheConfig(cacheNames = "role")
|
||||
@CacheConfig(cacheNames = "role", keyGenerator = "keyGenerator")
|
||||
public class RoleServiceImpl extends ServiceImpl<RoleMapper, Role> implements RoleService {
|
||||
|
||||
private final RoleMapper roleMapper;
|
||||
@ -154,7 +154,7 @@ public class RoleServiceImpl extends ServiceImpl<RoleMapper, Role> implements Ro
|
||||
|
||||
@Override
|
||||
public Integer findByRoles(Set<Role> roles) {
|
||||
if (roles.size() == 0) {
|
||||
if (CollUtil.isEmpty(roles)) {
|
||||
return Integer.MAX_VALUE;
|
||||
}
|
||||
Set<Role> roleSet = new HashSet<>();
|
||||
|
@ -18,7 +18,7 @@ package me.zhengjie.modules.system.service.impl;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import me.zhengjie.config.FileProperties;
|
||||
import me.zhengjie.config.properties.FileProperties;
|
||||
import me.zhengjie.exception.BadRequestException;
|
||||
import me.zhengjie.modules.security.service.OnlineUserService;
|
||||
import me.zhengjie.modules.security.service.UserCacheManager;
|
||||
@ -51,7 +51,7 @@ import java.util.stream.Collectors;
|
||||
*/
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
@CacheConfig(cacheNames = "user")
|
||||
@CacheConfig(cacheNames = "user", keyGenerator = "keyGenerator")
|
||||
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {
|
||||
|
||||
private final UserMapper userMapper;
|
||||
|
@ -58,7 +58,7 @@ login:
|
||||
# 存活时间/秒
|
||||
idle-time: 21600
|
||||
# 验证码
|
||||
login-code:
|
||||
code:
|
||||
# 验证码类型配置 查看 LoginProperties 类
|
||||
code-type: arithmetic
|
||||
# 登录图形验证码有效时间/分钟
|
||||
|
@ -60,7 +60,7 @@ login:
|
||||
# 存活时间/秒
|
||||
idle-time: 21600
|
||||
# 验证码
|
||||
login-code:
|
||||
code:
|
||||
# 验证码类型配置 查看 LoginProperties 类
|
||||
code-type: arithmetic
|
||||
# 登录图形验证码有效时间/分钟
|
||||
|
@ -19,7 +19,7 @@ import io.swagger.annotations.Api;
|
||||
import io.swagger.annotations.ApiOperation;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import me.zhengjie.annotation.AnonymousAccess;
|
||||
import me.zhengjie.annotation.rest.AnonymousAccess;
|
||||
import me.zhengjie.annotation.Log;
|
||||
import me.zhengjie.annotation.rest.AnonymousGetMapping;
|
||||
import me.zhengjie.domain.vo.TradeVo;
|
||||
|
@ -38,7 +38,7 @@ import org.springframework.transaction.annotation.Transactional;
|
||||
*/
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
@CacheConfig(cacheNames = "aliPay")
|
||||
@CacheConfig(cacheNames = "aliPay", keyGenerator = "keyGenerator")
|
||||
public class AliPayServiceImpl extends ServiceImpl<AliPayConfigMapper, AlipayConfig> implements AliPayService {
|
||||
|
||||
@Override
|
||||
|
@ -37,7 +37,7 @@ import org.springframework.transaction.annotation.Transactional;
|
||||
*/
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
@CacheConfig(cacheNames = "email")
|
||||
@CacheConfig(cacheNames = "email", keyGenerator = "keyGenerator")
|
||||
public class EmailServiceImpl extends ServiceImpl<EmailConfigMapper, EmailConfig> implements EmailService {
|
||||
|
||||
@Override
|
||||
|
@ -19,7 +19,7 @@ import cn.hutool.core.util.ObjectUtil;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import me.zhengjie.config.FileProperties;
|
||||
import me.zhengjie.config.properties.FileProperties;
|
||||
import me.zhengjie.domain.LocalStorage;
|
||||
import me.zhengjie.domain.vo.LocalStorageQueryCriteria;
|
||||
import me.zhengjie.exception.BadRequestException;
|
||||
|
@ -33,7 +33,7 @@ import org.springframework.transaction.annotation.Transactional;
|
||||
*/
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
@CacheConfig(cacheNames = "qiNiu")
|
||||
@CacheConfig(cacheNames = "qiNiu", keyGenerator = "keyGenerator")
|
||||
public class QiNiuConfigServiceImpl extends ServiceImpl<QiniuConfigMapper, QiniuConfig> implements QiNiuConfigService {
|
||||
|
||||
@Override
|
||||
|
@ -52,7 +52,7 @@ import java.util.*;
|
||||
*/
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
@CacheConfig(cacheNames = "qiNiu")
|
||||
@CacheConfig(cacheNames = "qiNiu", keyGenerator = "keyGenerator")
|
||||
public class QiniuContentServiceImpl extends ServiceImpl<QiniuContentMapper, QiniuContent> implements QiniuContentService {
|
||||
|
||||
private final QiniuContentMapper qiniuContentMapper;
|
||||
|
@ -76,6 +76,19 @@
|
||||
<artifactId>spring-boot-starter-data-redis</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!--Spring boot redisson-->
|
||||
<dependency>
|
||||
<groupId>org.redisson</groupId>
|
||||
<artifactId>redisson-spring-boot-starter</artifactId>
|
||||
<version>3.17.1</version>
|
||||
</dependency>
|
||||
|
||||
<!-- Spring boot websocket -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-websocket</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- mybatis -->
|
||||
<dependency>
|
||||
<groupId>com.baomidou</groupId>
|
||||
|
Loading…
Reference in New Issue
Block a user