From 73feff4dbbf9a91b0c65266f740a05047f45cfc8 Mon Sep 17 00:00:00 2001 From: easonzhu Date: Mon, 17 Mar 2025 10:46:29 +0800 Subject: [PATCH] first commit --- .gitignore | 14 + pom.xml | 180 +++++++++ .../diagnose/common/aspect/AuthAspect.java~ | 51 +++ .../diagnose/common/aspect/TaskAspect.java | 45 +++ .../diagnose/common/aspect/WebLogAspect.java | 82 ++++ .../diagnose/common/config/JsonConfig.java | 47 +++ .../common/config/ScheduleConfig.java | 22 ++ .../common/config/Swagger3Config.java | 47 +++ .../common/config/UpCorsConfiguration.java | 32 ++ .../common/config/cache/CacheConfig.java | 47 +++ .../common/config/cache/CacheConfig.java~ | 72 ++++ .../common/config/cache/CacheKey.java | 25 ++ .../common/config/cache/CacheKey.java~ | 373 ++++++++++++++++++ .../config/cache/HazelcastConfiguration.java | 91 +++++ .../config/mybatis/EasySqlInjector.java | 21 + .../config/mybatis/MybatisPlusConfig.java | 26 ++ .../config/mybatis/MybatisPlusConfig.java~ | 26 ++ .../diagnose/common/config/mybatis/Save.java | 64 +++ .../config/mybatis/SaveBatchSomeColumn.java | 99 +++++ .../common/constant/ScheduleLogResult.java | 25 ++ .../diagnose/common/entity/ScheduleLog.java | 208 ++++++++++ .../common/generator/CodeGenerator.java | 84 ++++ .../common/generator/CodeGenerator.java~ | 84 ++++ .../diagnose/common/handler/BizException.java | 72 ++++ .../common/handler/BizException.java~ | 72 ++++ .../handler/GlobalExceptionHandler.java | 97 +++++ .../common/mapper/ScheduleLogMapper.java | 16 + .../common/query/AppUserInfoQuery.java~ | 82 ++++ .../common/query/BaseProductQuery.java~ | 35 ++ .../common/query/KeywordPageQuery.java | 18 + .../common/query/ListAdvertQuery.java~ | 61 +++ .../common/query/ListScheduleLogQuery.java | 62 +++ .../common/query/OnlyIdPageQuery.java | 29 ++ .../diagnose/common/query/OnlyIdQuery.java | 29 ++ .../com/diagnose/common/query/PageQuery.java | 40 ++ .../common/query/SaveAdvertQuery.java~ | 114 ++++++ .../common/query/SetCommentTopQuery.java~ | 50 +++ .../com/diagnose/common/result/AppPager.java | 41 ++ .../diagnose/common/result/CommonResult.java | 87 ++++ .../com/diagnose/common/result/Pager.java | 49 +++ .../common/result/ResponseStatus.java | 59 +++ .../diagnose/common/service/CacheService.java | 317 +++++++++++++++ .../common/service/CommentBlackService.java~ | 285 +++++++++++++ .../common/service/MergeProductService.java~ | 112 ++++++ .../common/service/ScheduleLogService.java | 70 ++++ .../com/diagnose/common/util/CodecUtil.java | 58 +++ .../com/diagnose/common/util/CollectUtil.java | 15 + .../com/diagnose/common/util/Debounce.java | 48 +++ .../com/diagnose/common/util/HideUtils.java | 28 ++ .../java/com/diagnose/common/util/IPUtil.java | 39 ++ .../diagnose/common/util/RequestIdUtil.java | 41 ++ .../diagnose/common/util/RequestIdUtil.java~ | 41 ++ .../com/diagnose/common/util/RsaUtil.java | 145 +++++++ .../common/util/ShortUrlGenerator.java | 18 + .../com/diagnose/common/util/TextUtil.java | 28 ++ .../java/com/diagnose/common/util/UpDes.java | 142 +++++++ .../diagnose/common/util/WebServerInfo.java | 32 ++ .../common/util/logger/LoggerAgent.java | 46 +++ .../common/util/logger/LoggerUtil.java | 33 ++ .../common/validation/EnumValidator.java | 68 ++++ .../common/validation/IntArrayValidator.java | 56 +++ .../com/diagnose/common/vo/AdvertAppVO.java~ | 73 ++++ .../diagnose/common/vo/AppCUserInfoVO.java~ | 108 +++++ .../diagnose/common/vo/AppUserInfoVO.java~ | 81 ++++ .../java/com/diagnose/common/vo/AuthVO.java~ | 68 ++++ .../java/com/diagnose/common/vo/CountVO.java | 21 + .../com/diagnose/common/vo/IdCountVO.java | 24 ++ .../java/com/diagnose/common/vo/IdNameVO.java | 34 ++ .../com/diagnose/common/vo/InsertIdVO.java | 21 + .../com/diagnose/common/vo/OnlyBoolVO.java | 25 ++ .../java/com/diagnose/common/vo/OnlyIdVO.java | 25 ++ .../diagnose/common/vo/SafetyConfigVO.java~ | 153 +++++++ .../diagnose/common/vo/SensitiveWordVO.java~ | 48 +++ .../java/com/diagnose/constant/MktNum.java | 19 + .../com/diagnose/constant/MktTypePar.java | 19 + .../com/diagnose/constant/RiskLevel.java~ | 41 ++ .../java/com/diagnose/constant/SecMarPar.java | 19 + .../controller/DiagnoseController.java | 54 +++ .../diagnose/entity/CommentSortEntity.java~ | 92 +++++ .../java/com/diagnose/entity/RiskLevel.java~ | 92 +++++ .../com/diagnose/entity/ScheduleLog.java~ | 208 ++++++++++ .../com/diagnose/entity/SensitiveWord.java~ | 70 ++++ .../java/com/diagnose/entity/ShortUrl.java~ | 57 +++ .../com/diagnose/mapper/CommentMapper.java~ | 25 ++ .../com/diagnose/mapper/DiagnoseMapper.java | 34 ++ .../com/diagnose/mapper/FinanceMapper.java | 35 ++ .../java/com/diagnose/mapper/StockMapper.java | 19 + .../com/diagnose/mapper/UnionMapper.java~ | 18 + .../com/diagnose/service/SearchService.java | 36 ++ .../com/diagnose/service/SearchService.java~ | 38 ++ .../com/diagnose/service/StockService.java | 109 +++++ src/main/java/com/diagnose/startup/Main.java | 25 ++ src/main/java/com/diagnose/test3.java~ | 48 +++ .../java/com/diagnose/util/StringMatcher.java | 80 ++++ .../java/com/diagnose/util/TestSearch.java | 34 ++ .../vo/ComprehensiveEvaluationVO.java | 43 ++ .../com/diagnose/vo/DiagnoseBackTestVO.java | 44 +++ .../java/com/diagnose/vo/DiagnoseRankVO.java | 133 +++++++ .../com/diagnose/vo/FinanceCashShortVO.java | 51 +++ .../diagnose/vo/FinanceIndexAnalysisVO.java | 110 ++++++ .../diagnose/vo/FinanceIndexAnalysisVO.java~ | 102 +++++ .../com/diagnose/vo/FinancialValuationVO.java | 54 +++ src/main/java/com/diagnose/vo/StockVO.java | 146 +++++++ src/main/resources/application-dev.yaml | 10 + src/main/resources/application-prod.yaml | 10 + src/main/resources/application-test.yaml | 10 + src/main/resources/application.yaml | 3 + src/main/resources/dev/application.yaml | 44 +++ src/main/resources/logback-dev.xml | 15 + src/main/resources/logback-prod.xml | 58 +++ src/main/resources/logback-spring.xml | 18 + src/main/resources/logback-tst.xml | 54 +++ src/main/resources/prod/application.yaml | 44 +++ src/main/webapp/web.xml | 6 + 114 files changed, 7208 insertions(+) create mode 100644 .gitignore create mode 100644 pom.xml create mode 100644 src/main/java/com/diagnose/common/aspect/AuthAspect.java~ create mode 100644 src/main/java/com/diagnose/common/aspect/TaskAspect.java create mode 100644 src/main/java/com/diagnose/common/aspect/WebLogAspect.java create mode 100644 src/main/java/com/diagnose/common/config/JsonConfig.java create mode 100644 src/main/java/com/diagnose/common/config/ScheduleConfig.java create mode 100644 src/main/java/com/diagnose/common/config/Swagger3Config.java create mode 100644 src/main/java/com/diagnose/common/config/UpCorsConfiguration.java create mode 100644 src/main/java/com/diagnose/common/config/cache/CacheConfig.java create mode 100644 src/main/java/com/diagnose/common/config/cache/CacheConfig.java~ create mode 100644 src/main/java/com/diagnose/common/config/cache/CacheKey.java create mode 100644 src/main/java/com/diagnose/common/config/cache/CacheKey.java~ create mode 100644 src/main/java/com/diagnose/common/config/cache/HazelcastConfiguration.java create mode 100644 src/main/java/com/diagnose/common/config/mybatis/EasySqlInjector.java create mode 100644 src/main/java/com/diagnose/common/config/mybatis/MybatisPlusConfig.java create mode 100644 src/main/java/com/diagnose/common/config/mybatis/MybatisPlusConfig.java~ create mode 100644 src/main/java/com/diagnose/common/config/mybatis/Save.java create mode 100644 src/main/java/com/diagnose/common/config/mybatis/SaveBatchSomeColumn.java create mode 100644 src/main/java/com/diagnose/common/constant/ScheduleLogResult.java create mode 100644 src/main/java/com/diagnose/common/entity/ScheduleLog.java create mode 100644 src/main/java/com/diagnose/common/generator/CodeGenerator.java create mode 100644 src/main/java/com/diagnose/common/generator/CodeGenerator.java~ create mode 100644 src/main/java/com/diagnose/common/handler/BizException.java create mode 100644 src/main/java/com/diagnose/common/handler/BizException.java~ create mode 100644 src/main/java/com/diagnose/common/handler/GlobalExceptionHandler.java create mode 100644 src/main/java/com/diagnose/common/mapper/ScheduleLogMapper.java create mode 100644 src/main/java/com/diagnose/common/query/AppUserInfoQuery.java~ create mode 100644 src/main/java/com/diagnose/common/query/BaseProductQuery.java~ create mode 100644 src/main/java/com/diagnose/common/query/KeywordPageQuery.java create mode 100644 src/main/java/com/diagnose/common/query/ListAdvertQuery.java~ create mode 100644 src/main/java/com/diagnose/common/query/ListScheduleLogQuery.java create mode 100644 src/main/java/com/diagnose/common/query/OnlyIdPageQuery.java create mode 100644 src/main/java/com/diagnose/common/query/OnlyIdQuery.java create mode 100644 src/main/java/com/diagnose/common/query/PageQuery.java create mode 100644 src/main/java/com/diagnose/common/query/SaveAdvertQuery.java~ create mode 100644 src/main/java/com/diagnose/common/query/SetCommentTopQuery.java~ create mode 100644 src/main/java/com/diagnose/common/result/AppPager.java create mode 100644 src/main/java/com/diagnose/common/result/CommonResult.java create mode 100644 src/main/java/com/diagnose/common/result/Pager.java create mode 100644 src/main/java/com/diagnose/common/result/ResponseStatus.java create mode 100644 src/main/java/com/diagnose/common/service/CacheService.java create mode 100644 src/main/java/com/diagnose/common/service/CommentBlackService.java~ create mode 100644 src/main/java/com/diagnose/common/service/MergeProductService.java~ create mode 100644 src/main/java/com/diagnose/common/service/ScheduleLogService.java create mode 100644 src/main/java/com/diagnose/common/util/CodecUtil.java create mode 100644 src/main/java/com/diagnose/common/util/CollectUtil.java create mode 100644 src/main/java/com/diagnose/common/util/Debounce.java create mode 100644 src/main/java/com/diagnose/common/util/HideUtils.java create mode 100644 src/main/java/com/diagnose/common/util/IPUtil.java create mode 100644 src/main/java/com/diagnose/common/util/RequestIdUtil.java create mode 100644 src/main/java/com/diagnose/common/util/RequestIdUtil.java~ create mode 100644 src/main/java/com/diagnose/common/util/RsaUtil.java create mode 100644 src/main/java/com/diagnose/common/util/ShortUrlGenerator.java create mode 100644 src/main/java/com/diagnose/common/util/TextUtil.java create mode 100644 src/main/java/com/diagnose/common/util/UpDes.java create mode 100644 src/main/java/com/diagnose/common/util/WebServerInfo.java create mode 100644 src/main/java/com/diagnose/common/util/logger/LoggerAgent.java create mode 100644 src/main/java/com/diagnose/common/util/logger/LoggerUtil.java create mode 100644 src/main/java/com/diagnose/common/validation/EnumValidator.java create mode 100644 src/main/java/com/diagnose/common/validation/IntArrayValidator.java create mode 100644 src/main/java/com/diagnose/common/vo/AdvertAppVO.java~ create mode 100644 src/main/java/com/diagnose/common/vo/AppCUserInfoVO.java~ create mode 100644 src/main/java/com/diagnose/common/vo/AppUserInfoVO.java~ create mode 100644 src/main/java/com/diagnose/common/vo/AuthVO.java~ create mode 100644 src/main/java/com/diagnose/common/vo/CountVO.java create mode 100644 src/main/java/com/diagnose/common/vo/IdCountVO.java create mode 100644 src/main/java/com/diagnose/common/vo/IdNameVO.java create mode 100644 src/main/java/com/diagnose/common/vo/InsertIdVO.java create mode 100644 src/main/java/com/diagnose/common/vo/OnlyBoolVO.java create mode 100644 src/main/java/com/diagnose/common/vo/OnlyIdVO.java create mode 100644 src/main/java/com/diagnose/common/vo/SafetyConfigVO.java~ create mode 100644 src/main/java/com/diagnose/common/vo/SensitiveWordVO.java~ create mode 100644 src/main/java/com/diagnose/constant/MktNum.java create mode 100644 src/main/java/com/diagnose/constant/MktTypePar.java create mode 100644 src/main/java/com/diagnose/constant/RiskLevel.java~ create mode 100644 src/main/java/com/diagnose/constant/SecMarPar.java create mode 100644 src/main/java/com/diagnose/controller/DiagnoseController.java create mode 100644 src/main/java/com/diagnose/entity/CommentSortEntity.java~ create mode 100644 src/main/java/com/diagnose/entity/RiskLevel.java~ create mode 100644 src/main/java/com/diagnose/entity/ScheduleLog.java~ create mode 100644 src/main/java/com/diagnose/entity/SensitiveWord.java~ create mode 100644 src/main/java/com/diagnose/entity/ShortUrl.java~ create mode 100644 src/main/java/com/diagnose/mapper/CommentMapper.java~ create mode 100644 src/main/java/com/diagnose/mapper/DiagnoseMapper.java create mode 100644 src/main/java/com/diagnose/mapper/FinanceMapper.java create mode 100644 src/main/java/com/diagnose/mapper/StockMapper.java create mode 100644 src/main/java/com/diagnose/mapper/UnionMapper.java~ create mode 100644 src/main/java/com/diagnose/service/SearchService.java create mode 100644 src/main/java/com/diagnose/service/SearchService.java~ create mode 100644 src/main/java/com/diagnose/service/StockService.java create mode 100644 src/main/java/com/diagnose/startup/Main.java create mode 100644 src/main/java/com/diagnose/test3.java~ create mode 100644 src/main/java/com/diagnose/util/StringMatcher.java create mode 100644 src/main/java/com/diagnose/util/TestSearch.java create mode 100644 src/main/java/com/diagnose/vo/ComprehensiveEvaluationVO.java create mode 100644 src/main/java/com/diagnose/vo/DiagnoseBackTestVO.java create mode 100644 src/main/java/com/diagnose/vo/DiagnoseRankVO.java create mode 100644 src/main/java/com/diagnose/vo/FinanceCashShortVO.java create mode 100644 src/main/java/com/diagnose/vo/FinanceIndexAnalysisVO.java create mode 100644 src/main/java/com/diagnose/vo/FinanceIndexAnalysisVO.java~ create mode 100644 src/main/java/com/diagnose/vo/FinancialValuationVO.java create mode 100644 src/main/java/com/diagnose/vo/StockVO.java create mode 100644 src/main/resources/application-dev.yaml create mode 100644 src/main/resources/application-prod.yaml create mode 100644 src/main/resources/application-test.yaml create mode 100644 src/main/resources/application.yaml create mode 100644 src/main/resources/dev/application.yaml create mode 100644 src/main/resources/logback-dev.xml create mode 100644 src/main/resources/logback-prod.xml create mode 100644 src/main/resources/logback-spring.xml create mode 100644 src/main/resources/logback-tst.xml create mode 100644 src/main/resources/prod/application.yaml create mode 100644 src/main/webapp/web.xml diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..a7402e6 --- /dev/null +++ b/.gitignore @@ -0,0 +1,14 @@ +HELP.md +target/ +!.mvn/wrapper/maven-wrapper.jar +!**/src/main/**/target/ +!**/src/test/**/target/ + +### IntelliJ IDEA ### +.idea +*.iws +*.iml +*.ipr +*.log + +.vscode \ No newline at end of file diff --git a/pom.xml b/pom.xml new file mode 100644 index 0000000..d23f351 --- /dev/null +++ b/pom.xml @@ -0,0 +1,180 @@ + + + + 4.0.0 + DiagnoseApiServer + jar + + org.springframework.boot + spring-boot-starter-parent + 2.6.7 + + + + 11 + 11 + + + + org.springframework.boot + spring-boot-starter-web + + + org.springframework.boot + spring-boot-starter-aop + + + org.hibernate.validator + hibernate-validator + 6.2.0.Final + + + com.baomidou + mybatis-plus-boot-starter + 3.5.1 + + + com.baomidou + mybatis-plus-generator + 3.5.0 + + + org.freemarker + freemarker + 2.3.31 + + + com.baomidou + dynamic-datasource-spring-boot-starter + 3.5.0 + + + mysql + mysql-connector-java + 8.0.13 + + + com.hazelcast + hazelcast + 5.3.8 + + + com.hazelcast + hazelcast-sql + 5.3.8 + + + com.hazelcast + hazelcast-spring + 5.3.8 + + + com.alibaba + fastjson + 1.2.83 + + + io.springfox + springfox-boot-starter + 3.0.0 + + + + com.github.xiaoymin + knife4j-spring-boot-starter + 3.0.3 + + + com.google.guava + guava + 30.1.1-jre + + + cn.hutool + hutool-all + 5.8.3 + + + org.ahocorasick + ahocorasick + 0.6.3 + + + org.jsoup + jsoup + 1.9.2 + + + + com.tencentcloudapi + tencentcloud-sdk-java + + + 3.1.1142 + + + + + org.slf4j + slf4j-api + 1.7.36 + + + + + ch.qos.logback + logback-classic + 1.2.11 + + + + + ch.qos.logback + logback-core + 1.2.11 + + + + + org.slf4j + slf4j-log4j12 + 1.7.36 + runtime + + + + + + org.springframework.boot + spring-boot-maven-plugin + + com.syzb.startup.Main + + + + + + + thin-jar + + + + org.springframework.boot + spring-boot-maven-plugin + + com.syzb.startup.Main + ZIP + + + nothing + nothing + + + + + + + + + diff --git a/src/main/java/com/diagnose/common/aspect/AuthAspect.java~ b/src/main/java/com/diagnose/common/aspect/AuthAspect.java~ new file mode 100644 index 0000000..7089f31 --- /dev/null +++ b/src/main/java/com/diagnose/common/aspect/AuthAspect.java~ @@ -0,0 +1,51 @@ +package com.common.aspect; + +import com.common.annotation.Auth; +import com.common.constant.AccessRole; +import com.common.vo.BackendUserVO; +import com.rbac.service.AuthService; +import org.aspectj.lang.JoinPoint; +import org.aspectj.lang.annotation.Aspect; +import org.aspectj.lang.annotation.Before; +import org.aspectj.lang.annotation.Pointcut; +import org.aspectj.lang.reflect.MethodSignature; +import org.springframework.stereotype.Component; +import org.springframework.web.context.request.RequestContextHolder; +import org.springframework.web.context.request.ServletRequestAttributes; + +import javax.annotation.Resource; +import javax.servlet.http.HttpServletRequest; +import java.lang.reflect.Method; + +@Aspect +@Component +public class AuthAspect { + + @Resource + AuthService authService; + + @Pointcut("@annotation(com.common.annotation.Auth)") + private void pointcut() { + } + + // 前置通知 + @Before("pointcut()") + public void beforeCall(JoinPoint joinPoint) { + ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder.currentRequestAttributes(); + HttpServletRequest request = requestAttributes.getRequest(); + BackendUserVO backendUser = (BackendUserVO) request.getAttribute("backendUser"); + // 获取注解中的参数值 + MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature(); + Method method = methodSignature.getMethod(); + // 获取注解 + Auth annotation = method.getAnnotation(Auth.class); + // 获取注解参数的值 + AccessRole role = annotation.role(); + // 验证帐号的合法性 + authService.checkUserStatus(backendUser, role); + String callUrl = request.getRequestURI(); + // 校验权限 + //authService.checkUserPermission(backendUser, callUrl); + } + +} diff --git a/src/main/java/com/diagnose/common/aspect/TaskAspect.java b/src/main/java/com/diagnose/common/aspect/TaskAspect.java new file mode 100644 index 0000000..7aa4093 --- /dev/null +++ b/src/main/java/com/diagnose/common/aspect/TaskAspect.java @@ -0,0 +1,45 @@ +package com.diagnose.common.aspect; + +import com.diagnose.common.util.RequestIdUtil; +import com.diagnose.common.util.logger.LoggerUtil; +import org.aspectj.lang.JoinPoint; +import org.aspectj.lang.annotation.AfterReturning; +import org.aspectj.lang.annotation.Aspect; +import org.aspectj.lang.annotation.Before; +import org.aspectj.lang.annotation.Pointcut; +import org.aspectj.lang.reflect.MethodSignature; +import org.springframework.stereotype.Component; + +import java.lang.reflect.Method; +import java.util.Date; + +@Aspect +@Component +public class TaskAspect { + + @Pointcut("@annotation(org.springframework.scheduling.annotation.Scheduled)") + private void scheduledPointcut() { + } + + // 前置通知 + @Before("scheduledPointcut()") + public void beforeCall(JoinPoint joinPoint) { + RequestIdUtil.setTime(); + RequestIdUtil.setValue("TIME"); + // 获取注解中的参数值 + MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature(); + Method method = methodSignature.getMethod(); + LoggerUtil.data.info(String.format("定时任务:%s:启动了", method.getName())); + } + + // 最终通知 + @AfterReturning(pointcut = "scheduledPointcut()") + public void afterReturningCall(JoinPoint joinPoint) { + long start = RequestIdUtil.getTime(); + long time = new Date().getTime() - start; + // 获取注解中的参数值 + MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature(); + Method method = methodSignature.getMethod(); + LoggerUtil.data.info(String.format("定时任务:%s:耗时:%d", method.getName(), time)); + } +} diff --git a/src/main/java/com/diagnose/common/aspect/WebLogAspect.java b/src/main/java/com/diagnose/common/aspect/WebLogAspect.java new file mode 100644 index 0000000..07ef4fa --- /dev/null +++ b/src/main/java/com/diagnose/common/aspect/WebLogAspect.java @@ -0,0 +1,82 @@ +package com.diagnose.common.aspect; + +import com.alibaba.fastjson.JSONObject; +import com.diagnose.common.util.RequestIdUtil; +import com.diagnose.common.util.logger.LoggerUtil; +import org.apache.commons.lang3.exception.ExceptionUtils; +import org.aspectj.lang.JoinPoint; +import org.aspectj.lang.annotation.*; +import org.springframework.http.HttpEntity; +import org.springframework.stereotype.Component; +import org.springframework.web.context.request.RequestContextHolder; +import org.springframework.web.context.request.ServletRequestAttributes; +import org.springframework.web.multipart.MultipartFile; + +import javax.servlet.ServletRequest; +import javax.servlet.ServletResponse; +import javax.servlet.http.HttpServletRequest; +import java.util.ArrayList; +import java.util.Date; +import java.util.List; + +@Aspect +@Component +public class WebLogAspect { + + @Pointcut("@annotation(org.springframework.web.bind.annotation.RequestMapping)") + private void requestPointcut() { + } + + @Pointcut("@annotation(org.springframework.web.bind.annotation.GetMapping)") + private void getPointcut() { + } + + @Pointcut("@annotation(org.springframework.web.bind.annotation.PostMapping)") + private void postPointcut() { + } + + // 前置通知 + @Before("requestPointcut() || getPointcut() || postPointcut()") + public void beforeCall(JoinPoint joinPoint) { + RequestIdUtil.setTime(); + ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder.currentRequestAttributes(); + HttpServletRequest request = requestAttributes.getRequest(); + Object[] args = joinPoint.getArgs(); + List arguments = new ArrayList<>(); + for (Object arg : args) { + if (arg instanceof ServletRequest || arg instanceof ServletResponse || arg instanceof MultipartFile) { + //ServletRequest不能序列化,从入参里排除,否则报异常:java.lang.IllegalStateException: It is illegal to call this method if the current request is not in asynchronous mode (i.e. isAsyncStarted() returns false) + //ServletResponse不能序列化 从入参里排除,否则报异常:java.lang.IllegalStateException: getOutputStream() has already been called for this response + continue; + } + arguments.add(arg); + } + if (!request.getRequestURI().contains("/swagger") && !request.getRequestURI().contains("/v3/api-docs")) { + LoggerUtil.data.info(String.format("%s:param:%s", request.getRequestURI(), JSONObject.toJSONString(arguments))); + } + } + + // 最终通知 + @AfterReturning(returning = "returnOb", pointcut = "requestPointcut() || getPointcut() || postPointcut())") + public void afterReturningCall(JoinPoint joinPoint, Object returnOb) { + long start = RequestIdUtil.getTime(); + long time = new Date().getTime() - start; + ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder.currentRequestAttributes(); + HttpServletRequest request = requestAttributes.getRequest(); + if (!request.getRequestURI().contains("/swagger") && !request.getRequestURI().contains("/v3/api-docs") && !(returnOb instanceof HttpEntity)) { + LoggerUtil.data.info(String.format("%s:耗时:%d", request.getRequestURI(), time)); + LoggerUtil.data.info(String.format("%s:result:%s", request.getRequestURI(), JSONObject.toJSONString(returnOb))); + } + } + + // 异常通知 + @AfterThrowing(value = "requestPointcut() || getPointcut() || postPointcut()", throwing = "ex") + public void afterThrowing(JoinPoint joinPoint, Exception ex) { + ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder.currentRequestAttributes(); + HttpServletRequest request = requestAttributes.getRequest(); + if (!request.getRequestURI().contains("/swagger") && !request.getRequestURI().contains("/v3/api-docs")) { + LoggerUtil.data.info(String.format("%s:exception:%s", request.getRequestURI(), ExceptionUtils.getStackTrace(ex))); + } + } + +} diff --git a/src/main/java/com/diagnose/common/config/JsonConfig.java b/src/main/java/com/diagnose/common/config/JsonConfig.java new file mode 100644 index 0000000..2c80f8e --- /dev/null +++ b/src/main/java/com/diagnose/common/config/JsonConfig.java @@ -0,0 +1,47 @@ +package com.diagnose.common.config; + +import com.alibaba.fastjson.parser.ParserConfig; +import com.alibaba.fastjson.serializer.SerializerFeature; +import com.alibaba.fastjson.support.config.FastJsonConfig; +import com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter; +import org.springframework.boot.autoconfigure.http.HttpMessageConverters; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.http.MediaType; + +import java.nio.charset.StandardCharsets; +import java.util.ArrayList; +import java.util.List; + +@Configuration +public class JsonConfig { + + static { + ParserConfig.getGlobalInstance().setSafeMode(true); + } + + @Bean // 使用@Bean注入fastJsonHttpMessageConvert + public HttpMessageConverters fastJsonHttpMessageConverters() { + // 1.需要定义一个Convert转换消息的对象 + FastJsonHttpMessageConverter fastConverter = new FastJsonHttpMessageConverter(); + + // 2.添加fastjson的配置信息,比如是否要格式化返回的json数据 + FastJsonConfig fastJsonConfig = new FastJsonConfig(); + fastJsonConfig.setSerializerFeatures(SerializerFeature.WriteMapNullValue, // 是否输出值为null的字段 + SerializerFeature.WriteNullListAsEmpty, // 将Collection类型字段的字段空值输出为[] +// SerializerFeature.WriteNullNumberAsZero, // 将数值类型字段的空值输出为0 + SerializerFeature.DisableCircularReferenceDetect, // 禁用循环引用 + SerializerFeature.WriteDateUseDateFormat); //时间格式化 + + // 中文乱码解决方案 + List mediaTypes = new ArrayList<>(); + mediaTypes.add(new MediaType("application", "json", StandardCharsets.UTF_8));//设定json格式且编码为UTF-8 + fastConverter.setSupportedMediaTypes(mediaTypes); + + // 3.在convert中添加配置信息 + fastConverter.setFastJsonConfig(fastJsonConfig); + + return new HttpMessageConverters(fastConverter); + } + +} diff --git a/src/main/java/com/diagnose/common/config/ScheduleConfig.java b/src/main/java/com/diagnose/common/config/ScheduleConfig.java new file mode 100644 index 0000000..7750d54 --- /dev/null +++ b/src/main/java/com/diagnose/common/config/ScheduleConfig.java @@ -0,0 +1,22 @@ +package com.diagnose.common.config; + +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.context.annotation.Configuration; +import org.springframework.scheduling.annotation.EnableScheduling; +import org.springframework.scheduling.annotation.SchedulingConfigurer; +import org.springframework.scheduling.config.ScheduledTaskRegistrar; + +import java.util.concurrent.Executors; + +@Configuration +@ConditionalOnProperty(name = "scheduledEnable", havingValue = "true") +@EnableScheduling +public class ScheduleConfig implements SchedulingConfigurer { + + @Override + public void configureTasks(ScheduledTaskRegistrar taskRegistrar) { + // 开启定时任务多线程,防止默认单线程阻塞问题,超过核心线程数后,还是会阻塞 + taskRegistrar.setScheduler(Executors.newScheduledThreadPool(10)); + } + +} diff --git a/src/main/java/com/diagnose/common/config/Swagger3Config.java b/src/main/java/com/diagnose/common/config/Swagger3Config.java new file mode 100644 index 0000000..97ff948 --- /dev/null +++ b/src/main/java/com/diagnose/common/config/Swagger3Config.java @@ -0,0 +1,47 @@ +package com.diagnose.common.config; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import springfox.documentation.annotations.ApiIgnore; +import springfox.documentation.builders.ApiInfoBuilder; +import springfox.documentation.builders.PathSelectors; +import springfox.documentation.builders.RequestHandlerSelectors; +import springfox.documentation.service.ApiInfo; +import springfox.documentation.spi.DocumentationType; +import springfox.documentation.spring.web.plugins.Docket; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import javax.servlet.http.HttpSession; + +/** + * 利用swagger3构建API + * + * @author yuanchao + */ +@Configuration +public class Swagger3Config { + + @Bean + public Docket createRestApi() { + return new Docket(DocumentationType.OAS_30) + .apiInfo(apiInfo()) + .enable(true) + .select() + .apis(RequestHandlerSelectors.basePackage("com")) //扫描该包下的所有需要在Swagger中展示的API,@ApiIgnore注解标注的除外 + .paths(PathSelectors.any()) + .build() + .ignoredParameterTypes(HttpSession.class, HttpServletRequest.class, HttpServletResponse.class) + .ignoredParameterTypes(ApiIgnore.class); + } + + //创建API的基本信息,这些信息会在Swagger UI中进行显示 + private ApiInfo apiInfo() { + return new ApiInfoBuilder() + .title("数据应用API") + .description("数据应用API") + .version("1.0") + .build(); + } + +} diff --git a/src/main/java/com/diagnose/common/config/UpCorsConfiguration.java b/src/main/java/com/diagnose/common/config/UpCorsConfiguration.java new file mode 100644 index 0000000..5e09c6c --- /dev/null +++ b/src/main/java/com/diagnose/common/config/UpCorsConfiguration.java @@ -0,0 +1,32 @@ +package com.diagnose.common.config; + +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.web.cors.CorsConfiguration; +import org.springframework.web.cors.UrlBasedCorsConfigurationSource; +import org.springframework.web.filter.CorsFilter; + +import java.util.Collections; + +@Configuration +public class UpCorsConfiguration { + + @Bean("upCorsFilter") + @ConditionalOnProperty(name = "cors.enable", havingValue = "true") + public CorsFilter corsFilter() { + CorsConfiguration corsConfiguration = new CorsConfiguration(); + //1,允许任何来源 + corsConfiguration.setAllowedOriginPatterns(Collections.singletonList("*")); + //2,允许任何请求头 + corsConfiguration.addAllowedHeader(CorsConfiguration.ALL); + //3,允许任何方法 + corsConfiguration.addAllowedMethod(CorsConfiguration.ALL); + //4,允许凭证 + corsConfiguration.setAllowCredentials(true); + UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(); + source.registerCorsConfiguration("/**", corsConfiguration); + return new CorsFilter(source); + } + +} diff --git a/src/main/java/com/diagnose/common/config/cache/CacheConfig.java b/src/main/java/com/diagnose/common/config/cache/CacheConfig.java new file mode 100644 index 0000000..65f1ae8 --- /dev/null +++ b/src/main/java/com/diagnose/common/config/cache/CacheConfig.java @@ -0,0 +1,47 @@ +package com.diagnose.common.config.cache; + +import com.hazelcast.config.InMemoryFormat; + +import java.util.HashMap; +import java.util.Map; + +import static com.diagnose.common.config.cache.CacheKey.*; + +public class CacheConfig { + + public static final String DEFAULT_MAP_NAME = "default"; + + public static class LocalMapConfig { + public final int maxSize; + public final int liveSeconds; + public final InMemoryFormat inMemoryFormat; + + LocalMapConfig(int maxSize, int liveSeconds) { + this.maxSize = maxSize; + this.liveSeconds = liveSeconds; + this.inMemoryFormat = InMemoryFormat.BINARY; + } + + LocalMapConfig(int maxSize, int liveSeconds, InMemoryFormat inMemoryFormat) { + this.maxSize = maxSize; + this.liveSeconds = liveSeconds; + this.inMemoryFormat = inMemoryFormat; + } + } + + public static Map getConfigMap() { + // 设置近地缓存实时同步,不采用批量提交策略 + System.setProperty("hazelcast.map.invalidation.batch.enabled", "false"); + // PER_NODE:max-size指定单个集群成员中map条目的最大数量。这是max-size的默认策略。如果使用这个配置,需要注意max-size的值必须大于分区的数量(默认为271)。 + // PER_PARTITION:max-size指定每个分区存储的map条目最大数。这个策略建议不要在小规模的集群中使用,因为小规模的集群,单个节点包含了大量的分区,在执行回收策略时,会去按照分区的划分组个检查回收条件,导致效率低下。 + // USED_HEAP_SIZE:指在每个Hazelcast实例中,max-size指定map所占用的内存堆的(以megabytes计算,兆字节)最大值。需要注意这个策略不能工作在in-memory-format=OBJECT,因为当数据被设置为OBJECT时,无法确定所占用的内存大小。 + // USED_HEAP_PERCENTAGE:每个Hazelcast实例中,max-size指定map占用内存堆的百分比。例如,JVM被设置有1000MB,而这个值设置为max-size=10,当map条目数占用的堆数据超过100MB时,Hazelcast开始执行数据释放工作。需要注意的是当使用这个策略时,不能将in-memory-format设置为OBJECT,理由同上。 + // FREE_HEAP_SIZE:max-size指定了单个JVM的堆最小空闲空间,单位为megabytes。 + // FREE_HEAP_PERCENTAGE:max-size指定单个JVM的最小空闲空间的百分比。例如JVM分配了1000MB的空间,这个值设置为10,当空闲堆只有100MB时,会引发map的数据清除放行为。 + // 当map条数超过10000,会引发map的数据清除行为 + Map configMap = new HashMap<>(); + configMap.put(DISTRIBUTED_LOCK, new LocalMapConfig(1000, 0)); + + return configMap; + } +} diff --git a/src/main/java/com/diagnose/common/config/cache/CacheConfig.java~ b/src/main/java/com/diagnose/common/config/cache/CacheConfig.java~ new file mode 100644 index 0000000..7b15ae4 --- /dev/null +++ b/src/main/java/com/diagnose/common/config/cache/CacheConfig.java~ @@ -0,0 +1,72 @@ +package com.diagnose.common.config.cache; + +import com.hazelcast.config.InMemoryFormat; + +import java.util.HashMap; +import java.util.Map; + +import static com.diagnose.common.config.cache.CacheKey.*; + +public class CacheConfig { + + public static final String DEFAULT_MAP_NAME = "default"; + + public static class LocalMapConfig { + public final int maxSize; + public final int liveSeconds; + public final InMemoryFormat inMemoryFormat; + + LocalMapConfig(int maxSize, int liveSeconds) { + this.maxSize = maxSize; + this.liveSeconds = liveSeconds; + this.inMemoryFormat = InMemoryFormat.BINARY; + } + + LocalMapConfig(int maxSize, int liveSeconds, InMemoryFormat inMemoryFormat) { + this.maxSize = maxSize; + this.liveSeconds = liveSeconds; + this.inMemoryFormat = inMemoryFormat; + } + } + + public static Map getConfigMap() { + // 设置近地缓存实时同步,不采用批量提交策略 + System.setProperty("hazelcast.map.invalidation.batch.enabled", "false"); + // PER_NODE:max-size指定单个集群成员中map条目的最大数量。这是max-size的默认策略。如果使用这个配置,需要注意max-size的值必须大于分区的数量(默认为271)。 + // PER_PARTITION:max-size指定每个分区存储的map条目最大数。这个策略建议不要在小规模的集群中使用,因为小规模的集群,单个节点包含了大量的分区,在执行回收策略时,会去按照分区的划分组个检查回收条件,导致效率低下。 + // USED_HEAP_SIZE:指在每个Hazelcast实例中,max-size指定map所占用的内存堆的(以megabytes计算,兆字节)最大值。需要注意这个策略不能工作在in-memory-format=OBJECT,因为当数据被设置为OBJECT时,无法确定所占用的内存大小。 + // USED_HEAP_PERCENTAGE:每个Hazelcast实例中,max-size指定map占用内存堆的百分比。例如,JVM被设置有1000MB,而这个值设置为max-size=10,当map条目数占用的堆数据超过100MB时,Hazelcast开始执行数据释放工作。需要注意的是当使用这个策略时,不能将in-memory-format设置为OBJECT,理由同上。 + // FREE_HEAP_SIZE:max-size指定了单个JVM的堆最小空闲空间,单位为megabytes。 + // FREE_HEAP_PERCENTAGE:max-size指定单个JVM的最小空闲空间的百分比。例如JVM分配了1000MB的空间,这个值设置为10,当空闲堆只有100MB时,会引发map的数据清除放行为。 + // 当map条数超过10000,会引发map的数据清除行为 + Map configMap = new HashMap<>(); + configMap.put(DISTRIBUTED_LOCK, new LocalMapConfig(1000, 0)); + + configMap.put(DEPT, new LocalMapConfig(10000, 3600)); + configMap.put(TAG, new LocalMapConfig(10000, 3600)); + configMap.put(ADVISOR_INFO, new LocalMapConfig(10000, 300)); + + configMap.put(RECOMMEND, new LocalMapConfig(10000, 300)); + configMap.put(USER, new LocalMapConfig(10000, 3600)); + configMap.put(CAPTCHA, new LocalMapConfig(10000, 300)); + configMap.put(RBAC, new LocalMapConfig(10000, 300)); + + configMap.put(URL_MAP, new LocalMapConfig(10000, 300, InMemoryFormat.OBJECT)); + configMap.put(SCREEN, new LocalMapConfig(1000, 10, InMemoryFormat.OBJECT)); + configMap.put(VIDEO_TX_ONLINE, new LocalMapConfig(1000, 20, InMemoryFormat.OBJECT)); + configMap.put(VIDEO_LIVE_MESSAGE, new LocalMapConfig(10000, 86400)); + configMap.put(VIDEO_LIVE, new LocalMapConfig(10000, 300)); + configMap.put(VIDEO_LIVE_DELAY, new LocalMapConfig(10000, 10)); + configMap.put(VIDEO_LIVE_COLUMN, new LocalMapConfig(10000, 300)); + configMap.put(VIDEO_ACTIVITY, new LocalMapConfig(1000, 300)); + configMap.put(VIDEO_LIVE_LIBRARY, new LocalMapConfig(1000, 300)); + configMap.put(VIDEO_LIVE_USER_MAP, new LocalMapConfig(10000, 300)); + configMap.put(CUSTOMER_MAP, new LocalMapConfig(10000, 3600)); + configMap.put(QUESTION, new LocalMapConfig(1000, 30)); + + configMap.put(COURSE, new LocalMapConfig(10000, 300)); + configMap.put(GROUP, new LocalMapConfig(10000, 300)); + configMap.put(WX_USER, new LocalMapConfig(10000, 3600)); + return configMap; + } +} diff --git a/src/main/java/com/diagnose/common/config/cache/CacheKey.java b/src/main/java/com/diagnose/common/config/cache/CacheKey.java new file mode 100644 index 0000000..45e04b1 --- /dev/null +++ b/src/main/java/com/diagnose/common/config/cache/CacheKey.java @@ -0,0 +1,25 @@ +package com.diagnose.common.config.cache; + +import java.io.Serializable; + +public class CacheKey { + + public static class OnlyKeyObj implements Serializable { + private static final long serialVersionUID = 1L; + + @Override + public boolean equals(Object obj) { + return obj instanceof OnlyKeyObj; + } + } + + // 缓存空对象,防止缓存穿透 + public static final Object ONLY_KEY_OBJ = new OnlyKeyObj(); + + // 分布式锁 + public static final String DISTRIBUTED_LOCK = "distributed_lock"; + + public static class LockKey { + } + +} diff --git a/src/main/java/com/diagnose/common/config/cache/CacheKey.java~ b/src/main/java/com/diagnose/common/config/cache/CacheKey.java~ new file mode 100644 index 0000000..9d78ef5 --- /dev/null +++ b/src/main/java/com/diagnose/common/config/cache/CacheKey.java~ @@ -0,0 +1,373 @@ +package com.diagnose.common.config.cache; + +import java.io.Serializable; + +public class CacheKey { + + public static class OnlyKeyObj implements Serializable { + private static final long serialVersionUID = 1L; + + @Override + public boolean equals(Object obj) { + return obj instanceof OnlyKeyObj; + } + } + + // 缓存空对象,防止缓存穿透 + public static final Object ONLY_KEY_OBJ = new OnlyKeyObj(); + + // 分布式锁 + public static final String DISTRIBUTED_LOCK = "distributed_lock"; + + public static class LockKey { + // 清除多余定时器日志 + public static final String CLEAR_HISTORY_SCHEDULE_LOG = "clearHistoryScheduleLog"; + // 结束直播中/暂停中的直播 分布式锁(字符串常量) + public static final String STOP_LIVING_VIDEO_LOCK = "stop_living_video_lock"; + // 刷新视频直播状态 分布式锁(字符串常量) + public static final String UPDATE_VIDEO_LIVE_STATUS_LOCK = "update_video_live_status_lock"; + // 从cache刷新视频直播播放量到DB 分布式锁(字符串常量) + public static final String SAVE_VIDEO_COUNT_TO_DB_LOCK = "save_video_count_to_db_lock"; + // 购物车分布式锁 + public static final String VIDEO_LIVE_HISTORY_LOCK = "video_live_history_lock"; + public static final String SAVE_VIDEO_USER_DATA_TO_DB_LOCK = "save_video_user_data_to_db_lock"; + public static final String SAVE_VIDEO_CUSTOMER_DATA_TO_DB_LOCK = "save_video_customer_data_to_db_lock"; + public static final String LIVE_NOTIFY_LOCK = "live_notify_lock"; + public static final String REFRESH_TRANSCODE_STATUS = "refresh_transcode_status"; + public static final String SAVE_SHORT_VIDEO_WATCH_SECONDS = "save_short_video_watch_seconds"; + + public static final String COLLECT_LAST_WEEK_LOCK = "collect_last_week_lock"; + + public static final String COLLECT_LIVING_VIDEO_LOCK = "collect_living_video_lock"; + public static final String COLLECT_RECENT_END_VIDEO_LOCK = "collect_recent_end_video_lock"; + + public static final String LOAD_USER_BLACK_LIST = "load_user_black_list"; + public static final String SAVE_MESSAGE_READ = "save_message_read"; + public static final String SAVE_GROUP_USER = "save_group_user"; + public static final String COLLECT_GROUP_DATA = "collect_group_data"; + public static final String SYNC_ORDER = "sync_order"; + public static final String SYNC_MODULE_USER = "sync_module_user"; + } + + // 消息主题 + public static class MessageTopicKey { + public static final String VIDEO_MSG = "video_msg"; + public static final String VIDEO_NOTIFY = "video_notify"; + public static final String ADMIN_USER = "admin_user"; + public static final String VIDEO_REPORT = "video_report"; + public static final String PC_ADVISOR = "pc_advisor"; + public static final String PC_AUDIENCE = "pc_audience"; + public static final String SESSION_VIDEO_MSG = "session_video_msg"; + } + + // 后台用户 + public static final String USER = "user"; + + public static final class UserKey { + // userId -> userName + public static final String USER_MAP = "user_map"; + // staffNo -> User + public static final String STAFF_MAP = "staff_map"; + public static final String JWT_EXPIRE_MAP = "jwt_expire_map"; + public static final String LOGOUT_JWT_MAP = "logout_jwt_map"; + public static final String USER_DEPT_MAP = "user_dept_map"; + public static final String USER_BLACK_LIST = "user_black_list"; + public static final String USER_LOGIN_MAP = "user_login_map"; + } + + // 部门(营业部/分公司) + public static final String DEPT = "dept"; + + public static class DeptKey { + // deptId -> deptName + public static final String DEPT_MAP = "dept_map"; + // advisorId -> dept + public static final String ADVISOR_DEPT_MAP = "advisor_dept_map"; + // advisorId -> deptId + public static final String ADVISOR_DEPT_ID_MAP = "advisor_dept_id_map"; + // advisorId -> dept + public static final String ADVISOR_RELATION_DEPT_MAP = "advisor_relation_dept_map"; + // userId -> deptId + public static final String USER_DEPT_MAP = "user_dept_map"; + } + + // RBAC权限 + public static final String RBAC = "rbac"; + + public static class RbacKey { + public static final String ROLE_PERMISSIONS_URL = "role_permissions_url|"; + public static final String ALL_PERMISSIONS_URL = "all_permissions_url|"; + } + + // 管理后台图形验证码 + public static final String CAPTCHA = "captcha"; + + // 标签 + public static final String TAG = "tag"; + + public static class TagKey { + // tagId -> tagName + public static final String TAG_MAP = "tag_map"; + } + + // 投顾信息 + public static final String ADVISOR_INFO = "advisor_info"; + + public static final class AdvisorInfoKey { + // advisorId -> AdvisorBasic + public static final String ADVISOR_MAP = "advisor_map"; + // advisorId -> AdvisorBasicVO + public static final String ADVISOR_VO_MAP = "advisor_vo_map"; + // userId -> AdvisorBasic + public static final String USER_ADVISOR_MAP = "user_advisor_map"; + // SortedMap (followCount, advisorId) -> advisorId + public static final String APP_FOLLOW_COUNT_LIST = "app_follow_count_list"; + // SortedMap (readCount, advisorId) -> advisorId + public static final String APP_READ_COUNT_LIST = "app_read_count_list"; + // SortedMap (productCount, advisorId) -> advisorId + public static final String APP_PRODUCT_COUNT_LIST = "app_product_count_list"; + // AdvisorInfoAppVO + public static final String APP_OBJ = "app_obj|"; + // advisorId -> PN Counter + public static final String APP_FOLLOW_COUNT = "app_follow_count|"; + // userId -> List + public static final String USER_FOLLOW_ADVISOR = "user_follow_advisor|"; + public static final String USER_ADVISOR_DEPT_MAP = "user_advisor_dept_map"; + } + + public static final String ADVERT = "advert"; + + public static class AdvertKey { + public static final String APP_ADVERT_LIST = "app_advert_list|"; + } + + public static final String RECOMMEND = "recommend"; + + public static class RecommendKey { + public static final String APP_RECOMMEND_LIST = "app_recommend_list|"; + } + + // 视频直播信息 + public static final String VIDEO_LIVE = "video_live"; + // 视频直播自定义缓存过期时间(put方法设置的过期时间不生效,所以这样处理) + public static final String VIDEO_LIVE_DELAY = "video_live_delay"; + + public static class VideoLiveKey { + // videoId -> VideoLive + public static final String VIDEO_INFO = "video_info|"; + // videoId -> VideoLive 10s缓存 + public static final String VIDEO_INFO_DELAY = "video_info_delay|"; + // SortedSet (startTime auditTime) + public static final String APP_LIST = "app_list"; + public static final String APP_VIDEO_CART = "app_video_cart|"; + public static final String APP_VIDEO_TAG = "app_video_tag|"; + public static final String VIDEO_INFO_TAG = "video_info_tag|"; + public static final String ADVISOR_NO_PLAY_LIST = "advisor_no_play_list"; + // 与直播相关产品的权限 + public static final String VIDEO_OTHER_AUTH = "video_other_auth|"; + public static final String VIDEO_LIVE_RECENT_PUSH_CART = "video_live_recent_push_cart|"; + public static final String ONLINE_COUNT = "online_count|"; + public static final String APP_ADVISOR_LIST = "app_advisor_list|"; + public static final String APP_DEPT_LIST = "app_dept_list|"; + public static final String APP_ADVISOR_KEY_SET = "app_advisor_key_set|"; + public static final String APP_DEPT_KEY_SET = "app_dept_key_set|"; + } + + // 视频直播专栏 + public static final String VIDEO_LIVE_COLUMN = "video_live_column"; + + public static class VideoLiveColumnKey { + // List + public static final String COLUMN_IDS = "column_ids"; + // columnId -> VideoLiveColumn + public static final String COLUMN_INFO = "column_info|"; + // columnId -> Sort (videoId) + public static final String VIDEO_IDS = "video_ids|"; + public static final String LATEST_LIVING_VIDEO = "latest_living_video|"; + public static final String HIS_GUEST = "his_guest|"; + public static final String APP_FOLLOW_COUNT = "app_follow_count|"; + public static final String APP_PLAN_LIST = "app_plan_list"; + public static final String VIDEO_COLUMN = "video_column"; + } + + // 视频直播资源 + public static final String VIDEO_LIVE_LIBRARY = "video_live_library"; + + public static class VideoLiveLibraryKey { + // libraryId -> VideoLiveLibrary + public static final String LIBRARY_INFO = "library_info|"; + // videoId -> List + public static final String LIBRARY_IDS = "library_ids|"; + } + + public static class VideoRecordKey { + // 购物车点击数 + public static final String CART_READ_COUNT = "cart_read_count|"; + // 浏览数 + // videoId -> PV Counter + public static final String READ_COUNT = "read_count|"; + // 用户点赞 + // videoId -> UV Counter + public static final String FAVOR_USER_COUNT = "favor_user_count|"; + // videoId -> Set (userId) + public static final String USER_FAVOR_IDS = "user_favor_ids|"; + // 视频分享 + // videoId -> PV Counter + public static final String SHARE_COUNT = "share_count|"; + // 视频评论 + // videoId -> PV Counter + public static final String MESS_COUNT = "mess_count|"; + // 用户预约 + // userId -> Set (videoId) + public static final String USER_SUBSCRIBE_IDS = "user_subscribe_ids|"; + // videoId -> Set (userId) + public static final String VIDEO_SUBSCRIBE_IDS = "user_subscribe_ids|"; + public static final String USER_BROWSE_IDS = "user_browse_ids|"; + public static final String USER_FOLLOW_COLUMN = "user_follow_column|"; + public static final String TEMP_FAVOR_LIST = "temp_favor_list"; + // 投顾关注 + // advisorId -> Set (userId) + public static final String ADVISOR_FOLLOW_IDS = "advisor_follow_ids|"; + } + + // 视频互动消息 + public static final String VIDEO_LIVE_MESSAGE = "video_live_message"; + + public static class VideoLiveMessageKey { + // messageId -> VideoLiveMessage + public static final String MESSAGE_INFO = "message_info|"; + // videoId -> List(messageId) + public static final String MESSAGE_IDS = "message_ids|"; + public static final String MESSAGE_IDS_ADVISOR = "message_ids_advisor|"; + // 互动人数 + // videoId -> UV Counter + public static final String USER_COUNT = "read_user_count|"; + public static final String MESSAGE_TOP_20 = "message_top_20|"; + public static final String MESSAGE_ADVISOR_TOP_20 = "message_advisor_top_20|"; + public static final String MESSAGE_COUNT = "message_count|"; + } + + // 评论 + public static final String COMMENT = "comment"; + + public static class CommentKey { + public static final String APP_COMMENT_SORT_LIST = "app_comment_sort_list|"; + public static final String APP_COMMENT_OBJ = "app_comment_obj|"; + } + + // 评论禁言 + public static final String COMMENT_BLACK = "comment_black"; + + public static class CommentBlackKey { + public static final String ALL_BLACK_COMMENT = "all_black_comment"; + public static final String ALL_BLACK_USER = "all_black_user"; + } + + public static final String VIDEO_ACTIVITY = "video_activity"; + + public static class VideoActivityKey { + public static final String VIDEO_ACTIVITY_LIST = "video_activity_list"; + public static final String VIDEO_ACTIVITY_OBJ = "video_activity_obj|"; + } + + public static final String VIDEO_LIVE_HIS_DATE = "video_live_his_date"; + + public static final String QUESTION = "question"; + + public static class QuestionKey { + public static final String QUESTION_DETAILS = "question_details|"; + } + + public static final class OnlineLineKey { + public static final String USER_VIDEO_TOTAL_ONLINE = "user_video_total_online|"; + } + + public static final String URL_MAP = "url_map"; + + public static final class URL_KEY { + public static final String URL_KEY = "url_key|"; + public static final String URL_KEY_VIDEO_ID = "url_key_video_id|"; + public static final String URL_KEY_SHORT_VIDEO_ID = "url_key_short_video_id|"; + } + + public static final String VIDEO_TX_ONLINE = "video_tx_online|"; + + public static final class TXKey { + public static final String VIDEO_ONLINE_TX = "video_online_tx|"; + } + + public static final String CUSTOMER_MAP = "customer_map"; + + public static final class CustomerKey { + public static final String CUSTOMER_DETAILS = "customer_details|"; + public static final String VIDEO_CUSTOMER_SET = "video_customer_set"; + public static final String VIDEO_CUSTOMER_SALE_SET = "video_customer_sale_set"; + public static final String CUSTOMER_SALE = "customer_sale|"; + } + + public static final String WX_USER = "wx_user"; + + public static final class WxUserKey { + public static final String USER = "user|"; + } + + public static final String SCREEN = "screen"; + + public static final class ScreenKey { + public static final String SCREEN_VIDEO_INFO = "screen_video_info|"; + } + + public static final String VIDEO_LIVE_USER_MAP = "video_live_user_map"; + + public static final class VideoLiveUserKey { + public static final String LIVE_USER_OBJ = "live_user_obj|"; + } + + public static final String COURSE = "course"; + + public static final class CourseKey { + public static final String COURSE_INFO = "course_info|"; + public static final String COURSE_CONTENT = "course_content|"; + public static final String SERIAL_INFO = "serial_info|"; + public static final String SERIAL_CONTENT = "serial_content|"; + public static final String PAGE = "page|"; + public static final String SHORT_VIDEO = "short_video|"; + public static final String SHORT_VIDEO_FAVOR_USER_IDS = "favor_user_ids|"; + public static final String MAIN_TAB = "main_tab|"; + public static final String MAIN_COURSE_LIST = "main_course_list|"; + public static final String MAIN_SHORT_VIDEO_LIST = "main_short_video_list|"; + public static final String PC_COURSE_LIST = "pc_course_list|"; + public static final String SALE_USER_WORK_WEIXIN_QRCODE_IMAGE = "sale_user_work_weixin_qrcode_image|"; + public static final String SHORT_VIDEO_WATCH_LIST = "short_video_watch_list"; + public static final String COURSE_PACKAGE = "course_package|"; + public static final String COURSE_PACKAGE_CONTENT = "course_package_content|"; + } + + public static final String GROUP = "group"; + + // 消息主题 + public static class GroupMessageTopicKey { + public static final String ADMIN_GROUP_TOPIC = "admin_group_topic"; + public static final String ADMIN_PRIVATE_TOPIC = "admin_private_topic"; + public static final String ADMIN_SESSION_TOPIC = "admin_session_topic"; + public static final String APP_GROUP_TOPIC = "app_group_topic"; + public static final String APP_PRIVATE_TOPIC = "app_private_topic"; + public static final String APP_SESSION_TOPIC = "app_session_topic"; + } + + public static class GroupKey { + public static final String GROUP_INFO = "group_info|"; + public static final String MAIN_GROUP_LIST = "group_main_list|"; + public static final String GROUP_MESSAGE_LIST = "group_message_list|"; + public static final String GROUP_MESSAGE_DETAIL = "group_message_detail|"; + public static final String USER_TOTAL_ONLINE = "user_total_online|"; + public static final String TEMP_READ_LIST = "temp_read_list"; + public static final String GROUP_MESSAGE_DATE_ID_MAP = "group_message_date_id_map|"; + public static final String ONLINE_COUNT = "online_count|"; + } + + public static final String GROUP_ONLINE_USER = "group_online_user"; + + public static final String VIDEO_ONLINE_USER = "video_online_user"; + +} diff --git a/src/main/java/com/diagnose/common/config/cache/HazelcastConfiguration.java b/src/main/java/com/diagnose/common/config/cache/HazelcastConfiguration.java new file mode 100644 index 0000000..b9b0962 --- /dev/null +++ b/src/main/java/com/diagnose/common/config/cache/HazelcastConfiguration.java @@ -0,0 +1,91 @@ +package com.diagnose.common.config.cache; + +import com.hazelcast.config.*; +import com.hazelcast.core.Hazelcast; +import com.hazelcast.core.HazelcastInstance; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +import javax.annotation.PreDestroy; +import java.util.*; + +@Configuration +public class HazelcastConfiguration { + + @Value("${hazelcast.members}") + private String members; + + @Value("${hazelcast.serverPort}") + private Integer serverPort; + + private Set cacheNameSet = new HashSet<>(); + + @Bean + public HazelcastInstance hazelcastInstance() { + List memberList = Arrays.asList(members.split(",")); + Config config = new Config(); + // hazelcast作为缓存服务端监听的端口 + config.getNetworkConfig().setPort(serverPort); + // 如果目标缓存端口被占用,禁止重试其他端口 + config.getNetworkConfig().setPortAutoIncrement(false); + config.getNetworkConfig().getJoin().getAutoDetectionConfig().setEnabled(false); + config.getNetworkConfig().getJoin().getTcpIpConfig().setEnabled(true).setMembers(memberList); + config.getJetConfig().setEnabled(true); + String clusterName = "hazelcast-cluster"; + String instanceName = clusterName + "." + "localIP"; + config.setInstanceName(instanceName); + config.setClusterName(clusterName); + for (Map.Entry entry : CacheConfig.getConfigMap().entrySet()) { + String cacheName = entry.getKey(); + cacheNameSet.add(cacheName); + config.addMapConfig(new MapConfig() + .setName(cacheName) + .setEvictionConfig(new EvictionConfig() + .setEvictionPolicy(EvictionPolicy.LRU) + .setSize(entry.getValue().maxSize) + .setMaxSizePolicy(MaxSizePolicy.PER_NODE)) + .setTimeToLiveSeconds(entry.getValue().liveSeconds) + // 近地缓存设置 + .setNearCacheConfig(new NearCacheConfig() + .setInMemoryFormat(entry.getValue().inMemoryFormat) + .setCacheLocalEntries(true) + .setTimeToLiveSeconds(entry.getValue().liveSeconds / 2) + .setEvictionConfig(new EvictionConfig() + .setMaxSizePolicy(MaxSizePolicy.ENTRY_COUNT) + .setSize(entry.getValue().maxSize / 2)) + // 预加载近地缓存,防止近地缓存穿透(暂时不启用) +// .setPreloaderConfig(new NearCachePreloaderConfig() +// .setEnabled(true)) + ) + ); + } + + // 默认map配置,主要用于USER_VIDEO_TOTAL_ONLINE + videoId + config.addMapConfig(new MapConfig() + .setName(CacheConfig.DEFAULT_MAP_NAME) + .setNearCacheConfig(new NearCacheConfig() + .setInMemoryFormat(InMemoryFormat.OBJECT) + .setCacheLocalEntries(true) + .setTimeToLiveSeconds(3600 * 10) + .setMaxIdleSeconds(3600 * 2) + .setEvictionConfig(new EvictionConfig() + .setMaxSizePolicy(MaxSizePolicy.ENTRY_COUNT) + .setSize(100000)) + )); + HazelcastInstance instance = Hazelcast.newHazelcastInstance(config); + return instance; + } + + public void cleanCache() { + for (String cacheName : cacheNameSet) { + hazelcastInstance().getMap(cacheName).clear(); + } + } + + @PreDestroy + public void destroy() { + hazelcastInstance().shutdown(); + } + +} diff --git a/src/main/java/com/diagnose/common/config/mybatis/EasySqlInjector.java b/src/main/java/com/diagnose/common/config/mybatis/EasySqlInjector.java new file mode 100644 index 0000000..3d94a0a --- /dev/null +++ b/src/main/java/com/diagnose/common/config/mybatis/EasySqlInjector.java @@ -0,0 +1,21 @@ +package com.diagnose.common.config.mybatis; + +import com.baomidou.mybatisplus.annotation.FieldFill; +import com.baomidou.mybatisplus.core.injector.AbstractMethod; +import com.baomidou.mybatisplus.core.injector.DefaultSqlInjector; +import com.baomidou.mybatisplus.core.metadata.TableInfo; +import com.baomidou.mybatisplus.extension.injector.methods.InsertBatchSomeColumn; + +import java.util.List; + +public class EasySqlInjector extends DefaultSqlInjector { + + public List getMethodList(Class mapperClass, TableInfo tableInfo) { + List methodList = super.getMethodList(mapperClass, tableInfo); + methodList.add(new InsertBatchSomeColumn()); + methodList.add(new SaveBatchSomeColumn(i -> i.getFieldFill() == FieldFill.INSERT_UPDATE)); + methodList.add(new Save()); + return methodList; + } + +} diff --git a/src/main/java/com/diagnose/common/config/mybatis/MybatisPlusConfig.java b/src/main/java/com/diagnose/common/config/mybatis/MybatisPlusConfig.java new file mode 100644 index 0000000..e16f748 --- /dev/null +++ b/src/main/java/com/diagnose/common/config/mybatis/MybatisPlusConfig.java @@ -0,0 +1,26 @@ +package com.diagnose.common.config.mybatis; + +import com.baomidou.mybatisplus.annotation.DbType; +import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor; +import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor; +import org.mybatis.spring.annotation.MapperScan; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +@Configuration +@MapperScan("com.diagnose") +public class MybatisPlusConfig { + + @Bean + public MybatisPlusInterceptor mybatisPlusInterceptor() { + MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor(); + interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL)); + return interceptor; + } + + @Bean + public EasySqlInjector easySqlInjector() { + return new EasySqlInjector(); + } + +} diff --git a/src/main/java/com/diagnose/common/config/mybatis/MybatisPlusConfig.java~ b/src/main/java/com/diagnose/common/config/mybatis/MybatisPlusConfig.java~ new file mode 100644 index 0000000..d78e849 --- /dev/null +++ b/src/main/java/com/diagnose/common/config/mybatis/MybatisPlusConfig.java~ @@ -0,0 +1,26 @@ +package com.diagnose.common.config.mybatis; + +import com.baomidou.mybatisplus.annotation.DbType; +import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor; +import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor; +import org.mybatis.spring.annotation.MapperScan; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +@Configuration +@MapperScan("com.syzb") +public class MybatisPlusConfig { + + @Bean + public MybatisPlusInterceptor mybatisPlusInterceptor() { + MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor(); + interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL)); + return interceptor; + } + + @Bean + public EasySqlInjector easySqlInjector() { + return new EasySqlInjector(); + } + +} diff --git a/src/main/java/com/diagnose/common/config/mybatis/Save.java b/src/main/java/com/diagnose/common/config/mybatis/Save.java new file mode 100644 index 0000000..0e73db1 --- /dev/null +++ b/src/main/java/com/diagnose/common/config/mybatis/Save.java @@ -0,0 +1,64 @@ +package com.diagnose.common.config.mybatis; + +import cn.hutool.core.util.StrUtil; +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.core.injector.AbstractMethod; +import com.baomidou.mybatisplus.core.metadata.TableFieldInfo; +import com.baomidou.mybatisplus.core.metadata.TableInfo; +import com.baomidou.mybatisplus.core.metadata.TableInfoHelper; +import com.baomidou.mybatisplus.core.toolkit.sql.SqlScriptUtils; +import org.apache.ibatis.executor.keygen.Jdbc3KeyGenerator; +import org.apache.ibatis.executor.keygen.KeyGenerator; +import org.apache.ibatis.executor.keygen.NoKeyGenerator; +import org.apache.ibatis.mapping.MappedStatement; +import org.apache.ibatis.mapping.SqlSource; + +import java.util.stream.Collectors; + +public class Save extends AbstractMethod { + + public static final String saveSql = ""; + + public static final String methodName = "save"; + + public Save() { + super(methodName); + } + + public Save(String name) { + super(name); + } + + @Override + public MappedStatement injectMappedStatement(Class mapperClass, Class modelClass, TableInfo tableInfo) { + KeyGenerator keyGenerator = NoKeyGenerator.INSTANCE; + String columnScript = SqlScriptUtils.convertTrim(tableInfo.getAllInsertSqlColumnMaybeIf(null), + LEFT_BRACKET, RIGHT_BRACKET, null, COMMA); + String valuesScript = SqlScriptUtils.convertTrim(tableInfo.getAllInsertSqlPropertyMaybeIf(null), + LEFT_BRACKET, RIGHT_BRACKET, null, COMMA); + String updateScript = tableInfo.getFieldList().stream().map(TableFieldInfo::getColumn).map(column -> + String.format("%s = VALUES(%s),", column, column, column) + ).collect(Collectors.joining(NEWLINE)); + updateScript = SqlScriptUtils.convertTrim(updateScript, EMPTY, EMPTY, null, COMMA); + String keyProperty = null; + String keyColumn = null; + // 表包含主键处理逻辑,如果不包含主键当普通字段处理 + if (StrUtil.isNotBlank(tableInfo.getKeyProperty())) { + if (tableInfo.getIdType() == IdType.AUTO) { + /* 自增主键 */ + keyGenerator = Jdbc3KeyGenerator.INSTANCE; + keyProperty = tableInfo.getKeyProperty(); + keyColumn = tableInfo.getKeyColumn(); + } else { + if (null != tableInfo.getKeySequence()) { + keyGenerator = TableInfoHelper.genKeyGenerator(methodName, tableInfo, builderAssistant); + keyProperty = tableInfo.getKeyProperty(); + keyColumn = tableInfo.getKeyColumn(); + } + } + } + String sql = String.format(saveSql, tableInfo.getTableName(), columnScript, valuesScript, updateScript); + SqlSource sqlSource = languageDriver.createSqlSource(configuration, sql, modelClass); + return this.addInsertMappedStatement(mapperClass, modelClass, methodName, sqlSource, keyGenerator, keyProperty, keyColumn); + } +} \ No newline at end of file diff --git a/src/main/java/com/diagnose/common/config/mybatis/SaveBatchSomeColumn.java b/src/main/java/com/diagnose/common/config/mybatis/SaveBatchSomeColumn.java new file mode 100644 index 0000000..52b7fac --- /dev/null +++ b/src/main/java/com/diagnose/common/config/mybatis/SaveBatchSomeColumn.java @@ -0,0 +1,99 @@ +package com.diagnose.common.config.mybatis; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.core.injector.AbstractMethod; +import com.baomidou.mybatisplus.core.metadata.TableFieldInfo; +import com.baomidou.mybatisplus.core.metadata.TableInfo; +import com.baomidou.mybatisplus.core.metadata.TableInfoHelper; +import com.baomidou.mybatisplus.core.toolkit.sql.SqlScriptUtils; +import org.apache.ibatis.executor.keygen.Jdbc3KeyGenerator; +import org.apache.ibatis.executor.keygen.KeyGenerator; +import org.apache.ibatis.executor.keygen.NoKeyGenerator; +import org.apache.ibatis.mapping.MappedStatement; +import org.apache.ibatis.mapping.SqlSource; + +import java.util.List; +import java.util.function.Predicate; +import java.util.stream.Collectors; + +public class SaveBatchSomeColumn extends AbstractMethod { + + private static final String methodName = "saveBatchSomeColumn"; + + /** + * 字段筛选条件 + */ + private Predicate predicate; + + public Predicate getPredicate() { + return predicate; + } + + public void setPredicate(Predicate predicate) { + this.predicate = predicate; + } + + /** + * 默认方法名 + */ + public SaveBatchSomeColumn() { + super(methodName); + } + + /** + * 默认方法名 + * + * @param predicate 字段筛选条件 + */ + public SaveBatchSomeColumn(Predicate predicate) { + super(methodName); + this.predicate = predicate; + } + + /** + * @param name 方法名 + * @param predicate 字段筛选条件 + * @since 3.5.0 + */ + public SaveBatchSomeColumn(String name, Predicate predicate) { + super(name); + this.predicate = predicate; + } + + @Override + public MappedStatement injectMappedStatement(Class mapperClass, Class modelClass, TableInfo tableInfo) { + KeyGenerator keyGenerator = NoKeyGenerator.INSTANCE; + List fieldList = tableInfo.getFieldList(); + String insertSqlColumn = tableInfo.getKeyInsertSqlColumn(true, false) + + this.filterTableFieldInfo(fieldList, predicate, TableFieldInfo::getInsertSqlColumn, EMPTY); + String columnScript = LEFT_BRACKET + (insertSqlColumn.isEmpty() ? "" : insertSqlColumn.substring(0, insertSqlColumn.length() - 1)) + RIGHT_BRACKET; + String insertSqlProperty = tableInfo.getKeyInsertSqlProperty(true, ENTITY_DOT, false) + + this.filterTableFieldInfo(fieldList, predicate, i -> i.getInsertSqlProperty(ENTITY_DOT), EMPTY); + insertSqlProperty = LEFT_BRACKET + (insertSqlProperty.isEmpty() ? "" : insertSqlProperty.substring(0, insertSqlProperty.length() - 1)) + RIGHT_BRACKET; + String valuesScript = SqlScriptUtils.convertForeach(insertSqlProperty, "list", null, ENTITY, COMMA); + String updateScript = fieldList.stream().filter(predicate == null ? x -> true : predicate).map(TableFieldInfo::getColumn).map(column -> + String.format("%s = VALUES(%s),", column, column)).collect(Collectors.joining(NEWLINE)); + updateScript = SqlScriptUtils.convertTrim(updateScript, EMPTY, EMPTY, null, COMMA); + String keyProperty = null; + String keyColumn = null; + // 表包含主键处理逻辑,如果不包含主键当普通字段处理 + if (tableInfo.havePK()) { + if (tableInfo.getIdType() == IdType.AUTO) { + /* 自增主键 */ + keyGenerator = Jdbc3KeyGenerator.INSTANCE; + keyProperty = tableInfo.getKeyProperty(); + keyColumn = tableInfo.getKeyColumn(); + } else { + if (null != tableInfo.getKeySequence()) { + keyGenerator = TableInfoHelper.genKeyGenerator(methodName, tableInfo, builderAssistant); + keyProperty = tableInfo.getKeyProperty(); + keyColumn = tableInfo.getKeyColumn(); + } + } + } + String sql = String.format(Save.saveSql, tableInfo.getTableName(), columnScript, valuesScript, updateScript); + SqlSource sqlSource = languageDriver.createSqlSource(configuration, sql, modelClass); + return this.addInsertMappedStatement(mapperClass, modelClass, methodName, sqlSource, keyGenerator, keyProperty, keyColumn); + } + +} \ No newline at end of file diff --git a/src/main/java/com/diagnose/common/constant/ScheduleLogResult.java b/src/main/java/com/diagnose/common/constant/ScheduleLogResult.java new file mode 100644 index 0000000..6008a60 --- /dev/null +++ b/src/main/java/com/diagnose/common/constant/ScheduleLogResult.java @@ -0,0 +1,25 @@ +package com.diagnose.common.constant; + +public enum ScheduleLogResult { + + RUNNING(1, "执行中"), + SUCCESS(2, "成功"), + FAILURE(3, "失败"); + public final Integer value; + + public final String name; + + ScheduleLogResult(Integer value, String name) { + this.value = value; + this.name = name; + } + + public Integer getValue() { + return value; + } + + public String getName() { + return name; + } + +} diff --git a/src/main/java/com/diagnose/common/entity/ScheduleLog.java b/src/main/java/com/diagnose/common/entity/ScheduleLog.java new file mode 100644 index 0000000..ee11602 --- /dev/null +++ b/src/main/java/com/diagnose/common/entity/ScheduleLog.java @@ -0,0 +1,208 @@ +package com.diagnose.common.entity; + +import cn.hutool.core.util.StrUtil; +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; +import com.diagnose.common.constant.ScheduleLogResult; + +import java.io.Serializable; +import java.time.LocalDate; +import java.time.LocalDateTime; + +/** + *

