commit 2f813b341859d09bf457c539be43430b164660bd Author: huanghui <2397241381@qq.com> Date: Wed Jan 31 14:19:24 2024 +0800 初始化仓库 diff --git a/README.md b/README.md new file mode 100644 index 0000000..347f78c --- /dev/null +++ b/README.md @@ -0,0 +1,105 @@ +## 后端springboot + +### 采用redis缓存 + +#### 1.pom.xml文件改动 +- 1、增加redis依赖,删除exclusions即可 +```xml + + com.anji-plus + spring-boot-gaea + 2.0.5.RELEASE + + + + org.springframework.boot + spring-boot-starter-data-redis + + + + +``` + +- 2、 删除ehcache相关依赖 +```xml + + net.sf.ehcache + ehcache + 2.10.6 + +``` + + +#### 2.删除代码 +- 1、删除cache文件夹 +目录地址:com.anjiplus.template.gaea.business.cache + +- 2、删除相关bean +文件地址:com.anjiplus.template.gaea.business.config.BusinessAutoConfiguration.java +```java + @Bean + public CacheHelper gaeaCacheHelper(){ + return new ReportCacheHelper(); + } + + @Bean + public EhCacheCache ehCacheCache() { + return (EhCacheCache) ehCacheCacheManager().getCache("reportCache"); + } + + /** + * 创建ehCacheCacheManager + */ + @Bean + public EhCacheCacheManager ehCacheCacheManager() { + + return new EhCacheCacheManager(); + } +``` + +底层的实现方式如下: +CacheHelper底层默认实现为RedisCacheHelper。 +@ConditionalOnMissingBean 注解起到的作用 +```java +package com.anji.plus.gaea; + +@Configuration +@EnableConfigurationProperties({GaeaProperties.class}) +public class GaeaAutoConfiguration { + @Bean + @ConditionalOnClass({RedisAutoConfiguration.class}) + @ConditionalOnMissingBean + public CacheHelper cacheHelper() { + return new RedisCacheHelper(); + } +} +``` + +#### 3.bootstrap.yml加上对应的redis配置 +注意yml格式 +```yaml +spring: + redis: + host: 10.108.x.x + port: 6379 + password: **** + database: 1 + timeout: 10000 + pool: + max-active: 8 + max-idle: 8 + max-wait: -1 + min-idle: 0 + +``` +哨兵模式 +```yaml +spring: + redis: + sentinel: + master: master01 + nodes: 10.108.xx.xx:26379,10.108.xx.xx:26379,10.108.xx.xx:26379 + database: 1 + password: ******* + timeout: 10000 +``` diff --git a/lib/kudu/ImpalaJDBC41-2.5.41.jar b/lib/kudu/ImpalaJDBC41-2.5.41.jar new file mode 100644 index 0000000..058a54d Binary files /dev/null and b/lib/kudu/ImpalaJDBC41-2.5.41.jar differ diff --git a/lib/kudu/hive-metastore-1.2.1.jar b/lib/kudu/hive-metastore-1.2.1.jar new file mode 100644 index 0000000..074aaf2 Binary files /dev/null and b/lib/kudu/hive-metastore-1.2.1.jar differ diff --git a/lib/kudu/hive-service-1.2.1.jar b/lib/kudu/hive-service-1.2.1.jar new file mode 100644 index 0000000..75557f9 Binary files /dev/null and b/lib/kudu/hive-service-1.2.1.jar differ diff --git a/lib/kudu/libfb303-0.9.2.jar b/lib/kudu/libfb303-0.9.2.jar new file mode 100644 index 0000000..f693b42 Binary files /dev/null and b/lib/kudu/libfb303-0.9.2.jar differ diff --git a/lib/kudu/libthrift-0.9.2.jar b/lib/kudu/libthrift-0.9.2.jar new file mode 100644 index 0000000..39143a5 Binary files /dev/null and b/lib/kudu/libthrift-0.9.2.jar differ diff --git a/lib/kudu/logback-classic-1.2.3.jar b/lib/kudu/logback-classic-1.2.3.jar new file mode 100644 index 0000000..bed00c0 Binary files /dev/null and b/lib/kudu/logback-classic-1.2.3.jar differ diff --git a/lib/kudu/logback-core-1.2.3.jar b/lib/kudu/logback-core-1.2.3.jar new file mode 100644 index 0000000..487b395 Binary files /dev/null and b/lib/kudu/logback-core-1.2.3.jar differ diff --git a/lib/kudu/slf4j-api-1.7.30.jar b/lib/kudu/slf4j-api-1.7.30.jar new file mode 100644 index 0000000..29ac26f Binary files /dev/null and b/lib/kudu/slf4j-api-1.7.30.jar differ diff --git a/lib/mssqlserver/sqljdbc4-4.0.jar b/lib/mssqlserver/sqljdbc4-4.0.jar new file mode 100644 index 0000000..d6b7f6d Binary files /dev/null and b/lib/mssqlserver/sqljdbc4-4.0.jar differ diff --git a/lib/oracle/ojdbc6-11.2.0.4.jar b/lib/oracle/ojdbc6-11.2.0.4.jar new file mode 100644 index 0000000..767eba7 Binary files /dev/null and b/lib/oracle/ojdbc6-11.2.0.4.jar differ diff --git a/lib/postgresql/postgresql-9.4.1212.jre7.jar b/lib/postgresql/postgresql-9.4.1212.jre7.jar new file mode 100644 index 0000000..36c01b5 Binary files /dev/null and b/lib/postgresql/postgresql-9.4.1212.jre7.jar differ diff --git a/pom.xml b/pom.xml new file mode 100644 index 0000000..2aa88e4 --- /dev/null +++ b/pom.xml @@ -0,0 +1,250 @@ + + + + + org.springframework.boot + spring-boot-starter-parent + 2.3.5.RELEASE + + + + BigData + 4.0.0 + + com.BigData + BigData + 1.0.1 + + + UTF-8 + -Xdoclint:none + 1.8 + 1.8 + true + + + + + + org.springframework.boot + spring-boot-starter-web + + + org.apache.logging.log4j + log4j-to-slf4j + + + + + + org.apache.logging.log4j + log4j-to-slf4j + 2.15.0 + + + + org.apache.logging.log4j + log4j-api + 2.15.0 + + + + + org.springframework.boot + spring-boot-starter-cache + + + + org.springframework.boot + spring-boot-starter-test + test + + + + org.springframework + spring-mock + 2.0.8 + + + + org.springframework.cloud + spring-cloud-context + 2.2.6.RELEASE + + + + org.springframework.boot + spring-boot-configuration-processor + true + + + + com.anji-plus + spring-boot-gaea + 2.0.5.RELEASE + + + org.springframework.boot + spring-boot-starter-data-redis + + + + + + com.anji-plus + spring-boot-starter-gaea-oss + 2.0.5.RELEASE + + + + com.baomidou + mybatis-plus-boot-starter + 3.3.2 + + + + mysql + mysql-connector-java + 8.0.28 + + + org.flywaydb + flyway-core + 5.2.1 + + + + net.sf.ehcache + ehcache + 2.10.6 + + + + org.apache.httpcomponents + httpclient + 4.5.13 + + + + org.projectlombok + lombok + 1.18.10 + true + + + + com.itextpdf + itextpdf + 5.5.13.2 + + + com.itextpdf + itext-asian + 5.2.0 + + + + org.apache.poi + poi + 4.1.2 + + + org.apache.poi + poi-ooxml + 4.1.2 + + + org.apache.poi + poi-ooxml-schemas + 4.1.2 + + + + org.codehaus.groovy + groovy + 3.0.9 + + + + org.xhtmlrenderer + core-renderer + R8 + + + + com.itextpdf.tool + xmlworker + 5.5.13 + + + + + + + develop.anji-plus.com + MS@anji-plus.com + https://github.com/anji-plus + + + + + + dev + + dev + + + true + + + + + + + + src/main/resources + true + + + + + org.springframework.boot + spring-boot-maven-plugin + + true + + + + org.apache.maven.plugins + maven-resources-plugin + + + ttf + woff + woff2 + + + + + org.apache.maven.plugins + maven-assembly-plugin + 3.3.0 + + + src/main/assembly/assembly.xml + + + + + make-assembly + package + + single + + + + + + + diff --git a/src/main/assembly/assembly.xml b/src/main/assembly/assembly.xml new file mode 100644 index 0000000..694d0b9 --- /dev/null +++ b/src/main/assembly/assembly.xml @@ -0,0 +1,62 @@ + + assembly + + zip + + + true + + + lib/mssqlserver + lib + 0755 + + + lib/kudu + lib + 0755 + + + lib/oracle + lib + 0755 + + + src/main/assembly/bin + bin + 0755 + + + src/main/resources + conf + + bootstrap.yml + + + + target + lib + + aj-report-*.jar + + + *-javadoc.jar + *-sources.jar + + 0755 + + + ./../ + / + + LICENSE + NOTICE + + + + diff --git a/src/main/assembly/bin/restart.sh b/src/main/assembly/bin/restart.sh new file mode 100644 index 0000000..9a5e416 --- /dev/null +++ b/src/main/assembly/bin/restart.sh @@ -0,0 +1,5 @@ +#!/bin/bash +cd `dirname $0` +./stop.sh +./start.sh + diff --git a/src/main/assembly/bin/start.bat b/src/main/assembly/bin/start.bat new file mode 100644 index 0000000..e0650a8 --- /dev/null +++ b/src/main/assembly/bin/start.bat @@ -0,0 +1,42 @@ +@echo off & setlocal enabledelayedexpansion + +rem 判断cmd中是否有JAVA_HOME +rem set JAVA_HOME=D:\App\Java\jdk1.8.0_172 +IF "%JAVA_HOME%" == "" ( + goto END +) ELSE ( + goto START +) + +:END + rem cmd中未找到JAVA_HOME,请在此启动文件中第4行指定,然后尝试 + echo Not JAVA_HOME Find, Please add JAVA_HOME in this file line 4 + pause + exit + +:START + rem 获取应用的根目录 + cd ../ + set BIN_DIR=%cd% + set CONF_YML=%BIN_DIR%\conf\bootstrap.yml + + cd %BIN_DIR%\lib + rem 查找aj-report*.jar启动文件,版本号每次会变 + for /f "delims=" %%i in ('dir /a-d /b /on aj-report*.jar') do ( + set BOOT_JAR=%%i + ) + + rem 查找附加的驱动,加到java启动的classpath中 + for %%i in ("*") do ( + if "%%i" neq "%BOOT_JAR%" ( + set LIB_JARS=!LIB_JARS!%BIN_DIR%\lib\%%i; + ) + ) + + rem 启动内存设置,请根据自己需要调整 + cd %BIN_DIR%\bin + set JAVA_OPTS= -server -Xms1g -Xmx2g -Xmn256m -XX:PermSize=128m -Xss256k + + rem 正式启动 + "%JAVA_HOME%"\bin\java %JAVA_OPTS% -Xbootclasspath/a:%LIB_JARS% -jar -Dspring.config.location=%CONF_YML% %BIN_DIR%\lib\%BOOT_JAR% + pause diff --git a/src/main/assembly/bin/start.sh b/src/main/assembly/bin/start.sh new file mode 100644 index 0000000..6287380 --- /dev/null +++ b/src/main/assembly/bin/start.sh @@ -0,0 +1,26 @@ +#!/bin/bash + +#判断java是否存在 +command -v java >/dev/null 2>&1 || { echo >&2 "require java but it's not installed. Aborting."; sleep 5;exit 1; } + +cd `dirname $0` +BIN_DIR=`pwd` #安装目录 +cd ../ +DEPLOY_DIR=`pwd` +LIB_DIR=$DEPLOY_DIR/lib #jar目录 +CONF_DIR=$DEPLOY_DIR/conf #conf目录 +LOGS_DIR=$DEPLOY_DIR/logs #log目录 + +LIB_JARS=`ls $LIB_DIR|grep -v aj-report|awk '{print "'$LIB_DIR'/"$0}'|tr "\n" ":"` + +PIDS=`ps -f | grep java | grep "aj-report" |awk '{print $2}'` +if [ -n "$PIDS" ]; then + echo "ERROR: The AJ-Report already started!" + echo "PID: $PIDS" + exit 1 +fi + +JAVA_OPTS=" -server -Xms1g -Xmx2g -Xmn256m -XX:PermSize=128m -Xss256k " +nohup java $JAVA_OPTS -Xbootclasspath/a:$LIB_JARS -jar -Dspring.config.location=$CONF_DIR/bootstrap.yml $LIB_DIR/aj-report-*.jar >/dev/null 2>&1 & + +echo "AJ-Report 正在后台执行,请查看aj-report.log日志(${DEPLOY_DIR}/logs/aj-report.log),确定软件运行情况" diff --git a/src/main/assembly/bin/stop.sh b/src/main/assembly/bin/stop.sh new file mode 100644 index 0000000..c6ca5d5 --- /dev/null +++ b/src/main/assembly/bin/stop.sh @@ -0,0 +1,12 @@ +#!/bin/bash +pid=`ps ax | grep -i 'aj-report' | grep java | grep -v grep | awk '{print $1}'` +if [ -z "$pid" ] ; then + echo "No AJ-Report Server running." + exit -1; +fi + +kill -9 ${pid} + +echo "Send shutdown request to aj-reporte(${pid}) OK" + + diff --git a/src/main/java/com/anjiplus/template/gaea/business/ReportApplication.java b/src/main/java/com/anjiplus/template/gaea/business/ReportApplication.java new file mode 100644 index 0000000..c0b5a0d --- /dev/null +++ b/src/main/java/com/anjiplus/template/gaea/business/ReportApplication.java @@ -0,0 +1,29 @@ +package com.anjiplus.template.gaea.business; + +import com.anji.plus.gaea.annotation.enabled.EnabledGaeaConfiguration; +import org.mybatis.spring.annotation.MapperScan; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import springfox.documentation.swagger2.annotations.EnableSwagger2; + +/** + * 业务模板 + * @author lr + * @since 2021-02-03 + */ +@EnabledGaeaConfiguration +@SpringBootApplication(scanBasePackages = { + "com.anjiplus.template.gaea", + "com.anji.plus" +}) +@MapperScan(basePackages = { + "com.anjiplus.template.gaea.business.modules.*.dao", + "com.anjiplus.template.gaea.business.modules.*.**.dao", + "com.anji.plus.gaea.*.module.*.dao" +}) +@EnableSwagger2 +public class ReportApplication { + public static void main( String[] args ) { + SpringApplication.run(ReportApplication.class); + } +} diff --git a/src/main/java/com/anjiplus/template/gaea/business/base/BaseController.java b/src/main/java/com/anjiplus/template/gaea/business/base/BaseController.java new file mode 100644 index 0000000..0052d6c --- /dev/null +++ b/src/main/java/com/anjiplus/template/gaea/business/base/BaseController.java @@ -0,0 +1,25 @@ +package com.anjiplus.template.gaea.business.base; + +import org.springframework.context.i18n.LocaleContextHolder; + +import com.anji.plus.gaea.curd.controller.GaeaBaseController; +import com.anji.plus.gaea.curd.dto.BaseDTO; +import com.anji.plus.gaea.curd.entity.BaseEntity; +import com.anji.plus.gaea.curd.params.PageParam; + +/** + * 项目级的Controller公共处理基类 + * + * @author WongBin + * @date 2021/3/26 + */ +public abstract class BaseController

+ extends GaeaBaseController { + /** + * 获取当前语言类型 + * @return + */ + public String getI18nLang(){ + return LocaleContextHolder.getLocale().getLanguage(); + } +} diff --git a/src/main/java/com/anjiplus/template/gaea/business/base/BaseService.java b/src/main/java/com/anjiplus/template/gaea/business/base/BaseService.java new file mode 100644 index 0000000..6808cb9 --- /dev/null +++ b/src/main/java/com/anjiplus/template/gaea/business/base/BaseService.java @@ -0,0 +1,15 @@ +package com.anjiplus.template.gaea.business.base; + +import com.anji.plus.gaea.curd.entity.BaseEntity; +import com.anji.plus.gaea.curd.params.PageParam; +import com.anji.plus.gaea.curd.service.GaeaBaseService; +import org.springframework.context.i18n.LocaleContextHolder; + +/** + * 项目级的Service公共处理基类 + * @author WongBin + * @date 2021/3/26 + */ +public interface BaseService

extends GaeaBaseService { + +} diff --git a/src/main/java/com/anjiplus/template/gaea/business/base/HealthController.java b/src/main/java/com/anjiplus/template/gaea/business/base/HealthController.java new file mode 100644 index 0000000..63a5c64 --- /dev/null +++ b/src/main/java/com/anjiplus/template/gaea/business/base/HealthController.java @@ -0,0 +1,21 @@ +package com.anjiplus.template.gaea.business.base; + +import com.anji.plus.gaea.bean.ResponseBean; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RestController; + +/** + * @desc 用户管理 controller + * @author 木子李·De + * @date 2019-02-17 08:50:11.902 + **/ +@RestController +public class HealthController { + + @GetMapping("health") + public ResponseBean health() { + return ResponseBean.builder().build(); + } + +} diff --git a/src/main/java/com/anjiplus/template/gaea/business/cache/ReportCacheHelper.java b/src/main/java/com/anjiplus/template/gaea/business/cache/ReportCacheHelper.java new file mode 100644 index 0000000..7cb03a5 --- /dev/null +++ b/src/main/java/com/anjiplus/template/gaea/business/cache/ReportCacheHelper.java @@ -0,0 +1,150 @@ +package com.anjiplus.template.gaea.business.cache; + + +import com.anji.plus.gaea.cache.CacheHelper; +import com.google.common.collect.Maps; +import org.springframework.beans.BeansException; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.cache.Cache; +import org.springframework.context.ApplicationContext; +import org.springframework.context.ApplicationContextAware; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; + +public class ReportCacheHelper implements CacheHelper, ApplicationContextAware { + + @Autowired + private Cache cache; + + @Override + public String stringGet(String key) { + Cache.ValueWrapper valueWrapper = cache.get(key); + if (valueWrapper != null) { + return (String) valueWrapper.get(); + } + return CacheHelper.super.stringGet(key); + } + + @Override + public Boolean setIfAbsent(String key, String value) { + cache.putIfAbsent(key, value); + return true; + } + + + @Override + public boolean exist(String key) { + String cacheHoldTime = stringGet(key + "_HoldTime"); + if (cacheHoldTime != null && Long.parseLong(cacheHoldTime) > 0) { + if (Long.parseLong(cacheHoldTime) < System.currentTimeMillis()) { + delete(key + "_HoldTime"); + delete(key); + return false; + } + } + return cache.get(key) != null; + } + + + @Override + public void stringSet(String key, String value) { + cache.put(key, value); + } + + + @Override + public String regKey(String key) { + return CacheHelper.super.regKey(key); + } + + @Override + public void stringSetExpire(String key, String value, long seconds) { + stringSet(key, value); + if (seconds > 0) { + //缓存失效时间 + stringSet(key + "_HoldTime", String.valueOf(System.currentTimeMillis() + seconds * 1000)); + } + } + + @Override + public Map hashGet(String key) { + Cache.ValueWrapper t = cache.get(key); + if (t != null) { + return (Map) t.get(); + } + return Maps.newHashMap(); + } + + @Override + public String hashGetString(String key, String hashKey) { + Map stringStringMap = hashGet(key); + return stringStringMap.get(hashKey); + } + + @Override + public void hashDel(String key, String hashKey) { + Map stringStringMap = hashGet(key); + stringStringMap.remove(hashKey); + } + + @Override + public void hashBatchDel(String key, Set hashKeys) { + Map stringStringMap = hashGet(key); + hashKeys.forEach(stringStringMap::remove); + } + + @Override + public boolean hashExist(String key, String hashKey) { + if (exist(key)) { + Map map = hashGet(key); + return map.containsKey(hashKey); + } + return false; + } + + @Override + public boolean hashAnyExist(String key, String[] hashKeys) { + return CacheHelper.super.hashAnyExist(key, hashKeys); + } + + @Override + public void hashSet(String key, String hashKey, String hashValue) { + Map map; + if (exist(key)) { + map = hashGet(key); + } else { + map = new HashMap<>(); + } + map.put(hashKey, hashValue); + hashSet(key, map); + } + + @Override + public void hashSet(String key, Map hash) { + cache.put(key, hash); + } + + @Override + public boolean delete(String key) { + if (exist(key)) { + cache.evict(key); + } + return true; + } + + @Override + public boolean delete(List keys) { + keys.forEach(this::delete); + return true; + } + + + @Override + public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { + /*基于内存的本地缓存*/ + cache = (Cache) applicationContext.getBean("ehCacheCache"); + } +} diff --git a/src/main/java/com/anjiplus/template/gaea/business/code/ResponseCode.java b/src/main/java/com/anjiplus/template/gaea/business/code/ResponseCode.java new file mode 100644 index 0000000..0cefc8b --- /dev/null +++ b/src/main/java/com/anjiplus/template/gaea/business/code/ResponseCode.java @@ -0,0 +1,139 @@ +package com.anjiplus.template.gaea.business.code; + +/** + * 响应码 + * @author lr + * @since 2021-02-22 + */ +public interface ResponseCode { + + String NOT_NULL = "field.not.null"; + String NOT_EMPTY = "field.not.empty"; + String MIN = "field.min"; + String MAX = "field.max"; + String DICT_ERROR = "field.dict.error"; + + String USER_PASSWORD_ERROR = "User.password.error"; + /** + * 用户名或者密码不正确 + */ + String LOGIN_ERROR = "login.error"; + + /** + * 新密码不能和原密码一致 + */ + String USER_PASSWORD_CONFIG_PASSWORD_CANOT_EQUAL = "user.password.config.password.canot.equal"; + + /** + * 密码和确认密码不一致 + */ + String USER_INCONSISTENT_PASSWORD_ERROR = "user.inconsistent.password.error"; + + /** + * 旧密码不正确 + */ + String USER_OLD_PASSWORD_ERROR = "user.old.password.error"; + + + + /** + * 用户token过期 + */ + String USER_TOKEN_EXPIRED = "User.token.expired"; + + /** + * 字典项重复 + */ + String DICT_ITEM_REPEAT = "Dict.item.code.exist"; + + /** + * 数字字典国际化标识不能为null + */ + String DICT_CODE_LOCALE_NULL = "500-00002"; + + /** + * 参数为空 + */ + String PARAM_IS_NULL = "Rule.execute.param.null"; + + /** + * 规则编译不通过 + */ + String RULE_CONTENT_COMPILE_ERROR = "Rule.content.compile.error"; + + /** + * 规则执行不通过 + */ + String RULE_CONTENT_EXECUTE_ERROR = "Rule.content.execute.error"; + + /** + * 规则编码已存在 + */ + String RULE_CODE_EXIST = "Rule.code.exist"; + + /** + * 对应规则内容不存在 + */ + String RULE_CONTENT_NOT_EXIST = "Rule.content.not.exist"; + + /** + * 对应规则字段值不存在 + */ + String RULE_FIELDS_NOT_EXIST = "Rule.fields.not.exist"; + + /** + * 规则字段必填 + */ + String RULE_FIELD_VALUE_IS_REQUIRED = "Rule.field.value.is.required"; + + /** + * 规则字段值类型错误 + */ + String RULE_FIELD_VALUE_TYPE_ERROR = "Rule.field.value.type.error"; + + /** + * 规则参数校验不通过 + */ + String RULE_FIELDS_CHECK_ERROR = "Rule.fields.check.error"; + /** + * 组件未加载 + */ + String COMPONENT_NOT_LOAD = "Component.load.check.error"; + + String AUTH_PASSWORD_NOTSAME = "1001"; + String OLD_PASSWORD_ERROR = "1003"; + String USER_ONTEXIST_ORGINFO = "1004"; + String USER_ONTEXIST_ROLEINFO = "1005"; + String MENU_TABLE_CODE_EXIST = "1006"; + String USER_CODE_ISEXIST = "1007"; + String ROLE_CODE_ISEXIST = "1008"; + String MENU_CODE_ISEXIST = "1009"; + String ORG_CODE_ISEXIST = "1010"; + String SEARCHNAME_ISEXIST = "1011"; + String SETTINGNAME_ISEXIST = "1012"; + String DICCODE_ISEXIST = "1013"; + String DEVICEID_LENGTH = "1014"; + String USERINFO_EMPTY = "1015"; + String FILE_EMPTY_FILENAME = "2001"; + String FILE_SUFFIX_UNSUPPORTED = "2002"; + String FILE_UPLOAD_ERROR = "2003"; + String FILE_ONT_EXSIT = "2004"; + String FILE_OPERATION_FAILED = "file.operation.failed"; + + String PUSHCODE_NEED_UNIQUE = "3001"; + String RECEIVER_IS_EMPTY = "3002"; + String DATA_SOURCE_CONNECTION_FAILED = "4001"; + String DATA_SOURCE_TYPE_DOES_NOT_MATCH_TEMPORARILY = "4002"; + String EXECUTE_SQL_ERROR = "4003"; + String INCOMPLETE_PARAMETER_REPLACEMENT_VALUES = "4004"; + String EXECUTE_JS_ERROR = "4005"; + String ANALYSIS_DATA_ERROR = "4006"; + String REPORT_CODE_ISEXIST = "4007"; + String SET_CODE_ISEXIST = "4008"; + String SOURCE_CODE_ISEXIST = "4009"; + String CLASS_NOT_FOUND = "4010"; + String EXECUTE_GROOVY_ERROR = "4011"; + + String REPORT_SHARE_LINK_INVALID = "report.share.link.invalid"; + +} diff --git a/src/main/java/com/anjiplus/template/gaea/business/config/BusinessAutoConfiguration.java b/src/main/java/com/anjiplus/template/gaea/business/config/BusinessAutoConfiguration.java new file mode 100644 index 0000000..a5fbff0 --- /dev/null +++ b/src/main/java/com/anjiplus/template/gaea/business/config/BusinessAutoConfiguration.java @@ -0,0 +1,51 @@ +package com.anjiplus.template.gaea.business.config; + +import com.anji.plus.gaea.cache.CacheHelper; +import com.anjiplus.template.gaea.business.cache.ReportCacheHelper; +import com.anjiplus.template.gaea.business.runner.ApplicationInitRunner; +import org.mybatis.spring.annotation.MapperScan; +import org.springframework.cache.ehcache.EhCacheCache; +import org.springframework.cache.ehcache.EhCacheCacheManager; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +/** + * business配置类 + * @author lr + * @since 2021-04-08 + */ +@Configuration +@MapperScan(basePackages = { + "com.anjiplus.template.gaea.business.modules.*.dao", + "com.anjiplus.template.gaea.business.modules.*.**.dao" +}) +public class BusinessAutoConfiguration { + + /** + * 系统启动完执行 + * @return + */ + @Bean + public ApplicationInitRunner applicationInitRunner() { + return new ApplicationInitRunner(); + } + + @Bean + public CacheHelper gaeaCacheHelper(){ + return new ReportCacheHelper(); + } + + @Bean + public EhCacheCache ehCacheCache() { + return (EhCacheCache) ehCacheCacheManager().getCache("reportCache"); + } + + /** + * 创建ehCacheCacheManager + */ + @Bean + public EhCacheCacheManager ehCacheCacheManager() { + + return new EhCacheCacheManager(); + } +} diff --git a/src/main/java/com/anjiplus/template/gaea/business/config/DatabaseInitializer.java b/src/main/java/com/anjiplus/template/gaea/business/config/DatabaseInitializer.java new file mode 100644 index 0000000..129c42d --- /dev/null +++ b/src/main/java/com/anjiplus/template/gaea/business/config/DatabaseInitializer.java @@ -0,0 +1,56 @@ +package com.anjiplus.template.gaea.business.config; + +import com.zaxxer.hikari.HikariDataSource; +import lombok.AllArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.boot.autoconfigure.flyway.FlywayProperties; +import org.springframework.boot.autoconfigure.jdbc.DataSourceProperties; +import org.springframework.stereotype.Component; + +import javax.annotation.PostConstruct; +import java.sql.Connection; +import java.sql.SQLException; +import java.sql.Statement; + +/** + * Created by raodeming on 2021/7/5. + */ +@Slf4j +@Component +@AllArgsConstructor +@ConditionalOnProperty(value = {"spring.flyway.enabled"}) +public class DatabaseInitializer { + + private final FlywayProperties flywayProperties; + private final DataSourceProperties dataSourceProperties; + + @PostConstruct + public void init() throws SQLException { + log.info("DatabaseInitializer uses flyway init-sqls to initiate database"); + String url = dataSourceProperties.getUrl(); + // jdbc url最后一个 '/' 用于分割具体 schema?参数 + int lastSplitIndex = url.lastIndexOf('?'); + // 获取spring.datasource.url具体数据库schema前的jdbc url + String addressUrl = url.substring(0, lastSplitIndex); + String addresslast = url.substring(lastSplitIndex); + addressUrl = addressUrl.substring(0, addressUrl.lastIndexOf("/")); + // 直连数据库地址:jdbc:mysql://yourIp:port + HikariDataSource dataSource = new HikariDataSource(); + dataSource.setJdbcUrl(addressUrl.concat(addresslast)); + dataSource.setUsername(dataSourceProperties.getUsername()); + dataSource.setPassword(dataSourceProperties.getPassword()); + Connection connection = dataSource.getConnection(); + Statement statement = connection.createStatement(); + for (String sql : flywayProperties.getInitSqls()) { + // 通过flyway的init-sqls配置进行建库与数据库配置 + // executeUpdate:执行给定的SQL语句,该语句可以是INSERT,UPDATE或DELETE语句或不返回任何内容的SQL语句,例如SQL DDL语句。 + statement.executeUpdate(sql); + } + statement.close(); + connection.close(); + dataSource.close(); + log.info("DatabaseInitializer initialize completed"); + } + +} diff --git a/src/main/java/com/anjiplus/template/gaea/business/config/HikariPoolProperties.java b/src/main/java/com/anjiplus/template/gaea/business/config/HikariPoolProperties.java new file mode 100644 index 0000000..91d3a5d --- /dev/null +++ b/src/main/java/com/anjiplus/template/gaea/business/config/HikariPoolProperties.java @@ -0,0 +1,34 @@ +package com.anjiplus.template.gaea.business.config; + +import com.zaxxer.hikari.HikariConfig; +import com.zaxxer.hikari.pool.HikariPool; +import lombok.Data; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.stereotype.Component; + +/** + * Created by raodeming on 2021/8/6. + */ +@Component +@ConfigurationProperties(prefix = "spring.datasource.hikari") +@Data +public class HikariPoolProperties extends HikariConfig { + + + public HikariPool dataSource(String url, String username, String password, String driverClassName) { + HikariConfig hikariConfig = new HikariConfig(); + hikariConfig.setJdbcUrl(url); + hikariConfig.setUsername(username); + hikariConfig.setPassword(password); + hikariConfig.setDriverClassName(driverClassName); + + hikariConfig.setConnectionTimeout(getConnectionTimeout()); + hikariConfig.setValidationTimeout(getValidationTimeout()); + hikariConfig.setIdleTimeout(getIdleTimeout()); + hikariConfig.setMaxLifetime(getMaxLifetime()); + hikariConfig.setMaximumPoolSize(getMaximumPoolSize()); + hikariConfig.setMinimumIdle(getMinimumIdle()); + HikariPool hikariPool = new HikariPool(hikariConfig); + return hikariPool; + } +} diff --git a/src/main/java/com/anjiplus/template/gaea/business/constant/BusinessConstant.java b/src/main/java/com/anjiplus/template/gaea/business/constant/BusinessConstant.java new file mode 100644 index 0000000..4e2aa8f --- /dev/null +++ b/src/main/java/com/anjiplus/template/gaea/business/constant/BusinessConstant.java @@ -0,0 +1,39 @@ +package com.anjiplus.template.gaea.business.constant; + +/** + * 常量 + * @author lr + * @since 2021-03-26 + */ +public interface BusinessConstant { + + String LEFT_BIG_BOAST = "{"; + String RIGTH_BIG_BOAST = "}"; + String LEFT_MIDDLE_BOAST = "["; + String RIGHT_MIDDLE_BOAST = "]"; + String SLASH = "/"; + + String USER_GUEST = "guest"; + String USER_ADMIN = "admin"; + + + /** + * 字典项重复 + */ + String DICT_ITEM_EXIST_GROUP = "dictItemExist"; + + /** + * 所有url的权限码缓存key + */ + String GAEA_SECURITY_AUTHORITIES= "gaea:security:authorities:all"; + + /** + * 用户登录的token缓存key + */ + String GAEA_SECURITY_LOGIN_TOKEN = "gaea:security:login:token:%s"; + + /** + * 用户登录的主信息缓存信息 + */ + String GAEA_SECURITY_LOGIN_USER = "gaea:security:login:user:%s"; +} diff --git a/src/main/java/com/anjiplus/template/gaea/business/enums/DeleteFlagEnum.java b/src/main/java/com/anjiplus/template/gaea/business/enums/DeleteFlagEnum.java new file mode 100644 index 0000000..a883408 --- /dev/null +++ b/src/main/java/com/anjiplus/template/gaea/business/enums/DeleteFlagEnum.java @@ -0,0 +1,47 @@ +package com.anjiplus.template.gaea.business.enums; +public enum DeleteFlagEnum { + DELETED(1,"已删除"), + UNDELETED(0,"未删除"), + ; + + private int codeValue; + private String codeDesc; + + private DeleteFlagEnum(int codeValue, String codeDesc) { + this.codeValue = codeValue; + this.codeDesc = codeDesc; + } + + public int getCodeValue(){ return this.codeValue;} + + public String getCodeDesc(){ return this.codeDesc;} + + //根据codeValue获取枚举 + public static DeleteFlagEnum parseFromCodeValue(int codeValue){ + for (DeleteFlagEnum e : DeleteFlagEnum.values()){ + if(e.codeValue == codeValue){ return e;} + } + return null; + } + + //根据codeValue获取描述 + public static String getCodeDescByCodeValue(int codeValue){ + DeleteFlagEnum enumItem = parseFromCodeValue(codeValue); + return enumItem == null ? "" : enumItem.getCodeDesc(); + } + + //验证codeValue是否有效 + public static boolean validateCodeValue(int codeValue){ return parseFromCodeValue(codeValue)!=null;} + + //列出所有值字符串 + public static String getString(){ + StringBuffer buffer = new StringBuffer(); + for (DeleteFlagEnum e : DeleteFlagEnum.values()){ + buffer.append(e.codeValue).append("--").append(e.getCodeDesc()).append(", "); + } + buffer.deleteCharAt(buffer.lastIndexOf(",")); + return buffer.toString().trim(); + } + + +} diff --git a/src/main/java/com/anjiplus/template/gaea/business/enums/EnableFlagEnum.java b/src/main/java/com/anjiplus/template/gaea/business/enums/EnableFlagEnum.java new file mode 100644 index 0000000..5d4b207 --- /dev/null +++ b/src/main/java/com/anjiplus/template/gaea/business/enums/EnableFlagEnum.java @@ -0,0 +1,47 @@ +package com.anjiplus.template.gaea.business.enums; +public enum EnableFlagEnum { + ENABLE(1,"启用"), + DISABLE(0,"禁用"), + ; + + private int codeValue; + private String codeDesc; + + private EnableFlagEnum(int codeValue, String codeDesc) { + this.codeValue = codeValue; + this.codeDesc = codeDesc; + } + + public int getCodeValue(){ return this.codeValue;} + + public String getCodeDesc(){ return this.codeDesc;} + + //根据codeValue获取枚举 + public static EnableFlagEnum parseFromCodeValue(int codeValue){ + for (EnableFlagEnum e : EnableFlagEnum.values()){ + if(e.codeValue == codeValue){ return e;} + } + return null; + } + + //根据codeValue获取描述 + public static String getCodeDescByCodeBalue(int codeValue){ + EnableFlagEnum enumItem = parseFromCodeValue(codeValue); + return enumItem == null ? "" : enumItem.getCodeDesc(); + } + + //验证codeValue是否有效 + public static boolean validateCodeValue(int codeValue){ return parseFromCodeValue(codeValue)!=null;} + + //列出所有值字符串 + public static String getString(){ + StringBuffer buffer = new StringBuffer(); + for (EnableFlagEnum e : EnableFlagEnum.values()){ + buffer.append(e.codeValue).append("--").append(e.getCodeDesc()).append(", "); + } + buffer.deleteCharAt(buffer.lastIndexOf(",")); + return buffer.toString().trim(); + } + + +} diff --git a/src/main/java/com/anjiplus/template/gaea/business/enums/ExcelCenterStyleEnum.java b/src/main/java/com/anjiplus/template/gaea/business/enums/ExcelCenterStyleEnum.java new file mode 100644 index 0000000..b0efbc6 --- /dev/null +++ b/src/main/java/com/anjiplus/template/gaea/business/enums/ExcelCenterStyleEnum.java @@ -0,0 +1,73 @@ +package com.anjiplus.template.gaea.business.enums; + +/** + * @author zhouhang + * @description EXCEL居中方式 + * @date 2021/4/26 + */ +public enum ExcelCenterStyleEnum { + /** + * 左对齐 + */ + LEFT((short) 1, 1, "左对齐"), + /** + * 右对齐 + */ + RIGHT((short) 3, 2, "右对齐"), + /** + * 居中 + */ + CENTER((short) 2, 0, "居中"), + ; + + /** + * excel居中code + */ + private final short excelCode; + + /** + * 在线文档居中code + */ + private final Integer onlineExcelCode; + + /** + * 名称 + */ + private final String name; + + + public Integer getOnlineExcelCode() { + return onlineExcelCode; + } + + public String getName() { + return name; + } + + public short getExcelCode() { + return excelCode; + } + + ExcelCenterStyleEnum(short excelCode, Integer onlineExcelCode, String name) { + this.excelCode = excelCode; + this.onlineExcelCode = onlineExcelCode; + this.name = name; + } + + /** + * @param code excel居中样式code + * @return Enum_ExcelCenterStyle + * @description 根据excel居中样式获取在线文档居中样式 + * @author zhouhang + * @date 2021/4/26 + */ + public static ExcelCenterStyleEnum getExcelCenterStyleByExcelCenterCode(short code) { + for (ExcelCenterStyleEnum value : ExcelCenterStyleEnum.values()) { + if (code == value.getExcelCode()) { + return value; + } + } + return CENTER; + } + +} diff --git a/src/main/java/com/anjiplus/template/gaea/business/enums/ExportTypeEnum.java b/src/main/java/com/anjiplus/template/gaea/business/enums/ExportTypeEnum.java new file mode 100644 index 0000000..6b01a17 --- /dev/null +++ b/src/main/java/com/anjiplus/template/gaea/business/enums/ExportTypeEnum.java @@ -0,0 +1,30 @@ +package com.anjiplus.template.gaea.business.enums; + +/** + * Created by raodeming on 2021/9/3. + */ +public enum ExportTypeEnum { + + /**gaea_excel*/ + GAEA_TEMPLATE_EXCEL("gaea_template_excel", "gaea_template_excel"), + /**gaea_pdf*/ + GAEA_TEMPLATE_PDF("gaea_template_pdf", "gaea_template_pdf"), + ; + + private String codeValue; + private String codeDesc; + + private ExportTypeEnum(String codeValue, String codeDesc) { + this.codeValue = codeValue; + this.codeDesc = codeDesc; + } + + public String getCodeValue() { + return this.codeValue; + } + + public String getCodeDesc() { + return this.codeDesc; + } + +} diff --git a/src/main/java/com/anjiplus/template/gaea/business/enums/ReportTypeEnum.java b/src/main/java/com/anjiplus/template/gaea/business/enums/ReportTypeEnum.java new file mode 100644 index 0000000..f2d267a --- /dev/null +++ b/src/main/java/com/anjiplus/template/gaea/business/enums/ReportTypeEnum.java @@ -0,0 +1,33 @@ +package com.anjiplus.template.gaea.business.enums; + +/** + * Created by raodeming on 2022/5/8. + */ +public enum ReportTypeEnum { + + /**report_screen*/ + report_screen("report_screen", "大屏报表"), + /**report_excel*/ + report_excel("report_excel", "excel报表"), + ; + + private String codeValue; + private String codeDesc; + + ReportTypeEnum() { + } + + private ReportTypeEnum(String codeValue, String codeDesc) { + this.codeValue = codeValue; + this.codeDesc = codeDesc; + } + + public String getCodeValue() { + return this.codeValue; + } + + public String getCodeDesc() { + return this.codeDesc; + } + +} diff --git a/src/main/java/com/anjiplus/template/gaea/business/enums/SetTypeEnum.java b/src/main/java/com/anjiplus/template/gaea/business/enums/SetTypeEnum.java new file mode 100644 index 0000000..a0242f3 --- /dev/null +++ b/src/main/java/com/anjiplus/template/gaea/business/enums/SetTypeEnum.java @@ -0,0 +1,56 @@ +package com.anjiplus.template.gaea.business.enums; + +public enum SetTypeEnum { + SQL("sql", "sql"), + HTTP("http", "http"), + ; + + private String codeValue; + private String codeDesc; + + private SetTypeEnum(String codeValue, String codeDesc) { + this.codeValue = codeValue; + this.codeDesc = codeDesc; + } + + public String getCodeValue() { + return this.codeValue; + } + + public String getCodeDesc() { + return this.codeDesc; + } + + //根据codeValue获取枚举 + public static SetTypeEnum parseFromCodeValue(String codeValue) { + for (SetTypeEnum e : SetTypeEnum.values()) { + if (e.codeValue == codeValue) { + return e; + } + } + return null; + } + + //根据codeValue获取描述 + public static String getCodeDescByCodeBalue(String codeValue) { + SetTypeEnum enumItem = parseFromCodeValue(codeValue); + return enumItem == null ? "" : enumItem.getCodeDesc(); + } + + //验证codeValue是否有效 + public static boolean validateCodeValue(String codeValue) { + return parseFromCodeValue(codeValue) != null; + } + + //列出所有值字符串 + public static String getString() { + StringBuffer buffer = new StringBuffer(); + for (SetTypeEnum e : SetTypeEnum.values()) { + buffer.append(e.codeValue).append("--").append(e.getCodeDesc()).append(", "); + } + buffer.deleteCharAt(buffer.lastIndexOf(",")); + return buffer.toString().trim(); + } + + +} diff --git a/src/main/java/com/anjiplus/template/gaea/business/filter/CorsFilter.java b/src/main/java/com/anjiplus/template/gaea/business/filter/CorsFilter.java new file mode 100644 index 0000000..243a7fd --- /dev/null +++ b/src/main/java/com/anjiplus/template/gaea/business/filter/CorsFilter.java @@ -0,0 +1,43 @@ +package com.anjiplus.template.gaea.business.filter; + +import org.springframework.core.Ordered; +import org.springframework.core.annotation.Order; +import org.springframework.stereotype.Component; + +import javax.servlet.*; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; + +/** + * Created by raodeming on 2021/6/24. + */ +@Component +@Order(Ordered.HIGHEST_PRECEDENCE) +public class CorsFilter implements Filter { + + @Override + public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) + throws IOException, ServletException { + HttpServletRequest req = (HttpServletRequest) request; + HttpServletResponse res = (HttpServletResponse) response; + // 设置允许Cookie + res.addHeader("Access-Control-Allow-Credentials", "true"); + // 允许http://www.xxx.com域(自行设置,这里只做示例)发起跨域请求 + res.addHeader("Access-Control-Allow-Origin", req.getHeader("Origin")); + // 设置允许跨域请求的方法 + res.addHeader("Access-Control-Allow-Methods", "*"); + // 允许跨域请求包含content-type + res.addHeader("Access-Control-Allow-Headers", "*"); + res.addHeader("Access-Control-Expose-Headers", "*"); + chain.doFilter(req, res); + } + + @Override + public void destroy() { + } + + @Override + public void init(FilterConfig filterConfig) throws ServletException { + } +} diff --git a/src/main/java/com/anjiplus/template/gaea/business/filter/TokenFilter.java b/src/main/java/com/anjiplus/template/gaea/business/filter/TokenFilter.java new file mode 100644 index 0000000..b9214f6 --- /dev/null +++ b/src/main/java/com/anjiplus/template/gaea/business/filter/TokenFilter.java @@ -0,0 +1,245 @@ +package com.anjiplus.template.gaea.business.filter; + +import com.alibaba.fastjson.JSONObject; +import com.anji.plus.gaea.bean.ResponseBean; +import com.anji.plus.gaea.cache.CacheHelper; +import com.anji.plus.gaea.constant.GaeaConstant; +import com.anji.plus.gaea.utils.JwtBean; +import com.anjiplus.template.gaea.business.constant.BusinessConstant; +import com.anjiplus.template.gaea.business.modules.accessuser.controller.dto.GaeaUserDto; +import com.anjiplus.template.gaea.business.util.JwtUtil; +import org.apache.commons.lang3.StringUtils; +import org.apache.http.entity.ContentType; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.core.annotation.Order; +import org.springframework.stereotype.Component; +import org.springframework.util.AntPathMatcher; + +import javax.servlet.*; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.regex.Pattern; + +import static com.anji.plus.gaea.constant.GaeaConstant.URL_REPLACEMENT; + +/** + * 简单的鉴权 + * @author raodeming + * @date 2021/6/24. + */ +@Component +@Order(Integer.MIN_VALUE + 99) +public class TokenFilter implements Filter { + private static final Pattern PATTERN = Pattern.compile(".*().*"); + + @Value("${server.servlet.context-path:/}") + private String SLASH = "/"; + private AntPathMatcher antPathMatcher = new AntPathMatcher(); + + @Autowired + private CacheHelper cacheHelper; + @Autowired + private JwtBean jwtBean; + + /** + * 跳过token验证和权限验证的url清单 + */ + @Value("#{'${customer.skip-authenticate-urls:}'.split(',')}") + private List skipAuthenticateUrls; + private Pattern skipAuthenticatePattern; + + @Override + public void init(FilterConfig filterConfig) throws ServletException { + // 生成匹配正则,跳过token验证和权限验证的url + skipAuthenticatePattern = fitByList(skipAuthenticateUrls); + Filter.super.init(filterConfig); + } + + @Override + public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { + HttpServletRequest request = (HttpServletRequest) servletRequest; + HttpServletResponse response = (HttpServletResponse) servletResponse; + String uri = request.getRequestURI(); + + // TODO 暂时先不校验 直接放行 + /*if (true) { + filterChain.doFilter(request, response); + return; + }*/ + + //OPTIONS直接放行 + if ("OPTIONS".equalsIgnoreCase(request.getMethod())) { + filterChain.doFilter(request, response); + return; + } + + // swagger相关的直接放行 + if (uri.contains("swagger-ui") || uri.contains("swagger-resources")) { + filterChain.doFilter(request, response); + return; + } + + + if (SLASH.equals(uri) || SLASH.concat(BusinessConstant.SLASH).equals(uri)) { + if (BusinessConstant.SLASH.equals(uri)) { + response.sendRedirect("/index.html"); + return; + } + response.sendRedirect(SLASH + "/index.html"); + return; + } + + // 不需要token验证和权限验证的url,直接放行 + boolean skipAuthenticate = skipAuthenticatePattern.matcher(uri).matches(); + if (skipAuthenticate) { + filterChain.doFilter(request, response); + return; + } + //获取token + String token = request.getHeader("Authorization"); + //针对大屏分享,优先处理 + String shareToken = request.getHeader("Share-Token"); + if (StringUtils.isNotBlank(shareToken) && StringUtils.isBlank(token)) { + //需要处理 + // /reportDashboard/getData + // /reportDashboard/{reportCode} + // /reportExcel/preview + List reportCodeList = JwtUtil.getReportCodeList(shareToken); + if (!uri.endsWith("/reportDashboard/getData") && !uri.endsWith("/reportExcel/preview") && reportCodeList.stream().noneMatch(uri::contains)) { + ResponseBean responseBean = ResponseBean.builder().code("50014") + .message("分享链接已过期").build(); + response.getWriter().print(JSONObject.toJSONString(responseBean)); + return; + } + filterChain.doFilter(request, response); + return; + } + + + + if (StringUtils.isBlank(token)) { + error(response); + return; + } + + // 判断token是否过期 + String loginName = jwtBean.getUsername(token); + String tokenKey = String.format(BusinessConstant.GAEA_SECURITY_LOGIN_TOKEN, loginName); + String userKey = String.format(BusinessConstant.GAEA_SECURITY_LOGIN_USER, loginName); + if (!cacheHelper.exist(tokenKey)) { + error(response); + return; + } + + String gaeaUserJsonStr = cacheHelper.stringGet(userKey); + + // 判断用户是否有该url的权限 + if (!BusinessConstant.USER_ADMIN.equals(loginName)) { + AtomicBoolean authorizeFlag = authorize(request, gaeaUserJsonStr); + if (!authorizeFlag.get()) { + authError(response);//无权限 + return; + } + } + + // 延长有效期 + cacheHelper.stringSetExpire(tokenKey, token, 3600); + cacheHelper.stringSetExpire(userKey, gaeaUserJsonStr, 3600); + + + //执行 + filterChain.doFilter(request, response); + } + + @Override + public void destroy() { + Filter.super.destroy(); + } + + /** + * 根据名单,生成正则 + * + * @param skipUrlList + * @return + */ + private Pattern fitByList(List skipUrlList) { + if (skipUrlList == null || skipUrlList.size() == 0) { + return PATTERN; + } + StringBuffer patternString = new StringBuffer(); + patternString.append(".*("); + + skipUrlList.stream().forEach(url -> { + patternString.append(url.trim()); + patternString.append("|"); + }); + if (skipUrlList.size() > 0) { + patternString.deleteCharAt(patternString.length() - 1); + } + patternString.append(").*"); + + return Pattern.compile(patternString.toString()); + } + + /** 判断用户是否有该接口的权限 + * @return + */ + private AtomicBoolean authorize(HttpServletRequest request, String gaeaUserJsonStr){ + + //判断接口权限 + //请求路径 + String requestUrl = request.getRequestURI(); + if (!BusinessConstant.SLASH.equals(SLASH)) { + requestUrl = requestUrl.substring(SLASH.length()); + } + String methodValue = request.getMethod(); + //请求方法+#+请求路径 + String path = methodValue + GaeaConstant.URL_SPLIT + requestUrl; + + GaeaUserDto gaeaUserDto = JSONObject.parseObject(gaeaUserJsonStr, GaeaUserDto.class); + List userAuthorities = gaeaUserDto.getAuthorities(); + Map authoritiesAllMap = cacheHelper.hashGet(BusinessConstant.GAEA_SECURITY_AUTHORITIES); + + AtomicBoolean authFlag = new AtomicBoolean(false); + + // 接口GET#/gaeaDictItem/pageList + if(authoritiesAllMap.containsKey(path)){ + String permissionCode = authoritiesAllMap.get(path); + boolean flag = userAuthorities.contains(permissionCode); + authFlag.set(flag); + return authFlag; + } + + // 接口GET#/accessUser/roleTree/** + Optional optionalMatchKey = authoritiesAllMap.keySet().stream() + .filter(key -> StringUtils.isNotBlank(key) && key.contains(URL_REPLACEMENT)) + .filter(key -> antPathMatcher.match(key, path)).findFirst(); + if(optionalMatchKey.isPresent() == false){ + authFlag.set(true); + return authFlag; + } + String authoritieKey = optionalMatchKey.get(); + String needPermission = authoritiesAllMap.get(authoritieKey); + boolean flag = userAuthorities.contains(needPermission); + authFlag.set(flag); + return authFlag; + } + + private void error(HttpServletResponse response) throws IOException { + ResponseBean responseBean = ResponseBean.builder().code("User.credentials.expired").message("The Token has expired").build(); + response.setContentType(ContentType.APPLICATION_JSON.getMimeType()); + response.getWriter().print(JSONObject.toJSONString(responseBean)); + } + + private void authError(HttpServletResponse response) throws IOException { + ResponseBean responseBean = ResponseBean.builder().code("User.no.authority").message("no auth").build(); + response.setContentType(ContentType.APPLICATION_JSON.getMimeType()); + response.getWriter().print(JSONObject.toJSONString(responseBean)); + } +} diff --git a/src/main/java/com/anjiplus/template/gaea/business/filter/UrlDecodeFilter.java b/src/main/java/com/anjiplus/template/gaea/business/filter/UrlDecodeFilter.java new file mode 100644 index 0000000..0d79a3a --- /dev/null +++ b/src/main/java/com/anjiplus/template/gaea/business/filter/UrlDecodeFilter.java @@ -0,0 +1,77 @@ +package com.anjiplus.template.gaea.business.filter; + +import com.anji.plus.gaea.constant.GaeaConstant; +import org.apache.catalina.util.ParameterMap; +import org.apache.commons.lang3.StringUtils; +import org.apache.ibatis.ognl.IteratorEnumeration; +import org.springframework.core.Ordered; +import org.springframework.core.annotation.Order; +import org.springframework.stereotype.Component; + +import javax.servlet.*; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletRequestWrapper; +import java.io.IOException; +import java.net.URLDecoder; +import java.util.Enumeration; +import java.util.Map; +import java.util.Set; + +/** + * @author: Raod + * @since: 2022-01-26 + */ +@Component +@Order(Ordered.HIGHEST_PRECEDENCE + 1) +public class UrlDecodeFilter implements Filter { + + @Override + public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { + HttpServletRequest httpServletRequest = (HttpServletRequest) servletRequest; + ParameterMap parameterMap = (ParameterMap) httpServletRequest.getParameterMap(); + ParamHttpServletRequestWrapper wrapper = new ParamHttpServletRequestWrapper(httpServletRequest, parameterMap); + + Enumeration parameterNames = wrapper.getParameterNames(); + while (parameterNames.hasMoreElements()) { + String paramName = parameterNames.nextElement(); + String parameter = httpServletRequest.getParameter(paramName); + if (StringUtils.isNotBlank(parameter)) { + String decode = URLDecoder.decode(parameter, GaeaConstant.CHARSET_UTF8); + parameterMap.setLocked(false); + parameterMap.put(paramName, new String[]{decode}); + } + } + filterChain.doFilter(wrapper, servletResponse); + } + + /** + * 参数 + */ + class ParamHttpServletRequestWrapper extends HttpServletRequestWrapper { + + private ParameterMap parameterMap; + + public ParamHttpServletRequestWrapper(HttpServletRequest request, ParameterMap parameterMap) { + super(request); + this.parameterMap = parameterMap; + } + + @Override + public Map getParameterMap() { + return parameterMap; + } + + @Override + public Enumeration getParameterNames() { + + Set keySet = parameterMap.keySet(); + IteratorEnumeration iteratorEnumeration = new IteratorEnumeration(keySet.iterator()); + return iteratorEnumeration; + } + + @Override + public String[] getParameterValues(String name) { + return parameterMap.get(name); + } + } +} diff --git a/src/main/java/com/anjiplus/template/gaea/business/modules/accessauthority/controller/AccessAuthorityController.java b/src/main/java/com/anjiplus/template/gaea/business/modules/accessauthority/controller/AccessAuthorityController.java new file mode 100644 index 0000000..6da7ba0 --- /dev/null +++ b/src/main/java/com/anjiplus/template/gaea/business/modules/accessauthority/controller/AccessAuthorityController.java @@ -0,0 +1,67 @@ + +package com.anjiplus.template.gaea.business.modules.accessauthority.controller; + +import com.anji.plus.gaea.annotation.Permission; +import com.anji.plus.gaea.annotation.AccessKey; +import com.anji.plus.gaea.bean.KeyValue; +import com.anji.plus.gaea.bean.ResponseBean; +import com.anji.plus.gaea.bean.TreeNode; +import com.anji.plus.gaea.curd.controller.GaeaBaseController; +import com.anji.plus.gaea.curd.service.GaeaBaseService; +import com.anji.plus.gaea.holder.UserContentHolder; +import com.anji.plus.gaea.utils.GaeaBeanUtils; +import com.anji.plus.gaea.utils.GaeaUtils; +import com.anjiplus.template.gaea.business.modules.accessauthority.dao.entity.AccessAuthority; +import com.anjiplus.template.gaea.business.modules.accessauthority.service.AccessAuthorityService; +import com.anjiplus.template.gaea.business.modules.accessauthority.controller.dto.AccessAuthorityDto; +import com.anjiplus.template.gaea.business.modules.accessauthority.controller.param.AccessAuthorityParam; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.i18n.LocaleContextHolder; +import org.springframework.web.bind.annotation.*; +import io.swagger.annotations.Api; + +import java.util.List; +import java.util.Locale; +import java.util.Map; + +/** +* @desc 权限管理 controller +* @author 木子李·De +* @date 2019-02-17 08:50:10.009 +**/ +@RestController +@Api(tags = "权限管理管理") +@RequestMapping("/accessAuthority") +@Permission(code = "authorityManage", name = "权限管理") +public class AccessAuthorityController extends GaeaBaseController { + + @Autowired + private AccessAuthorityService accessAuthorityService; + + @Override + public GaeaBaseService getService() { + return accessAuthorityService; + } + + @Override + public AccessAuthority getEntity() { + return new AccessAuthority(); + } + + @Override + public AccessAuthorityDto getDTO() { + return new AccessAuthorityDto(); + } + + /** + * 获取一二级菜单 + * @return + */ + @Permission( code = "query", name = "查询") + @GetMapping("/menuTree") + public ResponseBean menuTree(){ + String username = UserContentHolder.getContext().getUsername(); + List parentTreeList = accessAuthorityService.getAuthorityTree(username, false); + return responseSuccessWithData(parentTreeList); + } +} \ No newline at end of file diff --git a/src/main/java/com/anjiplus/template/gaea/business/modules/accessauthority/controller/dto/AccessAuthorityDto.java b/src/main/java/com/anjiplus/template/gaea/business/modules/accessauthority/controller/dto/AccessAuthorityDto.java new file mode 100644 index 0000000..77cc98f --- /dev/null +++ b/src/main/java/com/anjiplus/template/gaea/business/modules/accessauthority/controller/dto/AccessAuthorityDto.java @@ -0,0 +1,58 @@ + +package com.anjiplus.template.gaea.business.modules.accessauthority.controller.dto; + +import java.io.Serializable; +import javax.validation.constraints.NotEmpty; +import javax.validation.constraints.NotNull; + +import com.anji.plus.gaea.annotation.Query; +import com.anji.plus.gaea.constant.QueryEnum; +import com.anji.plus.gaea.curd.dto.GaeaBaseDTO; +import io.swagger.annotations.ApiModelProperty; +import com.anji.plus.gaea.annotation.Formatter; +import lombok.Data; + +/** +* +* @description 权限管理 dto +* @author 木子李·De +* @date 2019-02-17 08:50:10.009 +**/ +@Data +public class AccessAuthorityDto extends GaeaBaseDTO implements Serializable { + /** 父菜单代码 */ + @ApiModelProperty(value = "父菜单代码") + private String parentTarget; + + /** 目标菜单 */ + @ApiModelProperty(value = "菜单代码") + @NotEmpty(message = "6002") + private String target; + + /** 目标菜单名称 */ + @ApiModelProperty(value = "菜单名称") + @NotEmpty(message = "6002") + private String targetName; + + /** 目标按钮 */ + @ApiModelProperty(value = "按钮代码") + @NotEmpty(message = "6002") + private String action; + + /** 目标按钮名称 */ + @ApiModelProperty(value = "按钮名称") + @NotEmpty(message = "6002") + private String actionName; + + /** 0--未删除 1--已删除 DIC_NAME=DEL_FLAG */ + @ApiModelProperty(value = " 0--未删除 1--已删除 DIC_NAME=DEL_FLAG") + private Integer deleteFlag; + + /** 0--已禁用 1--已启用 DIC_NAME=ENABLE_FLAG */ + @ApiModelProperty(value = "0--已禁用 1--已启用 DIC_NAME=ENABLE_FLAG") + @NotNull(message = "6002") + private Integer enableFlag; + + @ApiModelProperty(value = "sort") + private Integer sort; +} \ No newline at end of file diff --git a/src/main/java/com/anjiplus/template/gaea/business/modules/accessauthority/controller/param/AccessAuthorityParam.java b/src/main/java/com/anjiplus/template/gaea/business/modules/accessauthority/controller/param/AccessAuthorityParam.java new file mode 100644 index 0000000..344a14c --- /dev/null +++ b/src/main/java/com/anjiplus/template/gaea/business/modules/accessauthority/controller/param/AccessAuthorityParam.java @@ -0,0 +1,44 @@ +/**/ +package com.anjiplus.template.gaea.business.modules.accessauthority.controller.param; + +import lombok.Data; +import java.io.Serializable; +import com.anji.plus.gaea.annotation.Query; +import com.anji.plus.gaea.constant.QueryEnum; +import com.anji.plus.gaea.curd.params.PageParam; +import java.util.List; + +import java.util.Date; + +/** +* @desc AccessAuthority 权限管理查询输入类 +* @author 木子李·De +* @date 2019-02-17 08:50:10.009 +**/ +@Data +public class AccessAuthorityParam extends PageParam implements Serializable{ + + /** 父菜单代码 */ + @Query(value = QueryEnum.LIKE) + private String parentTarget; + + /** 菜单代码 */ + @Query(value = QueryEnum.LIKE) + private String target; + + /** 菜单名称 */ + @Query(value = QueryEnum.LIKE) + private String targetName; + + /** 按钮代码 */ + @Query(value = QueryEnum.LIKE) + private String action; + + /** 按钮名称 */ + @Query(value = QueryEnum.LIKE) + private String actionName; + + // 0--已禁用 1--已启用 DIC_NAME=ENABLE_FLAG + @Query + private Integer enableFlag; +} \ No newline at end of file diff --git a/src/main/java/com/anjiplus/template/gaea/business/modules/accessauthority/dao/AccessAuthorityMapper.java b/src/main/java/com/anjiplus/template/gaea/business/modules/accessauthority/dao/AccessAuthorityMapper.java new file mode 100644 index 0000000..9395dd2 --- /dev/null +++ b/src/main/java/com/anjiplus/template/gaea/business/modules/accessauthority/dao/AccessAuthorityMapper.java @@ -0,0 +1,17 @@ +package com.anjiplus.template.gaea.business.modules.accessauthority.dao; + +import org.apache.ibatis.annotations.Mapper; +import com.anji.plus.gaea.curd.mapper.GaeaBaseMapper; +import com.anjiplus.template.gaea.business.modules.accessauthority.dao.entity.AccessAuthority; + +import java.util.List; + +/** +* AccessAuthority Mapper +* @author 木子李·De +* @date 2019-02-17 08:50:10.009 +**/ +@Mapper +public interface AccessAuthorityMapper extends GaeaBaseMapper { + +} \ No newline at end of file diff --git a/src/main/java/com/anjiplus/template/gaea/business/modules/accessauthority/dao/entity/AccessAuthority.java b/src/main/java/com/anjiplus/template/gaea/business/modules/accessauthority/dao/entity/AccessAuthority.java new file mode 100644 index 0000000..1d04d89 --- /dev/null +++ b/src/main/java/com/anjiplus/template/gaea/business/modules/accessauthority/dao/entity/AccessAuthority.java @@ -0,0 +1,43 @@ + +package com.anjiplus.template.gaea.business.modules.accessauthority.dao.entity; + +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; +import com.anji.plus.gaea.curd.entity.GaeaBaseEntity; +import com.baomidou.mybatisplus.annotation.TableName; +import javax.validation.constraints.*; +import java.util.Date; +/** +* @description 权限管理 entity +* @author 木子李·De +* @date 2019-02-17 08:50:10.009 +**/ +@TableName(keepGlobalPrefix=true, value="access_authority") +@Data +public class AccessAuthority extends GaeaBaseEntity { + /** 父菜单代码 */ + private String parentTarget; + + /** 菜单代码 */ + private String target; + + /** 菜单名称 */ + private String targetName; + + /** 按钮代码 */ + private String action; + + /** 按钮名称 */ + private String actionName; + + /** 0--未删除 1--已删除 DIC_NAME=DEL_FLAG */ + private Integer deleteFlag; + + /** 0--已禁用 1--已启用 DIC_NAME=ENABLE_FLAG */ + private Integer enableFlag; + + private Integer sort; + + + +} diff --git a/src/main/java/com/anjiplus/template/gaea/business/modules/accessauthority/service/AccessAuthorityService.java b/src/main/java/com/anjiplus/template/gaea/business/modules/accessauthority/service/AccessAuthorityService.java new file mode 100644 index 0000000..0e3e023 --- /dev/null +++ b/src/main/java/com/anjiplus/template/gaea/business/modules/accessauthority/service/AccessAuthorityService.java @@ -0,0 +1,29 @@ + +package com.anjiplus.template.gaea.business.modules.accessauthority.service; + +import com.anji.plus.gaea.bean.TreeNode; +import com.anjiplus.template.gaea.business.modules.accessauthority.dao.entity.AccessAuthority; +import com.anjiplus.template.gaea.business.modules.accessauthority.controller.param.AccessAuthorityParam; +import com.anji.plus.gaea.curd.service.GaeaBaseService; + +import java.util.List; + +/** +* @desc AccessAuthority 权限管理服务接口 +* @author 木子李·De +* @date 2019-02-17 08:50:10.009 +**/ +public interface AccessAuthorityService extends GaeaBaseService { + + /** + * @param loginName 当前登录的用户名 + * @param withActionNode 带第三层的按钮节点 + * @return + */ + List getAuthorityTree(String loginName, boolean withActionNode); + + /** + * 扫描所有mvc url的需要权限码,建立拦截体系 + */ + void scanGaeaSecurityAuthorities(); +} \ No newline at end of file diff --git a/src/main/java/com/anjiplus/template/gaea/business/modules/accessauthority/service/impl/AccessAuthorityServiceImpl.java b/src/main/java/com/anjiplus/template/gaea/business/modules/accessauthority/service/impl/AccessAuthorityServiceImpl.java new file mode 100644 index 0000000..b261862 --- /dev/null +++ b/src/main/java/com/anjiplus/template/gaea/business/modules/accessauthority/service/impl/AccessAuthorityServiceImpl.java @@ -0,0 +1,140 @@ + +package com.anjiplus.template.gaea.business.modules.accessauthority.service.impl; + +import com.alibaba.fastjson.JSONObject; +import com.anji.plus.gaea.bean.TreeNode; +import com.anji.plus.gaea.cache.CacheHelper; +import com.anji.plus.gaea.constant.Enabled; +import com.anji.plus.gaea.curd.mapper.GaeaBaseMapper; +import com.anji.plus.gaea.init.InitRequestUrlMappings; +import com.anjiplus.template.gaea.business.constant.BusinessConstant; +import com.anjiplus.template.gaea.business.modules.accessauthority.dao.entity.AccessAuthority; +import com.anjiplus.template.gaea.business.modules.accessauthority.service.AccessAuthorityService; +import com.anjiplus.template.gaea.business.modules.accessauthority.dao.AccessAuthorityMapper; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import org.apache.commons.lang3.StringUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +/** +* @desc AccessAuthority 权限管理服务实现 +* @author 木子李·De +* @date 2019-02-17 08:50:10.009 +**/ +@Service +public class AccessAuthorityServiceImpl implements AccessAuthorityService { + + @Autowired + private InitRequestUrlMappings initRequestUrlMappings; + + @Autowired + private CacheHelper cacheHelper; + + @Autowired + private AccessAuthorityMapper accessAuthorityMapper; + + @Override + public GaeaBaseMapper getMapper() { + return accessAuthorityMapper; + } + + @Override + public List getAuthorityTree(String loginName, boolean withActionNode) { + // 查询出所有的菜单记录 + LambdaQueryWrapper wrapper = Wrappers.lambdaQuery(); + wrapper.select(AccessAuthority::getParentTarget, AccessAuthority::getTarget, AccessAuthority::getTargetName, AccessAuthority::getAction, AccessAuthority::getActionName) + .eq(AccessAuthority::getEnableFlag, 1) + .eq(AccessAuthority::getDeleteFlag, 0) + .orderByAsc(AccessAuthority::getSort); + // 按operator去筛选 后面再加where + List accessAuthorityList = getMapper().selectList(wrapper); + + // 筛选出一级菜单 + List parentNodes = accessAuthorityList.stream().filter(accessAuthority -> StringUtils.isBlank(accessAuthority.getParentTarget())) + .map(item -> { + TreeNode treeNode = new TreeNode(); + treeNode.setId(item.getTarget()); + treeNode.setLabel(item.getTargetName()); + return treeNode; + }).collect(Collectors.toList()); + + // 菜单-按钮的map + Map> targetActionsMap = accessAuthorityList.stream() + .filter(accessAuthority -> StringUtils.isNoneBlank(accessAuthority.getParentTarget())) + .collect(Collectors.groupingBy(AccessAuthority::getTarget)); + + // 设置每个一级菜单的二菜单 + parentNodes.stream().forEach(parentNode -> { + List alreadyTargets = new ArrayList<>(); + + accessAuthorityList.stream().forEach(authority -> { + if(!StringUtils.equals(parentNode.getId(), authority.getParentTarget()) || alreadyTargets.contains(authority.getTarget())){ + return; + } + // 找到一级菜单对应的二级菜单 + + // 初始化二级菜单节点 + TreeNode levelTwoMenuNode = new TreeNode(); + levelTwoMenuNode.setId(authority.getTarget()); + levelTwoMenuNode.setLabel(authority.getTargetName()); + levelTwoMenuNode.setChildren(new ArrayList()); + + // 初始化二级菜单的按钮 + if(withActionNode){ + List actionList = targetActionsMap.get(authority.getTarget()); + if(actionList != null && !actionList.isEmpty()){ + actionList.stream().forEach(action ->{ + TreeNode buttonNode = new TreeNode(); + buttonNode.setId(String.format("%s_%s", action.getTarget(), action.getAction())); + buttonNode.setLabel(action.getActionName()); + levelTwoMenuNode.getChildren().add(buttonNode); + }); + } + } + + // 将上面找到的二级菜单加入到一菜单的子树中去 + List children = parentNode.getChildren(); + if(children == null){ + children = new ArrayList(); + } + children.add(levelTwoMenuNode); + parentNode.setChildren(children); + + // 已经找过的二级菜单,后面不在重复添加 + alreadyTargets.add(authority.getTarget()); + }); + }); + + return parentNodes; + } + + @Override + public void scanGaeaSecurityAuthorities() { + /* 获取当前应用中所有的请求信息 + { + "applicationName": "aj-report", + "authCode": "authorityManage:query", + "authName": "权限管理查询", + "beanName": "accessAuthorityController", + "menuCode": "authorityManage", + "path": "GET#/accessAuthority/menuTree" + }*/ + List requestInfos = initRequestUrlMappings.getRequestInfos(Enabled.YES.getValue()); + + // key="GET#/accessAuthority/menuTree" value="authorityManage:query" + Map securityAuthorityMap = new HashMap(); + requestInfos.stream().forEach(requestInfo -> { + securityAuthorityMap.put(requestInfo.getPath(), requestInfo.getAuthCode()); + }); + + // 将key存入到缓存中 + cacheHelper.hashSet(BusinessConstant.GAEA_SECURITY_AUTHORITIES, securityAuthorityMap); + } +} \ No newline at end of file diff --git a/src/main/java/com/anjiplus/template/gaea/business/modules/accessrole/controller/AccessRoleController.java b/src/main/java/com/anjiplus/template/gaea/business/modules/accessrole/controller/AccessRoleController.java new file mode 100644 index 0000000..5614a30 --- /dev/null +++ b/src/main/java/com/anjiplus/template/gaea/business/modules/accessrole/controller/AccessRoleController.java @@ -0,0 +1,75 @@ + +package com.anjiplus.template.gaea.business.modules.accessrole.controller; + +import com.anji.plus.gaea.annotation.Permission; +import com.anji.plus.gaea.annotation.AccessKey; +import com.anji.plus.gaea.bean.ResponseBean; +import com.anji.plus.gaea.bean.TreeNode; +import com.anji.plus.gaea.curd.controller.GaeaBaseController; +import com.anji.plus.gaea.curd.service.GaeaBaseService; +import com.anji.plus.gaea.holder.UserContentHolder; +import com.anji.plus.gaea.utils.GaeaBeanUtils; +import com.anji.plus.gaea.utils.GaeaUtils; +import com.anjiplus.template.gaea.business.modules.accessrole.dao.entity.AccessRole; +import com.anjiplus.template.gaea.business.modules.accessrole.service.AccessRoleService; +import com.anjiplus.template.gaea.business.modules.accessrole.controller.dto.AccessRoleDto; +import com.anjiplus.template.gaea.business.modules.accessrole.controller.param.AccessRoleParam; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.*; +import io.swagger.annotations.Api; + +import java.util.List; +import java.util.Map; + +/** +* @desc 角色管理 controller +* @author 木子李·De +* @date 2019-02-17 08:50:14.136 +**/ +@RestController +@Api(tags = "角色管理管理") +@RequestMapping("/accessRole") +@Permission(code = "roleManage", name = "角色管理") +public class AccessRoleController extends GaeaBaseController { + + @Autowired + private AccessRoleService accessRoleService; + + @Override + public GaeaBaseService getService() { + return accessRoleService; + } + + @Override + public AccessRole getEntity() { + return new AccessRole(); + } + + @Override + public AccessRoleDto getDTO() { + return new AccessRoleDto(); + } + + /** + * 获取角色的 菜单按钮树 一级菜单 二级菜单 三级按钮 + * @return + */ + @Permission( code = "grantAuthority", name = "分配权限") + @GetMapping("/authorityTree/{roleCode}") + public ResponseBean authorityTree(@PathVariable("roleCode")String roleCode){ + String operator = UserContentHolder.getContext().getUsername(); + Map map = accessRoleService.getAuthorityTree(roleCode, operator); + return responseSuccessWithData(map); + } + + /** + * 保存角色的权限 + * @return + */ + @Permission( code = "grantAuthority", name = "分配权限") + @PostMapping("/saveAuthorityTree") + public ResponseBean saveAuthorityTree(@RequestBody AccessRoleDto dto){ + Boolean data = accessRoleService.saveAuthorityTree(dto); + return responseSuccessWithData(data); + } +} \ No newline at end of file diff --git a/src/main/java/com/anjiplus/template/gaea/business/modules/accessrole/controller/dto/AccessRoleDto.java b/src/main/java/com/anjiplus/template/gaea/business/modules/accessrole/controller/dto/AccessRoleDto.java new file mode 100644 index 0000000..c7e1062 --- /dev/null +++ b/src/main/java/com/anjiplus/template/gaea/business/modules/accessrole/controller/dto/AccessRoleDto.java @@ -0,0 +1,46 @@ + +package com.anjiplus.template.gaea.business.modules.accessrole.controller.dto; + +import java.io.Serializable; +import java.util.List; +import javax.validation.constraints.NotEmpty; +import javax.validation.constraints.NotNull; + +import com.anji.plus.gaea.annotation.Query; +import com.anji.plus.gaea.constant.QueryEnum; +import com.anji.plus.gaea.curd.dto.GaeaBaseDTO; +import io.swagger.annotations.ApiModelProperty; +import com.anji.plus.gaea.annotation.Formatter; +import lombok.Data; + +/** +* +* @description 角色管理 dto +* @author 木子李·De +* @date 2019-02-17 08:50:14.136 +**/ +@Data +public class AccessRoleDto extends GaeaBaseDTO implements Serializable { + + /** 角色编码 */ + @ApiModelProperty(value = "角色编码") + @NotEmpty(message = "6002") + private String roleCode; + + /** 角色名称 */ + @ApiModelProperty(value = "角色名称") + @NotEmpty(message = "6002") + private String roleName; + + /** 0--未删除 1--已删除 DIC_NAME=DEL_FLAG */ + @ApiModelProperty(value = " 0--未删除 1--已删除 DIC_NAME=DEL_FLAG") + private Integer deleteFlag; + + /** 0--已禁用 1--已启用 DIC_NAME=ENABLE_FLAG */ + @ApiModelProperty(value = "0--已禁用 1--已启用 DIC_NAME=ENABLE_FLAG") + @NotNull(message = "6002") + private Integer enableFlag; + + /** 角色保存的权限 */ + private List authorityList; +} \ No newline at end of file diff --git a/src/main/java/com/anjiplus/template/gaea/business/modules/accessrole/controller/param/AccessRoleParam.java b/src/main/java/com/anjiplus/template/gaea/business/modules/accessrole/controller/param/AccessRoleParam.java new file mode 100644 index 0000000..5e5d59f --- /dev/null +++ b/src/main/java/com/anjiplus/template/gaea/business/modules/accessrole/controller/param/AccessRoleParam.java @@ -0,0 +1,33 @@ +/**/ +package com.anjiplus.template.gaea.business.modules.accessrole.controller.param; + +import lombok.Data; +import java.io.Serializable; +import com.anji.plus.gaea.annotation.Query; +import com.anji.plus.gaea.constant.QueryEnum; +import com.anji.plus.gaea.curd.params.PageParam; +import java.util.List; + +import java.util.Date; + +/** +* @desc AccessRole 角色管理查询输入类 +* @author 木子李·De +* @date 2019-02-17 08:50:14.136 +**/ +@Data +public class AccessRoleParam extends PageParam implements Serializable{ + + /** 角色编码 */ + @Query(value = QueryEnum.LIKE) + private String roleCode; + + // 角色名称 + @Query(value = QueryEnum.LIKE) + private String roleName; + + // 0--已禁用 1--已启用 DIC_NAME=ENABLE_FLAG + @Query + private Integer enableFlag; + +} \ No newline at end of file diff --git a/src/main/java/com/anjiplus/template/gaea/business/modules/accessrole/dao/AccessRoleAuthorityMapper.java b/src/main/java/com/anjiplus/template/gaea/business/modules/accessrole/dao/AccessRoleAuthorityMapper.java new file mode 100644 index 0000000..7fe9995 --- /dev/null +++ b/src/main/java/com/anjiplus/template/gaea/business/modules/accessrole/dao/AccessRoleAuthorityMapper.java @@ -0,0 +1,15 @@ +package com.anjiplus.template.gaea.business.modules.accessrole.dao; + +import com.anji.plus.gaea.curd.mapper.GaeaBaseMapper; +import com.anjiplus.template.gaea.business.modules.accessrole.dao.entity.AccessRoleAuthority; +import org.apache.ibatis.annotations.Mapper; + +/** +* AccessRoleAuthority Mapper +* @author 木子李·De +* @date 2019-02-17 08:50:14.136 +**/ +@Mapper +public interface AccessRoleAuthorityMapper extends GaeaBaseMapper { + +} \ No newline at end of file diff --git a/src/main/java/com/anjiplus/template/gaea/business/modules/accessrole/dao/AccessRoleMapper.java b/src/main/java/com/anjiplus/template/gaea/business/modules/accessrole/dao/AccessRoleMapper.java new file mode 100644 index 0000000..9b78e95 --- /dev/null +++ b/src/main/java/com/anjiplus/template/gaea/business/modules/accessrole/dao/AccessRoleMapper.java @@ -0,0 +1,22 @@ +package com.anjiplus.template.gaea.business.modules.accessrole.dao; + +import org.apache.ibatis.annotations.Mapper; +import com.anji.plus.gaea.curd.mapper.GaeaBaseMapper; +import com.anjiplus.template.gaea.business.modules.accessrole.dao.entity.AccessRole; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.core.toolkit.Constants; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; + +import java.util.List; +/** +* AccessRole Mapper +* @author 木子李·De +* @date 2019-02-17 08:50:14.136 +**/ +@Mapper +public interface AccessRoleMapper extends GaeaBaseMapper { + + List checkedAuthoritys(@Param("roleCode")String roleCode); +} \ No newline at end of file diff --git a/src/main/java/com/anjiplus/template/gaea/business/modules/accessrole/dao/entity/AccessRole.java b/src/main/java/com/anjiplus/template/gaea/business/modules/accessrole/dao/entity/AccessRole.java new file mode 100644 index 0000000..e8e7b1a --- /dev/null +++ b/src/main/java/com/anjiplus/template/gaea/business/modules/accessrole/dao/entity/AccessRole.java @@ -0,0 +1,30 @@ + +package com.anjiplus.template.gaea.business.modules.accessrole.dao.entity; + +import lombok.Data; +import com.anji.plus.gaea.curd.entity.GaeaBaseEntity; +import com.baomidou.mybatisplus.annotation.TableName; +import javax.validation.constraints.*; +import java.util.Date; +/** +* @description 角色管理 entity +* @author 木子李·De +* @date 2019-02-17 08:50:14.136 +**/ +@TableName(keepGlobalPrefix=true, value="access_role") +@Data +public class AccessRole extends GaeaBaseEntity { + + /** 角色编码 */ + private String roleCode; + + /** 角色名称 */ + private String roleName; + + /** 0--未删除 1--已删除 DIC_NAME=DEL_FLAG */ + private Integer deleteFlag; + + /** 0--已禁用 1--已启用 DIC_NAME=ENABLE_FLAG */ + private Integer enableFlag; + +} diff --git a/src/main/java/com/anjiplus/template/gaea/business/modules/accessrole/dao/entity/AccessRoleAuthority.java b/src/main/java/com/anjiplus/template/gaea/business/modules/accessrole/dao/entity/AccessRoleAuthority.java new file mode 100644 index 0000000..cb20a8f --- /dev/null +++ b/src/main/java/com/anjiplus/template/gaea/business/modules/accessrole/dao/entity/AccessRoleAuthority.java @@ -0,0 +1,44 @@ +package com.anjiplus.template.gaea.business.modules.accessrole.dao.entity; + +import com.anji.plus.gaea.curd.entity.GaeaBaseEntity; +import com.baomidou.mybatisplus.annotation.FieldFill; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableName; +import com.baomidou.mybatisplus.annotation.Version; +import lombok.Data; + +import java.util.Date; + +/** + * @description 角色--菜单--按钮关联关系 entity + * @author 木子李·De + * @date 2019-02-17 08:50:14.136 + **/ +@TableName(keepGlobalPrefix=true, value="access_role_authority") +@Data +public class AccessRoleAuthority extends GaeaBaseEntity { + + /** 角色编码 */ + private String roleCode; + + /** 菜单代码 */ + private String target; + + /** 按钮代码 */ + private String action; + + @TableField(exist = false) + private String createBy; + + @TableField(exist = false) + private Date createTime; + + @TableField(exist = false) + private String updateBy; + + @TableField(exist = false) + private Date updateTime; + + @TableField(exist = false) + private Integer version; +} diff --git a/src/main/java/com/anjiplus/template/gaea/business/modules/accessrole/service/AccessRoleService.java b/src/main/java/com/anjiplus/template/gaea/business/modules/accessrole/service/AccessRoleService.java new file mode 100644 index 0000000..639fd1a --- /dev/null +++ b/src/main/java/com/anjiplus/template/gaea/business/modules/accessrole/service/AccessRoleService.java @@ -0,0 +1,34 @@ + +package com.anjiplus.template.gaea.business.modules.accessrole.service; + +import com.anji.plus.gaea.bean.ResponseBean; +import com.anjiplus.template.gaea.business.modules.accessrole.controller.dto.AccessRoleDto; +import com.anjiplus.template.gaea.business.modules.accessrole.dao.entity.AccessRole; +import com.anjiplus.template.gaea.business.modules.accessrole.controller.param.AccessRoleParam; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.anji.plus.gaea.curd.service.GaeaBaseService; + +import java.util.Map; + +/** +* @desc AccessRole 角色管理服务接口 +* @author 木子李·De +* @date 2019-02-17 08:50:14.136 +**/ +public interface AccessRoleService extends GaeaBaseService { + + /** 查询某角色的权限树 + * @param roleCode 被操作的对象 + * @param operator 当前登录者 + * @return + */ + Map getAuthorityTree(String roleCode, String operator); + + + /** 保存角色的权限 + * @param accessRoleDto + * @return + */ + Boolean saveAuthorityTree(AccessRoleDto accessRoleDto); +} \ No newline at end of file diff --git a/src/main/java/com/anjiplus/template/gaea/business/modules/accessrole/service/impl/AccessRoleServiceImpl.java b/src/main/java/com/anjiplus/template/gaea/business/modules/accessrole/service/impl/AccessRoleServiceImpl.java new file mode 100644 index 0000000..dea1b15 --- /dev/null +++ b/src/main/java/com/anjiplus/template/gaea/business/modules/accessrole/service/impl/AccessRoleServiceImpl.java @@ -0,0 +1,101 @@ + +package com.anjiplus.template.gaea.business.modules.accessrole.service.impl; + +import com.anji.plus.gaea.bean.TreeNode; +import com.anji.plus.gaea.curd.mapper.GaeaBaseMapper; +import com.anji.plus.gaea.exception.BusinessExceptionBuilder; +import com.anjiplus.template.gaea.business.code.ResponseCode; +import com.anjiplus.template.gaea.business.modules.accessauthority.service.AccessAuthorityService; +import com.anjiplus.template.gaea.business.modules.accessrole.controller.dto.AccessRoleDto; +import com.anjiplus.template.gaea.business.modules.accessrole.dao.AccessRoleAuthorityMapper; +import com.anjiplus.template.gaea.business.modules.accessrole.dao.entity.AccessRole; +import com.anjiplus.template.gaea.business.modules.accessrole.dao.entity.AccessRoleAuthority; +import com.anjiplus.template.gaea.business.modules.accessrole.service.AccessRoleService; +import com.anjiplus.template.gaea.business.modules.accessrole.dao.AccessRoleMapper; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import org.apache.commons.lang3.StringUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +/** +* @desc AccessRole 角色管理服务实现 +* @author 木子李·De +* @date 2019-02-17 08:50:14.136 +**/ +@Service +public class AccessRoleServiceImpl implements AccessRoleService { + + @Autowired + private AccessRoleMapper accessRoleMapper; + + @Autowired + private AccessRoleAuthorityMapper accessRoleAuthorityMapper; + + @Autowired + private AccessAuthorityService accessAuthorityService; + + @Override + public GaeaBaseMapper getMapper() { + return accessRoleMapper; + } + + @Override + public Map getAuthorityTree(String roleCode, String operator) { + Map result = new HashMap(); + + // 菜单按钮树 + List treeData = accessAuthorityService.getAuthorityTree(operator, true); + + // 该角色已选中的菜单及按钮 +// List checkedKeys = accessRoleMapper.checkedAuthoritys(roleCode); + + LambdaQueryWrapper accessRoleAuthorityWrapper = Wrappers.lambdaQuery(); + accessRoleAuthorityWrapper.select(AccessRoleAuthority::getTarget, AccessRoleAuthority::getAction); + accessRoleAuthorityWrapper.eq(AccessRoleAuthority::getRoleCode, roleCode); + List accessRoleAuthorities = accessRoleAuthorityMapper.selectList(accessRoleAuthorityWrapper); + List checkedKeys = accessRoleAuthorities.stream() + .map(accessRoleAuthority -> accessRoleAuthority.getTarget().concat("_").concat(accessRoleAuthority.getAction())).distinct().collect(Collectors.toList()); + + result.put("treeData", treeData); + result.put("checkedKeys", checkedKeys); + return result; + } + + @Override + public Boolean saveAuthorityTree(AccessRoleDto accessRoleDto) { + // 校验 + String roleCode = accessRoleDto.getRoleCode(); + List authorityList = accessRoleDto.getAuthorityList(); + if(StringUtils.isBlank(roleCode)){ + throw BusinessExceptionBuilder.build(ResponseCode.NOT_EMPTY, roleCode); + } + if(authorityList == null || authorityList.isEmpty()){ + throw BusinessExceptionBuilder.build(ResponseCode.NOT_EMPTY, authorityList); + } + + // 先清除该角色已保存的权限 + LambdaQueryWrapper wrapper = Wrappers.lambdaQuery(); + wrapper.eq(AccessRoleAuthority::getRoleCode, roleCode); + accessRoleAuthorityMapper.delete(wrapper); + + // 保存勾选的权限(菜单和按钮) + authorityList.stream().forEach(authorityStr -> { + if(!authorityStr.contains("_")){ + return; + } + String[] array = authorityStr.split("_"); + AccessRoleAuthority accessRoleAuthority = new AccessRoleAuthority(); + accessRoleAuthority.setRoleCode(roleCode); + accessRoleAuthority.setTarget(array[0].trim()); + accessRoleAuthority.setAction(array[1].trim()); + accessRoleAuthorityMapper.insert(accessRoleAuthority); + }); + return true; + } +} diff --git a/src/main/java/com/anjiplus/template/gaea/business/modules/accessuser/controller/AccessUserController.java b/src/main/java/com/anjiplus/template/gaea/business/modules/accessuser/controller/AccessUserController.java new file mode 100644 index 0000000..3781adf --- /dev/null +++ b/src/main/java/com/anjiplus/template/gaea/business/modules/accessuser/controller/AccessUserController.java @@ -0,0 +1,113 @@ + +package com.anjiplus.template.gaea.business.modules.accessuser.controller; + +import com.anji.plus.gaea.annotation.Permission; +import com.anji.plus.gaea.bean.ResponseBean; +import com.anji.plus.gaea.curd.controller.GaeaBaseController; +import com.anji.plus.gaea.curd.service.GaeaBaseService; +import com.anji.plus.gaea.holder.UserContentHolder; +import com.anjiplus.template.gaea.business.modules.accessuser.controller.dto.GaeaUserDto; +import com.anjiplus.template.gaea.business.modules.accessuser.controller.dto.UpdatePasswordDto; +import com.anjiplus.template.gaea.business.modules.accessuser.dao.entity.AccessUser; +import com.anjiplus.template.gaea.business.modules.accessuser.service.AccessUserService; +import com.anjiplus.template.gaea.business.modules.accessuser.controller.dto.AccessUserDto; +import com.anjiplus.template.gaea.business.modules.accessuser.controller.param.AccessUserParam; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import io.swagger.annotations.Api; + +import java.util.Map; + +/** +* @desc 用户管理 controller +* @author 木子李·De +* @date 2019-02-17 08:50:11.902 +**/ +@RestController +@Api(tags = "用户管理管理") +@RequestMapping("/accessUser") +@Permission(code = "userManage", name = "用户管理") +public class AccessUserController extends GaeaBaseController { + + @Autowired + private AccessUserService accessUserService; + + @Override + public GaeaBaseService getService() { + return accessUserService; + } + + @Override + public AccessUser getEntity() { + return new AccessUser(); + } + + @Override + public AccessUserDto getDTO() { + return new AccessUserDto(); + } + + + /** + * 获取用户的角色树 + * @return + */ + @Permission( code = "grantRole", name = "分配角色") + @GetMapping("/roleTree/{loginName}") + public ResponseBean getRoleTree(@PathVariable("loginName")String loginName){ + String operator = UserContentHolder.getContext().getUsername(); + Map map = accessUserService.getRoleTree(loginName, operator); + return responseSuccessWithData(map); + } + + /** + * 保存用户的角色树 + * @return + */ + @Permission( code = "grantRole", name = "分配角色") + @PostMapping("/saveRoleTree") + public ResponseBean saveRoleTree(@RequestBody AccessUserDto dto){ + Boolean data = accessUserService.saveRoleTree(dto); + return responseSuccessWithData(data); + } + + + /** + * 重置密码 + * @param dto + * @return + */ + @Permission( code = "resetPassword", name = "重置密码") + @PostMapping({"/resetPassword"}) + public ResponseBean resetPassword(@RequestBody GaeaUserDto dto) { + Boolean data = accessUserService.resetPassword(dto); + return responseSuccessWithData(data); + } + + /** + * 简单实现登录 + * @param dto + * @return + */ + @PostMapping({"/login"}) + public ResponseBean login(@RequestBody @Validated GaeaUserDto dto) { + return responseSuccessWithData(accessUserService.login(dto)); + } + + /** + * 修改自己的密码 + * @param dto + * @return + */ + @PostMapping("/updatePassword") + public ResponseBean updatePassword(@RequestBody UpdatePasswordDto dto) { + return responseSuccessWithData(accessUserService.updatePassword(dto)); + } + +} diff --git a/src/main/java/com/anjiplus/template/gaea/business/modules/accessuser/controller/dto/AccessUserDto.java b/src/main/java/com/anjiplus/template/gaea/business/modules/accessuser/controller/dto/AccessUserDto.java new file mode 100644 index 0000000..11d1fb9 --- /dev/null +++ b/src/main/java/com/anjiplus/template/gaea/business/modules/accessuser/controller/dto/AccessUserDto.java @@ -0,0 +1,66 @@ + +package com.anjiplus.template.gaea.business.modules.accessuser.controller.dto; + +import java.io.Serializable; +import javax.validation.constraints.NotEmpty; +import javax.validation.constraints.NotNull; + +import com.anji.plus.gaea.curd.dto.GaeaBaseDTO; +import com.anjiplus.template.gaea.business.modules.accessuser.dao.entity.AccessUser; +import io.swagger.annotations.ApiModelProperty; +import com.anji.plus.gaea.annotation.Formatter; +import lombok.Data; +import java.util.Date; +import java.util.List; + +/** +* +* @description 用户管理 dto +* @author 木子李·De +* @date 2019-02-17 08:50:11.902 +**/ +@Data +public class AccessUserDto extends GaeaBaseDTO implements Serializable { + + /**  登录名 */ + @ApiModelProperty(value = " 登录名") + @NotEmpty(message = "6002") + private String loginName; + + /** 真实用户 */ + @ApiModelProperty(value = "真实用户") + @NotEmpty(message = "6002") + private String realName; + + /** 手机号码 */ + @ApiModelProperty(value = "手机号码") + private String phone; + + /** 用户邮箱 */ + @ApiModelProperty(value = "用户邮箱") + private String email; + + /** 0--已禁用 1--已启用 DIC_NAME=ENABLE_FLAG */ + @ApiModelProperty(value = "0--已禁用 1--已启用 DIC_NAME=ENABLE_FLAG") + @NotNull(message = "6002") + private Integer enableFlag; + + /** 0--未删除 1--已删除 DIC_NAME=DEL_FLAG */ + @ApiModelProperty(value = " 0--未删除 1--已删除 DIC_NAME=DEL_FLAG") + private Integer deleteFlag; + + /** 最后一次登录IP */ + @ApiModelProperty(value = "最后一次登录IP") + private String lastLoginIp; + + /** 最后一次登陆时间 */ + @ApiModelProperty(value = "最后一次登陆时间") + private Date lastLoginTime; + + /** 备注 */ + @ApiModelProperty(value = "备注") + private String remark; + + /** 用户勾选的角色 */ + private List roleCodeList; +} diff --git a/src/main/java/com/anjiplus/template/gaea/business/modules/accessuser/controller/dto/GaeaUserDto.java b/src/main/java/com/anjiplus/template/gaea/business/modules/accessuser/controller/dto/GaeaUserDto.java new file mode 100644 index 0000000..02a9d19 --- /dev/null +++ b/src/main/java/com/anjiplus/template/gaea/business/modules/accessuser/controller/dto/GaeaUserDto.java @@ -0,0 +1,30 @@ +package com.anjiplus.template.gaea.business.modules.accessuser.controller.dto; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +import javax.validation.constraints.NotBlank; +import java.util.List; + +@ApiModel(value = "用户登录") +@Data +public class GaeaUserDto { + + @ApiModelProperty(value = "登录名") + @NotBlank + private String loginName; + + @ApiModelProperty(value = "密码") + @NotBlank + private String password; + + /** 真实用户 */ + private String realName; + + /** 登录成功后的 */ + private String token; + + /** 用户所拥有的权限合集 */ + private List authorities; +} diff --git a/src/main/java/com/anjiplus/template/gaea/business/modules/accessuser/controller/dto/UpdatePasswordDto.java b/src/main/java/com/anjiplus/template/gaea/business/modules/accessuser/controller/dto/UpdatePasswordDto.java new file mode 100644 index 0000000..daf8417 --- /dev/null +++ b/src/main/java/com/anjiplus/template/gaea/business/modules/accessuser/controller/dto/UpdatePasswordDto.java @@ -0,0 +1,25 @@ +package com.anjiplus.template.gaea.business.modules.accessuser.controller.dto; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +import javax.validation.constraints.NotBlank; +import java.util.List; + +@ApiModel(value = "修改密码") +@Data +public class UpdatePasswordDto { + + @ApiModelProperty(value = "旧密码密码") + @NotBlank + private String oldPassword; + + @ApiModelProperty(value = "密码") + @NotBlank + private String password; + + @ApiModelProperty(value = "密码") + @NotBlank + private String confirmPassword; +} diff --git a/src/main/java/com/anjiplus/template/gaea/business/modules/accessuser/controller/param/AccessUserParam.java b/src/main/java/com/anjiplus/template/gaea/business/modules/accessuser/controller/param/AccessUserParam.java new file mode 100644 index 0000000..0005c14 --- /dev/null +++ b/src/main/java/com/anjiplus/template/gaea/business/modules/accessuser/controller/param/AccessUserParam.java @@ -0,0 +1,37 @@ +/**/ +package com.anjiplus.template.gaea.business.modules.accessuser.controller.param; + +import lombok.Data; +import java.io.Serializable; +import com.anji.plus.gaea.annotation.Query; +import com.anji.plus.gaea.constant.QueryEnum; +import com.anji.plus.gaea.curd.params.PageParam; +import java.util.List; + +import java.util.Date; + +/** +* @desc AccessUser 用户管理查询输入类 +* @author 木子李·De +* @date 2019-02-17 08:50:11.902 +**/ +@Data +public class AccessUserParam extends PageParam implements Serializable{ + + //  登录名 + @Query(value = QueryEnum.LIKE) + private String loginName; + + // 真实用户 + @Query(value = QueryEnum.LIKE) + private String realName; + + // 手机号码 + @Query(value = QueryEnum.LIKE) + private String phone; + + // 0--已禁用 1--已启用 DIC_NAME=ENABLE_FLAG + @Query + private Integer enableFlag; + +} \ No newline at end of file diff --git a/src/main/java/com/anjiplus/template/gaea/business/modules/accessuser/dao/AccessUserMapper.java b/src/main/java/com/anjiplus/template/gaea/business/modules/accessuser/dao/AccessUserMapper.java new file mode 100644 index 0000000..0d8aa18 --- /dev/null +++ b/src/main/java/com/anjiplus/template/gaea/business/modules/accessuser/dao/AccessUserMapper.java @@ -0,0 +1,26 @@ +package com.anjiplus.template.gaea.business.modules.accessuser.dao; + +import org.apache.ibatis.annotations.Mapper; +import com.anji.plus.gaea.curd.mapper.GaeaBaseMapper; +import com.anjiplus.template.gaea.business.modules.accessuser.dao.entity.AccessUser; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.core.toolkit.Constants; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; + +import java.util.List; +/** +* AccessUser Mapper +* @author 木子李·De +* @date 2019-02-17 08:50:11.902 +**/ +@Mapper +public interface AccessUserMapper extends GaeaBaseMapper { + + /** 查询用户所拥有的所有角色下的权限 + * @param loginName + * @return + */ + List queryAuthoritiesByLoginName(@Param("loginName")String loginName); +} \ No newline at end of file diff --git a/src/main/java/com/anjiplus/template/gaea/business/modules/accessuser/dao/AccessUserRoleMapper.java b/src/main/java/com/anjiplus/template/gaea/business/modules/accessuser/dao/AccessUserRoleMapper.java new file mode 100644 index 0000000..2e4e687 --- /dev/null +++ b/src/main/java/com/anjiplus/template/gaea/business/modules/accessuser/dao/AccessUserRoleMapper.java @@ -0,0 +1,15 @@ +package com.anjiplus.template.gaea.business.modules.accessuser.dao; + +import com.anji.plus.gaea.curd.mapper.GaeaBaseMapper; +import com.anjiplus.template.gaea.business.modules.accessuser.dao.entity.AccessUserRole; +import org.apache.ibatis.annotations.Mapper; + +/** +* AccessUser Mapper +* @author 木子李·De +* @date 2019-02-17 08:50:11.902 +**/ +@Mapper +public interface AccessUserRoleMapper extends GaeaBaseMapper { + +} \ No newline at end of file diff --git a/src/main/java/com/anjiplus/template/gaea/business/modules/accessuser/dao/entity/AccessUser.java b/src/main/java/com/anjiplus/template/gaea/business/modules/accessuser/dao/entity/AccessUser.java new file mode 100644 index 0000000..5cd3815 --- /dev/null +++ b/src/main/java/com/anjiplus/template/gaea/business/modules/accessuser/dao/entity/AccessUser.java @@ -0,0 +1,48 @@ + +package com.anjiplus.template.gaea.business.modules.accessuser.dao.entity; + +import lombok.Data; +import com.anji.plus.gaea.curd.entity.GaeaBaseEntity; +import com.baomidou.mybatisplus.annotation.TableName; +import javax.validation.constraints.*; +import java.util.Date; +/** +* @description 用户管理 entity +* @author 木子李·De +* @date 2019-02-17 08:50:11.902 +**/ +@TableName(keepGlobalPrefix=true, value="access_user") +@Data +public class AccessUser extends GaeaBaseEntity { + + /**  登录名 */ + private String loginName; + + /** 密码 */ + private String password; + + /** 真实用户 */ + private String realName; + + /** 手机号码 */ + private String phone; + + /** 用户邮箱 */ + private String email; + + /** 备注 */ + private String remark; + + /** 0--已禁用 1--已启用 DIC_NAME=ENABLE_FLAG */ + private Integer enableFlag; + + /** 0--未删除 1--已删除 DIC_NAME=DEL_FLAG */ + private Integer deleteFlag; + + /** 最后一次登录IP */ + private String lastLoginIp; + + /** 最后一次登陆时间 */ + private Date lastLoginTime; + +} diff --git a/src/main/java/com/anjiplus/template/gaea/business/modules/accessuser/dao/entity/AccessUserRole.java b/src/main/java/com/anjiplus/template/gaea/business/modules/accessuser/dao/entity/AccessUserRole.java new file mode 100644 index 0000000..a56be7a --- /dev/null +++ b/src/main/java/com/anjiplus/template/gaea/business/modules/accessuser/dao/entity/AccessUserRole.java @@ -0,0 +1,40 @@ + +package com.anjiplus.template.gaea.business.modules.accessuser.dao.entity; + +import com.anji.plus.gaea.curd.entity.GaeaBaseEntity; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; + +import java.util.Date; + +/** +* @description 用户--角色关联关系 entity +* @author 木子李·De +* @date 2019-02-17 08:50:11.902 +**/ +@TableName(keepGlobalPrefix=true, value="access_user_role") +@Data +public class AccessUserRole extends GaeaBaseEntity { + + /**  登录名 */ + private String loginName; + + /** 角色编码 */ + private String roleCode; + + @TableField(exist = false) + private String createBy; + + @TableField(exist = false) + private Date createTime; + + @TableField(exist = false) + private String updateBy; + + @TableField(exist = false) + private Date updateTime; + + @TableField(exist = false) + private Integer version; +} diff --git a/src/main/java/com/anjiplus/template/gaea/business/modules/accessuser/service/AccessUserService.java b/src/main/java/com/anjiplus/template/gaea/business/modules/accessuser/service/AccessUserService.java new file mode 100644 index 0000000..900cee3 --- /dev/null +++ b/src/main/java/com/anjiplus/template/gaea/business/modules/accessuser/service/AccessUserService.java @@ -0,0 +1,52 @@ + +package com.anjiplus.template.gaea.business.modules.accessuser.service; + +import com.anjiplus.template.gaea.business.modules.accessuser.controller.dto.AccessUserDto; +import com.anjiplus.template.gaea.business.modules.accessuser.controller.dto.GaeaUserDto; +import com.anjiplus.template.gaea.business.modules.accessuser.controller.dto.UpdatePasswordDto; +import com.anjiplus.template.gaea.business.modules.accessuser.dao.entity.AccessUser; +import com.anjiplus.template.gaea.business.modules.accessuser.controller.param.AccessUserParam; +import com.anji.plus.gaea.curd.service.GaeaBaseService; + +import java.util.Map; + +/** +* @desc AccessUser 用户管理服务接口 +* @author 木子李·De +* @date 2019-02-17 08:50:11.902 +**/ +public interface AccessUserService extends GaeaBaseService { + + /** 获取用户的角色树 + * @param loginName 被操作的对象 + * @param operator 当前登录者 + * @return + */ + Map getRoleTree(String loginName, String operator); + + + /** 保存用户的角色树 + * @param accessUserDto + * @return + */ + Boolean saveRoleTree(AccessUserDto accessUserDto); + + /** 重置密码 + * @param gaeaUserDto + * @return + */ + Boolean resetPassword(GaeaUserDto gaeaUserDto); + + /** 用户登录 + * @param gaeaUserDto + * @return + */ + GaeaUserDto login(GaeaUserDto gaeaUserDto); + + /** + * 修改密码 + * @param dto + * @return + */ + Boolean updatePassword(UpdatePasswordDto dto); +} diff --git a/src/main/java/com/anjiplus/template/gaea/business/modules/accessuser/service/impl/AccessUserServiceImpl.java b/src/main/java/com/anjiplus/template/gaea/business/modules/accessuser/service/impl/AccessUserServiceImpl.java new file mode 100644 index 0000000..1ca1fe5 --- /dev/null +++ b/src/main/java/com/anjiplus/template/gaea/business/modules/accessuser/service/impl/AccessUserServiceImpl.java @@ -0,0 +1,277 @@ + +package com.anjiplus.template.gaea.business.modules.accessuser.service.impl; + +import com.alibaba.fastjson.JSONObject; +import com.anji.plus.gaea.bean.TreeNode; +import com.anji.plus.gaea.cache.CacheHelper; +import com.anji.plus.gaea.constant.BaseOperationEnum; +import com.anji.plus.gaea.constant.GaeaConstant; +import com.anji.plus.gaea.exception.BusinessException; +import com.anji.plus.gaea.exception.BusinessExceptionBuilder; +import com.anji.plus.gaea.curd.mapper.GaeaBaseMapper; +import com.anji.plus.gaea.holder.UserContentHolder; +import com.anji.plus.gaea.utils.GaeaUtils; +import com.anji.plus.gaea.utils.JwtBean; +import com.anjiplus.template.gaea.business.code.ResponseCode; +import com.anjiplus.template.gaea.business.constant.BusinessConstant; +import com.anjiplus.template.gaea.business.modules.accessrole.dao.AccessRoleAuthorityMapper; +import com.anjiplus.template.gaea.business.modules.accessrole.dao.AccessRoleMapper; +import com.anjiplus.template.gaea.business.modules.accessrole.dao.entity.AccessRole; +import com.anjiplus.template.gaea.business.modules.accessrole.dao.entity.AccessRoleAuthority; +import com.anjiplus.template.gaea.business.modules.accessuser.controller.dto.AccessUserDto; +import com.anjiplus.template.gaea.business.modules.accessuser.controller.dto.GaeaUserDto; +import com.anjiplus.template.gaea.business.modules.accessuser.controller.dto.UpdatePasswordDto; +import com.anjiplus.template.gaea.business.modules.accessuser.dao.AccessUserRoleMapper; +import com.anjiplus.template.gaea.business.modules.accessuser.dao.entity.AccessUser; +import com.anjiplus.template.gaea.business.modules.accessuser.dao.entity.AccessUserRole; +import com.anjiplus.template.gaea.business.modules.accessuser.service.AccessUserService; +import com.anjiplus.template.gaea.business.modules.accessuser.dao.AccessUserMapper; +import com.anjiplus.template.gaea.business.util.MD5Util; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import org.apache.commons.lang3.StringUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Service; + +import java.util.*; +import java.util.stream.Collectors; + +/** +* @desc AccessUser 用户管理服务实现 +* @author 木子李·De +* @date 2019-02-17 08:50:11.902 +**/ +@Service +public class AccessUserServiceImpl implements AccessUserService { + + @Autowired + private AccessRoleMapper accessRoleMapper; + + @Autowired + private AccessUserMapper accessUserMapper; + + @Autowired + private AccessUserRoleMapper accessUserRoleMapper; + + @Autowired + private AccessRoleAuthorityMapper accessRoleAuthorityMapper; + + @Value("${customer.user.default.password:'123456'}") + private String defaultPassword; + + @Override + public GaeaBaseMapper getMapper() { + return accessUserMapper; + } + + @Autowired + private JwtBean jwtBean; + + @Autowired + private CacheHelper cacheHelper; + + @Override + public Map getRoleTree(String loginName, String operator) { + Map result = new HashMap(); + List treeData = new ArrayList<>(); + List checkedKeys = new ArrayList(); + + // 角色树 + LambdaQueryWrapper roleQuery = Wrappers.lambdaQuery(); + roleQuery.select(AccessRole::getRoleCode, AccessRole::getRoleName); + // 按operator去筛选role 后面再加where + List roleList = accessRoleMapper.selectList(roleQuery); + if(roleList == null || roleList.isEmpty()){ + result.put("treeData", treeData); + result.put("checkedKeys", checkedKeys); + return result; + } + treeData = roleList.stream().map(role -> { + TreeNode treeNode = new TreeNode(); + treeNode.setId(role.getRoleCode()); + treeNode.setLabel(role.getRoleName()); + return treeNode; + }).collect(Collectors.toList()); + + // 该用户已保存的角色 + LambdaQueryWrapper queryWrapper = Wrappers.lambdaQuery(); + queryWrapper.select(AccessUserRole::getRoleCode) + .eq(AccessUserRole::getLoginName, loginName); + checkedKeys = accessUserRoleMapper.selectObjs(queryWrapper); + + result.put("treeData", treeData); + result.put("checkedKeys", checkedKeys); + return result; + } + + @Override + public Boolean saveRoleTree(AccessUserDto accessUserDto) { + // 校验 + String loginName = accessUserDto.getLoginName(); + List roleCodeList = accessUserDto.getRoleCodeList(); + if(StringUtils.isBlank(loginName)){ + throw BusinessExceptionBuilder.build(ResponseCode.NOT_EMPTY, loginName); + } + if(roleCodeList == null || roleCodeList.isEmpty()){ + throw BusinessExceptionBuilder.build(ResponseCode.NOT_EMPTY, roleCodeList); + } + + // 先清除该用户已保存的角色 + LambdaQueryWrapper wrapper = Wrappers.lambdaQuery(); + wrapper.eq(AccessUserRole::getLoginName, loginName); + accessUserRoleMapper.delete(wrapper); + + // 保存勾选的角色 + roleCodeList.stream().forEach(roleCode -> { + AccessUserRole accessUserRole = new AccessUserRole(); + accessUserRole.setLoginName(loginName); + accessUserRole.setRoleCode(roleCode); + accessUserRoleMapper.insert(accessUserRole); + }); + return true; + } + + @Override + public Boolean resetPassword(GaeaUserDto gaeaUserDto) { + String loginName = gaeaUserDto.getLoginName(); + if (GaeaConstant.SUPER_USER_NAME.equalsIgnoreCase(loginName)) { + throw BusinessExceptionBuilder.build("admin不允许重置密码"); + } + // 1.判断用户是否存在 + LambdaQueryWrapper wrapper = Wrappers.lambdaQuery(); + wrapper.eq(AccessUser::getLoginName, loginName); + AccessUser accessUser = accessUserMapper.selectOne(wrapper); + if (accessUser == null) { + throw BusinessExceptionBuilder.build("用户不存在"); + } + //默认密码 + accessUser.setPassword(MD5Util.encrypt(MD5Util.encrypt(defaultPassword.concat("gaea")))); + accessUserMapper.updateById(accessUser); + return true; + } + + @Override + public GaeaUserDto login(GaeaUserDto gaeaUserDto) { + + String loginName = gaeaUserDto.getLoginName(); + String password = gaeaUserDto.getPassword(); + + // 1.判断用户是否存在 + LambdaQueryWrapper wrapper = Wrappers.lambdaQuery(); + wrapper.eq(AccessUser::getLoginName, loginName); + AccessUser accessUser = accessUserMapper.selectOne(wrapper); + if (null == accessUser) { + throw BusinessExceptionBuilder.build(ResponseCode.LOGIN_ERROR); + } + // 2.密码错误 + if (!accessUser.getPassword().equals(MD5Util.encrypt(password))) { + throw BusinessExceptionBuilder.build(ResponseCode.USER_PASSWORD_ERROR); + } + + // 3.如果该用户登录未过期,这里允许一个用户在多个终端登录 + String tokenKey = String.format(BusinessConstant.GAEA_SECURITY_LOGIN_TOKEN, loginName); + String token = ""; + GaeaUserDto gaeaUser = new GaeaUserDto(); + if (cacheHelper.exist(tokenKey)) { + token = cacheHelper.stringGet(tokenKey); + } else { + // 生成用户token + String uuid = GaeaUtils.UUID(); + token = jwtBean.createToken(loginName, uuid, 0, GaeaConstant.TENANT_CODE); + cacheHelper.stringSetExpire(tokenKey, token, 3600); + } + + // 4.读取用户最新人权限主信息 + String userKey = String.format(BusinessConstant.GAEA_SECURITY_LOGIN_USER, loginName); + + //为了兼容底层其他数据库,不再写自定义sql +// List authorities = accessUserMapper.queryAuthoritiesByLoginName(loginName); + + //当前用户的roleCode集合 + LambdaQueryWrapper accessUserWrapper = Wrappers.lambdaQuery(); + accessUserWrapper.select(AccessUserRole::getRoleCode); + accessUserWrapper.eq(AccessUserRole::getLoginName, loginName); + List accessUserRoles = accessUserRoleMapper.selectList(accessUserWrapper); + Set roleCodeSet = accessUserRoles.stream().map(AccessUserRole::getRoleCode).collect(Collectors.toSet()); + if (roleCodeSet.size() < 1) { + gaeaUser.setAuthorities(new ArrayList<>()); + }else { + LambdaQueryWrapper accessRoleAuthorityWrapper = Wrappers.lambdaQuery(); + accessRoleAuthorityWrapper.select(AccessRoleAuthority::getTarget, AccessRoleAuthority::getAction); + accessRoleAuthorityWrapper.in(AccessRoleAuthority::getRoleCode, roleCodeSet); + List accessRoleAuthorities = accessRoleAuthorityMapper.selectList(accessRoleAuthorityWrapper); + List authorities = accessRoleAuthorities.stream() + .map(accessRoleAuthority -> accessRoleAuthority.getTarget().concat(":").concat(accessRoleAuthority.getAction())).distinct().collect(Collectors.toList()); + gaeaUser.setAuthorities(authorities); + } + + gaeaUser.setLoginName(loginName); + gaeaUser.setRealName(accessUser.getRealName()); + gaeaUser.setToken(token); + + String gaeaUserStr = JSONObject.toJSONString(gaeaUser); + cacheHelper.stringSetExpire(userKey, gaeaUserStr, 3600); + + return gaeaUser; + } + + /** + * 修改密码 + * + * @param dto + * @return + */ + @Override + public Boolean updatePassword(UpdatePasswordDto dto) { + if (!dto.getConfirmPassword().equals(dto.getPassword())) { + //密码和确认密码不一致 + throw BusinessExceptionBuilder.build(ResponseCode.USER_INCONSISTENT_PASSWORD_ERROR); + } + //新密码不能与老密码一样 + if(StringUtils.equals(dto.getOldPassword(), dto.getPassword())){ + throw BusinessExceptionBuilder.build(ResponseCode.USER_PASSWORD_CONFIG_PASSWORD_CANOT_EQUAL); + } + + String username = UserContentHolder.getUsername(); + + + LambdaQueryWrapper wrapper = Wrappers.lambdaQuery(); + wrapper.eq(AccessUser::getLoginName, username); + AccessUser accessUser = selectOne(wrapper); + String password = accessUser.getPassword(); + if (!MD5Util.encrypt(dto.getOldPassword()).equals(password)) { + throw BusinessExceptionBuilder.build(ResponseCode.USER_OLD_PASSWORD_ERROR); + } + accessUser.setPassword(MD5Util.encrypt(dto.getPassword())); + + accessUserMapper.updateById(accessUser); + return true; + } + + /** + * 操作前处理 + * + * @param entity 前端传递的对象 + * @param operationEnum 操作类型 + * @throws BusinessException 阻止程序继续执行或回滚事务 + */ + @Override + public void processBeforeOperation(AccessUser entity, BaseOperationEnum operationEnum) throws BusinessException { + //过滤密码 + switch (operationEnum) { + case INSERT: + //gaea是为了和前端加密保持一致 + entity.setPassword(MD5Util.encrypt(MD5Util.encrypt(defaultPassword.concat("gaea")))); + break; + case UPDATE: + //更新用户不允许修改密码 + entity.setPassword(null); + break; + default: + + break; + } + + } +} diff --git a/src/main/java/com/anjiplus/template/gaea/business/modules/dashboard/controller/ReportDashboardController.java b/src/main/java/com/anjiplus/template/gaea/business/modules/dashboard/controller/ReportDashboardController.java new file mode 100644 index 0000000..fdb66fb --- /dev/null +++ b/src/main/java/com/anjiplus/template/gaea/business/modules/dashboard/controller/ReportDashboardController.java @@ -0,0 +1,109 @@ + +package com.anjiplus.template.gaea.business.modules.dashboard.controller; + +import com.anji.plus.gaea.annotation.Permission; +import com.anji.plus.gaea.annotation.log.GaeaAuditLog; +import com.anji.plus.gaea.bean.ResponseBean; +import com.anjiplus.template.gaea.business.modules.dashboard.service.ReportDashboardService; +import com.anjiplus.template.gaea.business.modules.dashboard.controller.dto.ChartDto; +import com.anjiplus.template.gaea.business.modules.dashboard.controller.dto.ReportDashboardObjectDto; +import com.anjiplus.template.gaea.business.modules.reportshare.controller.dto.ReportShareDto; +import com.anjiplus.template.gaea.business.modules.reportshare.service.ReportShareService; +import io.swagger.annotations.Api; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.ResponseEntity; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; +import org.springframework.web.multipart.MultipartFile; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +/** +* @desc 大屏设计 controller +* @website https://gitee.com/anji-plus/gaea +* @author Raod +* @date 2021-04-12 14:52:21.761 +**/ +@RestController +@Api(tags = "大屏设计管理") +@Permission(code = "bigScreenManage", name = "大屏报表") +@RequestMapping("/reportDashboard") +public class ReportDashboardController { + + @Autowired + private ReportDashboardService reportDashboardService; + + @Autowired + private ReportShareService reportShareService; + + /** + * 预览、查询大屏详情 + * @param reportCode + * @return + */ + @GetMapping({"/{reportCode}"}) + @Permission(code = "view", name = "查看大屏") + public ResponseBean detail(@PathVariable("reportCode") String reportCode) { + return ResponseBean.builder().data(reportDashboardService.getDetail(reportCode)).build(); + } + + /** + * 保存大屏设计 + * @param dto + * @return + */ + @PostMapping + @Permission(code = "design", name = "设计大屏") + @GaeaAuditLog(pageTitle = "新增") + public ResponseBean insert(@RequestBody ReportDashboardObjectDto dto) { + reportDashboardService.insertDashboard(dto); + return ResponseBean.builder().build(); + } + + + /** + * 获取去单个图层数据 + * @param dto + * @return + */ + @PostMapping("/getData") + @Permission(code = "view", name = "查看大屏") + public ResponseBean getData(@RequestBody ChartDto dto) { + return ResponseBean.builder().data(reportDashboardService.getChartData(dto)).build(); + } + + + /** + * 导出大屏 + * @param reportCode + * @return + */ + @GetMapping("/export") + @Permission(code = "export", name = "导出大屏") + public ResponseEntity exportDashboard(HttpServletRequest request, HttpServletResponse response, + @RequestParam("reportCode") String reportCode, @RequestParam(value = "showDataSet",required = false, defaultValue = "1") Integer showDataSet) { + return reportDashboardService.exportDashboard(request, response, reportCode, showDataSet); + } + + /** + * 导入大屏 + * @param file 导入的zip文件 + * @param reportCode + * @return + */ + @PostMapping("/import/{reportCode}") + @Permission(code = "import", name = "导入大屏") + public ResponseBean importDashboard(@RequestParam("file") MultipartFile file, @PathVariable("reportCode") String reportCode) { + reportDashboardService.importDashboard(file, reportCode); + return ResponseBean.builder().build(); + } + + @PostMapping("/share") + @GaeaAuditLog(pageTitle = "分享") + @Permission(code = "share", name = "分享报表") + public ResponseBean share(@Validated @RequestBody ReportShareDto dto) { + return ResponseBean.builder().data(reportShareService.insertShare(dto)).build(); + } + +} diff --git a/src/main/java/com/anjiplus/template/gaea/business/modules/dashboard/controller/dto/ChartDto.java b/src/main/java/com/anjiplus/template/gaea/business/modules/dashboard/controller/dto/ChartDto.java new file mode 100644 index 0000000..d6b67f8 --- /dev/null +++ b/src/main/java/com/anjiplus/template/gaea/business/modules/dashboard/controller/dto/ChartDto.java @@ -0,0 +1,51 @@ + +package com.anjiplus.template.gaea.business.modules.dashboard.controller.dto; + +import lombok.Data; + +import java.io.Serializable; +import java.util.Map; + + +/** +* +* @description 大屏设计 dto +* @author Raod +* @date 2021-04-12 14:52:21.761 +**/ +@Data +public class ChartDto implements Serializable { + + private String chartType; + + /**数据集编码*/ + private String setCode; + + /** 传入的自定义参数*/ + private Map contextData; + + /**图表属性*/ + private Map chartProperties; + + /**时间字段*/ + private String timeLineFiled; + + /**时间颗粒度*/ + private String particles; + + /**时间格式化*/ + private String dataTimeFormat; + + /**时间展示层*/ + private String timeLineFormat; + + private int timeUnit; + + /**时间区间*/ + private String startTime; + + /**时间区间*/ + private String endTime; + + +} diff --git a/src/main/java/com/anjiplus/template/gaea/business/modules/dashboard/controller/dto/ReportDashboardDto.java b/src/main/java/com/anjiplus/template/gaea/business/modules/dashboard/controller/dto/ReportDashboardDto.java new file mode 100644 index 0000000..6812352 --- /dev/null +++ b/src/main/java/com/anjiplus/template/gaea/business/modules/dashboard/controller/dto/ReportDashboardDto.java @@ -0,0 +1,55 @@ + +package com.anjiplus.template.gaea.business.modules.dashboard.controller.dto; + +import com.anji.plus.gaea.curd.dto.GaeaBaseDTO; +import com.anjiplus.template.gaea.business.modules.dashboardwidget.controller.dto.ReportDashboardWidgetDto; +import lombok.Data; + +import java.io.Serializable; +import java.util.List; + + +/** +* +* @description 大屏设计 dto +* @author Raod +* @date 2021-04-12 14:52:21.761 +**/ +@Data +public class ReportDashboardDto extends GaeaBaseDTO implements Serializable { + /** 报表编码 */ + private String reportCode; + + /** 看板标题 */ + private String title; + + /** 宽度px */ + private Long width; + + /** 高度px */ + private Long height; + + /** 背景色 */ + private String backgroundColor; + + /** 背景图片 */ + private String backgroundImage; + + /** 工作台中的辅助线 */ + private String presetLine; + + /** 自动刷新间隔秒,数据字典REFRESH_TYPE */ + private Integer refreshSeconds; + + /** 0--已禁用 1--已启用 DIC_NAME=ENABLE_FLAG */ + private Integer enableFlag; + + /** 0--未删除 1--已删除 DIC_NAME=DEL_FLAG */ + private Integer deleteFlag; + + /** 排序,降序 */ + private Integer sort; + + private List widgets; + +} diff --git a/src/main/java/com/anjiplus/template/gaea/business/modules/dashboard/controller/dto/ReportDashboardObjectDto.java b/src/main/java/com/anjiplus/template/gaea/business/modules/dashboard/controller/dto/ReportDashboardObjectDto.java new file mode 100644 index 0000000..cc4ca08 --- /dev/null +++ b/src/main/java/com/anjiplus/template/gaea/business/modules/dashboard/controller/dto/ReportDashboardObjectDto.java @@ -0,0 +1,32 @@ + +package com.anjiplus.template.gaea.business.modules.dashboard.controller.dto; + +import com.anjiplus.template.gaea.business.modules.dashboardwidget.controller.dto.ReportDashboardWidgetDto; +import lombok.Data; + +import java.io.Serializable; +import java.util.List; + + +/** +* +* @description 大屏设计 dto +* @author Raod +* @date 2021-04-12 14:52:21.761 +**/ +@Data +public class ReportDashboardObjectDto implements Serializable { + + /** 报表编码 */ + private String reportCode; + /** + * 报表编码 + */ + private ReportDashboardDto dashboard; + + /** + * 大屏画布中的组件 + */ + private List widgets; + +} diff --git a/src/main/java/com/anjiplus/template/gaea/business/modules/dashboard/controller/param/ReportDashboardParam.java b/src/main/java/com/anjiplus/template/gaea/business/modules/dashboard/controller/param/ReportDashboardParam.java new file mode 100644 index 0000000..d044b96 --- /dev/null +++ b/src/main/java/com/anjiplus/template/gaea/business/modules/dashboard/controller/param/ReportDashboardParam.java @@ -0,0 +1,20 @@ +/**/ +package com.anjiplus.template.gaea.business.modules.dashboard.controller.param; + +import lombok.Data; +import java.io.Serializable; +import com.anji.plus.gaea.annotation.Query; +import com.anji.plus.gaea.constant.QueryEnum; +import com.anji.plus.gaea.curd.params.PageParam; + +import java.util.List; + + +/** +* @desc ReportDashboard 大屏设计查询输入类 +* @author Raod +* @date 2021-04-12 14:52:21.761 +**/ +@Data +public class ReportDashboardParam extends PageParam implements Serializable{ +} diff --git a/src/main/java/com/anjiplus/template/gaea/business/modules/dashboard/dao/ReportDashboardMapper.java b/src/main/java/com/anjiplus/template/gaea/business/modules/dashboard/dao/ReportDashboardMapper.java new file mode 100644 index 0000000..173e822 --- /dev/null +++ b/src/main/java/com/anjiplus/template/gaea/business/modules/dashboard/dao/ReportDashboardMapper.java @@ -0,0 +1,16 @@ +package com.anjiplus.template.gaea.business.modules.dashboard.dao; + +import org.apache.ibatis.annotations.Mapper; + +import com.anji.plus.gaea.curd.mapper.GaeaBaseMapper; +import com.anjiplus.template.gaea.business.modules.dashboard.dao.entity.ReportDashboard; + +/** +* ReportDashboard Mapper +* @author Raod +* @date 2021-04-12 14:52:21.761 +**/ +@Mapper +public interface ReportDashboardMapper extends GaeaBaseMapper { + +} diff --git a/src/main/java/com/anjiplus/template/gaea/business/modules/dashboard/dao/entity/ReportDashboard.java b/src/main/java/com/anjiplus/template/gaea/business/modules/dashboard/dao/entity/ReportDashboard.java new file mode 100644 index 0000000..76ad6cb --- /dev/null +++ b/src/main/java/com/anjiplus/template/gaea/business/modules/dashboard/dao/entity/ReportDashboard.java @@ -0,0 +1,54 @@ + +package com.anjiplus.template.gaea.business.modules.dashboard.dao.entity; + +import com.anji.plus.gaea.annotation.Unique; +import com.anji.plus.gaea.curd.entity.GaeaBaseEntity; +import com.anjiplus.template.gaea.business.code.ResponseCode; +import com.baomidou.mybatisplus.annotation.TableName; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +/** +* @description 大屏设计 entity +* @author Raod +* @date 2021-04-12 14:52:21.761 +**/ +@TableName(keepGlobalPrefix=true, value="gaea_report_dashboard") +@Data +public class ReportDashboard extends GaeaBaseEntity { + @ApiModelProperty(value = "报表编码") + @Unique(code = ResponseCode.REPORT_CODE_ISEXIST) + private String reportCode; + + @ApiModelProperty(value = "看板标题") + private String title; + + @ApiModelProperty(value = "宽度px") + private Long width; + + @ApiModelProperty(value = "高度px") + private Long height; + + @ApiModelProperty(value = "背景色") + private String backgroundColor; + + @ApiModelProperty(value = "背景图片") + private String backgroundImage; + + @ApiModelProperty(value = "工作台中的辅助线") + private String presetLine; + + @ApiModelProperty(value = "自动刷新间隔秒,数据字典REFRESH_TYPE") + private Integer refreshSeconds; + + @ApiModelProperty(value = "0--已禁用 1--已启用 DIC_NAME=ENABLE_FLAG") + private Integer enableFlag; + + @ApiModelProperty(value = " 0--未删除 1--已删除 DIC_NAME=DEL_FLAG") + private Integer deleteFlag; + + @ApiModelProperty(value = "排序,降序") + private Integer sort; + + +} diff --git a/src/main/java/com/anjiplus/template/gaea/business/modules/dashboard/service/ChartStrategy.java b/src/main/java/com/anjiplus/template/gaea/business/modules/dashboard/service/ChartStrategy.java new file mode 100644 index 0000000..ccaa4b0 --- /dev/null +++ b/src/main/java/com/anjiplus/template/gaea/business/modules/dashboard/service/ChartStrategy.java @@ -0,0 +1,26 @@ +package com.anjiplus.template.gaea.business.modules.dashboard.service; + +import com.alibaba.fastjson.JSONObject; +import com.anjiplus.template.gaea.business.modules.dashboard.controller.dto.ChartDto; + +import java.util.List; + +/** + * Created by raodeming on 2021/4/26. + */ +public interface ChartStrategy { + + /** + * 图表类型 + * @return + */ + String type(); + + /** + * 针对每种图表类型做单独的数据转换解析 + * + * @param dto + * @return + */ + Object transform(ChartDto dto, List data); +} diff --git a/src/main/java/com/anjiplus/template/gaea/business/modules/dashboard/service/ReportDashboardService.java b/src/main/java/com/anjiplus/template/gaea/business/modules/dashboard/service/ReportDashboardService.java new file mode 100644 index 0000000..2b8c1e3 --- /dev/null +++ b/src/main/java/com/anjiplus/template/gaea/business/modules/dashboard/service/ReportDashboardService.java @@ -0,0 +1,61 @@ + +package com.anjiplus.template.gaea.business.modules.dashboard.service; + +import com.anji.plus.gaea.curd.service.GaeaBaseService; +import com.anjiplus.template.gaea.business.modules.dashboard.controller.dto.ChartDto; +import com.anjiplus.template.gaea.business.modules.dashboard.controller.dto.ReportDashboardObjectDto; +import com.anjiplus.template.gaea.business.modules.dashboard.controller.param.ReportDashboardParam; +import com.anjiplus.template.gaea.business.modules.dashboard.dao.entity.ReportDashboard; +import org.springframework.http.ResponseEntity; +import org.springframework.web.multipart.MultipartFile; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +/** +* @desc ReportDashboard 大屏设计服务接口 +* @author Raod +* @date 2021-04-12 14:52:21.761 +**/ +public interface ReportDashboardService extends GaeaBaseService { + + /*** + * 查询详情 + * + * @param reportCode + */ + ReportDashboardObjectDto getDetail(String reportCode); + + /*** + * 保存大屏设计 + * + * @param dto + */ + void insertDashboard(ReportDashboardObjectDto dto); + + + /** + * 获取单个图表数据 + * @param dto + * @return + */ + Object getChartData(ChartDto dto); + + + /** + * 导出大屏,zip文件 + * @param request + * @param response + * @param reportCode + * @return + */ + ResponseEntity exportDashboard(HttpServletRequest request, HttpServletResponse response, String reportCode, Integer showDataSet); + + /** + * 导入大屏zip + * @param file + * @param reportCode + * @return + */ + void importDashboard(MultipartFile file, String reportCode); +} diff --git a/src/main/java/com/anjiplus/template/gaea/business/modules/dashboard/service/impl/BarChartServiceImpl.java b/src/main/java/com/anjiplus/template/gaea/business/modules/dashboard/service/impl/BarChartServiceImpl.java new file mode 100644 index 0000000..7874721 --- /dev/null +++ b/src/main/java/com/anjiplus/template/gaea/business/modules/dashboard/service/impl/BarChartServiceImpl.java @@ -0,0 +1,79 @@ +package com.anjiplus.template.gaea.business.modules.dashboard.service.impl; + +import com.alibaba.fastjson.JSONObject; +import com.anjiplus.template.gaea.business.modules.dashboard.controller.dto.ChartDto; +import com.anjiplus.template.gaea.business.modules.dashboard.service.ChartStrategy; +import org.springframework.stereotype.Component; + +import java.util.List; + +/** + * 柱状体或者折线图 + * Created by raodeming on 2021/4/26. + */ +@Component +public class BarChartServiceImpl implements ChartStrategy { + /** + * 图表类型 + * + * @return + */ + @Override + public String type() { + return "widget-barchart|widget-linechart"; + } + + /** + * 针对每种图表类型做单独的数据转换解析 + * + * @param dto + * @param data + * @return + */ + @Override + public Object transform(ChartDto dto, List data) { +// JSONObject json = new JSONObject(); +// List xAxis = new ArrayList<>(); +// List series = new ArrayList<>(); +// data.forEach(jsonObject -> { +// jsonObject.forEach((s, o) -> { +// if ("xAxis".equals(s)) { +// xAxis.add(o); +// } else { +// series.add(o); +// } +// }); +// }); +// +// json.put("xAxis", xAxis); +// JSONArray objects = new JSONArray(); +// JSONObject jsonObject = new JSONObject(); +// jsonObject.put("data", series); +// objects.add(jsonObject); +// json.put("series", objects); +// return json.toJSONString(); + return data; + } + + +/* { + "xAxis": [ + "哈哈", + "洗洗", + "来了", + "问问", + "天天" + ], + "series": [ + { + "data": [ + 1, + 2, + 3, + 4, + 5 + ] + } + ] + }*/ +} diff --git a/src/main/java/com/anjiplus/template/gaea/business/modules/dashboard/service/impl/BarLineChartServiceImpl.java b/src/main/java/com/anjiplus/template/gaea/business/modules/dashboard/service/impl/BarLineChartServiceImpl.java new file mode 100644 index 0000000..032620c --- /dev/null +++ b/src/main/java/com/anjiplus/template/gaea/business/modules/dashboard/service/impl/BarLineChartServiceImpl.java @@ -0,0 +1,105 @@ +package com.anjiplus.template.gaea.business.modules.dashboard.service.impl; + +import com.alibaba.fastjson.JSONObject; +import com.anjiplus.template.gaea.business.modules.dashboard.controller.dto.ChartDto; +import com.anjiplus.template.gaea.business.modules.dashboard.service.ChartStrategy; +import org.springframework.stereotype.Component; + +import java.util.List; + +/** + * 折柱图 + * Created by raodeming on 2021/4/26. + */ +@Component +public class BarLineChartServiceImpl implements ChartStrategy { + /** + * 图表类型 + * + * @return + */ + @Override + public String type() { + return "widget-barlinechart"; + } + + /** + * 针对每种图表类型做单独的数据转换解析 + * + * @param dto + * @param data + * @return + */ + @Override + public Object transform(ChartDto dto, List data) { +// JSONObject json = new JSONObject(); +// List xAxis = new ArrayList<>(); +// Map> series = new HashMap<>(); +// data.forEach(jsonObject -> { +// jsonObject.forEach((s, o) -> { +// if ("xAxis".equals(s)) { +// xAxis.add(o); +// } else { +// List objects; +// if (series.containsKey(s)) { +// objects = series.get(s); +// } else { +// objects = new ArrayList<>(); +// +// } +// objects.add(o); +// series.put(s, objects); +// +// } +// }); +// }); +// +// json.put("xAxis", xAxis); +// List result = new ArrayList<>(); +// series.forEach((s, objects) -> { +// JSONObject jsonObject = new JSONObject(); +// jsonObject.put("name", s); +// if (s.endsWith("bar")) { +// jsonObject.put("type", "bar"); +// } else { +// jsonObject.put("type", "line"); +// } +// jsonObject.put("data", objects); +// result.add(jsonObject); +// }); +// json.put("series", result); +// return json.toJSONString(); + return data; + } + + + /*{ + "xAxis": [ + "1月", + "2月", + "3月" + ], + "series": [ + { + "name": "指标1", //暂时用不上 + "type": "bar", //需要处理 + "data": [ + 2, + 49, + 2 + ] + }, + { + "name": "指标2", + "type": "line", + "yAxisIndex": 1, + "data": [ + 2, + 32, + 4 + ] + } + ] + }*/ + +} diff --git a/src/main/java/com/anjiplus/template/gaea/business/modules/dashboard/service/impl/GaugeChartServiceImpl.java b/src/main/java/com/anjiplus/template/gaea/business/modules/dashboard/service/impl/GaugeChartServiceImpl.java new file mode 100644 index 0000000..89fbe6f --- /dev/null +++ b/src/main/java/com/anjiplus/template/gaea/business/modules/dashboard/service/impl/GaugeChartServiceImpl.java @@ -0,0 +1,43 @@ +package com.anjiplus.template.gaea.business.modules.dashboard.service.impl; + +import com.alibaba.fastjson.JSONObject; +import com.anjiplus.template.gaea.business.modules.dashboard.controller.dto.ChartDto; +import com.anjiplus.template.gaea.business.modules.dashboard.service.ChartStrategy; +import org.springframework.stereotype.Component; + +import java.util.List; + +/** + * 饼图或者空心饼图或者漏斗图 + * Created by raodeming on 2021/4/26. + */ +@Component +public class GaugeChartServiceImpl implements ChartStrategy { + /** + * 图表类型 + * + * @return + */ + @Override + public String type() { + return "widget-gauge"; + } + + /** + * 针对每种图表类型做单独的数据转换解析 + * + * @param dto + * @param data + * @return + */ + @Override + public Object transform(ChartDto dto, List data) { + +// return "{\"value\": 50, \"name\": \"名称1\", \"unit\": \"%\"}"; + return data; + } + + + + +} diff --git a/src/main/java/com/anjiplus/template/gaea/business/modules/dashboard/service/impl/PieChartServiceImpl.java b/src/main/java/com/anjiplus/template/gaea/business/modules/dashboard/service/impl/PieChartServiceImpl.java new file mode 100644 index 0000000..5f1ffbf --- /dev/null +++ b/src/main/java/com/anjiplus/template/gaea/business/modules/dashboard/service/impl/PieChartServiceImpl.java @@ -0,0 +1,52 @@ +package com.anjiplus.template.gaea.business.modules.dashboard.service.impl; + +import com.alibaba.fastjson.JSONObject; +import com.anjiplus.template.gaea.business.modules.dashboard.controller.dto.ChartDto; +import com.anjiplus.template.gaea.business.modules.dashboard.service.ChartStrategy; +import org.springframework.stereotype.Component; + +import java.util.List; + +/** + * 饼图或者空心饼图或者漏斗图 + * Created by raodeming on 2021/4/26. + */ +@Component +public class PieChartServiceImpl implements ChartStrategy { + /** + * 图表类型 + * + * @return + */ + @Override + public String type() { + return "widget-piechart|widget-hollow-piechart|widget-funnel"; + } + + /** + * 针对每种图表类型做单独的数据转换解析 + * + * @param dto + * @param data + * @return + */ + @Override + public Object transform(ChartDto dto, List data) { + + return data; + } + +/* [ + { + "value": 11, + "name": "指标1" + }, + { + "value": 10, + "name": "指标2" + } + ]*/ + + + +} diff --git a/src/main/java/com/anjiplus/template/gaea/business/modules/dashboard/service/impl/ReportDashboardServiceImpl.java b/src/main/java/com/anjiplus/template/gaea/business/modules/dashboard/service/impl/ReportDashboardServiceImpl.java new file mode 100644 index 0000000..8cf36c4 --- /dev/null +++ b/src/main/java/com/anjiplus/template/gaea/business/modules/dashboard/service/impl/ReportDashboardServiceImpl.java @@ -0,0 +1,561 @@ + +package com.anjiplus.template.gaea.business.modules.dashboard.service.impl; + +import com.alibaba.fastjson.JSONObject; +import com.anji.plus.gaea.curd.mapper.GaeaBaseMapper; +import com.anji.plus.gaea.exception.BusinessExceptionBuilder; +import com.anji.plus.gaea.utils.GaeaAssert; +import com.anji.plus.gaea.utils.GaeaBeanUtils; +import com.anjiplus.template.gaea.business.code.ResponseCode; +import com.anjiplus.template.gaea.business.modules.dashboard.controller.dto.ChartDto; +import com.anjiplus.template.gaea.business.modules.dashboard.controller.dto.ReportDashboardDto; +import com.anjiplus.template.gaea.business.modules.dashboard.controller.dto.ReportDashboardObjectDto; +import com.anjiplus.template.gaea.business.modules.dashboard.dao.ReportDashboardMapper; +import com.anjiplus.template.gaea.business.modules.dashboard.service.ChartStrategy; +import com.anjiplus.template.gaea.business.modules.dashboard.service.ReportDashboardService; +import com.anjiplus.template.gaea.business.modules.file.entity.GaeaFile; +import com.anjiplus.template.gaea.business.modules.file.service.GaeaFileService; +import com.anjiplus.template.gaea.business.modules.file.util.FileUtils; +import com.anjiplus.template.gaea.business.modules.report.service.ReportService; +import com.anjiplus.template.gaea.business.util.DateUtil; +import com.anjiplus.template.gaea.business.modules.dashboardwidget.controller.dto.ReportDashboardWidgetDto; +import com.anjiplus.template.gaea.business.modules.dashboardwidget.controller.dto.ReportDashboardWidgetValueDto; +import com.anjiplus.template.gaea.business.modules.dashboard.dao.entity.ReportDashboard; +import com.anjiplus.template.gaea.business.modules.dashboardwidget.dao.entity.ReportDashboardWidget; +import com.anjiplus.template.gaea.business.modules.dashboardwidget.service.ReportDashboardWidgetService; +import com.anjiplus.template.gaea.business.modules.dataset.controller.dto.DataSetDto; +import com.anjiplus.template.gaea.business.modules.dataset.controller.dto.OriginalDataDto; +import com.anjiplus.template.gaea.business.modules.dataset.service.DataSetService; +import com.anjiplus.template.gaea.business.util.FileUtil; +import com.anjiplus.template.gaea.business.util.RequestUtil; +import com.anjiplus.template.gaea.business.util.UuidUtil; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.springframework.beans.BeanUtils; +import org.springframework.beans.BeansException; +import org.springframework.beans.factory.InitializingBean; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.ApplicationContext; +import org.springframework.context.ApplicationContextAware; +import org.springframework.http.MediaType; +import org.springframework.http.ResponseEntity; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.web.multipart.MultipartFile; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.File; +import java.net.URLEncoder; +import java.text.SimpleDateFormat; +import java.util.*; +import java.util.concurrent.CompletableFuture; + +/** + * @author Raod + * @desc ReportDashboard 大屏设计服务实现 + * @date 2021-04-12 14:52:21.761 + **/ +@Service +@Slf4j +//@RequiredArgsConstructor +public class ReportDashboardServiceImpl implements ReportDashboardService, InitializingBean, ApplicationContextAware { + + @Autowired + private ReportDashboardMapper reportDashboardMapper; + + @Autowired + private ReportDashboardWidgetService reportDashboardWidgetService; + + @Autowired + private DataSetService dataSetService; + + @Autowired + private GaeaFileService gaeaFileService; + + @Autowired + private ReportService reportService; + + @Value("${spring.gaea.subscribes.oss.downloadPath:}") + private String fileDownloadPath; + + @Value("${customer.file.tmp-path:.}") + private String dictPath; + + private final static String ZIP_PATH = "/tmp_zip/"; + private final static String JSON_PATH = "dashboard.json"; + + private Map queryServiceImplMap = new HashMap<>(); + private ApplicationContext applicationContext; + + @Override + public GaeaBaseMapper getMapper() { + return reportDashboardMapper; + } + + @Override + public ReportDashboardObjectDto getDetail(String reportCode) { + ReportDashboardObjectDto result = new ReportDashboardObjectDto(); + ReportDashboardDto reportDashboardDto = new ReportDashboardDto(); + ReportDashboard reportDashboard = this.selectOne("report_code", reportCode); + if (null == reportDashboard) { + return new ReportDashboardObjectDto(); + } + GaeaBeanUtils.copyAndFormatter(reportDashboard, reportDashboardDto); + + List list = reportDashboardWidgetService.list( + new QueryWrapper().lambda() + .eq(ReportDashboardWidget::getReportCode, reportCode) + .orderByAsc(ReportDashboardWidget::getSort) + ); + List reportDashboardWidgetDtoList = new ArrayList<>(); + list.forEach(reportDashboardWidget -> { + ReportDashboardWidgetDto reportDashboardWidgetDto = new ReportDashboardWidgetDto(); + ReportDashboardWidgetValueDto value = new ReportDashboardWidgetValueDto(); + value.setSetup(StringUtils.isNotBlank(reportDashboardWidget.getSetup()) ? JSONObject.parseObject(reportDashboardWidget.getSetup()) : new JSONObject()); + value.setData(StringUtils.isNotBlank(reportDashboardWidget.getData()) ? JSONObject.parseObject(reportDashboardWidget.getData()) : new JSONObject()); + value.setPosition(StringUtils.isNotBlank(reportDashboardWidget.getPosition()) ? JSONObject.parseObject(reportDashboardWidget.getPosition()) : new JSONObject()); + value.setCollapse(StringUtils.isNotBlank(reportDashboardWidget.getCollapse()) ? JSONObject.parseObject(reportDashboardWidget.getCollapse()) : new JSONObject()); + + //实时数据的替换 + analysisData(value); + reportDashboardWidgetDto.setType(reportDashboardWidget.getType()); + reportDashboardWidgetDto.setValue(value); + reportDashboardWidgetDto.setOptions(JSONObject.parseObject(reportDashboardWidget.getOptions())); + reportDashboardWidgetDtoList.add(reportDashboardWidgetDto); + }); + reportDashboardDto.setWidgets(reportDashboardWidgetDtoList); + result.setDashboard(reportDashboardDto); + result.setReportCode(reportCode); + return result; + } + + /*** + * 保存大屏设计 + * + * @param dto + */ + @Override + @Transactional(rollbackFor = Exception.class) + public void insertDashboard(ReportDashboardObjectDto dto) { + String reportCode = dto.getReportCode(); + GaeaAssert.notEmpty(reportCode, ResponseCode.PARAM_IS_NULL, "reportCode"); + //查询ReportDashboard + ReportDashboard reportDashboard = this.selectOne("report_code", reportCode); + ReportDashboard dashboard = new ReportDashboard(); + GaeaBeanUtils.copyAndFormatter(dto.getDashboard(), dashboard); + BeanUtils.copyProperties(dto.getDashboard(), dashboard); + dashboard.setReportCode(reportCode); + if (null == reportDashboard) { + //新增 + this.insert(dashboard); + } else { + //更新 + dashboard.setId(reportDashboard.getId()); + dashboard.setVersion(null); + this.update(dashboard); + } + + //删除reportDashboardWidget + reportDashboardWidgetService.delete(new QueryWrapper() + .lambda().eq(ReportDashboardWidget::getReportCode, reportCode)); + List widgets = dto.getWidgets(); + +// List reportDashboardWidgetList = new ArrayList<>(); + for (int i = 0; i < widgets.size(); i++) { + ReportDashboardWidget reportDashboardWidget = new ReportDashboardWidget(); + ReportDashboardWidgetDto reportDashboardWidgetDto = widgets.get(i); + String type = reportDashboardWidgetDto.getType(); + ReportDashboardWidgetValueDto value = reportDashboardWidgetDto.getValue(); + reportDashboardWidget.setReportCode(reportCode); + reportDashboardWidget.setType(type); + reportDashboardWidget.setSetup(value.getSetup() != null ? JSONObject.toJSONString(value.getSetup()) : ""); + reportDashboardWidget.setData(value.getData() != null ? JSONObject.toJSONString(value.getData()) : ""); + reportDashboardWidget.setPosition(value.getPosition() != null ? JSONObject.toJSONString(value.getPosition()) : ""); + reportDashboardWidget.setCollapse(value.getCollapse() != null ? JSONObject.toJSONString(value.getCollapse()) : ""); + reportDashboardWidget.setOptions(reportDashboardWidgetDto.getOptions() != null ? JSONObject.toJSONString(reportDashboardWidgetDto.getOptions()) : ""); + reportDashboardWidget.setEnableFlag(1); + reportDashboardWidget.setDeleteFlag(0); + reportDashboardWidget.setSort((long) (i + 1)); + + //兼容底层,不采用批量插入 + reportDashboardWidgetService.insert(reportDashboardWidget); + +// reportDashboardWidgetList.add(reportDashboardWidget); + } +// reportDashboardWidgetService.insertBatch(reportDashboardWidgetList); + + } + + @Override + public Object getChartData(ChartDto dto) { +// String chartType = dto.getChartType(); + DataSetDto setDto = new DataSetDto(); + setDto.setSetCode(dto.getSetCode()); + setDto.setContextData(dto.getContextData()); + OriginalDataDto result = dataSetService.getData(setDto); + List data = result.getData(); + //处理时间轴 + List resultData = buildTimeLine(data, dto); + return resultData; +// return getTarget(chartType).transform(dto, result.getData()); + } + + /** + * 导出大屏,zip文件 + * + * @param request + * @param response + * @param reportCode + * @return + */ + @Override + public ResponseEntity exportDashboard(HttpServletRequest request, HttpServletResponse response, String reportCode, Integer showDataSet) { + String userAgent = request.getHeader("User-Agent"); + boolean isIeBrowser = userAgent.indexOf("MSIE") > 0; + + ReportDashboardObjectDto detail = getDetail(reportCode); + List widgets = detail.getDashboard().getWidgets(); + detail.setWidgets(widgets); + detail.getDashboard().setWidgets(null); + + + //1.组装临时目录,/app/disk/upload/zip/临时文件夹 + String path = dictPath + ZIP_PATH + UuidUtil.generateShortUuid(); + + //将涉及到的图片保存下来(1.背景图,2.组件为图片的) + String backgroundImage = detail.getDashboard().getBackgroundImage(); + zipLoadImage(backgroundImage, path); + detail.getWidgets().stream() + .filter(reportDashboardWidgetDto -> "widget-image".equals(reportDashboardWidgetDto.getType())) + .forEach(reportDashboardWidgetDto -> { + String imageAddress = reportDashboardWidgetDto.getValue().getSetup().getString("imageAdress"); + zipLoadImage(imageAddress, path); + }); + + //showDataSet == 0 代表不包含数据集 + if (0 == showDataSet) { + detail.getWidgets().forEach(reportDashboardWidgetDto -> { + ReportDashboardWidgetValueDto value = reportDashboardWidgetDto.getValue(); + JSONObject data = value.getData(); + if (null != data && data.containsKey("dataType")) { + reportDashboardWidgetDto.getValue().getData().put("dataType", "staticData"); + } + }); + } + + + //2.将大屏设计到的json文件保存 + String jsonPath = path + "/" + JSON_PATH; + FileUtil.WriteStringToFile(jsonPath, JSONObject.toJSONString(detail)); + + + //将path文件夹打包zip + String zipPath = path + ".zip"; + FileUtil.compress(path, zipPath); + + + File file = new File(zipPath); + ResponseEntity.BodyBuilder builder = ResponseEntity.ok(); + builder.contentLength(file.length()); + //application/octet-stream 二进制数据流(最常见的文件下载) + builder.contentType(MediaType.APPLICATION_OCTET_STREAM); + if (isIeBrowser) { + builder.header("Content-Disposition", "attachment; filename=" + reportCode + ".zip"); + } else { + builder.header("Content-Disposition", "attacher; filename*=UTF-8''" + reportCode + ".zip"); + } + + ResponseEntity body = builder.body(FileUtils.readFileToByteArray(file)); + + //删除zip文件 + file.delete(); + //删除path临时文件夹 + FileUtil.delete(path); + log.info("删除临时文件:{},{}", zipPath, path); + + //异步统计下载次数 + CompletableFuture.runAsync(() -> { + log.info("=======>ip:{} 下载模板:{}", RequestUtil.getIpAddr(request), reportCode); + reportService.downloadStatistics(reportCode); + }); + + + return body; + } + + /** + * 导入大屏zip + * + * @param file + * @param reportCode + * @return + */ + @Override + @Transactional(rollbackFor = Exception.class) + public void importDashboard(MultipartFile file, String reportCode) { + log.info("导入开始,{}", reportCode); + //1.组装临时目录,/app/disk/upload/zip/临时文件夹 + String path = dictPath + ZIP_PATH + UuidUtil.generateShortUuid(); + //2.解压 + FileUtil.decompress(file, path); + // path/uuid/ + File parentPath = new File(path); + //获取打包的第一层目录 + File firstFile = parentPath.listFiles()[0]; + + File[] files = firstFile.listFiles(); + + //定义map + Map fileMap = new HashMap<>(); + String content = ""; + + for (int i = 0; i < files.length; i++) { + File childFile = files[i]; + if (JSON_PATH.equals(childFile.getName())) { + //json文件 + content = FileUtil.readFile(childFile); + } else if ("image".equals(childFile.getName())) { + File[] imageFiles = childFile.listFiles(); + //所有需要上传的图片 + for (File imageFile : imageFiles) { + //查看是否存在此image + String fileName = imageFile.getName().split("\\.")[0]; + //根据fileId,从gaea_file中读出filePath + LambdaQueryWrapper queryWrapper = Wrappers.lambdaQuery(); + queryWrapper.eq(GaeaFile::getFileId, fileName); + GaeaFile gaeaFile = gaeaFileService.selectOne(queryWrapper); + String uploadPath; + if (null == gaeaFile) { + GaeaFile upload = gaeaFileService.upload(imageFile); + log.info("存入图片: {}", upload.getFilePath()); + uploadPath = upload.getUrlPath(); + }else { + uploadPath = gaeaFile.getUrlPath(); + } + fileMap.put(fileName, uploadPath); + } + } + + } + + + //解析cotent + ReportDashboardObjectDto detail = JSONObject.parseObject(content, ReportDashboardObjectDto.class); + //将涉及到的图片路径替换(1.背景图,2.组件为图片的) + String backgroundImage = detail.getDashboard().getBackgroundImage(); + detail.getDashboard().setBackgroundImage(replaceUrl(backgroundImage, fileMap)); + detail.getWidgets().stream() + .filter(reportDashboardWidgetDto -> "widget-image".equals(reportDashboardWidgetDto.getType())) + .forEach(reportDashboardWidgetDto -> { + String imageAddress = reportDashboardWidgetDto.getValue().getSetup().getString("imageAdress"); + String address = replaceUrl(imageAddress, fileMap); + reportDashboardWidgetDto.getValue().getSetup().put("imageAdress", address); + reportDashboardWidgetDto.getOptions().getJSONArray("setup").getJSONObject(4).put("value", address); + }); + //将新的大屏编码赋值 + detail.setReportCode(reportCode); + + //解析结束,删除临时文件夹 + FileUtil.delete(path); + + log.info("解析成功,开始存入数据库..."); + insertDashboard(detail); + } + + + private String replaceUrl(String imageAddress, Map fileMap) { + if (StringUtils.isBlank(imageAddress)) { + return ""; + } + String fileId = imageAddress.substring(imageAddress.trim().length() - 36); + String orDefault = fileMap.getOrDefault(fileId, null); + if (StringUtils.isBlank(orDefault)) { + return imageAddress; + } + return orDefault; + } + + /** + * 将大屏涉及到的图片存入指定文件夹 + * @param imageAddress + * @param path + */ + private void zipLoadImage(String imageAddress, String path) { + //http://10.108.26.197:9095/file/download/1d9bcd35-82a1-4f08-9465-b66b930b6a8d + if (imageAddress.trim().startsWith(fileDownloadPath)) { + //以fileDownloadPath为前缀的代表为上传的图片 + String fileName = imageAddress.substring(fileDownloadPath.length() + 1); + //根据fileId,从gaea_file中读出filePath + LambdaQueryWrapper queryWrapper = Wrappers.lambdaQuery(); + queryWrapper.eq(GaeaFile::getFileId, fileName); + GaeaFile gaeaFile = gaeaFileService.selectOne(queryWrapper); + if (null != gaeaFile) { + byte[] file = gaeaFileService.getFile(gaeaFile.getFileId()); + path = path + "/image/"; + FileUtil.byte2File(file, path, gaeaFile.getFileId().concat(".").concat(gaeaFile.getFileType())); + } + } + + } + + public ChartStrategy getTarget(String type) { + for (String s : queryServiceImplMap.keySet()) { + if (s.contains(type)) { + return queryServiceImplMap.get(s); + } + } + throw BusinessExceptionBuilder.build(ResponseCode.RULE_CONTENT_NOT_EXIST); + } + + @Override + public void afterPropertiesSet() { + Map beanMap = applicationContext.getBeansOfType(ChartStrategy.class); + //遍历该接口的所有实现,将其放入map中 + for (ChartStrategy serviceImpl : beanMap.values()) { + queryServiceImplMap.put(serviceImpl.type(), serviceImpl); + } + } + + @Override + public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { + this.applicationContext = applicationContext; + } + + + /** + * 解析图层数据 + * + * @param dto + */ + public void analysisData(ReportDashboardWidgetValueDto dto) { +// if (StringUtils.isBlank(reportDashboardWidgetDto.getSetCode())) { +// return; +// } +// DataSetDto dto = new DataSetDto(); +// dto.setSetCode(reportDashboardWidgetDto.getSetCode()); +// if (reportDashboardWidgetDto.getContextData() != null && reportDashboardWidgetDto.getContextData().size() > 0) { +// dto.setContextData(reportDashboardWidgetDto.getContextData()); +// } +// OriginalDataDto data = dataSetService.getData(dto); +// reportDashboardWidgetDto.setData(JSONObject.toJSONString(data.getData())); + } + + + public List buildTimeLine(List data, ChartDto dto) { + Map chartProperties = dto.getChartProperties(); + if (null == chartProperties || chartProperties.size() < 1) { + return data; + } + Map contextData = dto.getContextData(); + if (null == contextData || contextData.size() < 1) { + return data; + } + if (contextData.containsKey("startTime") && contextData.containsKey("endTime")) { + dto.setStartTime(contextData.get("startTime").toString()); + dto.setEndTime(contextData.get("endTime").toString()); + } + if (StringUtils.isBlank(dto.getStartTime()) || StringUtils.isBlank(dto.getEndTime())) { + return data; + } + //获取时间轴字段和解析时间颗粒度 + + for (Map.Entry entry : chartProperties.entrySet()) { + String key = entry.getKey(); + String value = entry.getValue(); + dto.setParticles(value); + setTimeLineFormat(dto); + if (StringUtils.isNotBlank(dto.getDataTimeFormat())) { + dto.setTimeLineFiled(key); + break; + } + + } + + + if (StringUtils.isBlank(dto.getDataTimeFormat())) { + return data; + } + + Date beginTime = DateUtil.parseHmsTime(dto.getStartTime()); + Date endTime = DateUtil.parseHmsTime(dto.getEndTime()); + SimpleDateFormat showFormat = new SimpleDateFormat(dto.getTimeLineFormat()); + SimpleDateFormat dataFormat = new SimpleDateFormat(dto.getDataTimeFormat()); + + + Calendar calendar = Calendar.getInstance(); + calendar.setTime(beginTime); + + Calendar calendarEnd = Calendar.getInstance(); + calendarEnd.setTime(endTime); + + List timeLine = new ArrayList<>(); + List dataTimeline = new ArrayList<>(); + timeLine.add(showFormat.format(calendar.getTime())); + dataTimeline.add(dataFormat.format(calendar.getTime())); + + //添加时间轴数据 + while (true) { + calendar.add(dto.getTimeUnit(), 1); + timeLine.add(showFormat.format(calendar.getTime())); + dataTimeline.add(dataFormat.format(calendar.getTime())); + if (showFormat.format(calendar.getTime()).equals(showFormat.format(calendarEnd.getTime()))) { + break; + } + } + + //根据时间轴生成对应的时间线,数据不存在,补数据 + List result = new ArrayList<>(); + JSONObject jsonDemo = data.get(0); + String timeLineFiled = dto.getTimeLineFiled(); + for (String dateFormat : dataTimeline) { + boolean flag = true; + for (JSONObject datum : data) { + if (datum.containsKey(timeLineFiled) && datum.getString(timeLineFiled).equals(dateFormat)) { + result.add(datum); + flag = false; + } + } + if (flag) { + //补数据 + JSONObject json = new JSONObject(); + jsonDemo.forEach((s, o) -> { + if (s.equals(timeLineFiled)) { + json.put(timeLineFiled, dateFormat); + } else { + json.put(s, 0); + } + }); + result.add(json); + } + + } + return result; + } + + //设置时间格式 + private void setTimeLineFormat(ChartDto dto) { + String particles = dto.getParticles(); + if ("xAxis-hour".equals(particles)) { + dto.setDataTimeFormat("yyyy-MM-dd HH"); + dto.setTimeLineFormat("MM-dd HH"); + dto.setTimeUnit(Calendar.HOUR); + } else if ("xAxis-day".equals(particles)) { + dto.setDataTimeFormat("yyyy-MM-dd"); + dto.setTimeLineFormat("yyyy-MM-dd"); + dto.setTimeUnit(Calendar.DATE); + } else if ("xAxis-month".equals(particles)) { + dto.setDataTimeFormat("yyyy-MM"); + dto.setTimeLineFormat("yyyy-MM"); + dto.setTimeUnit(Calendar.MONTH); + } else if ("xAxis-year".equals(particles)) { + dto.setDataTimeFormat("yyyy"); + dto.setTimeLineFormat("yyyy"); + dto.setTimeUnit(Calendar.YEAR); + } + } +} diff --git a/src/main/java/com/anjiplus/template/gaea/business/modules/dashboardwidget/controller/dto/ReportDashboardWidgetDto.java b/src/main/java/com/anjiplus/template/gaea/business/modules/dashboardwidget/controller/dto/ReportDashboardWidgetDto.java new file mode 100644 index 0000000..a8538c2 --- /dev/null +++ b/src/main/java/com/anjiplus/template/gaea/business/modules/dashboardwidget/controller/dto/ReportDashboardWidgetDto.java @@ -0,0 +1,34 @@ + +package com.anjiplus.template.gaea.business.modules.dashboardwidget.controller.dto; + +import com.alibaba.fastjson.JSONObject; +import lombok.Data; + +import java.io.Serializable; + + +/** +* +* @description 大屏看板数据渲染 dto +* @author Raod +* @date 2021-04-12 15:12:43.724 +**/ +@Data +public class ReportDashboardWidgetDto implements Serializable { + + /** + * 组件类型参考字典DASHBOARD_PANEL_TYPE + */ + private String type; + + /** + * value + */ + private ReportDashboardWidgetValueDto value; + + /** + * options + */ + private JSONObject options; + +} diff --git a/src/main/java/com/anjiplus/template/gaea/business/modules/dashboardwidget/controller/dto/ReportDashboardWidgetValueDto.java b/src/main/java/com/anjiplus/template/gaea/business/modules/dashboardwidget/controller/dto/ReportDashboardWidgetValueDto.java new file mode 100644 index 0000000..51b660a --- /dev/null +++ b/src/main/java/com/anjiplus/template/gaea/business/modules/dashboardwidget/controller/dto/ReportDashboardWidgetValueDto.java @@ -0,0 +1,47 @@ + +package com.anjiplus.template.gaea.business.modules.dashboardwidget.controller.dto; + +import com.alibaba.fastjson.JSONObject; +import lombok.Data; + +import java.io.Serializable; + + +/** +* +* @description 大屏看板数据渲染 dto,已弃用 +* @author Raod +* @date 2021-04-12 15:12:43.724 +**/ +@Data +public class ReportDashboardWidgetValueDto implements Serializable { + /** 报表编码 */ + private String reportCode; + + /** 组件的渲染属性json */ + private JSONObject setup; + + /** 组件的数据属性json */ + private JSONObject data; + + /** 组件的配置属性json */ + private JSONObject collapse; + + /** 组件的大小位置属性json */ + private JSONObject position; + + private String options; + + /** 自动刷新间隔秒 */ + private Integer refreshSeconds; + + /** 0--已禁用 1--已启用 DIC_NAME=ENABLE_FLAG */ + private Integer enableFlag; + + /** 0--未删除 1--已删除 DIC_NAME=DEL_FLAG */ + private Integer deleteFlag; + + /** 排序,图层的概念 */ + private Long sort; + +} diff --git a/src/main/java/com/anjiplus/template/gaea/business/modules/dashboardwidget/controller/param/ReportDashboardWidgetParam.java b/src/main/java/com/anjiplus/template/gaea/business/modules/dashboardwidget/controller/param/ReportDashboardWidgetParam.java new file mode 100644 index 0000000..09f54bf --- /dev/null +++ b/src/main/java/com/anjiplus/template/gaea/business/modules/dashboardwidget/controller/param/ReportDashboardWidgetParam.java @@ -0,0 +1,20 @@ +/**/ +package com.anjiplus.template.gaea.business.modules.dashboardwidget.controller.param; + +import lombok.Data; +import java.io.Serializable; +import com.anji.plus.gaea.annotation.Query; +import com.anji.plus.gaea.constant.QueryEnum; +import com.anji.plus.gaea.curd.params.PageParam; + +import java.util.List; + + +/** +* @desc ReportDashboardWidget 大屏看板数据渲染查询输入类 +* @author Raod +* @date 2021-04-12 15:12:43.724 +**/ +@Data +public class ReportDashboardWidgetParam extends PageParam implements Serializable{ +} diff --git a/src/main/java/com/anjiplus/template/gaea/business/modules/dashboardwidget/dao/ReportDashboardWidgetMapper.java b/src/main/java/com/anjiplus/template/gaea/business/modules/dashboardwidget/dao/ReportDashboardWidgetMapper.java new file mode 100644 index 0000000..2570c7f --- /dev/null +++ b/src/main/java/com/anjiplus/template/gaea/business/modules/dashboardwidget/dao/ReportDashboardWidgetMapper.java @@ -0,0 +1,16 @@ +package com.anjiplus.template.gaea.business.modules.dashboardwidget.dao; + +import org.apache.ibatis.annotations.Mapper; + +import com.anji.plus.gaea.curd.mapper.GaeaBaseMapper; +import com.anjiplus.template.gaea.business.modules.dashboardwidget.dao.entity.ReportDashboardWidget; + +/** +* ReportDashboardWidget Mapper +* @author Raod +* @date 2021-04-12 15:12:43.724 +**/ +@Mapper +public interface ReportDashboardWidgetMapper extends GaeaBaseMapper { + +} diff --git a/src/main/java/com/anjiplus/template/gaea/business/modules/dashboardwidget/dao/entity/ReportDashboardWidget.java b/src/main/java/com/anjiplus/template/gaea/business/modules/dashboardwidget/dao/entity/ReportDashboardWidget.java new file mode 100644 index 0000000..2631236 --- /dev/null +++ b/src/main/java/com/anjiplus/template/gaea/business/modules/dashboardwidget/dao/entity/ReportDashboardWidget.java @@ -0,0 +1,50 @@ + +package com.anjiplus.template.gaea.business.modules.dashboardwidget.dao.entity; + +import com.anji.plus.gaea.curd.entity.GaeaBaseEntity; +import com.baomidou.mybatisplus.annotation.TableName; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +/** +* @description 大屏看板数据渲染 entity +* @author Raod +* @date 2021-04-12 15:12:43.724 +**/ +@TableName(keepGlobalPrefix=true, value="gaea_report_dashboard_widget") +@Data +public class ReportDashboardWidget extends GaeaBaseEntity { + @ApiModelProperty(value = "报表编码") + private String reportCode; + + @ApiModelProperty(value = "组件类型参考字典DASHBOARD_PANEL_TYPE") + private String type; + + @ApiModelProperty(value = "组件的渲染属性json") + private String setup; + + @ApiModelProperty(value = "组件的数据属性json") + private String data; + + @ApiModelProperty(value = "组件的配置属性json") + private String collapse; + + @ApiModelProperty(value = "组件的大小位置属性json") + private String position; + + private String options; + + @ApiModelProperty(value = "自动刷新间隔秒") + private Integer refreshSeconds; + + @ApiModelProperty(value = "0--已禁用 1--已启用 DIC_NAME=ENABLE_FLAG") + private Integer enableFlag; + + @ApiModelProperty(value = " 0--未删除 1--已删除 DIC_NAME=DEL_FLAG") + private Integer deleteFlag; + + @ApiModelProperty(value = "排序,图层的概念") + private Long sort; + + +} diff --git a/src/main/java/com/anjiplus/template/gaea/business/modules/dashboardwidget/service/ReportDashboardWidgetService.java b/src/main/java/com/anjiplus/template/gaea/business/modules/dashboardwidget/service/ReportDashboardWidgetService.java new file mode 100644 index 0000000..367030c --- /dev/null +++ b/src/main/java/com/anjiplus/template/gaea/business/modules/dashboardwidget/service/ReportDashboardWidgetService.java @@ -0,0 +1,21 @@ + +package com.anjiplus.template.gaea.business.modules.dashboardwidget.service; + +import com.anjiplus.template.gaea.business.modules.dashboardwidget.controller.param.ReportDashboardWidgetParam; +import com.anjiplus.template.gaea.business.modules.dashboardwidget.dao.entity.ReportDashboardWidget; +import com.anji.plus.gaea.curd.service.GaeaBaseService; + +/** +* @desc ReportDashboardWidget 大屏看板数据渲染服务接口 +* @author Raod +* @date 2021-04-12 15:12:43.724 +**/ +public interface ReportDashboardWidgetService extends GaeaBaseService { + + /*** + * 查询详情 + * + * @param id + */ + ReportDashboardWidget getDetail(Long id); +} diff --git a/src/main/java/com/anjiplus/template/gaea/business/modules/dashboardwidget/service/impl/ReportDashboardWidgetServiceImpl.java b/src/main/java/com/anjiplus/template/gaea/business/modules/dashboardwidget/service/impl/ReportDashboardWidgetServiceImpl.java new file mode 100644 index 0000000..11f0a06 --- /dev/null +++ b/src/main/java/com/anjiplus/template/gaea/business/modules/dashboardwidget/service/impl/ReportDashboardWidgetServiceImpl.java @@ -0,0 +1,34 @@ + +package com.anjiplus.template.gaea.business.modules.dashboardwidget.service.impl; + +import com.anji.plus.gaea.curd.mapper.GaeaBaseMapper; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import com.anjiplus.template.gaea.business.modules.dashboardwidget.dao.entity.ReportDashboardWidget; +import com.anjiplus.template.gaea.business.modules.dashboardwidget.service.ReportDashboardWidgetService; +import com.anjiplus.template.gaea.business.modules.dashboardwidget.dao.ReportDashboardWidgetMapper; +/** +* @desc ReportDashboardWidget 大屏看板数据渲染服务实现 +* @author Raod +* @date 2021-04-12 15:12:43.724 +**/ +@Service +//@RequiredArgsConstructor +public class ReportDashboardWidgetServiceImpl implements ReportDashboardWidgetService { + + @Autowired + private ReportDashboardWidgetMapper reportDashboardWidgetMapper; + + @Override + public GaeaBaseMapper getMapper() { + return reportDashboardWidgetMapper; + } + + @Override + public ReportDashboardWidget getDetail(Long id) { + ReportDashboardWidget reportDashboardWidget = this.selectOne(id); + return reportDashboardWidget; + } +} diff --git a/src/main/java/com/anjiplus/template/gaea/business/modules/dataset/controller/DataSetController.java b/src/main/java/com/anjiplus/template/gaea/business/modules/dataset/controller/DataSetController.java new file mode 100644 index 0000000..88a24bf --- /dev/null +++ b/src/main/java/com/anjiplus/template/gaea/business/modules/dataset/controller/DataSetController.java @@ -0,0 +1,145 @@ + +package com.anjiplus.template.gaea.business.modules.dataset.controller; + +import com.anji.plus.gaea.annotation.AccessKey; +import com.anji.plus.gaea.annotation.Permission; +import com.anji.plus.gaea.annotation.log.GaeaAuditLog; +import com.anji.plus.gaea.bean.ResponseBean; +import com.anji.plus.gaea.curd.controller.GaeaBaseController; +import com.anji.plus.gaea.curd.service.GaeaBaseService; +import com.anji.plus.gaea.holder.UserContentHolder; +import com.anji.plus.gaea.utils.GaeaUtils; +import com.anjiplus.template.gaea.business.modules.dataset.controller.dto.DataSetDto; +import com.anjiplus.template.gaea.business.modules.dataset.controller.param.DataSetParam; +import com.anjiplus.template.gaea.business.modules.dataset.controller.param.DataSetTestTransformParam; +import com.anjiplus.template.gaea.business.modules.dataset.dao.entity.DataSet; +import com.anjiplus.template.gaea.business.modules.dataset.service.DataSetService; +import io.swagger.annotations.Api; +import org.springframework.beans.BeanUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +/** +* @desc 数据集 controller +* @website https://gitee.com/anji-plus/gaea +* @author Raod +* @date 2021-03-18 12:11:31.150755900 +**/ +@RestController +@Api(tags = "数据集管理") +@Permission(code = "resultsetManage", name = "数据集管理") +@RequestMapping("/dataSet") +public class DataSetController extends GaeaBaseController { + + @Autowired + private DataSetService dataSetService; + + @Override + public GaeaBaseService getService() { + return dataSetService; + } + + @Override + public DataSet getEntity() { + return new DataSet(); + } + + @Override + public DataSetDto getDTO() { + return new DataSetDto(); + } + + @GetMapping("/detailBysetId/{id}") + @Permission( code = "query", name = "明细" ) + public ResponseBean detailBysetId(@PathVariable("id") Long id) { + this.logger.info("{}根据ID查询服务开始,id为:{}", this.getClass().getSimpleName(), id); + ResponseBean responseBean = this.responseSuccessWithData(dataSetService.detailSet(id)); + this.logger.info("{}根据ID查询结束,结果:{}", this.getClass().getSimpleName(), GaeaUtils.toJSONString(responseBean)); + return responseBean; + } + + @GetMapping({"/detailBysetCode/{setCode}"}) + @Permission( code = "query", name = "明细" ) + @AccessKey + public ResponseBean detailBysetCode(@PathVariable("setCode") String setCode) { + this.logger.info("{}根据setCode查询服务开始,setCode为:{}", this.getClass().getSimpleName(), setCode); + ResponseBean responseBean = this.responseSuccessWithData(dataSetService.detailSet(setCode)); + this.logger.info("{}根据setCode查询结束,结果:{}", this.getClass().getSimpleName(), GaeaUtils.toJSONString(responseBean)); + return responseBean; + } + + @PostMapping + @Permission( + code = "insert", + name = "新增" + ) + @GaeaAuditLog( + pageTitle = "新增" + ) + @Override + public ResponseBean insert(@RequestBody DataSetDto dto) { + this.logger.info("{}新增服务开始,参数:{}", this.getClass().getSimpleName(), GaeaUtils.toJSONString(dto)); + DataSetDto dataSetDto = dataSetService.insertSet(dto); + this.logger.info("{}新增服务结束,结果:{}", this.getClass().getSimpleName(), GaeaUtils.toJSONString(dataSetDto)); + return ResponseBean.builder().data(dataSetDto).build(); + } + + @PutMapping + @Permission( + code = "update", + name = "更新" + ) + @GaeaAuditLog( + pageTitle = "修改" + ) + @Override + public ResponseBean update(@RequestBody DataSetDto dto) { + String username = UserContentHolder.getContext().getUsername(); + this.logger.info("{}更新服务开始,更新人:{},参数:{}", this.getClass().getSimpleName(), username, GaeaUtils.toJSONString(dto)); + ResponseBean responseBean = this.responseSuccess(); + dataSetService.updateSet(dto); + this.logger.info("{}更新服务结束,结果:{}", this.getClass().getSimpleName(), GaeaUtils.toJSONString(responseBean)); + return this.responseSuccess(); + } + + @DeleteMapping({"/{id}"}) + @Permission( + code = "delete", + name = "删除" + ) + @GaeaAuditLog( + pageTitle = "删除" + ) + @Override + public ResponseBean deleteById(@PathVariable("id") Long id) { + this.logger.info("{}删除服务开始,参数ID:{}", this.getClass().getSimpleName(), id); + dataSetService.deleteSet(id); + this.logger.info("{}删除服务结束", this.getClass().getSimpleName()); + return this.responseSuccess(); + } + + /** + * 测试 数据转换是否正确 + * @param param + * @return + */ + @PostMapping("/testTransform") + @Permission( code = "query", name = "明细" ) + public ResponseBean testTransform(@Validated @RequestBody DataSetTestTransformParam param) { + DataSetDto dto = new DataSetDto(); + BeanUtils.copyProperties(param, dto); + return responseSuccessWithData(dataSetService.testTransform(dto)); + } + + /** + * 获取所有数据集 + * @return + */ + @GetMapping("/queryAllDataSet") + public ResponseBean queryAllDataSet() { + return responseSuccessWithData(dataSetService.queryAllDataSet()); + } + + +} diff --git a/src/main/java/com/anjiplus/template/gaea/business/modules/dataset/controller/dto/DataSetDto.java b/src/main/java/com/anjiplus/template/gaea/business/modules/dataset/controller/dto/DataSetDto.java new file mode 100644 index 0000000..2647a91 --- /dev/null +++ b/src/main/java/com/anjiplus/template/gaea/business/modules/dataset/controller/dto/DataSetDto.java @@ -0,0 +1,65 @@ + +package com.anjiplus.template.gaea.business.modules.dataset.controller.dto; + +import com.anji.plus.gaea.curd.dto.GaeaBaseDTO; +import com.anjiplus.template.gaea.business.modules.datasetparam.controller.dto.DataSetParamDto; +import com.anjiplus.template.gaea.business.modules.datasettransform.controller.dto.DataSetTransformDto; +import lombok.Data; + +import java.io.Serializable; +import java.util.List; +import java.util.Map; +import java.util.Set; + + +/** +* +* @description 数据集 dto +* @author Raod +* @date 2021-03-18 12:11:31.150755900 +**/ +@Data +public class DataSetDto extends GaeaBaseDTO implements Serializable { + /** 数据集编码 */ + private String setCode; + + /** 数据集名称 */ + private String setName; + + /** 数据集描述 */ + private String setDesc; + + /** 数据集类型 */ + private String setType; + + + /** 数据源编码 */ + private String sourceCode; + + /** 动态查询sql或者接口中的请求体 */ + private String dynSentence; + + /** 结果案例 */ + private String caseResult; + + /** 0--已禁用 1--已启用 DIC_NAME=ENABLE_FLAG */ + private Integer enableFlag; + + /** 0--未删除 1--已删除 DIC_NAME=DELETE_FLAG */ + private Integer deleteFlag; + + /** 请求参数集合 */ + private List dataSetParamDtoList; + + /** 数据转换集合 */ + private List dataSetTransformDtoList; + + /** 传入的自定义参数*/ + private Map contextData; + + private Set setParamList; + + /**指定字段*/ + private String fieldLabel; + +} diff --git a/src/main/java/com/anjiplus/template/gaea/business/modules/dataset/controller/dto/OriginalDataDto.java b/src/main/java/com/anjiplus/template/gaea/business/modules/dataset/controller/dto/OriginalDataDto.java new file mode 100644 index 0000000..c33d1fe --- /dev/null +++ b/src/main/java/com/anjiplus/template/gaea/business/modules/dataset/controller/dto/OriginalDataDto.java @@ -0,0 +1,32 @@ +package com.anjiplus.template.gaea.business.modules.dataset.controller.dto; + +import com.alibaba.fastjson.JSONObject; +import lombok.Data; + +import java.io.Serializable; +import java.util.List; + +/** + * Created by raodeming on 2021/3/26. + */ +@Data +public class OriginalDataDto implements Serializable { + + /**总数*/ + private long total; + + /**获取的数据详情*/ + private List data; + + public OriginalDataDto(List data) { + this.data = data; + } + + public OriginalDataDto(long total, List data) { + this.total = total; + this.data = data; + } + + public OriginalDataDto() { + } +} diff --git a/src/main/java/com/anjiplus/template/gaea/business/modules/dataset/controller/param/DataSetParam.java b/src/main/java/com/anjiplus/template/gaea/business/modules/dataset/controller/param/DataSetParam.java new file mode 100644 index 0000000..9730302 --- /dev/null +++ b/src/main/java/com/anjiplus/template/gaea/business/modules/dataset/controller/param/DataSetParam.java @@ -0,0 +1,34 @@ +/**/ +package com.anjiplus.template.gaea.business.modules.dataset.controller.param; + +import com.anji.plus.gaea.annotation.Query; +import com.anji.plus.gaea.constant.QueryEnum; +import com.anji.plus.gaea.curd.params.PageParam; +import lombok.Data; + +import java.io.Serializable; + + +/** +* @desc DataSet 数据集查询输入类 +* @author Raod +* @date 2021-03-18 12:11:31.150755900 +**/ +@Data +public class DataSetParam extends PageParam implements Serializable{ + /** 数据集编码 */ + @Query(QueryEnum.LIKE) + private String setCode; + + /** 数据集名称 */ + @Query(QueryEnum.LIKE) + private String setName; + + /** 数据源编码 */ + @Query(QueryEnum.EQ) + private String sourceCode; + + /** 数据集类型 */ + @Query(QueryEnum.EQ) + private String setType; +} diff --git a/src/main/java/com/anjiplus/template/gaea/business/modules/dataset/controller/param/DataSetTestTransformParam.java b/src/main/java/com/anjiplus/template/gaea/business/modules/dataset/controller/param/DataSetTestTransformParam.java new file mode 100644 index 0000000..8b13181 --- /dev/null +++ b/src/main/java/com/anjiplus/template/gaea/business/modules/dataset/controller/param/DataSetTestTransformParam.java @@ -0,0 +1,36 @@ +/**/ +package com.anjiplus.template.gaea.business.modules.dataset.controller.param; + +import com.anjiplus.template.gaea.business.modules.datasetparam.controller.dto.DataSetParamDto; +import com.anjiplus.template.gaea.business.modules.datasettransform.controller.dto.DataSetTransformDto; +import lombok.Data; + +import javax.validation.constraints.NotBlank; +import java.io.Serializable; +import java.util.List; + + +/** +* @desc DataSet 数据集查询输入类 +* @author Raod +* @date 2021-03-18 12:11:31.150755900 +**/ +@Data +public class DataSetTestTransformParam implements Serializable{ + + /** 数据源编码 */ + private String sourceCode; + + /** 动态查询sql或者接口中的请求体 */ + private String dynSentence; + + /** 数据集类型 */ + private String setType; + + /** 请求参数集合 */ + private List dataSetParamDtoList; + + /** 数据转换集合 */ + private List dataSetTransformDtoList; + +} diff --git a/src/main/java/com/anjiplus/template/gaea/business/modules/dataset/dao/DataSetMapper.java b/src/main/java/com/anjiplus/template/gaea/business/modules/dataset/dao/DataSetMapper.java new file mode 100644 index 0000000..d8514e4 --- /dev/null +++ b/src/main/java/com/anjiplus/template/gaea/business/modules/dataset/dao/DataSetMapper.java @@ -0,0 +1,16 @@ +package com.anjiplus.template.gaea.business.modules.dataset.dao; + +import org.apache.ibatis.annotations.Mapper; + +import com.anji.plus.gaea.curd.mapper.GaeaBaseMapper; +import com.anjiplus.template.gaea.business.modules.dataset.dao.entity.DataSet; + +/** +* DataSet Mapper +* @author Raod +* @date 2021-03-18 12:11:31.150755900 +**/ +@Mapper +public interface DataSetMapper extends GaeaBaseMapper { + +} diff --git a/src/main/java/com/anjiplus/template/gaea/business/modules/dataset/dao/entity/DataSet.java b/src/main/java/com/anjiplus/template/gaea/business/modules/dataset/dao/entity/DataSet.java new file mode 100644 index 0000000..d9313b5 --- /dev/null +++ b/src/main/java/com/anjiplus/template/gaea/business/modules/dataset/dao/entity/DataSet.java @@ -0,0 +1,48 @@ + +package com.anjiplus.template.gaea.business.modules.dataset.dao.entity; + +import com.anji.plus.gaea.annotation.Unique; +import com.anji.plus.gaea.curd.entity.GaeaBaseEntity; +import com.anjiplus.template.gaea.business.code.ResponseCode; +import com.baomidou.mybatisplus.annotation.TableName; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +/** +* @description 数据集 entity +* @author Raod +* @date 2021-03-18 12:11:31.150755900 +**/ +@TableName(keepGlobalPrefix=true, value="gaea_report_data_set") +@Data +public class DataSet extends GaeaBaseEntity { + @ApiModelProperty(value = "数据集编码") + @Unique(code = ResponseCode.SET_CODE_ISEXIST) + private String setCode; + + @ApiModelProperty(value = "数据集名称") + private String setName; + + @ApiModelProperty(value = "数据集描述") + private String setDesc; + + @ApiModelProperty(value = "数据集类型") + private String setType; + + @ApiModelProperty(value = "数据源编码") + private String sourceCode; + + @ApiModelProperty(value = "动态查询sql或者接口中的请求体") + private String dynSentence; + + @ApiModelProperty(value = "结果案例") + private String caseResult; + + @ApiModelProperty(value = "0--已禁用 1--已启用 DIC_NAME=ENABLE_FLAG") + private Integer enableFlag; + + @ApiModelProperty(value = "0--未删除 1--已删除 DIC_NAME=DELETE_FLAG") + private Integer deleteFlag; + + +} diff --git a/src/main/java/com/anjiplus/template/gaea/business/modules/dataset/service/DataSetService.java b/src/main/java/com/anjiplus/template/gaea/business/modules/dataset/service/DataSetService.java new file mode 100644 index 0000000..8d37e3f --- /dev/null +++ b/src/main/java/com/anjiplus/template/gaea/business/modules/dataset/service/DataSetService.java @@ -0,0 +1,70 @@ + +package com.anjiplus.template.gaea.business.modules.dataset.service; + +import com.anji.plus.gaea.curd.service.GaeaBaseService; +import com.anjiplus.template.gaea.business.modules.dataset.controller.dto.DataSetDto; +import com.anjiplus.template.gaea.business.modules.dataset.controller.dto.OriginalDataDto; +import com.anjiplus.template.gaea.business.modules.dataset.controller.param.DataSetParam; +import com.anjiplus.template.gaea.business.modules.dataset.dao.entity.DataSet; + +import java.util.List; + +/** +* @desc DataSet 数据集服务接口 +* @author Raod +* @date 2021-03-18 12:11:31.150755900 +**/ +public interface DataSetService extends GaeaBaseService { + + /** + * 单条详情 + * @param id + * @return + */ + DataSetDto detailSet(Long id); + + /** + * 单条详情 + * @param setCode + * @return + */ + DataSetDto detailSet(String setCode); + + /** + * 新增数据集、添加查询参数、数据转换 + * @param dto + */ + DataSetDto insertSet(DataSetDto dto); + + /** + * 更新数据集、添加查询参数、数据转换 + * @param dto + */ + void updateSet(DataSetDto dto); + + /** + * 删除数据集、添加查询参数、数据转换 + * @param id + */ + void deleteSet(Long id); + + /** + * 获取数据 + * @param dto + * @return + */ + OriginalDataDto getData(DataSetDto dto); + + /** + * + * @param dto + * @return + */ + OriginalDataDto testTransform(DataSetDto dto); + + /** + * 获取所有数据集 + * @return + */ + List queryAllDataSet(); +} diff --git a/src/main/java/com/anjiplus/template/gaea/business/modules/dataset/service/impl/DataSetServiceImpl.java b/src/main/java/com/anjiplus/template/gaea/business/modules/dataset/service/impl/DataSetServiceImpl.java new file mode 100644 index 0000000..d669254 --- /dev/null +++ b/src/main/java/com/anjiplus/template/gaea/business/modules/dataset/service/impl/DataSetServiceImpl.java @@ -0,0 +1,439 @@ + +package com.anjiplus.template.gaea.business.modules.dataset.service.impl; + +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONArray; +import com.alibaba.fastjson.JSONObject; +import com.alibaba.fastjson.parser.Feature; +import com.alibaba.fastjson.serializer.SerializerFeature; +import com.anji.plus.gaea.constant.Enabled; +import com.anji.plus.gaea.curd.mapper.GaeaBaseMapper; +import com.anji.plus.gaea.exception.BusinessExceptionBuilder; +import com.anji.plus.gaea.utils.GaeaBeanUtils; +import com.anjiplus.template.gaea.business.code.ResponseCode; +import com.anjiplus.template.gaea.business.enums.SetTypeEnum; +import com.anjiplus.template.gaea.business.modules.dataset.controller.dto.OriginalDataDto; +import com.anjiplus.template.gaea.business.modules.dataset.controller.dto.DataSetDto; +import com.anjiplus.template.gaea.business.modules.dataset.dao.DataSetMapper; +import com.anjiplus.template.gaea.business.modules.dataset.dao.entity.DataSet; +import com.anjiplus.template.gaea.business.modules.dataset.service.DataSetService; +import com.anjiplus.template.gaea.business.modules.datasetparam.controller.dto.DataSetParamDto; +import com.anjiplus.template.gaea.business.modules.datasetparam.dao.entity.DataSetParam; +import com.anjiplus.template.gaea.business.modules.datasetparam.service.DataSetParamService; +import com.anjiplus.template.gaea.business.modules.datasettransform.controller.dto.DataSetTransformDto; +import com.anjiplus.template.gaea.business.modules.datasettransform.dao.entity.DataSetTransform; +import com.anjiplus.template.gaea.business.modules.datasettransform.service.DataSetTransformService; +import com.anjiplus.template.gaea.business.modules.datasource.controller.dto.DataSourceDto; +import com.anjiplus.template.gaea.business.modules.datasource.dao.entity.DataSource; +import com.anjiplus.template.gaea.business.modules.datasource.service.DataSourceService; +import com.anjiplus.template.gaea.business.util.JdbcConstants; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import com.fasterxml.jackson.annotation.JsonFormat; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.springframework.beans.BeanUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.util.CollectionUtils; + +import java.util.*; +import java.util.stream.Collectors; + +/** + * @author Raod + * @desc DataSet 数据集服务实现 + * @date 2021-03-18 12:11:31.150755900 + **/ +@Service +//@RequiredArgsConstructor +@Slf4j +public class DataSetServiceImpl implements DataSetService { + + @Autowired + private DataSetMapper dataSetMapper; + + @Autowired + private DataSetParamService dataSetParamService; + + @Autowired + private DataSetTransformService dataSetTransformService; + + @Autowired + private DataSourceService dataSourceService; + + @Override + public GaeaBaseMapper getMapper() { + return dataSetMapper; + } + + /** + * 单条详情 + * + * @param id + * @return + */ + @Override + public DataSetDto detailSet(Long id) { + DataSetDto dto = new DataSetDto(); + DataSet result = selectOne(id); + String setCode = result.getSetCode(); + GaeaBeanUtils.copyAndFormatter(result, dto); + return getDetailSet(dto, setCode); + } + + /** + * 单条详情 + * + * @param setCode + * @return + */ + @Override + public DataSetDto detailSet(String setCode) { + DataSetDto dto = new DataSetDto(); + DataSet result = selectOne("set_code", setCode); + GaeaBeanUtils.copyAndFormatter(result, dto); + return getDetailSet(dto, setCode); + } + + public DataSetDto getDetailSet(DataSetDto dto, String setCode) { + //查询参数 + List dataSetParamList = dataSetParamService.list( + new QueryWrapper() + .lambda() + .eq(DataSetParam::getSetCode, setCode) + ); + List dataSetParamDtoList = new ArrayList<>(); + dataSetParamList.forEach(dataSetParam -> { + DataSetParamDto dataSetParamDto = new DataSetParamDto(); + GaeaBeanUtils.copyAndFormatter(dataSetParam, dataSetParamDto); + dataSetParamDtoList.add(dataSetParamDto); + }); + dto.setDataSetParamDtoList(dataSetParamDtoList); + + //数据转换 + + List dataSetTransformList = dataSetTransformService.list( + new QueryWrapper() + .lambda() + .eq(DataSetTransform::getSetCode, setCode) + .orderByAsc(DataSetTransform::getOrderNum) + ); + List dataSetTransformDtoList = new ArrayList<>(); + dataSetTransformList.forEach(dataSetTransform -> { + DataSetTransformDto dataSetTransformDto = new DataSetTransformDto(); + GaeaBeanUtils.copyAndFormatter(dataSetTransform, dataSetTransformDto); + dataSetTransformDtoList.add(dataSetTransformDto); + }); + dto.setDataSetTransformDtoList(dataSetTransformDtoList); + + if (StringUtils.isNotBlank(dto.getCaseResult())) { + try { + JSONArray jsonArray = JSONArray.parseArray(dto.getCaseResult()); + JSONObject jsonObject = jsonArray.getJSONObject(0); + dto.setSetParamList(jsonObject.keySet()); + } catch (Exception e) { + log.error("error", e); + } + } + return dto; + } + + + /** + * 新增数据集、添加查询参数、数据转换 + * + * @param dto + */ + @Override + @Transactional + public DataSetDto insertSet(DataSetDto dto) { + List dataSetParamDtoList = dto.getDataSetParamDtoList(); + List dataSetTransformDtoList = dto.getDataSetTransformDtoList(); + + //1.新增数据集 + DataSet dataSet = new DataSet(); + BeanUtils.copyProperties(dto, dataSet); + if (StringUtils.isNotBlank(dataSet.getCaseResult())) { + try { + JSONArray objects = JSONObject.parseArray(dataSet.getCaseResult()); + if (objects.size() > 1) { + Object o = objects.get(0); + objects = new JSONArray(); + objects.add(o); + dataSet.setCaseResult(JSON.toJSONString(objects, SerializerFeature.WriteMapNullValue)); + } + } catch (Exception e) { + log.info("结果集只保留一行数据失败...{}", e.getMessage()); + } + } + insert(dataSet); + //2.更新查询参数 + dataSetParamBatch(dataSetParamDtoList, dto.getSetCode()); + + //3.更新数据转换 + dataSetTransformBatch(dataSetTransformDtoList, dto.getSetCode()); + return dto; + } + + /** + * 更新数据集、添加查询参数、数据转换 + * + * @param dto + */ + @Override + @Transactional(rollbackFor = Exception.class) + public void updateSet(DataSetDto dto) { + List dataSetParamDtoList = dto.getDataSetParamDtoList(); + List dataSetTransformDtoList = dto.getDataSetTransformDtoList(); + //1.更新数据集 + DataSet dataSet = new DataSet(); + BeanUtils.copyProperties(dto, dataSet); + if (StringUtils.isNotBlank(dataSet.getCaseResult())) { + try { + JSONArray objects = JSONObject.parseArray(dataSet.getCaseResult()); + if (objects.size() > 1) { + Object o = objects.get(0); + objects = new JSONArray(); + objects.add(o); + dataSet.setCaseResult(JSON.toJSONString(objects, SerializerFeature.WriteMapNullValue)); + } + } catch (Exception e) { + log.info("结果集只保留一行数据失败...{}", e.getMessage()); + } + } + update(dataSet); + + //2.更新查询参数 + dataSetParamBatch(dataSetParamDtoList, dto.getSetCode()); + + //3.更新数据转换 + dataSetTransformBatch(dataSetTransformDtoList, dto.getSetCode()); + } + + + /** + * 删除数据集、添加查询参数、数据转换 + * + * @param id + */ + @Override + @Transactional(rollbackFor = Exception.class) + public void deleteSet(Long id) { + DataSet dataSet = selectOne(id); + String setCode = dataSet.getSetCode(); + //1.删除数据集 + deleteById(id); + + //2.删除查询参数 + dataSetParamService.delete( + new QueryWrapper() + .lambda() + .eq(DataSetParam::getSetCode, setCode) + ); + + //3.删除数据转换 + dataSetTransformService.delete( + new QueryWrapper() + .lambda() + .eq(DataSetTransform::getSetCode, setCode) + ); + } + + /** + * 获取数据 + * + * @param dto + * @return + */ + @Override + public OriginalDataDto getData(DataSetDto dto) { + + OriginalDataDto originalDataDto = new OriginalDataDto(); + String setCode = dto.getSetCode(); + if (StringUtils.isBlank(setCode)) { + return new OriginalDataDto(new ArrayList<>()); + } + //1.获取数据集、参数替换、数据转换 + DataSetDto dataSetDto = detailSet(setCode); + String dynSentence = dataSetDto.getDynSentence(); + //2.获取数据源 + DataSource dataSource; + if (StringUtils.isNotBlank(dataSetDto.getSetType()) + && dataSetDto.getSetType().equals(SetTypeEnum.HTTP.getCodeValue())) { + //http不需要数据源,兼容已有的逻辑,将http所需要的数据塞进DataSource + dataSource = new DataSource(); + dataSource.setSourceConfig(dynSentence); + dataSource.setSourceType(JdbcConstants.HTTP); + String body = JSONObject.parseObject(dynSentence).getString("body"); + if (StringUtils.isNotBlank(body)) { + dynSentence = body; + } else { + dynSentence = "{}"; + } + + } else { + dataSource = dataSourceService.selectOne("source_code", dataSetDto.getSourceCode()); + } + + //3.参数替换 + //3.1参数校验 + log.debug("参数校验替换前:{}", dto.getContextData()); + boolean verification = dataSetParamService.verification(dataSetDto.getDataSetParamDtoList(), dto.getContextData()); + if (!verification) { + throw BusinessExceptionBuilder.build(ResponseCode.RULE_FIELDS_CHECK_ERROR); + } + dynSentence = dataSetParamService.transform(dto.getContextData(), dynSentence); + log.debug("参数校验替换后:{}", dto.getContextData()); + //4.获取数据 + DataSourceDto dataSourceDto = new DataSourceDto(); + BeanUtils.copyProperties(dataSource, dataSourceDto); + dataSourceDto.setDynSentence(dynSentence); + dataSourceDto.setContextData(dto.getContextData()); + //获取total,判断contextData中是否传入分页参数 + if (null != dto.getContextData() + && dto.getContextData().containsKey("pageNumber") + && dto.getContextData().containsKey("pageSize")) { + long total = dataSourceService.total(dataSourceDto, dto); + originalDataDto.setTotal(total); + } + List data = dataSourceService.execute(dataSourceDto); + //5.数据转换 + List transform = dataSetTransformService.transform(dataSetDto.getDataSetTransformDtoList(), data); + originalDataDto.setData(transform); + return originalDataDto; + } + + /** + * @param dto + * @return + */ + @Override + public OriginalDataDto testTransform(DataSetDto dto) { + String dynSentence = dto.getDynSentence(); + + OriginalDataDto originalDataDto = new OriginalDataDto(); + String sourceCode = dto.getSourceCode(); + //1.获取数据源 + DataSource dataSource; + if (dto.getSetType().equals(SetTypeEnum.HTTP.getCodeValue())) { + //http不需要数据源,兼容已有的逻辑,将http所需要的数据塞进DataSource + dataSource = new DataSource(); + dataSource.setSourceConfig(dynSentence); + dataSource.setSourceType(JdbcConstants.HTTP); + String body = JSONObject.parseObject(dynSentence).getString("body"); + if (StringUtils.isNotBlank(body)) { + dynSentence = body; + } else { + dynSentence = "{}"; + } + + } else { + dataSource = dataSourceService.selectOne("source_code", sourceCode); + } + + //3.参数替换 + //3.1参数校验 + boolean verification = dataSetParamService.verification(dto.getDataSetParamDtoList(), null); + if (!verification) { + throw BusinessExceptionBuilder.build(ResponseCode.RULE_FIELDS_CHECK_ERROR); + } + + dynSentence = dataSetParamService.transform(dto.getDataSetParamDtoList(), dynSentence); + //4.获取数据 + DataSourceDto dataSourceDto = new DataSourceDto(); + BeanUtils.copyProperties(dataSource, dataSourceDto); + dataSourceDto.setDynSentence(dynSentence); + dataSourceDto.setContextData(setContextData(dto.getDataSetParamDtoList())); + + //获取total,判断DataSetParamDtoList中是否传入分页参数 + Map collect = dto.getDataSetParamDtoList().stream().collect(Collectors.toMap(DataSetParamDto::getParamName, DataSetParamDto::getSampleItem)); + if (collect.containsKey("pageNumber") && collect.containsKey("pageSize")) { + dto.setContextData(collect); + long total = dataSourceService.total(dataSourceDto, dto); + originalDataDto.setTotal(total); + } + + List data = dataSourceService.execute(dataSourceDto); + //5.数据转换 + List transform = dataSetTransformService.transform(dto.getDataSetTransformDtoList(), data); + originalDataDto.setData(transform); + return originalDataDto; + } + + + /** + * 获取所有数据集 + * + * @return + */ + @Override + public List queryAllDataSet() { + LambdaQueryWrapper wrapper = Wrappers.lambdaQuery(); + wrapper.select(DataSet::getSetCode, DataSet::getSetName, DataSet::getSetDesc, DataSet::getId) + .eq(DataSet::getEnableFlag, Enabled.YES.getValue()); + wrapper.orderByDesc(DataSet::getUpdateTime); + return dataSetMapper.selectList(wrapper); + } + + public void dataSetParamBatch(List dataSetParamDtoList, String setCode) { + dataSetParamService.delete( + new QueryWrapper() + .lambda() + .eq(DataSetParam::getSetCode, setCode) + ); + if (null == dataSetParamDtoList || dataSetParamDtoList.size() <= 0) { + return; + } +// List dataSetParamList = new ArrayList<>(); + dataSetParamDtoList.forEach(dataSetParamDto -> { + DataSetParam dataSetParam = new DataSetParam(); + BeanUtils.copyProperties(dataSetParamDto, dataSetParam); + dataSetParam.setSetCode(setCode); + //不采用批量 + dataSetParamService.insert(dataSetParam); +// dataSetParamList.add(dataSetParam); + }); +// dataSetParamService.insertBatch(dataSetParamList); + + } + + public void dataSetTransformBatch(List dataSetTransformDtoList, String setCode) { + dataSetTransformService.delete( + new QueryWrapper() + .lambda() + .eq(DataSetTransform::getSetCode, setCode) + ); + if (null == dataSetTransformDtoList || dataSetTransformDtoList.size() <= 0) { + return; + } +// List dataSetTransformList = new ArrayList<>(); + for (int i = 0; i < dataSetTransformDtoList.size(); i++) { + DataSetTransform dataSetTransform = new DataSetTransform(); + BeanUtils.copyProperties(dataSetTransformDtoList.get(i), dataSetTransform); + dataSetTransform.setOrderNum(i + 1); + dataSetTransform.setSetCode(setCode); + //不采用批量 + dataSetTransformService.insert(dataSetTransform); +// dataSetTransformList.add(dataSetTransform); + } +// dataSetTransformService.insertBatch(dataSetTransformList); + } + + /** + * dataSetParamDtoList转map + * + * @param dataSetParamDtoList + * @return + */ + public Map setContextData(List dataSetParamDtoList) { + Map map = new HashMap<>(); + if (null != dataSetParamDtoList && dataSetParamDtoList.size() > 0) { + dataSetParamDtoList.forEach(dataSetParamDto -> map.put(dataSetParamDto.getParamName(), dataSetParamDto.getSampleItem())); + } + return map; + } + +} diff --git a/src/main/java/com/anjiplus/template/gaea/business/modules/datasetparam/controller/DataSetParamController.java b/src/main/java/com/anjiplus/template/gaea/business/modules/datasetparam/controller/DataSetParamController.java new file mode 100644 index 0000000..4a7e076 --- /dev/null +++ b/src/main/java/com/anjiplus/template/gaea/business/modules/datasetparam/controller/DataSetParamController.java @@ -0,0 +1,61 @@ + +package com.anjiplus.template.gaea.business.modules.datasetparam.controller; + +import com.anji.plus.gaea.bean.ResponseBean; +import com.anji.plus.gaea.curd.controller.GaeaBaseController; +import com.anji.plus.gaea.curd.service.GaeaBaseService; +import com.anjiplus.template.gaea.business.modules.datasetparam.controller.dto.DataSetParamDto; +import com.anjiplus.template.gaea.business.modules.datasetparam.controller.param.DataSetParamParam; +import com.anjiplus.template.gaea.business.modules.datasetparam.controller.param.DataSetParamValidationParam; +import com.anjiplus.template.gaea.business.modules.datasetparam.dao.entity.DataSetParam; +import com.anjiplus.template.gaea.business.modules.datasetparam.service.DataSetParamService; +import io.swagger.annotations.Api; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +/** +* @desc 数据集动态参数 controller +* @website https://gitee.com/anji-plus/gaea +* @author Raod +* @date 2021-03-18 12:12:33.108033200 +**/ +@RestController +@Api(tags = "数据集动态参数管理") +@RequestMapping("/dataSetParam") +public class DataSetParamController extends GaeaBaseController { + + @Autowired + private DataSetParamService dataSetParamService; + + @Override + public GaeaBaseService getService() { + return dataSetParamService; + } + + @Override + public DataSetParam getEntity() { + return new DataSetParam(); + } + + @Override + public DataSetParamDto getDTO() { + return new DataSetParamDto(); + } + + /** + * 测试 查询参数是否正确 + * @param param + * @return + */ + @PostMapping("/verification") + public ResponseBean verification(@Validated @RequestBody DataSetParamValidationParam param) { + DataSetParamDto dto = new DataSetParamDto(); + dto.setSampleItem(param.getSampleItem()); + dto.setValidationRules(param.getValidationRules()); + return responseSuccessWithData(dataSetParamService.verification(dto)); + } +} diff --git a/src/main/java/com/anjiplus/template/gaea/business/modules/datasetparam/controller/dto/DataSetParamDto.java b/src/main/java/com/anjiplus/template/gaea/business/modules/datasetparam/controller/dto/DataSetParamDto.java new file mode 100644 index 0000000..81c5659 --- /dev/null +++ b/src/main/java/com/anjiplus/template/gaea/business/modules/datasetparam/controller/dto/DataSetParamDto.java @@ -0,0 +1,48 @@ + +package com.anjiplus.template.gaea.business.modules.datasetparam.controller.dto; + +import com.anji.plus.gaea.curd.dto.GaeaBaseDTO; +import lombok.Data; + +import java.io.Serializable; + + +/** +* +* @description 数据集动态参数 dto +* @author Raod +* @date 2021-03-18 12:12:33.108033200 +**/ +@Data +public class DataSetParamDto extends GaeaBaseDTO implements Serializable { + /** 数据集编码 */ + private String setCode; + + /** 参数名 */ + private String paramName; + + /** 参数描述 */ + private String paramDesc; + + /** 参数类型,字典= */ + private String paramType; + + /** 参数示例项 */ + private String sampleItem; + + /** 0--非必填 1--必填 DIC_NAME=REQUIRED_FLAG */ + private Integer requiredFlag; + + /** js校验字段值规则,满足校验返回 true */ + private String validationRules; + + /** 排序 */ + private Integer orderNum; + + /** 0--已禁用 1--已启用 DIC_NAME=ENABLE_FLAG */ + private Integer enableFlag; + + /** 0--未删除 1--已删除 DIC_NAME=DELETE_FLAG */ + private Integer deleteFlag; + +} diff --git a/src/main/java/com/anjiplus/template/gaea/business/modules/datasetparam/controller/param/DataSetParamParam.java b/src/main/java/com/anjiplus/template/gaea/business/modules/datasetparam/controller/param/DataSetParamParam.java new file mode 100644 index 0000000..6ad9882 --- /dev/null +++ b/src/main/java/com/anjiplus/template/gaea/business/modules/datasetparam/controller/param/DataSetParamParam.java @@ -0,0 +1,17 @@ +/**/ +package com.anjiplus.template.gaea.business.modules.datasetparam.controller.param; + +import com.anji.plus.gaea.curd.params.PageParam; +import lombok.Data; + +import java.io.Serializable; + + +/** +* @desc DataSetParam 数据集动态参数查询输入类 +* @author Raod +* @date 2021-03-18 12:12:33.108033200 +**/ +@Data +public class DataSetParamParam extends PageParam implements Serializable{ +} diff --git a/src/main/java/com/anjiplus/template/gaea/business/modules/datasetparam/controller/param/DataSetParamValidationParam.java b/src/main/java/com/anjiplus/template/gaea/business/modules/datasetparam/controller/param/DataSetParamValidationParam.java new file mode 100644 index 0000000..d2d9c0e --- /dev/null +++ b/src/main/java/com/anjiplus/template/gaea/business/modules/datasetparam/controller/param/DataSetParamValidationParam.java @@ -0,0 +1,22 @@ +package com.anjiplus.template.gaea.business.modules.datasetparam.controller.param; + +import lombok.Data; + +import javax.validation.constraints.NotBlank; +import java.io.Serializable; + +/** + * Created by raodeming on 2021/3/24. + */ +@Data +public class DataSetParamValidationParam implements Serializable { + + /** 参数示例项 */ + @NotBlank(message = "sampleItem not empty") + private String sampleItem; + + + /** js校验字段值规则,满足校验返回 true */ + @NotBlank(message = "validationRules not empty") + private String validationRules; +} diff --git a/src/main/java/com/anjiplus/template/gaea/business/modules/datasetparam/dao/DataSetParamMapper.java b/src/main/java/com/anjiplus/template/gaea/business/modules/datasetparam/dao/DataSetParamMapper.java new file mode 100644 index 0000000..c4f776c --- /dev/null +++ b/src/main/java/com/anjiplus/template/gaea/business/modules/datasetparam/dao/DataSetParamMapper.java @@ -0,0 +1,15 @@ +package com.anjiplus.template.gaea.business.modules.datasetparam.dao; + +import com.anji.plus.gaea.curd.mapper.GaeaBaseMapper; +import com.anjiplus.template.gaea.business.modules.datasetparam.dao.entity.DataSetParam; +import org.apache.ibatis.annotations.Mapper; + +/** +* DataSetParam Mapper +* @author Raod +* @date 2021-03-18 12:12:33.108033200 +**/ +@Mapper +public interface DataSetParamMapper extends GaeaBaseMapper { + +} diff --git a/src/main/java/com/anjiplus/template/gaea/business/modules/datasetparam/dao/entity/DataSetParam.java b/src/main/java/com/anjiplus/template/gaea/business/modules/datasetparam/dao/entity/DataSetParam.java new file mode 100644 index 0000000..96a1648 --- /dev/null +++ b/src/main/java/com/anjiplus/template/gaea/business/modules/datasetparam/dao/entity/DataSetParam.java @@ -0,0 +1,48 @@ + +package com.anjiplus.template.gaea.business.modules.datasetparam.dao.entity; + +import com.anji.plus.gaea.curd.entity.GaeaBaseEntity; +import com.baomidou.mybatisplus.annotation.TableName; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +/** +* @description 数据集动态参数 entity +* @author Raod +* @date 2021-03-18 12:12:33.108033200 +**/ +@TableName(keepGlobalPrefix=true, value="gaea_report_data_set_param") +@Data +public class DataSetParam extends GaeaBaseEntity { + @ApiModelProperty(value = "数据集编码") + private String setCode; + + @ApiModelProperty(value = "参数名") + private String paramName; + + @ApiModelProperty(value = "参数描述") + private String paramDesc; + + @ApiModelProperty(value = "参数类型,字典=") + private String paramType; + + @ApiModelProperty(value = "参数示例项") + private String sampleItem; + + @ApiModelProperty(value = "0--非必填 1--必填 DIC_NAME=REQUIRED_FLAG") + private Integer requiredFlag; + + @ApiModelProperty(value = "js校验字段值规则,满足校验返回 true") + private String validationRules; + + @ApiModelProperty(value = "排序") + private Integer orderNum; + + @ApiModelProperty(value = "0--已禁用 1--已启用 DIC_NAME=ENABLE_FLAG") + private Integer enableFlag; + + @ApiModelProperty(value = "0--未删除 1--已删除 DIC_NAME=DELETE_FLAG") + private Integer deleteFlag; + + +} diff --git a/src/main/java/com/anjiplus/template/gaea/business/modules/datasetparam/service/DataSetParamService.java b/src/main/java/com/anjiplus/template/gaea/business/modules/datasetparam/service/DataSetParamService.java new file mode 100644 index 0000000..b8afe47 --- /dev/null +++ b/src/main/java/com/anjiplus/template/gaea/business/modules/datasetparam/service/DataSetParamService.java @@ -0,0 +1,51 @@ + +package com.anjiplus.template.gaea.business.modules.datasetparam.service; + +import com.anji.plus.gaea.curd.service.GaeaBaseService; +import com.anjiplus.template.gaea.business.modules.datasetparam.controller.dto.DataSetParamDto; +import com.anjiplus.template.gaea.business.modules.datasetparam.controller.param.DataSetParamParam; +import com.anjiplus.template.gaea.business.modules.datasetparam.dao.entity.DataSetParam; + +import java.util.List; +import java.util.Map; + +/** + * @author Raod + * @desc DataSetParam 数据集动态参数服务接口 + * @date 2021-03-18 12:12:33.108033200 + **/ +public interface DataSetParamService extends GaeaBaseService { + + /** + * 参数替换 + * + * @param contextData + * @param dynSentence + * @return + */ + String transform(Map contextData, String dynSentence); + + /** + * 参数替换 + * + * @param dataSetParamDtoList + * @param dynSentence + * @return + */ + String transform(List dataSetParamDtoList, String dynSentence); + + /** + * 参数校验 js脚本 + * @param dataSetParamDto + * @return + */ + Object verification(DataSetParamDto dataSetParamDto); + + /** + * 参数校验 js脚本 + * + * @param dataSetParamDtoList + * @return + */ + boolean verification(List dataSetParamDtoList, Map contextData); +} diff --git a/src/main/java/com/anjiplus/template/gaea/business/modules/datasetparam/service/impl/DataSetParamServiceImpl.java b/src/main/java/com/anjiplus/template/gaea/business/modules/datasetparam/service/impl/DataSetParamServiceImpl.java new file mode 100644 index 0000000..e4679b8 --- /dev/null +++ b/src/main/java/com/anjiplus/template/gaea/business/modules/datasetparam/service/impl/DataSetParamServiceImpl.java @@ -0,0 +1,157 @@ + +package com.anjiplus.template.gaea.business.modules.datasetparam.service.impl; + +import com.anji.plus.gaea.curd.mapper.GaeaBaseMapper; +import com.anji.plus.gaea.exception.BusinessExceptionBuilder; +import com.anjiplus.template.gaea.business.modules.datasetparam.controller.dto.DataSetParamDto; +import com.anjiplus.template.gaea.business.modules.datasetparam.dao.DataSetParamMapper; +import com.anjiplus.template.gaea.business.modules.datasetparam.dao.entity.DataSetParam; +import com.anjiplus.template.gaea.business.modules.datasetparam.service.DataSetParamService; +import com.anjiplus.template.gaea.business.modules.datasetparam.util.ParamsResolverHelper; +import com.anjiplus.template.gaea.business.code.ResponseCode; +import com.fasterxml.jackson.databind.ObjectMapper; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import javax.script.Invocable; +import javax.script.ScriptEngine; +import javax.script.ScriptEngineManager; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** +* @desc DataSetParam 数据集动态参数服务实现 +* @author Raod +* @date 2021-03-18 12:12:33.108033200 +**/ +@Service +//@RequiredArgsConstructor +@Slf4j +public class DataSetParamServiceImpl implements DataSetParamService { + + private ScriptEngine engine; + { + ScriptEngineManager manager = new ScriptEngineManager(); + engine = manager.getEngineByName("JavaScript"); + } + + @Autowired + private DataSetParamMapper dataSetParamMapper; + + @Override + public GaeaBaseMapper getMapper() { + return dataSetParamMapper; + } + + /** + * 参数替换 + * + * @param contextData + * @param dynSentence + * @return + */ + @Override + public String transform(Map contextData, String dynSentence) { + if (StringUtils.isBlank(dynSentence)) { + return dynSentence; + } + if (dynSentence.contains("${")) { + dynSentence = ParamsResolverHelper.resolveParams(contextData, dynSentence); + } + if (dynSentence.contains("${")) { + throw BusinessExceptionBuilder.build(ResponseCode.INCOMPLETE_PARAMETER_REPLACEMENT_VALUES, dynSentence); + } + return dynSentence; + } + + /** + * 参数替换 + * + * @param dataSetParamDtoList + * @param dynSentence + * @return + */ + @Override + public String transform(List dataSetParamDtoList, String dynSentence) { + Map contextData = new HashMap<>(); + if (null == dataSetParamDtoList || dataSetParamDtoList.size() <= 0) { + return dynSentence; + } + dataSetParamDtoList.forEach(dataSetParamDto -> { + contextData.put(dataSetParamDto.getParamName(), dataSetParamDto.getSampleItem()); + }); + return transform(contextData, dynSentence); + } + + /** + * 参数校验 js脚本 + * + * @param dataSetParamDto + * @return + */ + @Override + public Object verification(DataSetParamDto dataSetParamDto) { + + String validationRules = dataSetParamDto.getValidationRules(); + if (StringUtils.isNotBlank(validationRules)) { + try { + engine.eval(validationRules); + if(engine instanceof Invocable){ + Invocable invocable = (Invocable) engine; + Object exec = invocable.invokeFunction("verification", dataSetParamDto); + ObjectMapper objectMapper = new ObjectMapper(); + if (exec instanceof Boolean) { + return objectMapper.convertValue(exec, Boolean.class); + }else { + return objectMapper.convertValue(exec, String.class); + } + + } + + } catch (Exception ex) { + throw BusinessExceptionBuilder.build(ResponseCode.EXECUTE_JS_ERROR, ex.getMessage()); + } + + } + return true; + } + + /** + * 参数校验 js脚本 + * + * @param dataSetParamDtoList + * @return + */ + @Override + public boolean verification(List dataSetParamDtoList, Map contextData) { + if (null == dataSetParamDtoList || dataSetParamDtoList.size() == 0) { + return true; + } + + for (DataSetParamDto dataSetParamDto : dataSetParamDtoList) { + if (null != contextData) { + String value = contextData.getOrDefault(dataSetParamDto.getParamName(), "").toString(); + dataSetParamDto.setSampleItem(value); + } + + Object verification = verification(dataSetParamDto); + if (verification instanceof Boolean) { + if (!(Boolean) verification) { + return false; + } + }else { + //将得到的值重新赋值给contextData + if (null != contextData) { + contextData.put(dataSetParamDto.getParamName(), verification); + } + dataSetParamDto.setSampleItem(verification.toString()); + } + + } + return true; + } + +} diff --git a/src/main/java/com/anjiplus/template/gaea/business/modules/datasetparam/util/ParamsResolverHelper.java b/src/main/java/com/anjiplus/template/gaea/business/modules/datasetparam/util/ParamsResolverHelper.java new file mode 100644 index 0000000..51aad48 --- /dev/null +++ b/src/main/java/com/anjiplus/template/gaea/business/modules/datasetparam/util/ParamsResolverHelper.java @@ -0,0 +1,36 @@ +package com.anjiplus.template.gaea.business.modules.datasetparam.util; + +import org.springframework.util.PropertyPlaceholderHelper; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/** + * Created by raodeming on 2021/3/23. + */ +public class ParamsResolverHelper { + private static String placeholderPrefix = "${"; + private static String placeholderSuffix = "}"; + private static PropertyPlaceholderHelper helper = + new PropertyPlaceholderHelper(placeholderPrefix, placeholderSuffix); + + public static String resolveParams(final Map param, String con) { + con = helper.replacePlaceholders(con, (key -> param.get(key) + "")); + return con; + } + + private static Pattern key = Pattern.compile("\\$\\{(.*?)\\}"); + + public static List findParamKeys(String con) { + Matcher m = key.matcher(con); + List ret = new ArrayList(); + while (m.find()) { + ret.add(m.group(1)); + } + return ret; + } + +} diff --git a/src/main/java/com/anjiplus/template/gaea/business/modules/datasettransform/controller/DataSetTransformController.java b/src/main/java/com/anjiplus/template/gaea/business/modules/datasettransform/controller/DataSetTransformController.java new file mode 100644 index 0000000..047708c --- /dev/null +++ b/src/main/java/com/anjiplus/template/gaea/business/modules/datasettransform/controller/DataSetTransformController.java @@ -0,0 +1,44 @@ + +package com.anjiplus.template.gaea.business.modules.datasettransform.controller; + +import com.anji.plus.gaea.curd.controller.GaeaBaseController; +import com.anji.plus.gaea.curd.service.GaeaBaseService; +import com.anjiplus.template.gaea.business.modules.datasettransform.controller.dto.DataSetTransformDto; +import com.anjiplus.template.gaea.business.modules.datasettransform.controller.param.DataSetTransformParam; +import com.anjiplus.template.gaea.business.modules.datasettransform.dao.entity.DataSetTransform; +import com.anjiplus.template.gaea.business.modules.datasettransform.service.DataSetTransformService; +import io.swagger.annotations.Api; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +/** +* @desc 数据集数据转换 controller +* @website https://gitee.com/anji-plus/gaea +* @author Raod +* @date 2021-03-18 12:13:15.591309400 +**/ +@RestController +@Api(tags = "数据集数据转换管理") +@RequestMapping("/dataSetTransform") +public class DataSetTransformController extends GaeaBaseController { + + @Autowired + private DataSetTransformService dataSetTransformService; + + @Override + public GaeaBaseService getService() { + return dataSetTransformService; + } + + @Override + public DataSetTransform getEntity() { + return new DataSetTransform(); + } + + @Override + public DataSetTransformDto getDTO() { + return new DataSetTransformDto(); + } + +} diff --git a/src/main/java/com/anjiplus/template/gaea/business/modules/datasettransform/controller/dto/DataSetTransformDto.java b/src/main/java/com/anjiplus/template/gaea/business/modules/datasettransform/controller/dto/DataSetTransformDto.java new file mode 100644 index 0000000..28db676 --- /dev/null +++ b/src/main/java/com/anjiplus/template/gaea/business/modules/datasettransform/controller/dto/DataSetTransformDto.java @@ -0,0 +1,36 @@ + +package com.anjiplus.template.gaea.business.modules.datasettransform.controller.dto; + +import com.anji.plus.gaea.curd.dto.GaeaBaseDTO; +import lombok.Data; + +import java.io.Serializable; + + +/** +* +* @description 数据集数据转换 dto +* @author Raod +* @date 2021-03-18 12:13:15.591309400 +**/ +@Data +public class DataSetTransformDto extends GaeaBaseDTO implements Serializable { + /** 数据集编码 */ + private String setCode; + + /** 数据转换类型,DIC_NAME=TRANSFORM_TYPE; js,javaBean,字典转换 */ + private String transformType; + + /** 数据转换script,处理逻辑 */ + private String transformScript; + + /** 排序,执行数据转换顺序 */ + private Integer orderNum; + + /** 0--已禁用 1--已启用 DIC_NAME=ENABLE_FLAG */ + private Integer enableFlag; + + /** 0--未删除 1--已删除 DIC_NAME=DELETE_FLAG */ + private Integer deleteFlag; + +} diff --git a/src/main/java/com/anjiplus/template/gaea/business/modules/datasettransform/controller/param/DataSetTransformParam.java b/src/main/java/com/anjiplus/template/gaea/business/modules/datasettransform/controller/param/DataSetTransformParam.java new file mode 100644 index 0000000..07ec30a --- /dev/null +++ b/src/main/java/com/anjiplus/template/gaea/business/modules/datasettransform/controller/param/DataSetTransformParam.java @@ -0,0 +1,17 @@ +/**/ +package com.anjiplus.template.gaea.business.modules.datasettransform.controller.param; + +import com.anji.plus.gaea.curd.params.PageParam; +import lombok.Data; + +import java.io.Serializable; + + +/** +* @desc DataSetTransform 数据集数据转换查询输入类 +* @author Raod +* @date 2021-03-18 12:13:15.591309400 +**/ +@Data +public class DataSetTransformParam extends PageParam implements Serializable{ +} diff --git a/src/main/java/com/anjiplus/template/gaea/business/modules/datasettransform/dao/DataSetTransformMapper.java b/src/main/java/com/anjiplus/template/gaea/business/modules/datasettransform/dao/DataSetTransformMapper.java new file mode 100644 index 0000000..209303b --- /dev/null +++ b/src/main/java/com/anjiplus/template/gaea/business/modules/datasettransform/dao/DataSetTransformMapper.java @@ -0,0 +1,15 @@ +package com.anjiplus.template.gaea.business.modules.datasettransform.dao; + +import com.anji.plus.gaea.curd.mapper.GaeaBaseMapper; +import com.anjiplus.template.gaea.business.modules.datasettransform.dao.entity.DataSetTransform; +import org.apache.ibatis.annotations.Mapper; + +/** +* DataSetTransform Mapper +* @author Raod +* @date 2021-03-18 12:13:15.591309400 +**/ +@Mapper +public interface DataSetTransformMapper extends GaeaBaseMapper { + +} diff --git a/src/main/java/com/anjiplus/template/gaea/business/modules/datasettransform/dao/entity/DataSetTransform.java b/src/main/java/com/anjiplus/template/gaea/business/modules/datasettransform/dao/entity/DataSetTransform.java new file mode 100644 index 0000000..e81ad29 --- /dev/null +++ b/src/main/java/com/anjiplus/template/gaea/business/modules/datasettransform/dao/entity/DataSetTransform.java @@ -0,0 +1,36 @@ + +package com.anjiplus.template.gaea.business.modules.datasettransform.dao.entity; + +import com.anji.plus.gaea.curd.entity.GaeaBaseEntity; +import com.baomidou.mybatisplus.annotation.TableName; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +/** +* @description 数据集数据转换 entity +* @author Raod +* @date 2021-03-18 12:13:15.591309400 +**/ +@TableName(keepGlobalPrefix=true, value="gaea_report_data_set_transform") +@Data +public class DataSetTransform extends GaeaBaseEntity { + @ApiModelProperty(value = "数据集编码") + private String setCode; + + @ApiModelProperty(value = "数据转换类型,DIC_NAME=TRANSFORM_TYPE; js,javaBean,字典转换") + private String transformType; + + @ApiModelProperty(value = "数据转换script,处理逻辑") + private String transformScript; + + @ApiModelProperty(value = "排序,执行数据转换顺序") + private Integer orderNum; + + @ApiModelProperty(value = "0--已禁用 1--已启用 DIC_NAME=ENABLE_FLAG") + private Integer enableFlag; + + @ApiModelProperty(value = "0--未删除 1--已删除 DIC_NAME=DELETE_FLAG") + private Integer deleteFlag; + + +} diff --git a/src/main/java/com/anjiplus/template/gaea/business/modules/datasettransform/service/DataSetTransformService.java b/src/main/java/com/anjiplus/template/gaea/business/modules/datasettransform/service/DataSetTransformService.java new file mode 100644 index 0000000..92a3bb8 --- /dev/null +++ b/src/main/java/com/anjiplus/template/gaea/business/modules/datasettransform/service/DataSetTransformService.java @@ -0,0 +1,21 @@ + +package com.anjiplus.template.gaea.business.modules.datasettransform.service; + +import com.alibaba.fastjson.JSONObject; +import com.anji.plus.gaea.curd.service.GaeaBaseService; +import com.anjiplus.template.gaea.business.modules.datasettransform.controller.dto.DataSetTransformDto; +import com.anjiplus.template.gaea.business.modules.datasettransform.controller.param.DataSetTransformParam; +import com.anjiplus.template.gaea.business.modules.datasettransform.dao.entity.DataSetTransform; + +import java.util.List; + +/** +* @desc DataSetTransform 数据集数据转换服务接口 +* @author Raod +* @date 2021-03-18 12:13:15.591309400 +**/ +public interface DataSetTransformService extends GaeaBaseService { + + List transform(List dataSetTransformDtoList, List data); + +} diff --git a/src/main/java/com/anjiplus/template/gaea/business/modules/datasettransform/service/IGroovyHandler.java b/src/main/java/com/anjiplus/template/gaea/business/modules/datasettransform/service/IGroovyHandler.java new file mode 100644 index 0000000..eb03cda --- /dev/null +++ b/src/main/java/com/anjiplus/template/gaea/business/modules/datasettransform/service/IGroovyHandler.java @@ -0,0 +1,14 @@ +package com.anjiplus.template.gaea.business.modules.datasettransform.service; + +import com.alibaba.fastjson.JSONObject; + +import java.util.List; + +/** + * @author: Raod + * @since: 2022-02-23 + */ +public interface IGroovyHandler { + + List transform(List data); +} diff --git a/src/main/java/com/anjiplus/template/gaea/business/modules/datasettransform/service/TransformStrategy.java b/src/main/java/com/anjiplus/template/gaea/business/modules/datasettransform/service/TransformStrategy.java new file mode 100644 index 0000000..ff8f35f --- /dev/null +++ b/src/main/java/com/anjiplus/template/gaea/business/modules/datasettransform/service/TransformStrategy.java @@ -0,0 +1,25 @@ +package com.anjiplus.template.gaea.business.modules.datasettransform.service; + +import com.alibaba.fastjson.JSONObject; +import com.anjiplus.template.gaea.business.modules.datasettransform.controller.dto.DataSetTransformDto; + +import java.util.List; + +/** + * Created by raodeming on 2021/3/23. + */ +public interface TransformStrategy { + /** + * 数据清洗转换 类型 + * @return + */ + String type(); + + /*** + * 清洗转换算法接口 + * @param def + * @param data + * @return + */ + List transform(DataSetTransformDto def, List data); +} diff --git a/src/main/java/com/anjiplus/template/gaea/business/modules/datasettransform/service/impl/DataSetTransformServiceImpl.java b/src/main/java/com/anjiplus/template/gaea/business/modules/datasettransform/service/impl/DataSetTransformServiceImpl.java new file mode 100644 index 0000000..ec2ca5b --- /dev/null +++ b/src/main/java/com/anjiplus/template/gaea/business/modules/datasettransform/service/impl/DataSetTransformServiceImpl.java @@ -0,0 +1,71 @@ + +package com.anjiplus.template.gaea.business.modules.datasettransform.service.impl; + +import com.alibaba.fastjson.JSONObject; +import com.anji.plus.gaea.curd.mapper.GaeaBaseMapper; +import com.anjiplus.template.gaea.business.modules.datasettransform.controller.dto.DataSetTransformDto; +import com.anjiplus.template.gaea.business.modules.datasettransform.dao.DataSetTransformMapper; +import com.anjiplus.template.gaea.business.modules.datasettransform.dao.entity.DataSetTransform; +import com.anjiplus.template.gaea.business.modules.datasettransform.service.DataSetTransformService; +import com.anjiplus.template.gaea.business.modules.datasettransform.service.TransformStrategy; +import org.springframework.beans.BeansException; +import org.springframework.beans.factory.InitializingBean; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.ApplicationContext; +import org.springframework.context.ApplicationContextAware; +import org.springframework.stereotype.Service; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** +* @desc DataSetTransform 数据集数据转换服务实现 +* @author Raod +* @date 2021-03-18 12:13:15.591309400 +**/ +@Service +//@RequiredArgsConstructor +public class DataSetTransformServiceImpl implements DataSetTransformService, InitializingBean, ApplicationContextAware { + + private final Map queryServiceImplMap = new HashMap<>(); + private ApplicationContext applicationContext; + + @Autowired + private DataSetTransformMapper dataSetTransformMapper; + + @Override + public GaeaBaseMapper getMapper() { + return dataSetTransformMapper; + } + + public TransformStrategy getTarget(String type) { + return queryServiceImplMap.get(type); + } + + @Override + public void afterPropertiesSet() { + Map beanMap = applicationContext.getBeansOfType(TransformStrategy.class); + //遍历该接口的所有实现,将其放入map中 + for (TransformStrategy serviceImpl : beanMap.values()) { + queryServiceImplMap.put(serviceImpl.type(), serviceImpl); + } + } + + @Override + public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { + this.applicationContext = applicationContext; + } + + @Override + public List transform(List dataSetTransformDtoList, List data) { + if (dataSetTransformDtoList == null || dataSetTransformDtoList.size() <= 0) { + return data; + } + + for (DataSetTransformDto dataSetTransformDto : dataSetTransformDtoList) { + data = getTarget(dataSetTransformDto.getTransformType()).transform(dataSetTransformDto, data); + } + return data; + } +} diff --git a/src/main/java/com/anjiplus/template/gaea/business/modules/datasettransform/service/impl/DictTransformServiceImpl.java b/src/main/java/com/anjiplus/template/gaea/business/modules/datasettransform/service/impl/DictTransformServiceImpl.java new file mode 100644 index 0000000..c7a5839 --- /dev/null +++ b/src/main/java/com/anjiplus/template/gaea/business/modules/datasettransform/service/impl/DictTransformServiceImpl.java @@ -0,0 +1,56 @@ +package com.anjiplus.template.gaea.business.modules.datasettransform.service.impl; + +import com.alibaba.fastjson.JSONObject; +import com.anjiplus.template.gaea.business.modules.datasettransform.controller.dto.DataSetTransformDto; +import com.anjiplus.template.gaea.business.modules.datasettransform.service.TransformStrategy; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.springframework.stereotype.Component; + +import java.util.List; +import java.util.Set; + +/** + * 字典转换 + * Created by raodeming on 2021/3/29. + */ +@Component +@Slf4j +public class DictTransformServiceImpl implements TransformStrategy { + + /** + * 数据清洗转换 类型 + * + * @return + */ + @Override + public String type() { + return "dict"; + } + + /*** + * 清洗转换算法接口 + * @param def + * @param data + * @return + */ + @Override + public List transform(DataSetTransformDto def, List data) { + String transformScript = def.getTransformScript(); + if (StringUtils.isBlank(transformScript)) { + return data; + } + JSONObject jsonObject = JSONObject.parseObject(transformScript); + Set keys = jsonObject.keySet(); + + data.forEach(dataDetail -> dataDetail.forEach((key, value) -> { + if (keys.contains(key)) { + String string = jsonObject.getJSONObject(key).getString(value.toString()); + if (StringUtils.isNotBlank(string)) { + dataDetail.put(key, string); + } + } + })); + return data; + } +} diff --git a/src/main/java/com/anjiplus/template/gaea/business/modules/datasettransform/service/impl/GroovyTransformServiceImpl.java b/src/main/java/com/anjiplus/template/gaea/business/modules/datasettransform/service/impl/GroovyTransformServiceImpl.java new file mode 100644 index 0000000..dc2de47 --- /dev/null +++ b/src/main/java/com/anjiplus/template/gaea/business/modules/datasettransform/service/impl/GroovyTransformServiceImpl.java @@ -0,0 +1,65 @@ +package com.anjiplus.template.gaea.business.modules.datasettransform.service.impl; + +import com.alibaba.fastjson.JSONObject; +import com.anji.plus.gaea.exception.BusinessExceptionBuilder; +import com.anjiplus.template.gaea.business.code.ResponseCode; +import com.anjiplus.template.gaea.business.modules.datasettransform.controller.dto.DataSetTransformDto; +import com.anjiplus.template.gaea.business.modules.datasettransform.service.IGroovyHandler; +import com.anjiplus.template.gaea.business.modules.datasettransform.service.TransformStrategy; +import groovy.lang.GroovyClassLoader; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Component; + +import javax.script.Invocable; +import javax.script.ScriptEngine; +import javax.script.ScriptEngineManager; +import java.util.List; + +/** + * Created by raodeming on 2021/3/23. + */ +@Component +@Slf4j +public class GroovyTransformServiceImpl implements TransformStrategy { + + private GroovyClassLoader groovyClassLoader = new GroovyClassLoader(); + + /** + * 数据清洗转换 类型 + * + * @return + */ + @Override + public String type() { + return "javaBean"; + } + + /*** + * 清洗转换算法接口 + * @param def + * @param data + * @return + */ + @Override + public List transform(DataSetTransformDto def, List data) { + String transformScript = def.getTransformScript(); + Class clazz = groovyClassLoader.parseClass(transformScript); + if (clazz != null) { + try { + Object instance = clazz.newInstance(); + if (instance!=null) { + if (instance instanceof IGroovyHandler) { + IGroovyHandler handler = (IGroovyHandler) instance; + return handler.transform(data); + } else { + System.err.println("转换失败!"); + } + } + } catch (Exception e) { + log.info("执行javaBean异常", e); + throw BusinessExceptionBuilder.build(ResponseCode.EXECUTE_GROOVY_ERROR, e.getMessage()); + } + } + return data; + } +} diff --git a/src/main/java/com/anjiplus/template/gaea/business/modules/datasettransform/service/impl/JsTransformServiceImpl.java b/src/main/java/com/anjiplus/template/gaea/business/modules/datasettransform/service/impl/JsTransformServiceImpl.java new file mode 100644 index 0000000..c236155 --- /dev/null +++ b/src/main/java/com/anjiplus/template/gaea/business/modules/datasettransform/service/impl/JsTransformServiceImpl.java @@ -0,0 +1,80 @@ +package com.anjiplus.template.gaea.business.modules.datasettransform.service.impl; + +import com.alibaba.fastjson.JSONObject; +import com.anji.plus.gaea.exception.BusinessExceptionBuilder; +import com.anjiplus.template.gaea.business.code.ResponseCode; +import com.anjiplus.template.gaea.business.modules.datasettransform.controller.dto.DataSetTransformDto; +import com.anjiplus.template.gaea.business.modules.datasettransform.service.TransformStrategy; +import jdk.nashorn.api.scripting.ScriptObjectMirror; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Component; + +import javax.script.Invocable; +import javax.script.ScriptEngine; +import javax.script.ScriptEngineManager; +import java.util.ArrayList; +import java.util.List; + +/** + * Created by raodeming on 2021/3/23. + */ +@Component +@Slf4j +public class JsTransformServiceImpl implements TransformStrategy { + + private ScriptEngine engine; + { + ScriptEngineManager manager = new ScriptEngineManager(); + engine = manager.getEngineByName("JavaScript"); + } + + /** + * 数据清洗转换 类型 + * + * @return + */ + @Override + public String type() { + return "js"; + } + + /*** + * 清洗转换算法接口 + * @param def + * @param data + * @return + */ + @Override + public List transform(DataSetTransformDto def, List data) { + return getValueFromJs(def,data); + } + + private List getValueFromJs(DataSetTransformDto def, List data) { + String js = def.getTransformScript(); + try { + engine.eval(js); + if(engine instanceof Invocable){ + Invocable invocable = (Invocable) engine; + Object dataTransform = invocable.invokeFunction("dataTransform", data); + if (dataTransform instanceof List) { + return (List) dataTransform; + } + //前端js自定义的数组[{"aa":"bb"}]解析后变成{"0":{"aa":"bb"}} + ScriptObjectMirror scriptObjectMirror = (ScriptObjectMirror) dataTransform; + List result = new ArrayList<>(); + scriptObjectMirror.forEach((key, value) -> { + ScriptObjectMirror valueObject = (ScriptObjectMirror) value; + JSONObject jsonObject = new JSONObject(); + jsonObject.putAll(valueObject); + result.add(jsonObject); + }); + return result; + } + + } catch (Exception ex) { + log.info("执行js异常", ex); + throw BusinessExceptionBuilder.build(ResponseCode.EXECUTE_JS_ERROR, ex.getMessage()); + } + return null; + } +} diff --git a/src/main/java/com/anjiplus/template/gaea/business/modules/datasource/config/HttpClientConfig.java b/src/main/java/com/anjiplus/template/gaea/business/modules/datasource/config/HttpClientConfig.java new file mode 100644 index 0000000..e1c8f2b --- /dev/null +++ b/src/main/java/com/anjiplus/template/gaea/business/modules/datasource/config/HttpClientConfig.java @@ -0,0 +1,214 @@ +package com.anjiplus.template.gaea.business.modules.datasource.config; + +import com.alibaba.fastjson.JSON; +import lombok.extern.slf4j.Slf4j; +import org.apache.http.Header; +import org.apache.http.HeaderElement; +import org.apache.http.HeaderElementIterator; +import org.apache.http.HttpHost; +import org.apache.http.client.HttpClient; +import org.apache.http.client.protocol.HttpClientContext; +import org.apache.http.config.Registry; +import org.apache.http.config.RegistryBuilder; +import org.apache.http.conn.ConnectionKeepAliveStrategy; +import org.apache.http.conn.socket.ConnectionSocketFactory; +import org.apache.http.conn.socket.PlainConnectionSocketFactory; +import org.apache.http.conn.ssl.NoopHostnameVerifier; +import org.apache.http.conn.ssl.SSLConnectionSocketFactory; +import org.apache.http.impl.client.DefaultHttpRequestRetryHandler; +import org.apache.http.impl.client.HttpClientBuilder; +import org.apache.http.impl.conn.PoolingHttpClientConnectionManager; +import org.apache.http.message.BasicHeader; +import org.apache.http.message.BasicHeaderElementIterator; +import org.apache.http.protocol.HTTP; +import org.apache.http.ssl.SSLContextBuilder; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.http.client.ClientHttpRequestFactory; +import org.springframework.http.client.HttpComponentsClientHttpRequestFactory; +import org.springframework.http.converter.HttpMessageConverter; +import org.springframework.http.converter.StringHttpMessageConverter; +import org.springframework.web.client.DefaultResponseErrorHandler; +import org.springframework.web.client.RestTemplate; + +import javax.net.ssl.HostnameVerifier; +import javax.net.ssl.SSLContext; +import java.nio.charset.Charset; +import java.security.KeyManagementException; +import java.security.KeyStoreException; +import java.security.NoSuchAlgorithmException; +import java.util.*; + +/** + * Created by raodeming on 2021/3/24. + */ +@Configuration +@Slf4j +public class HttpClientConfig { + @Autowired + private HttpClientPoolConfig httpClientPoolConfig; + + /** + * 创建HTTP客户端工厂 + */ + @Bean(name = "clientHttpRequestFactory") + public ClientHttpRequestFactory clientHttpRequestFactory() { + /** + * maxTotalConnection 和 maxConnectionPerRoute 必须要配 + */ + if (httpClientPoolConfig.getMaxTotalConnect() <= 0) { + throw new IllegalArgumentException("invalid maxTotalConnection: " + httpClientPoolConfig.getMaxTotalConnect()); + } + if (httpClientPoolConfig.getMaxConnectPerRoute() <= 0) { + throw new IllegalArgumentException("invalid maxConnectionPerRoute: " + httpClientPoolConfig.getMaxConnectPerRoute()); + } + HttpComponentsClientHttpRequestFactory clientHttpRequestFactory = new HttpComponentsClientHttpRequestFactory(httpClient()); + // 连接超时 + clientHttpRequestFactory.setConnectTimeout(httpClientPoolConfig.getConnectTimeout()); + // 数据读取超时时间,即SocketTimeout + clientHttpRequestFactory.setReadTimeout(httpClientPoolConfig.getReadTimeout()); + // 从连接池获取请求连接的超时时间,不宜过长,必须设置,比如连接不够用时,时间过长将是灾难性的 + clientHttpRequestFactory.setConnectionRequestTimeout(httpClientPoolConfig.getConnectionRequestTimout()); + return clientHttpRequestFactory; + } + + /** + * 初始化RestTemplate,并加入spring的Bean工厂,由spring统一管理 + */ + @Bean(name = "dataSourceRestTemplate") + public RestTemplate restTemplate(@Qualifier("clientHttpRequestFactory") ClientHttpRequestFactory factory) { + return createRestTemplate(factory); + } + + /** + * 配置httpClient + * + * @return + */ + @Bean + public HttpClient httpClient() { + HttpClientBuilder httpClientBuilder = HttpClientBuilder.create(); + try { + //设置信任ssl访问 + SSLContext sslContext = new SSLContextBuilder().loadTrustMaterial(null, (arg0, arg1) -> true).build(); + + httpClientBuilder.setSSLContext(sslContext); + HostnameVerifier hostnameVerifier = NoopHostnameVerifier.INSTANCE; + SSLConnectionSocketFactory sslConnectionSocketFactory = new SSLConnectionSocketFactory(sslContext, hostnameVerifier); + Registry socketFactoryRegistry = RegistryBuilder.create() + // 注册http和https请求 + .register("http", PlainConnectionSocketFactory.getSocketFactory()) + .register("https", sslConnectionSocketFactory).build(); + + //使用Httpclient连接池的方式配置(推荐),同时支持netty,okHttp以及其他http框架 + PoolingHttpClientConnectionManager poolingHttpClientConnectionManager = new PoolingHttpClientConnectionManager(socketFactoryRegistry); + // 最大连接数 + poolingHttpClientConnectionManager.setMaxTotal(httpClientPoolConfig.getMaxTotalConnect()); + // 同路由并发数 + poolingHttpClientConnectionManager.setDefaultMaxPerRoute(httpClientPoolConfig.getMaxConnectPerRoute()); + //配置连接池 + httpClientBuilder.setConnectionManager(poolingHttpClientConnectionManager); + // 重试次数 + httpClientBuilder.setRetryHandler(new DefaultHttpRequestRetryHandler(httpClientPoolConfig.getRetryTimes(), true)); + + //设置默认请求头 + List
headers = getDefaultHeaders(); + httpClientBuilder.setDefaultHeaders(headers); + //设置长连接保持策略 + httpClientBuilder.setKeepAliveStrategy(connectionKeepAliveStrategy()); + return httpClientBuilder.build(); + } catch (KeyManagementException | NoSuchAlgorithmException | KeyStoreException e) { + log.error("初始化HTTP连接池出错", e); + } + return null; + } + + + /** + * 配置长连接保持策略 + * + * @return + */ + public ConnectionKeepAliveStrategy connectionKeepAliveStrategy() { + return (response, context) -> { + // Honor 'keep-alive' header + HeaderElementIterator it = new BasicHeaderElementIterator( + response.headerIterator(HTTP.CONN_KEEP_ALIVE)); + while (it.hasNext()) { + HeaderElement he = it.nextElement(); + log.info("HeaderElement:{}", JSON.toJSONString(he)); + String param = he.getName(); + String value = he.getValue(); + if (value != null && "timeout".equalsIgnoreCase(param)) { + try { + return Long.parseLong(value) * 1000; + } catch (NumberFormatException ignore) { + log.error("解析长连接过期时间异常", ignore); + } + } + } + HttpHost target = (HttpHost) context.getAttribute( + HttpClientContext.HTTP_TARGET_HOST); + //如果请求目标地址,单独配置了长连接保持时间,使用该配置 + Optional> any = Optional.ofNullable(httpClientPoolConfig.getKeepAliveTargetHost()).orElseGet(HashMap::new) + .entrySet().stream().filter( + e -> e.getKey().equalsIgnoreCase(target.getHostName())).findAny(); + //否则使用默认长连接保持时间 + return any.map(en -> en.getValue() * 1000L).orElse(httpClientPoolConfig.getKeepAliveTime() * 1000L); + }; + } + + + /** + * 设置请求头 + * + * @return + */ + private List
getDefaultHeaders() { + List
headers = new ArrayList<>(); + headers.add(new BasicHeader("User-Agent", + "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/31.0.1650.16 Safari/537.36")); + headers.add(new BasicHeader("Accept-Encoding", "gzip,deflate")); + headers.add(new BasicHeader("Accept-Language", "zh-CN")); + headers.add(new BasicHeader("Connection", "Keep-Alive")); + return headers; + } + + + private RestTemplate createRestTemplate(ClientHttpRequestFactory factory) { + RestTemplate restTemplate = new RestTemplate(factory); + + //我们采用RestTemplate内部的MessageConverter + //重新设置StringHttpMessageConverter字符集,解决中文乱码问题 + modifyDefaultCharset(restTemplate); + + //设置错误处理器 + restTemplate.setErrorHandler(new DefaultResponseErrorHandler()); + + return restTemplate; + } + + /** + * 修改默认的字符集类型为utf-8 + * + * @param restTemplate + */ + private void modifyDefaultCharset(RestTemplate restTemplate) { + List> converterList = restTemplate.getMessageConverters(); + HttpMessageConverter converterTarget = null; + for (HttpMessageConverter item : converterList) { + if (StringHttpMessageConverter.class == item.getClass()) { + converterTarget = item; + break; + } + } + if (null != converterTarget) { + converterList.remove(converterTarget); + } + Charset defaultCharset = Charset.forName(httpClientPoolConfig.getCharset()); + converterList.add(1, new StringHttpMessageConverter(defaultCharset)); + } +} + diff --git a/src/main/java/com/anjiplus/template/gaea/business/modules/datasource/config/HttpClientPoolConfig.java b/src/main/java/com/anjiplus/template/gaea/business/modules/datasource/config/HttpClientPoolConfig.java new file mode 100644 index 0000000..ad12493 --- /dev/null +++ b/src/main/java/com/anjiplus/template/gaea/business/modules/datasource/config/HttpClientPoolConfig.java @@ -0,0 +1,53 @@ +package com.anjiplus.template.gaea.business.modules.datasource.config; + +import lombok.Data; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.stereotype.Component; + +import java.util.Map; + +/** + * Created by raodeming on 2021/3/24. + */ +@Component +@ConfigurationProperties(prefix = "spring.http-client.pool") +@Data +public class HttpClientPoolConfig { + /** + * java配置的优先级低于yml配置;如果yml配置不存在,会采用java配置 + */ + /** + * 连接池的最大连接数 + */ + private int maxTotalConnect = 1000; + /** + * 同路由的并发数 + */ + private int maxConnectPerRoute = 200; + /** + * 客户端和服务器建立连接超时,默认2s + */ + private int connectTimeout = 2 * 1000; + /** + * 指客户端从服务器读取数据包的间隔超时时间,不是总读取时间,默认30s + */ + private int readTimeout = 30 * 1000; + + private String charset = "UTF-8"; + /** + * 重试次数,默认2次 + */ + private int retryTimes = 2; + /** + * 从连接池获取连接的超时时间,不宜过长,单位ms + */ + private int connectionRequestTimout = 200; + /** + * 针对不同的地址,特别设置不同的长连接保持时间 + */ + private Map keepAliveTargetHost; + /** + * 针对不同的地址,特别设置不同的长连接保持时间,单位 s + */ + private int keepAliveTime = 60; +} diff --git a/src/main/java/com/anjiplus/template/gaea/business/modules/datasource/controller/DataSourceController.java b/src/main/java/com/anjiplus/template/gaea/business/modules/datasource/controller/DataSourceController.java new file mode 100644 index 0000000..ba6c3a4 --- /dev/null +++ b/src/main/java/com/anjiplus/template/gaea/business/modules/datasource/controller/DataSourceController.java @@ -0,0 +1,68 @@ + +package com.anjiplus.template.gaea.business.modules.datasource.controller; + +import com.anji.plus.gaea.annotation.Permission; +import com.anji.plus.gaea.bean.ResponseBean; +import com.anji.plus.gaea.curd.controller.GaeaBaseController; +import com.anji.plus.gaea.curd.service.GaeaBaseService; +import com.anjiplus.template.gaea.business.modules.datasource.controller.dto.DataSourceDto; +import com.anjiplus.template.gaea.business.modules.datasource.controller.param.ConnectionParam; +import com.anjiplus.template.gaea.business.modules.datasource.controller.param.DataSourceParam; +import com.anjiplus.template.gaea.business.modules.datasource.dao.entity.DataSource; +import com.anjiplus.template.gaea.business.modules.datasource.service.DataSourceService; +import io.swagger.annotations.Api; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +/** +* @desc 数据源 controller +* @website https://gitee.com/anji-plus/gaea +* @author Raod +* @date 2021-03-18 12:09:57.728203200 +**/ +@RestController +@Api(tags = "数据源管理") +@Permission(code = "datasourceManage", name = "数据源管理") +@RequestMapping("/dataSource") +public class DataSourceController extends GaeaBaseController { + + @Autowired + private DataSourceService dataSourceService; + + @Override + public GaeaBaseService getService() { + return dataSourceService; + } + + @Override + public DataSource getEntity() { + return new DataSource(); + } + + @Override + public DataSourceDto getDTO() { + return new DataSourceDto(); + } + + /** + * 获取所有数据源 + * @return + */ + @GetMapping("/queryAllDataSource") + public ResponseBean queryAllDataSource() { + return responseSuccessWithData(dataSourceService.queryAllDataSource()); + } + + /** + * 测试 连接 + * @param connectionParam + * @return + */ + @Permission( code = "query", name = "测试数据源") + @PostMapping("/testConnection") + public ResponseBean testConnection(@Validated @RequestBody ConnectionParam connectionParam) { + return responseSuccessWithData(dataSourceService.testConnection(connectionParam)); + } + +} diff --git a/src/main/java/com/anjiplus/template/gaea/business/modules/datasource/controller/dto/DataSourceDto.java b/src/main/java/com/anjiplus/template/gaea/business/modules/datasource/controller/dto/DataSourceDto.java new file mode 100644 index 0000000..e22eea6 --- /dev/null +++ b/src/main/java/com/anjiplus/template/gaea/business/modules/datasource/controller/dto/DataSourceDto.java @@ -0,0 +1,74 @@ + +package com.anjiplus.template.gaea.business.modules.datasource.controller.dto; + +import com.anji.plus.gaea.curd.dto.GaeaBaseDTO; +import lombok.Data; + +import java.io.Serializable; +import java.util.Map; + + +/** +* +* @description 数据源 dto +* @author Raod +* @date 2021-03-18 12:09:57.728203200 +**/ +@Data +public class DataSourceDto extends GaeaBaseDTO implements Serializable { + /** 数据源编码 */ + private String sourceCode; + + /** 数据源名称 */ + private String sourceName; + + /** 数据源描述 */ + private String sourceDesc; + + /** 数据源类型 DIC_NAME=SOURCE_TYPE; mysql,orace,sqlserver,elasticsearch,接口,javaBean,数据源类型字典中item-extend动态生成表单 */ + private String sourceType; + + /** 数据源连接配置json:关系库{ jdbcUrl:'', username:'', password:'','driverName':''}ES-sql{ apiUrl:'http://127.0.0.1:9092/_xpack/sql?format=json','method':'POST','body':'{"query":"select 1"}' } 接口{ apiUrl:'http://ip:port/url', method:'' } javaBean{ beanNamw:'xxx' } */ + private String sourceConfig; + + /** 0--已禁用 1--已启用 DIC_NAME=ENABLE_FLAG */ + private Integer enableFlag; + + /** 0--未删除 1--已删除 DIC_NAME=DELETE_FLAG */ + private Integer deleteFlag; + + /**************************************************************/ + /**关系型数据库jdbcUrl */ + private String jdbcUrl; + + /** 关系型数据库用户名 */ + private String username; + + /** 关系型数据库密码 */ + private String password; + + /** 关系型数据库驱动类 */ + private String driverName; + + /** 关系型数据库sql */ + private String sql; + + /** http requestUrl */ + private String apiUrl; + + /** http method */ + private String method; + + /** http header */ + private String header; + + /** http 请求体 */ + private String body; + + /** 动态查询sql或者接口中的请求体 */ + private String dynSentence; + + /** 传入的自定义参数,解决url中存在的动态参数*/ + private Map contextData; + +} diff --git a/src/main/java/com/anjiplus/template/gaea/business/modules/datasource/controller/param/ConnectionParam.java b/src/main/java/com/anjiplus/template/gaea/business/modules/datasource/controller/param/ConnectionParam.java new file mode 100644 index 0000000..ec97092 --- /dev/null +++ b/src/main/java/com/anjiplus/template/gaea/business/modules/datasource/controller/param/ConnectionParam.java @@ -0,0 +1,21 @@ +package com.anjiplus.template.gaea.business.modules.datasource.controller.param; + +import lombok.Data; + +import javax.validation.constraints.NotBlank; +import java.io.Serializable; + +/** + * Created by raodeming on 2021/3/19. + */ +@Data +public class ConnectionParam implements Serializable { + + /** 数据源类型 DIC_NAME=SOURCE_TYPE; mysql,orace,sqlserver,elasticsearch,接口,javaBean,数据源类型字典中item-extend动态生成表单 */ + @NotBlank(message = "sourceType not empty") + private String sourceType; + + /** 数据源连接配置json:关系库{ jdbcUrl:'', username:'', password:'','driverName':''}ES-sql{ apiUrl:'http://127.0.0.1:9092/_xpack/sql?format=json','method':'POST','body':'{"query":"select 1"}' } 接口{ apiUrl:'http://ip:port/url', method:'' } javaBean{ beanNamw:'xxx' } */ + @NotBlank(message = "sourceConfig not empty") + private String sourceConfig; +} diff --git a/src/main/java/com/anjiplus/template/gaea/business/modules/datasource/controller/param/DataSourceParam.java b/src/main/java/com/anjiplus/template/gaea/business/modules/datasource/controller/param/DataSourceParam.java new file mode 100644 index 0000000..f8d98e8 --- /dev/null +++ b/src/main/java/com/anjiplus/template/gaea/business/modules/datasource/controller/param/DataSourceParam.java @@ -0,0 +1,31 @@ +/**/ +package com.anjiplus.template.gaea.business.modules.datasource.controller.param; + +import com.anji.plus.gaea.annotation.Query; +import com.anji.plus.gaea.constant.QueryEnum; +import com.anji.plus.gaea.curd.params.PageParam; +import lombok.Data; + +import java.io.Serializable; + + +/** +* @desc DataSource 数据集查询输入类 +* @author Raod +* @date 2021-03-18 12:09:57.728203200 +**/ +@Data +public class DataSourceParam extends PageParam implements Serializable{ + + /** 数据源名称 */ + @Query(QueryEnum.LIKE) + private String sourceName; + + /** 数据源编码 */ + @Query(QueryEnum.LIKE) + private String sourceCode; + + /** 数据源类型 DIC_NAME=SOURCE_TYPE; mysql,orace,sqlserver,elasticsearch,接口,javaBean,数据源类型字典中item-extend动态生成表单 */ + @Query(QueryEnum.EQ) + private String sourceType; +} diff --git a/src/main/java/com/anjiplus/template/gaea/business/modules/datasource/dao/DataSourceMapper.java b/src/main/java/com/anjiplus/template/gaea/business/modules/datasource/dao/DataSourceMapper.java new file mode 100644 index 0000000..3bcf882 --- /dev/null +++ b/src/main/java/com/anjiplus/template/gaea/business/modules/datasource/dao/DataSourceMapper.java @@ -0,0 +1,16 @@ +package com.anjiplus.template.gaea.business.modules.datasource.dao; + +import org.apache.ibatis.annotations.Mapper; + +import com.anji.plus.gaea.curd.mapper.GaeaBaseMapper; +import com.anjiplus.template.gaea.business.modules.datasource.dao.entity.DataSource; + +/** +* DataSource Mapper +* @author Raod +* @date 2021-03-18 12:09:57.728203200 +**/ +@Mapper +public interface DataSourceMapper extends GaeaBaseMapper { + +} diff --git a/src/main/java/com/anjiplus/template/gaea/business/modules/datasource/dao/entity/DataSource.java b/src/main/java/com/anjiplus/template/gaea/business/modules/datasource/dao/entity/DataSource.java new file mode 100644 index 0000000..79f1e5b --- /dev/null +++ b/src/main/java/com/anjiplus/template/gaea/business/modules/datasource/dao/entity/DataSource.java @@ -0,0 +1,42 @@ + +package com.anjiplus.template.gaea.business.modules.datasource.dao.entity; + +import com.anji.plus.gaea.annotation.Unique; +import com.anji.plus.gaea.curd.entity.GaeaBaseEntity; +import com.anjiplus.template.gaea.business.code.ResponseCode; +import com.baomidou.mybatisplus.annotation.TableName; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +/** +* @description 数据源 entity +* @author Raod +* @date 2021-03-18 12:09:57.728203200 +**/ +@TableName(keepGlobalPrefix=true, value="gaea_report_data_source") +@Data +public class DataSource extends GaeaBaseEntity { + @ApiModelProperty(value = "数据源编码") + @Unique(code = ResponseCode.SOURCE_CODE_ISEXIST) + private String sourceCode; + + @ApiModelProperty(value = "数据源名称") + private String sourceName; + + @ApiModelProperty(value = "数据源描述") + private String sourceDesc; + + @ApiModelProperty(value = "数据源类型 DIC_NAME=SOURCE_TYPE; mysql,orace,sqlserver,elasticsearch,接口,javaBean,数据源类型字典中item-extend动态生成表单") + private String sourceType; + + @ApiModelProperty(value = "数据源连接配置json:关系库{ jdbcUrl:'', username:'', password:'','driverName':''}ES-sql{ apiUrl:'http://127.0.0.1:9092/_xpack/sql?format=json','method':'POST','body':'{\"query\":\"select 1\"}' } 接口{ apiUrl:'http://ip:port/url', method:'' } javaBean{ beanNamw:'xxx' }") + private String sourceConfig; + + @ApiModelProperty(value = "0--已禁用 1--已启用 DIC_NAME=ENABLE_FLAG") + private Integer enableFlag; + + @ApiModelProperty(value = "0--未删除 1--已删除 DIC_NAME=DELETE_FLAG") + private Integer deleteFlag; + + +} diff --git a/src/main/java/com/anjiplus/template/gaea/business/modules/datasource/service/DataSourceService.java b/src/main/java/com/anjiplus/template/gaea/business/modules/datasource/service/DataSourceService.java new file mode 100644 index 0000000..17e318b --- /dev/null +++ b/src/main/java/com/anjiplus/template/gaea/business/modules/datasource/service/DataSourceService.java @@ -0,0 +1,48 @@ + +package com.anjiplus.template.gaea.business.modules.datasource.service; + +import com.alibaba.fastjson.JSONObject; +import com.anji.plus.gaea.curd.service.GaeaBaseService; +import com.anjiplus.template.gaea.business.modules.dataset.controller.dto.DataSetDto; +import com.anjiplus.template.gaea.business.modules.datasource.controller.dto.DataSourceDto; +import com.anjiplus.template.gaea.business.modules.datasource.controller.param.ConnectionParam; +import com.anjiplus.template.gaea.business.modules.datasource.controller.param.DataSourceParam; +import com.anjiplus.template.gaea.business.modules.datasource.dao.entity.DataSource; + +import java.util.List; + +/** +* @desc DataSource 数据集服务接口 +* @author Raod +* @date 2021-03-18 12:09:57.728203200 +**/ +public interface DataSourceService extends GaeaBaseService { + + /** + * 获取所有数据源 + * @return + */ + List queryAllDataSource(); + + /** + * 测试 连接 + * @param connectionParam + * @return + */ + Boolean testConnection(ConnectionParam connectionParam); + + /** + * 执行sql + * @param dto + * @return + */ + List execute(DataSourceDto dto); + + /** + * 执行sql,统计数据total + * @param dataSourceDto + * @param dto + * @return + */ + long total(DataSourceDto dataSourceDto, DataSetDto dto); +} diff --git a/src/main/java/com/anjiplus/template/gaea/business/modules/datasource/service/JdbcService.java b/src/main/java/com/anjiplus/template/gaea/business/modules/datasource/service/JdbcService.java new file mode 100644 index 0000000..56dadf9 --- /dev/null +++ b/src/main/java/com/anjiplus/template/gaea/business/modules/datasource/service/JdbcService.java @@ -0,0 +1,39 @@ +package com.anjiplus.template.gaea.business.modules.datasource.service; + +import com.anjiplus.template.gaea.business.modules.datasource.controller.dto.DataSourceDto; + +import java.sql.Connection; +import java.sql.SQLException; + +/** + * Created by raodeming on 2021/8/6. + */ +public interface JdbcService { + + /** + * 删除数据库连接池 + * + * @param id + */ + void removeJdbcConnectionPool(Long id); + + + /** + * 获取连接 + * + * @param dataSource + * @return + * @throws SQLException + */ + Connection getPooledConnection(DataSourceDto dataSource) throws SQLException; + + /** + * 测试数据库连接 获取一个连接 + * + * @param dataSource + * @return + * @throws ClassNotFoundException driverName不正确 + * @throws SQLException + */ + Connection getUnPooledConnection(DataSourceDto dataSource) throws SQLException; +} diff --git a/src/main/java/com/anjiplus/template/gaea/business/modules/datasource/service/impl/DataSourceServiceImpl.java b/src/main/java/com/anjiplus/template/gaea/business/modules/datasource/service/impl/DataSourceServiceImpl.java new file mode 100644 index 0000000..0485a29 --- /dev/null +++ b/src/main/java/com/anjiplus/template/gaea/business/modules/datasource/service/impl/DataSourceServiceImpl.java @@ -0,0 +1,452 @@ + +package com.anjiplus.template.gaea.business.modules.datasource.service.impl; + +import com.alibaba.fastjson.JSONArray; +import com.alibaba.fastjson.JSONObject; +import com.anji.plus.gaea.constant.BaseOperationEnum; +import com.anji.plus.gaea.constant.Enabled; +import com.anji.plus.gaea.curd.mapper.GaeaBaseMapper; +import com.anji.plus.gaea.exception.BusinessException; +import com.anji.plus.gaea.exception.BusinessExceptionBuilder; +import com.anji.plus.gaea.utils.GaeaAssert; +import com.anjiplus.template.gaea.business.code.ResponseCode; +import com.anjiplus.template.gaea.business.constant.BusinessConstant; +import com.anjiplus.template.gaea.business.modules.dataset.controller.dto.DataSetDto; +import com.anjiplus.template.gaea.business.modules.datasetparam.service.DataSetParamService; +import com.anjiplus.template.gaea.business.modules.datasource.controller.dto.DataSourceDto; +import com.anjiplus.template.gaea.business.modules.datasource.controller.param.ConnectionParam; +import com.anjiplus.template.gaea.business.modules.datasource.dao.DataSourceMapper; +import com.anjiplus.template.gaea.business.modules.datasource.dao.entity.DataSource; +import com.anjiplus.template.gaea.business.modules.datasource.service.DataSourceService; +import com.anjiplus.template.gaea.business.modules.datasource.service.JdbcService; +import com.anjiplus.template.gaea.business.util.JdbcConstants; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.HttpEntity; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpMethod; +import org.springframework.http.ResponseEntity; +import org.springframework.stereotype.Service; +import org.springframework.web.client.RestClientException; +import org.springframework.web.client.RestTemplate; + +import javax.annotation.Resource; +import java.sql.*; +import java.util.ArrayList; +import java.util.Date; +import java.util.List; +import java.util.Map; + +/** + * @author Raod + * @desc DataSource 数据集服务实现 + * @date 2021-03-18 12:09:57.728203200 + **/ +@Service +@Slf4j +public class DataSourceServiceImpl implements DataSourceService { + + @Autowired + private DataSourceMapper dataSourceMapper; + + @Resource(name = "dataSourceRestTemplate") + private RestTemplate restTemplate; + + @Autowired + private DataSetParamService dataSetParamService; + + @Autowired + private JdbcService jdbcService; + + @Override + public GaeaBaseMapper getMapper() { + return dataSourceMapper; + } + + + /** + * 获取所有数据源 + * @return + */ + @Override + public List queryAllDataSource() { + LambdaQueryWrapper wrapper = Wrappers.lambdaQuery(); + wrapper.select(DataSource::getSourceCode, DataSource::getSourceName) + .eq(DataSource::getEnableFlag, Enabled.YES.getValue()); + wrapper.orderByDesc(DataSource::getUpdateTime); + return dataSourceMapper.selectList(wrapper); + } + + /** + * 测试 连接 + * + * @param connectionParam + * @return + */ + @Override + public Boolean testConnection(ConnectionParam connectionParam) { + String sourceType = connectionParam.getSourceType(); + String sourceConfig = connectionParam.getSourceConfig(); + DataSourceDto dto = new DataSourceDto(); + dto.setSourceConfig(sourceConfig); + switch (sourceType) { + case JdbcConstants.ELASTIC_SEARCH_SQL: + testElasticsearchSqlConnection(dto); + break; + case JdbcConstants.MYSQL: + case JdbcConstants.KUDU_IMAPLA: + case JdbcConstants.ORACLE: + case JdbcConstants.SQL_SERVER: + case JdbcConstants.JDBC: + case JdbcConstants.POSTGRESQL: + testRelationalDb(dto); + break; + case JdbcConstants.HTTP: + testHttp(dto); + break; + default: + throw BusinessExceptionBuilder.build(ResponseCode.DATA_SOURCE_TYPE_DOES_NOT_MATCH_TEMPORARILY); + } + log.info("测试连接成功:{}", JSONObject.toJSONString(connectionParam)); + return true; + + } + + @Override + public List execute(DataSourceDto dto) { + String sourceType = dto.getSourceType(); + switch (sourceType) { + case JdbcConstants.ELASTIC_SEARCH_SQL: + return executeElasticsearchSql(dto); + case JdbcConstants.MYSQL: + case JdbcConstants.KUDU_IMAPLA: + case JdbcConstants.ORACLE: + case JdbcConstants.SQL_SERVER: + case JdbcConstants.JDBC: + case JdbcConstants.POSTGRESQL: + return executeRelationalDb(dto); + case JdbcConstants.HTTP: + return executeHttp(dto); + default: + throw BusinessExceptionBuilder.build(ResponseCode.DATA_SOURCE_TYPE_DOES_NOT_MATCH_TEMPORARILY); + } + } + + /** + * 执行sql,统计数据total + * + * @param dto + * @return + */ + @Override + public long total(DataSourceDto sourceDto, DataSetDto dto) { + //区分数据类型 + String sourceType = sourceDto.getSourceType(); + switch (sourceType) { + case JdbcConstants.ELASTIC_SEARCH_SQL: + return 0; + case JdbcConstants.MYSQL: + return mysqlTotal(sourceDto, dto); + default: + throw BusinessExceptionBuilder.build(ResponseCode.DATA_SOURCE_TYPE_DOES_NOT_MATCH_TEMPORARILY); + } + + } + + /** + * 获取mysql count 和添加limit分页信息 + * @param sourceDto + * @param dto + * @return + */ + public long mysqlTotal(DataSourceDto sourceDto, DataSetDto dto){ + String dynSentence = sourceDto.getDynSentence(); + String sql = "select count(1) as count from (" + dynSentence + ") as gaeaExecute"; + sourceDto.setDynSentence(sql); + List result = execute(sourceDto); + + //sql 拼接 limit 分页信息 + int pageNumber = Integer.parseInt(dto.getContextData().getOrDefault("pageNumber", "1").toString()); + int pageSize = Integer.parseInt(dto.getContextData().getOrDefault("pageSize", "10").toString()); + String sqlLimit = " limit " + (pageNumber - 1) * pageSize + "," + pageSize; + sourceDto.setDynSentence(dynSentence.concat(sqlLimit)); + log.info("当前total:{}, 添加分页参数,sql语句:{}", JSONObject.toJSONString(result), sourceDto.getDynSentence()); + return result.get(0).getLongValue("count"); + } + + + + public List executeElasticsearchSql(DataSourceDto dto) { + analysisHttpConfig(dto); + HttpHeaders headers = new HttpHeaders(); + headers.setAll(JSONObject.parseObject(dto.getHeader(), Map.class)); + HttpEntity entity = new HttpEntity<>(dto.getDynSentence(), headers); + ResponseEntity exchange; + try { + exchange = restTemplate.exchange(dto.getApiUrl(), HttpMethod.valueOf(dto.getMethod()), entity, JSONObject.class); + } catch (Exception e) { + log.error("error",e); + throw BusinessExceptionBuilder.build(ResponseCode.DATA_SOURCE_CONNECTION_FAILED, e.getMessage()); + } + if (exchange.getStatusCode().isError()) { + throw BusinessExceptionBuilder.build(ResponseCode.DATA_SOURCE_CONNECTION_FAILED, exchange.getBody()); + } + List result; + try { + JSONObject body = exchange.getBody(); + //解析es sql数据 + if (null == body) { + return null; + } + JSONArray columns = body.getJSONArray("columns"); + JSONArray rows = body.getJSONArray("rows"); + result = new ArrayList<>(); + for (int i = 0; i < rows.size(); i++) { + JSONArray row = rows.getJSONArray(i); + JSONObject jsonObject = new JSONObject(); + for (int j = 0; j < row.size(); j++) { + String name = columns.getJSONObject(j).getString("name"); + String value = row.getString(j); + jsonObject.put(name, value); + } + result.add(jsonObject); + } + } catch (Exception e) { + log.error("error",e); + throw BusinessExceptionBuilder.build(ResponseCode.ANALYSIS_DATA_ERROR, e.getMessage()); + } + return result; + } + + public List executeRelationalDb(DataSourceDto dto) { + analysisRelationalDbConfig(dto); + Connection pooledConnection = null; + try { + pooledConnection = jdbcService.getPooledConnection(dto); + + PreparedStatement statement = pooledConnection.prepareStatement(dto.getDynSentence()); + ResultSet rs = statement.executeQuery(); + + int columnCount = rs.getMetaData().getColumnCount(); + + List columns = new ArrayList<>(); + for (int i = 1; i <= columnCount; i++) { + String columnName = rs.getMetaData().getColumnLabel(i); + columns.add(columnName); + } + List list = new ArrayList<>(); + while (rs.next()) { + JSONObject jo = new JSONObject(); + columns.forEach(t -> { + try { + Object value = rs.getObject(t); + //数据类型转换 + Object result = dealResult(value); + jo.put(t, result); + } catch (SQLException throwable) { + log.error("error",throwable); + throw BusinessExceptionBuilder.build(ResponseCode.EXECUTE_SQL_ERROR, throwable.getMessage()); + } + }); + list.add(jo); + } + return list; + } catch (Exception throwable) { + log.error("error",throwable); + throw BusinessExceptionBuilder.build(ResponseCode.EXECUTE_SQL_ERROR, throwable.getMessage()); + } finally { + try { + if (pooledConnection != null) { + pooledConnection.close(); + } + } catch (SQLException throwable) { + log.error("error",throwable); + throw BusinessExceptionBuilder.build(ResponseCode.DATA_SOURCE_CONNECTION_FAILED, throwable.getMessage()); + } + } + } + + /** + * 解决sql返回值 类型问题 + * (through reference chain: java.util.HashMap["pageData"]->java.util.ArrayList[0]->java.util.HashMap["UPDATE_TIME"]->oracle.sql.TIMESTAMP["stream"]) + * @param result + * @return + * @throws SQLException + */ + private Object dealResult(Object result) throws SQLException { + if (null == result) { + return result; + } + String type = result.getClass().getName(); + if ("oracle.sql.TIMESTAMP".equals(type)) { + //oracle.sql.TIMESTAMP处理逻辑 + return new Date((Long) JSONObject.toJSON(result)); + } + + return result; + } + + /** + * http 执行获取数据 + * + * @param dto + */ + public List executeHttp(DataSourceDto dto) { + analysisHttpConfig(dto); + HttpHeaders headers = new HttpHeaders(); + headers.setAll(JSONObject.parseObject(dto.getHeader(), Map.class)); + HttpEntity entity = new HttpEntity<>(dto.getDynSentence(), headers); + ResponseEntity exchange; + try { + exchange = restTemplate.exchange(dto.getApiUrl(), HttpMethod.valueOf(dto.getMethod()), entity, Object.class); + } catch (Exception e) { + log.error("error",e); + throw BusinessExceptionBuilder.build(ResponseCode.DATA_SOURCE_CONNECTION_FAILED, e.getMessage()); + } + if (exchange.getStatusCode().isError()) { + throw BusinessExceptionBuilder.build(ResponseCode.DATA_SOURCE_CONNECTION_FAILED, exchange.getBody()); + } + Object body = exchange.getBody(); + String jsonStr = JSONObject.toJSONString(body); + List result = new ArrayList<>(); + if (jsonStr.trim().startsWith(BusinessConstant.LEFT_BIG_BOAST) && jsonStr.trim().endsWith(BusinessConstant.RIGTH_BIG_BOAST)) { + //JSONObject + result.add(JSONObject.parseObject(jsonStr)); + } else if (jsonStr.trim().startsWith(BusinessConstant.LEFT_MIDDLE_BOAST) && jsonStr.trim().endsWith(BusinessConstant.RIGHT_MIDDLE_BOAST)) { + //List + result = JSONArray.parseArray(jsonStr, JSONObject.class); + } else { + result.add(new JSONObject()); + } + return result; + } + + /** + * 关系型数据库 测试连接 + * + * @param dto + */ + public void testRelationalDb(DataSourceDto dto) { + analysisRelationalDbConfig(dto); + try { + Connection unPooledConnection = jdbcService.getUnPooledConnection(dto); + String catalog = unPooledConnection.getCatalog(); + log.info("数据库测试连接成功:{}", catalog); + unPooledConnection.close(); + } catch (SQLException e) { + log.error("error",e); + if (e.getCause() instanceof ClassNotFoundException) { + throw BusinessExceptionBuilder.build(ResponseCode.CLASS_NOT_FOUND, e.getCause().getMessage()); + } else { + throw BusinessExceptionBuilder.build(ResponseCode.DATA_SOURCE_CONNECTION_FAILED, e.getMessage()); + } + + } + } + + /** + * http 测试连接 + * + * @param dto + */ + public void testHttp(DataSourceDto dto) { + analysisHttpConfig(dto); + String apiUrl = dto.getApiUrl(); + String method = dto.getMethod(); + String body = dto.getBody(); + HttpHeaders headers = new HttpHeaders(); + headers.setAll(JSONObject.parseObject(dto.getHeader(), Map.class)); + HttpEntity entity = new HttpEntity<>(body, headers); + ResponseEntity exchange; + try { + exchange = restTemplate.exchange(apiUrl, HttpMethod.valueOf(method), entity, Object.class); + if (exchange.getStatusCode().isError()) { + throw BusinessExceptionBuilder.build(ResponseCode.DATA_SOURCE_CONNECTION_FAILED, exchange.getBody()); + } + } catch (RestClientException e) { + throw BusinessExceptionBuilder.build(ResponseCode.DATA_SOURCE_CONNECTION_FAILED, e.getMessage()); + } + } + + + /** + * 关系型数据库 测试连接 + * + * @param dto + */ + public void testElasticsearchSqlConnection(DataSourceDto dto) { + analysisHttpConfig(dto); + String apiUrl = dto.getApiUrl(); + String method = dto.getMethod(); + String body = dto.getBody(); + HttpHeaders headers = new HttpHeaders(); + headers.setAll(JSONObject.parseObject(dto.getHeader(), Map.class)); + HttpEntity entity = new HttpEntity<>(body, headers); + ResponseEntity exchange; + try { + exchange = restTemplate.exchange(apiUrl, HttpMethod.valueOf(method), entity, Object.class); + if (exchange.getStatusCode().isError()) { + throw BusinessExceptionBuilder.build(ResponseCode.DATA_SOURCE_CONNECTION_FAILED, exchange.getBody()); + } + } catch (RestClientException e) { + throw BusinessExceptionBuilder.build(ResponseCode.DATA_SOURCE_CONNECTION_FAILED, e.getMessage()); + } + + } + + + public void analysisRelationalDbConfig(DataSourceDto dto) { + JSONObject json = JSONObject.parseObject(dto.getSourceConfig()); + GaeaAssert.isFalse(json.containsKey("jdbcUrl"), ResponseCode.PARAM_IS_NULL,"jdbcUrl not empty"); + GaeaAssert.isFalse(json.containsKey("driverName"), ResponseCode.PARAM_IS_NULL,"driverName not empty"); + String jdbcUrl = json.getString("jdbcUrl"); + String username = json.getString("username"); + String password = json.getString("password"); + String driverName = json.getString("driverName"); + dto.setJdbcUrl(jdbcUrl); + dto.setDriverName(driverName); + dto.setUsername(username); + dto.setPassword(password); + } + + + /** + * es通过api获取数据 + * + * @param dto + * @return + */ + public void analysisHttpConfig(DataSourceDto dto) { + JSONObject json = JSONObject.parseObject(dto.getSourceConfig()); + GaeaAssert.isFalse(json.containsKey("apiUrl"), ResponseCode.PARAM_IS_NULL,"apiUrl not empty"); + GaeaAssert.isFalse(json.containsKey("method"), ResponseCode.PARAM_IS_NULL,"method not empty"); + GaeaAssert.isFalse(json.containsKey("header"), ResponseCode.PARAM_IS_NULL,"header not empty"); + GaeaAssert.isFalse(json.containsKey("body"), ResponseCode.PARAM_IS_NULL,"body not empty"); + String apiUrl = json.getString("apiUrl"); + String method = json.getString("method"); + String header = json.getString("header"); + String body = json.getString("body"); + //解决url中存在的动态参数 + apiUrl = dataSetParamService.transform(dto.getContextData(), apiUrl); + //请求头中动态参数 + header = dataSetParamService.transform(dto.getContextData(), header); + dto.setApiUrl(apiUrl); + dto.setMethod(method); + dto.setHeader(header); + dto.setBody(body); + } + + /** + * 操作后续处理 + * + * @param entity + * @param operationEnum 操作类型 + * @throws BusinessException 阻止程序继续执行或回滚事务 + */ + @Override + public void processAfterOperation(DataSource entity, BaseOperationEnum operationEnum) throws BusinessException { + jdbcService.removeJdbcConnectionPool(entity.getId()); + } +} diff --git a/src/main/java/com/anjiplus/template/gaea/business/modules/datasource/service/impl/JdbcServiceImpl.java b/src/main/java/com/anjiplus/template/gaea/business/modules/datasource/service/impl/JdbcServiceImpl.java new file mode 100644 index 0000000..c9c7f98 --- /dev/null +++ b/src/main/java/com/anjiplus/template/gaea/business/modules/datasource/service/impl/JdbcServiceImpl.java @@ -0,0 +1,99 @@ +package com.anjiplus.template.gaea.business.modules.datasource.service.impl; + +import com.anjiplus.template.gaea.business.config.HikariPoolProperties; +import com.anjiplus.template.gaea.business.modules.datasource.controller.dto.DataSourceDto; +import com.anjiplus.template.gaea.business.modules.datasource.service.JdbcService; +import com.zaxxer.hikari.pool.HikariPool; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.sql.Connection; +import java.sql.SQLException; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +/** + * Created by raodeming on 2021/8/6. + */ +@Service +@Slf4j +public class JdbcServiceImpl implements JdbcService { + + @Autowired + private HikariPoolProperties hikariPoolProperties; + + /** + * 所有数据源的连接池存在map里 + */ + private Map map = new ConcurrentHashMap<>(); + private Object lock = new Object(); + + public HikariPool getJdbcConnectionPool(DataSourceDto dataSource) { + if (map.containsKey(dataSource.getId())) { + return map.get(dataSource.getId()); + } else { + try { + synchronized (lock) { + if (!map.containsKey(dataSource.getId())) { + HikariPool pool = hikariPoolProperties.dataSource(dataSource.getJdbcUrl(), + dataSource.getUsername(), dataSource.getPassword(), dataSource.getDriverName()); + map.put(dataSource.getId(), pool); + log.info("创建连接池成功:{}", dataSource.getJdbcUrl()); + } + } + return map.get(dataSource.getId()); + } finally { + } + } + } + + + /** + * 删除数据库连接池 + * + * @param id + */ + @Override + public void removeJdbcConnectionPool(Long id) { + try { + HikariPool pool = map.get(id); + if (pool != null) { + log.info("remove pool success, datasourceId:{}", id); + map.remove(id); + } + } catch (Exception e) { + log.error("error", e); + } finally { + } + } + + /** + * 获取连接 + * + * @param dataSource + * @return + * @throws SQLException + */ + @Override + public Connection getPooledConnection(DataSourceDto dataSource) throws SQLException{ + HikariPool pool = getJdbcConnectionPool(dataSource); + return pool.getConnection(); + } + + /** + * 测试数据库连接 获取一个连接 + * + * @param dataSource + * @return + * @throws ClassNotFoundException driverName不正确 + * @throws SQLException + */ + @Override + public Connection getUnPooledConnection(DataSourceDto dataSource) throws SQLException { + HikariPool druidDataSource = hikariPoolProperties.dataSource(dataSource.getJdbcUrl(), + dataSource.getUsername(), dataSource.getPassword(), dataSource.getDriverName()); + return druidDataSource.getConnection(); + } + +} diff --git a/src/main/java/com/anjiplus/template/gaea/business/modules/dict/controller/GaeaDictController.java b/src/main/java/com/anjiplus/template/gaea/business/modules/dict/controller/GaeaDictController.java new file mode 100644 index 0000000..e7c0fc7 --- /dev/null +++ b/src/main/java/com/anjiplus/template/gaea/business/modules/dict/controller/GaeaDictController.java @@ -0,0 +1,116 @@ +package com.anjiplus.template.gaea.business.modules.dict.controller; + +import com.anji.plus.gaea.annotation.Permission; +import com.anji.plus.gaea.bean.KeyValue; +import com.anji.plus.gaea.bean.ResponseBean; +import com.anji.plus.gaea.curd.controller.GaeaBaseController; +import com.anji.plus.gaea.curd.service.GaeaBaseService; +import com.anjiplus.template.gaea.business.modules.dict.controller.dto.GaeaDictDTO; +import com.anjiplus.template.gaea.business.modules.dict.controller.param.GaeaDictParam; +import com.anjiplus.template.gaea.business.modules.dict.dao.entity.GaeaDict; +import com.anjiplus.template.gaea.business.modules.dict.service.GaeaDictItemService; +import com.anjiplus.template.gaea.business.modules.dict.service.GaeaDictService; +import io.swagger.annotations.Api; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.i18n.LocaleContextHolder; +import org.springframework.web.bind.annotation.*; + +import java.util.*; + +/** + * (GaeaDict)实体类 + * + * @author lr + * @since 2021-02-23 10:01:02 + */ +@RestController +@RequestMapping("/gaeaDict") +@Api(value = "/gaeaDict", tags = "") +public class GaeaDictController extends GaeaBaseController { + + @Autowired + private GaeaDictService gaeaDictService; + + @Autowired + private GaeaDictItemService gaeaDictItemService; + + @Override + public GaeaBaseService getService() { + return gaeaDictService; + } + + @Override + public GaeaDict getEntity() { + return new GaeaDict(); + } + + @Override + public GaeaDictDTO getDTO() { + return new GaeaDictDTO(); + } + + + /** + * 刷新指定字典项 + * @return + */ + @PostMapping("/freshDict") + @Permission(code = "fresh",name = "刷新") + public ResponseBean refreshDict(@RequestBody List dictCodes) { + //刷新 + gaeaDictService.refreshCache(dictCodes); + return responseSuccess(); + } + + /** + * 下拉菜单 + * @return + */ + @GetMapping("/select/{dictCode}") + @Permission(code = "query",name = "下拉") + public ResponseBean select(@PathVariable("dictCode") String dictName){ + Locale locale = LocaleContextHolder.getLocale(); + //语言 + String language = locale.getLanguage(); + + List keyValues = gaeaDictService.select(dictName,language); + return responseSuccessWithData(keyValues); + } + + + /** + * 指定语言的字典项 + * @return + */ + @GetMapping("/map/{dictCode}") + public ResponseBean dictItemByLang(@PathVariable("dictCode") String dictCode){ + return responseSuccessWithData(gaeaDictItemService.getItemMap(dictCode)); + } + /** + * 下拉菜单 + * @return + */ + @GetMapping("/selectAll/{project}") + public ResponseBean selectTypecodes(@PathVariable String project){ + Locale locale = LocaleContextHolder.getLocale(); + //语言 + String language = locale.getLanguage(); + + Collection keyValues = gaeaDictService.selectTypeCode(project,language); + return responseSuccessWithData(keyValues); + } + + /** + * 获取所有字典 + * @return + */ + @GetMapping("/all") + public ResponseBean all(){ + Locale locale = LocaleContextHolder.getLocale(); + //语言 + String language = locale.getLanguage(); + + Map> all = gaeaDictService.all(language); + return responseSuccessWithData(all); + } +} diff --git a/src/main/java/com/anjiplus/template/gaea/business/modules/dict/controller/GaeaDictItemController.java b/src/main/java/com/anjiplus/template/gaea/business/modules/dict/controller/GaeaDictItemController.java new file mode 100644 index 0000000..92a431d --- /dev/null +++ b/src/main/java/com/anjiplus/template/gaea/business/modules/dict/controller/GaeaDictItemController.java @@ -0,0 +1,41 @@ +package com.anjiplus.template.gaea.business.modules.dict.controller; + +import com.anji.plus.gaea.curd.controller.GaeaBaseController; +import com.anjiplus.template.gaea.business.modules.dict.dao.entity.GaeaDictItem; +import com.anjiplus.template.gaea.business.modules.dict.controller.dto.GaeaDictItemDTO; +import com.anjiplus.template.gaea.business.modules.dict.controller.param.GaeaDictItemParam; +import com.anjiplus.template.gaea.business.modules.dict.service.GaeaDictItemService; +import com.anji.plus.gaea.curd.service.GaeaBaseService; +import io.swagger.annotations.Api; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; +import org.springframework.beans.factory.annotation.Autowired; + +/** + * 数据字典项(GaeaDictItem)实体类 + * + * @author lirui + * @since 2021-03-10 13:05:59 + */ +@RestController +@RequestMapping("/gaeaDictItem") +@Api(value = "/gaeaDictItem", tags = "数据字典项") +public class GaeaDictItemController extends GaeaBaseController { + @Autowired + private GaeaDictItemService gaeaDictItemService; + + @Override + public GaeaBaseService getService() { + return gaeaDictItemService; + } + + @Override + public GaeaDictItem getEntity() { + return new GaeaDictItem(); + } + + @Override + public GaeaDictItemDTO getDTO() { + return new GaeaDictItemDTO(); + } +} \ No newline at end of file diff --git a/src/main/java/com/anjiplus/template/gaea/business/modules/dict/controller/dto/GaeaDictDTO.java b/src/main/java/com/anjiplus/template/gaea/business/modules/dict/controller/dto/GaeaDictDTO.java new file mode 100644 index 0000000..e4c5830 --- /dev/null +++ b/src/main/java/com/anjiplus/template/gaea/business/modules/dict/controller/dto/GaeaDictDTO.java @@ -0,0 +1,36 @@ +package com.anjiplus.template.gaea.business.modules.dict.controller.dto; + +import com.anji.plus.gaea.curd.dto.GaeaBaseDTO; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +import java.io.Serializable; + +/** + * (GaeaDict)实体类 + * + * @author lr + * @since 2021-02-23 10:01:02 + */ +@ApiModel(value = "") +@Data +public class GaeaDictDTO extends GaeaBaseDTO implements Serializable { + /** + * 字典名称 + */ + @ApiModelProperty(value = "字典名称") + private String dictName; + /** + * 字典编号 + */ + @ApiModelProperty(value = "字典编号") + private String dictCode; + /** + * 字典描述 + */ + @ApiModelProperty(value = "字典描述") + private String remark; + + +} diff --git a/src/main/java/com/anjiplus/template/gaea/business/modules/dict/controller/dto/GaeaDictItemDTO.java b/src/main/java/com/anjiplus/template/gaea/business/modules/dict/controller/dto/GaeaDictItemDTO.java new file mode 100644 index 0000000..ef4cabb --- /dev/null +++ b/src/main/java/com/anjiplus/template/gaea/business/modules/dict/controller/dto/GaeaDictItemDTO.java @@ -0,0 +1,60 @@ +package com.anjiplus.template.gaea.business.modules.dict.controller.dto; + +import com.anji.plus.gaea.curd.dto.GaeaBaseDTO; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +import java.io.Serializable; + +/** + * 数据字典项(GaeaDictItem)实体类 + * + * @author lirui + * @since 2021-03-10 13:05:59 + */ +@ApiModel(value = "数据字典项") +@Data +public class GaeaDictItemDTO extends GaeaBaseDTO implements Serializable { + /** + * 数据字典编码 + */ + @ApiModelProperty(value = "数据字典编码") + private String dictCode; + /** + * 字典项名称 + */ + @ApiModelProperty(value = "字典项名称") + private String itemName; + /** + * 字典项值 + */ + @ApiModelProperty(value = "字典项值") + private String itemValue; + + /** + * 字典项扩展 + */ + @ApiModelProperty(value = "字典项扩展") + private String itemExtend; + /** + * 语言标识 + */ + @ApiModelProperty(value = "语言标识") + private String locale; + /** + * 描述 + */ + @ApiModelProperty(value = "描述") + private String remark; + /** + * 排序 + */ + @ApiModelProperty(value = "排序") + private Integer sort; + + /** + * 1:启用,0:禁用 + */ + private Integer enabled; +} diff --git a/src/main/java/com/anjiplus/template/gaea/business/modules/dict/controller/param/GaeaDictItemParam.java b/src/main/java/com/anjiplus/template/gaea/business/modules/dict/controller/param/GaeaDictItemParam.java new file mode 100644 index 0000000..1b148e8 --- /dev/null +++ b/src/main/java/com/anjiplus/template/gaea/business/modules/dict/controller/param/GaeaDictItemParam.java @@ -0,0 +1,39 @@ +package com.anjiplus.template.gaea.business.modules.dict.controller.param; + + +import com.anji.plus.gaea.annotation.Query; +import com.anji.plus.gaea.constant.QueryEnum; +import com.anji.plus.gaea.curd.params.PageParam; +import lombok.Data; + +import java.io.Serializable; + +/** + * 数据字典项(GaeaDictItem)param + * + * @author lirui + * @since 2021-03-10 13:05:59 + */ +@Data +public class GaeaDictItemParam extends PageParam implements Serializable { + + /** + * 数据字典编码 + */ + private String dictCode; + /** + * 字典项名称 + */ + @Query(QueryEnum.LIKE) + private String itemName; + + /** + * 语言标识 + */ + private String locale; + + /** + * 1:启用,0:禁用 + */ + private Integer enabled; +} diff --git a/src/main/java/com/anjiplus/template/gaea/business/modules/dict/controller/param/GaeaDictParam.java b/src/main/java/com/anjiplus/template/gaea/business/modules/dict/controller/param/GaeaDictParam.java new file mode 100644 index 0000000..5e23591 --- /dev/null +++ b/src/main/java/com/anjiplus/template/gaea/business/modules/dict/controller/param/GaeaDictParam.java @@ -0,0 +1,29 @@ +package com.anjiplus.template.gaea.business.modules.dict.controller.param; + + +import com.anji.plus.gaea.annotation.Query; +import com.anji.plus.gaea.constant.QueryEnum; +import com.anji.plus.gaea.curd.params.PageParam; +import lombok.Data; + +import java.io.Serializable; + +/** + * (GaeaDict)param + * + * @author lr + * @since 2021-02-23 10:01:02 + */ +@Data +public class GaeaDictParam extends PageParam implements Serializable { + /** + * 字典名称 + */ + @Query(QueryEnum.LIKE) + private String dictName; + /** + * 字典编号 + */ + @Query(QueryEnum.LIKE) + private String dictCode; +} diff --git a/src/main/java/com/anjiplus/template/gaea/business/modules/dict/dao/GaeaDictItemMapper.java b/src/main/java/com/anjiplus/template/gaea/business/modules/dict/dao/GaeaDictItemMapper.java new file mode 100644 index 0000000..2645182 --- /dev/null +++ b/src/main/java/com/anjiplus/template/gaea/business/modules/dict/dao/GaeaDictItemMapper.java @@ -0,0 +1,17 @@ +package com.anjiplus.template.gaea.business.modules.dict.dao; + +import com.anjiplus.template.gaea.business.modules.dict.dao.entity.GaeaDictItem; +import com.anji.plus.gaea.curd.mapper.GaeaBaseMapper; +import org.apache.ibatis.annotations.Mapper; + +/** + * 数据字典项(GaeaDictItem)Mapper + * + * @author lirui + * @since 2021-03-09 15:52:41 + */ +@Mapper +public interface GaeaDictItemMapper extends GaeaBaseMapper { + + +} \ No newline at end of file diff --git a/src/main/java/com/anjiplus/template/gaea/business/modules/dict/dao/GaeaDictMapper.java b/src/main/java/com/anjiplus/template/gaea/business/modules/dict/dao/GaeaDictMapper.java new file mode 100644 index 0000000..cfd7b4a --- /dev/null +++ b/src/main/java/com/anjiplus/template/gaea/business/modules/dict/dao/GaeaDictMapper.java @@ -0,0 +1,17 @@ +package com.anjiplus.template.gaea.business.modules.dict.dao; + +import com.anjiplus.template.gaea.business.modules.dict.dao.entity.GaeaDict; +import com.anji.plus.gaea.curd.mapper.GaeaBaseMapper; +import org.apache.ibatis.annotations.Mapper; + +/** + * (GaeaDict)Mapper + * + * @author lr + * @since 2021-02-23 10:01:02 + */ +@Mapper +public interface GaeaDictMapper extends GaeaBaseMapper { + + +} diff --git a/src/main/java/com/anjiplus/template/gaea/business/modules/dict/dao/entity/GaeaDict.java b/src/main/java/com/anjiplus/template/gaea/business/modules/dict/dao/entity/GaeaDict.java new file mode 100644 index 0000000..0bae690 --- /dev/null +++ b/src/main/java/com/anjiplus/template/gaea/business/modules/dict/dao/entity/GaeaDict.java @@ -0,0 +1,56 @@ +package com.anjiplus.template.gaea.business.modules.dict.dao.entity; + +import com.anji.plus.gaea.annotation.Unique; +import com.anji.plus.gaea.curd.entity.GaeaBaseEntity; +import com.anjiplus.template.gaea.business.code.ResponseCode; +import com.baomidou.mybatisplus.annotation.TableName; + +import java.io.Serializable; + +/** + * (GaeaDict)实体类 + * + * @author lr + * @since 2021-02-23 10:01:02 + */ +@TableName(keepGlobalPrefix=true, value = "gaea_dict") +public class GaeaDict extends GaeaBaseEntity implements Serializable { + /** + * 字典名称 + */ + private String dictName; + /** + * 字典编码 + */ + @Unique(code = ResponseCode.DICCODE_ISEXIST) + private String dictCode; + + /** + * 字典描述 + */ + private String remark; + + public String getDictName() { + return dictName; + } + + public void setDictName(String dictName) { + this.dictName = dictName; + } + + public String getDictCode() { + return dictCode; + } + + public void setDictCode(String dictCode) { + this.dictCode = dictCode; + } + + public String getRemark() { + return remark; + } + + public void setRemark(String remark) { + this.remark = remark; + } +} diff --git a/src/main/java/com/anjiplus/template/gaea/business/modules/dict/dao/entity/GaeaDictItem.java b/src/main/java/com/anjiplus/template/gaea/business/modules/dict/dao/entity/GaeaDictItem.java new file mode 100644 index 0000000..37f75c2 --- /dev/null +++ b/src/main/java/com/anjiplus/template/gaea/business/modules/dict/dao/entity/GaeaDictItem.java @@ -0,0 +1,123 @@ +package com.anjiplus.template.gaea.business.modules.dict.dao.entity; + +import com.anji.plus.gaea.annotation.UnionUnique; +import com.anji.plus.gaea.annotation.UnionUniqueCode; +import com.anjiplus.template.gaea.business.code.*; +import com.anji.plus.gaea.curd.entity.GaeaBaseEntity; +import com.anjiplus.template.gaea.business.constant.BusinessConstant; +import com.baomidou.mybatisplus.annotation.TableName; + +import java.io.Serializable; + +/** + * 数据字典项(GaeaDictItem)实体类 + * + * @author lirui + * @since 2021-03-09 15:52:41 + */ +@TableName(keepGlobalPrefix=true,value = "gaea_dict_item") +@UnionUniqueCode(group = BusinessConstant.DICT_ITEM_EXIST_GROUP, code = ResponseCode.DICT_ITEM_REPEAT) +public class GaeaDictItem extends GaeaBaseEntity implements Serializable { + + /** + * 数据字典编码 + */ + @UnionUnique(group = BusinessConstant.DICT_ITEM_EXIST_GROUP) + private String dictCode; + /** + * 字典项名称 + */ + private String itemName; + /** + * 字典项值 + */ + @UnionUnique(group = BusinessConstant.DICT_ITEM_EXIST_GROUP) + private String itemValue; + + /** + * 字典项扩展 + */ + private String itemExtend; + /** + * 语言标识 + */ + @UnionUnique(group = BusinessConstant.DICT_ITEM_EXIST_GROUP) + private String locale; + + /** + * 1:启用,0:禁用 + */ + private Integer enabled; + /** + * 描述 + */ + private String remark; + /** + * 排序 + */ + private Integer sort; + + public String getDictCode() { + return dictCode; + } + + public void setDictCode(String dictCode) { + this.dictCode = dictCode; + } + + public String getItemName() { + return itemName; + } + + public void setItemName(String itemName) { + this.itemName = itemName; + } + + public String getItemValue() { + return itemValue; + } + + public void setItemValue(String itemValue) { + this.itemValue = itemValue; + } + + public String getLocale() { + return locale; + } + + public void setLocale(String locale) { + this.locale = locale; + } + + public String getRemark() { + return remark; + } + + public void setRemark(String remark) { + this.remark = remark; + } + + public Integer getSort() { + return sort; + } + + public void setSort(Integer sort) { + this.sort = sort; + } + + public Integer getEnabled() { + return enabled; + } + + public void setEnabled(Integer enabled) { + this.enabled = enabled; + } + + public String getItemExtend() { + return itemExtend; + } + + public void setItemExtend(String itemExtend) { + this.itemExtend = itemExtend; + } +} diff --git a/src/main/java/com/anjiplus/template/gaea/business/modules/dict/service/GaeaDictItemService.java b/src/main/java/com/anjiplus/template/gaea/business/modules/dict/service/GaeaDictItemService.java new file mode 100644 index 0000000..4629154 --- /dev/null +++ b/src/main/java/com/anjiplus/template/gaea/business/modules/dict/service/GaeaDictItemService.java @@ -0,0 +1,23 @@ +package com.anjiplus.template.gaea.business.modules.dict.service; + +import com.anji.plus.gaea.curd.service.GaeaBaseService; +import com.anjiplus.template.gaea.business.modules.dict.controller.param.GaeaDictItemParam; +import com.anjiplus.template.gaea.business.modules.dict.dao.entity.GaeaDictItem; + +import java.util.Map; + +/** + * 数据字典项(GaeaDictItem)Service + * + * @author lirui + * @since 2021-03-10 13:05:59 + */ +public interface GaeaDictItemService extends GaeaBaseService { + + /** + * 根据字典编码获取字典项 + * @param dictCode + * @return + */ + Map getItemMap(String dictCode); +} diff --git a/src/main/java/com/anjiplus/template/gaea/business/modules/dict/service/GaeaDictService.java b/src/main/java/com/anjiplus/template/gaea/business/modules/dict/service/GaeaDictService.java new file mode 100644 index 0000000..1649a4b --- /dev/null +++ b/src/main/java/com/anjiplus/template/gaea/business/modules/dict/service/GaeaDictService.java @@ -0,0 +1,56 @@ +package com.anjiplus.template.gaea.business.modules.dict.service; + +import com.anji.plus.gaea.bean.KeyValue; +import com.anji.plus.gaea.curd.service.GaeaBaseService; +import com.anjiplus.template.gaea.business.modules.dict.controller.param.GaeaDictParam; +import com.anjiplus.template.gaea.business.modules.dict.dao.entity.GaeaDict; +import com.anjiplus.template.gaea.business.modules.dict.dao.entity.GaeaDictItem; + +import java.util.Collection; +import java.util.List; +import java.util.Map; + +/** + * (GaeaDict)Service + * + * @author lr + * @since 2021-02-23 10:01:02 + */ +public interface GaeaDictService extends GaeaBaseService { + + /** + * 刷新全部缓存 + * @param dictCodes + */ + void refreshCache(List dictCodes); + + + /** + * 获取指定字典code下拉 + * @param dictCode + * @param language + * @return + */ + List select(String dictCode, String language); + + /** + * 获取所有字典项 + * @return + */ + List findItems(List dictCodes); + /** + * 获取所有 typecode + * @param system + * @param language + * @return + */ + Collection selectTypeCode(String system, String language); + + + /** + * 获取所有数据字典 + * @param language + * @return + */ + Map> all(String language); +} diff --git a/src/main/java/com/anjiplus/template/gaea/business/modules/dict/service/impl/GaeaDictItemServiceImpl.java b/src/main/java/com/anjiplus/template/gaea/business/modules/dict/service/impl/GaeaDictItemServiceImpl.java new file mode 100644 index 0000000..414af7e --- /dev/null +++ b/src/main/java/com/anjiplus/template/gaea/business/modules/dict/service/impl/GaeaDictItemServiceImpl.java @@ -0,0 +1,98 @@ +package com.anjiplus.template.gaea.business.modules.dict.service.impl; + +import com.anji.plus.gaea.cache.CacheHelper; +import com.anji.plus.gaea.constant.BaseOperationEnum; +import com.anji.plus.gaea.constant.GaeaConstant; +import com.anji.plus.gaea.constant.GaeaKeyConstant; +import com.anji.plus.gaea.curd.mapper.GaeaBaseMapper; +import com.anji.plus.gaea.exception.BusinessException; +import com.anjiplus.template.gaea.business.modules.dict.dao.GaeaDictItemMapper; +import com.anjiplus.template.gaea.business.modules.dict.dao.entity.GaeaDictItem; +import com.anjiplus.template.gaea.business.modules.dict.service.GaeaDictItemService; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.i18n.LocaleContextHolder; +import org.springframework.stereotype.Service; +import org.springframework.util.CollectionUtils; + +import java.util.List; +import java.util.Locale; +import java.util.Map; +import java.util.Set; +import java.util.stream.Collectors; + +/** + * 数据字典项(GaeaDictItem)ServiceImpl + * + * @author lirui + * @since 2021-03-10 13:05:59 + */ +@Service +public class GaeaDictItemServiceImpl implements GaeaDictItemService { + @Autowired + private GaeaDictItemMapper gaeaDictItemMapper; + + @Autowired + private CacheHelper cacheHelper; + + @Override + public GaeaBaseMapper getMapper() { + return gaeaDictItemMapper; + } + + + @Override + public void processAfterOperation(GaeaDictItem entity, BaseOperationEnum operationEnum) throws BusinessException { + String dictCode = entity.getDictCode(); + String locale = entity.getLocale(); + + String key = GaeaKeyConstant.DICT_PREFIX + locale + GaeaConstant.REDIS_SPLIT + dictCode; + switch (operationEnum) { + case INSERT: + case UPDATE: + cacheHelper.hashSet(key, entity.getItemValue(), entity.getItemName()); + break; + case DELETE: + cacheHelper.hashDel(key, entity.getItemValue()); + default: + } + } + + @Override + public void processBatchAfterOperation(List entities, BaseOperationEnum operationEnum) throws BusinessException { + if (CollectionUtils.isEmpty(entities)) { + return; + } + + Map> dictItemMap = entities.stream() + .collect(Collectors.groupingBy(item -> item.getLocale() + GaeaConstant.REDIS_SPLIT +item.getDictCode(), + Collectors.toMap(GaeaDictItem::getItemValue, GaeaDictItem::getItemName,(v1,v2)-> v2))); + + switch (operationEnum) { + case DELETE_BATCH: + //遍历并保持到Redis中 + dictItemMap.entrySet().stream().forEach(entry -> { + String key = GaeaKeyConstant.DICT_PREFIX + entry.getKey(); + Set hashKeys = entry.getValue().keySet(); + cacheHelper.hashBatchDel(key, hashKeys); + }); + break; + default: + } + } + + @Override + public Map getItemMap(String dictCode) { + Locale locale = LocaleContextHolder.getLocale(); + + LambdaQueryWrapper wrapper = Wrappers.lambdaQuery(); + wrapper.eq(GaeaDictItem::getDictCode, dictCode); + wrapper.eq(GaeaDictItem::getLocale, locale.getLanguage()); + + List list = list(wrapper); + Map data = list.stream().collect(Collectors.toMap(GaeaDictItem::getItemValue, GaeaDictItem::getItemName, (v1, v2) -> v2)); + return data; + } + +} diff --git a/src/main/java/com/anjiplus/template/gaea/business/modules/dict/service/impl/GaeaDictServiceImpl.java b/src/main/java/com/anjiplus/template/gaea/business/modules/dict/service/impl/GaeaDictServiceImpl.java new file mode 100644 index 0000000..1216fe2 --- /dev/null +++ b/src/main/java/com/anjiplus/template/gaea/business/modules/dict/service/impl/GaeaDictServiceImpl.java @@ -0,0 +1,184 @@ +package com.anjiplus.template.gaea.business.modules.dict.service.impl; + +import com.anji.plus.gaea.bean.KeyValue; +import com.anji.plus.gaea.cache.CacheHelper; +import com.anji.plus.gaea.constant.Enabled; +import com.anji.plus.gaea.constant.GaeaConstant; +import com.anji.plus.gaea.constant.GaeaKeyConstant; +import com.anji.plus.gaea.curd.mapper.GaeaBaseMapper; +import com.anji.plus.gaea.utils.GaeaUtils; +import com.anjiplus.template.gaea.business.modules.dict.dao.GaeaDictItemMapper; +import com.anjiplus.template.gaea.business.modules.dict.dao.GaeaDictMapper; +import com.anjiplus.template.gaea.business.modules.dict.dao.entity.GaeaDict; +import com.anjiplus.template.gaea.business.modules.dict.dao.entity.GaeaDictItem; +import com.anjiplus.template.gaea.business.modules.dict.service.GaeaDictService; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import org.apache.commons.lang3.StringUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.util.CollectionUtils; + +import java.util.*; +import java.util.stream.Collectors; + +/** + * (GaeaDict)ServiceImpl + * + * @author lr + * @since 2021-02-23 10:01:02 + */ +@Service +public class GaeaDictServiceImpl implements GaeaDictService { + + @Autowired + private GaeaDictMapper gaeaDictMapper; + + @Autowired + private GaeaDictItemMapper gaeaDictItemMapper; + + @Autowired + private CacheHelper cacheHelper; + + @Override + public GaeaBaseMapper getMapper() { + return gaeaDictMapper; + } + + /** + * 刷新全部缓存 + * @param dictCodes + */ + @Override + public void refreshCache(List dictCodes) { + + //查询指定字典项 + List gaeaDictItems = findItems(dictCodes); + + //对数据字典项进行分组,分组key=语言标识:字典编码 + Map> dictItemMap = gaeaDictItems.stream() + .collect(Collectors + .groupingBy(item -> item.getLocale() + GaeaConstant.REDIS_SPLIT +item.getDictCode(), + Collectors.toMap(GaeaDictItem::getItemValue, GaeaDictItem::getItemName,(v1,v2)-> v2))); + + //遍历并保持到Redis中 + dictItemMap.entrySet().stream().forEach(entry -> { + String key = GaeaKeyConstant.DICT_PREFIX + entry.getKey(); + cacheHelper.delete(key); + cacheHelper.hashSet(key, entry.getValue()); + }); + } + + /** + * 根据国际化语言查询指定字典编码下拉列表 + * 先从Redis中获取 + * @param dictCode 字典名称 + * @param language 语言 + * @return + */ + @Override + public List select(String dictCode, String language) { + + //缓存字典Key + String dictKey = GaeaKeyConstant.DICT_PREFIX + language + GaeaConstant.REDIS_SPLIT + dictCode; + + Map dictMap = cacheHelper.hashGet(dictKey); + + //当查询的字典为空时 + if (CollectionUtils.isEmpty(dictMap)) { + LambdaQueryWrapper wrapper = Wrappers.lambdaQuery(); + wrapper.eq(GaeaDictItem::getDictCode, dictCode) + .eq(GaeaDictItem::getEnabled, Enabled.YES.getValue()) + .eq(GaeaDictItem::getLocale, language) + .orderByAsc(GaeaDictItem::getSort); + + List list = gaeaDictItemMapper.selectList(wrapper); + + List keyValues = list.stream() + .map(dictItemEntity -> new KeyValue(dictItemEntity.getItemValue(), dictItemEntity.getItemName(), dictItemEntity.getItemExtend())) + .collect(Collectors.toList()); + //当缓存不存在时,刷新缓存 + List dictCodes = new ArrayList<>(); + dictCodes.add(dictCode); + refreshCache(dictCodes); + return keyValues; + } + + List keyValues = GaeaUtils.formatKeyValue(dictMap); + + //添加扩展字段 + LambdaQueryWrapper gaeaDictItemWrapper = Wrappers.lambdaQuery(); + gaeaDictItemWrapper.eq(GaeaDictItem::getDictCode, dictCode); + gaeaDictItemWrapper.isNotNull(GaeaDictItem::getItemExtend); + + Map extendMap = gaeaDictItemMapper.selectList(gaeaDictItemWrapper).stream() + .filter(gaeaDictItem -> StringUtils.isNotBlank(gaeaDictItem.getItemExtend())) + .collect(Collectors.toMap(GaeaDictItem::getItemValue, GaeaDictItem::getItemExtend, (v1, v2) -> v2)); + if (!CollectionUtils.isEmpty(extendMap)) { + keyValues.stream().forEach(keyValue -> keyValue.setExtend(extendMap.get(keyValue.getId()))); + } + return keyValues; + } + + @Override + public List findItems(List dictCodes) { + + LambdaQueryWrapper gaeaDictItemQueryWrapper = Wrappers.lambdaQuery(); + gaeaDictItemQueryWrapper.eq(GaeaDictItem::getEnabled, Enabled.YES.getValue()); + if (!CollectionUtils.isEmpty(dictCodes)) { + gaeaDictItemQueryWrapper.in(GaeaDictItem::getDictCode, dictCodes); + } + return gaeaDictItemMapper.selectList(gaeaDictItemQueryWrapper); + } + + + @Override + public Collection selectTypeCode(String system, String language) { + + //缓存字典Key + String dictKey = GaeaKeyConstant.DICT_PREFIX + language + GaeaConstant.REDIS_SPLIT + system; + + Map dictMap = cacheHelper.hashGet(dictKey); + + //当查询的字典为空时 + if (CollectionUtils.isEmpty(dictMap)) { + LambdaQueryWrapper wrapper = Wrappers.lambdaQuery(); + //wrapper.eq(GaeaDict::getLocale, language).orderByAsc(GaeaDict::getSort); + + List list = getMapper().selectList(wrapper); + + Set keyValues = list.stream() + .map(dictItemEntity -> new KeyValue(dictItemEntity.getDictCode(), + dictItemEntity.getDictName())) + .collect(Collectors.toSet()); + return keyValues; + } + + return GaeaUtils.formatKeyValue(dictMap); + } + + + @Override + public Map> all(String language) { + LambdaQueryWrapper wrapper = Wrappers.lambdaQuery(); + wrapper.eq(GaeaDictItem::getEnabled, Enabled.YES.getValue()) + .eq(GaeaDictItem::getLocale, language) + .orderByAsc(GaeaDictItem::getSort); + + List list = gaeaDictItemMapper.selectList(wrapper); + Map> all = list.stream().collect( + Collectors.groupingBy( + GaeaDictItem::getDictCode, + Collectors.mapping(dictItemEntity -> { + Object itemValue = null; + try{ + itemValue = Integer.parseInt(dictItemEntity.getItemValue()); + }catch (Exception e){ + itemValue = dictItemEntity.getItemValue(); + } + return new KeyValue(itemValue, dictItemEntity.getItemName(), dictItemEntity.getItemExtend()); + },Collectors.toList()))); + return all; + } + +} diff --git a/src/main/java/com/anjiplus/template/gaea/business/modules/file/controller/GaeaFileController.java b/src/main/java/com/anjiplus/template/gaea/business/modules/file/controller/GaeaFileController.java new file mode 100644 index 0000000..d0d45af --- /dev/null +++ b/src/main/java/com/anjiplus/template/gaea/business/modules/file/controller/GaeaFileController.java @@ -0,0 +1,73 @@ +package com.anjiplus.template.gaea.business.modules.file.controller; + +import com.anji.plus.gaea.annotation.Permission; +import com.anji.plus.gaea.bean.ResponseBean; +import com.anji.plus.gaea.curd.service.GaeaBaseService; +import com.anjiplus.template.gaea.business.base.BaseController; +import com.anjiplus.template.gaea.business.modules.file.controller.dto.GaeaFileDTO; +import com.anjiplus.template.gaea.business.modules.file.controller.param.GaeaFileParam; +import com.anjiplus.template.gaea.business.modules.file.entity.GaeaFile; +import com.anjiplus.template.gaea.business.modules.file.service.GaeaFileService; +import io.swagger.annotations.Api; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.*; +import org.springframework.web.multipart.MultipartFile; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +/** + * (GaeaFile)实体类 + * + * @author peiyanni + * @since 2021-02-18 14:48:33 + */ +@RestController +@RequestMapping("/file") +@Api(value = "/file", tags = "") +public class GaeaFileController extends BaseController { + @Autowired + private GaeaFileService gaeaFileService; + + @PostMapping("/upload") + @Permission(code = "upload", name = "文件上传") + public ResponseBean upload(@RequestParam("file") MultipartFile file) { + return ResponseBean.builder().message("success").data((gaeaFileService.upload(file))).build(); + } + + @GetMapping(value = "/download/{fileId}") + public ResponseEntity download(HttpServletRequest request, HttpServletResponse response, @PathVariable("fileId") String fileId) { + return gaeaFileService.download(request, response, fileId); + } + + /** + * 获取实际服务类 + * + * @return + */ + @Override + public GaeaBaseService getService() { + return gaeaFileService; + } + + /** + * 获取当前Controller数据库实体Entity + * + * @return + */ + @Override + public GaeaFile getEntity() { + return new GaeaFile(); + } + + /** + * 获取当前Controller数据传输DTO + * + * @return + */ + @Override + public GaeaFileDTO getDTO() { + return new GaeaFileDTO(); + } +} diff --git a/src/main/java/com/anjiplus/template/gaea/business/modules/file/controller/dto/GaeaFileDTO.java b/src/main/java/com/anjiplus/template/gaea/business/modules/file/controller/dto/GaeaFileDTO.java new file mode 100644 index 0000000..86a735c --- /dev/null +++ b/src/main/java/com/anjiplus/template/gaea/business/modules/file/controller/dto/GaeaFileDTO.java @@ -0,0 +1,31 @@ +package com.anjiplus.template.gaea.business.modules.file.controller.dto; + +import com.anji.plus.gaea.curd.dto.GaeaBaseDTO; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +/** + * (GaeaFile)实体类 + * + * @author peiyanni + * @since 2021-02-18 14:48:27 + */ +@Data +public class GaeaFileDTO extends GaeaBaseDTO { + + /** 文件标识 */ + private String fileId; + + /** 文件类型 */ + private String fileType; + + /** 文件路径 */ + private String filePath; + + /** url路径 */ + private String urlPath; + + /** 内容说明 */ + private String fileInstruction; +} diff --git a/src/main/java/com/anjiplus/template/gaea/business/modules/file/controller/param/GaeaFileParam.java b/src/main/java/com/anjiplus/template/gaea/business/modules/file/controller/param/GaeaFileParam.java new file mode 100644 index 0000000..cac2f1b --- /dev/null +++ b/src/main/java/com/anjiplus/template/gaea/business/modules/file/controller/param/GaeaFileParam.java @@ -0,0 +1,27 @@ +package com.anjiplus.template.gaea.business.modules.file.controller.param; + + +import com.anji.plus.gaea.annotation.Query; +import com.anji.plus.gaea.constant.QueryEnum; +import com.anji.plus.gaea.curd.params.PageParam; +import lombok.Data; + +import java.io.Serializable; + +/** + * (GaeaFile)param + * + * @author peiyanni + * @since 2021-02-18 14:48:29 + */ +@Data +public class GaeaFileParam extends PageParam implements Serializable { + + /** 模糊查询 */ + @Query(value = QueryEnum.LIKE) + private String filePath; + + /** 模糊查询 */ + @Query(value = QueryEnum.EQ) + private String fileType; +} diff --git a/src/main/java/com/anjiplus/template/gaea/business/modules/file/dao/GaeaFileMapper.java b/src/main/java/com/anjiplus/template/gaea/business/modules/file/dao/GaeaFileMapper.java new file mode 100644 index 0000000..dabb1d3 --- /dev/null +++ b/src/main/java/com/anjiplus/template/gaea/business/modules/file/dao/GaeaFileMapper.java @@ -0,0 +1,17 @@ +package com.anjiplus.template.gaea.business.modules.file.dao; + +import com.anji.plus.gaea.curd.mapper.GaeaBaseMapper; +import com.anjiplus.template.gaea.business.modules.file.entity.GaeaFile; +import org.apache.ibatis.annotations.Mapper; + +/** + * (GaeaFile)Mapper + * + * @author peiyanni + * @since 2021-02-18 14:48:24 + */ +@Mapper +public interface GaeaFileMapper extends GaeaBaseMapper { + + +} diff --git a/src/main/java/com/anjiplus/template/gaea/business/modules/file/entity/GaeaFile.java b/src/main/java/com/anjiplus/template/gaea/business/modules/file/entity/GaeaFile.java new file mode 100644 index 0000000..49a9734 --- /dev/null +++ b/src/main/java/com/anjiplus/template/gaea/business/modules/file/entity/GaeaFile.java @@ -0,0 +1,34 @@ +package com.anjiplus.template.gaea.business.modules.file.entity; + +import com.baomidou.mybatisplus.annotation.TableName; +import com.anji.plus.gaea.curd.entity.GaeaBaseEntity; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +import java.io.Serializable; + +/** + * (GaeaFile)实体类 + * + * @author peiyanni + * @since 2021-02-18 14:48:20 + */ +@TableName(keepGlobalPrefix=true, value = "gaea_file") +@Data +public class GaeaFile extends GaeaBaseEntity implements Serializable { + + @ApiModelProperty(value = "文件标识") + private String fileId; + + @ApiModelProperty(value = "文件类型") + private String fileType; + + @ApiModelProperty(value = "文件路径") + private String filePath; + + @ApiModelProperty(value = "url路径") + private String urlPath; + + @ApiModelProperty(value = "内容说明") + private String fileInstruction; +} diff --git a/src/main/java/com/anjiplus/template/gaea/business/modules/file/service/GaeaFileService.java b/src/main/java/com/anjiplus/template/gaea/business/modules/file/service/GaeaFileService.java new file mode 100644 index 0000000..0581399 --- /dev/null +++ b/src/main/java/com/anjiplus/template/gaea/business/modules/file/service/GaeaFileService.java @@ -0,0 +1,53 @@ +package com.anjiplus.template.gaea.business.modules.file.service; + +import com.anji.plus.gaea.curd.service.GaeaBaseService; +import com.anjiplus.template.gaea.business.modules.file.entity.GaeaFile; +import com.anjiplus.template.gaea.business.modules.file.controller.param.GaeaFileParam; +import org.springframework.http.ResponseEntity; +import org.springframework.web.multipart.MultipartFile; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.File; + +/** + * (GaeaFile)Service + * + * @author peiyanni + * @since 2021-02-18 14:48:25 + */ +public interface GaeaFileService extends GaeaBaseService { + + /** + * 文件上传 + * + * @param multipartFile 文件 + * @return + */ + GaeaFile upload(MultipartFile multipartFile); + + + /** + * 文件上传 + * + * @param file 二选一 + * @return + */ + GaeaFile upload(File file); + /** + * 根据fileId显示图片或者下载文件 + * + * @param request + * @param response + * @param fileId + * @return + */ + ResponseEntity download(HttpServletRequest request, HttpServletResponse response, String fileId); + + /** + * 获取文件 + * @param fileId + * @return + */ + byte[] getFile(String fileId); +} diff --git a/src/main/java/com/anjiplus/template/gaea/business/modules/file/service/impl/GaeaFileServiceImpl.java b/src/main/java/com/anjiplus/template/gaea/business/modules/file/service/impl/GaeaFileServiceImpl.java new file mode 100644 index 0000000..c6332e5 --- /dev/null +++ b/src/main/java/com/anjiplus/template/gaea/business/modules/file/service/impl/GaeaFileServiceImpl.java @@ -0,0 +1,217 @@ +package com.anjiplus.template.gaea.business.modules.file.service.impl; + +import com.anji.plus.gaea.constant.BaseOperationEnum; +import com.anji.plus.gaea.curd.mapper.GaeaBaseMapper; +import com.anji.plus.gaea.exception.BusinessException; +import com.anji.plus.gaea.exception.BusinessExceptionBuilder; +import com.anji.plus.gaea.oss.exceptions.GaeaOSSException; +import com.anji.plus.gaea.oss.exceptions.GaeaOSSTypeLimitedException; +import com.anji.plus.gaea.oss.ossbuilder.GaeaOSSTemplate; +import com.anji.plus.gaea.oss.utils.ResponseUtil; +import com.anjiplus.template.gaea.business.code.ResponseCode; +import com.anjiplus.template.gaea.business.modules.file.dao.GaeaFileMapper; +import com.anjiplus.template.gaea.business.modules.file.entity.GaeaFile; +import com.anjiplus.template.gaea.business.modules.file.service.GaeaFileService; +import com.anjiplus.template.gaea.business.util.ResponseUtil2; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.apache.http.entity.ContentType; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.cloud.context.config.annotation.RefreshScope; +import org.springframework.http.ResponseEntity; +import org.springframework.mock.web.MockMultipartFile; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.web.multipart.MultipartFile; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.File; +import java.io.FileInputStream; +import java.util.List; +import java.util.UUID; + +/** + * 文件管理服务实现 + * @author: Raod + * @since: 2022-08-31 + */ +@Service +@Slf4j +@RefreshScope +public class GaeaFileServiceImpl implements GaeaFileService { + + @Value("${spring.gaea.subscribes.oss.downloadPath:''}") + private String fileDownloadPath; + + @Autowired + private GaeaOSSTemplate gaeaOSSTemplate; + + @Autowired + private GaeaFileMapper gaeaFileMapper; + + @Override + public GaeaBaseMapper getMapper() { + return gaeaFileMapper; + } + + /** + * 文件上传 + * + * @param multipartFile 文件 + * @return + */ + @Override + public GaeaFile upload(MultipartFile multipartFile) { + String originalFilename = multipartFile.getOriginalFilename(); + + if (StringUtils.isBlank(originalFilename)) { + throw BusinessExceptionBuilder.build(ResponseCode.FILE_EMPTY_FILENAME); + } + // 文件后缀 .png + String suffixName = originalFilename.substring(originalFilename.lastIndexOf(".")); + // 生成文件唯一性标识 + String fileId = UUID.randomUUID().toString(); + + // 生成在oss中存储的文件名 402b6193e70e40a9bf5b73a78ea1e8ab.png + String fileObjectName = fileId + suffixName; + // 生成链接通过fileId http访问路径 http://10.108.3.121:9089/meta/file/download/402b6193e70e40a9bf5b73a78ea1e8ab + String urlPath = fileDownloadPath + "/" + fileId; + + // 上传文件 + try{ + gaeaOSSTemplate.uploadFileByInputStream(multipartFile, fileObjectName); + }catch (GaeaOSSTypeLimitedException e){ + log.error("上传失败GaeaOSSTypeLimitedException", e); + throw BusinessExceptionBuilder.build(ResponseCode.FILE_SUFFIX_UNSUPPORTED, e.getMessage()); + }catch (GaeaOSSException e){ + log.error("上传失败GaeaOSSException", e); + throw BusinessExceptionBuilder.build(ResponseCode.FILE_UPLOAD_ERROR, e.getMessage()); + } + + // 保存到文件管理中 + GaeaFile gaeaFile = new GaeaFile(); + gaeaFile.setFileId(fileId); + gaeaFile.setFilePath(fileObjectName); + gaeaFile.setUrlPath(urlPath); + gaeaFile.setFileType(suffixName.replace(".", "")); + gaeaFile.setFileInstruction(originalFilename); + insert(gaeaFile); + + return gaeaFile; + } + + private MultipartFile getMultipartFile(File file){ + FileInputStream fileInputStream; + MultipartFile multipartFile; + try { + fileInputStream = new FileInputStream(file); + multipartFile = new MockMultipartFile(file.getName(),file.getName(), + ContentType.APPLICATION_OCTET_STREAM.toString(),fileInputStream); + } catch (Exception e) { + log.error("file转MultipartFile失败", e); + throw BusinessExceptionBuilder.build(ResponseCode.FILE_OPERATION_FAILED, e.getMessage()); + } + return multipartFile; + } + + /** + * 文件上传 + * + * @param file 文件 + * @return + */ + @Override + public GaeaFile upload(File file) { + return upload(getMultipartFile(file)); + } + + @Override + public ResponseEntity download(HttpServletRequest request, HttpServletResponse response, String fileId) { + try { + // fileId必填 + if(StringUtils.isBlank(fileId)){ + throw BusinessExceptionBuilder.build(ResponseCode.FILE_ONT_EXSIT); + } + // 根据fileId,从gaea_file中读出filePath + LambdaQueryWrapper queryWrapper = Wrappers.lambdaQuery(); + queryWrapper.eq(GaeaFile::getFileId, fileId); + GaeaFile gaeaFile = gaeaFileMapper.selectOne(queryWrapper); + if (null == gaeaFile) { + throw BusinessExceptionBuilder.build(ResponseCode.FILE_ONT_EXSIT); + } + + String userAgent = request.getHeader("User-Agent"); + boolean isIEBrowser = userAgent.indexOf("MSIE") > 0; + // 在oss中存储的文件名 402b6193e70e40a9bf5b73a78ea1e8ab.png + String fileObjectName = gaeaFile.getFileId().concat(".").concat(gaeaFile.getFileType()); + String originalFilename = gaeaFile.getFileInstruction(); + if (StringUtils.isBlank(fileObjectName) || StringUtils.isBlank(originalFilename)) { + throw BusinessExceptionBuilder.build(ResponseCode.FILE_ONT_EXSIT); + } + if (!originalFilename.endsWith(".".concat(gaeaFile.getFileType()))) { + originalFilename = originalFilename.concat(".").concat(gaeaFile.getFileType()); + } + + // 调用文件存储工厂,读取文件,返回字节数组 + byte[] fileBytes = gaeaOSSTemplate.downloadFile(fileObjectName); + + // 根据文件后缀来判断,是显示图片\视频\音频,还是下载文件 + return ResponseUtil2.writeBody(originalFilename, fileBytes, isIEBrowser); + } catch (Exception e) { + log.error("file download error", e); + throw BusinessExceptionBuilder.build(ResponseCode.FILE_OPERATION_FAILED, e.getMessage()); + } + } + + /** + * 获取文件 + * + * @param fileId + * @return + */ + @Override + public byte[] getFile(String fileId) { + // fileId必填 + if(StringUtils.isBlank(fileId)){ + throw BusinessExceptionBuilder.build(ResponseCode.FILE_ONT_EXSIT); + } + // 根据fileId,从gaea_file中读出filePath + LambdaQueryWrapper queryWrapper = Wrappers.lambdaQuery(); + queryWrapper.eq(GaeaFile::getFileId, fileId); + GaeaFile gaeaFile = gaeaFileMapper.selectOne(queryWrapper); + if (null == gaeaFile) { + throw BusinessExceptionBuilder.build(ResponseCode.FILE_ONT_EXSIT); + } + + // 在oss中存储的文件名 402b6193e70e40a9bf5b73a78ea1e8ab.png + String fileObjectName = gaeaFile.getFileId().concat(".").concat(gaeaFile.getFileType()); + String originalFilename = gaeaFile.getFileInstruction(); + if (StringUtils.isBlank(fileObjectName) || StringUtils.isBlank(originalFilename)) { + throw BusinessExceptionBuilder.build(ResponseCode.FILE_ONT_EXSIT); + } + + // 调用文件存储工厂,读取文件,返回字节数组 + return gaeaOSSTemplate.downloadFile(fileObjectName); + } + + /** + * 批处理操作后续处理 + * 删除本地已经存在的文件 + * + * @param entities + * @param operationEnum 操作类型 + * @throws BusinessException 阻止程序继续执行或回滚事务 + */ + @Override + public void processBatchAfterOperation(List entities, BaseOperationEnum operationEnum) throws BusinessException { + if (operationEnum.equals(BaseOperationEnum.DELETE_BATCH)) { + // 删除本地文件 + entities.forEach(gaeaFile -> gaeaOSSTemplate.deleteFile(gaeaFile.getFileId().concat(".").concat(gaeaFile.getFileType()))); + } + + } +} diff --git a/src/main/java/com/anjiplus/template/gaea/business/modules/file/util/FileUtils.java b/src/main/java/com/anjiplus/template/gaea/business/modules/file/util/FileUtils.java new file mode 100644 index 0000000..fca211b --- /dev/null +++ b/src/main/java/com/anjiplus/template/gaea/business/modules/file/util/FileUtils.java @@ -0,0 +1,31 @@ +package com.anjiplus.template.gaea.business.modules.file.util; + +import lombok.extern.slf4j.Slf4j; + +import java.io.*; + +/** + * Created by raodeming on 2021/7/8. + */ +@Slf4j +public class FileUtils { + public static byte[] readFileToByteArray(File file) { + byte[] buffer = null; + try { + FileInputStream fis = new FileInputStream(file); + ByteArrayOutputStream bos = new ByteArrayOutputStream(); + byte[] b = new byte[1024]; + int n; + while ((n = fis.read(b)) != -1) { + bos.write(b, 0, n); + } + fis.close(); + bos.close(); + buffer = bos.toByteArray(); + } catch (IOException e) { + log.error("error", e); + } + return buffer; + } + +} diff --git a/src/main/java/com/anjiplus/template/gaea/business/modules/file/util/StringPatternUtil.java b/src/main/java/com/anjiplus/template/gaea/business/modules/file/util/StringPatternUtil.java new file mode 100644 index 0000000..5741f5e --- /dev/null +++ b/src/main/java/com/anjiplus/template/gaea/business/modules/file/util/StringPatternUtil.java @@ -0,0 +1,98 @@ +package com.anjiplus.template.gaea.business.modules.file.util; + +import org.apache.commons.lang3.StringUtils; + +import java.util.regex.Matcher; +import java.util.regex.Pattern; + + +public class StringPatternUtil { + + + /** + * + *

Discription:[查找源sourceStr中是否包含pattern,返回boolean]

+ * @author + * @update:[日期YYYY-MM-DD] [更改人姓名] + * @param sourceStr + * @param pattern + * @return + */ + public static boolean stringMatch(String sourceStr, String pattern){ + boolean result=false; + try{ + if(StringUtils.isBlank(sourceStr)|| StringUtils.isBlank(pattern)){ + return result; + } + Pattern p = Pattern.compile(pattern); + Matcher m = p.matcher(sourceStr); + while (m.find()) { + //String aa=m.group(0); + result=true; + break ; + } + + }catch(Exception e){ + result=false; + } + return result; + } + + public static boolean stringMatchIgnoreCase(String sourceStr, String pattern){ + boolean result=false; + try{ + if(StringUtils.isBlank(sourceStr)|| StringUtils.isBlank(pattern)){ + return result; + } + sourceStr=sourceStr.toLowerCase(); + pattern=pattern.toLowerCase(); + result= stringMatch(sourceStr,pattern); + }catch(Exception e){ + result=false; + } + return result; + } + + + + /** + *

Discription:[查找源sourceStr中是否包含pattern,返回找到的字符串,未找到就返回空字符串]

+ * @author + * @update:[日期YYYY-MM-DD] [更改人姓名] + * @param sourceStr + * @param pattern + * @return + */ + public static String stringFind(String sourceStr, String pattern){ + String result=""; + try{ + if(StringUtils.isBlank(sourceStr)|| StringUtils.isBlank(pattern)){ + return result; + } + Pattern p = Pattern.compile(pattern); + Matcher m = p.matcher(sourceStr); + while (m.find()) { + result = m.group(0); + break; + } + }catch(Exception e){ + result=""; + } + return result; + } + + public static String replace(String sourceStr, String pattern, String replaceStr){ + String result=""; + try{ + if(StringUtils.isBlank(sourceStr)|| StringUtils.isBlank(pattern)){ + return result; + } + Pattern p = Pattern.compile(pattern); + Matcher m = p.matcher(sourceStr); + result = m.replaceAll(replaceStr); + }catch(Exception e){ + result=""; + } + return result; + } +} diff --git a/src/main/java/com/anjiplus/template/gaea/business/modules/report/constant/ExpConstant.java b/src/main/java/com/anjiplus/template/gaea/business/modules/report/constant/ExpConstant.java new file mode 100644 index 0000000..9e17df5 --- /dev/null +++ b/src/main/java/com/anjiplus/template/gaea/business/modules/report/constant/ExpConstant.java @@ -0,0 +1,25 @@ +package com.anjiplus.template.gaea.business.modules.report.constant; + + +import java.util.ArrayList; +import java.util.List; + +/** + * + */ +public class ExpConstant { + + public static final String[] FUNCTION = new String[]{"=SUM(", "=AVERAGE(", "=MAX(", "=MIN(", "=IF(", "=AND(", "=OR(", "=CONCAT("}; + + public static List getExpFunction(String e) { + List counts = new ArrayList<>(); + for (int i = 0; i < FUNCTION.length; i++) { + if(e.contains(FUNCTION[i])){ + counts.add(i); + } + } + + return counts; + } + +} diff --git a/src/main/java/com/anjiplus/template/gaea/business/modules/report/controller/ReportController.java b/src/main/java/com/anjiplus/template/gaea/business/modules/report/controller/ReportController.java new file mode 100644 index 0000000..fa44a3a --- /dev/null +++ b/src/main/java/com/anjiplus/template/gaea/business/modules/report/controller/ReportController.java @@ -0,0 +1,53 @@ +package com.anjiplus.template.gaea.business.modules.report.controller; + +import com.anji.plus.gaea.annotation.Permission; +import com.anji.plus.gaea.annotation.log.GaeaAuditLog; +import com.anji.plus.gaea.bean.ResponseBean; +import com.anji.plus.gaea.curd.controller.GaeaBaseController; +import com.anji.plus.gaea.curd.service.GaeaBaseService; +import com.anjiplus.template.gaea.business.modules.report.controller.dto.ReportDto; +import com.anjiplus.template.gaea.business.modules.report.controller.param.ReportParam; +import com.anjiplus.template.gaea.business.modules.report.dao.entity.Report; +import com.anjiplus.template.gaea.business.modules.report.service.ReportService; +import io.swagger.annotations.Api; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.*; + +/** + * TODO + * + * @author chenkening + * @date 2021/3/26 10:19 + */ +@RestController +@Api(tags = "报表数据管理") +@Permission(code = "reportManage", name = "报表管理") +@RequestMapping("/report") +public class ReportController extends GaeaBaseController { + + @Autowired + private ReportService reportService; + + @Override + public GaeaBaseService getService() { + return reportService; + } + + @Override + public Report getEntity() { + return new Report(); + } + + @Override + public ReportDto getDTO() { + return new ReportDto(); + } + + @PostMapping("/copy") + @Permission(code = "copy", name = "复制") + @GaeaAuditLog(pageTitle = "复制") + public ResponseBean copy(@RequestBody ReportDto dto) { + reportService.copy(dto); + return ResponseBean.builder().build(); + } +} diff --git a/src/main/java/com/anjiplus/template/gaea/business/modules/report/controller/dto/ReportDto.java b/src/main/java/com/anjiplus/template/gaea/business/modules/report/controller/dto/ReportDto.java new file mode 100644 index 0000000..84e8d1c --- /dev/null +++ b/src/main/java/com/anjiplus/template/gaea/business/modules/report/controller/dto/ReportDto.java @@ -0,0 +1,59 @@ +package com.anjiplus.template.gaea.business.modules.report.controller.dto; + +import com.anji.plus.gaea.curd.dto.GaeaBaseDTO; +import lombok.Data; + +import java.io.Serializable; + +/** + * + * @author chenkening + * @date 2021/3/26 10:34 + */ +@Data +public class ReportDto extends GaeaBaseDTO implements Serializable { + + /** 报表名称 */ + private String reportName; + + /** 报表编码 */ + private String reportCode; + + /**数据集编码,以|分割*/ + private String setCodes; + + /** 分组 */ + private String reportGroup; + + /** 备注 */ + private String reportDesc; + + /** 数据集查询参数 */ + private String setParam; + + /** 报表json字符串 */ + private String jsonStr; + + /** 报表类型 */ + private String reportType; + + /** 数据总计 */ + private long total; + + /** 报表缩略图 */ + private String reportImage; + + /** 0--已禁用 1--已启用 DIC_NAME=ENABLE_FLAG */ + private Integer enableFlag; + + /** 0--未删除 1--已删除 DIC_NAME=DELETE_FLAG */ + private Integer deleteFlag; + + + /** 报表作者 */ + private String reportAuthor; + + /** 下载次数 */ + private Long downloadCount; + +} diff --git a/src/main/java/com/anjiplus/template/gaea/business/modules/report/controller/param/ReportParam.java b/src/main/java/com/anjiplus/template/gaea/business/modules/report/controller/param/ReportParam.java new file mode 100644 index 0000000..87c066a --- /dev/null +++ b/src/main/java/com/anjiplus/template/gaea/business/modules/report/controller/param/ReportParam.java @@ -0,0 +1,36 @@ +package com.anjiplus.template.gaea.business.modules.report.controller.param; + +import com.anji.plus.gaea.annotation.Query; +import com.anji.plus.gaea.constant.QueryEnum; +import com.anji.plus.gaea.curd.params.PageParam; +import lombok.Data; + +import java.io.Serializable; + +/** + * TODO + * + * @author chenkening + * @date 2021/3/26 10:40 + */ +@Data +public class ReportParam extends PageParam implements Serializable{ + + /** 报表名称 */ + @Query(QueryEnum.LIKE) + private String reportName; + + /** 报表作者 */ + @Query(QueryEnum.LIKE) + private String reportAuthor; + + /** 报表编码 */ + @Query(QueryEnum.LIKE) + private String reportCode; + + /** 报表类型 */ + @Query(QueryEnum.EQ) + private String reportType; + + +} diff --git a/src/main/java/com/anjiplus/template/gaea/business/modules/report/dao/ReportMapper.java b/src/main/java/com/anjiplus/template/gaea/business/modules/report/dao/ReportMapper.java new file mode 100644 index 0000000..bfece32 --- /dev/null +++ b/src/main/java/com/anjiplus/template/gaea/business/modules/report/dao/ReportMapper.java @@ -0,0 +1,13 @@ +package com.anjiplus.template.gaea.business.modules.report.dao; + +import com.anji.plus.gaea.curd.mapper.GaeaBaseMapper; +import com.anjiplus.template.gaea.business.modules.report.dao.entity.Report; + +/** + * TODO + * + * @author chenkening + * @date 2021/3/26 10:19 + */ +public interface ReportMapper extends GaeaBaseMapper { +} diff --git a/src/main/java/com/anjiplus/template/gaea/business/modules/report/dao/entity/Report.java b/src/main/java/com/anjiplus/template/gaea/business/modules/report/dao/entity/Report.java new file mode 100644 index 0000000..09ed5f6 --- /dev/null +++ b/src/main/java/com/anjiplus/template/gaea/business/modules/report/dao/entity/Report.java @@ -0,0 +1,50 @@ +package com.anjiplus.template.gaea.business.modules.report.dao.entity; + +import com.anji.plus.gaea.annotation.Unique; +import com.anji.plus.gaea.curd.entity.GaeaBaseEntity; +import com.anjiplus.template.gaea.business.code.ResponseCode; +import com.baomidou.mybatisplus.annotation.TableName; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +/** + * TODO + * + * @author chenkening + * @date 2021/3/26 10:20 + */ +@TableName(keepGlobalPrefix=true, value="gaea_report") +@Data +public class Report extends GaeaBaseEntity { + + @ApiModelProperty(value = "名称") + private String reportName; + + @ApiModelProperty(value = "报表编码") + @Unique(code = ResponseCode.REPORT_CODE_ISEXIST) + private String reportCode; + + @ApiModelProperty(value = "分组") + private String reportGroup; + + @ApiModelProperty(value = "报表描述") + private String reportDesc; + + @ApiModelProperty(value = "报表类型") + private String reportType; + + @ApiModelProperty(value = "报表缩略图") + private String reportImage; + + @ApiModelProperty(value = "报表作者") + private String reportAuthor; + + @ApiModelProperty(value = "下载次数") + private Long downloadCount; + + @ApiModelProperty(value = "0--已禁用 1--已启用 DIC_NAME=ENABLE_FLAG") + private Integer enableFlag; + + @ApiModelProperty(value = "0--未删除 1--已删除 DIC_NAME=DELETE_FLAG") + private Integer deleteFlag; +} diff --git a/src/main/java/com/anjiplus/template/gaea/business/modules/report/service/ReportService.java b/src/main/java/com/anjiplus/template/gaea/business/modules/report/service/ReportService.java new file mode 100644 index 0000000..6ee95e5 --- /dev/null +++ b/src/main/java/com/anjiplus/template/gaea/business/modules/report/service/ReportService.java @@ -0,0 +1,27 @@ +package com.anjiplus.template.gaea.business.modules.report.service; + +import com.anji.plus.gaea.curd.service.GaeaBaseService; +import com.anjiplus.template.gaea.business.modules.report.controller.dto.ReportDto; +import com.anjiplus.template.gaea.business.modules.report.controller.param.ReportParam; +import com.anjiplus.template.gaea.business.modules.report.dao.entity.Report; + +/** + * + * @author chenkening + * @date 2021/3/26 10:35 + */ +public interface ReportService extends GaeaBaseService { + + + /** + * 下载次数+1 + * @param reportCode + */ + void downloadStatistics(String reportCode); + + /** + * 复制大屏 + * @param dto + */ + void copy(ReportDto dto); +} diff --git a/src/main/java/com/anjiplus/template/gaea/business/modules/report/service/impl/ReportServiceImpl.java b/src/main/java/com/anjiplus/template/gaea/business/modules/report/service/impl/ReportServiceImpl.java new file mode 100644 index 0000000..e44400b --- /dev/null +++ b/src/main/java/com/anjiplus/template/gaea/business/modules/report/service/impl/ReportServiceImpl.java @@ -0,0 +1,175 @@ +package com.anjiplus.template.gaea.business.modules.report.service.impl; + +import com.anji.plus.gaea.constant.BaseOperationEnum; +import com.anji.plus.gaea.curd.mapper.GaeaBaseMapper; +import com.anji.plus.gaea.exception.BusinessException; +import com.anji.plus.gaea.exception.BusinessExceptionBuilder; +import com.anji.plus.gaea.utils.GaeaBeanUtils; +import com.anjiplus.template.gaea.business.code.ResponseCode; +import com.anjiplus.template.gaea.business.enums.ReportTypeEnum; +import com.anjiplus.template.gaea.business.modules.dashboard.dao.entity.ReportDashboard; +import com.anjiplus.template.gaea.business.modules.dashboard.service.ReportDashboardService; +import com.anjiplus.template.gaea.business.modules.dashboardwidget.dao.entity.ReportDashboardWidget; +import com.anjiplus.template.gaea.business.modules.dashboardwidget.service.ReportDashboardWidgetService; +import com.anjiplus.template.gaea.business.modules.report.controller.dto.ReportDto; +import com.anjiplus.template.gaea.business.modules.report.dao.ReportMapper; +import com.anjiplus.template.gaea.business.modules.report.dao.entity.Report; +import com.anjiplus.template.gaea.business.modules.report.service.ReportService; +import com.anjiplus.template.gaea.business.modules.reportexcel.dao.entity.ReportExcel; +import com.anjiplus.template.gaea.business.modules.reportexcel.service.ReportExcelService; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.toolkit.StringUtils; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.util.CollectionUtils; + +import java.util.Collections; +import java.util.List; + +/** + * + * @author chenkening + * @date 2021/3/26 10:35 + */ +@Service +public class ReportServiceImpl implements ReportService { + + @Autowired + private ReportMapper reportMapper; + @Autowired + private ReportDashboardService reportDashboardService; + @Autowired + private ReportDashboardWidgetService reportDashboardWidgetService; + @Autowired + private ReportExcelService reportExcelService; + + @Override + public GaeaBaseMapper getMapper() { + return reportMapper; + } + + + @Override + public void processBatchBeforeOperation(List entities, BaseOperationEnum operationEnum) throws BusinessException { + ReportService.super.processBatchAfterOperation(entities, operationEnum); + switch (operationEnum) { + case DELETE_BATCH: + entities.forEach(report -> { + Long id = report.getId(); + Report delReport = selectOne(id); + if (null == delReport) { + return; + } + String reportCode = delReport.getReportCode(); + String reportType = delReport.getReportType(); + switch (ReportTypeEnum.valueOf(reportType)) { + case report_screen: + LambdaQueryWrapper reportDashboardLambdaQueryWrapper = Wrappers.lambdaQuery(); + reportDashboardLambdaQueryWrapper.eq(ReportDashboard::getReportCode, reportCode); + reportDashboardService.delete(reportDashboardLambdaQueryWrapper); + + LambdaQueryWrapper reportDashboardWidgetLambdaQueryWrapper = Wrappers.lambdaQuery(); + reportDashboardWidgetLambdaQueryWrapper.eq(ReportDashboardWidget::getReportCode, reportCode); + reportDashboardWidgetService.delete(reportDashboardWidgetLambdaQueryWrapper); + + break; + case report_excel: + LambdaQueryWrapper reportExcelLambdaQueryWrapper = Wrappers.lambdaQuery(); + reportExcelLambdaQueryWrapper.eq(ReportExcel::getReportCode, reportCode); + reportExcelService.delete(reportExcelLambdaQueryWrapper); + break; + default: + } + }); + break; + default: + + } + } + + /** + * 下载次数+1 + * + * @param reportCode + */ + @Override + public void downloadStatistics(String reportCode) { + Report report = selectOne("report_code", reportCode); + if (null != report) { + Long downloadCount = report.getDownloadCount(); + if (null == downloadCount) { + downloadCount = 0L; + }else { + downloadCount++; + } + report.setDownloadCount(downloadCount); + update(report); + } + + } + + @Override + public void copy(ReportDto dto) { + if (null == dto.getId()) { + throw BusinessExceptionBuilder.build(ResponseCode.NOT_NULL, "id"); + } + if (StringUtils.isBlank(dto.getReportCode())) { + throw BusinessExceptionBuilder.build(ResponseCode.NOT_NULL, "报表编码"); + } + Report report = selectOne(dto.getId()); + String reportCode = report.getReportCode(); + Report copyReport = copyReport(report, dto); + //复制主表数据 + insert(copyReport); + String copyReportCode = copyReport.getReportCode(); + String reportType = report.getReportType(); + switch (ReportTypeEnum.valueOf(reportType)) { + case report_screen: + //查询看板 + ReportDashboard reportDashboard = reportDashboardService.selectOne("report_code", reportCode); + if (null != reportDashboard) { + reportDashboard.setId(null); + reportDashboard.setReportCode(copyReportCode); + reportDashboardService.insert(reportDashboard); + } + + //查询组件 + List reportDashboardWidgetList = reportDashboardWidgetService.list("report_code", reportCode); + if (!CollectionUtils.isEmpty(reportDashboardWidgetList)) { + String finalCopyReportCode = copyReportCode; + reportDashboardWidgetList.forEach(reportDashboardWidget -> { + reportDashboardWidget.setId(null); + reportDashboardWidget.setReportCode(finalCopyReportCode); + }); + reportDashboardWidgetService.insertBatch(reportDashboardWidgetList); + } + + break; + case report_excel: + ReportExcel reportExcel = reportExcelService.selectOne("report_code", reportCode); + if (null != reportExcel) { + reportExcel.setId(null); + reportExcel.setReportCode(copyReportCode); + reportExcelService.insert(reportExcel); + } + + break; + default: + } + } + + private Report copyReport(Report report, ReportDto dto){ + //复制主表数据 + Report copyReport = new Report(); + GaeaBeanUtils.copyAndFormatter(report, copyReport); + copyReport.setReportCode(dto.getReportCode()); + copyReport.setReportName(dto.getReportName()); + return copyReport; + } + + @Override + public void processBeforeOperation(Report entity, BaseOperationEnum operationEnum) throws BusinessException { + + } +} diff --git a/src/main/java/com/anjiplus/template/gaea/business/modules/reportexcel/controller/ReportExcelController.java b/src/main/java/com/anjiplus/template/gaea/business/modules/reportexcel/controller/ReportExcelController.java new file mode 100644 index 0000000..fbb2186 --- /dev/null +++ b/src/main/java/com/anjiplus/template/gaea/business/modules/reportexcel/controller/ReportExcelController.java @@ -0,0 +1,91 @@ +package com.anjiplus.template.gaea.business.modules.reportexcel.controller; + +import com.anji.plus.gaea.annotation.Permission; +import com.anji.plus.gaea.annotation.log.GaeaAuditLog; +import com.anji.plus.gaea.bean.ResponseBean; +import com.anji.plus.gaea.code.ResponseCode; +import com.anji.plus.gaea.curd.controller.GaeaBaseController; +import com.anji.plus.gaea.curd.service.GaeaBaseService; +import com.anjiplus.template.gaea.business.modules.reportexcel.controller.dto.ReportExcelDto; +import com.anjiplus.template.gaea.business.modules.reportexcel.controller.param.ReportExcelParam; +import com.anjiplus.template.gaea.business.modules.reportexcel.dao.entity.ReportExcel; +import com.anjiplus.template.gaea.business.modules.reportexcel.service.ReportExcelService; +import com.anjiplus.template.gaea.business.modules.reportshare.controller.dto.ReportShareDto; +import com.anjiplus.template.gaea.business.modules.reportshare.service.ReportShareService; +import io.swagger.annotations.Api; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +/** + * @author chenkening + * @date 2021/4/13 15:12 + */ +@RestController +@Api(tags = "报表表格管理") +@Permission(code = "excelManage", name = "报表管理") +@RequestMapping("/reportExcel") +public class ReportExcelController extends GaeaBaseController { + + @Autowired + private ReportExcelService reportExcelService; + + @Autowired + private ReportShareService reportShareService; + + @Override + public GaeaBaseService getService() { + return reportExcelService; + } + + @Override + public ReportExcel getEntity() { + return new ReportExcel(); + } + + @Override + public ReportExcelDto getDTO() { + return new ReportExcelDto(); + } + + @GetMapping("/detailByReportCode/{reportCode}") + @Permission(code = "query", name = "详情") + @GaeaAuditLog(pageTitle = "详情") + public ResponseBean detailByReportCode(@PathVariable String reportCode) { + ReportExcelDto reportExcelDto = reportExcelService.detailByReportCode(reportCode); + return ResponseBean.builder().data(reportExcelDto).build(); + } + + @PostMapping("/preview") + @Permission(code = "view", name = "预览") + @GaeaAuditLog(pageTitle = "预览") + public ResponseBean preview(@RequestBody ReportExcelDto reportExcelDto) { + ReportExcelDto result = reportExcelService.preview(reportExcelDto); + return ResponseBean.builder().data(result).build(); + } + + + @PostMapping("/exportExcel") + @Permission(code = "export", name = "导出") + @GaeaAuditLog(pageTitle = "报表导出") + public ResponseBean exportExcel(@RequestBody ReportExcelDto reportExcelDto) { + + return ResponseBean.builder().code(ResponseCode.SUCCESS_CODE) + .data(reportExcelService.exportExcel(reportExcelDto)) + .message("导出成功,请稍后在文件管理中查看").build(); + } + +// @PostMapping("/exportPdf") +// public ResponseBean exportPdf(@RequestBody ReportExcelDto reportExcelDto) { +// reportExcelService.exportPdf(reportExcelDto); +// return ResponseBean.builder().code(ResponseCode.SUCCESS_CODE) +// .build(); +// } + + @PostMapping("/share") + @GaeaAuditLog(pageTitle = "excel分享") + @Permission(code = "share", name = "分享报表") + public ResponseBean share(@Validated @RequestBody ReportShareDto dto) { + return ResponseBean.builder().data(reportShareService.insertShare(dto)).build(); + } +} diff --git a/src/main/java/com/anjiplus/template/gaea/business/modules/reportexcel/controller/dto/CellStyleDto.java b/src/main/java/com/anjiplus/template/gaea/business/modules/reportexcel/controller/dto/CellStyleDto.java new file mode 100644 index 0000000..07cf70b --- /dev/null +++ b/src/main/java/com/anjiplus/template/gaea/business/modules/reportexcel/controller/dto/CellStyleDto.java @@ -0,0 +1,20 @@ +package com.anjiplus.template.gaea.business.modules.reportexcel.controller.dto; + +import lombok.Data; + +/** + * @author chenxg + * @date 2023/8/1 10:37 + */ +@Data +public class CellStyleDto { + /** + * 格式名称 + */ + private String fa; + + /** + * 格式类型 + */ + private String t; +} \ No newline at end of file diff --git a/src/main/java/com/anjiplus/template/gaea/business/modules/reportexcel/controller/dto/CommentDto.java b/src/main/java/com/anjiplus/template/gaea/business/modules/reportexcel/controller/dto/CommentDto.java new file mode 100644 index 0000000..acc2652 --- /dev/null +++ b/src/main/java/com/anjiplus/template/gaea/business/modules/reportexcel/controller/dto/CommentDto.java @@ -0,0 +1,42 @@ +package com.anjiplus.template.gaea.business.modules.reportexcel.controller.dto; + + +import lombok.Data; + +/** + * @author chenxg + * @date 2023/8/1 10:37 + */ +@Data +public class CommentDto { + /** + * 批注框左边距 + */ + private int left; + + /** + * 批注框上边距 + */ + private int top; + + /** + * 批注框宽度 + */ + private int width; + + /** + * 批注框高度 + */ + private int height; + + /** + * 批注内容 + */ + private String value; + + /** + * 批注框是否显示 + */ + private boolean isshow; +} + diff --git a/src/main/java/com/anjiplus/template/gaea/business/modules/reportexcel/controller/dto/GridRecordDataModel.java b/src/main/java/com/anjiplus/template/gaea/business/modules/reportexcel/controller/dto/GridRecordDataModel.java new file mode 100644 index 0000000..b704143 --- /dev/null +++ b/src/main/java/com/anjiplus/template/gaea/business/modules/reportexcel/controller/dto/GridRecordDataModel.java @@ -0,0 +1,58 @@ +package com.anjiplus.template.gaea.business.modules.reportexcel.controller.dto; + + +import com.alibaba.fastjson.JSONObject; +import lombok.Data; + +import java.util.List; + +/** + * 存储对象类 + * + * @author Administrator + */ +@Data +public class GridRecordDataModel { + /** + * 记录序列 + */ + Long id; + /** + * 文档ID + */ + String list_id; + /** + * 本记录的行_列 + */ + String row_col; + /** + * sheet序号 + */ + String index; + /** + * 状态是否当前sheet页 + */ + Integer status; + /** + * 块编号 第一块 fblock + */ + String block_id; + /** + * json串 + */ + JSONObject json_data; + /** + * 排序位置 + */ + Integer order; + /** + * 是否删除 + */ + Integer is_delete; + + /** + * sheet页数据 未编号分组 + */ + List dataList; + +} diff --git a/src/main/java/com/anjiplus/template/gaea/business/modules/reportexcel/controller/dto/ReportExcelDto.java b/src/main/java/com/anjiplus/template/gaea/business/modules/reportexcel/controller/dto/ReportExcelDto.java new file mode 100644 index 0000000..739563f --- /dev/null +++ b/src/main/java/com/anjiplus/template/gaea/business/modules/reportexcel/controller/dto/ReportExcelDto.java @@ -0,0 +1,67 @@ + +package com.anjiplus.template.gaea.business.modules.reportexcel.controller.dto; + +import com.anji.plus.gaea.curd.dto.GaeaBaseDTO; +import lombok.Data; + +import java.io.Serializable; +import java.util.List; + + +/** + * @author chenkening + * @date 2021/4/13 15:12 + */ +@Data +public class ReportExcelDto extends GaeaBaseDTO implements Serializable { + /** + * 报表名称 + */ + private String reportName; + + /** + * 报表编码 + */ + private String reportCode; + + /** + * 数据集编码,以|分割 + */ + private String setCodes; + + /** + * 分组 + */ + private String reportGroup; + + /** + * 数据集查询参数 + */ + private String setParam; + + /** + * 报表json字符串 + */ + private String jsonStr; + + /** + * 报表类型 + */ + private String reportType; + + /** + * 数据总计 + */ + private long total; + + /** + * 导出类型 + */ + private String exportType; + + /** + * 报表总体数据 + */ + private String rowDatas; + +} diff --git a/src/main/java/com/anjiplus/template/gaea/business/modules/reportexcel/controller/dto/ReportExcelStyleDto.java b/src/main/java/com/anjiplus/template/gaea/business/modules/reportexcel/controller/dto/ReportExcelStyleDto.java new file mode 100644 index 0000000..dc8d41f --- /dev/null +++ b/src/main/java/com/anjiplus/template/gaea/business/modules/reportexcel/controller/dto/ReportExcelStyleDto.java @@ -0,0 +1,97 @@ + +package com.anjiplus.template.gaea.business.modules.reportexcel.controller.dto; + +import com.anji.plus.gaea.curd.dto.GaeaBaseDTO; +import lombok.Data; + +import java.io.Serializable; + + +/** + * @author chenxg + * @date 2023/8/1 10:37 + */ +@Data +public class ReportExcelStyleDto extends GaeaBaseDTO implements Serializable { + /** + * 单元格值格式 + */ + private CellStyleDto ct; + + /** + * 内容的原始值 + */ + private String v; + + /** + * 内容的显示值 + */ + private String m; + + /** + * 背景颜色 + */ + private String bg; + + /** + * 字体编号 + */ + private String ff; + + /** + * 字体颜色 + */ + private String fc; + + /** + * 是否加粗 + */ + private boolean bl; + + /** + * 是否斜体 + */ + private boolean it; + + /** + * 字体大小 + */ + private int fs; + + /** + * 是否删除线 + */ + private boolean cl; + + /** + * 水平对齐方式 + */ + private int ht; + + /** + * 垂直对齐方式 + */ + private int vt; + + /** + * 文字旋转角度 + */ + private int tr; + + /** + * 是否自动换行 + */ + private int tb; + + /** + * 批注信息 + */ + private CommentDto ps; + + /** + * 单元格公式 + */ + private String f; + + +} \ No newline at end of file diff --git a/src/main/java/com/anjiplus/template/gaea/business/modules/reportexcel/controller/param/ReportExcelParam.java b/src/main/java/com/anjiplus/template/gaea/business/modules/reportexcel/controller/param/ReportExcelParam.java new file mode 100644 index 0000000..1320258 --- /dev/null +++ b/src/main/java/com/anjiplus/template/gaea/business/modules/reportexcel/controller/param/ReportExcelParam.java @@ -0,0 +1,18 @@ + +package com.anjiplus.template.gaea.business.modules.reportexcel.controller.param; + +import com.anji.plus.gaea.curd.params.PageParam; +import lombok.Data; + +import java.io.Serializable; + + +/** + * @author chenkening + * @date 2021/4/13 15:12 + */ +@Data +public class ReportExcelParam extends PageParam implements Serializable { + + +} diff --git a/src/main/java/com/anjiplus/template/gaea/business/modules/reportexcel/dao/ReportExcelMapper.java b/src/main/java/com/anjiplus/template/gaea/business/modules/reportexcel/dao/ReportExcelMapper.java new file mode 100644 index 0000000..422b83f --- /dev/null +++ b/src/main/java/com/anjiplus/template/gaea/business/modules/reportexcel/dao/ReportExcelMapper.java @@ -0,0 +1,11 @@ +package com.anjiplus.template.gaea.business.modules.reportexcel.dao; + +import com.anji.plus.gaea.curd.mapper.GaeaBaseMapper; +import com.anjiplus.template.gaea.business.modules.reportexcel.dao.entity.ReportExcel; + +/** + * @author chenkening + * @date 2021/4/13 15:11 + */ +public interface ReportExcelMapper extends GaeaBaseMapper { +} diff --git a/src/main/java/com/anjiplus/template/gaea/business/modules/reportexcel/dao/entity/ReportExcel.java b/src/main/java/com/anjiplus/template/gaea/business/modules/reportexcel/dao/entity/ReportExcel.java new file mode 100644 index 0000000..2fa43ec --- /dev/null +++ b/src/main/java/com/anjiplus/template/gaea/business/modules/reportexcel/dao/entity/ReportExcel.java @@ -0,0 +1,33 @@ +package com.anjiplus.template.gaea.business.modules.reportexcel.dao.entity; + +import com.anji.plus.gaea.curd.entity.GaeaBaseEntity; +import com.baomidou.mybatisplus.annotation.TableName; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +/** + * @author chenkening + * @date 2021/4/13 15:11 + */ +@TableName(value = "gaea_report_excel") +@Data +public class ReportExcel extends GaeaBaseEntity { + + @ApiModelProperty(value = "报表编码") + private String reportCode; + + @ApiModelProperty(value = "数据集编码,以|分割") + private String setCodes; + + @ApiModelProperty(value = "数据集查询参数") + private String setParam; + + @ApiModelProperty(value = "报表json字符串") + private String jsonStr; + + @ApiModelProperty(value = "0--已禁用 1--已启用 DIC_NAME=ENABLE_FLAG") + private Integer enableFlag; + + @ApiModelProperty(value = "0--未删除 1--已删除 DIC_NAME=DELETE_FLAG") + private Integer deleteFlag; +} diff --git a/src/main/java/com/anjiplus/template/gaea/business/modules/reportexcel/service/ReportExcelService.java b/src/main/java/com/anjiplus/template/gaea/business/modules/reportexcel/service/ReportExcelService.java new file mode 100644 index 0000000..0bceb4b --- /dev/null +++ b/src/main/java/com/anjiplus/template/gaea/business/modules/reportexcel/service/ReportExcelService.java @@ -0,0 +1,43 @@ +package com.anjiplus.template.gaea.business.modules.reportexcel.service; + + +import com.anji.plus.gaea.curd.service.GaeaBaseService; +import com.anjiplus.template.gaea.business.modules.reportexcel.controller.dto.ReportExcelDto; +import com.anjiplus.template.gaea.business.modules.reportexcel.controller.param.ReportExcelParam; +import com.anjiplus.template.gaea.business.modules.reportexcel.dao.entity.ReportExcel; + +/** + * TODO + * + * @author chenkening + * @date 2021/4/13 15:14 + */ +public interface ReportExcelService extends GaeaBaseService { + + /** + * 根据报表编码查询详情 + * + * @param reportCode + * @return + */ + ReportExcelDto detailByReportCode(String reportCode); + + /** + * 报表预览 + * + * @param reportExcelDto + * @return + */ + ReportExcelDto preview(ReportExcelDto reportExcelDto); + + + /** + * 导出为excel + * + * @param reportExcelDto + * @return + */ + Boolean exportExcel(ReportExcelDto reportExcelDto); + +// Boolean exportPdf(ReportExcelDto reportExcelDto); +} diff --git a/src/main/java/com/anjiplus/template/gaea/business/modules/reportexcel/service/impl/ReportExcelServiceImpl.java b/src/main/java/com/anjiplus/template/gaea/business/modules/reportexcel/service/impl/ReportExcelServiceImpl.java new file mode 100644 index 0000000..1551f51 --- /dev/null +++ b/src/main/java/com/anjiplus/template/gaea/business/modules/reportexcel/service/impl/ReportExcelServiceImpl.java @@ -0,0 +1,932 @@ +package com.anjiplus.template.gaea.business.modules.reportexcel.service.impl; + +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONArray; +import com.alibaba.fastjson.JSONObject; +import com.alibaba.fastjson.serializer.SerializerFeature; +import com.anji.plus.gaea.constant.BaseOperationEnum; +import com.anji.plus.gaea.curd.mapper.GaeaBaseMapper; +import com.anji.plus.gaea.exception.BusinessException; +import com.anji.plus.gaea.exception.BusinessExceptionBuilder; +import com.anji.plus.gaea.utils.GaeaAssert; +import com.anji.plus.gaea.utils.GaeaBeanUtils; +import com.anjiplus.template.gaea.business.code.ResponseCode; +import com.anjiplus.template.gaea.business.enums.ExportTypeEnum; +import com.anjiplus.template.gaea.business.modules.dataset.controller.dto.DataSetDto; +import com.anjiplus.template.gaea.business.modules.dataset.controller.dto.OriginalDataDto; +import com.anjiplus.template.gaea.business.modules.dataset.service.DataSetService; +import com.anjiplus.template.gaea.business.modules.file.service.GaeaFileService; +import com.anjiplus.template.gaea.business.modules.report.dao.ReportMapper; +import com.anjiplus.template.gaea.business.modules.report.dao.entity.Report; +import com.anjiplus.template.gaea.business.modules.reportexcel.controller.dto.ReportExcelDto; +import com.anjiplus.template.gaea.business.modules.reportexcel.controller.dto.ReportExcelStyleDto; +import com.anjiplus.template.gaea.business.modules.reportexcel.dao.ReportExcelMapper; +import com.anjiplus.template.gaea.business.modules.reportexcel.dao.entity.ReportExcel; +import com.anjiplus.template.gaea.business.modules.reportexcel.service.ReportExcelService; +import com.anjiplus.template.gaea.business.modules.reportexcel.util.CellType; +import com.anjiplus.template.gaea.business.modules.reportexcel.util.XlsUtil; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.itextpdf.text.*; +import com.itextpdf.text.pdf.BaseFont; +import com.itextpdf.text.pdf.PdfPCell; +import com.itextpdf.text.pdf.PdfPTable; +import com.itextpdf.text.pdf.PdfWriter; +import org.apache.commons.lang3.StringUtils; +import org.apache.poi.ss.usermodel.Cell; +import org.apache.poi.ss.usermodel.Row; +import org.apache.poi.ss.usermodel.Sheet; +import org.apache.poi.ss.usermodel.Workbook; +import org.apache.poi.xssf.usermodel.XSSFWorkbook; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.BeanUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Service; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.OutputStream; +import java.nio.file.Files; +import java.nio.file.Paths; +import java.util.List; +import java.util.*; +import java.util.stream.Collectors; + +/** + * TODO + * + * @author chenkening + * @date 2021/4/13 15:14 + */ +@Service +public class ReportExcelServiceImpl implements ReportExcelService { + + private Logger logger = LoggerFactory.getLogger(this.getClass()); + + @Autowired + private ReportExcelMapper reportExcelMapper; + + @Autowired + private DataSetService dataSetService; + + @Autowired + private GaeaFileService gaeaFileService; + + + @Autowired + private ReportMapper reportMapper; + + @Value("${customer.file.tmp-path:.}") + private String dictPath; + + private final static String ZIP_PATH = "/tmp_zip/"; + + + @Override + public GaeaBaseMapper getMapper() { + return reportExcelMapper; + } + + @Override + public ReportExcelDto detailByReportCode(String reportCode) { + QueryWrapper queryWrapper = new QueryWrapper<>(); + queryWrapper.eq("report_code", reportCode); + ReportExcel reportExcel = reportExcelMapper.selectOne(queryWrapper); + if (reportExcel != null) { + ReportExcelDto dto = new ReportExcelDto(); + BeanUtils.copyProperties(reportExcel, dto); + return dto; + } + return null; + } + + /** + * 操作前处理 + * + * @param entity 前端传递的对象 + * @param operationEnum 操作类型 + * @throws BusinessException 阻止程序继续执行或回滚事务 + */ + @Override + public void processBeforeOperation(ReportExcel entity, BaseOperationEnum operationEnum) throws BusinessException { + if (operationEnum.equals(BaseOperationEnum.INSERT)) { + String reportCode = entity.getReportCode(); + ReportExcel report = this.selectOne("report_code", reportCode); + if (null != report) { + this.deleteById(report.getId()); + } + } + } + + /** + * 报表预览 + */ + @Override + public ReportExcelDto preview(ReportExcelDto reportExcelDto) { + // 根据id查询 报表详情 + ReportExcel reportExcel = selectOne("report_code", reportExcelDto.getReportCode()); + QueryWrapper queryWrapper = new QueryWrapper<>(); + queryWrapper.eq("report_code", reportExcelDto.getReportCode()); + Report report = reportMapper.selectOne(queryWrapper); + GaeaAssert.notNull(reportExcel, ResponseCode.RULE_CONTENT_NOT_EXIST, "reportExcel"); + String setParam = reportExcelDto.getSetParam(); + + GaeaBeanUtils.copyAndFormatter(reportExcel, reportExcelDto); + if (StringUtils.isNotBlank(setParam)) { + reportExcelDto.setSetParam(setParam); + } + reportExcelDto.setReportName(report.getReportName()); + // 数据集解析 + String jsonStr = analysisReportData(reportExcelDto); + reportExcelDto.setJsonStr(jsonStr); +// reportExcelDto.setTotal(jsonObject.getJSONObject("rows").size()); + return reportExcelDto; + } + + @Override + public Boolean exportExcel(ReportExcelDto reportExcelDto) { + logger.error("导出..."); + exportExcelCore(reportExcelDto); + return true; + } + /** + * 抽取导出Excel核心逻辑 + */ + public void exportExcelCore(ReportExcelDto reportExcelDto) + { + String reportCode = reportExcelDto.getReportCode(); + String exportType = reportExcelDto.getExportType(); + List> reportExcelStyleList = new ArrayList<>(); + JSONObject rowData= JSON.parseObject(reportExcelDto.getRowDatas()); + // 将JSONObject对象转换为列表 + List dataNumList = rowData.keySet().stream().map(Integer::parseInt).sorted().collect(Collectors.toList()); + for (Integer i : dataNumList) { + JSONArray jsonArray = rowData.getJSONArray(i.toString()); + List reportExcelStyleDtos = jsonArray.toJavaList(ReportExcelStyleDto.class); + reportExcelStyleList.add(reportExcelStyleDtos); + } + ReportExcelDto report = detailByReportCode(reportCode); + reportExcelDto.setJsonStr(report.getJsonStr()); + String jsonStr = analysisReportData(reportExcelDto); + List lists=(List ) JSON.parse(jsonStr); + OutputStream out = null; + File file = null; + File pdfFile = null; + try { + String fileName = report.getReportCode(); + File dir = new File(dictPath + ZIP_PATH); + if (!dir.exists()){ + dir.mkdirs(); + } + String filePath = dir.getAbsolutePath() + File.separator + fileName + ".xlsx"; + file = new File(filePath); + out = Files.newOutputStream(Paths.get(filePath)); + XlsUtil.exportXlsFile(out, true, lists); + if (exportType.equals(ExportTypeEnum.GAEA_TEMPLATE_EXCEL.getCodeValue())) { + gaeaFileService.upload(file); + } + else if(exportType.equals(ExportTypeEnum.GAEA_TEMPLATE_PDF.getCodeValue())) + { + // 将Excel文件转换为PDF + String pdfFileName = fileName + ".pdf"; + String pdfFilePath = dir.getAbsolutePath() + File.separator + pdfFileName; + pdfFile = convertExcelToPdf(filePath, pdfFilePath,reportExcelStyleList); + gaeaFileService.upload(pdfFile); + } + + } catch (IOException e) { + logger.error("导出失败", e); + }finally { + try { + out.close(); + file.delete(); + if(!Objects.isNull(pdfFile)) + { + pdfFile.delete(); + } + } catch (IOException e) { + throw BusinessExceptionBuilder.build(ResponseCode.FILE_OPERATION_FAILED, e.getMessage()); + } + + } + } + // 将Excel文件转换为PDF + public File convertExcelToPdf(String excelFilePath, String pdfFilePath, List> reportExcelStyleList) { + try { + // 读取Excel文件 + Workbook workbook = new XSSFWorkbook(excelFilePath); + Sheet sheet = workbook.getSheetAt(0); + + // 创建PDF文档 + Document document = new Document(PageSize.A4); + PdfWriter pdfWriter = PdfWriter.getInstance(document, new FileOutputStream(pdfFilePath)); + document.open(); + + // 创建PDF表格 + PdfPTable table = new PdfPTable(sheet.getRow(0).getLastCellNum()); + table.setWidthPercentage(100); + + // 设置中文字体 + BaseFont baseFont = BaseFont.createFont("STSong-Light", "UniGB-UCS2-H", BaseFont.NOT_EMBEDDED); + Font font = new Font(baseFont, 10, Font.NORMAL); + + // 设置表头 + Row headerRow = sheet.getRow(0); + for (int i = 0; i < headerRow.getLastCellNum(); i++) { + Cell headerCell = headerRow.getCell(i); + + // 获取单元格样式 + PdfPCell tableCell = new PdfPCell(); + tableCell.setPhrase(new Phrase(getStringValue(headerCell), font)); + ReportExcelStyleDto reportExcelStyleDto = reportExcelStyleList.get(0).get(i); + if(!Objects.isNull(reportExcelStyleDto)) + { + processCellStyle(reportExcelStyleDto,tableCell,font); + } + table.addCell(tableCell); + } + + // 遍历Excel表格的行和列 + for (int i = 1; i <= sheet.getLastRowNum(); i++) { + Row row = sheet.getRow(i); + if (row == null) { + // 如果行为空,创建一个空的行并添加到PDF表格中 + row = sheet.createRow(i); + } + for (int j = 0; j < headerRow.getLastCellNum(); j++) { + Cell cell = row.getCell(j, Row.MissingCellPolicy.CREATE_NULL_AS_BLANK); + if (cell.getCellType() == org.apache.poi.ss.usermodel.CellType.BLANK) { + cell.setCellValue(" "); + } + PdfPCell tableCell = new PdfPCell(); + tableCell.setPhrase(new Phrase(getStringValue(cell), font)); + ReportExcelStyleDto reportExcelStyleDto = reportExcelStyleList.get(i).get(j); + if(!Objects.isNull(reportExcelStyleDto)) + { + processCellStyle(reportExcelStyleDto,tableCell,font); + } + table.addCell(tableCell); + } + } + + // 将表格添加到PDF文档中 + document.add(table); + + document.close(); + workbook.close(); + + System.out.println("Excel转换为PDF成功!"); + + return new File(pdfFilePath); + } catch (IOException e) { + e.printStackTrace(); + } catch (com.itextpdf.text.DocumentException e) { + e.printStackTrace(); + } + + return null; + } + + /** + * 处理导出pdf文件样式 + * @param tableCell + */ + public void processCellStyle(ReportExcelStyleDto reportExcelStyleDto,PdfPCell tableCell,Font font) + { + // 处理单元格背景颜色 + String bg = reportExcelStyleDto.getBg(); + java.awt.Color color = null; + if(!Objects.isNull(bg)) + { + color = parseRGB(bg); + tableCell.setBackgroundColor(new BaseColor(color.getRed(), color.getGreen(), color.getBlue())); + } + // 处理字体 + String fc = reportExcelStyleDto.getFc(); + Integer fs = reportExcelStyleDto.getFs(); + String ff = reportExcelStyleDto.getFf(); + Boolean bl = reportExcelStyleDto.isBl(); + Boolean it = reportExcelStyleDto.isIt(); + Boolean cl = reportExcelStyleDto.isCl(); + Integer ht = reportExcelStyleDto.getHt(); + Integer vt = reportExcelStyleDto.getVt(); + + + // 设置字体颜色 + if(!Objects.isNull(fc)) + { + color = parseRGB(fc); + font.setColor(new BaseColor(color.getRed(), color.getGreen(), color.getBlue())); + } + // 设置字体 + if(!Objects.isNull(ff) && !Objects.equals("0",ff)) + { + font.setFamily(ff.toString()); + } + // 设置字体大小 + if(!Objects.isNull(fs) && !Objects.equals(0,fs)) + { + font.setSize(fs); + } + // 设置字体加粗 + if(Objects.equals(Boolean.TRUE,bl)) + { + font.setStyle(Font.BOLD); + } + // 设置字体斜体 + if(Objects.equals(Boolean.TRUE,it)) + { + font.setStyle(Font.ITALIC); + } + // 设置字体加粗且斜体 + if(Objects.equals(Boolean.TRUE,bl) && Objects.equals(Boolean.TRUE,it)) + { + font.setStyle(Font.BOLDITALIC); + } + // 是否删除线 + if(Objects.equals(Boolean.TRUE,cl)) + { + // 如果是粗体且斜体 + if (font.getStyle() == Font.BOLDITALIC) + { + font.setStyle(Font.BOLDITALIC | Font.STRIKETHRU); + } + // 如果是粗体 + else if(font.getStyle() == Font.BOLD) + { + font.setStyle(Font.BOLD | Font.STRIKETHRU); + } + // 如果是斜体 + else if(font.getStyle() == Font.ITALIC) + { + font.setStyle(Font.ITALIC | Font.STRIKETHRU); + } + else + { + font.setStyle(Font.STRIKETHRU); + } + } + // 水平对齐 + if(!Objects.isNull(ht)) + { + if(Objects.equals(ht,0)) + { + tableCell.setHorizontalAlignment(Element.ALIGN_CENTER); + } + else if(Objects.equals(ht,1)) + { + tableCell.setHorizontalAlignment(Element.ALIGN_LEFT); + } + else if(Objects.equals(ht,2)) + { + tableCell.setHorizontalAlignment(Element.ALIGN_RIGHT); + } + } + // 垂直对齐 + if(!Objects.isNull(vt)) + { + if(Objects.equals(ht,0)) + { + tableCell.setVerticalAlignment(com.itextpdf.text.Element.ALIGN_MIDDLE); + } + else if(Objects.equals(ht,1)) + { + tableCell.setVerticalAlignment(Element.ALIGN_TOP); + } + else if(Objects.equals(ht,2)) + { + tableCell.setVerticalAlignment(Element.ALIGN_BOTTOM); + } + } + Phrase phrase = tableCell.getPhrase(); + tableCell.setPhrase(new Paragraph(phrase.getContent(), font)); + //处理字体 + tableCell.setBorderColor(BaseColor.BLACK); + + } + + public static java.awt.Color parseRGB(String rgb) { + try { + String[] components = rgb.substring(rgb.indexOf("(") + 1, rgb.indexOf(")")).split(","); + int red = Integer.parseInt(components[0].trim()); + int green = Integer.parseInt(components[1].trim()); + int blue = Integer.parseInt(components[2].trim()); + + return new java.awt.Color(red, green, blue); + } catch (Exception e) { + e.printStackTrace(); + return null; // 解析失败,返回null + } + } + + private String getStringValue(Cell cell) { + if (cell == null) { + return ""; + } else { + return cell.toString(); + } + } + /** + * 解析报表数据,动态插入列表数据和对象数据 + */ + private String analysisReportData(ReportExcelDto reportExcelDto) { + + String jsonStr = reportExcelDto.getJsonStr(); + String setParam = reportExcelDto.getSetParam(); + List dbObjectList = (List) JSON.parse(jsonStr); + + if (dbObjectList != null && !dbObjectList.isEmpty()) { + //数据集数据缓存 + Map setMap = new HashMap<>(); + for (int x = 0; x < dbObjectList.size(); x++) { + analysisSheetCellData(dbObjectList.get(x), setParam, setMap); + } + } + //fastjson $ref 循环引用 + return JSONObject.toJSONString(dbObjectList, SerializerFeature.DisableCircularReferenceDetect); + } + + /** + * 解析单sheet data + * + * @param dbObject + */ + private void analysisSheet(JSONObject dbObject, String setParma) { + //data是一个二维数组 + if (dbObject.containsKey("data") && null != dbObject.get("data")) { + List data = (List) dbObject.get("data"); + + + //行 + for (int r = 0; r < data.size(); r++) { + JSONArray jsonArray = data.get(r); + //列 + for (int c = 0; c < jsonArray.size(); c++) { + //单元格 + JSONObject cell = jsonArray.getJSONObject(c); + if (null != cell && cell.containsKey("v") && StringUtils.isNotBlank(cell.getString("v"))) { + String v = cell.getString("v"); + DataSetDto dataSet = getDataSet(v, setParma); + if (null != dataSet) { + OriginalDataDto originalDataDto = dataSetService.getData(dataSet); + if (null != originalDataDto.getData()) { + if (originalDataDto.getData().size() == 1) { + //对象 + JSONObject jsonObject = originalDataDto.getData().get(0); + String fieldLabel = jsonObject.getString(dataSet.getFieldLabel()); + + String replace = v.replace("#{".concat(dataSet.getSetCode()).concat(".").concat(dataSet.getFieldLabel()).concat("}"), fieldLabel); + dbObject.getJSONArray("data").getJSONArray(r).getJSONObject(c).put("v", replace); + dbObject.getJSONArray("data").getJSONArray(r).getJSONObject(c).put("m", replace); + + } else { + //集合 + JSONObject jsonObject = originalDataDto.getData().get(0); + String fieldLabel = jsonObject.getString(dataSet.getFieldLabel()); + + String replace = v.replace("#{".concat(dataSet.getSetCode()).concat(".").concat(dataSet.getFieldLabel()).concat("}"), fieldLabel); + dbObject.getJSONArray("data").getJSONArray(r).getJSONObject(c).put("v", replace); + dbObject.getJSONArray("data").getJSONArray(r).getJSONObject(c).put("m", replace); + } + } + + } + } + + + + } + } + + + System.out.println("aaaa"); + + + } + + + } + + /** + * 解析单sheet celldata + * + * @param dbObject + */ + private void analysisSheetCellData(JSONObject dbObject, String setParam, Map setMap) { + //清空data值 + dbObject.remove("data"); + //celldata是一个一维数组 + if (dbObject.containsKey("celldata") && null != dbObject.get("celldata")) { + List celldata = new ArrayList<>(); + celldata.addAll((List) dbObject.get("celldata")); + + //整理celldata数据,转换为map格式,方便后续使用单元格位置获取对应的cell对象 + Map cellDataMap = cellDataList2Map(celldata); + //清除原有的数据 + dbObject.getJSONArray("celldata").clear(); + //获取配置项中的合并属性 + JSONObject merge = dbObject.getJSONObject("config").getJSONObject("merge"); + if(merge != null) { + merge.clear(); + } + //定义存储每一列动态扩展的行数 + Map colAddCntMap = new HashMap<>(); + // 遍历已存在的单元格,查看是否存在动态参数 + for (int i = 0; i < celldata.size(); i++) { + //单元格对象 + JSONObject cellObj = celldata.get(i); + //fastjson深拷贝问题 + String cellStr = cellObj.toJSONString(); + analysisCellData(cellObj,setParam,colAddCntMap,cellStr,merge, dbObject,cellDataMap, setMap); + } + } + } + + /** + * 开始解析并渲染 cellData + * @param cellObject + */ + public void analysisCellData(JSONObject cellObject,String setParam,Map colAddCntMap,String cellStr, + JSONObject merge,JSONObject dbObject,Map cellDataMap, Map setMap){ + //获取行号 + Integer cellR = cellObject.getInteger("r"); + //获取列数 + Integer cellC = cellObject.getInteger("c"); + //获取此行已经动态增加的行数,默认0行 + int cnt = colAddCntMap.get(cellC) == null ? 0 : colAddCntMap.get(cellC); + //获取单元格类型 + CellType cellType = getCellType(cellObject); + switch (cellType){ + case BLACK: + //空数据单元格不处理 + break; + case DYNAMIC_MERGE: + case DYNAMIC: + //处理动态单元格 + String v = cellObject.getJSONObject("v").getString("v"); + DataSetDto dataSet = getDataSet(v, setParam); + handleDynamicCellObject(dataSet,v,cellStr,cnt,cellR,cellC,merge,dbObject,colAddCntMap, setMap); + break; + default: + //处理静态单元格 + handleStaticCellObject(cellStr,dbObject,cnt,cellR,cellC,cellDataMap,setParam,merge,colAddCntMap,cellType, setMap); + break; + } + } + + /** + * 处理动态数据单元格自动扩展 + * @param dataSet + * @param v + * @param cellStr + * @param cnt + * @param r + * @param c + * @param merge + * @param dbObject + * @param colAddCntMap + */ + public void handleDynamicCellObject(DataSetDto dataSet,String v,String cellStr,int cnt,int r,int c, + JSONObject merge,JSONObject dbObject,Map colAddCntMap, Map setMap){ + //获取动态数据 + OriginalDataDto originalDataDto; + if (dataSet != null && setMap.containsKey(dataSet.getSetCode())) { + originalDataDto = setMap.get(dataSet.getSetCode()); + }else { + originalDataDto = dataSetService.getData(dataSet); + setMap.put(dataSet.getSetCode(), originalDataDto); + } + List cellDynamicData = originalDataDto.getData(); + + if(cellDynamicData != null){ + //循环数据赋值 + for (int j = 0; j < cellDynamicData.size(); j++) { + //新增的行数据 + JSONObject addCell = cellDynamicData.get(j); + //字段 + String fieldLabel = addCell.getString(dataSet.getFieldLabel()); + if (StringUtils.isBlank(fieldLabel)) { + fieldLabel = StringUtils.EMPTY; + } + String replace = v.replace("#{".concat(dataSet.getSetCode()).concat(".").concat(dataSet.getFieldLabel()).concat("}"), fieldLabel); + //转字符串,解决深拷贝问题 + JSONObject addCellData = JSONObject.parseObject(cellStr); + + addCellData.put("r", cnt + r + j); //行数增加 + addCellData.put("c", c); + addCellData.getJSONObject("v").put("v", replace); + addCellData.getJSONObject("v").put("m", replace); + JSONObject cellMc = addCellData.getJSONObject("v").getJSONObject("mc"); + //判断是否是合并单元格 + if(null != cellMc){ + //处理合并单元格 + Integer rs = cellMc.getInteger("rs"); + cellMc.put("r", cnt + r + rs*j); //行数增加 + cellMc.put("c", c); + addCellData.put("r", cnt + r + rs*j); + //合并单元格需要处理config.merge + merge.put(cellMc.getString("r")+"_"+cellMc.getString("c"),cellMc); + //处理单元格扩展之后此列扩展的总行数 + colAddCntMap.put(c,cnt + rs * cellDynamicData.size() - 1); + }else{ + //处理单元格扩展之后此列扩展的总行数 + colAddCntMap.put(c,cnt + cellDynamicData.size() - 1); + } + dbObject.getJSONArray("celldata").add(addCellData); + } + } + } + + /** + * 处理静态单元格数据 + * @param cellStr + * @param dbObject + * @param cnt + * @param r + * @param c + * @param cellDataMap + * @param setParam + * @param merge + * @param colAddCntMap + * @param cellType + */ + public void handleStaticCellObject(String cellStr,JSONObject dbObject,int cnt,int r,int c, + Map cellDataMap,String setParam, + JSONObject merge,Map colAddCntMap,CellType cellType,Map setMap){ + //转字符串,解决深拷贝问题 + JSONObject addCellData = JSONObject.parseObject(cellStr); + int rows = 0; + switch(cellType){ + case STATIC: + case STATIC_MERGE: + //静态不扩展单元格只需要初始化位置就可以 + initCellPosition(addCellData,cnt,merge); + break; + case STATIC_AUTO: + //获取静态单元格右侧动态单元格的总行数 + rows = getRightDynamicCellRows(addCellData,cellDataMap,setParam,rows,cellType, setMap); + initCellPosition(addCellData,cnt,merge); + if(rows > 1){ + //需要把这个静态扩展单元格 改变为 静态合并扩展单元格,就是增加合并属性 mc 以及merge配置 + JSONObject mc = new JSONObject(); + mc.put("rs",rows); + mc.put("cs",1); + mc.put("r",addCellData.getIntValue("r")); + mc.put("c",addCellData.getIntValue("c")); + addCellData.getJSONObject("v").put("mc",mc); + //合并单元格需要处理config.merge + merge.put((mc.getInteger("r")) + "_" + mc.getString("c"),mc); + //处理单元格扩展之后此列扩展的总行数 + colAddCntMap.put(c,cnt + rows - 1); + } + break; + case STATIC_MERGE_AUTO: + //获取静态单元格右侧动态单元格的总行数 + rows = getRightDynamicCellRows(addCellData, cellDataMap, setParam, rows, cellType, setMap); + initCellPosition(addCellData,cnt,merge); + if(rows > 0){ + //需要修改单元格mc中的rs + JSONObject cellMc = addCellData.getJSONObject("v").getJSONObject("mc"); + int addCnt = cellMc.getInteger("rs"); + cellMc.put("rs",rows); + //合并单元格需要处理config.merge + merge.put((cellMc.getInteger("r")) + "_" + cellMc.getString("c"),cellMc); + //处理单元格扩展之后此列扩展的总行数 + colAddCntMap.put(c,cnt + rows - addCnt); + } + break; + } + dbObject.getJSONArray("celldata").add(addCellData); + } + + /** + * 初始化单元格位置,主要是这一列已经动态增加的行数 + * @param addCellData + * @param cnt + * @param merge + */ + public void initCellPosition(JSONObject addCellData,int cnt,JSONObject merge){ + addCellData.put("r", cnt + addCellData.getInteger("r"));//行数增加 + //是否是合并单元格 + JSONObject mc = addCellData.getJSONObject("v").getJSONObject("mc"); + if(mc != null){ + mc.put("r",addCellData.getInteger("r")); + initCellMerge(merge,mc); + } + } + + /** + * 初始化单元格合并属性的行数 + * @param merge + * @param mc + */ + public void initCellMerge(JSONObject merge,JSONObject mc){ + merge.put((mc.getInteger("r"))+"_"+mc.getString("c"),mc); + } + + /** + * 获取合并单元格右侧的动态扩展行数,用来设置当前单元格的实际 + * @param addCellData + * @param cellDataMap + * @param setParam + * @param sumRows + * @param cellType + * @return + */ + public int getRightDynamicCellRows(JSONObject addCellData,Map cellDataMap,String setParam,int sumRows,CellType cellType,Map setMap){ + //1、获取此单元格右侧关联的所有单元格 + List rightCellList = getRightDynamicCell(addCellData,cellDataMap,cellType); + //2、循环获取每个单元格的扩展行数 + for (JSONObject rightCell : rightCellList) { + //首先判断这个单元格是否也是【静态扩展单元格】 + CellType rightCellType = getCellType(rightCell); + switch (rightCellType){ + case STATIC_AUTO: + case STATIC_MERGE_AUTO: + //递归查找 + sumRows = getRightDynamicCellRows(rightCell,cellDataMap,setParam,sumRows,rightCellType, setMap); + break; + case BLACK: + case STATIC: + sumRows++; + break; + case STATIC_MERGE: + sumRows += rightCell.getJSONObject("v").getJSONObject("mc").getInteger("rs"); + break; + default: + List cellDynamicData = getDynamicDataList(rightCell.getJSONObject("v").getString("v"),setParam, setMap); + if(cellDynamicData != null && cellDynamicData.size() > 1){ + int size = cellDynamicData.size(); + sumRows += size; + }else{ + sumRows++; + } + break; + } + } + return sumRows; + } + + /** + * 获取扩展单元格右侧相邻的所有单元格实体 + * @param addCellData + * @param cellDataMap + * @param cellType + * @return + */ + public List getRightDynamicCell(JSONObject addCellData,Map cellDataMap,CellType cellType){ + //静态数据合并单元格需要根据右侧的单元格进行自动向下扩展 + //1、先获取右侧一列的关联的单元格,根据自身的位置,以及自己合并的合并的信息推断 + //如果自己位置是 2,5,并且本身合并 行数2,列数3,则需要推断出两个单元格的位置 + //分别是2,8 和 3,8 + Integer cellR = addCellData.getInteger("r"); + Integer cellC = addCellData.getInteger("c"); + Integer cellRs = 0; + Integer cellCs = 0; + switch (cellType){ + case STATIC_AUTO: + cellRs = 1; + cellCs = 1; + break; + case STATIC_MERGE_AUTO: + cellRs = addCellData.getJSONObject("v").getJSONObject("mc").getInteger("rs"); + cellCs = addCellData.getJSONObject("v").getJSONObject("mc").getInteger("cs"); + break; + } + List rightCells = new ArrayList<>(); + for(int nums = 0;nums < cellRs;nums++){ + int r = cellR + nums; + int c = cellC + cellCs; + String key = r + "," + c; + if(cellDataMap.containsKey(key)){ + JSONObject cellData = cellDataMap.get(r + "," + c); + rightCells.add(cellData); + } + } + return rightCells; + } + + /** + * 判断单元格类型 + * @param cellObject + * @return + */ + public CellType getCellType(JSONObject cellObject){ + JSONObject cellV1 = cellObject.getJSONObject("v"); + if (null != cellV1 && cellV1.containsKey("v") && StringUtils.isNotBlank(cellV1.getString("v"))) { + String cellV2 = cellObject.getJSONObject("v").getString("v"); + String auto = cellObject.getJSONObject("v").getString("auto"); + JSONObject mc = cellObject.getJSONObject("v").getJSONObject("mc"); + if(cellV2.contains("#{") && cellV2.contains("}") ){ + //动态单元格 + if(mc != null){ + return CellType.DYNAMIC_MERGE; + }else{ + return CellType.DYNAMIC; + } + }else{ + //静态单元格 + if(mc != null && "1".equals(auto)){ + return CellType.STATIC_MERGE_AUTO; + }else { + if("1".equals(auto)){ + return CellType.STATIC_AUTO; + }else if(mc != null){ + return CellType.STATIC_MERGE; + }else{ + return CellType.STATIC; + } + } + } + }else{ + return CellType.BLACK; + } + } + + /** + * list转为map结构,方便使用行列号查找对应cell对象 + * @param cellDataList + * @return + */ + public Map cellDataList2Map(List cellDataList){ + Map cellDataMap = new HashMap<>(); + for (JSONObject cellData : cellDataList) { + String r = cellData.getString("r"); + String c = cellData.getString("c"); + cellDataMap.put(r + "," + c, cellData); + } + return cellDataMap; + } + + /** + * 解析 #{xxxx.xxxxx} 数据 + * @param v + * @return + */ + private DataSetDto getDataSet(String v, String setParam) { + + DataSetDto dto = new DataSetDto(); + if (v.contains("#{") && v.contains("}")) { + int start = v.indexOf("#{") + 2; + int end = v.indexOf("}"); + if (start < end) { + String substring = v.substring(start, end); + if (substring.contains(".")) { + String[] split = substring.split("\\."); + dto.setSetCode( split[0]); + dto.setFieldLabel(split[1]); + getContextData(setParam, dto); + return dto; + } + } + } + return null; + } + + /** + * 获取单元格对应的动态数据集 + * @param v + * @param setParam + * @return + */ + private List getDynamicDataList(String v, String setParam, Map setMap){ + if(StringUtils.isNotBlank(v)){ + DataSetDto dataSet = getDataSet(v,setParam); + if(dataSet != null){ + OriginalDataDto originalDataDto; + if (setMap.containsKey(dataSet.getSetCode())) { + originalDataDto = setMap.get(dataSet.getSetCode()); + }else { + originalDataDto = dataSetService.getData(dataSet); + setMap.put(dataSet.getSetCode(), originalDataDto); + } + return originalDataDto.getData(); + }else{ + return null; + } + }else{ + return null; + } + } + + /** + * 动态参数替换 + * @param setParam + * @param dto + */ + private void getContextData(String setParam, DataSetDto dto) { + if (StringUtils.isNotBlank(setParam)) { + JSONObject setParamJson = JSONObject.parseObject(setParam); + Map map = new HashMap<>(); + // 查询条件 + if (setParamJson.containsKey(dto.getSetCode())) { + JSONObject paramCondition = setParamJson.getJSONObject(dto.getSetCode()); + map.putAll(paramCondition); + } + dto.setContextData(map); + } + } + +} diff --git a/src/main/java/com/anjiplus/template/gaea/business/modules/reportexcel/util/CellType.java b/src/main/java/com/anjiplus/template/gaea/business/modules/reportexcel/util/CellType.java new file mode 100644 index 0000000..0a86c30 --- /dev/null +++ b/src/main/java/com/anjiplus/template/gaea/business/modules/reportexcel/util/CellType.java @@ -0,0 +1,39 @@ +package com.anjiplus.template.gaea.business.modules.reportexcel.util; + +/** + * 单元格类型 + */ +public enum CellType { + DYNAMIC_MERGE("DYNAMIC_MERGE","动态合并单元格"), + DYNAMIC("DYNAMIC","动态单元格"), + STATIC("STATIC","静态单元格"), + STATIC_AUTO("STATIC_AUTO","静态扩展单元格"), + STATIC_MERGE("STATIC_MERGE","静态合并单元格"), + STATIC_MERGE_AUTO("STATIC_MERGE_AUTO","静态合并扩展单元格"), + BLACK("BLACK","空白单元格"); + + private String code; + private String name; + + CellType(String code,String name) { + this.code = code; + this.name = name; + } + + public String getCode() { + return code; + } + + public String getName() { + return name; + } + + public void setCode(String code) { + this.code = code; + } + + public void setName(String name) { + this.name = name; + } +} + diff --git a/src/main/java/com/anjiplus/template/gaea/business/modules/reportexcel/util/ColorUtil.java b/src/main/java/com/anjiplus/template/gaea/business/modules/reportexcel/util/ColorUtil.java new file mode 100644 index 0000000..5e9037e --- /dev/null +++ b/src/main/java/com/anjiplus/template/gaea/business/modules/reportexcel/util/ColorUtil.java @@ -0,0 +1,134 @@ +package com.anjiplus.template.gaea.business.modules.reportexcel.util; + + +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.apache.poi.hssf.usermodel.HSSFPalette; +import org.apache.poi.hssf.usermodel.HSSFWorkbook; +import org.apache.poi.hssf.util.HSSFColor; +import org.apache.poi.ss.usermodel.Cell; +import org.apache.poi.ss.usermodel.CellStyle; +import org.apache.poi.ss.usermodel.Color; +import org.apache.poi.xssf.usermodel.XSSFColor; + + +/** + * 来自:https://github.com/mengshukeji/LuckysheetServer + * + * @author Administrator + */ +@Slf4j +public class ColorUtil { + + private static final String S = "0123456789ABCDEF"; + + public static Short getColorByStr(String colorStr) { + HSSFWorkbook workbook = new HSSFWorkbook(); + HSSFPalette palette = workbook.getCustomPalette(); + + if (colorStr.toLowerCase().startsWith("rgb")) { + colorStr = colorStr.toLowerCase().replace("rgb(", "").replace(")", ""); + String[] colors = colorStr.split(","); + if (colors.length == 3) { + try { + int red = Integer.parseInt(colors[0].trim(), 16); + int green = Integer.parseInt(colors[1].trim(), 16); + int blue = Integer.parseInt(colors[2].trim(), 16); + + HSSFColor hssfColor = palette.findSimilarColor(red, green, blue); + return hssfColor.getIndex(); + } catch (Exception ex) { + log.error(ex.toString()); + return null; + } + } + return null; + } + + if (colorStr.equals("#000")) { + colorStr = "#000000"; + } + if (colorStr != null && colorStr.length() >= 6) { + try { + if (colorStr.length() == 8) { + colorStr = colorStr.substring(2); + } + if (colorStr.length() == 7) { + colorStr = colorStr.substring(1); + } + String str2 = colorStr.substring(0, 2); + String str3 = colorStr.substring(2, 4); + String str4 = colorStr.substring(4, 6); + int red = Integer.parseInt(str2, 16); + int green = Integer.parseInt(str3, 16); + int blue = Integer.parseInt(str4, 16); + + HSSFColor hssfColor = palette.findSimilarColor(red, green, blue); + return hssfColor.getIndex(); + } catch (Exception ex) { + log.error(ex.toString()); + return null; + } + } + return null; + } + + /** + * RGB转换成十六进制 + * + * @param r + * @param g + * @param b + * @return + */ + public static String convertRGBToHex(short r, short g, short b) { + String hex = ""; + if (r >= 0 && r < 256 && g >= 0 && g < 256 && b >= 0 && b < 256) { + int x, y, z; + x = r % 16; + r = (short) ((r - x) / 16); + y = g % 16; + g = (short) ((g - y) / 16); + z = b % 16; + b = (short) ((b - z) / 16); + hex = "#" + S.charAt(r) + S.charAt(x) + S.charAt(g) + S.charAt(y) + S.charAt(b) + S.charAt(z); + } + return hex; + } + + /** + * @param cell 单元格 + * @return 转换RGB颜色值 + * @description tint转换RBG + * @author zhouhang + * @date 2021/4/26 + */ + public static String getFillColorHex(Cell cell) { + String fillColorString = null; + if (cell != null) { + CellStyle cellStyle = cell.getCellStyle(); + Color color = cellStyle.getFillForegroundColorColor(); + if (color instanceof XSSFColor) { + XSSFColor xssfColor = (XSSFColor) color; + byte[] argb = xssfColor.getARGB(); + fillColorString = convertRGBToHex((short) (argb[1] & 0xFF), (short) (argb[2] & 0xFF), (short) (argb[3] & 0xFF)); + // TODO: 2021/4/26 添加透明度 +// if (xssfColor.hasTint()) { +// fillColorString += " * " + xssfColor.getTint(); +// byte[] rgb = xssfColor.getRGBWithTint(); +// fillColorString += " = [" + (argb[0] & 0xFF) + ", " + (rgb[0] & 0xFF) + ", " + (rgb[1] & 0xFF) + ", " + (rgb[2] & 0xFF) + "]"; +// } + } else if (color instanceof HSSFColor) { + HSSFColor hssfColor = (HSSFColor) color; + short[] rgb = hssfColor.getTriplet(); + fillColorString = convertRGBToHex((short) (rgb[0] & 0xFF), (short) (rgb[1] & 0xFF), (short) (rgb[2] & 0xFF)); + //去除黑色背景 + if (StringUtils.equals("#000000", fillColorString)) { + return null; + } + } + } + return fillColorString; + } + +} diff --git a/src/main/java/com/anjiplus/template/gaea/business/modules/reportexcel/util/ConstantUtil.java b/src/main/java/com/anjiplus/template/gaea/business/modules/reportexcel/util/ConstantUtil.java new file mode 100644 index 0000000..29df40c --- /dev/null +++ b/src/main/java/com/anjiplus/template/gaea/business/modules/reportexcel/util/ConstantUtil.java @@ -0,0 +1,313 @@ +package com.anjiplus.template.gaea.business.modules.reportexcel.util; + + +import org.apache.poi.ss.usermodel.HorizontalAlignment; +import org.apache.poi.ss.usermodel.VerticalAlignment; + +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.*; + +/** + * 来自:https://github.com/mengshukeji/LuckysheetServer + * + * @author cr + */ +public class ConstantUtil { + /** + * 导出。字体转换 + */ + public static Map ff_IntegerToName = new HashMap(); + /** + * 导入。字体转换 + */ + public static Map ff_NameToInteger = new HashMap(); + + /** + * 导入 36种数字格式。注意官方文档的编号不是连续的,22后面直接是37,所以数组中间补14个空值 + */ + public static String[] number_type = null; + /** + * 导入 36种格式的定义字符串 + */ + public static String[] number_format = null; + /** + * 数据类型 + */ + public static Map number_format_map = new HashMap(); + + static { + //格式 + nf(); + //字体 + ff(); + } + + private static void nf() { + number_type = new String[]{ + "General", "Decimal", "Decimal", "Decimal", "Decimal", "Currency", "Currency", "Currency", "Currency", + "Percentage", "Percentage", "Scientific", "Fraction", "Fraction", "Date", "Date", "Date", "Date", + "Time", "Time", "Time", "Time", "Time", + "", "", "", "", "", "", "", "", "", "", "", "", "", "", + "Accounting", "Accounting", "Accounting", "Accounting", "Accounting", + "Currency", "Accounting", "Currency", "Time", "Time", "Time", "Scientific", "Text" + }; + + number_format = new String[]{ + "General", "0", "0.00", "#,##0", "#,##0.00", "$#,##0;($#,##0)", "$#,##0;[Red]($#,##0)", "$#,##0.00;($#,##0.00)", "$#,##0.00;[Red]($#,##0.00)", + "0%", "0.00%", "0.00E+00", "# ?/?", "# ??/??", "m/d/yyyy", "d-mmm-yy", "d-mmm", "mmm-yy", + "h:mm AM/PM", "h:mm:ss AM/PM", "h:mm", "h:mm:ss", "m/d/yyyy h:mm", + "", "", "", "", "", "", "", "", "", "", "", "", "", "", + "#,##0;(#,##0)", "#,##0;[Red](#,##0)", "#,##0.00;(#,##0.00)", "#,##0.00;[Red](#,##0.00)", "_ * #,##0_ ;_ * (#,##0)_ ;_ * \"-\"_ ;_ @_", + "_ $* #,##0_ ;_ $* (#,##0)_ ;_ $* \"-\"_ ;_ @_", "_ * #,##0.00_ ;_ * (#,##0.00)_ ;_ * \"-\"??_ ;_ @_", "_ $* #,##0.00_ ;_ $* (#,##0.00)_ ;_ $* \"-\"??_ ;_ @_", "mm:ss", "[h]:mm:ss", "mm:ss.0", "##0.0E+00", "@" + }; + for (int x = 0; x < number_format.length; x++) { + if (number_format[x].length() > 0) { + number_format_map.put(number_format[x].toLowerCase(), x); + } + } + } + + private static void ff() { + //0 微软雅黑、1 宋体(Song)、2 黑体(ST Heiti)、3 楷体(ST Kaiti)、 4仿宋(ST FangSong)、 5 新宋体(ST Song)、 + // 6 华文新魏、 7华文行楷、 8 华文隶书、 9 Arial、 10 Times New Roman 、11 Tahoma 、12 Verdana + ff_IntegerToName.put(0, "微软雅黑"); + ff_IntegerToName.put(1, "宋体"); + ff_IntegerToName.put(2, "黑体"); + ff_IntegerToName.put(3, "楷体"); + ff_IntegerToName.put(4, "仿宋"); + ff_IntegerToName.put(5, "新宋体"); + ff_IntegerToName.put(6, "华文新魏"); + ff_IntegerToName.put(7, "华文行楷"); + ff_IntegerToName.put(8, "华文隶书"); + ff_IntegerToName.put(9, "Arial"); + ff_IntegerToName.put(10, "Times New Roman"); + ff_IntegerToName.put(11, "Tahoma"); + ff_IntegerToName.put(12, "Verdana"); + + //0 微软雅黑、1 宋体(Song)、2 黑体(ST Heiti)、3 楷体(ST Kaiti)、 4仿宋(ST FangSong)、 5 新宋体(ST Song)、 + // 6 华文新魏、 7华文行楷、 8 华文隶书、 9 Arial、 10 Times New Roman 、11 Tahoma 、12 Verdana + ff_NameToInteger.put("微软雅黑", 0); + ff_NameToInteger.put("宋体", 1); + ff_NameToInteger.put("Song", 1); + ff_NameToInteger.put("黑体", 2); + ff_NameToInteger.put("ST Heiti", 2); + ff_NameToInteger.put("楷体", 3); + ff_NameToInteger.put("ST Kaiti", 3); + ff_NameToInteger.put("仿宋", 4); + ff_NameToInteger.put("ST FangSong", 4); + ff_NameToInteger.put("新宋体", 5); + ff_NameToInteger.put("ST Song", 5); + ff_NameToInteger.put("华文新魏", 6); + ff_NameToInteger.put("华文行楷", 7); + ff_NameToInteger.put("华文隶书", 8); + ff_NameToInteger.put("Arial", 9); + ff_NameToInteger.put("Times New Roman", 10); + ff_NameToInteger.put("Tahoma", 11); + ff_NameToInteger.put("Verdana", 12); + } + + private static void borderType() { + //"border-left" | "border-right" | "border-top" | "border-bottom" | "border-all" + // | "border-outside" | "border-inside" | "border-horizontal" | "border-vertical" | "border-none" + ff_IntegerToName.put(0, "微软雅黑"); + ff_IntegerToName.put(1, "宋体"); + ff_IntegerToName.put(2, "黑体"); + ff_IntegerToName.put(3, "楷体"); + ff_IntegerToName.put(4, "仿宋"); + ff_IntegerToName.put(5, "新宋体"); + ff_IntegerToName.put(6, "华文新魏"); + ff_IntegerToName.put(7, "华文行楷"); + ff_IntegerToName.put(8, "华文隶书"); + ff_IntegerToName.put(9, "Arial"); + ff_IntegerToName.put(10, "Times New Roman"); + ff_IntegerToName.put(11, "Tahoma"); + ff_IntegerToName.put(12, "Verdana"); + + //0 微软雅黑、1 宋体(Song)、2 黑体(ST Heiti)、3 楷体(ST Kaiti)、 4仿宋(ST FangSong)、 5 新宋体(ST Song)、 + // 6 华文新魏、 7华文行楷、 8 华文隶书、 9 Arial、 10 Times New Roman 、11 Tahoma 、12 Verdana + ff_NameToInteger.put("微软雅黑", 0); + ff_NameToInteger.put("宋体", 1); + ff_NameToInteger.put("Song", 1); + ff_NameToInteger.put("黑体", 2); + ff_NameToInteger.put("ST Heiti", 2); + ff_NameToInteger.put("楷体", 3); + ff_NameToInteger.put("ST Kaiti", 3); + ff_NameToInteger.put("仿宋", 4); + ff_NameToInteger.put("ST FangSong", 4); + ff_NameToInteger.put("新宋体", 5); + ff_NameToInteger.put("ST Song", 5); + ff_NameToInteger.put("华文新魏", 6); + ff_NameToInteger.put("华文行楷", 7); + ff_NameToInteger.put("华文隶书", 8); + ff_NameToInteger.put("Arial", 9); + ff_NameToInteger.put("Times New Roman", 10); + ff_NameToInteger.put("Tahoma", 11); + ff_NameToInteger.put("Verdana", 12); + } + + + /** + * 按自定义格式 + * + * @param fa + * @return + */ + public static Integer getNumberFormatMap(String fa) { + if (number_format_map.containsKey(fa.toLowerCase())) { + return number_format_map.get(fa.toLowerCase()); + } + return -1; + } + + /** + * 获取poi表格垂直对齐 0 中间、1 上、2下 + * + * @param i + * @return + */ + public static VerticalAlignment getVerticalType(int i) { + if (0 == i) { + return VerticalAlignment.CENTER; + } else if (1 == i) { + return VerticalAlignment.TOP; + } else if (2 == i) { + return VerticalAlignment.BOTTOM; + } + //默认居中 + return VerticalAlignment.CENTER; + } + + /** + * 获取poi表格水平对齐 0 居中、1 左、2右 + * + * @param i + * @return + */ + public static HorizontalAlignment getHorizontaltype(int i) { + if (2 == i) { + return HorizontalAlignment.RIGHT; + } else if (1 == i) { + return HorizontalAlignment.LEFT; + } else if (0 == i) { + return HorizontalAlignment.CENTER; + } + //默认右 + return HorizontalAlignment.RIGHT; + } + + /** + * 文字旋转 + * 文字旋转角度(0=0,1=45,2=-45,3=竖排文字,4=90,5=-90) + * + * @param i + * @return + */ + public static short getRotation(int i) { + short t = 0; + switch (i) { + case 1: + t = 45; + break; + case 2: + t = -45; + break; + case 3: + t = 255; + break; + case 4: + t = 90; + break; + case 5: + t = -90; + break; + + default: + t = 0; + } + return t; + } + + + private static SimpleDateFormat df_DateTime = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); + + public static Date stringToDateTime(String date) { + if (date == null || date.length() == 0) { + return null; + } + try { + return df_DateTime.parse(date); + } catch (ParseException e) { + return null; + } + } + + private static SimpleDateFormat df_Date = new SimpleDateFormat("yyyy-MM-dd"); + + public static Date stringToDate(String date) { + if (date == null || date.length() == 0) { + return null; + } + try { + return df_Date.parse(date); + } catch (ParseException e) { + return null; + } + } + + public static Date toDate(String numberString) { + try { + Double _d = Double.parseDouble(numberString); + String _s = toDate(_d, "yyyy-MM-dd HH:mm:ss"); + if (numberString.indexOf(".") > -1) { + return stringToDate(_s); + } else { + return stringToDateTime(_s); + } + + } catch (Exception ex) { + System.out.println(ex.toString() + " " + numberString); + } + return null; + } + + private static final int SECONDS_PER_MINUTE = 60; + private static final int MINUTES_PER_HOUR = 60; + private static final int HOURS_PER_DAY = 24; + private static final int SECONDS_PER_DAY = (HOURS_PER_DAY * MINUTES_PER_HOUR * SECONDS_PER_MINUTE); + /** + * 一天的毫秒数 + **/ + private static final long DAY_MILLISECONDS = SECONDS_PER_DAY * 1000L; + + /** + * 转换方法 + * + * @parma numberString 要转换的浮点数 + * @parma format 要获得的格式 例如"hh:mm:ss" + **/ + public static String toDate(double numberString, String format) { + SimpleDateFormat sdFormat = new SimpleDateFormat(format); + int wholeDays = (int) Math.floor(numberString); + int millisecondsInday = (int) ((numberString - wholeDays) * DAY_MILLISECONDS + 0.5); + Calendar calendar = new GregorianCalendar(); + setCalendar(calendar, wholeDays, millisecondsInday, false); + return sdFormat.format(calendar.getTime()); + } + + private static void setCalendar(Calendar calendar, int wholeDays, + int millisecondsInDay, boolean use1904windowing) { + int startYear = 1900; + int dayAdjust = -1; // Excel thinks 2/29/1900 is a valid date, which it isn't + if (use1904windowing) { + startYear = 1904; + dayAdjust = 1; // 1904 date windowing uses 1/2/1904 as the first day + } else if (wholeDays < 61) { + // Date is prior to 3/1/1900, so adjust because Excel thinks 2/29/1900 exists + // If Excel date == 2/29/1900, will become 3/1/1900 in Java representation + dayAdjust = 0; + } + calendar.set(startYear, 0, wholeDays + dayAdjust, 0, 0, 0); + calendar.set(GregorianCalendar.MILLISECOND, millisecondsInDay); + } +} diff --git a/src/main/java/com/anjiplus/template/gaea/business/modules/reportexcel/util/MSExcelUtil.java b/src/main/java/com/anjiplus/template/gaea/business/modules/reportexcel/util/MSExcelUtil.java new file mode 100644 index 0000000..1e1d167 --- /dev/null +++ b/src/main/java/com/anjiplus/template/gaea/business/modules/reportexcel/util/MSExcelUtil.java @@ -0,0 +1,28 @@ +package com.anjiplus.template.gaea.business.modules.reportexcel.util; + +public class MSExcelUtil { + public static final short EXCEL_COLUMN_WIDTH_FACTOR = 256; + public static final short EXCEL_ROW_HEIGHT_FACTOR = 20; + public static final int UNIT_OFFSET_LENGTH = 7; + public static final int[] UNIT_OFFSET_MAP = new int[]{0, 36, 73, 109, 146, 182, 219}; + + public static short pixel2WidthUnits(int pxs) { + short widthUnits = (short) (EXCEL_COLUMN_WIDTH_FACTOR * (pxs / UNIT_OFFSET_LENGTH)); + widthUnits += UNIT_OFFSET_MAP[(pxs % UNIT_OFFSET_LENGTH)]; + return widthUnits; + } + + public static int widthUnits2Pixel(short widthUnits) { + int pixels = (widthUnits / EXCEL_COLUMN_WIDTH_FACTOR) * UNIT_OFFSET_LENGTH; + int offsetWidthUnits = widthUnits % EXCEL_COLUMN_WIDTH_FACTOR; + pixels += Math.floor((float) offsetWidthUnits / ((float) EXCEL_COLUMN_WIDTH_FACTOR / UNIT_OFFSET_LENGTH)); + return pixels; + } + + public static int heightUnits2Pixel(short heightUnits) { + int pixels = (heightUnits / EXCEL_ROW_HEIGHT_FACTOR); + int offsetWidthUnits = heightUnits % EXCEL_ROW_HEIGHT_FACTOR; + pixels += Math.floor((float) offsetWidthUnits / ((float) EXCEL_ROW_HEIGHT_FACTOR / UNIT_OFFSET_LENGTH)); + return pixels; + } +} diff --git a/src/main/java/com/anjiplus/template/gaea/business/modules/reportexcel/util/XlsSheetUtil.java b/src/main/java/com/anjiplus/template/gaea/business/modules/reportexcel/util/XlsSheetUtil.java new file mode 100644 index 0000000..a436002 --- /dev/null +++ b/src/main/java/com/anjiplus/template/gaea/business/modules/reportexcel/util/XlsSheetUtil.java @@ -0,0 +1,860 @@ +package com.anjiplus.template.gaea.business.modules.reportexcel.util; + +import com.alibaba.fastjson.JSONArray; +import com.alibaba.fastjson.JSONObject; +import lombok.extern.slf4j.Slf4j; +import org.apache.poi.ss.usermodel.*; +import org.apache.poi.ss.util.CellRangeAddress; + +import java.util.*; + +/** + * 来自:https://github.com/mengshukeji/LuckysheetServer + * sheet操作 + * + * @author Administrator + */ +@Slf4j +public class XlsSheetUtil { + /** + * 导出sheet + * + * @param wb + * @param sheetNum + * @param dbObject + */ + public static void exportSheet(Workbook wb, int sheetNum, JSONObject dbObject) { + Sheet sheet = wb.createSheet(); + + //设置sheet位置,名称 + if (dbObject.containsKey("name") && dbObject.get("name") != null) { + wb.setSheetName(sheetNum, dbObject.get("name").toString()); + } else { + wb.setSheetName(sheetNum, "sheet" + sheetNum); + } + //是否隐藏 + if (dbObject.containsKey("hide") && dbObject.get("hide").toString().equals("1")) { + wb.setSheetHidden(sheetNum, true); + } + //是否当前选中页 + if (dbObject.containsKey("status") && dbObject.get("status").toString().equals("1")) { + sheet.setSelected(true); + } + + + //循环数据 + if (dbObject.containsKey("celldata") && dbObject.get("celldata") != null) { + //取到所有单元格集合 + List cells_json = (List) dbObject.get("celldata"); + Map> cellMap = cellGroup(cells_json); + //循环每一行 + for (Integer r : cellMap.keySet()) { + Row row = sheet.createRow(r); + //循环每一列 + for (JSONObject col : cellMap.get(r)) { + createCell(wb, sheet, row, col); + } + } + } + + if (dbObject.containsKey("config") && dbObject.getJSONObject("config").containsKey("borderInfo")) { + JSONArray borderInfo = dbObject.getJSONObject("config").getJSONArray("borderInfo"); + setCellBoard(wb, borderInfo, sheet); + } + + + setColumAndRow(dbObject, sheet); + + } + + /** + * 每一个单元格 + * + * @param row + * @param dbObject + */ + private static void createCell(Workbook wb, Sheet sheet, Row row, JSONObject dbObject) { + if (dbObject.containsKey("c")) { + Integer c = getStrToInt(dbObject.get("c")); + if (c != null) { + Cell cell = row.createCell(c); + //取单元格中的v_json + if (dbObject.containsKey("v")) { + //获取v对象 + Object obj = dbObject.get("v"); + if (obj == null) { + //没有内容 + return; + } + //如果v对象直接是字符串 + if (obj instanceof String) { + if (((String) obj).length() > 0) { + cell.setCellValue(obj.toString()); + } + return; + } + + //转换v为对象(v是一个对象) + JSONObject v_json = (JSONObject) obj; + //样式 + CellStyle style = wb.createCellStyle(); + cell.setCellStyle(style); + + + //合并单元格 + //参数1:起始行 参数2:终止行 参数3:起始列 参数4:终止列 + //CellRangeAddress region1 = new CellRangeAddress(rowNumber, rowNumber, (short) 0, (short) 11); + + //mc 合并单元格 + if (v_json.containsKey("mc")) { + //是合并的单元格 + JSONObject mc = v_json.getJSONObject("mc"); + if (mc.containsKey("rs") && mc.containsKey("cs")) { + //合并的第一个单元格 + if (mc.containsKey("r") && mc.containsKey("c")) { + Integer _rs = getIntByDBObject(mc, "rs") - 1; + Integer _cs = getIntByDBObject(mc, "cs") - 1; + Integer _r = getIntByDBObject(mc, "r"); + Integer _c = getIntByDBObject(mc, "c"); + + CellRangeAddress region = new CellRangeAddress(_r.shortValue(), (_r.shortValue() + _rs.shortValue()), _c.shortValue(), (_c.shortValue() + _cs.shortValue())); + sheet.addMergedRegion(region); + } + } else { + //不是合并的第一个单元格 + return; + } + } + + + //取v值 (在数据类型中处理) + //ct 单元格值格式 (fa,t) + setFormatByCt(wb, cell, style, v_json); + + //font设置 + setCellStyleFont(wb, style, v_json); + + //bg 背景颜色 + if (v_json.containsKey("bg")) { + String _v = getByDBObject(v_json, "bg"); + Short _color = ColorUtil.getColorByStr(_v); + if (_color != null) { + style.setFillForegroundColor(_color); + style.setFillPattern(FillPatternType.SOLID_FOREGROUND); + } + } + + //vt 垂直对齐 垂直对齐方式(0=居中,1=上,2=下) + if (v_json.containsKey("vt")) { + Integer _v = getIntByDBObject(v_json, "vt"); + if (_v != null && _v >= 0 && _v <= 2) { + style.setVerticalAlignment(ConstantUtil.getVerticalType(_v)); + } + } else { + //默认设置居中 + style.setVerticalAlignment(ConstantUtil.getVerticalType(0)); + } + + //ht 水平对齐 水平对齐方式(0=居中,1=左对齐,2=右对齐) + if (v_json.containsKey("ht")) { + Integer _v = getIntByDBObject(v_json, "ht"); + if (_v != null && _v >= 0 && _v <= 2) { + style.setAlignment(ConstantUtil.getHorizontaltype(_v)); + } + } else { + //默认设置左对齐 + style.setAlignment(ConstantUtil.getHorizontaltype(1)); + } + + //tr 文字旋转 文字旋转角度(0=0,1=45,2=-45,3=竖排文字,4=90,5=-90) + if (v_json.containsKey("tr")) { + Integer _v = getIntByDBObject(v_json, "tr"); + if (_v != null) { + style.setRotation(ConstantUtil.getRotation(_v)); + } + } + + //tb 文本换行 0 截断、1溢出、2 自动换行 + // 2:setTextWrapped 0和1:IsTextWrapped = true + if (v_json.containsKey("tb")) { + Integer _v = getIntByDBObject(v_json, "tb"); + if (_v != null) { + if (_v >= 0 && _v <= 1) { + style.setWrapText(false); + } else { + style.setWrapText(true); + } + } + } + + //f 公式 + if (v_json.containsKey("f")) { + String _v = getByDBObject(v_json, "f"); + if (_v.length() > 0) { + try { + if (_v.startsWith("=")) { + cell.setCellFormula(_v.substring(1)); + } else { + cell.setCellFormula(_v); + } + } catch (Exception ex) { + log.error("公式 {};Error:{}", _v, ex.toString()); + } + } + } + + + } + + } + } + } + + /** + * 设置边框 + * + * @param borderInfo + * @param sheet + */ + private static void setCellBoard(Workbook wb, JSONArray borderInfo, Sheet sheet) { + + + //一定要通过 cell.getCellStyle() 不然的话之前设置的样式会丢失 + //设置边框 + for (int i = 0; i < borderInfo.size(); i++) { + JSONObject borderInfoObject = (JSONObject) borderInfo.get(i); + if (borderInfoObject.get("rangeType").equals("cell")) {//单个单元格 + JSONObject borderValueObject = borderInfoObject.getJSONObject("value"); + + JSONObject l = borderValueObject.getJSONObject("l"); + JSONObject r = borderValueObject.getJSONObject("r"); + JSONObject t = borderValueObject.getJSONObject("t"); + JSONObject b = borderValueObject.getJSONObject("b"); + + + int row_ = borderValueObject.getInteger("row_index"); + int col_ = borderValueObject.getInteger("col_index"); + + Row row = sheet.getRow(row_); + if (null == row) { + row = sheet.createRow(row_); + } + Cell cell = row.getCell(col_); + CellStyle style; + if (null == cell) { + style = wb.createCellStyle(); + cell = row.createCell(col_); + cell.setCellStyle(style); + } else { + style = cell.getCellStyle(); + } + + + if (l != null) { + style.setBorderLeft(BorderStyle.valueOf(l.getShort("style"))); //左边框 + Short color = ColorUtil.getColorByStr(l.getString("color")); + if (null != color) { + style.setLeftBorderColor(color);//左边框颜色 + } + + } + if (r != null) { + style.setBorderRight(BorderStyle.valueOf(r.getShort("style"))); //右边框 + Short color = ColorUtil.getColorByStr(r.getString("color")); + if (null != color) { + style.setRightBorderColor(color);//右边框颜色 + } + + } + if (t != null) { + style.setBorderTop(BorderStyle.valueOf(t.getShort("style"))); //顶部边框 + Short _vcolor = ColorUtil.getColorByStr(t.getString("color")); + if (null != _vcolor) { + style.setTopBorderColor(_vcolor);//顶部边框颜色 + } + + } + if (b != null) { + style.setBorderBottom(BorderStyle.valueOf(b.getShort("style"))); //底部边框 + Short _vcolor = ColorUtil.getColorByStr(b.getString("color")); + if (_vcolor != null) { + //底部边框颜色 + style.setBottomBorderColor(_vcolor); + } + } + + } else if (borderInfoObject.get("rangeType").equals("range")) { + //选区 + Short style_ = borderInfoObject.getShort("style"); + String borderType = borderInfoObject.getString("borderType"); + Short color = ColorUtil.getColorByStr(borderInfoObject.getString("color")); + JSONObject rangObject = (JSONObject) ((JSONArray) (borderInfoObject.get("range"))).get(0); + + JSONArray rowList = rangObject.getJSONArray("row"); + JSONArray columnList = rangObject.getJSONArray("column"); + + + for (int row_ = rowList.getInteger(0); row_ < rowList.getInteger(rowList.size() - 1) + 1; row_++) { + for (int col_ = columnList.getInteger(0); col_ < columnList.getInteger(columnList.size() - 1) + 1; col_++) { + Row row = sheet.getRow(row_); + if (null == row) { + row = sheet.createRow(row_); + } + Cell cell = row.getCell(col_); + CellStyle style; + if (null == cell) { + style = wb.createCellStyle(); + cell = row.createCell(col_); + cell.setCellStyle(style); + } else { + style = cell.getCellStyle(); + } + + //"border-left" | "border-right" | "border-top" | "border-bottom" | "border-all" | "border-horizontal" | "border-vertical" + // "border-outside" | "border-inside" | | "border-none" + if ("border-left".equals(borderType) || "border-all".equals(borderType)) { + style.setBorderLeft(BorderStyle.valueOf(style_)); //左边框 + style.setLeftBorderColor(color);//左边框颜色 + } + if ("border-right".equals(borderType) || "border-all".equals(borderType)) { + style.setBorderRight(BorderStyle.valueOf(style_)); //右边框 + style.setRightBorderColor(color);//右边框颜色 + } + + if ("border-top".equals(borderType) || "border-all".equals(borderType)) { + style.setBorderTop(BorderStyle.valueOf(style_)); //顶部边框 + style.setTopBorderColor(color);//顶部边框颜色 + } + + if ("border-bottom".equals(borderType) || "border-all".equals(borderType)) { + style.setBorderBottom(BorderStyle.valueOf(style_)); //底部边框 + style.setBottomBorderColor(color);//底部边框颜色 } + } + + if ("border-outside".equals(borderType)) { + //外圈边框 + if (row_ == rowList.getInteger(0)) { + style.setBorderTop(BorderStyle.valueOf(style_)); //顶部边框 + style.setTopBorderColor(color);//顶部边框颜色 + } + if (col_ == columnList.getInteger(0)) { + style.setBorderLeft(BorderStyle.valueOf(style_)); //左边框 + style.setLeftBorderColor(color);//左边框颜色 + } + if (row_ == rowList.getInteger(rowList.size() - 1)) { + style.setBorderBottom(BorderStyle.valueOf(style_)); //底部边框 + style.setBottomBorderColor(color);//底部边框颜色 } + } + if (col_ == columnList.getInteger(columnList.size() - 1)) { + style.setBorderRight(BorderStyle.valueOf(style_)); //右边框 + style.setRightBorderColor(color);//右边框颜色 + } + + } + + if ("border-horizontal".equals(borderType) || "border-inside".equals(borderType)) { + //内部横线 + if (row_ >= rowList.getInteger(0) + && row_ < rowList.getInteger(rowList.size() - 1) + && col_ >= columnList.getInteger(0) + && col_ <= columnList.getInteger(columnList.size() - 1)) { + style.setBorderBottom(BorderStyle.valueOf(style_)); //底部边框 + style.setBottomBorderColor(color);//底部边框颜色 } + } + } + + if ("border-vertical".equals(borderType) || "border-inside".equals(borderType)) { + //内部竖线 + if (row_ >= rowList.getInteger(0) + && row_ <= rowList.getInteger(rowList.size() - 1) + && col_ >= columnList.getInteger(0) + && col_ < columnList.getInteger(columnList.size() - 1)) { + style.setBorderRight(BorderStyle.valueOf(style_)); //右边框 + style.setRightBorderColor(color);//右边框颜色 + } + } + + if ("border-none".equals(borderType)) { + style.setBorderLeft(BorderStyle.NONE); //左边框 + style.setBorderRight(BorderStyle.NONE); //左边框 + style.setBorderTop(BorderStyle.NONE); //左边框 + style.setBorderBottom(BorderStyle.NONE); //左边框 + } + + } + } + + + } + } + + } + + + /** + * 设置单元格,宽、高 + * + * @param dbObject + * @param sheet + */ + private static void setColumAndRow(JSONObject dbObject, Sheet sheet) { + if (dbObject.containsKey("config")) { + JSONObject config = dbObject.getJSONObject("config"); + + if (config.containsKey("columnlen")) { + JSONObject columnlen = config.getJSONObject("columnlen"); + if (columnlen != null) { + for (String k : columnlen.keySet()) { + Integer _i = getStrToInt(k); + Integer _v = getStrToInt(columnlen.get(k).toString()); + if (_i != null && _v != null) { +// sheet.setColumnWidth(_i, MSExcelUtil.heightUnits2Pixel(_v.shortValue())); + // TODO 乘以32,有待商榷 + sheet.setColumnWidth(_i, _v * 32); + } + } + } + } + if (config.containsKey("rowlen")) { + JSONObject rowlen = config.getJSONObject("rowlen"); + if (rowlen != null) { + for (String k : rowlen.keySet()) { + Integer _i = getStrToInt(k); + Integer _v = getStrToInt(rowlen.get(k).toString()); + if (_i != null && _v != null) { + Row row = sheet.getRow(_i); + if (row != null) { +// row.setHeightInPoints(MSExcelUtil.pixel2WidthUnits(_v.shortValue())); + row.setHeightInPoints(_v.shortValue()); + } + } + } + } + } + } + } + + /** + * 单元格字体相关样式 + * + * @param wb + * @param style + * @param dbObject + */ + private static void setCellStyleFont(Workbook wb, CellStyle style, JSONObject dbObject) { + Font font = wb.createFont(); + style.setFont(font); + + //ff 字体 + if (dbObject.containsKey("ff")) { + if (dbObject.get("ff") instanceof Integer) { + Integer _v = getIntByDBObject(dbObject, "ff"); + if (_v != null && ConstantUtil.ff_IntegerToName.containsKey(_v)) { + font.setFontName(ConstantUtil.ff_IntegerToName.get(_v)); + } + } else if (dbObject.get("ff") instanceof String) { + font.setFontName(getByDBObject(dbObject, "ff")); + } + } + //fc 字体颜色 + if (dbObject.containsKey("fc")) { + String _v = getByDBObject(dbObject, "fc"); + Short _color = ColorUtil.getColorByStr(_v); + if (_color != null) { + font.setColor(_color); + } + } + //bl 粗体 + if (dbObject.containsKey("bl")) { + Integer _v = getIntByDBObject(dbObject, "bl"); + if (_v != null) { + if (_v.equals(1)) { + //是否粗体显示 + font.setBold(true); + } else { + font.setBold(false); + } + } + } + //it 斜体 + if (dbObject.containsKey("it")) { + Integer _v = getIntByDBObject(dbObject, "it"); + if (_v != null) { + if (_v.equals(1)) { + font.setItalic(true); + } else { + font.setItalic(false); + } + } + } + //fs 字体大小 + if (dbObject.containsKey("fs")) { + Integer _v = getStrToInt(getObjectByDBObject(dbObject, "fs")); + if (_v != null) { + font.setFontHeightInPoints(_v.shortValue()); + } + } + //cl 删除线 (导入没有) 0 常规 、 1 删除线 + if (dbObject.containsKey("cl")) { + Integer _v = getIntByDBObject(dbObject, "cl"); + if (_v != null) { + if (_v.equals(1)) { + font.setStrikeout(true); + } + } + } + //ul 下划线 + if (dbObject.containsKey("ul")) { + Integer _v = getIntByDBObject(dbObject, "ul"); + if (_v != null) { + if (_v.equals(1)) { + font.setUnderline(Font.U_SINGLE); + } else { + font.setUnderline(Font.U_NONE); + } + } + } + + } + + /** + * 设置cell边框颜色样式 + * + * @param style 样式 + * @param dbObject json对象 + * @param bs 样式 + * @param bc 样式 + */ + private static void setBorderStyle(CellStyle style, JSONObject dbObject, String bs, String bc) { + //bs 边框样式 + if (dbObject.containsKey(bs)) { + Integer _v = getStrToInt(getByDBObject(dbObject, bs)); + if (_v != null) { + //边框没有,不作改变 + if (bs.equals("bs") || bs.equals("bs_t")) { + style.setBorderTop(BorderStyle.valueOf(_v.shortValue())); + } + if (bs.equals("bs") || bs.equals("bs_b")) { + style.setBorderBottom(BorderStyle.valueOf(_v.shortValue())); + } + if (bs.equals("bs") || bs.equals("bs_l")) { + style.setBorderLeft(BorderStyle.valueOf(_v.shortValue())); + } + if (bs.equals("bs") || bs.equals("bs_r")) { + style.setBorderRight(BorderStyle.valueOf(_v.shortValue())); + } + + //bc 边框颜色 + String _vcolor = getByDBObject(dbObject, bc); + if (_vcolor != null) { + Short _color = ColorUtil.getColorByStr(_vcolor); + if (_color != null) { + if (bc.equals("bc") || bc.equals("bc_t")) { + style.setTopBorderColor(_color); + } + if (bc.equals("bc") || bc.equals("bc_b")) { + style.setBottomBorderColor(_color); + } + if (bc.equals("bc") || bc.equals("bc_l")) { + style.setLeftBorderColor(_color); + } + if (bc.equals("bc") || bc.equals("bc_r")) { + style.setRightBorderColor(_color); + } + } + } + } + } + } + + + /** + * 设置单元格格式 ct 单元格值格式 (fa,t) + * + * @param cell + * @param style + * @param dbObject + */ + private static void setFormatByCt(Workbook wb, Cell cell, CellStyle style, JSONObject dbObject) { + + if (!dbObject.containsKey("v") && dbObject.containsKey("ct")) { + /* 处理以下数据结构 + { + "celldata": [{ + "c": 0, + "r": 8, + "v": { + "ct": { + "s": [{ + "v": "sdsdgdf\r\ndfgdfg\r\ndsfgdfgdf\r\ndsfgdfg" + }], + "t": "inlineStr", + "fa": "General" + } + } + }] + } + */ + JSONObject ct = dbObject.getJSONObject("ct"); + if (ct.containsKey("s")) { + Object s = ct.get("s"); + if (s instanceof List && ((List) s).size() > 0) { + JSONObject _s1 = (JSONObject) ((List) s).get(0); + if (_s1.containsKey("v") && _s1.get("v") instanceof String) { + dbObject.put("v", _s1.get("v")); + style.setWrapText(true); + } + } + + } + } + + //String v = ""; //初始化 + if (dbObject.containsKey("v")) { + //v = v_json.get("v").toString(); + //取到v后,存到poi单元格对象 + //设置该单元格值 + //cell.setValue(v); + + //String v=getByDBObject(v_json,"v"); + //cell.setValue(v); + Object obj = getObjectByDBObject(dbObject, "v"); + if (obj instanceof Number) { + cell.setCellValue(Double.valueOf(obj.toString())); + } else if (obj instanceof Double) { + cell.setCellValue((Double) obj); + } else if (obj instanceof Date) { + cell.setCellValue((Date) obj); + } else if (obj instanceof Calendar) { + cell.setCellValue((Calendar) obj); + } else if (obj instanceof RichTextString) { + cell.setCellValue((RichTextString) obj); + } else if (obj instanceof String) { + cell.setCellValue((String) obj); + } else { + cell.setCellValue(obj.toString()); + } + + } + + if (dbObject.containsKey("ct")) { + JSONObject ct = dbObject.getJSONObject("ct"); + if (ct.containsKey("fa") && ct.containsKey("t")) { + //t 0=bool,1=datetime,2=error,3=null,4=numeric,5=string,6=unknown + String fa = getByDBObject(ct, "fa"); //单元格格式format定义串 + String t = getByDBObject(ct, "t"); //单元格格式type类型 + + Integer _i = ConstantUtil.getNumberFormatMap(fa); + switch (t) { + case "s": { + //字符串 + if (_i >= 0) { + style.setDataFormat(_i.shortValue()); + } else { + style.setDataFormat((short) 0); + } + cell.setCellType(org.apache.poi.ss.usermodel.CellType.STRING); + break; + } + case "d": { + //日期 + Date _d = null; + String v = getByDBObject(dbObject, "m"); + if (v.length() == 0) { + v = getByDBObject(dbObject, "v"); + } + if (v.length() > 0) { + if (v.indexOf("-") > -1) { + if (v.indexOf(":") > -1) { + _d = ConstantUtil.stringToDateTime(v); + } else { + _d = ConstantUtil.stringToDate(v); + } + } else { + _d = ConstantUtil.toDate(v); + } + } + if (_d != null) { + //能转换为日期 + cell.setCellValue(_d); + DataFormat format = wb.createDataFormat(); + style.setDataFormat(format.getFormat(fa)); + + } else { + //不能转换为日期 + if (_i >= 0) { + style.setDataFormat(_i.shortValue()); + } else { + style.setDataFormat((short) 0); + } + } + break; + } + case "b": { + //逻辑 + cell.setCellType(org.apache.poi.ss.usermodel.CellType.BOOLEAN); + if (_i >= 0) { + style.setDataFormat(_i.shortValue()); + } else { + DataFormat format = wb.createDataFormat(); + style.setDataFormat(format.getFormat(fa)); + } + break; + } + case "n": { + //数值 +// cell.setCellType(CellType.NUMERIC); + //数字转字符串 + cell.setCellType(org.apache.poi.ss.usermodel.CellType.STRING); + if (_i >= 0) { + style.setDataFormat(_i.shortValue()); + } else { + DataFormat format = wb.createDataFormat(); + style.setDataFormat(format.getFormat(fa)); + } + break; + } + case "u": + case "g": { + //general 自动类型 + //cell.setCellType(CellType._NONE); + if (_i >= 0) { + style.setDataFormat(_i.shortValue()); + } else { + DataFormat format = wb.createDataFormat(); + style.setDataFormat(format.getFormat(fa)); + } + break; + } + case "e": { + //错误 + cell.setCellType(org.apache.poi.ss.usermodel.CellType.ERROR); + if (_i >= 0) { + style.setDataFormat(_i.shortValue()); + } else { + DataFormat format = wb.createDataFormat(); + style.setDataFormat(format.getFormat(fa)); + } + break; + } + + } + + } + + } + } + + /** + * 内容按行分组 + * + * @param cells + * @return + */ + private static Map> cellGroup(List cells) { + Map> cellMap = new HashMap<>(100); + for (JSONObject dbObject : cells) { + //行号 + if (dbObject.containsKey("r")) { + Integer r = getStrToInt(dbObject.get("r")); + if (r != null) { + if (cellMap.containsKey(r)) { + cellMap.get(r).add(dbObject); + } else { + List list = new ArrayList<>(10); + list.add(dbObject); + cellMap.put(r, list); + } + } + } + + } + return cellMap; + } + + + /** + * 获取一个k的值 + * + * @param b + * @param k + * @return + */ + public static String getByDBObject(JSONObject b, String k) { + if (b.containsKey(k)) { + if (b.get(k) != null && b.get(k) instanceof String) { + return b.getString(k); + } + } + return null; + } + + /** + * 获取一个k的值 + * + * @param b + * @param k + * @return + */ + public static Object getObjectByDBObject(JSONObject b, String k) { + if (b.containsKey(k)) { + if (b.get(k) != null) { + return b.get(k); + } + } + return ""; + } + + /** + * 没有/无法转换 返回null + * + * @param b + * @param k + * @return + */ + public static Integer getIntByDBObject(JSONObject b, String k) { + if (b.containsKey(k)) { + if (b.get(k) != null) { + try { + String _s = b.getString(k).replace("px", ""); + Double _d = Double.parseDouble(_s); + return _d.intValue(); + } catch (Exception ex) { + log.error(ex.getMessage()); + return null; + } + } + } + return null; + } + + /** + * 转int + * + * @param str + * @return + */ + private static Integer getStrToInt(Object str) { + try { + if (str != null) { + return Integer.parseInt(str.toString()); + } + return null; + } catch (Exception ex) { + log.error("String:{};Error:{}", str, ex.getMessage()); + return null; + } + } + + private static Short getStrToShort(Object str) { + try { + if (str != null) { + return Short.parseShort(str.toString()); + } + return null; + } catch (Exception ex) { + log.error("String:{};Error:{}", str, ex.getMessage()); + return null; + } + } +} diff --git a/src/main/java/com/anjiplus/template/gaea/business/modules/reportexcel/util/XlsUtil.java b/src/main/java/com/anjiplus/template/gaea/business/modules/reportexcel/util/XlsUtil.java new file mode 100644 index 0000000..51ea0d3 --- /dev/null +++ b/src/main/java/com/anjiplus/template/gaea/business/modules/reportexcel/util/XlsUtil.java @@ -0,0 +1,453 @@ +package com.anjiplus.template.gaea.business.modules.reportexcel.util; + +import com.alibaba.fastjson.JSONArray; +import com.alibaba.fastjson.JSONObject; +import com.anjiplus.template.gaea.business.enums.ExcelCenterStyleEnum; +import com.anjiplus.template.gaea.business.modules.reportexcel.controller.dto.GridRecordDataModel; +import org.apache.commons.collections4.CollectionUtils; +import org.apache.poi.hssf.usermodel.HSSFCellStyle; +import org.apache.poi.hssf.usermodel.HSSFFont; +import org.apache.poi.hssf.usermodel.HSSFWorkbook; +import org.apache.poi.hssf.util.HSSFColor; +import org.apache.poi.ss.usermodel.*; +import org.apache.poi.ss.util.CellRangeAddress; +import org.apache.poi.xssf.usermodel.XSSFCellStyle; +import org.apache.poi.xssf.usermodel.XSSFColor; +import org.apache.poi.xssf.usermodel.XSSFFont; +import org.apache.poi.xssf.usermodel.XSSFWorkbook; + +import javax.validation.constraints.NotNull; +import java.io.IOException; +import java.io.OutputStream; +import java.util.*; + +/** + * 来自:https://github.com/mengshukeji/LuckysheetServer + * 使用poi导出xls + * + * @author Administrator + */ +public class XlsUtil { + + private final static String MODEL = "{\"c\":0,\"r\":0,\"v\":{\"m\":\"模板\",\"v\":\"模板\",\"bl\":1,\"ct\":{\"t\":\"g\",\"fa\":\"General\"}}}"; + private final static String BORDER_MODEL = "{\"rangeType\":\"cell\",\"value\":{\"b\":{\"color\":\"rgb(0, 0, 0)\",\"style\":1},\"r\":{\"color\":\"rgb(0, 0, 0)\",\"style\":1},\"col_index\":5,\"t\":{\"color\":\"rgb(0, 0, 0)\",\"style\":1},\"row_index\":7,\"l\":{\"color\":\"rgb(0, 0, 0)\",\"style\":1}}}"; + /** + * 默认行数 + */ + private static final int DEFAULT_ROW_INDEX = 84; + /** + * 默认列数 + */ + private static final int DEFAULT_COLUMN_INDEX = 64; + + /** + * 输出文件流 + * + * @param outputStream 流 + * @param isXlsx 是否是xlsx + * @param dbObjectList 数据 + */ + public static void exportXlsFile(OutputStream outputStream, Boolean isXlsx, List dbObjectList) throws IOException { + Workbook wb = null; + if (isXlsx) { + wb = new XSSFWorkbook(); + } else { + wb = new HSSFWorkbook(); + } + if (dbObjectList != null && dbObjectList.size() > 0) { + for (int x = 0; x < dbObjectList.size(); x++) { + XlsSheetUtil.exportSheet(wb, x, dbObjectList.get(x)); + } + } + wb.write(outputStream); + } + + /** + * @param workbook 工作簿 + * @return Map + * @description 读取excel + * @author zhouhang + * @date 2021/4/20 + */ + public static List readExcel(Workbook workbook) { + List list = new ArrayList<>(); + Iterator sheetIterator = workbook.sheetIterator(); + int sheetIndex = 0; + while (sheetIterator.hasNext()) { + Sheet sheet = sheetIterator.next(); + //生成默认MODEL + GridRecordDataModel model; + if (Objects.equals(0, sheetIndex)) { + model = strToModel("", (sheetIndex + 1) + "", 1, sheetIndex); + } else { + model = strToModel("", (sheetIndex + 1) + "", 0, sheetIndex); + } + sheetIndex++; + //读取sheet页 + readSheet(sheet, model, workbook); + //设置sheet页名称 + model.getJson_data().put("name", sheet.getSheetName()); + list.add(model); + } + return list; + } + + public static GridRecordDataModel strToModel(String list_id, String index, int status, int order) { + String strSheet = "{\"row\":84,\"name\":\"reSheetName\",\"chart\":[],\"color\":\"\",\"index\":\"reIndex\",\"order\":reOrder,\"column\":60,\"config\":{},\"status\":reStatus,\"celldata\":[],\"ch_width\":4748,\"rowsplit\":[],\"rh_height\":1790,\"scrollTop\":0,\"scrollLeft\":0,\"visibledatarow\":[],\"visibledatacolumn\":[],\"jfgird_select_save\":[],\"jfgrid_selection_range\":{}}"; + strSheet = strSheet.replace("reSheetName", "Sheet" + index).replace("reIndex", index).replace("reOrder", order + "").replace("reStatus", status + ""); + + JSONObject bson = JSONObject.parseObject(strSheet); + GridRecordDataModel model = new GridRecordDataModel(); + model.setBlock_id("fblock"); + model.setRow_col("5_5"); + model.setIndex(index); + model.setIs_delete(0); + model.setJson_data(bson); + model.setStatus(status); + model.setOrder(order); + model.setList_id(list_id); + return model; + } + + /** + * @param sheet sheet页 + * @param model 数据存储 + * @param workbook excel + * @description 读取单个sheet页 + * @author zhouhang + * @date 2021/4/20 + */ + private static void readSheet(Sheet sheet, GridRecordDataModel model, Workbook workbook) { + //excel数据集合 + List dataList = new ArrayList<>(); + model.setDataList(dataList); + //获取行迭代器 + Iterator rowIterator = sheet.rowIterator(); + //获取合并单元格信息 + Map rangeMap = getRangeMap(sheet); + //记录最大列 + int maxCellNumber = 0; + int maxRowNumber = 0; + //列宽 + JSONObject columnLenObj = new JSONObject(); + //行高 + JSONObject rowLenObj = new JSONObject(); + //读取文档 + while (rowIterator.hasNext()) { + Row row = rowIterator.next(); + int rowLen = ((int) row.getHeight()) / 20; + if (rowLen == 0) { + rowLen = 30; + } + rowLenObj.put(row.getRowNum() + "", rowLen); + Iterator cellIterator = row.cellIterator(); + maxRowNumber = row.getRowNum(); + while (cellIterator.hasNext()) { + //"{\"c\":0,\"r\":0,\"v\":{\"m\":\"模板\",\"v\":\"模板\",\"bl\":1,\"ct\":{\"t\":\"g\",\"fa\":\"General\"}}}"; + JSONObject dataModel = JSONObject.parseObject(MODEL); + //初始化默认单元格内容 + Cell cell = cellIterator.next(); + int columnLen = sheet.getColumnWidth(cell.getColumnIndex()) / 25; + if (columnLen == 0) { + columnLen = 73; + } + columnLenObj.put(cell.getColumnIndex() + "", columnLen); + //修改最大列 + maxCellNumber = Math.max(cell.getColumnIndex(), maxCellNumber); + //设置行列 + dataModel.put("c", cell.getColumnIndex()); + dataModel.put("r", row.getRowNum()); + //获取单元格内容 + switch (cell.getCellType()) { + case STRING: + dataModel.getJSONObject("v").put("m", cell.getStringCellValue()); + dataModel.getJSONObject("v").put("v", cell.getStringCellValue()); + break; + case NUMERIC: + dataModel.getJSONObject("v").put("m", cell.getNumericCellValue()); + dataModel.getJSONObject("v").put("v", cell.getNumericCellValue()); + break; + case BLANK: + dataModel.getJSONObject("v").put("m", ""); + dataModel.getJSONObject("v").put("v", ""); + break; + case BOOLEAN: + dataModel.getJSONObject("v").put("m", cell.getBooleanCellValue()); + dataModel.getJSONObject("v").put("v", cell.getBooleanCellValue()); + break; + case ERROR: + dataModel.getJSONObject("v").put("m", cell.getErrorCellValue()); + dataModel.getJSONObject("v").put("v", cell.getErrorCellValue()); + break; + default: + dataModel.getJSONObject("v").put("m", ""); + dataModel.getJSONObject("v").put("v", ""); + } + //设置单元格合并标记 + dealWithCellMarge(rangeMap, row, cell, dataModel); + //设置单元格样式、合并单元格信息 + dealWithExcelStyle(model, dataModel, cell, sheet, workbook); + dataList.add(dataModel); + } + } + //设置最大行、列 + model.getJson_data().put("column", Math.max(maxCellNumber, DEFAULT_COLUMN_INDEX)); + model.getJson_data().put("row", Math.max(maxRowNumber, DEFAULT_ROW_INDEX)); + //设置行高、列宽 + model.getJson_data().getJSONObject("config").put("columnlen", columnLenObj); + model.getJson_data().getJSONObject("config").put("rowlen", rowLenObj); + } + + /** + * @param sheet sheet页信息 + * @return Map 单元格合并信息 + * @description 获取合并单元格信息 所有合并单元的MAP + * @author zhouhang + * @date 2021/4/21 + */ + @NotNull + private static Map getRangeMap(Sheet sheet) { + List rangeAddressList = sheet.getMergedRegions(); + Map rangeMap = new HashMap<>(rangeAddressList.size() * 5); + for (CellRangeAddress cellAddresses : rangeAddressList) { + for (int i = cellAddresses.getFirstRow(); i <= cellAddresses.getLastRow(); i++) { + for (int j = cellAddresses.getFirstColumn(); j <= cellAddresses.getLastColumn(); j++) { + if (i == cellAddresses.getFirstRow() && j == cellAddresses.getFirstColumn()) { + //单元格合并初始值特殊标记 + rangeMap.put(i + "_" + j, cellAddresses.getFirstRow() + "_" + cellAddresses.getFirstColumn() + "_" + cellAddresses.getLastRow() + "_" + cellAddresses.getLastColumn()); + } else { + rangeMap.put(i + "_" + j, cellAddresses.getFirstRow() + "_" + cellAddresses.getFirstColumn()); + } + } + } + } + return rangeMap; + } + + /** + * @param rangeMap 合并信息 + * @param row 行信息 + * @param cell 单元格 + * @param dataModel 单元格数据存储信息 + * @description 设置单元格合并标记 + * @author zhouhang + * @date 2021/4/21 + */ + private static void dealWithCellMarge(Map rangeMap, Row row, Cell cell, JSONObject dataModel) { + if (rangeMap.containsKey(row.getRowNum() + "_" + cell.getColumnIndex())) { + String margeValue = rangeMap.get(row.getRowNum() + "_" + cell.getColumnIndex()); + JSONObject mcData = new JSONObject(); + String[] s = margeValue.split("_"); + mcData.put("r", Integer.parseInt(s[0])); + mcData.put("c", Integer.parseInt(s[1])); + if (s.length == 4) { + mcData.put("rs", Integer.parseInt(s[2]) - Integer.parseInt(s[0]) + 1); + mcData.put("cs", Integer.parseInt(s[3]) - Integer.parseInt(s[1]) + 1); + } + dataModel.getJSONObject("v").put("mc", mcData); + } + } + + /** + * @param model sheet页信息 + * @param dataModel 单元格信息 + * @param cell 单元格 + * @param sheet sheet页数据 + * @param workbook excel + * @description 获取单元格样式,设置单元格样式 + * @author zhouhang + * @date 2021/4/21 + */ + private static void dealWithExcelStyle(GridRecordDataModel model, JSONObject dataModel, Cell cell, Sheet sheet, Workbook workbook) { + //设置单元格合并信息 + dealWithExcelMerge(model, sheet); + //设置字体样式 + setFontStyle(dataModel, workbook, cell); + //设置单元格样式 + dealWithBorderStyle(model, cell, workbook); + } + + /** + * @param model 在线表格存储单元 + * @param cell cell + * @param workbook workbook + * @description 设置单元格样式 + * @author zhouhang + * @date 2021/4/22 + */ + private static void dealWithBorderStyle(GridRecordDataModel model, Cell cell, Workbook workbook) { + CellStyle cellStyle = cell.getCellStyle(); + //判断是否存在边框 + if (cellStyle.getBorderTop().getCode() > 0 || cellStyle.getBorderBottom().getCode() > 0 || + cellStyle.getBorderLeft().getCode() > 0 || cellStyle.getBorderRight().getCode() > 0) { + JSONObject border = JSONObject.parseObject(BORDER_MODEL); + border.getJSONObject("value").put("row_index", cell.getRowIndex()); + border.getJSONObject("value").put("col_index", cell.getColumnIndex()); + //xlsx + if (cellStyle instanceof XSSFCellStyle) { + XSSFCellStyle xssfCellStyle = (XSSFCellStyle) cellStyle; + if (Objects.equals((short) 0, cellStyle.getBorderTop().getCode())) { + border.getJSONObject("value").remove("t"); + } else { + border.getJSONObject("value").getJSONObject("t").put("color", dealWithRbg(xssfCellStyle.getTopBorderXSSFColor().getRGB())); + } + if (Objects.equals((short) 0, cellStyle.getBorderRight().getCode())) { + border.getJSONObject("value").remove("r"); + } else { + border.getJSONObject("value").getJSONObject("r").put("color", dealWithRbg(xssfCellStyle.getRightBorderXSSFColor().getRGB())); + } + if (Objects.equals((short) 0, cellStyle.getBorderLeft().getCode())) { + border.getJSONObject("value").remove("l"); + } else { + border.getJSONObject("value").getJSONObject("l").put("color", dealWithRbg(xssfCellStyle.getLeftBorderXSSFColor().getRGB())); + } + if (Objects.equals((short) 0, cellStyle.getBorderBottom().getCode())) { + border.getJSONObject("value").remove("b"); + } else { + border.getJSONObject("value").getJSONObject("b").put("color", dealWithRbg(xssfCellStyle.getBottomBorderXSSFColor().getRGB())); + } + } else if (cellStyle instanceof HSSFCellStyle) { + //xls + HSSFWorkbook hssfWorkbook = (HSSFWorkbook) workbook; + HSSFCellStyle hssfCellStyle = (HSSFCellStyle) cellStyle; + if (Objects.equals((short) 0, cellStyle.getBorderTop().getCode())) { + border.getJSONObject("value").remove("t"); + } else { + HSSFColor color = hssfWorkbook.getCustomPalette().getColor(hssfCellStyle.getTopBorderColor()); + border.getJSONObject("value").getJSONObject("t").put("color", dealWithRbgShort(color.getTriplet())); + } + if (Objects.equals((short) 0, cellStyle.getBorderRight().getCode())) { + border.getJSONObject("value").remove("r"); + } else { + HSSFColor color = hssfWorkbook.getCustomPalette().getColor(hssfCellStyle.getRightBorderColor()); + border.getJSONObject("value").getJSONObject("r").put("color", dealWithRbgShort(color.getTriplet())); + } + if (Objects.equals((short) 0, cellStyle.getBorderLeft().getCode())) { + border.getJSONObject("value").remove("l"); + } else { + HSSFColor color = hssfWorkbook.getCustomPalette().getColor(hssfCellStyle.getLeftBorderColor()); + border.getJSONObject("value").getJSONObject("l").put("color", dealWithRbgShort(color.getTriplet())); + } + if (Objects.equals((short) 0, cellStyle.getBorderBottom().getCode())) { + border.getJSONObject("value").remove("b"); + } else { + HSSFColor color = hssfWorkbook.getCustomPalette().getColor(hssfCellStyle.getBottomBorderColor()); + border.getJSONObject("value").getJSONObject("b").put("color", dealWithRbgShort(color.getTriplet())); + } + } + JSONArray borderInfo = model.getJson_data().getJSONObject("config").getJSONArray("borderInfo"); + if (Objects.isNull(borderInfo)) { + borderInfo = new JSONArray(); + model.getJson_data().getJSONObject("config").put("borderInfo", borderInfo); + } + borderInfo.add(border); + } + } + + /** + * @param rgb RBG short + * @return rbg(0, 0, 0) + * @description 转换RBG rbg(0,0,0) + * @author zhouhang + * @date 2021/4/26 + */ + private static String dealWithRbgShort(short[] rgb) { + return getRbg(Objects.nonNull(rgb), rgb[0], rgb[1], rgb[2]); + } + + @NotNull + private static String getRbg(boolean b2, short r, short b, short g) { + if (b2) { + return "rgb(" + (r & 0xFF) + ", " + (b & 0xFF) + ", " + (g & 0xFF) + ")"; + } else { + return "rgb(0, 0, 0)"; + } + } + + /** + * @param rgb RBG byte + * @return rbg(0, 0, 0) + * @description 转换RBG rbg(0,0,0) + * @author zhouhang + * @date 2021/4/26 + */ + private static String dealWithRbg(byte[] rgb) { + if (Objects.isNull(rgb)) { + return "rgb(0, 0, 0)"; + } + short[] shorts = new short[]{rgb[0], rgb[1], rgb[2]}; + return getRbg(true, shorts[0], shorts[1], shorts[2]); + } + + /** + * @param dataModel 单元格内容 + * @param workbook workbook + * @param cell cell + * @description s设置字体样式 + * @author zhouhang + * @date 2021/4/21 + */ + private static void setFontStyle(JSONObject dataModel, Workbook workbook, Cell cell) { + CellStyle cellStyle = cell.getCellStyle(); + Font font = workbook.getFontAt(cellStyle.getFontIndexAsInt()); + JSONObject v = dataModel.getJSONObject("v"); + //ht 水平对齐 水平对齐方式(0=居中,1=左对齐,2=右对齐) excel:左:1 中:2 右:3 未设置:0 + v.put("ht", ExcelCenterStyleEnum.getExcelCenterStyleByExcelCenterCode(cellStyle.getAlignment().getCode()).getOnlineExcelCode()); + //bl 字体加粗设置 + v.put("bl", font.getBold() ? 1 : 0); + //lt 斜体 + v.put("it", font.getItalic() ? 1 : 0); + //ff 字体 + v.put("ff", font.getFontName()); + //fc 字体颜色 + if (font instanceof HSSFFont) { + HSSFFont hssfFont = (HSSFFont) font; + HSSFColor hssfColor = hssfFont.getHSSFColor((HSSFWorkbook) workbook); + if (Objects.nonNull(hssfColor)) { + v.put("fc", ColorUtil.convertRGBToHex(hssfColor.getTriplet()[0], hssfColor.getTriplet()[1], hssfColor.getTriplet()[2])); + } + } else { + XSSFFont xssfFont = (XSSFFont) font; + XSSFColor xssfColor = xssfFont.getXSSFColor(); + if (Objects.nonNull(xssfColor)) { + v.put("fc", "#" + xssfColor.getARGBHex().substring(2)); + } + } + //fs 字体大小 + v.put("fs", font.getFontHeightInPoints()); + //cl 删除线 + v.put("cl", font.getStrikeout() ? 1 : 0); + //ul 下划线 + v.put("un", font.getUnderline()); + //背景色 + String fillColorHex = ColorUtil.getFillColorHex(cell); + if (Objects.nonNull(fillColorHex)) { + v.put("bg", fillColorHex); + } + } + + /** + * @param model sheet页信息 + * @param sheet sheet页 + * @description 设置单元格合并信息 + * @author zhouhang + * @date 2021/4/21 + */ + private static void dealWithExcelMerge(GridRecordDataModel model, Sheet sheet) { + if (CollectionUtils.isNotEmpty(sheet.getMergedRegions())) { + //{"color":"","list_id":"","column":60,"index":"1","jfgird_select_save":[],"rh_height":1790,"visibledatacolumn":[],"scrollTop":0,"block_id":"fblock","rowsplit":[],"visibledatarow":[],"jfgrid_selection_range":{},"name":"Sheet1","celldata":[],"ch_width":4748,"row":84,"scrollLeft":0,"id":364598,"chart":[],"config":{},"order":0,"status":1} + JSONObject jsonObject = model.getJson_data(); + JSONObject config = jsonObject.getJSONObject("config"); + JSONObject merge = new JSONObject(); + for (CellRangeAddress mergedRegion : sheet.getMergedRegions()) { + JSONObject mergeBase = new JSONObject(); + mergeBase.put("r", mergedRegion.getFirstRow()); + mergeBase.put("c", mergedRegion.getFirstColumn()); + mergeBase.put("rs", mergedRegion.getLastRow() - mergedRegion.getFirstRow() + 1); + mergeBase.put("cs", mergedRegion.getLastColumn() - mergedRegion.getFirstColumn() + 1); + merge.put(mergedRegion.getFirstRow() + "_" + mergedRegion.getFirstColumn(), mergeBase); + } + config.put("merge", merge); + } + } +} diff --git a/src/main/java/com/anjiplus/template/gaea/business/modules/reportshare/controller/ReportShareController.java b/src/main/java/com/anjiplus/template/gaea/business/modules/reportshare/controller/ReportShareController.java new file mode 100644 index 0000000..7588111 --- /dev/null +++ b/src/main/java/com/anjiplus/template/gaea/business/modules/reportshare/controller/ReportShareController.java @@ -0,0 +1,76 @@ + +package com.anjiplus.template.gaea.business.modules.reportshare.controller; + +import com.anji.plus.gaea.annotation.AccessKey; +import com.anji.plus.gaea.annotation.Permission; +import com.anji.plus.gaea.bean.ResponseBean; +import com.anji.plus.gaea.curd.controller.GaeaBaseController; +import com.anji.plus.gaea.curd.service.GaeaBaseService; +import com.anji.plus.gaea.utils.GaeaBeanUtils; +import com.anji.plus.gaea.utils.GaeaUtils; +import com.anjiplus.template.gaea.business.modules.reportshare.controller.dto.ReportShareDto; +import com.anjiplus.template.gaea.business.modules.reportshare.controller.param.ReportShareParam; +import com.anjiplus.template.gaea.business.modules.reportshare.dao.entity.ReportShare; +import com.anjiplus.template.gaea.business.modules.reportshare.service.ReportShareService; +import io.swagger.annotations.Api; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.*; + +/** + * @author Raod + * @desc 报表分享 controller + * @date 2021-08-18 13:37:26.663 + **/ +@RestController +@Api(tags = "报表分享管理") +@RequestMapping("/reportShare") +@Permission(code = "reportShareManage", name = "报表分享管理") +public class ReportShareController extends GaeaBaseController { + + @Autowired + private ReportShareService reportShareService; + + @Override + public GaeaBaseService getService() { + return reportShareService; + } + + @Override + public ReportShare getEntity() { + return new ReportShare(); + } + + @Override + public ReportShareDto getDTO() { + return new ReportShareDto(); + } + + + @GetMapping({"/{id}"}) + @AccessKey + @Override + @Permission(code = "detail", name = "明细") + public ResponseBean detail(@PathVariable("id") Long id) { + this.logger.info("{}根据ID查询服务开始,id为:{}", this.getClass().getSimpleName(), id); + ReportShare result = reportShareService.getDetail(id); + ReportShareDto dto = this.getDTO(); + GaeaBeanUtils.copyAndFormatter(result, dto); + ResponseBean responseBean = this.responseSuccessWithData(this.resultDtoHandle(dto)); + this.logger.info("{}根据ID查询结束,结果:{}", this.getClass().getSimpleName(), GaeaUtils.toJSONString(responseBean)); + return responseBean; + } + + @GetMapping({"/detailByCode"}) + @Permission(code = "detail", name = "明细") + public ResponseBean detailByCode(@RequestParam("shareCode") String shareCode) { + return ResponseBean.builder().data(reportShareService.detailByCode(shareCode)).build(); + } + + @PostMapping({"/shareDelay"}) + @Permission(code = "shareDelay", name = "分享延期") + public ResponseBean shareDelay(@RequestBody ReportShareDto dto) { + reportShareService.shareDelay(dto); + return ResponseBean.builder().build(); + } + +} diff --git a/src/main/java/com/anjiplus/template/gaea/business/modules/reportshare/controller/dto/ReportShareDto.java b/src/main/java/com/anjiplus/template/gaea/business/modules/reportshare/controller/dto/ReportShareDto.java new file mode 100644 index 0000000..b0c4944 --- /dev/null +++ b/src/main/java/com/anjiplus/template/gaea/business/modules/reportshare/controller/dto/ReportShareDto.java @@ -0,0 +1,65 @@ + +package com.anjiplus.template.gaea.business.modules.reportshare.controller.dto; + +import java.io.Serializable; + +import com.anji.plus.gaea.annotation.Formatter; +import com.anji.plus.gaea.curd.dto.GaeaBaseDTO; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +import javax.validation.constraints.NotEmpty; +import javax.validation.constraints.NotNull; +import java.util.Date; + +/** +* +* @description 报表分享 dto +* @author Raod +* @date 2021-08-18 13:37:26.663 +**/ +@Data +public class ReportShareDto extends GaeaBaseDTO implements Serializable { + /** 分享编码,系统生成,默认UUID */ + @ApiModelProperty(value = "分享编码,系统生成,默认UUID") + private String shareCode; + + /** 分享有效期类型,DIC_NAME=SHARE_VAILD */ + @ApiModelProperty(value = "分享有效期类型,DIC_NAME=SHARE_VAILD") + @NotNull(message = "6002") + private Integer shareValidType; + + /** 分享有效期 */ + @ApiModelProperty(value = "分享有效期") + private Date shareValidTime; + + /** 分享token */ + @ApiModelProperty(value = "分享token") + private String shareToken; + + /** 分享url */ + @ApiModelProperty(value = "分享url") + @NotEmpty(message = "6002") + private String shareUrl; + + /** 报表编码 */ + @ApiModelProperty(value = "报表编码") + @NotEmpty(message = "6002") + private String reportCode; + + /** 0--已禁用 1--已启用 DIC_NAME=ENABLE_FLAG */ + @ApiModelProperty(value = "0--已禁用 1--已启用 DIC_NAME=ENABLE_FLAG") + private Integer enableFlag; + + /** 0--未删除 1--已删除 DIC_NAME=DELETE_FLAG */ + @ApiModelProperty(value = "0--未删除 1--已删除 DIC_NAME=DELETE_FLAG") + private Integer deleteFlag; + + /** 分享码 */ + private String sharePassword; + + private boolean sharePasswordFlag = false; + + private String reportType; + +} diff --git a/src/main/java/com/anjiplus/template/gaea/business/modules/reportshare/controller/param/ReportShareParam.java b/src/main/java/com/anjiplus/template/gaea/business/modules/reportshare/controller/param/ReportShareParam.java new file mode 100644 index 0000000..3243060 --- /dev/null +++ b/src/main/java/com/anjiplus/template/gaea/business/modules/reportshare/controller/param/ReportShareParam.java @@ -0,0 +1,30 @@ +/**/ +package com.anjiplus.template.gaea.business.modules.reportshare.controller.param; + +import com.anji.plus.gaea.annotation.Query; +import com.anji.plus.gaea.constant.QueryEnum; +import com.anji.plus.gaea.curd.params.PageParam; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +import java.io.Serializable; + +/** + * @author Raod + * @desc ReportShare 报表分享查询输入类 + * @date 2021-08-18 13:37:26.663 + **/ +@Data +public class ReportShareParam extends PageParam implements Serializable { + /** 分享编码,系统生成,默认UUID */ + @Query(value = QueryEnum.EQ) + private String shareCode; + + /** 报表编码 */ + @Query(value = QueryEnum.LIKE) + private String reportCode; + + /** 分享有效期类型 */ + @Query(value = QueryEnum.EQ) + private String shareValidType; +} diff --git a/src/main/java/com/anjiplus/template/gaea/business/modules/reportshare/dao/ReportShareMapper.java b/src/main/java/com/anjiplus/template/gaea/business/modules/reportshare/dao/ReportShareMapper.java new file mode 100644 index 0000000..852490f --- /dev/null +++ b/src/main/java/com/anjiplus/template/gaea/business/modules/reportshare/dao/ReportShareMapper.java @@ -0,0 +1,15 @@ +package com.anjiplus.template.gaea.business.modules.reportshare.dao; + +import com.anji.plus.gaea.curd.mapper.GaeaBaseMapper; +import com.anjiplus.template.gaea.business.modules.reportshare.dao.entity.ReportShare; +import org.apache.ibatis.annotations.Mapper; +/** +* ReportShare Mapper +* @author Raod +* @date 2021-08-18 13:37:26.663 +**/ +@Mapper +public interface ReportShareMapper extends GaeaBaseMapper { + + +} diff --git a/src/main/java/com/anjiplus/template/gaea/business/modules/reportshare/dao/entity/ReportShare.java b/src/main/java/com/anjiplus/template/gaea/business/modules/reportshare/dao/entity/ReportShare.java new file mode 100644 index 0000000..b581504 --- /dev/null +++ b/src/main/java/com/anjiplus/template/gaea/business/modules/reportshare/dao/entity/ReportShare.java @@ -0,0 +1,52 @@ + +package com.anjiplus.template.gaea.business.modules.reportshare.dao.entity; + +import com.anji.plus.gaea.curd.entity.GaeaBaseEntity; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; + +import java.util.Date; +/** +* @description 报表分享 entity +* @author Raod +* @date 2021-08-18 13:37:26.663 +**/ +@TableName(keepGlobalPrefix=true, value="gaea_report_share") +@Data +public class ReportShare extends GaeaBaseEntity { + /** 分享编码,系统生成,默认UUID */ + private String shareCode; + + /** 分享有效期类型,DIC_NAME=SHARE_VAILD */ + private Integer shareValidType; + + /** 分享有效期 */ + private Date shareValidTime; + + /** 分享token */ + private String shareToken; + + /** 分享url */ + private String shareUrl; + + /** 报表编码 */ + private String reportCode; + + /** 0--已禁用 1--已启用 DIC_NAME=ENABLE_FLAG */ + private Integer enableFlag; + + /** 0--未删除 1--已删除 DIC_NAME=DELETE_FLAG */ + private Integer deleteFlag; + + /** 分享码 */ + private String sharePassword; + + @TableField(exist = false) + private boolean sharePasswordFlag; + + /** 大屏类型 report excel */ + @TableField(exist = false) + private String reportType; + +} diff --git a/src/main/java/com/anjiplus/template/gaea/business/modules/reportshare/service/ReportShareService.java b/src/main/java/com/anjiplus/template/gaea/business/modules/reportshare/service/ReportShareService.java new file mode 100644 index 0000000..d05b32e --- /dev/null +++ b/src/main/java/com/anjiplus/template/gaea/business/modules/reportshare/service/ReportShareService.java @@ -0,0 +1,33 @@ + +package com.anjiplus.template.gaea.business.modules.reportshare.service; + +import com.anji.plus.gaea.curd.service.GaeaBaseService; +import com.anjiplus.template.gaea.business.modules.reportshare.controller.dto.ReportShareDto; +import com.anjiplus.template.gaea.business.modules.reportshare.controller.param.ReportShareParam; +import com.anjiplus.template.gaea.business.modules.reportshare.dao.entity.ReportShare; + +/** +* @desc ReportShare 报表分享服务接口 +* @author Raod +* @date 2021-08-18 13:37:26.663 +**/ +public interface ReportShareService extends GaeaBaseService { + + /*** + * 查询详情 + * + * @param id + * @return + */ + ReportShare getDetail(Long id); + + ReportShareDto insertShare(ReportShareDto dto); + + ReportShare detailByCode(String shareCode); + + /** + * 延期过期时间 + * @param dto + */ + void shareDelay(ReportShareDto dto); +} diff --git a/src/main/java/com/anjiplus/template/gaea/business/modules/reportshare/service/impl/ReportShareServiceImpl.java b/src/main/java/com/anjiplus/template/gaea/business/modules/reportshare/service/impl/ReportShareServiceImpl.java new file mode 100644 index 0000000..02eec6e --- /dev/null +++ b/src/main/java/com/anjiplus/template/gaea/business/modules/reportshare/service/impl/ReportShareServiceImpl.java @@ -0,0 +1,163 @@ + +package com.anjiplus.template.gaea.business.modules.reportshare.service.impl; + +import com.anji.plus.gaea.constant.BaseOperationEnum; +import com.anji.plus.gaea.curd.mapper.GaeaBaseMapper; +import com.anji.plus.gaea.exception.BusinessException; +import com.anji.plus.gaea.exception.BusinessExceptionBuilder; +import com.anjiplus.template.gaea.business.code.ResponseCode; +import com.anjiplus.template.gaea.business.enums.EnableFlagEnum; +import com.anjiplus.template.gaea.business.modules.reportshare.controller.dto.ReportShareDto; +import com.anjiplus.template.gaea.business.modules.reportshare.dao.ReportShareMapper; +import com.anjiplus.template.gaea.business.modules.reportshare.dao.entity.ReportShare; +import com.anjiplus.template.gaea.business.modules.reportshare.service.ReportShareService; +import com.anjiplus.template.gaea.business.util.DateUtil; +import com.anjiplus.template.gaea.business.util.JwtUtil; +import com.anjiplus.template.gaea.business.util.MD5Util; +import com.anjiplus.template.gaea.business.util.UuidUtil; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import org.apache.commons.lang3.StringUtils; +import org.springframework.beans.BeanUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +/** +* @desc ReportShare 报表分享服务实现 +* @author Raod +* @date 2021-08-18 13:37:26.663 +**/ +@Service +public class ReportShareServiceImpl implements ReportShareService { + private static final String SHARE_AJFLAG = "#/aj/"; + private static final String SHARE_ELFLAG = "#/el/"; + + private static final String REPORT = "report_screen"; + private static final String EXCEL = "report_excel"; + /** + * 默认跳转路由为aj的页面 + */ + private static final String SHARE_FLAG = "#/aj/"; + + private static final String SHARE_URL = "#"; + + @Autowired + private ReportShareMapper reportShareMapper; + + @Override + public GaeaBaseMapper getMapper() { + return reportShareMapper; + } + + @Override + public ReportShare getDetail(Long id) { + ReportShare reportShare = this.selectOne(id); + return reportShare; + } + + @Override + public ReportShareDto insertShare(ReportShareDto dto) { + //设置分享码 + if (dto.isSharePasswordFlag()) { + dto.setSharePassword(UuidUtil.getRandomPwd(4)); + } + + ReportShareDto reportShareDto = new ReportShareDto(); + ReportShare entity = new ReportShare(); + BeanUtils.copyProperties(dto, entity); + insert(entity); + //将分享链接返回 + reportShareDto.setShareUrl(entity.getShareUrl()); + reportShareDto.setSharePassword(dto.getSharePassword()); + return reportShareDto; + } + + @Override + public ReportShare detailByCode(String shareCode) { + LambdaQueryWrapper wrapper = Wrappers.lambdaQuery(); + wrapper.eq(ReportShare::getShareCode, shareCode); + wrapper.eq(ReportShare::getEnableFlag, EnableFlagEnum.ENABLE.getCodeValue()); + ReportShare reportShare = selectOne(wrapper); + if (null == reportShare) { + throw BusinessExceptionBuilder.build(ResponseCode.REPORT_SHARE_LINK_INVALID); + } + //解析jwt token,获取密码 + String password = JwtUtil.getPassword(reportShare.getShareToken()); + if (StringUtils.isNotBlank(password)) { + //md5加密返回 + reportShare.setSharePassword(MD5Util.encrypt(password)); + } + return reportShare; + } + + /** + * 延期过期时间 + * + * @param dto + */ + @Override + public void shareDelay(ReportShareDto dto) { + Integer shareValidType = dto.getShareValidType(); + if (null == dto.getId() || null == shareValidType) { + throw BusinessExceptionBuilder.build("入参不完整"); + } + ReportShare entity = selectOne(dto.getId()); + entity.setShareValidTime(DateUtil.getFutureDateTmdHmsByTime(entity.getShareValidTime(), shareValidType)); + entity.setShareToken(JwtUtil.createToken(entity.getReportCode(), entity.getShareCode(), entity.getSharePassword(), entity.getShareValidTime())); + update(entity); + } + + @Override + public void processBeforeOperation(ReportShare entity, BaseOperationEnum operationEnum) throws BusinessException { + switch (operationEnum) { + case INSERT: + init(entity); + break; + default: + + break; + } + } + + /** + * 新增初始化 + * @param entity + */ + private void init(ReportShare entity) { + //前端地址 window.location.href https://report.anji-plus.com/index.html#/report/bigscreen + //截取#之前的内容 + //http://localhost:9528/#/bigscreen/viewer?reportCode=bigScreen2 + //http://127.0.0.1:9095/reportDashboard/getData + String shareCode = UuidUtil.generateShortUuid(); + entity.setShareCode(shareCode); + +// if (entity.getShareUrl().contains(SHARE_URL)) { +// String prefix = entity.getShareUrl().substring(0, entity.getShareUrl().indexOf("#")); +// entity.setShareUrl(prefix + SHARE_FLAG + shareCode); +// } else { +// entity.setShareUrl(entity.getShareUrl() + SHARE_FLAG + shareCode); +// } + + + if (REPORT.equals(entity.getReportType())) { + if (entity.getShareUrl().contains(SHARE_URL)) { + String prefix = entity.getShareUrl().substring(0, entity.getShareUrl().indexOf("#")); + entity.setShareUrl(prefix + SHARE_AJFLAG + shareCode); + }else { + entity.setShareUrl(entity.getShareUrl() + SHARE_AJFLAG + shareCode); + } + }else if (EXCEL.equals(entity.getReportType())) { + if (entity.getShareUrl().contains(SHARE_URL)) { + String prefix = entity.getShareUrl().substring(0, entity.getShareUrl().indexOf("#")); + entity.setShareUrl(prefix + SHARE_ELFLAG + shareCode); + }else { + entity.setShareUrl(entity.getShareUrl() + SHARE_ELFLAG + shareCode); + } + }else { + return; + } + + entity.setShareValidTime(DateUtil.getFutureDateTmdHms(entity.getShareValidType())); + entity.setShareToken(JwtUtil.createToken(entity.getReportCode(), shareCode, entity.getSharePassword(), entity.getShareValidTime())); + } +} diff --git a/src/main/java/com/anjiplus/template/gaea/business/runner/ApplicationInitRunner.java b/src/main/java/com/anjiplus/template/gaea/business/runner/ApplicationInitRunner.java new file mode 100644 index 0000000..6beecc7 --- /dev/null +++ b/src/main/java/com/anjiplus/template/gaea/business/runner/ApplicationInitRunner.java @@ -0,0 +1,31 @@ +package com.anjiplus.template.gaea.business.runner; + +import com.anjiplus.template.gaea.business.modules.accessauthority.service.AccessAuthorityService; +import com.anjiplus.template.gaea.business.modules.dict.service.GaeaDictService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.ApplicationArguments; +import org.springframework.boot.ApplicationRunner; + +/** + * @desc 启动加载器 + * @author WongBin + * @date 2019-02-17 08:50:10.009 + **/ +public class ApplicationInitRunner implements ApplicationRunner { + + @Autowired + private GaeaDictService gaeaDictService; + + @Autowired + private AccessAuthorityService accessAuthorityService; + + @Override + public void run(ApplicationArguments args) throws Exception { + + //1、数据字典刷新 + // gaeaDictService.refreshCache(null); + + //2. 建立url权限拦截体系 + accessAuthorityService.scanGaeaSecurityAuthorities(); + } +} diff --git a/src/main/java/com/anjiplus/template/gaea/business/util/AESUtil.java b/src/main/java/com/anjiplus/template/gaea/business/util/AESUtil.java new file mode 100644 index 0000000..9a488dd --- /dev/null +++ b/src/main/java/com/anjiplus/template/gaea/business/util/AESUtil.java @@ -0,0 +1,152 @@ +/* + *Copyright © 2018 anji-plus + *安吉加加信息技术有限公司 + *http://www.anji-plus.com + *All rights reserved. + */ +package com.anjiplus.template.gaea.business.util; + + +import org.apache.commons.lang3.StringUtils; + +import javax.crypto.Cipher; +import javax.crypto.KeyGenerator; +import javax.crypto.spec.SecretKeySpec; +import java.math.BigInteger; +import java.util.Base64; + + +public class AESUtil { + //算法 + private static final String ALGORITHMSTR = "AES/ECB/PKCS5Padding"; + + private static final String AES_KEY = "AnjiPLUSAjReport"; + + + /** + * 获取随机key + * + * @return + */ + public static String getKey() { + return AES_KEY; + } + + + /** + * 将byte[]转为各种进制的字符串 + * + * @param bytes byte[] + * @param radix 可以转换进制的范围,从Character.MIN_RADIX到Character.MAX_RADIX,超出范围后变为10进制 + * @return 转换后的字符串 + */ + public static String binary(byte[] bytes, int radix) { + return new BigInteger(1, bytes).toString(radix);// 这里的1代表正数 + } + + /** + * base 64 encode + * + * @param bytes 待编码的byte[] + * @return 编码后的base 64 code + */ + public static String base64Encode(byte[] bytes) { + //return Base64.encodeBase64String(bytes); + return Base64.getEncoder().encodeToString(bytes); + } + + /** + * base 64 decode + * + * @param base64Code 待解码的base 64 code + * @return 解码后的byte[] + * @throws Exception + */ + public static byte[] base64Decode(String base64Code) throws Exception { + Base64.Decoder decoder = Base64.getDecoder(); + return StringUtils.isEmpty(base64Code) ? null : decoder.decode(base64Code); + } + + + /** + * AES加密 + * + * @param content 待加密的内容 + * @param encryptKey 加密密钥 + * @return 加密后的byte[] + * @throws Exception + */ + public static byte[] aesEncryptToBytes(String content, String encryptKey) throws Exception { + KeyGenerator kgen = KeyGenerator.getInstance("AES"); + kgen.init(128); + Cipher cipher = Cipher.getInstance(ALGORITHMSTR); + cipher.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(encryptKey.getBytes(), "AES")); + + return cipher.doFinal(content.getBytes("utf-8")); + } + + + /** + * AES加密为base 64 code + * + * @param content 待加密的内容 + * @param encryptKey 加密密钥 + * @return 加密后的base 64 code + * @throws Exception + */ + public static String aesEncrypt(String content, String encryptKey) throws Exception { + if (StringUtils.isBlank(encryptKey)) { + return content; + } + return base64Encode(aesEncryptToBytes(content, encryptKey)); + } + + /** + * AES解密 + * + * @param encryptBytes 待解密的byte[] + * @param decryptKey 解密密钥 + * @return 解密后的String + * @throws Exception + */ + public static String aesDecryptByBytes(byte[] encryptBytes, String decryptKey) throws Exception { + KeyGenerator kgen = KeyGenerator.getInstance("AES"); + kgen.init(128); + + Cipher cipher = Cipher.getInstance(ALGORITHMSTR); + cipher.init(Cipher.DECRYPT_MODE, new SecretKeySpec(decryptKey.getBytes(), "AES")); + byte[] decryptBytes = cipher.doFinal(encryptBytes); + return new String(decryptBytes); + } + + + /** + * 将base 64 code AES解密 + * + * @param encryptStr 待解密的base 64 code + * @param decryptKey 解密密钥 + * @return 解密后的string + * @throws Exception + */ + public static String aesDecrypt(String encryptStr, String decryptKey) throws Exception { + if (StringUtils.isBlank(decryptKey)) { + return encryptStr; + } + return StringUtils.isEmpty(encryptStr) ? null : aesDecryptByBytes(base64Decode(encryptStr), decryptKey); + } + + /** + * 测试 + */ + public static void main(String[] args) throws Exception { + String randomString = getKey(); + String content = "report"; + System.out.println("加密前:" + content); + System.out.println("加密密钥和解密密钥:" + randomString); + String encrypt = aesEncrypt(content, randomString); + System.out.println("加密后:" + encrypt); + String decrypt = aesDecrypt(encrypt, randomString); + System.out.println("解密后:" + decrypt); + } + +} diff --git a/src/main/java/com/anjiplus/template/gaea/business/util/DateUtil.java b/src/main/java/com/anjiplus/template/gaea/business/util/DateUtil.java new file mode 100644 index 0000000..0422dd7 --- /dev/null +++ b/src/main/java/com/anjiplus/template/gaea/business/util/DateUtil.java @@ -0,0 +1,86 @@ +package com.anjiplus.template.gaea.business.util; + +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.Calendar; +import java.util.Date; + +/** + * Created by raodeming on 2021/4/29. + */ +public class DateUtil { + + private static String defaultDatePattern = "yyyy-MM-dd"; + + private static String defaultDateTimePattern = "yyyy-MM-dd HH:mm:ss.SSS"; + + private static String defaultyyyyMMddPattern = "yyyyMMdd"; + + private static String defaultYmdHmsPattern = "yyyy-MM-dd HH:mm:ss"; + + private static String defaultHmsPattern = "HH:mm:ss"; + /**字符串yyyy-MM-dd HH:mm:ss转日期 + * @param dateStr yyyy-MM-dd HH:mm:ss + * @return + */ + public static Date parseHmsTime(String dateStr) { + return parse(dateStr, defaultYmdHmsPattern); + } + + /**字符串转日期 + * @param dateStr + * @param pattern + * @return + */ + public static Date parse(String dateStr, String pattern) { + SimpleDateFormat sdf = new SimpleDateFormat(pattern); + if (dateStr == null || "".equals(dateStr)) { + return null; + } + try { + Date d = sdf.parse(dateStr); + return d; + } catch (ParseException e) { + System.out.println("日期转换错误: " + e.getMessage()); + return null; + } + } + + /** + * 获取未来第几天的日期 + * + * @param day + * @return + */ + public static Date getFutureDateTmdHms(int day) { + if (day <= 0) { + //默认2099年 + return parse("2099-01-01", defaultDatePattern); + } + Calendar calendar = Calendar.getInstance(); + calendar.set(Calendar.DAY_OF_YEAR, calendar.get(Calendar.DAY_OF_YEAR) + day); + return calendar.getTime(); + } + + /**未来时间 + * 根据指定时间获取 + * @param time + * @param day + * @return + */ + public static Date getFutureDateTmdHmsByTime(Date time, int day) { + if (day <= 0) { + //默认2099年 + return parse("2099-01-01", defaultDatePattern); + } + Calendar calendar = Calendar.getInstance(); + calendar.setTime(time); + calendar.set(Calendar.DAY_OF_YEAR, calendar.get(Calendar.DAY_OF_YEAR) + day); + return calendar.getTime(); + } + + public static void main(String[] args) { + Date futureDateTmdHms = getFutureDateTmdHms(7); + System.out.println(futureDateTmdHms); + } +} diff --git a/src/main/java/com/anjiplus/template/gaea/business/util/FileUtil.java b/src/main/java/com/anjiplus/template/gaea/business/util/FileUtil.java new file mode 100644 index 0000000..a0ac736 --- /dev/null +++ b/src/main/java/com/anjiplus/template/gaea/business/util/FileUtil.java @@ -0,0 +1,471 @@ +package com.anjiplus.template.gaea.business.util; + +import com.anji.plus.gaea.exception.BusinessExceptionBuilder; +import com.anjiplus.template.gaea.business.code.ResponseCode; +import lombok.extern.slf4j.Slf4j; +import org.springframework.web.multipart.MultipartFile; + +import java.io.*; +import java.net.URL; +import java.nio.channels.FileChannel; +import java.nio.charset.StandardCharsets; +import java.nio.file.*; +import java.nio.file.attribute.BasicFileAttributes; +import java.util.Enumeration; +import java.util.zip.*; + +/** + * Created by raodeming on 2021/8/23. + */ +@Slf4j +public class FileUtil { + + //链接url下载图片 + public static void downloadPicture(String urlPath, String path) { + URL url = null; + try { + url = new URL(urlPath); + DataInputStream dataInputStream = new DataInputStream(url.openStream()); + + FileOutputStream fileOutputStream = new FileOutputStream(path); + ByteArrayOutputStream output = new ByteArrayOutputStream(); + + byte[] buffer = new byte[1024]; + int length; + + while ((length = dataInputStream.read(buffer)) > 0) { + output.write(buffer, 0, length); + } + fileOutputStream.write(output.toByteArray()); + dataInputStream.close(); + fileOutputStream.close(); + log.info("链接下载图片:{},临时路径:{}", urlPath, path); + } catch (IOException e) { + log.error("根据链接下载失败", e); + throw BusinessExceptionBuilder.build(ResponseCode.FILE_OPERATION_FAILED, e.getMessage()); + } + } + + + /** + * 复制文件 + * + * @param source + * @param dest + * @throws IOException + */ + public static void copyFileUsingFileChannels(File source, File dest) { + FileChannel inputChannel = null; + FileChannel outputChannel = null; + try { + if (!dest.getParentFile().exists()) { + dest.getParentFile().mkdirs(); + } + inputChannel = new FileInputStream(source).getChannel(); + outputChannel = new FileOutputStream(dest).getChannel(); + outputChannel.transferFrom(inputChannel, 0, inputChannel.size()); + } catch (IOException e) { + log.error("复制文件失败", e); + throw BusinessExceptionBuilder.build(ResponseCode.FILE_OPERATION_FAILED, e.getMessage()); + } finally { + try { + inputChannel.close(); + outputChannel.close(); + } catch (IOException e) { + log.error("", e); + throw BusinessExceptionBuilder.build(ResponseCode.FILE_OPERATION_FAILED, e.getMessage()); + } + } + } + + /** + * 复制文件 + * + * @param source + * @param dest + * @throws IOException + */ + public static void copyFileUsingFileChannels(String source, String dest) { + copyFileUsingFileChannels(new File(source), new File(dest)); + } + + + public static void WriteStringToFile(String filePath, String content) { + try { + //不存在创建文件 + File file = new File(filePath); + if (!file.getParentFile().exists()) { + file.getParentFile().mkdirs(); + } + FileOutputStream outputStream = new FileOutputStream(filePath); + OutputStreamWriter outputWriter = new OutputStreamWriter(outputStream, StandardCharsets.UTF_8); + BufferedWriter bw = new BufferedWriter(outputWriter); + bw.write(content); + bw.close(); + outputWriter.close(); + outputStream.close(); + } catch (Exception e) { + log.error("写入文件失败", e); + throw BusinessExceptionBuilder.build(ResponseCode.FILE_OPERATION_FAILED, e.getMessage()); + } + } + + + /** + * 根据文件读取文本文件内容 + * + * @param file + * @return + */ + public static String readFile(File file) { + BufferedReader reader = null; + InputStreamReader isr = null; + StringBuilder sbf = new StringBuilder(); + try { + isr = new InputStreamReader(new FileInputStream(file), StandardCharsets.UTF_8); + reader = new BufferedReader(isr); + String tempStr; + while ((tempStr = reader.readLine()) != null) { + sbf.append(tempStr); + } + reader.close(); + return sbf.toString(); + } catch (IOException e) { + log.error("读文件失败", e); + throw BusinessExceptionBuilder.build(ResponseCode.FILE_OPERATION_FAILED, e.getMessage()); + } finally { + if (null != isr) { + try { + isr.close(); + } catch (IOException e) { + throw BusinessExceptionBuilder.build(ResponseCode.FILE_OPERATION_FAILED, e.getMessage()); + } + } + if (reader != null) { + try { + reader.close(); + } catch (IOException e1) { + throw BusinessExceptionBuilder.build(ResponseCode.FILE_OPERATION_FAILED, e1.getMessage()); + } + } + } + } + + /** + * 根据文件路径读取文本文件内容 + * + * @param filePath + * @return + */ + public static String readFile(String filePath) { + File file = new File(filePath); + return readFile(file); + } + + static final int BUFFER = 8192; + + /** + * 将文件夹压缩zip包 + * + * @param srcPath + * @param dstPath + * @throws IOException + */ + public static void compress(String srcPath, String dstPath) { + File srcFile = new File(srcPath); + File dstFile = new File(dstPath); + + FileOutputStream out = null; + ZipOutputStream zipOut = null; + try { + out = new FileOutputStream(dstFile); + CheckedOutputStream cos = new CheckedOutputStream(out, new CRC32()); + zipOut = new ZipOutputStream(cos, StandardCharsets.UTF_8); + String baseDir = ""; + compress(srcFile, zipOut, baseDir); + } catch (IOException e) { + log.error("压缩文件夹失败", e); + throw BusinessExceptionBuilder.build(ResponseCode.FILE_OPERATION_FAILED, e.getMessage()); + } finally { + if (null != zipOut) { + try { + zipOut.close(); + } catch (IOException e) { + log.error("", e); + throw BusinessExceptionBuilder.build(ResponseCode.FILE_OPERATION_FAILED, e.getMessage()); + } + out = null; + } + if (null != out) { + try { + out.close(); + } catch (IOException e) { + log.error("", e); + throw BusinessExceptionBuilder.build(ResponseCode.FILE_OPERATION_FAILED, e.getMessage()); + } + } + } + } + + private static void compress(File file, ZipOutputStream zipOut, String baseDir) { + if (file.isDirectory()) { + compressDirectory(file, zipOut, baseDir); + } else { + compressFile(file, zipOut, baseDir); + } + } + + /** + * 压缩一个目录 + */ + private static void compressDirectory(File dir, ZipOutputStream zipOut, String baseDir) { + File[] files = dir.listFiles(); + for (int i = 0; i < files.length; i++) { + compress(files[i], zipOut, baseDir + dir.getName() + "/"); + } + } + + /** + * 压缩一个文件 + */ + private static void compressFile(File file, ZipOutputStream zipOut, String baseDir) { + if (!file.exists()) { + return; + } + + BufferedInputStream bis = null; + try { + bis = new BufferedInputStream(new FileInputStream(file)); + ZipEntry entry = new ZipEntry(baseDir + file.getName()); + zipOut.putNextEntry(entry); + int count; + byte data[] = new byte[BUFFER]; + while ((count = bis.read(data, 0, BUFFER)) != -1) { + zipOut.write(data, 0, count); + } + + } catch (IOException e) { + log.error("压缩文件夹失败", e); + throw BusinessExceptionBuilder.build(ResponseCode.FILE_OPERATION_FAILED, e.getMessage()); + } finally { + if (null != bis) { + try { + bis.close(); + } catch (IOException e) { + log.error("", e); + throw BusinessExceptionBuilder.build(ResponseCode.FILE_OPERATION_FAILED, e.getMessage()); + } + } + } + } + + public static void decompress(String zipFile, String dstPath) { + try { + decompress(new ZipFile(zipFile), dstPath); + } catch (IOException e) { + log.error("", e); + throw BusinessExceptionBuilder.build(ResponseCode.FILE_OPERATION_FAILED, e.getMessage()); + } + } + + public static void decompress(MultipartFile zipFile, String dstPath) { + try { + File dir = new File(dstPath); + if (!dir.exists()){ + dir.mkdirs(); + } + String path = dir.getPath(); + String absolutePath = dir.getAbsolutePath(); + File file = new File(dir.getAbsolutePath() + File.separator + zipFile.getOriginalFilename()); + zipFile.transferTo(file); + decompress(new ZipFile(file), dstPath); + //解压完删除 + file.delete(); + } catch (IOException e) { + log.error("", e); + throw BusinessExceptionBuilder.build(ResponseCode.FILE_OPERATION_FAILED, e.getMessage()); + } + } + + /** + * 解压zip + * + * @param zip + * @param dstPath + * @throws IOException + */ + public static void decompress(ZipFile zip, String dstPath) { + log.info("解压zip:{},临时目录:{}", zip.getName(), dstPath); + File pathFile = new File(dstPath); + if (!pathFile.exists()) { + pathFile.mkdirs(); + } + try { + + for (Enumeration entries = zip.entries(); entries.hasMoreElements(); ) { + ZipEntry entry = (ZipEntry) entries.nextElement(); + String zipEntryName = entry.getName(); + InputStream in = null; + OutputStream out = null; + try { + in = zip.getInputStream(entry); + String outPath = (dstPath + "/" + zipEntryName).replaceAll("\\*", "/"); + ; + //判断路径是否存在,不存在则创建文件路径 + File file = new File(outPath.substring(0, outPath.lastIndexOf('/'))); + if (!file.exists()) { + file.mkdirs(); + } + //判断文件全路径是否为文件夹,如果是上面已经上传,不需要解压 + if (new File(outPath).isDirectory()) { + continue; + } + + out = new FileOutputStream(outPath); + byte[] buf1 = new byte[1024]; + int len; + while ((len = in.read(buf1)) > 0) { + out.write(buf1, 0, len); + } + } catch (IOException e) { + log.error("解压失败", e); + throw BusinessExceptionBuilder.build(ResponseCode.FILE_OPERATION_FAILED, e.getMessage()); + } finally { + if (null != in) { + try { + in.close(); + } catch (IOException e) { + log.error("", e); + throw BusinessExceptionBuilder.build(ResponseCode.FILE_OPERATION_FAILED, e.getMessage()); + } + } + + if (null != out) { + try { + out.close(); + } catch (IOException e) { + log.error("", e); + throw BusinessExceptionBuilder.build(ResponseCode.FILE_OPERATION_FAILED, e.getMessage()); + } + } + } + } + zip.close(); + } catch (IOException e) { + log.error("解压失败", e); + throw BusinessExceptionBuilder.build(ResponseCode.FILE_OPERATION_FAILED, e.getMessage()); + } + } + + /** + * 获取流文件 + * @param ins + * @param file + */ + private static void inputStreamToFile(InputStream ins, File file) { + try { + OutputStream os = new FileOutputStream(file); + int bytesRead = 0; + byte[] buffer = new byte[8192]; + while ((bytesRead = ins.read(buffer, 0, 8192)) != -1) { + os.write(buffer, 0, bytesRead); + } + os.close(); + ins.close(); + } catch (Exception e) { + log.error("获取流文件失败", e); + throw BusinessExceptionBuilder.build(ResponseCode.FILE_OPERATION_FAILED, e.getMessage()); + } + } + + /** + * 删除文件夹 + * + * @param path + */ + public static void delete(String path) { + + Path directory = Paths.get(path); + try { + Files.walkFileTree(directory, new SimpleFileVisitor() { + @Override + public FileVisitResult visitFile(Path file, BasicFileAttributes attributes) throws IOException { + Files.delete(file); // this will work because it's always a File + return FileVisitResult.CONTINUE; + } + + @Override + public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOException { + Files.delete(dir); //this will work because Files in the directory are already deleted + return FileVisitResult.CONTINUE; + } + }); + } catch (IOException e) { + log.error("删除文件失败", e); + throw BusinessExceptionBuilder.build(ResponseCode.FILE_OPERATION_FAILED, e.getMessage()); + } + } + + /** + * byte 转file + */ + public static File byte2File(byte[] buf, String filePath, String fileName){ + BufferedOutputStream bos = null; + FileOutputStream fos = null; + File file = null; + try{ + File dir = new File(filePath); + if (!dir.exists()){ + dir.mkdirs(); + } + file = new File(filePath + File.separator + fileName); + fos = new FileOutputStream(file); + bos = new BufferedOutputStream(fos); + bos.write(buf); + }catch (Exception e){ + log.error("", e); + throw BusinessExceptionBuilder.build(ResponseCode.FILE_OPERATION_FAILED, e.getMessage()); + } + finally{ + if (bos != null){ + try{ + bos.close(); + }catch (IOException e){ + log.error("", e); + throw BusinessExceptionBuilder.build(ResponseCode.FILE_OPERATION_FAILED, e.getMessage()); + } + } + if (fos != null){ + try{ + fos.close(); + }catch (IOException e){ + log.error("", e); + throw BusinessExceptionBuilder.build(ResponseCode.FILE_OPERATION_FAILED, e.getMessage()); + } + } + } + return file; + } + + + public static void main(String[] args) throws Exception { +// String targetFolderPath = "D:\\aa"; +// String rawZipFilePath = "D:\\aa.zip"; +// String newZipFilePath = "D:\\aa.zip"; +// +// +// //将目标目录的文件压缩成Zip文件 +// FileUtil.compress(targetFolderPath, newZipFilePath); +// +// //将Zip文件解压缩到目标目录 +// FileUtil.decompress(rawZipFilePath, targetFolderPath); + +// FileUtil.downloadPicture("http://10.108.26.197:9095/file/download/fd20d563-00aa-45e2-b5db-aff951f814ec", "D:\\abc.png"); + + +// delete("D:\\aa"); + + } + + +} diff --git a/src/main/java/com/anjiplus/template/gaea/business/util/JdbcConstants.java b/src/main/java/com/anjiplus/template/gaea/business/util/JdbcConstants.java new file mode 100644 index 0000000..0d2febe --- /dev/null +++ b/src/main/java/com/anjiplus/template/gaea/business/util/JdbcConstants.java @@ -0,0 +1,78 @@ +package com.anjiplus.template.gaea.business.util; + +/** + * Created by raodeming on 2021/3/19. + */ +public class JdbcConstants { + /** + * 已支持的数据源 + */ + public final static String KUDU_IMAPLA = "kudu_impala"; + public final static String HTTP = "http"; + public final static String MYSQL = "mysql"; + public final static String ORACLE = "oracle"; + public final static String ELASTIC_SEARCH_SQL = "elasticsearch_sql"; + public final static String SQL_SERVER = "mssqlserver"; + public final static String JDBC = "jdbc"; + public final static String POSTGRESQL = "postgresql"; + + + public final static String JTDS = "jtds"; + public final static String MOCK = "mock"; + public final static String HSQL = "hsql"; + public final static String DB2 = "db2"; + public final static String DB2_DRIVER = "COM.ibm.db2.jdbc.app.DB2Driver"; + public final static String POSTGRESQL_DRIVER = "org.postgresql.Driver"; + public final static String SYBASE = "sybase"; + public final static String SQL_SERVER_DRIVER = "com.microsoft.jdbc.sqlserver.SQLServerDriver"; + public final static String SQL_SERVER_DRIVER_SQLJDBC4 = "com.microsoft.sqlserver.jdbc.SQLServerDriver"; + public final static String SQL_SERVER_DRIVER_JTDS = "net.sourceforge.jtds.jdbc.Driver"; + public final static String ORACLE_DRIVER = "oracle.jdbc.OracleDriver"; + public final static String ORACLE_DRIVER2 = "oracle.jdbc.driver.OracleDriver"; + public final static String ALI_ORACLE = "AliOracle"; + public final static String ALI_ORACLE_DRIVER = "com.alibaba.jdbc.AlibabaDriver"; + public final static String MYSQL_DRIVER = "com.mysql.jdbc.Driver"; + public final static String MYSQL_DRIVER_6 = "com.mysql.cj.jdbc.Driver"; + public final static String MYSQL_DRIVER_REPLICATE = "com.mysql.jdbc."; + public final static String MARIADB = "mariadb"; + public final static String MARIADB_DRIVER = "org.mariadb.jdbc.Driver"; + public final static String DERBY = "derby"; + public final static String HBASE = "hbase"; + public final static String HIVE = "hive"; + public final static String HIVE_DRIVER = "org.apache.hive.jdbc.HiveDriver"; + public final static String H2 = "h2"; + public final static String H2_DRIVER = "org.h2.Driver"; + public final static String DM = "dm"; + public final static String DM_DRIVER = "dm.jdbc.driver.DmDriver"; + public final static String KINGBASE = "kingbase"; + public final static String KINGBASE_DRIVER = "com.kingbase.Driver"; + public final static String GBASE = "gbase"; + public final static String GBASE_DRIVER = "com.gbase.jdbc.Driver"; + public final static String XUGU = "xugu"; + public final static String XUGU_DRIVER = "com.xugu.cloudjdbc.Driver"; + public final static String OCEANBASE = "oceanbase"; + public final static String OCEANBASE_DRIVER = "com.mysql.jdbc.Driver"; + public final static String INFORMIX = "informix"; + public final static String ODPS = "odps"; + public final static String ODPS_DRIVER = "com.aliyun.odps.jdbc.OdpsDriver"; + public final static String TERADATA = "teradata"; + public final static String TERADATA_DRIVER = "com.teradata.jdbc.TeraDriver"; + public final static String LOG4JDBC = "log4jdbc"; + public final static String LOG4JDBC_DRIVER = "net.sf.log4jdbc.DriverSpy"; + public final static String PHOENIX = "phoenix"; + public final static String PHOENIX_DRIVER = "org.apache.phoenix.jdbc.PhoenixDriver"; + public final static String ENTERPRISEDB = "edb"; + public final static String ENTERPRISEDB_DRIVER = "com.edb.Driver"; + public final static String KYLIN = "kylin"; + public final static String KYLIN_DRIVER = "org.apache.kylin.jdbc.Driver"; + public final static String SQLITE = "sqlite"; + public final static String SQLITE_DRIVER = "org.sqlite.JDBC"; + public final static String ALIYUN_ADS = "aliyun_ads"; + public final static String ALIYUN_DRDS = "aliyun_drds"; + public final static String PRESTO = "presto"; + public final static String ELASTIC_SEARCH = "elasticsearch"; + public final static String ELASTIC_SEARCH_DRIVER = "com.alibaba.xdriver.elastic.jdbc.ElasticDriver"; + public final static String CLICKHOUSE = "clickhouse"; + public final static String CLICKHOUSE_DRIVER = "ru.yandex.clickhouse.ClickHouseDriver"; + +} diff --git a/src/main/java/com/anjiplus/template/gaea/business/util/JwtUtil.java b/src/main/java/com/anjiplus/template/gaea/business/util/JwtUtil.java new file mode 100644 index 0000000..2646159 --- /dev/null +++ b/src/main/java/com/anjiplus/template/gaea/business/util/JwtUtil.java @@ -0,0 +1,88 @@ +package com.anjiplus.template.gaea.business.util; + +import com.anji.plus.gaea.constant.GaeaConstant; +import com.anji.plus.gaea.exception.BusinessExceptionBuilder; +import com.anjiplus.template.gaea.business.code.ResponseCode; +import com.auth0.jwt.JWT; +import com.auth0.jwt.JWTVerifier; +import com.auth0.jwt.algorithms.Algorithm; +import com.auth0.jwt.interfaces.Claim; +import com.auth0.jwt.interfaces.DecodedJWT; +import org.apache.commons.lang3.StringUtils; + +import java.util.Arrays; +import java.util.Date; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +/** + * Created by raodeming on 2021/8/18. + */ +public class JwtUtil { + + private static final String JWT_SECRET = "aj-report"; + + public static String createToken(String reportCode, String shareCode, Date expires) { + return createToken(reportCode, shareCode, null, expires); + } + + public static String createToken(String reportCode, String shareCode, String password, Date expires) { + String token = JWT.create() + .withIssuedAt(new Date()) + .withExpiresAt(expires) + .withClaim("reportCode", reportCode) + .withClaim("shareCode", shareCode) + .withClaim("sharePassword", password) + .sign(Algorithm.HMAC256(JWT_SECRET)); + return token; + } + + + public static Map getClaim(String token) { + try { + JWTVerifier jwtVerifier = JWT.require(Algorithm.HMAC256(JWT_SECRET)).build(); + DecodedJWT decodedJwt = jwtVerifier.verify(token); + return decodedJwt.getClaims(); + } catch (Exception e) { + throw BusinessExceptionBuilder.build(ResponseCode.REPORT_SHARE_LINK_INVALID, e.getMessage()); + } + } + + public static String getReportCode(String token) { + Claim claim = getClaim(token).get("reportCode"); + if (null == claim) { + throw BusinessExceptionBuilder.build(ResponseCode.REPORT_SHARE_LINK_INVALID); + } + return claim.asString(); + } + + /** + * 存在多个分享token + * @param tokenList + * @return + */ + public static List getReportCodeList(String tokenList) { + return Arrays.stream(tokenList.split(GaeaConstant.SPLIT)).filter(StringUtils::isNotBlank).map(JwtUtil::getReportCode).distinct().collect(Collectors.toList()); + } + + public static String getShareCode(String token) { + Claim claim = getClaim(token).get("shareCode"); + if (null == claim) { + throw BusinessExceptionBuilder.build(ResponseCode.REPORT_SHARE_LINK_INVALID); + } + return claim.asString(); + } + + public static String getPassword(String token) { + Claim claim = getClaim(token).get("sharePassword"); + if (null == claim) { + return null; + } + if (StringUtils.isNotBlank(claim.asString())) { + return claim.asString(); + } + return null; + } + +} diff --git a/src/main/java/com/anjiplus/template/gaea/business/util/MD5Util.java b/src/main/java/com/anjiplus/template/gaea/business/util/MD5Util.java new file mode 100644 index 0000000..11c5e1b --- /dev/null +++ b/src/main/java/com/anjiplus/template/gaea/business/util/MD5Util.java @@ -0,0 +1,29 @@ +package com.anjiplus.template.gaea.business.util; + +import lombok.extern.slf4j.Slf4j; + +import java.security.MessageDigest; + +@Slf4j +public class MD5Util { + /** + * 获取指定字符串的md5值 + * @param dataStr 明文 + * @return String + */ + public static String encrypt(String dataStr) { + try { + MessageDigest m = MessageDigest.getInstance("MD5"); + m.update(dataStr.getBytes("UTF8")); + byte[] s = m.digest(); + StringBuilder result = new StringBuilder(); + for (int i = 0; i < s.length; i++) { + result.append(Integer.toHexString((0x000000FF & s[i]) | 0xFFFFFF00).substring(6)); + } + return result.toString(); + } catch (Exception e) { + log.error("error",e); + } + return ""; + } +} diff --git a/src/main/java/com/anjiplus/template/gaea/business/util/RequestUtil.java b/src/main/java/com/anjiplus/template/gaea/business/util/RequestUtil.java new file mode 100644 index 0000000..dda0273 --- /dev/null +++ b/src/main/java/com/anjiplus/template/gaea/business/util/RequestUtil.java @@ -0,0 +1,50 @@ +package com.anjiplus.template.gaea.business.util; + +import org.apache.commons.lang3.StringUtils; + +import javax.servlet.http.HttpServletRequest; + +/** + * @author: Raod + * @since: 2022-01-21 + */ +public class RequestUtil { + + /**获取ip地址 + * @param request + * @return + */ + public static String getIpAddr(HttpServletRequest request) { + String Xip = request.getHeader("X-Real-IP"); + String XFor = request.getHeader("X-Forwarded-For"); + if(StringUtils.isNotEmpty(XFor) && !"unKnown".equalsIgnoreCase(XFor)){ + //多次反向代理后会有多个ip值,第一个ip才是真实ip + int index = XFor.indexOf(","); + if(index != -1){ + return XFor.substring(0,index); + }else{ + return XFor; + } + } + XFor = Xip; + if(StringUtils.isNotEmpty(XFor) && !"unKnown".equalsIgnoreCase(XFor)){ + return XFor; + } + if (StringUtils.isBlank(XFor) || "unknown".equalsIgnoreCase(XFor)) { + XFor = request.getHeader("Proxy-Client-IP"); + } + if (StringUtils.isBlank(XFor) || "unknown".equalsIgnoreCase(XFor)) { + XFor = request.getHeader("WL-Proxy-Client-IP"); + } + if (StringUtils.isBlank(XFor) || "unknown".equalsIgnoreCase(XFor)) { + XFor = request.getHeader("HTTP_CLIENT_IP"); + } + if (StringUtils.isBlank(XFor) || "unknown".equalsIgnoreCase(XFor)) { + XFor = request.getHeader("HTTP_X_FORWARDED_FOR"); + } + if (StringUtils.isBlank(XFor) || "unknown".equalsIgnoreCase(XFor)) { + XFor = request.getRemoteAddr(); + } + return XFor; + } +} diff --git a/src/main/java/com/anjiplus/template/gaea/business/util/ResponseUtil2.java b/src/main/java/com/anjiplus/template/gaea/business/util/ResponseUtil2.java new file mode 100644 index 0000000..fe0aeda --- /dev/null +++ b/src/main/java/com/anjiplus/template/gaea/business/util/ResponseUtil2.java @@ -0,0 +1,60 @@ +package com.anjiplus.template.gaea.business.util; + +import com.anji.plus.gaea.oss.exceptions.GaeaOSSException; +import com.anji.plus.gaea.oss.utils.ResponseUtil; +import com.anji.plus.gaea.oss.utils.StringPatternUtil; +import org.springframework.http.CacheControl; +import org.springframework.http.MediaType; +import org.springframework.http.ResponseEntity; +import org.springframework.util.StringUtils; + +import java.net.URLEncoder; + +public class ResponseUtil2 extends ResponseUtil { + /** + * 根据文件后缀来判断,是显示图片\视频\音频,还是下载文件 + * @param fileObjectName 文件原始名称,如:订单导入.xls banner.png + * @param fileBytes 文件字节流 + * @param isIEBrowser 是否是IE浏览器 + * @return + */ + public static ResponseEntity writeBody(String fileObjectName, byte[] fileBytes, boolean isIEBrowser){ + try{ + if(StringUtils.isEmpty(fileObjectName) || !fileObjectName.contains(".")){ + throw new GaeaOSSException("original file name or type is empty"); + } + // 文件后缀名 + String fileSuffixName = fileObjectName.substring(fileObjectName.lastIndexOf(".")); + + // 初始化响应体 + ResponseEntity.BodyBuilder builder = ResponseEntity.ok(); + builder.contentLength(fileBytes.length); + + // 判断文件是图片视频还是文件 + String pattern1 = "(.png|.jpg|.jpeg|.bmp|.gif|.icon|.svg)"; + String pattern2 = "(.flv|.swf|.mkv|.avi|.rm|.rmvb|.mpeg|.mpg|.ogg|.ogv|.mov|.wmv|.mp4|.webm|.wav|.mid|.mp3|.aac)"; + if (StringPatternUtil.StringMatchIgnoreCase(fileSuffixName, pattern1)) { + if (fileSuffixName.equalsIgnoreCase(".svg")) { + builder.cacheControl(CacheControl.noCache()).contentType(MediaType.parseMediaType("image/svg+xml")); + } else { + builder.cacheControl(CacheControl.noCache()).contentType(MediaType.IMAGE_PNG); + } + } else if (StringPatternUtil.StringMatchIgnoreCase(fileSuffixName, pattern2)) { + builder.header("Content-Type", "video/mp4; charset=UTF-8"); + } else { + //application/octet-stream 二进制数据流(最常见的文件下载) + builder.contentType(MediaType.APPLICATION_OCTET_STREAM); + fileObjectName = URLEncoder.encode(fileObjectName, "UTF-8"); + if (isIEBrowser) { + builder.header("Content-Disposition", "attachment; filename=" + fileObjectName); + } else { + builder.header("Content-Disposition", "attacher; filename*=UTF-8''" + fileObjectName); + } + } + return builder.body(fileBytes); + }catch (Exception e){ + e.printStackTrace(); + return null; + } + } +} diff --git a/src/main/java/com/anjiplus/template/gaea/business/util/UuidUtil.java b/src/main/java/com/anjiplus/template/gaea/business/util/UuidUtil.java new file mode 100644 index 0000000..40031aa --- /dev/null +++ b/src/main/java/com/anjiplus/template/gaea/business/util/UuidUtil.java @@ -0,0 +1,65 @@ +package com.anjiplus.template.gaea.business.util; + +import java.security.SecureRandom; +import java.util.UUID; + +/** + * Created by raodeming on 2021/8/19. + */ +public class UuidUtil { + + public static String[] chars = new String[] { "a", "b", "c", "d", "e", "f", + "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", + "t", "u", "v", "w", "x", "y", "z", "0", "1", "2", "3", "4", "5", + "6", "7", "8", "9", "A", "B", "C", "D", "E", "F", "G", "H", "I", + "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", + "W", "X", "Y", "Z" }; + + + /** + * 8位短id + * @return + */ + public static String generateShortUuid() { + StringBuilder builder = new StringBuilder(); + String uuid = UUID.randomUUID().toString().replace("-", ""); + for (int i = 0; i < 8; i++) { + String str = uuid.substring(i * 4, i * 4 + 4); + int x = Integer.parseInt(str, 16); + builder.append(chars[x % 0x3E]); + } + return builder.toString(); + + } + + /** + * 获取随机小写密码 + * @param num + * @return + */ + public static String getRandomPwd(int num) { + StringBuilder builder = new StringBuilder(); + // 因为已经把 4 种字符放进list了,所以 i 取值从 4开始 + // 产生随机数用于随机调用生成字符的函数 + for (int i = 0; i < num; i++) { + SecureRandom random = new SecureRandom(); + int funNum = random.nextInt(chars.length); + builder.append(chars[funNum]); + } + + return builder.toString().toLowerCase(); + } + + + public static String generateUuid() { + return UUID.randomUUID().toString().replace("-", ""); + } + + public static void main(String[] args) { + for (int i = 0; i < 100; i++) { +// System.out.println(generateShortUuid()); + System.out.println(getRandomPwd(4)); + } + + } +} diff --git a/src/main/resources/bootstrap-dev.yml b/src/main/resources/bootstrap-dev.yml new file mode 100644 index 0000000..ace9169 --- /dev/null +++ b/src/main/resources/bootstrap-dev.yml @@ -0,0 +1,16 @@ +# 该文件配置会继承bootstrap.xml,只需要配置数据库等差异配置 +spring: + datasource: + url: jdbc:mysql://82.157.76.162:3306/aj_report?characterEncoding=UTF-8&serverTimezone=Asia/Shanghai&useSSL=false + username: root + password: wB4TL7Mp + gaea: + subscribes: + oss: #文件存储 + enabled: true + ##允许上传的文件后缀 + file-type-while-list: .png|.jpg|.gif|.icon|.pdf|.xlsx|.xls|.csv|.mp4|.avi|.jpeg|.aaa|.svg + # 用于文件上传成功后,生成文件的下载公网完整URL + downloadPath: http://82.157.76.162:9095/file/download + nfs: + path: /data/BS_File/ diff --git a/src/main/resources/bootstrap.yml b/src/main/resources/bootstrap.yml new file mode 100644 index 0000000..3fea610 --- /dev/null +++ b/src/main/resources/bootstrap.yml @@ -0,0 +1,101 @@ +server: + port: 9095 + servlet: + encoding: + charset: UTF-8 + force: true + enabled: true + +spring: + profiles: + active: dev + application: + name: aj-report + servlet: + multipart: + max-file-size: 10MB #上传图片大小限制为10MB + jackson: + date-format: yyyy-MM-dd HH:mm:ss + messages: + basename: i18n/messages + datasource: + url: jdbc:mysql://127.0.0.1:3306/aj_report?characterEncoding=UTF-8&serverTimezone=Asia/Shanghai&useSSL=false + username: root + password: wB4TL7Mp + type: com.zaxxer.hikari.HikariDataSource + hikari: + connection-timeout: 300000 # 连接超时时间 - 默认值:30秒。 + validation-timeout: 5000 # 连接被测试活动的最长时间 - 默认值:5秒。 + idle-timeout: 60000 # 连接池中允许闲置的最长时间 - 默认值:10分钟 + max-lifetime: 1800000 # 一个连接生命时长(毫秒),超时而没被使用则被释放 - 默认值:30分钟 + maximum-pool-size: 10 #连接池中允许的最大连接数,包括闲置和使用中的连接 - 默认值:10 + minimum-idle: 5 # 连接池中允许的最小空闲连接数 - 默认值:10。 + + #如果要使用redis,请参考report-core目录下的README.md文件中写的进行调整 + # redis: + # host: 127.0.0.1 + # port: 6379 + # password: root + # database: 1 + flyway: + enabled: true #是否开启flyway,默认true. + baseline-on-migrate: true + #数据库连接配置 + url: ${spring.datasource.url} + user: ${spring.datasource.username} + password: ${spring.datasource.password} + placeholder-replacement: false + init-sqls: + - CREATE DATABASE IF NOT EXISTS `aj_report` DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci; + gaea: + subscribes: + oss: #文件存储 都配置的情况下优先级minio->amazonS3->nfs + enabled: true + ##允许上传的文件后缀 + file-type-while-list: .png|.jpg|.gif|.icon|.pdf|.xlsx|.xls|.csv|.mp4|.avi|.jpeg|.aaa|.svg + # 用于文件上传成功后,生成文件的下载公网完整URL,http://serverip:9095/file/download,注意填写IP必须填写后端服务所在的机器IP + downloadPath: http://127.0.0.1:9095/file/download + nfs: + #上传对应本地全路径,注意目录不会自动创建,注意 Win是 \ 且有盘符,linux是 / 无盘符,注意目录权限问题 + path: /app/disk/upload/ + #若要使用minio文件存储,请启用以下配置 + #minio: + # url: http://127.0.0.1 + # port: 9000 + # access-key: minioreport + # secret-key: minioreport + # bucket-name: aj-report + #若要使用amazonS3文件存储,请启用以下配置 + #amazonS3: + # url: http://127.0.0.1 + # access-key: access-key + # secret-key: secret-key + # bucket-name: AJ-Report + #若minio和amazonS3都没有,使用服务器高可用的nfs共享盘 + +mybatis-plus: + configuration: + log-impl: org.apache.ibatis.logging.stdout.StdOutImpl #开启sql打印 + call-setters-on-nulls: true + mapperLocations: + - classpath*:/mapper/**/*.xml + - classpath*:/modeler-mybatis-mappings/**/*.xml + +management: + endpoints: + web: + base-path: / +logging: + config: classpath:logback.xml + +# 本应用自定义参数 +customer: + # 跳过token验证和权限验证的url清单 + skip-authenticate-urls: /gaeaDict/all, /login, /static, /file/download/, /index.html, /favicon.ico, /reportShare/detailByCode, /v2/api-docs, /reportDashboard/* + file: + #导入导出临时文件夹 默认.代表当前目录,拼接/tmp_zip/目录 + tmpPath: . + user: + ##新增用户默认密码 + default: + password: 123456 diff --git a/src/main/resources/db/migration/V1.0.0__init.sql b/src/main/resources/db/migration/V1.0.0__init.sql new file mode 100644 index 0000000..77f73d7 --- /dev/null +++ b/src/main/resources/db/migration/V1.0.0__init.sql @@ -0,0 +1,729 @@ + +SET NAMES utf8mb4; +SET FOREIGN_KEY_CHECKS = 0; + +CREATE DATABASE IF NOT EXISTS aj_report DEFAULT CHARACTER SET utf8 DEFAULT COLLATE utf8_general_ci; + +use aj_report; +-- ---------------------------- +-- Table structure for access_authority +-- ---------------------------- +DROP TABLE IF EXISTS `access_authority`; +CREATE TABLE `access_authority` ( + `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键', + `parent_target` varchar(64) CHARACTER SET utf8 COLLATE utf8_bin NULL DEFAULT NULL COMMENT '父ID', + `target` varchar(64) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL COMMENT '菜单代码', + `target_name` varchar(128) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL COMMENT '菜单名称', + `action` varchar(64) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL COMMENT '按钮代码', + `action_name` varchar(128) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL COMMENT '按钮名称', + `sort` int(8) NULL DEFAULT NULL, + `enable_flag` int(1) NOT NULL DEFAULT 1 COMMENT '0--已禁用 1--已启用 DIC_NAME=ENABLE_FLAG', + `delete_flag` int(1) NULL DEFAULT 0 COMMENT ' 0--未删除 1--已删除 DIC_NAME=DEL_FLAG', + `create_by` varchar(64) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL COMMENT '创建人', + `create_time` datetime NOT NULL COMMENT '创建时间', + `update_by` varchar(64) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL COMMENT '修改人', + `update_time` datetime NOT NULL COMMENT '修改时间', + `version` tinyint(8) NULL DEFAULT NULL, + PRIMARY KEY (`id`) USING BTREE, + UNIQUE INDEX `TA_uniq_index`(`target`, `action`) USING BTREE +) ENGINE = InnoDB AUTO_INCREMENT = 330 CHARACTER SET = utf8 COLLATE = utf8_bin COMMENT = '运营权限表' ROW_FORMAT = Dynamic; + +-- ---------------------------- +-- Records of access_authority +-- ---------------------------- +INSERT INTO `access_authority` VALUES (1, NULL, 'access', '用户权限', '', '', 1, 1, 0, 'admin', '2019-07-23 15:59:40', 'admin', '2019-07-23 15:59:40', 1); +INSERT INTO `access_authority` VALUES (2, NULL, 'report', '报表设计', '', '', 2, 1, 0, 'admin', '2019-07-23 15:59:40', 'admin', '2019-07-23 15:59:40', 1); +INSERT INTO `access_authority` VALUES (3, NULL, 'system', '系统设置', '', '', 3, 1, 0, 'admin', '2019-07-23 15:59:40', 'admin', '2019-07-23 15:59:40', 1); +INSERT INTO `access_authority` VALUES (101, 'access', 'authorityManage', '权限管理', 'insert', '新增权限', 101, 1, 0, 'admin', '2019-07-23 15:59:40', 'admin', '2019-07-23 15:59:40', 1); +INSERT INTO `access_authority` VALUES (102, 'access', 'authorityManage', '权限管理', 'update', '修改权限', 102, 1, 0, 'admin', '2019-07-23 15:59:40', 'admin', '2019-07-23 15:59:40', 1); +INSERT INTO `access_authority` VALUES (103, 'access', 'authorityManage', '权限管理', 'delete', '删除权限', 103, 1, 0, 'admin', '2019-07-23 15:59:40', 'admin', '2019-07-23 15:59:40', 1); +INSERT INTO `access_authority` VALUES (104, 'access', 'authorityManage', '权限管理', 'query', '查询权限', 104, 1, 0, 'admin', '2019-07-23 15:59:40', 'admin', '2019-07-23 15:59:40', 1); +INSERT INTO `access_authority` VALUES (105, 'access', 'roleManage', '角色管理', 'insert', '新建角色', 105, 1, 0, 'admin', '2019-07-23 15:59:40', 'admin', '2021-07-17 20:41:46', 2); +INSERT INTO `access_authority` VALUES (106, 'access', 'roleManage', '角色管理', 'update', '修改角色', 106, 1, 0, 'admin', '2019-07-23 15:59:40', 'admin', '2019-07-23 15:59:40', 1); +INSERT INTO `access_authority` VALUES (107, 'access', 'roleManage', '角色管理', 'delete', '删除角色', 107, 1, 0, 'admin', '2019-07-23 15:59:40', 'admin', '2019-07-23 15:59:40', 1); +INSERT INTO `access_authority` VALUES (108, 'access', 'roleManage', '角色管理', 'query', '查询角色', 108, 1, 0, 'admin', '2019-07-23 15:59:40', 'admin', '2019-07-23 15:59:40', 1); +INSERT INTO `access_authority` VALUES (109, 'access', 'roleManage', '角色管理', 'grantAuthority', '分配权限', 109, 1, 0, 'admin', '2019-07-23 15:59:40', 'admin', '2019-07-23 15:59:40', 1); +INSERT INTO `access_authority` VALUES (110, 'access', 'userManage', '用户管理', 'insert', '新增用户', 110, 1, 0, 'admin', '2019-07-23 15:59:40', 'admin', '2019-07-23 15:59:40', 1); +INSERT INTO `access_authority` VALUES (111, 'access', 'userManage', '用户管理', 'update', '修改用户', 111, 1, 0, 'admin', '2019-07-23 15:59:40', 'admin', '2019-07-23 15:59:40', 1); +INSERT INTO `access_authority` VALUES (112, 'access', 'userManage', '用户管理', 'delete', '删除用户', 112, 1, 0, 'admin', '2019-07-23 15:59:40', 'admin', '2019-07-23 15:59:40', 1); +INSERT INTO `access_authority` VALUES (113, 'access', 'userManage', '用户管理', 'query', '查询用户', 113, 1, 0, 'admin', '2019-07-23 15:59:40', 'admin', '2019-07-23 15:59:40', 1); +INSERT INTO `access_authority` VALUES (114, 'access', 'userManage', '用户管理', 'resetPassword', '重置密码', 114, 1, 0, 'admin', '2019-07-23 15:59:40', 'admin', '2019-07-23 15:59:40', 1); +INSERT INTO `access_authority` VALUES (115, 'access', 'userManage', '用户管理', 'grantRole', '分配角色', 115, 1, 0, 'admin', '2019-07-23 15:59:40', 'admin', '2019-07-23 15:59:40', 1); +INSERT INTO `access_authority` VALUES (200, 'report', 'datasourceManage', '数据源管理', 'insert', '新建数据源', 200, 1, 0, 'admin', '2019-07-23 15:59:40', 'admin', '2019-07-23 15:59:40', 1); +INSERT INTO `access_authority` VALUES (201, 'report', 'datasourceManage', '数据源管理', 'update', '修改数据源', 201, 1, 0, 'admin', '2019-07-23 15:59:40', 'admin', '2019-07-23 15:59:40', 1); +INSERT INTO `access_authority` VALUES (202, 'report', 'datasourceManage', '数据源管理', 'delete', '删除数据源', 202, 1, 0, 'admin', '2019-07-23 15:59:40', 'admin', '2019-07-23 15:59:40', 1); +INSERT INTO `access_authority` VALUES (203, 'report', 'datasourceManage', '数据源管理', 'query', '查询数据源', 203, 1, 0, 'admin', '2019-07-23 15:59:40', 'admin', '2019-07-23 15:59:40', 1); +INSERT INTO `access_authority` VALUES (204, 'report', 'resultsetManage', '数据集管理', 'insert', '新建数据集', 204, 1, 0, 'admin', '2019-07-23 15:59:40', 'admin', '2019-07-23 15:59:40', 1); +INSERT INTO `access_authority` VALUES (205, 'report', 'resultsetManage', '数据集管理', 'update', '修改数据集', 205, 1, 0, 'admin', '2019-07-23 15:59:40', 'admin', '2019-07-23 15:59:40', 1); +INSERT INTO `access_authority` VALUES (206, 'report', 'resultsetManage', '数据集管理', 'delete', '删除数据集', 206, 1, 0, 'admin', '2019-07-23 15:59:40', 'admin', '2019-07-23 15:59:40', 1); +INSERT INTO `access_authority` VALUES (207, 'report', 'resultsetManage', '数据集管理', 'query', '查询数据集', 207, 1, 0, 'admin', '2019-07-23 15:59:40', 'admin', '2019-07-23 15:59:40', 1); +INSERT INTO `access_authority` VALUES (221, 'report', 'reportManage', '报表管理', 'insert', '新建报表', 221, 1, 0, 'admin', '2019-07-23 15:59:40', 'admin', '2019-07-23 15:59:40', 1); +INSERT INTO `access_authority` VALUES (222, 'report', 'reportManage', '报表管理', 'update', '修改报表', 222, 1, 0, 'admin', '2019-07-23 15:59:40', 'admin', '2019-07-23 15:59:40', 1); +INSERT INTO `access_authority` VALUES (223, 'report', 'reportManage', '报表管理', 'delete', '删除报表', 223, 1, 0, 'admin', '2019-07-23 15:59:40', 'admin', '2019-07-23 15:59:40', 1); +INSERT INTO `access_authority` VALUES (224, 'report', 'reportManage', '报表管理', 'query', '查询报表', 224, 1, 0, 'admin', '2019-07-23 15:59:40', 'admin', '2019-07-23 15:59:40', 1); +INSERT INTO `access_authority` VALUES (231, 'report', 'bigScreenManage', '大屏报表', 'share', '分享报表', 231, 1, 0, 'admin', '2019-07-23 15:59:40', 'admin', '2019-07-23 15:59:40', 1); +INSERT INTO `access_authority` VALUES (232, 'report', 'bigScreenManage', '大屏报表', 'view', '查看大屏', 232, 1, 0, 'admin', '2019-07-23 15:59:40', 'admin', '2019-07-23 15:59:40', 1); +INSERT INTO `access_authority` VALUES (233, 'report', 'bigScreenManage', '大屏报表', 'design', '设计大屏', 233, 1, 0, 'admin', '2019-07-23 15:59:40', 'admin', '2019-07-23 15:59:40', 1); +INSERT INTO `access_authority` VALUES (234, 'report', 'bigScreenManage', '大屏报表', 'export', '导出大屏', 234, 1, 0, 'admin', '2019-07-23 15:59:40', 'admin', '2019-07-23 15:59:40', 1); +INSERT INTO `access_authority` VALUES (235, 'report', 'bigScreenManage', '大屏报表', 'import', '导入大屏', 235, 1, 0, 'admin', '2019-07-23 15:59:40', 'admin', '2019-07-23 15:59:40', 1); +INSERT INTO `access_authority` VALUES (236, 'report', 'excelManage', '表格报表', 'query', '查询报表', 236, 1, 0, 'admin', '2019-07-23 15:59:40', 'admin', '2019-07-23 15:59:40', 1); +INSERT INTO `access_authority` VALUES (237, 'report', 'excelManage', '表格报表', 'insert', '新建表格', 237, 1, 0, 'admin', '2019-07-23 15:59:40', 'admin', '2019-07-23 15:59:40', 1); +INSERT INTO `access_authority` VALUES (238, 'report', 'excelManage', '表格报表', 'update', '更新表格', 238, 1, 0, 'admin', '2019-07-23 15:59:40', 'admin', '2019-07-23 15:59:40', 1); +INSERT INTO `access_authority` VALUES (239, 'report', 'excelManage', '表格报表', 'view', '查看表格', 239, 1, 0, 'admin', '2019-07-23 15:59:40', 'admin', '2019-07-23 15:59:40', 1); +INSERT INTO `access_authority` VALUES (240, 'report', 'excelManage', '表格报表', 'export', '导出表格', 240, 1, 0, 'admin', '2019-07-23 15:59:40', 'admin', '2019-07-23 15:59:40', 1); +INSERT INTO `access_authority` VALUES (300, 'system', 'fileManage', '文件管理', 'query', '查询文件', 300, 1, 0, 'admin', '2019-07-23 15:59:40', 'admin', '2019-07-23 15:59:40', 1); +INSERT INTO `access_authority` VALUES (301, 'system', 'fileManage', '文件管理', 'upload', '上传文件', 300, 1, 0, 'admin', '2019-07-23 15:59:40', 'admin', '2019-07-23 15:59:40', 1); +INSERT INTO `access_authority` VALUES (302, 'system', 'fileManage', '文件管理', 'update', '更新文件', 300, 1, 0, 'admin', '2019-07-23 15:59:40', 'admin', '2019-07-23 15:59:40', 1); +INSERT INTO `access_authority` VALUES (303, 'system', 'fileManage', '文件管理', 'delete', '删除文件', 300, 1, 0, 'admin', '2019-07-23 15:59:40', 'admin', '2019-07-23 15:59:40', 1); +INSERT INTO `access_authority` VALUES (304, 'system', 'dictManage', '数据字典', 'query', '数据字典查询', 300, 1, 0, 'admin', '2019-07-23 15:59:40', 'admin', '2019-07-23 15:59:40', 1); +INSERT INTO `access_authority` VALUES (305, 'system', 'dictManage', '数据字典', 'insert', '数据字典新增', 300, 1, 0, 'admin', '2019-07-23 15:59:40', 'admin', '2019-07-23 15:59:40', 1); +INSERT INTO `access_authority` VALUES (306, 'system', 'dictManage', '数据字典', 'update', '更新数据字典', 300, 1, 0, 'admin', '2019-07-23 15:59:40', 'admin', '2019-07-23 15:59:40', 1); +INSERT INTO `access_authority` VALUES (307, 'system', 'dictManage', '数据字典', 'delete', '删除数据字典', 300, 1, 0, 'admin', '2019-07-23 15:59:40', 'admin', '2019-07-23 15:59:40', 1); +INSERT INTO `access_authority` VALUES (308, 'system', 'dictManage', '数据字典', 'fresh', '刷新数据字典', 300, 1, 0, 'admin', '2019-07-23 15:59:40', 'admin', '2019-07-23 15:59:40', 1); +INSERT INTO `access_authority` VALUES (309, 'system', 'dictItemManage', '数据字典项', 'query', '查询数据字典项', 300, 1, 0, 'admin', '2019-07-23 15:59:40', 'admin', '2019-07-23 15:59:40', 1); +INSERT INTO `access_authority` VALUES (310, 'system', 'dictItemManage', '数据字典项', 'insert', '新增数据字典项', 300, 1, 0, 'admin', '2019-07-23 15:59:40', 'admin', '2019-07-23 15:59:40', 1); +INSERT INTO `access_authority` VALUES (311, 'system', 'dictItemManage', '数据字典项', 'update', '更新数据字典项', 300, 1, 0, 'admin', '2019-07-23 15:59:40', 'admin', '2019-07-23 15:59:40', 1); +INSERT INTO `access_authority` VALUES (312, 'system', 'dictItemManage', '数据字典项', 'delete', '删除数据字典项', 300, 1, 0, 'admin', '2019-07-23 15:59:40', 'admin', '2019-07-23 15:59:40', 1); +INSERT INTO `access_authority` VALUES (313, 'access', 'authorityManage', '权限管理', 'detail', '权限明细', 101, 1, 0, 'admin', '2019-07-23 15:59:40', 'admin', '2019-07-23 15:59:40', 1); +INSERT INTO `access_authority` VALUES (314, 'access', 'roleManage', '角色管理', 'detail', '角色明细', 105, 1, 0, 'admin', '2019-07-23 15:59:40', 'admin', '2021-07-17 20:41:46', 2); +INSERT INTO `access_authority` VALUES (315, 'access', 'userManage', '用户管理', 'detail', '用户明细', 110, 1, 0, 'admin', '2019-07-23 15:59:40', 'admin', '2019-07-23 15:59:40', 1); +INSERT INTO `access_authority` VALUES (316, 'report', 'datasourceManage', '数据源管理', 'detail', '数据源明细', 200, 1, 0, 'admin', '2019-07-23 15:59:40', 'admin', '2019-07-23 15:59:40', 1); +INSERT INTO `access_authority` VALUES (317, 'report', 'resultsetManage', '数据集管理', 'detail', '数据集明细', 204, 1, 0, 'admin', '2019-07-23 15:59:40', 'admin', '2019-07-23 15:59:40', 1); +INSERT INTO `access_authority` VALUES (318, 'report', 'reportManage', '报表管理', 'detail', '报表明细', 221, 1, 0, 'admin', '2019-07-23 15:59:40', 'admin', '2019-07-23 15:59:40', 1); +INSERT INTO `access_authority` VALUES (319, 'report', 'bigScreenManage', '大屏报表', 'detail', '大屏明细', 231, 1, 0, 'admin', '2019-07-23 15:59:40', 'admin', '2019-07-23 15:59:40', 1); +INSERT INTO `access_authority` VALUES (320, 'report', 'excelManage', '表格报表', 'detail', 'excel明细', 234, 1, 0, 'admin', '2019-07-23 15:59:40', 'admin', '2019-07-23 15:59:40', 1); +INSERT INTO `access_authority` VALUES (321, 'system', 'fileManage', '文件管理', 'detail', '文件明细', 300, 1, 0, 'admin', '2019-07-23 15:59:40', 'admin', '2019-07-23 15:59:40', 1); +INSERT INTO `access_authority` VALUES (322, 'system', 'dictManage', '数据字典', 'detail', '数据字典明细', 300, 1, 0, 'admin', '2019-07-23 15:59:40', 'admin', '2019-07-23 15:59:40', 1); +INSERT INTO `access_authority` VALUES (323, 'system', 'dictItemManage', '数据字典项', 'detail', '数据字典项明细', 300, 1, 0, 'admin', '2019-07-23 15:59:40', 'admin', '2019-07-23 15:59:40', 1); +INSERT INTO `access_authority` VALUES (324, 'report', 'bigScreenManage', '大屏报表', 'copy', '复制大屏', 236, 1, 0, 'admin', '2019-07-23 15:59:40', 'admin', '2019-07-23 15:59:40', 1); +INSERT INTO `access_authority` VALUES (325, 'report', 'reportShareManage', '报表分享', 'query', '查询报表分享', 231, 1, 0, 'admin', '2019-07-23 15:59:40', 'admin', '2019-07-23 15:59:40', 1); +INSERT INTO `access_authority` VALUES (326, 'report', 'reportShareManage', '报表分享', 'detail', '查询明细', 232, 1, 0, 'admin', '2019-07-23 15:59:40', 'admin', '2019-07-23 15:59:40', 1); +INSERT INTO `access_authority` VALUES (327, 'report', 'reportShareManage', '报表分享', 'shareDelay', '分享延期', 233, 1, 0, 'admin', '2019-07-23 15:59:40', 'admin', '2019-07-23 15:59:40', 1); +INSERT INTO `access_authority` VALUES (328, 'report', 'reportShareManage', '报表分享', 'delete', '删除分享', 234, 1, 0, 'admin', '2019-07-23 15:59:40', 'admin', '2019-07-23 15:59:40', 1); +INSERT INTO `access_authority` VALUES (329, 'report', 'excelManage', '表格报表', 'share', '分享报表', 231, 1, 0, 'admin', '2023-01-10 07:31:06', 'admin', '2023-01-10 07:31:06', 1); + +-- ---------------------------- +-- Table structure for access_role +-- ---------------------------- +DROP TABLE IF EXISTS `access_role`; +CREATE TABLE `access_role` ( + `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键', + `role_code` varchar(32) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL COMMENT '角色编码', + `role_name` varchar(64) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL COMMENT '角色名称', + `enable_flag` int(1) NOT NULL DEFAULT 1 COMMENT '0--已禁用 1--已启用 DIC_NAME=ENABLE_FLAG', + `delete_flag` int(1) NULL DEFAULT 0 COMMENT ' 0--未删除 1--已删除 DIC_NAME=DEL_FLAG', + `create_by` varchar(64) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL COMMENT '创建人', + `create_time` datetime NOT NULL COMMENT '创建时间', + `update_by` varchar(64) CHARACTER SET utf8 COLLATE utf8_bin NULL DEFAULT NULL COMMENT '更新人', + `update_time` datetime NULL DEFAULT NULL COMMENT '更新时间', + `version` tinyint(4) NULL DEFAULT NULL, + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB AUTO_INCREMENT = 4 CHARACTER SET = utf8 COLLATE = utf8_bin COMMENT = '运营角色表' ROW_FORMAT = Dynamic; + +-- ---------------------------- +-- Records of access_role +-- ---------------------------- +INSERT INTO `access_role` VALUES (1, 'root', '超级管理员', 1, 0, 'root', '2019-07-23 16:00:33', 'root', '2019-07-23 16:00:33', 1); +INSERT INTO `access_role` VALUES (2, 'designer', '设计员', 1, 0, 'root', '2019-07-23 16:00:33', 'root', '2019-07-23 16:00:33', 1); +INSERT INTO `access_role` VALUES (3, 'viewer', '查看员', 1, 0, 'root', '2019-07-23 16:00:33', 'root', '2019-07-23 16:00:33', 1); + +-- ---------------------------- +-- Table structure for access_role_authority +-- ---------------------------- +DROP TABLE IF EXISTS `access_role_authority`; +CREATE TABLE `access_role_authority` ( + `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键', + `role_code` varchar(32) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL COMMENT '角色名称', + `target` varchar(64) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL COMMENT '权限目标', + `action` varchar(64) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL, + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB AUTO_INCREMENT = 622 CHARACTER SET = utf8 COLLATE = utf8_bin COMMENT = '运营角色权限表' ROW_FORMAT = Dynamic; + +-- ---------------------------- +-- Records of access_role_authority +-- ---------------------------- +INSERT INTO `access_role_authority` VALUES (460, 'viewer', 'datasourceManage', 'query'); +INSERT INTO `access_role_authority` VALUES (461, 'viewer', 'resultsetManage', 'query'); +INSERT INTO `access_role_authority` VALUES (462, 'viewer', 'reportManage', 'query'); +INSERT INTO `access_role_authority` VALUES (463, 'viewer', 'bigScreenManage', 'share'); +INSERT INTO `access_role_authority` VALUES (464, 'viewer', 'bigScreenManage', 'view'); +INSERT INTO `access_role_authority` VALUES (465, 'designer', 'datasourceManage', 'insert'); +INSERT INTO `access_role_authority` VALUES (466, 'designer', 'datasourceManage', 'update'); +INSERT INTO `access_role_authority` VALUES (467, 'designer', 'datasourceManage', 'delete'); +INSERT INTO `access_role_authority` VALUES (468, 'designer', 'datasourceManage', 'query'); +INSERT INTO `access_role_authority` VALUES (469, 'designer', 'resultsetManage', 'insert'); +INSERT INTO `access_role_authority` VALUES (470, 'designer', 'resultsetManage', 'update'); +INSERT INTO `access_role_authority` VALUES (471, 'designer', 'resultsetManage', 'delete'); +INSERT INTO `access_role_authority` VALUES (472, 'designer', 'resultsetManage', 'query'); +INSERT INTO `access_role_authority` VALUES (473, 'designer', 'reportManage', 'insert'); +INSERT INTO `access_role_authority` VALUES (474, 'designer', 'reportManage', 'update'); +INSERT INTO `access_role_authority` VALUES (475, 'designer', 'reportManage', 'delete'); +INSERT INTO `access_role_authority` VALUES (476, 'designer', 'reportManage', 'query'); +INSERT INTO `access_role_authority` VALUES (477, 'designer', 'bigScreenManage', 'share'); +INSERT INTO `access_role_authority` VALUES (478, 'designer', 'bigScreenManage', 'view'); +INSERT INTO `access_role_authority` VALUES (479, 'designer', 'bigScreenManage', 'design'); +INSERT INTO `access_role_authority` VALUES (555, 'root', 'authorityManage', 'insert'); +INSERT INTO `access_role_authority` VALUES (556, 'root', 'authorityManage', 'update'); +INSERT INTO `access_role_authority` VALUES (557, 'root', 'authorityManage', 'delete'); +INSERT INTO `access_role_authority` VALUES (558, 'root', 'authorityManage', 'query'); +INSERT INTO `access_role_authority` VALUES (559, 'root', 'roleManage', 'insert'); +INSERT INTO `access_role_authority` VALUES (560, 'root', 'roleManage', 'update'); +INSERT INTO `access_role_authority` VALUES (561, 'root', 'roleManage', 'delete'); +INSERT INTO `access_role_authority` VALUES (562, 'root', 'roleManage', 'query'); +INSERT INTO `access_role_authority` VALUES (563, 'root', 'roleManage', 'grantAuthority'); +INSERT INTO `access_role_authority` VALUES (564, 'root', 'userManage', 'insert'); +INSERT INTO `access_role_authority` VALUES (565, 'root', 'userManage', 'update'); +INSERT INTO `access_role_authority` VALUES (566, 'root', 'userManage', 'delete'); +INSERT INTO `access_role_authority` VALUES (567, 'root', 'userManage', 'query'); +INSERT INTO `access_role_authority` VALUES (568, 'root', 'userManage', 'resetPassword'); +INSERT INTO `access_role_authority` VALUES (569, 'root', 'userManage', 'grantRole'); +INSERT INTO `access_role_authority` VALUES (570, 'root', 'datasourceManage', 'insert'); +INSERT INTO `access_role_authority` VALUES (571, 'root', 'datasourceManage', 'update'); +INSERT INTO `access_role_authority` VALUES (572, 'root', 'datasourceManage', 'delete'); +INSERT INTO `access_role_authority` VALUES (573, 'root', 'datasourceManage', 'query'); +INSERT INTO `access_role_authority` VALUES (574, 'root', 'resultsetManage', 'insert'); +INSERT INTO `access_role_authority` VALUES (575, 'root', 'resultsetManage', 'update'); +INSERT INTO `access_role_authority` VALUES (576, 'root', 'resultsetManage', 'delete'); +INSERT INTO `access_role_authority` VALUES (577, 'root', 'resultsetManage', 'query'); +INSERT INTO `access_role_authority` VALUES (578, 'root', 'reportManage', 'insert'); +INSERT INTO `access_role_authority` VALUES (579, 'root', 'reportManage', 'update'); +INSERT INTO `access_role_authority` VALUES (580, 'root', 'reportManage', 'delete'); +INSERT INTO `access_role_authority` VALUES (581, 'root', 'reportManage', 'query'); +INSERT INTO `access_role_authority` VALUES (582, 'root', 'bigScreenManage', 'share'); +INSERT INTO `access_role_authority` VALUES (583, 'root', 'bigScreenManage', 'view'); +INSERT INTO `access_role_authority` VALUES (584, 'root', 'bigScreenManage', 'design'); +INSERT INTO `access_role_authority` VALUES (585, 'root', 'bigScreenManage', 'export'); +INSERT INTO `access_role_authority` VALUES (586, 'root', 'bigScreenManage', 'import'); +INSERT INTO `access_role_authority` VALUES (587, 'root', 'excelManage', 'query'); +INSERT INTO `access_role_authority` VALUES (588, 'root', 'excelManage', 'view'); +INSERT INTO `access_role_authority` VALUES (589, 'root', 'excelManage', 'export'); +INSERT INTO `access_role_authority` VALUES (590, 'root', 'fileManage', 'query'); +INSERT INTO `access_role_authority` VALUES (591, 'root', 'fileManage', 'upload'); +INSERT INTO `access_role_authority` VALUES (592, 'root', 'fileManage', 'update'); +INSERT INTO `access_role_authority` VALUES (593, 'root', 'fileManage', 'delete'); +INSERT INTO `access_role_authority` VALUES (594, 'root', 'dictManage', 'query'); +INSERT INTO `access_role_authority` VALUES (595, 'root', 'dictManage', 'insert'); +INSERT INTO `access_role_authority` VALUES (596, 'root', 'dictManage', 'update'); +INSERT INTO `access_role_authority` VALUES (597, 'root', 'dictManage', 'delete'); +INSERT INTO `access_role_authority` VALUES (598, 'root', 'dictManage', 'fresh'); +INSERT INTO `access_role_authority` VALUES (599, 'root', 'dictItemManage', 'query'); +INSERT INTO `access_role_authority` VALUES (600, 'root', 'dictItemManage', 'insert'); +INSERT INTO `access_role_authority` VALUES (601, 'root', 'dictItemManage', 'update'); +INSERT INTO `access_role_authority` VALUES (602, 'root', 'dictItemManage', 'delete'); +INSERT INTO `access_role_authority` VALUES (603, 'root', 'excelManage', 'insert'); +INSERT INTO `access_role_authority` VALUES (604, 'root', 'excelManage', 'update'); +INSERT INTO `access_role_authority` VALUES (605, 'root', 'authorityManage', 'detail'); +INSERT INTO `access_role_authority` VALUES (606, 'root', 'roleManage', 'detail'); +INSERT INTO `access_role_authority` VALUES (607, 'root', 'userManage', 'detail'); +INSERT INTO `access_role_authority` VALUES (608, 'root', 'datasourceManage', 'detail'); +INSERT INTO `access_role_authority` VALUES (609, 'root', 'resultsetManage', 'detail'); +INSERT INTO `access_role_authority` VALUES (610, 'root', 'reportManage', 'detail'); +INSERT INTO `access_role_authority` VALUES (611, 'root', 'bigScreenManage', 'detail'); +INSERT INTO `access_role_authority` VALUES (612, 'root', 'bigScreenManage', 'copy'); +INSERT INTO `access_role_authority` VALUES (613, 'root', 'excelManage', 'detail'); +INSERT INTO `access_role_authority` VALUES (614, 'root', 'fileManage', 'detail'); +INSERT INTO `access_role_authority` VALUES (615, 'root', 'dictManage', 'detail'); +INSERT INTO `access_role_authority` VALUES (616, 'root', 'dictItemManage', 'detail'); +INSERT INTO `access_role_authority` VALUES (617, 'root', 'reportShareManage', 'query'); +INSERT INTO `access_role_authority` VALUES (618, 'root', 'reportShareManage', 'detail'); +INSERT INTO `access_role_authority` VALUES (619, 'root', 'reportShareManage', 'shareDelay'); +INSERT INTO `access_role_authority` VALUES (620, 'root', 'reportShareManage', 'delete'); +INSERT INTO `access_role_authority` VALUES (621, 'root', 'excelManage', 'share'); + +-- ---------------------------- +-- Table structure for access_user +-- ---------------------------- +DROP TABLE IF EXISTS `access_user`; +CREATE TABLE `access_user` ( + `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键', + `login_name` varchar(64) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL COMMENT ' 登录名', + `real_name` varchar(64) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL COMMENT '真实用户', + `password` varchar(128) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL COMMENT '密码', + `phone` varchar(16) CHARACTER SET utf8 COLLATE utf8_bin NULL DEFAULT NULL COMMENT '手机号码', + `email` varchar(64) CHARACTER SET utf8 COLLATE utf8_bin NULL DEFAULT NULL COMMENT '用户邮箱', + `remark` varchar(512) CHARACTER SET utf8 COLLATE utf8_bin NULL DEFAULT NULL COMMENT '备注', + `last_login_time` datetime NULL DEFAULT NULL COMMENT '最后一次登陆时间', + `last_login_ip` varchar(16) CHARACTER SET utf8 COLLATE utf8_bin NULL DEFAULT NULL COMMENT '最后一次登录IP', + `enable_flag` int(1) NOT NULL DEFAULT 1 COMMENT '0--已禁用 1--已启用 DIC_NAME=ENABLE_FLAG', + `delete_flag` int(1) NOT NULL DEFAULT 0 COMMENT ' 0--未删除 1--已删除 DIC_NAME=DEL_FLAG', + `create_by` varchar(64) CHARACTER SET utf8 COLLATE utf8_bin NULL DEFAULT NULL COMMENT '创建人', + `create_time` datetime NULL DEFAULT NULL COMMENT '创建时间', + `update_by` varchar(64) CHARACTER SET utf8 COLLATE utf8_bin NULL DEFAULT NULL COMMENT '更新人', + `update_time` datetime NULL DEFAULT NULL COMMENT '更新时间', + `version` tinyint(4) NULL DEFAULT NULL, + PRIMARY KEY (`id`) USING BTREE, + UNIQUE INDEX `IDX1`(`login_name`) USING BTREE +) ENGINE = InnoDB AUTO_INCREMENT = 308 CHARACTER SET = utf8 COLLATE = utf8_bin COMMENT = '运营用户表' ROW_FORMAT = Dynamic; + +-- ---------------------------- +-- Records of access_user +-- ---------------------------- +INSERT INTO `access_user` VALUES (1, 'admin', '管理员', 'afbc19467fbff0690b5eba5209d0e966', '18019216253', 'admin1@admin.com', NULL, '2018-08-20 22:04:02', '172.30.16.129', 1, 0, 'admin', '2019-07-23 16:00:38', 'admin', '2019-07-23 16:00:38', 1); +INSERT INTO `access_user` VALUES (2, 'guest', '访客', '5632ad5d163ccaf1ecc305315a1a8e16', '18019214578', 'admin1@admin.com', NULL, '2018-08-20 22:04:02', '172.30.16.129', 1, 0, 'guest', '2019-07-23 16:00:38', 'admin', '2019-07-23 16:00:38', 1); + +-- ---------------------------- +-- Table structure for access_user_role +-- ---------------------------- +DROP TABLE IF EXISTS `access_user_role`; +CREATE TABLE `access_user_role` ( + `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键', + `login_name` varchar(32) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL COMMENT '权限目标', + `role_code` varchar(32) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL COMMENT '角色名称', + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB AUTO_INCREMENT = 17 CHARACTER SET = utf8 COLLATE = utf8_bin COMMENT = '运营角色权限表' ROW_FORMAT = Dynamic; + +-- ---------------------------- +-- Records of access_user_role +-- ---------------------------- +INSERT INTO `access_user_role` VALUES (13, 'guest', 'viewer'); +INSERT INTO `access_user_role` VALUES (14, 'admin', 'root'); +INSERT INTO `access_user_role` VALUES (15, 'admin', 'designer'); +INSERT INTO `access_user_role` VALUES (16, 'admin', 'viewer'); + +-- ---------------------------- +-- Table structure for flyway_schema_history +-- ---------------------------- +DROP TABLE IF EXISTS `flyway_schema_history`; +CREATE TABLE `flyway_schema_history` ( + `installed_rank` int(11) NOT NULL, + `version` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL, + `description` varchar(200) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL, + `type` varchar(20) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL, + `script` varchar(1000) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL, + `checksum` int(11) NULL DEFAULT NULL, + `installed_by` varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL, + `installed_on` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + `execution_time` int(11) NOT NULL, + `success` tinyint(1) NOT NULL, + PRIMARY KEY (`installed_rank`) USING BTREE, + INDEX `flyway_schema_history_s_idx`(`success`) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic; + +-- ---------------------------- +-- Table structure for gaea_dict +-- ---------------------------- +DROP TABLE IF EXISTS `gaea_dict`; +CREATE TABLE `gaea_dict` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `dict_name` varchar(64) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '字典名称', + `dict_code` varchar(64) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '字典编码', + `remark` varchar(64) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '描述', + `create_by` varchar(64) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '创建人', + `create_time` timestamp NULL DEFAULT NULL COMMENT '创建时间', + `update_by` varchar(64) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '更新用户', + `update_time` timestamp NULL DEFAULT NULL COMMENT '更新时间', + `version` int(11) NULL DEFAULT NULL COMMENT '版本', + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB AUTO_INCREMENT = 61 CHARACTER SET = utf8 COLLATE = utf8_general_ci COMMENT = '数组字典' ROW_FORMAT = Dynamic; + +-- ---------------------------- +-- Records of gaea_dict +-- ---------------------------- +INSERT INTO `gaea_dict` VALUES (1, '删除状态', 'DELETE_FLAG', NULL, 'admin', '2021-03-09 16:43:09', 'admin', '2021-03-09 16:43:09', 1); +INSERT INTO `gaea_dict` VALUES (2, '是否启用', 'ENABLE_FLAG', NULL, 'admin', '2021-03-09 16:43:09', 'admin', '2021-03-09 16:43:09', 1); +INSERT INTO `gaea_dict` VALUES (3, '文件状态', 'FILE_STATUS', NULL, 'admin', '2021-03-09 16:43:09', 'admin', '2021-03-09 16:43:09', 1); +INSERT INTO `gaea_dict` VALUES (4, '是否启用', 'FILTER_FLAG', NULL, 'admin', '2021-03-09 16:43:09', 'admin', '2021-03-09 16:43:09', 1); +INSERT INTO `gaea_dict` VALUES (5, '数据过滤类型', 'FILTER_TYPE', NULL, 'admin', '2021-03-09 16:43:09', 'admin', '2021-03-09 16:43:09', 1); +INSERT INTO `gaea_dict` VALUES (6, '指标类型', 'ITEM_TYPE', NULL, 'admin', '2021-03-09 16:43:09', 'admin', '2021-03-09 16:43:09', 1); +INSERT INTO `gaea_dict` VALUES (7, '国际化标识', 'LOCALE', 'ssssss', 'admin', '2021-03-09 16:43:09', 'admin', '2021-03-27 22:20:00', 2); +INSERT INTO `gaea_dict` VALUES (8, '数据源类型', 'SOURCE_TYPE', '', 'admin', '2021-03-23 13:16:58', 'admin', '2021-04-13 16:43:30', 4); +INSERT INTO `gaea_dict` VALUES (9, '数据转换类型', 'TRANSFORM_TYPE', NULL, 'admin', '2021-03-23 13:24:28', 'admin', '2021-03-23 13:24:32', 1); +INSERT INTO `gaea_dict` VALUES (10, '是否必填', 'REQUIRED_FLAG', NULL, 'admin', '2021-03-23 13:25:50', 'admin', '2021-03-23 13:25:53', 1); +INSERT INTO `gaea_dict` VALUES (11, '行业类型', 'SYS_CATA_TYPE', '系统所属行业类型', 'admin', '2021-03-25 13:07:38', 'admin', '2021-03-25 13:07:38', 1); +INSERT INTO `gaea_dict` VALUES (12, '报表类型', 'REPORT_TYPE', '报表类型', 'admin', '2021-03-26 11:48:06', 'admin', '2021-03-26 11:48:11', NULL); +INSERT INTO `gaea_dict` VALUES (13, '菜单国际化', 'MENU_LANGUAGE', '菜单国际化配置', 'admin', '2021-04-06 16:33:33', 'admin', '2021-04-06 16:33:33', 1); +INSERT INTO `gaea_dict` VALUES (14, '报表分组', 'REPORT_GROUP', '报表分组', 'admin', '2021-04-07 09:36:40', 'admin', '2021-04-07 09:36:42', 1); +INSERT INTO `gaea_dict` VALUES (15, '报表组件类型', 'DASHBOARD_PANEL_TYPE', '报表组件类型', 'admin', '2021-04-12 10:42:50', 'admin', '2021-04-12 10:42:55', 1); +INSERT INTO `gaea_dict` VALUES (16, '图表属性', 'CHART_PROPERTIES', '报表属性', 'admin', '2021-04-29 10:28:15', 'admin', '2021-06-23 10:47:20', 3); +INSERT INTO `gaea_dict` VALUES (17, '分享有效期', 'SHARE_VAILD', '报表分享', 'admin', '2021-08-18 13:29:19', 'admin', '2021-08-18 13:29:24', 1); +INSERT INTO `gaea_dict` VALUES (18, '柱状图属性', 'BAR_PROPERTIES', '柱状图属性', 'admin', '2021-04-29 10:28:15', 'admin', '2021-06-23 10:47:20', 1); +INSERT INTO `gaea_dict` VALUES (19, '折线图属性', 'LINE_PROPERTIES', '折线图属性', 'admin', '2021-04-29 10:28:15', 'admin', '2021-06-23 10:47:20', 1); +INSERT INTO `gaea_dict` VALUES (20, '柱线图属性', 'BAR_LINE_PROPERTIES', '柱线图属性', 'admin', '2021-04-29 10:28:15', 'admin', '2021-06-23 10:47:20', 1); +INSERT INTO `gaea_dict` VALUES (21, '饼图属性', 'PIE_PROPERTIES', '饼图、漏斗图', 'admin', '2021-04-29 10:28:15', 'admin', '2021-06-23 10:47:20', 1); +INSERT INTO `gaea_dict` VALUES (22, '单文本图属性', 'TEXT_PROPERTIES', '仪表盘、百分比、文本框、滚动文本', 'admin', '2021-04-29 10:28:15', 'admin', '2021-06-23 10:47:20', 1); +INSERT INTO `gaea_dict` VALUES (23, '堆叠图属性', 'STACK_PROPERTIES', '堆叠图属性', 'admin', '2021-04-29 10:28:15', 'admin', '2021-06-23 10:47:20', 1); +INSERT INTO `gaea_dict` VALUES (24, '地图属性', 'MAP_PROPERTIES', '地图属性', 'admin', '2021-04-29 10:28:15', 'admin', '2021-06-23 10:47:20', 1); +INSERT INTO `gaea_dict` VALUES (25, '数据集类型', 'SET_TYPE', '数据集类型', 'admin', '2021-11-16 14:43:12', 'admin', '2021-11-16 14:43:12', 1); +INSERT INTO `gaea_dict` VALUES (26, 'XY坐标属性', 'COORD_PROPERTIES', 'XY坐标属性', 'admin', '2023-01-10 07:31:04', 'admin', '2023-01-10 07:31:04', 1); +INSERT INTO `gaea_dict` VALUES (27, '源端目标端属性', 'SOUTAR_PROPERTIES', '源端目标端属性', 'admin', '2023-01-10 07:31:05', 'admin', '2023-01-10 07:31:05', 1); +INSERT INTO `gaea_dict` VALUES (28, '雷达属性', 'RADAR_PROPERTIES', '雷达属性', 'admin', '2023-01-10 07:31:07', 'admin', '2023-01-10 07:31:07', 1); +INSERT INTO `gaea_dict` VALUES (29, '下拉框属性', 'SELECT_PROPERTIES', '下拉框属性', 'admin', '2023-01-10 07:31:07', 'admin', '2023-01-10 07:31:07', 1); + +-- ---------------------------- +-- Table structure for gaea_dict_item +-- ---------------------------- +DROP TABLE IF EXISTS `gaea_dict_item`; +CREATE TABLE `gaea_dict_item` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `dict_code` varchar(64) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '数据字典编码', + `item_name` varchar(64) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '字典项名称', + `item_value` varchar(64) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '字典项值', + `item_extend` varchar(2048) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '字典扩展项', + `enabled` int(1) NULL DEFAULT 1 COMMENT '1:启用 0:禁用', + `locale` varchar(16) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '语言标识', + `remark` varchar(64) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '描述', + `sort` int(11) NULL DEFAULT NULL COMMENT '排序', + `create_by` varchar(64) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '创建人', + `create_time` timestamp NULL DEFAULT NULL COMMENT '创建时间', + `update_by` varchar(64) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '更新用户', + `update_time` timestamp NULL DEFAULT NULL COMMENT '更新时间', + `version` int(11) NULL DEFAULT NULL COMMENT '版本', + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB AUTO_INCREMENT = 327 CHARACTER SET = utf8 COLLATE = utf8_general_ci COMMENT = '数据字典项' ROW_FORMAT = Dynamic; + +-- ---------------------------- +-- Records of gaea_dict_item +-- ---------------------------- +INSERT INTO `gaea_dict_item` VALUES (1, 'AUDIT_FLAG', '待审核', 'waiting', NULL, 1, 'zh', '待审核', 1, 'admin', '2021-03-09 16:43:09', 'admin', '2021-03-09 16:43:09', 1); +INSERT INTO `gaea_dict_item` VALUES (2, 'AUDIT_FLAG', '审核中', 'ongoing', NULL, 1, 'zh', '审核中', 2, 'admin', '2021-03-09 16:43:09', 'admin', '2021-03-09 16:43:09', 1); +INSERT INTO `gaea_dict_item` VALUES (3, 'AUDIT_FLAG', '通过', 'approved', NULL, 1, 'zh', '通过', 3, 'admin', '2021-03-09 16:43:09', 'admin', '2021-03-09 16:43:09', 1); +INSERT INTO `gaea_dict_item` VALUES (4, 'AUDIT_FLAG', '拒绝', 'rejected', NULL, 1, 'zh', '拒绝', 4, 'admin', '2021-03-09 16:43:09', 'admin', '2021-03-09 16:43:09', 1); +INSERT INTO `gaea_dict_item` VALUES (5, 'DELETE_FLAG', '已删除', '1', NULL, 1, 'zh', '已删除', 5, 'admin', '2021-03-09 16:43:09', 'admin', '2021-03-31 12:04:26', 2); +INSERT INTO `gaea_dict_item` VALUES (6, 'DELETE_FLAG', '未删除', '0', NULL, 1, 'zh', '未删除', 6, 'admin', '2021-03-09 16:43:09', 'admin', '2021-03-31 12:04:49', 3); +INSERT INTO `gaea_dict_item` VALUES (7, 'ENABLE_FLAG', '禁用', '0', NULL, 1, 'zh', '已禁用', 2, 'admin', '2021-03-09 16:43:09', 'admin', '2021-04-08 14:41:13', 3); +INSERT INTO `gaea_dict_item` VALUES (8, 'ENABLE_FLAG', '启用', '1', NULL, 1, 'zh', '已启用', 1, 'admin', '2021-03-09 16:43:09', 'admin', '2021-04-08 14:41:18', 3); +INSERT INTO `gaea_dict_item` VALUES (9, 'SYSTEM_CODE', 'CTS电脑端', 'CTS-PC', NULL, 1, 'zh', 'CTS电脑端', 9, 'admin', '2021-03-09 16:43:09', 'admin', '2021-03-09 16:43:09', 1); +INSERT INTO `gaea_dict_item` VALUES (10, 'SYSTEM_CODE', 'CTS App端', 'CTS-APP', NULL, 1, 'zh', 'CTS App端', 10, 'admin', '2021-03-09 16:43:09', 'admin', '2021-03-09 16:43:09', 1); +INSERT INTO `gaea_dict_item` VALUES (11, 'FILTER_FLAG', '已禁用', '0', NULL, 1, 'zh', '已禁用', 7, 'admin', '2021-03-09 16:43:09', 'admin', '2021-03-09 16:43:09', 1); +INSERT INTO `gaea_dict_item` VALUES (12, 'FILTER_FLAG', '已启用', '1', NULL, 1, 'zh', '已启用', 8, 'admin', '2021-03-09 16:43:09', 'admin', '2021-03-09 16:43:09', 1); +INSERT INTO `gaea_dict_item` VALUES (13, 'FILTER_TYPE', 'js脚本', 'jsCalc', NULL, 1, 'zh', 'js脚本', 3, 'admin', '2021-03-09 16:43:09', 'admin', '2021-03-09 16:43:09', 1); +INSERT INTO `gaea_dict_item` VALUES (14, 'FILTER_TYPE', '新增字段', 'addField', NULL, 1, 'zh', '新增字段', 3, 'admin', '2021-03-09 16:43:09', 'admin', '2021-03-09 16:43:09', 1); +INSERT INTO `gaea_dict_item` VALUES (15, 'FILTER_TYPE', '替换字段', 'replaceField', NULL, 1, 'zh', '替换字段', 3, 'admin', '2021-03-09 16:43:09', 'admin', '2021-03-09 16:43:09', 1); +INSERT INTO `gaea_dict_item` VALUES (16, 'FILTER_TYPE', 'ip解析java处理', 'ipTransform', NULL, 1, 'zh', 'ip解析java处理', 3, 'admin', '2021-03-09 16:43:09', 'admin', '2021-03-09 16:43:09', 1); +INSERT INTO `gaea_dict_item` VALUES (17, 'FILTER_TYPE', 'vpn在线时长java处理', 'vpnTransform', NULL, 1, 'zh', 'vpn在线时长java处理', 3, 'admin', '2021-03-09 16:43:09', 'admin', '2021-03-09 16:43:09', 1); +INSERT INTO `gaea_dict_item` VALUES (18, 'SETTING_TYPE', '字符串', 'input', NULL, 1, 'zh', '字符串', 10, 'admin', '2021-03-09 16:43:09', 'admin', '2021-03-09 16:43:09', 1); +INSERT INTO `gaea_dict_item` VALUES (19, 'SETTING_TYPE', '数字', 'input-number', NULL, 1, 'zh', '数字', 10, 'admin', '2021-03-09 16:43:09', 'admin', '2021-03-09 16:43:09', 1); +INSERT INTO `gaea_dict_item` VALUES (20, 'SETTING_TYPE', '文本区域', 'textarea', NULL, 1, 'zh', '文本区域', 10, 'admin', '2021-03-09 16:43:09', 'admin', '2021-03-09 16:43:09', 1); +INSERT INTO `gaea_dict_item` VALUES (21, 'SETTING_TYPE', '数据字典', 'code-select', NULL, 1, 'zh', '数据字典', 10, 'admin', '2021-03-09 16:43:09', 'admin', '2021-03-09 16:43:09', 1); +INSERT INTO `gaea_dict_item` VALUES (22, 'SETTING_TYPE', '下拉列表', 'select', NULL, 1, 'zh', '下拉列表', 10, 'admin', '2021-03-09 16:43:09', 'admin', '2021-03-09 16:43:09', 1); +INSERT INTO `gaea_dict_item` VALUES (23, 'SETTING_TYPE', '单选按钮', 'radio-group', NULL, 1, 'zh', '单选按钮', 10, 'admin', '2021-03-09 16:43:09', 'admin', '2021-03-09 16:43:09', 1); +INSERT INTO `gaea_dict_item` VALUES (24, 'SETTING_TYPE', '多选按钮', 'checkbox-group', NULL, 1, 'zh', '多选按钮', 10, 'admin', '2021-03-09 16:43:09', 'admin', '2021-03-09 16:43:09', 1); +INSERT INTO `gaea_dict_item` VALUES (25, 'SETTING_TYPE', '自定义表单', 'custom-form', NULL, 1, 'zh', '自定义表单', 10, 'admin', '2021-03-09 16:43:09', 'admin', '2021-03-09 16:43:09', 1); +INSERT INTO `gaea_dict_item` VALUES (26, 'FILE_STATUS', '生成中', 'creating', NULL, 1, 'zh', '生成中', 3, 'admin', '2021-03-09 16:43:09', 'admin', '2021-03-09 16:43:09', 1); +INSERT INTO `gaea_dict_item` VALUES (27, 'FILE_STATUS', '生成成功', 'success', NULL, 1, 'zh', '生成成功', 3, 'admin', '2021-03-09 16:43:09', 'admin', '2021-03-09 16:43:09', 1); +INSERT INTO `gaea_dict_item` VALUES (28, 'FILE_STATUS', '生成失败', 'failed', NULL, 1, 'zh', '生成失败', 3, 'admin', '2021-03-09 16:43:09', 'admin', '2021-03-09 16:43:09', 1); +INSERT INTO `gaea_dict_item` VALUES (29, 'LOCALE', '中文', 'zh', NULL, 1, 'zh', '中文', NULL, 'admin', '2021-03-09 16:43:09', 'admin', '2021-03-09 16:43:09', 1); +INSERT INTO `gaea_dict_item` VALUES (30, 'LOCALE', '英文', 'en', NULL, 1, 'zh', '英文', NULL, 'admin', '2021-03-09 16:43:09', 'admin', '2021-03-09 16:43:09', 1); +INSERT INTO `gaea_dict_item` VALUES (31, 'LOCALE', 'Chinese', 'zh', NULL, 1, 'en', 'Chinese', NULL, 'admin', '2021-03-09 16:43:09', 'admin', '2021-03-09 16:43:09', 1); +INSERT INTO `gaea_dict_item` VALUES (32, 'LOCALE', 'English', 'en', NULL, 1, 'en', 'English', 1, 'admin', '2021-03-09 16:43:09', 'admin', '2021-03-09 16:43:09', 1); +INSERT INTO `gaea_dict_item` VALUES (33, 'REQUIRED_FLAG', '必填', '1', NULL, 1, 'zh', NULL, 2, 'admin', '2021-03-23 10:54:08', 'admin', '2021-03-23 10:54:08', 1); +INSERT INTO `gaea_dict_item` VALUES (34, 'REQUIRED_FLAG', '非必填', '0', NULL, 1, 'zh', NULL, 2, 'admin', '2021-03-23 10:54:08', 'admin', '2021-03-23 10:54:08', 1); +INSERT INTO `gaea_dict_item` VALUES (35, 'TRANSFORM_TYPE', 'js脚本', 'js', NULL, 1, 'zh', NULL, 2, 'admin', '2021-03-23 10:54:08', 'admin', '2021-03-23 10:54:08', 1); +INSERT INTO `gaea_dict_item` VALUES (36, 'TRANSFORM_TYPE', 'java脚本', 'javaBean', NULL, 1, 'zh', NULL, 2, 'admin', '2021-03-23 10:54:08', 'admin', '2021-03-23 10:54:08', 1); +INSERT INTO `gaea_dict_item` VALUES (37, 'TRANSFORM_TYPE', '字典翻译', 'dict', '{\"dict1\": {\"1\": \"男\",\"0\": \"女\"},\"dict2\": {\"mysql\": \"mysql\",\"sqlserver\": \"sqlserver\"}}', 1, 'zh', NULL, 2, 'admin', '2021-03-23 10:54:08', 'admin', '2021-03-23 10:54:08', 1); +INSERT INTO `gaea_dict_item` VALUES (38, 'SYS_CATA_TYPE', '行业01', '1001', NULL, 1, 'zh', NULL, 1, 'admin', '2021-03-25 13:10:32', 'admin', '2021-03-25 13:10:32', 1); +INSERT INTO `gaea_dict_item` VALUES (39, 'SYS_CATA_TYPE', '行业02', '1002', NULL, 1, 'zh', NULL, 2, 'admin', '2021-03-25 13:11:01', 'admin', '2021-03-25 13:11:01', 1); +INSERT INTO `gaea_dict_item` VALUES (40, 'REPORT_TYPE', 'excel报表', 'report_excel', NULL, 1, 'zh', NULL, NULL, 'admin', '2021-03-26 11:49:28', 'admin', '2021-03-26 11:50:19', NULL); +INSERT INTO `gaea_dict_item` VALUES (41, 'REPORT_TYPE', '大屏报表', 'report_screen', NULL, 1, 'zh', NULL, NULL, 'admin', '2021-03-26 11:50:25', 'admin', '2021-03-26 11:50:21', NULL); +INSERT INTO `gaea_dict_item` VALUES (42, 'REPORT_GROUP', '分组1', 'group_1', NULL, 1, 'zh', NULL, 1, 'admin', '2021-04-07 09:39:45', 'admin', '2021-04-13 16:44:31', 2); +INSERT INTO `gaea_dict_item` VALUES (43, 'REPORT_GROUP', '分组2', 'group_2', NULL, 1, 'zh', NULL, 1, 'admin', '2021-04-07 09:40:55', 'admin', '2021-04-07 09:40:52', 1); +INSERT INTO `gaea_dict_item` VALUES (44, 'INF_STATUS', '审核通过', '5', NULL, 1, 'zh', NULL, 25, 'admin', '2021-04-07 11:02:42', 'admin', '2021-04-07 15:01:35', 3); +INSERT INTO `gaea_dict_item` VALUES (45, 'RULE_PARAM_TYPE', 'int', 'int', NULL, 1, 'zh', NULL, 3, 'zouya', '2021-04-09 09:43:22', 'zouya', '2021-04-09 09:43:22', 1); +INSERT INTO `gaea_dict_item` VALUES (46, 'PUSH_TYPE', 'APP端', 'appsp', NULL, 1, 'zh', 'App端推送采用推送平台Appsp', 4, 'admin', '2021-04-09 10:13:33', 'admin', '2021-04-09 10:14:11', 3); +INSERT INTO `gaea_dict_item` VALUES (47, 'DASHBOARD_PANEL_TYPE', '文本', 'text', NULL, 1, 'zh', 'App端推送采用推送平台Appsp', 4, 'admin', '2021-04-09 10:13:33', 'admin', '2021-04-09 10:14:11', 3); +INSERT INTO `gaea_dict_item` VALUES (48, 'DASHBOARD_PANEL_TYPE', '滚动文本', '\r\nscrollingText', NULL, 1, 'zh', 'App端推送采用推送平台Appsp', 4, 'admin', '2021-04-09 10:13:33', 'admin', '2021-04-09 10:14:11', 3); +INSERT INTO `gaea_dict_item` VALUES (49, 'DASHBOARD_PANEL_TYPE', '超链接', 'hyperlinks', NULL, 1, 'zh', 'App端推送采用推送平台Appsp', 4, 'admin', '2021-04-09 10:13:33', 'admin', '2021-04-09 10:14:11', 3); +INSERT INTO `gaea_dict_item` VALUES (50, 'DASHBOARD_PANEL_TYPE', '当前时间', 'currentTime', NULL, 1, 'zh', 'App端推送采用推送平台Appsp', 4, 'admin', '2021-04-09 10:13:33', 'admin', '2021-04-09 10:14:11', 3); +INSERT INTO `gaea_dict_item` VALUES (51, 'DASHBOARD_PANEL_TYPE', '图片', 'picture', NULL, 1, 'zh', 'App端推送采用推送平台Appsp', 4, 'admin', '2021-04-09 10:13:33', 'admin', '2021-04-09 10:14:11', 3); +INSERT INTO `gaea_dict_item` VALUES (52, 'DASHBOARD_PANEL_TYPE', '轮播图片', 'rotatePictures', NULL, 1, 'zh', 'App端推送采用推送平台Appsp', 4, 'admin', '2021-04-09 10:13:33', 'admin', '2021-04-09 10:14:11', 3); +INSERT INTO `gaea_dict_item` VALUES (53, 'MENU_LANGUAGE', '图标库', 'SvgDemo', '', 1, 'zh', '', 1, 'admin', '2021-04-06 16:34:10', 'admin', '2021-04-06 16:34:10', 1); +INSERT INTO `gaea_dict_item` VALUES (54, 'MENU_LANGUAGE', '代码生成', 'Generator', NULL, 1, 'zh', '', 1, 'admin', '2021-04-06 16:34:10', 'admin', '2021-04-06 16:34:10', 1); +INSERT INTO `gaea_dict_item` VALUES (55, 'MENU_LANGUAGE', '项目列表', 'Project', '', 1, 'zh', '', 1, 'admin', '2021-04-06 16:34:10', 'admin', '2021-04-06 16:34:10', 1); +INSERT INTO `gaea_dict_item` VALUES (56, 'MENU_LANGUAGE', '生成示例-单表', 'AlipayConfig', '', 1, 'zh', '', 1, 'admin', '2021-04-06 16:34:10', 'admin', '2021-04-06 16:34:10', 1); +INSERT INTO `gaea_dict_item` VALUES (57, 'MENU_LANGUAGE', '设备信息-主表', 'DeviceInfo', '', 1, 'zh', '', 1, 'admin', '2021-04-06 16:34:10', 'admin', '2021-04-06 16:34:10', 1); +INSERT INTO `gaea_dict_item` VALUES (58, 'MENU_LANGUAGE', '设备类型-子表', 'DeviceModel', '', 1, 'zh', '', 1, 'admin', '2021-04-06 16:34:10', 'admin', '2021-04-06 16:34:10', 1); +INSERT INTO `gaea_dict_item` VALUES (59, 'MENU_LANGUAGE', '设备日志-子表', 'DeviceLogDetail', '', 1, 'zh', '', 1, 'admin', '2021-04-06 16:34:10', 'admin', '2021-04-06 16:34:10', 1); +INSERT INTO `gaea_dict_item` VALUES (60, 'MENU_LANGUAGE', 'API文档', 'API', '', 1, 'zh', '', 1, 'admin', '2021-04-06 16:34:10', 'admin', '2021-04-06 16:34:10', 1); +INSERT INTO `gaea_dict_item` VALUES (61, 'MENU_LANGUAGE', '系统通告', 'Announcement', '', 1, 'zh', '', 1, 'admin', '2021-04-06 16:34:10', 'admin', '2021-04-06 16:34:10', 1); +INSERT INTO `gaea_dict_item` VALUES (62, 'REPORT_GROUP', '分组3', 'group_3', NULL, 1, 'zh', NULL, 3, 'admin', '2021-04-13 16:45:28', 'admin', '2021-04-13 16:45:28', 1); +INSERT INTO `gaea_dict_item` VALUES (63, 'MENU_LANGUAGE', '文件管理', 'FileManagement', NULL, 1, 'zh', NULL, 1, 'admin', '2021-04-27 13:57:58', 'admin', '2021-04-27 13:57:58', 1); +INSERT INTO `gaea_dict_item` VALUES (64, 'CHART_PROPERTIES', 'x轴字段', 'xAxis', NULL, 1, 'zh', NULL, 1, 'admin', '2023-01-10 07:31:00', 'admin', '2023-01-10 07:31:00', 1); +INSERT INTO `gaea_dict_item` VALUES (65, 'CHART_PROPERTIES', '柱状', 'bar', NULL, 1, 'zh', NULL, 6, 'admin', '2021-04-29 10:48:43', 'admin', '2021-04-29 10:48:50', 1); +INSERT INTO `gaea_dict_item` VALUES (66, 'CHART_PROPERTIES', '折线', 'line', NULL, 1, 'zh', NULL, 7, 'admin', '2021-04-29 10:48:43', 'admin', '2021-04-29 10:48:50', 1); +INSERT INTO `gaea_dict_item` VALUES (67, 'CHART_PROPERTIES', '饼图/仪表盘/气泡地图name', 'name', NULL, 1, 'zh', NULL, 8, 'admin', '2021-04-29 10:48:43', 'admin', '2021-04-29 10:48:50', 1); +INSERT INTO `gaea_dict_item` VALUES (68, 'CHART_PROPERTIES', '饼图/仪表盘/气泡地图value', 'value', NULL, 1, 'zh', NULL, 9, 'admin', '2021-04-29 10:48:43', 'admin', '2021-04-29 10:48:50', 1); +INSERT INTO `gaea_dict_item` VALUES (69, 'CHART_PROPERTIES', '时间轴-时', 'xAxis-hour', NULL, 1, 'zh', NULL, 2, 'admin', '2021-04-29 10:48:43', 'admin', '2021-04-29 10:48:50', 1); +INSERT INTO `gaea_dict_item` VALUES (70, 'CHART_PROPERTIES', '时间轴-天', 'xAxis-day', NULL, 1, 'zh', NULL, 3, 'admin', '2021-04-29 10:48:43', 'admin', '2021-04-29 10:48:50', 1); +INSERT INTO `gaea_dict_item` VALUES (71, 'CHART_PROPERTIES', '时间轴-月', 'xAxis-month', NULL, 1, 'zh', NULL, 4, 'admin', '2021-04-29 10:48:43', 'admin', '2021-04-29 10:48:50', 1); +INSERT INTO `gaea_dict_item` VALUES (72, 'CHART_PROPERTIES', '时间轴-年', 'xAxis-year', NULL, 1, 'zh', NULL, 5, 'admin', '2021-04-29 10:48:43', 'admin', '2021-04-29 10:48:50', 1); +INSERT INTO `gaea_dict_item` VALUES (73, 'CHART_PROPERTIES', '文本数字', 'text', NULL, 1, 'zh', NULL, 10, 'admin', '2023-01-10 07:30:55', 'admin', '2023-01-10 07:30:55', 1); +INSERT INTO `gaea_dict_item` VALUES (74, 'SOURCE_TYPE', 'mysql', 'mysql', '[{\"label\":\"driverName\",\"value\":\"com.mysql.cj.jdbc.Driver\",\"labelValue\":\"驱动类\"},{\"label\":\"jdbcUrl\",\"value\":\"jdbc:mysql://127.0.0.1:3306/test_db?useUnicode=true&characterEncoding=UTF-8&serverTimezone=GMT%2B8\",\"labelValue\":\"连接串\"},{\"label\":\"username\",\"value\":\"root\",\"labelValue\":\"用户名\"},{\"label\":\"password\",\"value\":\"root\",\"labelValue\":\"密码\"}]', 1, 'zh', NULL, 1, '管理员', '2021-03-23 10:54:08', 'lixiaoyan', '2021-03-26 13:22:05', 3); +INSERT INTO `gaea_dict_item` VALUES (75, 'SOURCE_TYPE', 'oracle', 'oracle', '[{\"label\":\"driverName\",\"value\":\"oracle.jdbc.driver.OracleDriver\",\"labelValue\":\"驱动类\"},{\"label\":\"jdbcUrl\",\"value\":\"jdbc:oracle:thin:@//localhost:1521/orcl\",\"labelValue\":\"连接串\"},{\"label\":\"username\",\"value\":\"root\",\"labelValue\":\"用户名\"},{\"label\":\"password\",\"value\":\"root\",\"labelValue\":\"密码\"}]', 1, 'zh', NULL, 2, 'admin', '2021-03-23 10:54:08', 'admin', '2021-03-23 10:54:08', 1); +INSERT INTO `gaea_dict_item` VALUES (76, 'SOURCE_TYPE', 'mssqlserver', 'mssqlserver', '[{\"label\":\"driverName\",\"value\":\"com.microsoft.sqlserver.jdbc.SQLServerDriver\",\"labelValue\":\"驱动类\"},{\"label\":\"jdbcUrl\",\"value\":\"jdbc:sqlserver://127.0.0.1:1433;DatabaseName=test_db\",\"labelValue\":\"连接串\"},{\"label\":\"username\",\"value\":\"root\",\"labelValue\":\"用户名\"},{\"label\":\"password\",\"value\":\"root\",\"labelValue\":\"密码\"}]', 1, 'zh', NULL, 3, 'admin', '2021-03-23 10:54:08', 'admin', '2021-03-23 10:54:08', 1); +INSERT INTO `gaea_dict_item` VALUES (77, 'SOURCE_TYPE', 'elasticsearch_sql', 'elasticsearch_sql', '[{\"label\":\"apiUrl\",\"value\":\"http://10.108.26.164:9200/_xpack/sql?format=json\",\"labelValue\":\"请求路径\"},{\"label\":\"method\",\"value\":\"POST\",\"labelValue\":\"请求方式\"},{\"label\":\"header\",\"value\":\"{\\\"Content-Type\\\":\\\"application/json\\\"}\",\"labelValue\":\"请求头\"},{\"label\":\"body\",\"value\":\"{\\\"query\\\":\\\"select 1\\\"}\",\"labelValue\":\"请求体\"}]', 1, 'zh', NULL, 11, '管理员', '2021-03-23 10:54:08', 'admin', '2021-04-13 13:12:33', 9); +INSERT INTO `gaea_dict_item` VALUES (78, 'SOURCE_TYPE', 'kudu impala', 'kudu_impala', '[{\"label\":\"driverName\",\"value\":\"com.cloudera.impala.jdbc41.Driver\",\"labelValue\":\"驱动类\"},{\"label\":\"jdbcUrl\",\"value\":\"jdbc:impala://10.108.3.111:21050/ods\",\"labelValue\":\"连接串\"},{\"label\":\"username\",\"value\":\"\",\"labelValue\":\"用户名\"},{\"label\":\"password\",\"value\":\"\",\"labelValue\":\"密码\"}]', 1, 'zh', NULL, 12, 'admin', '2021-03-23 10:54:08', 'admin', '2021-04-01 09:18:09', 3); +INSERT INTO `gaea_dict_item` VALUES (79, 'SOURCE_TYPE', 'jdbc', 'jdbc', '[{\"label\":\"driverName\",\"value\":\"com.mysql.cj.jdbc.Driver\",\"labelValue\":\"驱动类\"},{\"label\":\"jdbcUrl\",\"value\":\"jdbc:mysql://127.0.0.1:3306/test_db?useUnicode=true&characterEncoding=UTF-8&serverTimezone=GMT%2B8\",\"labelValue\":\"连接串\"},{\"label\":\"username\",\"value\":\"root\",\"labelValue\":\"用户名\"},{\"label\":\"password\",\"value\":\"root\",\"labelValue\":\"密码\"}]', 1, 'zh', NULL, 21, '管理员', '2021-04-13 17:26:38', 'admin', '2021-04-13 17:26:38', 1); +INSERT INTO `gaea_dict_item` VALUES (80, 'SOURCE_TYPE', 'http', 'http', '[{\"label\":\"apiUrl\",\"value\":\"https://gateway.test.com/api/getdata\",\"labelValue\":\"请求路径\"},{\"label\":\"method\",\"value\":\"POST\",\"labelValue\":\"请求方式\"},{\"label\":\"header\",\"value\":\"{\\\"Content-Type\\\":\\\"application/json;charset=UTF-8\\\"}\",\"labelValue\":\"请求头\"},{\"label\":\"body\",\"value\":\"{\\\"username\\\":\\\"admin\\\",\\\"password\\\":\\\"de12878c0ef5beb7d8848c3af8f54afb\\\",\\\"verifyCode\\\":\\\"\\\"}\",\"labelValue\":\"请求体\"}]', 1, 'zh', NULL, 29, '管理员', '2021-04-13 17:26:38', 'admin', '2021-04-13 17:26:38', 1); +INSERT INTO `gaea_dict_item` VALUES (81, 'CHART_PROPERTIES', 'y轴字段', 'yAxis', NULL, 1, 'zh', NULL, 11, 'admin', '2021-07-05 15:33:59', 'admin', '2021-07-05 15:33:59', 1); +INSERT INTO `gaea_dict_item` VALUES (82, 'SHARE_VAILD', '永久有效', '0', NULL, 1, 'zh', NULL, 1, 'admin', '2021-08-18 13:30:21', 'admin', '2021-08-18 13:30:21', 1); +INSERT INTO `gaea_dict_item` VALUES (83, 'SHARE_VAILD', '1天', '1', NULL, 1, 'zh', NULL, 2, 'admin', '2021-08-18 13:30:39', 'admin', '2021-08-18 13:30:39', 1); +INSERT INTO `gaea_dict_item` VALUES (84, 'SHARE_VAILD', '7天', '7', NULL, 1, 'zh', NULL, 3, 'admin', '2021-08-18 13:30:51', 'admin', '2021-08-18 13:30:56', 2); +INSERT INTO `gaea_dict_item` VALUES (85, 'SHARE_VAILD', '30天', '30', NULL, 1, 'zh', NULL, 4, 'admin', '2021-08-18 13:31:11', 'admin', '2021-08-18 13:31:11', 1); +INSERT INTO `gaea_dict_item` VALUES (86, 'BAR_PROPERTIES', 'x轴字段', 'xAxis', NULL, 1, 'zh', NULL, 1, 'admin', '2021-08-20 10:19:35', 'admin', '2021-08-20 10:19:35', 1); +INSERT INTO `gaea_dict_item` VALUES (87, 'BAR_PROPERTIES', '柱状', 'bar', NULL, 1, 'zh', NULL, 2, 'admin', '2021-08-20 10:19:56', 'admin', '2021-08-20 10:19:56', 1); +INSERT INTO `gaea_dict_item` VALUES (88, 'LINE_PROPERTIES', 'x轴字段', 'xAxis', NULL, 1, 'zh', NULL, 1, 'admin', '2021-08-20 10:27:39', 'admin', '2021-08-20 10:27:39', 1); +INSERT INTO `gaea_dict_item` VALUES (89, 'LINE_PROPERTIES', '折线', 'line', NULL, 1, 'zh', NULL, 2, 'admin', '2021-08-20 10:27:49', 'admin', '2021-08-20 10:27:49', 1); +INSERT INTO `gaea_dict_item` VALUES (90, 'BAR_LINE_PROPERTIES', 'x轴字段', 'xAxis', NULL, 1, 'zh', NULL, 1, 'admin', '2021-08-20 10:31:51', 'admin', '2021-08-20 10:31:51', 1); +INSERT INTO `gaea_dict_item` VALUES (91, 'BAR_LINE_PROPERTIES', 'x轴时间轴-时', 'xAxis-hour', NULL, 1, 'zh', NULL, 2, 'admin', '2021-08-20 10:32:11', 'admin', '2021-08-20 10:32:11', 1); +INSERT INTO `gaea_dict_item` VALUES (92, 'BAR_LINE_PROPERTIES', 'x轴时间轴-天', 'xAxis-day', NULL, 1, 'zh', NULL, 3, 'admin', '2021-08-20 10:32:25', 'admin', '2021-08-20 10:32:25', 1); +INSERT INTO `gaea_dict_item` VALUES (93, 'BAR_LINE_PROPERTIES', 'x轴时间轴-月', 'xAxis-month', NULL, 1, 'zh', NULL, 4, 'admin', '2021-08-20 10:32:38', 'admin', '2021-08-20 10:32:38', 1); +INSERT INTO `gaea_dict_item` VALUES (94, 'BAR_LINE_PROPERTIES', '时间轴-年', 'xAxis-year', NULL, 1, 'zh', NULL, 5, 'admin', '2021-08-20 10:32:52', 'admin', '2021-08-20 10:32:52', 1); +INSERT INTO `gaea_dict_item` VALUES (95, 'BAR_LINE_PROPERTIES', '柱状', 'bar', NULL, 1, 'zh', NULL, 6, 'admin', '2021-08-20 10:33:02', 'admin', '2021-08-20 10:33:02', 1); +INSERT INTO `gaea_dict_item` VALUES (96, 'BAR_LINE_PROPERTIES', '折线', 'line', NULL, 1, 'zh', NULL, 7, 'admin', '2021-08-20 10:33:11', 'admin', '2021-08-20 10:33:11', 1); +INSERT INTO `gaea_dict_item` VALUES (97, 'PIE_PROPERTIES', '名称name', 'name', NULL, 1, 'zh', NULL, 1, 'admin', '2021-08-20 10:35:27', 'admin', '2021-08-20 10:35:27', 1); +INSERT INTO `gaea_dict_item` VALUES (98, 'PIE_PROPERTIES', '数值value', 'value', NULL, 1, 'zh', NULL, 2, 'admin', '2021-08-20 10:35:38', 'admin', '2021-08-20 10:35:38', 1); +INSERT INTO `gaea_dict_item` VALUES (99, 'TEXT_PROPERTIES', '文本数字', 'text', NULL, 1, 'zh', NULL, 1, 'admin', '2021-08-20 10:36:04', 'admin', '2021-08-20 10:36:04', 1); +INSERT INTO `gaea_dict_item` VALUES (100, 'STACK_PROPERTIES', 'x轴字段', 'xAxis', NULL, 1, 'zh', NULL, 1, 'admin', '2021-08-20 10:31:51', 'admin', '2021-08-20 10:31:51', 1); +INSERT INTO `gaea_dict_item` VALUES (101, 'STACK_PROPERTIES', 'x轴时间轴-时', 'xAxis-hour', NULL, 1, 'zh', NULL, 2, 'admin', '2021-08-20 10:32:11', 'admin', '2021-08-20 10:32:11', 1); +INSERT INTO `gaea_dict_item` VALUES (102, 'STACK_PROPERTIES', 'x轴时间轴-天', 'xAxis-day', NULL, 1, 'zh', NULL, 3, 'admin', '2021-08-20 10:32:25', 'admin', '2021-08-20 10:32:25', 1); +INSERT INTO `gaea_dict_item` VALUES (103, 'STACK_PROPERTIES', 'x轴时间轴-月', 'xAxis-month', NULL, 1, 'zh', NULL, 4, 'admin', '2021-08-20 10:32:38', 'admin', '2021-08-20 10:32:38', 1); +INSERT INTO `gaea_dict_item` VALUES (104, 'STACK_PROPERTIES', '时间轴-年', 'xAxis-year', NULL, 1, 'zh', NULL, 5, 'admin', '2021-08-20 10:32:52', 'admin', '2021-08-20 10:32:52', 1); +INSERT INTO `gaea_dict_item` VALUES (105, 'STACK_PROPERTIES', 'y轴字段', 'yAxis', NULL, 1, 'zh', NULL, 6, 'admin', '2021-08-20 10:32:52', 'admin', '2021-08-20 10:32:52', 1); +INSERT INTO `gaea_dict_item` VALUES (106, 'STACK_PROPERTIES', '柱状', 'bar', NULL, 1, 'zh', NULL, 7, 'admin', '2021-08-20 10:33:02', 'admin', '2021-08-20 10:33:02', 1); +INSERT INTO `gaea_dict_item` VALUES (107, 'STACK_PROPERTIES', '折线', 'line', NULL, 1, 'zh', NULL, 8, 'admin', '2021-08-20 10:33:11', 'admin', '2021-08-20 10:33:11', 1); +INSERT INTO `gaea_dict_item` VALUES (108, 'MAP_PROPERTIES', '名称name', 'name', NULL, 1, 'zh', NULL, 1, 'admin', '2021-08-20 10:41:00', 'admin', '2021-08-20 10:41:00', 1); +INSERT INTO `gaea_dict_item` VALUES (109, 'MAP_PROPERTIES', '数值value', 'value', NULL, 1, 'zh', NULL, 2, 'admin', '2021-08-20 10:41:11', 'admin', '2021-08-20 10:41:11', 1); +INSERT INTO `gaea_dict_item` VALUES (110, 'SET_TYPE', 'sql', 'sql', NULL, 1, 'zh', NULL, NULL, 'admin', '2021-11-16 14:43:42', 'admin', '2021-11-16 14:43:42', 1); +INSERT INTO `gaea_dict_item` VALUES (111, 'SET_TYPE', 'http', 'http', NULL, 1, 'zh', NULL, NULL, 'admin', '2021-11-16 14:43:51', 'admin', '2021-11-16 14:43:51', 1); +INSERT INTO `gaea_dict_item` VALUES (112, 'COORD_PROPERTIES', '数据', 'series', NULL, 1, 'zh', NULL, NULL, 'admin', '2023-01-10 07:31:04', 'admin', '2023-01-10 07:31:04', 1); +INSERT INTO `gaea_dict_item` VALUES (113, 'COORD_PROPERTIES', 'X轴', 'xAxis', NULL, 1, 'zh', NULL, NULL, 'admin', '2023-01-10 07:31:04', 'admin', '2023-01-10 07:31:04', 1); +INSERT INTO `gaea_dict_item` VALUES (114, 'COORD_PROPERTIES', 'Y轴', 'yAxis', NULL, 1, 'zh', NULL, NULL, 'admin', '2023-01-10 07:31:04', 'admin', '2023-01-10 07:31:04', 1); +INSERT INTO `gaea_dict_item` VALUES (115, 'SOUTAR_PROPERTIES', '源端', 'source', NULL, 1, 'zh', NULL, NULL, 'admin', '2023-01-10 07:31:05', 'admin', '2023-01-10 07:31:05', 1); +INSERT INTO `gaea_dict_item` VALUES (116, 'SOUTAR_PROPERTIES', '目标端', 'target', NULL, 1, 'zh', NULL, NULL, 'admin', '2023-01-10 07:31:05', 'admin', '2023-01-10 07:31:05', 1); +INSERT INTO `gaea_dict_item` VALUES (117, 'SOUTAR_PROPERTIES', '数值', 'value', NULL, 1, 'zh', NULL, NULL, 'admin', '2023-01-10 07:31:05', 'admin', '2023-01-10 07:31:05', 1); +INSERT INTO `gaea_dict_item` VALUES (118, 'RADAR_PROPERTIES', '名称', 'name', NULL, 1, 'zh', NULL, NULL, 'admin', '2023-01-10 07:31:07', 'admin', '2023-01-10 07:31:07', 1); +INSERT INTO `gaea_dict_item` VALUES (119, 'RADAR_PROPERTIES', '雷达顶点', 'radar', NULL, 1, 'zh', NULL, NULL, 'admin', '2023-01-10 07:31:07', 'admin', '2023-01-10 07:31:07', 1); +INSERT INTO `gaea_dict_item` VALUES (120, 'SELECT_PROPERTIES', '显示值', 'label', NULL, 1, 'zh', NULL, NULL, 'admin', '2023-01-10 07:31:07', 'admin', '2023-01-10 07:31:07', 1); +INSERT INTO `gaea_dict_item` VALUES (121, 'SELECT_PROPERTIES', '提交值', 'value', NULL, 1, 'zh', NULL, NULL, 'admin', '2023-01-10 07:31:07', 'admin', '2023-01-10 07:31:07', 1); + +-- ---------------------------- +-- Table structure for gaea_file +-- ---------------------------- +DROP TABLE IF EXISTS `gaea_file`; +CREATE TABLE `gaea_file` ( + `id` bigint(20) NOT NULL AUTO_INCREMENT, + `file_id` varchar(64) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '生成的唯一uuid', + `file_type` varchar(20) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '文件类型,字典FILE_TYPE', + `file_path` varchar(1024) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '文件在linux中的完整目录,比如/app/dist/export/excel/${fileid}.xlsx', + `url_path` varchar(1024) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '通过接口的下载完整http路径', + `file_instruction` varchar(1024) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '文件内容说明,比如 对账单(202001~202012)', + `create_by` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL, + `create_time` timestamp NULL DEFAULT NULL, + `update_by` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL, + `update_time` timestamp NULL DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP, + `version` int(11) NULL DEFAULT NULL, + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB AUTO_INCREMENT = 830 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic; + +-- ---------------------------- +-- Table structure for gaea_report +-- ---------------------------- +DROP TABLE IF EXISTS `gaea_report`; +CREATE TABLE `gaea_report` ( + `id` bigint(11) NOT NULL AUTO_INCREMENT, + `report_name` varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '名称', + `report_code` varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '报表编码', + `report_group` varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '分组', + `report_type` varchar(20) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '报表类型', + `report_image` varchar(512) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '报表缩略图', + `report_desc` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '报表描述', + `report_author` varchar(512) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '报表作者', + `download_count` bigint(11) NULL DEFAULT NULL COMMENT '报表下载次数', + `enable_flag` int(1) NULL DEFAULT 1 COMMENT '0--已禁用 1--已启用 DIC_NAME=ENABLE_FLAG', + `delete_flag` int(1) NULL DEFAULT 0 COMMENT '0--未删除 1--已删除 DIC_NAME=DELETE_FLAG', + `create_by` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '创建人', + `create_time` datetime NULL DEFAULT NULL COMMENT '创建时间', + `update_by` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '更新人', + `update_time` datetime NULL DEFAULT NULL COMMENT '更新时间', + `version` int(8) NULL DEFAULT NULL COMMENT '版本号', + PRIMARY KEY (`id`) USING BTREE, + UNIQUE INDEX `UNIQUE_REPORT_CODE`(`report_code`) USING BTREE +) ENGINE = InnoDB AUTO_INCREMENT = 194 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic; + +-- ---------------------------- +-- Table structure for gaea_report_dashboard +-- ---------------------------- +DROP TABLE IF EXISTS `gaea_report_dashboard`; +CREATE TABLE `gaea_report_dashboard` ( + `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '看板id', + `report_code` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '报表编码', + `title` varchar(254) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '看板标题', + `width` bigint(20) NULL DEFAULT NULL COMMENT '宽度px', + `height` bigint(20) NULL DEFAULT NULL COMMENT '高度px', + `background_color` varchar(24) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '背景色', + `background_image` varchar(254) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '背景图片', + `preset_line` varchar(4096) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '工作台中的辅助线', + `refresh_seconds` int(11) NULL DEFAULT NULL COMMENT '自动刷新间隔秒', + `enable_flag` int(1) NULL DEFAULT 1 COMMENT '0--已禁用 1--已启用 DIC_NAME=ENABLE_FLAG', + `delete_flag` int(1) NULL DEFAULT 0 COMMENT ' 0--未删除 1--已删除 DIC_NAME=DEL_FLAG', + `sort` int(11) NULL DEFAULT 0 COMMENT '排序,降序', + `create_by` varchar(64) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL, + `create_time` datetime NULL DEFAULT NULL, + `update_by` varchar(64) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL, + `update_time` datetime NULL DEFAULT NULL, + `version` int(8) NULL DEFAULT NULL COMMENT '版本号', + PRIMARY KEY (`id`) USING BTREE, + UNIQUE INDEX `UNIQUE_REPORT_CODE`(`report_code`) USING BTREE +) ENGINE = InnoDB AUTO_INCREMENT = 276 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic; + +-- ---------------------------- +-- Table structure for gaea_report_dashboard_widget +-- ---------------------------- +DROP TABLE IF EXISTS `gaea_report_dashboard_widget`; +CREATE TABLE `gaea_report_dashboard_widget` ( + `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '组件id', + `report_code` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '报表编码', + `type` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '组件类型参考字典DASHBOARD_PANEL_TYPE', + `setup` text CHARACTER SET utf8 COLLATE utf8_general_ci NULL COMMENT '组件的渲染属性json', + `data` text CHARACTER SET utf8 COLLATE utf8_general_ci NULL COMMENT '组件的数据属性json', + `collapse` text CHARACTER SET utf8 COLLATE utf8_general_ci NULL COMMENT '组件的配置属性json', + `position` text CHARACTER SET utf8 COLLATE utf8_general_ci NULL COMMENT '组件的大小位置属性json', + `options` text CHARACTER SET utf8 COLLATE utf8_general_ci NULL COMMENT 'options配置项', + `refresh_seconds` int(11) NULL DEFAULT NULL COMMENT '自动刷新间隔秒', + `enable_flag` int(1) NULL DEFAULT 1 COMMENT '0--已禁用 1--已启用 DIC_NAME=ENABLE_FLAG', + `delete_flag` int(1) NULL DEFAULT 0 COMMENT ' 0--未删除 1--已删除 DIC_NAME=DEL_FLAG', + `sort` bigint(20) NULL DEFAULT 0 COMMENT '排序,图层的概念', + `create_by` varchar(64) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL, + `create_time` datetime NULL DEFAULT NULL, + `update_by` varchar(64) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL, + `update_time` datetime NULL DEFAULT NULL, + `version` int(8) NULL DEFAULT NULL COMMENT '版本号', + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB AUTO_INCREMENT = 8712 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic; + +-- ---------------------------- +-- Table structure for gaea_report_data_set +-- ---------------------------- +DROP TABLE IF EXISTS `gaea_report_data_set`; +CREATE TABLE `gaea_report_data_set` ( + `id` bigint(20) NOT NULL AUTO_INCREMENT, + `set_code` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '数据集编码', + `set_name` varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '数据集名称', + `set_desc` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '数据集描述', + `source_code` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '数据源编码', + `dyn_sentence` varchar(2048) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '动态查询sql或者接口中的请求体', + `case_result` text CHARACTER SET utf8 COLLATE utf8_general_ci NULL COMMENT '结果案例', + `enable_flag` int(1) NULL DEFAULT 1 COMMENT '0--已禁用 1--已启用 DIC_NAME=ENABLE_FLAG', + `delete_flag` int(1) NULL DEFAULT 0 COMMENT '0--未删除 1--已删除 DIC_NAME=DELETE_FLAG', + `create_by` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '创建人', + `create_time` datetime NULL DEFAULT NULL COMMENT '创建时间', + `update_by` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '更新人', + `update_time` datetime NULL DEFAULT NULL COMMENT '更新时间', + `version` int(8) NULL DEFAULT NULL, + `set_type` varchar(10) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL, + PRIMARY KEY (`id`) USING BTREE, + UNIQUE INDEX `unique_set_code`(`set_code`) USING BTREE +) ENGINE = InnoDB AUTO_INCREMENT = 73 CHARACTER SET = utf8 COLLATE = utf8_general_ci COMMENT = '数据集管理' ROW_FORMAT = Dynamic; + +-- ---------------------------- +-- Table structure for gaea_report_data_set_param +-- ---------------------------- +DROP TABLE IF EXISTS `gaea_report_data_set_param`; +CREATE TABLE `gaea_report_data_set_param` ( + `id` bigint(20) NOT NULL AUTO_INCREMENT, + `set_code` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '数据集编码', + `param_name` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '参数名', + `param_desc` varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '参数描述', + `param_type` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '参数类型,字典=', + `sample_item` varchar(1080) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '参数示例项', + `required_flag` int(1) NULL DEFAULT 1 COMMENT '0--非必填 1--必填 DIC_NAME=REQUIRED_FLAG', + `validation_rules` varchar(2048) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT 'js校验字段值规则,满足校验返回 true', + `order_num` int(11) NULL DEFAULT NULL COMMENT '排序', + `enable_flag` int(1) NULL DEFAULT 1 COMMENT '0--已禁用 1--已启用 DIC_NAME=ENABLE_FLAG', + `delete_flag` int(1) NULL DEFAULT 0 COMMENT '0--未删除 1--已删除 DIC_NAME=DELETE_FLAG', + `create_by` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '创建人', + `create_time` datetime NULL DEFAULT NULL COMMENT '创建时间', + `update_by` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '更新人', + `update_time` datetime NULL DEFAULT NULL COMMENT '更新时间', + `version` int(8) NULL DEFAULT NULL, + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB AUTO_INCREMENT = 60 CHARACTER SET = utf8 COLLATE = utf8_general_ci COMMENT = '数据集查询参数' ROW_FORMAT = Dynamic; + +-- ---------------------------- +-- Table structure for gaea_report_data_set_transform +-- ---------------------------- +DROP TABLE IF EXISTS `gaea_report_data_set_transform`; +CREATE TABLE `gaea_report_data_set_transform` ( + `id` bigint(20) NOT NULL AUTO_INCREMENT, + `set_code` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '数据集编码', + `transform_type` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '数据转换类型,DIC_NAME=TRANSFORM_TYPE; js,javaBean,字典转换', + `transform_script` varchar(10800) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '数据转换script,处理逻辑', + `order_num` int(2) NULL DEFAULT NULL COMMENT '排序,执行数据转换顺序', + `enable_flag` int(1) NULL DEFAULT 1 COMMENT '0--已禁用 1--已启用 DIC_NAME=ENABLE_FLAG', + `delete_flag` int(1) NULL DEFAULT 0 COMMENT '0--未删除 1--已删除 DIC_NAME=DELETE_FLAG', + `create_by` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '创建人', + `create_time` datetime NULL DEFAULT NULL COMMENT '创建时间', + `update_by` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '更新人', + `update_time` datetime NULL DEFAULT NULL COMMENT '更新时间', + `version` int(8) NULL DEFAULT NULL, + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB AUTO_INCREMENT = 37 CHARACTER SET = utf8 COLLATE = utf8_general_ci COMMENT = '数据集数据转换' ROW_FORMAT = Dynamic; + +-- ---------------------------- +-- Table structure for gaea_report_data_source +-- ---------------------------- +DROP TABLE IF EXISTS `gaea_report_data_source`; +CREATE TABLE `gaea_report_data_source` ( + `id` bigint(20) NOT NULL AUTO_INCREMENT, + `source_code` varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '数据源编码', + `source_name` varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '数据源名称', + `source_desc` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '数据源描述', + `source_type` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '数据源类型 DIC_NAME=SOURCE_TYPE; mysql,orace,sqlserver,elasticsearch,接口,javaBean,数据源类型字典中item-extend动态生成表单', + `source_config` varchar(2048) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '数据源连接配置json:关系库{ jdbcUrl:\'\', username:\'\', password:\'\' } ES{ hostList:\'ip1:9300,ip2:9300,ip3:9300\', clusterName:\'elasticsearch_cluster\' } 接口{ apiUrl:\'http://ip:port/url\', method:\'\' } javaBean{ beanNamw:\'xxx\' }', + `enable_flag` int(1) NULL DEFAULT 1 COMMENT '0--已禁用 1--已启用 DIC_NAME=ENABLE_FLAG', + `delete_flag` int(1) NULL DEFAULT 0 COMMENT '0--未删除 1--已删除 DIC_NAME=DELETE_FLAG', + `create_by` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '创建人', + `create_time` datetime NULL DEFAULT NULL COMMENT '创建时间', + `update_by` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '更新人', + `update_time` datetime NULL DEFAULT NULL COMMENT '更新时间', + `version` int(8) NULL DEFAULT NULL, + PRIMARY KEY (`id`) USING BTREE, + UNIQUE INDEX `unique_source_code`(`source_code`) USING BTREE +) ENGINE = InnoDB AUTO_INCREMENT = 2 CHARACTER SET = utf8 COLLATE = utf8_general_ci COMMENT = '数据源管理' ROW_FORMAT = Dynamic; + +-- ---------------------------- +-- Table structure for gaea_report_excel +-- ---------------------------- +DROP TABLE IF EXISTS `gaea_report_excel`; +CREATE TABLE `gaea_report_excel` ( + `id` bigint(11) NOT NULL AUTO_INCREMENT, + `report_code` varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '报表编码', + `set_codes` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '数据集编码,以|分割', + `set_param` varchar(1024) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '数据集查询参数', + `json_str` text CHARACTER SET utf8 COLLATE utf8_general_ci NULL COMMENT '报表json串', + `enable_flag` int(1) NULL DEFAULT 1 COMMENT '0--已禁用 1--已启用 DIC_NAME=ENABLE_FLAG', + `delete_flag` int(1) NULL DEFAULT 0 COMMENT '0--未删除 1--已删除 DIC_NAME=DELETE_FLAG', + `create_by` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '创建人', + `create_time` datetime NULL DEFAULT NULL COMMENT '创建时间', + `update_by` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '更新人', + `update_time` datetime NULL DEFAULT NULL COMMENT '更新时间', + `version` int(8) NULL DEFAULT NULL COMMENT '版本号', + PRIMARY KEY (`id`) USING BTREE, + UNIQUE INDEX `UNIQUE_REPORT_CODE`(`report_code`) USING BTREE +) ENGINE = InnoDB AUTO_INCREMENT = 215 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic; + +-- ---------------------------- +-- Table structure for gaea_report_share +-- ---------------------------- +DROP TABLE IF EXISTS `gaea_report_share`; +CREATE TABLE `gaea_report_share` ( + `id` bigint(20) NOT NULL AUTO_INCREMENT, + `share_code` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '分享编码,系统生成,默认UUID', + `share_valid_type` int(2) NULL DEFAULT NULL COMMENT '分享有效期类型,DIC_NAME=SHARE_VAILD', + `share_valid_time` datetime NULL DEFAULT NULL COMMENT '分享有效期', + `share_token` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '分享token', + `share_url` varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '分享url', + `share_password` varchar(10) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '分享码', + `report_code` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '报表编码', + `enable_flag` int(1) NULL DEFAULT 1 COMMENT '0--已禁用 1--已启用 DIC_NAME=ENABLE_FLAG', + `delete_flag` int(1) NULL DEFAULT 0 COMMENT '0--未删除 1--已删除 DIC_NAME=DELETE_FLAG', + `create_by` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '创建人', + `create_time` datetime NULL DEFAULT NULL COMMENT '创建时间', + `update_by` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '更新人', + `update_time` datetime NULL DEFAULT NULL COMMENT '更新时间', + `version` int(8) NULL DEFAULT NULL, + PRIMARY KEY (`id`) USING BTREE, + UNIQUE INDEX `UNIQUE_SHARE_CODE`(`share_code`) USING BTREE +) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8 COLLATE = utf8_general_ci COMMENT = '报表分享' ROW_FORMAT = Dynamic; + +SET FOREIGN_KEY_CHECKS = 1; diff --git a/src/main/resources/db/migration/V1.1.0__update.sql b/src/main/resources/db/migration/V1.1.0__update.sql new file mode 100644 index 0000000..e69de29 diff --git a/src/main/resources/db/migration/V1.2.0__update.sql b/src/main/resources/db/migration/V1.2.0__update.sql new file mode 100644 index 0000000..56c7670 --- /dev/null +++ b/src/main/resources/db/migration/V1.2.0__update.sql @@ -0,0 +1,7 @@ +-- 增加地图解析属性 +INSERT INTO `aj_report`.`gaea_dict`(`dict_name`, `dict_code`, `remark`, `create_by`, `create_time`, `update_by`, `update_time`, `version`) VALUES ('地图经纬度属性', 'MAP_V2_PROPERTIES', '地图属性', 'admin', '2021-04-29 10:28:15', 'admin', '2021-06-23 10:47:20', 1); + +INSERT INTO `aj_report`.`gaea_dict_item`(`dict_code`, `item_name`, `item_value`, `item_extend`, `enabled`, `locale`, `remark`, `sort`, `create_by`, `create_time`, `update_by`, `update_time`, `version`) VALUES ('MAP_V2_PROPERTIES', '地址名称', 'name', NULL, 1, 'zh', NULL, 1, 'admin', '2021-08-20 10:41:00', 'admin', '2021-08-20 10:41:00', 1); +INSERT INTO `aj_report`.`gaea_dict_item`(`dict_code`, `item_name`, `item_value`, `item_extend`, `enabled`, `locale`, `remark`, `sort`, `create_by`, `create_time`, `update_by`, `update_time`, `version`) VALUES ('MAP_V2_PROPERTIES', '经度坐标', 'longitude', NULL, 1, 'zh', NULL, 1, 'admin', '2021-08-20 10:41:00', 'admin', '2021-08-20 10:41:00', 1); +INSERT INTO `aj_report`.`gaea_dict_item`(`dict_code`, `item_name`, `item_value`, `item_extend`, `enabled`, `locale`, `remark`, `sort`, `create_by`, `create_time`, `update_by`, `update_time`, `version`) VALUES ('MAP_V2_PROPERTIES', '维度坐标', 'latitude', NULL, 1, 'zh', NULL, 1, 'admin', '2021-08-20 10:41:00', 'admin', '2021-08-20 10:41:00', 1); +INSERT INTO `aj_report`.`gaea_dict_item`(`dict_code`, `item_name`, `item_value`, `item_extend`, `enabled`, `locale`, `remark`, `sort`, `create_by`, `create_time`, `update_by`, `update_time`, `version`) VALUES ('MAP_V2_PROPERTIES', '数值', 'value', NULL, 1, 'zh', NULL, 1, 'admin', '2021-08-20 10:41:00', 'admin', '2021-08-20 10:41:00', 1); diff --git a/src/main/resources/dev.yml b/src/main/resources/dev.yml new file mode 100644 index 0000000..61052fd --- /dev/null +++ b/src/main/resources/dev.yml @@ -0,0 +1,17 @@ +# 该文件配置会继承bootstrap.xml,只需要配置数据库等差异配置 +spring: + datasource: + url: jdbc:mysql://127.0.0.1:3306/aj_report?characterEncoding=UTF-8&serverTimezone=Asia/Shanghai&useSSL=false + username: root + password: 123456 + gaea: + subscribes: + oss: #文件存储 都配置的情况下优先级minio->amazonS3->nfs + enabled: true + ##允许上传的文件后缀 + file-type-while-list: .png|.jpg|.gif|.icon|.pdf|.xlsx|.xls|.csv|.mp4|.avi|.jpeg|.aaa|.svg + # 用于文件上传成功后,生成文件的下载公网完整URL,http://serverip:9095/file/download,注意填写IP必须填写后端服务所在的机器IP + downloadPath: http://127.0.0.1:9095/file/download + nfs: + #上传对应本地全路径,注意目录不会自动创建,注意 Win是 \ 且有盘符,linux是 / 无盘符,注意目录权限问题 + path: C:\Users\hh\Desktop\DS\report-core\File\ diff --git a/src/main/resources/ehcache.xml b/src/main/resources/ehcache.xml new file mode 100644 index 0000000..2d8bb8d --- /dev/null +++ b/src/main/resources/ehcache.xml @@ -0,0 +1,36 @@ + + + + + + + + + + diff --git a/src/main/resources/i18n/messages.properties b/src/main/resources/i18n/messages.properties new file mode 100644 index 0000000..4226685 --- /dev/null +++ b/src/main/resources/i18n/messages.properties @@ -0,0 +1,6 @@ +500=\u7CFB\u7EDF\u5F02\u5E38 +200=\u64CD\u4F5C\u6210\u529F +2001=\u6587\u4EF6\u540D\u4E0D\u5141\u8BB8\u4E3A\u7A7A +2002=\u6587\u4EF6\u7C7B\u578B\u4E0D\u652F\u6301 +2003=\u6587\u4EF6\u4E0A\u4F20\u5931\u8D25 +6001={0} diff --git a/src/main/resources/i18n/messages_en_US.properties b/src/main/resources/i18n/messages_en_US.properties new file mode 100644 index 0000000..9b37389 --- /dev/null +++ b/src/main/resources/i18n/messages_en_US.properties @@ -0,0 +1,53 @@ +500=Server error +200=success + +User.password.error=Password error +user.password.config.password.canot.equal=user password config password canot equal +user.inconsistent.password.error=user inconsistent password error +user.old.password.error=user old password error + +1013=The code does not allow duplication +2001=File names are not allowed to be empty +2002=Unsupported suffix type +2003=File upload failed:{0} +2004=File does not exist +file.operation.failed=File operation failed\uFF1A{0} + +field.not.null={} can not be null +field.not.empty={} can not be empty +field.min={} must great then {} +field.max={} must less then {} +field.dict.error={} value error + +login.error=username or password error +User.token.expired=User token has expired + +3001=Template code does not allow duplication +3002=The receiver is not allowed to be empty +Insert.failure=Insert failure +Update.failure=Update failure\uFF0Ccheck version +Delete.failure=Delete failure +Dict.item.code.exist=Dict item code exist +Rule.execute.param.null=Rule execute param null +Rule.content.compile.error=Rule content compile error +Rule.content.execute.error=Rule content execute error +Rule.content.not.exist=Rule content not exist +Rule.code.exist=Rule code exist +Rule.fields.not.exist=Rule fields not exist +Rule.field.value.is.required=Rule field value is required +Rule.field.value.type.error=Rule field value type error +Rule.fields.check.error=Rule fields check error +Component.load.check.error={0} Component not load +4001=Data source connection failed {0} +4002=Data source type is not currently supported +4003=execute sql error, {0} +4004=Incomplete parameter replacement values {0} +4005=execute js error {0} +4006=analysis data error {0} +4007=The report code does not allow duplication +4008=The set code does not allow duplication +4009=The source code does not allow duplication {0} +4010=Can't auto find match driver class +4011=execute javaBean error {0} + +report.share.link.invalid=report share link invalid diff --git a/src/main/resources/i18n/messages_zh_CN.properties b/src/main/resources/i18n/messages_zh_CN.properties new file mode 100644 index 0000000..7222ba5 --- /dev/null +++ b/src/main/resources/i18n/messages_zh_CN.properties @@ -0,0 +1,57 @@ +500=\u7CFB\u7EDF\u5F02\u5E38 +200=\u64CD\u4F5C\u6210\u529F + +User.password.error=\u5BC6\u7801\u4E0D\u6B63\u786E +user.password.config.password.canot.equal=\u65B0\u5BC6\u7801\u4E0D\u80FD\u548C\u539F\u5BC6\u7801\u4E00\u81F4 +user.inconsistent.password.error=\u5BC6\u7801\u548C\u786E\u8BA4\u5BC6\u7801\u4E0D\u4E00\u81F4 +user.old.password.error=\u65E7\u5BC6\u7801\u4E0D\u6B63\u786E +1013=\u7F16\u7801\u4E0D\u5141\u8BB8\u91CD\u590D +2001=\u6587\u4EF6\u540D\u4E0D\u5141\u8BB8\u4E3A\u7A7A +2002=\u6587\u4EF6\u7C7B\u578B\u4E0D\u652F\u6301 +2003=\u6587\u4EF6\u4E0A\u4F20\u5931\u8D25\uFF1A{0} +2004=\u6587\u4EF6\u4E0D\u5B58\u5728 +file.operation.failed=\u6587\u4EF6\u64CD\u4F5C\u5931\u8D25\uFF1A{0} + +field.not.null={}\u4E0D\u80FD\u4E3Anull +field.not.empty={}\u4E0D\u80FD\u4E3A\u7A7A\u5B57\u7B26\u4E32 +field.min={}\u5FC5\u987B\u5927\u4E8E\u7B49\u4E8E{} +field.max={}\u5FC5\u987B\u5C0F\u4E8E\u7B49\u4E8E{} +field.dict.error={}\u5C5E\u6027 + +login.error=\u7528\u6237\u540D\u6216\u8005\u5BC6\u7801\u4E0D\u6B63\u786E +User.token.expired=\u7528\u6237\u672A\u767B\u5F55\u6216\u767B\u5F55\u4FE1\u606F\u8FC7\u671F + + +3001=\u6A21\u677F\u4EE3\u7801\u4E0D\u5141\u8BB8\u91CD\u590D +3002=\u63A5\u6536\u4EBA\u4E0D\u5141\u8BB8\u4E3A\u7A7A +Dict.item.code.exist=\u6570\u636E\u5B57\u5178\u9879\u503C\u5DF2\u5B58\u5728 +Insert.failure=\u63D2\u5165\u5931\u8D25 +Update.failure=\u66F4\u65B0\u5931\u8D25\uFF0C\u68C0\u67E5\u7248\u672C\u53F7\u662F\u5426\u4E00\u81F4 +Delete.failure=\u5220\u9664\u5931\u8D25 +Rule.execute.param.null=\u89C4\u5219\u6267\u884C\u53C2\u6570\u4E0D\u80FD\u4E3A\u7A7A +Rule.content.compile.error=\u89C4\u5219\u5185\u5BB9\u7F16\u8BD1\u5931\u8D25 +Rule.content.execute.error=\u89C4\u5219\u6267\u884C\u5931\u8D25 +Rule.code.exist=\u89C4\u5219\u7F16\u7801\u5DF2\u5B58\u5728 +Rule.content.not.exist=\u5BF9\u5E94\u89C4\u5219\u5185\u5BB9\u4E0D\u5B58\u5728 +Rule.fields.not.exist=\u5BF9\u5E94\u89C4\u5219\u5B57\u6BB5\u503C\u4E0D\u5B58\u5728 +Rule.field.value.is.required=\u89C4\u5219\u5B57\u6BB5\u5FC5\u586B +Rule.field.value.type.error=\u89C4\u5219\u5B57\u6BB5\u503C\u7C7B\u578B\u9519\u8BEF +Rule.fields.check.error=\u89C4\u5219\u53C2\u6570\u6821\u9A8C\u4E0D\u901A\u8FC7 +Component.load.check.error={0}\u7EC4\u4EF6\u672A\u52A0\u8F7D + +4001=\u6570\u636E\u6E90\u8FDE\u63A5\u5931\u8D25\uFF0C{0} +4002=\u6570\u636E\u6E90\u7C7B\u578B\u6682\u4E0D\u652F\u6301 +4003=\u6267\u884Csql\u5931\u8D25\uFF0C{0} +4004=\u53C2\u6570\u66FF\u6362\u503C\u4E0D\u5168\uFF0C{0} +4005=\u6267\u884Cjs\u5931\u8D25\uFF0C{0} +4006=\u89E3\u6790\u6570\u636E\u5931\u8D25\uFF0C{0} +4007=\u62A5\u8868\u7F16\u7801\u4E0D\u5141\u8BB8\u91CD\u590D +4008=\u6570\u636E\u96C6\u7F16\u7801\u4E0D\u5141\u8BB8\u91CD\u590D +4009=\u6570\u636E\u6E90\u7F16\u7801\u4E0D\u5141\u8BB8\u91CD\u590D +4010=\u9A71\u52A8\u5305\u4E0D\u5B58\u5728\uFF0C{0} +4011=\u6267\u884CjavaBean\u5931\u8D25\uFF0C{0} +6001={0} + +7001=\u89E3\u6790\u5931\u8D25 + +report.share.link.invalid=\u5206\u4EAB\u94FE\u63A5\u5DF2\u5931\u6548 diff --git a/src/main/resources/logback.xml b/src/main/resources/logback.xml new file mode 100644 index 0000000..a2bd80e --- /dev/null +++ b/src/main/resources/logback.xml @@ -0,0 +1,34 @@ + + + + + + + + + %d{MM-dd HH:mm:ss.SSS} | %thread |-%-5level %logger{36}:%L - %msg%n + + + INFO + + + + + + ${LOG_HOME}/${LOG_NAME}.log + + ${LOG_HOME}/%d{yyyy-MM-dd}/${LOG_NAME}-%i.log + 50MB + 30 + + + %d{MM-dd HH:mm:ss.SSS} |-%-5level %logger{36}:%L - %m%n + + + + + + + + + diff --git a/src/main/resources/mapper/AccessAuthorityMapper.xml b/src/main/resources/mapper/AccessAuthorityMapper.xml new file mode 100644 index 0000000..139ba26 --- /dev/null +++ b/src/main/resources/mapper/AccessAuthorityMapper.xml @@ -0,0 +1,27 @@ + + + + + + + + + + + + + + + + + + + + + + + + id,parent_target,target,target_name,action,action_name,create_by,create_time,delete_flag,enable_flag,sort,update_by,update_time,version + + + \ No newline at end of file diff --git a/src/main/resources/mapper/AccessRoleAuthorityMapper.xml b/src/main/resources/mapper/AccessRoleAuthorityMapper.xml new file mode 100644 index 0000000..68e1779 --- /dev/null +++ b/src/main/resources/mapper/AccessRoleAuthorityMapper.xml @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + id,role_code,target,action + + + \ No newline at end of file diff --git a/src/main/resources/mapper/AccessRoleMapper.xml b/src/main/resources/mapper/AccessRoleMapper.xml new file mode 100644 index 0000000..4242193 --- /dev/null +++ b/src/main/resources/mapper/AccessRoleMapper.xml @@ -0,0 +1,26 @@ + + + + + + + + + + + + + + + + + + + + id,role_code,role_name,delete_flag,enable_flag,create_by,create_time,update_by,update_time,version + + + + \ No newline at end of file diff --git a/src/main/resources/mapper/AccessUserMapper.xml b/src/main/resources/mapper/AccessUserMapper.xml new file mode 100644 index 0000000..9cbb7dc --- /dev/null +++ b/src/main/resources/mapper/AccessUserMapper.xml @@ -0,0 +1,36 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + id,login_name,password,real_name,email,phone,remark, + last_login_ip,last_login_time, + delete_flag,enable_flag,create_by,create_time,update_by,update_time,version + + + + \ No newline at end of file diff --git a/src/main/resources/mapper/AccessUserRoleMapper.xml b/src/main/resources/mapper/AccessUserRoleMapper.xml new file mode 100644 index 0000000..9b7dd39 --- /dev/null +++ b/src/main/resources/mapper/AccessUserRoleMapper.xml @@ -0,0 +1,15 @@ + + + + + + + + + + + + id,login_name,role_code + + + \ No newline at end of file diff --git a/src/main/resources/mapper/DataSetMapper.xml b/src/main/resources/mapper/DataSetMapper.xml new file mode 100644 index 0000000..585950b --- /dev/null +++ b/src/main/resources/mapper/DataSetMapper.xml @@ -0,0 +1,29 @@ + + + + + + + + + + + + + + + + + + + + + + + + id,set_code,set_name,set_desc,source_code,dyn_sentence,case_result,enable_flag,delete_flag,create_by,create_time,update_by,update_time,version + + + + + diff --git a/src/main/resources/mapper/DataSetParamMapper.xml b/src/main/resources/mapper/DataSetParamMapper.xml new file mode 100644 index 0000000..779d114 --- /dev/null +++ b/src/main/resources/mapper/DataSetParamMapper.xml @@ -0,0 +1,31 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + id,set_code,param_name,param_desc,param_type,sample_item,required_flag,validation_rules,order_num,enable_flag,delete_flag,create_by,create_time,update_by,update_time,version + + + + + diff --git a/src/main/resources/mapper/DataSetTransformMapper.xml b/src/main/resources/mapper/DataSetTransformMapper.xml new file mode 100644 index 0000000..13f2adc --- /dev/null +++ b/src/main/resources/mapper/DataSetTransformMapper.xml @@ -0,0 +1,27 @@ + + + + + + + + + + + + + + + + + + + + + + id,set_code,transform_type,transform_script,order_num,enable_flag,delete_flag,create_by,create_time,update_by,update_time,version + + + + + diff --git a/src/main/resources/mapper/DataSourceMapper.xml b/src/main/resources/mapper/DataSourceMapper.xml new file mode 100644 index 0000000..a060de8 --- /dev/null +++ b/src/main/resources/mapper/DataSourceMapper.xml @@ -0,0 +1,28 @@ + + + + + + + + + + + + + + + + + + + + + + + id,source_code,source_name,source_desc,source_type,source_config,enable_flag,delete_flag,create_by,create_time,update_by,update_time,version + + + + + diff --git a/src/main/resources/mapper/ReportDashboardMapper.xml b/src/main/resources/mapper/ReportDashboardMapper.xml new file mode 100644 index 0000000..f29f602 --- /dev/null +++ b/src/main/resources/mapper/ReportDashboardMapper.xml @@ -0,0 +1,32 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + id,report_code,title,width,height,background_color,background_image,preset_line,refresh_seconds,enable_flag,delete_flag,sort,create_by,create_time,update_by,update_time + + + + + diff --git a/src/main/resources/mapper/ReportDashboardWidgetMapper.xml b/src/main/resources/mapper/ReportDashboardWidgetMapper.xml new file mode 100644 index 0000000..8a98fec --- /dev/null +++ b/src/main/resources/mapper/ReportDashboardWidgetMapper.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + + + + + + + + + + + id,report_code,`type`,setup,`data`,`position`,collapse,enable_flag,delete_flag,sort,create_by,create_time,update_by,update_time + + + + + diff --git a/src/main/resources/mapper/ReportExcelMapper.xml b/src/main/resources/mapper/ReportExcelMapper.xml new file mode 100644 index 0000000..a5a50b0 --- /dev/null +++ b/src/main/resources/mapper/ReportExcelMapper.xml @@ -0,0 +1,22 @@ + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/main/resources/mapper/ReportMapper.xml b/src/main/resources/mapper/ReportMapper.xml new file mode 100644 index 0000000..b63ef94 --- /dev/null +++ b/src/main/resources/mapper/ReportMapper.xml @@ -0,0 +1,29 @@ + + + + + + + + + + + + + + + + + + + + + + + + id,report_name,report_code,json_str,enable_flag,delete_flag,create_by,create_time,update_by,update_time,version + + + + + diff --git a/src/main/resources/mapper/ReportShareMapper.xml b/src/main/resources/mapper/ReportShareMapper.xml new file mode 100644 index 0000000..b26b792 --- /dev/null +++ b/src/main/resources/mapper/ReportShareMapper.xml @@ -0,0 +1,26 @@ + + + + + + + + + + + + + + + + + + + + + + + id,share_code,share_valid_type,share_valid_time,share_url,report_code,enable_flag,delete_flag,create_by,create_time,update_by,update_time,version + + + diff --git a/src/main/resources/prod.yml b/src/main/resources/prod.yml new file mode 100644 index 0000000..ace9169 --- /dev/null +++ b/src/main/resources/prod.yml @@ -0,0 +1,16 @@ +# 该文件配置会继承bootstrap.xml,只需要配置数据库等差异配置 +spring: + datasource: + url: jdbc:mysql://82.157.76.162:3306/aj_report?characterEncoding=UTF-8&serverTimezone=Asia/Shanghai&useSSL=false + username: root + password: wB4TL7Mp + gaea: + subscribes: + oss: #文件存储 + enabled: true + ##允许上传的文件后缀 + file-type-while-list: .png|.jpg|.gif|.icon|.pdf|.xlsx|.xls|.csv|.mp4|.avi|.jpeg|.aaa|.svg + # 用于文件上传成功后,生成文件的下载公网完整URL + downloadPath: http://82.157.76.162:9095/file/download + nfs: + path: /data/BS_File/