commit 901691aaeab093a8521f89c9943723625e9699fe Author: Jerry Yan <792602257@qq.com> Date: Thu Nov 28 15:10:09 2024 +0800 Init diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..5b8c69d --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +.idea/ +logs/ +target/ diff --git a/.idea/.gitignore b/.idea/.gitignore new file mode 100644 index 0000000..35410ca --- /dev/null +++ b/.idea/.gitignore @@ -0,0 +1,8 @@ +# 默认忽略的文件 +/shelf/ +/workspace.xml +# 基于编辑器的 HTTP 客户端请求 +/httpRequests/ +# Datasource local storage ignored files +/dataSources/ +/dataSources.local.xml diff --git a/.idea/compiler.xml b/.idea/compiler.xml new file mode 100644 index 0000000..d139e29 --- /dev/null +++ b/.idea/compiler.xml @@ -0,0 +1,19 @@ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/encodings.xml b/.idea/encodings.xml new file mode 100644 index 0000000..63e9001 --- /dev/null +++ b/.idea/encodings.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/.idea/jarRepositories.xml b/.idea/jarRepositories.xml new file mode 100644 index 0000000..d83aa6e --- /dev/null +++ b/.idea/jarRepositories.xml @@ -0,0 +1,25 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 0000000..d5cd614 --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,12 @@ + + + + + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..94a25f7 --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..e69de29 diff --git a/pom.xml b/pom.xml new file mode 100644 index 0000000..2371ef3 --- /dev/null +++ b/pom.xml @@ -0,0 +1,215 @@ + + + 4.0.0 + + org.springframework.boot + spring-boot-starter-parent + 2.3.12.RELEASE + + + com.ycwl + basic + 0.0.1-SNAPSHOT + liuying + 流影 + + + + 8 + 8 + 8 + 3.4.0 + 5.6.0 + 1.2.76 + 2.0.7 + 5.1.10 + + true + + + 2.17.0 + + + + + + + + org.springframework.boot + spring-boot-starter-aop + + + + + org.springframework.boot + spring-boot-starter-web + + + + + org.springframework.boot + spring-boot-starter-data-redis + + + io.lettuce + lettuce-core + + + + + + redis.clients + jedis + + + + + mysql + mysql-connector-java + runtime + + + + + org.springframework.boot + spring-boot-starter-test + test + + + + org.springframework.boot + spring-boot-configuration-processor + + + + + com.baomidou + mybatis-plus-boot-starter + ${mybatisplus.boot.starter.version} + + + + + org.projectlombok + lombok + + + + + + cn.hutool + hutool-all + ${hutool-all.version} + + + + com.google.zxing + core + 3.3.3 + + + + com.alibaba + fastjson + ${fastjson.version} + + + + + org.apache.commons + commons-lang3 + + + + + com.github.xiaoymin + knife4j-spring-boot-starter + ${knife4j-spring-boot-starter.version} + + + + + com.github.pagehelper + pagehelper + ${pagehelper.version} + + + org.mybatis + mybatis + + + org.mybatis + mybatis-spring + + + + + + + io.jsonwebtoken + jjwt + 0.9.0 + + + org.apache.commons + commons-text + 1.1 + + + + + org.apache.commons + commons-lang3 + + + + + com.aliyun + alibaba-dingtalk-service-sdk + 2.0.0 + + + + + + + + + + + + + + + + + org.redisson + redisson + 3.14.1 + + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + + + + + spring-milestones + Spring Milestones + https://repo.spring.io/milestone + + false + + + + + diff --git a/src/main/java/com/ycwl/basic/Application.java b/src/main/java/com/ycwl/basic/Application.java new file mode 100644 index 0000000..dc94933 --- /dev/null +++ b/src/main/java/com/ycwl/basic/Application.java @@ -0,0 +1,15 @@ +package com.ycwl.basic; + +import org.mybatis.spring.annotation.MapperScan; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +@MapperScan(basePackages = "com.ycwl.basic.mapper") +public class Application { + + public static void main(String[] args) { + SpringApplication.run(Application.class, args); + } + +} diff --git a/src/main/java/com/ycwl/basic/annotation/IgnoreToken.java b/src/main/java/com/ycwl/basic/annotation/IgnoreToken.java new file mode 100644 index 0000000..03020ed --- /dev/null +++ b/src/main/java/com/ycwl/basic/annotation/IgnoreToken.java @@ -0,0 +1,21 @@ +package com.ycwl.basic.annotation; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * ignore token validation + *

+ * check all req except add this annotation + * this annotation could use in method and class type + *

