diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..ff96ea4d --- /dev/null +++ b/.gitignore @@ -0,0 +1,7 @@ +.idea +target +*.iml +/view/flutter/**/gen/* +**/*.log +dist +logs diff --git a/derby.log b/derby.log new file mode 100644 index 00000000..e69de29b diff --git a/pom.xml b/pom.xml new file mode 100644 index 00000000..4dc13d53 --- /dev/null +++ b/pom.xml @@ -0,0 +1,104 @@ + + + + 4.0.0 + + com.anji-plus + spring-boot-gaea-parent + 1.0.0.RELEASE + + + com.anjiplus.template.gaea + template-gaea + anjiplus-template-gaea + 1.0.0-SNAPSHOT + template-gaea + pom + + + report-core + + + + 1.0.0-SNAPSHOT + 1.0.0-SNAPSHOT + 1.0.0-SNAPSHOT + 1.0.0-SNAPSHOT + 1.0.0-SNAPSHOT + true + + + + + + com.anjiplus.template.gaea + template-gaea-auth + ${project.version} + + + com.anjiplus.template.gaea + template-gaea-business + ${project.version} + + + com.anjiplus.template.gaea + template-gaea-common + ${project.version} + + + + com.anjiplus.template.gaea + template-gaea-generator + ${gaea.generator.version} + + + + com.anji-plus + spring-boot-gaea + ${gaea.version} + + + com.anji-plus + spring-boot-starter-gaea-security + ${gaea.security.version} + + + + com.anji-plus + spring-boot-starter-gaea-export + ${gaea.export.version} + + + + com.anji-plus + spring-boot-starter-gaea-log + ${gaea.log.version} + + + + + + + + dev + + dev + + + true + + + + + + + nexus-releases + http://nexus.anji-plus.com:8081/repository/maven-releases/ + + + nexus-snapshots + http://nexus.anji-plus.com:8081/repository/maven-snapshots/ + + + diff --git a/report-core/pom.xml b/report-core/pom.xml new file mode 100644 index 00000000..da3c9e3b --- /dev/null +++ b/report-core/pom.xml @@ -0,0 +1,115 @@ + + + + + com.anjiplus.template.gaea + template-gaea + 1.0.0-SNAPSHOT + ../ + + 4.0.0 + aj-report + aj-report + + + + com.anjiplus.template.gaea + template-gaea-common + + + + + + + + + + + + + + com.anjiplus.template.gaea + template-gaea-generator + + + + com.baomidou + mybatis-plus-boot-starter + + + + mysql + mysql-connector-java + + + + org.springframework.boot + spring-boot-starter-test + test + + + + + + + + + + + + + com.anji-plus + spring-boot-starter-gaea-export + + + com.anji-plus + spring-boot-starter-gaea-log + + + + + com.alibaba + druid + 1.1.22 + + + + + owinfo + impalajdbc41 + 1.0.0 + system + ${project.basedir}/src/main/resources/lib/ImpalaJDBC41.jar + + + org.apache.hive + hive-jdbc + 1.2.1 + + + org.eclipse.jetty.aggregate + jetty-all + + + + + + + + + src/main/resources + true + + + + + org.springframework.boot + spring-boot-maven-plugin + + true + + + + + diff --git a/report-core/src/main/java/com/anjiplus/template/gaea/business/ReportApplication.java b/report-core/src/main/java/com/anjiplus/template/gaea/business/ReportApplication.java new file mode 100644 index 00000000..ce50103e --- /dev/null +++ b/report-core/src/main/java/com/anjiplus/template/gaea/business/ReportApplication.java @@ -0,0 +1,27 @@ +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; + +/** + * 业务模板 + * @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" +}) +public class ReportApplication { + public static void main( String[] args ) { + SpringApplication.run(ReportApplication.class); + } +} diff --git a/report-core/src/main/java/com/anjiplus/template/gaea/business/base/BaseController.java b/report-core/src/main/java/com/anjiplus/template/gaea/business/base/BaseController.java new file mode 100644 index 00000000..0052d6c5 --- /dev/null +++ b/report-core/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/report-core/src/main/java/com/anjiplus/template/gaea/business/base/BaseService.java b/report-core/src/main/java/com/anjiplus/template/gaea/business/base/BaseService.java new file mode 100644 index 00000000..6808cb91 --- /dev/null +++ b/report-core/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/report-core/src/main/java/com/anjiplus/template/gaea/business/code/ResponseCode.java b/report-core/src/main/java/com/anjiplus/template/gaea/business/code/ResponseCode.java new file mode 100644 index 00000000..d4c5ed63 --- /dev/null +++ b/report-core/src/main/java/com/anjiplus/template/gaea/business/code/ResponseCode.java @@ -0,0 +1,68 @@ +package com.anjiplus.template.gaea.business.code; + +/** + * 响应码 + * @author lr + * @since 2021-02-22 + */ +public interface ResponseCode { + + /** + * 字典项重复 + */ + 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"; +} diff --git a/report-core/src/main/java/com/anjiplus/template/gaea/business/config/BusinessAutoConfiguration.java b/report-core/src/main/java/com/anjiplus/template/gaea/business/config/BusinessAutoConfiguration.java new file mode 100644 index 00000000..9c6751a1 --- /dev/null +++ b/report-core/src/main/java/com/anjiplus/template/gaea/business/config/BusinessAutoConfiguration.java @@ -0,0 +1,29 @@ +package com.anjiplus.template.gaea.business.config; + +import com.anjiplus.template.gaea.business.runner.ApplicationInitRunner; + +import org.mybatis.spring.annotation.MapperScan; +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(); + } +} diff --git a/report-core/src/main/java/com/anjiplus/template/gaea/business/constant/BusinessConstant.java b/report-core/src/main/java/com/anjiplus/template/gaea/business/constant/BusinessConstant.java new file mode 100644 index 00000000..3c825b93 --- /dev/null +++ b/report-core/src/main/java/com/anjiplus/template/gaea/business/constant/BusinessConstant.java @@ -0,0 +1,14 @@ +package com.anjiplus.template.gaea.business.constant; + +/** + * 常量 + * @author lr + * @since 2021-03-26 + */ +public interface BusinessConstant { + + /** + * 字典项重复 + */ + String DICT_ITEM_EXIST_GROUP = "dictItemExist"; +} diff --git a/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dashboard/controller/ReportDashboardController.java b/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dashboard/controller/ReportDashboardController.java new file mode 100644 index 00000000..a1754871 --- /dev/null +++ b/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dashboard/controller/ReportDashboardController.java @@ -0,0 +1,64 @@ + +package com.anjiplus.template.gaea.business.modules.data.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.data.dashboard.controller.dto.ChartDto; +import com.anjiplus.template.gaea.business.modules.data.dashboard.controller.dto.ReportDashboardObjectDto; +import com.anjiplus.template.gaea.business.modules.data.dashboard.service.ReportDashboardService; +import io.swagger.annotations.Api; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.*; + +/** +* @desc 大屏设计 controller +* @website https://gitee.com/anji-plus/gaea +* @author Raod +* @date 2021-04-12 14:52:21.761 +**/ +@RestController +@Api(tags = "大屏设计管理") +@RequestMapping("/reportDashboard") +public class ReportDashboardController { + + @Autowired + private ReportDashboardService reportDashboardService; + + /** + * 预览、查询大屏详情 + * @param reportCode + * @return + */ + @GetMapping({"/{reportCode}"}) + @Permission(code = "DETAIL", name = "明细") + public ResponseBean detail(@PathVariable("reportCode") String reportCode) { + return ResponseBean.builder().data(reportDashboardService.getDetail(reportCode)).build(); + } + + /** + * 保存大屏设计 + * @param dto + * @return + */ + @PostMapping + @Permission(code = "INSERT", name = "新增") + @GaeaAuditLog(pageTitle = "新增") + public ResponseBean insert(@RequestBody ReportDashboardObjectDto dto) { + reportDashboardService.insertDashboard(dto); + return ResponseBean.builder().build(); + } + + + /** + * 获取去单个图层数据 + * @param dto + * @return + */ + @PostMapping("/getData") + @Permission(code = "DETAIL", name = "明细图表数据") + public ResponseBean getData(@RequestBody ChartDto dto) { + return ResponseBean.builder().data(reportDashboardService.getChartData(dto)).build(); + } + +} diff --git a/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dashboard/controller/dto/ChartDto.java b/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dashboard/controller/dto/ChartDto.java new file mode 100644 index 00000000..b821eff3 --- /dev/null +++ b/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dashboard/controller/dto/ChartDto.java @@ -0,0 +1,51 @@ + +package com.anjiplus.template.gaea.business.modules.data.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/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dashboard/controller/dto/ReportDashboardDto.java b/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dashboard/controller/dto/ReportDashboardDto.java new file mode 100644 index 00000000..b4ba347a --- /dev/null +++ b/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dashboard/controller/dto/ReportDashboardDto.java @@ -0,0 +1,55 @@ + +package com.anjiplus.template.gaea.business.modules.data.dashboard.controller.dto; + +import com.anji.plus.gaea.curd.dto.GaeaBaseDTO; +import com.anjiplus.template.gaea.business.modules.data.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; + +} \ No newline at end of file diff --git a/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dashboard/controller/dto/ReportDashboardObjectDto.java b/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dashboard/controller/dto/ReportDashboardObjectDto.java new file mode 100644 index 00000000..a74d3fa9 --- /dev/null +++ b/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dashboard/controller/dto/ReportDashboardObjectDto.java @@ -0,0 +1,32 @@ + +package com.anjiplus.template.gaea.business.modules.data.dashboard.controller.dto; + +import com.anjiplus.template.gaea.business.modules.data.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/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dashboard/controller/param/ReportDashboardParam.java b/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dashboard/controller/param/ReportDashboardParam.java new file mode 100644 index 00000000..f2045fcd --- /dev/null +++ b/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dashboard/controller/param/ReportDashboardParam.java @@ -0,0 +1,20 @@ +/**/ +package com.anjiplus.template.gaea.business.modules.data.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{ +} \ No newline at end of file diff --git a/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dashboard/dao/ReportDashboardMapper.java b/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dashboard/dao/ReportDashboardMapper.java new file mode 100644 index 00000000..9c339a02 --- /dev/null +++ b/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dashboard/dao/ReportDashboardMapper.java @@ -0,0 +1,16 @@ +package com.anjiplus.template.gaea.business.modules.data.dashboard.dao; + +import org.apache.ibatis.annotations.Mapper; + +import com.anji.plus.gaea.curd.mapper.GaeaBaseMapper; +import com.anjiplus.template.gaea.business.modules.data.dashboard.dao.entity.ReportDashboard; + +/** +* ReportDashboard Mapper +* @author Raod +* @date 2021-04-12 14:52:21.761 +**/ +@Mapper +public interface ReportDashboardMapper extends GaeaBaseMapper { + +} \ No newline at end of file diff --git a/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dashboard/dao/entity/ReportDashboard.java b/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dashboard/dao/entity/ReportDashboard.java new file mode 100644 index 00000000..24623063 --- /dev/null +++ b/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dashboard/dao/entity/ReportDashboard.java @@ -0,0 +1,58 @@ + +package com.anjiplus.template.gaea.business.modules.data.dashboard.dao.entity; + +import com.anji.plus.gaea.annotation.Unique; +import com.anjiplus.template.gaea.common.RespCommonCode; +import lombok.Data; +import io.swagger.annotations.ApiModelProperty; + +import com.anji.plus.gaea.curd.entity.GaeaBaseEntity; +import com.baomidou.mybatisplus.annotation.TableName; + +import javax.validation.constraints.*; +import java.sql.Timestamp; + +/** +* @description 大屏设计 entity +* @author Raod +* @date 2021-04-12 14:52:21.761 +**/ +@TableName(value="gaea_report_dashboard") +@Data +public class ReportDashboard extends GaeaBaseEntity { + @ApiModelProperty(value = "报表编码") + @Unique(code = RespCommonCode.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; + + +} \ No newline at end of file diff --git a/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dashboard/service/ChartStrategy.java b/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dashboard/service/ChartStrategy.java new file mode 100644 index 00000000..aaa79d0c --- /dev/null +++ b/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dashboard/service/ChartStrategy.java @@ -0,0 +1,26 @@ +package com.anjiplus.template.gaea.business.modules.data.dashboard.service; + +import com.alibaba.fastjson.JSONObject; +import com.anjiplus.template.gaea.business.modules.data.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/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dashboard/service/ReportDashboardService.java b/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dashboard/service/ReportDashboardService.java new file mode 100644 index 00000000..2a5d62c6 --- /dev/null +++ b/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dashboard/service/ReportDashboardService.java @@ -0,0 +1,38 @@ + +package com.anjiplus.template.gaea.business.modules.data.dashboard.service; + +import com.anji.plus.gaea.curd.service.GaeaBaseService; +import com.anjiplus.template.gaea.business.modules.data.dashboard.controller.dto.ChartDto; +import com.anjiplus.template.gaea.business.modules.data.dashboard.controller.dto.ReportDashboardObjectDto; +import com.anjiplus.template.gaea.business.modules.data.dashboard.controller.param.ReportDashboardParam; +import com.anjiplus.template.gaea.business.modules.data.dashboard.dao.entity.ReportDashboard; + +/** +* @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); +} diff --git a/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dashboard/service/impl/BarChartServiceImpl.java b/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dashboard/service/impl/BarChartServiceImpl.java new file mode 100644 index 00000000..780d17d3 --- /dev/null +++ b/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dashboard/service/impl/BarChartServiceImpl.java @@ -0,0 +1,81 @@ +package com.anjiplus.template.gaea.business.modules.data.dashboard.service.impl; + +import com.alibaba.fastjson.JSONArray; +import com.alibaba.fastjson.JSONObject; +import com.anjiplus.template.gaea.business.modules.data.dashboard.controller.dto.ChartDto; +import com.anjiplus.template.gaea.business.modules.data.dashboard.service.ChartStrategy; +import org.springframework.stereotype.Component; + +import java.util.ArrayList; +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/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dashboard/service/impl/BarLineChartServiceImpl.java b/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dashboard/service/impl/BarLineChartServiceImpl.java new file mode 100644 index 00000000..362abb0e --- /dev/null +++ b/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dashboard/service/impl/BarLineChartServiceImpl.java @@ -0,0 +1,108 @@ +package com.anjiplus.template.gaea.business.modules.data.dashboard.service.impl; + +import com.alibaba.fastjson.JSONObject; +import com.anjiplus.template.gaea.business.modules.data.dashboard.controller.dto.ChartDto; +import com.anjiplus.template.gaea.business.modules.data.dashboard.service.ChartStrategy; +import org.springframework.stereotype.Component; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * 折柱图 + * 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/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dashboard/service/impl/GaugeChartServiceImpl.java b/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dashboard/service/impl/GaugeChartServiceImpl.java new file mode 100644 index 00000000..c9d75a05 --- /dev/null +++ b/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dashboard/service/impl/GaugeChartServiceImpl.java @@ -0,0 +1,43 @@ +package com.anjiplus.template.gaea.business.modules.data.dashboard.service.impl; + +import com.alibaba.fastjson.JSONObject; +import com.anjiplus.template.gaea.business.modules.data.dashboard.controller.dto.ChartDto; +import com.anjiplus.template.gaea.business.modules.data.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/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dashboard/service/impl/PieChartServiceImpl.java b/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dashboard/service/impl/PieChartServiceImpl.java new file mode 100644 index 00000000..e19e0055 --- /dev/null +++ b/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dashboard/service/impl/PieChartServiceImpl.java @@ -0,0 +1,52 @@ +package com.anjiplus.template.gaea.business.modules.data.dashboard.service.impl; + +import com.alibaba.fastjson.JSONObject; +import com.anjiplus.template.gaea.business.modules.data.dashboard.controller.dto.ChartDto; +import com.anjiplus.template.gaea.business.modules.data.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/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dashboard/service/impl/ReportDashboardServiceImpl.java b/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dashboard/service/impl/ReportDashboardServiceImpl.java new file mode 100644 index 00000000..cfc1bd56 --- /dev/null +++ b/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dashboard/service/impl/ReportDashboardServiceImpl.java @@ -0,0 +1,314 @@ + +package com.anjiplus.template.gaea.business.modules.data.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.data.dashboard.controller.dto.ChartDto; +import com.anjiplus.template.gaea.business.modules.data.dashboard.controller.dto.ReportDashboardDto; +import com.anjiplus.template.gaea.business.modules.data.dashboard.controller.dto.ReportDashboardObjectDto; +import com.anjiplus.template.gaea.business.modules.data.dashboard.dao.ReportDashboardMapper; +import com.anjiplus.template.gaea.business.modules.data.dashboard.dao.entity.ReportDashboard; +import com.anjiplus.template.gaea.business.modules.data.dashboard.service.ChartStrategy; +import com.anjiplus.template.gaea.business.modules.data.dashboard.service.ReportDashboardService; +import com.anjiplus.template.gaea.business.modules.data.dashboard.util.DateUtil; +import com.anjiplus.template.gaea.business.modules.data.dashboardwidget.controller.dto.ReportDashboardWidgetDto; +import com.anjiplus.template.gaea.business.modules.data.dashboardwidget.controller.dto.ReportDashboardWidgetValueDto; +import com.anjiplus.template.gaea.business.modules.data.dashboardwidget.dao.entity.ReportDashboardWidget; +import com.anjiplus.template.gaea.business.modules.data.dashboardwidget.service.ReportDashboardWidgetService; +import com.anjiplus.template.gaea.business.modules.data.dataSet.controller.dto.DataSetDto; +import com.anjiplus.template.gaea.business.modules.data.dataSet.controller.dto.OriginalDataDto; +import com.anjiplus.template.gaea.business.modules.data.dataSet.service.DataSetService; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +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.context.ApplicationContext; +import org.springframework.context.ApplicationContextAware; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.text.SimpleDateFormat; +import java.util.*; + +/** + * @author Raod + * @desc ReportDashboard 大屏设计服务实现 + * @date 2021-04-12 14:52:21.761 + **/ +@Service +//@RequiredArgsConstructor +public class ReportDashboardServiceImpl implements ReportDashboardService, InitializingBean, ApplicationContextAware { + + @Autowired + private ReportDashboardMapper reportDashboardMapper; + + @Autowired + private ReportDashboardWidgetService reportDashboardWidgetService; + + @Autowired + private DataSetService dataSetService; + + 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); + GaeaAssert.notNull(reportDashboard, ResponseCode.RULE_CONTENT_NOT_EXIST, "reportDashboard"); + 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); + reportDashboardWidgetDtoList.add(reportDashboardWidgetDto); + }); + reportDashboardDto.setWidgets(reportDashboardWidgetDtoList); + result.setDashboard(reportDashboardDto); + result.setReportCode(reportCode); + return result; + } + + /*** + * 保存大屏设计 + * + * @param dto + */ + @Override + @Transactional + 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()); + 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.setEnableFlag(1); + reportDashboardWidget.setDeleteFlag(0); + reportDashboardWidget.setSort((long) (i + 1)); + 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()); + } + + 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; + } + //获取时间轴字段和解析时间颗粒度 + chartProperties.forEach((key, value) -> { + dto.setParticles(value); + setTimeLineFormat(dto); + if (StringUtils.isNotBlank(dto.getDataTimeFormat())) { + dto.setTimeLineFiled(key); + return; + } + }); + + 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/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dashboard/util/DateUtil.java b/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dashboard/util/DateUtil.java new file mode 100644 index 00000000..da8e3f4b --- /dev/null +++ b/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dashboard/util/DateUtil.java @@ -0,0 +1,47 @@ +package com.anjiplus.template.gaea.business.modules.data.dashboard.util; + +import java.text.ParseException; +import java.text.SimpleDateFormat; +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; + } + } +} diff --git a/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dashboardwidget/controller/dto/ReportDashboardWidgetDto.java b/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dashboardwidget/controller/dto/ReportDashboardWidgetDto.java new file mode 100644 index 00000000..43965a43 --- /dev/null +++ b/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dashboardwidget/controller/dto/ReportDashboardWidgetDto.java @@ -0,0 +1,28 @@ + +package com.anjiplus.template.gaea.business.modules.data.dashboardwidget.controller.dto; + +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; + +} diff --git a/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dashboardwidget/controller/dto/ReportDashboardWidgetValueDto.java b/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dashboardwidget/controller/dto/ReportDashboardWidgetValueDto.java new file mode 100644 index 00000000..c7a5ded1 --- /dev/null +++ b/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dashboardwidget/controller/dto/ReportDashboardWidgetValueDto.java @@ -0,0 +1,42 @@ + +package com.anjiplus.template.gaea.business.modules.data.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; + + /** 0--已禁用 1--已启用 DIC_NAME=ENABLE_FLAG */ + private Integer enableFlag; + + /** 0--未删除 1--已删除 DIC_NAME=DEL_FLAG */ + private Integer deleteFlag; + + /** 排序,图层的概念 */ + private Long sort; + +} diff --git a/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dashboardwidget/controller/param/ReportDashboardWidgetParam.java b/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dashboardwidget/controller/param/ReportDashboardWidgetParam.java new file mode 100644 index 00000000..8e6073c5 --- /dev/null +++ b/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dashboardwidget/controller/param/ReportDashboardWidgetParam.java @@ -0,0 +1,20 @@ +/**/ +package com.anjiplus.template.gaea.business.modules.data.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{ +} \ No newline at end of file diff --git a/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dashboardwidget/dao/ReportDashboardWidgetMapper.java b/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dashboardwidget/dao/ReportDashboardWidgetMapper.java new file mode 100644 index 00000000..cfa0d532 --- /dev/null +++ b/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dashboardwidget/dao/ReportDashboardWidgetMapper.java @@ -0,0 +1,16 @@ +package com.anjiplus.template.gaea.business.modules.data.dashboardwidget.dao; + +import org.apache.ibatis.annotations.Mapper; + +import com.anji.plus.gaea.curd.mapper.GaeaBaseMapper; +import com.anjiplus.template.gaea.business.modules.data.dashboardwidget.dao.entity.ReportDashboardWidget; + +/** +* ReportDashboardWidget Mapper +* @author Raod +* @date 2021-04-12 15:12:43.724 +**/ +@Mapper +public interface ReportDashboardWidgetMapper extends GaeaBaseMapper { + +} \ No newline at end of file diff --git a/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dashboardwidget/dao/entity/ReportDashboardWidget.java b/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dashboardwidget/dao/entity/ReportDashboardWidget.java new file mode 100644 index 00000000..2214cb40 --- /dev/null +++ b/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dashboardwidget/dao/entity/ReportDashboardWidget.java @@ -0,0 +1,45 @@ + +package com.anjiplus.template.gaea.business.modules.data.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(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; + + @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/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dashboardwidget/service/ReportDashboardWidgetService.java b/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dashboardwidget/service/ReportDashboardWidgetService.java new file mode 100644 index 00000000..690d5830 --- /dev/null +++ b/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dashboardwidget/service/ReportDashboardWidgetService.java @@ -0,0 +1,21 @@ + +package com.anjiplus.template.gaea.business.modules.data.dashboardwidget.service; + +import com.anjiplus.template.gaea.business.modules.data.dashboardwidget.dao.entity.ReportDashboardWidget; +import com.anjiplus.template.gaea.business.modules.data.dashboardwidget.controller.param.ReportDashboardWidgetParam; +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); +} \ No newline at end of file diff --git a/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dashboardwidget/service/impl/ReportDashboardWidgetServiceImpl.java b/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dashboardwidget/service/impl/ReportDashboardWidgetServiceImpl.java new file mode 100644 index 00000000..f6dff004 --- /dev/null +++ b/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dashboardwidget/service/impl/ReportDashboardWidgetServiceImpl.java @@ -0,0 +1,34 @@ + +package com.anjiplus.template.gaea.business.modules.data.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.data.dashboardwidget.dao.entity.ReportDashboardWidget; +import com.anjiplus.template.gaea.business.modules.data.dashboardwidget.service.ReportDashboardWidgetService; +import com.anjiplus.template.gaea.business.modules.data.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; + } +} \ No newline at end of file diff --git a/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dataSet/controller/DataSetController.java b/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dataSet/controller/DataSetController.java new file mode 100644 index 00000000..e5a0e58a --- /dev/null +++ b/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dataSet/controller/DataSetController.java @@ -0,0 +1,149 @@ + +package com.anjiplus.template.gaea.business.modules.data.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.data.dataSet.controller.dto.DataSetDto; +import com.anjiplus.template.gaea.business.modules.data.dataSet.controller.param.DataSetParam; +import com.anjiplus.template.gaea.business.modules.data.dataSet.controller.param.DataSetTestTransformParam; +import com.anjiplus.template.gaea.business.modules.data.dataSet.dao.entity.DataSet; +import com.anjiplus.template.gaea.business.modules.data.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 = "数据集管理") +@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 = "DETAIL", + 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 = "DETAIL", + 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") + 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/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dataSet/controller/dto/DataSetDto.java b/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dataSet/controller/dto/DataSetDto.java new file mode 100644 index 00000000..acef9c28 --- /dev/null +++ b/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dataSet/controller/dto/DataSetDto.java @@ -0,0 +1,58 @@ + +package com.anjiplus.template.gaea.business.modules.data.dataSet.controller.dto; + +import com.anji.plus.gaea.curd.dto.GaeaBaseDTO; +import com.anjiplus.template.gaea.business.modules.data.dataSetParam.controller.dto.DataSetParamDto; +import com.anjiplus.template.gaea.business.modules.data.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 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; + +} \ No newline at end of file diff --git a/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dataSet/controller/dto/OriginalDataDto.java b/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dataSet/controller/dto/OriginalDataDto.java new file mode 100644 index 00000000..12b4aad0 --- /dev/null +++ b/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dataSet/controller/dto/OriginalDataDto.java @@ -0,0 +1,32 @@ +package com.anjiplus.template.gaea.business.modules.data.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/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dataSet/controller/param/DataSetParam.java b/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dataSet/controller/param/DataSetParam.java new file mode 100644 index 00000000..f96ecf93 --- /dev/null +++ b/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dataSet/controller/param/DataSetParam.java @@ -0,0 +1,30 @@ +/**/ +package com.anjiplus.template.gaea.business.modules.data.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; +} \ No newline at end of file diff --git a/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dataSet/controller/param/DataSetTestTransformParam.java b/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dataSet/controller/param/DataSetTestTransformParam.java new file mode 100644 index 00000000..33739099 --- /dev/null +++ b/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dataSet/controller/param/DataSetTestTransformParam.java @@ -0,0 +1,34 @@ +/**/ +package com.anjiplus.template.gaea.business.modules.data.dataSet.controller.param; + +import com.anjiplus.template.gaea.business.modules.data.dataSetParam.controller.dto.DataSetParamDto; +import com.anjiplus.template.gaea.business.modules.data.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{ + + /** 数据源编码 */ + @NotBlank(message = "sourceCode not empty") + private String sourceCode; + + /** 动态查询sql或者接口中的请求体 */ + private String dynSentence; + + /** 请求参数集合 */ + private List dataSetParamDtoList; + + /** 数据转换集合 */ + private List dataSetTransformDtoList; + +} \ No newline at end of file diff --git a/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dataSet/dao/DataSetMapper.java b/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dataSet/dao/DataSetMapper.java new file mode 100644 index 00000000..fe6a9ab9 --- /dev/null +++ b/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dataSet/dao/DataSetMapper.java @@ -0,0 +1,16 @@ +package com.anjiplus.template.gaea.business.modules.data.dataSet.dao; + +import org.apache.ibatis.annotations.Mapper; + +import com.anji.plus.gaea.curd.mapper.GaeaBaseMapper; +import com.anjiplus.template.gaea.business.modules.data.dataSet.dao.entity.DataSet; + +/** +* DataSet Mapper +* @author Raod +* @date 2021-03-18 12:11:31.150755900 +**/ +@Mapper +public interface DataSetMapper extends GaeaBaseMapper { + +} \ No newline at end of file diff --git a/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dataSet/dao/entity/DataSet.java b/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dataSet/dao/entity/DataSet.java new file mode 100644 index 00000000..05da2eb0 --- /dev/null +++ b/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dataSet/dao/entity/DataSet.java @@ -0,0 +1,45 @@ + +package com.anjiplus.template.gaea.business.modules.data.dataSet.dao.entity; + +import com.anji.plus.gaea.annotation.Unique; +import com.anji.plus.gaea.curd.entity.GaeaBaseEntity; +import com.anjiplus.template.gaea.common.RespCommonCode; +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(value="gaea_report_data_set") +@Data +public class DataSet extends GaeaBaseEntity { + @ApiModelProperty(value = "数据集编码") + @Unique(code = RespCommonCode.SET_CODE_ISEXIST) + private String setCode; + + @ApiModelProperty(value = "数据集名称") + private String setName; + + @ApiModelProperty(value = "数据集描述") + private String setDesc; + + @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/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dataSet/service/DataSetService.java b/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dataSet/service/DataSetService.java new file mode 100644 index 00000000..b9dd4dd3 --- /dev/null +++ b/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dataSet/service/DataSetService.java @@ -0,0 +1,70 @@ + +package com.anjiplus.template.gaea.business.modules.data.dataSet.service; + +import com.anji.plus.gaea.curd.service.GaeaBaseService; +import com.anjiplus.template.gaea.business.modules.data.dataSet.controller.dto.DataSetDto; +import com.anjiplus.template.gaea.business.modules.data.dataSet.controller.dto.OriginalDataDto; +import com.anjiplus.template.gaea.business.modules.data.dataSet.controller.param.DataSetParam; +import com.anjiplus.template.gaea.business.modules.data.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/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dataSet/service/impl/DataSetServiceImpl.java b/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dataSet/service/impl/DataSetServiceImpl.java new file mode 100644 index 00000000..3b536c51 --- /dev/null +++ b/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dataSet/service/impl/DataSetServiceImpl.java @@ -0,0 +1,343 @@ + +package com.anjiplus.template.gaea.business.modules.data.dataSet.service.impl; + +import com.alibaba.fastjson.JSONArray; +import com.alibaba.fastjson.JSONObject; +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.modules.data.dataSet.controller.dto.OriginalDataDto; +import com.anjiplus.template.gaea.business.modules.data.dataSet.controller.dto.DataSetDto; +import com.anjiplus.template.gaea.business.modules.data.dataSet.dao.DataSetMapper; +import com.anjiplus.template.gaea.business.modules.data.dataSet.dao.entity.DataSet; +import com.anjiplus.template.gaea.business.modules.data.dataSet.service.DataSetService; +import com.anjiplus.template.gaea.business.modules.data.dataSetParam.controller.dto.DataSetParamDto; +import com.anjiplus.template.gaea.business.modules.data.dataSetParam.dao.entity.DataSetParam; +import com.anjiplus.template.gaea.business.modules.data.dataSetParam.service.DataSetParamService; +import com.anjiplus.template.gaea.business.modules.data.dataSetTransform.controller.dto.DataSetTransformDto; +import com.anjiplus.template.gaea.business.modules.data.dataSetTransform.dao.entity.DataSetTransform; +import com.anjiplus.template.gaea.business.modules.data.dataSetTransform.service.DataSetTransformService; +import com.anjiplus.template.gaea.business.modules.data.dataSource.controller.dto.DataSourceDto; +import com.anjiplus.template.gaea.business.modules.data.dataSource.dao.entity.DataSource; +import com.anjiplus.template.gaea.business.modules.data.dataSource.service.DataSourceService; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +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; +import org.springframework.transaction.annotation.Transactional; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +/** +* @desc DataSet 数据集服务实现 +* @author Raod +* @date 2021-03-18 12:11:31.150755900 +**/ +@Service +//@RequiredArgsConstructor +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) { + } + } + 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); + insert(dataSet); + //2.更新查询参数 + dataSetParamBatch(dataSetParamDtoList, dto.getSetCode()); + + //3.更新数据转换 + dataSetTransformBatch(dataSetTransformDtoList, dto.getSetCode()); + return dto; + } + + /** + * 更新数据集、添加查询参数、数据转换 + * + * @param dto + */ + @Override + @Transactional + public void updateSet(DataSetDto dto) { + List dataSetParamDtoList = dto.getDataSetParamDtoList(); + List dataSetTransformDtoList = dto.getDataSetTransformDtoList(); + //1.更新数据集 + DataSet dataSet = new DataSet(); + BeanUtils.copyProperties(dto, dataSet); + update(dataSet); + + //2.更新查询参数 + dataSetParamBatch(dataSetParamDtoList, dto.getSetCode()); + + //3.更新数据转换 + dataSetTransformBatch(dataSetTransformDtoList, dto.getSetCode()); + } + + + /** + * 删除数据集、添加查询参数、数据转换 + * + * @param id + */ + @Override + 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(); + //1.获取数据集、参数替换、数据转换 + DataSetDto dataSetDto = detailSet(setCode); + //2.获取数据源 + DataSource dataSource = dataSourceService.selectOne("source_code", dataSetDto.getSourceCode()); + //3.参数替换 + //3.1参数校验 + boolean verification = dataSetParamService.verification(dataSetDto.getDataSetParamDtoList(), dto.getContextData()); + if (!verification) { + throw BusinessExceptionBuilder.build(ResponseCode.RULE_FIELDS_CHECK_ERROR); + } + String dynSentence = dataSetParamService.transform(dto.getContextData(), dataSetDto.getDynSentence()); + //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) { + OriginalDataDto originalDataDto = new OriginalDataDto(); + String sourceCode = dto.getSourceCode(); + //1.获取数据源 + DataSource 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); + } + + String dynSentence = dataSetParamService.transform(dto.getDataSetParamDtoList(), dto.getDynSentence()); + //4.获取数据 + DataSourceDto dataSourceDto = new DataSourceDto(); + BeanUtils.copyProperties(dataSource, dataSourceDto); + dataSourceDto.setDynSentence(dynSentence); + dataSourceDto.setContextData(dto.getContextData()); + + //获取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()); + 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); + 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); + dataSetTransformList.add(dataSetTransform); + } + dataSetTransformService.insertBatch(dataSetTransformList); + } + +} diff --git a/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dataSetParam/controller/DataSetParamController.java b/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dataSetParam/controller/DataSetParamController.java new file mode 100644 index 00000000..dbefff3b --- /dev/null +++ b/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dataSetParam/controller/DataSetParamController.java @@ -0,0 +1,62 @@ + +package com.anjiplus.template.gaea.business.modules.data.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.data.dataSetParam.controller.dto.DataSetParamDto; +import com.anjiplus.template.gaea.business.modules.data.dataSetParam.controller.param.DataSetParamParam; +import com.anjiplus.template.gaea.business.modules.data.dataSetParam.controller.param.DataSetParamValidationParam; +import com.anjiplus.template.gaea.business.modules.data.dataSetParam.dao.entity.DataSetParam; +import com.anjiplus.template.gaea.business.modules.data.dataSetParam.service.DataSetParamService; +import com.anjiplus.template.gaea.business.modules.data.dataSource.controller.param.ConnectionParam; +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)); + } +} \ No newline at end of file diff --git a/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dataSetParam/controller/dto/DataSetParamDto.java b/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dataSetParam/controller/dto/DataSetParamDto.java new file mode 100644 index 00000000..546eba3a --- /dev/null +++ b/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dataSetParam/controller/dto/DataSetParamDto.java @@ -0,0 +1,48 @@ + +package com.anjiplus.template.gaea.business.modules.data.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; + +} \ No newline at end of file diff --git a/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dataSetParam/controller/param/DataSetParamParam.java b/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dataSetParam/controller/param/DataSetParamParam.java new file mode 100644 index 00000000..7c1513bf --- /dev/null +++ b/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dataSetParam/controller/param/DataSetParamParam.java @@ -0,0 +1,17 @@ +/**/ +package com.anjiplus.template.gaea.business.modules.data.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{ +} \ No newline at end of file diff --git a/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dataSetParam/controller/param/DataSetParamValidationParam.java b/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dataSetParam/controller/param/DataSetParamValidationParam.java new file mode 100644 index 00000000..530e210f --- /dev/null +++ b/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dataSetParam/controller/param/DataSetParamValidationParam.java @@ -0,0 +1,22 @@ +package com.anjiplus.template.gaea.business.modules.data.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/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dataSetParam/dao/DataSetParamMapper.java b/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dataSetParam/dao/DataSetParamMapper.java new file mode 100644 index 00000000..fae58736 --- /dev/null +++ b/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dataSetParam/dao/DataSetParamMapper.java @@ -0,0 +1,15 @@ +package com.anjiplus.template.gaea.business.modules.data.dataSetParam.dao; + +import com.anji.plus.gaea.curd.mapper.GaeaBaseMapper; +import com.anjiplus.template.gaea.business.modules.data.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 { + +} \ No newline at end of file diff --git a/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dataSetParam/dao/entity/DataSetParam.java b/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dataSetParam/dao/entity/DataSetParam.java new file mode 100644 index 00000000..758a01ea --- /dev/null +++ b/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dataSetParam/dao/entity/DataSetParam.java @@ -0,0 +1,48 @@ + +package com.anjiplus.template.gaea.business.modules.data.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(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/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dataSetParam/service/DataSetParamService.java b/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dataSetParam/service/DataSetParamService.java new file mode 100644 index 00000000..6ae3a2fb --- /dev/null +++ b/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dataSetParam/service/DataSetParamService.java @@ -0,0 +1,52 @@ + +package com.anjiplus.template.gaea.business.modules.data.dataSetParam.service; + +import com.anji.plus.gaea.curd.service.GaeaBaseService; +import com.anjiplus.template.gaea.business.modules.data.dataSet.controller.dto.DataSetDto; +import com.anjiplus.template.gaea.business.modules.data.dataSetParam.controller.dto.DataSetParamDto; +import com.anjiplus.template.gaea.business.modules.data.dataSetParam.controller.param.DataSetParamParam; +import com.anjiplus.template.gaea.business.modules.data.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 + */ + boolean verification(DataSetParamDto dataSetParamDto); + + /** + * 参数校验 js脚本 + * + * @param dataSetParamDtoList + * @return + */ + boolean verification(List dataSetParamDtoList, Map contextData); +} \ No newline at end of file diff --git a/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dataSetParam/service/impl/DataSetParamServiceImpl.java b/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dataSetParam/service/impl/DataSetParamServiceImpl.java new file mode 100644 index 00000000..554caf60 --- /dev/null +++ b/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dataSetParam/service/impl/DataSetParamServiceImpl.java @@ -0,0 +1,136 @@ + +package com.anjiplus.template.gaea.business.modules.data.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.data.dataSetParam.controller.dto.DataSetParamDto; +import com.anjiplus.template.gaea.business.modules.data.dataSetParam.dao.DataSetParamMapper; +import com.anjiplus.template.gaea.business.modules.data.dataSetParam.dao.entity.DataSetParam; +import com.anjiplus.template.gaea.business.modules.data.dataSetParam.service.DataSetParamService; +import com.anjiplus.template.gaea.business.modules.data.dataSetParam.util.ParamsResolverHelper; +import com.anjiplus.template.gaea.common.RespCommonCode; +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.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(RespCommonCode.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 boolean verification(DataSetParamDto dataSetParamDto) { + + String sampleItem = dataSetParamDto.getSampleItem(); + String validationRules = dataSetParamDto.getValidationRules(); + if (StringUtils.isNotBlank(validationRules)) { + validationRules = validationRules + "\nvar result = verification('" + sampleItem + "');"; + try { + engine.eval(validationRules); + return Boolean.parseBoolean(engine.get("result").toString()); + + } catch (Exception ex) { + throw BusinessExceptionBuilder.build(RespCommonCode.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); + } + if (!verification(dataSetParamDto)) { + return false; + } + } + return true; + } + +} \ No newline at end of file diff --git a/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dataSetParam/util/ParamsResolverHelper.java b/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dataSetParam/util/ParamsResolverHelper.java new file mode 100644 index 00000000..e0d79bff --- /dev/null +++ b/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dataSetParam/util/ParamsResolverHelper.java @@ -0,0 +1,36 @@ +package com.anjiplus.template.gaea.business.modules.data.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/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dataSetTransform/controller/DataSetTransformController.java b/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dataSetTransform/controller/DataSetTransformController.java new file mode 100644 index 00000000..4c5ff8b0 --- /dev/null +++ b/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dataSetTransform/controller/DataSetTransformController.java @@ -0,0 +1,44 @@ + +package com.anjiplus.template.gaea.business.modules.data.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.data.dataSetTransform.controller.dto.DataSetTransformDto; +import com.anjiplus.template.gaea.business.modules.data.dataSetTransform.controller.param.DataSetTransformParam; +import com.anjiplus.template.gaea.business.modules.data.dataSetTransform.dao.entity.DataSetTransform; +import com.anjiplus.template.gaea.business.modules.data.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(); + } + +} \ No newline at end of file diff --git a/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dataSetTransform/controller/dto/DataSetTransformDto.java b/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dataSetTransform/controller/dto/DataSetTransformDto.java new file mode 100644 index 00000000..53001d45 --- /dev/null +++ b/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dataSetTransform/controller/dto/DataSetTransformDto.java @@ -0,0 +1,36 @@ + +package com.anjiplus.template.gaea.business.modules.data.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; + +} \ No newline at end of file diff --git a/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dataSetTransform/controller/param/DataSetTransformParam.java b/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dataSetTransform/controller/param/DataSetTransformParam.java new file mode 100644 index 00000000..13752b5f --- /dev/null +++ b/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dataSetTransform/controller/param/DataSetTransformParam.java @@ -0,0 +1,17 @@ +/**/ +package com.anjiplus.template.gaea.business.modules.data.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{ +} \ No newline at end of file diff --git a/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dataSetTransform/dao/DataSetTransformMapper.java b/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dataSetTransform/dao/DataSetTransformMapper.java new file mode 100644 index 00000000..6c04dba9 --- /dev/null +++ b/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dataSetTransform/dao/DataSetTransformMapper.java @@ -0,0 +1,15 @@ +package com.anjiplus.template.gaea.business.modules.data.dataSetTransform.dao; + +import com.anji.plus.gaea.curd.mapper.GaeaBaseMapper; +import com.anjiplus.template.gaea.business.modules.data.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 { + +} \ No newline at end of file diff --git a/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dataSetTransform/dao/entity/DataSetTransform.java b/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dataSetTransform/dao/entity/DataSetTransform.java new file mode 100644 index 00000000..4ad053ed --- /dev/null +++ b/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dataSetTransform/dao/entity/DataSetTransform.java @@ -0,0 +1,36 @@ + +package com.anjiplus.template.gaea.business.modules.data.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(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/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dataSetTransform/service/DataSetTransformService.java b/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dataSetTransform/service/DataSetTransformService.java new file mode 100644 index 00000000..41997d30 --- /dev/null +++ b/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dataSetTransform/service/DataSetTransformService.java @@ -0,0 +1,21 @@ + +package com.anjiplus.template.gaea.business.modules.data.dataSetTransform.service; + +import com.alibaba.fastjson.JSONObject; +import com.anji.plus.gaea.curd.service.GaeaBaseService; +import com.anjiplus.template.gaea.business.modules.data.dataSetTransform.controller.dto.DataSetTransformDto; +import com.anjiplus.template.gaea.business.modules.data.dataSetTransform.controller.param.DataSetTransformParam; +import com.anjiplus.template.gaea.business.modules.data.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); + +} \ No newline at end of file diff --git a/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dataSetTransform/service/TransformStrategy.java b/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dataSetTransform/service/TransformStrategy.java new file mode 100644 index 00000000..b8935771 --- /dev/null +++ b/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dataSetTransform/service/TransformStrategy.java @@ -0,0 +1,25 @@ +package com.anjiplus.template.gaea.business.modules.data.dataSetTransform.service; + +import com.alibaba.fastjson.JSONObject; +import com.anjiplus.template.gaea.business.modules.data.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/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dataSetTransform/service/impl/DataSetTransformServiceImpl.java b/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dataSetTransform/service/impl/DataSetTransformServiceImpl.java new file mode 100644 index 00000000..f61d1167 --- /dev/null +++ b/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dataSetTransform/service/impl/DataSetTransformServiceImpl.java @@ -0,0 +1,71 @@ + +package com.anjiplus.template.gaea.business.modules.data.dataSetTransform.service.impl; + +import com.alibaba.fastjson.JSONObject; +import com.anji.plus.gaea.curd.mapper.GaeaBaseMapper; +import com.anjiplus.template.gaea.business.modules.data.dataSetTransform.controller.dto.DataSetTransformDto; +import com.anjiplus.template.gaea.business.modules.data.dataSetTransform.dao.DataSetTransformMapper; +import com.anjiplus.template.gaea.business.modules.data.dataSetTransform.dao.entity.DataSetTransform; +import com.anjiplus.template.gaea.business.modules.data.dataSetTransform.service.DataSetTransformService; +import com.anjiplus.template.gaea.business.modules.data.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; + } +} \ No newline at end of file diff --git a/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dataSetTransform/service/impl/DictTransformServiceImpl.java b/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dataSetTransform/service/impl/DictTransformServiceImpl.java new file mode 100644 index 00000000..ff4de0ed --- /dev/null +++ b/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dataSetTransform/service/impl/DictTransformServiceImpl.java @@ -0,0 +1,56 @@ +package com.anjiplus.template.gaea.business.modules.data.dataSetTransform.service.impl; + +import com.alibaba.fastjson.JSONObject; +import com.anjiplus.template.gaea.business.modules.data.dataSetTransform.controller.dto.DataSetTransformDto; +import com.anjiplus.template.gaea.business.modules.data.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/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dataSetTransform/service/impl/JsTransformServiceImpl.java b/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dataSetTransform/service/impl/JsTransformServiceImpl.java new file mode 100644 index 00000000..1c41d583 --- /dev/null +++ b/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dataSetTransform/service/impl/JsTransformServiceImpl.java @@ -0,0 +1,62 @@ +package com.anjiplus.template.gaea.business.modules.data.dataSetTransform.service.impl; + +import com.alibaba.fastjson.JSONObject; +import com.anji.plus.gaea.exception.BusinessExceptionBuilder; +import com.anjiplus.template.gaea.business.modules.data.dataSetTransform.controller.dto.DataSetTransformDto; +import com.anjiplus.template.gaea.business.modules.data.dataSetTransform.service.TransformStrategy; +import com.anjiplus.template.gaea.common.RespCommonCode; +import jdk.nashorn.api.scripting.ScriptObjectMirror; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Component; + +import javax.script.ScriptEngine; +import javax.script.ScriptEngineManager; +import java.util.List; +import java.util.stream.Collectors; + +/** + * 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(); + js = js + "\nvar result = dataTransform(eval(" + data.toString() + "));"; + try { + engine.eval(js); + ScriptObjectMirror result = (ScriptObjectMirror) engine.get("result"); + return result.values().stream().map(o -> JSONObject.parseObject(JSONObject.toJSONString(o))).collect(Collectors.toList()); + } catch (Exception ex) { + throw BusinessExceptionBuilder.build(RespCommonCode.EXECUTE_JS_ERROR, ex.getMessage()); + } + } +} diff --git a/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dataSource/config/HttpClientConfig.java b/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dataSource/config/HttpClientConfig.java new file mode 100644 index 00000000..01e1dcf3 --- /dev/null +++ b/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dataSource/config/HttpClientConfig.java @@ -0,0 +1,214 @@ +package com.anjiplus.template.gaea.business.modules.data.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/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dataSource/config/HttpClientPoolConfig.java b/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dataSource/config/HttpClientPoolConfig.java new file mode 100644 index 00000000..a8b91faa --- /dev/null +++ b/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dataSource/config/HttpClientPoolConfig.java @@ -0,0 +1,53 @@ +package com.anjiplus.template.gaea.business.modules.data.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/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dataSource/controller/DataSourceController.java b/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dataSource/controller/DataSourceController.java new file mode 100644 index 00000000..8e569e9e --- /dev/null +++ b/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dataSource/controller/DataSourceController.java @@ -0,0 +1,67 @@ + +package com.anjiplus.template.gaea.business.modules.data.dataSource.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.data.dataSource.controller.dto.DataSourceDto; +import com.anjiplus.template.gaea.business.modules.data.dataSource.controller.param.ConnectionParam; +import com.anjiplus.template.gaea.business.modules.data.dataSource.controller.param.DataSourceParam; +import com.anjiplus.template.gaea.business.modules.data.dataSource.dao.entity.DataSource; +import com.anjiplus.template.gaea.business.modules.data.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 = "数据源管理") +@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 + */ + @PostMapping("/testConnection") + public ResponseBean testConnection(@Validated @RequestBody ConnectionParam connectionParam) { + return responseSuccessWithData(dataSourceService.testConnection(connectionParam)); + } + + + +} \ No newline at end of file diff --git a/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dataSource/controller/dto/DataSourceDto.java b/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dataSource/controller/dto/DataSourceDto.java new file mode 100644 index 00000000..0ed5a42e --- /dev/null +++ b/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dataSource/controller/dto/DataSourceDto.java @@ -0,0 +1,74 @@ + +package com.anjiplus.template.gaea.business.modules.data.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; + +} \ No newline at end of file diff --git a/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dataSource/controller/param/ConnectionParam.java b/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dataSource/controller/param/ConnectionParam.java new file mode 100644 index 00000000..0ccb40cf --- /dev/null +++ b/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dataSource/controller/param/ConnectionParam.java @@ -0,0 +1,21 @@ +package com.anjiplus.template.gaea.business.modules.data.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/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dataSource/controller/param/DataSourceParam.java b/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dataSource/controller/param/DataSourceParam.java new file mode 100644 index 00000000..1804b03d --- /dev/null +++ b/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dataSource/controller/param/DataSourceParam.java @@ -0,0 +1,31 @@ +/**/ +package com.anjiplus.template.gaea.business.modules.data.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; +} \ No newline at end of file diff --git a/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dataSource/dao/DataSourceMapper.java b/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dataSource/dao/DataSourceMapper.java new file mode 100644 index 00000000..dcf1e224 --- /dev/null +++ b/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dataSource/dao/DataSourceMapper.java @@ -0,0 +1,16 @@ +package com.anjiplus.template.gaea.business.modules.data.dataSource.dao; + +import org.apache.ibatis.annotations.Mapper; + +import com.anji.plus.gaea.curd.mapper.GaeaBaseMapper; +import com.anjiplus.template.gaea.business.modules.data.dataSource.dao.entity.DataSource; + +/** +* DataSource Mapper +* @author Raod +* @date 2021-03-18 12:09:57.728203200 +**/ +@Mapper +public interface DataSourceMapper extends GaeaBaseMapper { + +} \ No newline at end of file diff --git a/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dataSource/dao/entity/DataSource.java b/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dataSource/dao/entity/DataSource.java new file mode 100644 index 00000000..4999ab5a --- /dev/null +++ b/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dataSource/dao/entity/DataSource.java @@ -0,0 +1,42 @@ + +package com.anjiplus.template.gaea.business.modules.data.dataSource.dao.entity; + +import com.anji.plus.gaea.annotation.Unique; +import com.anji.plus.gaea.curd.entity.GaeaBaseEntity; +import com.anjiplus.template.gaea.common.RespCommonCode; +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(value="gaea_report_data_source") +@Data +public class DataSource extends GaeaBaseEntity { + @ApiModelProperty(value = "数据源编码") + @Unique(code = RespCommonCode.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/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dataSource/pool/api/IConfig.java b/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dataSource/pool/api/IConfig.java new file mode 100644 index 00000000..f7354808 --- /dev/null +++ b/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dataSource/pool/api/IConfig.java @@ -0,0 +1,39 @@ +package com.anjiplus.template.gaea.business.modules.data.dataSource.pool.api; + +/** + * 配置接口 + * @author binbin.hou + * @since 1.0.0 + */ +public interface IConfig { + + /** + * 设置驱动类 + * + * @param driverClass 驱动类 + * @since 1.0.0 + */ + void setDriverClass(final String driverClass); + + /** + * jdbc url + * @param jdbcUrl url + * @since 1.0.0 + */ + void setJdbcUrl(final String jdbcUrl); + + /** + * 设置用户信息 + * @param user 用户信息 + * @since 1.0.0 + */ + void setUser(final String user); + + /** + * 设置密码 + * @param password 密码 + * @since 1.0.0 + */ + void setPassword(final String password); + +} diff --git a/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dataSource/pool/api/IDataSourceConfig.java b/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dataSource/pool/api/IDataSourceConfig.java new file mode 100644 index 00000000..fb90392c --- /dev/null +++ b/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dataSource/pool/api/IDataSourceConfig.java @@ -0,0 +1,13 @@ +package com.anjiplus.template.gaea.business.modules.data.dataSource.pool.api; + +import javax.sql.DataSource; + +/** + * 配置接口 + * @author binbin.hou + * @since 1.0.0 + */ +public interface IDataSourceConfig extends IConfig, DataSource { + + +} diff --git a/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dataSource/pool/api/ILifeCycle.java b/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dataSource/pool/api/ILifeCycle.java new file mode 100644 index 00000000..5f0089df --- /dev/null +++ b/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dataSource/pool/api/ILifeCycle.java @@ -0,0 +1,21 @@ +package com.anjiplus.template.gaea.business.modules.data.dataSource.pool.api; + +/** + * 生命周期管理 + * @since 1.1.0 + */ +public interface ILifeCycle { + + /** + * 生命的初始化 + * @since 1.1.0 + */ + void init(); + + /** + * 生命的销毁 + * @since 1.1.0 + */ + void destroy(); + +} diff --git a/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dataSource/pool/api/IPooledDataSourceConfig.java b/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dataSource/pool/api/IPooledDataSourceConfig.java new file mode 100644 index 00000000..f542c7de --- /dev/null +++ b/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dataSource/pool/api/IPooledDataSourceConfig.java @@ -0,0 +1,93 @@ +package com.anjiplus.template.gaea.business.modules.data.dataSource.pool.api; + +import com.anjiplus.template.gaea.business.modules.data.dataSource.pool.connection.IPooledConnection; + +/** + * 池化的接口 + * @author binbin.hou + * @since 1.0.0 + */ +public interface IPooledDataSourceConfig extends IDataSourceConfig { + + /** + * 归还连接 + * @param pooledConnection 连接池信息 + * @since 1.5.0 + */ + void returnConnection(IPooledConnection pooledConnection); + + /** + * 设置最小尺寸 + * + * @param minSize 大小 + * @since 1.1.0 + */ + void setMinSize(final int minSize); + + /** + * 设置最大的大小 + * + * @param maxSize 最大的大小 + * @since 1.1.0 + */ + void setMaxSize(final int maxSize); + + /** + * 设置最大的等待时间 + * @param maxWaitMills 最大的等待时间 + * @since 1.1.0 + */ + void setMaxWaitMills(final long maxWaitMills); + + /** + * 设置验证查询的语句 + * + * 如果这个值为空,那么 {@link #setTestOnBorrow(boolean)} + * {@link #setTestOnIdle(boolean)}} + * {@link #setTestOnReturn(boolean)} + * 都将无效 + * @param validQuery 验证查询的语句 + * @since 1.5.0 + */ + void setValidQuery(final String validQuery); + + /** + * 验证的超时秒数 + * @param validTimeOutSeconds 验证的超时秒数 + * @since 1.5.0 + */ + void setValidTimeOutSeconds(final int validTimeOutSeconds); + + /** + * 获取连接时进行校验 + * + * 备注:影响性能 + * @param testOnBorrow 是否 + * @since 1.5.0 + */ + void setTestOnBorrow(final boolean testOnBorrow); + + /** + * 归还连接时进行校验 + * + * 备注:影响性能 + * @param testOnReturn 归还连接时进行校验 + * @since 1.5.0 + */ + void setTestOnReturn(final boolean testOnReturn); + + /** + * 闲暇的时候进行校验 + * @param testOnIdle 闲暇的时候进行校验 + * @since 1.5.0 + */ + void setTestOnIdle(final boolean testOnIdle); + + /** + * 闲暇时进行校验的时间间隔 + * @param testOnIdleIntervalSeconds 时间间隔 + * @since 1.5.0 + */ + void setTestOnIdleIntervalSeconds(final long testOnIdleIntervalSeconds); + +} diff --git a/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dataSource/pool/connection/IPooledConnection.java b/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dataSource/pool/connection/IPooledConnection.java new file mode 100644 index 00000000..f0365db0 --- /dev/null +++ b/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dataSource/pool/connection/IPooledConnection.java @@ -0,0 +1,56 @@ +package com.anjiplus.template.gaea.business.modules.data.dataSource.pool.connection; + +import com.anjiplus.template.gaea.business.modules.data.dataSource.pool.api.IPooledDataSourceConfig; + +import java.sql.Connection; + +/** + * 池化的连接池 + * @since 1.1.0 + */ +public interface IPooledConnection extends Connection { + + + /** + * 是否繁忙 + * @since 1.1.0 + * @return 状态 + */ + boolean isBusy(); + + /** + * 设置状态 + * @param busy 状态 + * @since 1.1.0 + */ + void setBusy(boolean busy); + + /** + * 获取真正的连接 + * @return 连接 + * @since 1.1.0 + */ + Connection getConnection(); + + /** + * 设置连接信息 + * @param connection 连接信息 + * @since 1.1.0 + */ + void setConnection(Connection connection); + + /** + * 设置对应的数据源 + * @param dataSource 数据源 + * @since 1.5.0 + */ + void setDataSource(final IPooledDataSourceConfig dataSource); + + /** + * 获取对应的数据源信息 + * @return 数据源 + * @since 1.5.0 + */ + IPooledDataSourceConfig getDataSource(); + +} diff --git a/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dataSource/pool/connection/PooledConnection.java b/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dataSource/pool/connection/PooledConnection.java new file mode 100644 index 00000000..8d5f03df --- /dev/null +++ b/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dataSource/pool/connection/PooledConnection.java @@ -0,0 +1,457 @@ +package com.anjiplus.template.gaea.business.modules.data.dataSource.pool.connection; + +import com.anjiplus.template.gaea.business.modules.data.dataSource.pool.api.IPooledDataSourceConfig; +import com.anjiplus.template.gaea.business.modules.data.dataSource.pool.exception.JdbcPoolException; +import lombok.extern.slf4j.Slf4j; + +import java.sql.*; +import java.util.Map; +import java.util.Properties; +import java.util.concurrent.Executor; + +/** + * 池化的连接 + * + * @since 1.1.0 + */ +@Slf4j +public class PooledConnection implements IPooledConnection { + + /** + * 是否繁忙 + * @since 1.1.0 + */ + private volatile boolean isBusy; + + /** + * 数据库链接信息 + * @since 1.1.0 + */ + private Connection connection; + + /** + * 对应的数据源信息 + * + * @since 1.1.0 + */ + private IPooledDataSourceConfig dataSource; + + @Override + public Statement createStatement() throws SQLException { + checkStatus(); + + return connection.createStatement(); + } + + @Override + public PreparedStatement prepareStatement(String sql) throws SQLException { + checkStatus(); + + return connection.prepareStatement(sql); + } + + @Override + public CallableStatement prepareCall(String sql) throws SQLException { + checkStatus(); + + return connection.prepareCall(sql); + } + + @Override + public String nativeSQL(String sql) throws SQLException { + checkStatus(); + + return connection.nativeSQL(sql); + } + + @Override + public void setAutoCommit(boolean autoCommit) throws SQLException { + checkStatus(); + + connection.setAutoCommit(autoCommit); + } + + @Override + public boolean getAutoCommit() throws SQLException { + checkStatus(); + + return connection.getAutoCommit(); + } + + @Override + public void commit() throws SQLException { + checkStatus(); + + connection.commit(); + } + + @Override + public void rollback() throws SQLException { + checkStatus(); + + connection.rollback(); + } + + @Override + public void close() throws SQLException { + checkStatus(); + + this.dataSource.returnConnection(this); + } + + @Override + public boolean isClosed() throws SQLException { + checkStatus(); + + return connection.isClosed(); + } + + @Override + public DatabaseMetaData getMetaData() throws SQLException { + checkStatus(); + + return connection.getMetaData(); + } + + @Override + public void setReadOnly(boolean readOnly) throws SQLException { + checkStatus(); + + connection.setReadOnly(readOnly); + } + + @Override + public boolean isReadOnly() throws SQLException { + checkStatus(); + + return connection.isReadOnly(); + } + + @Override + public void setCatalog(String catalog) throws SQLException { + checkStatus(); + + connection.setCatalog(catalog); + } + + @Override + public String getCatalog() throws SQLException { + checkStatus(); + + return connection.getCatalog(); + } + + @Override + public void setTransactionIsolation(int level) throws SQLException { + checkStatus(); + + connection.setTransactionIsolation(level); + } + + @Override + public int getTransactionIsolation() throws SQLException { + checkStatus(); + + return connection.getTransactionIsolation(); + } + + @Override + public SQLWarning getWarnings() throws SQLException { + checkStatus(); + + return connection.getWarnings(); + } + + @Override + public void clearWarnings() throws SQLException { + checkStatus(); + + connection.clearWarnings(); + } + + @Override + public Statement createStatement(int resultSetType, int resultSetConcurrency) throws SQLException { + checkStatus(); + + return connection.createStatement(resultSetType, resultSetConcurrency); + } + + @Override + public PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency) throws SQLException { + checkStatus(); + + return connection.prepareStatement(sql, resultSetType, resultSetConcurrency); + } + + @Override + public CallableStatement prepareCall(String sql, int resultSetType, int resultSetConcurrency) throws SQLException { + checkStatus(); + + return connection.prepareCall(sql, resultSetType, resultSetConcurrency); + } + + @Override + public Map> getTypeMap() throws SQLException { + checkStatus(); + + return connection.getTypeMap(); + } + + @Override + public void setTypeMap(Map> map) throws SQLException { + checkStatus(); + + connection.setTypeMap(map); + } + + @Override + public void setHoldability(int holdability) throws SQLException { + checkStatus(); + + connection.setHoldability(holdability); + } + + @Override + public int getHoldability() throws SQLException { + checkStatus(); + + return connection.getHoldability(); + } + + @Override + public Savepoint setSavepoint() throws SQLException { + checkStatus(); + + return connection.setSavepoint(); + } + + @Override + public Savepoint setSavepoint(String name) throws SQLException { + checkStatus(); + + return connection.setSavepoint(name); + } + + @Override + public void rollback(Savepoint savepoint) throws SQLException { + checkStatus(); + + connection.rollback(savepoint); + } + + @Override + public void releaseSavepoint(Savepoint savepoint) throws SQLException { + checkStatus(); + + connection.releaseSavepoint(savepoint); + } + + @Override + public Statement createStatement(int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException { + checkStatus(); + + return connection.createStatement(resultSetType, resultSetConcurrency, resultSetHoldability); + } + + @Override + public PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException { + checkStatus(); + + return connection.prepareStatement(sql, resultSetType, resultSetConcurrency, resultSetHoldability); + } + + @Override + public CallableStatement prepareCall(String sql, int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException { + checkStatus(); + + return connection.prepareCall(sql, resultSetType, resultSetConcurrency, resultSetHoldability); + } + + @Override + public PreparedStatement prepareStatement(String sql, int autoGeneratedKeys) throws SQLException { + checkStatus(); + + return connection.prepareStatement(sql, autoGeneratedKeys); + } + + @Override + public PreparedStatement prepareStatement(String sql, int[] columnIndexes) throws SQLException { + checkStatus(); + + return connection.prepareStatement(sql, columnIndexes); + } + + @Override + public PreparedStatement prepareStatement(String sql, String[] columnNames) throws SQLException { + checkStatus(); + + return connection.prepareStatement(sql, columnNames); + } + + @Override + public Clob createClob() throws SQLException { + checkStatus(); + + return connection.createClob(); + } + + @Override + public Blob createBlob() throws SQLException { + checkStatus(); + + return connection.createBlob(); + } + + @Override + public NClob createNClob() throws SQLException { + checkStatus(); + + return connection.createNClob(); + } + + @Override + public SQLXML createSQLXML() throws SQLException { + checkStatus(); + + return connection.createSQLXML(); + } + + @Override + public boolean isValid(int timeout) throws SQLException { + checkStatus(); + + return connection.isValid(timeout); + } + + @Override + public void setClientInfo(String name, String value) throws SQLClientInfoException { + checkStatus(); + + connection.setClientInfo(name, value); + } + + @Override + public void setClientInfo(Properties properties) throws SQLClientInfoException { + checkStatus(); + + connection.setClientInfo(properties); + } + + @Override + public String getClientInfo(String name) throws SQLException { + checkStatus(); + + return connection.getClientInfo(name); + } + + @Override + public Properties getClientInfo() throws SQLException { + checkStatus(); + + return connection.getClientInfo(); + } + + @Override + public Array createArrayOf(String typeName, Object[] elements) throws SQLException { + checkStatus(); + + return connection.createArrayOf(typeName, elements); + } + + @Override + public Struct createStruct(String typeName, Object[] attributes) throws SQLException { + checkStatus(); + + return connection.createStruct(typeName, attributes); + } + + @Override + public void setSchema(String schema) throws SQLException { + checkStatus(); + + connection.setSchema(schema); + } + + @Override + public String getSchema() throws SQLException { + checkStatus(); + + return connection.getSchema(); + } + + @Override + public void abort(Executor executor) throws SQLException { + checkStatus(); + + connection.abort(executor); + } + + @Override + public void setNetworkTimeout(Executor executor, int milliseconds) throws SQLException { + checkStatus(); + + connection.setNetworkTimeout(executor, milliseconds); + } + + @Override + public int getNetworkTimeout() throws SQLException { + checkStatus(); + + return connection.getNetworkTimeout(); + } + + @Override + public T unwrap(Class iface) throws SQLException { + checkStatus(); + + return connection.unwrap(iface); + } + + @Override + public boolean isWrapperFor(Class iface) throws SQLException { + checkStatus(); + + return connection.isWrapperFor(iface); + } + + @Override + public boolean isBusy() { + return isBusy; + } + + @Override + public void setBusy(boolean busy) { + isBusy = busy; + } + + @Override + public Connection getConnection() { + return connection; + } + + @Override + public void setConnection(Connection connection) { + this.connection = connection; + } + + @Override + public IPooledDataSourceConfig getDataSource() { + return dataSource; + } + + @Override + public void setDataSource(IPooledDataSourceConfig dataSource) { + this.dataSource = dataSource; + } + + /** + * 对于设置为繁忙的连接,等价于关闭 + * @since 1.4.0 + */ + private void checkStatus() { + if(!isBusy) { + throw new JdbcPoolException("Connection has been closed"); + } + } + +} diff --git a/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dataSource/pool/constant/JdbcConstants.java b/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dataSource/pool/constant/JdbcConstants.java new file mode 100644 index 00000000..419b72cf --- /dev/null +++ b/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dataSource/pool/constant/JdbcConstants.java @@ -0,0 +1,71 @@ +package com.anjiplus.template.gaea.business.modules.data.dataSource.pool.constant; + +/** + * Created by raodeming on 2021/3/19. + */ +public class JdbcConstants { + 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 = "postgresql"; + public final static String POSTGRESQL_DRIVER = "org.postgresql.Driver"; + public final static String SYBASE = "sybase"; + public final static String SQL_SERVER = "sqlserver"; + 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 = "oracle"; + 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 = "mysql"; + 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_SQL = "elasticsearch_sql"; + 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"; + public final static String KUDU_IMAPLA = "kudu_impala"; + public final static String HTTP = "http"; +} diff --git a/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dataSource/pool/constant/PooledConst.java b/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dataSource/pool/constant/PooledConst.java new file mode 100644 index 00000000..b584060d --- /dev/null +++ b/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dataSource/pool/constant/PooledConst.java @@ -0,0 +1,71 @@ +package com.anjiplus.template.gaea.business.modules.data.dataSource.pool.constant; + +/** + * 线程池常量 + * @since 1.1.0 + */ +public final class PooledConst { + + private PooledConst(){} + + /** + * 默认的最小连接数 + * @since 1.1.0 + */ + public static final int DEFAULT_MIN_SIZE = 10; + + /** + * 默认最大的连接数 + * @since 1.1.0 + */ + public static final int DEFAULT_MAX_SIZE = 300; + + /** + * 默认最大的等待毫秒数 + * + * 默认:1 min + * + * @since 1.3.0 + */ + public static final int DEFAULT_MAX_WAIT_MILLS = 60 * 1000; + + /** + * 默认验证查询的语句 + * @since 1.5.0 + */ + public static final String DEFAULT_VALID_QUERY = "select 1 from dual"; + + /** + * 默认的验证的超时时间 + * @since 1.5.0 + */ + public static final int DEFAULT_VALID_TIME_OUT_SECONDS = 5; + + /** + * 获取连接时,默认不校验 + * @since 1.5.0 + */ + public static final boolean DEFAULT_TEST_ON_BORROW = false; + + + /** + * 归还连接时,默认不校验 + * @since 1.5.0 + */ + public static final boolean DEFAULT_TEST_ON_RETURN = false; + + /** + * 默认闲暇的时候,进行校验 + * + * @since 1.5.0 + */ + public static final boolean DEFAULT_TEST_ON_IDLE = true; + + /** + * 1min 自动校验一次 + * + * @since 1.5.0 + */ + public static final long DEFAULT_TEST_ON_IDLE_INTERVAL_SECONDS = 60; + +} diff --git a/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dataSource/pool/datasource/AbstractDataSourceConfig.java b/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dataSource/pool/datasource/AbstractDataSourceConfig.java new file mode 100644 index 00000000..786bc5f7 --- /dev/null +++ b/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dataSource/pool/datasource/AbstractDataSourceConfig.java @@ -0,0 +1,68 @@ +package com.anjiplus.template.gaea.business.modules.data.dataSource.pool.datasource; + +/** + * @author binbin.hou + * @since 1.0.0 + */ +public class AbstractDataSourceConfig extends DataSourceConfigAdaptor { + + /** + * 驱动类 + * @since 1.0.0 + */ + protected String driverClass; + + /** + * jdbc url + * @since 1.0.0 + */ + protected String jdbcUrl; + + /** + * 用户 + * @since 1.0.0 + */ + protected String user; + + /** + * 密码 + * @since 1.0.0 + */ + protected String password; + + public String getDriverClass() { + return driverClass; + } + + @Override + public void setDriverClass(String driverClass) { + this.driverClass = driverClass; + } + + public String getJdbcUrl() { + return jdbcUrl; + } + + @Override + public void setJdbcUrl(String jdbcUrl) { + this.jdbcUrl = jdbcUrl; + } + + public String getUser() { + return user; + } + + @Override + public void setUser(String user) { + this.user = user; + } + + public String getPassword() { + return password; + } + + @Override + public void setPassword(String password) { + this.password = password; + } +} diff --git a/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dataSource/pool/datasource/AbstractPooledDataSourceConfig.java b/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dataSource/pool/datasource/AbstractPooledDataSourceConfig.java new file mode 100644 index 00000000..786fb5ec --- /dev/null +++ b/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dataSource/pool/datasource/AbstractPooledDataSourceConfig.java @@ -0,0 +1,159 @@ +package com.anjiplus.template.gaea.business.modules.data.dataSource.pool.datasource; + +import com.anjiplus.template.gaea.business.modules.data.dataSource.pool.api.ILifeCycle; +import com.anjiplus.template.gaea.business.modules.data.dataSource.pool.api.IPooledDataSourceConfig; +import com.anjiplus.template.gaea.business.modules.data.dataSource.pool.constant.PooledConst; + +/** + * @author binbin.hou + * @since 1.1.0 + */ +public abstract class AbstractPooledDataSourceConfig extends AbstractDataSourceConfig + implements IPooledDataSourceConfig, ILifeCycle { + + /** + * 最小尺寸 + * @since 1.1.0 + */ + protected int minSize = PooledConst.DEFAULT_MIN_SIZE; + + /** + * 最大尺寸 + * @since 1.1.0 + */ + protected int maxSize = PooledConst.DEFAULT_MAX_SIZE; + + /** + * 最大的等待时间 + * @since 1.3.0 + */ + protected long maxWaitMills = PooledConst.DEFAULT_MAX_WAIT_MILLS; + + /** + * 验证查询 + * @since 1.5.0 + */ + protected String validQuery = PooledConst.DEFAULT_VALID_QUERY; + + /** + * 验证的超时时间 + * @since 1.5.0 + */ + protected int validTimeOutSeconds = PooledConst.DEFAULT_VALID_TIME_OUT_SECONDS; + + /** + * 获取时验证 + * @since 1.5.0 + */ + protected boolean testOnBorrow = PooledConst.DEFAULT_TEST_ON_BORROW; + + /** + * 归还时验证 + * @since 1.5.0 + */ + protected boolean testOnReturn = PooledConst.DEFAULT_TEST_ON_RETURN; + + /** + * 闲暇时验证 + * @since 1.5.0 + */ + protected boolean testOnIdle = PooledConst.DEFAULT_TEST_ON_IDLE; + + /** + * 闲暇时验证的时间间隔 + * @since 1.5.0 + */ + protected long testOnIdleIntervalSeconds = PooledConst.DEFAULT_TEST_ON_IDLE_INTERVAL_SECONDS; + + public int getMinSize() { + return minSize; + } + + @Override + public void setMinSize(int minSize) { + this.minSize = minSize; + } + + public int getMaxSize() { + return maxSize; + } + + @Override + public void setMaxSize(int maxSize) { + this.maxSize = maxSize; + } + + public long getMaxWaitMills() { + return maxWaitMills; + } + + @Override + public void setMaxWaitMills(long maxWaitMills) { + this.maxWaitMills = maxWaitMills; + } + + public String getValidQuery() { + return validQuery; + } + + @Override + public void setValidQuery(String validQuery) { + this.validQuery = validQuery; + } + + public int getValidTimeOutSeconds() { + return validTimeOutSeconds; + } + + @Override + public void setValidTimeOutSeconds(int validTimeOutSeconds) { + this.validTimeOutSeconds = validTimeOutSeconds; + } + + public boolean isTestOnBorrow() { + return testOnBorrow; + } + + @Override + public void setTestOnBorrow(boolean testOnBorrow) { + this.testOnBorrow = testOnBorrow; + } + + public boolean isTestOnReturn() { + return testOnReturn; + } + + @Override + public void setTestOnReturn(boolean testOnReturn) { + this.testOnReturn = testOnReturn; + } + + public boolean isTestOnIdle() { + return testOnIdle; + } + + @Override + public void setTestOnIdle(boolean testOnIdle) { + this.testOnIdle = testOnIdle; + } + + public long getTestOnIdleIntervalSeconds() { + return testOnIdleIntervalSeconds; + } + + @Override + public void setTestOnIdleIntervalSeconds(long testOnIdleIntervalSeconds) { + this.testOnIdleIntervalSeconds = testOnIdleIntervalSeconds; + } + + @Override + public void init() { + + } + + @Override + public void destroy() { + + } + +} diff --git a/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dataSource/pool/datasource/DataSourceConfigAdaptor.java b/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dataSource/pool/datasource/DataSourceConfigAdaptor.java new file mode 100644 index 00000000..dcab7f88 --- /dev/null +++ b/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dataSource/pool/datasource/DataSourceConfigAdaptor.java @@ -0,0 +1,82 @@ +package com.anjiplus.template.gaea.business.modules.data.dataSource.pool.datasource; + +import com.anjiplus.template.gaea.business.modules.data.dataSource.pool.api.IDataSourceConfig; + +import java.io.PrintWriter; +import java.sql.Connection; +import java.sql.SQLException; +import java.sql.SQLFeatureNotSupportedException; +import java.util.logging.Logger; + +/** + * @author binbin.hou + * @since 1.0.0 + */ +public class DataSourceConfigAdaptor implements IDataSourceConfig { + + @Override + public Connection getConnection() throws SQLException { + return null; + } + + @Override + public Connection getConnection(String username, String password) throws SQLException { + return null; + } + + @Override + public T unwrap(Class iface) throws SQLException { + return null; + } + + @Override + public boolean isWrapperFor(Class iface) throws SQLException { + return false; + } + + @Override + public PrintWriter getLogWriter() throws SQLException { + return null; + } + + @Override + public void setLogWriter(PrintWriter out) throws SQLException { + + } + + @Override + public void setLoginTimeout(int seconds) throws SQLException { + + } + + @Override + public int getLoginTimeout() throws SQLException { + return 0; + } + + @Override + public Logger getParentLogger() throws SQLFeatureNotSupportedException { + return null; + } + + @Override + public void setDriverClass(String driverClass) { + + } + + @Override + public void setJdbcUrl(String jdbcUrl) { + + } + + @Override + public void setUser(String user) { + + } + + @Override + public void setPassword(String password) { + + } + +} diff --git a/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dataSource/pool/datasource/PooledDataSource.java b/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dataSource/pool/datasource/PooledDataSource.java new file mode 100644 index 00000000..24b7def2 --- /dev/null +++ b/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dataSource/pool/datasource/PooledDataSource.java @@ -0,0 +1,240 @@ +package com.anjiplus.template.gaea.business.modules.data.dataSource.pool.datasource; + +import com.anjiplus.template.gaea.business.modules.data.dataSource.pool.connection.IPooledConnection; +import com.anjiplus.template.gaea.business.modules.data.dataSource.pool.connection.PooledConnection; +import com.anjiplus.template.gaea.business.modules.data.dataSource.pool.exception.JdbcPoolException; +import com.anjiplus.template.gaea.business.modules.data.dataSource.pool.util.DriverClassUtil; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; + +import java.sql.Connection; +import java.sql.DriverManager; +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.List; +import java.util.Optional; +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.TimeUnit; + +/** + * 池化的数据源 + * + * @author binbin.hou + * @since 1.1.0 + */ +@Slf4j +public class PooledDataSource extends AbstractPooledDataSourceConfig { + + /** + * 内置的队列 + * + * @since 1.1.0 + */ + private List pool = new ArrayList<>(); + + @Override + public synchronized void init() { + DriverClassUtil.loadDriverClass(super.driverClass, super.jdbcUrl); + + this.initJdbcPool(); + + // 初始化 idle check + this.initTestOnIdle(); + } + + @Override + public synchronized Connection getConnection() throws SQLException { + //1. 获取第一个不是 busy 的连接 + Optional connectionOptional = getFreeConnectionFromPool(); + if (connectionOptional.isPresent()) { + return connectionOptional.get(); + } + + //2. 考虑是否可以扩容 + if (pool.size() >= maxSize) { + //2.1 立刻返回 + if (maxWaitMills <= 0) { + throw new JdbcPoolException("Can't get connection from pool!"); + } + + + //2.2 循环等待 + final long startWaitMills = System.currentTimeMillis(); + final long endWaitMills = startWaitMills + maxWaitMills; + while (System.currentTimeMillis() < endWaitMills) { + Optional optional = getFreeConnectionFromPool(); + if (optional.isPresent()) { + return optional.get(); + } + + try { + TimeUnit.MILLISECONDS.sleep(1); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + } + log.debug("等待连接池归还,wait for 1 mills"); + } + + //2.3 等待超时 + throw new JdbcPoolException("Can't get connection from pool, wait time out for mills: " + maxWaitMills); + } + + //3. 扩容(暂时只扩容一个) + log.debug("开始扩容连接池大小,step: 1"); + IPooledConnection pooledConnection = createPooledConnection(); + pooledConnection.setBusy(true); + this.pool.add(pooledConnection); + log.debug("从扩容后的连接池中获取连接"); + return pooledConnection; + } + + @Override + public void returnConnection(IPooledConnection pooledConnection) { + // 验证状态 + if (testOnReturn) { + checkValid(pooledConnection); + } + + // 设置为不繁忙 + pooledConnection.setBusy(false); + log.debug("归还连接,状态设置为不繁忙"); + } + + /** + * 获取空闲的连接 + * + * @return 连接 + * @since 1.3.0 + */ + private Optional getFreeConnectionFromPool() { + for (IPooledConnection pc : pool) { + if (!pc.isBusy()) { + pc.setBusy(true); + log.debug("从连接池中获取连接"); + + // 验证有效性 + if (testOnBorrow) { + log.debug("Test on borrow start"); + checkValid(pc); + log.debug("Test on borrow finish"); + } + + return Optional.of(pc); + } + } + // 空 + return Optional.empty(); + } + + + /** + * https://stackoverflow.com/questions/3668506/efficient-sql-test-query-or-validation-query-that-will-work-across-all-or-most + *