+ * + *

+ * + * @author helloSyzb + * @since 2022-11-09 + */ +public class ScheduleLog implements Serializable { + + + /** + * 同步记录ID + */ + @TableId(value = "id", type = IdType.AUTO) + private Integer id; + + /** + * 服务名 + */ + @TableField("server_name") + private String serverName; + + /** + * 定时任务名称 + */ + @TableField("schedule_name") + private String scheduleName; + + /** + * 执行时间 + */ + private LocalDate date; + + /** + * 实际开始时间 + */ + @TableField("start_time") + private LocalDateTime startTime; + + /** + * 实际结束时间 + */ + @TableField("end_time") + private LocalDateTime endTime; + + /** + * 执行结果:1:执行中 2:成功 3:失败 + */ + private Integer result; + + /** + * 附加信息json + */ + private String ext; + + /** + * 异常信息 + */ + private String error; + + /** + * 执行机器IP + */ + private String ip; + + public static ScheduleLog start(String scheduleName, String ip) { + String server = System.getProperty("server.server"); + ScheduleLog log = new ScheduleLog(); + log.setServerName(server); + log.setScheduleName(scheduleName); + log.setDate(LocalDate.now()); + log.setStartTime(LocalDateTime.now()); + log.setResult(ScheduleLogResult.RUNNING.value); + log.setIp(ip); + return log; + } + + public static ScheduleLog success(Integer id, String ext) { + ScheduleLog log = new ScheduleLog(); + log.setId(id); + log.setEndTime(LocalDateTime.now()); + log.setResult(ScheduleLogResult.SUCCESS.value); + if (StrUtil.isNotEmpty(ext)) { + log.setExt(ext); + } + return log; + } + + public static ScheduleLog error(Integer id, String error) { + ScheduleLog log = new ScheduleLog(); + log.setId(id); + log.setEndTime(LocalDateTime.now()); + log.setResult(ScheduleLogResult.FAILURE.value); + if (StrUtil.isNotEmpty(error)) { + log.setError(error); + } + return log; + } + + public Integer getId() { + return id; + } + + public void setId(Integer id) { + this.id = id; + } + + public String getServerName() { + return serverName; + } + + public void setServerName(String serverName) { + this.serverName = serverName; + } + + public String getScheduleName() { + return scheduleName; + } + + public void setScheduleName(String scheduleName) { + this.scheduleName = scheduleName; + } + + public LocalDate getDate() { + return date; + } + + public void setDate(LocalDate date) { + this.date = date; + } + + public LocalDateTime getStartTime() { + return startTime; + } + + public void setStartTime(LocalDateTime startTime) { + this.startTime = startTime; + } + + public LocalDateTime getEndTime() { + return endTime; + } + + public void setEndTime(LocalDateTime endTime) { + this.endTime = endTime; + } + + public Integer getResult() { + return result; + } + + public void setResult(Integer result) { + this.result = result; + } + + public String getExt() { + return ext; + } + + public void setExt(String ext) { + this.ext = ext; + } + + public String getError() { + return error; + } + + public void setError(String error) { + this.error = error; + } + + public String getIp() { + return ip; + } + + public void setIp(String ip) { + this.ip = ip; + } + + @Override + public String toString() { + return "ScheduleLog{" + + "id=" + id + + ", serverName=" + serverName + + ", scheduleName=" + scheduleName + + ", date=" + date + + ", startTime=" + startTime + + ", endTime=" + endTime + + ", result=" + result + + ", ext=" + ext + + ", error=" + error + + ", ip=" + ip + + "}"; + } +} diff --git a/src/main/java/com/diagnose/common/generator/CodeGenerator.java b/src/main/java/com/diagnose/common/generator/CodeGenerator.java new file mode 100644 index 0000000..41398c2 --- /dev/null +++ b/src/main/java/com/diagnose/common/generator/CodeGenerator.java @@ -0,0 +1,84 @@ +package com.diagnose.common.generator; + +import cn.hutool.core.util.StrUtil; +import com.baomidou.mybatisplus.core.exceptions.MybatisPlusException; +import com.baomidou.mybatisplus.generator.AutoGenerator; +import com.baomidou.mybatisplus.generator.config.*; +import com.baomidou.mybatisplus.generator.config.rules.NamingStrategy; +import com.baomidou.mybatisplus.generator.engine.FreemarkerTemplateEngine; + +import java.util.Scanner; + +// 演示例子,执行 main 方法控制台输入模块表名回车自动生成对应项目目录中 +public class CodeGenerator { + + public static String scanner(String tip) { + Scanner scanner = new Scanner(System.in); + String help = "请输入" + tip + ":"; + System.out.println(help); + if (scanner.hasNext()) { + String ipt = scanner.nextLine(); + if (StrUtil.isNotBlank(ipt)) { + return ipt; + } + } + throw new MybatisPlusException("请输入正确的" + tip + "!"); + } + + public static void main(String[] args) { + DataSourceConfig dsc = new DataSourceConfig + .Builder("jdbc:mysql://47.96.178.171:3306/db_upsync?allowMultiQueries=true&useUnicode=true&characterEncoding=UTF-8&useSSL=false&serverTimezone=GMT%2B8", + "eason", + "mysql2025easonzhu") +// .Builder("jdbc:mysql://172.16.9.44:3306/db_crm_dyqh?allowMultiQueries=true&useUnicode=true&characterEncoding=UTF-8&serverTimezone=GMT%2B8&useSSL=false", +// "taf", +// "taf2015") + .build(); + // 代码生成器 + AutoGenerator mpg = new AutoGenerator(dsc); + + String moduleName = scanner("模块名"); + String projectPath = System.getProperty("user.dir") + ""; + + // 全局配置 + GlobalConfig globalConfig = new GlobalConfig + .Builder() + .outputDir(projectPath + "/src/main/java") + .author("helloSyzb") + .openDir(false) + .fileOverride() + .build(); + + // 包配置 + PackageConfig packageConfig = new PackageConfig + .Builder() + .parent("com.diagnose") + .moduleName(moduleName) + .build(); + + // 配置模板 + TemplateConfig templateConfig = new TemplateConfig + .Builder() + .mapperXml(null) + .service(null, null) + .controller(null) + .build(); + + // 策略配置 + StrategyConfig strategyConfig = new StrategyConfig + .Builder() + .addInclude(scanner("表名,多个英文逗号分割").split(",")) + .entityBuilder() + .naming(NamingStrategy.underline_to_camel) + .controllerBuilder() + .enableRestStyle() + .build(); + + mpg.global(globalConfig); + mpg.packageInfo(packageConfig); + mpg.template(templateConfig); + mpg.strategy(strategyConfig); + mpg.execute(new FreemarkerTemplateEngine()); + } + +} \ No newline at end of file diff --git a/src/main/java/com/diagnose/common/generator/CodeGenerator.java~ b/src/main/java/com/diagnose/common/generator/CodeGenerator.java~ new file mode 100644 index 0000000..8061129 --- /dev/null +++ b/src/main/java/com/diagnose/common/generator/CodeGenerator.java~ @@ -0,0 +1,84 @@ +package com.diagnose.common.generator; + +import cn.hutool.core.util.StrUtil; +import com.baomidou.mybatisplus.core.exceptions.MybatisPlusException; +import com.baomidou.mybatisplus.generator.AutoGenerator; +import com.baomidou.mybatisplus.generator.config.*; +import com.baomidou.mybatisplus.generator.config.rules.NamingStrategy; +import com.baomidou.mybatisplus.generator.engine.FreemarkerTemplateEngine; + +import java.util.Scanner; + +// 演示例子,执行 main 方法控制台输入模块表名回车自动生成对应项目目录中 +public class CodeGenerator { + + public static String scanner(String tip) { + Scanner scanner = new Scanner(System.in); + String help = "请输入" + tip + ":"; + System.out.println(help); + if (scanner.hasNext()) { + String ipt = scanner.nextLine(); + if (StrUtil.isNotBlank(ipt)) { + return ipt; + } + } + throw new MybatisPlusException("请输入正确的" + tip + "!"); + } + + public static void main(String[] args) { + DataSourceConfig dsc = new DataSourceConfig + .Builder("jdbc:mysql://47.96.178.171:3306/db_upsync?allowMultiQueries=true&useUnicode=true&characterEncoding=UTF-8&useSSL=false&serverTimezone=GMT%2B8", + "eason", + "mysql2025easonzhu") +// .Builder("jdbc:mysql://172.16.9.44:3306/db_crm_dyqh?allowMultiQueries=true&useUnicode=true&characterEncoding=UTF-8&serverTimezone=GMT%2B8&useSSL=false", +// "taf", +// "taf2015") + .build(); + // 代码生成器 + AutoGenerator mpg = new AutoGenerator(dsc); + + String moduleName = scanner("模块名"); + String projectPath = System.getProperty("user.dir") + ""; + + // 全局配置 + GlobalConfig globalConfig = new GlobalConfig + .Builder() + .outputDir(projectPath + "/src/main/java") + .author("helloSyzb") + .openDir(false) + .fileOverride() + .build(); + + // 包配置 + PackageConfig packageConfig = new PackageConfig + .Builder() + .parent("com.syzb") + .moduleName(moduleName) + .build(); + + // 配置模板 + TemplateConfig templateConfig = new TemplateConfig + .Builder() + .mapperXml(null) + .service(null, null) + .controller(null) + .build(); + + // 策略配置 + StrategyConfig strategyConfig = new StrategyConfig + .Builder() + .addInclude(scanner("表名,多个英文逗号分割").split(",")) + .entityBuilder() + .naming(NamingStrategy.underline_to_camel) + .controllerBuilder() + .enableRestStyle() + .build(); + + mpg.global(globalConfig); + mpg.packageInfo(packageConfig); + mpg.template(templateConfig); + mpg.strategy(strategyConfig); + mpg.execute(new FreemarkerTemplateEngine()); + } + +} \ No newline at end of file diff --git a/src/main/java/com/diagnose/common/handler/BizException.java b/src/main/java/com/diagnose/common/handler/BizException.java new file mode 100644 index 0000000..2c7b792 --- /dev/null +++ b/src/main/java/com/diagnose/common/handler/BizException.java @@ -0,0 +1,72 @@ +package com.diagnose.common.handler; + +import com.diagnose.common.result.ResponseStatus; + +public class BizException extends RuntimeException { + + private static final long serialVersionUID = 1L; + + /** + * 错误码 + */ + protected Integer errorCode = -1; + /** + * 错误信息 + */ + protected String errorMsg; + + public BizException() { + super(); + } + + public BizException(ResponseStatus responseStatus) { + super(responseStatus.code.toString() + "," + responseStatus.message); + this.errorCode = responseStatus.code; + this.errorMsg = responseStatus.message; + } + + public BizException(ResponseStatus responseStatus, String extendMsg) { + super(responseStatus.code.toString() + "," + responseStatus.message + "," + extendMsg); + this.errorCode = responseStatus.code; + this.errorMsg = extendMsg; + } + + public BizException(ResponseStatus responseStatus, Throwable cause) { + super(responseStatus.code.toString() + "," + responseStatus.message, cause); + this.errorCode = responseStatus.code; + this.errorMsg = responseStatus.message; + } + + public BizException(String errorMsg) { + super(errorMsg); + this.errorMsg = errorMsg; + } + + public BizException(Integer errorCode, String errorMsg) { + super(errorCode.toString() + "," + errorMsg); + this.errorCode = errorCode; + this.errorMsg = errorMsg; + } + + public BizException(Integer errorCode, String errorMsg, Throwable cause) { + super(errorCode.toString() + "," + errorMsg, cause); + this.errorCode = errorCode; + this.errorMsg = errorMsg; + } + + public Integer getErrorCode() { + return errorCode; + } + + public void setErrorCode(Integer errorCode) { + this.errorCode = errorCode; + } + + public String getErrorMsg() { + return errorMsg; + } + + public void setErrorMsg(String errorMsg) { + this.errorMsg = errorMsg; + } +} diff --git a/src/main/java/com/diagnose/common/handler/BizException.java~ b/src/main/java/com/diagnose/common/handler/BizException.java~ new file mode 100644 index 0000000..fdf7839 --- /dev/null +++ b/src/main/java/com/diagnose/common/handler/BizException.java~ @@ -0,0 +1,72 @@ +package com.diagnose.common.handler; + +import com.syzb.common.result.ResponseStatus; + +public class BizException extends RuntimeException { + + private static final long serialVersionUID = 1L; + + /** + * 错误码 + */ + protected Integer errorCode = -1; + /** + * 错误信息 + */ + protected String errorMsg; + + public BizException() { + super(); + } + + public BizException(ResponseStatus responseStatus) { + super(responseStatus.code.toString() + "," + responseStatus.message); + this.errorCode = responseStatus.code; + this.errorMsg = responseStatus.message; + } + + public BizException(ResponseStatus responseStatus, String extendMsg) { + super(responseStatus.code.toString() + "," + responseStatus.message + "," + extendMsg); + this.errorCode = responseStatus.code; + this.errorMsg = extendMsg; + } + + public BizException(ResponseStatus responseStatus, Throwable cause) { + super(responseStatus.code.toString() + "," + responseStatus.message, cause); + this.errorCode = responseStatus.code; + this.errorMsg = responseStatus.message; + } + + public BizException(String errorMsg) { + super(errorMsg); + this.errorMsg = errorMsg; + } + + public BizException(Integer errorCode, String errorMsg) { + super(errorCode.toString() + "," + errorMsg); + this.errorCode = errorCode; + this.errorMsg = errorMsg; + } + + public BizException(Integer errorCode, String errorMsg, Throwable cause) { + super(errorCode.toString() + "," + errorMsg, cause); + this.errorCode = errorCode; + this.errorMsg = errorMsg; + } + + public Integer getErrorCode() { + return errorCode; + } + + public void setErrorCode(Integer errorCode) { + this.errorCode = errorCode; + } + + public String getErrorMsg() { + return errorMsg; + } + + public void setErrorMsg(String errorMsg) { + this.errorMsg = errorMsg; + } +} diff --git a/src/main/java/com/diagnose/common/handler/GlobalExceptionHandler.java b/src/main/java/com/diagnose/common/handler/GlobalExceptionHandler.java new file mode 100644 index 0000000..724b260 --- /dev/null +++ b/src/main/java/com/diagnose/common/handler/GlobalExceptionHandler.java @@ -0,0 +1,97 @@ +package com.diagnose.common.handler; + +import com.google.common.collect.ImmutableSet; +import com.diagnose.common.result.CommonResult; +import com.diagnose.common.result.ResponseStatus; +import com.diagnose.common.util.logger.LoggerUtil; +import org.apache.commons.lang3.exception.ExceptionUtils; +import org.springframework.http.HttpStatus; +import org.springframework.http.converter.HttpMessageNotReadableException; +import org.springframework.validation.FieldError; +import org.springframework.web.bind.MethodArgumentNotValidException; +import org.springframework.web.bind.MissingServletRequestParameterException; +import org.springframework.web.bind.annotation.ControllerAdvice; +import org.springframework.web.bind.annotation.ExceptionHandler; +import org.springframework.web.bind.annotation.ResponseBody; + +import javax.servlet.http.HttpServletRequest; +import javax.validation.ConstraintViolationException; +import java.util.Set; + +@ControllerAdvice +public class GlobalExceptionHandler { + + /** + * 处理自定义的业务异常 + * + * @param req + * @param e + * @return + */ + @ExceptionHandler(value = BizException.class) + @ResponseBody + public CommonResult bizExceptionHandler(HttpServletRequest req, BizException e) { + LoggerUtil.error("发生业务异常:" + req.getRequestURI() + ":" + ExceptionUtils.getStackTrace(e)); + return CommonResult.error(e.getErrorCode(), e.getErrorMsg()); + } + + @ExceptionHandler({ConstraintViolationException.class}) + @org.springframework.web.bind.annotation.ResponseStatus(HttpStatus.OK) + @ResponseBody + public CommonResult handleConstraintViolationException(HttpServletRequest req, ConstraintViolationException ex) { + LoggerUtil.error("GET参数异常:" + req.getRequestURI() + ":" + ExceptionUtils.getStackTrace(ex)); + return CommonResult.error(ResponseStatus.PARM_ERROR.code, ex.getMessage()); + } + + // 入参错误返回200,统一定义返回信息 + @ExceptionHandler({MethodArgumentNotValidException.class}) + @org.springframework.web.bind.annotation.ResponseStatus(HttpStatus.OK) + @ResponseBody + public CommonResult handleMethodArgumentNotValidException(HttpServletRequest req, MethodArgumentNotValidException ex) { + StringBuilder sb = new StringBuilder(); + for (FieldError err : ex.getBindingResult().getFieldErrors()) { + sb.append("字段:") + .append(err.getField()) + .append(",传入值:") + .append(err.getRejectedValue()) + .append(",") + .append(err.getDefaultMessage()) + .append("; "); + } + LoggerUtil.error("POST参数异常:" + req.getRequestURI() + ":" + ExceptionUtils.getStackTrace(ex)); + return CommonResult.error(ResponseStatus.PARM_ERROR.code, sb.toString()); + } + + @ExceptionHandler({MissingServletRequestParameterException.class}) + @org.springframework.web.bind.annotation.ResponseStatus(HttpStatus.OK) + @ResponseBody + public CommonResult handleMissingServletRequestParameterException(HttpServletRequest req, MissingServletRequestParameterException ex) { + StringBuilder sb = new StringBuilder("字段:") + .append(ex.getParameterName()) + .append(",类型:") + .append(ex.getParameterType()) + .append(":") + .append(ex.getMessage()) + .append("."); + LoggerUtil.error("入参缺失:" + req.getRequestURI() + ":" + ExceptionUtils.getStackTrace(ex)); + return CommonResult.error(ResponseStatus.PARM_ERROR.code, sb.toString()); + } + + @ExceptionHandler({HttpMessageNotReadableException.class}) + @org.springframework.web.bind.annotation.ResponseStatus(HttpStatus.OK) + @ResponseBody + public CommonResult handleHttpMessageNotReadableException(HttpServletRequest req, HttpMessageNotReadableException ex) { + StringBuilder sb = new StringBuilder("入参格式或类型错误:") + .append(ex.getMessage()); + LoggerUtil.error("入参格式或类型错误:" + req.getRequestURI() + ":" + ExceptionUtils.getStackTrace(ex)); + return CommonResult.error(ResponseStatus.PARM_ERROR.code, sb.toString()); + } + + @ExceptionHandler(value = Exception.class) + @ResponseBody + public CommonResult doHandlerException(HttpServletRequest req, Exception e) { + LoggerUtil.error("全局异常捕获:" + req.getRequestURI() + ":" + ExceptionUtils.getStackTrace(e)); + return CommonResult.error(ResponseStatus.SYS_BUSY); + } + +} diff --git a/src/main/java/com/diagnose/common/mapper/ScheduleLogMapper.java b/src/main/java/com/diagnose/common/mapper/ScheduleLogMapper.java new file mode 100644 index 0000000..d31daf4 --- /dev/null +++ b/src/main/java/com/diagnose/common/mapper/ScheduleLogMapper.java @@ -0,0 +1,16 @@ +package com.diagnose.common.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.diagnose.common.entity.ScheduleLog; + +/** + *