+ * + * @ahtuor yangchen + */ +@Retention(RetentionPolicy.RUNTIME) +@Target(value = {ElementType.METHOD, ElementType.TYPE}) +public @interface IgnoreToken { + +} diff --git a/src/main/java/com/ycwl/basic/aspectj/RequestParameterAspectj.java b/src/main/java/com/ycwl/basic/aspectj/RequestParameterAspectj.java new file mode 100644 index 0000000..c90ea17 --- /dev/null +++ b/src/main/java/com/ycwl/basic/aspectj/RequestParameterAspectj.java @@ -0,0 +1,69 @@ +package com.ycwl.basic.aspectj; + +import com.alibaba.fastjson.JSON; +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.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.stereotype.Component; +import org.springframework.web.context.request.RequestContextHolder; +import org.springframework.web.context.request.ServletRequestAttributes; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.util.Enumeration; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; + +/** + * @date 2022年10月13日 13:55 + * 入参参数打印类 + */ +@Aspect +@Component +public class RequestParameterAspectj { + + private static final Logger LOGGER = LoggerFactory.getLogger(RequestParameterAspectj.class); + + @Pointcut("execution(* com.ycwl.basic.controller.*.*.*(..))") + public void classPackage() { + + } + + @Around("classPackage()") + public Object parameterPoint(ProceedingJoinPoint joinPoint) throws Throwable { + final ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes(); + if (requestAttributes != null) { + final HttpServletRequest request = requestAttributes.getRequest(); + String requestURI = request.getRequestURI(); + String method = request.getMethod(); + + HashSet parameterValueSet = new HashSet<>(); + Object[] requestParameterValue = joinPoint.getArgs(); + for (Object o : requestParameterValue) { + if (!(o instanceof HttpServletRequest || o instanceof HttpServletResponse)) { + parameterValueSet.add(String.valueOf(o)); + } + } + + Enumeration parameterNames = request.getParameterNames(); + Map parameterUrlMap = new HashMap<>(); + while (parameterNames.hasMoreElements()) { + String parameterName = parameterNames.nextElement(); + String parameterValue = request.getParameter(parameterName); + parameterUrlMap.put(parameterName, parameterValue); + } + + if (parameterUrlMap.isEmpty()) { + LOGGER.info("当前请求的路径为-> {} 请求方式为-> {} 参数为-> {}", requestURI, method, JSON.toJSONString(parameterValueSet)); + } else { + LOGGER.info("当前请求的路径为-> {} 请求方式为-> {} 参数为-> {} 路径传参为-> {}", requestURI, method, + JSON.toJSONString(parameterValueSet), JSON.toJSONString(parameterUrlMap)); + } + } + return joinPoint.proceed(); + } +} diff --git a/src/main/java/com/ycwl/basic/config/CustomRedisCacheManager.java b/src/main/java/com/ycwl/basic/config/CustomRedisCacheManager.java new file mode 100644 index 0000000..69ebc4e --- /dev/null +++ b/src/main/java/com/ycwl/basic/config/CustomRedisCacheManager.java @@ -0,0 +1,56 @@ +package com.ycwl.basic.config; + +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.cache.RedisCacheConfiguration; +import org.springframework.data.redis.connection.RedisConnectionFactory; +import org.springframework.data.redis.core.RedisTemplate; +import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer; +import org.springframework.data.redis.serializer.RedisSerializationContext; +import org.springframework.data.redis.serializer.StringRedisSerializer; + +import java.time.Duration; + +/** + * @author wenshijia + * @date 2021年07月05日 18:34 + * 修改redis缓存序列化器 + */ +@Configuration +@EnableCaching +public class CustomRedisCacheManager extends CachingConfigurerSupport { + + @Bean + public RedisCacheConfiguration redisCacheConfiguration() { + Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer<>(Object.class); + RedisCacheConfiguration configuration = RedisCacheConfiguration.defaultCacheConfig(); + configuration = configuration.serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(jackson2JsonRedisSerializer)).entryTtl(Duration.ofMinutes(1)); + return configuration; + } + + /** + * 处理redis连接工具显示redis key值显示乱码问题,value值没处理 + * + * @param factory RedisConnectionFactory + * @return org.springframework.data.redis.core.RedisTemplate + * @date 2022/9/21 13:58 + */ + @Bean + public RedisTemplate redisTemplate(RedisConnectionFactory factory) { + RedisTemplate redisTemplate = new RedisTemplate<>(); + + redisTemplate.setConnectionFactory(factory); + + final StringRedisSerializer stringRedisSerializer = new StringRedisSerializer(); + redisTemplate.setKeySerializer(stringRedisSerializer); + redisTemplate.setValueSerializer(stringRedisSerializer); + + redisTemplate.setHashKeySerializer(stringRedisSerializer); + + redisTemplate.afterPropertiesSet(); + return redisTemplate; + } + +} diff --git a/src/main/java/com/ycwl/basic/config/FilterConfig.java b/src/main/java/com/ycwl/basic/config/FilterConfig.java new file mode 100644 index 0000000..712bbad --- /dev/null +++ b/src/main/java/com/ycwl/basic/config/FilterConfig.java @@ -0,0 +1,22 @@ +package com.ycwl.basic.config; + +import com.ycwl.basic.filter.XssFilter; +import org.springframework.boot.web.servlet.FilterRegistrationBean; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +import javax.servlet.DispatcherType; + +@Configuration +public class FilterConfig { + @Bean + public FilterRegistrationBean xssFilterRegistrationBean(){ + FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean(); + filterRegistrationBean.setFilter(new XssFilter()); + filterRegistrationBean.setOrder(1); + filterRegistrationBean.setDispatcherTypes(DispatcherType.REQUEST); + filterRegistrationBean.setEnabled(true); + filterRegistrationBean.addUrlPatterns("/*"); + return filterRegistrationBean; + } +} diff --git a/src/main/java/com/ycwl/basic/config/MybatisPlusPageConfig.java b/src/main/java/com/ycwl/basic/config/MybatisPlusPageConfig.java new file mode 100644 index 0000000..b426119 --- /dev/null +++ b/src/main/java/com/ycwl/basic/config/MybatisPlusPageConfig.java @@ -0,0 +1,32 @@ +package com.ycwl.basic.config; + +import com.baomidou.mybatisplus.annotation.DbType; +import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor; +import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +/** + * @author wenshijia + * @date 2021年06月04日 9:42 + */ +@Configuration +public class MybatisPlusPageConfig { + + /* 旧版本配置 + @Bean + public PaginationInterceptor paginationInterceptor(){ + return new PaginationInterceptor(); + }*/ + + /** + * 新的分页插件,一缓和二缓遵循mybatis的规则, + * 需要设置 MybatisConfiguration#useDeprecatedExecutor = false 避免缓存出现问题 + */ + @Bean + public MybatisPlusInterceptor mybatisPlusInterceptor() { + MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor(); + interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL)); + return interceptor; + } +} diff --git a/src/main/java/com/ycwl/basic/config/PageHelperConfig.java b/src/main/java/com/ycwl/basic/config/PageHelperConfig.java new file mode 100644 index 0000000..2a7748c --- /dev/null +++ b/src/main/java/com/ycwl/basic/config/PageHelperConfig.java @@ -0,0 +1,26 @@ +package com.ycwl.basic.config; + +import com.github.pagehelper.PageInterceptor; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +import java.util.Properties; + +/** + * @date 2022年05月18日 15:43 + * PageHelper配置类 + */ +@Configuration +public class PageHelperConfig { + + @Bean(name = "pageHelper") + public PageInterceptor pageHelper() { + PageInterceptor pageHelper = new PageInterceptor(); + Properties properties = new Properties(); + properties.setProperty("reasonable", "false"); + // 配置数据库的方言 + properties.setProperty("helperDialect", "mysql"); + pageHelper.setProperties(properties); + return pageHelper; + } +} diff --git a/src/main/java/com/ycwl/basic/config/RedisConfig.java b/src/main/java/com/ycwl/basic/config/RedisConfig.java new file mode 100644 index 0000000..5908cd9 --- /dev/null +++ b/src/main/java/com/ycwl/basic/config/RedisConfig.java @@ -0,0 +1,50 @@ +package com.ycwl.basic.config; + +import com.fasterxml.jackson.annotation.JsonAutoDetect; +import com.fasterxml.jackson.annotation.PropertyAccessor; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.jsontype.impl.LaissezFaireSubTypeValidator; +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.Jackson2JsonRedisSerializer; +import org.springframework.data.redis.serializer.StringRedisSerializer; + +import javax.annotation.Resource; + +@Configuration +public class RedisConfig { + + @Resource + private RedisConnectionFactory redisConnectionFactory; + + @Bean + public RedisTemplate redisTemplate() { + RedisTemplate redisTemplate = new RedisTemplate<>(); + redisTemplate.setConnectionFactory(redisConnectionFactory); + + // 使用Jackson2JsonRedisSerialize 替换默认序列化 + Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class); + + ObjectMapper objectMapper = new ObjectMapper(); + objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY); + objectMapper.activateDefaultTyping(LaissezFaireSubTypeValidator.instance, ObjectMapper.DefaultTyping.NON_FINAL); + + jackson2JsonRedisSerializer.setObjectMapper(objectMapper); + + // 设置value的序列化规则和 key的序列化规则 + redisTemplate.setValueSerializer(jackson2JsonRedisSerializer); + redisTemplate.setKeySerializer(new StringRedisSerializer()); + + redisTemplate.setHashKeySerializer(jackson2JsonRedisSerializer); + redisTemplate.setHashValueSerializer(jackson2JsonRedisSerializer); + + redisTemplate.setDefaultSerializer(jackson2JsonRedisSerializer); + redisTemplate.setEnableDefaultSerializer(true); + redisTemplate.afterPropertiesSet(); + + return redisTemplate; + } + +} diff --git a/src/main/java/com/ycwl/basic/config/RedissonConfig.java b/src/main/java/com/ycwl/basic/config/RedissonConfig.java new file mode 100644 index 0000000..423cc02 --- /dev/null +++ b/src/main/java/com/ycwl/basic/config/RedissonConfig.java @@ -0,0 +1,31 @@ +//package com.ycwl.basic.config; +// +//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; +// +//@Configuration +//public class RedissonConfig { +// +// @Value("${spring.redis.host}") +// private String host; +// @Value("${spring.redis.port}") +// private String port; +// @Value("${spring.redis.password}") +// private String password; +// +// @Bean +// public RedissonClient getRedisSon() { +// Config config = new Config(); +// String address = new StringBuilder("redis://").append(host).append(":").append(port).toString(); +// config.useSingleServer().setAddress(address); +// if (null != password && !"".equals(password.trim())) { +// config.useSingleServer().setPassword(password); +// } +// return Redisson.create(config); +// } +// +//} diff --git a/src/main/java/com/ycwl/basic/config/SwaggerConfig.java b/src/main/java/com/ycwl/basic/config/SwaggerConfig.java new file mode 100644 index 0000000..8abeba1 --- /dev/null +++ b/src/main/java/com/ycwl/basic/config/SwaggerConfig.java @@ -0,0 +1,72 @@ +package com.ycwl.basic.config; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import springfox.documentation.builders.ApiInfoBuilder; +import springfox.documentation.builders.ParameterBuilder; +import springfox.documentation.builders.PathSelectors; +import springfox.documentation.builders.RequestHandlerSelectors; +import springfox.documentation.schema.ModelRef; +import springfox.documentation.service.ApiInfo; +import springfox.documentation.service.Contact; +import springfox.documentation.service.Parameter; +import springfox.documentation.spi.DocumentationType; +import springfox.documentation.spring.web.plugins.Docket; +import springfox.documentation.swagger2.annotations.EnableSwagger2WebMvc; + +import java.util.ArrayList; +import java.util.List; + +/** + * Swagger 配置类 + * 原生: /swagger-ui.html + * 美化: /doc.html + */ +@Configuration +@EnableSwagger2WebMvc +public class SwaggerConfig { + + /** + * Swagger 实例 Bean 是 Docket, 所以通过配置 Docket 实例来配置 Swagger + */ + @Bean + public Docket docket() { + + return new Docket(DocumentationType.SWAGGER_2) + // 展示在 Swagger 页面上的自定义工程描述信息 + .apiInfo(apiInfo()) + // 选择展示哪些接口 + .select() + //只有com.zcy.e.firstaid包内的才去展示 + .apis(RequestHandlerSelectors.basePackage("com.ycwl")) + .paths(PathSelectors.any()) + .build() + .globalOperationParameters(getGlobalRequestParameters()); + } + + /** + * Swagger 的描述信息 + */ + public ApiInfo apiInfo() { + + return new ApiInfoBuilder() + .title("city-investment-smart-park") + .description("城投智慧园区") + .contact(new Contact("ycwl", "www.xxx.com", "xxxxxxxxx.com")) + .version("1.0") + .build(); + } + + private List getGlobalRequestParameters() { + List parameters = new ArrayList<>(); + parameters.add(new ParameterBuilder() + .name("token") + .description("登录令牌") + .parameterType("header") + .modelRef(new ModelRef("String")) + .required(true) + .build()); + return parameters; + } + +} diff --git a/src/main/java/com/ycwl/basic/config/WebMvcConfig.java b/src/main/java/com/ycwl/basic/config/WebMvcConfig.java new file mode 100644 index 0000000..b95a5c1 --- /dev/null +++ b/src/main/java/com/ycwl/basic/config/WebMvcConfig.java @@ -0,0 +1,118 @@ +package com.ycwl.basic.config; + +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.module.SimpleModule; +import com.ycwl.basic.interceptor.AuthInterceptor; +import com.ycwl.basic.xss.XssJacksonDeserializer; +import com.ycwl.basic.xss.XssJacksonSerializer; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.http.converter.HttpMessageConverter; +import org.springframework.http.converter.StringHttpMessageConverter; +import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder; +import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter; +import org.springframework.web.cors.CorsConfiguration; +import org.springframework.web.cors.UrlBasedCorsConfigurationSource; +import org.springframework.web.filter.CorsFilter; +import org.springframework.web.servlet.config.annotation.InterceptorRegistry; +import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry; +import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; + +import java.util.List; + +/** + * @date 2022年10月14日 11:20 + */ +@Configuration +public class WebMvcConfig implements WebMvcConfigurer { + + @Autowired + private AuthInterceptor authInterceptor; + + @Override + public void addInterceptors(InterceptorRegistry registry) { + registry.addInterceptor(authInterceptor) + // 拦截除指定接口外的所有请求,通过判断 注解 来决定是否需要做登录验证 + .addPathPatterns("/**") + .excludePathPatterns("/swagger-resources/**", "/webjars/**", "/v2/api-docs", "/doc.html/**", "/error", "/csrf", "/"); + } + + /** + * 配置静态资源 + */ + @Override + public void addResourceHandlers(ResourceHandlerRegistry registry) { + registry.addResourceHandler("/static/**").addResourceLocations("classpath:/static/"); + registry.addResourceHandler("/templates/**").addResourceLocations("classpath:/templates/"); + /*放行swagger*/ + registry.addResourceHandler("doc.html").addResourceLocations("classpath:/META-INF/resources/"); + registry.addResourceHandler("/webjars/**").addResourceLocations("classpath:/META-INF/resources/webjars/"); + } + + /** + * attention:简单跨域就是GET,HEAD和POST请求,但是POST请求的"Content-Type"只能是application/x-www-form-urlencoded, multipart/form-data 或 text/plain + * 反之,就是非简单跨域,此跨域有一个预检机制,说直白点,就是会发两次请求,一次OPTIONS请求,一次真正的请求 + */ + @Bean + public CorsFilter corsFilter() { + final UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(); + final CorsConfiguration config = new CorsConfiguration(); + config.setAllowCredentials(true); + // 允许向该服务器提交请求的URI,*表示全部允许,在SpringMVC中,如果设成*,会自动转成当前请求头中的Origin + config.addAllowedOrigin("*"); + // 允许访问的头信息,*表示全部 + config.addAllowedHeader("*"); + // 预检请求的缓存时间(秒),即在这个时间段里,对于相同的跨域请求不会再预检了 + config.setMaxAge(18000L); + // 允许提交请求的方法,*表示全部允许 + config.addAllowedMethod("OPTIONS"); + config.addAllowedMethod("HEAD"); + config.addAllowedMethod("GET"); + config.addAllowedMethod("PUT"); + config.addAllowedMethod("POST"); + config.addAllowedMethod("DELETE"); + config.addAllowedMethod("PATCH"); + source.registerCorsConfiguration("/**", config); + return new CorsFilter(source); + } + + + @Bean + public WebMvcConfigurer createConvert() { + return new WebMvcConfigurer() { + @Override + public void extendMessageConverters(List> converters) { + Jackson2ObjectMapperBuilder builder = new Jackson2ObjectMapperBuilder(); + ObjectMapper mapper = builder.build(); + /*注入自定义的序列化工具,将RequestBody的参数进行转译后传输*/ + SimpleModule simpleModule = new SimpleModule(); + // XSS序列化 + simpleModule.addSerializer(String.class, new XssJacksonSerializer()); + simpleModule.addDeserializer(String.class, new XssJacksonDeserializer()); + mapper.registerModule(simpleModule); + converters.add(new MappingJackson2HttpMessageConverter(mapper)); + } + }; + } + + + @Autowired + private StringHttpMessageConverter stringHttpMessageConverter; + @Autowired + private MappingJackson2HttpMessageConverter httpMessageConverter; + /** + * 添加转换器 + */ + @Override + public void extendMessageConverters(List> converters) { + for (int i = 0; i < converters.size(); i++) { + if (converters.get(i) instanceof StringHttpMessageConverter){ + converters.set(i, stringHttpMessageConverter); + } + if (converters.get(i) instanceof MappingJackson2HttpMessageConverter) { + converters.set(i, httpMessageConverter); + } + } + } +} diff --git a/src/main/java/com/ycwl/basic/constant/BaseContextHandler.java b/src/main/java/com/ycwl/basic/constant/BaseContextHandler.java new file mode 100644 index 0000000..57470d2 --- /dev/null +++ b/src/main/java/com/ycwl/basic/constant/BaseContextHandler.java @@ -0,0 +1,113 @@ +package com.ycwl.basic.constant; + +import com.ycwl.basic.utils.StringUtil; +import lombok.Data; + +import java.time.LocalDateTime; +import java.util.HashMap; +import java.util.Map; + +@Data +public class BaseContextHandler { + + public static ThreadLocal> threadLocal = new ThreadLocal(); + + public BaseContextHandler() { + } + + public static void set(String key, Object value) { + Object map; + if ((map = (Map) threadLocal.get()) == null) { + map = new HashMap(); + threadLocal.set((Map) map); + } + + ((Map) map).put(key, value); + } + + public static Object get(String key) { + Object map; + if ((map = (Map) threadLocal.get()) == null) { + map = new HashMap(); + threadLocal.set((Map) map); + } + + return ((Map) map).get(key); + } + + public static void setToken(String token) { + set("currentUserToken", token); + } + + public static String getToken() { + return StringUtil.a(get("currentUserToken")); + } + + public static String getAccount() { + return returnObjectValue(get("currentAccount")); + } + + public static void setAccount(String userName) { + set("currentAccount", userName); + } + + public static String getPhone() { + return returnObjectValue(get("currentPhone")); + } + + public static void setPhone(String phone) { + set("currentPhone", phone); + } + + public static String getName() { + return returnObjectValue(get("currentName")); + } + + public static void setName(String name) { + set("currentName", name); + } + + public static String getUserId() { + return returnObjectValue(get("currentUserId")); + } + + public static void setUserId(String userId) { + set("currentUserId", userId); + } + + + public static String getRoleId() { + return get("currentRoleId").toString(); + } + + public static void setRoleId(String roleId) { + set("currentRoleId", roleId); + } + + public static LocalDateTime getUserExpireTime() { + return (LocalDateTime) get("currentUserExpireTime"); + } + + public static void setUserExpireTime(LocalDateTime localDateTime) { + set("currentUserExpireTime", localDateTime); + } + + + /** + * 返回value + * + * @param value + * @return + */ + private static String returnObjectValue(Object value) { + return value == null ? null : value.toString(); + } + + /** + * 移除threadLocal + */ + public static void remove() { + threadLocal.remove(); + } + +} diff --git a/src/main/java/com/ycwl/basic/constant/CommonReturnMessageConstant.java b/src/main/java/com/ycwl/basic/constant/CommonReturnMessageConstant.java new file mode 100644 index 0000000..6328d3b --- /dev/null +++ b/src/main/java/com/ycwl/basic/constant/CommonReturnMessageConstant.java @@ -0,0 +1,15 @@ +package com.ycwl.basic.constant; + +/** + * @date 2022年11月21日 10:17 + * 公共的返回消息 + */ +public class CommonReturnMessageConstant { + + public static final String SAVE_SUCCESS = "保存成功"; + public static final String SAVE_FAILED = "保存失败"; + + private CommonReturnMessageConstant() { + + } +} diff --git a/src/main/java/com/ycwl/basic/constant/ConsumeIsBindApplicationSiteConstant.java b/src/main/java/com/ycwl/basic/constant/ConsumeIsBindApplicationSiteConstant.java new file mode 100644 index 0000000..9d69664 --- /dev/null +++ b/src/main/java/com/ycwl/basic/constant/ConsumeIsBindApplicationSiteConstant.java @@ -0,0 +1,21 @@ +package com.ycwl.basic.constant; + +/** + * @date 2022年11月21日 9:59 + * 消费管理收费机是否绑定应用场所状态类 + */ +public class ConsumeIsBindApplicationSiteConstant { + + /** + * 未绑定 + */ + public static final int UNBOUND = 0; + /** + * 已绑定 + */ + public static final int BOUND = 1; + + private ConsumeIsBindApplicationSiteConstant() { + + } +} diff --git a/src/main/java/com/ycwl/basic/constant/PermissionConstant.java b/src/main/java/com/ycwl/basic/constant/PermissionConstant.java new file mode 100644 index 0000000..9b89502 --- /dev/null +++ b/src/main/java/com/ycwl/basic/constant/PermissionConstant.java @@ -0,0 +1,6 @@ +package com.ycwl.basic.constant; + +public class PermissionConstant { + public final static String USER_PERMISSION_URL = "userPermissionUrl:"; + public final static String ROLE_STATUS = "roleStatus:"; +} diff --git a/src/main/java/com/ycwl/basic/constant/RequestConstant.java b/src/main/java/com/ycwl/basic/constant/RequestConstant.java new file mode 100644 index 0000000..d34f159 --- /dev/null +++ b/src/main/java/com/ycwl/basic/constant/RequestConstant.java @@ -0,0 +1,5 @@ +package com.ycwl.basic.constant; + +public class RequestConstant { + public final static String UPDATE_PASSWORD = "/api/adminUser/v1/updatePassword"; +} diff --git a/src/main/java/com/ycwl/basic/constant/ShareParkingSpaceRedisKeyConstant.java b/src/main/java/com/ycwl/basic/constant/ShareParkingSpaceRedisKeyConstant.java new file mode 100644 index 0000000..d33d619 --- /dev/null +++ b/src/main/java/com/ycwl/basic/constant/ShareParkingSpaceRedisKeyConstant.java @@ -0,0 +1,18 @@ +package com.ycwl.basic.constant; + +public class ShareParkingSpaceRedisKeyConstant { + // 更改数量时候的锁 + public final static String UPDATE_NUMBER_LOCK_KEY="ShareParking:updateNumberLockKey"; + // 地上车位 + public final static String GROUND_PARKING_SPACE_NUMBER="ShareParking:groundParkingSpaceNumber"; + // 地下车位数 + public final static String UNDERGROUND_PARKING_SPACE_NUMBER="ShareParking:undergroundParkingSpaceNumber"; + // 每日开放预约时间 + public final static String OPEN_TIME="ShareParking:openTime"; + // 预约后当日车辆最晚停留时间 + public final static String RESIDENCE_TIME="ShareParking:residenceTime"; + //取消时间 + public final static String CANCEL_TIME="ShareParking:cancelTime"; + //支付时间 + public final static String PAY_TIME="ShareParking:payTime"; +} diff --git a/src/main/java/com/ycwl/basic/controller/pc/AdminUserController.java b/src/main/java/com/ycwl/basic/controller/pc/AdminUserController.java new file mode 100644 index 0000000..b7cb34b --- /dev/null +++ b/src/main/java/com/ycwl/basic/controller/pc/AdminUserController.java @@ -0,0 +1,89 @@ +package com.ycwl.basic.controller.pc; + +import com.github.pagehelper.PageInfo; + +import com.ycwl.basic.annotation.IgnoreToken; +import com.ycwl.basic.model.pc.adminUser.req.*; +import com.ycwl.basic.model.pc.adminUser.resp.AdminUserListRespVO; +import com.ycwl.basic.model.pc.adminUser.resp.StaffSimpleInfoRespVO; +import com.ycwl.basic.service.pc.AdminUserService; +import com.ycwl.basic.utils.ApiResponse; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.*; + +import java.util.List; + +@RestController +@RequestMapping("/api/adminUser/v1") +@Slf4j +@Api(tags = "系统后台用户管理") +public class AdminUserController { + + @Autowired + AdminUserService adminUserService; + + + @PostMapping(value = "/login") + @ApiOperation(value = "登录") + @IgnoreToken + public ApiResponse login(@RequestBody LoginReqVO loginReqVO) throws Exception { + log.info("{}:开始登录管理后台", loginReqVO.getAccount()); + return adminUserService.login(loginReqVO); + } + + @PostMapping(value = "/updatePassword") + @ApiOperation(value = "用户自己修改密码") + public ApiResponse updatePassword(@RequestBody UpdatePasswordReqVO updatePasswordReqVO) throws Exception { + log.info("{}:开始修改管理后台密码", updatePasswordReqVO.getId()); + return adminUserService.updatePassword(updatePasswordReqVO); + } + + @PostMapping(value = "/list") + @ApiOperation(value = "系统后台用户列表") + //@IgnoreToken + public ApiResponse>> list(@RequestBody AdminUserListReqVO adminUserListReqVO) { + return adminUserService.list(adminUserListReqVO); + } + + @PostMapping(value = "/query/list") + @ApiOperation(value = "系统后台用户列表查询") + @IgnoreToken + public ApiResponse>> queryList(@RequestBody AdminUserListReqVO adminUserListReqVO) { + return adminUserService.list(adminUserListReqVO); + } + + @PostMapping(value = "/add") + @ApiOperation(value = "添加系统后台用户") + //@IgnoreToken + public ApiResponse add(@RequestBody AddOrUpdateAdminUserReqVO addOrUpdateAdminUserReqVO) { + return adminUserService.addOrUpdate(addOrUpdateAdminUserReqVO); + } + + @PostMapping(value = "/update") + @ApiOperation(value = "更新系统后台用户") + //@IgnoreToken + public ApiResponse update(@RequestBody AddOrUpdateAdminUserReqVO addOrUpdateAdminUserReqVO) { + return adminUserService.addOrUpdate(addOrUpdateAdminUserReqVO); + } + + @GetMapping(value = "/delete/{id}") + @ApiOperation(value = "删除") + //@IgnoreToken + public ApiResponse delete(@PathVariable("id") String id) { + return adminUserService.delete(id); + } + + @PostMapping(value = "/resetPassword") + @ApiOperation(value = "重置密码") + //@IgnoreToken + public ApiResponse resetPassword(@RequestBody ResetPasswordReqVO resetPasswordReqVO) { + log.info("{}:开始重置后台密码", resetPasswordReqVO.getId()); + return adminUserService.resetPassword(resetPasswordReqVO); + } + + +} + diff --git a/src/main/java/com/ycwl/basic/controller/pc/RoleController.java b/src/main/java/com/ycwl/basic/controller/pc/RoleController.java new file mode 100644 index 0000000..8e96361 --- /dev/null +++ b/src/main/java/com/ycwl/basic/controller/pc/RoleController.java @@ -0,0 +1,67 @@ +package com.ycwl.basic.controller.pc; + +import com.github.pagehelper.PageInfo; +import com.ycwl.basic.annotation.IgnoreToken; +import com.ycwl.basic.model.pc.role.req.AddOrUpdateRoleReqVO; +import com.ycwl.basic.model.pc.role.req.RoleListReqVO; +import com.ycwl.basic.model.pc.role.resp.RoleListRespVO; +import com.ycwl.basic.service.pc.RoleService; +import com.ycwl.basic.utils.ApiResponse; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.*; + +import java.util.List; + +@RestController +@RequestMapping("/api/role/v1") +@Api(tags = "系统角色管理") +public class RoleController { + + @Autowired + RoleService roleService; + + @PostMapping(value = "/list") + @ApiOperation(value = "角色列表") + @IgnoreToken + public ApiResponse>> list(@RequestBody RoleListReqVO roleListReqVO) { + return roleService.list(roleListReqVO); + } + + @PostMapping(value = "/addOrUpdate") + @ApiOperation(value = "添加或更新角色") + @IgnoreToken + public ApiResponse addOrUpdate(@RequestBody AddOrUpdateRoleReqVO addOrUpdateRoleReqVO) { + return roleService.addOrUpdate(addOrUpdateRoleReqVO); + } + + @GetMapping(value = "/delete/{id}") + @ApiOperation(value = "删除") + @IgnoreToken + public ApiResponse delete(@PathVariable("id") String id) { + return roleService.delete(id); + } + + @GetMapping(value = "/updateReturnMenu/{id}") + @ApiOperation(value = "编辑回显该角色当前菜单") + @IgnoreToken + public ApiResponse updateReturnMenu(@PathVariable("id") String id) { + return roleService.updateReturnMenu(id); + } + + @GetMapping(value = "/menu/{type}") + @ApiOperation(value = " 菜单") + @IgnoreToken + public ApiResponse menu(@PathVariable("type") Integer type) { + return roleService.menu(type); + } + + @GetMapping(value = "/updateStatus/{id}") + @ApiOperation(value = "更改角色类型状态") + //@IgnoreToken + public ApiResponse updateStatus(@PathVariable("id") String id) { + return roleService.updateStatus(id); + } +} + diff --git a/src/main/java/com/ycwl/basic/enums/AppStatesCodeEnum.java b/src/main/java/com/ycwl/basic/enums/AppStatesCodeEnum.java new file mode 100644 index 0000000..1590eca --- /dev/null +++ b/src/main/java/com/ycwl/basic/enums/AppStatesCodeEnum.java @@ -0,0 +1,36 @@ +package com.ycwl.basic.enums; + +import lombok.Getter; +import lombok.Setter; + +/** + * @author songmingsong + * @since 2022-11-23 + * 状态码定义 + */ +public enum AppStatesCodeEnum { + + /** + * 通用操作码 + */ + USER_STATES_CODE(1), + UNKNOWN_MISTAKE(500, "未知错误"), + NO_STAFFINFO_ERROR(411, "员工信息不存在"), + ; + + @Getter + public int code; + + @Getter + @Setter + public String message; + + AppStatesCodeEnum(int code, String message) { + this.code = code; + this.message = message; + } + + AppStatesCodeEnum(Integer statesCode) { + this.code = statesCode; + } +} diff --git a/src/main/java/com/ycwl/basic/enums/BizCodeEnum.java b/src/main/java/com/ycwl/basic/enums/BizCodeEnum.java new file mode 100644 index 0000000..28e2c99 --- /dev/null +++ b/src/main/java/com/ycwl/basic/enums/BizCodeEnum.java @@ -0,0 +1,41 @@ +package com.ycwl.basic.enums; + +import lombok.Getter; +import lombok.Setter; + +/** + * @author wenshijia + * @date 2021年05月25日 22:29 + * 状态码定义约束,共6位数,前三位代表服务,后4位代表接口 + * 比如 商品服务210,购物车是220、用户服务230,403代表权限 + */ +public enum BizCodeEnum { + + /** + * 通用操作码 + */ + UNKNOWN_MISTAKE(500, "未知错误"), + + VERIFY_CODE_ERROR(600, "验证码错误"), + + NO_VERIFY_CODE_AUTH(700, "未进行授权"), + + TOLL_MACHINE_BIND_APPLICATION_SITE(1000, "当前收费机已经绑定了应用场所"), + TOLL_MACHINE_EXIST(1001, "当前收费机编号已经存在"), + APPLICATION_SITE_EXIST(1002, "当前应用场所已经存在"), + + CONFERENCE_DEVICE_EXIST(2001, "当前会议设设备已经存在"), + ; + + @Getter + public int code; + + @Getter + @Setter + public String message; + + BizCodeEnum(int code, String message) { + this.code = code; + this.message = message; + } +} diff --git a/src/main/java/com/ycwl/basic/exception/AppException.java b/src/main/java/com/ycwl/basic/exception/AppException.java new file mode 100644 index 0000000..ae77c6c --- /dev/null +++ b/src/main/java/com/ycwl/basic/exception/AppException.java @@ -0,0 +1,27 @@ +package com.ycwl.basic.exception; + +import com.ycwl.basic.enums.AppStatesCodeEnum; +import lombok.Data; + +/** + * @author songminsgong + * @since 2022-11-23 + */ +@Data +public class AppException extends RuntimeException { + + private Integer code; + private String msg; + + public AppException(Integer code, String message) { + super(message); + this.code = code; + this.msg = message; + } + + public AppException(AppStatesCodeEnum mobileCodeEnum) { + super(mobileCodeEnum.getMessage()); + this.code = mobileCodeEnum.getCode(); + this.msg = mobileCodeEnum.getMessage(); + } +} diff --git a/src/main/java/com/ycwl/basic/exception/BaseException.java b/src/main/java/com/ycwl/basic/exception/BaseException.java new file mode 100644 index 0000000..ea6473b --- /dev/null +++ b/src/main/java/com/ycwl/basic/exception/BaseException.java @@ -0,0 +1,38 @@ +package com.ycwl.basic.exception; + +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +/** + * @author yangchen + */ +@Getter +@Setter +@NoArgsConstructor +public class BaseException extends RuntimeException { + + private int status = 500; + + public BaseException(String message, int status) { + super(message); + this.status = status; + } + + public BaseException(String message) { + super(message); + } + + public BaseException(String message, Throwable cause) { + super(message, cause); + } + + public BaseException(Throwable cause) { + super(cause); + } + + public BaseException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) { + super(message, cause, enableSuppression, writableStackTrace); + } + +} diff --git a/src/main/java/com/ycwl/basic/exception/BizException.java b/src/main/java/com/ycwl/basic/exception/BizException.java new file mode 100644 index 0000000..0292a1e --- /dev/null +++ b/src/main/java/com/ycwl/basic/exception/BizException.java @@ -0,0 +1,27 @@ +package com.ycwl.basic.exception; + +import com.ycwl.basic.enums.BizCodeEnum; +import lombok.Data; + +/** + * @author wenshijia + * @date 2021年05月25日 22:41 + */ +@Data +public class BizException extends RuntimeException { + + private Integer code; + private String msg; + + public BizException(Integer code, String message) { + super(message); + this.code = code; + this.msg = message; + } + + public BizException(BizCodeEnum bizCodeEnum) { + super(bizCodeEnum.getMessage()); + this.code = bizCodeEnum.getCode(); + this.msg = bizCodeEnum.getMessage(); + } +} diff --git a/src/main/java/com/ycwl/basic/exception/CheckTokenException.java b/src/main/java/com/ycwl/basic/exception/CheckTokenException.java new file mode 100644 index 0000000..255e2be --- /dev/null +++ b/src/main/java/com/ycwl/basic/exception/CheckTokenException.java @@ -0,0 +1,13 @@ +package com.ycwl.basic.exception; + + +import com.ycwl.basic.utils.ApiConst; + +public class CheckTokenException extends BaseException { + + public CheckTokenException(String message) { + // 5003 + super(message, ApiConst.Code.CODE_NO_SESSION.code()); + } + +} diff --git a/src/main/java/com/ycwl/basic/exception/CustomExceptionHandle.java b/src/main/java/com/ycwl/basic/exception/CustomExceptionHandle.java new file mode 100644 index 0000000..47aac5a --- /dev/null +++ b/src/main/java/com/ycwl/basic/exception/CustomExceptionHandle.java @@ -0,0 +1,88 @@ +package com.ycwl.basic.exception; + +import com.ycwl.basic.enums.BizCodeEnum; +import com.ycwl.basic.utils.ApiResponse; +import org.apache.tomcat.util.http.fileupload.impl.SizeLimitExceededException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.http.HttpStatus; +import org.springframework.http.converter.HttpMessageNotReadableException; +import org.springframework.web.bind.annotation.ExceptionHandler; +import org.springframework.web.bind.annotation.RestControllerAdvice; + +import javax.servlet.http.HttpServletResponse; + +/** + * @date 2022年09月23日 10:19 + * 全局异常处理器 + */ +@RestControllerAdvice(basePackages = {"com.ycwl.smartPark"}) +public class CustomExceptionHandle { + + private static final Logger LOGGER = LoggerFactory.getLogger(CustomExceptionHandle.class); + + @ExceptionHandler(CheckTokenException.class) + public ApiResponse tokenExceptionHandler(HttpServletResponse response, BaseException ex) { + response.setStatus(HttpStatus.INTERNAL_SERVER_ERROR.value()); + return ApiResponse.buildResponse(200, ex.getMessage()); + } + + @ExceptionHandler(MissTokenException.class) + public ApiResponse tokenMissExceptionHandler(HttpServletResponse response, BaseException ex) { + response.setStatus(HttpStatus.INTERNAL_SERVER_ERROR.value()); + return ApiResponse.buildResponse(ex.getStatus(), ex.getMessage()); + } + + @ExceptionHandler(TokenExpireException.class) + public ApiResponse tokenExpireException(HttpServletResponse response, BaseException ex) { + response.setStatus(HttpStatus.OK.value()); + return ApiResponse.buildResponse(ex.getStatus(), ex.getMessage()); + } + + @ExceptionHandler(BaseException.class) + public ApiResponse baseExceptionHandler(HttpServletResponse response, BaseException ex) { + response.setStatus(HttpStatus.INTERNAL_SERVER_ERROR.value()); + return ApiResponse.buildResponse(ex.getStatus(), ex.getMessage()); + } + + /** + * 自定义异常统一处理类 + */ + @ExceptionHandler(value = BizException.class) + public ApiResponse handle(BizException bizException) { + return ApiResponse.buildResponse(bizException.getCode(), bizException.getMsg()); + } + + /** + * 异常统一返回处理 + */ + @ExceptionHandler(value = Exception.class) + public ApiResponse handle(Exception e) { + LOGGER.error("系统异常 -> {}", e.getMessage(), e); + return ApiResponse.buildResult(BizCodeEnum.UNKNOWN_MISTAKE); + } + + /** + * 移动端自定义异常统一处理类 + */ + @ExceptionHandler(value = AppException.class) + public ApiResponse handle(AppException appException) { + return ApiResponse.buildResponse(appException.getCode(), appException.getMsg()); + } + + /** + * 移动端自定义异常统一处理类 + */ + @ExceptionHandler(value = HttpMessageNotReadableException.class) + public ApiResponse handle(HttpMessageNotReadableException httpMessageNotReadableException) { + return ApiResponse.buildResponse(500, "请求参数格式错误"); + } + + /** + * 文件上传超长异常统一处理 + */ + @ExceptionHandler(value = SizeLimitExceededException.class) + public ApiResponse handle(SizeLimitExceededException sizeLimitExceededException) { + return ApiResponse.buildResponse(415, "文件过大,请重新上传"); + } +} diff --git a/src/main/java/com/ycwl/basic/exception/MissTokenException.java b/src/main/java/com/ycwl/basic/exception/MissTokenException.java new file mode 100644 index 0000000..bcd8721 --- /dev/null +++ b/src/main/java/com/ycwl/basic/exception/MissTokenException.java @@ -0,0 +1,13 @@ +package com.ycwl.basic.exception; + + +import com.ycwl.basic.utils.ApiConst; + +public class MissTokenException extends BaseException { + + public MissTokenException(String message) { + // 5003 + super(message, ApiConst.Code.CODE_MISS_TOKEN_ERROR.code()); + } + +} diff --git a/src/main/java/com/ycwl/basic/exception/PermissionException.java b/src/main/java/com/ycwl/basic/exception/PermissionException.java new file mode 100644 index 0000000..01385a1 --- /dev/null +++ b/src/main/java/com/ycwl/basic/exception/PermissionException.java @@ -0,0 +1,11 @@ +package com.ycwl.basic.exception; + + +import com.ycwl.basic.utils.ApiConst; + +public class PermissionException extends BaseException{ + public PermissionException(String message) { + // 5003 + super(message, ApiConst.Code.CODE_COMMON_ERROR.code()); + } +} diff --git a/src/main/java/com/ycwl/basic/exception/RoleStatusException.java b/src/main/java/com/ycwl/basic/exception/RoleStatusException.java new file mode 100644 index 0000000..381cb17 --- /dev/null +++ b/src/main/java/com/ycwl/basic/exception/RoleStatusException.java @@ -0,0 +1,11 @@ +package com.ycwl.basic.exception; + + +import com.ycwl.basic.utils.ApiConst; + +public class RoleStatusException extends BaseException{ + public RoleStatusException(String message) { + // 5003 + super(message, ApiConst.Code.CODE_COMMON_ERROR.code()); + } +} \ No newline at end of file diff --git a/src/main/java/com/ycwl/basic/exception/TokenExpireException.java b/src/main/java/com/ycwl/basic/exception/TokenExpireException.java new file mode 100644 index 0000000..694c4d0 --- /dev/null +++ b/src/main/java/com/ycwl/basic/exception/TokenExpireException.java @@ -0,0 +1,14 @@ +package com.ycwl.basic.exception; + +import com.ycwl.basic.utils.ApiConst; + +/** + * @author yangchen + */ +public class TokenExpireException extends BaseException { + public TokenExpireException(String message) { + // 5003 + super(message, ApiConst.Code.CODE_NO_SESSION.code()); + } + +} diff --git a/src/main/java/com/ycwl/basic/filter/XssFilter.java b/src/main/java/com/ycwl/basic/filter/XssFilter.java new file mode 100644 index 0000000..95cba91 --- /dev/null +++ b/src/main/java/com/ycwl/basic/filter/XssFilter.java @@ -0,0 +1,33 @@ +package com.ycwl.basic.filter; + +import com.ycwl.basic.xss.XSSHttpServletRequestWrapper; + +import javax.servlet.*; +import javax.servlet.http.HttpServletRequest; +import java.io.IOException; + +public class XssFilter implements Filter { + /** + * 初始化方法 + */ + @Override + public void init(FilterConfig filterConfig) throws ServletException { + } + /** + * 过滤方法 + */ + @Override + public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { + ServletRequest wrapper = null; + if (request instanceof HttpServletRequest) { + HttpServletRequest servletRequest = (HttpServletRequest) request; + wrapper = new XSSHttpServletRequestWrapper(servletRequest); + } + + if (null == wrapper) { + chain.doFilter(request, response); + } else { + chain.doFilter(wrapper, response); + } + } +} diff --git a/src/main/java/com/ycwl/basic/interceptor/AuthInterceptor.java b/src/main/java/com/ycwl/basic/interceptor/AuthInterceptor.java new file mode 100644 index 0000000..34a4daf --- /dev/null +++ b/src/main/java/com/ycwl/basic/interceptor/AuthInterceptor.java @@ -0,0 +1,184 @@ +package com.ycwl.basic.interceptor; + +import com.fasterxml.jackson.databind.ObjectMapper; +import com.ycwl.basic.annotation.IgnoreToken; +import com.ycwl.basic.constant.BaseContextHandler; +import com.ycwl.basic.constant.PermissionConstant; +import com.ycwl.basic.constant.RequestConstant; +import com.ycwl.basic.exception.CheckTokenException; +import com.ycwl.basic.exception.MissTokenException; +import com.ycwl.basic.exception.PermissionException; +import com.ycwl.basic.exception.TokenExpireException; +import com.ycwl.basic.model.jwt.JwtInfo; +import com.ycwl.basic.utils.JwtTokenUtil; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.redis.core.RedisTemplate; +import org.springframework.stereotype.Component; +import org.springframework.web.method.HandlerMethod; +import org.springframework.web.servlet.handler.HandlerInterceptorAdapter; + +import javax.servlet.http.Cookie; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.io.PrintWriter; +import java.time.LocalDateTime; +import java.time.ZoneId; +import java.util.List; + +@Slf4j +@Component +public class AuthInterceptor extends HandlerInterceptorAdapter { + + @Autowired + JwtTokenUtil jwtTokenUtil; + + @Autowired + RedisTemplate redisTemplate; + + @Override + public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { + if (!(handler instanceof HandlerMethod)) { + return super.preHandle(request, response, handler); + } + String requestURI = request.getRequestURI(); + + HandlerMethod handlerMethod = (HandlerMethod) handler; + // 获取类上面的注解 + IgnoreToken ignoreClassToken = handlerMethod.getBeanType().getAnnotation(IgnoreToken.class); + // 获取方法上的注解 + IgnoreToken ignoreMethodToken = handlerMethod.getMethodAnnotation(IgnoreToken.class); + if (ignoreClassToken != null || ignoreMethodToken != null) { + // 放行 + return super.preHandle(request, response, handler); + } + + // 放行白名单 + if (getWhite(request.getRequestURI())) { + return true; + } + + /* + 验证token + */ + // 获取 token + String token = getToken(request); + if (StringUtils.isEmpty(token)) { + log.error("==> 请求 header 缺少 Token [{}]", token); + throw new MissTokenException("请求头缺少token"); + } + + + // 解析 token & 验证 token 有效期 + JwtInfo jwtInfo; + try { + jwtInfo = jwtTokenUtil.parsingToken(token); + log.info("用户信息:" + jwtInfo.toString()); + LocalDateTime expireTime = jwtInfo.getExpireTime(); + if (LocalDateTime.now(ZoneId.systemDefault()).isAfter(expireTime)) { + throw new TokenExpireException("token过期"); + } + BaseContextHandler.setToken(token); + BaseContextHandler.setName(jwtInfo.getName()); + BaseContextHandler.setUserId(jwtInfo.getUserId()); + BaseContextHandler.setAccount(jwtInfo.getAccount()); + BaseContextHandler.setPhone(jwtInfo.getPhone()); + BaseContextHandler.setRoleId(jwtInfo.getRoleId()); + BaseContextHandler.setUserExpireTime(jwtInfo.getExpireTime()); + } catch (CheckTokenException e) { + throw new CheckTokenException("token无效"); + } + +// if (getBusinessWhite(requestURI)) { +// if (!getPermission(jwtInfo.getRoleId(), requestURI)) { +// throw new PermissionException("无权访问"); +// } +// } + + return true; + } + + public static void sendJsonMessage(HttpServletResponse response, Object obj) { + + ObjectMapper objectMapper = new ObjectMapper(); + response.setContentType("application/json; charset=utf-8"); + + try (PrintWriter writer = response.getWriter()) { + writer.print(objectMapper.writeValueAsString(obj)); + response.flushBuffer(); + } catch (IOException e) { + log.warn("响应json数据给前端异常 -> {}", e.getMessage(), e); + } + + } + + + /** + * 在请求完全结束后调用, 常用于清理资源等工作 + */ + @Override + public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { + BaseContextHandler.remove(); + super.afterCompletion(request, response, handler, ex); + } + + public String getToken(HttpServletRequest request) { + String token = request.getHeader("token"); + if (StringUtils.isEmpty(token)) { + if (request.getCookies() != null) { + for (Cookie cookie : request.getCookies()) { + if (("token").equals(cookie.getName())) { + token = cookie.getValue(); + } + } + } + } + return token; + } + + + //白名单swagger2 + private boolean getWhite(String path) { + return StringUtils.containsAny( + path, + "springfox", "swagger", "v2", + "webjars", "doc.html", "favicon.ico" + ); + } + + /** + * 业务接口白名单 + * + * @param + * @return + */ + private boolean getBusinessWhite(String path) { + if (path.contains(RequestConstant.UPDATE_PASSWORD)) { + return false; + } + return true; + } + + + private boolean getPermission(String roleId, String url) { + Object permissionUrl = redisTemplate.opsForValue().get(PermissionConstant.USER_PERMISSION_URL + roleId); + if (permissionUrl != null) { + List permissionUrlList = (List) permissionUrl; + String urlWithParameters = url.substring(url.lastIndexOf("/") + 1, url.length()); + boolean flag = StringUtils.isNumeric(urlWithParameters); + if (flag) { + url = url.substring(0, url.lastIndexOf("/")); + } + for (String str : permissionUrlList) { + if (str.equals(url)) { + return true; + } + + } + } + return false; + } + +} diff --git a/src/main/java/com/ycwl/basic/mapper/pc/AdminUserMapper.java b/src/main/java/com/ycwl/basic/mapper/pc/AdminUserMapper.java new file mode 100644 index 0000000..f49dbf0 --- /dev/null +++ b/src/main/java/com/ycwl/basic/mapper/pc/AdminUserMapper.java @@ -0,0 +1,28 @@ +package com.ycwl.basic.mapper.pc; + + + +import com.ycwl.basic.model.pc.adminUser.entity.LoginEntity; +import com.ycwl.basic.model.pc.adminUser.req.AddOrUpdateAdminUserReqVO; +import com.ycwl.basic.model.pc.adminUser.req.AdminUserListReqVO; +import com.ycwl.basic.model.pc.adminUser.req.ResetPasswordReqVO; +import com.ycwl.basic.model.pc.adminUser.req.UpdatePasswordReqVO; +import com.ycwl.basic.model.pc.adminUser.resp.AdminUserListRespVO; +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; + +import java.util.List; + +@Mapper +public interface AdminUserMapper { + List list(AdminUserListReqVO adminUserListReqVO); + int delete(String id); + int resetPassword(ResetPasswordReqVO resetPasswordReqVO); + int add(AddOrUpdateAdminUserReqVO addOrUpdateAdminUserReqVO); + int update(AddOrUpdateAdminUserReqVO addOrUpdateAdminUserReqVO); + LoginEntity login(@Param("account")String account); + + int updatePassword(UpdatePasswordReqVO updatePasswordReqVO); + + String getPasswordByAccount(@Param("id")String id); +} diff --git a/src/main/java/com/ycwl/basic/mapper/pc/MenuMapper.java b/src/main/java/com/ycwl/basic/mapper/pc/MenuMapper.java new file mode 100644 index 0000000..0a1f16d --- /dev/null +++ b/src/main/java/com/ycwl/basic/mapper/pc/MenuMapper.java @@ -0,0 +1,15 @@ +package com.ycwl.basic.mapper.pc; + +import com.ycwl.basic.model.pc.menu.MenuNode; +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; + +import java.util.List; + +@Mapper +public interface MenuMapper { + int delete(@Param("id")String id); + int addRoleMenu(@Param("id")String id,@Param("list") List list); + + ListgetListByType(@Param("type")Integer type); +} diff --git a/src/main/java/com/ycwl/basic/mapper/pc/RoleMapper.java b/src/main/java/com/ycwl/basic/mapper/pc/RoleMapper.java new file mode 100644 index 0000000..21e69b8 --- /dev/null +++ b/src/main/java/com/ycwl/basic/mapper/pc/RoleMapper.java @@ -0,0 +1,24 @@ +package com.ycwl.basic.mapper.pc; + +import com.ycwl.basic.model.pc.menu.MenuNode; +import com.ycwl.basic.model.pc.role.req.AddOrUpdateRoleReqVO; +import com.ycwl.basic.model.pc.role.req.RoleListReqVO; +import com.ycwl.basic.model.pc.role.resp.RoleListRespVO; +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; + +import java.util.List; + +@Mapper +public interface RoleMapper { + List list(RoleListReqVO roleListReqVO); + int delete(String id); + int add(AddOrUpdateRoleReqVO addOrUpdateRoleReqVO); + int update(AddOrUpdateRoleReqVO addOrUpdateRoleReqVO); + + List getMenuById(@Param("id")String id); + + int updateStatus(@Param("id")String id); + + int getRoleStatus(@Param("id")String id); +} diff --git a/src/main/java/com/ycwl/basic/model/common/BaseQueryParameterReq.java b/src/main/java/com/ycwl/basic/model/common/BaseQueryParameterReq.java new file mode 100644 index 0000000..5b3e391 --- /dev/null +++ b/src/main/java/com/ycwl/basic/model/common/BaseQueryParameterReq.java @@ -0,0 +1,19 @@ +package com.ycwl.basic.model.common; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +/** + * @date 2021年10月26日 14:09 + */ +@ApiModel(value = "公共查询参数实体类", description = "公共查询参数实体类") +@Data +public class BaseQueryParameterReq { + + @ApiModelProperty(value = "当前页数") + private Integer page = 1; + + @ApiModelProperty(value = "每页条数") + private Integer pageSize = 10; +} diff --git a/src/main/java/com/ycwl/basic/model/jwt/JwtInfo.java b/src/main/java/com/ycwl/basic/model/jwt/JwtInfo.java new file mode 100644 index 0000000..f3adc48 --- /dev/null +++ b/src/main/java/com/ycwl/basic/model/jwt/JwtInfo.java @@ -0,0 +1,55 @@ +package com.ycwl.basic.model.jwt; + +import com.fasterxml.jackson.annotation.JsonFormat; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; +import lombok.ToString; + +import java.io.Serializable; +import java.time.LocalDateTime; + +/** + * @author yangchen + */ +@Data +@NoArgsConstructor +@AllArgsConstructor +@ToString +public class JwtInfo implements Serializable { + + private static final long serialVersionUID = 5452605590172369563L; + + /** + * 用户名称 + */ + private String name; + + /** + * 用户ID + */ + private String userId; + + /** + * 角色ID + */ + private String roleId; + + /** + * 用户账号 + */ + private String account; + private String phone; + + + /** + * 生成 token 的时间 + *

+ * 会加一个 expire 作为 token 的有效期 + */ + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") + private LocalDateTime expireTime; + + + +} diff --git a/src/main/java/com/ycwl/basic/model/pc/adminUser/entity/GetTokenReqVO.java b/src/main/java/com/ycwl/basic/model/pc/adminUser/entity/GetTokenReqVO.java new file mode 100644 index 0000000..032bd04 --- /dev/null +++ b/src/main/java/com/ycwl/basic/model/pc/adminUser/entity/GetTokenReqVO.java @@ -0,0 +1,9 @@ +package com.ycwl.basic.model.pc.adminUser.entity; + +import lombok.Data; + +@Data +public class GetTokenReqVO { + private String account; + private String password; +} diff --git a/src/main/java/com/ycwl/basic/model/pc/adminUser/entity/LoginEntity.java b/src/main/java/com/ycwl/basic/model/pc/adminUser/entity/LoginEntity.java new file mode 100644 index 0000000..41b4281 --- /dev/null +++ b/src/main/java/com/ycwl/basic/model/pc/adminUser/entity/LoginEntity.java @@ -0,0 +1,13 @@ +package com.ycwl.basic.model.pc.adminUser.entity; + +import lombok.Data; + +@Data +public class LoginEntity { + private String staffId; + private String staffName; + private String account; + private String password; + private String roleId; + private String typeName; +} diff --git a/src/main/java/com/ycwl/basic/model/pc/adminUser/req/AddOrUpdateAdminUserReqVO.java b/src/main/java/com/ycwl/basic/model/pc/adminUser/req/AddOrUpdateAdminUserReqVO.java new file mode 100644 index 0000000..46afeb0 --- /dev/null +++ b/src/main/java/com/ycwl/basic/model/pc/adminUser/req/AddOrUpdateAdminUserReqVO.java @@ -0,0 +1,19 @@ +package com.ycwl.basic.model.pc.adminUser.req; + + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +@Data +@ApiModel(value = "新增或更新后台管理人员VO") +public class AddOrUpdateAdminUserReqVO { + @ApiModelProperty(value = "id,有为更新,没有为新增") + private String id; + @ApiModelProperty(value = "角色ID") + private String roleId; + @ApiModelProperty(value = "账号") + private String account; + @ApiModelProperty(value = "密码") + private String password; +} diff --git a/src/main/java/com/ycwl/basic/model/pc/adminUser/req/AdminUserListReqVO.java b/src/main/java/com/ycwl/basic/model/pc/adminUser/req/AdminUserListReqVO.java new file mode 100644 index 0000000..135b85d --- /dev/null +++ b/src/main/java/com/ycwl/basic/model/pc/adminUser/req/AdminUserListReqVO.java @@ -0,0 +1,23 @@ +package com.ycwl.basic.model.pc.adminUser.req; + +import com.ycwl.basic.model.common.BaseQueryParameterReq; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +@Data +@ApiModel(value = "后台管理人员请求VO") +public class AdminUserListReqVO extends BaseQueryParameterReq { + @ApiModelProperty(value = "姓名") + private String name; + @ApiModelProperty(value = "账号") + private String phone; + @ApiModelProperty(value = "工号") + private String jobNo; + @ApiModelProperty(value = "组织ID") + private String companyId; + //@ApiModelProperty(value = "部门ID") + //private String departmentId; + @ApiModelProperty(value = "角色ID") + private String roleId; +} diff --git a/src/main/java/com/ycwl/basic/model/pc/adminUser/req/LoginReqVO.java b/src/main/java/com/ycwl/basic/model/pc/adminUser/req/LoginReqVO.java new file mode 100644 index 0000000..a4cd5bb --- /dev/null +++ b/src/main/java/com/ycwl/basic/model/pc/adminUser/req/LoginReqVO.java @@ -0,0 +1,14 @@ +package com.ycwl.basic.model.pc.adminUser.req; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +@Data +@ApiModel(value = "登录请求VO") +public class LoginReqVO { + @ApiModelProperty(value = "账号") + private String account; + @ApiModelProperty(value = "密码") + private String password; +} diff --git a/src/main/java/com/ycwl/basic/model/pc/adminUser/req/ResetPasswordReqVO.java b/src/main/java/com/ycwl/basic/model/pc/adminUser/req/ResetPasswordReqVO.java new file mode 100644 index 0000000..1975424 --- /dev/null +++ b/src/main/java/com/ycwl/basic/model/pc/adminUser/req/ResetPasswordReqVO.java @@ -0,0 +1,14 @@ +package com.ycwl.basic.model.pc.adminUser.req; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +@Data +@ApiModel(value = "重置密码请求VO") +public class ResetPasswordReqVO { + @ApiModelProperty(value = "id") + private String id; + @ApiModelProperty(value = "密码") + private String password; +} diff --git a/src/main/java/com/ycwl/basic/model/pc/adminUser/req/UpdatePasswordReqVO.java b/src/main/java/com/ycwl/basic/model/pc/adminUser/req/UpdatePasswordReqVO.java new file mode 100644 index 0000000..6c85894 --- /dev/null +++ b/src/main/java/com/ycwl/basic/model/pc/adminUser/req/UpdatePasswordReqVO.java @@ -0,0 +1,16 @@ +package com.ycwl.basic.model.pc.adminUser.req; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +@Data +@ApiModel(value = "") +public class UpdatePasswordReqVO { + @ApiModelProperty(value = "id",hidden = true) + private String id; + @ApiModelProperty(value = "密码") + private String pwd; + @ApiModelProperty(value = "新密码") + private String newPwd; +} diff --git a/src/main/java/com/ycwl/basic/model/pc/adminUser/resp/AdminUserListRespVO.java b/src/main/java/com/ycwl/basic/model/pc/adminUser/resp/AdminUserListRespVO.java new file mode 100644 index 0000000..a75cc5d --- /dev/null +++ b/src/main/java/com/ycwl/basic/model/pc/adminUser/resp/AdminUserListRespVO.java @@ -0,0 +1,28 @@ +package com.ycwl.basic.model.pc.adminUser.resp; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +@Data +@ApiModel(value = "后台管理人员返回列表VO") +public class AdminUserListRespVO { + @ApiModelProperty(value = "id") + private String id; + @ApiModelProperty(value = "员工ID") + private String staffId; + @ApiModelProperty(value = "员工姓名") + private String staffName; + @ApiModelProperty(value = "手机号") + private String phone; + @ApiModelProperty(value = "工号") + private String jobNo; + @ApiModelProperty(value = "组织") + private String companyName; + @ApiModelProperty(value = "组织ID") + private String companyId; + @ApiModelProperty(value = "角色") + private String roleName; + @ApiModelProperty(value = "角色ID") + private String roleId; +} diff --git a/src/main/java/com/ycwl/basic/model/pc/adminUser/resp/LoginRespVO.java b/src/main/java/com/ycwl/basic/model/pc/adminUser/resp/LoginRespVO.java new file mode 100644 index 0000000..3783a47 --- /dev/null +++ b/src/main/java/com/ycwl/basic/model/pc/adminUser/resp/LoginRespVO.java @@ -0,0 +1,22 @@ +package com.ycwl.basic.model.pc.adminUser.resp; + + +import com.ycwl.basic.model.pc.menu.MenuNode; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +import java.util.List; + +@Data +@ApiModel(value = "登录返回VO") +public class LoginRespVO { + @ApiModelProperty(value = "token") + private String token; + @ApiModelProperty(value = "用户名") + private String name; + @ApiModelProperty(value = "角色名") + private String typeName; + @ApiModelProperty(value = "菜单列表") + private List menuNodeList; +} diff --git a/src/main/java/com/ycwl/basic/model/pc/adminUser/resp/StaffSimpleInfoRespVO.java b/src/main/java/com/ycwl/basic/model/pc/adminUser/resp/StaffSimpleInfoRespVO.java new file mode 100644 index 0000000..e54fced --- /dev/null +++ b/src/main/java/com/ycwl/basic/model/pc/adminUser/resp/StaffSimpleInfoRespVO.java @@ -0,0 +1,16 @@ +package com.ycwl.basic.model.pc.adminUser.resp; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +@Data +@ApiModel(value = "员工信息返回VO") +public class StaffSimpleInfoRespVO { + @ApiModelProperty(value = "id") + private String id; + @ApiModelProperty(value = "名字") + private String name; + @ApiModelProperty(value = "工号") + private String jobNo; +} diff --git a/src/main/java/com/ycwl/basic/model/pc/menu/MenuNode.java b/src/main/java/com/ycwl/basic/model/pc/menu/MenuNode.java new file mode 100644 index 0000000..29f2902 --- /dev/null +++ b/src/main/java/com/ycwl/basic/model/pc/menu/MenuNode.java @@ -0,0 +1,35 @@ +package com.ycwl.basic.model.pc.menu; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +import java.util.List; + +/** + * @date 2022年10月20日 10:59 + * 菜单数node类 + */ +@Data +@ApiModel(value = "菜单数node类", description = "菜单数node类") +public class MenuNode { + + @ApiModelProperty(value = "当前节点ID") + private String id; + + @ApiModelProperty(value = "父节点ID") + private String parentId; + + @ApiModelProperty(value = "菜单名") + private String name; + + @ApiModelProperty(value = "路由") + private String target; + + @ApiModelProperty(value = "排序") + private Integer sort; + + @ApiModelProperty(value = "子节点数据") + private List childrenList; + +} diff --git a/src/main/java/com/ycwl/basic/model/pc/role/req/AddOrUpdateRoleReqVO.java b/src/main/java/com/ycwl/basic/model/pc/role/req/AddOrUpdateRoleReqVO.java new file mode 100644 index 0000000..3f17833 --- /dev/null +++ b/src/main/java/com/ycwl/basic/model/pc/role/req/AddOrUpdateRoleReqVO.java @@ -0,0 +1,19 @@ +package com.ycwl.basic.model.pc.role.req; + +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +import java.util.List; + +@Data +public class AddOrUpdateRoleReqVO { + @ApiModelProperty(value = "id,更新的时候传") + private String id; + @ApiModelProperty(value = "角色名称") + private String name; + @ApiModelProperty(value = "0系统角色 1业务角色") + private Integer type; + @ApiModelProperty(value = "菜单ID列表") + private List menuIdList; + +} diff --git a/src/main/java/com/ycwl/basic/model/pc/role/req/RoleListReqVO.java b/src/main/java/com/ycwl/basic/model/pc/role/req/RoleListReqVO.java new file mode 100644 index 0000000..97362c2 --- /dev/null +++ b/src/main/java/com/ycwl/basic/model/pc/role/req/RoleListReqVO.java @@ -0,0 +1,15 @@ +package com.ycwl.basic.model.pc.role.req; + +import com.ycwl.basic.model.common.BaseQueryParameterReq; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +@Data +@ApiModel(value = "角色请求列表VO") +public class RoleListReqVO extends BaseQueryParameterReq { + @ApiModelProperty(value = "名字") + private String name; + @ApiModelProperty(value = "0系统角色 1业务角色") + private Integer type; +} diff --git a/src/main/java/com/ycwl/basic/model/pc/role/resp/RoleListRespVO.java b/src/main/java/com/ycwl/basic/model/pc/role/resp/RoleListRespVO.java new file mode 100644 index 0000000..9ad279f --- /dev/null +++ b/src/main/java/com/ycwl/basic/model/pc/role/resp/RoleListRespVO.java @@ -0,0 +1,20 @@ +package com.ycwl.basic.model.pc.role.resp; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +import java.util.Date; + +@Data +@ApiModel(value = "角色列表返回数据VO") +public class RoleListRespVO { + @ApiModelProperty(value = "id") + private String id; + @ApiModelProperty(value = "名字") + private String name; + @ApiModelProperty(value = "0正常 1关闭") + private Integer status; + @ApiModelProperty(value = "创建时间") + private Date createTime; +} diff --git a/src/main/java/com/ycwl/basic/model/snowFlake/UniqueId.java b/src/main/java/com/ycwl/basic/model/snowFlake/UniqueId.java new file mode 100644 index 0000000..c11c43f --- /dev/null +++ b/src/main/java/com/ycwl/basic/model/snowFlake/UniqueId.java @@ -0,0 +1,49 @@ +package com.ycwl.basic.model.snowFlake; +import io.swagger.annotations.ApiModelProperty; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.io.Serializable; + +/** + * @author Created by liuhongguang on 2019年10月27日 + * @Description + */ +@NoArgsConstructor +@AllArgsConstructor +@Data +public class UniqueId implements Serializable { + + /** + * 0 + 41 + 5 + 5 + 12 + * 固定 + 时间戳 + 工作机器ID + 数据中心ID + 序列号 + */ + + private static final long serialVersionUID = 8632670752020316524L; + + /** + * 工作机器ID、数据中心ID、序列号、上次生成ID的时间戳 + */ + @ApiModelProperty(value = "机器ID") + private long machineId; + + @ApiModelProperty(value = "数据中心ID") + private long datacenterId; + + @ApiModelProperty(value = "毫秒内序列") + private long sequence; + + @ApiModelProperty(value = "时间戳") + private long timestamp; + + @Override + public String toString() { + return "UniqueIdRespVo{" + + "服务机器ID=" + machineId + + ", 数据中心ID=" + datacenterId + + ", 毫秒内的序列=" + sequence + + ", 生成时间与预设时间戳间隔=" + timestamp + + '}'; + } +} diff --git a/src/main/java/com/ycwl/basic/model/snowFlake/UniqueIdMetaData.java b/src/main/java/com/ycwl/basic/model/snowFlake/UniqueIdMetaData.java new file mode 100644 index 0000000..83d0f4e --- /dev/null +++ b/src/main/java/com/ycwl/basic/model/snowFlake/UniqueIdMetaData.java @@ -0,0 +1,85 @@ +package com.ycwl.basic.model.snowFlake; + +import io.swagger.annotations.ApiModelProperty; + +public class UniqueIdMetaData { + /** + * 取当前系统启动时间为参考起始时间, + * 取1995-04-01为参考日 + */ +// public static final long START_TIME = LocalDateTime.now().toInstant(ZoneOffset.UTC).toEpochMilli(); + public static final long START_TIME = 796665600000L; + + /** + * 机器ID所占位数 + */ + @ApiModelProperty(value = "机器位数") + public static final long MACHINE_ID_BITS = 5L; + + /** + * 机器ID最大值31,0-31 + */ + @ApiModelProperty(value = "机器ID最大") + public static final long MAX_MACHINE_ID = ~(-1L << MACHINE_ID_BITS); + + /** + * 数据中心ID所占位数 + */ + @ApiModelProperty(value = "数据中心ID所占位数") + public static final long DATACENTER_ID_BITS = 5L; + + /** + * 数据中心ID最大值31,0-31 + */ + @ApiModelProperty(value = "数据中心ID最大值") + public static final long MAX_DATACENTER_ID = ~(-1L << MACHINE_ID_BITS); + + /** + * Sequence所占位数 + */ + @ApiModelProperty(value = "序列所占位数") + public static final long SEQUENCE_BITS = 12L; + + /** + * 机器ID偏移量12 + */ + @ApiModelProperty(value = "机器ID偏移量") + public static final long MACHINE_SHIFT_BITS = SEQUENCE_BITS; + + /** + * 数据中心ID偏移量12+5=17 + */ + @ApiModelProperty(value = "数据中心ID偏移量") + public static final long DATACENTER_SHIFT_BITS = SEQUENCE_BITS + MACHINE_ID_BITS; + + /** + * 时间戳的偏移量12+5+5=22 + */ + @ApiModelProperty(value = "时间戳偏移量") + public static final long TIMESTAMP_LEFT_SHIFT_BITS = SEQUENCE_BITS + MACHINE_ID_BITS + DATACENTER_ID_BITS; + + /** + * Sequence掩码4095 + */ + @ApiModelProperty(value = "序列掩码") + public static final long SEQUENCE_MASK = ~(-1L << SEQUENCE_BITS); + + /** + * 机器ID掩码1023 + */ + @ApiModelProperty(value = "机器ID掩码") + public static final long MACHINE_MASK = ~(-1L << MACHINE_ID_BITS); + + /** + * 数据中心掩码1023 + */ + @ApiModelProperty(value = "数据中心掩码") + public static final long DATACENTER_MASK = ~(-1L << MACHINE_ID_BITS); + + /** + * 时间戳掩码2的41次方减1 + */ + @ApiModelProperty(value = "时间戳掩码") + public static final long TIMESTAMP_MASK = ~(-1L << 41L); + +} diff --git a/src/main/java/com/ycwl/basic/service/impl/pc/AdminUserServiceImpl.java b/src/main/java/com/ycwl/basic/service/impl/pc/AdminUserServiceImpl.java new file mode 100644 index 0000000..a304ee7 --- /dev/null +++ b/src/main/java/com/ycwl/basic/service/impl/pc/AdminUserServiceImpl.java @@ -0,0 +1,157 @@ +package com.ycwl.basic.service.impl.pc; + +import cn.hutool.crypto.digest.DigestUtil; +import com.github.pagehelper.PageHelper; +import com.github.pagehelper.PageInfo; + +import com.ycwl.basic.constant.BaseContextHandler; +import com.ycwl.basic.exception.RoleStatusException; +import com.ycwl.basic.mapper.pc.AdminUserMapper; +import com.ycwl.basic.mapper.pc.RoleMapper; +import com.ycwl.basic.model.jwt.JwtInfo; +import com.ycwl.basic.model.pc.adminUser.entity.LoginEntity; +import com.ycwl.basic.model.pc.adminUser.req.*; +import com.ycwl.basic.model.pc.adminUser.resp.AdminUserListRespVO; +import com.ycwl.basic.model.pc.adminUser.resp.LoginRespVO; +import com.ycwl.basic.model.pc.menu.MenuNode; +import com.ycwl.basic.service.pc.AdminUserService; +import com.ycwl.basic.utils.ApiResponse; +import com.ycwl.basic.utils.JwtTokenUtil; +import com.ycwl.basic.utils.SnowFlakeUtil; +import org.apache.commons.lang3.StringUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.redis.core.RedisTemplate; +import org.springframework.stereotype.Service; + +import java.util.ArrayList; +import java.util.List; + +import static com.ycwl.basic.constant.PermissionConstant.ROLE_STATUS; + + +@Service +public class AdminUserServiceImpl implements AdminUserService { + + @Autowired + AdminUserMapper adminUserMapper; + + + @Autowired + RoleMapper roleMapper; + + @Autowired + JwtTokenUtil jwtTokenUtil; + + @Autowired + RedisTemplate redisTemplate; + + + @Override + public ApiResponse list(AdminUserListReqVO adminUserListReqVO) { + PageHelper.startPage(adminUserListReqVO.getPage(), adminUserListReqVO.getPageSize()); + List list = adminUserMapper.list(adminUserListReqVO); + PageInfo pageInfo = new PageInfo(list); + return ApiResponse.buildSuccessResponse(pageInfo); + } + + @Override + public ApiResponse addOrUpdate(AddOrUpdateAdminUserReqVO addOrUpdateAdminUserReqVO) { + addOrUpdateAdminUserReqVO.setPassword(DigestUtil.md5Hex(addOrUpdateAdminUserReqVO.getPassword())); + String id = addOrUpdateAdminUserReqVO.getId(); + if (StringUtils.isBlank(id)) { + addOrUpdateAdminUserReqVO.setId(SnowFlakeUtil.getId()); + String password = addOrUpdateAdminUserReqVO.getPassword(); + addOrUpdateAdminUserReqVO.setPassword(password); + int add = adminUserMapper.add(addOrUpdateAdminUserReqVO); + if (add > 0) { + return ApiResponse.buildSuccessResponse(null); + } + } else { + int update = adminUserMapper.update(addOrUpdateAdminUserReqVO); + if (update > 0) { + return ApiResponse.buildSuccessResponse(null); + } + } + return ApiResponse.buildCommonErrorResponse("失败"); + } + + @Override + public ApiResponse delete(String id) { + if (adminUserMapper.delete(id) > 0) { + return ApiResponse.buildSuccessResponse(null); + } + return ApiResponse.buildCommonErrorResponse("失败"); + } + + @Override + public ApiResponse resetPassword(ResetPasswordReqVO resetPasswordReqVO) { + resetPasswordReqVO.setPassword(DigestUtil.md5Hex(resetPasswordReqVO.getPassword())); + if (adminUserMapper.resetPassword(resetPasswordReqVO) > 0) { + return ApiResponse.buildSuccessResponse(null); + } + return ApiResponse.buildCommonErrorResponse("失败"); + } + + + + @Override + public ApiResponse login(LoginReqVO loginReqVO) throws Exception { + String account = loginReqVO.getAccount(); + String password = loginReqVO.getPassword(); + LoginEntity login = adminUserMapper.login(account); + if (login == null) { + return ApiResponse.buildCommonErrorResponse("账号不存在或密码错误"); + } + if (!login.getPassword().equals(DigestUtil.md5Hex(password))) { + return ApiResponse.buildCommonErrorResponse("账号不存在或密码错误"); + } + String roleId = login.getRoleId(); + + Object roleObject = redisTemplate.opsForValue().get(ROLE_STATUS + roleId); + + if (roleObject != null) { + if (roleObject.toString().equals("1")) { + throw new RoleStatusException("该角色下的账号已被封禁,请联系管理员"); + } + } + List menuById = roleMapper.getMenuById(roleId); + List MenuList = new ArrayList<>(); + for (MenuNode item : menuById) { + if ("-1".equals(item.getParentId())) { + MenuList.add(item); + } + for (MenuNode item2 : menuById) { + if (item2.getParentId().equals(item.getId())) { + if (item.getChildrenList() == null) { + item.setChildrenList(new ArrayList<>()); + } + item.getChildrenList().add(item2); + } + } + } + LoginRespVO loginRespVO = new LoginRespVO(); + String token = jwtTokenUtil.generateToken(new JwtInfo(login.getStaffName(), login.getStaffId(), roleId, login.getAccount(), login.getAccount(), null)); + loginRespVO.setToken(token); + loginRespVO.setName(login.getStaffName()); + loginRespVO.setTypeName(login.getTypeName()); + loginRespVO.setMenuNodeList(MenuList); + return ApiResponse.buildSuccessResponse(loginRespVO); + } + + @Override + public ApiResponse updatePassword(UpdatePasswordReqVO updatePasswordReqVO) { + String userId = BaseContextHandler.getUserId(); + updatePasswordReqVO.setId(userId); + String passwordByAccount = adminUserMapper.getPasswordByAccount(updatePasswordReqVO.getId()); + String pwd = DigestUtil.md5Hex(updatePasswordReqVO.getPwd()); + if (!passwordByAccount.equals(pwd)) { + return ApiResponse.buildCommonErrorResponse("密码错误!修改失败"); + } + String newPwd = DigestUtil.md5Hex(updatePasswordReqVO.getNewPwd()); + updatePasswordReqVO.setNewPwd(newPwd); + if (adminUserMapper.updatePassword(updatePasswordReqVO) > 0) { + return ApiResponse.buildSuccessResponse(null); + } + return ApiResponse.buildCommonErrorResponse("失败"); + } +} diff --git a/src/main/java/com/ycwl/basic/service/impl/pc/RoleServiceImpl.java b/src/main/java/com/ycwl/basic/service/impl/pc/RoleServiceImpl.java new file mode 100644 index 0000000..f9f1809 --- /dev/null +++ b/src/main/java/com/ycwl/basic/service/impl/pc/RoleServiceImpl.java @@ -0,0 +1,131 @@ +package com.ycwl.basic.service.impl.pc; + +import com.github.pagehelper.PageHelper; +import com.github.pagehelper.PageInfo; +import com.ycwl.basic.mapper.pc.MenuMapper; +import com.ycwl.basic.mapper.pc.RoleMapper; +import com.ycwl.basic.model.pc.menu.MenuNode; +import com.ycwl.basic.model.pc.role.req.AddOrUpdateRoleReqVO; +import com.ycwl.basic.model.pc.role.req.RoleListReqVO; +import com.ycwl.basic.model.pc.role.resp.RoleListRespVO; +import com.ycwl.basic.service.pc.RoleService; +import com.ycwl.basic.utils.ApiResponse; +import com.ycwl.basic.utils.SnowFlakeUtil; +import org.apache.commons.lang3.StringUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.redis.core.RedisTemplate; +import org.springframework.stereotype.Service; + +import java.util.ArrayList; +import java.util.List; + +import static com.ycwl.basic.constant.PermissionConstant.ROLE_STATUS; + + +@Service +public class RoleServiceImpl implements RoleService { + + @Autowired + RoleMapper roleMapper; + + @Autowired + MenuMapper menuMapper; + + @Autowired + RedisTemplate redisTemplate; + + @Override + public ApiResponse list(RoleListReqVO roleListReqVO) { + PageHelper.startPage(roleListReqVO.getPage(),roleListReqVO.getPageSize()); + if(roleListReqVO.getType()==null){ + roleListReqVO.setType(0); + } + List list = roleMapper.list(roleListReqVO); + PageInfo pageInfo = new PageInfo(list); + return ApiResponse.buildSuccessResponse(pageInfo); + } + + @Override + public ApiResponse addOrUpdate(AddOrUpdateRoleReqVO addOrUpdateRoleReqVO) { + String id = addOrUpdateRoleReqVO.getId(); + if(StringUtils.isBlank(id)){ + String roleId = SnowFlakeUtil.getId(); + addOrUpdateRoleReqVO.setId(roleId); + if(roleMapper.add(addOrUpdateRoleReqVO)>0){ + menuMapper.addRoleMenu(roleId,addOrUpdateRoleReqVO.getMenuIdList()); + return ApiResponse.buildSuccessResponse(null); + } + }else { + if(roleMapper.update(addOrUpdateRoleReqVO)>0){ + menuMapper.delete(addOrUpdateRoleReqVO.getId()); + if(addOrUpdateRoleReqVO.getMenuIdList()!=null&addOrUpdateRoleReqVO.getMenuIdList().size()>0){ + menuMapper.addRoleMenu(addOrUpdateRoleReqVO.getId(),addOrUpdateRoleReqVO.getMenuIdList()); + } + return ApiResponse.buildSuccessResponse(null); + } + } + return ApiResponse.buildCommonErrorResponse("失败"); + } + + @Override + public ApiResponse delete(String id) { + if(roleMapper.delete(id)>0){ + menuMapper.delete(id); + return ApiResponse.buildSuccessResponse(null); + } + return ApiResponse.buildCommonErrorResponse("失败"); + } + + @Override + public ApiResponse updateReturnMenu(String id) { + List menuById = roleMapper.getMenuById(id); + List MenuList = new ArrayList<>(); + for (MenuNode item :menuById) { + if ("-1".equals(item.getParentId())) { + MenuList.add(item); + } + for (MenuNode item2 : menuById) { + if (item2.getParentId().equals(item.getId())) { + if (item.getChildrenList() == null) { + item.setChildrenList(new ArrayList<>()); + } + item.getChildrenList().add(item2); + } + } + } + return ApiResponse.buildSuccessResponse(MenuList); + } + + @Override + public ApiResponse menu(Integer type) { + if(type==null){ + type=1; + } + List listByType = menuMapper.getListByType(type); + List MenuList = new ArrayList<>(); + for (MenuNode item :listByType) { + if ("-1".equals(item.getParentId())) { + MenuList.add(item); + } + for (MenuNode item2 : listByType) { + if (item2.getParentId().equals(item.getId())) { + if (item.getChildrenList() == null) { + item.setChildrenList(new ArrayList<>()); + } + item.getChildrenList().add(item2); + } + } + } + return ApiResponse.buildSuccessResponse(MenuList); + } + + @Override + public ApiResponse updateStatus(String id) { + if(roleMapper.updateStatus(id)>0){ + redisTemplate.opsForValue().set(ROLE_STATUS+id,roleMapper.getRoleStatus(id)); + return ApiResponse.buildSuccessResponse(null); + } + return ApiResponse.buildCommonErrorResponse("失败"); + } + +} diff --git a/src/main/java/com/ycwl/basic/service/pc/AdminUserService.java b/src/main/java/com/ycwl/basic/service/pc/AdminUserService.java new file mode 100644 index 0000000..fb3d2d8 --- /dev/null +++ b/src/main/java/com/ycwl/basic/service/pc/AdminUserService.java @@ -0,0 +1,14 @@ +package com.ycwl.basic.service.pc; + + +import com.ycwl.basic.model.pc.adminUser.req.*; +import com.ycwl.basic.utils.ApiResponse; + +public interface AdminUserService { + ApiResponse list(AdminUserListReqVO adminUserListReqVO); + ApiResponse addOrUpdate(AddOrUpdateAdminUserReqVO addOrUpdateAdminUserReqVO); + ApiResponse delete(String id); + ApiResponse resetPassword(ResetPasswordReqVO resetPasswordReqVO); + ApiResponse login(LoginReqVO loginReqVO) throws Exception; + ApiResponse updatePassword(UpdatePasswordReqVO updatePasswordReqVO); +} diff --git a/src/main/java/com/ycwl/basic/service/pc/MerchantService.java b/src/main/java/com/ycwl/basic/service/pc/MerchantService.java new file mode 100644 index 0000000..f369605 --- /dev/null +++ b/src/main/java/com/ycwl/basic/service/pc/MerchantService.java @@ -0,0 +1,4 @@ +package com.ycwl.basic.service.pc; + +public interface MerchantService { +} diff --git a/src/main/java/com/ycwl/basic/service/pc/RoleService.java b/src/main/java/com/ycwl/basic/service/pc/RoleService.java new file mode 100644 index 0000000..e4474a4 --- /dev/null +++ b/src/main/java/com/ycwl/basic/service/pc/RoleService.java @@ -0,0 +1,15 @@ +package com.ycwl.basic.service.pc; + +import com.ycwl.basic.model.pc.role.req.AddOrUpdateRoleReqVO; +import com.ycwl.basic.model.pc.role.req.RoleListReqVO; +import com.ycwl.basic.utils.ApiResponse; + +public interface RoleService { + ApiResponse list(RoleListReqVO roleListReqVO); + ApiResponse addOrUpdate(AddOrUpdateRoleReqVO addOrUpdateRoleReqVO); + ApiResponse delete(String id); + ApiResponse updateReturnMenu(String id); + ApiResponse menu(Integer type); + ApiResponse updateStatus(String id); + +} diff --git a/src/main/java/com/ycwl/basic/task/GetSpaceChinaMobileLiveSteamJob.java b/src/main/java/com/ycwl/basic/task/GetSpaceChinaMobileLiveSteamJob.java new file mode 100644 index 0000000..4740bff --- /dev/null +++ b/src/main/java/com/ycwl/basic/task/GetSpaceChinaMobileLiveSteamJob.java @@ -0,0 +1,176 @@ +//package com.ycwl.basic.task; +// +// +//import cn.hutool.core.util.StrUtil; +//import com.alibaba.fastjson.JSONArray; +//import com.alibaba.fastjson.JSONObject; +//import com.tu.common.redis.RedisUtils; +//import com.tu.common.utils.ChinaMobileUtil; +//import com.tu.common.utils.DateUtils; +//import com.tu.dao.TuSpaceManageDao; +//import com.tu.dto.GetLiveSteamUrlDTO; +//import lombok.extern.slf4j.Slf4j; +//import org.springframework.beans.factory.annotation.Autowired; +//import org.springframework.beans.factory.annotation.Value; +//import org.springframework.core.annotation.Order; +//import org.springframework.scheduling.annotation.EnableScheduling; +//import org.springframework.scheduling.annotation.Scheduled; +//import org.springframework.stereotype.Component; +// +//import javax.annotation.PostConstruct; +//import java.util.*; +// +//import static com.tu.common.utils.ChinaMobileUtil.getTokenBySend; +//import static com.tu.common.utils.ChinaMobileUtil.sendPost; +// +//@Slf4j +//@Component +//@EnableScheduling +//public class GetSpaceChinaMobileLiveSteamJob { +// +// @Autowired +// TuSpaceManageDao tuSpaceManageDao; +// @Autowired +// RedisUtils redisUtils; +// @Autowired +// ChinaMobileUtil chinaMobileUtil; +// @Value("${spring.profiles.active}") +// private String springProfile; +// +// //public static String token = null; +// private static Queue failMsgSubQueue = new LinkedList(); // 保存订阅失败的数据 +// +// /** +// * 订阅消息 +// */ +// @PostConstruct +// public void msgSubscription() { +// new Thread(() -> { +// if (springProfile.equals("prod")) { +// List liveSteamUrl = tuSpaceManageDao.getLiveSteamUrl(null, 2); +// List deviceIdList = new ArrayList<>(); +// for (GetLiveSteamUrlDTO item : liveSteamUrl) { +// String deviceSn = item.getDeviceSn(); +// if (deviceSn != null && !deviceSn.equals("")) { +// deviceIdList.add(deviceSn); +// +// if (deviceIdList.size() == 29) { +// // 30条数据为一组,分开订阅 +// String msg = doMsgSubscription(deviceIdList); +// if (StrUtil.isBlank(msg)) { +// // 消息订阅失败,过一会儿再试试 +// List failDeviceIdList = new ArrayList<>(); +// Collections.copy(failDeviceIdList, deviceIdList); +// failMsgSubQueue.offer(failDeviceIdList); +// } +// deviceIdList = new ArrayList<>(); +// } +// +// } +// } +// doMsgSubscription(deviceIdList); +// } +// }).start(); +// +// } +// +// +// /** +// * 每小时扫描订阅失败的消息 +// */ +// @PostConstruct +// @Scheduled(cron = "0 0 * * * *") +// public void scanQueue() { +// if (failMsgSubQueue.size() > 0) { +// Object poll = failMsgSubQueue.poll(); +// if (poll != null) { +// List pollList = (List) poll; +// String msg = doMsgSubscription(pollList); +// if (StrUtil.isBlank(msg)) { +// // 消息订阅失败,过一会儿再试试 +// List failDeviceIdList = new ArrayList<>(); +// Collections.copy(failDeviceIdList, pollList); +// failMsgSubQueue.offer(failDeviceIdList); +// } +// } +// } +// } +// +// +// @PostConstruct +// @Scheduled(fixedRate = 1000 * 60 * 60 * 2) +// @Order(1) +// public void getToken() { +// if (springProfile.equals("prod")) { +// String tokenBySend = getTokenBySend(); +// redisUtils.set("CHINA_MOBILE_TOKEN_KEY_NEW", tokenBySend, RedisUtils.HOUR_TOW_EXPIRE); +// } +// } +// +// @Scheduled(cron = "0 */19 * * * *") +// @PostConstruct +// @Order(2) +// public void setLiveSteam() { +// new Thread(() -> { +// if (springProfile.equals("prod")) { +// List liveSteamUrl = tuSpaceManageDao.getLiveSteamUrl(null, 2); +// for (GetLiveSteamUrlDTO item : liveSteamUrl) { +// String url = getLiveSteam(item.getDeviceSn()); +// if (url != null && !url.equals("")) { +// tuSpaceManageDao.updateLiveSteamUrl(item.getId(), url); +// } +// } +// } +// }).start(); +// } +// +// public String getLiveSteam(String deviceId) { +// log.info("【移动】开始获取视频流" + deviceId); +// String url_hls = "https://open.andmu.cn/v3/open/api/device/hls"; +// JSONObject bodyParam = new JSONObject(); +// bodyParam.put("deviceId", deviceId); +// bodyParam.put("endTime", DateUtils.addDateDays(new Date(), 2).getTime()); +// log.info("【移动】bodyParam->{}", bodyParam); +// String res = sendPost(url_hls, bodyParam, chinaMobileUtil.getTempToken()); +// log.info("【移动】开始获取视频流结果:-》{}" + res); +// JSONObject jsonObject = JSONObject.parseObject(res); +// String m3u8Url = null; +// if (jsonObject.get("resultCode").toString().equals("000000")) { +// String data = jsonObject.get("data").toString(); +// JSONObject jsonData = JSONObject.parseObject(data); +// m3u8Url = jsonData.get("m3u8Url").toString(); +// } +// // token已过期 +// if (jsonObject.get("resultCode").toString().equals("11504")) { +// // 删除redis的token,会重新获取 +// redisUtils.delete("CHINA_MOBILE_TOKEN_KEY_NEW"); +// getLiveSteam(deviceId); +// } +// return m3u8Url; +// } +// +// +// public static void main(String[] args) { +// +// //List deviceIdList =new ArrayList<>(30); +// //deviceIdList.add("2"); +// //deviceIdList.add("1"); +// // +// //List failDeviceIdList = new ArrayList<>(deviceIdList); +// //failMsgSubQueue.offer(failDeviceIdList); +// //deviceIdList = new ArrayList<>(); +// //List pollList = ( List) failMsgSubQueue.poll(); +// //for (String s : pollList) { +// // System.out.println(s); +// //} +// //System.out.println(failMsgSubQueue.poll()); +// //System.out.println(failMsgSubQueue.size()); +// +// +// //String s = doMsgSubscription(Arrays.asList("040312e7fc9f", "743fc2dae410")); +// //System.out.println(s); +// } +// +// +// +//} diff --git a/src/main/java/com/ycwl/basic/utils/ApiConst.java b/src/main/java/com/ycwl/basic/utils/ApiConst.java new file mode 100644 index 0000000..2957969 --- /dev/null +++ b/src/main/java/com/ycwl/basic/utils/ApiConst.java @@ -0,0 +1,108 @@ +package com.ycwl.basic.utils; + +/** + * Api常量定义类 + * + * @version 1.0.0 + */ +public class ApiConst { + + /** + * 返回CODE码定义, 按照httpstatus的code码定义, 系统自定义的为四位数 + * + * @version 1.0.0 + */ + public static enum Code { + + /** + * 成功返回码 + */ + CODE_SUCCESS_ZERO(0), + + /** + * 成功返回码 + */ + CODE_SUCCESS(200), + + /** + * 返回内容为空 + */ + CODE_CONTENT_EMPTY(204), + + /** + * 访问被拒绝 + */ + CODE_REJECT(403), + + /** + * 无权限访问 + */ + CODE_NO_AUTH(401), + + /** + * 请求方法错误 + */ + CODE_NOT_EXIST(404), + + /** + * 请求版本错误 + */ + CODE_VERSION_ERROR(406), + + /** + * 获取锁错误 + */ + CODE_GET_LOCK_ERROR(423), + + /** + * 请求参数错误 + */ + CODE_PARAM_ERROR(4001), + + /** + * 服务器错误 + */ + CODE_SERVER_ERROR(500), + + /** + * 其他业务码定义 + */ + CODE_COMMON_ERROR(5001), + + /** + * 自动完成登录状态 + */ + CODE_LOGIN_RETRY(5002), + + /** + * 用户过期或处在无登录状态 + */ + CODE_NO_SESSION(5003), + + /** + * 请求第三方错误 + */ + CODE_THIRDPARTY_ERROR(5004), + + /** + * 检查异常 + */ + CODE_CHECK_ERROR(5005), + + /** + * 缺少TOKEN异常 + */ + CODE_MISS_TOKEN_ERROR(5006); + + private Code(int intCode) { + this.intCode = intCode; + } + + private int intCode; + + public int code() { + return intCode; + } + + } +} diff --git a/src/main/java/com/ycwl/basic/utils/ApiResponse.java b/src/main/java/com/ycwl/basic/utils/ApiResponse.java new file mode 100644 index 0000000..c729fdf --- /dev/null +++ b/src/main/java/com/ycwl/basic/utils/ApiResponse.java @@ -0,0 +1,193 @@ +package com.ycwl.basic.utils; + + +import com.fasterxml.jackson.annotation.JsonIgnore; +import com.ycwl.basic.enums.BizCodeEnum; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; + +import java.io.Serializable; + +/** + * 所有接口返回数据的携带对象 + * + * @param + * @version 1.0.0 + */ +@ApiModel(value = "通用返回数据对象") +public class ApiResponse implements Serializable { + + private static final long serialVersionUID = 1L; + + /** + * 返回CODE码,详见{@link ApiConst.Code}中常量定义 + */ + @ApiModelProperty(value = "状态码") + private int code; + + /** + * 返回message + */ + @ApiModelProperty(value = "数据描述") + private String msg; + + /** + * 成功返回数据 + */ + @ApiModelProperty(value = "数据") + private T data; + + public ApiResponse() { + + } + + /** + * 构建成功返回数据对象 + * + * @param data 返回数据内容 + * @return + */ + public static ApiResponse buildSuccessResponse(T data) { + ApiResponse response = new ApiResponse(); + response.setCode(ApiConst.Code.CODE_SUCCESS.code()); + response.setData(data); + return response; + } + + /** + * 构建空返回对象 + * + * @return + */ + public static ApiResponse buildEmptyResponse() { + ApiResponse response = new ApiResponse(); + response.setCode(ApiConst.Code.CODE_CONTENT_EMPTY.code()); + return response; + } + + /** + * 构建常规错误返回对象 + * + * @param msg + * @return + */ + public static ApiResponse buildCommonErrorResponse(String msg) { + return buildResponse(ApiConst.Code.CODE_COMMON_ERROR, msg); + } + + /** + * 构建自定义CODE码对象 + * + * @param code + * @param data + * @param msg + * @return + */ + public static ApiResponse buildResponse(int code, T data, String msg) { + ApiResponse response = new ApiResponse(); + response.setCode(code); + response.setData(data); + response.setMsg(msg); + return response; + } + + /** + * 根据返回值构建结果 + * + * @param flag + * @param + * @return + */ + public static ApiResponse buildFlagResponse(boolean flag, T data) { + ApiResponse response = new ApiResponse(); + if (flag) { + response.setCode(ApiConst.Code.CODE_SUCCESS.code()); + response.setData(data); + response.setMsg("成功"); + return response; + } + response.setCode(ApiConst.Code.CODE_COMMON_ERROR.code()); + response.setData(data); + response.setMsg("失败"); + return response; + } + + /** + * 构建CODE码和提示信息对象 + * + * @param code + * @param msg + * @return + */ + public static ApiResponse buildResponse(ApiConst.Code code, String msg) { + ApiResponse response = new ApiResponse(); + response.setCode(code.code()); + response.setMsg(msg); + return response; + } + + /** + * 构建用户自定义CODE码和提示信息对象 + * + * @param code + * @param msg + * @return + */ + public static ApiResponse buildResponse(int code, String msg) { + ApiResponse response = new ApiResponse(); + response.setCode(code); + response.setMsg(msg); + return response; + } + + public static ApiResponse buildResult(BizCodeEnum bizCodeEnum) { + ApiResponse apiResponse = new ApiResponse(); + apiResponse.setCode(bizCodeEnum.code); + apiResponse.setMsg(bizCodeEnum.message); + + return apiResponse; + } + + /** + * 是否执行成功 + * + * @return + */ + @JsonIgnore + public boolean isSuccess() { + return ApiConst.Code.CODE_SUCCESS.code() == this.code; + } + + public int getCode() { + return code; + } + + public void setCode(int code) { + this.code = code; + } + + public String getMsg() { + return msg; + } + + public void setMsg(String msg) { + this.msg = msg; + } + + public T getData() { + return data; + } + + public void setData(T data) { + this.data = data; + } + + @Override + public String toString() { + StringBuilder builder = new StringBuilder(); + builder.append("[code=").append(code).append(", msg=").append(msg).append(", data=").append(data) + .append("]"); + return builder.toString(); + } + +} diff --git a/src/main/java/com/ycwl/basic/utils/BeanCopierUtils.java b/src/main/java/com/ycwl/basic/utils/BeanCopierUtils.java new file mode 100644 index 0000000..203c548 --- /dev/null +++ b/src/main/java/com/ycwl/basic/utils/BeanCopierUtils.java @@ -0,0 +1,44 @@ +package com.ycwl.basic.utils; + +import org.springframework.cglib.beans.BeanCopier; + +import java.util.HashMap; +import java.util.Map; + +/** + * @date 2022年03月09日 9:04 + * @author wenshijia + * BeanCopier工具类 + */ +public class BeanCopierUtils { + + public static Map beanCopierCacheMap = new HashMap<>(); + + /** + * + * 将soruce对象的属性转换给target对象 + * @date 2022/3/9 9:11 + * @param source 需要转换的对象 + * @param target 目标对象 + */ + public static void copyProperties(Object source, Object target) { + BeanCopier beanCopier; + + String cacheKey = source.getClass().toString() + target.getClass().toString(); + + if (!beanCopierCacheMap.containsKey(cacheKey)) { + synchronized (BeanCopierUtils.class) { + if (!beanCopierCacheMap.containsKey(cacheKey)) { + beanCopier = BeanCopier.create(source.getClass(), target.getClass(), false); + beanCopierCacheMap.put(cacheKey, beanCopier); + } else { + beanCopier = beanCopierCacheMap.get(cacheKey); + } + } + } else { + beanCopier = beanCopierCacheMap.get(cacheKey); + } + + beanCopier.copy(source, target, null); + } +} diff --git a/src/main/java/com/ycwl/basic/utils/CodeGenerator.java b/src/main/java/com/ycwl/basic/utils/CodeGenerator.java new file mode 100644 index 0000000..aa31180 --- /dev/null +++ b/src/main/java/com/ycwl/basic/utils/CodeGenerator.java @@ -0,0 +1,137 @@ +//package com.ycwl.smartPark.utils; +// +//import com.baomidou.mybatisplus.core.exceptions.MybatisPlusException; +//import com.baomidou.mybatisplus.core.toolkit.StringPool; +//import com.baomidou.mybatisplus.core.toolkit.StringUtils; +//import com.baomidou.mybatisplus.generator.AutoGenerator; +//import com.baomidou.mybatisplus.generator.InjectionConfig; +//import com.baomidou.mybatisplus.generator.config.*; +//import com.baomidou.mybatisplus.generator.config.po.TableInfo; +//import com.baomidou.mybatisplus.generator.config.rules.NamingStrategy; +//import com.baomidou.mybatisplus.generator.engine.FreemarkerTemplateEngine; +// +//import java.util.ArrayList; +//import java.util.List; +//import java.util.Scanner; +// +///** +// * 执行 main 方法控制台输入模块表名回车自动生成对应项目目录中 +// * +// * @author songmingsong +// * @since 1.0.0 +// */ +// +//public class CodeGenerator { +// +// /** +// *

+// * 读取控制台内容 +// *

+// */ +// public static String scanner(String tip) { +// Scanner scanner = new Scanner(System.in); +// StringBuilder help = new StringBuilder(); +// help.append("请输入" + tip + ":"); +// System.out.println(help.toString()); +// if (scanner.hasNext()) { +// String ipt = scanner.next(); +// if (StringUtils.isNotEmpty(ipt)) { +// return ipt; +// } +// } +// throw new MybatisPlusException("请输入正确的" + tip + "!"); +// } +// +// public static void main(String[] args) { +// // 代码生成器 +// AutoGenerator mpg = new AutoGenerator(); +// +// // 全局配置 +// GlobalConfig gc = new GlobalConfig(); +// String projectPath = System.getProperty("user.dir"); +// // 生成到那个模块下 +// gc.setOutputDir(projectPath + "/src/main/java"); +// //作者 +// gc.setAuthor("songmingsong"); +// //打开输出目录 +// gc.setOpen(false); +// //xml开启 BaseResultMap +// gc.setBaseResultMap(true); +// //xml 开启BaseColumnList +// gc.setBaseColumnList(true); +// // 实体属性 Swagger2 注解 +// gc.setSwagger2(true); +// mpg.setGlobalConfig(gc); +// +// // 数据源配置 +// DataSourceConfig dsc = new DataSourceConfig(); +// dsc.setUrl("jdbc:mysql://49.4.2.89:3306/smart_park?useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia" + +// "/Shanghai"); +// dsc.setDriverName("com.mysql.cj.jdbc.Driver"); +// dsc.setUsername("root"); +// dsc.setPassword("yckj@2017"); +// mpg.setDataSource(dsc); +// +// // 包配置 +// PackageConfig pc = new PackageConfig(); +// pc.setParent("com.ycwl.smartPark") +// .setEntity("model.app.notice.entity") +// .setMapper("mapper.app") +// .setService("service.app") +// .setServiceImpl("service.impl.app") +// .setController("controller.app"); +// mpg.setPackageInfo(pc); +// +// // 自定义配置 +// InjectionConfig cfg = new InjectionConfig() { +// @Override +// public void initMap() { +// // to do nothing +// } +// }; +// +// // 如果模板引擎是 freemarker +// String templatePath = "/templates/mapper.xml.ftl"; +// // 如果模板引擎是 velocity +// // String templatePath = "/templates/mapper.xml.vm"; +// +// // 自定义输出配置 +// List focList = new ArrayList<>(); +// // 自定义配置会被优先输出 +// focList.add(new FileOutConfig(templatePath) { +// @Override +// public String outputFile(TableInfo tableInfo) { +// // 自定义输出文件名 , 如果你 Entity 设置了前后缀、此处注意 xml 的名称会跟着发生变化!! +// return projectPath + "/src/main/resources/mapper/" + tableInfo.getEntityName() + "Mapper" +// + StringPool.DOT_XML; +// } +// }); +// cfg.setFileOutConfigList(focList); +// mpg.setCfg(cfg); +// +// // 配置模板 +// TemplateConfig templateConfig = new TemplateConfig(); +// +// templateConfig.setXml(null); +// mpg.setTemplate(templateConfig); +// +// // 策略配置 +// StrategyConfig strategy = new StrategyConfig(); +// //数据库表映射到实体的命名策略 +// strategy.setNaming(NamingStrategy.underline_to_camel); +// //数据库表字段映射到实体的命名策略 +// strategy.setColumnNaming(NamingStrategy.no_change); +// //lombok模型 +// strategy.setEntityLombokModel(true); +// //生成 @RestController 控制器 +// strategy.setRestControllerStyle(true); +// strategy.setInclude(scanner("表名,多个英文逗号分割").split(",")); +// strategy.setControllerMappingHyphenStyle(true); +// //表前缀 +// strategy.setTablePrefix("t_"); +// mpg.setStrategy(strategy); +// mpg.setTemplateEngine(new FreemarkerTemplateEngine()); +// mpg.execute(); +// } +// +//} diff --git a/src/main/java/com/ycwl/basic/utils/CommonUtil.java b/src/main/java/com/ycwl/basic/utils/CommonUtil.java new file mode 100644 index 0000000..2c5287e --- /dev/null +++ b/src/main/java/com/ycwl/basic/utils/CommonUtil.java @@ -0,0 +1,186 @@ +package com.ycwl.basic.utils; + +import com.fasterxml.jackson.databind.ObjectMapper; +import lombok.extern.slf4j.Slf4j; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.io.PrintWriter; +import java.net.InetAddress; +import java.net.UnknownHostException; +import java.nio.charset.StandardCharsets; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; +import java.security.SecureRandom; +import java.util.UUID; +import java.util.concurrent.ThreadLocalRandom; + +/** + * @author wenshijia + * @date 2021年05月26日 23:02 + */ +@Slf4j +public class CommonUtil { + /** + * 生成指定长度随机字母和数字 + */ + private static final String ALL_CHAR_NUM = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; + + private static SecureRandom random; + + static { + try { + random = SecureRandom.getInstance("SHA1PRNG"); + } catch (NoSuchAlgorithmException e) { + e.printStackTrace(); + } + } + + + /** + * 获取ip + * + * @param request + * @return + */ + public static String getIpAddr(HttpServletRequest request) { + String ipAddress = null; + try { + ipAddress = request.getHeader("x-forwarded-for"); + if (ipAddress == null || ipAddress.length() == 0 || "unknown".equalsIgnoreCase(ipAddress)) { + ipAddress = request.getHeader("Proxy-Client-IP"); + } + if (ipAddress == null || ipAddress.length() == 0 || "unknown".equalsIgnoreCase(ipAddress)) { + ipAddress = request.getHeader("WL-Proxy-Client-IP"); + } + if (ipAddress == null || ipAddress.length() == 0 || "unknown".equalsIgnoreCase(ipAddress)) { + ipAddress = request.getRemoteAddr(); + if ("127.0.0.1".equals(ipAddress)) { + // 根据网卡取本机配置的IP + InetAddress inet = null; + try { + inet = InetAddress.getLocalHost(); + } catch (UnknownHostException e) { + e.printStackTrace(); + } + ipAddress = inet.getHostAddress(); + } + } + // 对于通过多个代理的情况,第一个IP为客户端真实IP,多个IP按照','分割 + if (ipAddress != null && ipAddress.length() > 15) { + // "***.***.***.***".length() + // = 15 + if (ipAddress.indexOf(",") > 0) { + ipAddress = ipAddress.substring(0, ipAddress.indexOf(",")); + } + } + } catch (Exception e) { + ipAddress = ""; + } + return ipAddress; + } + + /** + * md5加密 + * + * @param data 需要加密的字符串 + * @return java.lang.String + * @author wenshijia + * @date 2021/5/26 23:02 + */ + public static String MD5(String data) { + try { + MessageDigest md = MessageDigest.getInstance("MD5"); + byte[] array = md.digest(data.getBytes(StandardCharsets.UTF_8)); + StringBuilder sb = new StringBuilder(); + for (byte item : array) { + sb.append(Integer.toHexString((item & 0xFF) | 0x100).substring(1, 3)); + } + + return sb.toString().toUpperCase(); + } catch (Exception exception) { + + } + return null; + + } + + /** + * 生成随机数 + * + * @param length 生成的随机数的长度 + * @return java.lang.String + * @author wenshijia + * @date 2021/5/27 16:38 + */ + public static String getRandomCode(int length) { + StringBuilder stringBuilder = new StringBuilder(); + for (int i = 0; i < length; i++) { + stringBuilder.append(random.nextInt(10)); + } + + return stringBuilder.toString(); + } + + /** + * 获取当前时间的时间戳 + * + * @return long + * @author wenshijia + * @date 2021/5/27 22:02 + */ + public static long getCurrentTimestamp() { + return System.currentTimeMillis(); + } + + /** + * UUID生成 + * + * @return java.lang.String + * @author wenshijia + * @date 2021/5/30 21:16 + */ + public static String generateUUID() { + return UUID.randomUUID().toString().replace("-", ""); + } + + /** + * 生成指定长度随机字母和数字 + * + * @param length 需要生成的字符串长度 + * @return java.lang.String + * @author wenshijia + * @date 2021/5/31 16:43 + */ + public static String getStringNumRandom(int length) { + ThreadLocalRandom random = ThreadLocalRandom.current(); + //生成随机数字和字母, + StringBuilder saltString = new StringBuilder(length); + for (int i = 1; i <= length; ++i) { + saltString.append(ALL_CHAR_NUM.charAt(random.nextInt(ALL_CHAR_NUM.length()))); + } + return saltString.toString(); + } + + /** + * @param response 返回response + * @param obj 返回的数据 + * @author wenshijia + * @date 2021/6/2 21:11 + */ + public static void sendJsonMessage(HttpServletResponse response, Object obj) { + + ObjectMapper objectMapper = new ObjectMapper(); + response.setContentType("application/json; charset=utf-8"); + + try (PrintWriter writer = response.getWriter()) { + writer.print(objectMapper.writeValueAsString(obj)); + + response.flushBuffer(); + } catch (IOException e) { + log.warn("响应json数据给前端异常 -> {}", e.getMessage(), e); + } + + } +} diff --git a/src/main/java/com/ycwl/basic/utils/CustomBigDecimalUtils.java b/src/main/java/com/ycwl/basic/utils/CustomBigDecimalUtils.java new file mode 100644 index 0000000..f9467db --- /dev/null +++ b/src/main/java/com/ycwl/basic/utils/CustomBigDecimalUtils.java @@ -0,0 +1,202 @@ +package com.ycwl.basic.utils; + +import java.math.BigDecimal; +import java.math.RoundingMode; + +/** + * @date 2022年06月02日 13:40 + * 自定义的BigDecimal计算工具类 + */ +public class CustomBigDecimalUtils { + + public static final BigDecimal HUNDRED_BIG_DECIMAL = new BigDecimal("100"); + + /** + * 除法 + * + * @param divisor 除数 + * @param dividend 被除数 + * @param scale 保留的小数位数 + * @param roundingMode 舍入模式:比如四舍五入 + * @return java.math.BigDecimal + * @date 2022/6/2 13:43 + */ + public static BigDecimal divide(BigDecimal divisor, + BigDecimal dividend, + int scale, + RoundingMode roundingMode) { + if (divisor == null || dividend == null) { + throw new NullPointerException("传入的数据不能为空"); + } + + if (Double.compare(divisor.doubleValue(), BigDecimal.ZERO.doubleValue()) == 0 || + Double.compare(dividend.doubleValue(), BigDecimal.ZERO.doubleValue()) == 0) { + return BigDecimal.ZERO; + } + + return divisor.divide(dividend, scale, roundingMode); + } + + /** + * 除法 + * + * @param divisor 除数 + * @param dividend 被除数 + * @param scale 保留的小数位数 + * @param roundingMode 舍入模式:比如四舍五入 + * @return java.math.BigDecimal + * @date 2022/6/2 13:43 + */ + public static BigDecimal divide(Integer divisor, + Integer dividend, + int scale, + RoundingMode roundingMode) { + if (divisor == null || dividend == null) { + throw new NullPointerException("传入的数据不能为空"); + } + + if (divisor == 0 || dividend == 0) { + return BigDecimal.ZERO; + } + + return new BigDecimal(divisor).divide(new BigDecimal(dividend), scale, roundingMode); + } + + /** + * 除法 + * + * @param divisor 除数 + * @param dividend 被除数 + * @param scale 保留的小数位数 + * @param roundingMode 舍入模式:比如四舍五入 + * @return java.math.BigDecimal + * @date 2022/6/2 13:43 + */ + public static BigDecimal divide(Double divisor, + Double dividend, + int scale, + RoundingMode roundingMode) { + if (divisor == null || dividend == null) { + throw new NullPointerException("传入的数据不能为空"); + } + + if (Double.compare(divisor, BigDecimal.ZERO.doubleValue()) == 0 || + Double.compare(dividend, BigDecimal.ZERO.doubleValue()) == 0) { + return BigDecimal.ZERO; + } + + return new BigDecimal(String.valueOf(divisor)).divide(new BigDecimal(String.valueOf(dividend)), + scale, roundingMode); + } + + /** + * 除法 + * + * @param divisor 除数 + * @param dividend 被除数 + * @param scale 保留的小数位数 + * @param roundingMode 舍入模式:比如四舍五入 + * @return java.math.BigDecimal + * @date 2022/6/2 13:43 + */ + public static BigDecimal divide(Double divisor, + Integer dividend, + int scale, + RoundingMode roundingMode) { + if (divisor == null || dividend == null) { + throw new NullPointerException("传入的数据不能为空"); + } + + if (Double.compare(divisor, BigDecimal.ZERO.doubleValue()) == 0 || + Double.compare(dividend, BigDecimal.ZERO.doubleValue()) == 0) { + return BigDecimal.ZERO; + } + + return new BigDecimal(String.valueOf(divisor)).divide(new BigDecimal(String.valueOf(dividend)), + scale, roundingMode); + } + + /** + * 减法 + * + * @param subtraction 减数 + * @param minuend 被减数 + * @return java.math.BigDecimal + * @date 2022/6/2 13:53 + */ + public static BigDecimal subtract(BigDecimal subtraction, + BigDecimal minuend) { + if (subtraction == null || minuend == null) { + throw new NullPointerException("传入的数据不能为空"); + } + + return subtraction.subtract(minuend); + } + + /** + * 减法 + * + * @param subtraction 减数 + * @param minuend 被减数 + * @return java.math.BigDecimal + * @date 2022/6/2 13:53 + */ + public static BigDecimal subtract(Double subtraction, + Double minuend) { + if (subtraction == null || minuend == null) { + throw new NullPointerException("传入的数据不能为空"); + } + + return new BigDecimal(String.valueOf(subtraction)).subtract(new BigDecimal(String.valueOf(minuend))); + } + + /** + * 减法 + * + * @param subtraction 减数 + * @param minuend 被减数 + * @return java.math.BigDecimal + * @date 2022/6/2 13:53 + */ + public static BigDecimal subtract(BigDecimal subtraction, + Double minuend) { + if (subtraction == null || minuend == null) { + throw new NullPointerException("传入的数据不能为空"); + } + + return subtraction.subtract(new BigDecimal(minuend)); + } + + /** + * 加法 + * @date 2022/6/7 17:31 + * @param addend 加数 + * @param summand 被加数 + * @return java.lang.Double + */ + public static Double add(Double addend, + Double summand) { + if (addend == null || summand == null) { + throw new NullPointerException("传入的数据不能为空"); + } + + return new BigDecimal(addend.toString()).add(new BigDecimal(summand.toString())).doubleValue(); + } + + /** + * 加法 + * @date 2022/6/7 17:31 + * @param addend 加数 + * @param summand 被加数 + * @return java.lang.Double + */ + public static Double add(BigDecimal addend, + BigDecimal summand) { + if (addend == null || summand == null) { + throw new NullPointerException("传入的数据不能为空"); + } + + return addend.add(summand).doubleValue(); + } + +} diff --git a/src/main/java/com/ycwl/basic/utils/JwtAnalysisUtil.java b/src/main/java/com/ycwl/basic/utils/JwtAnalysisUtil.java new file mode 100644 index 0000000..36521ff --- /dev/null +++ b/src/main/java/com/ycwl/basic/utils/JwtAnalysisUtil.java @@ -0,0 +1,82 @@ +package com.ycwl.basic.utils; + + +import com.ycwl.basic.model.jwt.JwtInfo; +import io.jsonwebtoken.Claims; +import io.jsonwebtoken.JwtBuilder; +import io.jsonwebtoken.Jwts; +import io.jsonwebtoken.SignatureAlgorithm; + +import java.time.Instant; +import java.time.LocalDateTime; +import java.time.ZoneId; +import java.util.Iterator; +import java.util.Map; + +/** + * @author yangchen + */ +public class JwtAnalysisUtil { + + /** + * 生成 Token + * + * @param jwtInfo + * @param priKey + * @param expireTime + * @return + * @throws Exception + */ + public static String generateToken(JwtInfo jwtInfo, byte[] priKey, LocalDateTime expireTime) throws Exception { + JwtBuilder builder = Jwts.builder().setSubject(jwtInfo.getAccount()) + .claim("userId", jwtInfo.getUserId()) + .claim("roleId", jwtInfo.getRoleId()) + .claim("phone", jwtInfo.getPhone()) + .claim("name", jwtInfo.getName()) + // 返回从1970 00:00:00 到现在的毫秒差(实际的过期时间) + .claim("expire", expireTime.atZone(ZoneId.systemDefault()).toInstant().toEpochMilli()); + return builder.signWith(SignatureAlgorithm.RS256, RsaKeyUtil.getPrivateKey(priKey)).compact(); + } + + /** + * 解析 Token + * + * @param token + * @param pubKey + * @return + * @throws Exception + */ + public static JwtInfo getInfoFromToken(String token, byte[] pubKey) throws Exception { + Claims body = (Claims) RsaKeyUtil.parserToken(token, pubKey).getBody(); + Iterator var3 = body.entrySet().iterator(); + while (var3.hasNext()) { + Map.Entry entry = (Map.Entry) var3.next(); + if (!"sub".equals(entry.getKey()) + && !"userId".equals(entry.getKey()) + && !"phone".equals(entry.getKey()) + && !"roleId".equals(entry.getKey()) + && !"account".equals(entry.getKey()) + && !"name".equals(entry.getKey()) + && !"roleName".equals(entry.getKey()) + && !"expire".equals(entry.getKey())); + } + + // convert + LocalDateTime expireTime = null; + try { + // expire time + Object expire = body.get("expire"); + if (expire != null) { + expireTime = LocalDateTime.ofInstant(Instant.ofEpochMilli((Long) expire), ZoneId.systemDefault()); + } + } catch (Exception e) { + e.printStackTrace(); + } + return new JwtInfo(StringUtil.a(body.get("name")), + StringUtil.a(body.get("userId")), + StringUtil.a(body.get("roleId")), + body.getSubject(), + StringUtil.a(body.get("phone")), + expireTime); + } +} diff --git a/src/main/java/com/ycwl/basic/utils/JwtTokenUtil.java b/src/main/java/com/ycwl/basic/utils/JwtTokenUtil.java new file mode 100644 index 0000000..4922d71 --- /dev/null +++ b/src/main/java/com/ycwl/basic/utils/JwtTokenUtil.java @@ -0,0 +1,114 @@ +package com.ycwl.basic.utils; + +import com.ycwl.basic.exception.CheckTokenException; +import com.ycwl.basic.model.jwt.JwtInfo; +import lombok.Getter; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; + +import java.time.LocalDateTime; + +; + +/** + * @author yangchen + */ +@SuppressWarnings("ALL") +@Slf4j +@Component +public class JwtTokenUtil { + + @Getter + @Value("${jwt.expire:15}") + private int expire; + + private static String PRI_KEY = "MIICdQIBADANBgkqhkiG9w0BAQEFAASCAl8wggJbAgEAAoGBAKOpJ+Ob4VI6sipH47lNQF94YVjNvf/NS8x8gsq/qYG8JOM016prGpHBF6fZOv1yKDnBwJRwC+2oBm3PmybXUZiKIYScoLIFcoV9GbuZZ1ktEWpzUSbN4ZHMj2ylkVHi07HlR4L3PzJlbzC410yg2ZS2WKoanJRHUAmrcN4bvXvBAgMBAAECgYBw7LLdVh1uw5lTmy8CGM+mEEX7JFtJObpnajJE+2JWZh99tmRo7mXy1C0iX71YS4B9+baLtZRFc36cHneLoV5mqhWOf84W/zha+z5dlh1ErSLL6t8YKpJ2GQUMu9Y90VHf5eyhUTu0W7bc+Nvr3GSzaDpMy4fm0XjrazIBuYDvAQJBAOShdiZJnKPBLP98XsVD8L3EB1Tpe3qFviYHhvnhaafMmoY8AR3OqMAIn8jLUiUsIdiOpWL2tNFfCkk0kwLpb2kCQQC3QKXKQjY1j8YGrSQw8YFry5qFcdHP+ybw8lc090wHZjFYlpLSjL6AoTwt+bMyArr2WWCN9G/tU5aVLajZc/aZAkByMtAQGc664L+4MYgo4mG6d9Ltr930eh9bYYEjCVu76+/3QruQBuy1Vtlw81XpqVySjdXAU9hHiEBcBn20A6OZAkAW65IQ8ykel+X3zc4aBQrf9a5VBIBumAYt2tHHgSrUPhbr8qFYjlwBcKk7QuED302NJG6sMqeRMoRCElztHdD5AkAWZCbWQQtFmgWB9fZQxKT94c+zL7HJwgcmtmQq8JHgcoOE1jgi5bVksm8vhDeATOAUEAt0Dt+vwTPaPvFL5JdW"; + private static String PUB_KEY = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCjqSfjm+FSOrIqR+O5TUBfeGFYzb3/zUvMfILKv6mBvCTjNNeqaxqRwRen2Tr9cig5wcCUcAvtqAZtz5sm11GYiiGEnKCyBXKFfRm7mWdZLRFqc1EmzeGRzI9spZFR4tOx5UeC9z8yZW8wuNdMoNmUtliqGpyUR1AJq3DeG717wQIDAQAB"; + + /** + * 生成 token + * + * @param jwtInfo + * @param otherInfo + * @param expireTime 会增加一个 expire 作为 token 的过期时间 + * @return + * @throws Exception + */ + public String generateToken(JwtInfo jwtInfo) throws Exception { + // 过期时间,默认 15 天 + LocalDateTime expireTime = LocalDateTime.now().plusDays(expire); + byte[] bytes = RsaKeyUtil.toBytes(PRI_KEY); + String token = JwtAnalysisUtil.generateToken(jwtInfo, bytes, expireTime); + return token; + } + + + /** + * 解析Token + * + * @param token + * @return + * @throws Exception + */ + public JwtInfo parsingToken(String token) throws CheckTokenException { + try { + JwtInfo infoFromToken = JwtAnalysisUtil.getInfoFromToken(token, RsaKeyUtil.toBytes(PUB_KEY)); + return infoFromToken; + } catch (Exception e) { + e.printStackTrace(); + throw new CheckTokenException("token is invalid"); + } + } + + /*********************************************** 测试 ***************************************************/ + + /** + * 测试 token + * + * @param args + */ +// public static void main(String[] args) throws Exception { +// +// JwtInfo jwtInfo = new JwtInfo("阿豹", "1", "role1", "yangchen", 1, LocalDateTime.now(), new HashMap<>()); +// +// long a = Instant.now().toEpochMilli(); +// +// JwtTokenUtil jwtTokenUtil = new JwtTokenUtil(); +// String token = jwtTokenUtil.generateToken(jwtInfo); +// +// log.info("==> generate token: " + (Instant.now().toEpochMilli() - a) + " ms"); +// +// System.out.println("======="); +// System.out.println(); +// +// System.out.println(token); +// +// System.out.println(); +// System.out.println("======="); +// +// long b = Instant.now().toEpochMilli(); +// +// JwtInfo jwtInfo1 = jwtTokenUtil.parsingToken(token); +// +// log.info("==> paring token end " + (Instant.now().toEpochMilli() - b) + " ms"); +// +// System.out.println(); +// System.out.println(); +// System.out.println(); +// System.out.println(jwtInfo); +// System.out.println("======="); +// System.out.println(jwtInfo1.toString()); +// +// } + public static void main(String[] args) throws Exception { + JwtInfo jwtInfo = new JwtInfo(); + jwtInfo.setUserId("1"); + LocalDateTime expireTime = LocalDateTime.now().plusDays(9999999); + byte[] bytes = RsaKeyUtil.toBytes(PRI_KEY); + String token = JwtAnalysisUtil.generateToken(jwtInfo, bytes, expireTime); + System.out.println(token); + } + + +} diff --git a/src/main/java/com/ycwl/basic/utils/ObjectConvertUtils.java b/src/main/java/com/ycwl/basic/utils/ObjectConvertUtils.java new file mode 100644 index 0000000..8ddfc6e --- /dev/null +++ b/src/main/java/com/ycwl/basic/utils/ObjectConvertUtils.java @@ -0,0 +1,180 @@ +package com.ycwl.basic.utils; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.BeanUtils; +import org.springframework.beans.BeanWrapper; +import org.springframework.beans.BeanWrapperImpl; + +import java.beans.PropertyDescriptor; +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +/** + * @date 2022年07月14日 14:12 + * 数据格式转换工具类 + */ +public class ObjectConvertUtils { + + private static final Logger LOGGER = LoggerFactory.getLogger(ObjectConvertUtils.class); + + /** + * 浅克隆 + * + * @param source 原对象 + * @param clazz 目标对象 + * @return T + * @date 2022/4/6 13:45 + */ + public static T clone(Object source, Class clazz) { + return clone(source, clazz, true); + } + /** + * + * @date 2022/7/18 16:36 + * @param source 原对象 + * @param clazz 目标对象 + * @param whetherAssignNull 是否赋值空值:true是 false否 + * @return T + */ + public static T clone(Object source, Class clazz, Boolean whetherAssignNull) { + T target; + + if (source == null) { + return null; + } + + try { + target = clazz.newInstance(); + if (whetherAssignNull) { + BeanUtils.copyProperties(source, target); + } else { + BeanUtils.copyProperties(source, target, getNullPropertyNames(source)); + } + return target; + } catch (Exception e) { + LOGGER.error("数据转换异常", e); + return null; + } + } + + /** + * 对象与对象之间的数据转换 + * + * @param source 转换的数据对象 + * @param target 需要转换数据的对象 + * @date 2022/7/14 17:24 + */ + public static void clone(Object source, Object target) { + clone(source, target, true); + } + /** + * + * @date 2022/7/18 16:39 + * @param source 转换的数据对象 + * @param target 需要转换数据的对象 + * @param whetherAssignNull 是否赋值空值:true是 false否 + */ + public static void clone(Object source, Object target, Boolean whetherAssignNull) { + if (source == null) { + return; + } + + try { + if (whetherAssignNull) { + BeanUtils.copyProperties(source, target, getNullPropertyNames(source)); + } else { + BeanUtils.copyProperties(source, target); + } + } catch (Exception e) { + LOGGER.error("数据转换异常", e); + } + } + + /** + * 对象与对象之间的数据转换 + * + * @param source 转换的数据对象 + * @param target 需要转换数据的对象 + * @date 2022/7/15 9:11 + */ + public static void cglibBeanCopierCloneObject(Object source, Object target) { + BeanCopierUtils.copyProperties(source, target); + } + /** + * 对象与对象之间的数据转换 + * + * @param source 转换的数据对象 + * @param target 需要转换数据的对象 + * @date 2022/7/15 9:11 + */ + public static T cglibBeanCopierCloneObject(Object source, Class target) { + T t; + try { + t = target.newInstance(); + BeanCopierUtils.copyProperties(source, t); + } catch (InstantiationException | IllegalAccessException e) { + throw new RuntimeException(e); + } + return t; + } + + /** + * 将list集合转换为传入的对象的数据集合 + * + * @param sourceList 原数据集合 + * @param clazz 需要转换的集合数据对象 + * @return java.util.List + * @date 2022/4/6 13:49 + */ + public static List cloneList(List sourceList, Class clazz) { + return cloneList(sourceList, clazz, true); + } + /** + * + * @date 2022/7/18 16:41 + * @param sourceList 原数据集合 + * @param clazz 需要转换的集合数据对象 + * @param whetherAssignNull 是否赋值空值:true是 false否 + * @return java.util.List + */ + public static List cloneList(List sourceList, Class clazz, Boolean whetherAssignNull) { + try { + List targetList = new ArrayList<>(sourceList.size()); + for (Object source : sourceList) { + if (whetherAssignNull) { + targetList.add(clone(source, clazz)); + } else { + targetList.add(clone(source, clazz, false)); + } + } + + return targetList; + } catch (Exception e) { + LOGGER.error("数据转换异常", e); + return null; + } + } + + + /** + * 获取需要忽略的属性 + */ + public static String[] getNullPropertyNames(Object source) { + final BeanWrapper src = new BeanWrapperImpl(source); + PropertyDescriptor[] pds = src.getPropertyDescriptors(); + + Set emptyNames = new HashSet<>(); + for (PropertyDescriptor pd : pds) { + Object srcValue = src.getPropertyValue(pd.getName()); + // 此处判断可根据需求修改 + if (srcValue == null) { + emptyNames.add(pd.getName()); + } + } + String[] result = new String[emptyNames.size()]; + return emptyNames.toArray(result); + } +} diff --git a/src/main/java/com/ycwl/basic/utils/RedisCacheOperationUtils.java b/src/main/java/com/ycwl/basic/utils/RedisCacheOperationUtils.java new file mode 100644 index 0000000..a79c170 --- /dev/null +++ b/src/main/java/com/ycwl/basic/utils/RedisCacheOperationUtils.java @@ -0,0 +1,77 @@ +package com.ycwl.basic.utils; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.redis.core.*; +import org.springframework.stereotype.Component; + +import java.util.List; + +/** + * @date 2022年08月08日 16:06 + * redis缓存操作行为工具类 + */ +@Component +public class RedisCacheOperationUtils { + + /** + * string类型的redis操作类 + */ + private static StringRedisTemplate stringRedisTemplate; + /** + * 通用的redis操作类 + */ + private static RedisTemplate redisTemplate; + + /** + * 创建string类型的操作对象 + */ + public static BoundValueOperations createValueOperations(String cacheKey) { + return stringRedisTemplate.boundValueOps(cacheKey); + } + /** + * 创建list类型的操作对象 + */ + public static BoundListOperations> createListOperations(String cacheKey) { + return redisTemplate.boundListOps(cacheKey); + } + /** + * 创建hash类型的操作对象 + */ + public static BoundHashOperations createHashOperations(String cacheKey) { + return redisTemplate.boundHashOps(cacheKey); + } + /** + * 创建set类型的操作对象 + */ + public static BoundSetOperations createSetOperations(String cacheKey) { + return redisTemplate.boundSetOps(cacheKey); + } + /** + * 创建zset类型的操作对象 + */ + public static BoundZSetOperations createZSetOperations(String cacheKey) { + return redisTemplate.boundZSetOps(cacheKey); + } + /** + * 判断缓存key值是否存在 + */ + public static Boolean hasKey(String cacheKey) { + return redisTemplate.hasKey(cacheKey); + } + /** + * 删除缓存的redis缓存key + */ + public static Boolean delete(String cacheKey) { + return redisTemplate.delete(cacheKey); + } + + @Autowired + public void setStringRedisTemplate(StringRedisTemplate stringRedisTemplate) { + RedisCacheOperationUtils.stringRedisTemplate = stringRedisTemplate; + } + + @Autowired + public void setRedisTemplate(RedisTemplate redisTemplate) { + RedisCacheOperationUtils.redisTemplate = redisTemplate; + } +} diff --git a/src/main/java/com/ycwl/basic/utils/RsaKeyUtil.java b/src/main/java/com/ycwl/basic/utils/RsaKeyUtil.java new file mode 100644 index 0000000..bdfa4ef --- /dev/null +++ b/src/main/java/com/ycwl/basic/utils/RsaKeyUtil.java @@ -0,0 +1,79 @@ +package com.ycwl.basic.utils; + +import io.jsonwebtoken.Claims; +import io.jsonwebtoken.Jws; +import io.jsonwebtoken.Jwts; + +import java.io.IOException; +import java.security.*; +import java.security.spec.PKCS8EncodedKeySpec; +import java.security.spec.X509EncodedKeySpec; +import java.util.Base64; +import java.util.HashMap; +import java.util.Map; + +/** + * @author yangchen + */ +@SuppressWarnings("ALL") +public class RsaKeyUtil { + + public RsaKeyUtil() { + } + + public static PublicKey getPublicKey(byte[] publicKey) throws Exception { + X509EncodedKeySpec spec = new X509EncodedKeySpec(publicKey); + return KeyFactory.getInstance("RSA").generatePublic(spec); + } + + public static PrivateKey getPrivateKey(byte[] privateKey) throws Exception { + PKCS8EncodedKeySpec spec = new PKCS8EncodedKeySpec(privateKey); + return KeyFactory.getInstance("RSA").generatePrivate(spec); + } + + public static Map generateKey(String password) throws IOException, NoSuchAlgorithmException { + KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA"); + SecureRandom secureRandom = new SecureRandom(password.getBytes()); + keyPairGenerator.initialize(1024, secureRandom); + KeyPair keyPair; + byte[] publicKeyBytes = (keyPair = keyPairGenerator.genKeyPair()).getPublic().getEncoded(); + byte[] privateKeyBytes = keyPair.getPrivate().getEncoded(); + HashMap map; + (map = new HashMap()).put("pub", publicKeyBytes); + map.put("pri", privateKeyBytes); + return map; + } + + public static String toHexString(byte[] b) { + return Base64.getEncoder().encodeToString(b); + } + + public static final byte[] toBytes(String s) throws IOException { + return Base64.getDecoder().decode(s); + } + + public static Jws parserToken(String token, byte[] pubKey) throws Exception { + return Jwts.parser().setSigningKey(RsaKeyUtil.getPublicKey(pubKey)).parseClaimsJws(token); + } + + /** + * 测试类 + * + * @param args + * @throws NoSuchAlgorithmException + */ + public static void main(String[] args) throws Exception { + KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA"); + SecureRandom secureRandom = new SecureRandom("123".getBytes()); + keyPairGenerator.initialize(1024, secureRandom); + KeyPair keyPair = keyPairGenerator.genKeyPair(); + System.out.println(keyPair.getPublic().getEncoded()); + + System.out.println("===="); + + /** + * 生成公私密钥 + */ + Map keyMap = RsaKeyUtil.generateKey("123456"); + } +} diff --git a/src/main/java/com/ycwl/basic/utils/SnowFlakeUtil.java b/src/main/java/com/ycwl/basic/utils/SnowFlakeUtil.java new file mode 100644 index 0000000..7fc4d6f --- /dev/null +++ b/src/main/java/com/ycwl/basic/utils/SnowFlakeUtil.java @@ -0,0 +1,138 @@ +package com.ycwl.basic.utils; + + +import com.ycwl.basic.model.snowFlake.UniqueId; +import com.ycwl.basic.model.snowFlake.UniqueIdMetaData; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.stereotype.Component; + +import java.util.Date; + +/** + * @author Created by liuhongguang + * @Description + */ +@Component +public class SnowFlakeUtil { + + private Logger log = LoggerFactory.getLogger(com.ycwl.basic.utils.SnowFlakeUtil.class); + /** + * 记录上一毫秒数 + */ + private static long lastTimestamp = -1L; + + /** + * 记录毫秒内的序列,0-4095 + */ + private static long sequence = 0L; + + private static Long machineId = 1L; + + private static Long datacenterId =1L; + + + public static synchronized String getId() { + long timestamp = System.currentTimeMillis(); + + // 如果当前时间小于上一次ID生成的时间戳,说明系统时钟被修改过,回退在上一次ID生成时间之前应当抛出异常!!! + if (timestamp < lastTimestamp) { + throw new IllegalStateException( + String.format("Clock moved backwards. Refusing to generate id for %d milliseconds", lastTimestamp - timestamp)); + } + + //如果是同一时间生成的,则进行毫秒内序列 + if (lastTimestamp == timestamp) { + sequence = (sequence + 1) & UniqueIdMetaData.SEQUENCE_MASK; + //毫秒内序列溢出 + if (sequence == 0) { + //阻塞到下一个毫秒,获得新的时间戳 + timestamp = System.currentTimeMillis(); + while (timestamp <= lastTimestamp) { + timestamp = System.currentTimeMillis(); + } + return String.valueOf(timestamp); + } + } + //时间戳改变,毫秒内序列重置 + else { + sequence = 0L; + } + + // 上次生成ID的时间截 + lastTimestamp = timestamp; + + // 移位并通过或运算组成64位ID + + return String.valueOf(((timestamp - UniqueIdMetaData.START_TIME) << UniqueIdMetaData.TIMESTAMP_LEFT_SHIFT_BITS) + | (datacenterId << UniqueIdMetaData.DATACENTER_SHIFT_BITS) + | (machineId<< UniqueIdMetaData.MACHINE_SHIFT_BITS) + | sequence); + } + + + + + + public UniqueId explainId(long id) { + UniqueId uniqueId = com.ycwl.basic.utils.SnowFlakeUtil.convert(id); + if (uniqueId == null) { + log.error("==> 解析ID失败, ID不合法"); + return null; + } + return uniqueId; + } + + + public Date transTime(long time) { + return new Date(time + UniqueIdMetaData.START_TIME); + } + + + /** + * 唯一ID对象解析返回ID + * + * @param uniqueId + * @return + */ + public static long convert(UniqueId uniqueId) { + long result = 0; + try { + result = 0L; + + result |= uniqueId.getSequence(); + + result |= uniqueId.getMachineId() << UniqueIdMetaData.MACHINE_SHIFT_BITS; + + result |= uniqueId.getDatacenterId() << UniqueIdMetaData.DATACENTER_SHIFT_BITS; + + result |= uniqueId.getTimestamp() << UniqueIdMetaData.TIMESTAMP_LEFT_SHIFT_BITS; + + } catch (Exception e) { + e.printStackTrace(); + return result; + } + return result; + } + + + public static UniqueId convert(long id) { + UniqueId uniqueId = null; + try { + uniqueId = new UniqueId(); + + uniqueId.setSequence(id & UniqueIdMetaData.SEQUENCE_MASK); + + uniqueId.setMachineId((id >>> UniqueIdMetaData.MACHINE_SHIFT_BITS) & UniqueIdMetaData.MACHINE_MASK); + + uniqueId.setDatacenterId((id >>> UniqueIdMetaData.DATACENTER_SHIFT_BITS) & UniqueIdMetaData.DATACENTER_MASK); + + uniqueId.setTimestamp((id >>> UniqueIdMetaData.TIMESTAMP_LEFT_SHIFT_BITS) & UniqueIdMetaData.TIMESTAMP_MASK); + + } catch (Exception e) { + e.printStackTrace(); + return uniqueId; + } + return uniqueId; + } +} diff --git a/src/main/java/com/ycwl/basic/utils/StringUtil.java b/src/main/java/com/ycwl/basic/utils/StringUtil.java new file mode 100644 index 0000000..195f959 --- /dev/null +++ b/src/main/java/com/ycwl/basic/utils/StringUtil.java @@ -0,0 +1,11 @@ +package com.ycwl.basic.utils; + +public final class StringUtil { + + public StringUtil() { + } + + public static String a(Object obj) { + return obj == null ? "" : obj.toString(); + } +} \ No newline at end of file diff --git a/src/main/java/com/ycwl/basic/xss/XSSHttpServletRequestWrapper.java b/src/main/java/com/ycwl/basic/xss/XSSHttpServletRequestWrapper.java new file mode 100644 index 0000000..4037f47 --- /dev/null +++ b/src/main/java/com/ycwl/basic/xss/XSSHttpServletRequestWrapper.java @@ -0,0 +1,200 @@ +package com.ycwl.basic.xss; + + +import cn.hutool.core.collection.CollectionUtil; +import org.apache.commons.lang3.StringUtils; +import org.apache.commons.text.StringEscapeUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import javax.servlet.ReadListener; +import javax.servlet.ServletInputStream; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletRequestWrapper; +import java.io.*; +import java.nio.charset.StandardCharsets; +import java.util.Arrays; +import java.util.Map; + +/** + * 重新包装一下Request。重写一些获取参数的方法,将每个参数都进行过滤 + */ +public class XSSHttpServletRequestWrapper extends HttpServletRequestWrapper { + private static final Logger logger = LoggerFactory.getLogger(XSSHttpServletRequestWrapper.class); + + private HttpServletRequest request; + /** + * 请求体 RequestBody + */ + private String reqBody; + + /** + * Constructs a request object wrapping the given request. + * + * @param request The request to wrap + * @throws IllegalArgumentException if the request is null + */ + public XSSHttpServletRequestWrapper(HttpServletRequest request) { + super(request); + logger.info("---xss XSSHttpServletRequestWrapper created-----"); + this.request = request; + reqBody = getBodyString(); + } + + + @Override + public String getQueryString() { + return StringEscapeUtils.escapeHtml4(super.getQueryString()); + } + + /** + * The default behavior of this method is to return getParameter(String + * name) on the wrapped request object. + * + * @param name + */ + @Override + public String getParameter(String name) { + logger.info("---xss XSSHttpServletRequestWrapper work getParameter-----"); + String parameter = request.getParameter(name); + if (StringUtils.isNotBlank(parameter)) { + logger.info("----filter before--name:{}--value:{}----", name, parameter); + parameter = StringEscapeUtils.escapeHtml4(parameter); + logger.info("----filter after--name:{}--value:{}----", name, parameter); + } + return parameter; + } + + /** + * The default behavior of this method is to return + * getParameterValues(String name) on the wrapped request object. + * + * @param name + */ + @Override + public String[] getParameterValues(String name) { + logger.info("---xss XSSHttpServletRequestWrapper work getParameterValues-----"); + String[] parameterValues = request.getParameterValues(name); + if (parameterValues != null && parameterValues.length > 0) { + if (!CollectionUtil.isEmpty(Arrays.asList(parameterValues))) { + // 经 “@Belief_7” 指正 这种方式不能更改parameterValues里面的值,要换成下面👇的写法 + //for (String value : parameterValues) { + // logger.info("----filter before--name:{}--value:{}----", name, value); + // value = StringEscapeUtils.escapeHtml4(value); + // logger.info("----filter after--name:{}--value:{}----", name, value); + // } + for (int i = 0; i < parameterValues.length; i++) + { + parameterValues[i] = StringEscapeUtils.escapeHtml4(parameterValues[i]); + } + } + } + return parameterValues; + } + + /** + * The default behavior of this method is to return getParameterMap() on the + * wrapped request object. + */ + @Override + public Map getParameterMap() { + logger.info("---xss XSSHttpServletRequestWrapper work getParameterMap-----"); + Map map = request.getParameterMap(); + if (map != null && !map.isEmpty()) { + for (String[] value : map.values()) { + /*循环所有的value*/ + for (String str : value) { + logger.info("----filter before--value:{}----", str, str); + str = StringEscapeUtils.escapeHtml4(str); + logger.info("----filter after--value:{}----", str, str); + } + } + } + return map; + } + + /*重写输入流的方法,因为使用RequestBody的情况下是不会走上面的方法的*/ + /** + * The default behavior of this method is to return getReader() on the + * wrapped request object. + */ + @Override + public BufferedReader getReader() throws IOException { + logger.info("---xss XSSHttpServletRequestWrapper work getReader-----"); + return new BufferedReader(new InputStreamReader(getInputStream())); + } + + /** + * The default behavior of this method is to return getInputStream() on the + * wrapped request object. + */ + @Override + public ServletInputStream getInputStream() throws IOException { + logger.info("---xss XSSHttpServletRequestWrapper work getInputStream-----"); + /*创建字节数组输入流*/ + final ByteArrayInputStream bais = new ByteArrayInputStream(reqBody.getBytes(StandardCharsets.UTF_8)); + return new ServletInputStream() { + @Override + public boolean isFinished() { + return false; + } + + @Override + public boolean isReady() { + return false; + } + + @Override + public void setReadListener(ReadListener listener) { + } + + @Override + public int read() throws IOException { + return bais.read(); + } + }; + } + + + /** + * 获取请求体 + * + * @return 请求体 + */ + private String getBodyString() { + StringBuilder builder = new StringBuilder(); + InputStream inputStream = null; + BufferedReader reader = null; + + try { + inputStream = request.getInputStream(); + + reader = new BufferedReader(new InputStreamReader(inputStream)); + + String line; + + while ((line = reader.readLine()) != null) { + builder.append(line); + } + } catch (IOException e) { + logger.error("-----get Body String Error:{}----", e.getMessage(), e); + } finally { + if (inputStream != null) { + try { + inputStream.close(); + } catch (IOException e) { + logger.error("-----get Body String Error:{}----", e.getMessage(), e); + } + } + if (reader != null) { + try { + reader.close(); + } catch (IOException e) { + logger.error("-----get Body String Error:{}----", e.getMessage(), e); + } + } + } + return builder.toString(); + } +} + diff --git a/src/main/java/com/ycwl/basic/xss/XssJacksonDeserializer.java b/src/main/java/com/ycwl/basic/xss/XssJacksonDeserializer.java new file mode 100644 index 0000000..ce20ea7 --- /dev/null +++ b/src/main/java/com/ycwl/basic/xss/XssJacksonDeserializer.java @@ -0,0 +1,17 @@ +package com.ycwl.basic.xss; + +import com.fasterxml.jackson.core.JsonParser; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.DeserializationContext; +import com.fasterxml.jackson.databind.JsonDeserializer; +import org.apache.commons.text.StringEscapeUtils; +import java.io.IOException; + + +public class XssJacksonDeserializer extends JsonDeserializer { + @Override + public String deserialize(JsonParser jp, DeserializationContext ctxt) throws IOException, JsonProcessingException { + return StringEscapeUtils.escapeHtml4(jp.getText()); + } + +} diff --git a/src/main/java/com/ycwl/basic/xss/XssJacksonSerializer.java b/src/main/java/com/ycwl/basic/xss/XssJacksonSerializer.java new file mode 100644 index 0000000..726b423 --- /dev/null +++ b/src/main/java/com/ycwl/basic/xss/XssJacksonSerializer.java @@ -0,0 +1,18 @@ +package com.ycwl.basic.xss; + +import com.fasterxml.jackson.core.JsonGenerator; +import com.fasterxml.jackson.databind.JsonSerializer; +import com.fasterxml.jackson.databind.SerializerProvider; +import org.apache.commons.text.StringEscapeUtils; +import java.io.IOException; + +public class XssJacksonSerializer extends JsonSerializer{ + @Override + public void serialize(String value, JsonGenerator jgen, SerializerProvider provider) throws IOException { + jgen.writeString(StringEscapeUtils.escapeHtml4(value)); + } + + + + +} diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml new file mode 100644 index 0000000..29a10da --- /dev/null +++ b/src/main/resources/application.yml @@ -0,0 +1,62 @@ +server: + port: 8030 + +spring: + application: + name: basic + main: + allow-bean-definition-overriding: true + mvc: + # 启用hiddenMethod过滤器(头像上传) + hiddenmethod: + filter: + enabled: true + datasource: # 数据源的相关配置 + type: com.zaxxer.hikari.HikariDataSource # 数据源类型:HikariCP + driver-class-name: com.mysql.cj.jdbc.Driver # mysql驱动 + url: jdbc:mysql://8.134.112.96:3306/liuying_mgmt_re?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true + username: root + password: yckj2017 + hikari: + connection-timeout: 30000 # 等待连接池分配连接的最大时长(毫秒),超过这个时长还没可用的连接则发生SQLException, 默认:30秒 + minimum-idle: 5 # 最小连接数 + maximum-pool-size: 20 # 最大连接数 + auto-commit: true # 事务自动提交 + idle-timeout: 60000 # 连接超时的最大时长(毫秒) + pool-name: DateSourceHikariCP # 连接池名字 + max-lifetime: 180000 # 连接的生命时长(毫秒) + connection-test-query: SELECT 1 # 连接测试语句 + jackson: + date-format: "yyyy-MM-dd HH:mm:ss" + time-zone: GMT+8 + redis: + host: 10.59.3.242 + port: 6379 + # 密码过于复杂需要使用''引起来,要不可能导致项目无法启动,因为无法识别特殊字符 + password: yckj2018 + jedis: + pool: + max-active: -1 # 连接池最大连接数(使用负值表示没有限制) + min-idle: 1 # 连接池中的最小空闲连接 + time-between-eviction-runs: 3000 + timeout: 40000 + # 配置用户头像存放静态资源文件夹 + resources: + static-locations: classpath:/META-INF/resources/,classpath:/resources/,classpath:/static/,classpath:/public/ + # 配置请求文件大小 + servlet: + multipart: + max-file-size: 10MB + max-request-size: 10MB + +# MyBatis +mybatis-plus: + configuration: + # 开启驼峰命名法 + map-underscore-to-camel-case: true + use-generated-keys: true + # 这个配置会将执行的sql打印出来,在开发或测试的时候可以用 + log-impl: org.apache.ibatis.logging.stdout.StdOutImpl +# 指定使用的日志配置文件 +logging: + config: classpath:logback-spring.xml diff --git a/src/main/resources/logback-spring.xml b/src/main/resources/logback-spring.xml new file mode 100644 index 0000000..7170e80 --- /dev/null +++ b/src/main/resources/logback-spring.xml @@ -0,0 +1,133 @@ + + + + + + + + + + + + + + + + + %d{yyyy-MM-dd HH:mm:ss.SSS} %highlight(%-5level) --- [%15.15(%thread)] %cyan(%-40.40(%logger{40})) : %msg%n + + UTF-8 + + + + + + + + + + logs/project_info.log + + true + + ERROR + DENY + ACCEPT + + + + + + + logs/project_info.%d.%i.log + + 30 + + 20GB + + 10MB + + + + + %d{yyyy-MM-dd HH:mm:ss.SSS} %-5level --- [%15.15(%thread)] %-40.40(%logger{40}) : %msg%n + + UTF-8 + + + + + + + + + + logs/project_error.log + + true + + + ERROR + + + + + + + logs/project_error.%d.%i.log + + 30 + + 20GB + + 10MB + + + + + %d{yyyy-MM-dd HH:mm:ss.SSS} %-5level --- [%15.15(%thread)] %-40.40(%logger{40}) : %msg%n + + UTF-8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/main/resources/mapper/pc/AdminUserMapper.xml b/src/main/resources/mapper/pc/AdminUserMapper.xml new file mode 100644 index 0000000..af3f09b --- /dev/null +++ b/src/main/resources/mapper/pc/AdminUserMapper.xml @@ -0,0 +1,103 @@ + + + + + insert into admin_user(`id`, + `role_id`, + `staff_id`, + `account`, + `password`) + values (#{id}, + #{roleId}, + #{staffId}, + #{account}, + #{password}) + + + update + admin_user + set is_remove=1 + where id = #{id} + + + + update + admin_user + set password=#{password} + where id = #{id} + + + + update admin_user + set `role_id` =#{roleId}, + `staff_id` =#{staffId} + where id = #{id} + + + update + admin_user + set password=#{newPwd} + where staff_id = #{id} + and is_remove = 0 + + + + + + + + diff --git a/src/main/resources/mapper/pc/MenuMapper.xml b/src/main/resources/mapper/pc/MenuMapper.xml new file mode 100644 index 0000000..a08b20f --- /dev/null +++ b/src/main/resources/mapper/pc/MenuMapper.xml @@ -0,0 +1,31 @@ + + + + + insert into role_menu(`role_id`, `menu_id`) + values + + (#{id},#{item}) + + + + + delete + from role_menu + where role_id = #{id} + + + + + + diff --git a/src/main/resources/mapper/pc/RoleMapper.xml b/src/main/resources/mapper/pc/RoleMapper.xml new file mode 100644 index 0000000..3fd7e38 --- /dev/null +++ b/src/main/resources/mapper/pc/RoleMapper.xml @@ -0,0 +1,80 @@ + + + + + insert into role(`id`, `name`, `type`) + values (#{id}, #{name}, #{type}) + + + + update + role + set is_remove=1 + where id = #{id} + + + + update + role + set `name`=#{name} + where id = #{id} + + + + + + + + + + + update + role + set status = + (CASE + status + WHEN 1 THEN + 0 + WHEN 0 THEN + 1 + ELSE null + END) + where id = #{id} + + diff --git a/src/test/java/com/ycwl/basic/BasicApplicationTests.java b/src/test/java/com/ycwl/basic/BasicApplicationTests.java new file mode 100644 index 0000000..bc67874 --- /dev/null +++ b/src/test/java/com/ycwl/basic/BasicApplicationTests.java @@ -0,0 +1,13 @@ +package com.ycwl.basic; + +import org.junit.jupiter.api.Test; +import org.springframework.boot.test.context.SpringBootTest; + +@SpringBootTest +class BasicApplicationTests { + + @Test + void contextLoads() { + } + +}