+ * 真正支持标准的,直接使用 {@link Connection#isValid(int)} 验证比较合适 + * + * @param pooledConnection 连接池信息 + * @since 1.5.0 + */ + private void checkValid(final IPooledConnection pooledConnection) { + if (StringUtils.isNotEmpty(super.validQuery)) { + Connection connection = pooledConnection.getConnection(); + try { + // 如果连接无效,重新申请一个新的替代 + if (!connection.isValid(super.validTimeOutSeconds)) { + log.debug("Old connection is inValid, start create one for it."); + + Connection newConnection = createConnection(); + pooledConnection.setConnection(newConnection); + log.debug("Old connection is inValid, finish create one for it."); + } + } catch (SQLException throwables) { + throw new JdbcPoolException(throwables); + } + } else { + log.debug("valid query is empty, ignore valid."); + } + } + + /** + * 初始化连接池 + * + * @since 1.1.0 + */ + private void initJdbcPool() { + final int minSize = super.minSize; + pool = new ArrayList<>(minSize); + + for (int i = 0; i < minSize; i++) { + IPooledConnection pooledConnection = createPooledConnection(); + + pool.add(pooledConnection); + } + } + + /** + * 创建一个池化的连接 + * + * @return 连接 + * @since 1.1.0 + */ + private IPooledConnection createPooledConnection() { + Connection connection = createConnection(); + + IPooledConnection pooledConnection = new PooledConnection(); + pooledConnection.setBusy(false); + pooledConnection.setConnection(connection); + pooledConnection.setDataSource(this); + + return pooledConnection; + } + + /** + * 创建新连接 + * + * @return 连接 + * @since 1.1.0 + */ + private Connection createConnection() { + try { + if (StringUtils.isBlank(super.getUser()) && StringUtils.isBlank(super.getPassword())) { + return DriverManager.getConnection(super.getJdbcUrl()); + } + return DriverManager.getConnection(super.getJdbcUrl(), + super.getUser(), super.getPassword()); + } catch (SQLException e) { + throw new JdbcPoolException(e); + } + } + + + /** + * 初始化空闲时检验 + * + * @since 1.5.0 + */ + private void initTestOnIdle() { + if (StringUtils.isNotEmpty(validQuery)) { + ScheduledExecutorService idleExecutor = Executors.newSingleThreadScheduledExecutor(); + + idleExecutor.scheduleAtFixedRate(this::testOnIdleCheck, super.testOnIdleIntervalSeconds, testOnIdleIntervalSeconds, TimeUnit.SECONDS); + log.debug("Test on idle config with interval seonds: " + testOnIdleIntervalSeconds); + } + } + + /** + * 验证所有的空闲连接是否有效 + * + * @since 1.5.0 + */ + private void testOnIdleCheck() { + log.debug("start check test on idle"); + for (IPooledConnection pc : this.pool) { + if (!pc.isBusy()) { + checkValid(pc); + } + } + log.debug("finish check test on idle"); + } + +} diff --git a/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dataSource/pool/datasource/UnPooledDataSource.java b/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dataSource/pool/datasource/UnPooledDataSource.java new file mode 100644 index 00000000..e45010c9 --- /dev/null +++ b/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dataSource/pool/datasource/UnPooledDataSource.java @@ -0,0 +1,26 @@ +package com.anjiplus.template.gaea.business.modules.data.dataSource.pool.datasource; + +import com.anjiplus.template.gaea.business.modules.data.dataSource.pool.util.DriverClassUtil; +import org.apache.commons.lang3.StringUtils; + +import java.sql.Connection; +import java.sql.DriverManager; +import java.sql.SQLException; + +/** + * @author binbin.hou + * @since 1.0.0 + */ +public class UnPooledDataSource extends AbstractDataSourceConfig { + + @Override + public Connection getConnection() throws SQLException { + DriverClassUtil.loadDriverClass(super.driverClass, super.jdbcUrl); + if (StringUtils.isBlank(super.getUser()) && StringUtils.isBlank(super.getPassword())) { + return DriverManager.getConnection(super.jdbcUrl); + } + return DriverManager.getConnection(super.getJdbcUrl(), + super.getUser(), super.getPassword()); + } + +} diff --git a/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dataSource/pool/exception/JdbcPoolException.java b/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dataSource/pool/exception/JdbcPoolException.java new file mode 100644 index 00000000..ace4113d --- /dev/null +++ b/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dataSource/pool/exception/JdbcPoolException.java @@ -0,0 +1,28 @@ +package com.anjiplus.template.gaea.business.modules.data.dataSource.pool.exception; + +/** + * @author binbin.hou + * @since 1.0.0 + */ +public class JdbcPoolException extends RuntimeException { + + public JdbcPoolException() { + } + + public JdbcPoolException(String message) { + super(message); + } + + public JdbcPoolException(String message, Throwable cause) { + super(message, cause); + } + + public JdbcPoolException(Throwable cause) { + super(cause); + } + + public JdbcPoolException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) { + super(message, cause, enableSuppression, writableStackTrace); + } + +} diff --git a/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dataSource/pool/util/DataSourceHandleUtil.java b/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dataSource/pool/util/DataSourceHandleUtil.java new file mode 100644 index 00000000..604ceeae --- /dev/null +++ b/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dataSource/pool/util/DataSourceHandleUtil.java @@ -0,0 +1,13 @@ +package com.anjiplus.template.gaea.business.modules.data.dataSource.pool.util; + +/** + * Created by raodeming on 2021/3/19. + */ +public class DataSourceHandleUtil { + + + public static void mysqlConnection() { + + + } +} diff --git a/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dataSource/pool/util/DriverClassUtil.java b/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dataSource/pool/util/DriverClassUtil.java new file mode 100644 index 00000000..da1f71de --- /dev/null +++ b/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dataSource/pool/util/DriverClassUtil.java @@ -0,0 +1,89 @@ +package com.anjiplus.template.gaea.business.modules.data.dataSource.pool.util; + +import com.anji.plus.gaea.exception.BusinessExceptionBuilder; +import com.anjiplus.template.gaea.common.RespCommonCode; +import org.apache.commons.lang3.StringUtils; + +import java.util.HashMap; +import java.util.Map; + +/** + * Created by raodeming on 2021/4/19. + */ +public final class DriverClassUtil { + + /** + * 存放驱动类信息 + */ + private static final Map DRIVER_CLASS_MAP; + + static { + DRIVER_CLASS_MAP = new HashMap<>(32); + DRIVER_CLASS_MAP.put("jdbc:db2", "COM.ibm.db2.jdbc.app.DB2Driver"); + DRIVER_CLASS_MAP.put("jdbc:firebirdsql", "org.firebirdsql.jdbc.FBDriver"); + DRIVER_CLASS_MAP.put("jdbc:edbc", "ca.edbc.jdbc.EdbcDriver"); + DRIVER_CLASS_MAP.put("jdbc:pointbase", "com.pointbase.jdbc.jdbcUniversalDriver"); + DRIVER_CLASS_MAP.put("jdbc:fake", "com.alibaba.druid.mock.MockDriver"); + DRIVER_CLASS_MAP.put("jdbc:informix-sqli", "com.informix.jdbc.IfxDriver"); + DRIVER_CLASS_MAP.put("jdbc:sqlite", "org.sqlite.JDBC"); + DRIVER_CLASS_MAP.put("jdbc:microsoft", "com.microsoft.jdbc.sqlserver.SQLServerDriver"); + DRIVER_CLASS_MAP.put("jdbc:hsqldb", "org.hsqldb.jdbcDriver"); + DRIVER_CLASS_MAP.put("jdbc:postgresql", "org.postgresql.Driver"); + DRIVER_CLASS_MAP.put("jdbc:ingres", "com.ingres.jdbc.IngresDriver"); + DRIVER_CLASS_MAP.put("jdbc:cloudscape", "COM.cloudscape.core.JDBCDriver"); + DRIVER_CLASS_MAP.put("jdbc:JSQLConnect", "com.jnetdirect.jsql.JSQLDriver"); + DRIVER_CLASS_MAP.put("jdbc:derby", "org.apache.derby.jdbc.EmbeddedDriver"); + DRIVER_CLASS_MAP.put("jdbc:timesten", "com.timesten.jdbc.TimesTenDriver"); + DRIVER_CLASS_MAP.put("jdbc:interbase", "interbase.interclient.Driver"); + DRIVER_CLASS_MAP.put("jdbc:h2", "org.h2.Driver"); + DRIVER_CLASS_MAP.put("jdbc:as400", "com.ibm.as400.access.AS400JDBCDriver"); + DRIVER_CLASS_MAP.put("jdbc:sybase:Tds", "com.sybase.jdbc2.jdbc.SybDriver"); + DRIVER_CLASS_MAP.put("jdbc:mock", "com.alibaba.druid.mock.MockDriver"); + DRIVER_CLASS_MAP.put("jdbc:oracle", "oracle.jdbc.driver.OracleDriver"); + DRIVER_CLASS_MAP.put("jdbc:mysql", "com.mysql.jdbc.Driver"); + DRIVER_CLASS_MAP.put("jdbc:odps", "com.aliyun.odps.jdbc.OdpsDriver"); + DRIVER_CLASS_MAP.put("jdbc:mckoi", "com.mckoi.JDBCDriver"); + DRIVER_CLASS_MAP.put("jdbc:jtds", "net.sourceforge.jtds.jdbc.Driver"); + DRIVER_CLASS_MAP.put("jdbc:sapdb", "com.sap.dbtech.jdbc.DriverSapDB"); + DRIVER_CLASS_MAP.put("jdbc:JTurbo", "com.newatlanta.jturbo.driver.Driver"); + DRIVER_CLASS_MAP.put("jdbc:mimer:multi1", "com.mimer.jdbc.Driver"); + } + + /** + * 加载驱动类信息 + * @param driverClass 驱动类 + * @param url 连接信息 + */ + public static void loadDriverClass(String driverClass, final String url) { + if(StringUtils.isEmpty(driverClass)) { + driverClass = getDriverClassByUrl(url); + } + + try { + Class.forName(driverClass); + } catch (ClassNotFoundException e) { + throw BusinessExceptionBuilder.build(RespCommonCode.CLASS_NOT_FOUND, e.getMessage()); + } + } + + + /** + * 根据 URL 获取对应的驱动类 + * + * 1. 禁止 url 为空 + * 2. 如果未找到,则直接报错。 + * @param url url + * @return 驱动信息 + */ + private static String getDriverClassByUrl(final String url) { + for(Map.Entry entry : DRIVER_CLASS_MAP.entrySet()) { + String urlPrefix = entry.getKey(); + if(url.startsWith(urlPrefix)) { + return entry.getValue(); + } + } + + throw BusinessExceptionBuilder.build(RespCommonCode.CLASS_NOT_FOUND, "Can't auto find match driver class for url: " + url); + } + +} diff --git a/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dataSource/pool/util/JdbcUtil.java b/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dataSource/pool/util/JdbcUtil.java new file mode 100644 index 00000000..94d6eb26 --- /dev/null +++ b/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dataSource/pool/util/JdbcUtil.java @@ -0,0 +1,100 @@ +package com.anjiplus.template.gaea.business.modules.data.dataSource.pool.util; + +import com.anjiplus.template.gaea.business.modules.data.dataSource.controller.dto.DataSourceDto; +import com.anjiplus.template.gaea.business.modules.data.dataSource.pool.datasource.PooledDataSource; +import com.anjiplus.template.gaea.business.modules.data.dataSource.pool.datasource.UnPooledDataSource; +import lombok.extern.slf4j.Slf4j; + +import java.sql.Connection; +import java.sql.SQLException; +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.locks.Lock; +import java.util.concurrent.locks.ReentrantLock; + +/** + * Created by raodeming on 2021/3/18. + */ +@Slf4j +public class JdbcUtil { + + private static Lock lock = new ReentrantLock(); + + private static Lock deleteLock = new ReentrantLock(); + + //所有数据源的连接池存在map里 + static Map map = new HashMap<>(); + + public static PooledDataSource getJdbcConnectionPool(DataSourceDto dataSource) { + if (map.containsKey(dataSource.getId())) { + return map.get(dataSource.getId()); + } else { + lock.lock(); + try { + log.debug(Thread.currentThread().getName() + "获取锁"); + if (!map.containsKey(dataSource.getId())) { + PooledDataSource pool = new PooledDataSource(); + pool.setJdbcUrl(dataSource.getJdbcUrl()); + pool.setUser(dataSource.getUsername()); + pool.setPassword(dataSource.getPassword()); + pool.setDriverClass(dataSource.getDriverName()); + pool.init(); + map.put(dataSource.getId(), pool); + log.info("创建连接池成功:{}", dataSource.getJdbcUrl()); + } + return map.get(dataSource.getId()); + } finally { + lock.unlock(); + } + } + } + + /** + * 删除数据库连接池 + * @param id + */ + public static void removeJdbcConnectionPool(Long id) { + deleteLock.lock(); + try { + PooledDataSource pool = map.get(id); + if (pool != null) { + map.remove(id); + } + } catch (Exception e) { + log.error(e.toString()); + } finally { + deleteLock.unlock(); + } + + } + + /** + * 获取连接 + * @param dataSource + * @return + * @throws SQLException + */ + public static Connection getPooledConnection(DataSourceDto dataSource) throws SQLException { + PooledDataSource pool = getJdbcConnectionPool(dataSource); + return pool.getConnection(); + } + + /** + * 测试数据库连接 获取一个连接 + * @param dataSource + * @return + * @throws ClassNotFoundException driverName不正确 + * @throws SQLException + */ + public static Connection getUnPooledConnection(DataSourceDto dataSource) throws SQLException { + UnPooledDataSource source = new UnPooledDataSource(); + source.setJdbcUrl(dataSource.getJdbcUrl()); + source.setDriverClass(dataSource.getDriverName()); + source.setUser(dataSource.getUsername()); + source.setPassword(dataSource.getPassword()); + return source.getConnection(); + } + + + +} diff --git a/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dataSource/service/DataSourceService.java b/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dataSource/service/DataSourceService.java new file mode 100644 index 00000000..220b0b25 --- /dev/null +++ b/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dataSource/service/DataSourceService.java @@ -0,0 +1,48 @@ + +package com.anjiplus.template.gaea.business.modules.data.dataSource.service; + +import com.alibaba.fastjson.JSONObject; +import com.anji.plus.gaea.curd.service.GaeaBaseService; +import com.anjiplus.template.gaea.business.modules.data.dataSet.controller.dto.DataSetDto; +import com.anjiplus.template.gaea.business.modules.data.dataSource.controller.dto.DataSourceDto; +import com.anjiplus.template.gaea.business.modules.data.dataSource.controller.param.ConnectionParam; +import com.anjiplus.template.gaea.business.modules.data.dataSource.controller.param.DataSourceParam; +import com.anjiplus.template.gaea.business.modules.data.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); +} \ No newline at end of file diff --git a/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dataSource/service/impl/DataSourceServiceImpl.java b/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dataSource/service/impl/DataSourceServiceImpl.java new file mode 100644 index 00000000..a6d2e991 --- /dev/null +++ b/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/dataSource/service/impl/DataSourceServiceImpl.java @@ -0,0 +1,384 @@ + +package com.anjiplus.template.gaea.business.modules.data.dataSource.service.impl; + +import com.alibaba.fastjson.JSONArray; +import com.alibaba.fastjson.JSONObject; +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.GaeaAssert; +import com.anjiplus.template.gaea.business.code.ResponseCode; +import com.anjiplus.template.gaea.business.modules.data.dataSet.controller.dto.DataSetDto; +import com.anjiplus.template.gaea.business.modules.data.dataSetParam.service.DataSetParamService; +import com.anjiplus.template.gaea.business.modules.data.dataSource.controller.dto.DataSourceDto; +import com.anjiplus.template.gaea.business.modules.data.dataSource.controller.param.ConnectionParam; +import com.anjiplus.template.gaea.business.modules.data.dataSource.dao.DataSourceMapper; +import com.anjiplus.template.gaea.business.modules.data.dataSource.dao.entity.DataSource; +import com.anjiplus.template.gaea.business.modules.data.dataSource.pool.constant.JdbcConstants; +import com.anjiplus.template.gaea.business.modules.data.dataSource.pool.util.JdbcUtil; +import com.anjiplus.template.gaea.business.modules.data.dataSource.service.DataSourceService; +import com.anjiplus.template.gaea.common.RespCommonCode; +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.Connection; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.ArrayList; +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; + + @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()); + 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: + testRelationalDb(dto); + break; + case JdbcConstants.HTTP: + testHttp(dto); + break; + default: + throw BusinessExceptionBuilder.build(RespCommonCode.DATA_SOURCE_TYPE_DOES_NOT_MATCH_TEMPORARILY); + } + 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: + return executeRelationalDb(dto); + case JdbcConstants.HTTP: + return executeHttp(dto); + default: + throw BusinessExceptionBuilder.build(RespCommonCode.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(RespCommonCode.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) { + throw BusinessExceptionBuilder.build(RespCommonCode.DATA_SOURCE_CONNECTION_FAILED, e.getMessage()); + } + if (exchange.getStatusCode().isError()) { + throw BusinessExceptionBuilder.build(RespCommonCode.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) { + throw BusinessExceptionBuilder.build(RespCommonCode.ANALYSIS_DATA_ERROR, e.getMessage()); + } + return result; + } + + public List executeRelationalDb(DataSourceDto dto) { + analysisRelationalDbConfig(dto); + Connection pooledConnection = null; + try { + pooledConnection = JdbcUtil.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); + jo.put(t, value); + } catch (SQLException throwable) { + throw BusinessExceptionBuilder.build(RespCommonCode.EXECUTE_SQL_ERROR, throwable.getMessage()); + } + }); + list.add(jo); + } + return list; + } catch (Exception throwable) { + throw BusinessExceptionBuilder.build(RespCommonCode.EXECUTE_SQL_ERROR, throwable.getMessage()); + } finally { + try { + pooledConnection.close(); + } catch (SQLException throwable) { + throw BusinessExceptionBuilder.build(RespCommonCode.DATA_SOURCE_CONNECTION_FAILED, throwable.getMessage()); + } + } + } + + /** + * 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, JSONObject.class); + } catch (Exception e) { + throw BusinessExceptionBuilder.build(RespCommonCode.DATA_SOURCE_CONNECTION_FAILED, e.getMessage()); + } + if (exchange.getStatusCode().isError()) { + throw BusinessExceptionBuilder.build(RespCommonCode.DATA_SOURCE_CONNECTION_FAILED, exchange.getBody()); + } + JSONObject body = exchange.getBody(); + List result = new ArrayList<>(); + result.add(body); + return result; + } + + /** + * 关系型数据库 测试连接 + * + * @param dto + */ + public void testRelationalDb(DataSourceDto dto) { + analysisRelationalDbConfig(dto); + try { + Connection unPooledConnection = JdbcUtil.getUnPooledConnection(dto); + String catalog = unPooledConnection.getCatalog(); + log.info("数据库测试连接成功:{}", catalog); + unPooledConnection.close(); + } catch (Exception e) { + throw BusinessExceptionBuilder.build(RespCommonCode.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(RespCommonCode.DATA_SOURCE_CONNECTION_FAILED, exchange.getBody()); + } + } catch (RestClientException e) { + throw BusinessExceptionBuilder.build(RespCommonCode.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(RespCommonCode.DATA_SOURCE_CONNECTION_FAILED, exchange.getBody()); + } + } catch (RestClientException e) { + throw BusinessExceptionBuilder.build(RespCommonCode.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); + } + + +} \ No newline at end of file diff --git a/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/report/constant/ExpConstant.java b/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/report/constant/ExpConstant.java new file mode 100644 index 00000000..86d674fe --- /dev/null +++ b/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/report/constant/ExpConstant.java @@ -0,0 +1,25 @@ +package com.anjiplus.template.gaea.business.modules.data.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/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/report/controller/ReportController.java b/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/report/controller/ReportController.java new file mode 100644 index 00000000..b1c7db76 --- /dev/null +++ b/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/report/controller/ReportController.java @@ -0,0 +1,60 @@ +package com.anjiplus.template.gaea.business.modules.data.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.data.report.controller.dto.ReportDto; +import com.anjiplus.template.gaea.business.modules.data.report.controller.param.ReportParam; +import com.anjiplus.template.gaea.business.modules.data.report.dao.entity.Report; +import com.anjiplus.template.gaea.business.modules.data.report.service.ReportService; +import io.swagger.annotations.Api; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.DeleteMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +/** + * TODO + * + * @author chenkening + * @date 2021/3/26 10:19 + */ +@RestController +@Api(tags = "报表数据管理") +@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(); + } + + @DeleteMapping("/delReport") + @Permission( + code = "DELETE", + name = "删除" + ) + @GaeaAuditLog( + pageTitle = "删除" + ) + public ResponseBean delReport(@RequestBody ReportDto reportDto) { + reportService.delReport(reportDto); + return ResponseBean.builder().build(); + } +} diff --git a/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/report/controller/dto/ReportDto.java b/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/report/controller/dto/ReportDto.java new file mode 100644 index 00000000..98003946 --- /dev/null +++ b/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/report/controller/dto/ReportDto.java @@ -0,0 +1,44 @@ +package com.anjiplus.template.gaea.business.modules.data.report.controller.dto; + +import com.anji.plus.gaea.curd.dto.GaeaBaseDTO; +import lombok.Data; + +import java.io.Serializable; + +/** + * TODO + * + * @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; + +} diff --git a/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/report/controller/param/ReportParam.java b/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/report/controller/param/ReportParam.java new file mode 100644 index 00000000..4017f41f --- /dev/null +++ b/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/report/controller/param/ReportParam.java @@ -0,0 +1,30 @@ +package com.anjiplus.template.gaea.business.modules.data.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 reportCode; + + /** 报表类型 */ + @Query(QueryEnum.EQ) + private String reportType; +} diff --git a/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/report/dao/ReportMapper.java b/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/report/dao/ReportMapper.java new file mode 100644 index 00000000..e9e2e567 --- /dev/null +++ b/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/report/dao/ReportMapper.java @@ -0,0 +1,13 @@ +package com.anjiplus.template.gaea.business.modules.data.report.dao; + +import com.anji.plus.gaea.curd.mapper.GaeaBaseMapper; +import com.anjiplus.template.gaea.business.modules.data.report.dao.entity.Report; + +/** + * TODO + * + * @author chenkening + * @date 2021/3/26 10:19 + */ +public interface ReportMapper extends GaeaBaseMapper { +} diff --git a/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/report/dao/entity/Report.java b/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/report/dao/entity/Report.java new file mode 100644 index 00000000..b60b8a78 --- /dev/null +++ b/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/report/dao/entity/Report.java @@ -0,0 +1,41 @@ +package com.anjiplus.template.gaea.business.modules.data.report.dao.entity; + +import com.anji.plus.gaea.annotation.Unique; +import com.anji.plus.gaea.curd.entity.GaeaBaseEntity; +import com.anjiplus.template.gaea.common.RespCommonCode; +import com.baomidou.mybatisplus.annotation.TableName; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +/** + * TODO + * + * @author chenkening + * @date 2021/3/26 10:20 + */ +@TableName(value="gaea_report") +@Data +public class Report extends GaeaBaseEntity { + + @ApiModelProperty(value = "名称") + private String reportName; + + @ApiModelProperty(value = "报表编码") + @Unique(code = RespCommonCode.REPORT_CODE_ISEXIST) + private String reportCode; + + @ApiModelProperty(value = "分组") + private String reportGroup; + + @ApiModelProperty(value = "报表描述") + private String reportDesc; + + @ApiModelProperty(value = "报表类型") + private String reportType; + + @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/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/report/service/ReportService.java b/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/report/service/ReportService.java new file mode 100644 index 00000000..9afca1f0 --- /dev/null +++ b/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/report/service/ReportService.java @@ -0,0 +1,17 @@ +package com.anjiplus.template.gaea.business.modules.data.report.service; + +import com.anji.plus.gaea.curd.service.GaeaBaseService; +import com.anjiplus.template.gaea.business.modules.data.report.controller.dto.ReportDto; +import com.anjiplus.template.gaea.business.modules.data.report.controller.param.ReportParam; +import com.anjiplus.template.gaea.business.modules.data.report.dao.entity.Report; + +/** + * TODO + * + * @author chenkening + * @date 2021/3/26 10:35 + */ +public interface ReportService extends GaeaBaseService { + + void delReport(ReportDto reportDto); +} diff --git a/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/report/service/impl/ReportServiceImpl.java b/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/report/service/impl/ReportServiceImpl.java new file mode 100644 index 00000000..34104887 --- /dev/null +++ b/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/report/service/impl/ReportServiceImpl.java @@ -0,0 +1,45 @@ +package com.anjiplus.template.gaea.business.modules.data.report.service.impl; + +import com.anji.plus.gaea.curd.mapper.GaeaBaseMapper; +import com.anjiplus.template.gaea.business.modules.data.report.controller.dto.ReportDto; +import com.anjiplus.template.gaea.business.modules.data.report.dao.ReportMapper; +import com.anjiplus.template.gaea.business.modules.data.report.dao.entity.Report; +import com.anjiplus.template.gaea.business.modules.data.report.service.ReportService; +import com.anjiplus.template.gaea.business.modules.data.reportexcel.dao.ReportExcelMapper; +import com.anjiplus.template.gaea.business.modules.data.reportexcel.dao.entity.ReportExcel; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +/** + * TODO + * + * @author chenkening + * @date 2021/3/26 10:35 + */ +@Service +public class ReportServiceImpl implements ReportService { + + private Logger logger = LoggerFactory.getLogger(this.getClass()); + @Autowired + private ReportMapper reportMapper; + + @Autowired + private ReportExcelMapper reportExcelMapper; + + @Override + public GaeaBaseMapper getMapper() { + return reportMapper; + } + + + @Override + public void delReport(ReportDto reportDto) { + deleteById(reportDto.getId()); + QueryWrapper queryWrapper = new QueryWrapper<>(); + queryWrapper.eq("report_code" , reportDto.getReportCode()); + reportExcelMapper.delete(queryWrapper); + } +} diff --git a/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/reportexcel/controller/ReportExcelController.java b/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/reportexcel/controller/ReportExcelController.java new file mode 100644 index 00000000..2d9d7451 --- /dev/null +++ b/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/reportexcel/controller/ReportExcelController.java @@ -0,0 +1,97 @@ +package com.anjiplus.template.gaea.business.modules.data.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.data.reportexcel.controller.dto.ReportExcelDto; +import com.anjiplus.template.gaea.business.modules.data.reportexcel.controller.param.ReportExcelParam; +import com.anjiplus.template.gaea.business.modules.data.reportexcel.dao.entity.ReportExcel; +import com.anjiplus.template.gaea.business.modules.data.reportexcel.service.ReportExcelService; +import io.swagger.annotations.Api; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +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; + +/** + * @author chenkening + * @date 2021/4/13 15:12 + */ +@RestController +@Api(tags = "报表表格管理") +@RequestMapping("/reportExcel") +public class ReportExcelController extends GaeaBaseController { + + @Autowired + private ReportExcelService reportExcelService; + + @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 = "DETAIL", + name = "详情" + ) + @GaeaAuditLog( + pageTitle = "详情" + ) + public ResponseBean detailByReportCode(@PathVariable String reportCode) { + ReportExcelDto reportExcelDto = reportExcelService.detailByReportCode(reportCode); + return ResponseBean.builder().data(reportExcelDto).build(); + } + + @PostMapping("/preview") + @Permission( + code = "DETAIL", + name = "预览" + ) + @GaeaAuditLog( + pageTitle = "预览" + ) + public ResponseBean preview(@RequestBody ReportExcelDto reportExcelDto) { + ReportExcelDto result = reportExcelService.preview(reportExcelDto); + return ResponseBean.builder().data(result).build(); + } + + + @PostMapping("/exportExcel") + @Permission( + code = "IMPORT", + 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(); +// } +} diff --git a/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/reportexcel/controller/dto/ReportExcelDto.java b/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/reportexcel/controller/dto/ReportExcelDto.java new file mode 100644 index 00000000..ed36dd48 --- /dev/null +++ b/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/reportexcel/controller/dto/ReportExcelDto.java @@ -0,0 +1,43 @@ + +package com.anjiplus.template.gaea.business.modules.data.reportexcel.controller.dto; + +import com.anji.plus.gaea.curd.dto.GaeaBaseDTO; +import lombok.Data; + +import java.io.Serializable; + + +/** + * @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; + +} diff --git a/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/reportexcel/controller/param/ReportExcelParam.java b/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/reportexcel/controller/param/ReportExcelParam.java new file mode 100644 index 00000000..11d0a9f2 --- /dev/null +++ b/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/reportexcel/controller/param/ReportExcelParam.java @@ -0,0 +1,18 @@ + +package com.anjiplus.template.gaea.business.modules.data.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/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/reportexcel/dao/ReportExcelMapper.java b/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/reportexcel/dao/ReportExcelMapper.java new file mode 100644 index 00000000..2fe2ac51 --- /dev/null +++ b/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/reportexcel/dao/ReportExcelMapper.java @@ -0,0 +1,11 @@ +package com.anjiplus.template.gaea.business.modules.data.reportexcel.dao; + +import com.anji.plus.gaea.curd.mapper.GaeaBaseMapper; +import com.anjiplus.template.gaea.business.modules.data.reportexcel.dao.entity.ReportExcel; + +/** + * @author chenkening + * @date 2021/4/13 15:11 + */ +public interface ReportExcelMapper extends GaeaBaseMapper { +} diff --git a/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/reportexcel/dao/entity/ReportExcel.java b/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/reportexcel/dao/entity/ReportExcel.java new file mode 100644 index 00000000..45cb42fb --- /dev/null +++ b/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/reportexcel/dao/entity/ReportExcel.java @@ -0,0 +1,33 @@ +package com.anjiplus.template.gaea.business.modules.data.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/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/reportexcel/service/ReportExcelService.java b/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/reportexcel/service/ReportExcelService.java new file mode 100644 index 00000000..8d5c9577 --- /dev/null +++ b/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/reportexcel/service/ReportExcelService.java @@ -0,0 +1,39 @@ +package com.anjiplus.template.gaea.business.modules.data.reportexcel.service; + +import com.anji.plus.gaea.curd.service.GaeaBaseService; +import com.anjiplus.template.gaea.business.modules.data.reportexcel.controller.dto.ReportExcelDto; +import com.anjiplus.template.gaea.business.modules.data.reportexcel.controller.param.ReportExcelParam; +import com.anjiplus.template.gaea.business.modules.data.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/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/reportexcel/service/impl/ReportExcelServiceImpl.java b/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/reportexcel/service/impl/ReportExcelServiceImpl.java new file mode 100644 index 00000000..804fd4a7 --- /dev/null +++ b/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/reportexcel/service/impl/ReportExcelServiceImpl.java @@ -0,0 +1,146 @@ +package com.anjiplus.template.gaea.business.modules.data.reportexcel.service.impl; + +import com.alibaba.fastjson.JSONObject; +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.export.enums.ExportTypeEnum; +import com.anji.plus.gaea.export.utils.ExportUtil; +import com.anji.plus.gaea.export.vo.ExportOperation; +import com.anji.plus.gaea.holder.UserContentHolder; +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.data.report.dao.ReportMapper; +import com.anjiplus.template.gaea.business.modules.data.report.dao.entity.Report; +import com.anjiplus.template.gaea.business.modules.data.reportexcel.controller.dto.ReportExcelDto; +import com.anjiplus.template.gaea.business.modules.data.reportexcel.dao.ReportExcelMapper; +import com.anjiplus.template.gaea.business.modules.data.reportexcel.dao.entity.ReportExcel; +import com.anjiplus.template.gaea.business.modules.data.reportexcel.service.ReportExcelService; +import com.anjiplus.template.gaea.business.modules.data.reportexcel.util.ReportUtil; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import org.apache.commons.lang3.StringUtils; +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.scheduling.concurrent.ThreadPoolTaskExecutor; +import org.springframework.stereotype.Service; + +import java.time.LocalDateTime; + +/** + * 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 ThreadPoolTaskExecutor threadPoolExportExecutor; + + @Autowired + private ReportMapper reportMapper; + + @Value("${file.dist-path}") + private String dictPath; + + @Autowired + private ReportUtil reportUtil; + + @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()); + JSONObject jsonObject = reportUtil.reportParse(reportExcelDto); + reportExcelDto.setJsonStr(JSONObject.toJSONString(jsonObject)); + reportExcelDto.setTotal(jsonObject.getJSONObject("rows").size()); + return reportExcelDto; + } + + @Override + public Boolean exportExcel(ReportExcelDto reportExcelDto) { + ExportOperation exportOperation = new ExportOperation(); + //指明导出数据查询到结果开始时间 + exportOperation.setResultStartTime(LocalDateTime.now()); + ReportExcelDto result = preview(reportExcelDto); + //指明导出数据查询到结果结束时间 + exportOperation.setResultEndTime(LocalDateTime.now()); + //指明导出数据查询到结果条数 + exportOperation.setResultSize(result.getTotal()); + //指明采用什么模式导出 + exportOperation.setExportType(StringUtils.isBlank(reportExcelDto.getExportType()) + ? ExportTypeEnum.GAEA_TEMPLATE_EXCEL.getCodeValue() : reportExcelDto.getExportType()); + //设置导出的文件名 + exportOperation.setFileTitle(result.getReportName()); + //设置导出的文件存放目录 + exportOperation.setFilePath(dictPath); + //设置导出的数据jsonStr + exportOperation.setJsonStr(result.getJsonStr()); + //保存当前操作人 + exportOperation.setCreaterUsername(UserContentHolder.getContext().getUsername()); + //调用盖亚组件实现导出文件 + threadPoolExportExecutor.execute(() -> { + ExportUtil.getInstance().exportByFilePathSimple(exportOperation, null); + }); + return true; + } + +} diff --git a/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/reportexcel/util/ReportUtil.java b/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/reportexcel/util/ReportUtil.java new file mode 100644 index 00000000..f0d58b4c --- /dev/null +++ b/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/data/reportexcel/util/ReportUtil.java @@ -0,0 +1,1109 @@ +package com.anjiplus.template.gaea.business.modules.data.reportexcel.util; + +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONArray; +import com.alibaba.fastjson.JSONObject; +import com.alibaba.fastjson.parser.Feature; +import com.anji.plus.gaea.export.utils.QrCodeOrBarCodeUtil; +import com.anjiplus.template.gaea.business.modules.data.dataSet.controller.dto.DataSetDto; +import com.anjiplus.template.gaea.business.modules.data.dataSet.controller.dto.OriginalDataDto; +import com.anjiplus.template.gaea.business.modules.data.dataSet.service.DataSetService; +import com.anjiplus.template.gaea.business.modules.data.report.constant.ExpConstant; +import com.anjiplus.template.gaea.business.modules.data.reportexcel.controller.dto.ReportExcelDto; +import freemarker.template.Configuration; +import freemarker.template.Template; +import org.apache.commons.lang3.StringUtils; +import org.apache.poi.ddf.EscherClientAnchorRecord; +import org.apache.poi.hssf.usermodel.HSSFDataFormat; +import org.apache.poi.ss.usermodel.BorderStyle; +import org.apache.poi.ss.usermodel.Cell; +import org.apache.poi.ss.usermodel.CellType; +import org.apache.poi.ss.usermodel.ClientAnchor; +import org.apache.poi.ss.usermodel.CreationHelper; +import org.apache.poi.ss.usermodel.DataFormat; +import org.apache.poi.ss.usermodel.FillPatternType; +import org.apache.poi.ss.usermodel.HorizontalAlignment; +import org.apache.poi.ss.usermodel.Picture; +import org.apache.poi.ss.usermodel.Row; +import org.apache.poi.ss.usermodel.VerticalAlignment; +import org.apache.poi.ss.usermodel.Workbook; +import org.apache.poi.ss.util.CellRangeAddress; +import org.apache.poi.ss.util.RegionUtil; +import org.apache.poi.xssf.usermodel.XSSFCellStyle; +import org.apache.poi.xssf.usermodel.XSSFColor; +import org.apache.poi.xssf.usermodel.XSSFDataFormat; +import org.apache.poi.xssf.usermodel.XSSFDrawing; +import org.apache.poi.xssf.usermodel.XSSFFont; +import org.apache.poi.xssf.usermodel.XSSFRow; +import org.apache.poi.xssf.usermodel.XSSFSheet; +import org.apache.poi.xssf.usermodel.XSSFWorkbook; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; +import org.springframework.util.CollectionUtils; + +import java.io.ByteArrayOutputStream; +import java.io.FileOutputStream; +import java.io.StringReader; +import java.io.StringWriter; +import java.math.BigDecimal; +import java.text.SimpleDateFormat; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Date; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.OptionalDouble; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +/** + * TODO + * + * @author chenkening + * @date 2021/3/26 10:30 + */ +@Component +public class ReportUtil { + + /** + * 记录日志 + */ + protected static Logger logger = LoggerFactory.getLogger(ReportUtil.class); + + @Autowired + private DataSetService dataSetService; + + + public JSONObject reportParse(ReportExcelDto reportExcelDto) { + + // 取第一个sheet + JSONObject jsonObject = JSONObject.parseObject(reportExcelDto.getJsonStr(), Feature.OrderedField).getJSONArray("sheet").getJSONObject(0); +// JSONObject jsonObject = JSONObject.parseObject(reportExcelDto.getJsonStr()); + + logger.info("excelJSON信息:{}\n", jsonObject); + JSONObject rowsJsonObject = jsonObject.getJSONObject("rows"); + // 所有的样式数组。 + JSONArray styles = jsonObject.getJSONArray("styles"); +// System.out.println(styles); + logger.info("需要解析的JSON {}", rowsJsonObject); + + //用于存储语法解析后的json + JSONObject syntaxJsonObject = new JSONObject(true); + + Map dataSetMap = new HashMap<>(); + + Map> map = new HashMap<>(); + rowsJsonObject.remove("len"); + for (String s : rowsJsonObject.keySet()) { + List list = Collections.singletonList(rowsJsonObject.getJSONObject(s)); + map.put(Integer.parseInt(s), list); + } + + // 解决rows 行乱序 + syntaxParse(map, syntaxJsonObject, reportExcelDto.getSetCodes(), reportExcelDto.getSetParam(), dataSetMap); + JSONObject jsonMap = new JSONObject(true); + + JSONObject jsonObject1 = JSONObject.parseObject(JSON.toJSONString(syntaxJsonObject), Feature.OrderedField); + jsonObject1.put("len", jsonObject1.size() + 30); + jsonObject.put("rows", jsonObject1); + jsonObject.put("name", reportExcelDto.getReportName()); + return jsonObject; + } + + /** + * 包含动态表达式的行解析 + * + * @param mapss rows + * @param syntaxJsonObject 存储解析后的json + * @param dbCode 编码 + * @param setParam 查询条件数据集 + * @param dataSetMap 数据集 + */ + public void syntaxParse(Map> mapss, JSONObject syntaxJsonObject, String dbCode, String setParam, Map dataSetMap) { + + String[] split = dbCode.split("\\|"); + // 解析过几次表达式列。 + int count = 1; + for (Map.Entry> integerListEntry : mapss.entrySet()) { + List listobj = Stream.of(integerListEntry.getValue()).collect(Collectors.toList()); + JSONArray jsonObject1 = JSONArray.parseArray(listobj.toString()); + JSONArray jsonArray = (JSONArray) jsonObject1.get(0); + // cells json + JSONObject jsonObject2 = JSONObject.parseObject(jsonArray.get(0).toString()); + for (Map.Entry stringObjectEntry2 : jsonObject2.entrySet()) { + if (stringObjectEntry2.getKey() == "cells") { + JSONObject cell = (JSONObject) stringObjectEntry2.getValue(); + if (jsonObject2.toString().contains("#{")) { + + for (int i = 0; i < split.length; i++) { + JSONObject setParamJson = JSONObject.parseObject(setParam); + + String code = split[i]; + + String newCode = String.format("#{%s", code); + // 如果表达式包含具体code编码,进。否则不做处理 + if (jsonObject2.toString().contains(newCode) && StringUtils.isNotBlank(code)) { + DataSetDto dto = new DataSetDto(); + dto.setSetCode(code); + Map map = new HashMap<>(); + // 查询条件 + if (setParamJson.containsKey(code)) { + JSONObject paramCondition = setParamJson.getJSONObject(code); + paramCondition.entrySet().forEach(item -> map.put(item.getKey(), item.getValue())); + } + + dto.setContextData(map); + OriginalDataDto originalDataDto = dataSetService.getData(dto); + dataSetMap.clear(); + List list = (List) JSONObject.toJSON(originalDataDto.getData()); + dataSetMap.put("list", list); + boolean flag = true; + //仅拿到为cells的json ,目前推拽有问题,会存在 列为-1 ,排除掉不解析 + for (Map.Entry objectEntry : cell.entrySet()) { + JSONObject object = (JSONObject) objectEntry.getValue(); + for (Map.Entry stringObjectEntry : object.entrySet()) { + if (stringObjectEntry.getKey().equals("-1")) { + flag = false; + } + } + } + if (flag) { + if (syntaxJsonObject.size() == 0) { + StringBuffer sb = new StringBuffer(); + String str = jsonObject2.toString().replaceAll("#\\{", "\\${"); + sb.append(String.format("{<#list list as %s> ", code)); + sb.append(String.format("\"${%s_index+%s}\":%s,", code, integerListEntry.getKey(), str)); + sb.append(""); + sb.append("}"); + logger.info("替换后的str: {}", sb); + String parseJsonStr = parseTemplate(sb.toString(), dataSetMap); + if (parseJsonStr.equals("{}")) { + syntaxJsonObject.putAll(isNullParseJson(jsonObject2, newCode, syntaxJsonObject.size(), integerListEntry.getKey(), 0)); + } else { + syntaxJsonObject.putAll(JSONObject.parseObject(parseJsonStr, Feature.OrderedField)); + } + } else { + StringBuffer sb = new StringBuffer(); + String str = jsonObject2.toString().replaceAll("#\\{", "\\${").replaceAll("\\\\n", ""); + sb.append(String.format("{<#list list as %s> ", code)); + sb.append(String.format("\"${%s_index+%s}\":%s,", code, syntaxJsonObject.size() + integerListEntry.getKey() - count, str)); + sb.append(""); + sb.append("}"); + logger.info("替换后的str: {}", sb); + String parseJsonStr = parseTemplate(sb.toString(), dataSetMap); + syntaxJsonObject.putAll(JSONObject.parseObject(parseJsonStr, Feature.OrderedField)); + // 如果查出来没有数据,会被替换为 {} ,不能put到 syntaxJsonObject,就会少一行,不操作count + if (parseJsonStr.equals("{}")) { + syntaxJsonObject.putAll(isNullParseJson(jsonObject2, newCode, syntaxJsonObject.size(), integerListEntry.getKey(), count)); + } else { + syntaxJsonObject.putAll(JSONObject.parseObject(parseJsonStr, Feature.OrderedField)); + } + count++; + } + } + } + } + // 存在 函数表达式 + } else if (!CollectionUtils.isEmpty(ExpConstant.getExpFunction(jsonObject2.toString()))) { + // 函数下标集合 + List indexs = ExpConstant.getExpFunction(jsonObject2.toString()); + for (Integer index : indexs) { + // 函数值 + String exp = ExpConstant.FUNCTION[index]; + + List bigDecimalList = new ArrayList<>(); + for (Map.Entry entryHanShu : jsonObject2.entrySet()) { + JSONObject jb3 = (JSONObject) entryHanShu.getValue(); + for (Map.Entry entry4 : jb3.entrySet()) { + // 得到最下面的 {"style":1,"text":"=SUM(A3)"} + JSONObject cellJson = (JSONObject) entry4.getValue(); + if (cellJson.containsKey("text")) { + if (StringUtils.isNotBlank(cellJson.get("text").toString()) && cellJson.get("text").toString().contains(exp)) { + for (Map.Entry rowsJson : syntaxJsonObject.entrySet()) { + // 拿到一行 中的cells + JSONObject rowsJsonToCells = (JSONObject) JSONObject.parseObject(rowsJson.getValue().toString()).get("cells"); + if (rowsJsonToCells.containsKey(entry4.getKey())) { + JSONObject textJson = (JSONObject) rowsJsonToCells.get(entry4.getKey()); + if (textJson.containsKey("text")) { + // 列值。 + String value = textJson.get("text").toString(); + try { + bigDecimalList.add(new BigDecimal(value)); + } catch (Exception exception) { + logger.info("函数计算错误,错误列{}、值{}", entry4, value); + } + } + } + } + if (!CollectionUtils.isEmpty(bigDecimalList)) { + switch (exp) { + case "=MIN(": + Optional min = bigDecimalList.stream().min((o1, o2) -> o1.compareTo(o2)); + cellJson.replace("text", cellJson.get("text"), min.get() + ""); + break; + case "=MAX(": + Optional max = bigDecimalList.stream().max((o1, o2) -> o1.compareTo(o2)); + cellJson.replace("text", cellJson.get("text"), max.get() + ""); + break; + case "=SUM(": + BigDecimal sums = bigDecimalList.stream().reduce(BigDecimal.ZERO, BigDecimal::add); + cellJson.replace("text", cellJson.get("text"), sums + ""); + break; + case "=AVERAGE(": + OptionalDouble average = bigDecimalList.stream().mapToDouble(BigDecimal::doubleValue).average(); + cellJson.replace("text", cellJson.get("text"), average.getAsDouble() + ""); + break; + default: + break; + } + } else { + cellJson.replace("text", cellJson.get("text"), ""); + } + } + } + } + } + + } + if (syntaxJsonObject.size() == 0) { + syntaxJsonObject.put(integerListEntry.getKey() + "", jsonObject2); + } else { + syntaxJsonObject.put(syntaxJsonObject.size() + integerListEntry.getKey() - count + "", jsonObject2); + count++; + } + } else { + + if (count == 1 && syntaxJsonObject.size() == 0) { + syntaxJsonObject.put(integerListEntry.getKey() + "", jsonObject2); + } else { + syntaxJsonObject.put(syntaxJsonObject.size() + integerListEntry.getKey() - count + "", jsonObject2); + count++; + } + } + } + } + } + + } + + /** + * 解析的表达式未null 即 {} + * + * @param jsonObject 本行json + * @param newCode 表达式编码 + * @param syntax 存储解析后的json大小 + * @param entryNum 本次循环的num + * @param count + * @return + */ + public static JSONObject isNullParseJson(JSONObject jsonObject, String newCode, Integer syntax, Integer entryNum, int count) { + JSONObject cellsJson = jsonObject.getJSONObject("cells"); + for (Map.Entry entry : cellsJson.entrySet()) { + JSONObject elementJson = JSONObject.parseObject(entry.getValue().toString()); + if (elementJson.containsKey("text")) { + String text = (String) elementJson.get("text"); + if (text.contains(newCode)) { + elementJson.put("text", ""); + } + } + cellsJson.put(entry.getKey(), elementJson); + } + jsonObject.put("cells", cellsJson); + JSONObject newJson = new JSONObject(); + newJson.put(String.valueOf((syntax + entryNum - count)), jsonObject); + return newJson; + } + + /** + * 报表格式化解析 + * + * @param templateValue + * @param maps + * @return + */ + private static String parseTemplate(String templateValue, Map maps) { + try { + Configuration configuration = new Configuration(); + configuration.setNumberFormat("#.#########"); + configuration.setClassicCompatible(true); + StringWriter writer = new StringWriter(); + Template template = new Template("template", new StringReader(templateValue), configuration); + template.process(maps, writer); + return writer.toString(); + + } catch (Exception e) { + e.printStackTrace(); + } + return null; + } + + public static void main(String[] args) { + String str = "{\"sheet\":[{\"name\":\"sheet2\",\"freeze\":\"A1\",\"styles\":[{\"valign\":\"top\"}],\"merges\":[],\"rows\":{\"0\":{\"cells\":{\"0\":{\"text\":{\"type\":\"QRCode\",\"content\":\"http://gaea.anji-plus.com\",\"width\":125,\"height\":125,\"ri\":0,\"ci\":0},\"style\":0}},\"height\":163},\"len\":100},\"cols\":{\"len\":20},\"validations\":[],\"autofilter\":{}}]}"; + + // 取第一个sheet + JSONObject jsonObject = JSONObject.parseObject(str); +// XSSFWorkbook workbook = new XSSFWorkbook(); +// XSSFSheet sheet = workbook.createSheet(); + try { + exportExcel(jsonObject); +// makePhoto(jsonArray , workbook , sheet); +// workbook.write(new FileOutputStream("E:\\excel\\e\\dsad.xlsx")); + } catch (Exception e) { + e.printStackTrace(); + } + + + } + + public static Map exportExcel(JSONObject a) { +// JSONObject jsonObject = JSONObject.parseObject(result.getJsonStr()); + JSONObject jsonObject = a.getJSONArray("sheet").getJSONObject(0); + JSONObject rows = jsonObject.getJSONObject("rows"); + JSONObject cols = jsonObject.getJSONObject("cols"); + if (cols.containsKey("len")) { + cols.remove("len"); + } + EscherClientAnchorRecord escherClientAnchorRecord; + + if (rows.containsKey("-1")) { + rows.remove("-1"); + } +// JSONArray photos = jsonObject.getJSONArray("QRCodeOrBarCode"); + // 所有的样式数组。 + JSONArray styles = jsonObject.getJSONArray("styles"); + +// 1.创建一个工作簿 + XSSFWorkbook workbook = new XSSFWorkbook(); + + +// 2.创建一个工作表 + XSSFSheet sheet = workbook.createSheet("news"); + try { + sheet.autoSizeColumn(1, true); + // 设置默认列宽 + sheet.setDefaultColumnWidth(12); + sheet.setDefaultRowHeight((short) 360); + Iterator colsIte = cols.keySet().iterator(); + while (colsIte.hasNext()) { + String next = colsIte.next(); //列 + JSONObject colStyle = cols.getJSONObject(next); + if (colStyle.containsKey("width")) { + // 自定义 width * 32 + sheet.setColumnWidth(Integer.parseInt(next), colStyle.getInteger("width") * 30); + } + } + +// if (photos != null) { +// // make photo +// makePhoto(photos, workbook, sheet); +// } + for (Map.Entry entry : rows.entrySet()) { + if (!entry.getKey().contains("len")) { + + // 创建一行 + Row row = sheet.createRow(Integer.parseInt(entry.getKey())); + JSONObject jsonObject1 = (JSONObject) entry.getValue(); + + //设置行高 + if (jsonObject1.containsKey("height")) { + int height = (int) jsonObject1.get("height"); + row.setHeight((short) (height * 14.7)); + } + // cells 获取到一行 + JSONObject cells = (JSONObject) jsonObject1.get("cells"); + if (cells.containsKey("-1")) { + cells.remove("-1"); + } + + setCellStyle(cells, workbook , sheet , styles, row); + + } + } + + Iterator iterator = rows.keySet().iterator(); + while (iterator.hasNext()) { + String rownum = iterator.next(); //行 + if (rownum.equals("len")) { + continue; + } + JSONObject cells = rows.getJSONObject(rownum).getJSONObject("cells"); + if (cells == null) { + continue; + } else { + Iterator cellsIte = cells.keySet().iterator(); + while (cellsIte.hasNext()) { + String cellnum = cellsIte.next(); //列 + JSONObject cellJSON = cells.getJSONObject(cellnum); + if (cellJSON != null) { + if (cellJSON.containsKey("merge")) { + List list = (List) cellJSON.get("merge"); +// // 起始行, 终止行, 起始列, 终止列 + CellRangeAddress cra = new CellRangeAddress(Integer.parseInt(rownum), Integer.parseInt(rownum) + list.get(0), Integer.parseInt(cellnum), Integer.parseInt(cellnum) + list.get(1)); + sheet.addMergedRegion(cra); + + + if (cellJSON.containsKey("style")) { + int style = (int) cellJSON.get("style"); + JSONObject jsonObject4 = (JSONObject) styles.get(style); + if (jsonObject4.containsKey("border")) { + JSONObject borders = (JSONObject) jsonObject4.get("border"); + + Iterator borderIterator = borders.keySet().iterator(); + while (borderIterator.hasNext()) { + String borderSide = borderIterator.next(); + // 设置单元格的边框 + switch (borderSide) { + case "top": + JSONArray top = borders.getJSONArray("top"); + // 上边框 + RegionUtil.setBorderTop(BorderStyle.valueOf(top.get(0).toString().toUpperCase()).getCode(), cra, sheet); + case "left": + JSONArray left = borders.getJSONArray("left"); + // 左边框 + RegionUtil.setBorderLeft(BorderStyle.valueOf(left.get(0).toString().toUpperCase()).getCode(), cra, sheet); + case "bottom": + JSONArray bottom = borders.getJSONArray("bottom"); + // 下边框 + RegionUtil.setBorderBottom(BorderStyle.valueOf(bottom.get(0).toString().toUpperCase()).getCode(), cra, sheet); + case "right": + JSONArray right = borders.getJSONArray("right"); + // 右边框 + RegionUtil.setBorderRight(BorderStyle.valueOf(right.get(0).toString().toUpperCase()).getCode(), cra, sheet); + default: + break; + } + } + } + } + + } + } + + } + } + } + + + + + String fileName = (new SimpleDateFormat("yyyyMMddHHmmss")).format(new Date()); + + FileOutputStream fos = new FileOutputStream("E:\\excel\\e\\" + fileName + ".xlsx"); + workbook.write(fos); + } catch (Exception e) { + e.printStackTrace(); + } + return null; + } + + public static Map exportExcel(ReportExcelDto result) { + // 取第一个sheet +// JSONObject jsonObject = JSONObject.parseObject(result.getJsonStr(), Feature.OrderedField).getJSONArray("sheet").getJSONObject(0); + JSONObject jsonObject = JSONObject.parseObject(result.getJsonStr()); +// jsonObject.put("QRCodeOrBarCode", "[\n" + +// " {\n" + +// " \"type\": \"QRCode\",\n" + +// " \"content\": \"https://gaea.anji-plus.com\",\n" + +// " \"height\": \"128\",\n" + +// " \"width\": \"128\",\n" + +// " \"backgroundColor\": \"#FFFFFF\",\n" + +// " \"foregroundColor\": \"#000000\",\n" + +// " \"ri\": 1,\n" + +// " \"ci\": \"1\"\n" + +// " },\n" + +// " {\n" + +// " \"type\": \"BarCode\",\n" + +// " \"content\": \"6926557300360\",\n" + +// " \"height\": \"50\",\n" + +// " \"width\": \"450\",\n" + +// " \"backgroundColor\": \"#FFFFFF\",\n" + +// " \"foregroundColor\": \"#000000\",\n" + +// " \"ri\": 1,\n" + +// " \"ci\": \"1\"\n" + +// " }\n" + +// " ]"); + JSONObject rows = (JSONObject) jsonObject.get("rows"); + JSONObject cols = (JSONObject) jsonObject.get("cols"); + if (cols.containsKey("len")) { + cols.remove("len"); + } + if (rows.containsKey("-1")) { + rows.remove("-1"); + } + JSONArray photos = jsonObject.getJSONArray("QRCodeOrBarCode"); + // 所有的样式数组。 + JSONArray styles = jsonObject.getJSONArray("styles"); + +// 1.创建一个工作簿 + XSSFWorkbook workbook = new XSSFWorkbook(); + + +// 2.创建一个工作表 + XSSFSheet sheet = workbook.createSheet(result.getReportName()); + try { + sheet.autoSizeColumn(1, true); + // 设置默认列宽 + sheet.setDefaultColumnWidth(12); + Iterator colsIte = cols.keySet().iterator(); + while (colsIte.hasNext()) { + String next = colsIte.next(); //列 + JSONObject colStyle = cols.getJSONObject(next); + if (colStyle.containsKey("width")) { + // 自定义 width * 32 + sheet.setColumnWidth(Integer.parseInt(next), colStyle.getInteger("width") * 32); + } + } + for (Map.Entry entry : rows.entrySet()) { + if (!entry.getKey().contains("len")) { + + // 创建一行 + Row row = sheet.createRow(Integer.parseInt(entry.getKey())); + JSONObject jsonObject1 = (JSONObject) entry.getValue(); + + //设置行高 + if (jsonObject1.containsKey("height")) { + int height = (int) jsonObject1.get("height"); + row.setHeight((short) (height * 14.7)); + } else { + row.setHeight((short) 360); + } + // cells 获取到一行 + JSONObject cells = (JSONObject) jsonObject1.get("cells"); + if (cells.containsKey("-1")) { + cells.remove("-1"); + } + + setCellStyle(cells, workbook, sheet , styles, row); + + } + } + + Iterator iterator = rows.keySet().iterator(); + while (iterator.hasNext()) { + String rownum = iterator.next(); //行 + if (rownum.equals("len")) { + continue; + } + JSONObject cells = rows.getJSONObject(rownum).getJSONObject("cells"); + if (cells == null) { + continue; + } else { + Iterator cellsIte = cells.keySet().iterator(); + while (cellsIte.hasNext()) { + String cellnum = cellsIte.next(); //列 + JSONObject cellJSON = cells.getJSONObject(cellnum); + if (cellJSON != null) { + if (cellJSON.containsKey("merge")) { + List list = (List) cellJSON.get("merge"); +// // 起始行, 终止行, 起始列, 终止列 + CellRangeAddress cra = new CellRangeAddress(Integer.parseInt(rownum), Integer.parseInt(rownum) + list.get(0), Integer.parseInt(cellnum), Integer.parseInt(cellnum) + list.get(1)); + sheet.addMergedRegion(cra); + + + if (cellJSON.containsKey("style")) { + int style = (int) cellJSON.get("style"); + JSONObject jsonObject4 = (JSONObject) styles.get(style); + if (jsonObject4.containsKey("border")) { + JSONObject borders = (JSONObject) jsonObject4.get("border"); + + Iterator borderIterator = borders.keySet().iterator(); + while (borderIterator.hasNext()) { + String borderSide = borderIterator.next(); + // 设置单元格的边框 + switch (borderSide) { + case "top": + JSONArray top = borders.getJSONArray("top"); + // 上边框 + RegionUtil.setBorderTop(BorderStyle.valueOf(top.get(0).toString().toUpperCase()).getCode(), cra, sheet); + case "left": + JSONArray left = borders.getJSONArray("left"); + // 左边框 + RegionUtil.setBorderLeft(BorderStyle.valueOf(left.get(0).toString().toUpperCase()).getCode(), cra, sheet); + case "bottom": + JSONArray bottom = borders.getJSONArray("bottom"); + // 下边框 + RegionUtil.setBorderBottom(BorderStyle.valueOf(bottom.get(0).toString().toUpperCase()).getCode(), cra, sheet); + case "right": + JSONArray right = borders.getJSONArray("right"); + // 右边框 + RegionUtil.setBorderRight(BorderStyle.valueOf(right.get(0).toString().toUpperCase()).getCode(), cra, sheet); + default: + break; + } + } + } + } + + } + } + + } + } + } + Map map = new HashMap<>(); + if (photos != null) { + // make photo + makePhoto(photos, workbook, sheet); + } + String fileName = result.getReportName() + (new SimpleDateFormat("yyyyMMddHHmmss")).format(new Date()); + + FileOutputStream fos = new FileOutputStream("E:\\excel\\e\\" + fileName + ".xlsx"); + workbook.write(fos); + } catch (Exception e) { + e.printStackTrace(); + } + return null; + } + + /** + * @param cells 当前行每一列 + * @param workbook + * @param styles 样式 + * @param row 当前行 + */ + private static void setCellStyle(JSONObject cells, XSSFWorkbook workbook, XSSFSheet sheet ,JSONArray styles, Row row) { + + for (Map.Entry entry2 : cells.entrySet()) { + + XSSFCellStyle cellStyle = workbook.createCellStyle(); + DataFormat df = workbook.createDataFormat(); + + JSONObject jsonObject3 = (JSONObject) entry2.getValue(); + // 创建一列 + Cell cell = row.createCell(Integer.parseInt(entry2.getKey())); + Object text = jsonObject3.get("text"); + String cellValue = null; + if(text instanceof JSONObject){ + JSONObject jsonObject = (JSONObject) text; + JSONArray jsonArray = new JSONArray(); + jsonArray.add(jsonObject); + try { + makePhoto(jsonArray , workbook , sheet ); + } catch (Exception e) { + logger.info("makePhoto error" , e); + } + } else if(text instanceof String){ + cell = (Cell) text; + // 创建第 某行 第几个单元格 + if (StringUtils.isNotBlank(cellValue)) { + cell.setCellValue(cellValue); + if (!CollectionUtils.isEmpty(ExpConstant.getExpFunction(cellValue))) { + cell.setCellFormula(cellValue.substring(1)); + cellStyle.setDataFormat(HSSFDataFormat.getBuiltinFormat("0.00")); + cell.setCellType(CellType.FORMULA); + } + } + } + + + if (StringUtils.isNotBlank(jsonObject3.getString("style"))) { + // 样式 id + int style = (int) jsonObject3.get("style"); + JSONObject jsonObject4 = (JSONObject) styles.get(style); + + if (!jsonObject4.containsKey("valign")) { + cellStyle.setVerticalAlignment(VerticalAlignment.valueOf("CENTER")); + } else { + String str1 = jsonObject4.getString("valign").toUpperCase(); + if ("MIDDLE".equals(str1)) { + str1 = "CENTER"; + } + cellStyle.setVerticalAlignment(VerticalAlignment.valueOf(str1)); + } + // 设置局中 + if (jsonObject4.containsKey("align")) { + String align = (String) jsonObject4.get("align"); + cellStyle.setAlignment(HorizontalAlignment.valueOf(align.toUpperCase())); + + } + + //------------------------bgColor + if (jsonObject4.containsKey("bgcolor")) { + + String str1 = jsonObject4.getString("bgcolor"); + XSSFColor xSSFColor = new XSSFColor(); + if (str1.indexOf("#") != -1) { + byte[] arrayOfByte = {(byte) Integer.parseInt(str1.substring(1, 3), 16), (byte) Integer.parseInt(str1.substring(3, 5), 16), (byte) Integer.parseInt(str1.substring(5, 7), 16)}; + xSSFColor.setRGB(arrayOfByte); + } + cellStyle.setFillForegroundColor(xSSFColor); + cellStyle.setFillBackgroundColor(xSSFColor); + cellStyle.setFillPattern(FillPatternType.BIG_SPOTS); + } + + + if (jsonObject4.containsKey("format")) { + String format = (String) jsonObject4.get("format"); + if(text instanceof String){ + switch (format) { + case "formula": + // 函数 + cell.setCellType(CellType.FORMULA); + break; + case "rmb": + //货币 + if (StringUtils.isNotBlank(cellValue)) { + try { + + cell.setCellValue(Integer.parseInt(cellValue)); + XSSFDataFormat xssfDataFormat = workbook.createDataFormat(); + cellStyle.setDataFormat(xssfDataFormat.getFormat("¥#,##0_);\\[Red](¥#,##0)")); + cell.setCellStyle(cellStyle); + } catch (Exception e) { + } + } + break; + case "number": + // 数值 + if (StringUtils.isNotBlank(cellValue)) { + + try { + cell.setCellValue(Integer.parseInt(cellValue)); + cellStyle.setDataFormat(HSSFDataFormat.getBuiltinFormat("0.00")); + cell.setCellStyle(cellStyle); + + } catch (Exception e) { + } + } + break; + case "date": + + break; + case "date2": + + break; + case "time": + + break; + case "datetime": + + break; + case "percent": + //百分比 + if (StringUtils.isNotBlank(cellValue)) { + + try { + cell.setCellValue(Integer.parseInt(cellValue) / 100); + cellStyle.setDataFormat(HSSFDataFormat.getBuiltinFormat("0.00%")); + cell.setCellStyle(cellStyle); + + } catch (Exception e) { + } + } + break; + case "eur": + //欧元 + if (StringUtils.isNotBlank(cellValue)) { +// + try { + + cell.setCellValue(Integer.parseInt(cellValue)); + XSSFDataFormat xssfDataFormat = workbook.createDataFormat(); + cellStyle.setDataFormat(xssfDataFormat.getFormat("€#,##0_);\\[Red](¥#,##0)")); + cell.setCellStyle(cellStyle); + + } catch (Exception e) { + } + } + break; + case "usd": + //美元 + if (StringUtils.isNotBlank(cellValue)) { +// + try { + cell.setCellValue(Integer.parseInt(cellValue)); + XSSFDataFormat xssfDataFormat = workbook.createDataFormat(); + cellStyle.setDataFormat(xssfDataFormat.getFormat("$#,##0_);\\[Red](¥#,##0)")); + cell.setCellStyle(cellStyle); + + } catch (Exception e) { + } + } + break; + default: + cell.setCellType(CellType.STRING); + + } + } + } +// ------------------------------border-------------------------- + if (jsonObject4.containsKey("border")) { + JSONObject borders = (JSONObject) jsonObject4.get("border"); + + Iterator borderIterator = borders.keySet().iterator(); + while (borderIterator.hasNext()) { + String borderSide = borderIterator.next(); + // 设置单元格的边框 + switch (borderSide) { + case "top": + JSONArray top = borders.getJSONArray("top"); + tracingBorder(BorderStyle.valueOf(top.get(0).toString().toUpperCase()).getCode(), "top", cellStyle); + case "left": + JSONArray left = borders.getJSONArray("left"); + tracingBorder(BorderStyle.valueOf(left.get(0).toString().toUpperCase()).getCode(), "left", cellStyle); + case "bottom": + JSONArray bottom = borders.getJSONArray("bottom"); + tracingBorder(BorderStyle.valueOf(bottom.get(0).toString().toUpperCase()).getCode(), "bottom", cellStyle); + case "right": + JSONArray right = borders.getJSONArray("right"); + tracingBorder(BorderStyle.valueOf(right.get(0).toString().toUpperCase()).getCode(), "right", cellStyle); + } + } + } + + if (jsonObject4.containsKey("font") || jsonObject4.containsKey("underline") || jsonObject4.containsKey("strike") || jsonObject4.containsKey("color")) { + XSSFFont xSSFFont = workbook.createFont(); + + //------------------------------font-------------------------- + JSONObject fontObj = (JSONObject) jsonObject4.get("font"); + Object object1 = jsonObject4.get("underline"); + Object object2 = jsonObject4.get("strike"); + if (null != fontObj) { + if (fontObj.containsKey("name")) { + xSSFFont.setFontName(fontObj.getString("name")); + } + if (fontObj.containsKey("italic")) { + xSSFFont.setItalic(true); + } + if (fontObj.containsKey("size")) { + xSSFFont.setFontHeightInPoints(fontObj.getShort("size").shortValue()); + } + if (fontObj.containsKey("bold")) { + boolean bool = fontObj.getBoolean("bold").booleanValue(); + xSSFFont.setBold(bool); + } + } + + if (null != object1) { + xSSFFont.setUnderline((byte) 1); + } + if (null != object2) { + xSSFFont.setStrikeout(true); + } + + //------------------------------color-------------------------- + if (jsonObject4.containsKey("color")) { + String colorStr = jsonObject4.getString("color"); + XSSFColor xssfColor = new XSSFColor(); + + if (colorStr.length() > 6) { + if (colorStr.contains("rgb")) { + colorStr = colorStr.replace("rgb", "").replace("(", "").replace(")", ""); + String[] arrayOfString = colorStr.split(","); + if (arrayOfString.length == 3) { + byte[] arrayOfByte = {(byte) Integer.parseInt(arrayOfString[0]), (byte) Integer.parseInt(arrayOfString[1]), (byte) Integer.parseInt(arrayOfString[2])}; + xssfColor.setRGB(arrayOfByte); + } + } else if (colorStr.contains("#")) { + byte[] arrayOfByte = {(byte) Integer.parseInt(colorStr.substring(1, 3), 16), (byte) Integer.parseInt(colorStr.substring(3, 5), 16), (byte) Integer.parseInt(colorStr.substring(5, 7), 16)}; + xssfColor.setRGB(arrayOfByte); + } + } + xSSFFont.setColor(xssfColor); + } + cellStyle.setFont(xSSFFont); + + } + cellStyle.setWrapText(true); + cell.setCellStyle((cellStyle)); + + } + + + } + } + + + /** + * @param borderCode BordetStyle 枚举值 + * @param border top、right、bottom 、left + * @param cellStyle + */ + public static void tracingBorder(int borderCode, String border, XSSFCellStyle cellStyle) { + + switch (borderCode) { + case 0: + switch (border) { + case "top": + cellStyle.setBorderTop(BorderStyle.NONE); + break; + case "left": + cellStyle.setBorderLeft(BorderStyle.NONE); + break; + case "bottom": + cellStyle.setBorderBottom(BorderStyle.NONE); + break; + case "right": + cellStyle.setBorderRight(BorderStyle.NONE); + break; + default: + break; + } + break; + case 1: + switch (border) { + case "top": + cellStyle.setBorderTop(BorderStyle.THIN); + break; + case "left": + cellStyle.setBorderLeft(BorderStyle.THIN); + break; + case "bottom": + cellStyle.setBorderBottom(BorderStyle.THIN); + break; + case "right": + cellStyle.setBorderRight(BorderStyle.THIN); + break; + default: + break; + } + break; + case 2: + switch (border) { + case "top": + cellStyle.setBorderTop(BorderStyle.MEDIUM); + break; + case "left": + cellStyle.setBorderLeft(BorderStyle.MEDIUM); + break; + case "bottom": + cellStyle.setBorderBottom(BorderStyle.MEDIUM); + break; + case "right": + cellStyle.setBorderRight(BorderStyle.MEDIUM); + break; + default: + break; + } + break; + case 3: + switch (border) { + case "top": + cellStyle.setBorderTop(BorderStyle.DASHED); + break; + case "left": + cellStyle.setBorderLeft(BorderStyle.DASHED); + break; + case "bottom": + cellStyle.setBorderBottom(BorderStyle.DASHED); + break; + case "right": + cellStyle.setBorderRight(BorderStyle.DASHED); + break; + default: + break; + } + break; + case 4: + cellStyle.setBorderBottom(BorderStyle.DOTTED); + break; + case 5: + cellStyle.setBorderBottom(BorderStyle.THICK); + break; + case 6: + cellStyle.setBorderBottom(BorderStyle.DOUBLE); + break; + case 7: + cellStyle.setBorderBottom(BorderStyle.HAIR); + break; + case 8: + cellStyle.setBorderBottom(BorderStyle.MEDIUM_DASHED); + break; + case 9: + cellStyle.setBorderBottom(BorderStyle.DASH_DOT); + break; + case 10: + cellStyle.setBorderBottom(BorderStyle.MEDIUM_DASH_DOT); + break; + case 11: + cellStyle.setBorderBottom(BorderStyle.DASH_DOT_DOT); + break; + case 12: + cellStyle.setBorderBottom(BorderStyle.MEDIUM_DASH_DOT_DOT); + break; + case 13: + cellStyle.setBorderBottom(BorderStyle.SLANTED_DASH_DOT); + break; + default: + break; + } + } + + /** + * 导出excel生成图片 + * @param photos 图片数组 + * @param workbook + * @param sheet + * @throws Exception + */ + public static void makePhoto(JSONArray photos, Workbook workbook, XSSFSheet sheet) throws Exception { + ByteArrayOutputStream byteArrayOut = null; + for (int i = 0; i < photos.size(); i++) { + JSONObject qrCodeJson = (JSONObject) photos.get(i); + + if(qrCodeJson.get("type").toString().equals("QRCode")){ + // 二维码 + byteArrayOut = QrCodeOrBarCodeUtil.encodeQRCode + (qrCodeJson.getString("content"), "", qrCodeJson.getInteger("width"), qrCodeJson.getInteger("height")); + + }else if(qrCodeJson.get("type").toString().equals("BarCode")){ + // 条形码 + byteArrayOut = QrCodeOrBarCodeUtil.encodeBarCode + (qrCodeJson.getString("content"), qrCodeJson.getInteger("width"), qrCodeJson.getInteger("height")); + + } + + XSSFRow row = null; + if(sheet.getRow(qrCodeJson.getInteger("ri")) == null){ + row = sheet.createRow(qrCodeJson.getInteger("ri")); + row.setHeight((short) 360); + } else { + row = sheet.getRow(qrCodeJson.getInteger("ri")); + } + + // 原图片宽高。 + double imageWidth = qrCodeJson.getInteger("width"); + double imageHeight = qrCodeJson.getInteger("height"); + + // 列宽像素 + double cellWidth = sheet.getColumnWidthInPixels(qrCodeJson.getInteger("ci")); + // getHeightInPoints()方法获取的是点(磅),就是excel设置的行高,1英寸有72磅,一般显示屏一英寸是96个像素: 行高像素 + double cellHeight = row.getHeightInPoints() / 72 * 96; + + // 图片宽 / 列宽 + double cellWidthD = imageWidth / cellWidth; + int cellWidthI= (int) cellWidthD; + + // 图片高 / 列高 + double rowHeightD = imageHeight / cellHeight; + int rowHeightDI = (int) rowHeightD; + // 1023、255 为宽高 此从第r行、c列开始 、、、 扩充到 r+rowHeightDI行、c+cellWidthI列 +// XSSFClientAnchor anchor = new XSSFClientAnchor +// (0,0,1025,255, +// qrCodeJson.getInteger("ci"), +// row.getRowNum(), +// qrCodeJson.getInteger("ci")+ (cellWidthI == 0 ? 1 : cellWidthI), +// row.getRowNum() + (rowHeightDI == 0 ? 1 : rowHeightDI)); +// anchor.setAnchorType(ClientAnchor.AnchorType.DONT_MOVE_AND_RESIZE); +// //画图器 一个sheet只能一个 + XSSFDrawing drawing = sheet.createDrawingPatriarch(); +// drawing.createPicture(anchor , workbook.addPicture(byteArrayOut.toByteArray() , XSSFWorkbook.PICTURE_TYPE_PNG)); + + + CreationHelper helper = workbook.getCreationHelper(); + int jdpictureIdx = workbook.addPicture(byteArrayOut.toByteArray(), Workbook.PICTURE_TYPE_JPEG);// 根据需要调整参数,如果是PNG,就改为 Workbook.PICTURE_TYPE_PNG + // 插入图片,如果原图宽度大于最终要求的图片宽度,就按比例缩小,否则展示原图 + ClientAnchor jdanchor = helper.createClientAnchor(); + // 起始画图的行列。 + jdanchor.setCol1(qrCodeJson.getInteger("ci")); + jdanchor.setRow1(row.getRowNum()); + Picture pict = drawing.createPicture(jdanchor, jdpictureIdx); + pict.resize(); + } + } +} diff --git a/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/dict/controller/GaeaDictController.java b/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/dict/controller/GaeaDictController.java new file mode 100644 index 00000000..fdf65ce6 --- /dev/null +++ b/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/dict/controller/GaeaDictController.java @@ -0,0 +1,99 @@ +package com.anjiplus.template.gaea.business.modules.dict.controller; + +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") + public ResponseBean refreshDict(@RequestBody List dictCodes) { + //刷新 + gaeaDictService.refreshCache(dictCodes); + return responseSuccess(); + } + + /** + * 下拉菜单 + * @return + */ + @GetMapping("/select/{dictCode}") + 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); + } +} diff --git a/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/dict/controller/GaeaDictItemController.java b/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/dict/controller/GaeaDictItemController.java new file mode 100644 index 00000000..92a431d3 --- /dev/null +++ b/report-core/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/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/dict/controller/dto/GaeaDictDTO.java b/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/dict/controller/dto/GaeaDictDTO.java new file mode 100644 index 00000000..f26f75eb --- /dev/null +++ b/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/dict/controller/dto/GaeaDictDTO.java @@ -0,0 +1,56 @@ +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 java.io.Serializable; + +/** + * (GaeaDict)实体类 + * + * @author lr + * @since 2021-02-23 10:01:02 + */ +@ApiModel(value = "") +public class GaeaDictDTO extends GaeaBaseDTO implements Serializable { + /** + * 字典名称 + */ + @ApiModelProperty(value = "字典名称") + private String dictName; + /** + * 字典编号 + */ + @ApiModelProperty(value = "字典编号") + private String dictCode; + /** + * 字典描述 + */ + @ApiModelProperty(value = "字典描述") + 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/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/dict/controller/dto/GaeaDictItemDTO.java b/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/dict/controller/dto/GaeaDictItemDTO.java new file mode 100644 index 00000000..3978d8f7 --- /dev/null +++ b/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/dict/controller/dto/GaeaDictItemDTO.java @@ -0,0 +1,119 @@ +package com.anjiplus.template.gaea.business.modules.dict.controller.dto; + +import com.anji.plus.gaea.annotation.Formatter; +import com.anji.plus.gaea.curd.dto.GaeaBaseDTO; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; + +import java.io.Serializable; +/** + * 数据字典项(GaeaDictItem)实体类 + * + * @author lirui + * @since 2021-03-10 13:05:59 + */ +@ApiModel(value = "数据字典项") +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 = "语言标识") + @Formatter(dictCode = "LOCALE", targetField = "localeView") + private String locale; + + private String localeView; + /** + * 描述 + */ + @ApiModelProperty(value = "描述") + private String remark; + /** + * 排序 + */ + @ApiModelProperty(value = "排序") + 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 String getItemExtend() { + return itemExtend; + } + public void setItemExtend(String itemExtend) { + this.itemExtend = itemExtend; + } + + public String getLocaleView() { + return localeView; + } + + public void setLocaleView(String localeView) { + this.localeView = localeView; + } +} diff --git a/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/dict/controller/param/GaeaDictItemParam.java b/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/dict/controller/param/GaeaDictItemParam.java new file mode 100644 index 00000000..1b148e86 --- /dev/null +++ b/report-core/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/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/dict/controller/param/GaeaDictParam.java b/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/dict/controller/param/GaeaDictParam.java new file mode 100644 index 00000000..5e23591c --- /dev/null +++ b/report-core/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/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/dict/dao/GaeaDictItemMapper.java b/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/dict/dao/GaeaDictItemMapper.java new file mode 100644 index 00000000..26451825 --- /dev/null +++ b/report-core/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/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/dict/dao/GaeaDictMapper.java b/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/dict/dao/GaeaDictMapper.java new file mode 100644 index 00000000..cfd7b4a4 --- /dev/null +++ b/report-core/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/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/dict/dao/entity/GaeaDict.java b/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/dict/dao/entity/GaeaDict.java new file mode 100644 index 00000000..6fb79734 --- /dev/null +++ b/report-core/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.common.RespCommonCode; +import com.baomidou.mybatisplus.annotation.TableName; + +import java.io.Serializable; + +/** + * (GaeaDict)实体类 + * + * @author lr + * @since 2021-02-23 10:01:02 + */ +@TableName("gaea_dict") +public class GaeaDict extends GaeaBaseEntity implements Serializable { + /** + * 字典名称 + */ + private String dictName; + /** + * 字典编码 + */ + @Unique(code = RespCommonCode.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/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/dict/dao/entity/GaeaDictItem.java b/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/dict/dao/entity/GaeaDictItem.java new file mode 100644 index 00000000..49bfa5ea --- /dev/null +++ b/report-core/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("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/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/dict/service/GaeaDictItemService.java b/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/dict/service/GaeaDictItemService.java new file mode 100644 index 00000000..46291544 --- /dev/null +++ b/report-core/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/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/dict/service/GaeaDictService.java b/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/dict/service/GaeaDictService.java new file mode 100644 index 00000000..16d74fb7 --- /dev/null +++ b/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/dict/service/GaeaDictService.java @@ -0,0 +1,47 @@ +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; + +/** + * (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); +} diff --git a/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/dict/service/impl/GaeaDictItemServiceImpl.java b/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/dict/service/impl/GaeaDictItemServiceImpl.java new file mode 100644 index 00000000..3e4def12 --- /dev/null +++ b/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/dict/service/impl/GaeaDictItemServiceImpl.java @@ -0,0 +1,97 @@ +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/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/dict/service/impl/GaeaDictServiceImpl.java b/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/dict/service/impl/GaeaDictServiceImpl.java new file mode 100644 index 00000000..640b3b59 --- /dev/null +++ b/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/dict/service/impl/GaeaDictServiceImpl.java @@ -0,0 +1,158 @@ +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(); + 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); + } +} diff --git a/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/export/controller/GaeaExportController.java b/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/export/controller/GaeaExportController.java new file mode 100644 index 00000000..d5206167 --- /dev/null +++ b/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/export/controller/GaeaExportController.java @@ -0,0 +1,74 @@ +package com.anjiplus.template.gaea.business.modules.export.controller; + +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.utils.GaeaBeanUtils; +import com.anjiplus.template.gaea.business.modules.export.controller.dto.GaeaExportDTO; +import com.anjiplus.template.gaea.business.modules.export.controller.param.GaeaExportParam; +import com.anjiplus.template.gaea.business.modules.export.controller.param.GaeaExportQueryParam; +import com.anjiplus.template.gaea.business.modules.export.dao.entity.GaeaExport; +import com.anjiplus.template.gaea.business.modules.export.service.GaeaExportService; +import com.anji.plus.gaea.export.vo.ExportOperation; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import io.swagger.annotations.Api; +import org.springframework.beans.factory.annotation.Autowired; +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 java.util.List; +import java.util.stream.Collectors; + +/** + * 导出中心(GaeaExport)实体类 + * + * @author makejava + * @since 2021-02-07 17:12:31 + */ +@RestController +@RequestMapping("/export") +@Api(value = "/export", tags = "导出中心") +public class GaeaExportController extends GaeaBaseController { + @Autowired + private GaeaExportService gaeaExportService; + + @Override + public GaeaBaseService getService() { + return gaeaExportService; + } + + @Override + public GaeaExport getEntity() { + return new GaeaExport(); + } + + @Override + public GaeaExportDTO getDTO() { + return new GaeaExportDTO(); + } + + @PostMapping("/queryAdvanceExport") + @GaeaAuditLog(pageTitle = "高级查询") + public ResponseBean queryExportInfo(@RequestBody GaeaExportQueryParam param) { + Page exportList=gaeaExportService.getExportListPage(param); + List list = exportList.getRecords().stream() + .map(entity -> GaeaBeanUtils.copyAndFormatter(entity, getDTO())) + .collect(Collectors.toList()); + Page pageDto = new Page<>(); + pageDto.setCurrent(exportList.getCurrent()); + pageDto.setRecords(list); + pageDto.setPages(exportList.getPages()); + pageDto.setTotal(exportList.getTotal()); + pageDto.setSize(exportList.getSize()); + return responseSuccessWithData(pageDto); + } + + @PostMapping("/saveExportLog") + public Boolean export(@RequestBody ExportOperation exportOperation) { + return gaeaExportService.saveExportLog(exportOperation); + } + +} diff --git a/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/export/controller/dto/GaeaExportDTO.java b/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/export/controller/dto/GaeaExportDTO.java new file mode 100644 index 00000000..b608ee91 --- /dev/null +++ b/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/export/controller/dto/GaeaExportDTO.java @@ -0,0 +1,144 @@ +package com.anjiplus.template.gaea.business.modules.export.controller.dto; + +import com.anji.plus.gaea.curd.dto.GaeaBaseDTO; +import com.fasterxml.jackson.annotation.JsonFormat; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; + +import java.time.LocalDateTime; +import java.util.Date; + +/** + * 导出中心(GaeaExport)实体类 + * + * @author makejava + * @since 2021-02-07 17:12:25 + */ +@ApiModel(value = "导出中心") +public class GaeaExportDTO extends GaeaBaseDTO { + /** + * 文件在t_file中的id,前端传它来读流接口显示,http://auth/file/download/fileId + */ + @ApiModelProperty(value = "文件在t_file中的id,前端传它来读流接口显示,http://auth/file/download/fileId") + private String fileId; + /** + * 文件标题,比如:对账单报表6月份报表 + */ + @ApiModelProperty(value = "文件标题,比如:对账单报表6月份报表") + private String fileTitle; + /** + * 导出前,查询的数据开始时间 + */ + @ApiModelProperty(value = "导出前,查询的数据开始时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss",timezone = "GMT+8") + private LocalDateTime resultStartTime; + /** + * 导出前,查询的数据结束时间 + */ + @ApiModelProperty(value = "导出前,查询的数据结束时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss",timezone = "GMT+8") + private LocalDateTime resultEndTime; + /** + * 导出查询结果,数据总条数 + */ + @ApiModelProperty(value = "导出查询结果,数据总条数") + private Long resultSize; + /** + * 文件导出触发时间 + */ + @ApiModelProperty(value = "文件导出触发时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss",timezone = "GMT+8") + private LocalDateTime fileCreateTime; + /** + * 文件生成完成时间 + */ + @ApiModelProperty(value = "文件生成完成时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss",timezone = "GMT+8") + private LocalDateTime fileFinishTime; + /** + * 文件状态,creating生成中,success生成成功,failed生成失败 + */ + @ApiModelProperty(value = "文件状态,creating生成中,success生成成功,failed生成失败") + private String fileStatus; + /** + * 备注 + */ + @ApiModelProperty(value = "备注") + private String remark; + + public String getFileId() { + return fileId; + } + + public void setFileId(String fileId) { + this.fileId = fileId; + } + + public String getFileTitle() { + return fileTitle; + } + + public void setFileTitle(String fileTitle) { + this.fileTitle = fileTitle; + } + + + + public Long getResultSize() { + return resultSize; + } + + public void setResultSize(Long resultSize) { + this.resultSize = resultSize; + } + + public LocalDateTime getResultStartTime() { + return resultStartTime; + } + + public void setResultStartTime(LocalDateTime resultStartTime) { + this.resultStartTime = resultStartTime; + } + + public LocalDateTime getResultEndTime() { + return resultEndTime; + } + + public void setResultEndTime(LocalDateTime resultEndTime) { + this.resultEndTime = resultEndTime; + } + + public LocalDateTime getFileCreateTime() { + return fileCreateTime; + } + + public void setFileCreateTime(LocalDateTime fileCreateTime) { + this.fileCreateTime = fileCreateTime; + } + + public LocalDateTime getFileFinishTime() { + return fileFinishTime; + } + + public void setFileFinishTime(LocalDateTime fileFinishTime) { + this.fileFinishTime = fileFinishTime; + } + + public String getFileStatus() { + return fileStatus; + } + + public void setFileStatus(String fileStatus) { + this.fileStatus = fileStatus; + } + + public String getRemark() { + return remark; + } + + public void setRemark(String remark) { + this.remark = remark; + } + + +} diff --git a/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/export/controller/param/GaeaExportParam.java b/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/export/controller/param/GaeaExportParam.java new file mode 100644 index 00000000..bafb04ec --- /dev/null +++ b/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/export/controller/param/GaeaExportParam.java @@ -0,0 +1,26 @@ +package com.anjiplus.template.gaea.business.modules.export.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.Getter; +import lombok.Setter; + +import java.io.Serializable; + +/** + * 导出中心(GaeaExport)param + * + * @author makejava + * @since 2021-02-07 17:12:26 + */ +@Getter +@Setter +public class GaeaExportParam extends PageParam implements Serializable { + /** + * 文件标题 + */ + @Query(QueryEnum.LIKE) + private String fileTitle; +} diff --git a/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/export/controller/param/GaeaExportQueryParam.java b/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/export/controller/param/GaeaExportQueryParam.java new file mode 100644 index 00000000..dd5eb2ee --- /dev/null +++ b/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/export/controller/param/GaeaExportQueryParam.java @@ -0,0 +1,23 @@ +package com.anjiplus.template.gaea.business.modules.export.controller.param; + +import com.anjiplus.template.gaea.common.dto.BaseQueryBO; +import lombok.Getter; +import lombok.Setter; + +import java.io.Serializable; + +/** + * 功能描述: + * + * @Author: peiyanni + * @Date: 2021/2/20 12:49 + */ +@Setter +@Getter +public class GaeaExportQueryParam extends BaseQueryBO implements Serializable{ + + /** + * 文件标题 + */ + private String fileTitle; +} diff --git a/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/export/dao/GaeaExportMapper.java b/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/export/dao/GaeaExportMapper.java new file mode 100644 index 00000000..df67e390 --- /dev/null +++ b/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/export/dao/GaeaExportMapper.java @@ -0,0 +1,30 @@ +package com.anjiplus.template.gaea.business.modules.export.dao; + +import com.anjiplus.template.gaea.business.modules.export.controller.param.GaeaExportQueryParam; +import com.anjiplus.template.gaea.business.modules.export.dao.entity.GaeaExport; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.core.toolkit.Constants; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.anji.plus.gaea.curd.mapper.GaeaBaseMapper; +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; + +import java.util.List; + +/** + * 导出中心(GaeaExport)Mapper + * + * @author makejava + * @since 2021-02-07 17:12:16 + */ +@Mapper +public interface GaeaExportMapper extends GaeaBaseMapper { + /** + * 导出信息的高级查询 + * @param page + * @param bo + * @param wrapper + * @return + */ + List queryExportInfo(Page page, @Param("bo") GaeaExportQueryParam bo, @Param(Constants.WRAPPER) QueryWrapper wrapper); +} diff --git a/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/export/dao/entity/GaeaExport.java b/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/export/dao/entity/GaeaExport.java new file mode 100644 index 00000000..632153fd --- /dev/null +++ b/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/export/dao/entity/GaeaExport.java @@ -0,0 +1,126 @@ +package com.anjiplus.template.gaea.business.modules.export.dao.entity; + +import com.anji.plus.gaea.annotation.Formatter; +import com.baomidou.mybatisplus.annotation.TableName; +import com.anji.plus.gaea.curd.entity.GaeaBaseEntity; + +import java.io.Serializable; +import java.time.LocalDateTime; + +/** + * 导出中心(GaeaExport)实体类 + * + * @author peiyanni + * @since 2021-02-07 17:12:14 + */ +@TableName("gaea_export") +public class GaeaExport extends GaeaBaseEntity implements Serializable { + /** + * 文件在t_file中的id,前端传它来读流接口显示,http://auth/file/download/fileId + */ + private String fileId; + /** + * 文件标题,比如:对账单报表6月份报表 + */ + private String fileTitle; + /** + * 导出前,查询的数据开始时间 + */ + private LocalDateTime resultStartTime; + /** + * 导出前,查询的数据结束时间 + */ + private LocalDateTime resultEndTime; + /** + * 导出查询结果,数据总条数 + */ + private Long resultSize; + /** 文件导出触发时间 */ + private LocalDateTime fileCreateTime; + + /** 文件生成完成时间 */ + private LocalDateTime fileFinishTime; + /** + * 文件状态,creating生成中,success生成成功,failed生成失败 + */ + @Formatter(dictCode="FILE_STATUS",targetField = "fileStatus") + private String fileStatus; + /** + * 备注 + */ + private String remark; + + public String getFileId() { + return fileId; + } + + public void setFileId(String fileId) { + this.fileId = fileId; + } + + public String getFileTitle() { + return fileTitle; + } + + public void setFileTitle(String fileTitle) { + this.fileTitle = fileTitle; + } + + public LocalDateTime getResultStartTime() { + return resultStartTime; + } + + public LocalDateTime getResultEndTime() { + return resultEndTime; + } + + public LocalDateTime getFileFinishTime() { + return fileFinishTime; + } + + public void setFileFinishTime(LocalDateTime fileFinishTime) { + this.fileFinishTime = fileFinishTime; + } + + public Long getResultSize() { + return resultSize; + } + + public void setResultSize(Long resultSize) { + this.resultSize = resultSize; + } + + public void setResultStartTime(LocalDateTime resultStartTime) { + this.resultStartTime = resultStartTime; + } + + public void setResultEndTime(LocalDateTime resultEndTime) { + this.resultEndTime = resultEndTime; + } + + public LocalDateTime getFileCreateTime() { + return fileCreateTime; + } + + public void setFileCreateTime(LocalDateTime fileCreateTime) { + this.fileCreateTime = fileCreateTime; + } + + public String getFileStatus() { + return fileStatus; + } + + public void setFileStatus(String fileStatus) { + this.fileStatus = fileStatus; + } + + public String getRemark() { + return remark; + } + + public void setRemark(String remark) { + this.remark = remark; + } + + +} diff --git a/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/export/service/GaeaExportService.java b/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/export/service/GaeaExportService.java new file mode 100644 index 00000000..7d02207e --- /dev/null +++ b/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/export/service/GaeaExportService.java @@ -0,0 +1,32 @@ +package com.anjiplus.template.gaea.business.modules.export.service; + +import com.anjiplus.template.gaea.business.modules.export.dao.entity.GaeaExport; +import com.anji.plus.gaea.export.vo.ExportOperation; +import com.anjiplus.template.gaea.business.modules.export.controller.param.GaeaExportParam; +import com.anjiplus.template.gaea.business.modules.export.controller.param.GaeaExportQueryParam; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.anji.plus.gaea.curd.service.GaeaBaseService; + +/** + * 导出中心(GaeaExport)Service + * + * @author peiyanni + * @since 2021-02-07 17:12:22 + */ +public interface GaeaExportService extends GaeaBaseService { + /** + * 导出中心-高级查询 + * 需要 QueryWrapper 类型的动态参数,用来进行获取组装好的QueryWrapper对象 + * @param queryParam + * @return + */ + Page getExportListPage(GaeaExportQueryParam queryParam, QueryWrapper ...qe); + + /** + * 导出操作,保存导出日志信息到表Gaea_export + * @param exportOperation + * @return + */ + Boolean saveExportLog(ExportOperation exportOperation); +} diff --git a/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/export/service/impl/GaeaExportServiceImpl.java b/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/export/service/impl/GaeaExportServiceImpl.java new file mode 100644 index 00000000..e3fb8e92 --- /dev/null +++ b/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/export/service/impl/GaeaExportServiceImpl.java @@ -0,0 +1,73 @@ +package com.anjiplus.template.gaea.business.modules.export.service.impl; + +import com.anjiplus.template.gaea.business.modules.export.dao.GaeaExportMapper; +import com.anjiplus.template.gaea.business.modules.export.dao.entity.GaeaExport; +import com.anjiplus.template.gaea.business.modules.export.service.GaeaExportService; +import com.anjiplus.template.gaea.business.modules.file.dao.GaeaFileMapper; +import com.anjiplus.template.gaea.business.modules.file.entity.GaeaFile; +import com.anji.plus.gaea.export.vo.ExportOperation; +import com.anjiplus.template.gaea.business.modules.export.controller.param.GaeaExportQueryParam; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.anjiplus.template.gaea.common.aop.GaeaQuery; +import com.anji.plus.gaea.curd.mapper.GaeaBaseMapper; +import org.springframework.beans.BeanUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.Date; +import java.util.List; + +/** + * 导出中心(GaeaExport)ServiceImpl + * + * @author makejava + * @since 2021-02-07 17:12:24 + */ +@Service +public class GaeaExportServiceImpl implements GaeaExportService { + @Autowired + private GaeaExportMapper gaeaExportMapper; + @Autowired + private GaeaFileMapper gaeaFileMapper; + + @Override + public GaeaBaseMapper getMapper() { + return gaeaExportMapper; + } + + + @Override + @GaeaQuery + public Page getExportListPage(GaeaExportQueryParam queryParam, QueryWrapper... qe) { + Page page = new Page<>(queryParam.getPageNumber(), queryParam.getPageSize()); + QueryWrapper queryWrapper = (null != qe && qe.length > 0) ? qe[0] : null; + List gaeaExports = gaeaExportMapper.queryExportInfo(page, queryParam, queryWrapper); + page.setRecords(gaeaExports); + return page; + } + + @Override + @Transactional + public Boolean saveExportLog(ExportOperation exportOperation) { + //需要保存两张表数据 gaea_file ,gaea_export数据 + Date nowDate = new Date(); + GaeaFile gaeaFile = new GaeaFile(); + gaeaFile.setFileId(exportOperation.getFileId()); + gaeaFile.setFilePath(exportOperation.getFilePath()); + gaeaFile.setCreateBy(exportOperation.getCreaterUsername()); + gaeaFile.setCreateTime(nowDate); + gaeaFile.setUpdateBy(exportOperation.getCreaterUsername()); + gaeaFile.setUpdateTime(nowDate); + gaeaFileMapper.insert(gaeaFile); + GaeaExport export = new GaeaExport(); + BeanUtils.copyProperties(exportOperation, export); + export.setCreateBy(exportOperation.getCreaterUsername()); + export.setCreateTime(nowDate); + export.setUpdateBy(exportOperation.getCreaterUsername()); + export.setUpdateTime(nowDate); + gaeaExportMapper.insert(export); + return true; + } +} diff --git a/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/file/controller/GaeaFileController.java b/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/file/controller/GaeaFileController.java new file mode 100644 index 00000000..30009f11 --- /dev/null +++ b/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/file/controller/GaeaFileController.java @@ -0,0 +1,71 @@ +package com.anjiplus.template.gaea.business.modules.file.controller; + +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") + 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/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/file/controller/dto/GaeaFileDTO.java b/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/file/controller/dto/GaeaFileDTO.java new file mode 100644 index 00000000..649c7f64 --- /dev/null +++ b/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/file/controller/dto/GaeaFileDTO.java @@ -0,0 +1,67 @@ +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; + +/** + * (GaeaFile)实体类 + * + * @author peiyanni + * @since 2021-02-18 14:48:27 + */ +@ApiModel(value = "") +public class GaeaFileDTO extends GaeaBaseDTO { + + /** + * 文件uuid + */ + private String fileId; + /** + * 文件在linux中的完整目录,比如/app/dist/export/excel/${fileid}.xlsx + */ + @ApiModelProperty(value = "文件在linux中的完整目录,比如/app/dist/export/excel/${fileid}.xlsx") + private String filePath; + /** + * 通过接口的下载完整http路径 + */ + @ApiModelProperty(value = "通过接口的下载完整http路径") + private String urlPath; + /** + * 文件内容说明,比如 对账单(202001~202012) + */ + @ApiModelProperty(value = "文件内容说明,比如 对账单(202001~202012)") + private String fileInstruction; + + public String getFilePath() { + return filePath; + } + + public void setFilePath(String filePath) { + this.filePath = filePath; + } + + public String getUrlPath() { + return urlPath; + } + + public void setUrlPath(String urlPath) { + this.urlPath = urlPath; + } + + public String getFileInstruction() { + return fileInstruction; + } + + public void setFileInstruction(String fileInstruction) { + this.fileInstruction = fileInstruction; + } + + public String getFileId() { + return fileId; + } + + public void setFileId(String fileId) { + this.fileId = fileId; + } +} diff --git a/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/file/controller/param/GaeaFileParam.java b/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/file/controller/param/GaeaFileParam.java new file mode 100644 index 00000000..0aa4040b --- /dev/null +++ b/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/file/controller/param/GaeaFileParam.java @@ -0,0 +1,31 @@ +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 java.io.Serializable; + +/** + * (GaeaFile)param + * + * @author peiyanni + * @since 2021-02-18 14:48:29 + */ +public class GaeaFileParam extends PageParam implements Serializable { + + /** + * 文件在linux中的完整目录,比如/app/dist/export/excel/${fileid}.xlsx + */ + @Query(QueryEnum.LIKE) + private String filePath; + + public String getFilePath() { + return filePath; + } + + public void setFilePath(String filePath) { + this.filePath = filePath; + } +} diff --git a/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/file/dao/GaeaFileMapper.java b/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/file/dao/GaeaFileMapper.java new file mode 100644 index 00000000..dabb1d35 --- /dev/null +++ b/report-core/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/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/file/entity/GaeaFile.java b/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/file/entity/GaeaFile.java new file mode 100644 index 00000000..38852564 --- /dev/null +++ b/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/file/entity/GaeaFile.java @@ -0,0 +1,65 @@ +package com.anjiplus.template.gaea.business.modules.file.entity; + +import com.baomidou.mybatisplus.annotation.TableName; +import com.anji.plus.gaea.curd.entity.GaeaBaseEntity; + +import java.io.Serializable; + +/** + * (GaeaFile)实体类 + * + * @author peiyanni + * @since 2021-02-18 14:48:20 + */ +@TableName("gaea_file") +public class GaeaFile extends GaeaBaseEntity implements Serializable { + + /** + * 文件uuid + */ + private String fileId; + /** + * 文件在linux中的完整目录,比如/app/dist/export/excel/${fileid}.xlsx + */ + private String filePath; + /** + * 通过接口的下载完整http路径 + */ + private String urlPath; + /** + * 文件内容说明,比如 对账单(202001~202012) + */ + private String fileInstruction; + + public String getFilePath() { + return filePath; + } + + public void setFilePath(String filePath) { + this.filePath = filePath; + } + + public String getUrlPath() { + return urlPath; + } + + public void setUrlPath(String urlPath) { + this.urlPath = urlPath; + } + + public String getFileInstruction() { + return fileInstruction; + } + + public void setFileInstruction(String fileInstruction) { + this.fileInstruction = fileInstruction; + } + + public String getFileId() { + return fileId; + } + + public void setFileId(String fileId) { + this.fileId = fileId; + } +} diff --git a/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/file/service/GaeaFileService.java b/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/file/service/GaeaFileService.java new file mode 100644 index 00000000..6c7f0331 --- /dev/null +++ b/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/file/service/GaeaFileService.java @@ -0,0 +1,38 @@ +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; + +/** + * (GaeaFile)Service + * + * @author peiyanni + * @since 2021-02-18 14:48:25 + */ +public interface GaeaFileService extends GaeaBaseService { + + + /** + * 文件上传 + * + * @param file + * @return 文件访问路径 + */ + String upload(MultipartFile file); + + /** + * 根据fileId显示图片或者下载文件 + * + * @param request + * @param response + * @param fileId + * @return + */ + ResponseEntity download(HttpServletRequest request, HttpServletResponse response, String fileId); +} diff --git a/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/file/service/impl/GaeaFileServiceImpl.java b/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/file/service/impl/GaeaFileServiceImpl.java new file mode 100644 index 00000000..259e3a8d --- /dev/null +++ b/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/file/service/impl/GaeaFileServiceImpl.java @@ -0,0 +1,187 @@ +package com.anjiplus.template.gaea.business.modules.file.service.impl; + +import com.anji.plus.gaea.constant.BaseOperationEnum; +import com.anji.plus.gaea.exception.BusinessException; +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.modules.export.dao.GaeaExportMapper; +import com.anjiplus.template.gaea.business.modules.export.dao.entity.GaeaExport; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import com.anjiplus.template.gaea.common.RespCommonCode; +import com.anji.plus.gaea.curd.mapper.GaeaBaseMapper; +import com.anji.plus.gaea.exception.BusinessExceptionBuilder; +import com.anjiplus.template.gaea.common.util.StringPatternUtil; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.io.FileUtils; +import org.apache.commons.lang3.StringUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.http.CacheControl; +import org.springframework.http.MediaType; +import org.springframework.http.ResponseEntity; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.transaction.interceptor.TransactionAspectSupport; +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.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.UUID; +import java.util.stream.Collectors; + +/** + * (GaeaFile)ServiceImpl + * + * @author peiyanni + * @since 2021-02-18 14:48:26 + */ +@Service +@Slf4j +public class GaeaFileServiceImpl implements GaeaFileService { + + @Value("${file.dist-path:''}") + private String dictPath; + + @Value("${file.white-list:''}") + private String whiteList; + + @Value("${file.excelSuffix:''}") + private String excelSuffix; + + @Value("${file.downloadPath:''}") + private String fileDownloadPath; + + @Autowired + private GaeaFileMapper gaeaFileMapper; + @Autowired + private GaeaExportMapper gaeaExportMapper; + + @Override + public GaeaBaseMapper getMapper() { + return gaeaFileMapper; + } + + @Override + @Transactional(rollbackFor = Exception.class) + public String upload(MultipartFile file) { + try { + String fileName = file.getOriginalFilename(); + if (StringUtils.isBlank(fileName)) { + throw BusinessExceptionBuilder.build(RespCommonCode.FILE_EMPTY_FILENAME); + } + String suffixName = fileName.substring(fileName.lastIndexOf(".")); + //白名单校验(不区分大小写) + List list = new ArrayList(Arrays.asList(whiteList.split("\\|"))); + list.addAll(list.stream().map(String::toUpperCase).collect(Collectors.toList())); + if (!list.contains(suffixName)) { + throw BusinessExceptionBuilder.build(RespCommonCode.FILE_SUFFIX_UNSUPPORTED); + } + // 生成文件唯一性标识 + String fileId = UUID.randomUUID().toString(); + String newFileName = fileId + suffixName; + // 本地文件保存路径 + String filePath = dictPath + newFileName; + String urlPath = fileDownloadPath + File.separator + fileId; + + GaeaFile gaeaFile = new GaeaFile(); + gaeaFile.setFilePath(filePath); + gaeaFile.setFileId(fileId); + gaeaFile.setUrlPath(urlPath); + gaeaFileMapper.insert(gaeaFile); + + //写文件 将文件保存/app/dictPath/upload/下 + File dest = new File(dictPath + newFileName); + file.transferTo(dest); + // 将完整的http访问路径返回 + return urlPath; + } catch (Exception e) { + TransactionAspectSupport.currentTransactionStatus().setRollbackOnly(); + log.error("file upload error: {}", e); + throw BusinessExceptionBuilder.build(RespCommonCode.FILE_UPLOAD_ERROR); + } + } + + @Override + public ResponseEntity download(HttpServletRequest request, HttpServletResponse response, String fileId) { + try { + String userAgent = request.getHeader("User-Agent"); + boolean isIEBrowser = userAgent.indexOf("MSIE") > 0; + //根据fileId,从gaea_file中读出filePath + LambdaQueryWrapper queryWrapper = Wrappers.lambdaQuery(); + queryWrapper.eq(GaeaFile::getFileId, fileId); + GaeaFile gaeaFile = gaeaFileMapper.selectOne(queryWrapper); + if (null == gaeaFile) { + throw BusinessExceptionBuilder.build(RespCommonCode.FILE_ONT_EXSIT); + } + //解析文件路径、文件名和后缀 + String filePath = gaeaFile.getFilePath(); + if (StringUtils.isBlank(filePath)) { + throw BusinessExceptionBuilder.build(RespCommonCode.FILE_ONT_EXSIT); + } + String filename = filePath.substring(filePath.lastIndexOf(File.separator)); + String fileSuffix = filename.substring(filename.lastIndexOf(".")); + //特殊处理:如果是excel文件,则从t_export表中查询文件名 + List list = Arrays.asList(excelSuffix.split("\\|")); + if (list.contains(fileSuffix)) { + LambdaQueryWrapper exportWrapper = Wrappers.lambdaQuery(); + exportWrapper.eq(GaeaExport::getFileId, fileId); + GaeaExport exportPO = gaeaExportMapper.selectOne(exportWrapper); + if (null != exportPO) { + filename = exportPO.getFileTitle() + fileSuffix; + } + } + //根据文件后缀来判断,是显示图片\视频\音频,还是下载文件 + File file = new File(filePath); + ResponseEntity.BodyBuilder builder = ResponseEntity.ok(); + builder.contentLength(file.length()); + if (StringPatternUtil.StringMatchIgnoreCase(fileSuffix, "(.png|.jpg|.jpeg|.bmp|.gif|.icon)")) { + builder.cacheControl(CacheControl.noCache()).contentType(MediaType.IMAGE_PNG); + } else if (StringPatternUtil.StringMatchIgnoreCase(fileSuffix, "(.flv|.swf|.mkv|.avi|.rm|.rmvb|.mpeg|.mpg|.ogg|.ogv|.mov|.wmv|.mp4|.webm|.wav|.mid|.mp3|.aac)")) { + builder.header("Content-Type", "video/mp4; charset=UTF-8"); + } else { + //application/octet-stream 二进制数据流(最常见的文件下载) + builder.contentType(MediaType.APPLICATION_OCTET_STREAM); + filename = URLEncoder.encode(filename, "UTF-8"); + if (isIEBrowser) { + builder.header("Content-Disposition", "attachment; filename=" + filename); + } else { + builder.header("Content-Disposition", "attacher; filename*=UTF-8''" + filename); + } + } + return builder.body(FileUtils.readFileToByteArray(file)); + } catch (Exception e) { + log.error("file download error: {}", e); + return null; + } + } + + /** + * 批处理操作后续处理 + * 删除本地已经存在的文件 + * + * @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 -> { + String filePath = gaeaFile.getFilePath(); + File file = new File(filePath); + if (file.exists()) { + file.delete(); + } + }); + } + + } +} diff --git a/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/gaeaUiI18n/controller/GaeaUiI18nController.java b/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/gaeaUiI18n/controller/GaeaUiI18nController.java new file mode 100644 index 00000000..98a8ae72 --- /dev/null +++ b/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/gaeaUiI18n/controller/GaeaUiI18nController.java @@ -0,0 +1,100 @@ + +package com.anjiplus.template.gaea.business.modules.gaeaUiI18n.controller; + +import com.anji.plus.gaea.annotation.AccessKey; +import com.anji.plus.gaea.bean.ResponseBean; +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.base.BaseController; +import com.anjiplus.template.gaea.business.modules.gaeaUiI18n.controller.dto.GaeaUiI18nDto; +import com.anjiplus.template.gaea.business.modules.gaeaUiI18n.controller.param.GaeaUiI18nParam; +import com.anjiplus.template.gaea.business.modules.gaeaUiI18n.dao.entity.GaeaUiI18n; +import com.anjiplus.template.gaea.business.modules.gaeaUiI18n.service.GaeaUiI18nService; + +import io.swagger.annotations.Api; +import org.apache.commons.lang3.StringUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.*; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** +* @desc ui文字国际化处理 controller +* @website https://gitee.com/anji-plus/gaea +* @author 王斌 +* @date 2021-03-25 15:30:59.286 +**/ +@RestController +@Api(tags = "ui文字国际化处理管理") +@RequestMapping("/gaeaUiI18n") +public class GaeaUiI18nController extends BaseController { + + @Autowired + private GaeaUiI18nService gaeaUiI18nService; + + @Override + public GaeaBaseService getService() { + return gaeaUiI18nService; + } + + @Override + public GaeaUiI18n getEntity() { + return new GaeaUiI18n(); + } + + @Override + public GaeaUiI18nDto getDTO() { + return new GaeaUiI18nDto(); + } + + + @GetMapping({"/{id}"}) + @AccessKey + @Override + public ResponseBean detail(@PathVariable("id") Long id) { + this.logger.info("{}根据ID查询服务开始,id为:{}", this.getClass().getSimpleName(), id); + GaeaUiI18n result = gaeaUiI18nService.getDetail(id); + GaeaUiI18nDto 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; + } + + @PostMapping(value = "/scan") + public ResponseBean scan(@RequestParam String table){ + gaeaUiI18nService.scan(table); + return responseSuccess(); + } + + @GetMapping(value = "/getTables") + public ResponseBean getTables(){ + List t = gaeaUiI18nService.getUi18nTables(); + return responseSuccessWithData(t); + } + + @PostMapping(value = "/listI18nFields") + public ResponseBean getI18nFields(@RequestBody GaeaUiI18nDto q){ + GaeaUiI18n qry = new GaeaUiI18n(); + GaeaBeanUtils.copyAndFormatter(q,qry); + // 客户端测试时,以前端参数为准 + if(StringUtils.isEmpty(qry.getLocale())) { + qry.setLocale(getI18nLang()); + } + Map ret = new HashMap(); + for(String table : q.getRefer().split(",")) { + qry.setRefer(table); + Map t = gaeaUiI18nService.getI18nFields(qry); + ret.putIfAbsent(qry.getModule(),new HashMap<>()); + // 合并module子节点 + ((Map)ret.get(qry.getModule())).putAll((Map)t.get(qry.getModule())); + } + + ret.put("locale",q.getLocale()); + return responseSuccessWithData(ret); + } + +} diff --git a/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/gaeaUiI18n/controller/dto/GaeaUiI18nDto.java b/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/gaeaUiI18n/controller/dto/GaeaUiI18nDto.java new file mode 100644 index 00000000..2d5e5dca --- /dev/null +++ b/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/gaeaUiI18n/controller/dto/GaeaUiI18nDto.java @@ -0,0 +1,50 @@ + +package com.anjiplus.template.gaea.business.modules.gaeaUiI18n.controller.dto; + +import java.io.Serializable; + +import com.anji.plus.gaea.curd.dto.GaeaBaseDTO; +import com.anji.plus.gaea.annotation.Formatter; +import lombok.Data; +import java.sql.Timestamp; + + +/** +* +* @description ui文字国际化处理 dto +* @author 王斌 +* @date 2021-03-25 15:30:59.286 +**/ +@Data +public class GaeaUiI18nDto extends GaeaBaseDTO implements Serializable { + /** 语言标识 */ + @Formatter(dictCode = "LOCALE",targetField = "localeCn") + private String locale; + private String localeCn; + + /** 行业标识 */ + @Formatter(dictCode = "SYS_CATA_TYPE",targetField = "cataTypeCn") + private String cataType; + private String cataTypeCn; + + /** 所属系统 */ + private String system; + + /** 所属菜单编号 */ + private String module; + + /** 字段编码 */ + private String code; + + /** 字段名称 */ + private String name; + + /** 业务描述 */ + private String remark; + private String refer; + /** 启用状态 */ + @Formatter(dictCode = "ENABLE_FLAG",targetField = "enabledCn") + private Integer enabled; + private String enabledCn; + +} \ No newline at end of file diff --git a/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/gaeaUiI18n/controller/param/GaeaUiI18nParam.java b/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/gaeaUiI18n/controller/param/GaeaUiI18nParam.java new file mode 100644 index 00000000..f36d5b7b --- /dev/null +++ b/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/gaeaUiI18n/controller/param/GaeaUiI18nParam.java @@ -0,0 +1,54 @@ +/**/ +package com.anjiplus.template.gaea.business.modules.gaeaUiI18n.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 GaeaUiI18n ui文字国际化处理查询输入类 +* @author 王斌 +* @date 2021-03-25 15:30:59.286 +**/ +@Data +public class GaeaUiI18nParam extends PageParam implements Serializable{ + + /** 精确查询 */ + @Query + private String locale; + + /** 精确查询 */ + @Query + private String cataType; + + /** 精确查询 */ + @Query + private String system; + + /** 模糊查询 */ + @Query(value = QueryEnum.LIKE) + private String code; + + /** 模糊查询 */ + @Query(value = QueryEnum.LIKE) + private String name; + + /** 模糊查询 */ + @Query(value = QueryEnum.LIKE) + private String remark; + + @Query(value = QueryEnum.EQ) + private String refer; + + @Query(value = QueryEnum.EQ) + private String module; + + /** 精确查询 */ + @Query + private Integer enabled; +} \ No newline at end of file diff --git a/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/gaeaUiI18n/dao/GaeaUiI18nMapper.java b/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/gaeaUiI18n/dao/GaeaUiI18nMapper.java new file mode 100644 index 00000000..7abfe917 --- /dev/null +++ b/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/gaeaUiI18n/dao/GaeaUiI18nMapper.java @@ -0,0 +1,33 @@ +package com.anjiplus.template.gaea.business.modules.gaeaUiI18n.dao; + +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; + +import java.util.List; + +import com.anji.plus.gaea.curd.mapper.GaeaBaseMapper; +import com.anjiplus.template.gaea.business.modules.gaeaUiI18n.dao.entity.GaeaUiI18n; +import com.anjiplus.template.gaea.business.modules.gaeaUiI18n.service.impl.ColumnDesc; + +/** +* GaeaUiI18n Mapper +* @author 王斌 +* @date 2021-03-25 15:30:59.286 +**/ +@Mapper +public interface GaeaUiI18nMapper extends GaeaBaseMapper { + + /** + * 查询表的定义,字段中文描述等信息 + * @param tableName + * @return + */ + List queryColumns(@Param(value = "tableName") String tableName); + + /** + * 查询项目所有的表名 + * @param s + * @return + */ + List queryTables(@Param(value = "tableName") String s); +} \ No newline at end of file diff --git a/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/gaeaUiI18n/dao/entity/GaeaUiI18n.java b/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/gaeaUiI18n/dao/entity/GaeaUiI18n.java new file mode 100644 index 00000000..6381e5b2 --- /dev/null +++ b/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/gaeaUiI18n/dao/entity/GaeaUiI18n.java @@ -0,0 +1,46 @@ + +package com.anjiplus.template.gaea.business.modules.gaeaUiI18n.dao.entity; + +import lombok.Data; +import io.swagger.annotations.ApiModelProperty; + +import com.anji.plus.gaea.curd.entity.GaeaBaseEntity; +import com.baomidou.mybatisplus.annotation.TableName; + +/** +* @description ui文字国际化处理 entity +* @author 王斌 +* @date 2021-03-25 15:30:59.286 +**/ +@TableName(value="gaea_ui_i18n") +@Data +public class GaeaUiI18n extends GaeaBaseEntity { + @ApiModelProperty(value = "语言标识") + private String locale; + + @ApiModelProperty(value = "行业标识") + private String cataType; + + @ApiModelProperty(value = "所属系统") + private String system; + + @ApiModelProperty(value = "所属模块") + private String module; + + @ApiModelProperty(value = "字段编码") + private String code; + + @ApiModelProperty(value = "字段名称") + private String name; + + @ApiModelProperty(value = "业务描述") + private String remark; + + @ApiModelProperty(value = "关联表名") + private String refer; + + @ApiModelProperty(value = "启用状态") + private Integer enabled; + + +} \ No newline at end of file diff --git a/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/gaeaUiI18n/service/GaeaUiI18nService.java b/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/gaeaUiI18n/service/GaeaUiI18nService.java new file mode 100644 index 00000000..b9ca6b5a --- /dev/null +++ b/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/gaeaUiI18n/service/GaeaUiI18nService.java @@ -0,0 +1,46 @@ + +package com.anjiplus.template.gaea.business.modules.gaeaUiI18n.service; + +import com.anjiplus.template.gaea.business.base.BaseService; +import com.anjiplus.template.gaea.business.modules.gaeaUiI18n.dao.entity.GaeaUiI18n; +import com.anjiplus.template.gaea.business.modules.gaeaUiI18n.controller.param.GaeaUiI18nParam; + +import java.util.List; +import java.util.Map; + +/** +* @desc GaeaUiI18n ui文字国际化处理服务接口 +* @author 王斌 +* @date 2021-03-25 15:30:59.286 +**/ +public interface GaeaUiI18nService extends BaseService { + + /*** + * 查询详情 + * + * @param id + * @return + */ + GaeaUiI18n getDetail(Long id); + + /** + * 新加功能菜单时,i18n同步、初始化,以单表为单位处理 + * 优先从 自动生成处理表查询,没有则从源表查询,减少重复维护 + * + * @param table 表名称 + */ + void scan(String table); + + /** + * 查询项目所有的表 + * @return + */ + List getUi18nTables(); + + /** + * 菜单初始化时,查询该菜单需要的国际化列表 + * @param initQry + * @return map + */ + Map getI18nFields(GaeaUiI18n initQry); +} \ No newline at end of file diff --git a/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/gaeaUiI18n/service/impl/ColumnDesc.java b/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/gaeaUiI18n/service/impl/ColumnDesc.java new file mode 100644 index 00000000..77d44336 --- /dev/null +++ b/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/gaeaUiI18n/service/impl/ColumnDesc.java @@ -0,0 +1,11 @@ +package com.anjiplus.template.gaea.business.modules.gaeaUiI18n.service.impl; + +import com.anjiplus.template.gaea.generator.domain.Column; + +/** + * @author WongBin + * @date 2021/3/26 + */ +public class ColumnDesc extends Column { + +} diff --git a/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/gaeaUiI18n/service/impl/GaeaUiI18nServiceImpl.java b/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/gaeaUiI18n/service/impl/GaeaUiI18nServiceImpl.java new file mode 100644 index 00000000..ac49537e --- /dev/null +++ b/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/gaeaUiI18n/service/impl/GaeaUiI18nServiceImpl.java @@ -0,0 +1,162 @@ + +package com.anjiplus.template.gaea.business.modules.gaeaUiI18n.service.impl; + +import cn.hutool.core.util.StrUtil; + +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.anjiplus.template.gaea.generator.domain.Column; +import com.anjiplus.template.gaea.generator.service.GeneratorService; +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.beans.factory.annotation.Value; +import org.springframework.context.i18n.LocaleContextHolder; +import org.springframework.stereotype.Service; +import org.springframework.util.CollectionUtils; + +import com.anjiplus.template.gaea.business.modules.gaeaUiI18n.dao.entity.GaeaUiI18n; +import com.anjiplus.template.gaea.business.modules.gaeaUiI18n.service.GaeaUiI18nService; +import com.anjiplus.template.gaea.business.modules.gaeaUiI18n.dao.GaeaUiI18nMapper; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.stream.Collectors; + +/** +* @desc GaeaUiI18n ui文字国际化处理服务实现 +* @author 王斌 +* @date 2021-03-25 15:30:59.286 +**/ +@Service +@Slf4j +public class GaeaUiI18nServiceImpl implements GaeaUiI18nService { + + @Autowired + private GaeaUiI18nMapper gaeaUiI18nMapper; + + @Override + public GaeaBaseMapper getMapper() { + return gaeaUiI18nMapper; + } + + @Override + public GaeaUiI18n getDetail(Long id) { + GaeaUiI18n gaeaUiI18n = this.selectOne(id); + return gaeaUiI18n; + } + + @Autowired(required = false) + GeneratorService generatorService; + + @Value("${spring.application.name}") + private String applicationName; + + @Override + public void processBeforeOperation(GaeaUiI18n entity, + BaseOperationEnum type) throws BusinessException { + if(BaseOperationEnum.INSERT.equals(type)){ + entity.setSystem(applicationName); + //entity.setCataType(""); + } + } + + @Override + public void scan(String table) { + assert table!=null; + LambdaQueryWrapper wrapper = Wrappers.lambdaQuery(); + wrapper.eq(GaeaUiI18n::getRefer,table); + if(gaeaUiI18nMapper.selectCount(wrapper) > 0){ + log.warn("{} exist,ignore",table); + throw new BusinessException("6001",new String[]{"该表的字段已维护国际化配置"}); + } + List columnDescList = generatorService.getColumns(table); + //List columnDescList = gaeaUiI18nMapper.queryColumns(table); + if(!CollectionUtils.isEmpty(columnDescList)){ + List list = columnDescList.stream().map(item->{ + if(item.getRemark()!=null && item.getRemark().length()>20){ + item.setRemark(item.getRemark().substring(0,20)); + } + GaeaUiI18n it = new GaeaUiI18n(); + it.setCode(StrUtil.toCamelCase(item.getColumnName())); + it.setName(item.getRemark()); + it.setLocale(getI18nLang()); + it.setSystem(applicationName); + it.setRemark(item.getRemark()); + it.setEnabled(Enabled.YES.getValue()); + it.setRefer(item.getTableName()); + return it; + }).collect(Collectors.toList()); + + int ret = gaeaUiI18nMapper.insertBatch(list); + log.info("insert-batch-for:{},size:{}",table,ret); + } + } + + private String getI18nLang(){ + return LocaleContextHolder.getLocale().getLanguage(); + } + + @Override + public List getUi18nTables() { + return gaeaUiI18nMapper.queryTables(""); + } + + @Override + public Map getI18nFields(GaeaUiI18n q) { + String table = q.getRefer(); + String tableAlias = ""; + // 提取表名称和别名 + if(q.getRefer().contains(":")) { + table = q.getRefer().split(":")[0]; + tableAlias = Optional.ofNullable(q.getRefer().substring(table.length() + 1)).orElse(""); + q.setRefer(table); + } + + LambdaQueryWrapper qry = Wrappers.lambdaQuery(); + qry.eq(GaeaUiI18n::getLocale,q.getLocale()) + .and(t->t.eq(GaeaUiI18n::getEnabled,Enabled.YES.getValue())) + // 所属行业 + .and(t->t.eq(GaeaUiI18n::getCataType,q.getCataType()).or().isNull(GaeaUiI18n::getCataType)) + // 同一个表 或同一个菜单 + .and(t->t.eq(GaeaUiI18n::getRefer,q.getRefer()).or().eq(GaeaUiI18n::getModule,q.getModule())) + ; + List list = gaeaUiI18nMapper.selectList(qry); + + HashMap kv = new HashMap(); + // 表级别 字段默认设置 + list.stream().filter(i->i.getRefer()!=null && i.getCataType()==null).forEach(i->{ + kv.put(i.getCode(),i.getName()); + }); + // 表级别 字段行业属性,覆盖默认设置 + list.stream().filter(i->i.getRefer()!=null && i.getCataType()!=null).forEach(i->{ + kv.put(i.getCode(),i.getName()); + }); + + Map result = new HashMap(); + // 挂载在module根节点 + if(tableAlias.length()<1) { + result.put(q.getModule(), kv); + }else { + // 作为module的子节点 + result.putIfAbsent(q.getModule(),new HashMap<>()); + ((Map)result.get(q.getModule())).put(tableAlias,kv); + } + + // 设置模块级别的字段配置 + HashMap m = new HashMap(); + list.stream().filter(i->i.getRefer()==null && i.getModule().equals(q.getModule())).forEach(item->{ + m.put(item.getCode(),item.getName()); + }); + if(!m.isEmpty()) { + ((Map)result.get(q.getModule())).putAll(m); + } + return result; + } +} \ No newline at end of file diff --git a/report-core/src/main/java/com/anjiplus/template/gaea/business/runner/ApplicationInitRunner.java b/report-core/src/main/java/com/anjiplus/template/gaea/business/runner/ApplicationInitRunner.java new file mode 100644 index 00000000..bd28e86a --- /dev/null +++ b/report-core/src/main/java/com/anjiplus/template/gaea/business/runner/ApplicationInitRunner.java @@ -0,0 +1,24 @@ +package com.anjiplus.template.gaea.business.runner; + +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; + +/** + * 启动加载后执行 + * @author lr + * @since 2021-04-08 + */ +public class ApplicationInitRunner implements ApplicationRunner { + + @Autowired + private GaeaDictService gaeaDictService; + + @Override + public void run(ApplicationArguments args) throws Exception { + + //1、数据字典刷新 + gaeaDictService.refreshCache(null); + } +} diff --git a/report-core/src/main/resources/bootstrap-dev.yml b/report-core/src/main/resources/bootstrap-dev.yml new file mode 100644 index 00000000..e8c4e1d6 --- /dev/null +++ b/report-core/src/main/resources/bootstrap-dev.yml @@ -0,0 +1,83 @@ +spring: + application: + name: gaea-business + cloud: + nacos: + server-addr: 10.108.26.121:8848,10.108.26.145:8848 + username: gaea + password: p@ss1234 +# config: +# namespace: 5c6b6687-ad43-450f-88b6-e704ff78d83f +# file-extension: yaml + discovery: + namespace: 5c6b6687-ad43-450f-88b6-e704ff78d83f + jackson: + date-format: yyyy-MM-dd HH:mm:ss + messages: + basename: i18n/messages + datasource: + url: jdbc:mysql://10.108.26.197:3306/aj_report?characterEncoding=UTF-8&serverTimezone=Asia/Shanghai&useSSL=false + username: root + password: appuser@anji + redis: + host: 10.108.26.197 + port: 6379 + password: appuser@anji + database: 1 +generator: + enabled: true + workspace: /workspace/gaea + templatePath: template +server: + port: 9092 +# servlet: +# context-path: /business +mybatis-plus: + configuration: + log-impl: org.apache.ibatis.logging.stdout.StdOutImpl + call-setters-on-nulls: true + mapperLocations: + - classpath*:/mapper/**/*.xml + - classpath*:/modeler-mybatis-mappings/**/*.xml + + gaea: + subscribes: + security: + enabled: true + push: + enabled: true + sms: + aliyun: + access-key-id: + secret: + audit-log: + enabled: true + callback-url: http://127.0.0.1:9091/log/callback + export: + enabled: true + + # 邮箱发送配置 + mail: + # host不配置会注入失败 + host: smtp.163.com + default-encoding: utf-8 + protocol: smtp + properties: + mail: + smtp: + connectiontimeout: 5000 + timeout: 3000 + +management: + endpoints: + web: + base-path: / +logging: + level: + com.alibaba.cloud.nacos.client.NacosPropertySourceBuilder: debug +file: + dist-path: /app/disk/upload/ + white-list: .png|.jpg|.gif|.icon|.pdf|.xlsx|.xls|.csv|.mp4|.avi + excelSuffix: .xlsx|.xls|.csv + downloadPath: http://10.108.26.197/business/file/download + diff --git a/report-core/src/main/resources/bootstrap-prod.yml b/report-core/src/main/resources/bootstrap-prod.yml new file mode 100644 index 00000000..fc5119d8 --- /dev/null +++ b/report-core/src/main/resources/bootstrap-prod.yml @@ -0,0 +1,17 @@ +spring: + application: + name: gaea-business + cloud: + nacos: + server-addr: 10.108.142.118:8848 + username: gaea + password: p@ss1234 + config: + namespace: fe5a998f-1149-4f55-aa83-e7552279058c + file-extension: yaml + discovery: + namespace: fe5a998f-1149-4f55-aa83-e7552279058c +generator: + enabled: false + workspace: /workspace/gaea + templatePath: template \ No newline at end of file diff --git a/report-core/src/main/resources/bootstrap.yml b/report-core/src/main/resources/bootstrap.yml new file mode 100644 index 00000000..0c268749 --- /dev/null +++ b/report-core/src/main/resources/bootstrap.yml @@ -0,0 +1,9 @@ +spring: + profiles: + active: @spring.profiles.active@ + +logging: + config: classpath:logback.xml +generator: + tableExclude: + mysql: "AND table_name not like 'gaea_%' AND table_name not like 'ACT_%'" \ No newline at end of file diff --git a/report-core/src/main/resources/i18n/messages.properties b/report-core/src/main/resources/i18n/messages.properties new file mode 100644 index 00000000..42266854 --- /dev/null +++ b/report-core/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/report-core/src/main/resources/i18n/messages_en_US.properties b/report-core/src/main/resources/i18n/messages_en_US.properties new file mode 100644 index 00000000..35bad51b --- /dev/null +++ b/report-core/src/main/resources/i18n/messages_en_US.properties @@ -0,0 +1,33 @@ +500=Server error +200=success +1013=The code does not allow duplication +2001=File names are not allowed to be empty +2002=Unsupported suffix type +2003=File upload failed +2004=File does not exist + +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 +4002=Data source type is not currently supported +4003=execute sql error +4004=Incomplete parameter replacement values +4005=execute js error +4006=analysis data error +4007=The report code does not allow duplication +4008=The set code does not allow duplication +4009=The source code does not allow duplication diff --git a/report-core/src/main/resources/i18n/messages_zh_CN.properties b/report-core/src/main/resources/i18n/messages_zh_CN.properties new file mode 100644 index 00000000..2399eff3 --- /dev/null +++ b/report-core/src/main/resources/i18n/messages_zh_CN.properties @@ -0,0 +1,38 @@ +500=\u7CFB\u7EDF\u5F02\u5E38 +200=\u64CD\u4F5C\u6210\u529F +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 +2004=\u6587\u4EF6\u4E0D\u5B58\u5728 + +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 +4002=\u6570\u636E\u6E90\u7C7B\u578B\u6682\u4E0D\u652F\u6301 +4003=\u6267\u884Csql\u5931\u8D25 +4004=\u53C2\u6570\u66FF\u6362\u503C\u4E0D\u5168 +4005=\u6267\u884Cjs\u5931\u8D25 +4006=\u89E3\u6790\u6570\u636E\u5931\u8D25 +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 +6001={0} + +7001=\u89E3\u6790\u5931\u8D25 + diff --git a/report-core/src/main/resources/lib/ImpalaJDBC41.jar b/report-core/src/main/resources/lib/ImpalaJDBC41.jar new file mode 100644 index 00000000..058a54d9 Binary files /dev/null and b/report-core/src/main/resources/lib/ImpalaJDBC41.jar differ diff --git a/report-core/src/main/resources/logback.xml b/report-core/src/main/resources/logback.xml new file mode 100644 index 00000000..b6752c24 --- /dev/null +++ b/report-core/src/main/resources/logback.xml @@ -0,0 +1,37 @@ + + + + + + + + + %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 + + + + + + + + + + + + \ No newline at end of file diff --git a/report-core/src/main/resources/mapper/DataSetMapper.xml b/report-core/src/main/resources/mapper/DataSetMapper.xml new file mode 100644 index 00000000..88731dbc --- /dev/null +++ b/report-core/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 + + + + + \ No newline at end of file diff --git a/report-core/src/main/resources/mapper/DataSetParamMapper.xml b/report-core/src/main/resources/mapper/DataSetParamMapper.xml new file mode 100644 index 00000000..428988c2 --- /dev/null +++ b/report-core/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 + + + + + \ No newline at end of file diff --git a/report-core/src/main/resources/mapper/DataSetTransformMapper.xml b/report-core/src/main/resources/mapper/DataSetTransformMapper.xml new file mode 100644 index 00000000..dca23fa3 --- /dev/null +++ b/report-core/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 + + + + + \ No newline at end of file diff --git a/report-core/src/main/resources/mapper/DataSourceMapper.xml b/report-core/src/main/resources/mapper/DataSourceMapper.xml new file mode 100644 index 00000000..af55c19e --- /dev/null +++ b/report-core/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 + + + + + \ No newline at end of file diff --git a/report-core/src/main/resources/mapper/GaeaExportMapper.xml b/report-core/src/main/resources/mapper/GaeaExportMapper.xml new file mode 100644 index 00000000..f9253ece --- /dev/null +++ b/report-core/src/main/resources/mapper/GaeaExportMapper.xml @@ -0,0 +1,48 @@ + + + + + + + + + + + + + + + + + + + + + + + + id, file_id, file_title, result_start_time, result_end_time, result_size, file_create_time, file_finish_time, + file_status, create_by, update_by, create_time, update_time, version, remark + + + + + diff --git a/report-core/src/main/resources/mapper/GaeaUiI18nMapper.xml b/report-core/src/main/resources/mapper/GaeaUiI18nMapper.xml new file mode 100644 index 00000000..db8442aa --- /dev/null +++ b/report-core/src/main/resources/mapper/GaeaUiI18nMapper.xml @@ -0,0 +1,50 @@ + + + + + + + + + + + + + + + + + + + + + + + id,locale,cata_type,system,code,name,remark,enabled,create_by,create_time,update_by,update_time,version + + + + + + + \ No newline at end of file diff --git a/report-core/src/main/resources/mapper/ReportDashboardMapper.xml b/report-core/src/main/resources/mapper/ReportDashboardMapper.xml new file mode 100644 index 00000000..ab9aa8bf --- /dev/null +++ b/report-core/src/main/resources/mapper/ReportDashboardMapper.xml @@ -0,0 +1,31 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + 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 + + + + + \ No newline at end of file diff --git a/report-core/src/main/resources/mapper/ReportDashboardWidgetMapper.xml b/report-core/src/main/resources/mapper/ReportDashboardWidgetMapper.xml new file mode 100644 index 00000000..476e6388 --- /dev/null +++ b/report-core/src/main/resources/mapper/ReportDashboardWidgetMapper.xml @@ -0,0 +1,29 @@ + + + + + + + + + + + + + + + + + + + + + + + + id,report_code,`type`,setup,`data`,`position`,collapse,enable_flag,delete_flag,sort,create_by,create_time,update_by,update_time + + + + + diff --git a/report-core/src/main/resources/mapper/ReportExcelMapper.xml b/report-core/src/main/resources/mapper/ReportExcelMapper.xml new file mode 100644 index 00000000..216277cc --- /dev/null +++ b/report-core/src/main/resources/mapper/ReportExcelMapper.xml @@ -0,0 +1,22 @@ + + + + + + + + + + + + + + + + + + + + + + diff --git a/report-core/src/main/resources/mapper/ReportMapper.xml b/report-core/src/main/resources/mapper/ReportMapper.xml new file mode 100644 index 00000000..1a506d65 --- /dev/null +++ b/report-core/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/report-core/src/test/resources/application.properties b/report-core/src/test/resources/application.properties new file mode 100644 index 00000000..e69de29b