+ * Mapper 接口 + *

+ * + * @author helloSyzb + * @since 2021-11-23 + */ +public interface ScheduleLogMapper extends BaseMapper { + +} diff --git a/src/main/java/com/diagnose/common/query/AppUserInfoQuery.java~ b/src/main/java/com/diagnose/common/query/AppUserInfoQuery.java~ new file mode 100644 index 0000000..a05df25 --- /dev/null +++ b/src/main/java/com/diagnose/common/query/AppUserInfoQuery.java~ @@ -0,0 +1,82 @@ +package com.syzb.common.query; + +import io.swagger.annotations.ApiModelProperty; + +import javax.validation.constraints.Max; +import javax.validation.constraints.Min; +import javax.validation.constraints.NotNull; + +public class AppUserInfoQuery { + + @ApiModelProperty("登录方式 1:用户名密码 2:token") + @NotNull + @Min(1) + @Max(2) + private Integer loginType; + + @ApiModelProperty("用户名") + private String userName; + + @ApiModelProperty("密码") + private String password; + + @ApiModelProperty("token") + private String token; + + @ApiModelProperty("refreshToken") + private String refreshToken; + + @ApiModelProperty("客户类型 1:H5 2:Web") + @NotNull + @Min(1) + @Max(2) + private Integer clientType; + + public Integer getLoginType() { + return loginType; + } + + public void setLoginType(Integer loginType) { + this.loginType = loginType; + } + + public String getUserName() { + return userName; + } + + public void setUserName(String userName) { + this.userName = userName; + } + + public String getPassword() { + return password; + } + + public void setPassword(String password) { + this.password = password; + } + + public String getToken() { + return token; + } + + public void setToken(String token) { + this.token = token; + } + + public String getRefreshToken() { + return refreshToken; + } + + public void setRefreshToken(String refreshToken) { + this.refreshToken = refreshToken; + } + + public Integer getClientType() { + return clientType; + } + + public void setClientType(Integer clientType) { + this.clientType = clientType; + } +} diff --git a/src/main/java/com/diagnose/common/query/BaseProductQuery.java~ b/src/main/java/com/diagnose/common/query/BaseProductQuery.java~ new file mode 100644 index 0000000..e2632f8 --- /dev/null +++ b/src/main/java/com/diagnose/common/query/BaseProductQuery.java~ @@ -0,0 +1,35 @@ +package com.syzb.common.query; + +import io.swagger.annotations.ApiModelProperty; + +public class BaseProductQuery implements IProduct { + + @ApiModelProperty("产品id") + private Integer productId; + + @ApiModelProperty("产品类型:1观点包 2单篇观点 3视频 5交易圈 6图文直播间 7组合 8锦囊") + private Integer productType; + + public BaseProductQuery(Integer productId, Integer productType) { + this.productId = productId; + this.productType = productType; + } + + @Override + public Integer getProductId() { + return productId; + } + + public void setProductId(Integer productId) { + this.productId = productId; + } + + @Override + public Integer getProductType() { + return productType; + } + + public void setProductType(Integer productType) { + this.productType = productType; + } +} diff --git a/src/main/java/com/diagnose/common/query/KeywordPageQuery.java b/src/main/java/com/diagnose/common/query/KeywordPageQuery.java new file mode 100644 index 0000000..c10e248 --- /dev/null +++ b/src/main/java/com/diagnose/common/query/KeywordPageQuery.java @@ -0,0 +1,18 @@ +package com.diagnose.common.query; + +import io.swagger.annotations.ApiModelProperty; + +public class KeywordPageQuery extends PageQuery { + + @ApiModelProperty("关键词") + private String keyword; + + public String getKeyword() { + return keyword; + } + + public void setKeyword(String keyword) { + this.keyword = keyword; + } + +} diff --git a/src/main/java/com/diagnose/common/query/ListAdvertQuery.java~ b/src/main/java/com/diagnose/common/query/ListAdvertQuery.java~ new file mode 100644 index 0000000..203090c --- /dev/null +++ b/src/main/java/com/diagnose/common/query/ListAdvertQuery.java~ @@ -0,0 +1,61 @@ +package com.syzb.common.query; + +import io.swagger.annotations.ApiModelProperty; + +public class ListAdvertQuery extends PageQuery { + + @ApiModelProperty("产品类型:0投顾 1观点包 2单篇观点 3视频 5交易圈 6图文直播间 7组合 8锦囊 10H5") + private Integer productType; + + @ApiModelProperty("产品ID") + private Integer productId; + + @ApiModelProperty("名称 仅H5") + private String name; + + @ApiModelProperty("位置 1:投顾首页 2:App首页 3:小程序首页") + private Integer position; + + @ApiModelProperty("创建者") + private Integer createUserId; + + public Integer getProductType() { + return productType; + } + + public void setProductType(Integer productType) { + this.productType = productType; + } + + public Integer getProductId() { + return productId; + } + + public void setProductId(Integer productId) { + this.productId = productId; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public Integer getPosition() { + return position; + } + + public void setPosition(Integer position) { + this.position = position; + } + + public Integer getCreateUserId() { + return createUserId; + } + + public void setCreateUserId(Integer createUserId) { + this.createUserId = createUserId; + } +} diff --git a/src/main/java/com/diagnose/common/query/ListScheduleLogQuery.java b/src/main/java/com/diagnose/common/query/ListScheduleLogQuery.java new file mode 100644 index 0000000..6f2f45c --- /dev/null +++ b/src/main/java/com/diagnose/common/query/ListScheduleLogQuery.java @@ -0,0 +1,62 @@ +package com.diagnose.common.query; + +import javax.validation.constraints.NotEmpty; +import javax.validation.constraints.NotNull; +import java.time.LocalDate; + +public class ListScheduleLogQuery { + + private String serverName; + + private String scheduleName; + + @NotEmpty + @NotNull + private LocalDate date; + + private Integer result; + + @NotEmpty + @NotNull + private String token; + + public String getServerName() { + return serverName; + } + + public void setServerName(String serverName) { + this.serverName = serverName; + } + + public String getScheduleName() { + return scheduleName; + } + + public void setScheduleName(String scheduleName) { + this.scheduleName = scheduleName; + } + + public LocalDate getDate() { + return date; + } + + public void setDate(LocalDate date) { + this.date = date; + } + + public Integer getResult() { + return result; + } + + public void setResult(Integer result) { + this.result = result; + } + + public String getToken() { + return token; + } + + public void setToken(String token) { + this.token = token; + } +} diff --git a/src/main/java/com/diagnose/common/query/OnlyIdPageQuery.java b/src/main/java/com/diagnose/common/query/OnlyIdPageQuery.java new file mode 100644 index 0000000..fe38b1e --- /dev/null +++ b/src/main/java/com/diagnose/common/query/OnlyIdPageQuery.java @@ -0,0 +1,29 @@ +package com.diagnose.common.query; + +import io.swagger.annotations.ApiModelProperty; + +import javax.validation.constraints.Min; +import javax.validation.constraints.NotNull; + +public class OnlyIdPageQuery extends PageQuery { + + @ApiModelProperty("ID") + @NotNull + @Min(1) + private Integer id; + + public OnlyIdPageQuery() { + } + + public OnlyIdPageQuery(Integer id) { + this.id = id; + } + + public Integer getId() { + return id; + } + + public void setId(Integer id) { + this.id = id; + } +} diff --git a/src/main/java/com/diagnose/common/query/OnlyIdQuery.java b/src/main/java/com/diagnose/common/query/OnlyIdQuery.java new file mode 100644 index 0000000..e4e0c4d --- /dev/null +++ b/src/main/java/com/diagnose/common/query/OnlyIdQuery.java @@ -0,0 +1,29 @@ +package com.diagnose.common.query; + +import io.swagger.annotations.ApiModelProperty; + +import javax.validation.constraints.Min; +import javax.validation.constraints.NotNull; + +public class OnlyIdQuery { + + @ApiModelProperty("ID") + @NotNull + @Min(1) + private Integer id; + + public OnlyIdQuery() { + } + + public OnlyIdQuery(Integer id) { + this.id = id; + } + + public Integer getId() { + return id; + } + + public void setId(Integer id) { + this.id = id; + } +} diff --git a/src/main/java/com/diagnose/common/query/PageQuery.java b/src/main/java/com/diagnose/common/query/PageQuery.java new file mode 100644 index 0000000..481f6cb --- /dev/null +++ b/src/main/java/com/diagnose/common/query/PageQuery.java @@ -0,0 +1,40 @@ +package com.diagnose.common.query; + +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import io.swagger.annotations.ApiModelProperty; + +import javax.validation.constraints.Min; + +public class PageQuery { + + @ApiModelProperty("当前页数") + @Min(1) + private Integer current = 1; + + @ApiModelProperty("每页记录数") + @Min(1) + private Integer size = 10; + + // public Page toPage() { +// return new Page(this.getCurrent(), this.getSize()); +// } + public Page toPage() { + return new Page<>(this.getCurrent(), this.getSize()); + } + + public Integer getCurrent() { + return current; + } + + public void setCurrent(Integer current) { + this.current = current; + } + + public Integer getSize() { + return size; + } + + public void setSize(Integer size) { + this.size = size; + } +} diff --git a/src/main/java/com/diagnose/common/query/SaveAdvertQuery.java~ b/src/main/java/com/diagnose/common/query/SaveAdvertQuery.java~ new file mode 100644 index 0000000..9a303ac --- /dev/null +++ b/src/main/java/com/diagnose/common/query/SaveAdvertQuery.java~ @@ -0,0 +1,114 @@ +package com.diagnose.common.query; + +import com.syzb.common.constant.AdvertPosition; +import com.syzb.common.entity.Advert; +import com.syzb.common.validation.EnumValidator; +import io.swagger.annotations.ApiModelProperty; + +import javax.validation.constraints.Max; +import javax.validation.constraints.Min; +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.NotNull; +import java.time.LocalDateTime; + +public class SaveAdvertQuery implements IProduct { + + @ApiModelProperty("位置 1:投顾首页 2:App首页 3:小程序首页") + @NotNull + @EnumValidator(AdvertPosition.class) + private Integer position; + + @ApiModelProperty("权重") + @NotNull + @Min(1) + @Max(100) + private Integer weight; + + @ApiModelProperty("产品类型:0投顾 1观点包 2单篇观点 3视频 5交易圈 6图文直播间 7组合 8锦囊 10H5") + @Min(0) + private Integer productType; + + @ApiModelProperty("产品ID") + @Min(1) + private Integer productId; + + @ApiModelProperty("名称 仅H5类型") + private String name; + + @ApiModelProperty("URL 仅H5类型") + private String url; + + @ApiModelProperty("图片URL") + @NotBlank + private String imgUrl; + + public Advert toPO(Integer createUserId) { + Advert advert = new Advert(); + advert.setPosition(this.position); + advert.setWeight(this.weight); + advert.setProductType(this.productType); + advert.setProductId(this.productId); + advert.setName(this.name); + advert.setUrl(this.url); + advert.setImgUrl(this.imgUrl); + advert.setCreateUserId(createUserId); + advert.setCreateTime(LocalDateTime.now()); + return advert; + } + + public Integer getPosition() { + return position; + } + + public void setPosition(Integer position) { + this.position = position; + } + + public Integer getWeight() { + return weight; + } + + public void setWeight(Integer weight) { + this.weight = weight; + } + + public Integer getProductType() { + return productType; + } + + public void setProductType(Integer productType) { + this.productType = productType; + } + + public Integer getProductId() { + return productId; + } + + public void setProductId(Integer productId) { + this.productId = productId; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getUrl() { + return url; + } + + public void setUrl(String url) { + this.url = url; + } + + public String getImgUrl() { + return imgUrl; + } + + public void setImgUrl(String imgUrl) { + this.imgUrl = imgUrl; + } +} diff --git a/src/main/java/com/diagnose/common/query/SetCommentTopQuery.java~ b/src/main/java/com/diagnose/common/query/SetCommentTopQuery.java~ new file mode 100644 index 0000000..1eb1f65 --- /dev/null +++ b/src/main/java/com/diagnose/common/query/SetCommentTopQuery.java~ @@ -0,0 +1,50 @@ +package com.syzb.common.query; + +import io.swagger.annotations.ApiModelProperty; + +import javax.validation.constraints.Max; +import javax.validation.constraints.Min; +import javax.validation.constraints.NotNull; + +public class SetCommentTopQuery { + + @ApiModelProperty("评论id") + @NotNull + private Integer id; + + @ApiModelProperty("置顶: 1设置置顶 2取消置顶") + @NotNull + @Min(1) + @Max(2) + private Integer flag; + + @ApiModelProperty("置顶权重") + @NotNull + @Min(0) + @Max(1000) + private Integer weight; + + public Integer getId() { + return id; + } + + public void setId(Integer id) { + this.id = id; + } + + public Integer getFlag() { + return flag; + } + + public void setFlag(Integer flag) { + this.flag = flag; + } + + public Integer getWeight() { + return weight; + } + + public void setWeight(Integer weight) { + this.weight = weight; + } +} diff --git a/src/main/java/com/diagnose/common/result/AppPager.java b/src/main/java/com/diagnose/common/result/AppPager.java new file mode 100644 index 0000000..abbe6a2 --- /dev/null +++ b/src/main/java/com/diagnose/common/result/AppPager.java @@ -0,0 +1,41 @@ +package com.diagnose.common.result; + +import java.io.Serializable; +import java.util.Collections; +import java.util.List; + +public class AppPager implements Serializable { + + private static final long serialVersionUID = 1L; + + private List list; + + private boolean hasNext; + + public static AppPager emptyPager() { + return (AppPager) EMPTY_PAGER; + } + + public static final AppPager EMPTY_PAGER = new AppPager<>(Collections.emptyList(), false); + + public AppPager(List list, boolean hasNext) { + this.list = list; + this.hasNext = hasNext; + } + + public List getList() { + return list; + } + + public void setList(List list) { + this.list = list; + } + + public boolean isHasNext() { + return hasNext; + } + + public void setHasNext(boolean hasNext) { + this.hasNext = hasNext; + } +} diff --git a/src/main/java/com/diagnose/common/result/CommonResult.java b/src/main/java/com/diagnose/common/result/CommonResult.java new file mode 100644 index 0000000..d6b9977 --- /dev/null +++ b/src/main/java/com/diagnose/common/result/CommonResult.java @@ -0,0 +1,87 @@ +package com.diagnose.common.result; + +import com.diagnose.common.util.RequestIdUtil; +import io.swagger.annotations.ApiModelProperty; + +public class CommonResult { + + @ApiModelProperty(value = "状态码", name = "code") + private Integer code; + + @ApiModelProperty(value = "消息", name = "message") + private String message; + + @ApiModelProperty(value = "数据体", name = "data") + private T data; + + @ApiModelProperty(value = "请求id", name = "requestId") + private String requestId; + + public CommonResult(Integer code, String message, T data) { + this.code = code; + this.message = message; + this.data = data; + this.requestId = RequestIdUtil.getValue(); + } + + public static CommonResult error(Integer code, String message) { + return new CommonResult(code, message, null); + } + + public static CommonResult error(ResponseStatus responseStatus) { + return new CommonResult(responseStatus.code, responseStatus.message, null); + } + + public static CommonResult success() { + return CommonResult.success(null); + } + + public static CommonResult success(T data) { + return new CommonResult(ResponseStatus.OK.code, ResponseStatus.OK.message, data); + } + + public boolean isSuccess() { + return ResponseStatus.OK.code.equals(this.code); + } + + public Integer getCode() { + return code; + } + + public void setCode(Integer code) { + this.code = code; + } + + public String getMessage() { + return message; + } + + public void setMessage(String message) { + this.message = message; + } + + public T getData() { + return data; + } + + public void setData(T data) { + this.data = data; + } + + public String getRequestId() { + return requestId; + } + + public void setRequestId(String requestId) { + this.requestId = requestId; + } + + @Override + public String toString() { + return "CommonResult{" + + "code=" + code + + ", message='" + message + '\'' + + ", data=" + data + + '}'; + } +} diff --git a/src/main/java/com/diagnose/common/result/Pager.java b/src/main/java/com/diagnose/common/result/Pager.java new file mode 100644 index 0000000..1e954c9 --- /dev/null +++ b/src/main/java/com/diagnose/common/result/Pager.java @@ -0,0 +1,49 @@ +package com.diagnose.common.result; + +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; + +import java.util.Collections; +import java.util.List; + +public class Pager { + + private List list; + + private long total; + + public static Pager emptyPager() { + return (Pager) EMPTY_PAGER; + } + + public static final Pager EMPTY_PAGER = new Pager<>(Collections.emptyList(), 0); + + public Pager(List list, long total) { + this.list = list; + this.total = total; + } + + public Pager(Page page) { + this.list = page.getRecords(); + this.total = page.getTotal(); + } + + public static Pager fromPage(Page page) { + return new Pager(page); + } + + public List getList() { + return list; + } + + public void setList(List list) { + this.list = list; + } + + public long getTotal() { + return total; + } + + public void setTotal(long total) { + this.total = total; + } +} diff --git a/src/main/java/com/diagnose/common/result/ResponseStatus.java b/src/main/java/com/diagnose/common/result/ResponseStatus.java new file mode 100644 index 0000000..e4cba80 --- /dev/null +++ b/src/main/java/com/diagnose/common/result/ResponseStatus.java @@ -0,0 +1,59 @@ +package com.diagnose.common.result; + +/** + * 0: 成功 + * 1000——1999: 认证相关错误码 + * 2000——2999: 会话相关错误码 + * 3000——3999: 外部系统相关错误码 + * 4000——4999: 参数相关错误码 + * 5000——5999: 系统内部相关错误码 + * 6000——6999:业务相关错误码 + */ +public enum ResponseStatus { + /*********************成功*************************/ + OK(0, "OK"), + + /*********************认证**************************/ + AUTH_FAIL(1000, "认证失败"), + AUTH_FAIL_CAPTCHA(1001, "认证码错误"), + PERMISSION_ERROR(1007, "权限不足"), + DATA_PERMISSION_ERROR(1008, "数据权限不足"), + PASSWORD_ERROR(1011, "密码错误"), + + /*********************SESSIION********************/ + SESSION_EXPIRY(2000, "未登录,不允许操作"), + SESSION_EXCEED(2001, "登录超时,请重新登录"), + SESSION_PASSWORD_RESET(2002, "密码被重置,请重新登录"), + PHONE_NOT_LOGIN(2003, "手机号未登录,不允许操作"), + SESSION_USER_LOGOUT(2007, "账户已退出,请重新登陆"), + + /*********************外部系统***********************/ + OUTSYS_ERROR(3000, "外部系统错误"), + + /*********************入参系统***********************/ + PARM_ERROR(4000, "入参错误"), + + /*********************内部系统***********************/ + SYS_BUSY(5000, "系统忙,请稍后重试"), + + /*********************业务***********************/ + /** + * 自定义响应信息 + */ + STATUS_ERROR(6006, "操作状态不对,不允许操作"), + ; + // 成员变量 + public final Integer code; + public final String message; + + ResponseStatus(int code, String message) { + this.code = code; + this.message = message; + } + + //覆盖方法 + @Override + public String toString() { + return this.code + "_" + this.message; + } +} diff --git a/src/main/java/com/diagnose/common/service/CacheService.java b/src/main/java/com/diagnose/common/service/CacheService.java new file mode 100644 index 0000000..61ba507 --- /dev/null +++ b/src/main/java/com/diagnose/common/service/CacheService.java @@ -0,0 +1,317 @@ +package com.diagnose.common.service; + +import com.alibaba.fastjson.JSONObject; +import com.diagnose.common.entity.ScheduleLog; +import com.hazelcast.collection.ISet; +import com.hazelcast.core.HazelcastInstance; +import com.hazelcast.crdt.pncounter.PNCounter; +import com.hazelcast.instance.impl.HazelcastInstanceProxy; +import com.hazelcast.map.IMap; +import com.diagnose.common.config.cache.CacheKey; +import com.diagnose.common.handler.BizException; +import com.diagnose.common.util.logger.LoggerUtil; +import org.apache.commons.lang3.exception.ExceptionUtils; +import org.springframework.stereotype.Component; + +import javax.annotation.Nullable; +import javax.annotation.Resource; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.Callable; +import java.util.concurrent.TimeUnit; + +import static com.diagnose.common.config.cache.CacheKey.ONLY_KEY_OBJ; + +@Component +public class CacheService { + + @Resource + private ScheduleLogService scheduleLogService; + + @Resource + private HazelcastInstance hazelcastInstance; + + private static final int UNLOCK_SLEEP_TIME = 5000; + + private static final Set loadedSet = new HashSet<>(); + + /** + * 从缓存加载数据,未找到则执行load回调 + * + * @param mapName cacheMap的名字 + * @param key cacheKey + * @param load 加载数据回调 + * @param 数据类型 + * @return + */ + public T get(String mapName, String key, Callable load) { + Map cacheMap = hazelcastInstance.getMap(mapName); + return this.get(cacheMap, key, load); + } + + /** + * 从缓存加载数据,未找到则执行load回调 + * + * @param cacheMap cacheMap + * @param key cacheKey + * @param load 加载数据回调 + * @param 数据类型 + * @return + */ + public T get(Map cacheMap, String key, Callable load) { + Object obj = cacheMap.get(key); + if (obj == null) { + T result; + try { + result = load.call(); + } catch (BizException e) { + throw e; + } catch (Exception e) { + throw new RuntimeException(e); + } + if (result == null) { + // 防止缓存穿透 + cacheMap.put(key, ONLY_KEY_OBJ); + return null; + } + cacheMap.put(key, result); + return result; + } else if (ONLY_KEY_OBJ.equals(obj)) { + return null; + } + return (T) obj; + } + + public ISet getSet(String key, Callable> load) { + ISet iSet = hazelcastInstance.getSet(key); + if (loadedSet.contains(key) || !iSet.isEmpty()) { + loadedSet.add(key); + return iSet; + } + simpleLock("task-getSet-" + key, + 0, TimeUnit.SECONDS, + 10, TimeUnit.SECONDS, + () -> { + try { + Set set = load.call(); + iSet.addAll(set); + loadedSet.add(key); + } catch (BizException e) { + throw e; + } catch (Exception e) { + throw new RuntimeException(e); + } + }); + return iSet; + } + + public IMap getMap(String key, Callable> load) { + IMap iMap = hazelcastInstance.getMap(key); + if (loadedSet.contains(key) || !iMap.isEmpty()) { + loadedSet.add(key); + return iMap; + } + simpleLock("task-getMap-" + key, + 0, TimeUnit.SECONDS, + 10, TimeUnit.SECONDS, + () -> { + try { + Map map = load.call(); + iMap.clear(); + iMap.putAll(map); + loadedSet.add(key); + } catch (BizException e) { + throw e; + } catch (Exception e) { + throw new RuntimeException(e); + } + }); + return iMap; + } + + public Integer getLong(String key, Callable load, int delta) { + PNCounter counter = hazelcastInstance.getPNCounter(key); + long v = counter.get(); + if (loadedSet.contains(key) || v != 0) { + loadedSet.add(key); + if (delta == 0) { + return (int) v; + } + return (int) counter.addAndGet(delta); + } + simpleLock("task-getLong-" + key, + 0, TimeUnit.SECONDS, + 10, TimeUnit.SECONDS, + () -> { + try { + int value = load.call(); + counter.reset(); + counter.addAndGet(value + delta); + loadedSet.add(key); + } catch (BizException e) { + throw e; + } catch (Exception e) { + throw new RuntimeException(e); + } + }); + return (int) counter.get(); + } + + /** + * 如果key不存在则执行load回调并返回执行结果,如果存在返回默认值(一般用于防止缓存穿透) + * + * @param cacheMap cacheMap + * @param key cacheKey + * @param load 回调方法 + * @param defaultValue 默认值 + * @param 数据类型 + * @return + */ + public T runNx(Map cacheMap, String key, Callable load, T defaultValue) { + Object obj = cacheMap.get(key); + if (obj == null) { + T result; + try { + result = load.call(); + } catch (Exception e) { + throw new RuntimeException(e); + } + // 防止缓存穿透 + cacheMap.put(key, ONLY_KEY_OBJ); + return result; + } + return defaultValue; + } + + /** + * 多线程锁 + * + * @param taskName 任务名字 + * @param time 加锁时间值 + * @param timeunit 加锁时间类型 + * @param leaseTime 自动释放时间值 + * @param leaseTimeunit 自动释放时间类型 + * @param fn 加锁成功后执行的方法 + * @param 类型 + */ + public void lock(String taskName, + long time, @Nullable TimeUnit timeunit, + long leaseTime, @Nullable TimeUnit leaseTimeunit, + Callable fn) { + try { + IMap map = hazelcastInstance.getMap(CacheKey.DISTRIBUTED_LOCK); + boolean lock = map.tryLock(taskName, time, timeunit, leaseTime, leaseTimeunit); + if (lock) { + String host = ((HazelcastInstanceProxy) hazelcastInstance).getOriginal().getLocalEndpoint().getAddress().getHost(); + Integer logId = null; + long runTime = 0; + try { + logId = scheduleLogService.save(ScheduleLog.start(taskName, host)); + long startTime = System.currentTimeMillis(); + LoggerUtil.data.info(taskName + "-开始"); + T result = fn.call(); + runTime = System.currentTimeMillis() - startTime; + String resultJSON = JSONObject.toJSONString(result); + LoggerUtil.data.info(taskName + "-结束:" + runTime, resultJSON); + scheduleLogService.save(ScheduleLog.success(logId, result == null ? null : resultJSON)); + } catch (Exception e) { + LoggerUtil.error.error(taskName + "-异常:" + ExceptionUtils.getStackTrace(e)); + scheduleLogService.save(ScheduleLog.error(logId, ExceptionUtils.getStackTrace(e))); + } finally { + if (runTime >= UNLOCK_SLEEP_TIME) { + map.forceUnlock(taskName); + } else if (lock) { + TimeUnit.MILLISECONDS.sleep(UNLOCK_SLEEP_TIME - runTime); + if (map.isLocked(taskName)) { + map.unlock(taskName); + } + } + } + } + } catch (Exception e) { + LoggerUtil.error.error(taskName + "-异常:" + ExceptionUtils.getStackTrace(e)); + } + } + + /** + * 多线程锁 + * + * @param taskName 任务名字 + * @param time 加锁时间值 + * @param timeunit 加锁时间类型 + * @param leaseTime 自动释放时间值 + * @param leaseTimeunit 自动释放时间类型 + * @param fn 加锁成功后执行的方法 + */ + public void lock(String taskName, + long time, @Nullable TimeUnit timeunit, + long leaseTime, @Nullable TimeUnit leaseTimeunit, + Runnable fn) { + try { + IMap map = hazelcastInstance.getMap(CacheKey.DISTRIBUTED_LOCK); + long runTime = 0; + boolean lock = map.tryLock(taskName, time, timeunit, leaseTime, leaseTimeunit); + if (lock) { + String host = ((HazelcastInstanceProxy) hazelcastInstance).getOriginal().getLocalEndpoint().getAddress().getHost(); + Integer logId = null; + try { + logId = scheduleLogService.save(ScheduleLog.start(taskName, host)); + long startTime = System.currentTimeMillis(); + LoggerUtil.data.info(taskName + "-开始"); + fn.run(); + runTime = System.currentTimeMillis() - startTime; + LoggerUtil.data.info(taskName + "-结束:" + runTime); + scheduleLogService.save(ScheduleLog.success(logId, null)); + } catch (Exception e) { + LoggerUtil.error.error(taskName + "-异常:" + ExceptionUtils.getStackTrace(e)); + scheduleLogService.save(ScheduleLog.error(logId, ExceptionUtils.getStackTrace(e))); + } finally { + if (runTime >= UNLOCK_SLEEP_TIME) { + map.forceUnlock(taskName); + } else if (lock) { + TimeUnit.MILLISECONDS.sleep(UNLOCK_SLEEP_TIME - runTime); + if (map.isLocked(taskName)) { + map.unlock(taskName); + } + } + } + } + } catch (Exception e) { + LoggerUtil.error.error(taskName + "-异常:" + ExceptionUtils.getStackTrace(e)); + } + } + + public void simpleLock(String key, long time, @Nullable TimeUnit timeunit, long leaseTime, @Nullable TimeUnit leaseTimeunit, Runnable fn) { + IMap map = hazelcastInstance.getMap(CacheKey.DISTRIBUTED_LOCK); + boolean lock = false; + try { + lock = map.tryLock(key, time, timeunit, leaseTime, leaseTimeunit); + if (lock) { + fn.run(); + } + } catch (InterruptedException e) { + throw new RuntimeException(e); + } finally { + if (lock && map.isLocked(key)) { + map.unlock(key); + } + } + } + + public Integer getLong(String cacheKey, int delta) { + PNCounter counter = hazelcastInstance.getPNCounter(cacheKey); + return (int) counter.addAndGet(delta); + } + + public void clearCache(String mapName, List cacheKeys) { + Map cacheMap = hazelcastInstance.getMap(mapName); + cacheKeys.forEach(cacheMap::remove); + } + + public void clearCache(String mapName, String cacheKey) { + Map cacheMap = hazelcastInstance.getMap(mapName); + cacheMap.remove(cacheKey); + } +} diff --git a/src/main/java/com/diagnose/common/service/CommentBlackService.java~ b/src/main/java/com/diagnose/common/service/CommentBlackService.java~ new file mode 100644 index 0000000..be3fa08 --- /dev/null +++ b/src/main/java/com/diagnose/common/service/CommentBlackService.java~ @@ -0,0 +1,285 @@ +package com.diagnose.common.service; + +import cn.hutool.core.util.StrUtil; +import com.alibaba.fastjson.JSONObject; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.google.common.collect.Table; +import com.hazelcast.core.HazelcastInstance; +import com.hazelcast.map.IMap; +import com.syzb.common.constant.CommentBlackScope; +import com.syzb.common.constant.CommentBlackStatus; +import com.syzb.common.constant.CommentBlackType; +import com.syzb.common.entity.CommentBlack; +import com.syzb.common.handler.BizException; +import com.syzb.common.mapper.CommentBlackMapper; +import com.syzb.common.query.AddCommentBlackQuery; +import com.syzb.common.query.BaseProductQuery; +import com.syzb.common.query.CommentBlackQuery; +import com.syzb.common.query.RemoveCommentBlackQuery; +import com.syzb.common.result.Pager; +import com.syzb.common.result.ResponseStatus; +import com.syzb.common.util.logger.LoggerUtil; +import com.syzb.common.vo.BackendUserVO; +import com.syzb.common.vo.CommentBlackVO; +import com.syzb.common.vo.MergeProductInfoVO; +import com.syzb.rbac.entity.Dept; +import com.syzb.rbac.entity.UserDept; +import com.syzb.rbac.service.DeptService; +import com.syzb.rbac.service.UserService; +import com.syzb.rbac.service.WxUserService; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.util.CollectionUtils; + +import javax.annotation.Resource; +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; +import java.util.*; +import java.util.stream.Collectors; + +import static com.syzb.common.config.cache.CacheKey.COMMENT_BLACK; +import static com.syzb.common.config.cache.CacheKey.CommentBlackKey.ALL_BLACK_COMMENT; +import static com.syzb.common.config.cache.CacheKey.CommentBlackKey.ALL_BLACK_USER; + +@Service +public class CommentBlackService { + + @Resource + private CommentBlackMapper commentBlackMapper; + + @Resource + private UserService userService; + + @Resource + private MergeProductService mergeProductService; + + @Resource + private HazelcastInstance hazelcastInstance; + + @Resource + private CacheService cacheService; + + @Resource + private DeptService deptService; + + @Resource + private WxUserService wxUserService; + + private static final DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"); + + @Transactional(rollbackFor = Exception.class) + public Integer addCommentBlack(BackendUserVO backendUserVO, AddCommentBlackQuery query) { + String userPhone = query.getUserPhone(); + LocalDateTime now = LocalDateTime.now(); + //禁言开始时间-1s + now = now.minusSeconds(1L); + QueryWrapper wrapper = Wrappers.query(); + wrapper.eq("phone", userPhone) + .in("status", Arrays.asList(CommentBlackStatus.EFFECT.value, CommentBlackStatus.EXPIRED.value)) + .lt("start_time", now) + .ge("end_time", now); + long validSize = commentBlackMapper.selectCount(wrapper); + if (validSize > 0) { + throw new BizException(ResponseStatus.REPETITIVE_ERROR); + } + CommentBlack commentBlack = query.toPO(); + commentBlack.setStartTime(now); + commentBlack.setStatus(CommentBlackStatus.EFFECT.value); + commentBlack.setOperatorId(backendUserVO.getUserId()); + commentBlack.setUpdateTime(now); + commentBlack.setAdvisorId(backendUserVO.getAdvisorId()); + if (CommentBlackType.DAY.value.equals(commentBlack.getType())) { + commentBlack.setEndTime(now.plusDays(1)); + } else if (CommentBlackType.MONTH.value.equals(commentBlack.getType())) { + commentBlack.setEndTime(now.plusMonths(1)); + } else { + commentBlack.setEndTime(now.plusYears(100)); + } + int count = commentBlackMapper.insert(commentBlack); + if (count < 1) { + throw new BizException(ResponseStatus.DB_SAVE_ERROR); + } + this.clearCache(ALL_BLACK_USER, ALL_BLACK_COMMENT); + return commentBlack.getId(); + } + + @Transactional(rollbackFor = Exception.class) + public void removeCommentBlack(BackendUserVO backendUserVO, RemoveCommentBlackQuery query) { + LocalDateTime now = LocalDateTime.now(); + QueryWrapper wrapper = Wrappers.query(); + wrapper.eq("phone", query.getUserPhone()) + .eq("product_id", query.getProductId()) + .eq("product_type", query.getProductType()) + .in("status", Arrays.asList(CommentBlackStatus.EFFECT.value, CommentBlackStatus.EXPIRED.value)) + .lt("start_time", now) + .ge("end_time", now); + List commentBlackList = commentBlackMapper.selectList(wrapper); + if (CollectionUtils.isEmpty(commentBlackList)) { + throw new BizException(ResponseStatus.REMOVE_BLACK_USER_ERROR); + } + for (CommentBlack commentBlack : commentBlackList) { + CommentBlack updateObj = new CommentBlack(); + updateObj.setId(commentBlack.getId()); + updateObj.setStatus(CommentBlackStatus.REMOVED.value); + updateObj.setUpdateTime(now); + updateObj.setEndTime(now); + int count = commentBlackMapper.updateById(updateObj); + if (count < 1) { + throw new BizException(ResponseStatus.DB_SAVE_ERROR); + } + } + this.clearCache(ALL_BLACK_USER, ALL_BLACK_COMMENT); + } + + public Pager queryCommentBlackList(BackendUserVO backendUserVO, CommentBlackQuery query) { + LocalDateTime startTime = null; + LocalDateTime endTime = null; + LocalDateTime startOpTime = null; + LocalDateTime endOpTime = null; + if (StrUtil.isNotEmpty(query.getStartTime())) { + startTime = LocalDateTime.parse(query.getStartTime(), formatter); + } + if (StrUtil.isNotEmpty(query.getEndTime())) { + endTime = LocalDateTime.parse(query.getEndTime(), formatter); + } + if (StrUtil.isNotEmpty(query.getStartOpTime())) { + startOpTime = LocalDateTime.parse(query.getStartOpTime(), formatter); + } + if (StrUtil.isNotEmpty(query.getEndOpTime())) { + endOpTime = LocalDateTime.parse(query.getEndOpTime(), formatter); + } + QueryWrapper wrapper = Wrappers.query(); + wrapper.like(StrUtil.isNotEmpty(query.getUserName()), "user_name", query.getUserName()) + .eq(StrUtil.isNotEmpty(query.getPhone()), "phone", query.getPhone()) + .eq(query.getStatus() != null, "status", query.getStatus()) + .eq(query.getType() != null, "type", query.getType()) + .eq(query.getProductType() != null, "product_type", query.getProductType()) + .eq(query.getProductType() != null && query.getProductId() != null, "product_id", query.getProductId()) + .like(StrUtil.isNotBlank(query.getContent()), "content", query.getContent()) + .like(StrUtil.isNotEmpty(query.getReason()), "reason", query.getReason()) + .eq(query.getOperatorId() != null, "operator_id", query.getOperatorId()) + .ge(startTime != null, "start_time", startTime) + .lt(endTime != null, "start_time", endTime) + .ge(startOpTime != null, "end_time", startOpTime) + .lt(endOpTime != null, "end_time", endOpTime); + wrapper.orderByDesc("start_time"); + Page page = commentBlackMapper.selectPage(query.toPage(), wrapper); + List list = page.getRecords(); + if (CollectionUtils.isEmpty(list)) { + return Pager.emptyPager(); + } + List baseProductQueryList = list.stream().map(commentBlack -> { + if (commentBlack.getProductId() != null && commentBlack.getProductType() != null) { + return new BaseProductQuery(commentBlack.getProductId(), commentBlack.getProductType()); + } + return null; + }).filter(Objects::nonNull).collect(Collectors.toList()); + Table productTable = mergeProductService.queryMergeProductInfo(baseProductQueryList); + Map userMap = userService.getUserMap(); + Map deptMap = deptService.getDeptMap(); + List voList = list.stream().map(CommentBlackVO::new).collect(Collectors.toList()); + for (CommentBlackVO commentBlackVO : voList) { + // 查询产品信息 + if (commentBlackVO.getProductId() != null && commentBlackVO.getProductType() != null) { + MergeProductInfoVO mergeProductInfoVO = productTable.get(commentBlackVO.getProductType(), commentBlackVO.getProductId()); + if (mergeProductInfoVO != null) { + commentBlackVO.setProductName(mergeProductInfoVO.getProductName()); + } + } + LocalDateTime now = LocalDateTime.now(); + if (CommentBlackStatus.EFFECT.value.equals(commentBlackVO.getStatus()) && now.isAfter(commentBlackVO.getEndTime())) { + commentBlackVO.setStatus(CommentBlackStatus.EXPIRED.value); + } + UserDept user = userMap.get(commentBlackVO.getOperatorId()); + if (user != null) { + commentBlackVO.setOperatorName(user.getName()); + } + if (StrUtil.isNotEmpty(commentBlackVO.getUserOrgNo())) { + Dept dept = deptMap.get(commentBlackVO.getUserOrgNo()); + if (dept != null) { + commentBlackVO.setUserOrgName(dept.getName()); + } + } + commentBlackVO.setUserHeadPic(wxUserService.getHeadPic(commentBlackVO.getPhone())); + } + return new Pager<>(voList, page.getTotal()); + } + + /** + * 校验是否禁言 + */ + public boolean checkIsBlack(String phone, Integer productId, Integer productType) { + // 判断是否禁言用户 + Set blackUsers = getAllBlackUser(); + if (!blackUsers.contains(phone)) { + return false; + } + List blackComments = getAllBlackComment(); + if (CollectionUtils.isEmpty(blackComments)) { + return false; + } + for (CommentBlack commentBlack : blackComments) { + if (commentBlack.getPhone().equals(phone)) { + if (CommentBlackScope.PRODUCT.value.equals(commentBlack.getScope())) { + if (commentBlack.getProductId().equals(productId) && commentBlack.getProductType().equals(productType)) { + return true; + } + } else if (CommentBlackScope.PRODUCT_TYPE.value.equals(commentBlack.getScope())) { + if (commentBlack.getProductType().equals(productType)) { + return true; + } + } else if (CommentBlackScope.GLOBAL.value.equals(commentBlack.getScope())) { + return true; + } + } + } + return false; + } + + private Set getAllBlackUser() { + return cacheService.get(COMMENT_BLACK, ALL_BLACK_USER, () -> + getAllBlackComment().stream().map(CommentBlack::getPhone).collect(Collectors.toSet())); + } + + private List getAllBlackComment() { + LocalDateTime now = LocalDateTime.now(); + return cacheService.get(COMMENT_BLACK, ALL_BLACK_COMMENT, () -> { + QueryWrapper wrapper = Wrappers.query() + .in("status", Arrays.asList(CommentBlackStatus.EFFECT.value, CommentBlackStatus.EXPIRED.value)) + .lt("start_time", now) + .gt("end_time", now); + List commentBlackList = commentBlackMapper.selectList(wrapper); + LoggerUtil.info("db当前黑名单用户:" + JSONObject.toJSONString(commentBlackList)); + return commentBlackList; + }); + } + + public Set getBlackUserIds(Integer productId, Integer productType) { + Set blackUsers = new HashSet<>(); + List blackComments = getAllBlackComment(); + for (CommentBlack commentBlack : blackComments) { + if (CommentBlackScope.PRODUCT.value.equals(commentBlack.getScope())) { + if (commentBlack.getProductId().equals(productId) && commentBlack.getProductType().equals(productType)) { + blackUsers.add(commentBlack.getPhone()); + } + } else if (CommentBlackScope.PRODUCT_TYPE.value.equals(commentBlack.getScope())) { + if (commentBlack.getProductType().equals(productType)) { + blackUsers.add(commentBlack.getPhone()); + } + } else if (CommentBlackScope.GLOBAL.value.equals(commentBlack.getScope())) { + blackUsers.add(commentBlack.getPhone()); + } + } + return blackUsers; + } + + private void clearCache(String... cacheKeys) { + IMap cacheMap = hazelcastInstance.getMap(COMMENT_BLACK); + for (String key : cacheKeys) { + cacheMap.remove(key); + } + } + +} diff --git a/src/main/java/com/diagnose/common/service/MergeProductService.java~ b/src/main/java/com/diagnose/common/service/MergeProductService.java~ new file mode 100644 index 0000000..c74a2df --- /dev/null +++ b/src/main/java/com/diagnose/common/service/MergeProductService.java~ @@ -0,0 +1,112 @@ +package com.diagnose.common.service; + +import com.google.common.collect.HashBasedTable; +import com.google.common.collect.Table; +import com.syzb.advisor.entity.AdvisorBasic; +import com.syzb.advisor.service.AdvisorInfoService; +import com.syzb.advisor.vo.AdvisorInfoAppVO; +import com.syzb.common.constant.ProductType; +import com.syzb.common.query.IProduct; +import com.syzb.common.util.CollectUtil; +import com.syzb.common.vo.MergeProductInfoVO; +import com.syzb.course.query.IdAndSaleUserQuery; +import com.syzb.course.service.ShortVideoService; +import com.syzb.course.vo.ShortVideoVO; +import com.syzb.video.service.app.AppVideoColumnService; +import com.syzb.video.service.app.AppVideoInfoService; +import com.syzb.video.vo.column.VideoColumnAppVO; +import com.syzb.video.vo.info.VideoInfoAppVO; +import org.springframework.stereotype.Service; +import org.springframework.util.CollectionUtils; + +import javax.annotation.Resource; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +@Service +public class MergeProductService { + + @Resource + private AdvisorInfoService advisorInfoService; + + @Resource + private AppVideoInfoService appVideoInfoService; + + @Resource + private AppVideoColumnService appVideoColumnService; + + @Resource + private ShortVideoService shortVideoService; + + public Table queryMergeProductInfo(List productQueryList) { + Table voTable = HashBasedTable.create(); + Table objTable = this.queryMergeProductInfo(productQueryList, false); + objTable.cellSet().forEach(cell -> voTable.put(cell.getRowKey(), cell.getColumnKey(), (MergeProductInfoVO) cell.getValue())); + return voTable; + } + + /** + * 查询产品信息 + * + * @param productQueryList + * @return productType、productId、MergeProductInfoVO + */ + public Table queryMergeProductInfo(List productQueryList, boolean returnDetail) { + Table table = HashBasedTable.create(); + if (CollectionUtils.isEmpty(productQueryList)) { + return table; + } + // 去重 + productQueryList = productQueryList.stream().filter(product -> product.getProductType() != null && product.getProductId() != null).filter(CollectUtil.distinctByKey(product -> product.getProductType() + ":" + product.getProductId())).collect(Collectors.toList()); + Map advisorBasicMap = advisorInfoService.getAdvisorMap(); + productQueryList.forEach(product -> { + // 查询产品信息,投顾信息,团队信息 + if (ProductType.ADVISOR_INFO.value.equals(product.getProductType())) { + AdvisorInfoAppVO advisorInfoVO = advisorInfoService.getForApp(product.getProductId(), null); + if (advisorInfoVO != null) { + Object value = returnDetail ? advisorInfoVO : new MergeProductInfoVO(product.getProductId(), advisorInfoVO.getShowName(), advisorInfoVO.getProfile(), advisorInfoVO.getStatus(), null, advisorInfoVO.getCreateTime(), advisorInfoVO.getPublishTime(), advisorBasicMap.get(product.getProductId()), ProductType.ADVISOR_INFO.value, null, null, null); + table.put(product.getProductType(), product.getProductId(), value); + } + } else if (ProductType.VIDEO_SINGLE.value.equals(product.getProductType())) { + VideoInfoAppVO videoInfoVO = appVideoInfoService.getVideoInfo(product.getProductId(), null); + if (videoInfoVO != null) { + Object value; + if (returnDetail) { + value = videoInfoVO; + } else { + MergeProductInfoVO vo = new MergeProductInfoVO(product.getProductId(), videoInfoVO.getTitle(), videoInfoVO.getViewPoint(), + videoInfoVO.getStatus(), videoInfoVO.getRiskLevel(), videoInfoVO.getCreateTime(), videoInfoVO.getAuditTime(), advisorBasicMap.get(videoInfoVO.getAdvisorId()), + ProductType.VIDEO_SINGLE.value, null, null, null + ); + vo.setVideoPlayType(videoInfoVO.getPlayType()); + value = vo; + } + table.put(product.getProductType(), product.getProductId(), value); + } + } else if (ProductType.VIDEO_COLUMN.value.equals(product.getProductType())) { + VideoColumnAppVO columnVO = appVideoColumnService.getColumnDetail(product.getProductId(), null); + if (columnVO != null) { + Object value; + if (returnDetail) { + value = columnVO; + } else { + value = new MergeProductInfoVO(product.getProductId(), columnVO.getName(), columnVO.getIntroduce(), + columnVO.getStatus(), null, null, null, null, + ProductType.VIDEO_COLUMN.value, null, null, null + ); + } + table.put(product.getProductType(), product.getProductId(), value); + } + } else if (ProductType.SHORT_VIDEO.value.equals(product.getProductType())) { + ShortVideoVO shortVideoVO = shortVideoService.getForApp(new IdAndSaleUserQuery(product.getProductId()), null, false); + Object value = returnDetail ? shortVideoVO : new MergeProductInfoVO(product.getProductId(), shortVideoVO.getTitle(), shortVideoVO.getViewPoint(), + shortVideoVO.getStatus(), shortVideoVO.getRiskLevel(), shortVideoVO.getCreateTime(), shortVideoVO.getAuditTime(), advisorBasicMap.get(shortVideoVO.getAdvisorId()), + ProductType.SHORT_VIDEO.value, null, null, null); + table.put(product.getProductType(), product.getProductId(), value); + } + }); + return table; + } + +} diff --git a/src/main/java/com/diagnose/common/service/ScheduleLogService.java b/src/main/java/com/diagnose/common/service/ScheduleLogService.java new file mode 100644 index 0000000..45dd0f3 --- /dev/null +++ b/src/main/java/com/diagnose/common/service/ScheduleLogService.java @@ -0,0 +1,70 @@ +package com.diagnose.common.service; + +import cn.hutool.core.util.StrUtil; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import com.diagnose.common.entity.ScheduleLog; +import com.diagnose.common.handler.BizException; +import com.diagnose.common.mapper.ScheduleLogMapper; +import com.diagnose.common.query.ListScheduleLogQuery; +import com.diagnose.common.result.ResponseStatus; +import com.diagnose.common.util.CodecUtil; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import javax.annotation.Resource; +import java.time.LocalDate; +import java.time.format.DateTimeFormatter; +import java.util.List; + +@Service +public class ScheduleLogService { + + private static final String salt = "UP_OEM_SCHEDULE_LOG"; + + @Resource + private ScheduleLogMapper scheduleLogMapper; + + public List list(ListScheduleLogQuery query) { + checkToken(query); + String serverName = query.getServerName(); + String scheduleName = query.getScheduleName(); + LocalDate date = query.getDate(); + Integer result = query.getResult(); + QueryWrapper wrapper = Wrappers.query(); + wrapper.eq(StrUtil.isNotEmpty(serverName), "server_name", serverName) + .eq(StrUtil.isNotEmpty(scheduleName), "schedule_name", scheduleName) + .eq(date != null, "date", date) + .eq(result != null && result != 0, "result", result); + return scheduleLogMapper.selectList(wrapper); + } + + @Transactional + public Integer save(ScheduleLog log) { + if (log.getId() == null) { + scheduleLogMapper.insert(log); + } else { + scheduleLogMapper.updateById(log); + } + return log.getId(); + } + + @Transactional + public void clearHistory(int saveDays) { + LocalDate saveDate = LocalDate.now().minusDays(saveDays); + QueryWrapper wrapper = Wrappers.query(); + wrapper.lt("date", saveDate); + scheduleLogMapper.delete(wrapper); + } + + private void checkToken(ListScheduleLogQuery query) { + String token = query.getToken(); + LocalDate date = query.getDate(); + String dateStr = date.format(DateTimeFormatter.BASIC_ISO_DATE); + String hash = CodecUtil.md5(dateStr + salt); + if (!hash.equals(token)) { + throw new BizException(ResponseStatus.AUTH_FAIL); + } + } + +} diff --git a/src/main/java/com/diagnose/common/util/CodecUtil.java b/src/main/java/com/diagnose/common/util/CodecUtil.java new file mode 100644 index 0000000..5f7505e --- /dev/null +++ b/src/main/java/com/diagnose/common/util/CodecUtil.java @@ -0,0 +1,58 @@ +package com.diagnose.common.util; + +import cn.hutool.core.util.StrUtil; +import com.google.common.base.Charsets; +import org.springframework.util.DigestUtils; + +import javax.crypto.Mac; +import javax.crypto.spec.SecretKeySpec; +import java.math.BigInteger; +import java.nio.charset.StandardCharsets; +import java.security.InvalidKeyException; +import java.security.NoSuchAlgorithmException; +import java.util.Base64; + +public class CodecUtil { + + public static String md5(String src) { + return new BigInteger(1, DigestUtils.md5Digest(src.getBytes(Charsets.UTF_8))).toString(16); + } + + public static String md5(byte[] src) { + return new BigInteger(1, DigestUtils.md5Digest(src)).toString(16); + } + + private static byte[] byteMerger(byte[] byte1, byte[] byte2) { + byte[] byte3 = new byte[byte1.length + byte2.length]; + System.arraycopy(byte1, 0, byte3, 0, byte1.length); + System.arraycopy(byte2, 0, byte3, byte1.length, byte2.length); + return byte3; + } + + public static String sha1(String key, String str) throws NoSuchAlgorithmException, InvalidKeyException { + Mac mac = Mac.getInstance("HmacSHA1"); + SecretKeySpec secretKeySpec = new SecretKeySpec(key.getBytes(StandardCharsets.UTF_8), mac.getAlgorithm()); + mac.init(secretKeySpec); + + byte[] hash = mac.doFinal(str.getBytes(StandardCharsets.UTF_8)); + byte[] sigBuf = byteMerger(hash, str.getBytes(StandardCharsets.UTF_8)); + return Base64.getEncoder().encodeToString(sigBuf); + } + + public static String mobileEncrypt(String mobile) { + if (StrUtil.isEmpty(mobile) || (mobile.length() != 11)) { + return ""; + } + return mobile.replaceAll("(\\w{3})\\w*(\\w{4})", "$1****$2"); + } + + // 带盐值的MD5加密 + public static String md5WithSalt(String key, String salt) { + return md5(key + salt); + } + + public static void main(String[] args) { + String sign = md5WithSalt("video_demo", "1615860427"); + System.out.println(sign); + } +} diff --git a/src/main/java/com/diagnose/common/util/CollectUtil.java b/src/main/java/com/diagnose/common/util/CollectUtil.java new file mode 100644 index 0000000..b5bdb2f --- /dev/null +++ b/src/main/java/com/diagnose/common/util/CollectUtil.java @@ -0,0 +1,15 @@ +package com.diagnose.common.util; + +import java.util.HashMap; +import java.util.Map; +import java.util.function.Function; +import java.util.function.Predicate; + +public class CollectUtil { + + public static Predicate distinctByKey(Function keyExtractor) { + Map seen = new HashMap<>(); + return t -> seen.putIfAbsent(keyExtractor.apply(t), Boolean.TRUE) == null; + } + +} diff --git a/src/main/java/com/diagnose/common/util/Debounce.java b/src/main/java/com/diagnose/common/util/Debounce.java new file mode 100644 index 0000000..6bff549 --- /dev/null +++ b/src/main/java/com/diagnose/common/util/Debounce.java @@ -0,0 +1,48 @@ +package com.diagnose.common.util; + +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.ScheduledFuture; +import java.util.concurrent.TimeUnit; + +public class Debounce { + + // 线程池用于调度任务 + private final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1); + + // 保存当前的调度任务 + private ScheduledFuture future; + + // 防抖函数 + public void debounce(Runnable task, long delayInMillis) { + // 如果之前有未执行的任务,取消它 + if (future != null && !future.isDone()) { + future.cancel(false); + } + + // 调度新的任务 + future = scheduler.schedule(task, delayInMillis, TimeUnit.MILLISECONDS); + } + + // 用于关闭线程池 + public void shutdown() { + scheduler.shutdown(); + } + +// public static void main(String[] args) throws InterruptedException { +// Debounce debounce = new Debounce(); +// +// // 模拟多次快速调用 +// for (int i = 1; i <= 5; i++) { +// int j = i; +// // 应该只答应最后一次任务的序号 +// debounce.debounce(() -> System.out.println("Task executed!" + j), 500); +// Thread.sleep(100); // 每100毫秒触发一次 +// } +// +// // 给出足够时间执行最后一次任务 +// Thread.sleep(1100); +// +// debounce.shutdown(); +// } +} \ No newline at end of file diff --git a/src/main/java/com/diagnose/common/util/HideUtils.java b/src/main/java/com/diagnose/common/util/HideUtils.java new file mode 100644 index 0000000..1e1b387 --- /dev/null +++ b/src/main/java/com/diagnose/common/util/HideUtils.java @@ -0,0 +1,28 @@ +package com.diagnose.common.util; + +import cn.hutool.core.util.StrUtil; + +public class HideUtils { + + public static String hidePhoneNo(String phoneNo) { + if (StrUtil.isBlank(phoneNo)) { + return phoneNo; + } + if (phoneNo.length() >= 7) { + //前三后四 + return phoneNo.substring(0, 3) + "****" + + phoneNo.substring(phoneNo.length() - 4); + } else { + return phoneNo; + } + } + + public static String maskLastName(String name) { + if (StrUtil.isBlank(name)) { + return null; + } + int length = name.length(); + return name.substring(0, length - 1) + "*"; + } + +} diff --git a/src/main/java/com/diagnose/common/util/IPUtil.java b/src/main/java/com/diagnose/common/util/IPUtil.java new file mode 100644 index 0000000..4fe208f --- /dev/null +++ b/src/main/java/com/diagnose/common/util/IPUtil.java @@ -0,0 +1,39 @@ +package com.diagnose.common.util; + +import org.springframework.stereotype.Component; + +import javax.servlet.http.HttpServletRequest; + +@Component +public class IPUtil { + + /** + * 获取IP地址 + * + * @param request + * @return + */ + public static String getIpAddr(HttpServletRequest request) { + String ip = request.getHeader("x-forwarded-for"); + if (ip == null || ip.isEmpty() || "unknown".equalsIgnoreCase(ip)) { + ip = request.getHeader("X-Real-IP"); + } + if (ip == null || ip.isEmpty() || "unknown".equalsIgnoreCase(ip)) { + ip = request.getHeader("Proxy-Client-IP"); + } + if (ip == null || ip.isEmpty() || "unknown".equalsIgnoreCase(ip)) { + ip = request.getHeader("WL-Proxy-Client-IP"); + } + if (ip == null || ip.isEmpty() || "unknown".equalsIgnoreCase(ip)) { + ip = request.getRemoteAddr(); + } + if ("0:0:0:0:0:0:0:1".equals(ip)) { + ip = "127.0.0.1"; + } + if (ip.split(",").length > 1) { + ip = ip.split(",")[0]; + } + return ip; + } + +} diff --git a/src/main/java/com/diagnose/common/util/RequestIdUtil.java b/src/main/java/com/diagnose/common/util/RequestIdUtil.java new file mode 100644 index 0000000..e26dbc5 --- /dev/null +++ b/src/main/java/com/diagnose/common/util/RequestIdUtil.java @@ -0,0 +1,41 @@ +package com.diagnose.common.util; + +import cn.hutool.core.util.RandomUtil; +import cn.hutool.core.util.StrUtil; +import org.slf4j.MDC; + +import java.util.Date; + +public class RequestIdUtil { + + public static void setValue(String str) { + String requestId = RandomUtil.randomString(6); + MDC.put("requestId", str + "-" + requestId); + } + + public static void setValue() { + String requestId = RandomUtil.randomString(6); + MDC.put("requestId", requestId); + } + + public static String getValue() { + String requestId = MDC.get("requestId"); + return StrUtil.isNotEmpty(requestId) ? requestId : ""; + } + + public static void removeValue() { + MDC.remove("requestId"); + } + + public static void setTime() { + MDC.put("requestTime", String.valueOf(new Date().getTime())); + } + + public static long getTime() { + return Long.parseLong(MDC.get("requestTime")); + } + + public static void removeTime() { + MDC.remove("requestTime"); + } +} diff --git a/src/main/java/com/diagnose/common/util/RequestIdUtil.java~ b/src/main/java/com/diagnose/common/util/RequestIdUtil.java~ new file mode 100644 index 0000000..b5334be --- /dev/null +++ b/src/main/java/com/diagnose/common/util/RequestIdUtil.java~ @@ -0,0 +1,41 @@ +package com.syzb.common.util; + +import cn.hutool.core.util.RandomUtil; +import cn.hutool.core.util.StrUtil; +import org.slf4j.MDC; + +import java.util.Date; + +public class RequestIdUtil { + + public static void setValue(String str) { + String requestId = RandomUtil.randomString(6); + MDC.put("requestId", str + "-" + requestId); + } + + public static void setValue() { + String requestId = RandomUtil.randomString(6); + MDC.put("requestId", requestId); + } + + public static String getValue() { + String requestId = MDC.get("requestId"); + return StrUtil.isNotEmpty(requestId) ? requestId : ""; + } + + public static void removeValue() { + MDC.remove("requestId"); + } + + public static void setTime() { + MDC.put("requestTime", String.valueOf(new Date().getTime())); + } + + public static long getTime() { + return Long.parseLong(MDC.get("requestTime")); + } + + public static void removeTime() { + MDC.remove("requestTime"); + } +} diff --git a/src/main/java/com/diagnose/common/util/RsaUtil.java b/src/main/java/com/diagnose/common/util/RsaUtil.java new file mode 100644 index 0000000..75503d0 --- /dev/null +++ b/src/main/java/com/diagnose/common/util/RsaUtil.java @@ -0,0 +1,145 @@ +package com.diagnose.common.util; + +import cn.hutool.core.codec.Base64; +import com.diagnose.common.util.logger.LoggerUtil; +import org.apache.commons.lang3.exception.ExceptionUtils; + +import javax.crypto.Cipher; +import java.io.ByteArrayOutputStream; +import java.nio.charset.StandardCharsets; +import java.security.KeyFactory; +import java.security.PrivateKey; +import java.security.PublicKey; +import java.security.spec.PKCS8EncodedKeySpec; +import java.security.spec.X509EncodedKeySpec; +import java.util.Arrays; + +public class RsaUtil { + + /** + * RSA最大加密大小 + */ + private final static int MAX_ENCRYPT_BLOCK = 117; + + /** + * ** + * RSA最大解密大小 + */ + private final static int MAX_DECRYPT_BLOCK = 128; + + /** + * 公钥加密 + * + * @param pubKey 公钥字符串 + * @param str 需要加密操作的字符串 + * @return 结果再Base64加密后的字符串 + * @throws Exception + */ + public static String pubKeyEncryption(String pubKey, String str) { + try { + // String 转 公钥 + PublicKey rsaPublicKey = getPublicKey(pubKey); + //公钥加密 + X509EncodedKeySpec x509EncodedKeySpec = new X509EncodedKeySpec(rsaPublicKey.getEncoded()); + KeyFactory keyFactory = KeyFactory.getInstance("RSA"); + PublicKey publicKey = keyFactory.generatePublic(x509EncodedKeySpec); + Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding"); + cipher.init(Cipher.ENCRYPT_MODE, publicKey); + byte[] inputArray = str.getBytes(); + int inputLength = inputArray.length; + // 分段加密 + int offSet = 0; + byte[] resultBytes = {}; + byte[] cache; + while (inputLength - offSet > 0) { + if (inputLength - offSet > MAX_ENCRYPT_BLOCK) { + cache = cipher.doFinal(inputArray, offSet, MAX_ENCRYPT_BLOCK); + offSet += MAX_ENCRYPT_BLOCK; + } else { + cache = cipher.doFinal(inputArray, offSet, inputLength - offSet); + offSet = inputLength; + } + resultBytes = Arrays.copyOf(resultBytes, resultBytes.length + cache.length); + System.arraycopy(cache, 0, resultBytes, resultBytes.length - cache.length, cache.length); + } + return Base64.encode(resultBytes); + } catch (Exception exception) { + LoggerUtil.info("RsaUtil.pubKeyEncryption异常:" + ExceptionUtils.getStackTrace(exception)); + return null; + } + } + + /** + * 用私钥 解密 + * + * @param priKey 私钥字符串 + * @param encryptionBase64Str RSA加密后又base64编码后的字符串 + * @return 解密结果 + * @throws Exception + */ + public static String priKeyDecryption(String priKey, String encryptionBase64Str) { + try { + // base64 解码 + byte[] base64 = Base64.decode(encryptionBase64Str); + // String 转 私钥 + PrivateKey rsaPrivateKey = getPrivateKey(priKey); + //私钥解密 + PKCS8EncodedKeySpec pkcs8EncodedKeySpec = new PKCS8EncodedKeySpec(rsaPrivateKey.getEncoded()); + KeyFactory keyFactory = KeyFactory.getInstance("RSA"); + PrivateKey privateKey = keyFactory.generatePrivate(pkcs8EncodedKeySpec); + Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding"); + cipher.init(Cipher.DECRYPT_MODE, privateKey); + // 返回UTF-8编码的解密信息 + int inputLen = base64.length; + ByteArrayOutputStream out = new ByteArrayOutputStream(); + int offSet = 0; + byte[] cache; + int i = 0; + // 对数据分段解密 + while (inputLen - offSet > 0) { + if (inputLen - offSet > MAX_DECRYPT_BLOCK) { + cache = cipher.doFinal(base64, offSet, MAX_DECRYPT_BLOCK); + } else { + cache = cipher.doFinal(base64, offSet, inputLen - offSet); + } + out.write(cache, 0, cache.length); + i++; + offSet = i * MAX_DECRYPT_BLOCK; + } + out.close(); + return out.toString(StandardCharsets.UTF_8); + } catch (Exception exception) { + LoggerUtil.info("RsaUtil.priKeyDecryption异常:" + ExceptionUtils.getStackTrace(exception)); + return null; + } + } + + /** + * String转公钥PublicKey + * + * @param key + * @return + * @throws Exception + */ + private static PublicKey getPublicKey(String key) throws Exception { + byte[] keyBytes = Base64.decode(key); + X509EncodedKeySpec keySpec = new X509EncodedKeySpec(keyBytes); + KeyFactory keyFactory = KeyFactory.getInstance("RSA"); + return keyFactory.generatePublic(keySpec); + } + + /** + * String转私钥PrivateKey + * + * @param key + * @return + * @throws Exception + */ + private static PrivateKey getPrivateKey(String key) throws Exception { + byte[] keyBytes = Base64.decode(key); + PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(keyBytes); + KeyFactory keyFactory = KeyFactory.getInstance("RSA"); + return keyFactory.generatePrivate(keySpec); + } + +} diff --git a/src/main/java/com/diagnose/common/util/ShortUrlGenerator.java b/src/main/java/com/diagnose/common/util/ShortUrlGenerator.java new file mode 100644 index 0000000..525bf1d --- /dev/null +++ b/src/main/java/com/diagnose/common/util/ShortUrlGenerator.java @@ -0,0 +1,18 @@ +package com.diagnose.common.util; + +import cn.hutool.core.codec.Base62; +import cn.hutool.core.convert.Convert; +import cn.hutool.core.util.ArrayUtil; +import cn.hutool.core.util.HashUtil; +import cn.hutool.core.util.RandomUtil; + +public class ShortUrlGenerator { + + public static String generateShortUrl(String url) { + int hash = HashUtil.bkdrHash(url); + byte[] hashBytes = Convert.intToBytes(hash); + byte[] randomBytes = RandomUtil.randomBytes(1); + return Base62.encode(ArrayUtil.addAll(hashBytes, randomBytes)); + } + +} \ No newline at end of file diff --git a/src/main/java/com/diagnose/common/util/TextUtil.java b/src/main/java/com/diagnose/common/util/TextUtil.java new file mode 100644 index 0000000..0f6d651 --- /dev/null +++ b/src/main/java/com/diagnose/common/util/TextUtil.java @@ -0,0 +1,28 @@ +package com.diagnose.common.util; + +import cn.hutool.core.util.StrUtil; +import org.jsoup.Jsoup; +import org.jsoup.safety.Whitelist; + +public class TextUtil { + + public static String removeHtmlTags(String text) { + text = Jsoup.parse(text).text(); + return text.replaceAll("\\s*|\t|\r|\n| ", ""); + } + + /** + * 处理富文本中的XSS攻击内容 + * + * @param unsafeHtml 富文本内容 + * @return 清洗后的文本内容 + */ + public static String cleanUnsafeHtml(String unsafeHtml) { + if (StrUtil.isEmpty(unsafeHtml)) { + return unsafeHtml; + } + Whitelist whitelist = Whitelist.relaxed(); + return Jsoup.clean(unsafeHtml, whitelist); + } + +} diff --git a/src/main/java/com/diagnose/common/util/UpDes.java b/src/main/java/com/diagnose/common/util/UpDes.java new file mode 100644 index 0000000..b751a68 --- /dev/null +++ b/src/main/java/com/diagnose/common/util/UpDes.java @@ -0,0 +1,142 @@ +package com.diagnose.common.util; + +import com.diagnose.common.util.logger.LoggerUtil; +import org.apache.commons.lang3.exception.ExceptionUtils; + +import javax.crypto.Cipher; +import javax.crypto.SecretKeyFactory; +import javax.crypto.spec.DESKeySpec; +import javax.crypto.spec.IvParameterSpec; +import java.nio.charset.StandardCharsets; +import java.security.Key; +import java.util.Base64; + +public class UpDes { + + private static final byte[] DEFAULT_IV = {0x75, 0x70, 0x63, 0x68, 0x69, 0x6e, 0x61, 0x31}; + + private Key mKey; + + public UpDes() { + } + + public UpDes(String strKey) { + setKey(strKey); // 生成密匙 + } + + public Key getKey() { + return mKey; + } + + /** + * 根据参数生成 KEY + */ + public void setKey(String strKey) { + try { + SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DES"); + DESKeySpec keySpec = new DESKeySpec(strKey.getBytes()); + keyFactory.generateSecret(keySpec); + mKey = keyFactory.generateSecret(keySpec); + } catch (Exception e) { + LoggerUtil.error("UpDes.setKey:" + ExceptionUtils.getStackTrace(e)); + } + } + + /** + * 加密 String 明文输入 ,String 密文输出 + */ + public String encryptStr(String strMing) { + return encryptStr(strMing, DEFAULT_IV); + } + + /** + * 加密 String 明文输入 ,String 密文输出 + */ + public String encryptStr(String strMing, byte[] biv) { + byte[] byteMi; + byte[] byteMing; + String strMi = ""; + try { + byteMing = strMing.getBytes(); + byteMi = this.encryptByte(byteMing, biv); + strMi = Base64.getEncoder().encodeToString(byteMi); + } catch (Throwable t) { + LoggerUtil.error("UpDes.encryptStr:" + ExceptionUtils.getStackTrace(t)); + } + return strMi; + } + + /** + * 加密以 byte[] 明文输入 ,byte[] 密文输出 + * + * @param byteS byteS + * @return byte + */ + private byte[] encryptByte(byte[] byteS, byte[] biv) { + byte[] byteFina = null; + Cipher cipher; + try { + IvParameterSpec iv = new IvParameterSpec(biv); + cipher = Cipher.getInstance("DES/CBC/PKCS5Padding"); + cipher.init(Cipher.ENCRYPT_MODE, mKey, iv); + byteFina = cipher.doFinal(byteS); + } catch (Exception e) { + LoggerUtil.error("UpDes.encryptByte:" + ExceptionUtils.getStackTrace(e)); + } + return byteFina; + } + + /** + * 解密 以 String 密文输入 ,String 明文输出 + * + * @param strMi strMi + * @return String + */ + public String decryptStr(String strMi) { + return decryptStr(strMi, DEFAULT_IV); + } + + /** + * 解密 以 String 密文输入 ,String 明文输出 + * + * @param strMi strMi + * @param biv biv + * @return String + */ + public String decryptStr(String strMi, byte[] biv) { + byte[] byteMing; + byte[] byteMi; + String strMing = ""; + try { + byteMi = Base64.getDecoder().decode(strMi); + byteMing = this.decryptByte(byteMi, biv); + strMing = new String(byteMing, StandardCharsets.UTF_8); + } catch (Exception e) { + LoggerUtil.error("UpDes.decryptStr:" + ExceptionUtils.getStackTrace(e)); + } + return strMing; + } + + /** + * 解密以 byte[] 密文输入 , 以 byte[] 明文输出 + * + * @param byteD byteD + * @param biv biv + * @return byte + */ + private byte[] decryptByte(byte[] byteD, byte[] biv) { + Cipher cipher; + byte[] byteFina = null; + try { + + IvParameterSpec iv = new IvParameterSpec(biv); + cipher = Cipher.getInstance("DES/CBC/PKCS5Padding"); + cipher.init(Cipher.DECRYPT_MODE, mKey, iv); + byteFina = cipher.doFinal(byteD); + } catch (Exception e) { + LoggerUtil.error("UpDes.decryptByte:" + ExceptionUtils.getStackTrace(e)); + } + return byteFina; + } + +} diff --git a/src/main/java/com/diagnose/common/util/WebServerInfo.java b/src/main/java/com/diagnose/common/util/WebServerInfo.java new file mode 100644 index 0000000..a135c36 --- /dev/null +++ b/src/main/java/com/diagnose/common/util/WebServerInfo.java @@ -0,0 +1,32 @@ +package com.diagnose.common.util; + +import cn.hutool.core.exceptions.ExceptionUtil; +import com.diagnose.common.util.logger.LoggerUtil; +import org.springframework.boot.web.context.WebServerApplicationContext; +import org.springframework.stereotype.Component; + +import javax.annotation.Resource; +import java.net.InetAddress; +import java.net.UnknownHostException; + +@Component +public class WebServerInfo { + + @Resource + private WebServerApplicationContext webServerApplicationContext; + + public String getServerIp() { + // 获取本地的 IP 地址,Spring Boot 默认会绑定到 0.0.0.0(所有网络接口) + try { + InetAddress inetAddress = InetAddress.getLocalHost(); + return inetAddress.getHostAddress(); + } catch (UnknownHostException e) { + LoggerUtil.error(ExceptionUtil.stacktraceToString(e)); + } + return "0.0.0.0"; + } + + public int getServerPort() { + return webServerApplicationContext.getWebServer().getPort(); + } +} \ No newline at end of file diff --git a/src/main/java/com/diagnose/common/util/logger/LoggerAgent.java b/src/main/java/com/diagnose/common/util/logger/LoggerAgent.java new file mode 100644 index 0000000..6e1b648 --- /dev/null +++ b/src/main/java/com/diagnose/common/util/logger/LoggerAgent.java @@ -0,0 +1,46 @@ +package com.diagnose.common.util.logger; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.Arrays; +import java.util.Objects; +import java.util.stream.Collectors; + +public class LoggerAgent { + + private final Logger logger; + + private LoggerAgent(String name) { + logger = LoggerFactory.getLogger(name); + } + + public static LoggerAgent build(String name) { + return new LoggerAgent(name); + } + + public void info(String message) { + logger.info(message); + } + + public void info(Object... message) { + logger.info(Arrays.stream(message).filter(Objects::nonNull).map(Object::toString).collect(Collectors.joining( ))); + } + + public void error(String message) { + logger.error(message); + } + + public void error(Object... message) { + logger.error(Arrays.stream(message).filter(Objects::nonNull).map(Object::toString).collect(Collectors.joining( ))); + } + + public void warn(String message) { + logger.warn(message); + } + + public void warn(Object... message) { + logger.warn(Arrays.stream(message).filter(Objects::nonNull).map(Object::toString).collect(Collectors.joining( ))); + } + +} diff --git a/src/main/java/com/diagnose/common/util/logger/LoggerUtil.java b/src/main/java/com/diagnose/common/util/logger/LoggerUtil.java new file mode 100644 index 0000000..35bfcaa --- /dev/null +++ b/src/main/java/com/diagnose/common/util/logger/LoggerUtil.java @@ -0,0 +1,33 @@ +package com.diagnose.common.util.logger; + +public class LoggerUtil { + + public static final LoggerAgent video = LoggerAgent.build("video"); + + public static final LoggerAgent data = LoggerAgent.build("data"); + + public static final LoggerAgent error = LoggerAgent.build("error"); + + public static final LoggerAgent websocket = LoggerAgent.build("websocket"); + + public static final LoggerAgent auth = LoggerAgent.build("auth"); + + public static final LoggerAgent api = LoggerAgent.build("api"); + + public static void info(String message) { + data.info(message); + } + + public static void info(Object... message) { + data.info(message); + } + + public static void error(String message) { + error.error(message); + } + + public static void error(Object... message) { + error.error(message); + } + +} diff --git a/src/main/java/com/diagnose/common/validation/EnumValidator.java b/src/main/java/com/diagnose/common/validation/EnumValidator.java new file mode 100644 index 0000000..a04a62c --- /dev/null +++ b/src/main/java/com/diagnose/common/validation/EnumValidator.java @@ -0,0 +1,68 @@ +package com.diagnose.common.validation; + +import com.google.common.collect.Sets; + +import javax.validation.Constraint; +import javax.validation.ConstraintValidator; +import javax.validation.ConstraintValidatorContext; +import javax.validation.Payload; +import java.lang.annotation.Documented; +import java.lang.annotation.Retention; +import java.lang.annotation.Target; +import java.lang.reflect.Field; +import java.util.Set; + +import static java.lang.annotation.ElementType.*; +import static java.lang.annotation.RetentionPolicy.RUNTIME; + +@Documented +@Constraint(validatedBy = EnumChecker.class) +@Target({METHOD, FIELD, ANNOTATION_TYPE, PARAMETER, CONSTRUCTOR}) +@Retention(RUNTIME) +public @interface EnumValidator { + + String message() default "不符合枚举值定义"; + + Class[] groups() default {}; + + Class[] payload() default {}; + + Class> value(); + +} + +class EnumChecker implements ConstraintValidator { + + private Set AVAILABLE_ENUM_VALUES; + + public static Set getValuesSet(Class> enumClass, Field valueField) throws IllegalAccessException { + Enum[] enums = enumClass.getEnumConstants(); + Set valuesSet = Sets.newHashSetWithExpectedSize(enums.length); + for (Enum e : enums) { + Object valueObj = valueField.get(e); + valuesSet.add((Integer) valueObj); + } + return valuesSet; + } + + @Override + public void initialize(EnumValidator validator) { + try { + Class> enumClass = validator.value(); + Field valueField = enumClass.getField("value"); + AVAILABLE_ENUM_VALUES = getValuesSet(enumClass, valueField); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + @Override + public boolean isValid(Integer value, ConstraintValidatorContext context) { + if (value == null) { + return true; + } else { + return AVAILABLE_ENUM_VALUES.contains(value); + } + } + +} \ No newline at end of file diff --git a/src/main/java/com/diagnose/common/validation/IntArrayValidator.java b/src/main/java/com/diagnose/common/validation/IntArrayValidator.java new file mode 100644 index 0000000..a2975b3 --- /dev/null +++ b/src/main/java/com/diagnose/common/validation/IntArrayValidator.java @@ -0,0 +1,56 @@ +package com.diagnose.common.validation; + +import com.google.common.collect.Sets; + +import javax.validation.Constraint; +import javax.validation.ConstraintValidator; +import javax.validation.ConstraintValidatorContext; +import javax.validation.Payload; +import java.lang.annotation.Documented; +import java.lang.annotation.Retention; +import java.lang.annotation.Target; +import java.util.Set; + +import static java.lang.annotation.ElementType.*; +import static java.lang.annotation.RetentionPolicy.RUNTIME; + +@Documented +@Constraint(validatedBy = IntArrayChecker.class) +@Target({METHOD, FIELD, ANNOTATION_TYPE, PARAMETER, CONSTRUCTOR}) +@Retention(RUNTIME) +public @interface IntArrayValidator { + + String message() default "不符合取值范围"; + + Class[] groups() default {}; + + Class[] payload() default {}; + + int[] value(); + +} + +class IntArrayChecker implements ConstraintValidator { + + private Set AVAILABLE_VALUES; + + @Override + public void initialize(IntArrayValidator validator) { + int[] values = validator.value(); + Set valuesSet = Sets.newHashSetWithExpectedSize(values.length); + for (int value : values) { + valuesSet.add(value); + } + AVAILABLE_VALUES = valuesSet; + } + + @Override + public boolean isValid(Integer value, ConstraintValidatorContext context) { + if (value == null) { + return true; + } else { + return AVAILABLE_VALUES.contains(value); + } + } + +} \ No newline at end of file diff --git a/src/main/java/com/diagnose/common/vo/AdvertAppVO.java~ b/src/main/java/com/diagnose/common/vo/AdvertAppVO.java~ new file mode 100644 index 0000000..d539ee1 --- /dev/null +++ b/src/main/java/com/diagnose/common/vo/AdvertAppVO.java~ @@ -0,0 +1,73 @@ +package com.diagnose.common.vo; + +import com.diagnose.common.entity.Advert; +import com.diagnose.common.query.IProduct; +import io.swagger.annotations.ApiModelProperty; + +import java.io.Serializable; + +public class AdvertAppVO implements IProduct, Serializable { + + @ApiModelProperty("产品类型:0投顾 1观点包 2单篇观点 3视频 5交易圈 6图文直播间 7组合 8锦囊 10H5") + private Integer productType; + + @ApiModelProperty("产品ID") + private Integer productId; + + @ApiModelProperty("名称 仅H5类型") + private String name; + + @ApiModelProperty("URL 仅H5类型") + private String url; + + @ApiModelProperty("图片URL") + private String imgUrl; + + public AdvertAppVO(Advert advert) { + this.productType = advert.getProductType(); + this.productId = advert.getProductId(); + this.name = advert.getName(); + this.url = advert.getUrl(); + this.imgUrl = advert.getImgUrl(); + } + + public Integer getProductType() { + return productType; + } + + public void setProductType(Integer productType) { + this.productType = productType; + } + + public Integer getProductId() { + return productId; + } + + public void setProductId(Integer productId) { + this.productId = productId; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getUrl() { + return url; + } + + public void setUrl(String url) { + this.url = url; + } + + public String getImgUrl() { + return imgUrl; + } + + public void setImgUrl(String imgUrl) { + this.imgUrl = imgUrl; + } +} diff --git a/src/main/java/com/diagnose/common/vo/AppCUserInfoVO.java~ b/src/main/java/com/diagnose/common/vo/AppCUserInfoVO.java~ new file mode 100644 index 0000000..debf857 --- /dev/null +++ b/src/main/java/com/diagnose/common/vo/AppCUserInfoVO.java~ @@ -0,0 +1,108 @@ +package com.diagnose.common.vo; + +import com.syzb.business.vo.BusinessUserVO; +import io.swagger.annotations.ApiModelProperty; + +public class AppCUserInfoVO { + + @ApiModelProperty("用户id") + private String userId; + + @ApiModelProperty("用户名") + private String userName; + + @ApiModelProperty("昵称") + private String nickName; + + @ApiModelProperty("用户头像") + private String imgUrl; + + @ApiModelProperty("客户类型 1:H5 2:Web") + private Integer clientType; + + @ApiModelProperty("token") + private String token; + + @ApiModelProperty("refreshToken") + private String refreshToken; + + @ApiModelProperty("upToken") + private String upToken; + + public AppCUserInfoVO() { + } + + public AppCUserInfoVO(String token, String refreshToken, BusinessUserVO userVO, Integer clientType) { + this.userId = userVO.getUserId().toString(); + this.userName = userVO.getUsername(); + this.nickName = userVO.getNickName(); + this.imgUrl = userVO.getHeadPicUrl(); + this.clientType = clientType; + this.token = token; + this.refreshToken = refreshToken; + } + + public String getUserId() { + return userId; + } + + public void setUserId(String userId) { + this.userId = userId; + } + + public String getUserName() { + return userName; + } + + public void setUserName(String userName) { + this.userName = userName; + } + + public String getNickName() { + return nickName; + } + + public void setNickName(String nickName) { + this.nickName = nickName; + } + + public String getImgUrl() { + return imgUrl; + } + + public void setImgUrl(String imgUrl) { + this.imgUrl = imgUrl; + } + + public Integer getClientType() { + return clientType; + } + + public void setClientType(Integer clientType) { + this.clientType = clientType; + } + + public String getToken() { + return token; + } + + public void setToken(String token) { + this.token = token; + } + + public String getRefreshToken() { + return refreshToken; + } + + public void setRefreshToken(String refreshToken) { + this.refreshToken = refreshToken; + } + + public String getUpToken() { + return upToken; + } + + public void setUpToken(String upToken) { + this.upToken = upToken; + } +} diff --git a/src/main/java/com/diagnose/common/vo/AppUserInfoVO.java~ b/src/main/java/com/diagnose/common/vo/AppUserInfoVO.java~ new file mode 100644 index 0000000..2638cd3 --- /dev/null +++ b/src/main/java/com/diagnose/common/vo/AppUserInfoVO.java~ @@ -0,0 +1,81 @@ +package com.syzb.common.vo; + +import io.swagger.annotations.ApiModelProperty; + +public class AppUserInfoVO { + + @ApiModelProperty("用户姓名") + private String userName; + + @ApiModelProperty("客户风险等级,1保守型2谨慎型3稳健型4积极型5激进型-1最低风险类型") + private String corpRiskLevel; + + @ApiModelProperty("客户风险测评日,YYYYMMDD") + private String corpBeginDate; + + @ApiModelProperty("客户风险到期日,YYYYMMDD") + private String corpEndDate; + + @ApiModelProperty("营业部编号") + private String branchNo; + + @ApiModelProperty("机构标志:0个人 1机构 2自营 3产品 4特法户 5产品(机构端)6机构(机构端)") + public String organFlag; + + public String getUserName() { + return userName; + } + + public AppUserInfoVO(String userName, String corpRiskLevel, String corpBeginDate, String corpEndDate, String branchNo, String organFlag) { + this.userName = userName; + this.corpRiskLevel = corpRiskLevel; + this.corpBeginDate = corpBeginDate; + this.corpEndDate = corpEndDate; + this.branchNo = branchNo; + this.organFlag = organFlag; + } + + public void setUserName(String userName) { + this.userName = userName; + } + + public String getCorpRiskLevel() { + return corpRiskLevel; + } + + public void setCorpRiskLevel(String corpRiskLevel) { + this.corpRiskLevel = corpRiskLevel; + } + + public String getCorpBeginDate() { + return corpBeginDate; + } + + public void setCorpBeginDate(String corpBeginDate) { + this.corpBeginDate = corpBeginDate; + } + + public String getCorpEndDate() { + return corpEndDate; + } + + public void setCorpEndDate(String corpEndDate) { + this.corpEndDate = corpEndDate; + } + + public String getBranchNo() { + return branchNo; + } + + public void setBranchNo(String branchNo) { + this.branchNo = branchNo; + } + + public String getOrganFlag() { + return organFlag; + } + + public void setOrganFlag(String organFlag) { + this.organFlag = organFlag; + } +} diff --git a/src/main/java/com/diagnose/common/vo/AuthVO.java~ b/src/main/java/com/diagnose/common/vo/AuthVO.java~ new file mode 100644 index 0000000..96af218 --- /dev/null +++ b/src/main/java/com/diagnose/common/vo/AuthVO.java~ @@ -0,0 +1,68 @@ +package com.diagnose.common.vo; + +import com.syzb.advisor.vo.AdvisorInfoAdminVO; +import com.syzb.rbac.entity.UserLogin; +import com.syzb.rbac.vo.UserAdminVO; +import io.swagger.annotations.ApiModelProperty; + +import java.util.List; + +public class AuthVO { + + @ApiModelProperty("用户信息") + private UserAdminVO user; + + @ApiModelProperty("投顾信息") + private AdvisorInfoAdminVO advisorInfo; + + @ApiModelProperty("角色权限名列表") + private List roles; + + @ApiModelProperty("token") + private String token; + + public AuthVO(UserLogin user, String token) { + this.user = new UserAdminVO(user); + this.token = token; + } + + public AuthVO(UserAdminVO user, AdvisorInfoAdminVO advisorInfo, List roles, String token) { + this.user = user; + this.advisorInfo = advisorInfo; + this.roles = roles; + this.token = token; + } + + public String getToken() { + return token; + } + + public void setToken(String token) { + this.token = token; + } + + public UserAdminVO getUser() { + return user; + } + + public void setUser(UserAdminVO user) { + this.user = user; + } + + public AdvisorInfoAdminVO getAdvisorInfo() { + return advisorInfo; + } + + public void setAdvisorInfo(AdvisorInfoAdminVO advisorInfo) { + this.advisorInfo = advisorInfo; + } + + public List getRoles() { + return roles; + } + + public void setRoles(List roles) { + this.roles = roles; + } + +} diff --git a/src/main/java/com/diagnose/common/vo/CountVO.java b/src/main/java/com/diagnose/common/vo/CountVO.java new file mode 100644 index 0000000..a48efb1 --- /dev/null +++ b/src/main/java/com/diagnose/common/vo/CountVO.java @@ -0,0 +1,21 @@ +package com.diagnose.common.vo; + +import io.swagger.annotations.ApiModelProperty; + +public class CountVO { + + @ApiModelProperty("执行动作后的数量") + private Integer count; + + public Integer getCount() { + return count; + } + + public void setCount(Integer count) { + this.count = count; + } + + public CountVO(Integer count) { + this.count = count; + } +} diff --git a/src/main/java/com/diagnose/common/vo/IdCountVO.java b/src/main/java/com/diagnose/common/vo/IdCountVO.java new file mode 100644 index 0000000..7150e01 --- /dev/null +++ b/src/main/java/com/diagnose/common/vo/IdCountVO.java @@ -0,0 +1,24 @@ +package com.diagnose.common.vo; + +public class IdCountVO { + + private Integer id; + + private Integer count; + + public Integer getId() { + return id; + } + + public void setId(Integer id) { + this.id = id; + } + + public Integer getCount() { + return count; + } + + public void setCount(Integer count) { + this.count = count; + } +} diff --git a/src/main/java/com/diagnose/common/vo/IdNameVO.java b/src/main/java/com/diagnose/common/vo/IdNameVO.java new file mode 100644 index 0000000..95fd0cd --- /dev/null +++ b/src/main/java/com/diagnose/common/vo/IdNameVO.java @@ -0,0 +1,34 @@ +package com.diagnose.common.vo; + +import java.io.Serializable; + +public class IdNameVO implements Serializable { + + private Integer id; + + private String name; + + public IdNameVO() { + } + + public IdNameVO(Integer id, String name) { + this.id = id; + this.name = name; + } + + public Integer getId() { + return id; + } + + public void setId(Integer id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } +} diff --git a/src/main/java/com/diagnose/common/vo/InsertIdVO.java b/src/main/java/com/diagnose/common/vo/InsertIdVO.java new file mode 100644 index 0000000..8afc2c9 --- /dev/null +++ b/src/main/java/com/diagnose/common/vo/InsertIdVO.java @@ -0,0 +1,21 @@ +package com.diagnose.common.vo; + +import io.swagger.annotations.ApiModelProperty; + +public class InsertIdVO { + + @ApiModelProperty("ID") + private Integer id; + + public InsertIdVO(Integer id) { + this.id = id; + } + + public Integer getId() { + return id; + } + + public void setId(Integer id) { + this.id = id; + } +} diff --git a/src/main/java/com/diagnose/common/vo/OnlyBoolVO.java b/src/main/java/com/diagnose/common/vo/OnlyBoolVO.java new file mode 100644 index 0000000..7c9c07b --- /dev/null +++ b/src/main/java/com/diagnose/common/vo/OnlyBoolVO.java @@ -0,0 +1,25 @@ +package com.diagnose.common.vo; + +import io.swagger.annotations.ApiModelProperty; + +import java.io.Serializable; + +public class OnlyBoolVO implements Serializable { + + private static final long serialVersionUID = 1L; + + @ApiModelProperty("ID") + private Boolean result; + + public OnlyBoolVO(Boolean result) { + this.result = result; + } + + public Boolean getResult() { + return result; + } + + public void setResult(Boolean result) { + this.result = result; + } +} diff --git a/src/main/java/com/diagnose/common/vo/OnlyIdVO.java b/src/main/java/com/diagnose/common/vo/OnlyIdVO.java new file mode 100644 index 0000000..405067a --- /dev/null +++ b/src/main/java/com/diagnose/common/vo/OnlyIdVO.java @@ -0,0 +1,25 @@ +package com.diagnose.common.vo; + +import io.swagger.annotations.ApiModelProperty; + +import java.io.Serializable; + +public class OnlyIdVO implements Serializable { + + private static final long serialVersionUID = 1L; + + @ApiModelProperty("ID") + private Integer id; + + public OnlyIdVO(Integer id) { + this.id = id; + } + + public Integer getId() { + return id; + } + + public void setId(Integer id) { + this.id = id; + } +} diff --git a/src/main/java/com/diagnose/common/vo/SafetyConfigVO.java~ b/src/main/java/com/diagnose/common/vo/SafetyConfigVO.java~ new file mode 100644 index 0000000..bf80c9a --- /dev/null +++ b/src/main/java/com/diagnose/common/vo/SafetyConfigVO.java~ @@ -0,0 +1,153 @@ +package com.syzb.common.vo; + +import io.swagger.annotations.ApiModelProperty; + +import java.io.Serializable; + +public class SafetyConfigVO implements Serializable { + + private static final long serialVersionUID = 1L; + + @ApiModelProperty("密码有效天数") + private Integer passwordPeriod; + + @ApiModelProperty("密码组成:1大写字母 2小写字母 3数字 4特殊字母,逗号隔开") + private String passwordComposition; + + @ApiModelProperty("密码组成正则表达式") + private String regexPattern; + + @ApiModelProperty("密码到期前多少天提醒用户") + private Integer expirationReminder; + + @ApiModelProperty("密码最大长度") + private Integer passwordMax; + + @ApiModelProperty("密码最小长度") + private Integer passwordMin; + + @ApiModelProperty("密码不能与前多少次旧密码相同") + private Integer passwordSame; + + @ApiModelProperty("登录多少分钟后未操作,强制离线") + private Integer maxLeftTime; + + @ApiModelProperty("登录失败多少次会被锁定") + private Integer errorCount; + + @ApiModelProperty("登录失败N次后,锁定的时间,分钟") + private Integer lockTime; + + @ApiModelProperty("中台登录是否开启短信验证:0未开启 1已开启") + private Integer checkMessage; + + @ApiModelProperty("短信开启后,用户白名单") + private String messageWhite; + + @ApiModelProperty("短信有效期多长时间,分钟") + private Integer messageValidTime; + + public Integer getPasswordPeriod() { + return passwordPeriod; + } + + public void setPasswordPeriod(Integer passwordPeriod) { + this.passwordPeriod = passwordPeriod; + } + + public String getPasswordComposition() { + return passwordComposition; + } + + public void setPasswordComposition(String passwordComposition) { + this.passwordComposition = passwordComposition; + } + + public Integer getExpirationReminder() { + return expirationReminder; + } + + public void setExpirationReminder(Integer expirationReminder) { + this.expirationReminder = expirationReminder; + } + + public Integer getPasswordMax() { + return passwordMax; + } + + public void setPasswordMax(Integer passwordMax) { + this.passwordMax = passwordMax; + } + + public Integer getPasswordMin() { + return passwordMin; + } + + public void setPasswordMin(Integer passwordMin) { + this.passwordMin = passwordMin; + } + + public Integer getPasswordSame() { + return passwordSame; + } + + public void setPasswordSame(Integer passwordSame) { + this.passwordSame = passwordSame; + } + + public Integer getMaxLeftTime() { + return maxLeftTime; + } + + public void setMaxLeftTime(Integer maxLeftTime) { + this.maxLeftTime = maxLeftTime; + } + + public Integer getErrorCount() { + return errorCount; + } + + public void setErrorCount(Integer errorCount) { + this.errorCount = errorCount; + } + + public Integer getLockTime() { + return lockTime; + } + + public void setLockTime(Integer lockTime) { + this.lockTime = lockTime; + } + + public Integer getCheckMessage() { + return checkMessage; + } + + public void setCheckMessage(Integer checkMessage) { + this.checkMessage = checkMessage; + } + + public String getMessageWhite() { + return messageWhite; + } + + public void setMessageWhite(String messageWhite) { + this.messageWhite = messageWhite; + } + + public Integer getMessageValidTime() { + return messageValidTime; + } + + public void setMessageValidTime(Integer messageValidTime) { + this.messageValidTime = messageValidTime; + } + + public String getRegexPattern() { + return regexPattern; + } + + public void setRegexPattern(String regexPattern) { + this.regexPattern = regexPattern; + } +} diff --git a/src/main/java/com/diagnose/common/vo/SensitiveWordVO.java~ b/src/main/java/com/diagnose/common/vo/SensitiveWordVO.java~ new file mode 100644 index 0000000..4824917 --- /dev/null +++ b/src/main/java/com/diagnose/common/vo/SensitiveWordVO.java~ @@ -0,0 +1,48 @@ +package com.diagnose.common.vo; + +import com.diagnose.common.entity.SensitiveWord; +import io.swagger.annotations.ApiModelProperty; + +import java.time.LocalDateTime; + +public class SensitiveWordVO { + + @ApiModelProperty("ID") + private Integer id; + + @ApiModelProperty("内容") + private String word; + + @ApiModelProperty("添加时间") + private LocalDateTime createTime; + + public SensitiveWordVO(SensitiveWord sensitive) { + setId(sensitive.getId()); + setWord(sensitive.getWord()); + setCreateTime(sensitive.getCreateTime()); + } + + public Integer getId() { + return id; + } + + public void setId(Integer id) { + this.id = id; + } + + public String getWord() { + return word; + } + + public void setWord(String word) { + this.word = word; + } + + public LocalDateTime getCreateTime() { + return createTime; + } + + public void setCreateTime(LocalDateTime createTime) { + this.createTime = createTime; + } +} diff --git a/src/main/java/com/diagnose/constant/MktNum.java b/src/main/java/com/diagnose/constant/MktNum.java new file mode 100644 index 0000000..31fbf7e --- /dev/null +++ b/src/main/java/com/diagnose/constant/MktNum.java @@ -0,0 +1,19 @@ +package com.diagnose.constant; + +// 股票所属市场 0:深圳 1:上海 7:北京 +public enum MktNum { + + SZ(0, "深圳"), + SH(1, "上海"), + BJ(7, "北京"), + ; + + public final Integer value; + public final String name; + + MktNum(Integer value, String name) { + this.value = value; + this.name = name; + } + +} diff --git a/src/main/java/com/diagnose/constant/MktTypePar.java b/src/main/java/com/diagnose/constant/MktTypePar.java new file mode 100644 index 0000000..c5ef8d3 --- /dev/null +++ b/src/main/java/com/diagnose/constant/MktTypePar.java @@ -0,0 +1,19 @@ +package com.diagnose.constant; + +// 证券市场 1:深圳证券交易所 2:上海证券交易所 190:北京证券交易所 +public enum MktTypePar { + + SZ(1, "深圳"), + SH(2, "上海"), + BJ(190, "北京"), + ; + + public final Integer value; + public final String name; + + MktTypePar(Integer value, String name) { + this.value = value; + this.name = name; + } + +} diff --git a/src/main/java/com/diagnose/constant/RiskLevel.java~ b/src/main/java/com/diagnose/constant/RiskLevel.java~ new file mode 100644 index 0000000..a068991 --- /dev/null +++ b/src/main/java/com/diagnose/constant/RiskLevel.java~ @@ -0,0 +1,41 @@ +package com.syzb.common.constant; + +import java.util.Arrays; + +public enum RiskLevel { + + LOW_RISK(1, "低风险"), + LOW_MIDDLE_RISK(2, "中低风险"), + MIDDLE_RISK(3, "中风险"), + MIDDLE_HIGH_RISK(4, "中高风险"), + HIGH_RISK(5, "高风险"), + ; + public final Integer value; + + public final String name; + + RiskLevel(Integer value, String name) { + this.value = value; + this.name = name; + } + + public Integer getValue() { + return value; + } + + public String getName() { + return name; + } + + /** + * 获取风险等级描述 + * + * @param riskLevel 风险等级code + * @return 风险等级描述 + */ + public static String parseName(Integer riskLevel) { + return Arrays.stream(RiskLevel.values()) + .filter(s -> s.value.equals(riskLevel)).findFirst() + .map(logicType -> logicType.name).orElse(null); + } +} diff --git a/src/main/java/com/diagnose/constant/SecMarPar.java b/src/main/java/com/diagnose/constant/SecMarPar.java new file mode 100644 index 0000000..ad4806b --- /dev/null +++ b/src/main/java/com/diagnose/constant/SecMarPar.java @@ -0,0 +1,19 @@ +package com.diagnose.constant; + +// 股票市场 1:深圳 2:上海 8:北京 +public enum SecMarPar { + + SZ(1, "深圳"), + SH(2, "上海"), + BJ(8, "北京"), + ; + + public final Integer value; + public final String name; + + SecMarPar(Integer value, String name) { + this.value = value; + this.name = name; + } + +} diff --git a/src/main/java/com/diagnose/controller/DiagnoseController.java b/src/main/java/com/diagnose/controller/DiagnoseController.java new file mode 100644 index 0000000..9d7c20c --- /dev/null +++ b/src/main/java/com/diagnose/controller/DiagnoseController.java @@ -0,0 +1,54 @@ +package com.diagnose.controller; + +import com.diagnose.common.result.CommonResult; +import com.diagnose.service.SearchService; +import com.diagnose.service.StockService; +import com.diagnose.vo.ComprehensiveEvaluationVO; +import com.diagnose.vo.FinancialValuationVO; +import com.diagnose.vo.StockVO; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import io.swagger.annotations.ApiParam; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; + +import javax.annotation.Resource; +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.NotNull; +import java.util.List; + +@Api(tags = "投顾") +@RestController +public class DiagnoseController { + + @Resource + private SearchService searchService; + + @Resource + private StockService stockService; + + @ApiOperation("综合搜索") + @GetMapping("/diagnose/search") + public CommonResult> search(@RequestParam("关键词") @Validated @NotBlank @ApiParam(required = true) String keyword) { + List list = searchService.search(keyword); + return CommonResult.success(list); + } + + @ApiOperation("综合评分") + @GetMapping("/diagnose/comprehensiveEvaluation") + public CommonResult comprehensiveEvaluation(@RequestParam("证券统一编码") @Validated @NotNull @ApiParam(required = true) Long stkUniCode) { + ComprehensiveEvaluationVO vo = stockService.comprehensiveEvaluation(stkUniCode); + return CommonResult.success(vo); + } + + @ApiOperation("财务估值") + @GetMapping("/diagnose/financialValuation") + public CommonResult financialValuation(@RequestParam("证券统一编码") @Validated @NotNull @ApiParam(required = true) Long stkUniCode) { + FinancialValuationVO vo = stockService.financialValuation(stkUniCode); + return CommonResult.success(vo); + } + + +} diff --git a/src/main/java/com/diagnose/entity/CommentSortEntity.java~ b/src/main/java/com/diagnose/entity/CommentSortEntity.java~ new file mode 100644 index 0000000..a7ac6dc --- /dev/null +++ b/src/main/java/com/diagnose/entity/CommentSortEntity.java~ @@ -0,0 +1,92 @@ +package com.syzb.common.entity; + +import com.google.common.collect.ComparisonChain; +import io.swagger.annotations.ApiModelProperty; + +import java.io.Serializable; +import java.time.LocalDateTime; + +public class CommentSortEntity implements Serializable, Comparable { + + private static final long serialVersionUID = 1L; + + @ApiModelProperty("评论id") + private Integer id; + + @ApiModelProperty("评论时间") + private LocalDateTime commentTime; + + @ApiModelProperty("置顶权重") + private Integer weight; + + @ApiModelProperty("用户id") + private String userId; + + @ApiModelProperty("是否公开:1是 2否") + private Integer isOpen; + + public CommentSortEntity() { + } + + public CommentSortEntity(Comment comment) { + this.id = comment.getId(); + this.commentTime = comment.getCommentTime(); + this.weight = comment.getWeight(); + this.userId = comment.getUserId(); + this.isOpen = comment.getIsOpen(); + } + + public CommentSortEntity(LocalDateTime commentTime, Integer weight) { + this.commentTime = commentTime; + this.weight = weight; + } + + @Override + public int compareTo(CommentSortEntity o) { + // 倒序 加-号 + return -ComparisonChain.start() + .compare(this.weight == null ? (Integer) 0 : this.weight, o.weight == null ? (Integer) 0 : o.weight) + .compare(this.commentTime, o.commentTime).result(); + } + + public Integer getId() { + return id; + } + + public void setId(Integer id) { + this.id = id; + } + + public LocalDateTime getCommentTime() { + return commentTime; + } + + public void setCommentTime(LocalDateTime commentTime) { + this.commentTime = commentTime; + } + + public Integer getWeight() { + return weight; + } + + public void setWeight(Integer weight) { + this.weight = weight; + } + + public String getUserId() { + return userId; + } + + public void setUserId(String userId) { + this.userId = userId; + } + + public Integer getIsOpen() { + return isOpen; + } + + public void setIsOpen(Integer isOpen) { + this.isOpen = isOpen; + } + +} diff --git a/src/main/java/com/diagnose/entity/RiskLevel.java~ b/src/main/java/com/diagnose/entity/RiskLevel.java~ new file mode 100644 index 0000000..7f5ae7f --- /dev/null +++ b/src/main/java/com/diagnose/entity/RiskLevel.java~ @@ -0,0 +1,92 @@ +package com.syzb.common.entity; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; + +import java.io.Serializable; +import java.time.LocalDateTime; + +/** + *

+ * 风险等级配置 + *

+ * + * @author helloSyzb + * @since 2022-11-09 + */ +public class RiskLevel implements Serializable { + + + @TableId(value = "id", type = IdType.AUTO) + private Integer id; + + /** + * 1观点包 2单篇观点 3视频 5交易圈 6图文直播间 7组合 8锦囊 21三方产品-增值产品 22三方产品-课程 23三方产品-ETF专区 24三方产品-选股工具 25三方产品-小飞机理财 + */ + @TableField("product_type") + private Integer productType; + + /** + * 风险等级:1低风险 2中低风险 3中风险 4中高风险 5高风险 + */ + @TableField("risk_level") + private Integer riskLevel; + + @TableField("update_user_id") + private Integer updateUserId; + + @TableField("update_time") + private LocalDateTime updateTime; + + public Integer getId() { + return id; + } + + public void setId(Integer id) { + this.id = id; + } + + public Integer getProductType() { + return productType; + } + + public void setProductType(Integer productType) { + this.productType = productType; + } + + public Integer getRiskLevel() { + return riskLevel; + } + + public void setRiskLevel(Integer riskLevel) { + this.riskLevel = riskLevel; + } + + public Integer getUpdateUserId() { + return updateUserId; + } + + public void setUpdateUserId(Integer updateUserId) { + this.updateUserId = updateUserId; + } + + public LocalDateTime getUpdateTime() { + return updateTime; + } + + public void setUpdateTime(LocalDateTime updateTime) { + this.updateTime = updateTime; + } + + @Override + public String toString() { + return "RiskLevel{" + + "id=" + id + + ", productType=" + productType + + ", riskLevel=" + riskLevel + + ", updateUserId=" + updateUserId + + ", updateTime=" + updateTime + + "}"; + } +} diff --git a/src/main/java/com/diagnose/entity/ScheduleLog.java~ b/src/main/java/com/diagnose/entity/ScheduleLog.java~ new file mode 100644 index 0000000..3b9081f --- /dev/null +++ b/src/main/java/com/diagnose/entity/ScheduleLog.java~ @@ -0,0 +1,208 @@ +package com.diagnose.common.entity; + +import cn.hutool.core.util.StrUtil; +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; +import com.syzb.common.constant.ScheduleLogResult; + +import java.io.Serializable; +import java.time.LocalDate; +import java.time.LocalDateTime; + +/** + *

+ * + *

+ * + * @author helloSyzb + * @since 2022-11-09 + */ +public class ScheduleLog implements Serializable { + + + /** + * 同步记录ID + */ + @TableId(value = "id", type = IdType.AUTO) + private Integer id; + + /** + * 服务名 + */ + @TableField("server_name") + private String serverName; + + /** + * 定时任务名称 + */ + @TableField("schedule_name") + private String scheduleName; + + /** + * 执行时间 + */ + private LocalDate date; + + /** + * 实际开始时间 + */ + @TableField("start_time") + private LocalDateTime startTime; + + /** + * 实际结束时间 + */ + @TableField("end_time") + private LocalDateTime endTime; + + /** + * 执行结果:1:执行中 2:成功 3:失败 + */ + private Integer result; + + /** + * 附加信息json + */ + private String ext; + + /** + * 异常信息 + */ + private String error; + + /** + * 执行机器IP + */ + private String ip; + + public static ScheduleLog start(String scheduleName, String ip) { + String server = System.getProperty("server.server"); + ScheduleLog log = new ScheduleLog(); + log.setServerName(server); + log.setScheduleName(scheduleName); + log.setDate(LocalDate.now()); + log.setStartTime(LocalDateTime.now()); + log.setResult(ScheduleLogResult.RUNNING.value); + log.setIp(ip); + return log; + } + + public static ScheduleLog success(Integer id, String ext) { + ScheduleLog log = new ScheduleLog(); + log.setId(id); + log.setEndTime(LocalDateTime.now()); + log.setResult(ScheduleLogResult.SUCCESS.value); + if (StrUtil.isNotEmpty(ext)) { + log.setExt(ext); + } + return log; + } + + public static ScheduleLog error(Integer id, String error) { + ScheduleLog log = new ScheduleLog(); + log.setId(id); + log.setEndTime(LocalDateTime.now()); + log.setResult(ScheduleLogResult.FAILURE.value); + if (StrUtil.isNotEmpty(error)) { + log.setError(error); + } + return log; + } + + public Integer getId() { + return id; + } + + public void setId(Integer id) { + this.id = id; + } + + public String getServerName() { + return serverName; + } + + public void setServerName(String serverName) { + this.serverName = serverName; + } + + public String getScheduleName() { + return scheduleName; + } + + public void setScheduleName(String scheduleName) { + this.scheduleName = scheduleName; + } + + public LocalDate getDate() { + return date; + } + + public void setDate(LocalDate date) { + this.date = date; + } + + public LocalDateTime getStartTime() { + return startTime; + } + + public void setStartTime(LocalDateTime startTime) { + this.startTime = startTime; + } + + public LocalDateTime getEndTime() { + return endTime; + } + + public void setEndTime(LocalDateTime endTime) { + this.endTime = endTime; + } + + public Integer getResult() { + return result; + } + + public void setResult(Integer result) { + this.result = result; + } + + public String getExt() { + return ext; + } + + public void setExt(String ext) { + this.ext = ext; + } + + public String getError() { + return error; + } + + public void setError(String error) { + this.error = error; + } + + public String getIp() { + return ip; + } + + public void setIp(String ip) { + this.ip = ip; + } + + @Override + public String toString() { + return "ScheduleLog{" + + "id=" + id + + ", serverName=" + serverName + + ", scheduleName=" + scheduleName + + ", date=" + date + + ", startTime=" + startTime + + ", endTime=" + endTime + + ", result=" + result + + ", ext=" + ext + + ", error=" + error + + ", ip=" + ip + + "}"; + } +} diff --git a/src/main/java/com/diagnose/entity/SensitiveWord.java~ b/src/main/java/com/diagnose/entity/SensitiveWord.java~ new file mode 100644 index 0000000..dd805b5 --- /dev/null +++ b/src/main/java/com/diagnose/entity/SensitiveWord.java~ @@ -0,0 +1,70 @@ +package com.syzb.common.entity; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; + +import java.io.Serializable; +import java.time.LocalDateTime; + +/** + *

+ * + *

+ * + * @author helloSyzb + * @since 2022-08-26 + */ +public class SensitiveWord implements Serializable { + + + /** + * 主键 + */ + @TableId(value = "id", type = IdType.AUTO) + private Integer id; + + /** + * 敏感词 + */ + private String word; + + /** + * 创建时间 + */ + @TableField("create_time") + private LocalDateTime createTime; + + public Integer getId() { + return id; + } + + public void setId(Integer id) { + this.id = id; + } + + public String getWord() { + return word; + } + + public void setWord(String word) { + this.word = word; + } + + public LocalDateTime getCreateTime() { + return createTime; + } + + public void setCreateTime(LocalDateTime createTime) { + this.createTime = createTime; + } + + @Override + public String toString() { + return "SensitiveWord{" + + "id=" + id + + ", word=" + word + + ", createTime=" + createTime + + "}"; + } +} diff --git a/src/main/java/com/diagnose/entity/ShortUrl.java~ b/src/main/java/com/diagnose/entity/ShortUrl.java~ new file mode 100644 index 0000000..0a60a72 --- /dev/null +++ b/src/main/java/com/diagnose/entity/ShortUrl.java~ @@ -0,0 +1,57 @@ +package com.syzb.common.entity; + +import com.baomidou.mybatisplus.annotation.TableId; + +import java.io.Serializable; + +/** + *

+ * + *

+ * + * @author helloSyzb + * @since 2024-07-02 + */ +public class ShortUrl implements Serializable { + + + /** + * 哈希后得短链 + */ + @TableId("resize_url") + private String resizeUrl; + + /** + * 原始链接 + */ + private String url; + + public ShortUrl(String resizeUrl, String url) { + this.resizeUrl = resizeUrl; + this.url = url; + } + + public String getResizeUrl() { + return resizeUrl; + } + + public void setResizeUrl(String resizeUrl) { + this.resizeUrl = resizeUrl; + } + + public String getUrl() { + return url; + } + + public void setUrl(String url) { + this.url = url; + } + + @Override + public String toString() { + return "ShortUrl{" + + "resizeUrl=" + resizeUrl + + ", url=" + url + + "}"; + } +} diff --git a/src/main/java/com/diagnose/mapper/CommentMapper.java~ b/src/main/java/com/diagnose/mapper/CommentMapper.java~ new file mode 100644 index 0000000..7692475 --- /dev/null +++ b/src/main/java/com/diagnose/mapper/CommentMapper.java~ @@ -0,0 +1,25 @@ +package com.diagnose.common.mapper; + +import com.baomidou.mybatisplus.core.conditions.Wrapper; +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.baomidou.mybatisplus.core.toolkit.Constants; +import com.syzb.common.entity.Comment; +import com.syzb.common.vo.IdCountVO; +import org.apache.ibatis.annotations.Param; +import org.apache.ibatis.annotations.Select; + +import java.util.List; + +/** + *

+ * 评论表 Mapper 接口 + *

+ * + * @author helloSyzb + * @since 2024-04-25 + */ +public interface CommentMapper extends BaseMapper { + + @Select("select ${ew.sqlSelect} from comment ${ew.customSqlSegment}") + List selectCommentCount(@Param(Constants.WRAPPER) Wrapper wrapper); +} diff --git a/src/main/java/com/diagnose/mapper/DiagnoseMapper.java b/src/main/java/com/diagnose/mapper/DiagnoseMapper.java new file mode 100644 index 0000000..fc753c8 --- /dev/null +++ b/src/main/java/com/diagnose/mapper/DiagnoseMapper.java @@ -0,0 +1,34 @@ +package com.diagnose.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.diagnose.vo.DiagnoseBackTestVO; +import com.diagnose.vo.DiagnoseRankVO; +import org.apache.ibatis.annotations.Param; +import org.apache.ibatis.annotations.Select; + +import java.math.BigDecimal; +import java.util.List; + +public interface DiagnoseMapper extends BaseMapper { + + @Select("SELECT * FROM (" + + " SELECT *, ROW_NUMBER() OVER (PARTITION BY stk_uni_code ORDER BY trade_date DESC) AS rn\n" + + " FROM _fe_stk_diag_rank\n" + + " WHERE stk_uni_code = #{stkUniCode} AND isvalid = 1\n" + + ") t WHERE t.rn = 1") + DiagnoseRankVO selectRank(@Param("stkUniCode") Long stkUniCode); + + @Select("SELECT max(total_indu_rank) AS _total_indu_rank FROM _fe_stk_diag_rank WHERE plate_uni_code = #{plateUniCode}") + Integer selectTotalInduCount(@Param("plateUniCode") Long plateUniCode); + + @Select("SELECT max(total_mkt_rank) AS _total_mkt_rank FROM _fe_stk_diag_rank") + Integer selectTotalMktCount(); + + @Select("SELECT * FROM (" + + " SELECT *, RANK() OVER (ORDER BY trade_date DESC) AS rk\n" + + " FROM _fe_stk_diag_backtest\n" + + " WHERE star = #{star} AND isvalid = 1\n" + + ") t WHERE t.rk = 1") + List selectBackTest(@Param("star") BigDecimal star); + +} diff --git a/src/main/java/com/diagnose/mapper/FinanceMapper.java b/src/main/java/com/diagnose/mapper/FinanceMapper.java new file mode 100644 index 0000000..d1e4aa0 --- /dev/null +++ b/src/main/java/com/diagnose/mapper/FinanceMapper.java @@ -0,0 +1,35 @@ +package com.diagnose.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.diagnose.vo.FinanceCashShortVO; +import com.diagnose.vo.FinanceIndexAnalysisVO; +import com.diagnose.vo.FinancialValuationVO; +import org.apache.ibatis.annotations.Param; +import org.apache.ibatis.annotations.Select; + +import java.util.List; + +public interface FinanceMapper extends BaseMapper { + + @Select("SELECT * FROM (" + + " SELECT fin_sum_mac, score, ROW_NUMBER() OVER (PARTITION BY stk_code, mkt_num ORDER BY trd_date DESC) AS rn\n" + + " FROM _fin_val_fac\n" + + " WHERE stk_code = #{stkCode} AND mkt_num = #{mktNum}\n" + + ") t WHERE t.rn = 1") + FinancialValuationVO selectFinancialValuation(@Param("stkCode") String stkCode, @Param("mktNum") Integer mktNum); + + @Select("SELECT * FROM (" + + " SELECT *, ROW_NUMBER() OVER (PARTITION BY stk_code, sec_mar_par ORDER BY end_date DESC) AS rn\n" + + " FROM _fin_idx_ana\n" + + " WHERE stk_code = #{stkCode} AND sec_mar_par = #{secMarPar}\n" + + ") t WHERE t.rn <= 5") + List selectFinanceIndexAnalysis(@Param("stkCode") String stkCode, @Param("secMarPar") Integer secMarPar); + + @Select("SELECT * FROM (" + + " SELECT *, ROW_NUMBER() OVER (PARTITION BY stk_code, sec_mar_par ORDER BY end_date DESC) AS rn\n" + + " FROM _fin_cash_short\n" + + " WHERE stk_code = #{stkCode} AND sec_mar_par = #{secMarPar}\n" + + ") t WHERE t.rn <= 5") + List selectFinanceCashShort(@Param("stkCode") String stkCode, @Param("secMarPar") Integer secMarPar); + +} diff --git a/src/main/java/com/diagnose/mapper/StockMapper.java b/src/main/java/com/diagnose/mapper/StockMapper.java new file mode 100644 index 0000000..1c3ed18 --- /dev/null +++ b/src/main/java/com/diagnose/mapper/StockMapper.java @@ -0,0 +1,19 @@ +package com.diagnose.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.diagnose.vo.StockVO; +import org.apache.ibatis.annotations.Select; + +import java.util.List; + +public interface StockMapper extends BaseMapper { + + @Select("SELECT sc.sec_uni_code, sc.sec_code, sc.sec_short_name, sc.sec_spe_short_name, sc.mkt_type_par, pi.plate_uni_code, pi.plate_name, pi.plate_code\n" + + "FROM _pub_sec_code sc\n" + + "JOIN _pub_sec_plate sp\n" + + "ON sc.sec_uni_code = sp.sec_uni_code\n" + + "JOIN pub_plate_info pi\n" + + "ON sp.plate_uni_code = pi.plate_uni_code") + List selectAllStock(); + +} diff --git a/src/main/java/com/diagnose/mapper/UnionMapper.java~ b/src/main/java/com/diagnose/mapper/UnionMapper.java~ new file mode 100644 index 0000000..e3b459e --- /dev/null +++ b/src/main/java/com/diagnose/mapper/UnionMapper.java~ @@ -0,0 +1,18 @@ +package com.diagnose.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.diagnose.common.vo.CountVO; +import com.diagnose.vo.StockVO; +import org.apache.ibatis.annotations.Select; + +import java.util.List; + +public interface UnionMapper extends BaseMapper { + + @Select("SELECT sc.sec_uni_code, sc.sec_code, sc.sec_short_name, sc.sec_spe_short_name, sc.mkt_type_par, pi.plate_uni_code, pi.plate_name, pi.plate_code FROM _pub_sec_code sc\n" + + "JOIN _pub_sec_plate sp\n" + + "ON sc.SEC_UNI_CODE = sp.SEC_UNI_CODE\n" + + "JOIN pub_plate_info pi\n" + + "ON sp.PLATE_UNI_CODE = pi.PLATE_UNI_CODE") + List selectAllStock(); +} diff --git a/src/main/java/com/diagnose/service/SearchService.java b/src/main/java/com/diagnose/service/SearchService.java new file mode 100644 index 0000000..bcf1b06 --- /dev/null +++ b/src/main/java/com/diagnose/service/SearchService.java @@ -0,0 +1,36 @@ +package com.diagnose.service; + +import cn.hutool.core.lang.Validator; +import com.diagnose.vo.StockVO; +import org.springframework.stereotype.Service; + +import javax.annotation.Resource; +import javax.validation.constraints.NotNull; +import java.util.List; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +@Service +public class SearchService { + + private static final int limit = 10; + + @Resource + private StockService stockService; + + public List search(String keyword) { + String keywordTrim = keyword.trim(); + List allStockList = stockService.selectALlStockCache(); + Stream parallelStream = allStockList.parallelStream(); + if (Validator.isNumber(keywordTrim)) { + parallelStream = parallelStream.filter(stock -> stock.getSecCode().contains(keywordTrim)); + } else if (Validator.isWord(keywordTrim)) { + String keywordUpper = keywordTrim.toUpperCase(); + parallelStream = parallelStream.filter(stock -> stock.getSecSpeShortName().contains(keywordUpper) ); + } else { + parallelStream = parallelStream.filter(stock -> stock.getSecShortName().contains(keywordTrim)); + } + return parallelStream.limit(limit).collect(Collectors.toList()); + } + +} diff --git a/src/main/java/com/diagnose/service/SearchService.java~ b/src/main/java/com/diagnose/service/SearchService.java~ new file mode 100644 index 0000000..2d8b6f0 --- /dev/null +++ b/src/main/java/com/diagnose/service/SearchService.java~ @@ -0,0 +1,38 @@ +package com.diagnose.service; + +import cn.hutool.core.lang.Validator; +import com.diagnose.vo.StockVO; +import org.springframework.stereotype.Service; + +import javax.annotation.Resource; +import javax.validation.constraints.NotNull; +import java.util.List; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +@Service +public class SearchService { + + private static final int limit = 10; + + @Resource + private StockService stockService; + + public List search(String keyword) { + String keywordTrim = keyword.trim(); + List allStockList = stockService.selectALlStockCache(); + Stream parallelStream = allStockList.parallelStream(); + if (Validator.isNumber(keywordTrim)) { + parallelStream = parallelStream.filter(stock -> stock.getSecCode().contains(keywordTrim)); + } else if (Validator.isWord(keywordTrim)) { + String keywordUpper = keywordTrim.toUpperCase(); + parallelStream = parallelStream.filter(stock -> stock.getSecSpeShortName().contains(keywordUpper) ); + } else { + parallelStream = parallelStream.filter(stock -> stock.getSecShortName().contains(keywordTrim)); + } + return parallelStream.limit(limit).collect(Collectors.toList()); + } + + public List rank(@NotNull Long stkUniCode) { + } +} diff --git a/src/main/java/com/diagnose/service/StockService.java b/src/main/java/com/diagnose/service/StockService.java new file mode 100644 index 0000000..6acba3f --- /dev/null +++ b/src/main/java/com/diagnose/service/StockService.java @@ -0,0 +1,109 @@ +package com.diagnose.service; + +import com.diagnose.mapper.DiagnoseMapper; +import com.diagnose.mapper.FinanceMapper; +import com.diagnose.mapper.StockMapper; +import com.diagnose.vo.*; +import org.springframework.stereotype.Service; + +import javax.annotation.Resource; +import java.math.BigDecimal; +import java.util.List; +import java.util.Map; +import java.util.function.Function; +import java.util.stream.Collectors; + +@Service +public class StockService { + + private static final long cacheExpires = 60 * 60 * 1000; + + private static long cacheTime = 0; + + private List stockListCache = null; + + private Map stockMapCache = null; // + + @Resource + private StockMapper stockMapper; + + @Resource + private FinanceMapper financeMapper; + + @Resource + private DiagnoseMapper diagnoseMapper; + + public List selectAllStock() { + return stockMapper.selectAllStock(); + } + + public synchronized List selectALlStockCache () { + long now = System.currentTimeMillis(); + if (stockListCache == null || now - cacheTime > cacheExpires) { + stockListCache = selectAllStock(); + cacheTime = now; + } + return stockListCache; + } + + public StockVO getStock(Long stkUniCode) { + if (stockMapCache == null) { + stockMapCache = selectALlStockCache().stream().collect(Collectors.toMap(StockVO::getSecUniCode, Function.identity())); + } + return stockMapCache.get(stkUniCode); + } + + public DiagnoseRankVO rank(StockVO stock) { + DiagnoseRankVO diagnoseRankVO = diagnoseMapper.selectRank(stock.getSecUniCode()); + Integer totalInduCount = diagnoseMapper.selectTotalInduCount(stock.getPlateUniCode()); + Integer totalMktCount = diagnoseMapper.selectTotalMktCount(); + diagnoseRankVO.setTotalInduCount(totalInduCount); + diagnoseRankVO.setTotalMktCount(totalMktCount); + return diagnoseRankVO; + } + + public ComprehensiveEvaluationVO comprehensiveEvaluation(Long stkUniCode) { + StockVO stock = getStock(stkUniCode); + if (stock == null) { + return null; + } + DiagnoseRankVO diagnoseRankVO = rank(stock); + BigDecimal star = diagnoseRankVO.getTotalStar(); + if (star == null) { + return null; + } + List backTestList = diagnoseMapper.selectBackTest(star); + ComprehensiveEvaluationVO vo = new ComprehensiveEvaluationVO(); + vo.setStock(stock); + vo.setRank(diagnoseRankVO); + vo.setBackTestList(backTestList); + return vo; + } + + public FinancialValuationVO financialValuation(Long stkUniCode) { + StockVO stock = getStock(stkUniCode); + if (stock == null) { + return null; + } + String secCode = stock.getSecCode(); + Integer mktNum = stock.getMktNum(); + FinancialValuationVO vo = financeMapper.selectFinancialValuation(secCode, mktNum); + Integer secMarPar = stock.getSecMarPar(); + List financeIndexAnalysisList = financeMapper.selectFinanceIndexAnalysis(secCode, secMarPar); + financeIndexAnalysisList.forEach(fiaVO -> { + if (fiaVO.getEndDate() != null && fiaVO.getEndDate().length() > 10) { + fiaVO.setEndDate(fiaVO.getEndDate().substring(0, 10)); + } + }); + vo.setFinanceIndexAnalysisList(financeIndexAnalysisList); + List financeCashShortList = financeMapper.selectFinanceCashShort(secCode, secMarPar); + financeCashShortList.forEach(fcsVO -> { + if (fcsVO.getEndDate() != null && fcsVO.getEndDate().length() > 10) { + fcsVO.setEndDate(fcsVO.getEndDate().substring(0, 10)); + } + }); + vo.setFinanceCashShortList(financeCashShortList); + return vo; + } + +} diff --git a/src/main/java/com/diagnose/startup/Main.java b/src/main/java/com/diagnose/startup/Main.java new file mode 100644 index 0000000..71dd66c --- /dev/null +++ b/src/main/java/com/diagnose/startup/Main.java @@ -0,0 +1,25 @@ +package com.diagnose.startup; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.cache.annotation.EnableCaching; +import org.springframework.context.annotation.ComponentScan; +import org.springframework.context.annotation.EnableAspectJAutoProxy; +import org.springframework.scheduling.annotation.EnableAsync; +import org.springframework.transaction.annotation.EnableTransactionManagement; + +@ComponentScan("com.diagnose") +@SpringBootApplication +@EnableCaching +@EnableTransactionManagement +@EnableAspectJAutoProxy(proxyTargetClass = true, exposeProxy = true) +@EnableAsync +public class Main { + + public static void main(String[] args) { + SpringApplication app = new SpringApplication(Main.class); + app.setRegisterShutdownHook(true); + app.run(args); + } + +} diff --git a/src/main/java/com/diagnose/test3.java~ b/src/main/java/com/diagnose/test3.java~ new file mode 100644 index 0000000..2fb7ce6 --- /dev/null +++ b/src/main/java/com/diagnose/test3.java~ @@ -0,0 +1,48 @@ +package com.diagnose; + +import org.ahocorasick.trie.Emit; +import org.ahocorasick.trie.Trie; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; + +public class test3 { + + public static void main(String[] args) { + // 示例数据 + List list = new ArrayList<>(); + list.add("hello world"); + list.add("java programming"); + list.add("ahocorasick algorithm"); + list.add("substring matching"); + list.add("performance optimization"); + list.add("data structures"); + list.add("algorithm design"); + list.add("string search"); + list.add("efficient matching"); + list.add("aho-corasick implementation"); + list.add("another example"); + list.add("yet another example"); + list.add("example"); + list.add("abcexample"); + list.add("abcexampledef"); + + // 目标子串 + String input = "example"; + + Trie trie = Trie.builder() + .ignoreOverlaps() + .addKeyword(input) // 将目标子串作为模式插入 + .build(); + + // 匹配字符串 + Collection emits = trie.parseText(input); + + // 输出结果 + System.out.println("匹配到的字符串:"); + for (Emit emit : emits) { + System.out.println(emit.getKeyword()); + } + } +} diff --git a/src/main/java/com/diagnose/util/StringMatcher.java b/src/main/java/com/diagnose/util/StringMatcher.java new file mode 100644 index 0000000..16f7fee --- /dev/null +++ b/src/main/java/com/diagnose/util/StringMatcher.java @@ -0,0 +1,80 @@ +package com.diagnose.util; + +import java.util.*; + +public class StringMatcher { + + private final int GRAM_SIZE = 1; + + private Map> indexMap = new HashMap<>(); + private List dataList; + + public StringMatcher(List dataList) { + this.dataList = dataList; + buildIndex(); + } + + private void buildIndex() { + // 为了平衡性能和内存,可以考虑只索引n-gram + for (int i = 0; i < dataList.size(); i++) { + String s = dataList.get(i); + // 生成所有可能的子串或n-gram + for (int j = 0; j < s.length() - GRAM_SIZE + 1; j++) { + String gram = s.substring(j, j + GRAM_SIZE); // n-gram + indexMap.computeIfAbsent(gram, k -> new HashSet<>()).add(i); + } + } + } + + public List search(String query, int limit) { + // 如果查询字符串长度小于GRAM_SIZE,使用简单遍历 + if (query.length() < GRAM_SIZE) { + return simpleSearch(query, limit); + } + + Set candidates = null; + + // 使用查询的n-gram找候选集 + for (int i = 0; i <= query.length() - GRAM_SIZE; i++) { + String gram = query.substring(i, i + GRAM_SIZE); + Set indices = indexMap.getOrDefault(gram, Collections.emptySet()); + + if (candidates == null) { + candidates = new HashSet<>(indices); + } else { + candidates.retainAll(indices); + } + + if (candidates.isEmpty()) { + return Collections.emptyList(); + } + } + + // 验证候选集 + List result = new ArrayList<>(); + for (Integer idx : candidates) { + if (dataList.get(idx).contains(query)) { + result.add(dataList.get(idx)); + if (result.size() >= limit) { + break; + } + } + } + + return result; + } + + private List simpleSearch(String query, int limit) { + // 简单遍历法 + List result = new ArrayList<>(); + for (String s : dataList) { + if (s.contains(query)) { + result.add(s); + if (result.size() >= limit) { + break; + } + } + } + return result; + } +} \ No newline at end of file diff --git a/src/main/java/com/diagnose/util/TestSearch.java b/src/main/java/com/diagnose/util/TestSearch.java new file mode 100644 index 0000000..f0627c5 --- /dev/null +++ b/src/main/java/com/diagnose/util/TestSearch.java @@ -0,0 +1,34 @@ +package com.diagnose.util; + +import java.util.ArrayList; +import java.util.List; + +public class TestSearch { + + public static void main(String[] args) { + // 示例数据 + List list = new ArrayList<>(); + list.add("hello world"); + list.add("java programming"); + list.add("ahocorasick algorithm"); + list.add("substring matching"); + list.add("performance optimization"); + list.add("data structures"); + list.add("algorithm design"); + list.add("string search"); + list.add("efficient matching"); + list.add("aho-corasick implementation"); + list.add("another example"); + list.add("yet another example"); + list.add("example"); + list.add("abcexample"); + list.add("abcexampledef"); + + StringMatcher matcher = new StringMatcher(list); + List results = matcher.search("example", 10); + + for (String result : results) { + System.out.println(result); + } + } +} diff --git a/src/main/java/com/diagnose/vo/ComprehensiveEvaluationVO.java b/src/main/java/com/diagnose/vo/ComprehensiveEvaluationVO.java new file mode 100644 index 0000000..b073d6a --- /dev/null +++ b/src/main/java/com/diagnose/vo/ComprehensiveEvaluationVO.java @@ -0,0 +1,43 @@ +package com.diagnose.vo; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; + +import java.util.List; + +@ApiModel("综合评分") +public class ComprehensiveEvaluationVO { + + @ApiModelProperty("股票基本信息") + private StockVO stock; + + @ApiModelProperty("评分排名") + private DiagnoseRankVO rank; + + @ApiModelProperty("回测列表") + private List backTestList; + + public DiagnoseRankVO getRank() { + return rank; + } + + public void setRank(DiagnoseRankVO rank) { + this.rank = rank; + } + + public StockVO getStock() { + return stock; + } + + public void setStock(StockVO stock) { + this.stock = stock; + } + + public List getBackTestList() { + return backTestList; + } + + public void setBackTestList(List backTestList) { + this.backTestList = backTestList; + } +} diff --git a/src/main/java/com/diagnose/vo/DiagnoseBackTestVO.java b/src/main/java/com/diagnose/vo/DiagnoseBackTestVO.java new file mode 100644 index 0000000..60ecf47 --- /dev/null +++ b/src/main/java/com/diagnose/vo/DiagnoseBackTestVO.java @@ -0,0 +1,44 @@ +package com.diagnose.vo; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; + +import java.io.Serializable; + +@ApiModel("回测分析") +public class DiagnoseBackTestVO implements Serializable { + + @ApiModelProperty("持仓周期") + private String timeSpan; + + @ApiModelProperty("平均超额收益率") + private String avgExcessRet; + + @ApiModelProperty("胜率") + private String winRate; + + public String getTimeSpan() { + return timeSpan; + } + + public void setTimeSpan(String timeSpan) { + this.timeSpan = timeSpan; + } + + public String getAvgExcessRet() { + return avgExcessRet; + } + + public void setAvgExcessRet(String avgExcessRet) { + this.avgExcessRet = avgExcessRet; + } + + public String getWinRate() { + return winRate; + } + + public void setWinRate(String winRate) { + this.winRate = winRate; + } + +} diff --git a/src/main/java/com/diagnose/vo/DiagnoseRankVO.java b/src/main/java/com/diagnose/vo/DiagnoseRankVO.java new file mode 100644 index 0000000..5b77989 --- /dev/null +++ b/src/main/java/com/diagnose/vo/DiagnoseRankVO.java @@ -0,0 +1,133 @@ +package com.diagnose.vo; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; + +import java.io.Serializable; +import java.math.BigDecimal; + +@ApiModel("得分排名") +public class DiagnoseRankVO implements Serializable { + + @ApiModelProperty("行业排名") + private Integer totalInduRank; + + @ApiModelProperty("行业总数") + private Integer totalInduCount; + + @ApiModelProperty("市场排名") + private Integer totalMktRank; + + @ApiModelProperty("市场总数") + private Integer totalMktCount; + + @ApiModelProperty("综合得分") + private BigDecimal totalScore; + + @ApiModelProperty("综合星级") + private BigDecimal totalStar; + + @ApiModelProperty("财务得分") + private BigDecimal finScore; + + @ApiModelProperty("量化得分") + private BigDecimal volScore; + + @ApiModelProperty("市场热度得分") + private BigDecimal mhotScore; + + @ApiModelProperty("主力得分") + private BigDecimal mainScore; + + @ApiModelProperty("题材得分") + private BigDecimal mqScore; + + public Integer getTotalInduRank() { + return totalInduRank; + } + + public void setTotalInduRank(Integer totalInduRank) { + this.totalInduRank = totalInduRank; + } + + public Integer getTotalInduCount() { + return totalInduCount; + } + + public void setTotalInduCount(Integer totalInduCount) { + this.totalInduCount = totalInduCount; + } + + public Integer getTotalMktRank() { + return totalMktRank; + } + + public void setTotalMktRank(Integer totalMktRank) { + this.totalMktRank = totalMktRank; + } + + public Integer getTotalMktCount() { + return totalMktCount; + } + + public void setTotalMktCount(Integer totalMktCount) { + this.totalMktCount = totalMktCount; + } + + public BigDecimal getTotalScore() { + return totalScore; + } + + public void setTotalScore(BigDecimal totalScore) { + this.totalScore = totalScore; + } + + public BigDecimal getTotalStar() { + return totalStar; + } + + public void setTotalStar(BigDecimal totalStar) { + this.totalStar = totalStar; + } + + public BigDecimal getFinScore() { + return finScore; + } + + public void setFinScore(BigDecimal finScore) { + this.finScore = finScore; + } + + public BigDecimal getVolScore() { + return volScore; + } + + public void setVolScore(BigDecimal volScore) { + this.volScore = volScore; + } + + public BigDecimal getMhotScore() { + return mhotScore; + } + + public void setMhotScore(BigDecimal mhotScore) { + this.mhotScore = mhotScore; + } + + public BigDecimal getMainScore() { + return mainScore; + } + + public void setMainScore(BigDecimal mainScore) { + this.mainScore = mainScore; + } + + public BigDecimal getMqScore() { + return mqScore; + } + + public void setMqScore(BigDecimal mqScore) { + this.mqScore = mqScore; + } + +} diff --git a/src/main/java/com/diagnose/vo/FinanceCashShortVO.java b/src/main/java/com/diagnose/vo/FinanceCashShortVO.java new file mode 100644 index 0000000..2c7b183 --- /dev/null +++ b/src/main/java/com/diagnose/vo/FinanceCashShortVO.java @@ -0,0 +1,51 @@ +package com.diagnose.vo; + +import io.swagger.annotations.ApiModelProperty; + +public class FinanceCashShortVO { + + @ApiModelProperty("截止日期") + private String endDate; + + @ApiModelProperty("经营活动现金流量净额") + private String cs10000; + + @ApiModelProperty("投资活动现金流量净额") + private String cs20000; + + @ApiModelProperty("筹资活动现金流量净额") + private String cs30000; + + public String getEndDate() { + return endDate; + } + + public void setEndDate(String endDate) { + this.endDate = endDate; + } + + public String getCs10000() { + return cs10000; + } + + public void setCs10000(String cs10000) { + this.cs10000 = cs10000; + } + + public String getCs20000() { + return cs20000; + } + + public void setCs20000(String cs20000) { + this.cs20000 = cs20000; + } + + public String getCs30000() { + return cs30000; + } + + public void setCs30000(String cs30000) { + this.cs30000 = cs30000; + } + +} diff --git a/src/main/java/com/diagnose/vo/FinanceIndexAnalysisVO.java b/src/main/java/com/diagnose/vo/FinanceIndexAnalysisVO.java new file mode 100644 index 0000000..8ffff4f --- /dev/null +++ b/src/main/java/com/diagnose/vo/FinanceIndexAnalysisVO.java @@ -0,0 +1,110 @@ +package com.diagnose.vo; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; + +import java.math.BigDecimal; + +@ApiModel("财务指标分析") +public class FinanceIndexAnalysisVO { + + @ApiModelProperty("截止日期") + private String endDate; + + @ApiModelProperty("销售净利率") + private BigDecimal salNpr; + + @ApiModelProperty("销售毛利率") + private BigDecimal salGir; + + @ApiModelProperty("净资产收益率") + private BigDecimal roea; + + @ApiModelProperty("净利润同比增长率_同比") + private BigDecimal npYoy; + + @ApiModelProperty("营业收入 同比") + private BigDecimal orYoy; + + @ApiModelProperty("总资产周转率") + private BigDecimal taRate; + + @ApiModelProperty("应付账款周转率") + private BigDecimal apRate; + + @ApiModelProperty("资产负债率") + private BigDecimal assDebt; + + public String getEndDate() { + return endDate; + } + + public void setEndDate(String endDate) { + this.endDate = endDate; + } + + public BigDecimal getSalNpr() { + return salNpr; + } + + public void setSalNpr(BigDecimal salNpr) { + this.salNpr = salNpr; + } + + public BigDecimal getSalGir() { + return salGir; + } + + public void setSalGir(BigDecimal salGir) { + this.salGir = salGir; + } + + public BigDecimal getRoea() { + return roea; + } + + public void setRoea(BigDecimal roea) { + this.roea = roea; + } + + public BigDecimal getNpYoy() { + return npYoy; + } + + public void setNpYoy(BigDecimal npYoy) { + this.npYoy = npYoy; + } + + public BigDecimal getOrYoy() { + return orYoy; + } + + public void setOrYoy(BigDecimal orYoy) { + this.orYoy = orYoy; + } + + public BigDecimal getTaRate() { + return taRate; + } + + public void setTaRate(BigDecimal taRate) { + this.taRate = taRate; + } + + public BigDecimal getApRate() { + return apRate; + } + + public void setApRate(BigDecimal apRate) { + this.apRate = apRate; + } + + public BigDecimal getAssDebt() { + return assDebt; + } + + public void setAssDebt(BigDecimal assDebt) { + this.assDebt = assDebt; + } + +} diff --git a/src/main/java/com/diagnose/vo/FinanceIndexAnalysisVO.java~ b/src/main/java/com/diagnose/vo/FinanceIndexAnalysisVO.java~ new file mode 100644 index 0000000..b712902 --- /dev/null +++ b/src/main/java/com/diagnose/vo/FinanceIndexAnalysisVO.java~ @@ -0,0 +1,102 @@ +package com.diagnose.vo; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; + +import java.math.BigDecimal; + +@ApiModel("财务指标分析") +public class FinanceIndexAnalysisVO { + + @ApiModelProperty("截止日期") + private String endDate; + + @ApiModelProperty("销售净利率") + private BigDecimal salNpr; + + @ApiModelProperty("销售毛利率") + private BigDecimal salGir; + + @ApiModelProperty("净资产收益率") + private BigDecimal roea; + + @ApiModelProperty("净利润同比增长率_同比") + private BigDecimal npYoy; + + @ApiModelProperty("营业收入 同比") + private BigDecimal orYoy; + + @ApiModelProperty("总资产周转率") + private BigDecimal taRate; + + @ApiModelProperty("应付账款周转率") + private BigDecimal apRate; + + @ApiModelProperty("资产负债率") + private BigDecimal assDebt; + + public BigDecimal getSalNpr() { + return salNpr; + } + + public void setSalNpr(BigDecimal salNpr) { + this.salNpr = salNpr; + } + + public BigDecimal getSalGir() { + return salGir; + } + + public void setSalGir(BigDecimal salGir) { + this.salGir = salGir; + } + + public BigDecimal getRoea() { + return roea; + } + + public void setRoea(BigDecimal roea) { + this.roea = roea; + } + + public BigDecimal getNpYoy() { + return npYoy; + } + + public void setNpYoy(BigDecimal npYoy) { + this.npYoy = npYoy; + } + + public BigDecimal getOrYoy() { + return orYoy; + } + + public void setOrYoy(BigDecimal orYoy) { + this.orYoy = orYoy; + } + + public BigDecimal getTaRate() { + return taRate; + } + + public void setTaRate(BigDecimal taRate) { + this.taRate = taRate; + } + + public BigDecimal getApRate() { + return apRate; + } + + public void setApRate(BigDecimal apRate) { + this.apRate = apRate; + } + + public BigDecimal getAssDebt() { + return assDebt; + } + + public void setAssDebt(BigDecimal assDebt) { + this.assDebt = assDebt; + } + +} diff --git a/src/main/java/com/diagnose/vo/FinancialValuationVO.java b/src/main/java/com/diagnose/vo/FinancialValuationVO.java new file mode 100644 index 0000000..7a0c2a0 --- /dev/null +++ b/src/main/java/com/diagnose/vo/FinancialValuationVO.java @@ -0,0 +1,54 @@ +package com.diagnose.vo; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; + +import java.util.List; + +@ApiModel("财务估值") +public class FinancialValuationVO { + + @ApiModelProperty("总结性机器语") + private String finSumMac; + + @ApiModelProperty("财务估值得分") + private Integer score; + + @ApiModelProperty("财务指标分析列表") + private List financeIndexAnalysisList; + + @ApiModelProperty("现金流量列表") + private List financeCashShortList; + + public String getFinSumMac() { + return finSumMac; + } + + public void setFinSumMac(String finSumMac) { + this.finSumMac = finSumMac; + } + + public Integer getScore() { + return score; + } + + public void setScore(Integer score) { + this.score = score; + } + + public List getFinanceIndexAnalysisList() { + return financeIndexAnalysisList; + } + + public void setFinanceIndexAnalysisList(List financeIndexAnalysisList) { + this.financeIndexAnalysisList = financeIndexAnalysisList; + } + + public List getFinanceCashShortList() { + return financeCashShortList; + } + + public void setFinanceCashShortList(List financeCashShortList) { + this.financeCashShortList = financeCashShortList; + } +} diff --git a/src/main/java/com/diagnose/vo/StockVO.java b/src/main/java/com/diagnose/vo/StockVO.java new file mode 100644 index 0000000..2376825 --- /dev/null +++ b/src/main/java/com/diagnose/vo/StockVO.java @@ -0,0 +1,146 @@ +package com.diagnose.vo; + +import com.diagnose.constant.MktNum; +import com.diagnose.constant.MktTypePar; +import com.diagnose.constant.SecMarPar; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; + +import java.io.Serializable; + +@ApiModel("股票基本信息") +public class StockVO implements Serializable { + + @ApiModelProperty("证券统一编码") + private Long secUniCode; + + @ApiModelProperty("证券代码") + private String secCode; + + @ApiModelProperty("证券简称") + private String secShortName; + + @ApiModelProperty("证券拼音简称") + private String secSpeShortName; + + @ApiModelProperty("证券市场 1:深圳证券交易所 2:上海证券交易所 190:北京证券交易所") + private Integer mktTypePar; + + @ApiModelProperty("板块统一编码") + private Long plateUniCode; + + @ApiModelProperty("板块名称") + private String plateName; + + @ApiModelProperty("板块代码") + private String plateCode; + + // 股票所属市场 0:深圳 1:上海 + public Integer getMktNum() { + if (mktTypePar == null) { + return null; + } + if (MktTypePar.SZ.value.equals(mktTypePar)) { + return MktNum.SZ.value; + } else if (MktTypePar.SH.value.equals(mktTypePar)) { + return MktNum.SH.value; + } else if (MktTypePar.BJ.value.equals(mktTypePar)) { + return MktNum.BJ.value; + } + return null; + } + + // 股票市场 1:深圳 2:上海 8:北京 + public Integer getSecMarPar() { + if (mktTypePar == null) { + return null; + } + if (MktTypePar.SZ.value.equals(mktTypePar)) { + return SecMarPar.SZ.value; + } else if (MktTypePar.SH.value.equals(mktTypePar)) { + return SecMarPar.SH.value; + } else if (MktTypePar.BJ.value.equals(mktTypePar)) { + return SecMarPar.BJ.value; + } + return null; + } + + public Long getSecUniCode() { + return secUniCode; + } + + public void setSecUniCode(Long secUniCode) { + this.secUniCode = secUniCode; + } + + public String getSecCode() { + return secCode; + } + + public void setSecCode(String secCode) { + this.secCode = secCode; + } + + public String getSecShortName() { + return secShortName; + } + + public void setSecShortName(String secShortName) { + this.secShortName = secShortName; + } + + public String getSecSpeShortName() { + return secSpeShortName; + } + + public void setSecSpeShortName(String secSpeShortName) { + this.secSpeShortName = secSpeShortName; + } + + public Integer getMktTypePar() { + return mktTypePar; + } + + public void setMktTypePar(Integer mktTypePar) { + this.mktTypePar = mktTypePar; + } + + public Long getPlateUniCode() { + return plateUniCode; + } + + public void setPlateUniCode(Long plateUniCode) { + this.plateUniCode = plateUniCode; + } + + public String getPlateName() { + return plateName; + } + + public void setPlateName(String plateName) { + this.plateName = plateName; + } + + public String getPlateCode() { + return plateCode; + } + + public void setPlateCode(String plateCode) { + this.plateCode = plateCode; + } + + @Override + public String toString() { + return "StockVO{" + + "secUniCode='" + secUniCode + '\'' + + ", secCode='" + secCode + '\'' + + ", secShortName='" + secShortName + '\'' + + ", secSpeShortName='" + secSpeShortName + '\'' + + ", mktTypePar='" + mktTypePar + '\'' + + ", plateUniCode='" + plateUniCode + '\'' + + ", plateName='" + plateName + '\'' + + ", plateCode='" + plateCode + '\'' + + '}'; + } + +} diff --git a/src/main/resources/application-dev.yaml b/src/main/resources/application-dev.yaml new file mode 100644 index 0000000..b3e1e91 --- /dev/null +++ b/src/main/resources/application-dev.yaml @@ -0,0 +1,10 @@ +spring: + config: + activate: + on-profile: dev + # 引入开发环境配置文件 + import: + - optional:classpath:/dev/advisorServer.yaml + - optional:classpath:/dev/application.yaml + - optional:classpath:/dev/tencentConfig.yaml + - optional:classpath:/dev/business.yaml \ No newline at end of file diff --git a/src/main/resources/application-prod.yaml b/src/main/resources/application-prod.yaml new file mode 100644 index 0000000..975fe0c --- /dev/null +++ b/src/main/resources/application-prod.yaml @@ -0,0 +1,10 @@ +spring: + config: + activate: + on-profile: prod-admin + import: + - optional:classpath:/prod/advisorServer.yaml + - optional:classpath:/prod/application.yaml + - optional:classpath:/prod/tencentConfig.yaml + - optional:classpath:/prod/business.yaml + - optional:classpath:/prod/admin.yaml \ No newline at end of file diff --git a/src/main/resources/application-test.yaml b/src/main/resources/application-test.yaml new file mode 100644 index 0000000..3c14cac --- /dev/null +++ b/src/main/resources/application-test.yaml @@ -0,0 +1,10 @@ +spring: + config: + activate: + on-profile: test + # 引入开发环境配置文件 + import: + - optional:classpath:/dev/advisorServer.yaml + - optional:classpath:/dev/application.yaml + - optional:classpath:/dev/tencentConfig.yaml + - optional:classpath:/dev/business.yaml \ No newline at end of file diff --git a/src/main/resources/application.yaml b/src/main/resources/application.yaml new file mode 100644 index 0000000..ac80f5e --- /dev/null +++ b/src/main/resources/application.yaml @@ -0,0 +1,3 @@ +spring: + profiles: + active: dev # 默认使用开发环境配置 \ No newline at end of file diff --git a/src/main/resources/dev/application.yaml b/src/main/resources/dev/application.yaml new file mode 100644 index 0000000..c65bbd3 --- /dev/null +++ b/src/main/resources/dev/application.yaml @@ -0,0 +1,44 @@ +hazelcast: + members: 127.0.0.1:5709 #缓存集群的ip端口号 + serverPort: 5709 #自己作为缓存服务器监听的端口号 +mybatis-plus: + configuration: + call-setters-on-nulls: true #如果查询结果中包含空值的列,则 MyBatis 在映射的时候,不会映射这个字段 + log-impl: org.apache.ibatis.logging.stdout.StdOutImpl #这个配置会将执行的sql打印出来,在开发或测试的时候可以用 + map-underscore-to-camel-case: true #是否开启自动驼峰命名规则映射:从数据库列名到Java属性驼峰命名的类似映射 +spring: + main: + allow-circular-references: true + application: + name: diagnose-api-server + servlet: + multipart: + maxFileSize: 10MB + maxRequestSize: 20MB + datasource: #初始化连接池的连接数量 + dynamic: + primary: master + strict: false #严格匹配数据源,默认false. true未匹配到指定数据源时抛异常,false使用默认数据源 + hikari: + min-idle: 5 #最小空闲连接数量 + max-pool-size: 25 #连接池最大连接数,默认是10 + idle-timeout: 100000 #空闲连接存活最大时间,默认600000(10分钟) + is_auto-commit: true #此属性控制从池返回的连接的默认自动提交行为,默认值:true + max-lifetime: 600000 #此属性控制池中连接的最长生命周期,值0表示无限生命周期,默认1800000即30分钟 + connection-timeout: 15000 #数据库连接超时时间,默认30秒,即30000 + connection-test-query: SELECT 1 FROM DUAL + validation-timeout: 30000 + datasource: + master: + driver-class-name: com.mysql.cj.jdbc.Driver + url: jdbc:mysql://47.96.178.171:3306/db_upsync?allowMultiQueries=true&useUnicode=true&characterEncoding=UTF-8&useSSL=false&allowPublicKeyRetrieval=true&serverTimezone=GMT%2B8 + username: eason + password: mysql2025easonzhu + mvc: + pathmatch: + matching-strategy: ant_path_matcher #Springfox 使用的路径匹配是基于AntPathMatcher的,而Spring Boot 2.6.X使用的是PathPatternMatcher。 + lifecycle: + timeout-per-shutdown-phase: "10s" +springfox: + documentation: + enabled: true #是否开启swagger \ No newline at end of file diff --git a/src/main/resources/logback-dev.xml b/src/main/resources/logback-dev.xml new file mode 100644 index 0000000..a9017f4 --- /dev/null +++ b/src/main/resources/logback-dev.xml @@ -0,0 +1,15 @@ + + + + + + %d{yyyy-MM-dd HH:mm:ss.SSS}|%-4.5level|%X{requestId}|%msg%n + + + + + + + + + \ No newline at end of file diff --git a/src/main/resources/logback-prod.xml b/src/main/resources/logback-prod.xml new file mode 100644 index 0000000..f8c4a66 --- /dev/null +++ b/src/main/resources/logback-prod.xml @@ -0,0 +1,58 @@ + + + + + + + + + + ${LOG_PATH}/advisor_server-%d{yyyyMMdd}.log + 30 + 1GB + + + %d{yyyy-MM-dd HH:mm:ss.SSS}|%-4.5level|%X{requestId}|%msg%n + + + + + + ${LOG_PATH}/advisor_server-data-%d{yyyyMMdd}.log + 30 + 1GB + + + %d{yyyy-MM-dd HH:mm:ss.SSS}|%-4.5level|%X{requestId}|%msg%n + + + + + + ${LOG_PATH}/advisor_server-error-%d{yyyyMMdd}.log + 30 + 1GB + + + %d{yyyy-MM-dd HH:mm:ss.SSS}|%-4.5level|%X{requestId}|%msg%n + + + + + + + + + + + + + + + + + + + + + diff --git a/src/main/resources/logback-spring.xml b/src/main/resources/logback-spring.xml new file mode 100644 index 0000000..4155e28 --- /dev/null +++ b/src/main/resources/logback-spring.xml @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/main/resources/logback-tst.xml b/src/main/resources/logback-tst.xml new file mode 100644 index 0000000..7ddcaa0 --- /dev/null +++ b/src/main/resources/logback-tst.xml @@ -0,0 +1,54 @@ + + + + + + + + + + ${LOG_PATH}/advisor_server-%d{yyyyMMdd}.log + 30 + 1GB + + + %d{yyyy-MM-dd HH:mm:ss.SSS}|%-4.5level|%X{requestId}|%msg%n + + + + + + ${LOG_PATH}/advisor_server-data-%d{yyyyMMdd}.log + 30 + 1GB + + + %d{yyyy-MM-dd HH:mm:ss.SSS}|%-4.5level|%X{requestId}|%msg%n + + + + + + ${LOG_PATH}/advisor_server-error-%d{yyyyMMdd}.log + 30 + 1GB + + + %d{yyyy-MM-dd HH:mm:ss.SSS}|%-4.5level|%X{requestId}|%msg%n + + + + + + + + + + + + + + + + + diff --git a/src/main/resources/prod/application.yaml b/src/main/resources/prod/application.yaml new file mode 100644 index 0000000..71e71e9 --- /dev/null +++ b/src/main/resources/prod/application.yaml @@ -0,0 +1,44 @@ +hazelcast: + members: 172.26.1.9,172.26.1.15 #缓存集群的ip端口号 + serverPort: 5709 #自己作为缓存服务器监听的端口号 +mybatis-plus: + configuration: + call-setters-on-nulls: true #如果查询结果中包含空值的列,则 MyBatis 在映射的时候,不会映射这个字段 + log-impl: org.apache.ibatis.logging.stdout.StdOutImpl #这个配置会将执行的sql打印出来,在开发或测试的时候可以用 + map-underscore-to-camel-case: true #是否开启自动驼峰命名规则映射:从数据库列名到Java属性驼峰命名的类似映射 +spring: + main: + allow-circular-references: true + application: + name: diagnose-api-server + servlet: + multipart: + maxFileSize: 10MB + maxRequestSize: 20MB + datasource: #初始化连接池的连接数量 + dynamic: + primary: master + strict: false #严格匹配数据源,默认false. true未匹配到指定数据源时抛异常,false使用默认数据源 + hikari: + min-idle: 5 #最小空闲连接数量 + max-pool-size: 25 #连接池最大连接数,默认是10 + idle-timeout: 100000 #空闲连接存活最大时间,默认600000(10分钟) + is_auto-commit: true #此属性控制从池返回的连接的默认自动提交行为,默认值:true + max-lifetime: 600000 #此属性控制池中连接的最长生命周期,值0表示无限生命周期,默认1800000即30分钟 + connection-timeout: 15000 #数据库连接超时时间,默认30秒,即30000 + connection-test-query: SELECT 1 FROM DUAL + validation-timeout: 30000 + datasource: + master: + driver-class-name: com.mysql.cj.jdbc.Driver + url: jdbc:mysql://172.26.1.2:3306/db_upsync?allowMultiQueries=true&useUnicode=true&characterEncoding=UTF-8&useSSL=false&allowPublicKeyRetrieval=true&serverTimezone=GMT%2B8 + username: tgdba + password: szTGdb@20250210 + mvc: + pathmatch: + matching-strategy: ant_path_matcher #Springfox 使用的路径匹配是基于AntPathMatcher的,而Spring Boot 2.6.X使用的是PathPatternMatcher。 + lifecycle: + timeout-per-shutdown-phase: "10s" +springfox: + documentation: + enabled: false #是否开启swagger \ No newline at end of file diff --git a/src/main/webapp/web.xml b/src/main/webapp/web.xml new file mode 100644 index 0000000..88c213a --- /dev/null +++ b/src/main/webapp/web.xml @@ -0,0 +1,6 @@ + +