zhaojinyu 2 miesięcy temu
commit
5e9b08b4da
100 zmienionych plików z 10253 dodań i 0 usunięć
  1. 8 0
      .idea/.gitignore
  2. 23 0
      .idea/compiler.xml
  3. 13 0
      .idea/encodings.xml
  4. 20 0
      .idea/jarRepositories.xml
  5. 12 0
      .idea/misc.xml
  6. 4 0
      .idea/vcs.xml
  7. 18 0
      Dockerfile
  8. 194 0
      README.md
  9. 191 0
      pom.xml
  10. 228 0
      ureport2-console/LICENSE-2.0.html
  11. 76 0
      ureport2-console/pom.xml
  12. 125 0
      ureport2-console/src/main/java/com/bstek/ureport/console/BaseServletAction.java
  13. 36 0
      ureport2-console/src/main/java/com/bstek/ureport/console/DataReportApplication.java
  14. 52 0
      ureport2-console/src/main/java/com/bstek/ureport/console/MobileUtils.java
  15. 42 0
      ureport2-console/src/main/java/com/bstek/ureport/console/RenderPageServletAction.java
  16. 35 0
      ureport2-console/src/main/java/com/bstek/ureport/console/RequestHolder.java
  17. 32 0
      ureport2-console/src/main/java/com/bstek/ureport/console/ServletAction.java
  18. 158 0
      ureport2-console/src/main/java/com/bstek/ureport/console/UReportServlet.java
  19. 48 0
      ureport2-console/src/main/java/com/bstek/ureport/console/WriteJsonServletAction.java
  20. 85 0
      ureport2-console/src/main/java/com/bstek/ureport/console/cache/HttpSessionReportCache.java
  21. 67 0
      ureport2-console/src/main/java/com/bstek/ureport/console/cache/ObjectMap.java
  22. 98 0
      ureport2-console/src/main/java/com/bstek/ureport/console/cache/TempObjectCache.java
  23. 50 0
      ureport2-console/src/main/java/com/bstek/ureport/console/chart/ChartServletAction.java
  24. 13 0
      ureport2-console/src/main/java/com/bstek/ureport/console/config/DataReportListener.java
  25. 54 0
      ureport2-console/src/main/java/com/bstek/ureport/console/designer/DataResult.java
  26. 517 0
      ureport2-console/src/main/java/com/bstek/ureport/console/designer/DatasourceServletAction.java
  27. 215 0
      ureport2-console/src/main/java/com/bstek/ureport/console/designer/DesignerServletAction.java
  28. 132 0
      ureport2-console/src/main/java/com/bstek/ureport/console/designer/ReportDefinitionWrapper.java
  29. 40 0
      ureport2-console/src/main/java/com/bstek/ureport/console/designer/ReportUtils.java
  30. 55 0
      ureport2-console/src/main/java/com/bstek/ureport/console/designer/SearchFormDesignerAction.java
  31. 120 0
      ureport2-console/src/main/java/com/bstek/ureport/console/excel/ExportExcel97ServletAction.java
  32. 136 0
      ureport2-console/src/main/java/com/bstek/ureport/console/excel/ExportExcelServletAction.java
  33. 32 0
      ureport2-console/src/main/java/com/bstek/ureport/console/exception/ReportDesignException.java
  34. 469 0
      ureport2-console/src/main/java/com/bstek/ureport/console/html/HtmlPreviewServletAction.java
  35. 137 0
      ureport2-console/src/main/java/com/bstek/ureport/console/html/Tools.java
  36. 62 0
      ureport2-console/src/main/java/com/bstek/ureport/console/image/ImageServletAction.java
  37. 29 0
      ureport2-console/src/main/java/com/bstek/ureport/console/importexcel/ExcelParser.java
  38. 303 0
      ureport2-console/src/main/java/com/bstek/ureport/console/importexcel/HSSFExcelParser.java
  39. 85 0
      ureport2-console/src/main/java/com/bstek/ureport/console/importexcel/ImportExcelServletAction.java
  40. 35 0
      ureport2-console/src/main/java/com/bstek/ureport/console/importexcel/Span.java
  41. 308 0
      ureport2-console/src/main/java/com/bstek/ureport/console/importexcel/XSSFExcelParser.java
  42. 224 0
      ureport2-console/src/main/java/com/bstek/ureport/console/pdf/ExportPdfServletAction.java
  43. 79 0
      ureport2-console/src/main/java/com/bstek/ureport/console/res/ResourceLoaderServletAction.java
  44. 571 0
      ureport2-console/src/main/java/com/bstek/ureport/console/ureport/controller/DataReportController.java
  45. 35 0
      ureport2-console/src/main/java/com/bstek/ureport/console/ureport/entity/CodeNumEntity.java
  46. 109 0
      ureport2-console/src/main/java/com/bstek/ureport/console/ureport/entity/ReportEntity.java
  47. 36 0
      ureport2-console/src/main/java/com/bstek/ureport/console/ureport/entity/SystemEntity.java
  48. 34 0
      ureport2-console/src/main/java/com/bstek/ureport/console/ureport/entity/UserEntity.java
  49. 17 0
      ureport2-console/src/main/java/com/bstek/ureport/console/ureport/mapper/CodeNumMapper.java
  50. 8 0
      ureport2-console/src/main/java/com/bstek/ureport/console/ureport/mapper/ReportMapper.java
  51. 8 0
      ureport2-console/src/main/java/com/bstek/ureport/console/ureport/mapper/SystemMapper.java
  52. 8 0
      ureport2-console/src/main/java/com/bstek/ureport/console/ureport/mapper/UserMapper.java
  53. 11 0
      ureport2-console/src/main/java/com/bstek/ureport/console/ureport/model/PaginationReport.java
  54. 16 0
      ureport2-console/src/main/java/com/bstek/ureport/console/ureport/model/ReportCrForm.java
  55. 15 0
      ureport2-console/src/main/java/com/bstek/ureport/console/ureport/model/ReportInfoModel.java
  56. 11 0
      ureport2-console/src/main/java/com/bstek/ureport/console/ureport/model/ReportInfoVO.java
  57. 22 0
      ureport2-console/src/main/java/com/bstek/ureport/console/ureport/model/ReportInitVo.java
  58. 17 0
      ureport2-console/src/main/java/com/bstek/ureport/console/ureport/model/ReportListVO.java
  59. 21 0
      ureport2-console/src/main/java/com/bstek/ureport/console/ureport/model/ReportPreviewVO.java
  60. 10 0
      ureport2-console/src/main/java/com/bstek/ureport/console/ureport/model/ReportSelectorVO.java
  61. 8 0
      ureport2-console/src/main/java/com/bstek/ureport/console/ureport/model/ReportUpForm.java
  62. 54 0
      ureport2-console/src/main/java/com/bstek/ureport/console/ureport/service/CodeNumService.java
  63. 71 0
      ureport2-console/src/main/java/com/bstek/ureport/console/ureport/service/ReportService.java
  64. 24 0
      ureport2-console/src/main/java/com/bstek/ureport/console/ureport/service/SystemService.java
  65. 25 0
      ureport2-console/src/main/java/com/bstek/ureport/console/ureport/service/UserService.java
  66. 89 0
      ureport2-console/src/main/java/com/bstek/ureport/console/ureport/service/impl/CodeNumServiceImpl.java
  67. 132 0
      ureport2-console/src/main/java/com/bstek/ureport/console/ureport/service/impl/ReportServiceImpl.java
  68. 23 0
      ureport2-console/src/main/java/com/bstek/ureport/console/ureport/service/impl/SystemServiceImpl.java
  69. 21 0
      ureport2-console/src/main/java/com/bstek/ureport/console/ureport/service/impl/UserServiceImpl.java
  70. 54 0
      ureport2-console/src/main/java/com/bstek/ureport/console/ureport/util/DownUtil.java
  71. 67 0
      ureport2-console/src/main/java/com/bstek/ureport/console/ureport/util/JwtUtil.java
  72. 624 0
      ureport2-console/src/main/java/com/bstek/ureport/console/ureport/util/UreportExcelUtil.java
  73. 405 0
      ureport2-console/src/main/java/com/bstek/ureport/console/ureport/util/UreportPdfUtil.java
  74. 120 0
      ureport2-console/src/main/java/com/bstek/ureport/console/ureport/util/UreportPreviewUtil.java
  75. 105 0
      ureport2-console/src/main/java/com/bstek/ureport/console/ureport/util/UreportUtil.java
  76. 640 0
      ureport2-console/src/main/java/com/bstek/ureport/console/ureport/util/UreportWordUtil.java
  77. 91 0
      ureport2-console/src/main/java/com/bstek/ureport/console/util/ActionResult.java
  78. 24 0
      ureport2-console/src/main/java/com/bstek/ureport/console/util/DbTableConModel.java
  79. 717 0
      ureport2-console/src/main/java/com/bstek/ureport/console/util/FileUtil.java
  80. 11 0
      ureport2-console/src/main/java/com/bstek/ureport/console/util/ListVO.java
  81. 8 0
      ureport2-console/src/main/java/com/bstek/ureport/console/util/Page.java
  82. 12 0
      ureport2-console/src/main/java/com/bstek/ureport/console/util/PageListVO.java
  83. 25 0
      ureport2-console/src/main/java/com/bstek/ureport/console/util/Pagination.java
  84. 10 0
      ureport2-console/src/main/java/com/bstek/ureport/console/util/PaginationVO.java
  85. 31 0
      ureport2-console/src/main/java/com/bstek/ureport/console/util/RandomUtil.java
  86. 44 0
      ureport2-console/src/main/java/com/bstek/ureport/console/util/RequestUtil.java
  87. 86 0
      ureport2-console/src/main/java/com/bstek/ureport/console/util/UReportJdbcUtil.java
  88. 120 0
      ureport2-console/src/main/java/com/bstek/ureport/console/word/ExportWordServletAction.java
  89. 127 0
      ureport2-console/src/main/resources/application.yml
  90. 327 0
      ureport2-console/src/main/resources/logback-spring.xml
  91. 7 0
      ureport2-console/src/main/resources/mapper/ReportMapper.xml
  92. 7 0
      ureport2-console/src/main/resources/mapper/SystemMapper.xml
  93. 7 0
      ureport2-console/src/main/resources/mapper/UserMapper.xml
  94. 169 0
      ureport2-console/src/main/resources/template/template.ureport.xml
  95. 53 0
      ureport2-console/src/main/resources/ureport-console-context.xml
  96. 179 0
      ureport2-console/src/main/resources/ureport.xml
  97. 127 0
      ureport2-console/target/classes/application.yml
  98. BIN
      ureport2-console/target/classes/com/bstek/ureport/console/BaseServletAction.class
  99. BIN
      ureport2-console/target/classes/com/bstek/ureport/console/DataReportApplication.class
  100. BIN
      ureport2-console/target/classes/com/bstek/ureport/console/MobileUtils.class

+ 8 - 0
.idea/.gitignore

@@ -0,0 +1,8 @@
+# 默认忽略的文件
+/shelf/
+/workspace.xml
+# 基于编辑器的 HTTP 客户端请求
+/httpRequests/
+# Datasource local storage ignored files
+/dataSources/
+/dataSources.local.xml

+ 23 - 0
.idea/compiler.xml

@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+  <component name="CompilerConfiguration">
+    <annotationProcessing>
+      <profile name="Maven default annotation processors profile" enabled="true">
+        <sourceOutputDir name="target/generated-sources/annotations" />
+        <sourceTestOutputDir name="target/generated-test-sources/test-annotations" />
+        <outputRelativeToContentRoot value="true" />
+        <module name="ureport2-font" />
+        <module name="ureport2-console" />
+        <module name="ureport2-core" />
+      </profile>
+    </annotationProcessing>
+  </component>
+  <component name="JavacSettings">
+    <option name="ADDITIONAL_OPTIONS_OVERRIDE">
+      <module name="jnpf-datareport" options="-parameters" />
+      <module name="ureport2-console" options="-parameters" />
+      <module name="ureport2-core" options="-parameters" />
+      <module name="ureport2-font" options="-parameters" />
+    </option>
+  </component>
+</project>

+ 13 - 0
.idea/encodings.xml

@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+  <component name="Encoding">
+    <file url="file://$PROJECT_DIR$/src/main/java" charset="UTF-8" />
+    <file url="file://$PROJECT_DIR$/src/main/resources" charset="UTF-8" />
+    <file url="file://$PROJECT_DIR$/ureport2-console/src/main/java" charset="UTF-8" />
+    <file url="file://$PROJECT_DIR$/ureport2-console/src/main/resources" charset="UTF-8" />
+    <file url="file://$PROJECT_DIR$/ureport2-core/src/main/java" charset="UTF-8" />
+    <file url="file://$PROJECT_DIR$/ureport2-core/src/main/resources" charset="UTF-8" />
+    <file url="file://$PROJECT_DIR$/ureport2-font/src/main/java" charset="UTF-8" />
+    <file url="file://$PROJECT_DIR$/ureport2-font/src/main/resources" charset="UTF-8" />
+  </component>
+</project>

+ 20 - 0
.idea/jarRepositories.xml

@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+  <component name="RemoteRepositoriesConfiguration">
+    <remote-repository>
+      <option name="id" value="central" />
+      <option name="name" value="Central Repository" />
+      <option name="url" value="http://127.0.0.1:9999/repository/maven-public/" />
+    </remote-repository>
+    <remote-repository>
+      <option name="id" value="central" />
+      <option name="name" value="Maven Central repository" />
+      <option name="url" value="https://repo1.maven.org/maven2" />
+    </remote-repository>
+    <remote-repository>
+      <option name="id" value="jboss.community" />
+      <option name="name" value="JBoss Community repository" />
+      <option name="url" value="https://repository.jboss.org/nexus/content/repositories/public/" />
+    </remote-repository>
+  </component>
+</project>

+ 12 - 0
.idea/misc.xml

@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+  <component name="ExternalStorageConfigurationManager" enabled="true" />
+  <component name="MavenProjectsManager">
+    <option name="originalFiles">
+      <list>
+        <option value="$PROJECT_DIR$/pom.xml" />
+      </list>
+    </option>
+  </component>
+  <component name="ProjectRootManager" version="2" languageLevel="JDK_21" default="true" project-jdk-name="21" project-jdk-type="JavaSDK" />
+</project>

+ 4 - 0
.idea/vcs.xml

@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+  <component name="VcsDirectoryMappings" defaultProject="true" />
+</project>

+ 18 - 0
Dockerfile

@@ -0,0 +1,18 @@
+# 基础镜像
+FROM hub.yinmaisoft.com/jnpf-devops-agent/base-datareport-jre:21
+# FROM hub.yinmaisoft.com/jnpf-devops-agent/base-datareport-jre:17
+# FROM hub.yinmaisoft.com/jnpf-devops-agent/base-datareport-jre:11
+# FROM hub.yinmaisoft.com/jnpf-devops-agent/base-datareport-jre:8
+LABEL maintainer=jnpf-team
+
+# 指定运行时的工作目录
+WORKDIR /data/jnpfsoft/reportApi
+
+# 将构建产物jar包拷贝到运行时目录中
+COPY ureport2-console/target/*.jar ./jnpf-datareport.jar
+
+# 指定容器内运行端口
+EXPOSE 30007
+
+# 指定容器启动时要运行的命令
+ENTRYPOINT ["/bin/sh","-c","java -Dfile.encoding=utf8 -Djava.security.egd=file:/dev/./urandom -jar jnpf-datareport.jar"]

+ 194 - 0
README.md

@@ -0,0 +1,194 @@
+
+> 特别说明:源码、JDK、MySQL、Redis等存放路径禁止包含中文、空格、特殊字符等
+
+## 一 环境要求
+
+### 1.1 开发环境
+
+| 类目     | 版本说明或建议     |
+|--------|-----------------------------------------------------------------------------------------------------------------|
+| 硬件     | 开发电脑建议使用I3及以上CPU,16G及以上内存       |
+| 操作系统   | Windows 10/11,MacOS          |
+| JDK    | 默认使用JDK 21,如需要切换JDK 8/11/17版本请参考文档调整代码,推荐使用 `OpenJDK`,如 `Liberica JDK`、`Eclipse Temurin`、`Alibaba Dragonwell`、`BiSheng` 等发行版;)                                                                                  |
+| Maven | 依赖管理工具,推荐使用 `3.6.3` 及以上版本  |
+| Redis | 数据缓存,推荐使用 `5.0` 及以上版本 |
+| 数据库    | 兼容 `MySQL 5.7.x/8.x`、`SQLServer 2012+`、`Oracle 11g`、`PostgreSQL 12+`、`达梦数据库(DM8)`、`人大金仓数据库(KingbaseES_V8R6)` |
+| IDE   | 代码集成开发环境,推荐使用 `IDEA2024` 及以上版本,兼容 `Eclipse`、 `Spring Tool Suite` 等IDE工具 |
+
+### 1.2 运行环境
+
+> 适用于测试或生产环境
+
+| 类目 | 版本说明或建议                                                                                                         |
+| --- |-----------------------------------------------------------------------------------------------------------------|
+| 服务器配置 | 建议至少在 `4C/16G/50G`  的机器配置下运行;                                                                                       |
+| 操作系统 | 建议使用 `Windows Server 2019` 及以上版本或主流 `Linux` 发行版本,推荐使用 `Linux` 环境;兼容 `统信UOS`,`OpenEuler`,`麒麟服务器版` 等信创环境;    |
+| JRE | 默认使用JRE 21,如需要切换JRE 8/11/17版本请参考文档调整代码;推荐使用 `OpenJDK`,如 `Liberica JDK`、`Eclipse Temurin`、`Alibaba Dragonwell`、`BiSheng` 等发行版;   |
+| Redis |  数据缓存,推荐使用 Redis `5.0` 及以上版本     |
+| 数据库 | 兼容 `MySQL 5.7.x/8.x`、`SQLServer 2012+`、`Oracle 11g`、`PostgreSQL 12+`、`达梦数据库(DM8)`、`人大金仓数据库(KingbaseES_V8R6)` |
+| 中间件(兼容)) | 东方通 `Tong-web`、金蝶天燕-应用服务器`AAS` v10;                                                                             |
+
+## 二 关联项目
+
+### 2.1 后端项目
+
+> 提供基于报表服务,适用于如下任一后端
+
+| 项目 | 分支 | 说明 |
+| --- | --- | --- | 
+| jnpf-java-boot | v6.0.x-stable | Java单体后端项目源码 |
+| jnpf-java-cloud | v6.0.x-stable | Java微服务后端项目源码 |
+| jnpf-dotnet | v6.0.x-stable | .NET单体后端项目源码 |
+| jnpf-dotnet-cloud | v6.0.x-stable | .NET微服务后端项目源码 |
+
+### 2.2 前端项目
+
+| 项目 | 分支 | 说明 |
+| --- | --- | --- |
+| jnpf-web-datareport      |  v6.0.x-stable | 报表前端项目源码       |
+
+## 三 使用说明
+
+### 3.1 Maven私服配置
+
+> 建议使用 Apache Maven 3.6.3 及以上版本<br>以解决依赖无法从公共Maven仓库下载的问题<br>通过官方私服下载依赖完成后,由于IDEA的缓存可能会出现部分报红,重启IDEA即可
+
+打开Maven安装目录中的 `conf/settings.xml` 文件,<br>
+在 `<servers></servers>` 中添加如下内容
+
+```xml
+<server>
+  <id>maven-releases</id>
+  <username>您的账号</username>
+  <password>您的密码</password>
+</server>
+```
+
+在 `<mirrors></mirrors>` 中添加
+
+```xml
+<mirror>
+  <id>maven-snapshots</id>
+  <mirrorOf>*</mirrorOf>
+  <name>maven-snapshots</name>
+  <url>https://repository.jnpfsoft.com/repository/maven-public/</url>
+</mirror>
+```
+
+### 3.2 环境配置
+
+- 打开 `ureport2-console/src/main/resources` 中的 `application.yml`
+- 修改配置
+  - 端口配置
+  - `数据库` 配置和 `Redis` 配置
+  - 是否开启多租户
+- 打开 `ureport2-console/src/main/java/com.bstek.ureport.console/DataReportApplication` 运行
+
+### 3.3 数据库配置示例
+
+打开 `ureport2-console/src/main/resources` 中的 `application.yml`
+
+#### MySQL数据库
+
+```yaml
+  datasource:
+    db-type: MySQL
+    host: 127.0.0.1
+    port: 3306
+    db-name: jnpf_init
+    username: dbuser
+    password: dbpasswd
+    db-schema:
+    prepare-url:
+```
+
+#### SQLServer数据库
+
+```yaml
+  datasource:
+    db-type: SQLServer
+    host: 127.0.0.1
+    port: 1433
+    db-name: jnpf_init
+    username: dbuser
+    password: dbpasswd
+    db-schema:
+    prepare-url:
+```
+
+#### Oracle数据库
+
+```yaml
+  datasource:
+    db-type: Oracle
+    host: 127.0.0.1
+    port: 1521
+    db-name:
+    username: DBUSER
+    password: dbpasswd
+    db-schema:
+    prepare-url: jdbc:oracle:thin:@127.0.0.1:1521:ORCL
+```
+
+#### PostgreSQL数据库配置
+
+```yaml
+  datasource:
+    db-type: PostgreSQL
+    host: 127.0.0.1
+    port: 5432
+    db-name: jnpf_init
+    username: dbuser
+    password: dbpasswd
+    db-schema: public
+    prepare-url:
+```
+
+#### 达梦(DM8)数据库
+
+```yaml
+  datasource:
+    db-type: DM
+    host: 127.0.0.1
+    port: 5236
+    db-name: JNPF_INIT
+    username: DBUSER
+    password: dbpasswd
+    db-schema:
+    prepare-url:
+    tablespace: MAIN
+```
+
+#### 人大金仓(KingbaseES_V8R6)数据库
+
+```yaml
+  datasource:
+    db-type: KingbaseES
+    host: 127.0.0.1
+    port: 54321
+    db-name: jnpf_init
+    username: dbuser
+    password: dbpasswd
+    db-schema:
+    prepare-url:
+    tablespace: jnpf
+```
+
+
+
+### 3.4 数据集条件用法
+
+例子
+
+```sql
+${
+"select * from base_user where 1=1" +(emptyparam("F_Gender")==true?"":" and F_Gender=:F_Gender") +(emptyparam("F_RealName")==true?"":" and F_RealName like :F_RealName") +(emptyparam("F_QuickQuery")==true?"":" and F_QuickQuery like :F_QuickQuery")
+}
+```
+对应参数填写
+
+参数名  | 数据类型  | 默认值
+-----|-------- | -------------
+F_RealName  | String |
+F_QuickQuery  | String |
+F_Gender  | Integer |

+ 191 - 0
pom.xml

@@ -0,0 +1,191 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+
+    <parent>
+        <groupId>com.jnpf</groupId>
+        <artifactId>jnpf-dependencies</artifactId>
+        <version>6.0.0-RELEASE</version>
+    </parent>
+
+    <groupId>com.jnpf</groupId>
+    <artifactId>jnpf-datareport</artifactId>
+    <version>6.0.0-RELEASE</version>
+    <packaging>pom</packaging>
+
+    <modules>
+        <module>ureport2-console</module>
+        <module>ureport2-core</module>
+        <module>ureport2-font</module>
+    </modules>
+
+    <properties>
+        <poi.version>4.1.2</poi.version>
+        <oooxml-schemas.version>1.4</oooxml-schemas.version>
+        <poi-ooxml-schemas>4.1.2</poi-ooxml-schemas>
+    </properties>
+
+    <dependencyManagement>
+        <dependencies>
+            <!-- SpringBoot 依赖配置 -->
+            <!--<dependency>
+                <groupId>org.springframework.boot</groupId>
+                <artifactId>spring-boot-dependencies</artifactId>
+                <version>${spring-boot.version}</version>
+                <type>pom</type>
+                <scope>import</scope>
+            </dependency>-->
+        </dependencies>
+    </dependencyManagement>
+
+    <dependencies>
+        <dependency>
+            <groupId>commons-beanutils</groupId>
+            <artifactId>commons-beanutils-core</artifactId>
+            <version>1.8.3</version>
+        </dependency>
+        <dependency>
+            <groupId>org.antlr</groupId>
+            <artifactId>antlr4-runtime</artifactId>
+            <version>4.5.3</version>
+        </dependency>
+        <dependency>
+            <groupId>org.dom4j</groupId>
+            <artifactId>dom4j</artifactId>
+            <exclusions>
+                <exclusion>
+                    <artifactId>xml-apis</artifactId>
+                    <groupId>xml-apis</groupId>
+                </exclusion>
+            </exclusions>
+        </dependency>
+        <dependency>
+            <groupId>com.github.librepdf</groupId>
+            <artifactId>openpdf</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>com.github.librepdf</groupId>
+            <artifactId>openpdf-fonts-extra</artifactId>
+        </dependency>
+
+
+        <!-- excel工具 -->
+        <dependency>
+            <groupId>org.apache.poi</groupId>
+            <artifactId>poi</artifactId>
+            <version>${poi.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.poi</groupId>
+            <artifactId>poi-ooxml</artifactId>
+            <version>${poi.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.poi</groupId>
+            <artifactId>poi-scratchpad</artifactId>
+            <version>${poi.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.poi</groupId>
+            <artifactId>ooxml-schemas</artifactId>
+            <version>${oooxml-schemas.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.poi</groupId>
+            <artifactId>poi-ooxml-schemas</artifactId>
+            <version>${poi-ooxml-schemas}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.velocity</groupId>
+            <artifactId>velocity-engine-core</artifactId>
+        </dependency>
+
+
+        <!-- commons-configuration 自动加载的是2.1的版本,编译时会报错,所以再加上这个 -->
+        <dependency>
+            <groupId>commons-lang</groupId>
+            <artifactId>commons-lang</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>com.jnpf</groupId>
+            <artifactId>jnpf-common-security</artifactId>
+            <version>${project.version}</version>
+        </dependency>
+
+        <!--继承依赖-->
+        <!--
+        <dependency>
+            <groupId>org.projectlombok</groupId>
+            <artifactId>lombok</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-web</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>com.google.zxing</groupId>
+            <artifactId>core</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>com.alibaba</groupId>
+            <artifactId>fastjson</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.commons</groupId>
+            <artifactId>commons-lang3</artifactId>
+        </dependency>
+        -->
+    </dependencies>
+
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-compiler-plugin</artifactId>
+            </plugin>
+        </plugins>
+
+        <resources>
+            <resource>
+                <filtering>false</filtering>
+                <directory>src/main/resources</directory>
+                <includes>
+                    <include>**</include>
+                </includes>
+            </resource>
+            <resource>
+                <filtering>false</filtering>
+                <directory>src/main/java</directory>
+                <includes>
+                    <include>**/*.xml</include>
+                    <include>**/*.xsd</include>
+                    <include>**/*.schemas</include>
+                    <include>**/*.handlers</include>
+                    <include>**/*.properties</include>
+                    <include>**/*.png</include>
+                    <include>**/*.jpg</include>
+                    <include>**/*.gif</include>
+                    <include>**/*.css</include>
+                    <include>**/*.js</include>
+                    <include>**/*.map</include>
+                    <include>**/*.html</include>
+                    <include>**/*.jsp</include>
+                    <include>**/*.txt</include>
+                    <include>**/*.eot</include>
+                    <include>**/*.svg</include>
+                    <include>**/*.ttf</include>
+                    <include>**/*.ttc</include>
+                    <include>**/*.TTF</include>
+                    <include>**/*.TTC</include>
+                    <include>**/*.woff</include>
+                    <include>**/*.woff2</include>
+                    <include>**/*.md</include>
+                    <include>**/*.template</include>
+                </includes>
+            </resource>
+        </resources>
+    </build>
+
+</project>

+ 228 - 0
ureport2-console/LICENSE-2.0.html

@@ -0,0 +1,228 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+  <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
+  <meta charset="utf-8">
+  <title>Apache License, Version 2.0</title>
+</head>
+<body>
+<div class="container">
+  <style type="text/css">
+  /* The following code is added by mdx_elementid.py
+     It was originally lifted from http://subversion.apache.org/style/site.css */
+  /*
+   * Hide class="elementid-permalink", except when an enclosing heading
+   * has the :hover property.
+   */
+  .headerlink, .elementid-permalink {
+    visibility: hidden;
+  }
+  h2:hover > .headerlink, h3:hover > .headerlink, h1:hover > .headerlink, h6:hover > .headerlink, h4:hover > .headerlink, h5:hover > .headerlink, dt:hover > .elementid-permalink { visibility: visible }
+  </style>
+  <p>Apache License<br>
+  Version 2.0, January 2004<br>
+  <a href=
+  "http://www.apache.org/licenses/">http://www.apache.org/licenses/</a></p>
+  <p>TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND
+  DISTRIBUTION</p>
+  <p><strong><a name="definitions" id="definitions">1.
+  Definitions</a></strong>.</p>
+  <p>"License" shall mean the terms and conditions for use,
+  reproduction, and distribution as defined by Sections 1 through 9
+  of this document.</p>
+  <p>"Licensor" shall mean the copyright owner or entity authorized
+  by the copyright owner that is granting the License.</p>
+  <p>"Legal Entity" shall mean the union of the acting entity and
+  all other entities that control, are controlled by, or are under
+  common control with that entity. For the purposes of this
+  definition, "control" means (i) the power, direct or indirect, to
+  cause the direction or management of such entity, whether by
+  contract or otherwise, or (ii) ownership of fifty percent (50%)
+  or more of the outstanding shares, or (iii) beneficial ownership
+  of such entity.</p>
+  <p>"You" (or "Your") shall mean an individual or Legal Entity
+  exercising permissions granted by this License.</p>
+  <p>"Source" form shall mean the preferred form for making
+  modifications, including but not limited to software source code,
+  documentation source, and configuration files.</p>
+  <p>"Object" form shall mean any form resulting from mechanical
+  transformation or translation of a Source form, including but not
+  limited to compiled object code, generated documentation, and
+  conversions to other media types.</p>
+  <p>"Work" shall mean the work of authorship, whether in Source or
+  Object form, made available under the License, as indicated by a
+  copyright notice that is included in or attached to the work (an
+  example is provided in the Appendix below).</p>
+  <p>"Derivative Works" shall mean any work, whether in Source or
+  Object form, that is based on (or derived from) the Work and for
+  which the editorial revisions, annotations, elaborations, or
+  other modifications represent, as a whole, an original work of
+  authorship. For the purposes of this License, Derivative Works
+  shall not include works that remain separable from, or merely
+  link (or bind by name) to the interfaces of, the Work and
+  Derivative Works thereof.</p>
+  <p>"Contribution" shall mean any work of authorship, including
+  the original version of the Work and any modifications or
+  additions to that Work or Derivative Works thereof, that is
+  intentionally submitted to Licensor for inclusion in the Work by
+  the copyright owner or by an individual or Legal Entity
+  authorized to submit on behalf of the copyright owner. For the
+  purposes of this definition, "submitted" means any form of
+  electronic, verbal, or written communication sent to the Licensor
+  or its representatives, including but not limited to
+  communication on electronic mailing lists, source code control
+  systems, and issue tracking systems that are managed by, or on
+  behalf of, the Licensor for the purpose of discussing and
+  improving the Work, but excluding communication that is
+  conspicuously marked or otherwise designated in writing by the
+  copyright owner as "Not a Contribution."</p>
+  <p>"Contributor" shall mean Licensor and any individual or Legal
+  Entity on behalf of whom a Contribution has been received by
+  Licensor and subsequently incorporated within the Work.</p>
+  <p><strong><a name="copyright" id="copyright">2. Grant of
+  Copyright License</a></strong>. Subject to the terms and
+  conditions of this License, each Contributor hereby grants to You
+  a perpetual, worldwide, non-exclusive, no-charge, royalty-free,
+  irrevocable copyright license to reproduce, prepare Derivative
+  Works of, publicly display, publicly perform, sublicense, and
+  distribute the Work and such Derivative Works in Source or Object
+  form.</p>
+  <p><strong><a name="patent" id="patent">3. Grant of Patent
+  License</a></strong>. Subject to the terms and conditions of this
+  License, each Contributor hereby grants to You a perpetual,
+  worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+  (except as stated in this section) patent license to make, have
+  made, use, offer to sell, sell, import, and otherwise transfer
+  the Work, where such license applies only to those patent claims
+  licensable by such Contributor that are necessarily infringed by
+  their Contribution(s) alone or by combination of their
+  Contribution(s) with the Work to which such Contribution(s) was
+  submitted. If You institute patent litigation against any entity
+  (including a cross-claim or counterclaim in a lawsuit) alleging
+  that the Work or a Contribution incorporated within the Work
+  constitutes direct or contributory patent infringement, then any
+  patent licenses granted to You under this License for that Work
+  shall terminate as of the date such litigation is filed.</p>
+  <p><strong><a name="redistribution" id="redistribution">4.
+  Redistribution</a></strong>. You may reproduce and distribute
+  copies of the Work or Derivative Works thereof in any medium,
+  with or without modifications, and in Source or Object form,
+  provided that You meet the following conditions:</p>
+  <ol style="list-style: lower-latin;">
+    <li>You must give any other recipients of the Work or
+    Derivative Works a copy of this License; and</li>
+    <li>You must cause any modified files to carry prominent
+    notices stating that You changed the files; and</li>
+    <li>You must retain, in the Source form of any Derivative Works
+    that You distribute, all copyright, patent, trademark, and
+    attribution notices from the Source form of the Work, excluding
+    those notices that do not pertain to any part of the Derivative
+    Works; and</li>
+    <li>If the Work includes a "NOTICE" text file as part of its
+    distribution, then any Derivative Works that You distribute
+    must include a readable copy of the attribution notices
+    contained within such NOTICE file, excluding those notices that
+    do not pertain to any part of the Derivative Works, in at least
+    one of the following places: within a NOTICE text file
+    distributed as part of the Derivative Works; within the Source
+    form or documentation, if provided along with the Derivative
+    Works; or, within a display generated by the Derivative Works,
+    if and wherever such third-party notices normally appear. The
+    contents of the NOTICE file are for informational purposes only
+    and do not modify the License. You may add Your own attribution
+    notices within Derivative Works that You distribute, alongside
+    or as an addendum to the NOTICE text from the Work, provided
+    that such additional attribution notices cannot be construed as
+    modifying the License.<br>
+    <br>
+    You may add Your own copyright statement to Your modifications
+    and may provide additional or different license terms and
+    conditions for use, reproduction, or distribution of Your
+    modifications, or for any such Derivative Works as a whole,
+    provided Your use, reproduction, and distribution of the Work
+    otherwise complies with the conditions stated in this
+    License.</li>
+  </ol>
+  <p><strong><a name="contributions" id="contributions">5.
+  Submission of Contributions</a></strong>. Unless You explicitly
+  state otherwise, any Contribution intentionally submitted for
+  inclusion in the Work by You to the Licensor shall be under the
+  terms and conditions of this License, without any additional
+  terms or conditions. Notwithstanding the above, nothing herein
+  shall supersede or modify the terms of any separate license
+  agreement you may have executed with Licensor regarding such
+  Contributions.</p>
+  <p><strong><a name="trademarks" id="trademarks">6.
+  Trademarks</a></strong>. This License does not grant permission
+  to use the trade names, trademarks, service marks, or product
+  names of the Licensor, except as required for reasonable and
+  customary use in describing the origin of the Work and
+  reproducing the content of the NOTICE file.</p>
+  <p><strong><a name="no-warranty" id="no-warranty">7. Disclaimer
+  of Warranty</a></strong>. Unless required by applicable law or
+  agreed to in writing, Licensor provides the Work (and each
+  Contributor provides its Contributions) on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+  implied, including, without limitation, any warranties or
+  conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or
+  FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for
+  determining the appropriateness of using or redistributing the
+  Work and assume any risks associated with Your exercise of
+  permissions under this License.</p>
+  <p><strong><a name="no-liability" id="no-liability">8. Limitation
+  of Liability</a></strong>. In no event and under no legal theory,
+  whether in tort (including negligence), contract, or otherwise,
+  unless required by applicable law (such as deliberate and grossly
+  negligent acts) or agreed to in writing, shall any Contributor be
+  liable to You for damages, including any direct, indirect,
+  special, incidental, or consequential damages of any character
+  arising as a result of this License or out of the use or
+  inability to use the Work (including but not limited to damages
+  for loss of goodwill, work stoppage, computer failure or
+  malfunction, or any and all other commercial damages or losses),
+  even if such Contributor has been advised of the possibility of
+  such damages.</p>
+  <p><strong><a name="additional" id="additional">9. Accepting
+  Warranty or Additional Liability</a></strong>. While
+  redistributing the Work or Derivative Works thereof, You may
+  choose to offer, and charge a fee for, acceptance of support,
+  warranty, indemnity, or other liability obligations and/or rights
+  consistent with this License. However, in accepting such
+  obligations, You may act only on Your own behalf and on Your sole
+  responsibility, not on behalf of any other Contributor, and only
+  if You agree to indemnify, defend, and hold each Contributor
+  harmless for any liability incurred by, or claims asserted
+  against, such Contributor by reason of your accepting any such
+  warranty or additional liability.</p>
+  <p>END OF TERMS AND CONDITIONS</p>
+  <h1 id="apply">APPENDIX: How to apply the Apache License to your
+  work<a class="headerlink" href="#apply" title=
+  "Permanent link">?</a></h1>
+  <p>To apply the Apache License to your work, attach the following
+  boilerplate notice, with the fields enclosed by brackets "[]"
+  replaced with your own identifying information. (Don't include
+  the brackets!) The text should be enclosed in the appropriate
+  comment syntax for the file format. We also recommend that a file
+  or class name and description of purpose be included on the same
+  "printed page" as the copyright notice for easier identification
+  within third-party archives.</p>
+  <div class="codehilite">
+    <pre>Copyright [yyyy] [name of copyright owner]
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+    </pre>
+  </div>
+</div>
+
+</body>
+</html>

+ 76 - 0
ureport2-console/pom.xml

@@ -0,0 +1,76 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+	<parent>
+		<artifactId>jnpf-datareport</artifactId>
+		<groupId>com.jnpf</groupId>
+		<version>6.0.0-RELEASE</version>
+	</parent>
+	<modelVersion>4.0.0</modelVersion>
+
+	<artifactId>ureport2-console</artifactId>
+
+	<dependencies>
+		<dependency>
+			<groupId>com.jnpf</groupId>
+			<artifactId>ureport2-core</artifactId>
+			<version>${project.version}</version>
+		</dependency>
+		<dependency>
+			<groupId>com.jnpf</groupId>
+			<artifactId>ureport2-font</artifactId>
+			<version>${project.version}</version>
+		</dependency>
+		<dependency>
+			<groupId>com.jnpf</groupId>
+			<artifactId>jnpf-common-security</artifactId>
+			<version>${project.version}</version>
+		</dependency>
+    </dependencies>
+	<licenses>
+		<license>
+			<name>The Apache License, Version 2.0</name>
+			<url>http://www.apache.org/licenses/LICENSE-2.0.txt</url>
+		</license>
+	</licenses>
+	<developers>
+		<developer>
+			<name>Gaojie</name>
+			<email>@bstek.com</email>
+			<organization>Bstek</organization>
+			<organizationUrl>http://www.bstek.com</organizationUrl>
+		</developer>
+	</developers>
+	<scm>
+		<connection>https://github.com/youseries/ureport.git</connection>
+		<developerConnection>https://github.com/youseries/ureport.git</developerConnection>
+		<url>https://github.com/youseries/ureport</url>
+	</scm>
+	<organization>
+		<name>Bstek</name>
+		<url>http://www.bstek.com</url>
+	</organization>
+	<name>UReport2 Console Project</name>
+	<url>https://github.com/youseries/ureport/tree/master/ureport2-console</url>
+
+	<build>
+		<finalName>jnpf-datareport-${project.version}</finalName>
+		<plugins>
+			<plugin>
+				<groupId>org.springframework.boot</groupId>
+				<artifactId>spring-boot-maven-plugin</artifactId>
+				<configuration>
+					<!-- 指定该Main Class为全局的唯一入口 -->
+					<mainClass>com.bstek.ureport.console.DataReportApplication</mainClass>
+					<layout>ZIP</layout>
+				</configuration>
+				<executions>
+					<execution>
+						<goals>
+							<goal>repackage</goal><!--可以把依赖的包都打包到生成的Jar包中-->
+						</goals>
+					</execution>
+				</executions>
+			</plugin>
+		</plugins>
+	</build>
+</project>

+ 125 - 0
ureport2-console/src/main/java/com/bstek/ureport/console/BaseServletAction.java

@@ -0,0 +1,125 @@
+/*******************************************************************************
+ * Copyright 2017 Bstek
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License.  You may obtain a copy
+ * of the License at
+ * 
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ ******************************************************************************/
+package com.bstek.ureport.console;
+
+import java.lang.reflect.Method;
+import java.net.URLDecoder;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.Map;
+
+import jakarta.servlet.ServletException;
+import jakarta.servlet.http.HttpServletRequest;
+import jakarta.servlet.http.HttpServletResponse;
+
+import org.apache.commons.lang3.StringUtils;
+
+
+/**
+ * @author
+ * @since 2016年6月3日
+ */
+public abstract class BaseServletAction implements ServletAction {
+	protected Throwable buildRootException(Throwable throwable){
+		if(throwable.getCause()==null){
+			return throwable;
+		}
+		return buildRootException(throwable.getCause());
+	}
+
+	protected String decode(String value){
+		if(value==null){
+			return value;
+		}
+		try{
+			value=URLDecoder.decode(value, "utf-8");
+			value=URLDecoder.decode(value, "utf-8");
+			return value;
+		}catch(Exception ex){
+			return value;
+		}
+	}
+	protected String decodeContent(String content){
+		if(content==null){
+			return content;
+		}
+		try{
+			content=URLDecoder.decode(content, "utf-8");
+			return content;
+		}catch(Exception ex){
+			return content;
+		}
+	}
+	
+	protected Map<String, Object> buildParameters(HttpServletRequest req) {
+		Map<String,Object> parameters=new HashMap<String,Object>();
+		Enumeration<?> enumeration=req.getParameterNames();
+		while(enumeration.hasMoreElements()){
+			Object obj=enumeration.nextElement();
+			if(obj==null){
+				continue;
+			}
+			String name=obj.toString();
+			String value=req.getParameter(name);
+			if(name==null || value==null || name.startsWith("_")){
+				continue;
+			}
+			parameters.put(name, decode(value));
+		}
+		return parameters;
+	}
+	
+	protected void invokeMethod(String methodName,HttpServletRequest req,HttpServletResponse resp) throws ServletException{
+		try{
+			Method method=this.getClass().getMethod(methodName, new Class<?>[]{HttpServletRequest.class,HttpServletResponse.class});			
+			method.invoke(this, new Object[]{req,resp});
+		}catch(Exception ex){
+			throw new ServletException(ex);
+		}
+	}
+	
+	protected String retriveMethod(HttpServletRequest req) throws ServletException{
+		String path=req.getContextPath()+UReportServlet.URL;
+		String uri=req.getRequestURI();
+		String targetUrl=uri.substring(path.length());
+		int slashPos=targetUrl.indexOf("/",1);
+		if(slashPos>-1){
+			String methodName=targetUrl.substring(slashPos+1).trim();
+			return methodName.length()>0 ? methodName : null;
+		}
+		return null;
+	}
+	
+	protected String buildDownloadFileName(String reportFileName,String fileName,String extName){
+		if(StringUtils.isNotBlank(fileName)){
+			fileName=decode(fileName);
+			if(!fileName.toLowerCase().endsWith(extName)){
+				fileName=fileName+extName;
+			}
+			return fileName;
+		}else{
+			int pos=reportFileName.indexOf(":");
+			if(pos>0){
+				reportFileName=reportFileName.substring(pos+1,reportFileName.length());
+			}
+			pos=reportFileName.toLowerCase().indexOf(".ureport.xml");
+			if(pos>0){
+				reportFileName=reportFileName.substring(0,pos);
+			}
+			return "ureport-"+reportFileName+extName;
+		}
+	}
+}

+ 36 - 0
ureport2-console/src/main/java/com/bstek/ureport/console/DataReportApplication.java

@@ -0,0 +1,36 @@
+package com.bstek.ureport.console;
+
+import com.bstek.ureport.console.config.DataReportListener;
+import jakarta.servlet.MultipartConfigElement;
+import org.mybatis.spring.annotation.MapperScan;
+import org.springframework.beans.factory.ObjectProvider;
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
+import org.springframework.boot.web.servlet.ServletRegistrationBean;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.ImportResource;
+
+/**
+ * 启动类
+ * @author Administrator
+ */
+@SpringBootApplication(scanBasePackages ={"com.bstek.ureport.console","com.bstek.ureport.utils", "jnpf"},exclude = {DataSourceAutoConfiguration.class})
+@ImportResource("classpath:ureport.xml")
+@MapperScan(basePackages = {"com.bstek.ureport.console.ureport.mapper"})
+public class DataReportApplication {
+
+    public static void main(String[] args) {
+        SpringApplication springApplication = new SpringApplication(DataReportApplication.class);
+        //添加监听器
+        springApplication.addListeners(new DataReportListener());
+        springApplication.run(args);
+    }
+
+    @Bean
+    public ServletRegistrationBean<UReportServlet> buildUreportServlet(ObjectProvider<MultipartConfigElement> multipartConfig){
+        ServletRegistrationBean<UReportServlet> servletRegistrationBean = new ServletRegistrationBean<>(new UReportServlet(), "/*");
+        multipartConfig.ifAvailable(servletRegistrationBean::setMultipartConfig);
+        return servletRegistrationBean;
+    }
+}

+ 52 - 0
ureport2-console/src/main/java/com/bstek/ureport/console/MobileUtils.java

@@ -0,0 +1,52 @@
+/*******************************************************************************
+ * Copyright 2017 Bstek
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License.  You may obtain a copy
+ * of the License at
+ * 
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ ******************************************************************************/
+package com.bstek.ureport.console;
+
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import jakarta.servlet.http.HttpServletRequest;
+
+/**
+ * @author
+ * @since 10月11日
+ */
+public class MobileUtils {
+	private static String phoneReg = "\\b(ip(hone|od)|android|opera m(ob|in)i"    
+            +"|windows (phone|ce)|blackberry"    
+            +"|s(ymbian|eries60|amsung)|p(laybook|alm|rofile/midp"    
+            +"|laystation portable)|nokia|fennec|htc[-_]"    
+            +"|mobile|up.browser|[1-4][0-9]{2}x[1-4][0-9]{2})\\b";    
+	private static String tableReg = "\\b(ipad|tablet|(Nexus 7)|up.browser"    
+            +"|[1-4][0-9]{2}x[1-4][0-9]{2})\\b";
+	private static Pattern phonePat = Pattern.compile(phoneReg, Pattern.CASE_INSENSITIVE);
+	private static Pattern tablePat = Pattern.compile(tableReg, Pattern.CASE_INSENSITIVE);
+	
+	public static boolean isMobile(HttpServletRequest req){
+		String userAgent = req.getHeader("USER-AGENT");  
+        if(userAgent==null){    
+            userAgent = "";    
+        }
+        userAgent=userAgent.toLowerCase();
+        Matcher matcherPhone = phonePat.matcher(userAgent);    
+        Matcher matcherTable = tablePat.matcher(userAgent);    
+        if(matcherPhone.find() || matcherTable.find()){    
+            return true;    
+        } else {    
+            return false;    
+        }    
+    } 
+}

+ 42 - 0
ureport2-console/src/main/java/com/bstek/ureport/console/RenderPageServletAction.java

@@ -0,0 +1,42 @@
+/*******************************************************************************
+ * Copyright 2017 Bstek
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License.  You may obtain a copy
+ * of the License at
+ * 
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ ******************************************************************************/
+package com.bstek.ureport.console;
+
+import org.apache.velocity.app.Velocity;
+import org.apache.velocity.app.VelocityEngine;
+import org.apache.velocity.runtime.RuntimeConstants;
+import org.springframework.beans.BeansException;
+import org.springframework.context.ApplicationContext;
+import org.springframework.context.ApplicationContextAware;
+
+
+/**
+ * @author
+ * @since 2016年6月6日
+ */
+public abstract class RenderPageServletAction extends WriteJsonServletAction implements ApplicationContextAware{
+	protected VelocityEngine ve;
+	protected ApplicationContext applicationContext;
+	@Override
+	public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
+		this.applicationContext=applicationContext;
+		ve = new VelocityEngine();
+		ve.setProperty(Velocity.RESOURCE_LOADER, "class");
+		ve.setProperty("class.resource.loader.class","org.apache.velocity.runtime.resource.loader.ClasspathResourceLoader");
+//		ve.setProperty(RuntimeConstants.RUNTIME_LOG_LOGSYSTEM,new NullLogChute());
+		ve.init();	
+	}
+}

+ 35 - 0
ureport2-console/src/main/java/com/bstek/ureport/console/RequestHolder.java

@@ -0,0 +1,35 @@
+/*******************************************************************************
+ * Copyright 2017 Bstek
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License.  You may obtain a copy
+ * of the License at
+ * 
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ ******************************************************************************/
+package com.bstek.ureport.console;
+
+import jakarta.servlet.http.HttpServletRequest;
+
+/**
+ * @author
+ * @since 3月8日
+ */
+public class RequestHolder {
+	private static final ThreadLocal<HttpServletRequest> requestThreadLocal=new ThreadLocal<HttpServletRequest>();
+	public static void setRequest(HttpServletRequest request){
+		requestThreadLocal.set(request);
+	}
+	public static HttpServletRequest getRequest(){
+		return requestThreadLocal.get();
+	}
+	public static void clean(){
+		requestThreadLocal.remove();
+	}
+}

+ 32 - 0
ureport2-console/src/main/java/com/bstek/ureport/console/ServletAction.java

@@ -0,0 +1,32 @@
+/*******************************************************************************
+ * Copyright 2017 Bstek
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License.  You may obtain a copy
+ * of the License at
+ * 
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ ******************************************************************************/
+package com.bstek.ureport.console;
+
+import java.io.IOException;
+
+import jakarta.servlet.ServletException;
+import jakarta.servlet.http.HttpServletRequest;
+import jakarta.servlet.http.HttpServletResponse;
+
+/**
+ * @author 
+ * @since 1月25日
+ */
+public interface ServletAction {
+	public static final String PREVIEW_KEY="p";
+	void execute(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException;
+	String url();
+}

+ 158 - 0
ureport2-console/src/main/java/com/bstek/ureport/console/UReportServlet.java

@@ -0,0 +1,158 @@
+/*******************************************************************************
+ * Copyright 2017 Bstek
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License.  You may obtain a copy
+ * of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ ******************************************************************************/
+package com.bstek.ureport.console;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.PrintWriter;
+import java.text.SimpleDateFormat;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Map;
+
+import com.fasterxml.jackson.annotation.JsonInclude;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.SerializationFeature;
+import jakarta.servlet.ServletConfig;
+import jakarta.servlet.ServletException;
+import jakarta.servlet.http.HttpServlet;
+import jakarta.servlet.http.HttpServletRequest;
+import jakarta.servlet.http.HttpServletResponse;
+
+import com.bstek.ureport.console.util.ActionResult;
+import jnpf.util.UserProvider;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.web.context.WebApplicationContext;
+import org.springframework.web.context.support.SpringBeanAutowiringSupport;
+import org.springframework.web.context.support.WebApplicationContextUtils;
+
+/**
+ * @author
+ * @since 1月25日
+ */
+@Slf4j
+public class UReportServlet extends HttpServlet {
+
+
+    private static final long serialVersionUID = 533049461276487971L;
+    public static final String URL = "";
+    private Map<String, ServletAction> actionMap = new HashMap<String, ServletAction>();
+
+    @Override
+    public void init(ServletConfig config) throws ServletException {
+        super.init(config);
+        WebApplicationContext applicationContext = getWebApplicationContext(config);
+        Collection<ServletAction> handlers = applicationContext.getBeansOfType(ServletAction.class).values();
+        for (ServletAction handler : handlers) {
+            String url = handler.url();
+            if (actionMap.containsKey(url)) {
+                throw new RuntimeException("Handler [" + url + "] already exist.");
+            }
+            actionMap.put(url, handler);
+        }
+        //使@Autowired生效
+        SpringBeanAutowiringSupport.processInjectionBasedOnServletContext(this,
+                config.getServletContext());
+    }
+
+    protected WebApplicationContext getWebApplicationContext(ServletConfig config) {
+        return WebApplicationContextUtils.getWebApplicationContext(config.getServletContext());
+    }
+
+
+
+    @Override
+    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
+        String path = req.getContextPath() + URL;
+        String uri = req.getRequestURI();
+        String targetUrl = uri.substring(path.length());
+        if (targetUrl.length() < 1) {
+            outContent(resp, "Welcome to use ureport,please specify target url.");
+            return;
+        }
+        int slashPos = targetUrl.indexOf("/", 1);
+        if (slashPos > -1) {
+            targetUrl = targetUrl.substring(0, slashPos);
+        }
+        ServletAction targetHandler = actionMap.get(targetUrl);
+        if (targetHandler == null) {
+            outContent(resp, "Handler [" + targetUrl + "] not exist.");
+            return;
+        }
+        RequestHolder.setRequest(req);
+        try {
+            String userId = UserProvider.getLoginUserId();
+            if(userId != null){
+                targetHandler.execute(req, resp);
+                return;
+            }
+            writeObjectToJson(resp, ActionResult.fail("token验证失败"));
+        } catch (Exception ex) {
+//			resp.setCharacterEncoding("UTF-8");
+//			PrintWriter pw=resp.getWriter();
+//			Throwable e=buildRootException(ex);
+//			resp.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
+//			String errorMsg = e.getMessage();
+//			if(StringUtils.isBlank(errorMsg)){
+//				errorMsg=e.getClass().getName();
+//			}
+//			pw.write(errorMsg);
+//			pw.close();
+//			throw new ServletException(ex);
+            log.error(ex.getMessage(), ex);
+//			ex.printStackTrace();
+            writeObjectToJson(resp, ActionResult.fail("请检查接口路径、参数和数据库连接"));
+        } finally {
+            RequestHolder.clean();
+        }
+    }
+
+    private Throwable buildRootException(Throwable throwable) {
+        if (throwable.getCause() == null) {
+            return throwable;
+        }
+        return buildRootException(throwable.getCause());
+    }
+
+    private void outContent(HttpServletResponse resp, String msg) throws IOException {
+        resp.setContentType("text/html");
+        PrintWriter pw = resp.getWriter();
+        pw.write("<html>");
+        pw.write("<header><title>UReport Console</title></header>");
+        pw.write("<body>");
+        pw.write(msg);
+        pw.write("</body>");
+        pw.write("</html>");
+        pw.flush();
+        pw.close();
+    }
+
+    protected void writeObjectToJson(HttpServletResponse resp, Object obj) throws IOException {
+        resp.setContentType("text/json");
+        resp.setCharacterEncoding("UTF-8");
+        ObjectMapper mapper = new ObjectMapper();
+        mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
+        mapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);
+        mapper.setDateFormat(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"));
+        OutputStream out = resp.getOutputStream();
+        try {
+            mapper.writeValue(out, obj);
+        } finally {
+            out.flush();
+            out.close();
+        }
+    }
+}

+ 48 - 0
ureport2-console/src/main/java/com/bstek/ureport/console/WriteJsonServletAction.java

@@ -0,0 +1,48 @@
+/*******************************************************************************
+ * Copyright 2017 Bstek
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License.  You may obtain a copy
+ * of the License at
+ * 
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ ******************************************************************************/
+package com.bstek.ureport.console;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.text.SimpleDateFormat;
+
+import com.fasterxml.jackson.annotation.JsonInclude;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.SerializationFeature;
+import jakarta.servlet.http.HttpServletResponse;
+
+
+/**
+ * @author
+ * @since 2016年5月23日
+ */
+public abstract class WriteJsonServletAction extends BaseServletAction{
+	protected void writeObjectToJson(HttpServletResponse resp,Object obj) throws IOException{
+		resp.setContentType("application/json");
+		resp.setCharacterEncoding("UTF-8");
+		ObjectMapper mapper = new ObjectMapper();
+		mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
+		mapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);
+		mapper.setDateFormat(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"));
+		OutputStream out = resp.getOutputStream();
+		try {
+			mapper.writeValue(out, obj);
+		} finally {
+			out.flush();
+			out.close();
+		}
+	}
+}

+ 85 - 0
ureport2-console/src/main/java/com/bstek/ureport/console/cache/HttpSessionReportCache.java

@@ -0,0 +1,85 @@
+/*******************************************************************************
+ * Copyright 2017 Bstek
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License.  You may obtain a copy
+ * of the License at
+ * 
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ ******************************************************************************/
+package com.bstek.ureport.console.cache;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import jakarta.servlet.http.HttpServletRequest;
+
+import com.bstek.ureport.cache.ReportCache;
+import com.bstek.ureport.console.RequestHolder;
+
+/**
+ * @author
+ * @since 3月8日
+ */
+public class HttpSessionReportCache implements ReportCache {
+	private Map<String,ObjectMap> sessionReportMap=new HashMap<String,ObjectMap>();
+	private boolean disabled;
+	@Override
+	public Object getObject(String file) {
+		HttpServletRequest req=RequestHolder.getRequest();
+		if(req==null){
+			return null;
+		}
+		ObjectMap objMap = getObjectMap(req);
+		return objMap.get(file);
+	}
+
+	@Override
+	public void storeObject(String file, Object object) {
+		HttpServletRequest req=RequestHolder.getRequest();
+		if(req==null){
+			return;
+		}
+		ObjectMap map = getObjectMap(req);
+		map.put(file, object);
+	}
+	
+	@Override
+	public boolean disabled() {
+		return disabled;
+	}
+	
+	public void setDisabled(boolean disabled) {
+		this.disabled = disabled;
+	}
+
+	private ObjectMap getObjectMap(HttpServletRequest req) {
+		List<String> expiredList=new ArrayList<String>();
+		for(String key:sessionReportMap.keySet()){
+			ObjectMap reportObj=sessionReportMap.get(key);
+			if(reportObj.isExpired()){
+				expiredList.add(key);
+			}
+		}
+		for(String key:expiredList){
+			sessionReportMap.remove(key);
+		}
+		String sessionId=req.getSession().getId();
+		ObjectMap obj=sessionReportMap.get(sessionId);
+		if(obj!=null){
+			return obj;
+		}else{
+			ObjectMap objMap=new ObjectMap();
+			sessionReportMap.put(sessionId, objMap);
+			return objMap;
+		}
+	}
+}

+ 67 - 0
ureport2-console/src/main/java/com/bstek/ureport/console/cache/ObjectMap.java

@@ -0,0 +1,67 @@
+/*******************************************************************************
+ * Copyright 2017 Bstek
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License.  You may obtain a copy
+ * of the License at
+ * 
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ ******************************************************************************/
+package com.bstek.ureport.console.cache;
+
+import java.util.Iterator;
+import java.util.LinkedHashMap;
+import java.util.Map;
+import java.util.Map.Entry;
+
+/**
+ * @author
+ * @since 9月6日
+ */
+public class ObjectMap {
+	private final int MAX_ITEM=3;
+	private static final int MILLISECOND=300000;//设置缓存时间
+	private Map<String, Object> map=new LinkedHashMap<String, Object>();
+	private long start;
+	public ObjectMap() {
+		this.start=System.currentTimeMillis();
+	}
+	public void put(String key,Object obj){
+		this.start=System.currentTimeMillis();
+		if(map.containsKey(key)){
+			map.remove(key);
+		}else{
+			if(map.size()>MAX_ITEM){
+				String lastFile=null;
+				for(Iterator<Entry<String,Object>> it=map.entrySet().iterator();it.hasNext();){
+					Entry<String,Object> entry=it.next();
+					lastFile=entry.getKey();
+					break;
+				}
+				map.remove(lastFile);
+			}
+		}
+		map.put(key, obj);
+	}
+	public Object get(String key){
+		this.start=System.currentTimeMillis();
+		return this.map.get(key);
+	}
+	public void remove(String key){
+		this.map.remove(key);
+	}
+	public boolean isExpired(){
+		long end=System.currentTimeMillis();
+		long value=end-start;
+		if(value>=MILLISECOND){
+			return true;
+		}
+		return false;
+	}
+}

+ 98 - 0
ureport2-console/src/main/java/com/bstek/ureport/console/cache/TempObjectCache.java

@@ -0,0 +1,98 @@
+/*******************************************************************************
+ * Copyright 2017 Bstek
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License.  You may obtain a copy
+ * of the License at
+ * 
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ ******************************************************************************/
+package com.bstek.ureport.console.cache;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import jakarta.servlet.http.HttpServletRequest;
+
+import com.bstek.ureport.console.RequestHolder;
+import jnpf.util.UserProvider;
+
+
+/**
+ * @author 
+ * @since 9月6日
+ */
+public class TempObjectCache{
+	private static TempObjectCache tempObjectCache=new TempObjectCache();
+	private Map<String,ObjectMap> sessionMap=new HashMap<String,ObjectMap>();
+	public static Object getObject(String key){
+		return tempObjectCache.get(key);
+	}
+	public static void putObject(String key,Object obj){
+		tempObjectCache.store(key, obj);
+	}
+	
+	public static void removeObject(String key){
+		tempObjectCache.remove(key);
+	}
+	
+	public void remove(String key){
+		HttpServletRequest req=RequestHolder.getRequest();
+		if(req==null){
+			return;
+		}
+		ObjectMap mapObject = getReportMap(req);
+		if(mapObject!=null){
+			mapObject.remove(key);
+		}
+	}
+	
+	public Object get(String key) {
+		HttpServletRequest req=RequestHolder.getRequest();
+		if(req==null){
+			return null;
+		}
+		ObjectMap mapObject = getReportMap(req);
+		return mapObject.get(key);
+	}
+
+	public void store(String key, Object obj) {
+		HttpServletRequest req=RequestHolder.getRequest();
+		if(req==null){
+			return;
+		}
+		ObjectMap mapObject = getReportMap(req);
+		mapObject.put(key, obj);
+	}
+
+	private ObjectMap getReportMap(HttpServletRequest req) {
+		List<String> expiredList=new ArrayList<String>();
+		for(String key:sessionMap.keySet()){
+			ObjectMap reportObj=sessionMap.get(key);
+			if(reportObj.isExpired()){
+				expiredList.add(key);
+			}
+		}
+		for(String key:expiredList){
+			sessionMap.remove(key);
+		}
+//		String sessionId=req.getSession().getId();
+		String sessionId = UserProvider.getUser().getToken();
+		ObjectMap obj=sessionMap.get(sessionId);
+		if(obj!=null){
+			return obj;
+		}else{
+			ObjectMap mapObject=new ObjectMap();
+			sessionMap.put(sessionId, mapObject);
+			return mapObject;
+		}
+	}
+}

+ 50 - 0
ureport2-console/src/main/java/com/bstek/ureport/console/chart/ChartServletAction.java

@@ -0,0 +1,50 @@
+/*******************************************************************************
+ * Copyright 2017 Bstek
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License.  You may obtain a copy
+ * of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ ******************************************************************************/
+package com.bstek.ureport.console.chart;
+
+import java.io.IOException;
+
+import jakarta.servlet.ServletException;
+import jakarta.servlet.http.HttpServletRequest;
+import jakarta.servlet.http.HttpServletResponse;
+
+import com.bstek.ureport.cache.*;
+import com.bstek.ureport.chart.ChartData;
+import com.bstek.ureport.console.RenderPageServletAction;
+import com.bstek.ureport.console.util.ActionResult;
+import com.bstek.ureport.utils.UnitUtils;
+
+/**
+ * @author
+ * @since 6月30日
+ */
+public class ChartServletAction extends RenderPageServletAction {
+	@Override
+	public void execute(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
+		storeData(req, resp);
+		writeObjectToJson(resp, ActionResult.success());
+	}
+
+	public void storeData(HttpServletRequest req, HttpServletResponse resp)  {
+		String chartId = req.getParameter("_chartId");
+		CacheUtils.setChartData(chartId);
+	}
+
+	@Override
+	public String url() {
+		return "/chart";
+	}
+}

+ 13 - 0
ureport2-console/src/main/java/com/bstek/ureport/console/config/DataReportListener.java

@@ -0,0 +1,13 @@
+package com.bstek.ureport.console.config;
+
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.context.ApplicationListener;
+import org.springframework.context.event.ContextRefreshedEvent;
+
+@Slf4j
+public class DataReportListener implements ApplicationListener<ContextRefreshedEvent> {
+    @Override
+    public void onApplicationEvent(ContextRefreshedEvent event) {
+        System.out.println("报表启动完成");
+    }
+}

+ 54 - 0
ureport2-console/src/main/java/com/bstek/ureport/console/designer/DataResult.java

@@ -0,0 +1,54 @@
+/*******************************************************************************
+ * Copyright 2017 Bstek
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License.  You may obtain a copy
+ * of the License at
+ * 
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ ******************************************************************************/
+package com.bstek.ureport.console.designer;
+
+import java.util.List;
+import java.util.Map;
+
+/**
+ * @author
+ * @since 3月13日
+ */
+public class DataResult {
+	private List<Map<String,Object>> data;
+	private List<String> fields;
+	private int total;
+	private int currentTotal;
+	public List<Map<String, Object>> getData() {
+		return data;
+	}
+	public void setData(List<Map<String, Object>> data) {
+		this.data = data;
+	}
+	public List<String> getFields() {
+		return fields;
+	}
+	public void setFields(List<String> fields) {
+		this.fields = fields;
+	}
+	public int getTotal() {
+		return total;
+	}
+	public void setTotal(int total) {
+		this.total = total;
+	}
+	public int getCurrentTotal() {
+		return currentTotal;
+	}
+	public void setCurrentTotal(int currentTotal) {
+		this.currentTotal = currentTotal;
+	}
+}

+ 517 - 0
ureport2-console/src/main/java/com/bstek/ureport/console/designer/DatasourceServletAction.java

@@ -0,0 +1,517 @@
+/*******************************************************************************
+ * Copyright 2017 Bstek
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License.  You may obtain a copy
+ * of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ ******************************************************************************/
+package com.bstek.ureport.console.designer;
+
+import java.beans.PropertyDescriptor;
+import java.io.IOException;
+import java.lang.reflect.Method;
+import java.sql.Connection;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.ResultSetMetaData;
+import java.sql.SQLException;
+import java.util.*;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import jakarta.servlet.ServletException;
+import jakarta.servlet.http.HttpServletRequest;
+import jakarta.servlet.http.HttpServletResponse;
+import javax.sql.DataSource;
+
+import com.bstek.ureport.console.config.SysConfig;
+import com.bstek.ureport.console.util.ActionResult;
+import com.bstek.ureport.console.util.UReportJdbcUtil;
+import com.bstek.ureport.utils.TenantLineSqlParseUtil;
+import jnpf.database.model.entity.DbLinkEntity;
+import jnpf.database.source.DbBase;
+import jnpf.database.util.ConnUtil;
+import jnpf.database.util.DataSourceUtil;
+import jnpf.database.util.DbTypeUtil;
+import jnpf.database.util.DynamicDataSourceUtil;
+import jnpf.util.DesUtil;
+import org.apache.commons.beanutils.PropertyUtils;
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.dao.DataAccessException;
+import org.springframework.jdbc.core.PreparedStatementCallback;
+import org.springframework.jdbc.core.PreparedStatementCreator;
+import org.springframework.jdbc.core.PreparedStatementCreatorFactory;
+import org.springframework.jdbc.core.SqlParameter;
+import org.springframework.jdbc.core.namedparam.MapSqlParameterSource;
+import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate;
+import org.springframework.jdbc.core.namedparam.NamedParameterUtils;
+import org.springframework.jdbc.core.namedparam.ParsedSql;
+import org.springframework.jdbc.core.namedparam.SqlParameterSource;
+import org.springframework.jdbc.datasource.SingleConnectionDataSource;
+import org.springframework.jdbc.support.JdbcUtils;
+
+import com.bstek.ureport.Utils;
+import com.bstek.ureport.build.Context;
+import com.bstek.ureport.console.RenderPageServletAction;
+import com.bstek.ureport.console.exception.ReportDesignException;
+import com.bstek.ureport.definition.dataset.Field;
+import com.bstek.ureport.definition.datasource.DataType;
+import com.bstek.ureport.expression.ExpressionUtils;
+import com.bstek.ureport.expression.model.Expression;
+import com.bstek.ureport.expression.model.data.ExpressionData;
+import com.bstek.ureport.expression.model.data.ObjectExpressionData;
+import com.bstek.ureport.utils.ProcedureUtils;
+
+/**
+ * @author
+ * @since 2月6日
+ */
+public class DatasourceServletAction extends RenderPageServletAction {
+    @Autowired
+    private SysConfig sysConfig;
+    @Autowired
+    private DataSourceUtil dataSourceUtil;
+
+    @Override
+    public void execute(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
+        String method = retriveMethod(req);
+        if (method != null) {
+            invokeMethod(method, req, resp);
+        }
+    }
+
+    //内置数据源名称
+    public void loadBuildinDatasources(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
+
+        try {
+            String dbName = dataSourceUtil.getDbName();
+            List<String> list = new ArrayList<>();
+            list.add(dbName);
+            writeObjectToJson(resp, list);
+        } catch (Exception e) {
+            writeObjectToJson(resp, ActionResult.fail("请先配置正确的数据源"));
+        }
+    }
+
+    public void loadMethods(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
+        String beanId = req.getParameter("beanId");
+        Object obj = applicationContext.getBean(beanId);
+        Class<?> clazz = obj.getClass();
+        Method[] methods = clazz.getMethods();
+        List<String> result = new ArrayList<String>();
+        for (Method method : methods) {
+            Class<?>[] types = method.getParameterTypes();
+            if (types.length != 3) {
+                continue;
+            }
+            Class<?> typeClass1 = types[0];
+            Class<?> typeClass2 = types[1];
+            Class<?> typeClass3 = types[2];
+            if (!String.class.isAssignableFrom(typeClass1)) {
+                continue;
+            }
+            if (!String.class.isAssignableFrom(typeClass2)) {
+                continue;
+            }
+            if (!Map.class.isAssignableFrom(typeClass3)) {
+                continue;
+            }
+            result.add(method.getName());
+        }
+        writeObjectToJson(resp, result);
+    }
+
+    public void buildClass(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
+        String clazz = req.getParameter("clazz");
+        List<Field> result = new ArrayList<Field>();
+        try {
+            Class<?> targetClass = Class.forName(clazz);
+            PropertyDescriptor[] propertyDescriptors = PropertyUtils.getPropertyDescriptors(targetClass);
+            for (PropertyDescriptor pd : propertyDescriptors) {
+                String name = pd.getName();
+                if ("class".equals(name)) {
+                    continue;
+                }
+                result.add(new Field(name));
+            }
+            writeObjectToJson(resp, result);
+        } catch (Exception ex) {
+            throw new ReportDesignException(ex);
+        }
+    }
+
+    //添加数据集
+    public void buildDatabaseTables(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
+        List<Map<String, String>> tables = new ArrayList<Map<String, String>>();
+        try {
+            tables = buildDatabase(req);
+        } catch (Exception ex) {
+            throw new ServletException(ex);
+        }
+        writeObjectToJson(resp, tables);
+    }
+
+    private List<Map<String, String>> buildDatabase(HttpServletRequest req) throws ServletException {
+        Connection conn = null;
+        PreparedStatement preparedStatement = null;
+        List<Map<String, String>> tables;
+        try {
+            String type = req.getParameter("type");
+            if ("buildin".equals(type)) {
+                conn = DynamicDataSourceUtil.getCurrentConnection();
+                tables = UReportJdbcUtil.getDataTables(conn, null);
+            } else {
+                String username = req.getParameter("username");
+                String password = req.getParameter("password");
+                password = DesUtil.aesOrDecode(password, false, true);
+//                String driver = req.getParameter("driver");
+                String url = req.getParameter("url");
+                DbLinkEntity dbLinkEntity = DynamicDataSourceUtil.switchToDataSource(username, password, url, null);
+                conn = ConnUtil.getConn(dbLinkEntity);
+                tables = UReportJdbcUtil.getDataTables(conn, dbLinkEntity);
+            }
+        } catch (Exception ex) {
+            throw new ServletException(ex);
+        } finally {
+            JdbcUtils.closeStatement(preparedStatement);
+            JdbcUtils.closeConnection(conn);
+        }
+        return tables;
+    }
+
+    public void buildFields(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
+        String sql = req.getParameter("sql");
+        String parameters = req.getParameter("parameters");
+        String type = req.getParameter("type");
+        Connection conn = null;
+        final List<Field> fields = new ArrayList<Field>();
+        try {
+            if ("buildin".equals(type)) {
+                conn = DynamicDataSourceUtil.getCurrentConnection();
+                Map<String, Object> map = buildParameters(parameters, conn);
+                sql = parseSql(sql, map);
+                UReportJdbcUtil.checkSqlSafe(sql, conn, null);
+                if (ProcedureUtils.isProcedure(sql)) {
+                    List<Field> fieldsList = ProcedureUtils.procedureColumnsQuery(sql, map, conn);
+                    fields.addAll(fieldsList);
+                } else {
+                    //不查询数据, 只返回列数据
+                    sql = String.format("select * from (%s) temp_table_00 where 1=2", sql);
+                    DataSource dataSource = new SingleConnectionDataSource(conn, false);
+                    NamedParameterJdbcTemplate jdbc = new NamedParameterJdbcTemplate(dataSource);
+                    PreparedStatementCreator statementCreator = getPreparedStatementCreator(sql, new MapSqlParameterSource(map));
+                    //获取字段只需要一行数据
+                    jdbc.getJdbcTemplate().setQueryTimeout(sysConfig.getQueryTimeout());
+                    jdbc.getJdbcTemplate().setMaxRows(1);
+                    jdbc.getJdbcOperations().execute(statementCreator, new PreparedStatementCallback<Object>() {
+                        @Override
+                        public Object doInPreparedStatement(PreparedStatement ps) throws SQLException, DataAccessException {
+                            ResultSet rs = null;
+                            try {
+                                rs = ps.executeQuery();
+                                ResultSetMetaData metadata = rs.getMetaData();
+                                int columnCount = metadata.getColumnCount();
+                                for (int i = 0; i < columnCount; i++) {
+                                    String columnName = metadata.getColumnLabel(i + 1);
+                                    fields.add(new Field(columnName));
+                                }
+                                return null;
+                            } finally {
+                                JdbcUtils.closeResultSet(rs);
+                            }
+                        }
+                    });
+                }
+                writeObjectToJson(resp, fields);
+            } else {
+                String username = req.getParameter("username");
+                String password = req.getParameter("password");
+                password = DesUtil.aesOrDecode(password, false, true);
+//                String driver = req.getParameter("driver");
+                String url = req.getParameter("url");
+                DbLinkEntity dbLinkEntity = DynamicDataSourceUtil.switchToDataSource(username, password, url, null);
+                conn = ConnUtil.getConn(dbLinkEntity);
+                Map<String, Object> map = buildParameters(parameters, conn);
+                sql = parseSql(sql, map);
+                UReportJdbcUtil.checkSqlSafe(sql, conn, dbLinkEntity);
+                if (ProcedureUtils.isProcedure(sql)) {
+                    List<Field> fieldsList = ProcedureUtils.procedureColumnsQuery(sql, map, conn);
+                    fields.addAll(fieldsList);
+                } else {
+                    //不查询数据, 只返回列数据
+                    sql = String.format("select * from (%s) temp_table_00 where 1=2", sql);
+                    DataSource dataSource = new SingleConnectionDataSource(conn, false);
+                    NamedParameterJdbcTemplate jdbc = new NamedParameterJdbcTemplate(dataSource);
+                    PreparedStatementCreator statementCreator = getPreparedStatementCreator(sql, new MapSqlParameterSource(map));
+                    //获取字段只需要一行数据
+                    jdbc.getJdbcTemplate().setQueryTimeout(sysConfig.getQueryTimeout());
+                    jdbc.getJdbcTemplate().setMaxRows(1);
+                    jdbc.getJdbcOperations().execute(statementCreator, new PreparedStatementCallback<Object>() {
+                        @Override
+                        public Object doInPreparedStatement(PreparedStatement ps) throws SQLException, DataAccessException {
+                            ResultSet rs = null;
+                            try {
+                                rs = ps.executeQuery();
+                                ResultSetMetaData metadata = rs.getMetaData();
+                                int columnCount = metadata.getColumnCount();
+                                for (int i = 0; i < columnCount; i++) {
+                                    String columnName = metadata.getColumnLabel(i + 1);
+                                    fields.add(new Field(columnName));
+                                }
+                                return null;
+                            } finally {
+                                JdbcUtils.closeResultSet(rs);
+                            }
+                        }
+                    });
+                }
+                writeObjectToJson(resp, fields);
+            }
+        } catch (Exception ex) {
+            writeObjectToJson(resp, ActionResult.fail("服务端措误:"+ex.getMessage()));
+        } finally {
+            JdbcUtils.closeConnection(conn);
+        }
+    }
+
+    protected PreparedStatementCreator getPreparedStatementCreator(String sql, SqlParameterSource paramSource) {
+        ParsedSql parsedSql = NamedParameterUtils.parseSqlStatement(sql);
+        String sqlToUse = NamedParameterUtils.substituteNamedParameters(parsedSql, paramSource);
+        Object[] params = NamedParameterUtils.buildValueArray(parsedSql, paramSource, null);
+        List<SqlParameter> declaredParameters = NamedParameterUtils.buildSqlParameterList(parsedSql, paramSource);
+        PreparedStatementCreatorFactory pscf = new PreparedStatementCreatorFactory(sqlToUse, declaredParameters);
+        return pscf.newPreparedStatementCreator(params);
+    }
+
+
+    public void previewData(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
+        String sql = req.getParameter("sql");
+        String parameters = req.getParameter("parameters");
+        String type = req.getParameter("type");
+        Connection conn = null;
+        try {
+            if ("buildin".equals(type)) {
+                conn = DynamicDataSourceUtil.getCurrentConnection();
+                UReportJdbcUtil.checkSqlSafe(sql, conn, null);
+            } else {
+                String url = req.getParameter("url");
+                String username = req.getParameter("username");
+                String password = req.getParameter("password");
+                password = DesUtil.aesOrDecode(password, false, true);
+                DbLinkEntity dbLinkEntity = DynamicDataSourceUtil.switchToDataSource(username, password, url, null);
+                conn = ConnUtil.getConn(dbLinkEntity);
+                UReportJdbcUtil.checkSqlSafe(sql, conn, dbLinkEntity);
+            }
+            Map<String, Object> map = buildParameters(parameters, conn);
+            sql = parseSql(sql, map);
+            List<Map<String, Object>> list = null;
+            if (ProcedureUtils.isProcedure(sql)) {
+                list = ProcedureUtils.procedureQuery(sql, map, conn);
+            } else {
+                //Column模式多租户
+                sql = TenantLineSqlParseUtil.parseSql(sql);
+                DataSource dataSource = new SingleConnectionDataSource(conn, false);
+                NamedParameterJdbcTemplate jdbc = new NamedParameterJdbcTemplate(dataSource);
+                jdbc.getJdbcTemplate().setQueryTimeout(sysConfig.getQueryTimeout());
+                jdbc.getJdbcTemplate().setFetchSize(sysConfig.getMaxRows());
+                jdbc.getJdbcTemplate().setMaxRows(sysConfig.getMaxRows());
+                list = jdbc.queryForList(sql, map);
+            }
+            int size = list.size();
+            int currentTotal = size;
+            if (currentTotal > 500) {
+                currentTotal = 500;
+            }
+            List<Map<String, Object>> ls = new ArrayList<Map<String, Object>>();
+            for (int i = 0; i < currentTotal; i++) {
+                ls.add(list.get(i));
+            }
+            DataResult result = new DataResult();
+            List<String> fields = new ArrayList<String>();
+            if (size > 0) {
+                Map<String, Object> item = list.get(0);
+                for (String name : item.keySet()) {
+                    fields.add(name);
+                }
+            }
+            result.setFields(fields);
+            result.setCurrentTotal(currentTotal);
+            result.setData(ls);
+            result.setTotal(size);
+            writeObjectToJson(resp, result);
+        } catch (Exception ex) {
+            writeObjectToJson(resp, ActionResult.fail(ex.getMessage()));
+        } finally {
+            if (conn != null) {
+                try {
+                    conn.close();
+                } catch (SQLException e) {
+                    e.printStackTrace();
+                }
+            }
+        }
+    }
+
+
+    private String parseSql(String sql, Map<String, Object> parameters) {
+        sql = sql.trim();
+        Context context = new Context(applicationContext, parameters);
+        if (sql.startsWith(ExpressionUtils.EXPR_PREFIX) && sql.endsWith(ExpressionUtils.EXPR_SUFFIX)) {
+            sql = sql.substring(2, sql.length() - 1);
+            Expression expr = ExpressionUtils.parseExpression(sql);
+            sql = executeSqlExpr(expr, context);
+            return sql;
+        } else {
+            String sqlForUse = sql;
+            Pattern pattern = Pattern.compile("\\$\\{.*?\\}");
+            Matcher matcher = pattern.matcher(sqlForUse);
+            while (matcher.find()) {
+                String substr = matcher.group();
+                String sqlExpr = substr.substring(2, substr.length() - 1);
+                Expression expr = ExpressionUtils.parseExpression(sqlExpr);
+                String result = executeSqlExpr(expr, context);
+                sqlForUse = sqlForUse.replace(substr, result);
+            }
+            Utils.logToConsole("DESIGN SQL:" + sqlForUse);
+            return sqlForUse;
+        }
+    }
+
+    private String parseSql2(String sql, Map<String, Object> parameters) {
+        sql = sql.trim();
+        Set<String> keySet = parameters.keySet();
+        for (Iterator iter = keySet.iterator(); iter.hasNext(); ) {
+            String key = String.valueOf(iter.next());
+            String value = String.valueOf(parameters.get(key));
+//            if (dataSourceConfig.getDriverClassName().contains("oracle")){
+//                sql = sql.replace(key, "'"+value+"'");
+//            }else {
+            sql = sql.replace(key, value);
+//            }
+        }
+        return sql;
+//        Context context = new Context(applicationContext, parameters);
+//        if (sql.startsWith(ExpressionUtils.EXPR_PREFIX) && sql.endsWith(ExpressionUtils.EXPR_SUFFIX)) {
+//            sql = sql.substring(2, sql.length() - 1);
+//            Expression expr = ExpressionUtils.parseExpression(sql);
+//            sql = executeSqlExpr(expr, context);
+//            return sql;
+//        } else {
+//            String sqlForUse = sql;
+//            Pattern pattern = Pattern.compile("\\$\\{.*?\\}");
+//            Matcher matcher = pattern.matcher(sqlForUse);
+//            while (matcher.find()) {
+//                String substr = matcher.group();
+//                String sqlExpr = substr.substring(2, substr.length() - 1);
+//                Expression expr = ExpressionUtils.parseExpression(sqlExpr);
+//                String result = executeSqlExpr(expr, context);
+//                sqlForUse = sqlForUse.replace(substr, result);
+//            }
+//            Utils.logToConsole("DESIGN SQL:" + sqlForUse);
+//            return sqlForUse;
+//        }
+    }
+
+    private String executeSqlExpr(Expression sqlExpr, Context context) {
+        String sqlForUse = null;
+        ExpressionData<?> exprData = sqlExpr.execute(null, null, context);
+        if (exprData instanceof ObjectExpressionData) {
+            ObjectExpressionData data = (ObjectExpressionData) exprData;
+            Object obj = data.getData();
+            if (obj != null) {
+                String s = obj.toString();
+                s = s.replaceAll("\\\\", "");
+                sqlForUse = s;
+            }
+        }
+        return sqlForUse;
+    }
+
+    public void testConnection(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
+        String username = req.getParameter("username");
+        String password = req.getParameter("password");
+        String driver = req.getParameter("driver");
+        String url = req.getParameter("url");
+        Connection conn = null;
+        try {
+            password = DesUtil.aesOrDecode(password, false, true);
+            conn = ConnUtil.getConn(username, password, url);
+            if (conn != null) {
+                writeObjectToJson(resp, ActionResult.success("数据库连接成功"));
+            }
+        } catch (Exception ex) {
+            ex.printStackTrace();
+        } finally {
+            if (conn != null) {
+                try {
+                    conn.close();
+                } catch (SQLException e) {
+                    e.printStackTrace();
+                }
+            }
+        }
+        writeObjectToJson(resp, ActionResult.fail("数据库连接失败"));
+    }
+
+    @SuppressWarnings("unchecked")
+    private Map<String, Object> buildParameters(String parameters, Connection connection) throws IOException {
+        Map<String, Object> map = new HashMap<String, Object>();
+        if (StringUtils.isBlank(parameters)) {
+            return map;
+        }
+        String dbEncode = DbTypeUtil.getDb(connection).getJnpfDbEncode();
+        boolean oracle = DbBase.ORACLE.equalsIgnoreCase(dbEncode) || DbBase.DM.equalsIgnoreCase(dbEncode);
+        ObjectMapper mapper = new ObjectMapper();
+        List<Map<String, Object>> list = mapper.readValue(parameters, ArrayList.class);
+        for (Map<String, Object> param : list) {
+            String name = param.get("name").toString();
+            DataType type = DataType.valueOf(param.get("type").toString());
+            String defaultValue = (String) param.get("defaultValue");
+            if (defaultValue == null || defaultValue.equals("")) {
+                switch (type) {
+                    case Boolean:
+                        map.put(name, false);
+                    case Date:
+                        map.put(name, new Date());
+                    case Float:
+                        map.put(name, new Float(0));
+                    case Integer:
+                        map.put(name, 0);
+                    case String:
+                        if (defaultValue != null && defaultValue.equals("")) {
+                            map.put(name, "");
+                        } else {
+                            map.put(name, "null");
+                        }
+                        break;
+                    case List:
+                        map.put(name, new ArrayList<Object>());
+                }
+            } else {
+                 boolean date = type == DataType.Date;
+                if (oracle && date) {
+                    map.put(name, "TO_DATE('" + defaultValue + "', 'yyyy-mm-dd hh24:mi:ss')");
+                } else {
+                    //map.put(name, "'"+type.parse(defaultValue)+"'");
+                    map.put(name, type.parse(defaultValue));
+                }
+            }
+        }
+        return map;
+    }
+
+    @Override
+    public String url() {
+        return "/datasource";
+    }
+}

+ 215 - 0
ureport2-console/src/main/java/com/bstek/ureport/console/designer/DesignerServletAction.java

@@ -0,0 +1,215 @@
+/*******************************************************************************
+ * Copyright 2017 Bstek
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License.  You may obtain a copy
+ * of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ ******************************************************************************/
+package com.bstek.ureport.console.designer;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import jakarta.servlet.ServletException;
+import jakarta.servlet.http.HttpServletRequest;
+import jakarta.servlet.http.HttpServletResponse;
+
+import org.antlr.v4.runtime.ANTLRInputStream;
+import org.antlr.v4.runtime.CommonTokenStream;
+import org.apache.commons.io.IOUtils;
+import org.springframework.beans.BeansException;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.ApplicationContext;
+
+import com.bstek.ureport.cache.*;
+import com.bstek.ureport.console.RenderPageServletAction;
+import com.bstek.ureport.console.cache.TempObjectCache;
+import com.bstek.ureport.console.exception.ReportDesignException;
+import com.bstek.ureport.definition.ReportDefinition;
+import com.bstek.ureport.dsl.ReportParserLexer;
+import com.bstek.ureport.dsl.ReportParserParser;
+import com.bstek.ureport.dsl.ReportParserParser.DatasetContext;
+import com.bstek.ureport.export.ReportRender;
+import com.bstek.ureport.expression.ErrorInfo;
+import com.bstek.ureport.expression.ScriptErrorListener;
+import com.bstek.ureport.parser.ReportParser;
+import com.bstek.ureport.provider.report.ReportProvider;
+
+/**
+ * @author
+ * @since 1月25日
+ */
+public class DesignerServletAction extends RenderPageServletAction {
+    private ReportRender reportRender;
+    private ReportParser reportParser;
+    private List<ReportProvider> reportProviders = new ArrayList<ReportProvider>();
+
+    @Override
+    public void execute(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
+        String method = retriveMethod(req);
+        if (method != null) {
+            invokeMethod(method, req, resp);
+        } else {
+            loadReport(req, resp);
+        }
+    }
+
+    public void scriptValidation(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
+        String content = req.getParameter("content");
+        ANTLRInputStream antlrInputStream = new ANTLRInputStream(content);
+        ReportParserLexer lexer = new ReportParserLexer(antlrInputStream);
+        CommonTokenStream tokenStream = new CommonTokenStream(lexer);
+        ReportParserParser parser = new ReportParserParser(tokenStream);
+        ScriptErrorListener errorListener = new ScriptErrorListener();
+        parser.removeErrorListeners();
+        parser.addErrorListener(errorListener);
+        parser.expression();
+        List<ErrorInfo> infos = errorListener.getInfos();
+        writeObjectToJson(resp, infos);
+    }
+
+    public void conditionScriptValidation(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
+        String content = req.getParameter("content");
+        ANTLRInputStream antlrInputStream = new ANTLRInputStream(content);
+        ReportParserLexer lexer = new ReportParserLexer(antlrInputStream);
+        CommonTokenStream tokenStream = new CommonTokenStream(lexer);
+        ReportParserParser parser = new ReportParserParser(tokenStream);
+        ScriptErrorListener errorListener = new ScriptErrorListener();
+        parser.removeErrorListeners();
+        parser.addErrorListener(errorListener);
+        parser.expr();
+        List<ErrorInfo> infos = errorListener.getInfos();
+        writeObjectToJson(resp, infos);
+    }
+
+
+    public void parseDatasetName(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
+        String expr = req.getParameter("expr");
+        ANTLRInputStream antlrInputStream = new ANTLRInputStream(expr);
+        ReportParserLexer lexer = new ReportParserLexer(antlrInputStream);
+        CommonTokenStream tokenStream = new CommonTokenStream(lexer);
+        ReportParserParser parser = new ReportParserParser(tokenStream);
+        parser.removeErrorListeners();
+        DatasetContext ctx = parser.dataset();
+        String datasetName = ctx.Identifier().getText();
+        Map<String, String> result = new HashMap<String, String>();
+        result.put("datasetName", datasetName);
+        writeObjectToJson(resp, result);
+    }
+
+    //保存到临时缓存
+    public void savePreviewData(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
+        String content = req.getParameter("content");
+        String token = req.getHeader("Authorization");
+        content = decodeContent(content);
+        InputStream inputStream = IOUtils.toInputStream(content, "utf-8");
+        ReportDefinition reportDef = reportParser.parse(inputStream, "p");
+        reportRender.rebuildReportDefinition(reportDef);
+        IOUtils.closeQuietly(inputStream);
+        TempObjectCache.putObject(token, reportDef);
+    }
+
+    public void loadReport(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
+        String file = req.getParameter("file");
+        if (file == null) {
+            throw new ReportDesignException("Report file can not be null.");
+        }
+        file = ReportUtils.decodeFileName(file);
+        Object obj = TempObjectCache.getObject(file);
+        if (obj != null && obj instanceof ReportDefinition) {
+            ReportDefinition reportDef = (ReportDefinition) obj;
+            TempObjectCache.removeObject(file);
+            writeObjectToJson(resp, new ReportDefinitionWrapper(reportDef));
+        } else {
+            if ("".equals(file)) {
+                file = "classpath:template/template.ureport.xml";
+            }
+            ReportDefinition reportDef = reportRender.parseReport(file);
+            writeObjectToJson(resp, new ReportDefinitionWrapper(reportDef));
+        }
+    }
+
+    public void deleteReportFile(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
+        String file = req.getParameter("file");
+        if (file == null) {
+            throw new ReportDesignException("Report file can not be null.");
+        }
+        ReportProvider targetReportProvider = null;
+        for (ReportProvider provider : reportProviders) {
+            if (file.startsWith(provider.getPrefix())) {
+                targetReportProvider = provider;
+                break;
+            }
+        }
+        if (targetReportProvider == null) {
+            throw new ReportDesignException("File [" + file + "] not found available report provider.");
+        }
+        targetReportProvider.deleteReport(file);
+    }
+
+
+    public void saveReportFile(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
+        String file = req.getParameter("file");
+        file = ReportUtils.decodeFileName(file);
+        String content = req.getParameter("content");
+        content = decodeContent(content);
+        ReportProvider targetReportProvider = null;
+        for (ReportProvider provider : reportProviders) {
+            if (file.startsWith(provider.getPrefix())) {
+                targetReportProvider = provider;
+                break;
+            }
+        }
+        if (targetReportProvider == null) {
+            throw new ReportDesignException("File [" + file + "] not found available report provider.");
+        }
+        targetReportProvider.saveReport(file, content);
+        InputStream inputStream = IOUtils.toInputStream(content, "utf-8");
+        ReportDefinition reportDef = reportParser.parse(inputStream, file);
+        reportRender.rebuildReportDefinition(reportDef);
+        CacheUtils.cacheReportDefinition(file, reportDef);
+        IOUtils.closeQuietly(inputStream);
+    }
+
+    public void loadReportProviders(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
+        writeObjectToJson(resp, reportProviders);
+    }
+
+    public void setReportRender(ReportRender reportRender) {
+        this.reportRender = reportRender;
+    }
+
+    public void setReportParser(ReportParser reportParser) {
+        this.reportParser = reportParser;
+    }
+
+    @Override
+    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
+        super.setApplicationContext(applicationContext);
+        Collection<ReportProvider> providers = applicationContext.getBeansOfType(ReportProvider.class).values();
+        for (ReportProvider provider : providers) {
+            if (provider.disabled() || provider.getName() == null) {
+                continue;
+            }
+            reportProviders.add(provider);
+        }
+    }
+
+    @Override
+    public String url() {
+        return "/designer";
+    }
+}

+ 132 - 0
ureport2-console/src/main/java/com/bstek/ureport/console/designer/ReportDefinitionWrapper.java

@@ -0,0 +1,132 @@
+/*******************************************************************************
+ * Copyright 2017 Bstek
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License.  You may obtain a copy
+ * of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ ******************************************************************************/
+package com.bstek.ureport.console.designer;
+
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import com.bstek.ureport.definition.CellDefinition;
+import com.bstek.ureport.definition.ColumnDefinition;
+import com.bstek.ureport.definition.HeaderFooterDefinition;
+import com.bstek.ureport.definition.Paper;
+import com.bstek.ureport.definition.ReportDefinition;
+import com.bstek.ureport.definition.RowDefinition;
+import com.bstek.ureport.definition.datasource.DatasourceDefinition;
+import com.bstek.ureport.definition.searchform.SearchForm;
+
+/**
+ * @author
+ * @since 1月29日
+ */
+public class ReportDefinitionWrapper implements Serializable {
+	private Paper paper;
+	private HeaderFooterDefinition header;
+	private HeaderFooterDefinition footer;
+	private SearchForm searchForm;
+	private String searchFormXml;
+	private List<RowDefinition> rows;
+	private List<ColumnDefinition> columns;
+	private List<DatasourceDefinition> datasources;
+	private Map<String,CellDefinition> cellsMap=new HashMap<String,CellDefinition>();
+	public ReportDefinitionWrapper(ReportDefinition report) {
+		this.paper=report.getPaper();
+		this.header=report.getHeader();
+		this.footer=report.getFooter();
+		this.searchForm=report.getSearchForm();
+		this.searchFormXml=report.getSearchFormXml();
+		this.rows=report.getRows();
+		this.columns=report.getColumns();
+		this.datasources=report.getDatasources();
+		for(CellDefinition cell:report.getCells()){
+			cellsMap.put(cell.getRowNumber()+","+cell.getColumnNumber(), cell);
+		}
+	}
+
+	public Paper getPaper() {
+		return paper;
+	}
+
+	public void setPaper(Paper paper) {
+		this.paper = paper;
+	}
+
+	public HeaderFooterDefinition getHeader() {
+		return header;
+	}
+
+	public void setHeader(HeaderFooterDefinition header) {
+		this.header = header;
+	}
+
+	public HeaderFooterDefinition getFooter() {
+		return footer;
+	}
+
+	public void setFooter(HeaderFooterDefinition footer) {
+		this.footer = footer;
+	}
+
+	public SearchForm getSearchForm() {
+		return searchForm;
+	}
+
+	public void setSearchForm(SearchForm searchForm) {
+		this.searchForm = searchForm;
+	}
+
+	public String getSearchFormXml() {
+		return searchFormXml;
+	}
+
+	public void setSearchFormXml(String searchFormXml) {
+		this.searchFormXml = searchFormXml;
+	}
+
+	public List<RowDefinition> getRows() {
+		return rows;
+	}
+
+	public void setRows(List<RowDefinition> rows) {
+		this.rows = rows;
+	}
+
+	public List<ColumnDefinition> getColumns() {
+		return columns;
+	}
+
+	public void setColumns(List<ColumnDefinition> columns) {
+		this.columns = columns;
+	}
+
+	public List<DatasourceDefinition> getDatasources() {
+		return datasources;
+	}
+
+	public void setDatasources(List<DatasourceDefinition> datasources) {
+		this.datasources = datasources;
+	}
+
+	public Map<String, CellDefinition> getCellsMap() {
+		return cellsMap;
+	}
+
+	public void setCellsMap(Map<String, CellDefinition> cellsMap) {
+		this.cellsMap = cellsMap;
+	}
+}

+ 40 - 0
ureport2-console/src/main/java/com/bstek/ureport/console/designer/ReportUtils.java

@@ -0,0 +1,40 @@
+/*******************************************************************************
+ * Copyright 2017 Bstek
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License.  You may obtain a copy
+ * of the License at
+ * 
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ ******************************************************************************/
+package com.bstek.ureport.console.designer;
+
+import java.io.UnsupportedEncodingException;
+import java.net.URLDecoder;
+
+import com.bstek.ureport.console.exception.ReportDesignException;
+
+/**
+ * @author
+ * @since 1月26日
+ */
+public class ReportUtils {
+	public static String decodeFileName(String fileName){
+		if(fileName==null){
+			return fileName;
+		}
+		try {
+			fileName=URLDecoder.decode(fileName, "utf-8");
+			fileName=URLDecoder.decode(fileName, "utf-8");
+			return fileName;
+		} catch (UnsupportedEncodingException e) {
+			throw new ReportDesignException(e);
+		}
+	}
+}

+ 55 - 0
ureport2-console/src/main/java/com/bstek/ureport/console/designer/SearchFormDesignerAction.java

@@ -0,0 +1,55 @@
+/*******************************************************************************
+ * Copyright 2017 Bstek
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License.  You may obtain a copy
+ * of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ ******************************************************************************/
+package com.bstek.ureport.console.designer;
+
+import java.io.IOException;
+import java.io.PrintWriter;
+
+import jakarta.servlet.ServletException;
+import jakarta.servlet.http.HttpServletRequest;
+import jakarta.servlet.http.HttpServletResponse;
+
+import com.bstek.ureport.console.util.ActionResult;
+import org.apache.velocity.Template;
+import org.apache.velocity.VelocityContext;
+
+import com.bstek.ureport.console.RenderPageServletAction;
+
+/**
+ * @author Jacky.gao
+ * @since 2017年10月24日
+ */
+public class SearchFormDesignerAction extends RenderPageServletAction {
+
+	@Override
+	public void execute(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
+//		VelocityContext context = new VelocityContext();
+//		context.put("contextPath", req.getContextPath());
+//		resp.setContentType("text/html");
+//		resp.setCharacterEncoding("utf-8");
+//		Template template=ve.getTemplate("ureport-html/searchform.html","utf-8");
+//		PrintWriter writer=resp.getWriter();
+//		template.merge(context, writer);
+//		writer.close();
+		Object contextPath = req.getContextPath();
+		writeObjectToJson(resp, ActionResult.success(contextPath));
+	}
+
+	@Override
+	public String url() {
+		return "/searchFormDesigner";
+	}
+}

+ 120 - 0
ureport2-console/src/main/java/com/bstek/ureport/console/excel/ExportExcel97ServletAction.java

@@ -0,0 +1,120 @@
+/*******************************************************************************
+ * Copyright 2017 Bstek
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License.  You may obtain a copy
+ * of the License at
+ * 
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ ******************************************************************************/
+package com.bstek.ureport.console.excel;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.util.Map;
+
+import jakarta.servlet.ServletException;
+import jakarta.servlet.http.HttpServletRequest;
+import jakarta.servlet.http.HttpServletResponse;
+
+import org.apache.commons.lang.StringUtils;
+
+import com.bstek.ureport.build.ReportBuilder;
+import com.bstek.ureport.console.BaseServletAction;
+import com.bstek.ureport.console.cache.TempObjectCache;
+import com.bstek.ureport.console.exception.ReportDesignException;
+import com.bstek.ureport.definition.ReportDefinition;
+import com.bstek.ureport.exception.ReportComputeException;
+import com.bstek.ureport.export.ExportConfigure;
+import com.bstek.ureport.export.ExportConfigureImpl;
+import com.bstek.ureport.export.ExportManager;
+import com.bstek.ureport.export.excel.low.Excel97Producer;
+import com.bstek.ureport.model.Report;
+
+/**
+ * 已废弃
+ * @author
+ * @since 7月3日
+ */
+public class ExportExcel97ServletAction extends BaseServletAction {
+	private ReportBuilder reportBuilder;
+	private ExportManager exportManager;
+	private Excel97Producer excelProducer=new Excel97Producer();
+	
+	@Override
+	public void execute(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
+		String method=retriveMethod(req);
+		if(method!=null){
+			invokeMethod(method, req, resp);
+		}else{			
+			buildExcel(req, resp,false,false);
+		}
+	}
+	public void paging(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
+		buildExcel(req, resp, true, false);
+	}
+	
+	public void sheet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
+		buildExcel(req, resp, false, true);
+	}
+	
+	public void buildExcel(HttpServletRequest req, HttpServletResponse resp,boolean withPage,boolean withSheet) throws IOException {
+		String file=req.getParameter("_u");
+		if(StringUtils.isBlank(file)){
+			throw new ReportComputeException("Report file can not be null.");
+		}
+		String fileName=req.getParameter("_n");
+		if(StringUtils.isNotBlank(fileName)){
+			fileName=decode(fileName);
+		}else{
+			fileName="ureport.xls";
+		}
+		resp.setContentType("application/octet-stream;charset=ISO8859-1");
+		resp.setHeader("Content-Disposition","attachment;filename=\"" + fileName + "\"");
+		Map<String, Object> parameters = buildParameters(req);
+		OutputStream outputStream=resp.getOutputStream();
+		if(file.equals(PREVIEW_KEY)){
+			ReportDefinition reportDefinition=(ReportDefinition)TempObjectCache.getObject(PREVIEW_KEY);
+			if(reportDefinition==null){
+				throw new ReportDesignException("Report data has expired,can not do export excel.");
+			}
+			Report report=reportBuilder.buildReport(reportDefinition, parameters);	
+			if(withPage){
+				excelProducer.produceWithPaging(report, outputStream);
+			}else if(withSheet){
+				excelProducer.produceWithSheet(report, outputStream);
+			}else{
+				excelProducer.produce(report, outputStream);				
+			}
+		}else{
+			ExportConfigure configure=new ExportConfigureImpl(file,parameters,outputStream);
+			if(withPage){
+				exportManager.exportExcelWithPaging(configure);
+			}else if(withSheet){
+				exportManager.exportExcelWithPagingSheet(configure);
+			}else{
+				exportManager.exportExcel(configure);
+			}
+		}
+		outputStream.flush();
+		outputStream.close();
+	}
+	
+	public void setReportBuilder(ReportBuilder reportBuilder) {
+		this.reportBuilder = reportBuilder;
+	}
+	public void setExportManager(ExportManager exportManager) {
+		this.exportManager = exportManager;
+	}
+
+	@Override
+	public String url() {
+		return "/excel97";
+	}
+}

+ 136 - 0
ureport2-console/src/main/java/com/bstek/ureport/console/excel/ExportExcelServletAction.java

@@ -0,0 +1,136 @@
+/*******************************************************************************
+ * Copyright 2017 Bstek
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License.  You may obtain a copy
+ * of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ ******************************************************************************/
+package com.bstek.ureport.console.excel;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.net.URLEncoder;
+import java.sql.Connection;
+import java.sql.SQLException;
+import java.text.SimpleDateFormat;
+import java.util.Map;
+import java.util.UUID;
+
+import jakarta.servlet.ServletException;
+import jakarta.servlet.http.HttpServletRequest;
+import jakarta.servlet.http.HttpServletResponse;
+import javax.sql.DataSource;
+
+import com.bstek.ureport.console.ureport.service.ReportService;
+import jnpf.database.util.DynamicDataSourceUtil;
+import org.apache.commons.lang.StringUtils;
+
+import com.bstek.ureport.build.ReportBuilder;
+import com.bstek.ureport.console.BaseServletAction;
+import com.bstek.ureport.console.cache.TempObjectCache;
+import com.bstek.ureport.definition.ReportDefinition;
+import com.bstek.ureport.exception.ReportComputeException;
+import com.bstek.ureport.export.ExportManager;
+import com.bstek.ureport.export.excel.high.ExcelProducer;
+import com.bstek.ureport.model.Report;
+import org.apache.poi.xssf.streaming.SXSSFWorkbook;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.jdbc.support.JdbcUtils;
+
+/**
+ * 导出报表到Excel
+ * @author
+ * @since 4月17日
+ */
+public class ExportExcelServletAction extends BaseServletAction {
+    @Autowired
+    private ReportService reportService;
+    private ReportBuilder reportBuilder;
+    private ExportManager exportManager;
+    private ExcelProducer excelProducer = new ExcelProducer();
+
+    @Override
+    public void execute(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
+        String method = retriveMethod(req);
+        if (method != null) {
+            invokeMethod(method, req, resp);
+        } else {
+            buildExcel(req, resp, false, false);
+        }
+    }
+
+    public void paging(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
+        buildExcel(req, resp, true, false);
+    }
+
+    public void sheet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
+        buildExcel(req, resp, false, true);
+    }
+
+    public void buildExcel(HttpServletRequest req, HttpServletResponse resp, boolean withPage, boolean withSheet) throws IOException {
+        String token = req.getParameter("token");
+        token = decode(token);
+        String id = req.getParameter("id");
+        id = decode(id);
+        if (StringUtils.isBlank(token) || StringUtils.isBlank(id)) {
+            throw new ReportComputeException("Report file can not be null.");
+        }
+        OutputStream outputStream = null;
+        Connection connection = null;
+        try {
+            String fullName = null;
+            ReportDefinition reportDefinition = (ReportDefinition) TempObjectCache.getObject(id);
+            if (reportDefinition == null) {
+                reportDefinition = (ReportDefinition) TempObjectCache.getObject(token);
+                fullName = String.valueOf(UUID.randomUUID());
+            } else {
+                fullName = reportService.GetInfo(id).getFullName();
+            }
+            resp.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(fullName + ".xlsx", "UTF-8"));
+            resp.setCharacterEncoding("UTF-8");
+            resp.setHeader("content-Type", "application/x-download");
+            outputStream = resp.getOutputStream();
+            Map<String, Object> parameters =buildParameters(req);
+            try {
+                connection = DynamicDataSourceUtil.getCurrentConnection();
+            } catch (SQLException throwables) {
+                throwables.printStackTrace();
+            }
+            Report report = reportBuilder.buildReportToConnection(reportDefinition, parameters, connection);
+            SXSSFWorkbook workbook = null;
+            if (withPage) {
+                excelProducer.produceWithPaging(report, outputStream);
+            } else if (withSheet) {
+                excelProducer.produceWithSheet(report, outputStream);
+            } else {
+                excelProducer.produce(report, outputStream);
+            }
+        } finally {
+            JdbcUtils.closeConnection(connection);
+            outputStream.flush();
+            outputStream.close();
+        }
+    }
+
+    public void setReportBuilder(ReportBuilder reportBuilder) {
+        this.reportBuilder = reportBuilder;
+    }
+
+    public void setExportManager(ExportManager exportManager) {
+        this.exportManager = exportManager;
+    }
+
+    @Override
+    public String url() {
+        return "/excel";
+    }
+
+}

+ 32 - 0
ureport2-console/src/main/java/com/bstek/ureport/console/exception/ReportDesignException.java

@@ -0,0 +1,32 @@
+/*******************************************************************************
+ * Copyright 2017 Bstek
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License.  You may obtain a copy
+ * of the License at
+ * 
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ ******************************************************************************/
+package com.bstek.ureport.console.exception;
+
+import com.bstek.ureport.exception.ReportException;
+
+/**
+ * @author
+ * @since 1月26日
+ */
+public class ReportDesignException extends ReportException {
+	private static final long serialVersionUID = 4046240733455821337L;
+	public ReportDesignException(Exception ex) {
+		super(ex);
+	}
+	public ReportDesignException(String msg) {
+		super(msg);
+	}
+}

+ 469 - 0
ureport2-console/src/main/java/com/bstek/ureport/console/html/HtmlPreviewServletAction.java

@@ -0,0 +1,469 @@
+/*******************************************************************************
+ * Copyright 2017 Bstek
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License.  You may obtain a copy
+ * of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ ******************************************************************************/
+package com.bstek.ureport.console.html;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.sql.Connection;
+import java.sql.SQLException;
+import java.util.*;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import jakarta.servlet.ServletException;
+import jakarta.servlet.http.HttpServletRequest;
+import jakarta.servlet.http.HttpServletResponse;
+
+import jnpf.database.util.DynamicDataSourceUtil;
+import com.bstek.ureport.console.ureport.entity.ReportEntity;
+import com.bstek.ureport.console.ureport.model.ReportPreviewVO;
+import com.bstek.ureport.console.ureport.service.ReportService;
+import com.bstek.ureport.console.ureport.util.*;
+import com.bstek.ureport.console.util.ActionResult;
+import com.bstek.ureport.export.*;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang.StringUtils;
+import org.apache.velocity.VelocityContext;
+
+import com.bstek.ureport.build.Context;
+import com.bstek.ureport.build.ReportBuilder;
+import com.bstek.ureport.build.paging.Page;
+import com.bstek.ureport.cache.*;
+import com.bstek.ureport.chart.ChartData;
+import com.bstek.ureport.console.MobileUtils;
+import com.bstek.ureport.console.RenderPageServletAction;
+import com.bstek.ureport.console.cache.TempObjectCache;
+import com.bstek.ureport.console.exception.ReportDesignException;
+import com.bstek.ureport.definition.Paper;
+import com.bstek.ureport.definition.ReportDefinition;
+import com.bstek.ureport.definition.searchform.FormPosition;
+import com.bstek.ureport.exception.ReportComputeException;
+import com.bstek.ureport.export.html.HtmlProducer;
+import com.bstek.ureport.export.html.HtmlReport;
+import com.bstek.ureport.export.html.SearchFormData;
+import com.bstek.ureport.model.Report;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.jdbc.support.JdbcUtils;
+
+/**
+ * @author
+ * @since 2月15日
+ */
+@Slf4j
+public class HtmlPreviewServletAction extends RenderPageServletAction {
+
+    @Autowired
+    private ReportService reportService;
+    private ExportManager exportManager;
+    private ReportBuilder reportBuilder;
+    private ReportRender reportRender;
+    private HtmlProducer htmlProducer = new HtmlProducer();
+
+    @Override
+    public void execute(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
+        String method = retriveMethod(req);
+        if (method != null) {
+            invokeMethod(method, req, resp);
+        } else {
+            Map<String, Object> objectMap = new HashMap<String, Object>();
+            VelocityContext context = new VelocityContext();
+            HtmlReport htmlReport = null;
+            String errorMsg = null;
+            try {
+                htmlReport = loadReport(req);
+            } catch (Exception ex) {
+                if (!(ex instanceof ReportDesignException)) {
+                    ex.printStackTrace();
+                }
+                errorMsg = buildExceptionMessage(ex);
+            }
+            String title = buildTitle(req);
+            context.put("title", title);
+            if (htmlReport == null) {
+                context.put("content", "<div style='color:red'><strong>报表计算出错,错误信息如下:</strong><br><div style=\"margin:10px\">" + errorMsg + "</div></div>");
+                context.put("error", true);
+                context.put("searchFormJs", "");
+                context.put("downSearchFormHtml", "");
+                context.put("upSearchFormHtml", "");
+            } else {
+                SearchFormData formData = htmlReport.getSearchFormData();
+                if (formData != null) {
+                    context.put("searchFormJs", formData.getJs());
+                    if (formData.getFormPosition().equals(FormPosition.up)) {
+                        context.put("upSearchFormHtml", formData.getHtml());
+                        context.put("downSearchFormHtml", "");
+                    } else {
+                        context.put("downSearchFormHtml", formData.getHtml());
+                        context.put("upSearchFormHtml", "");
+                    }
+                } else {
+                    context.put("searchFormJs", "");
+                    context.put("downSearchFormHtml", "");
+                    context.put("upSearchFormHtml", "");
+                }
+                objectMap.put("content", htmlReport.getContent());
+                objectMap.put("style", htmlReport.getStyle());
+                context.put("content", htmlReport.getContent());
+                context.put("style", htmlReport.getStyle());
+                context.put("reportAlign", htmlReport.getReportAlign());
+                context.put("totalPage", htmlReport.getTotalPage());
+                context.put("totalPageWithCol", htmlReport.getTotalPageWithCol());
+                context.put("pageIndex", htmlReport.getPageIndex());
+                context.put("chartDatas", convertJson(htmlReport.getChartDatas()));
+                context.put("error", false);
+                context.put("file", req.getParameter("_u"));
+                context.put("intervalRefreshValue", htmlReport.getHtmlIntervalRefreshValue());
+                String customParameters = buildCustomParameters(req);
+                context.put("customParameters", customParameters);
+                context.put("_t", "");
+                Tools tools = null;
+                if (MobileUtils.isMobile(req)) {
+                    tools = new Tools(false);
+                    tools.setShow(false);
+                } else {
+                    String toolsInfo = req.getParameter("_t");
+                    if (StringUtils.isNotBlank(toolsInfo)) {
+                        tools = new Tools(false);
+                        if (toolsInfo.equals("0")) {
+                            tools.setShow(false);
+                        } else {
+                            String[] infos = toolsInfo.split(",");
+                            for (String name : infos) {
+                                tools.doInit(name);
+                            }
+                        }
+                        context.put("_t", toolsInfo);
+                        context.put("hasTools", true);
+                    } else {
+                        tools = new Tools(true);
+                    }
+                }
+                context.put("tools", tools);
+            }
+            context.put("contextPath", req.getContextPath());
+            writeObjectToJson(resp, objectMap);
+        }
+    }
+
+    private String buildTitle(HttpServletRequest req) {
+        String title = req.getParameter("_title");
+        if (StringUtils.isBlank(title)) {
+            title = req.getParameter("_u");
+            title = decode(title);
+            int point = title.lastIndexOf(".ureport.xml");
+            if (point > -1) {
+                title = title.substring(0, point);
+            }
+            if (title.equals("p")) {
+                title = "设计中报表";
+            }
+        } else {
+            title = decode(title);
+        }
+        return title + "-ureport";
+    }
+
+    private String convertJson(Collection<ChartData> data) {
+        if (data == null || data.size() == 0) {
+            return "";
+        }
+        ObjectMapper mapper = new ObjectMapper();
+        try {
+            String json = mapper.writeValueAsString(data);
+            return json;
+        } catch (Exception e) {
+            throw new ReportComputeException(e);
+        }
+    }
+
+    public void loadData(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
+        HtmlReport htmlReport = loadReport(req);
+        writeObjectToJson(resp, htmlReport);
+    }
+
+    //展示内容
+    public void loadPrintPages(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
+        String id = req.getParameter("id");
+        id = decode(id);
+        String token = req.getParameter("token");
+        token = decode(token);
+        if (StringUtils.isBlank(id) || StringUtils.isBlank(token)) {
+            writeObjectToJson(resp, ActionResult.fail("请检查参数"));
+        }
+        if ("preview".equals(id)) {
+            ReportDefinition reportDefinition = (ReportDefinition) TempObjectCache.getObject(token);
+            Connection connection = null;
+            try {
+                connection = DynamicDataSourceUtil.getCurrentConnection();
+            } catch (SQLException throwables) {
+                throwables.printStackTrace();
+                log.error("数据源错误:"+throwables.getMessage());
+            }
+            Report report;
+            try {
+                Map<String, Object> parameters =buildParameters(req);
+                report = reportBuilder.buildReports(reportDefinition, parameters, connection);
+            }finally {
+                JdbcUtils.closeConnection(connection);
+            }
+            Map<String, ChartData> chartMap = report.getContext().getChartDataMap();
+            if (chartMap.size() > 0) {
+                CacheUtils.storeChartDataMap(chartMap);
+            }
+            FullPageData pageData = PageBuilder.buildFullPageData(report);
+            StringBuilder sb = new StringBuilder();
+            List<List<Page>> list = pageData.getPageList();
+            Context context = report.getContext();
+            if (list.size() > 0) {
+                for (int i = 0; i < list.size(); i++) {
+                    List<Page> columnPages = list.get(i);
+                    if (i == 0) {
+                        String html = htmlProducer.produce(context, columnPages, pageData.getColumnMargin(), false);
+                        sb.append(html);
+                    } else {
+                        String html = htmlProducer.produce(context, columnPages, pageData.getColumnMargin(), false);
+                        sb.append(html);
+                    }
+                }
+            } else {
+                List<Page> pages = report.getPages();
+                for (int i = 0; i < pages.size(); i++) {
+                    Page page = pages.get(i);
+                    if (i == 0) {
+                        String html = htmlProducer.produce(context, page, false);
+                        sb.append(html);
+                    } else {
+                        String html = htmlProducer.produce(context, page, true);
+                        sb.append(html);
+                    }
+                }
+            }
+            Object obj = sb;
+            writeObjectToJson(resp, ActionResult.success(obj));
+        } else {
+            ReportEntity entity = reportService.GetInfo(id);
+            if (entity == null) {
+                writeObjectToJson(resp, ActionResult.fail("数据不存在"));
+            } else {
+                ReportPreviewVO vo = null;
+                Map<String, Object> parameters =buildParameters(req);
+                UreportPreviewUtil previewUtil = new UreportPreviewUtil();
+                Connection connection = null;
+                try {
+                    connection = DynamicDataSourceUtil.getCurrentConnection();
+                } catch (SQLException throwables) {
+                    throwables.printStackTrace();
+                    log.error("数据源错误:"+throwables.getMessage());
+                }
+                vo = previewUtil.preview(entity, false, 1, parameters, connection, false);
+                try {
+                    connection.close();
+                } catch (SQLException throwables) {
+                    log.error("点击打印报错:"+throwables.getMessage());
+                }
+                Object obj = vo.getContent();
+                writeObjectToJson(resp, ActionResult.success(obj));
+            }
+        }
+    }
+
+    public void loadPagePaper(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
+        String id = req.getParameter("id");
+        id = decode(id);
+        String token = req.getParameter("token");
+        token = decode(token);
+        if (StringUtils.isBlank(id) || StringUtils.isBlank(token)) {
+            writeObjectToJson(resp, ActionResult.fail("请检查参数"));
+        }
+        if ("preview".equals(id)) {
+            ReportDefinition reportDefinition = (ReportDefinition) TempObjectCache.getObject(token);
+            Map<String, Object> parameters = buildParameters(req);
+            Connection connection = null;
+            try {
+                connection = DynamicDataSourceUtil.getCurrentConnection();
+            } catch (SQLException throwables) {
+                throwables.printStackTrace();
+                log.error("数据源错误:"+throwables.getMessage());
+            }
+            Report report;
+            try {
+                report = reportBuilder.buildReportToConnection(reportDefinition, parameters, connection);
+            }finally {
+                JdbcUtils.closeConnection(connection);
+            }
+            Paper paper = report.getPaper();
+            writeObjectToJson(resp, paper);
+        } else {
+            ReportEntity entity = reportService.GetInfo(id);
+            if (entity == null) {
+                writeObjectToJson(resp, ActionResult.fail("数据不存在"));
+            } else {
+                Connection connection = null;
+                try {
+                    connection = DynamicDataSourceUtil.getCurrentConnection();
+                } catch (SQLException throwables) {
+                    throwables.printStackTrace();
+                    log.error("数据源错误:"+throwables.getMessage());
+                }
+                byte[] content = entity.getContent().getBytes();
+                ByteArrayInputStream inputStream = new ByteArrayInputStream(content);
+                ReportDefinition reportDefinition = UreportUtil.parseReport(inputStream, entity.getFullName());
+                Map<String, Object> parameters =buildParameters(req);
+                Report report = reportBuilder.buildReportToConnection(reportDefinition, parameters, connection);
+                try {
+                    connection.close();
+                } catch (SQLException throwables) {
+                    throwables.printStackTrace();
+                }
+                writeObjectToJson(resp, report.getPaper());
+            }
+        }
+    }
+
+    private HtmlReport loadReport(HttpServletRequest req) {
+        Map<String, Object> parameters = buildParameters(req);
+        HtmlReport htmlReport = null;
+        String file = req.getParameter("_u");
+        file = decode(file);
+        String pageIndex = req.getParameter("_i");
+        if (StringUtils.isBlank(file)) {
+            throw new ReportComputeException("Report file can not be null.");
+        }
+        if (file.equals(PREVIEW_KEY)) {
+            ReportDefinition reportDefinition = (ReportDefinition) TempObjectCache.getObject(PREVIEW_KEY);
+            if (reportDefinition == null) {
+                throw new ReportDesignException("Report data has expired,can not do preview.");
+            }
+            Report report = reportBuilder.buildReport(reportDefinition, parameters);
+            Map<String, ChartData> chartMap = report.getContext().getChartDataMap();
+            if (chartMap.size() > 0) {
+                CacheUtils.storeChartDataMap(chartMap);
+            }
+            htmlReport = new HtmlReport();
+            String html = null;
+            if (StringUtils.isNotBlank(pageIndex) && !pageIndex.equals("0")) {
+                Context context = report.getContext();
+                int index = Integer.valueOf(pageIndex);
+                SinglePageData pageData = PageBuilder.buildSinglePageData(index, report);
+                List<Page> pages = pageData.getPages();
+                if (pages.size() == 1) {
+                    Page page = pages.get(0);
+                    html = htmlProducer.produce(context, page, false);
+                } else {
+                    html = htmlProducer.produce(context, pages, pageData.getColumnMargin(), false);
+                }
+                htmlReport.setTotalPage(pageData.getTotalPages());
+                htmlReport.setPageIndex(index);
+            } else {
+                html = htmlProducer.produce(report);
+            }
+            if (report.getPaper().isColumnEnabled()) {
+                htmlReport.setColumn(report.getPaper().getColumnCount());
+            }
+            htmlReport.setChartDatas(report.getContext().getChartDataMap().values());
+            htmlReport.setContent(html);
+            htmlReport.setTotalPage(report.getPages().size());
+            htmlReport.setStyle(reportDefinition.getStyle());
+            htmlReport.setSearchFormData(reportDefinition.buildSearchFormData(report.getContext().getDatasetMap(), parameters));
+            htmlReport.setReportAlign(report.getPaper().getHtmlReportAlign().name());
+            htmlReport.setHtmlIntervalRefreshValue(report.getPaper().getHtmlIntervalRefreshValue());
+        } else {
+            if (StringUtils.isNotBlank(pageIndex) && !pageIndex.equals("0")) {
+                int index = Integer.valueOf(pageIndex);
+                htmlReport = exportManager.exportHtml(file, req.getContextPath(), parameters, index);
+            } else {
+                htmlReport = exportManager.exportHtml(file, req.getContextPath(), parameters);
+            }
+        }
+        return htmlReport;
+    }
+
+
+    private String buildCustomParameters(HttpServletRequest req) {
+        StringBuilder sb = new StringBuilder();
+        Enumeration<?> enumeration = req.getParameterNames();
+        while (enumeration.hasMoreElements()) {
+            Object obj = enumeration.nextElement();
+            if (obj == null) {
+                continue;
+            }
+            String name = obj.toString();
+            String value = req.getParameter(name);
+            if (name == null || value == null || (name.startsWith("_") && !name.equals("_n"))) {
+                continue;
+            }
+            if (sb.length() > 0) {
+                sb.append("&");
+            }
+            sb.append(name);
+            sb.append("=");
+            sb.append(value);
+        }
+        return sb.toString();
+    }
+
+    private String buildExceptionMessage(Throwable throwable) {
+        Throwable root = buildRootException(throwable);
+        StringWriter sw = new StringWriter();
+        PrintWriter pw = new PrintWriter(sw);
+        root.printStackTrace(pw);
+        String trace = sw.getBuffer().toString();
+        trace = trace.replaceAll("\n", "<br>");
+        pw.close();
+        return trace;
+    }
+
+    public void setExportManager(ExportManager exportManager) {
+        this.exportManager = exportManager;
+    }
+
+    public void setReportBuilder(ReportBuilder reportBuilder) {
+        this.reportBuilder = reportBuilder;
+    }
+
+    public void setReportRender(ReportRender reportRender) {
+        this.reportRender = reportRender;
+    }
+
+    //数据源连接
+//    private Connection buildConnection() {
+//        HttpServletResponse resp = null;
+//        Connection conn = null;
+//        DataConfigEntity dataConfigEntity = dataConfigService.GetInfo();
+//        Map<String, Object> map = JSONUtil.StringToMap(JSONUtil.StringToMap(dataConfigEntity.getDatasource()).get("dataSource").toString());
+//        String username = map.get("username").toString();
+//        String password = map.get("password").toString();
+//        String driver = map.get("driver").toString();
+//        String url = map.get("url").toString();
+//        try {
+//            Class.forName(driver);
+//            conn = DriverManager.getConnection(url, username, password);
+//        } catch (Exception e) {
+//            try {
+//                writeObjectToJson(resp, ActionResult.fail("请先配置正确的数据源"));
+//            } catch (Exception ex) {
+//                ex.printStackTrace();
+//            }
+//        }
+//        return conn;
+//    }
+
+    @Override
+    public String url() {
+        return "/preview";
+    }
+}

+ 137 - 0
ureport2-console/src/main/java/com/bstek/ureport/console/html/Tools.java

@@ -0,0 +1,137 @@
+/*******************************************************************************
+ * Copyright 2017 Bstek
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License.  You may obtain a copy
+ * of the License at
+ * 
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ ******************************************************************************/
+package com.bstek.ureport.console.html;
+
+/**
+ * @author 
+ * @since 6月1日
+ */
+public class Tools {
+	private boolean show=true;
+	private boolean word=true;
+	private boolean excel=true;
+	private boolean pdf=true;
+	private boolean pagingExcel=true;
+	private boolean sheetPagingExcel=true;
+	private boolean print=true;
+	private boolean pdfPrint=true;
+	private boolean pdfPreviewPrint=true;
+	private boolean paging=true;
+	public Tools(boolean init) {
+		if(init){
+			word=true;
+			excel=true;
+			pdf=true;
+			pagingExcel=true;
+			sheetPagingExcel=true;
+			print=true;
+			pdfPrint=true;
+			pdfPreviewPrint=true;
+			paging=true;
+		}else{
+			word=false;
+			excel=false;
+			pdf=false;
+			pagingExcel=false;
+			sheetPagingExcel=false;
+			print=false;
+			pdfPrint=false;
+			pdfPreviewPrint=false;
+			paging=false;
+		}
+	}
+	public void doInit(String name){
+		if(name.equals("5")){
+			word=true;
+		}else if(name.equals("6")){
+			excel=true;
+		}else if(name.equals("4")){
+			pdf=true;
+		}else if(name.equals("1")){
+			print=true;
+		}else if(name.equals("2")){
+			pdfPrint=true;
+		}else if(name.equals("3")){
+			pdfPreviewPrint=true;
+		}else if(name.equals("9")){
+			paging=true;
+		}else if(name.equals("7")){
+			pagingExcel=true;
+		}else if(name.equals("8")){
+			sheetPagingExcel=true;
+		}
+	}
+	public boolean isShow() {
+		return show;
+	}
+	public void setShow(boolean show) {
+		this.show = show;
+	}
+	public boolean isWord() {
+		return word;
+	}
+	public void setWord(boolean word) {
+		this.word = word;
+	}
+	public boolean isExcel() {
+		return excel;
+	}
+	public void setExcel(boolean excel) {
+		this.excel = excel;
+	}
+	public boolean isPdf() {
+		return pdf;
+	}
+	public void setPdf(boolean pdf) {
+		this.pdf = pdf;
+	}
+	public boolean isPagingExcel() {
+		return pagingExcel;
+	}
+	public void setPagingExcel(boolean pagingExcel) {
+		this.pagingExcel = pagingExcel;
+	}
+	public boolean isSheetPagingExcel() {
+		return sheetPagingExcel;
+	}
+	public void setSheetPagingExcel(boolean sheetPagingExcel) {
+		this.sheetPagingExcel = sheetPagingExcel;
+	}
+	public boolean isPrint() {
+		return print;
+	}
+	public void setPrint(boolean print) {
+		this.print = print;
+	}
+	public boolean isPdfPrint() {
+		return pdfPrint;
+	}
+	public void setPdfPrint(boolean pdfPrint) {
+		this.pdfPrint = pdfPrint;
+	}
+	public boolean isPdfPreviewPrint() {
+		return pdfPreviewPrint;
+	}
+	public void setPdfPreviewPrint(boolean pdfPreviewPrint) {
+		this.pdfPreviewPrint = pdfPreviewPrint;
+	}
+	public boolean isPaging() {
+		return paging;
+	}
+	public void setPaging(boolean paging) {
+		this.paging = paging;
+	}
+}

+ 62 - 0
ureport2-console/src/main/java/com/bstek/ureport/console/image/ImageServletAction.java

@@ -0,0 +1,62 @@
+/*******************************************************************************
+ * Copyright 2017 Bstek
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License.  You may obtain a copy
+ * of the License at
+ * 
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ ******************************************************************************/
+package com.bstek.ureport.console.image;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+import jakarta.servlet.ServletException;
+import jakarta.servlet.http.HttpServletRequest;
+import jakarta.servlet.http.HttpServletResponse;
+
+import org.apache.commons.io.IOUtils;
+import org.apache.commons.lang.StringUtils;
+
+import com.bstek.ureport.cache.ResourceCache;
+import com.bstek.ureport.console.ServletAction;
+
+/**
+ * @author
+ * @since 2016年6月6日
+ */
+public class ImageServletAction implements ServletAction{
+	public static final String URL="/image";
+	@Override
+	public void execute(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
+		String key=req.getParameter("_key");
+		if(StringUtils.isNotBlank(key)){
+			byte[] bytes=(byte[])ResourceCache.getObject(key);
+			InputStream input=new ByteArrayInputStream(bytes);
+			OutputStream output=resp.getOutputStream();
+			resp.setContentType("image/png");
+			try{
+				IOUtils.copy(input, output);			
+			}finally{
+				IOUtils.closeQuietly(input);
+				IOUtils.closeQuietly(output);
+			}
+		}else{
+			//processImage(req, resp);			
+		}
+	}
+
+	@Override
+	public String url() {
+		return URL;
+	}
+}

+ 29 - 0
ureport2-console/src/main/java/com/bstek/ureport/console/importexcel/ExcelParser.java

@@ -0,0 +1,29 @@
+/*******************************************************************************
+ * Copyright 2017 Bstek
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License.  You may obtain a copy
+ * of the License at
+ * 
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ ******************************************************************************/
+package com.bstek.ureport.console.importexcel;
+
+import java.io.InputStream;
+
+import com.bstek.ureport.definition.ReportDefinition;
+
+/**
+ * @author
+ * @since 5月27日
+ */
+public abstract class ExcelParser {
+	public abstract ReportDefinition parse(InputStream inputStream) throws Exception;
+	public abstract boolean support(String name);
+}

+ 303 - 0
ureport2-console/src/main/java/com/bstek/ureport/console/importexcel/HSSFExcelParser.java

@@ -0,0 +1,303 @@
+/*******************************************************************************
+ * Copyright 2017 Bstek
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License.  You may obtain a copy
+ * of the License at
+ * 
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ ******************************************************************************/
+package com.bstek.ureport.console.importexcel;
+
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.poi.hssf.usermodel.HSSFCell;
+import org.apache.poi.hssf.usermodel.HSSFCellStyle;
+import org.apache.poi.hssf.usermodel.HSSFFont;
+import org.apache.poi.hssf.usermodel.HSSFRow;
+import org.apache.poi.hssf.usermodel.HSSFSheet;
+import org.apache.poi.hssf.usermodel.HSSFWorkbook;
+import org.apache.poi.hssf.util.HSSFColor;
+import org.apache.poi.ss.usermodel.BorderStyle;
+import org.apache.poi.ss.usermodel.CellType;
+import org.apache.poi.ss.usermodel.FillPatternType;
+import org.apache.poi.ss.usermodel.Font;
+import org.apache.poi.ss.usermodel.HorizontalAlignment;
+import org.apache.poi.ss.usermodel.VerticalAlignment;
+import org.apache.poi.ss.util.CellRangeAddress;
+
+import com.bstek.ureport.definition.Alignment;
+import com.bstek.ureport.definition.Border;
+import com.bstek.ureport.definition.CellDefinition;
+import com.bstek.ureport.definition.CellStyle;
+import com.bstek.ureport.definition.ColumnDefinition;
+import com.bstek.ureport.definition.Orientation;
+import com.bstek.ureport.definition.PagingMode;
+import com.bstek.ureport.definition.Paper;
+import com.bstek.ureport.definition.PaperSize;
+import com.bstek.ureport.definition.PaperType;
+import com.bstek.ureport.definition.ReportDefinition;
+import com.bstek.ureport.definition.RowDefinition;
+import com.bstek.ureport.definition.value.SimpleValue;
+
+/**
+ * @author
+ * @since 5月27日
+ */
+public class HSSFExcelParser extends ExcelParser {
+	@Override
+	public ReportDefinition parse(InputStream inputStream) throws Exception {
+		ReportDefinition report=new ReportDefinition();
+		List<RowDefinition> rowDefs=new ArrayList<RowDefinition>();
+		report.setRows(rowDefs);
+		List<ColumnDefinition> columnDefs=new ArrayList<ColumnDefinition>();
+		report.setColumns(columnDefs);
+		List<CellDefinition> cellDefs=new ArrayList<CellDefinition>();
+		report.setCells(cellDefs);
+		HSSFWorkbook book=new HSSFWorkbook(inputStream);
+		HSSFSheet sheet=book.getSheetAt(0);
+		int firstRow=0;
+		int rowCount=sheet.getPhysicalNumberOfRows();
+		int maxColumnCount=buildMaxColumn(sheet);
+		for(int i=firstRow;i<rowCount;i++){
+			HSSFRow row=sheet.getRow(i);
+			if(row==null){
+				RowDefinition rowDef=new RowDefinition();
+				rowDef.setHeight(20);
+				rowDef.setRowNumber(i+1);
+				rowDefs.add(rowDef);
+				addBlankCells(cellDefs, i+1, maxColumnCount);
+				continue;
+			}
+			RowDefinition rowDef=new RowDefinition();
+			int height=row.getHeight()/20;
+			rowDef.setHeight(height);
+			rowDef.setRowNumber(i+1);
+			rowDefs.add(rowDef);
+			for(int j=0;j<maxColumnCount;j++){
+				boolean isMergeRegion=isMergedRegion(sheet, i, j);
+				if(isMergeRegion){
+					continue;
+				}
+				HSSFCell cell=row.getCell(j);
+				if(cell==null){
+					CellDefinition cellDef=new CellDefinition();
+					cellDef.setValue(new SimpleValue(""));
+					cellDef.setRowNumber(i+1);
+					cellDef.setColumnNumber(j+1);
+					cellDefs.add(cellDef);
+					continue;
+				}
+				Span span=getSpan(sheet, i, j);
+				
+				Object value=null;
+				CellType cellType=cell.getCellTypeEnum();
+				switch(cellType){
+				case STRING:
+					value=cell.getStringCellValue();
+					break;
+				case BOOLEAN:
+					value=cell.getBooleanCellValue();
+					break;
+				case NUMERIC:
+					value=cell.getNumericCellValue();
+					break;
+				case FORMULA:
+					value=cell.getCellFormula();
+					break;
+				default:
+					value="";
+				}
+				CellDefinition cellDef=new CellDefinition();
+				cellDef.setValue(new SimpleValue(value !=null ? value.toString() : ""));
+				cellDef.setRowNumber(i+1);
+				cellDef.setColumnNumber(j+1);
+				cellDef.setRowSpan(span.getRowSpan());
+				cellDef.setColSpan(span.getColSpan());
+				cellDef.setCellStyle(buildCellStyle(cell,book));
+				cellDefs.add(cellDef);
+			}
+		}
+		for(int i=0;i<maxColumnCount;i++){
+			ColumnDefinition col=new ColumnDefinition();
+			int width=sheet.getColumnWidth(i);
+			col.setWidth(width/37);
+			col.setColumnNumber(i+1);
+			columnDefs.add(col);
+		}
+		book.close();
+		inputStream.close();
+		Paper paper=new Paper();
+		paper.setPaperType(PaperType.A4);
+		paper.setOrientation(Orientation.portrait);
+		paper.setPagingMode(PagingMode.fitpage);
+		PaperSize pageSize=PaperType.A4.getPaperSize();
+		paper.setWidth(pageSize.getWidth());
+		paper.setHeight(paper.getHeight());
+		report.setPaper(paper);
+		return report;
+	}
+
+	private CellStyle buildCellStyle(HSSFCell cell,HSSFWorkbook book){
+		CellStyle style=new CellStyle();
+		HSSFCellStyle cellStyle=cell.getCellStyle();
+		HorizontalAlignment align=cellStyle.getAlignmentEnum();
+		if(align.equals(HorizontalAlignment.CENTER)){
+			style.setAlign(Alignment.center);
+		}else if(align.equals(HorizontalAlignment.RIGHT)){
+			style.setAlign(Alignment.right);
+		}else{
+			style.setAlign(Alignment.left);
+		}
+		VerticalAlignment valign=cellStyle.getVerticalAlignmentEnum();
+		if(valign.equals(VerticalAlignment.BOTTOM)){
+			style.setValign(Alignment.bottom);
+		}else if(valign.equals(VerticalAlignment.TOP)){
+			style.setValign(Alignment.top);
+		}else if(valign.equals(VerticalAlignment.CENTER)){
+			style.setValign(Alignment.middle);
+		}else{
+			style.setValign(Alignment.middle);
+		}
+		HSSFFont font=cellStyle.getFont(book);
+		if(font.getBold()){
+			style.setBold(true);
+		}
+		if(font.getItalic()){
+			style.setItalic(true);
+		}
+		if(font.getUnderline()!=Font.U_NONE){
+			style.setUnderline(true);
+		}
+		HSSFColor color=font.getHSSFColor(book);
+		if(color!=null){
+			short[] rgb=color.getTriplet();
+			style.setForecolor(rgb[0]+","+rgb[1]+","+rgb[2]);
+		}else{
+			style.setForecolor("0,0,0");			
+		}
+		FillPatternType pattern=cellStyle.getFillPatternEnum();
+		if(pattern!=null && pattern.equals(FillPatternType.SOLID_FOREGROUND)){
+			HSSFColor bgcolor=cellStyle.getFillForegroundColorColor();
+			if(bgcolor!=null){
+				short[] rgb=bgcolor.getTriplet();
+				style.setBgcolor(rgb[0]+","+rgb[1]+","+rgb[2]);
+			}		
+		}
+		int fontSize=font.getFontHeight()/20;
+		style.setFontSize(fontSize);
+		BorderStyle borderStyle=cellStyle.getBorderLeftEnum();
+		if(!borderStyle.equals(BorderStyle.NONE)){
+			Border border=new Border();
+			border.setColor("0,0,0");
+			border.setStyle(com.bstek.ureport.definition.BorderStyle.solid);
+			border.setWidth(1);
+			style.setLeftBorder(border);
+		}
+		borderStyle=cellStyle.getBorderRightEnum();
+		if(!borderStyle.equals(BorderStyle.NONE)){
+			Border border=new Border();
+			border.setColor("0,0,0");
+			border.setStyle(com.bstek.ureport.definition.BorderStyle.solid);
+			border.setWidth(1);
+			style.setRightBorder(border);
+		}
+		borderStyle=cellStyle.getBorderTopEnum();
+		if(!borderStyle.equals(BorderStyle.NONE)){
+			Border border=new Border();
+			border.setColor("0,0,0");
+			border.setStyle(com.bstek.ureport.definition.BorderStyle.solid);
+			border.setWidth(1);
+			style.setTopBorder(border);
+		}
+		borderStyle=cellStyle.getBorderBottomEnum();
+		if(!borderStyle.equals(BorderStyle.NONE)){
+			Border border=new Border();
+			border.setColor("0,0,0");
+			border.setStyle(com.bstek.ureport.definition.BorderStyle.solid);
+			border.setWidth(1);
+			style.setBottomBorder(border);
+		}
+		return style;
+	}
+	
+	
+	private Span getSpan(HSSFSheet sheet,int row ,int column){
+		int sheetMergeCount = sheet.getNumMergedRegions(); 
+		for (int i = 0; i < sheetMergeCount; i++) {
+			CellRangeAddress range = sheet.getMergedRegion(i);
+			int firstColumn = range.getFirstColumn();
+			int lastColumn = range.getLastColumn();
+			int firstRow = range.getFirstRow();
+			if(row == firstRow && column==firstColumn){  
+				int lastRow = range.getLastRow();
+				int rowSpan=lastRow-firstRow;
+				if(rowSpan>0){
+					rowSpan++;
+				}
+				int colSpan=lastColumn-firstColumn;
+				if(colSpan>0){
+					colSpan++;
+				}
+				return new Span(rowSpan,colSpan);
+			}
+		}
+		return new Span(0,0);
+	}
+
+	private boolean isMergedRegion(HSSFSheet sheet, int row, int column) {
+		int sheetMergeCount = sheet.getNumMergedRegions();
+		for (int i = 0; i < sheetMergeCount; i++) {
+			CellRangeAddress range = sheet.getMergedRegion(i);
+			int firstColumn = range.getFirstColumn();
+			int lastColumn = range.getLastColumn();
+			int firstRow = range.getFirstRow();
+			int lastRow = range.getLastRow();
+			if (row > firstRow && row < lastRow) {
+				if (column > firstColumn && column < lastColumn) {
+					return true;
+				}
+			}
+		}
+		return false;
+	}
+	
+	private int buildMaxColumn(HSSFSheet sheet){
+		int rowCount=sheet.getPhysicalNumberOfRows();
+		int maxColumnCount=0;
+		for(int i=0;i<rowCount;i++){
+			HSSFRow row=sheet.getRow(i);
+			if(row==null){
+				continue;
+			}
+			int columnCount=row.getPhysicalNumberOfCells();
+			if(columnCount>maxColumnCount){
+				maxColumnCount=columnCount;
+			}
+		}
+		return maxColumnCount;
+	}
+	
+	protected void addBlankCells(List<CellDefinition> cellDefs,int rowNumber,int totalColumn){
+		for(int i=0;i<totalColumn;i++){
+			CellDefinition cellDef=new CellDefinition();
+			cellDef.setValue(new SimpleValue(""));
+			cellDef.setRowNumber(rowNumber);
+			cellDef.setColumnNumber(i+1);
+			cellDefs.add(cellDef);
+		}
+	}
+	
+	@Override
+	public boolean support(String name) {
+		return name.toLowerCase().endsWith(".xls");
+	}
+}

+ 85 - 0
ureport2-console/src/main/java/com/bstek/ureport/console/importexcel/ImportExcelServletAction.java

@@ -0,0 +1,85 @@
+/*******************************************************************************
+ * Copyright 2017 Bstek
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License.  You may obtain a copy
+ * of the License at
+ * 
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ ******************************************************************************/
+package com.bstek.ureport.console.importexcel;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.List;
+
+import jakarta.servlet.ServletException;
+import jakarta.servlet.http.HttpServletRequest;
+import jakarta.servlet.http.HttpServletResponse;
+
+import com.bstek.ureport.console.designer.ReportDefinitionWrapper;
+import com.bstek.ureport.console.util.ActionResult;
+import jakarta.servlet.http.Part;
+import lombok.extern.slf4j.Slf4j;
+
+import com.bstek.ureport.console.RenderPageServletAction;
+import com.bstek.ureport.definition.ReportDefinition;
+import org.apache.tomcat.util.http.fileupload.FileUploadBase;
+
+/**
+ * @author
+ * @since 5月25日
+ */
+@Slf4j
+public class ImportExcelServletAction extends RenderPageServletAction {
+	private List<ExcelParser> excelParsers=new ArrayList<ExcelParser>();
+
+	public ImportExcelServletAction(){
+		excelParsers.add(new HSSFExcelParser());
+		excelParsers.add(new XSSFExcelParser());
+	}
+	@Override
+	public void execute(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
+		if(!req.getContentType().startsWith(FileUploadBase.MULTIPART)){
+			throw new RuntimeException("导入未包含Excel文件");
+		}
+		ReportDefinition report=null;
+		try {
+			for (Part part : req.getParts()) {
+				String name=part.getSubmittedFileName().toLowerCase();
+				if((name.endsWith(".xls") || name.endsWith(".xlsx"))){
+					InputStream inputStream=part.getInputStream();
+					for(ExcelParser parser:excelParsers){
+						if(parser.support(name)){
+							report=parser.parse(inputStream);
+							break;
+						}
+					}
+					inputStream.close();
+					break;
+				}
+			}
+		} catch (Exception e) {
+			log.error("导入Excel失败:" + e.getMessage(), e);
+			writeObjectToJson(resp,ActionResult.fail("请选择一个合法的Excel导入"));
+		}
+		if(report!=null){
+			ReportDefinitionWrapper wrapper = new ReportDefinitionWrapper(report);
+			writeObjectToJson(resp, ActionResult.success(wrapper));
+		}else{
+			writeObjectToJson(resp,ActionResult.fail("请选择一个合法的Excel导入"));
+		}
+	}
+	
+	@Override
+	public String url() {
+		return "/import";
+	}
+}

+ 35 - 0
ureport2-console/src/main/java/com/bstek/ureport/console/importexcel/Span.java

@@ -0,0 +1,35 @@
+/*******************************************************************************
+ * Copyright 2017 Bstek
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License.  You may obtain a copy
+ * of the License at
+ * 
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ ******************************************************************************/
+package com.bstek.ureport.console.importexcel;
+
+/**
+ * @author
+ * @since 5月26日
+ */
+public class Span {
+	private int rowSpan;
+	private int colSpan;
+	public Span(int rowSpan,int colSpan) {
+		this.rowSpan=rowSpan;
+		this.colSpan=colSpan;
+	}
+	public int getRowSpan() {
+		return rowSpan;
+	}
+	public int getColSpan() {
+		return colSpan;
+	}
+}

+ 308 - 0
ureport2-console/src/main/java/com/bstek/ureport/console/importexcel/XSSFExcelParser.java

@@ -0,0 +1,308 @@
+/*******************************************************************************
+ * Copyright 2017 Bstek
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License.  You may obtain a copy
+ * of the License at
+ * 
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ ******************************************************************************/
+package com.bstek.ureport.console.importexcel;
+
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.poi.ss.usermodel.BorderStyle;
+import org.apache.poi.ss.usermodel.CellType;
+import org.apache.poi.ss.usermodel.FillPatternType;
+import org.apache.poi.ss.usermodel.Font;
+import org.apache.poi.ss.usermodel.HorizontalAlignment;
+import org.apache.poi.ss.usermodel.VerticalAlignment;
+import org.apache.poi.ss.util.CellRangeAddress;
+import org.apache.poi.xssf.usermodel.XSSFCell;
+import org.apache.poi.xssf.usermodel.XSSFCellStyle;
+import org.apache.poi.xssf.usermodel.XSSFColor;
+import org.apache.poi.xssf.usermodel.XSSFFont;
+import org.apache.poi.xssf.usermodel.XSSFRow;
+import org.apache.poi.xssf.usermodel.XSSFSheet;
+import org.apache.poi.xssf.usermodel.XSSFWorkbook;
+
+import com.bstek.ureport.definition.Alignment;
+import com.bstek.ureport.definition.Border;
+import com.bstek.ureport.definition.CellDefinition;
+import com.bstek.ureport.definition.CellStyle;
+import com.bstek.ureport.definition.ColumnDefinition;
+import com.bstek.ureport.definition.Orientation;
+import com.bstek.ureport.definition.PagingMode;
+import com.bstek.ureport.definition.Paper;
+import com.bstek.ureport.definition.PaperSize;
+import com.bstek.ureport.definition.PaperType;
+import com.bstek.ureport.definition.ReportDefinition;
+import com.bstek.ureport.definition.RowDefinition;
+import com.bstek.ureport.definition.value.SimpleValue;
+
+/**
+ * @author
+ * @since 5月27日
+ */
+public class XSSFExcelParser extends ExcelParser {
+	@Override
+	public ReportDefinition parse(InputStream inputStream) throws Exception {
+		ReportDefinition report=new ReportDefinition();
+		List<RowDefinition> rowDefs=new ArrayList<RowDefinition>();
+		report.setRows(rowDefs);
+		List<ColumnDefinition> columnDefs=new ArrayList<ColumnDefinition>();
+		report.setColumns(columnDefs);
+		List<CellDefinition> cellDefs=new ArrayList<CellDefinition>();
+		report.setCells(cellDefs);
+		XSSFWorkbook book=new XSSFWorkbook(inputStream);
+		XSSFSheet sheet=book.getSheetAt(0);
+		int firstRow=0;
+		int rowCount=sheet.getPhysicalNumberOfRows();
+		int maxColumnCount=buildMaxColumn(sheet);
+		for(int i=firstRow;i<rowCount;i++){
+			XSSFRow row=sheet.getRow(i);
+			if(row==null){
+				RowDefinition rowDef=new RowDefinition();
+				rowDef.setHeight(20);
+				rowDef.setRowNumber(i+1);
+				rowDefs.add(rowDef);
+				addBlankCells(cellDefs, i+1, maxColumnCount);
+				continue;
+			}
+			RowDefinition rowDef=new RowDefinition();
+			int height=row.getHeight()/20;
+			rowDef.setHeight(height);
+			rowDef.setRowNumber(i+1);
+			rowDefs.add(rowDef);
+			for(int j=0;j<maxColumnCount;j++){
+				boolean isMergeRegion=isMergedRegion(sheet, i, j);
+				if(isMergeRegion){
+					continue;
+				}
+				XSSFCell cell=row.getCell(j);
+				if(cell==null){
+					CellDefinition cellDef=new CellDefinition();
+					cellDef.setValue(new SimpleValue(""));
+					cellDef.setRowNumber(i+1);
+					cellDef.setColumnNumber(j+1);
+					cellDefs.add(cellDef);
+					continue;
+				}
+				Span span=getSpan(sheet, i, j);
+				
+				Object value=null;
+				CellType cellType=cell.getCellTypeEnum();
+				switch(cellType){
+				case STRING:
+					value=cell.getStringCellValue();
+					break;
+				case BOOLEAN:
+					value=cell.getBooleanCellValue();
+					break;
+				case NUMERIC:
+					value=cell.getNumericCellValue();
+					break;
+				case FORMULA:
+					value=cell.getCellFormula();
+					break;
+				default:
+					value="";
+				}
+				CellDefinition cellDef=new CellDefinition();
+				cellDef.setValue(new SimpleValue(value !=null ? value.toString() : ""));
+				cellDef.setRowNumber(i+1);
+				cellDef.setColumnNumber(j+1);
+				cellDef.setRowSpan(span.getRowSpan());
+				cellDef.setColSpan(span.getColSpan());
+				cellDef.setCellStyle(buildCellStyle(cell,book));
+				cellDefs.add(cellDef);
+			}
+		}
+		for(int i=0;i<maxColumnCount;i++){
+			ColumnDefinition col=new ColumnDefinition();
+			int width=sheet.getColumnWidth(i);
+			col.setWidth(width/37);
+			col.setColumnNumber(i+1);
+			columnDefs.add(col);
+		}
+		book.close();
+		inputStream.close();
+		Paper paper=new Paper();
+		paper.setPaperType(PaperType.A4);
+		paper.setOrientation(Orientation.portrait);
+		paper.setPagingMode(PagingMode.fitpage);
+		PaperSize pageSize=PaperType.A4.getPaperSize();
+		paper.setWidth(pageSize.getWidth());
+		paper.setHeight(paper.getHeight());
+		report.setPaper(paper);
+		return report;
+	}
+
+	private CellStyle buildCellStyle(XSSFCell cell,XSSFWorkbook book){
+		CellStyle style=new CellStyle();
+		XSSFCellStyle cellStyle=cell.getCellStyle();
+		HorizontalAlignment align=cellStyle.getAlignmentEnum();
+		if(align.equals(HorizontalAlignment.CENTER)){
+			style.setAlign(Alignment.center);
+		}else if(align.equals(HorizontalAlignment.RIGHT)){
+			style.setAlign(Alignment.right);
+		}else{
+			style.setAlign(Alignment.left);
+		}
+		VerticalAlignment valign=cellStyle.getVerticalAlignmentEnum();
+		if(valign.equals(VerticalAlignment.BOTTOM)){
+			style.setValign(Alignment.bottom);
+		}else if(valign.equals(VerticalAlignment.TOP)){
+			style.setValign(Alignment.top);
+		}else if(valign.equals(VerticalAlignment.CENTER)){
+			style.setValign(Alignment.middle);
+		}else{
+			style.setValign(Alignment.middle);
+		}
+		XSSFFont font=cellStyle.getFont();
+		if(font.getBold()){
+			style.setBold(true);
+		}
+		if(font.getItalic()){
+			style.setItalic(true);
+		}
+		if(font.getUnderline()!=Font.U_NONE){
+			style.setUnderline(true);
+		}
+		XSSFColor color=font.getXSSFColor();
+		if(color!=null){
+			String rgb=color.getARGBHex();
+			style.setForecolor(hex2Rgb(rgb));
+		}else{
+			style.setForecolor("0,0,0");			
+		}
+		FillPatternType pattern=cellStyle.getFillPatternEnum();
+		if(pattern!=null && pattern.equals(FillPatternType.SOLID_FOREGROUND)){
+			XSSFColor bgcolor=cellStyle.getFillForegroundColorColor();
+			if(bgcolor!=null){
+				String hex=bgcolor.getARGBHex();
+				style.setBgcolor(hex2Rgb(hex));					
+			}
+		}
+		int fontSize=font.getFontHeight()/20;
+		style.setFontSize(fontSize);
+		BorderStyle borderStyle=cellStyle.getBorderLeftEnum();
+		if(!borderStyle.equals(BorderStyle.NONE)){
+			Border border=new Border();
+			border.setColor("0,0,0");
+			border.setStyle(com.bstek.ureport.definition.BorderStyle.solid);
+			border.setWidth(1);
+			style.setLeftBorder(border);
+		}
+		borderStyle=cellStyle.getBorderRightEnum();
+		if(!borderStyle.equals(BorderStyle.NONE)){
+			Border border=new Border();
+			border.setColor("0,0,0");
+			border.setStyle(com.bstek.ureport.definition.BorderStyle.solid);
+			border.setWidth(1);
+			style.setRightBorder(border);
+		}
+		borderStyle=cellStyle.getBorderTopEnum();
+		if(!borderStyle.equals(BorderStyle.NONE)){
+			Border border=new Border();
+			border.setColor("0,0,0");
+			border.setStyle(com.bstek.ureport.definition.BorderStyle.solid);
+			border.setWidth(1);
+			style.setTopBorder(border);
+		}
+		borderStyle=cellStyle.getBorderBottomEnum();
+		if(!borderStyle.equals(BorderStyle.NONE)){
+			Border border=new Border();
+			border.setColor("0,0,0");
+			border.setStyle(com.bstek.ureport.definition.BorderStyle.solid);
+			border.setWidth(1);
+			style.setBottomBorder(border);
+		}
+		return style;
+	}
+
+	private  String hex2Rgb(String colorStr) {
+		return Integer.valueOf(colorStr.substring( 2, 4 ),16 )+","+
+				Integer.valueOf( colorStr.substring( 4, 6 ), 16 )+","+
+	            Integer.valueOf( colorStr.substring( 6, 8 ), 16 );
+	}
+	
+	private Span getSpan(XSSFSheet sheet,int row ,int column){
+		int sheetMergeCount = sheet.getNumMergedRegions(); 
+		for (int i = 0; i < sheetMergeCount; i++) {
+			CellRangeAddress range = sheet.getMergedRegion(i);
+			int firstColumn = range.getFirstColumn();
+			int lastColumn = range.getLastColumn();
+			int firstRow = range.getFirstRow();
+			if(row == firstRow && column==firstColumn){  
+				int lastRow = range.getLastRow();
+				int rowSpan=lastRow-firstRow;
+				if(rowSpan>0){
+					rowSpan++;
+				}
+				int colSpan=lastColumn-firstColumn;
+				if(colSpan>0){
+					colSpan++;
+				}
+				return new Span(rowSpan,colSpan);
+			}
+		}
+		return new Span(0,0);
+	}
+
+	private boolean isMergedRegion(XSSFSheet sheet, int row, int column) {
+		int sheetMergeCount = sheet.getNumMergedRegions();
+		for (int i = 0; i < sheetMergeCount; i++) {
+			CellRangeAddress range = sheet.getMergedRegion(i);
+			int firstColumn = range.getFirstColumn();
+			int lastColumn = range.getLastColumn();
+			int firstRow = range.getFirstRow();
+			int lastRow = range.getLastRow();
+			if (row > firstRow && row < lastRow) {
+				if (column > firstColumn && column < lastColumn) {
+					return true;
+				}
+			}
+		}
+		return false;
+	}
+	
+	private int buildMaxColumn(XSSFSheet sheet){
+		int rowCount=sheet.getPhysicalNumberOfRows();
+		int maxColumnCount=0;
+		for(int i=0;i<rowCount;i++){
+			XSSFRow row=sheet.getRow(i);
+			if(row==null){
+				continue;
+			}
+			int columnCount=row.getPhysicalNumberOfCells();
+			if(columnCount>maxColumnCount){
+				maxColumnCount=columnCount;
+			}
+		}
+		return maxColumnCount;
+	}
+	
+	protected void addBlankCells(List<CellDefinition> cellDefs,int rowNumber,int totalColumn){
+		for(int i=0;i<totalColumn;i++){
+			CellDefinition cellDef=new CellDefinition();
+			cellDef.setValue(new SimpleValue(""));
+			cellDef.setRowNumber(rowNumber);
+			cellDef.setColumnNumber(i+1);
+			cellDefs.add(cellDef);
+		}
+	}
+	
+	@Override
+	public boolean support(String name) {
+		return name.toLowerCase().endsWith(".xlsx");
+	}
+}

+ 224 - 0
ureport2-console/src/main/java/com/bstek/ureport/console/pdf/ExportPdfServletAction.java

@@ -0,0 +1,224 @@
+/*******************************************************************************
+ * Copyright 2017 Bstek
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License.  You may obtain a copy
+ * of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ ******************************************************************************/
+package com.bstek.ureport.console.pdf;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.net.URLEncoder;
+import java.sql.Connection;
+import java.sql.SQLException;
+import java.util.Map;
+import java.util.UUID;
+
+import com.bstek.ureport.console.WriteJsonServletAction;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import jakarta.servlet.ServletException;
+import jakarta.servlet.http.HttpServletRequest;
+import jakarta.servlet.http.HttpServletResponse;
+
+import jnpf.database.util.DynamicDataSourceUtil;
+import com.bstek.ureport.console.ureport.entity.ReportEntity;
+import com.bstek.ureport.console.ureport.service.ReportService;
+import com.bstek.ureport.console.util.ActionResult;
+import com.bstek.ureport.console.ureport.util.UreportUtil;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang.StringUtils;
+
+import com.bstek.ureport.build.ReportBuilder;
+import com.bstek.ureport.console.cache.TempObjectCache;
+import com.bstek.ureport.console.exception.ReportDesignException;
+import com.bstek.ureport.definition.Paper;
+import com.bstek.ureport.definition.ReportDefinition;
+import com.bstek.ureport.exception.ReportComputeException;
+import com.bstek.ureport.export.ExportManager;
+import com.bstek.ureport.export.ReportRender;
+import com.bstek.ureport.export.pdf.PdfProducer;
+import com.bstek.ureport.model.Report;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.http.MediaType;
+import org.springframework.jdbc.support.JdbcUtils;
+
+/**
+ * 导出报表到PDF
+ * @author
+ * @since 3月20日
+ */
+@Slf4j
+public class ExportPdfServletAction extends WriteJsonServletAction {
+    @Autowired
+    private ReportService reportService;
+
+    private ReportBuilder reportBuilder;
+    private ExportManager exportManager;
+    private ReportRender reportRender;
+    private PdfProducer pdfProducer = new PdfProducer();
+
+    @Override
+    public void execute(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
+        String method = retriveMethod(req);
+        if (method != null) {
+            invokeMethod(method, req, resp);
+        } else {
+            buildPdf(req, resp, false);
+        }
+    }
+
+    public void show(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
+        buildPdf(req, resp, true);
+    }
+
+    //临时预览时候的导出pdf
+    public void buildPdf(HttpServletRequest req, HttpServletResponse resp, boolean forPrint) throws IOException {
+        String token = req.getParameter("token");
+        token = decode(token);
+        String id = req.getParameter("id");
+        id = decode(id);
+        if (StringUtils.isBlank(token) || StringUtils.isBlank(id)) {
+            throw new ReportComputeException("Report file can not be null.");
+        }
+        OutputStream outputStream = null;
+        try {
+            String fullName = null;
+            ReportDefinition reportDefinition = (ReportDefinition) TempObjectCache.getObject(id);
+            if (reportDefinition == null) {
+                reportDefinition = (ReportDefinition) TempObjectCache.getObject(token);
+                fullName = String.valueOf(UUID.randomUUID());
+            } else {
+                fullName = reportService.GetInfo(id).getFullName();
+            }
+            outputStream = resp.getOutputStream();
+            Map<String, Object> parameters = buildParameters(req);
+            if (reportDefinition == null) {
+                throw new ReportDesignException("Report data has expired,can not do export pdf.");
+            }
+            if (forPrint) {
+                resp.setCharacterEncoding("UTF-8");
+                resp.setHeader("content-Type", MediaType.APPLICATION_PDF_VALUE);
+                Connection connection = DynamicDataSourceUtil.getCurrentConnection();
+                Report report;
+                try {
+                    report = reportBuilder.buildReportToConnection(reportDefinition, parameters, connection);
+                }finally {
+                    JdbcUtils.closeConnection(connection);
+                }
+                pdfProducer.produce(report, outputStream);
+            } else {
+                resp.setCharacterEncoding("UTF-8");
+                resp.setHeader("content-Type", MediaType.APPLICATION_OCTET_STREAM_VALUE);
+                resp.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(fullName + ".pdf", "UTF-8"));
+                Connection connection = DynamicDataSourceUtil.getCurrentConnection();
+                Report report;
+                try {
+                    report = reportBuilder.buildReportToConnection(reportDefinition, parameters, connection);
+                } finally {
+                    JdbcUtils.closeConnection(connection);
+                }
+                pdfProducer.produce(report, outputStream);
+            }
+        } catch (Exception ex) {
+            writeObjectToJson(resp, ActionResult.fail("请检查参数"));
+        } finally {
+                outputStream.flush();
+                outputStream.close();
+        }
+    }
+
+    public void newPaging(HttpServletRequest req, HttpServletResponse resp) throws IOException {
+        String id = req.getParameter("id");
+        id = decode(id);
+        String token = req.getHeader("Authorization");
+        token = decode(token);
+        if (StringUtils.isBlank(id) || StringUtils.isBlank(token)) {
+            writeObjectToJson(resp, ActionResult.fail("请检查参数"));
+        }
+        if ("preview".equals(id)) {
+            ReportDefinition reportDefinition = (ReportDefinition) TempObjectCache.getObject(token);
+            Map<String, Object> parameters = buildParameters(req);
+            Connection connection = null;
+            try {
+                connection = DynamicDataSourceUtil.getCurrentConnection();
+            } catch (SQLException throwables) {
+                throwables.printStackTrace();
+                log.error("数据源错误:"+throwables.getMessage());
+            }
+            Report report;
+            try {
+                report = reportBuilder.buildReportToConnection(reportDefinition, parameters, connection);
+            }finally {
+                JdbcUtils.closeConnection(connection);
+            }
+            String paper = req.getParameter("_paper");
+            ObjectMapper mapper = new ObjectMapper();
+            Paper newPaper = mapper.readValue(paper, Paper.class);
+            report.rePaging(newPaper);
+            reportDefinition.setPaper(newPaper);
+            writeObjectToJson(resp, report.getPaper());
+        } else {
+            ReportEntity entity = reportService.GetInfo(id);
+            if (entity == null) {
+                writeObjectToJson(resp, ActionResult.fail("数据不存在"));
+            } else {
+                Connection connection = null;
+                try {
+                    connection = DynamicDataSourceUtil.getCurrentConnection();
+                } catch (SQLException throwables) {
+                    throwables.printStackTrace();
+                    log.error("数据源错误:"+throwables.getMessage());
+                }
+                ReportDefinition reportDefinition = (ReportDefinition) TempObjectCache.getObject(id);
+                Report report;
+                try {
+
+                    if(reportDefinition == null) {
+                        byte[] content = entity.getContent().getBytes();
+                        ByteArrayInputStream inputStream = new ByteArrayInputStream(content);
+                        reportDefinition = UreportUtil.parseReport(inputStream, entity.getFullName());
+                    }
+                    Map<String, Object> parameters = buildParameters(req);
+                    report = reportBuilder.buildReportToConnection(reportDefinition, parameters, connection);
+                }finally {
+                    JdbcUtils.closeConnection(connection);
+                }
+                //获取
+                String paper = req.getParameter("_paper");
+                ObjectMapper mapper = new ObjectMapper();
+                Paper newPaper = mapper.readValue(paper, Paper.class);
+                report.rePaging(newPaper);
+                reportDefinition.setPaper(newPaper);
+                writeObjectToJson(resp, report.getPaper());
+            }
+        }
+    }
+
+    public void setReportRender(ReportRender reportRender) {
+        this.reportRender = reportRender;
+    }
+
+    public void setExportManager(ExportManager exportManager) {
+        this.exportManager = exportManager;
+    }
+
+    public void setReportBuilder(ReportBuilder reportBuilder) {
+        this.reportBuilder = reportBuilder;
+    }
+
+    @Override
+    public String url() {
+        return "/pdf";
+    }
+
+}

+ 79 - 0
ureport2-console/src/main/java/com/bstek/ureport/console/res/ResourceLoaderServletAction.java

@@ -0,0 +1,79 @@
+/*******************************************************************************
+ * Copyright 2017 Bstek
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License.  You may obtain a copy
+ * of the License at
+ * 
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ ******************************************************************************/
+package com.bstek.ureport.console.res;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+import jakarta.servlet.ServletException;
+import jakarta.servlet.http.HttpServletRequest;
+import jakarta.servlet.http.HttpServletResponse;
+
+import org.apache.commons.io.IOUtils;
+import org.springframework.beans.BeansException;
+import org.springframework.context.ApplicationContext;
+import org.springframework.context.ApplicationContextAware;
+
+import com.bstek.ureport.console.ServletAction;
+import com.bstek.ureport.console.UReportServlet;
+
+/**
+ * @author 
+ * @since 2016年6月6日
+ */
+public class ResourceLoaderServletAction implements ServletAction,ApplicationContextAware{
+	public static final String URL="/res";
+	private ApplicationContext applicationContext;
+	@Override
+	public void execute(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
+//		String path=req.getContextPath()+UReportServlet.URL+URL;
+//		String uri=req.getRequestURI();
+//		String resPath=uri.substring(path.length()+1);
+//		String p="classpath:"+resPath;
+//		if(p.endsWith(".js")){
+//			resp.setContentType("text/javascript");
+//		}else if(p.endsWith(".css")){
+//			resp.setContentType("text/css");
+//		}else if(p.endsWith(".png")){
+//			resp.setContentType("image/png");
+//		}else if(p.endsWith(".jpg")){
+//			resp.setContentType("image/jpeg");
+//		}else if(p.endsWith(".svg")){
+//			resp.setContentType("image/svg+xml");
+//		}else{
+//			resp.setContentType("application/octet-stream");
+//		}
+//		InputStream input=applicationContext.getResource(p).getInputStream();
+//		OutputStream output=resp.getOutputStream();
+//		try{
+//			IOUtils.copy(input, output);
+//		}finally{
+//			IOUtils.closeQuietly(input);
+//			IOUtils.closeQuietly(output);
+//		}
+	}
+
+	@Override
+	public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
+		this.applicationContext=applicationContext;
+	}
+	
+	@Override
+	public String url() {
+		return URL;
+	}
+}

+ 571 - 0
ureport2-console/src/main/java/com/bstek/ureport/console/ureport/controller/DataReportController.java

@@ -0,0 +1,571 @@
+package com.bstek.ureport.console.ureport.controller;
+
+import cn.hutool.core.bean.BeanUtil;
+import cn.hutool.core.util.ObjectUtil;
+import com.bstek.ureport.build.ReportBuilder;
+import com.bstek.ureport.console.BaseServletAction;
+import com.bstek.ureport.console.cache.TempObjectCache;
+import com.bstek.ureport.console.designer.ReportDefinitionWrapper;
+import com.bstek.ureport.console.ureport.entity.ReportEntity;
+import com.bstek.ureport.console.ureport.entity.SystemEntity;
+import com.bstek.ureport.console.ureport.entity.UserEntity;
+import com.bstek.ureport.console.ureport.model.*;
+import com.bstek.ureport.console.ureport.service.CodeNumService;
+import com.bstek.ureport.console.ureport.service.ReportService;
+import com.bstek.ureport.console.ureport.service.SystemService;
+import com.bstek.ureport.console.ureport.service.UserService;
+import com.bstek.ureport.console.ureport.util.DownUtil;
+import com.bstek.ureport.console.ureport.util.UreportPreviewUtil;
+import com.bstek.ureport.console.ureport.util.UreportUtil;
+import com.bstek.ureport.console.util.*;
+import com.bstek.ureport.definition.ReportDefinition;
+import com.bstek.ureport.definition.datasource.DatasourceDefinition;
+import com.bstek.ureport.definition.datasource.JdbcDatasourceDefinition;
+import com.bstek.ureport.export.ReportRender;
+import com.bstek.ureport.export.html.HtmlReport;
+import com.bstek.ureport.model.Report;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.SerializationFeature;
+import jakarta.servlet.http.Part;
+import jnpf.constant.CodeConst;
+import jnpf.database.util.DynamicDataSourceUtil;
+import jnpf.util.JsonUtil;
+import jnpf.util.StringUtil;
+import jnpf.util.UserProvider;
+import jnpf.util.context.RequestContext;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.dao.QueryTimeoutException;
+import org.springframework.jdbc.support.JdbcUtils;
+
+import jakarta.servlet.ServletException;
+import jakarta.servlet.http.HttpServletRequest;
+import jakarta.servlet.http.HttpServletResponse;
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.nio.charset.StandardCharsets;
+import java.sql.Connection;
+import java.sql.SQLException;
+import java.text.SimpleDateFormat;
+import java.util.*;
+import java.util.stream.Collectors;
+
+/**
+ * 核心控制层,大部分功能
+ */
+@Slf4j
+public class DataReportController extends BaseServletAction {
+
+    public static final String MAIN_SYSTEM = "mainSystem";
+    @Autowired
+    private ReportService reportService;
+    @Autowired
+    private ReportRender reportRender;
+    @Autowired
+    private UserService userService;
+    @Autowired
+    private SystemService systemService;
+    @Autowired
+    private CodeNumService codeNumService;
+
+    @Override
+    public void execute(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
+        String url = retriveMethod(req);
+        String method = req.getMethod();
+        if (method.equals("POST")) {
+            if (url == null) {
+                savaData(req, resp);
+            } else if (url.contains("Actions/Copy")) {
+                String id = url.split("/")[0];
+                copyReport(req, resp, id);
+            } else if (url.contains("Actions/Import")) {//导入
+                importDataReport(req, resp);
+            }
+        } else if (method.equals("PUT")) {
+            if (url.contains("Actions/State")) {
+                String id = url.split("/")[0];
+                stateDataReport(req, resp, id);
+            }else {
+                String id = url;//ids.substring(strStartIndex + 1);
+                if (StringUtil.isEmpty(id)) {
+                    writeObjectToJson(resp, ActionResult.fail("数据不存在"));
+                    return;
+                }
+                updateData(req, resp, id);
+            }
+        } else if (method.equals("DELETE")) {
+            if (StringUtil.isEmpty(url)) {
+                writeObjectToJson(resp, ActionResult.fail("数据不存在"));
+                return;
+            }
+            deleteData(req, resp, url);
+        } else if (method.equals("GET")) {
+            if (url == null) {
+                getList(req, resp);
+            } else if (url.equals("init")) {
+                init(req, resp);
+            } else if (url.equals("Selector")) {
+                Selector(req, resp);
+            } else if (url.equals("preview")) {
+                previewData(req, resp);
+            } else if (url.contains("Actions/Export")) {
+                //截取id
+                String id = url.split("/")[0];
+                exportDataReport(req, resp, id);
+            } else {
+                //打开报表
+                if (StringUtil.isEmpty(url)) {
+                    writeObjectToJson(resp, ActionResult.fail("数据不存在"));
+                    return;
+                }
+                getInfo(req, resp, url);
+            }
+        }
+    }
+
+    /**
+     * 更新状态
+     *
+     * @param req
+     * @param resp
+     * @param id
+     */
+    private void stateDataReport(HttpServletRequest req, HttpServletResponse resp, String id) throws IOException {
+        ReportEntity entity = reportService.GetInfo(id);
+        if(entity==null){
+            writeObjectToJson(resp, ActionResult.fail("更新接口状态失败,数据不存在"));
+        }else {
+            entity.setEnabledMark("0".equals(String.valueOf(entity.getEnabledMark()))?1:0);
+            reportService.Update(id,entity);
+            writeObjectToJson(resp, ActionResult.success("更新接口状态成功"));
+        }
+    }
+
+    /**
+     * 导出报表
+     *
+     * @param req
+     * @param resp
+     * @param id
+     */
+    private void exportDataReport(HttpServletRequest req, HttpServletResponse resp, String id) {
+        ReportEntity entity = reportService.GetInfo(id);
+        if (StringUtil.isEmpty(entity.getSystemId())){
+            SystemEntity code = systemService.getInfoByEnCode(RequestContext.getAppCode());
+            if (BeanUtil.isNotEmpty(code)){
+                entity.setSystemId(code.getId());
+            }
+        }
+        String contentJson = entity.getContent();
+        try {
+            byte[] content = entity.getContent().getBytes(StandardCharsets.UTF_8);
+            ByteArrayInputStream inputStream = new ByteArrayInputStream(content);
+            ReportDefinition reportDefinition = UreportUtil.parseReport(inputStream, entity.getFullName(), true);
+            for (DatasourceDefinition definition : reportDefinition.getDatasources()) {
+                if (definition instanceof JdbcDatasourceDefinition) {
+                    contentJson = contentJson.replaceAll("password=\"" + ((JdbcDatasourceDefinition) definition).getPassword() + "\"", "password=\"\"");
+                }
+            }
+            entity.setContent(contentJson);
+        } catch (Exception e) {
+            log.error(e.getMessage());
+        }
+        String objectToString = JsonUtil.getObjectToString(entity);
+        DownUtil.downloadFile(objectToString, entity.getFullName() + ".json");
+    }
+
+    /**
+     * 导入
+     *
+     * @param req
+     * @param resp
+     */
+    private void importDataReport(HttpServletRequest req, HttpServletResponse resp) throws IOException, ServletException {
+        String fileContent = null;
+        SystemEntity code = systemService.getInfoByEnCode(RequestContext.getAppCode());
+        try {
+            String contentType = req.getContentType();
+            String type = "0";
+            if (contentType != null && contentType.contains("multipart/form-data")) {
+                Part file = req.getPart("file");
+                type = req.getParameter("type");
+                if (file != null) {
+                    fileContent = FileUtil.getFileContent(file);
+                }
+            }
+            ReportEntity entity = JsonUtil.getJsonToBean(fileContent, ReportEntity.class);
+            if (entity.getContent() == null || entity.getContent().isEmpty()) {
+                writeObjectToJson(resp, ActionResult.fail("导入失败,数据有误"));
+            }
+            StringJoiner joiner = new StringJoiner("、");
+            boolean idCheck=false;
+            if (StringUtil.isEmpty(entity.getSystemId())
+                    ||!entity.getSystemId().equals(code.getId())){
+                entity.setId(jnpf.util.RandomUtil.uuId());
+                entity.setEnCode(codeNumService.getCodeFunction(() ->
+                        codeNumService.getCodeOnce(CodeConst.BB), encode -> reportService.IsExistEncode(encode)));
+                entity.setSystemId(code.getId());
+            }else {
+                idCheck = true;
+            }
+            ReportEntity reportEntity = reportService.GetInfo(entity.getId());
+            if (idCheck&&reportEntity != null) {
+                joiner.add("ID");
+            }
+            if (reportService.IsExistByFullName(entity.getFullName(), null, code.getId())) {
+                joiner.add("名称");
+            }
+            if (reportService.IsExistEncode(entity.getEnCode())){
+                joiner.add("编码");
+            }
+            if (ObjectUtil.equal(type, "0") && joiner.length() > 0) {
+                writeObjectToJson(resp, ActionResult.fail(joiner.toString() + "重复"));
+            }
+            if (ObjectUtil.equal(type, "1") && joiner.length() > 0) {
+                String copyNum = UUID.randomUUID().toString().substring(0, 5);
+                entity.setFullName(entity.getFullName() + ".副本" + copyNum);
+                entity.setEnCode(entity.getEnCode() + copyNum);
+                entity.setId(null);
+            }
+            String token = req.getHeader("Authorization");
+            String userId = UserProvider.getLoginUserId();
+            entity.setCreatorTime(new Date());
+            entity.setCreatorUser(userId);
+            entity.setLastModifyTime(null);
+            entity.setLastModifyUser(null);
+            entity.setEnabledMark(0);
+            String appCode = RequestContext.getAppCode();
+            SystemEntity systemEntity = systemService.getInfoByEnCode(appCode);
+            entity.setSystemId(systemEntity!=null?systemEntity.getId():"");
+            reportService.Create(entity);
+            writeObjectToJson(resp, ActionResult.success("导入成功"));
+        } catch (Exception e) {
+            log.error(e.getMessage(), e);
+            writeObjectToJson(resp, ActionResult.fail("导入失败,数据有误"));
+        }
+    }
+
+    //初始化
+    public void init(HttpServletRequest req, HttpServletResponse resp) throws IOException {
+        ReportDefinition reportDef = reportRender.parseReport("classpath:template/template.ureport.xml");
+        writeObjectToJson(resp, ActionResult.success(new ReportDefinitionWrapper(reportDef)));
+    }
+
+    //列表
+    public void getList(HttpServletRequest req, HttpServletResponse resp) throws IOException {
+        String currentPage = req.getParameter("currentPage");
+        String pageSize = req.getParameter("pageSize");
+        String enabledMark = req.getParameter("enabledMark");
+
+        PaginationReport paginationReport = new PaginationReport();
+        paginationReport.setKeyword(req.getParameter("keyword"));
+        if (ObjectUtil.isNotEmpty(currentPage)) {
+            paginationReport.setCurrentPage(Long.parseLong(currentPage));
+        }
+        paginationReport.setCategory(req.getParameter("category"));
+        if (ObjectUtil.isNotEmpty(pageSize)) {
+            paginationReport.setPageSize(Long.parseLong(pageSize));
+        }
+        if (ObjectUtil.isNotEmpty(enabledMark)) {
+            paginationReport.setEnabledMark(Integer.parseInt(enabledMark));
+        }
+
+        String appCode = RequestContext.getAppCode();
+        if (!MAIN_SYSTEM.equals(appCode)){
+            SystemEntity infoByEnCode = systemService.getInfoByEnCode(appCode);
+            paginationReport.setSystemId(infoByEnCode!=null?infoByEnCode.getId():appCode);
+        }
+
+        List<ReportEntity> data = reportService.GetList(paginationReport);
+        List<ReportListVO> list = JsonUtil.getJsonToList(data, ReportListVO.class);
+        for (ReportListVO vo : list) {
+            if (vo.getCreatorUser() != null && !vo.getCreatorUser().equals("")) {
+                UserEntity entity = userService.getInfo(vo.getCreatorUser());
+                if (entity != null) {
+                    vo.setCreatorUser(entity.getRealName() + "/" + entity.getAccount());
+                } else {
+                    vo.setCreatorUser("");
+                }
+            }
+            UserEntity entity1 = null;
+            if (vo.getLastModifyUser() != null && !vo.getLastModifyUser().equals("")) {
+                entity1 = userService.getInfo(vo.getLastModifyUser());
+                if (entity1 != null) {
+                    vo.setLastModifyUser(entity1.getRealName() + "/" + entity1.getAccount());
+                } else {
+                    vo.setLastModifyUser("");
+                }
+            }
+        }
+        PaginationVO pagination = JsonUtil.getJsonToBean(paginationReport, PaginationVO.class);
+        writeObjectToJson(resp, ActionResult.page(list, pagination));
+    }
+
+    //下拉
+    public void Selector(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
+        String appCode = RequestContext.getAppCode();
+        SystemEntity infoByEnCode = systemService.getInfoByEnCode(appCode);
+        String systemId = infoByEnCode!=null?infoByEnCode.getId():"";
+        List<ReportEntity> data = reportService.GetList().stream().filter(t -> Objects.equals(t.getEnabledMark(), 1) && Objects.equals(t.getSystemId(),systemId)).collect(Collectors.toList());
+        List<ReportSelectorVO> list = JsonUtil.getJsonToList(data, ReportSelectorVO.class);
+        ListVO vo = new ListVO();
+        vo.setList(list);
+        writeObjectToJson(resp, ActionResult.success(vo));
+    }
+
+    //预览报表
+    public void previewData(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
+        String id = req.getParameter("id");
+        String page = req.getParameter("page");
+        String token = req.getHeader("Authorization");
+        String isSwitch = req.getParameter("isSwitch");
+        if ("preview".equals(id)) {
+            try {
+                //未保存文件在编辑器预览
+                ReportDefinition reportDefinition = (ReportDefinition) TempObjectCache.getObject(token);
+                Map<String, Object> parameters = buildParameters(req);
+                ReportBuilder reportBuilder = new ReportBuilder();
+                Connection connection = DynamicDataSourceUtil.getCurrentConnection();
+                Report report;
+                try {
+                    if ("true".equals(isSwitch) && TempObjectCache.getObject(token + "_report") != null) {
+                        report = (Report) TempObjectCache.getObject(token + "_report");
+                    } else {
+                        report = reportBuilder.buildReports(reportDefinition, parameters, connection);
+                    }
+                } finally {
+                    JdbcUtils.closeConnection(connection);
+                }
+                UreportPreviewUtil previewUtil = new UreportPreviewUtil();
+                HtmlReport htmlReport = null;
+                //分页操作
+                if ("".equals(page) || null == page || "0".equals(page)) {
+                    htmlReport = previewUtil.loadReport(report, false, 0);
+                } else {
+                    htmlReport = previewUtil.loadReport(report, true, Integer.valueOf(page));
+                    TempObjectCache.putObject(token + "_report", report);
+                }
+                htmlReport.setStyle(reportDefinition.getStyle());
+                htmlReport.setSearchFormData(reportDefinition.buildSearchFormData(report.getContext().getDatasetMap(), parameters));
+                writeObjectToJson(resp, ActionResult.success(htmlReport));
+            } catch (QueryTimeoutException qt) {
+                log.error(qt.getMessage());
+                writeObjectToJson(resp, ActionResult.fail("查询数据库超时, 请减少查询的数据量"));
+            } catch (Exception e) {
+//                e.printStackTrace();
+                log.error(e.getMessage(), e);
+                writeObjectToJson(resp, ActionResult.fail("缓存已超时"));
+            }
+        } else {
+            //通过id预览
+            ReportEntity entity = reportService.GetInfo(id);
+            if (Objects.equals(entity.getEnabledMark(), 0)) {
+                writeObjectToJson(resp, ActionResult.fail("报表已被禁用"));
+            }
+            Map<String, Object> parameters = buildParameters(req);
+            UreportPreviewUtil previewUtil = new UreportPreviewUtil();
+            Connection connection = null;
+            try {
+                connection = DynamicDataSourceUtil.getCurrentConnection();
+            } catch (SQLException throwables) {
+                throwables.printStackTrace();
+            }
+            ReportPreviewVO vo;
+            if ("".equals(page) || null == page || "0".equals(page)) {
+                vo = previewUtil.preview(entity, false, 1, parameters, connection, false);
+            } else {
+                vo = previewUtil.preview(entity, true, Integer.valueOf(page), parameters, connection, "true".equals(isSwitch));
+            }
+            vo.setEnabledMark(entity.getEnabledMark());
+            try {
+                connection.close();
+            } catch (SQLException throwables) {
+                log.error("点击预览报错:" + throwables.getMessage());
+            }
+            writeObjectToJson(resp, ActionResult.success(vo));
+        }
+    }
+
+    //通过id打开到报表编辑器
+    public void getInfo(HttpServletRequest req, HttpServletResponse resp, String id) throws ServletException, IOException {
+        ReportEntity entity = reportService.GetInfo(id);
+        ReportDefinition reportDefinition = null;
+        if (entity == null) {
+            writeObjectToJson(resp, ActionResult.fail("数据不存在"));
+        }
+        byte[] content = entity.getContent().getBytes(StandardCharsets.UTF_8);
+        ByteArrayInputStream inputStream = new ByteArrayInputStream(content);
+        reportDefinition = UreportUtil.parseReport(inputStream, entity.getFullName(), true);
+        ReportDefinitionWrapper wrapper = new ReportDefinitionWrapper(reportDefinition);
+        ReportInfoModel model = JsonUtil.getJsonToBean(entity, ReportInfoModel.class);
+        writeObjectToJson(resp, ActionResult.successTOBase(wrapper, model));
+    }
+
+    //保存报表
+    public void savaData(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
+        String payload = RequestUtil.getPayload(req);
+        SystemEntity code = systemService.getInfoByEnCode(RequestContext.getAppCode());
+        String token = req.getHeader("Authorization");
+        Map<String, Object> map = JsonUtil.stringToMap(payload);
+        if (map == null) {
+            writeObjectToJson(resp, ActionResult.fail("不能添加空数据"));
+        } else {
+            ReportCrForm reportCrForm = JsonUtil.getJsonToBean(map, ReportCrForm.class);
+            reportCrForm.setContent(UreportUtil.decodeContent(reportCrForm.getContent()));
+            ReportEntity entity = JsonUtil.getJsonToBean(reportCrForm, ReportEntity.class);
+            if (reportService.IsExistByFullName(entity.getFullName(), entity.getId(),null==code?null:code.getId())) {
+                writeObjectToJson(resp, ActionResult.fail("名称不能重复"));
+            }else if (reportService.IsExistEncode(entity.getEnCode())){
+                writeObjectToJson(resp, ActionResult.fail("编码不能重复"));
+            }else {
+                //检查表格内容是否合规
+                byte[] content = entity.getContent().getBytes(StandardCharsets.UTF_8);
+                ByteArrayInputStream inputStream = new ByteArrayInputStream(content);
+                UreportUtil.parseReport(inputStream, entity.getFullName());
+
+                String userId = UserProvider.getLoginUserId();
+                entity.setCreatorUser(userId);
+                String appCode = RequestContext.getAppCode();
+                SystemEntity systemEntity = systemService.getInfoByEnCode(appCode);
+                entity.setSystemId(systemEntity!=null?systemEntity.getId():"");
+                reportService.Create(entity);
+                Object id = entity.getId();
+                writeObjectToJson(resp, ActionResult.success(id));
+            }
+        }
+    }
+
+    //修改
+    public void updateData(HttpServletRequest req, HttpServletResponse resp, String id) throws ServletException, IOException {
+        String token = req.getHeader("Authorization");
+        SystemEntity code = systemService.getInfoByEnCode(RequestContext.getAppCode());
+        String payload = RequestUtil.getPayload(req);
+        Map<String, Object> map = JsonUtil.stringToMap(payload);
+        if (id == null || id.isEmpty()) {
+            writeObjectToJson(resp, ActionResult.fail("数据不存在,修改失败"));
+        }else {
+            ReportUpForm reportUpForm = JsonUtil.getJsonToBean(map, ReportUpForm.class);
+            reportUpForm.setContent(UreportUtil.decodeContent(reportUpForm.getContent()));
+            ReportEntity entity = JsonUtil.getJsonToBean(reportUpForm, ReportEntity.class);
+            //entity.setContent(UreportUtil.decodeContent(entity.getContent()));
+            if (reportService.IsExistByFullName(entity.getFullName(), id,null==code?null:code.getId())) {
+                writeObjectToJson(resp, ActionResult.fail("名称不能重复"));
+            }else if (reportService.IsExistEncode(entity.getEnCode(),id)){
+                writeObjectToJson(resp, ActionResult.fail("编码不能重复"));
+            }  else {
+                //检查表格内容是否合规
+                byte[] content = entity.getContent().getBytes(StandardCharsets.UTF_8);
+                ByteArrayInputStream inputStream = new ByteArrayInputStream(content);
+                UreportUtil.parseReport(inputStream, entity.getFullName());
+
+                String userId = UserProvider.getLoginUserId();
+                entity.setLastModifyUser(userId);
+                boolean flags = reportService.Update(id, entity);
+                if (flags) {
+                    writeObjectToJson(resp, ActionResult.success("修改成功"));
+                } else {
+                    writeObjectToJson(resp, ActionResult.fail("数据不存在,修改失败"));
+                }
+            }
+        }
+    }
+
+    //复制报表
+    public void copyReport(HttpServletRequest req, HttpServletResponse resp, String id) throws ServletException, IOException {
+        String token = req.getHeader("Authorization");
+        if (id == null || id.isEmpty()) {
+            writeObjectToJson(resp, ActionResult.fail("数据不存在,复制失败"));
+        } else {
+            ReportEntity entity = reportService.GetInfo(id);
+            String userId = UserProvider.getLoginUserId();
+            entity.setCreatorUser(userId);
+            boolean flags = reportService.Copy(entity);
+            if (flags) {
+                writeObjectToJson(resp, ActionResult.success("复制成功"));
+            } else {
+                writeObjectToJson(resp, ActionResult.fail("数据不存在,复制失败"));
+            }
+        }
+    }
+
+    //删除
+    public void deleteData(HttpServletRequest req, HttpServletResponse resp, String id) throws ServletException, IOException {
+        if (id == null || id.isEmpty()) {
+            writeObjectToJson(resp, ActionResult.fail("数据不存在,修改失败"));
+        } else {
+            ReportEntity entity = reportService.GetInfo(id);
+            boolean flags = reportService.Delete(entity);
+            if (flags) {
+                writeObjectToJson(resp, ActionResult.success("删除成功"));
+            } else {
+                writeObjectToJson(resp, ActionResult.fail("数据不存在,修改失败"));
+            }
+        }
+    }
+
+    /*//通过id导出报表
+    public void exportData(HttpServletRequest req, HttpServletResponse resp, String id, String type) throws ServletException, IOException {
+        ReportEntity entity = reportService.GetInfo(id);
+        if (entity == null) {
+            writeObjectToJson(resp, ActionResult.fail("导出数据不能为空"));
+        }
+        String fileName = entity.getFullName();
+        resp.setCharacterEncoding("UTF-8");
+        resp.setHeader("content-Type", "application/x-download");
+        Connection connection = null;
+        try {
+            if (!dataSourceConfig.isMultiTenancy()) {
+                connection = dataSource.getConnection();
+            } else {
+                connection = JdbcUtil.getConn(dataSourceConfig.getUserName(), dataSourceConfig.getPassword(), dataSourceConfig.getUrl().replace("{dbName}", TenantHolder.getDatasourceName()));
+            }
+        } catch (Exception throwables) {
+            throwables.printStackTrace();
+            log.error("数据源错误:" + throwables.getMessage());
+        }
+        if (type.toLowerCase().equals("pdf")) {
+            resp.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(fileName + ".pdf", "UTF-8"));
+            OutputStream outputStream = resp.getOutputStream();
+            UreportPdfUtil pdfUtil = new UreportPdfUtil();
+            pdfUtil.buildPdfToConnection(entity, outputStream, connection);
+            outputStream.flush();
+            outputStream.close();
+        } else if (type.toLowerCase().equals("word")) {
+            resp.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(fileName + ".docx", "UTF-8"));
+            UreportWordUtil wordUtil = new UreportWordUtil();
+            XWPFDocument xwpfDocument = wordUtil.buildWord(entity, connection);
+            xwpfDocument.write(resp.getOutputStream());
+            xwpfDocument.close();
+        } else if (type.toLowerCase().equals("excel")) {
+            resp.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(fileName + ".xlsx", "UTF-8"));
+            UreportExcelUtil excelUtil = new UreportExcelUtil();
+            Workbook workbook = excelUtil.buildExcel(entity, false, false, connection);
+            workbook.write(resp.getOutputStream());
+            workbook.close();
+        }
+    }*/
+
+
+    @Override
+    public String url() {
+        return "/Data";
+    }
+
+    protected void writeObjectToJson(HttpServletResponse resp, Object obj) throws IOException {
+        resp.setContentType("application/json");
+        resp.setCharacterEncoding("UTF-8");
+        ObjectMapper mapper = new ObjectMapper();
+//        mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
+        mapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);
+        mapper.setDateFormat(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"));
+        OutputStream out = resp.getOutputStream();
+        try {
+            mapper.writeValue(out, obj);
+        } finally {
+            out.flush();
+            out.close();
+        }
+    }
+
+}

+ 35 - 0
ureport2-console/src/main/java/com/bstek/ureport/console/ureport/entity/CodeNumEntity.java

@@ -0,0 +1,35 @@
+package com.bstek.ureport.console.ureport.entity;
+
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableName;
+import jnpf.base.entity.SuperBaseEntity;
+import lombok.Data;
+
+/**
+ * @author JNPF开发平台组
+ * @version v6.0.0
+ * @copyright 引迈信息技术有限公司
+ * @date 2025/2/28 11:08:05
+ */
+@Data
+@TableName("base_code_num")
+public class CodeNumEntity extends SuperBaseEntity.SuperCUDBaseEntity<String> {
+    /**
+     * 编码类型:ZZ-组织,GW-岗位,YHZ-用户组,YHJS-用户角色,
+     * ZZJS-组织角色,GWJS-岗位角色,SF-身份编码,LC-流程,MH-门户,BDHC-表单回传
+     */
+    @TableField("F_TYPE")
+    private String type;
+
+    /**
+     * 日期(用户重置序号)
+     */
+    @TableField("F_DATE_VALUE")
+    private Integer dateValue;
+
+    /**
+     * 编号(1开始)
+     */
+    @TableField("F_NUM")
+    private Integer num;
+}

+ 109 - 0
ureport2-console/src/main/java/com/bstek/ureport/console/ureport/entity/ReportEntity.java

@@ -0,0 +1,109 @@
+package com.bstek.ureport.console.ureport.entity;
+
+import com.baomidou.mybatisplus.annotation.FieldFill;
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import jnpf.base.entity.SuperBaseEntity;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+import java.util.Date;
+
+@Data
+@EqualsAndHashCode(callSuper = true)
+@TableName("data_report")
+public class ReportEntity extends SuperBaseEntity.SuperTBaseEntity<String> {
+
+
+    /**
+     * 报表名称
+     */
+    @TableField("F_FullName")
+    private String fullName;
+
+    /**
+     * 报表内容
+     */
+    @TableField("F_Content")
+    private String content;
+
+    /**
+     * 字典分类
+     */
+    @TableField("F_CategoryId")
+    private String categoryId;
+
+    /**
+     * 编码
+     */
+    @TableField("F_EnCode")
+    private String enCode;
+
+    /**
+     * 系统id
+     */
+    @TableField("f_system_id")
+    private String systemId;
+
+    /**
+     * 状态(0-默认,禁用,1-启用)
+     */
+    @TableField("F_EnabledMark")
+    private Integer enabledMark;
+
+    /**
+     * 排序码
+     */
+    @TableField("F_SortCode")
+    private Long sortCode;
+
+    /**
+     * 描述
+     */
+    @TableField("F_Description")
+    private String description;
+
+    /**
+     * 创建时间
+     */
+    @TableField("F_CreatorTime")
+    private Date creatorTime;
+
+    /**
+     * 创建用户
+     */
+    @TableField("F_CreatorUserId")
+    private String creatorUser;
+
+    /**
+     * 编辑时间
+     */
+    @TableField(value = "F_LastModifyTime",fill = FieldFill.INSERT)
+    private Date lastModifyTime;
+
+    /**
+     * 编辑用户
+     */
+    @TableField(value = "F_LastModifyUserId",fill = FieldFill.INSERT)
+    private String lastModifyUser;
+
+    /**
+     * 删除标志
+     */
+    @TableField("F_DeleteMark")
+    private Integer deleteMark;
+
+    /**
+     * 删除时间
+     */
+    @TableField("F_DeleteTime")
+    private String deleteTime;
+
+    /**
+     * 删除用户
+     */
+    @TableField("F_DeleteUserId")
+    private String deleteUserId;
+
+}

+ 36 - 0
ureport2-console/src/main/java/com/bstek/ureport/console/ureport/entity/SystemEntity.java

@@ -0,0 +1,36 @@
+package com.bstek.ureport.console.ureport.entity;
+
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import lombok.Data;
+
+/**
+ * 系统
+ *
+ * @author JNPF开发平台组
+ * @version V3.1.0
+ * @copyright 引迈信息技术有限公司
+ * @date 2019年9月27日 上午9:18
+ */
+@Data
+@TableName("base_system")
+public class SystemEntity {
+    /**
+     * 用户主键
+     */
+    @TableId("F_ID")
+    private String id;
+    /**
+     * 系统名称
+     */
+    @TableField("F_FULL_NAME")
+    private String fullName;
+
+    /**
+     * 系统编号
+     */
+    @TableField("F_EN_CODE")
+    private String enCode;
+
+}

+ 34 - 0
ureport2-console/src/main/java/com/bstek/ureport/console/ureport/entity/UserEntity.java

@@ -0,0 +1,34 @@
+package com.bstek.ureport.console.ureport.entity;
+
+import com.baomidou.mybatisplus.annotation.*;
+import lombok.Data;
+
+
+/**
+ * 用户信息
+ *
+ * @author JNPF开发平台组
+ * @version V3.0.0
+ * @copyright 引迈信息技术有限公司
+ * @date 2019年9月26日 上午9:18
+ */
+@Data
+@TableName("base_user")
+public class UserEntity {
+    /**
+     * 用户主键
+     */
+    @TableId("F_ID")
+    private String id;
+    /**
+     * 账户
+     */
+    @TableField("F_ACCOUNT")
+    private String account;
+
+    /**
+     * 姓名
+     */
+    @TableField("F_REAL_NAME")
+    private String realName;
+}

+ 17 - 0
ureport2-console/src/main/java/com/bstek/ureport/console/ureport/mapper/CodeNumMapper.java

@@ -0,0 +1,17 @@
+package com.bstek.ureport.console.ureport.mapper;
+
+import com.bstek.ureport.console.ureport.entity.CodeNumEntity;
+import jnpf.base.mapper.SuperMapper;
+
+
+/**
+ * 编码序号
+ *
+ * @author JNPF开发平台组
+ * @version v6.0.0
+ * @copyright 引迈信息技术有限公司
+ * @date 2025/2/28 11:13:44
+ */
+public interface CodeNumMapper extends SuperMapper<CodeNumEntity> {
+
+}

+ 8 - 0
ureport2-console/src/main/java/com/bstek/ureport/console/ureport/mapper/ReportMapper.java

@@ -0,0 +1,8 @@
+package com.bstek.ureport.console.ureport.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.bstek.ureport.console.ureport.entity.ReportEntity;
+
+public interface ReportMapper extends BaseMapper<ReportEntity> {
+
+}

+ 8 - 0
ureport2-console/src/main/java/com/bstek/ureport/console/ureport/mapper/SystemMapper.java

@@ -0,0 +1,8 @@
+package com.bstek.ureport.console.ureport.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.bstek.ureport.console.ureport.entity.SystemEntity;
+
+public interface SystemMapper extends BaseMapper<SystemEntity> {
+
+}

+ 8 - 0
ureport2-console/src/main/java/com/bstek/ureport/console/ureport/mapper/UserMapper.java

@@ -0,0 +1,8 @@
+package com.bstek.ureport.console.ureport.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.bstek.ureport.console.ureport.entity.UserEntity;
+
+public interface UserMapper extends BaseMapper<UserEntity> {
+
+}

+ 11 - 0
ureport2-console/src/main/java/com/bstek/ureport/console/ureport/model/PaginationReport.java

@@ -0,0 +1,11 @@
+package com.bstek.ureport.console.ureport.model;
+
+import com.bstek.ureport.console.util.Pagination;
+import lombok.Data;
+
+@Data
+public class PaginationReport extends Pagination {
+    private String category;
+    private Integer enabledMark;
+    private String systemId;
+}

+ 16 - 0
ureport2-console/src/main/java/com/bstek/ureport/console/ureport/model/ReportCrForm.java

@@ -0,0 +1,16 @@
+package com.bstek.ureport.console.ureport.model;
+
+import lombok.Data;
+
+@Data
+public class ReportCrForm {
+    private String fullName;
+    private String content;
+    private String categoryId;
+    private String enCode;
+    private Integer enabledMark;
+    private Long sortCode;
+    private String description;
+    private String creatorUser;
+
+}

+ 15 - 0
ureport2-console/src/main/java/com/bstek/ureport/console/ureport/model/ReportInfoModel.java

@@ -0,0 +1,15 @@
+package com.bstek.ureport.console.ureport.model;
+
+import lombok.Data;
+
+@Data
+public class ReportInfoModel {
+    private String id;
+    private String fullName;
+    private String categoryId;
+    private String enCode;
+    private Integer enabledMark;
+    private Long sortCode;
+    private String description;
+    private String creatorUser;
+}

+ 11 - 0
ureport2-console/src/main/java/com/bstek/ureport/console/ureport/model/ReportInfoVO.java

@@ -0,0 +1,11 @@
+package com.bstek.ureport.console.ureport.model;
+
+import lombok.Data;
+
+@Data
+public class ReportInfoVO {
+    //报表内容
+    private Object content;
+    //报表信息
+    private ReportInfoModel baseInfo;
+}

+ 22 - 0
ureport2-console/src/main/java/com/bstek/ureport/console/ureport/model/ReportInitVo.java

@@ -0,0 +1,22 @@
+package com.bstek.ureport.console.ureport.model;
+
+import com.bstek.ureport.definition.*;
+import com.bstek.ureport.definition.datasource.DatasourceDefinition;
+import com.bstek.ureport.definition.searchform.SearchForm;
+import lombok.Data;
+
+import java.util.List;
+
+@Data
+public class ReportInitVo {
+    private Paper paper;
+    private CellDefinition rootCell;
+    private HeaderFooterDefinition header;
+    private HeaderFooterDefinition footer;
+    private SearchForm searchForm;
+    private List<CellDefinition> cellsMap;
+    private List<RowDefinition> rows;
+    private List<ColumnDefinition> columns;
+    private List<DatasourceDefinition> datasources;
+    private String searchFormXml;
+}

+ 17 - 0
ureport2-console/src/main/java/com/bstek/ureport/console/ureport/model/ReportListVO.java

@@ -0,0 +1,17 @@
+package com.bstek.ureport.console.ureport.model;
+
+import lombok.Data;
+
+@Data
+public class ReportListVO {
+    private String id;
+    private String fullName;
+    private String enCode;
+    private String creatorUser;
+    private Long creatorTime;
+    private String categoryId;
+    private String lastModifyUser;
+    private Long lastModifyTime;
+    private Integer enabledMark;
+    private Long sortCode;
+}

+ 21 - 0
ureport2-console/src/main/java/com/bstek/ureport/console/ureport/model/ReportPreviewVO.java

@@ -0,0 +1,21 @@
+package com.bstek.ureport.console.ureport.model;
+
+import com.bstek.ureport.chart.ChartData;
+import com.bstek.ureport.export.html.SearchFormData;
+import lombok.Data;
+
+import java.util.Collection;
+
+@Data
+public class ReportPreviewVO {
+    private String content;
+    private String style;
+    private int totalPage;
+    private int pageIndex;
+    private int column;
+    private String reportAlign;
+    private Collection<ChartData> chartDatas;
+    private int htmlIntervalRefreshValue;
+    private SearchFormData searchFormData;
+    private int enabledMark;
+}

+ 10 - 0
ureport2-console/src/main/java/com/bstek/ureport/console/ureport/model/ReportSelectorVO.java

@@ -0,0 +1,10 @@
+package com.bstek.ureport.console.ureport.model;
+
+import lombok.Data;
+
+@Data
+public class ReportSelectorVO {
+    private String id;
+    private String fullName;
+    private String categoryId;
+}

+ 8 - 0
ureport2-console/src/main/java/com/bstek/ureport/console/ureport/model/ReportUpForm.java

@@ -0,0 +1,8 @@
+package com.bstek.ureport.console.ureport.model;
+
+import lombok.Data;
+
+@Data
+public class ReportUpForm extends ReportCrForm {
+    private String lastModifyUser;
+}

+ 54 - 0
ureport2-console/src/main/java/com/bstek/ureport/console/ureport/service/CodeNumService.java

@@ -0,0 +1,54 @@
+package com.bstek.ureport.console.ureport.service;
+
+import com.bstek.ureport.console.ureport.entity.CodeNumEntity;
+import jnpf.base.service.SuperService;
+
+
+import java.util.List;
+import java.util.function.Predicate;
+import java.util.function.Supplier;
+
+/**
+ * 编码序号
+ *
+ * @author JNPF开发平台组
+ * @version v6.0.0
+ * @copyright 引迈信息技术有限公司
+ * @date 2025/2/28 11:14:52
+ */
+public interface CodeNumService extends SuperService<CodeNumEntity> {
+
+    /**
+     * 根据类型获取数据
+     *
+     * @param type
+     * @return
+     */
+    Integer getNumByType(String type, Integer times);
+
+    /**
+     * 获取多次编码
+     *
+     * @param type
+     * @param num
+     * @return
+     */
+    List<String> getCode(String type, Integer num);
+
+    /**
+     * 获取一次编码
+     *
+     * @param type
+     * @return
+     */
+    String getCodeOnce(String type);
+
+    /**
+     * 函数式获取编码
+     *
+     * @param getCode   获取编码
+     * @param existCode 判断编码是否存在
+     * @return
+     */
+    String getCodeFunction(Supplier<String> getCode, Predicate<String> existCode);
+}

+ 71 - 0
ureport2-console/src/main/java/com/bstek/ureport/console/ureport/service/ReportService.java

@@ -0,0 +1,71 @@
+package com.bstek.ureport.console.ureport.service;
+
+import com.baomidou.mybatisplus.extension.service.IService;
+import com.bstek.ureport.console.ureport.entity.ReportEntity;
+import com.bstek.ureport.console.ureport.model.PaginationReport;
+
+import java.util.List;
+import java.util.Map;
+
+public interface ReportService extends IService<ReportEntity> {
+
+    /**
+     * 报表列表
+     * @return
+     */
+    List<ReportEntity> GetList(PaginationReport paginationReport);
+
+    /**
+     * 报表列表(无分页)
+     * @return
+     */
+    List<ReportEntity> GetList();
+
+    /**
+     * 分类
+     * @param categoryId
+     * @return
+     */
+    List<ReportEntity> Selector(String categoryId);
+
+    /**
+     * 预览/打开 报表
+     * @param id
+     * @return
+     */
+    ReportEntity GetInfo(String id);
+
+    /**
+     * 验证名称重复
+     *
+     * @param id   主键值
+     * @param fullName 文件夹称
+     */
+    boolean IsExistByFullName(String fullName, String id,String systemId);
+
+    /**
+     *  删除报表
+     */
+    boolean Delete(ReportEntity entity);
+
+    /**
+     *  删除报表
+     */
+    boolean Copy(ReportEntity entity);
+
+    /**
+     *  保存报表
+     */
+    boolean Create(ReportEntity entity);
+
+    /**
+     *  修改报表
+     * @param entity
+     * @return
+     */
+    boolean Update(String id, ReportEntity entity);
+
+    boolean IsExistEncode(String enCode);
+
+    boolean IsExistEncode(String enCode,String id);
+}

+ 24 - 0
ureport2-console/src/main/java/com/bstek/ureport/console/ureport/service/SystemService.java

@@ -0,0 +1,24 @@
+package com.bstek.ureport.console.ureport.service;
+
+import com.baomidou.mybatisplus.extension.service.IService;
+import com.bstek.ureport.console.ureport.entity.SystemEntity;
+
+/**
+ * 用户信息
+ *
+ * @author JNPF开发平台组
+ * @version V3.0.0
+ * @copyright 引迈信息技术有限公司
+ * @date 2019年9月26日 上午9:18
+ */
+public interface SystemService extends IService<SystemEntity> {
+
+    /**
+     * 通过编码获取系统信息
+     *
+     * @param enCode
+     * @return
+     */
+    SystemEntity getInfoByEnCode(String enCode);
+
+}

+ 25 - 0
ureport2-console/src/main/java/com/bstek/ureport/console/ureport/service/UserService.java

@@ -0,0 +1,25 @@
+package com.bstek.ureport.console.ureport.service;
+
+import com.baomidou.mybatisplus.extension.service.IService;
+import com.bstek.ureport.console.ureport.entity.UserEntity;
+
+import java.util.List;
+
+/**
+ * 用户信息
+ *
+ * @author JNPF开发平台组
+ * @version V3.0.0
+ * @copyright 引迈信息技术有限公司
+ * @date 2019年9月26日 上午9:18
+ */
+public interface UserService extends IService<UserEntity> {
+    /**
+     * 信息
+     *
+     * @param id 主键值
+     * @return
+     */
+    UserEntity getInfo(String id);
+
+}

+ 89 - 0
ureport2-console/src/main/java/com/bstek/ureport/console/ureport/service/impl/CodeNumServiceImpl.java

@@ -0,0 +1,89 @@
+package com.bstek.ureport.console.ureport.service.impl;
+
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.bstek.ureport.console.ureport.entity.CodeNumEntity;
+import com.bstek.ureport.console.ureport.mapper.CodeNumMapper;
+import com.bstek.ureport.console.ureport.service.CodeNumService;
+import jnpf.base.service.SuperServiceImpl;
+
+import jnpf.util.DateUtil;
+import jnpf.util.RandomUtil;
+import lombok.Synchronized;
+import org.springframework.stereotype.Service;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Objects;
+import java.util.function.Predicate;
+import java.util.function.Supplier;
+import java.util.stream.Stream;
+
+/**
+ * 编码获取服务
+ *
+ * @author JNPF开发平台组
+ * @version v6.0.0
+ * @copyright 引迈信息技术有限公司
+ * @date 2025/2/28 11:16:06
+ */
+@Service
+public class CodeNumServiceImpl extends SuperServiceImpl<CodeNumMapper, CodeNumEntity> implements CodeNumService {
+
+    @Synchronized
+    @Override
+    public Integer getNumByType(String type, Integer times) {
+        CodeNumEntity codeNumEntity;
+        Integer num = 1;
+        Integer dateValue = Integer.parseInt(DateUtil.nowDateTime().substring(0, 8));
+
+        QueryWrapper<CodeNumEntity> wrapper = new QueryWrapper<>();
+        wrapper.lambda().eq(CodeNumEntity::getType, type);
+        List<CodeNumEntity> list = this.list(wrapper);
+        if (!list.isEmpty()) {
+            codeNumEntity = list.get(0);
+            if (Objects.equals(dateValue, codeNumEntity.getDateValue())) {
+                num = codeNumEntity.getNum();
+            }
+        } else {
+            codeNumEntity = new CodeNumEntity();
+            codeNumEntity.setId(RandomUtil.uuId());
+
+
+        }
+        codeNumEntity.setType(type);
+        codeNumEntity.setDateValue(dateValue);
+        codeNumEntity.setNum(num + times);
+        this.saveOrUpdate(codeNumEntity);
+        return num;
+    }
+
+    @Override
+    public List<String> getCode(String type, Integer num) {
+        Integer value = this.getNumByType(type, num);
+        List<String> list = new ArrayList<>();
+        for (int n = 0; n < num; n++) {
+            String numStr = String.format("%06d", value + n);
+            String sb = type +
+                    DateUtil.nowDateTime().substring(0, 8) +
+                    numStr;
+            list.add(sb);
+        }
+        return list;
+    }
+
+
+    @Override
+    @Synchronized
+    public String getCodeOnce(String type) {
+        return this.getCode(type, 1).get(0);
+    }
+
+    @Override
+    @Synchronized
+    public String getCodeFunction(Supplier<String> getCode, Predicate<String> existCode) {
+        return Stream.generate(getCode)
+                .filter(code -> !existCode.test(code))
+                .findFirst()
+                .orElseThrow(() -> new RuntimeException("无法获取唯一编码"));
+    }
+}

+ 132 - 0
ureport2-console/src/main/java/com/bstek/ureport/console/ureport/service/impl/ReportServiceImpl.java

@@ -0,0 +1,132 @@
+package com.bstek.ureport.console.ureport.service.impl;
+
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.bstek.ureport.console.ureport.entity.ReportEntity;
+import com.bstek.ureport.console.ureport.mapper.ReportMapper;
+import com.bstek.ureport.console.ureport.model.PaginationReport;
+import com.bstek.ureport.console.ureport.service.ReportService;
+import com.bstek.ureport.utils.DateUtil;
+import com.bstek.ureport.console.util.RandomUtil;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.logging.log4j.util.Strings;
+import org.springframework.stereotype.Service;
+
+import java.util.List;
+import java.util.UUID;
+
+@Service
+public class ReportServiceImpl extends ServiceImpl<ReportMapper, ReportEntity> implements ReportService {
+
+    @Override
+    public List<ReportEntity> GetList(PaginationReport paginationReport) {
+        QueryWrapper<ReportEntity> queryWrapper = new QueryWrapper<>();
+        //支持encode和fullName
+        if (Strings.isNotEmpty(paginationReport.getKeyword())){
+            queryWrapper.lambda().and(t->t.like(ReportEntity::getFullName,paginationReport.getKeyword())
+                    .or().like(ReportEntity::getEnCode,paginationReport.getKeyword())
+            );
+        }
+        if (Strings.isNotEmpty(paginationReport.getCategory())){
+            queryWrapper.lambda().eq(ReportEntity::getCategoryId, paginationReport.getCategory());
+        }
+        if (paginationReport.getEnabledMark()!=null){
+            queryWrapper.lambda().eq(ReportEntity::getEnabledMark, paginationReport.getEnabledMark());
+        }
+        if (Strings.isNotEmpty(paginationReport.getSystemId())){
+            queryWrapper.lambda().eq(ReportEntity::getSystemId, paginationReport.getSystemId());
+        }
+        queryWrapper.lambda().orderByAsc(ReportEntity::getSortCode).orderByDesc(ReportEntity::getCreatorTime);
+        Page<ReportEntity> page = new Page<>(paginationReport.getCurrentPage(), paginationReport.getPageSize());
+        IPage<ReportEntity> userPage = this.page(page, queryWrapper);
+        return paginationReport.setData(userPage.getRecords(), userPage.getTotal());
+    }
+
+    @Override
+    public List<ReportEntity> GetList() {
+        QueryWrapper<ReportEntity> queryWrapper = new QueryWrapper<>();
+        queryWrapper.lambda().orderByDesc(ReportEntity::getCreatorTime);
+        return this.list(queryWrapper);
+    }
+
+    @Override
+    public List<ReportEntity> Selector(String categoryId) {
+        QueryWrapper<ReportEntity> queryWrapper = new QueryWrapper<>();
+        queryWrapper.lambda().eq(ReportEntity::getCategoryId, categoryId);
+        return this.list(queryWrapper);
+    }
+
+    @Override
+    public ReportEntity GetInfo(String id) {
+        QueryWrapper<ReportEntity> queryWrapper = new QueryWrapper<>();
+        queryWrapper.lambda().eq(ReportEntity::getId,id);
+        return this.getOne(queryWrapper);
+    }
+
+    @Override
+    public boolean IsExistByFullName(String fullName,String id,String systemId) {
+        QueryWrapper<ReportEntity> queryWrapper = new QueryWrapper<>();
+        queryWrapper.lambda().eq(ReportEntity::getFullName, fullName);
+        queryWrapper.lambda().eq(ReportEntity::getSystemId, systemId);
+        if (!StringUtils.isEmpty(id)) {
+            queryWrapper.lambda().ne(ReportEntity::getId, id);
+        }
+        return this.count(queryWrapper) > 0;
+    }
+
+    @Override
+    public boolean Delete(ReportEntity entity) {
+        return this.removeById(entity.getId());
+    }
+
+    @Override
+    public boolean Copy(ReportEntity entity) {
+        String copyNum = UUID.randomUUID().toString().substring(0, 5);
+        entity.setId(null);
+        entity.setLastModifyTime(null);
+        entity.setLastModifyUser(null);
+        entity.setFullName(entity.getFullName() + ".副本" + copyNum);
+        entity.setEnCode(entity.getEnCode() + copyNum);
+        entity.setEnabledMark(0);
+        return Create(entity);
+    }
+
+    @Override
+    public boolean Create(ReportEntity entity) {
+        if (entity.getId() == null || "".equals(entity.getId())){
+            entity.setId(RandomUtil.uuId());
+            entity.setCreatorTime(DateUtil.getNowDate());
+        }
+        return this.save(entity);
+    }
+
+    @Override
+    public boolean Update(String id, ReportEntity entity) {
+        entity.setId(id);
+        entity.setLastModifyTime(DateUtil.getNowDate());
+        return this.updateById(entity);
+    }
+
+    @Override
+    public boolean IsExistEncode(String enCode) {
+        LambdaQueryWrapper<ReportEntity> queryWrapper = new LambdaQueryWrapper<>();
+        queryWrapper.eq(ReportEntity::getEnCode, enCode);
+        List<ReportEntity> list = this.list(queryWrapper);
+        return CollectionUtils.isNotEmpty(list);
+    }
+
+    @Override
+    public boolean IsExistEncode(String enCode, String id) {
+        QueryWrapper<ReportEntity> queryWrapper = new QueryWrapper<>();
+        queryWrapper.lambda().eq(ReportEntity::getEnCode, enCode);
+        if (!StringUtils.isEmpty(id)) {
+            queryWrapper.lambda().ne(ReportEntity::getId, id);
+        }
+        return this.count(queryWrapper) > 0;
+    }
+
+}

+ 23 - 0
ureport2-console/src/main/java/com/bstek/ureport/console/ureport/service/impl/SystemServiceImpl.java

@@ -0,0 +1,23 @@
+package com.bstek.ureport.console.ureport.service.impl;
+
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.bstek.ureport.console.ureport.entity.SystemEntity;
+import com.bstek.ureport.console.ureport.mapper.SystemMapper;
+import com.bstek.ureport.console.ureport.service.SystemService;
+import jnpf.util.StringUtil;
+import org.springframework.stereotype.Service;
+
+@Service
+public class SystemServiceImpl extends ServiceImpl<SystemMapper, SystemEntity> implements SystemService {
+
+
+    public SystemEntity getInfoByEnCode(String enCode) {
+        if (StringUtil.isEmpty(enCode)) {
+            return null;
+        }
+        QueryWrapper<SystemEntity> queryWrapper = new QueryWrapper<>();
+        queryWrapper.lambda().eq(SystemEntity::getEnCode, enCode);
+        return this.getOne(queryWrapper);
+    }
+}

+ 21 - 0
ureport2-console/src/main/java/com/bstek/ureport/console/ureport/service/impl/UserServiceImpl.java

@@ -0,0 +1,21 @@
+package com.bstek.ureport.console.ureport.service.impl;
+
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.bstek.ureport.console.ureport.entity.UserEntity;
+import com.bstek.ureport.console.ureport.mapper.UserMapper;
+import com.bstek.ureport.console.ureport.service.UserService;
+import org.springframework.stereotype.Service;
+
+@Service
+public class UserServiceImpl extends ServiceImpl<UserMapper, UserEntity> implements UserService {
+    @Override
+    public UserEntity getInfo(String id) {
+        if(id == null){
+            return null;
+        }
+        QueryWrapper<UserEntity> queryWrapper = new QueryWrapper<>();
+        queryWrapper.lambda().eq(UserEntity::getId, id);
+        return this.getOne(queryWrapper);
+    }
+}

+ 54 - 0
ureport2-console/src/main/java/com/bstek/ureport/console/ureport/util/DownUtil.java

@@ -0,0 +1,54 @@
+package com.bstek.ureport.console.ureport.util;
+
+import jnpf.util.ServletUtil;
+import lombok.extern.slf4j.Slf4j;
+
+import jakarta.servlet.http.HttpServletRequest;
+import jakarta.servlet.http.HttpServletResponse;
+import java.io.*;
+
+/**
+ * 下载工具类
+ *
+ * @author JNPF开发平台组
+ * @version V3.1.0
+ * @copyright 引迈信息技术有限公司(https://www.jnpfsoft.com)
+ * @date 2021-07-14
+ */
+@Slf4j
+public class DownUtil {
+
+    /**
+     * 下载文件
+     * @param str
+     * @param fileName
+     */
+    public static Boolean downloadFile(String str, String fileName) {
+        HttpServletResponse response = ServletUtil.getResponse();
+        HttpServletRequest request = ServletUtil.getRequest();
+        OutputStream os = null;
+        try {
+            response.reset();
+            response.setContentType("application/octet-stream; charset=utf-8");
+            response.setHeader("Content-Disposition", "attachment; filename=" + new String(fileName.getBytes(),"ISO8859-1"));
+            byte[] bytes = str.getBytes("utf-8");
+            os = response.getOutputStream();
+            // 将字节流传入到响应流里,响应到浏览器
+            os.write(bytes);
+            os.close();
+            return true;
+        } catch (Exception ex) {
+            log.error("导出失败:", ex);
+            throw new RuntimeException("导出失败");
+        }finally {
+            try {
+                if (null != os) {
+                    os.close();
+                }
+            } catch (IOException ioEx) {
+                log.error("导出失败:", ioEx);
+            }
+        }
+    }
+
+}

+ 67 - 0
ureport2-console/src/main/java/com/bstek/ureport/console/ureport/util/JwtUtil.java

@@ -0,0 +1,67 @@
+package com.bstek.ureport.console.ureport.util;
+
+import com.nimbusds.jwt.JWTClaimsSet;
+import com.nimbusds.jwt.SignedJWT;
+
+import java.util.Date;
+
+/**
+ *
+ * @author JNPF开发平台组
+ * @version V3.1.0
+ * @copyright 引迈信息技术有限公司
+ * @date 2021/3/16 10:51
+ */
+public class JwtUtil {
+
+    /**
+     * 获取jwt中的携带的Redis的token
+     * @param token
+     * @return
+     */
+    public static String getRealToken(String token) {
+        String realToken;
+        try {
+            SignedJWT sjwt = SignedJWT.parse(token.split(" ")[1]);
+            JWTClaimsSet claims = sjwt.getJWTClaimsSet();
+            realToken =  String.valueOf(claims.getClaim("token"));
+            return realToken;
+        } catch (Exception e) {
+            return realToken = null;
+        }
+    }
+
+    /**
+     * getUserInfo
+     * @param token
+     * @return
+     */
+    public static JWTClaimsSet getUserInfo(String token) {
+        String realToken;
+        try {
+            SignedJWT sjwt = SignedJWT.parse(token.split(" ")[1]);
+            JWTClaimsSet claims = sjwt.getJWTClaimsSet();
+            return claims;
+        } catch (Exception e) {
+            return null;
+        }
+    }
+
+    /**
+     * 获取jwt中的过期时间
+     * @param token
+     * @return
+     */
+    public static Date getExp(String token){
+        Date date;
+        try {
+            SignedJWT sjwt = SignedJWT.parse(token.split(" ")[1]);
+            JWTClaimsSet claims = sjwt.getJWTClaimsSet();
+            date = (Date)claims.getClaim("exp");
+            return date;
+        } catch (Exception e) {
+            return date = null;
+        }
+    }
+
+}

+ 624 - 0
ureport2-console/src/main/java/com/bstek/ureport/console/ureport/util/UreportExcelUtil.java

@@ -0,0 +1,624 @@
+package com.bstek.ureport.console.ureport.util;
+
+import com.bstek.ureport.Utils;
+import com.bstek.ureport.build.ReportBuilder;
+import com.bstek.ureport.build.paging.Page;
+import com.bstek.ureport.chart.ChartData;
+import com.bstek.ureport.console.ureport.entity.ReportEntity;
+import com.bstek.ureport.definition.Orientation;
+import com.bstek.ureport.definition.Paper;
+import com.bstek.ureport.definition.PaperType;
+import com.bstek.ureport.definition.ReportDefinition;
+import com.bstek.ureport.export.excel.high.CellStyleContext;
+import com.bstek.ureport.model.Cell;
+import com.bstek.ureport.model.Row;
+import com.bstek.ureport.model.*;
+import com.bstek.ureport.utils.ImageUtils;
+import com.bstek.ureport.utils.UnitUtils;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.io.IOUtils;
+import org.apache.poi.ss.usermodel.*;
+import org.apache.poi.ss.util.CellRangeAddress;
+import org.apache.poi.xssf.streaming.SXSSFWorkbook;
+import org.apache.poi.xssf.usermodel.XSSFCellStyle;
+import org.apache.poi.xssf.usermodel.XSSFClientAnchor;
+import org.apache.poi.xssf.usermodel.XSSFPrintSetup;
+
+import javax.imageio.ImageIO;
+import java.awt.image.BufferedImage;
+import java.io.ByteArrayInputStream;
+import java.io.FileOutputStream;
+import java.io.InputStream;
+import java.math.BigDecimal;
+import java.sql.Connection;
+import java.util.*;
+
+@Slf4j
+public class UreportExcelUtil {
+
+    private ReportBuilder reportBuilder = new ReportBuilder();
+
+    public Workbook buildExcel(ReportEntity map, boolean withPaging, boolean withSheet, Connection connection) {
+        SXSSFWorkbook workbook = new SXSSFWorkbook();
+        try {
+            if (map != null) {
+                byte[] content = map.getContent().getBytes();
+                ByteArrayInputStream inputStream = new ByteArrayInputStream(content);
+                ReportDefinition reportDefinition = UreportUtil.parseReport(inputStream, map.getFullName());
+                Map<String, Object> parameters = new HashMap<>();
+                Report report = reportBuilder.buildReportToConnection(reportDefinition, parameters,connection);
+                if (withPaging) {
+                    workbook = build(report, withSheet);
+                } else {
+                    workbook = build(report);
+                }
+            }
+        } catch (Exception e) {
+            log.error("生成excel报表错误:" + e.getMessage());
+        }
+        return workbook;
+    }
+
+    //---------------------------------------生成excel------------------------------------------
+
+    public SXSSFWorkbook build(Report report, boolean withSheet) throws Exception {
+        CellStyleContext cellStyleContext = new CellStyleContext();
+        SXSSFWorkbook wb = new SXSSFWorkbook(1000);
+        CreationHelper creationHelper = wb.getCreationHelper();
+        Paper paper = report.getPaper();
+        List<Column> columns = report.getColumns();
+        Map<Row, Map<Column, Cell>> cellMap = report.getRowColCellMap();
+        int columnSize = columns.size();
+        List<Page> pages = report.getPages();
+        int rowNumber = 0;
+        int pageIndex = 1;
+        Sheet sheet = null;
+        Iterator var15 = pages.iterator();
+        while (var15.hasNext()) {
+            Page page = (Page) var15.next();
+            if (withSheet) {
+                sheet = createSheet(wb, paper, "第" + pageIndex + "页");
+                rowNumber = 0;
+            } else if (sheet == null) {
+                sheet = createSheet(wb, paper, (String) null);
+            }
+            ++pageIndex;
+            Drawing<?> drawing = sheet.createDrawingPatriarch();
+            List<Row> rows = page.getRows();
+            for (int rowIndex = 0; rowIndex < rows.size(); ++rowIndex) {
+                Row r = (Row) rows.get(rowIndex);
+                org.apache.poi.ss.usermodel.Row row = sheet.getRow(rowNumber);
+                if (row == null) {
+                    row = sheet.createRow(rowNumber);
+                }
+                Map<Column, Cell> colCell = (Map) cellMap.get(r);
+                int skipCol = 0;
+                for (int i = 0; i < columnSize; ++i) {
+                    Column col = (Column) columns.get(i);
+                    int w = col.getWidth();
+                    if (w < 1) {
+                        ++skipCol;
+                    } else {
+                        int colNum = i - skipCol;
+                        double colWidth = (double) UnitUtils.pointToPixel((double) w) * 37.5D;
+                        sheet.setColumnWidth(colNum, (short) ((int) colWidth));
+                        org.apache.poi.ss.usermodel.Cell cell = row.getCell(colNum);
+                        if (cell == null) {
+                            cell = row.createCell(colNum);
+                            Cell cellInfo = null;
+                            if (colCell != null) {
+                                cellInfo = (Cell) colCell.get(col);
+                            }
+                            if (cellInfo != null) {
+                                XSSFCellStyle style = cellStyleContext.produceXSSFCellStyle(wb, cellInfo);
+                                int colSpan = cellInfo.getColSpan();
+                                int rowSpan = cellInfo.getPageRowSpan();
+                                int rowEnd = rowSpan;
+                                if (rowSpan == 0) {
+                                    rowEnd = rowSpan + 1;
+                                }
+                                rowEnd += rowNumber;
+                                int colStart = i;
+                                int colEnd = colSpan;
+                                if (colSpan == 0) {
+                                    colEnd = colSpan + 1;
+                                }
+                                colEnd += i;
+                                for (int j = rowNumber; j < rowEnd; ++j) {
+                                    org.apache.poi.ss.usermodel.Row rr = sheet.getRow(j);
+                                    if (rr == null) {
+                                        rr = sheet.createRow(j);
+                                    }
+                                    for (int c = colStart; c < colEnd; ++c) {
+                                        org.apache.poi.ss.usermodel.Cell cc = rr.getCell(c - skipCol);
+                                        if (cc == null) {
+                                            cc = rr.createCell(c - skipCol);
+                                        }
+                                        cc.setCellStyle(style);
+                                    }
+                                }
+                                if (colSpan > 0 || rowSpan > 0) {
+                                    if (rowSpan > 0) {
+                                        --rowSpan;
+                                    }
+                                    if (colSpan > 0) {
+                                        --colSpan;
+                                    }
+                                    CellRangeAddress cellRegion = new CellRangeAddress(rowNumber, rowNumber + rowSpan, i - skipCol, i - skipCol + colSpan);
+                                    sheet.addMergedRegion(cellRegion);
+                                }
+                                Object obj = cellInfo.getFormatData();
+                                if (obj != null) {
+                                    if (obj instanceof String) {
+                                        cell.setCellValue((String) obj);
+                                        cell.setCellType(CellType.STRING);
+                                    } else if (obj instanceof Number) {
+                                        BigDecimal bigDecimal = Utils.toBigDecimal(obj);
+                                        cell.setCellValue((double) bigDecimal.floatValue());
+                                        cell.setCellType(CellType.NUMERIC);
+                                    } else if (obj instanceof Boolean) {
+                                        cell.setCellValue((Boolean) obj);
+                                        cell.setCellType(CellType.BOOLEAN);
+                                    } else {
+                                        int width;
+                                        int height;
+                                        int leftMargin;
+                                        int topMargin;
+                                        if (obj instanceof Image) {
+                                            Image img = (Image) obj;
+                                            InputStream inputStream = ImageUtils.base64DataToInputStream(img.getBase64Data());
+                                            BufferedImage bufferedImage = ImageIO.read(inputStream);
+                                            width = bufferedImage.getWidth();
+                                            height = bufferedImage.getHeight();
+                                            IOUtils.closeQuietly(inputStream);
+                                            inputStream = ImageUtils.base64DataToInputStream(img.getBase64Data());
+                                            width = 0;
+                                            height = 0;
+                                            leftMargin = getWholeWidth(columns, i, cellInfo.getColSpan());
+                                            topMargin = getWholeHeight(rows, rowIndex, cellInfo.getRowSpan());
+                                            HorizontalAlignment align = style.getAlignmentEnum();
+                                            if (align.equals(HorizontalAlignment.CENTER)) {
+                                                width = (leftMargin - width) / 2;
+                                            } else if (align.equals(HorizontalAlignment.RIGHT)) {
+                                                width = leftMargin - width;
+                                            }
+                                            VerticalAlignment valign = style.getVerticalAlignmentEnum();
+                                            if (valign.equals(VerticalAlignment.CENTER)) {
+                                                height = (topMargin - height) / 2;
+                                            } else if (valign.equals(VerticalAlignment.BOTTOM)) {
+                                                height = topMargin - height;
+                                            }
+                                            try {
+                                                XSSFClientAnchor anchor = (XSSFClientAnchor) creationHelper.createClientAnchor();
+                                                byte[] bytes = IOUtils.toByteArray(inputStream);
+                                                int pictureFormat = buildImageFormat(img);
+                                                int pictureIndex = wb.addPicture(bytes, pictureFormat);
+                                                anchor.setCol1(i);
+                                                anchor.setCol2(i + colSpan);
+                                                anchor.setRow1(rowNumber);
+                                                anchor.setRow2(rowNumber + rowSpan);
+                                                anchor.setDx1(width * 9525);
+                                                anchor.setDx2(width * 9525);
+                                                anchor.setDy1(height * 9525);
+                                                anchor.setDy2(height * 9525);
+                                                drawing.createPicture(anchor, pictureIndex);
+                                            } finally {
+                                                IOUtils.closeQuietly(inputStream);
+                                            }
+                                        } else if (obj instanceof ChartData) {
+                                            ChartData chartData = (ChartData) obj;
+                                            String base64Data = chartData.retriveBase64Data();
+                                            if (base64Data != null) {
+                                                Image img = new Image(base64Data, chartData.getWidth(), chartData.getHeight());
+                                                InputStream inputStream = ImageUtils.base64DataToInputStream(img.getBase64Data());
+                                                BufferedImage bufferedImage = ImageIO.read(inputStream);
+                                                width = bufferedImage.getWidth();
+                                                height = bufferedImage.getHeight();
+                                                IOUtils.closeQuietly(inputStream);
+                                                inputStream = ImageUtils.base64DataToInputStream(img.getBase64Data());
+                                                leftMargin = 0;
+                                                topMargin = 0;
+                                                int wholeWidth = getWholeWidth(columns, i, cellInfo.getColSpan());
+                                                int wholeHeight = getWholeHeight(rows, rowIndex, cellInfo.getRowSpan());
+                                                HorizontalAlignment align = style.getAlignmentEnum();
+                                                if (align.equals(HorizontalAlignment.CENTER)) {
+                                                    leftMargin = (wholeWidth - width) / 2;
+                                                } else if (align.equals(HorizontalAlignment.RIGHT)) {
+                                                    leftMargin = wholeWidth - width;
+                                                }
+
+                                                VerticalAlignment valign = style.getVerticalAlignmentEnum();
+                                                if (valign.equals(VerticalAlignment.CENTER)) {
+                                                    topMargin = (wholeHeight - height) / 2;
+                                                } else if (valign.equals(VerticalAlignment.BOTTOM)) {
+                                                    topMargin = wholeHeight - height;
+                                                }
+
+                                                try {
+                                                    XSSFClientAnchor anchor = (XSSFClientAnchor) creationHelper.createClientAnchor();
+                                                    byte[] bytes = IOUtils.toByteArray(inputStream);
+                                                    int pictureFormat = buildImageFormat(img);
+                                                    int pictureIndex = wb.addPicture(bytes, pictureFormat);
+                                                    anchor.setCol1(i);
+                                                    anchor.setCol2(i + colSpan);
+                                                    anchor.setRow1(rowNumber);
+                                                    anchor.setRow2(rowNumber + rowSpan);
+                                                    anchor.setDx1(leftMargin * 9525);
+                                                    anchor.setDx2(width * 9525);
+                                                    anchor.setDy1(topMargin * 9525);
+                                                    anchor.setDy2(height * 9525);
+                                                    drawing.createPicture(anchor, pictureIndex);
+                                                } finally {
+                                                    IOUtils.closeQuietly(inputStream);
+                                                }
+                                            }
+                                        } else if (obj instanceof Date) {
+                                            cell.setCellValue((Date) obj);
+                                        }
+                                    }
+                                }
+                            }
+                        }
+                    }
+                }
+                row.setHeight((short) UnitUtils.pointToTwip(r.getHeight()));
+                ++rowNumber;
+            }
+            sheet.setRowBreak(rowNumber - 1);
+        }
+        return wb;
+    }
+
+    public SXSSFWorkbook build(Report report) throws Exception {
+        CellStyleContext cellStyleContext = new CellStyleContext();
+        SXSSFWorkbook wb = new SXSSFWorkbook(100000);
+        CreationHelper creationHelper = wb.getCreationHelper();
+        Paper paper = report.getPaper();
+
+        List<Column> columns = report.getColumns();
+        Map<Row, Map<Column, Cell>> cellMap = report.getRowColCellMap();
+        int columnSize = columns.size();
+        Sheet sheet = createSheet(wb, paper, (String) null);
+        Drawing<?> drawing = sheet.createDrawingPatriarch();
+        List<Row> rows = report.getRows();
+        int rowNumber = 0;
+        Iterator var14 = rows.iterator();
+        while (var14.hasNext()) {
+            Row r = (Row) var14.next();
+            int realHeight = r.getRealHeight();
+            if (realHeight >= 1) {
+                if (r.isForPaging()) {
+                    return wb;
+                }
+                org.apache.poi.ss.usermodel.Row row = sheet.getRow(rowNumber);
+                if (row == null) {
+                    row = sheet.createRow(rowNumber);
+                }
+                Map<Column, Cell> colCell = (Map) cellMap.get(r);
+                int skipCol = 0;
+                for (int i = 0; i < columnSize; ++i) {
+                    Column col = (Column) columns.get(i);
+                    int w = col.getWidth();
+                    if (w < 1) {
+                        ++skipCol;
+                    } else {
+                        double colWidth = (double) UnitUtils.pointToPixel((double) w) * 37.5D;
+                        int colNum = i - skipCol;
+                        sheet.setColumnWidth(colNum, (short) ((int) colWidth));
+                        org.apache.poi.ss.usermodel.Cell cell = row.getCell(colNum);
+                        if (cell == null) {
+                            cell = row.createCell(colNum);
+                            Cell cellInfo = null;
+                            if (colCell != null) {
+                                cellInfo = (Cell) colCell.get(col);
+                            }
+                            if (cellInfo != null && !cellInfo.isForPaging()) {
+                                XSSFCellStyle style = cellStyleContext.produceXSSFCellStyle(wb, cellInfo);
+                                int colSpan = cellInfo.getColSpan();
+                                int rowSpan = cellInfo.getRowSpan();
+                                int rowEnd = rowSpan;
+                                if (rowSpan == 0) {
+                                    rowEnd = rowSpan + 1;
+                                }
+                                rowEnd += rowNumber;
+                                int colStart = i;
+                                int colEnd = colSpan;
+                                if (colSpan == 0) {
+                                    colEnd = colSpan + 1;
+                                }
+                                colEnd += i;
+                                for (int j = rowNumber; j < rowEnd; ++j) {
+                                    org.apache.poi.ss.usermodel.Row rr = sheet.getRow(j);
+                                    if (rr == null) {
+                                        rr = sheet.createRow(j);
+                                    }
+                                    for (int c = colStart; c < colEnd; ++c) {
+                                        org.apache.poi.ss.usermodel.Cell cc = rr.getCell(c - skipCol);
+                                        if (cc == null) {
+                                            cc = rr.createCell(c - skipCol);
+                                        }
+                                        cc.setCellStyle(style);
+                                    }
+                                }
+                                if (colSpan > 0 || rowSpan > 0) {
+                                    if (rowSpan > 0) {
+                                        --rowSpan;
+                                    }
+                                    if (colSpan > 0) {
+                                        --colSpan;
+                                    }
+                                    CellRangeAddress cellRegion = new CellRangeAddress(rowNumber, rowNumber + rowSpan, i - skipCol, i - skipCol + colSpan);
+                                    sheet.addMergedRegion(cellRegion);
+                                }
+                                Object obj = cellInfo.getFormatData();
+                                if (obj != null) {
+                                    if (obj instanceof String) {
+                                        cell.setCellValue((String) obj);
+                                        cell.setCellType(CellType.STRING);
+                                    } else if (obj instanceof Number) {
+                                        BigDecimal bigDecimal = Utils.toBigDecimal(obj);
+                                        cell.setCellValue(bigDecimal.doubleValue());
+                                        cell.setCellType(CellType.NUMERIC);
+                                    } else if (obj instanceof Boolean) {
+                                        cell.setCellValue((Boolean) obj);
+                                        cell.setCellType(CellType.BOOLEAN);
+                                    } else {
+                                        int width;
+                                        int height;
+                                        int leftMargin;
+                                        int topMargin;
+                                        if (obj instanceof Image) {
+                                            Image img = (Image) obj;
+                                            InputStream inputStream = ImageUtils.base64DataToInputStream(img.getBase64Data());
+                                            BufferedImage bufferedImage = ImageIO.read(inputStream);
+                                            width = bufferedImage.getWidth();
+                                            height = bufferedImage.getHeight();
+                                            IOUtils.closeQuietly(inputStream);
+                                            inputStream = ImageUtils.base64DataToInputStream(img.getBase64Data());
+                                            width = 0;
+                                            height = 0;
+                                            leftMargin = getWholeWidth(columns, i, cellInfo.getColSpan());
+                                            topMargin = getWholeHeight(rows, rowNumber, cellInfo.getRowSpan());
+                                            HorizontalAlignment align = style.getAlignmentEnum();
+                                            if (align.equals(HorizontalAlignment.CENTER)) {
+                                                width = (leftMargin - width) / 2;
+                                            } else if (align.equals(HorizontalAlignment.RIGHT)) {
+                                                width = leftMargin - width;
+                                            }
+                                            VerticalAlignment valign = style.getVerticalAlignmentEnum();
+                                            if (valign.equals(VerticalAlignment.CENTER)) {
+                                                height = (topMargin - height) / 2;
+                                            } else if (valign.equals(VerticalAlignment.BOTTOM)) {
+                                                height = topMargin - height;
+                                            }
+                                            try {
+                                                XSSFClientAnchor anchor = (XSSFClientAnchor) creationHelper.createClientAnchor();
+                                                byte[] bytes = IOUtils.toByteArray(inputStream);
+                                                int pictureFormat = buildImageFormat(img);
+                                                int pictureIndex = wb.addPicture(bytes, pictureFormat);
+                                                anchor.setCol1(i);
+                                                anchor.setCol2(i + colSpan);
+                                                anchor.setRow1(rowNumber);
+                                                anchor.setRow2(rowNumber + rowSpan);
+                                                anchor.setDx1(width * 9525);
+                                                anchor.setDx2(width * 9525);
+                                                anchor.setDy1(height * 9525);
+                                                anchor.setDy2(height * 9525);
+                                                drawing.createPicture(anchor, pictureIndex);
+                                            } finally {
+                                                IOUtils.closeQuietly(inputStream);
+                                            }
+                                        } else if (obj instanceof ChartData) {
+                                            ChartData chartData = (ChartData) obj;
+                                            String base64Data = chartData.retriveBase64Data();
+                                            if (base64Data != null) {
+                                                Image img = new Image(base64Data, chartData.getWidth(), chartData.getHeight());
+                                                InputStream inputStream = ImageUtils.base64DataToInputStream(img.getBase64Data());
+                                                BufferedImage bufferedImage = ImageIO.read(inputStream);
+                                                width = bufferedImage.getWidth();
+                                                height = bufferedImage.getHeight();
+                                                IOUtils.closeQuietly(inputStream);
+                                                inputStream = ImageUtils.base64DataToInputStream(img.getBase64Data());
+                                                leftMargin = 0;
+                                                topMargin = 0;
+                                                int wholeWidth = getWholeWidth(columns, i, cellInfo.getColSpan());
+                                                int wholeHeight = getWholeHeight(rows, rowNumber, cellInfo.getRowSpan());
+                                                HorizontalAlignment align = style.getAlignmentEnum();
+                                                if (align.equals(HorizontalAlignment.CENTER)) {
+                                                    leftMargin = (wholeWidth - width) / 2;
+                                                } else if (align.equals(HorizontalAlignment.RIGHT)) {
+                                                    leftMargin = wholeWidth - width;
+                                                }
+                                                VerticalAlignment valign = style.getVerticalAlignmentEnum();
+                                                if (valign.equals(VerticalAlignment.CENTER)) {
+                                                    topMargin = (wholeHeight - height) / 2;
+                                                } else if (valign.equals(VerticalAlignment.BOTTOM)) {
+                                                    topMargin = wholeHeight - height;
+                                                }
+                                                try {
+                                                    XSSFClientAnchor anchor = (XSSFClientAnchor) creationHelper.createClientAnchor();
+                                                    byte[] bytes = IOUtils.toByteArray(inputStream);
+                                                    int pictureFormat = buildImageFormat(img);
+                                                    int pictureIndex = wb.addPicture(bytes, pictureFormat);
+                                                    anchor.setCol1(i);
+                                                    anchor.setCol2(i + colSpan);
+                                                    anchor.setRow1(rowNumber);
+                                                    anchor.setRow2(rowNumber + rowSpan);
+                                                    anchor.setDx1(leftMargin * 9525);
+                                                    anchor.setDx2(width * 9525);
+                                                    anchor.setDy1(topMargin * 9525);
+                                                    anchor.setDy2(height * 9525);
+                                                    drawing.createPicture(anchor, pictureIndex);
+                                                } finally {
+                                                    IOUtils.closeQuietly(inputStream);
+                                                }
+                                            }
+                                        } else if (obj instanceof Date) {
+                                            cell.setCellValue((Date) obj);
+                                        }
+                                    }
+                                }
+                            }
+                        }
+                    }
+                }
+                row.setHeight((short) UnitUtils.pointToTwip(r.getRealHeight()));
+                ++rowNumber;
+            }
+        }
+        sheet.setRowBreak(rowNumber - 1);
+        return wb;
+    }
+
+    private int getWholeWidth(List<Column> columns, int colNumber, int colSpan) {
+        Column col = (Column) columns.get(colNumber);
+        int start = colNumber + 1;
+        int end = colNumber + colSpan;
+        int w = col.getWidth();
+
+        for (int i = start; i < end; ++i) {
+            Column c = (Column) columns.get(i);
+            w += c.getWidth();
+        }
+
+        w = UnitUtils.pointToPixel((double) w);
+        return w;
+    }
+
+    private int getWholeHeight(List<Row> rows, int rowNumber, int rowSpan) {
+        Row row = (Row) rows.get(rowNumber);
+        int start = rowNumber + 1;
+        int end = rowNumber + rowSpan;
+        int h = row.getRealHeight();
+
+        for (int i = start; i < end; ++i) {
+            Row r = (Row) rows.get(i);
+            h += r.getRealHeight();
+        }
+
+        h = UnitUtils.pointToPixel((double) h);
+        return h;
+    }
+
+    private Sheet createSheet(SXSSFWorkbook wb, Paper paper, String name) {
+        Sheet sheet = null;
+        if (name == null) {
+            sheet = wb.createSheet();
+        } else {
+            sheet = wb.createSheet(name);
+        }
+
+        PaperType paperType = paper.getPaperType();
+        XSSFPrintSetup printSetup = (XSSFPrintSetup) sheet.getPrintSetup();
+        Orientation orientation = paper.getOrientation();
+        if (orientation.equals(Orientation.landscape)) {
+            printSetup.setOrientation(PrintOrientation.LANDSCAPE);
+        }
+
+        setupPaper(paperType, printSetup);
+        int leftMargin = paper.getLeftMargin();
+        int rightMargin = paper.getRightMargin();
+        int topMargin = paper.getTopMargin();
+        int bottomMargin = paper.getBottomMargin();
+        sheet.setMargin((short) 0, (double) UnitUtils.pointToInche((float) leftMargin));
+        sheet.setMargin((short) 1, (double) UnitUtils.pointToInche((float) rightMargin));
+        sheet.setMargin((short) 2, (double) UnitUtils.pointToInche((float) topMargin));
+        sheet.setMargin((short) 3, (double) UnitUtils.pointToInche((float) bottomMargin));
+        return sheet;
+    }
+
+    private int buildImageFormat(Image img) {
+        int type = 6;
+        String path = img.getPath();
+        if (path == null) {
+            return type;
+        } else {
+            path = path.toLowerCase();
+            if (path.endsWith("jpg") || path.endsWith("jpeg")) {
+                type = 5;
+            }
+
+            return type;
+        }
+    }
+
+    private boolean setupPaper(PaperType paperType, XSSFPrintSetup printSetup) {
+        boolean setup = false;
+        switch (paperType) {
+            case A0:
+                printSetup.setPaperSize(PaperSize.A4_PAPER);
+                break;
+            case A1:
+                printSetup.setPaperSize(PaperSize.A4_PAPER);
+                break;
+            case A2:
+                printSetup.setPaperSize(PaperSize.A4_PAPER);
+                break;
+            case A3:
+                printSetup.setPaperSize(PaperSize.A3_PAPER);
+                setup = true;
+                break;
+            case A4:
+                printSetup.setPaperSize(PaperSize.A4_PAPER);
+                setup = true;
+                break;
+            case A5:
+                printSetup.setPaperSize(PaperSize.A5_PAPER);
+                setup = true;
+                break;
+            case A6:
+                printSetup.setPaperSize(PaperSize.A4_PAPER);
+                break;
+            case A7:
+                printSetup.setPaperSize(PaperSize.A4_PAPER);
+                break;
+            case A8:
+                printSetup.setPaperSize(PaperSize.A4_PAPER);
+                break;
+            case A9:
+                printSetup.setPaperSize(PaperSize.A4_PAPER);
+                break;
+            case A10:
+                printSetup.setPaperSize(PaperSize.A4_PAPER);
+                break;
+            case B0:
+                printSetup.setPaperSize(PaperSize.A4_PAPER);
+                break;
+            case B1:
+                printSetup.setPaperSize(PaperSize.A4_PAPER);
+                break;
+            case B2:
+                printSetup.setPaperSize(PaperSize.A4_PAPER);
+                break;
+            case B3:
+                printSetup.setPaperSize(PaperSize.A4_PAPER);
+                break;
+            case B4:
+                printSetup.setPaperSize(PaperSize.B4_PAPER);
+                setup = true;
+                break;
+            case B5:
+                printSetup.setPaperSize(PaperSize.B4_PAPER);
+                setup = true;
+                break;
+            case B6:
+                printSetup.setPaperSize(PaperSize.A4_PAPER);
+                break;
+            case B7:
+                printSetup.setPaperSize(PaperSize.A4_PAPER);
+                break;
+            case B8:
+                printSetup.setPaperSize(PaperSize.A4_PAPER);
+                break;
+            case B9:
+                printSetup.setPaperSize(PaperSize.A4_PAPER);
+                break;
+            case B10:
+                printSetup.setPaperSize(PaperSize.A4_PAPER);
+                break;
+            case CUSTOM:
+                printSetup.setPaperSize(PaperSize.A4_PAPER);
+        }
+        return setup;
+    }
+}

+ 405 - 0
ureport2-console/src/main/java/com/bstek/ureport/console/ureport/util/UreportPdfUtil.java

@@ -0,0 +1,405 @@
+package com.bstek.ureport.console.ureport.util;
+
+import com.bstek.ureport.build.ReportBuilder;
+import com.bstek.ureport.build.paging.Page;
+import com.bstek.ureport.chart.ChartData;
+import com.bstek.ureport.console.ureport.entity.ReportEntity;
+import com.bstek.ureport.definition.*;
+import com.bstek.ureport.export.FullPageData;
+import com.bstek.ureport.export.PageBuilder;
+import com.bstek.ureport.export.pdf.CellBorderEvent;
+import com.bstek.ureport.export.pdf.CellPhrase;
+import com.bstek.ureport.export.pdf.PageHeaderFooterEvent;
+import com.bstek.ureport.model.Cell;
+import com.bstek.ureport.model.Image;
+import com.bstek.ureport.model.*;
+import com.bstek.ureport.model.Row;
+import com.bstek.ureport.utils.ImageUtils;
+import com.bstek.ureport.utils.UnitUtils;
+import com.lowagie.text.*;
+import com.lowagie.text.pdf.PdfPCell;
+import com.lowagie.text.pdf.PdfPTable;
+import com.lowagie.text.pdf.PdfWriter;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.io.IOUtils;
+import org.apache.commons.lang.StringUtils;
+
+import java.awt.Color;
+import java.io.ByteArrayInputStream;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.sql.Connection;
+import java.util.List;
+import java.util.*;
+
+@Slf4j
+public class UreportPdfUtil {
+    CellPhrase cellPhrase = new CellPhrase();
+
+    private ReportBuilder reportBuilder = new ReportBuilder();
+
+    //手动带入数据库连接
+    public void buildPdfToConnection(ReportEntity map, OutputStream outputStream, Connection connection) {
+        if (map != null) {
+            byte[] content = map.getContent().getBytes();
+            ByteArrayInputStream inputStream = new ByteArrayInputStream(content);
+            ReportDefinition reportDefinition = UreportUtil.parseReport(inputStream, map.getFullName());
+            Map<String, Object> parameters = new HashMap<>();
+            Report report = reportBuilder.buildReportToConnection(reportDefinition, parameters,connection);
+            build(report, outputStream);
+        }
+    }
+
+    public void buildPdf(ReportDefinition reportDefinition, OutputStream outputStream,Connection connection) {
+        if (reportDefinition != null) {
+            Map<String, Object> parameters = new HashMap<>();
+            Report report = reportBuilder.buildReportToConnection(reportDefinition, parameters,connection);
+            build(report, outputStream);
+        }
+    }
+
+    //---------------------------------------生成pdf------------------------------------------
+    public void build(Report report, OutputStream outputStream) {
+        Paper paper = report.getPaper();
+        int width = paper.getWidth();
+        int height = paper.getHeight();
+        Rectangle pageSize = new RectangleReadOnly((float) width, (float) height);
+        if (paper.getOrientation().equals(Orientation.landscape)) {
+            pageSize = ((Rectangle) pageSize).rotate();
+        }
+        int leftMargin = paper.getLeftMargin();
+        int rightMargin = paper.getRightMargin();
+        int topMargin = paper.getTopMargin();
+        int bottomMargin = paper.getBottomMargin();
+        Document document = new Document((Rectangle) pageSize, (float) leftMargin, (float) rightMargin, (float) topMargin, (float) bottomMargin);
+        try {
+            PdfWriter writer = PdfWriter.getInstance(document, outputStream);
+            PageHeaderFooterEvent headerFooterEvent = new PageHeaderFooterEvent(report);
+            writer.setPageEvent(headerFooterEvent);
+            document.open();
+            List<Column> columns = report.getColumns();
+            List<Integer> columnsWidthList = new ArrayList();
+            int[] intArr = this.buildColumnSizeAndTotalWidth(columns, columnsWidthList);
+            int colSize = intArr[0];
+            int totalWidth = intArr[1];
+            int[] columnsWidth = new int[columnsWidthList.size()];
+            for (int i = 0; i < columnsWidthList.size(); ++i) {
+                columnsWidth[i] = (Integer) columnsWidthList.get(i);
+            }
+            FullPageData pageData = PageBuilder.buildFullPageData(report);
+            List<List<Page>> list = pageData.getPageList();
+            Iterator var28;
+            if (list.size() > 0) {
+                int columnCount = paper.getColumnCount();
+                int w = columnCount * totalWidth + (columnCount - 1) * paper.getColumnMargin();
+                int size = columnCount + (columnCount - 1);
+                int[] widths = new int[size];
+                for (int i = 0; i < size; ++i) {
+                    int mode = (i + 1) % 2;
+                    if (mode == 0) {
+                        widths[i] = paper.getColumnMargin();
+                    } else {
+                        widths[i] = totalWidth;
+                    }
+                }
+                float tableHeight = ((Rectangle) pageSize).getHeight() - (float) paper.getTopMargin() - (float) paper.getBottomMargin();
+                Map<Row, Map<Column, Cell>> cellMap = report.getRowColCellMap();
+                var28 = list.iterator();
+                while (var28.hasNext()) {
+                    List<Page> pages = (List) var28.next();
+                    PdfPTable table = new PdfPTable(size);
+                    table.setLockedWidth(true);
+                    table.setTotalWidth((float) w);
+                    table.setWidths(widths);
+                    table.setHorizontalAlignment(0);
+                    int ps = pages.size();
+                    int left;
+                    label124:
+                    for (left = 0; left < ps; ++left) {
+                        if (left > 0) {
+                            PdfPCell pdfMarginCell = new PdfPCell();
+                            pdfMarginCell.setBorder(0);
+                            table.addCell(pdfMarginCell);
+                        }
+                        Page page = (Page) pages.get(left);
+                        PdfPTable childTable = new PdfPTable(colSize);
+                        childTable.setLockedWidth(true);
+                        childTable.setTotalWidth((float) totalWidth);
+                        childTable.setWidths(columnsWidth);
+                        childTable.setHorizontalAlignment(0);
+                        List<Row> rows = page.getRows();
+                        Iterator var36 = rows.iterator();
+                        while (true) {
+                            Map colMap;
+                            do {
+                                if (!var36.hasNext()) {
+                                    float childTableHeight = childTable.calculateHeights(false);
+                                    if (tableHeight > childTableHeight) {
+                                        for (int j = 0; j < columns.size(); ++j) {
+                                            PdfPCell lastCell = new PdfPCell();
+                                            lastCell.setBorder(0);
+                                            childTable.addCell(lastCell);
+                                        }
+                                    }
+                                    PdfPCell pdfContainerCell = new PdfPCell(childTable);
+                                    pdfContainerCell.setBorder(0);
+                                    table.addCell(pdfContainerCell);
+                                    continue label124;
+                                }
+                                Row row = (Row) var36.next();
+                                colMap = (Map) cellMap.get(row);
+                            } while (colMap == null);
+                            Iterator var39 = columns.iterator();
+                            while (var39.hasNext()) {
+                                Column col = (Column) var39.next();
+                                if (col.getWidth() >= 1) {
+                                    Cell cell = (Cell) colMap.get(col);
+                                    if (cell != null) {
+                                        int cellHeight = this.buildCellHeight(cell, rows);
+                                        PdfPCell pdfcell = this.buildPdfPCell(cell, cellHeight);
+                                        childTable.addCell(pdfcell);
+                                    }
+                                }
+                            }
+                        }
+                    }
+                    if (ps < columnCount) {
+                        left = columnCount - ps;
+                        for (int i = 0; i < left; ++i) {
+                            PdfPCell pdfMarginCell = new PdfPCell();
+                            pdfMarginCell.setBorder(0);
+                            table.addCell(pdfMarginCell);
+                            pdfMarginCell = new PdfPCell();
+                            pdfMarginCell.setBorder(0);
+                            table.addCell(pdfMarginCell);
+                        }
+                    }
+                    document.add(table);
+                    document.newPage();
+                }
+            } else {
+                List<Page> pages = report.getPages();
+                Map<Row, Map<Column, Cell>> cellMap = report.getRowColCellMap();
+                Iterator var48 = pages.iterator();
+                label93:
+                while (var48.hasNext()) {
+                    Page page = (Page) var48.next();
+                    PdfPTable table = new PdfPTable(colSize);
+                    table.setLockedWidth(true);
+                    table.setTotalWidth((float) totalWidth);
+                    table.setWidths(columnsWidth);
+                    table.setHorizontalAlignment(0);
+                    List<Row> rows = page.getRows();
+                    var28 = rows.iterator();
+                    while (true) {
+                        Map colMap;
+                        do {
+                            if (!var28.hasNext()) {
+                                document.add(table);
+                                document.newPage();
+                                continue label93;
+                            }
+                            Row row = (Row) var28.next();
+                            colMap = (Map) cellMap.get(row);
+                        } while (colMap == null);
+                        Iterator var56 = columns.iterator();
+                        while (var56.hasNext()) {
+                            Column col = (Column) var56.next();
+                            if (col.getWidth() >= 1) {
+                                Cell cell = (Cell) colMap.get(col);
+                                if (cell != null) {
+                                    int cellHeight = this.buildCellHeight(cell, rows);
+                                    PdfPCell pdfcell = this.buildPdfPCell(cell, cellHeight);
+                                    table.addCell(pdfcell);
+                                }
+                            }
+                        }
+                    }
+                }
+            }
+            document.close();
+        } catch (Exception e) {
+            log.error(e.getMessage());
+        }
+    }
+
+    private int buildCellHeight(Cell cell, List<Row> rows) {
+        int height = cell.getRow().getRealHeight();
+        int rowSpan = cell.getPageRowSpan();
+        if (rowSpan > 0) {
+            int pos = rows.indexOf(cell.getRow());
+            int start = pos + 1;
+            int end = start + rowSpan - 1;
+
+            for (int i = start; i < end; ++i) {
+                height += ((Row) rows.get(i)).getRealHeight();
+            }
+        }
+
+        return height;
+    }
+
+    private PdfPCell buildPdfPCell(Cell cellInfo, int cellHeight) throws Exception {
+        CellStyle style = cellInfo.getCellStyle();
+        CellStyle customStyle = cellInfo.getCustomCellStyle();
+        CellStyle rowStyle = cellInfo.getRow().getCustomCellStyle();
+        CellStyle colStyle = cellInfo.getColumn().getCustomCellStyle();
+        PdfPCell cell = this.newPdfCell(cellInfo, cellHeight);
+        cell.setPadding(0);
+        cell.setBorder(0);
+        cell.setCellEvent(new CellBorderEvent(style, customStyle));
+        int rowSpan = cellInfo.getPageRowSpan();
+        if (rowSpan > 0) {
+            cell.setRowspan(rowSpan);
+        }
+
+        int colSpan = cellInfo.getColSpan();
+        if (colSpan > 0) {
+            cell.setColspan(colSpan);
+        }
+
+        Alignment align = style.getAlign();
+        if (customStyle != null && customStyle.getAlign() != null) {
+            align = customStyle.getAlign();
+        }
+
+        if (rowStyle != null && rowStyle.getAlign() != null) {
+            align = rowStyle.getAlign();
+        }
+
+        if (colStyle != null && colStyle.getAlign() != null) {
+            align = colStyle.getAlign();
+        }
+
+        if (align != null) {
+            if (align.equals(Alignment.left)) {
+                cell.setHorizontalAlignment(0);
+            } else if (align.equals(Alignment.center)) {
+                cell.setHorizontalAlignment(1);
+            } else if (align.equals(Alignment.right)) {
+                cell.setHorizontalAlignment(2);
+            }
+        }
+
+        Alignment valign = style.getValign();
+        if (customStyle != null && customStyle.getValign() != null) {
+            valign = customStyle.getValign();
+        }
+
+        if (rowStyle != null && rowStyle.getValign() != null) {
+            valign = rowStyle.getValign();
+        }
+
+        if (colStyle != null && colStyle.getValign() != null) {
+            valign = colStyle.getValign();
+        }
+
+        if (valign != null) {
+            if (valign.equals(Alignment.top)) {
+                cell.setVerticalAlignment(4);
+            } else if (valign.equals(Alignment.middle)) {
+                cell.setVerticalAlignment(5);
+            } else if (valign.equals(Alignment.bottom)) {
+                cell.setVerticalAlignment(6);
+            }
+        }
+
+        String bgcolor = style.getBgcolor();
+        if (customStyle != null && StringUtils.isNotBlank(customStyle.getBgcolor())) {
+            bgcolor = customStyle.getBgcolor();
+        }
+
+        if (rowStyle != null && StringUtils.isNotBlank(rowStyle.getBgcolor())) {
+            bgcolor = rowStyle.getBgcolor();
+        }
+
+        if (colStyle != null && StringUtils.isNotBlank(colStyle.getBgcolor())) {
+            bgcolor = colStyle.getBgcolor();
+        }
+
+        if (StringUtils.isNotEmpty(bgcolor)) {
+            String[] colors = bgcolor.split(",");
+            cell.setBackgroundColor(new Color(Integer.valueOf(colors[0]), Integer.valueOf(colors[1]), Integer.valueOf(colors[2])));
+        }
+
+        return cell;
+    }
+
+    private int[] buildColumnSizeAndTotalWidth(List<Column> columns, List<Integer> list) {
+        int count = 0;
+        int totalWidth = 0;
+
+        for (int i = 0; i < columns.size(); ++i) {
+            Column col = (Column) columns.get(i);
+            int width = col.getWidth();
+            if (width >= 1) {
+                ++count;
+                list.add(width);
+                totalWidth += width;
+            }
+        }
+
+        return new int[]{count, totalWidth};
+    }
+
+    private PdfPCell newPdfCell(Cell cellInfo, int cellHeight) throws Exception {
+        PdfPCell cell = null;
+        Object cellData = cellInfo.getFormatData();
+        if (cellData instanceof Image) {
+            Image img = (Image) cellData;
+            cell = new PdfPCell(this.buildPdfImage(img.getBase64Data(), 0, 0));
+        } else if (cellData instanceof ChartData) {
+            ChartData chartData = (ChartData) cellData;
+            String base64Data = chartData.retriveBase64Data();
+            if (base64Data != null) {
+                Image img = new Image(base64Data, chartData.getWidth(), chartData.getHeight());
+                cell = new PdfPCell(this.buildPdfImage(img.getBase64Data(), 0, 0));
+            } else {
+                cell = new PdfPCell();
+                CellPhrase pargraph = new CellPhrase(cellInfo, "");
+                cell.setPhrase(pargraph);
+                cell.setMinimumHeight(cellHeight);
+            }
+        } else {
+            Font font = cellPhrase.buildPdfFont(cellInfo);
+            cell = new PdfPCell();
+            Phrase phrase = new Phrase(String.valueOf(cellData), font);
+            cell.setPhrase(phrase);
+            cell.setMinimumHeight(cellHeight);
+        }
+
+        CellStyle style = cellInfo.getCellStyle();
+        if (style != null && style.getLineHeight() > 0.0F) {
+            cell.setLeading(style.getLineHeight(), style.getLineHeight());
+        }
+        return cell;
+    }
+
+    private com.lowagie.text.Image buildPdfImage(String base64Data, int width, int height) throws Exception {
+        com.lowagie.text.Image pdfImg = null;
+        InputStream input = ImageUtils.base64DataToInputStream(base64Data);
+
+        try {
+            byte[] bytes = IOUtils.toByteArray(input);
+            pdfImg = com.lowagie.text.Image.getInstance(bytes);
+            float imgWidth = pdfImg.getWidth();
+            float imgHeight = pdfImg.getHeight();
+            if (width == 0) {
+                width = Float.valueOf(imgWidth).intValue();
+            }
+
+            if (height == 0) {
+                height = Float.valueOf(imgHeight).intValue();
+            }
+
+            width = UnitUtils.pixelToPoint((double) (width - 2));
+            height = UnitUtils.pixelToPoint((double) (height - 2));
+            pdfImg.scaleToFit((float) width, (float) height);
+        } finally {
+            IOUtils.closeQuietly(input);
+        }
+
+        return pdfImg;
+    }
+
+}

+ 120 - 0
ureport2-console/src/main/java/com/bstek/ureport/console/ureport/util/UreportPreviewUtil.java

@@ -0,0 +1,120 @@
+package com.bstek.ureport.console.ureport.util;
+
+import com.bstek.ureport.build.Context;
+import com.bstek.ureport.build.ReportBuilder;
+import com.bstek.ureport.build.paging.Page;
+import com.bstek.ureport.console.cache.TempObjectCache;
+import com.bstek.ureport.console.ureport.entity.ReportEntity;
+import com.bstek.ureport.console.ureport.model.ReportPreviewVO;
+import com.bstek.ureport.definition.ReportDefinition;
+import com.bstek.ureport.export.PageBuilder;
+import com.bstek.ureport.export.SinglePageData;
+import com.bstek.ureport.export.html.HtmlProducer;
+import com.bstek.ureport.export.html.HtmlReport;
+import com.bstek.ureport.model.Report;
+
+import java.io.ByteArrayInputStream;
+import java.io.UnsupportedEncodingException;
+import java.sql.Connection;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+public class UreportPreviewUtil {
+
+    private ReportBuilder reportBuilder = new ReportBuilder();
+    private HtmlProducer htmlProducer = new HtmlProducer();
+
+    public ReportPreviewVO priviews(Map<String, Object> map, boolean page, int index, Connection connection) {
+        ReportPreviewVO vo = new ReportPreviewVO();
+        if (map != null) {
+            byte[] content = map.get("F_Content").toString().getBytes();
+            ByteArrayInputStream inputStream = new ByteArrayInputStream(content);
+            ReportDefinition reportDefinition = UreportUtil.parseReport(inputStream, map.get("F_FullName").toString());
+            Map<String, Object> parameters = new HashMap<>();
+            Report report = reportBuilder.buildReports(reportDefinition, parameters,connection);
+            HtmlReport htmlReport = loadReport(report, page, index);
+            htmlReport.setStyle(reportDefinition.getStyle());
+            htmlReport.setSearchFormData(reportDefinition.buildSearchFormData(report.getContext().getDatasetMap(), parameters));
+            vo.setContent(htmlReport.getContent());
+            vo.setPageIndex(htmlReport.getPageIndex());
+            vo.setStyle(htmlReport.getStyle());
+            vo.setTotalPage(htmlReport.getTotalPage());
+            TempObjectCache.putObject("p",reportDefinition);
+        }
+        return vo;
+    }
+
+    public ReportPreviewVO preview(ReportEntity entity, boolean page, int index, Map<String, Object> parameters, Connection connection, boolean isSwitch) {
+        ReportPreviewVO vo = new ReportPreviewVO();
+        if (entity != null) {
+            byte[] content = new byte[0];
+            try {
+                content = entity.getContent().getBytes("UTF-8");
+            } catch (UnsupportedEncodingException e) {
+                e.printStackTrace();
+            }
+            ByteArrayInputStream inputStream = new ByteArrayInputStream(content);
+            ReportDefinition reportDefinition = UreportUtil.parseReport(inputStream, entity.getFullName());
+            TempObjectCache.putObject(entity.getId(),reportDefinition);
+            //Map<String, Object> parameters = new HashMap<>();
+            Report report;
+            if(isSwitch && TempObjectCache.getObject(entity.getId() + "_report") != null){
+                report = (Report) TempObjectCache.getObject(entity.getId() + "_report");
+            }else {
+                report = reportBuilder.buildReports(reportDefinition, parameters, connection, reportDefinition.getSearchForm());
+                if(page){
+                    TempObjectCache.putObject(entity.getId() + "_report", report);
+                }
+            }
+            HtmlReport htmlReport = loadReport(report, page, index);
+            htmlReport.setStyle(reportDefinition.getStyle());
+            htmlReport.setSearchFormData(reportDefinition.buildSearchFormData(report.getContext().getDatasetMap(), parameters));
+            vo.setContent(htmlReport.getContent());
+            vo.setPageIndex(htmlReport.getPageIndex());
+            vo.setStyle(htmlReport.getStyle());
+            vo.setTotalPage(htmlReport.getTotalPage());
+            vo.setSearchFormData(htmlReport.getSearchFormData());
+            vo.setChartDatas(htmlReport.getChartDatas());
+        }
+        return vo;
+    }
+
+    public HtmlReport loadReport(Report report, boolean page, int index) {
+        HtmlReport htmlReport = new HtmlReport();
+        String html = null;
+        if (page) {
+            SinglePageData pageData = PageBuilder.buildSinglePageData(index, report);
+            html = this.produce(report, pageData);
+            htmlReport.setContent(html);
+            htmlReport.setTotalPage(pageData.getTotalPages());
+            htmlReport.setPageIndex(index);
+        } else {
+            html = htmlProducer.produce(report);
+            htmlReport.setContent(html);
+        }
+        if (report.getPaper().isColumnEnabled()) {
+            htmlReport.setColumn(report.getPaper().getColumnCount());
+        }
+        htmlReport.setChartDatas(report.getContext().getChartDataMap().values());
+        htmlReport.setTotalPage(report.getPages().size());
+        htmlReport.setReportAlign(report.getPaper().getHtmlReportAlign().name());
+        htmlReport.setHtmlIntervalRefreshValue(report.getPaper().getHtmlIntervalRefreshValue());
+        return htmlReport;
+    }
+
+    //分页
+    private String produce(Report report, SinglePageData pageData) {
+        Context context = report.getContext();
+        List<Page> pages = pageData.getPages();
+        String html = null;
+        if (pages.size() == 1) {
+            Page page = pages.get(0);
+            html = htmlProducer.produce(context, page, false);
+        } else {
+            html = htmlProducer.produce(context, pages, pageData.getColumnMargin(), false);
+        }
+        return html;
+    }
+
+}

+ 105 - 0
ureport2-console/src/main/java/com/bstek/ureport/console/ureport/util/UreportUtil.java

@@ -0,0 +1,105 @@
+package com.bstek.ureport.console.ureport.util;
+
+import com.bstek.ureport.cache.*;
+import com.bstek.ureport.definition.CellDefinition;
+import com.bstek.ureport.definition.Expand;
+import com.bstek.ureport.definition.ReportDefinition;
+import com.bstek.ureport.exception.ReportParseException;
+import com.bstek.ureport.export.builder.down.DownCellbuilder;
+import com.bstek.ureport.export.builder.right.RightCellbuilder;
+import com.bstek.ureport.parser.ReportParser;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URLDecoder;
+import java.util.List;
+
+
+public class UreportUtil {
+
+    private static DownCellbuilder downCellParentbuilder = new DownCellbuilder();
+    private static RightCellbuilder rightCellParentbuilder = new RightCellbuilder();
+
+    /**
+     *
+     * @param inputStream
+     * @param fileName
+     * @param isEdit 编辑模式时报错将会继续处理不会停止 避免编辑界面无法打开
+     * @return
+     */
+    public static ReportDefinition parseReport(InputStream inputStream, String fileName, boolean isEdit) {
+        ReportParser reportParser = new ReportParser();
+        ReportDefinition var4;
+        try {
+            ReportDefinition reportDefinition = reportParser.parse(inputStream, fileName, isEdit);
+            rebuildReportDefinition(reportDefinition);
+            CacheUtils.cacheReportDefinition(fileName, reportDefinition);
+            var4 = reportDefinition;
+        } finally {
+            try {
+                if (inputStream != null) {
+                    inputStream.close();
+                }
+            } catch (IOException var11) {
+                throw new ReportParseException(var11);
+            }
+        }
+        return var4;
+    }
+
+
+    //转成report内容 有错误会转换失败
+    public static ReportDefinition parseReport(InputStream inputStream, String fileName) {
+        return parseReport(inputStream, fileName, false);
+    }
+
+    //转成utf-8格式
+    public static String decodeContent(String content) {
+        if (content == null) {
+            return content;
+        }
+        try {
+            content = URLDecoder.decode(content, "utf-8");
+            return content;
+        } catch (Exception ex) {
+            return content;
+        }
+    }
+
+    private static void rebuildReportDefinition(ReportDefinition reportDefinition) {
+        List<CellDefinition> cells = reportDefinition.getCells();
+        for (CellDefinition cell : cells) {
+            addRowChildCell(cell, cell);
+            addColumnChildCell(cell, cell);
+        }
+        for (CellDefinition cell : cells) {
+            Expand expand = cell.getExpand();
+            if (expand.equals(Expand.Down)) {
+                downCellParentbuilder.buildParentCell(cell, cells);
+            } else if (expand.equals(Expand.Right)) {
+                rightCellParentbuilder.buildParentCell(cell, cells);
+            }
+        }
+    }
+
+    private static void addRowChildCell(CellDefinition cell, CellDefinition childCell) {
+        CellDefinition leftCell = cell.getLeftParentCell();
+        if (leftCell == null) {
+            return;
+        }
+        List<CellDefinition> childrenCells = leftCell.getRowChildrenCells();
+        childrenCells.add(childCell);
+        addRowChildCell(leftCell, childCell);
+    }
+
+    private static void addColumnChildCell(CellDefinition cell, CellDefinition childCell) {
+        CellDefinition topCell = cell.getTopParentCell();
+        if (topCell == null) {
+            return;
+        }
+        List<CellDefinition> childrenCells = topCell.getColumnChildrenCells();
+        childrenCells.add(childCell);
+        addColumnChildCell(topCell, childCell);
+    }
+
+}

+ 640 - 0
ureport2-console/src/main/java/com/bstek/ureport/console/ureport/util/UreportWordUtil.java

@@ -0,0 +1,640 @@
+package com.bstek.ureport.console.ureport.util;
+
+import com.bstek.ureport.build.ReportBuilder;
+import com.bstek.ureport.build.paging.Page;
+import com.bstek.ureport.chart.ChartData;
+import com.bstek.ureport.console.ureport.entity.ReportEntity;
+import com.bstek.ureport.definition.*;
+import com.bstek.ureport.exception.ReportComputeException;
+import com.bstek.ureport.export.word.DxaUtils;
+import com.bstek.ureport.model.*;
+import com.bstek.ureport.utils.ImageUtils;
+import com.bstek.ureport.utils.UnitUtils;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.io.IOUtils;
+import org.apache.commons.lang.StringUtils;
+import org.apache.poi.util.Units;
+import org.apache.poi.xwpf.usermodel.*;
+import org.openxmlformats.schemas.wordprocessingml.x2006.main.*;
+
+import javax.imageio.ImageIO;
+import java.awt.image.BufferedImage;
+import java.io.ByteArrayInputStream;
+import java.io.FileOutputStream;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.math.BigInteger;
+import java.sql.Connection;
+import java.text.SimpleDateFormat;
+import java.util.*;
+
+@Slf4j
+public class UreportWordUtil {
+
+    private ReportBuilder reportBuilder = new ReportBuilder();
+
+    public XWPFDocument buildWord(ReportEntity map, Connection connection) {
+        XWPFDocument document = new XWPFDocument();
+        if (map != null) {
+            byte[] content = map.getContent().getBytes();
+            ByteArrayInputStream inputStream = new ByteArrayInputStream(content);
+            ReportDefinition reportDefinition = UreportUtil.parseReport(inputStream, map.getFullName());
+            Map<String, Object> parameters = new HashMap<>();
+            Report report = reportBuilder.buildReportToConnection(reportDefinition, parameters,connection);
+            document = this.build(report);
+        }
+        return document;
+    }
+
+    //---------------------------------------生成word------------------------------------------
+    public XWPFDocument build(Report report) {
+        XWPFDocument document = new XWPFDocument();
+        try {
+            CTSectPr sectpr = document.getDocument().getBody().addNewSectPr();
+            if (!sectpr.isSetPgSz()) {
+                sectpr.addNewPgSz();
+            }
+
+            CTPageSz pageSize = sectpr.getPgSz();
+            Paper paper = report.getPaper();
+            Orientation orientation = paper.getOrientation();
+            if (orientation.equals(Orientation.landscape)) {
+                pageSize.setOrient(STPageOrientation.LANDSCAPE);
+                pageSize.setH(BigInteger.valueOf((long) DxaUtils.points2dxa(paper.getWidth())));
+                pageSize.setW(BigInteger.valueOf((long) DxaUtils.points2dxa(paper.getHeight())));
+            } else {
+                pageSize.setOrient(STPageOrientation.PORTRAIT);
+                pageSize.setW(BigInteger.valueOf((long) DxaUtils.points2dxa(paper.getWidth())));
+                pageSize.setH(BigInteger.valueOf((long) DxaUtils.points2dxa(paper.getHeight())));
+            }
+
+            int columnCount = paper.getColumnCount();
+            if (paper.isColumnEnabled() && columnCount > 0) {
+                CTColumns cols = CTColumns.Factory.newInstance();
+                cols.setNum(new BigInteger(String.valueOf(columnCount)));
+                int columnMargin = paper.getColumnMargin();
+                cols.setSpace(new BigInteger(String.valueOf(DxaUtils.points2dxa(columnMargin))));
+                sectpr.setCols(cols);
+            }
+
+            CTPageMar pageMar = sectpr.addNewPgMar();
+            pageMar.setLeft(BigInteger.valueOf((long) DxaUtils.points2dxa(paper.getLeftMargin())));
+            pageMar.setRight(BigInteger.valueOf((long) DxaUtils.points2dxa(paper.getRightMargin())));
+            pageMar.setTop(BigInteger.valueOf((long) DxaUtils.points2dxa(paper.getTopMargin())));
+            pageMar.setBottom(BigInteger.valueOf((long) DxaUtils.points2dxa(paper.getBottomMargin())));
+            List<Column> columns = report.getColumns();
+            int[] intArr = this.buildColumnSizeAndTotalWidth(columns);
+            int totalColumn = intArr[0];
+            int tableWidth = intArr[1];
+            List<Page> pages = report.getPages();
+            Map<Row, Map<Column, Cell>> cellMap = report.getRowColCellMap();
+            int totalPages = pages.size();
+            int pageIndex = 1;
+
+            for (Iterator var18 = pages.iterator(); var18.hasNext(); ++pageIndex) {
+                Page page = (Page) var18.next();
+                List<Row> rows = page.getRows();
+                XWPFTable table = document.createTable(rows.size(), totalColumn);
+                table.getCTTbl().getTblPr().unsetTblBorders();
+                table.getCTTbl().addNewTblPr().addNewTblW().setW(BigInteger.valueOf((long) DxaUtils.points2dxa(tableWidth)));
+
+                for (int rowNumber = 0; rowNumber < rows.size(); ++rowNumber) {
+                    Row row = (Row) rows.get(rowNumber);
+                    int height = row.getRealHeight();
+                    XWPFTableRow tableRow = table.getRow(rowNumber);
+                    tableRow.setHeight(DxaUtils.points2dxa(height));
+                    Map<Column, Cell> colCell = (Map) cellMap.get(row);
+                    if (colCell != null) {
+                        int skipCol = 0;
+                        Iterator var28 = columns.iterator();
+
+                        while (var28.hasNext()) {
+                            Column col = (Column) var28.next();
+                            int width = col.getWidth();
+                            if (width < 1) {
+                                ++skipCol;
+                            } else {
+                                int colNumber = col.getColumnNumber() - 1 - skipCol;
+                                Cell cell = (Cell) colCell.get(col);
+                                XWPFTableCell tableCell = tableRow.getCell(colNumber);
+                                if (tableCell != null) {
+                                    tableCell.getCTTc().addNewTcPr().addNewTcW().setW(BigInteger.valueOf((long) DxaUtils.points2dxa(width)));
+                                    if (cell != null) {
+                                        this.buildTableCellStyle(table, tableCell, cell, rowNumber, colNumber);
+                                    }
+                                }
+                            }
+                        }
+                    }
+                }
+
+                if (pageIndex < totalPages) {
+                    XWPFParagraph paragraph = document.createParagraph();
+                    XWPFRun run = paragraph.createRun();
+                    run.setFontSize(0);
+                    run.addBreak(BreakType.PAGE);
+                }
+            }
+        } catch (Exception var41) {
+            throw new ReportComputeException(var41);
+        }
+        return document;
+    }
+
+    private int[] buildColumnSizeAndTotalWidth(List<Column> columns) {
+        int count = 0;
+        int totalWidth = 0;
+
+        for (int i = 0; i < columns.size(); ++i) {
+            Column col = (Column) columns.get(i);
+            int width = col.getWidth();
+            if (width >= 1) {
+                ++count;
+                totalWidth += width;
+            }
+        }
+
+        return new int[]{count, totalWidth};
+    }
+
+    private void buildTableCellStyle(XWPFTable table, XWPFTableCell tableCell, Cell cell, int rowNumber, int columnNumber) {
+        CellStyle style = cell.getCellStyle();
+        CellStyle customStyle = cell.getCustomCellStyle();
+        CellStyle rowStyle = cell.getRow().getCustomCellStyle();
+        CellStyle colStyle = cell.getColumn().getCustomCellStyle();
+        CTTcPr cellProperties = tableCell.getCTTc().addNewTcPr();
+        Border leftBorder = style.getLeftBorder();
+        Border rightBorder = style.getRightBorder();
+        Border topBorder = style.getTopBorder();
+        Border bottomBorder = style.getBottomBorder();
+        if (customStyle != null) {
+            if (customStyle.getLeftBorder() != null) {
+                leftBorder = customStyle.getLeftBorder();
+            }
+
+            if (customStyle.getRightBorder() != null) {
+                rightBorder = customStyle.getRightBorder();
+            }
+
+            if (customStyle.getTopBorder() != null) {
+                topBorder = customStyle.getTopBorder();
+            }
+
+            if (customStyle.getBottomBorder() != null) {
+                bottomBorder = customStyle.getBottomBorder();
+            }
+        }
+
+        int rowSpan = cell.getPageRowSpan();
+        int colSpan = cell.getColSpan();
+        int end;
+        int i;
+        XWPFTableCell xwpfTableCell;
+        if (style.getLeftBorder() != null) {
+            if (rowSpan > 0) {
+                end = rowNumber + rowSpan;
+
+                for (i = rowNumber; i < end; ++i) {
+                    xwpfTableCell = table.getRow(i).getCell(columnNumber);
+                    this.buildCellBorder(leftBorder, xwpfTableCell, 1);
+                }
+            } else {
+                this.buildCellBorder(leftBorder, tableCell, 1);
+            }
+        }
+
+        int lastRow;
+        XWPFTableCell c;
+        if (rightBorder != null) {
+            lastRow = columnNumber;
+            if (colSpan > 0) {
+                lastRow = columnNumber + (colSpan - 1);
+            }
+
+            if (rowSpan > 0) {
+                end = rowNumber + rowSpan;
+
+                for (i = rowNumber; i < end; ++i) {
+                    c = table.getRow(i).getCell(lastRow);
+                    this.buildCellBorder(style.getRightBorder(), c, 2);
+                }
+            } else {
+                c = table.getRow(rowNumber).getCell(lastRow);
+                this.buildCellBorder(rightBorder, c, 2);
+            }
+        }
+
+        if (topBorder != null) {
+            if (colSpan > 0) {
+                end = columnNumber + colSpan;
+
+                for (end = columnNumber; end < end; ++end) {
+                    xwpfTableCell = table.getRow(rowNumber).getCell(end);
+                    this.buildCellBorder(topBorder, xwpfTableCell, 3);
+                }
+            } else {
+                this.buildCellBorder(topBorder, tableCell, 3);
+            }
+        }
+
+        if (bottomBorder != null) {
+            lastRow = rowNumber;
+            if (rowSpan > 0) {
+                lastRow = rowNumber + (rowSpan - 1);
+            }
+
+            if (colSpan > 0) {
+                end = columnNumber + colSpan;
+
+                for (i = columnNumber; i < end; ++i) {
+                    c = table.getRow(lastRow).getCell(i);
+                    this.buildCellBorder(bottomBorder, c, 4);
+                }
+            } else {
+                c = table.getRow(lastRow).getCell(columnNumber);
+                this.buildCellBorder(bottomBorder, c, 4);
+            }
+        }
+
+        List<XWPFParagraph> paras = tableCell.getParagraphs();
+        c = null;
+        XWPFParagraph para;
+        if (paras != null && paras.size() > 0) {
+            para = (XWPFParagraph) paras.get(0);
+        } else {
+            para = tableCell.addParagraph();
+        }
+
+        List<XWPFRun> runs = para.getRuns();
+        xwpfTableCell = null;
+        XWPFRun run;
+        if (runs != null && runs.size() > 0) {
+            run = (XWPFRun) runs.get(0);
+        } else {
+            run = para.createRun();
+        }
+
+        Object value = cell.getFormatData();
+        String fontFamily;
+        if (value instanceof String) {
+            fontFamily = value.toString();
+            if (fontFamily.contains("\n")) {
+                String[] line = fontFamily.split("\n");
+                run.setText(line[0], 0);
+
+                for (int k = 1; k < line.length; ++k) {
+                    run.addBreak();
+                    run.setText(line[k], k);
+                }
+            } else {
+                run.setText(fontFamily);
+            }
+        } else if (value instanceof Number) {
+            run.setText(String.valueOf(value));
+        } else if (value instanceof Boolean) {
+            run.setText(value.toString());
+        } else if (!(value instanceof Image) && !(value instanceof ChartData)) {
+            if (value instanceof Date) {
+                Date date = (Date) value;
+                SimpleDateFormat sd = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
+                run.setText(sd.format(date));
+            }
+        } else {
+            fontFamily = null;
+            Image img;
+            String imageType;
+            if (value instanceof Image) {
+                img = (Image) value;
+            } else {
+                ChartData chartData = (ChartData) value;
+                imageType = chartData.retriveBase64Data();
+                if (imageType != null) {
+                    img = new Image(imageType, chartData.getWidth(), chartData.getHeight());
+                } else {
+                    img = new Image("", chartData.getWidth(), chartData.getHeight());
+                }
+            }
+
+            String path = img.getPath();
+            imageType = "png";
+            if (StringUtils.isNotBlank(path)) {
+                path = path.toLowerCase();
+                if (!path.endsWith(".jpg") && !path.endsWith(".jpeg")) {
+                    if (path.endsWith(".gif")) {
+                        imageType = "gif";
+                    }
+                } else {
+                    imageType = "jpeg";
+                }
+            }
+
+            String base64Data = img.getBase64Data();
+            if (StringUtils.isNotBlank(base64Data)) {
+                InputStream inputStream = null;
+
+                try {
+                    inputStream = ImageUtils.base64DataToInputStream(base64Data);
+                    BufferedImage bufferedImage = ImageIO.read(inputStream);
+                    int width = bufferedImage.getWidth();
+                    int height = bufferedImage.getHeight();
+                    IOUtils.closeQuietly(inputStream);
+                    inputStream = ImageUtils.base64DataToInputStream(base64Data);
+                    width = UnitUtils.pixelToPoint((double) width);
+                    height = UnitUtils.pixelToPoint((double) height);
+                    if (imageType.equals("jpeg")) {
+                        run.addPicture(inputStream, 5, "ureport-" + rowNumber + "-" + columnNumber + ".jpg", Units.toEMU((double) width), Units.toEMU((double) height));
+                    } else if (imageType.equals("png")) {
+                        run.addPicture(inputStream, 6, "ureport-" + rowNumber + "-" + columnNumber + ".png", Units.toEMU((double) width), Units.toEMU((double) height));
+                    } else if (imageType.equals("gif")) {
+                        run.addPicture(inputStream, 8, "ureport-" + rowNumber + "-" + columnNumber + ".gif", Units.toEMU((double) width), Units.toEMU((double) height));
+                    }
+                } catch (Exception var37) {
+                    throw new ReportComputeException(var37);
+                } finally {
+                    IOUtils.closeQuietly(inputStream);
+                }
+            }
+        }
+
+        fontFamily = style.getFontFamily();
+        if (customStyle != null && StringUtils.isNotBlank(customStyle.getFontFamily())) {
+            fontFamily = customStyle.getFontFamily();
+        }
+
+        if (rowStyle != null && StringUtils.isNotBlank(rowStyle.getFontFamily())) {
+            fontFamily = rowStyle.getFontFamily();
+        }
+
+        if (colStyle != null && StringUtils.isNotBlank(colStyle.getFontFamily())) {
+            fontFamily = colStyle.getFontFamily();
+        }
+
+        if (StringUtils.isNotBlank(fontFamily)) {
+            run.setFontFamily(fontFamily);
+        }
+
+        int fontSize = style.getFontSize();
+        if (customStyle != null && customStyle.getFontSize() > 0) {
+            fontSize = customStyle.getFontSize();
+        }
+
+        if (rowStyle != null && rowStyle.getFontSize() > 0) {
+            fontSize = rowStyle.getFontSize();
+        }
+
+        if (colStyle != null && colStyle.getFontSize() > 0) {
+            fontSize = colStyle.getFontSize();
+        }
+
+        if (fontSize > 0) {
+            run.setFontSize(fontSize);
+        }
+
+        boolean bold = style.getBold() == null ? false : style.getBold();
+        if (customStyle != null && customStyle.getBold() != null) {
+            bold = customStyle.getBold();
+        }
+
+        if (rowStyle != null && rowStyle.getBold() != null) {
+            bold = rowStyle.getBold();
+        }
+
+        if (colStyle != null && colStyle.getBold() != null) {
+            bold = colStyle.getBold();
+        }
+
+        if (bold) {
+            run.setBold(true);
+        }
+
+        boolean italic = style.getItalic() == null ? false : style.getItalic();
+        if (customStyle != null && customStyle.getItalic() != null) {
+            italic = customStyle.getItalic();
+        }
+
+        if (rowStyle != null && rowStyle.getItalic() != null) {
+            italic = rowStyle.getItalic();
+        }
+
+        if (colStyle != null && colStyle.getItalic() != null) {
+            italic = colStyle.getItalic();
+        }
+
+        if (italic) {
+            run.setItalic(true);
+        }
+
+        boolean underline = style.getUnderline() == null ? false : style.getUnderline();
+        if (customStyle != null && customStyle.getUnderline() != null) {
+            underline = customStyle.getUnderline();
+        }
+
+        if (rowStyle != null && rowStyle.getUnderline() != null) {
+            underline = rowStyle.getUnderline();
+        }
+
+        if (colStyle != null && colStyle.getUnderline() != null) {
+            underline = colStyle.getUnderline();
+        }
+
+        if (underline) {
+            run.setUnderline(UnderlinePatterns.SINGLE);
+        }
+
+        String bgcolor = style.getBgcolor();
+        if (customStyle != null && StringUtils.isNotBlank(customStyle.getBgcolor())) {
+            bgcolor = customStyle.getBgcolor();
+        }
+
+        if (rowStyle != null && StringUtils.isNotBlank(rowStyle.getBgcolor())) {
+            bgcolor = rowStyle.getBgcolor();
+        }
+
+        if (colStyle != null && StringUtils.isNotBlank(colStyle.getBgcolor())) {
+            bgcolor = colStyle.getBgcolor();
+        }
+
+        if (bgcolor != null) {
+            CTShd ctshd = cellProperties.addNewShd();
+            ctshd.setFill(this.toHex(bgcolor.split(",")));
+        }
+
+        String forecolor = style.getForecolor();
+        if (customStyle != null && StringUtils.isNotBlank(customStyle.getForecolor())) {
+            forecolor = customStyle.getForecolor();
+        }
+
+        if (rowStyle != null && StringUtils.isNotBlank(rowStyle.getForecolor())) {
+            forecolor = rowStyle.getForecolor();
+        }
+
+        if (colStyle != null && StringUtils.isNotBlank(colStyle.getForecolor())) {
+            forecolor = colStyle.getForecolor();
+        }
+
+        if (forecolor != null) {
+            run.setColor(this.toHex(forecolor.split(",")));
+        }
+
+        Alignment align = style.getAlign();
+        if (customStyle != null && customStyle.getAlign() != null) {
+            align = customStyle.getAlign();
+        }
+
+        if (rowStyle != null && rowStyle.getAlign() != null) {
+            align = rowStyle.getAlign();
+        }
+
+        if (align != null) {
+            if (align.equals(Alignment.left)) {
+                para.setAlignment(ParagraphAlignment.LEFT);
+            } else if (align.equals(Alignment.right)) {
+                para.setAlignment(ParagraphAlignment.RIGHT);
+            } else if (align.equals(Alignment.center)) {
+                para.setAlignment(ParagraphAlignment.CENTER);
+            }
+        }
+
+        if (style.getLineHeight() > 0.0F) {
+            para.setSpacingBetween((double) style.getLineHeight());
+        }
+
+        align = style.getValign();
+        if (customStyle != null && customStyle.getValign() != null) {
+            align = customStyle.getValign();
+        }
+
+        if (rowStyle != null && rowStyle.getValign() != null) {
+            align = rowStyle.getValign();
+        }
+
+        if (colStyle != null && colStyle.getValign() != null) {
+            align = colStyle.getValign();
+        }
+
+        if (align != null) {
+            CTVerticalJc verticalAlign = cellProperties.addNewVAlign();
+            if (align.equals(Alignment.top)) {
+                verticalAlign.setVal(STVerticalJc.TOP);
+            } else if (align.equals(Alignment.middle)) {
+                verticalAlign.setVal(STVerticalJc.CENTER);
+            } else if (align.equals(Alignment.bottom)) {
+                verticalAlign.setVal(STVerticalJc.BOTTOM);
+            }
+        }
+
+        int startCol = columnNumber;
+        int startRow = rowNumber;
+        int endRow = rowNumber;
+        int endCol = columnNumber;
+        if (colSpan > 0) {
+            endCol = columnNumber + colSpan - 1;
+        }
+
+        if (rowSpan > 0) {
+            endRow = rowNumber + rowSpan - 1;
+        }
+
+        if (columnNumber != endCol) {
+            if (rowSpan > 0) {
+                for (i = rowNumber; i <= endRow; ++i) {
+                    this.mergeCellsHorizontal(table, i, startCol, endCol);
+                }
+            } else {
+                this.mergeCellsHorizontal(table, rowNumber, columnNumber, endCol);
+            }
+        }
+
+        if (rowNumber != endRow) {
+            if (colSpan > 0) {
+                for (i = startCol; i <= endCol; ++i) {
+                    this.mergeCellsVertically(table, i, startRow, endRow);
+                }
+            } else {
+                this.mergeCellsVertically(table, startCol, rowNumber, endRow);
+            }
+        }
+
+    }
+
+    private void mergeCellsHorizontal(XWPFTable table, int row, int startCol, int endCol) {
+        for (int cellIndex = startCol; cellIndex <= endCol; ++cellIndex) {
+            XWPFTableCell cell = table.getRow(row).getCell(cellIndex);
+            if (cellIndex == startCol) {
+                cell.getCTTc().addNewTcPr().addNewHMerge().setVal(STMerge.RESTART);
+            } else {
+                cell.getCTTc().addNewTcPr().addNewHMerge().setVal(STMerge.CONTINUE);
+            }
+        }
+
+    }
+
+    private void mergeCellsVertically(XWPFTable table, int col, int fromRow, int toRow) {
+        for (int rowIndex = fromRow; rowIndex <= toRow; ++rowIndex) {
+            XWPFTableCell cell = table.getRow(rowIndex).getCell(col);
+            if (rowIndex == fromRow) {
+                cell.getCTTc().addNewTcPr().addNewVMerge().setVal(STMerge.RESTART);
+            } else {
+                cell.getCTTc().addNewTcPr().addNewVMerge().setVal(STMerge.CONTINUE);
+            }
+        }
+
+    }
+
+    private void buildCellBorder(Border border, XWPFTableCell tableCell, int type) {
+        CTTcPr cellPropertie = tableCell.getCTTc().getTcPr();
+        if (cellPropertie == null) {
+            cellPropertie = tableCell.getCTTc().addNewTcPr();
+        }
+
+        CTTcBorders borders = cellPropertie.getTcBorders();
+        if (borders == null) {
+            borders = cellPropertie.addNewTcBorders();
+        }
+
+        BorderStyle borderStyle = border.getStyle();
+        CTBorder ctborder = null;
+        if (type == 1) {
+            ctborder = borders.addNewLeft();
+        } else if (type == 2) {
+            ctborder = borders.addNewRight();
+        } else if (type == 3) {
+            ctborder = borders.addNewTop();
+        } else if (type == 4) {
+            ctborder = borders.addNewBottom();
+        }
+
+        if (borderStyle.equals(BorderStyle.dashed)) {
+            ctborder.setVal(STBorder.DASHED);
+        } else if (borderStyle.equals(BorderStyle.doublesolid)) {
+            ctborder.setVal(STBorder.DOUBLE);
+        } else {
+            ctborder.setVal(STBorder.SINGLE);
+        }
+
+        int borderWidth = border.getWidth();
+        if (borderWidth > 1) {
+            ctborder.setSz(BigInteger.valueOf((long) DxaUtils.points2dxa(borderWidth)));
+        }
+
+        String color = border.getColor();
+        if (StringUtils.isNotBlank(color)) {
+            ctborder.setColor(this.toHex(color.split(",")));
+        }
+
+    }
+
+    private String toHex(String[] rgb) {
+        StringBuffer sb = new StringBuffer();
+        String R = Integer.toHexString(Integer.valueOf(rgb[0]));
+        String G = Integer.toHexString(Integer.valueOf(rgb[1]));
+        String B = Integer.toHexString(Integer.valueOf(rgb[2]));
+        R = R.length() == 1 ? "0" + R : R;
+        G = G.length() == 1 ? "0" + G : G;
+        B = B.length() == 1 ? "0" + B : B;
+        sb.append(R);
+        sb.append(G);
+        sb.append(B);
+        return sb.toString();
+    }
+}

+ 91 - 0
ureport2-console/src/main/java/com/bstek/ureport/console/util/ActionResult.java

@@ -0,0 +1,91 @@
+package com.bstek.ureport.console.util;
+
+import com.fasterxml.jackson.annotation.JsonInclude;
+import lombok.Data;
+
+import java.util.List;
+
+@Data
+@JsonInclude(JsonInclude.Include.NON_NULL)
+public class ActionResult<T> {
+
+    private Integer code;
+
+    private String msg;
+
+    private T data;
+
+    private T baseInfo;
+
+
+    public static ActionResult success() {
+        ActionResult jsonData = new ActionResult();
+        jsonData.setCode(200);
+        jsonData.setMsg("Success");
+        return jsonData;
+    }
+
+    public static ActionResult success(String msg) {
+        ActionResult jsonData = new ActionResult();
+        jsonData.setCode(200);
+        jsonData.setMsg(msg);
+        return jsonData;
+    }
+
+    public static ActionResult success(Object object) {
+        ActionResult jsonData = new ActionResult();
+        jsonData.setData(object);
+        jsonData.setCode(200);
+        jsonData.setMsg("Success");
+        return jsonData;
+    }
+
+    public static ActionResult successTOBase(Object object,Object obj) {
+        ActionResult jsonData = new ActionResult();
+        jsonData.setData(object);
+        jsonData.setBaseInfo(obj);
+        jsonData.setCode(200);
+        jsonData.setMsg("Success");
+        return jsonData;
+    }
+
+    public static<T> ActionResult page(List<T> list, PaginationVO pagination) {
+        ActionResult jsonData = new ActionResult();
+        PageListVO<T> vo = new PageListVO<>();
+        vo.setList(list);
+        vo.setPagination(pagination);
+        jsonData.setData(vo);
+        jsonData.setCode(200);
+        jsonData.setMsg("Success");
+        return jsonData;
+    }
+
+    public static ActionResult success(String msg, Object object) {
+        ActionResult jsonData = new ActionResult();
+        jsonData.setData(object);
+        jsonData.setCode(200);
+        jsonData.setMsg(msg);
+        return jsonData;
+    }
+
+    public static ActionResult fail(Integer code, String message) {
+        ActionResult jsonData = new ActionResult();
+        jsonData.setCode(code);
+        jsonData.setMsg(message);
+        return jsonData;
+    }
+
+    public static ActionResult fail(String msg, String data) {
+        ActionResult jsonData = new ActionResult();
+        jsonData.setMsg(msg);
+        jsonData.setData(data);
+        return jsonData;
+    }
+
+    public static ActionResult fail(String msg) {
+        ActionResult jsonData = new ActionResult();
+        jsonData.setMsg(msg);
+        jsonData.setCode(400);
+        return jsonData;
+    }
+}

+ 24 - 0
ureport2-console/src/main/java/com/bstek/ureport/console/util/DbTableConModel.java

@@ -0,0 +1,24 @@
+package com.bstek.ureport.console.util;
+
+import lombok.Data;
+
+@Data
+public class DbTableConModel {
+    // 标识
+    private String id;
+    // 表名
+    private String table;
+    private String newTable;
+    // 表说明
+    private String tableName;
+    // 大小
+    private String size;
+    // 总数
+    private Integer sum;
+    // 说明
+    private String description;
+    // 主键
+    private String primaryKey;
+    // 数据源主键
+    private String dataSourceId;
+}

+ 717 - 0
ureport2-console/src/main/java/com/bstek/ureport/console/util/FileUtil.java

@@ -0,0 +1,717 @@
+package com.bstek.ureport.console.util;
+
+import com.baomidou.mybatisplus.core.toolkit.Constants;
+import jakarta.servlet.http.Part;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.web.multipart.MultipartFile;
+
+import java.io.*;
+import java.text.DateFormat;
+import java.text.DecimalFormat;
+import java.text.SimpleDateFormat;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Date;
+import java.util.List;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipOutputStream;
+
+@Slf4j
+public class FileUtil {
+
+    /**
+     * 判断文件夹是否存在
+     *
+     * @param filePath 文件地址
+     * @return
+     */
+    public static boolean fileIsExists(String filePath) {
+        File f = new File(filePath);
+        if (!f.exists()) {
+            return false;
+        }
+        return true;
+    }
+
+    /**
+     * 判断文件是否存在
+     *
+     * @param filePath
+     * @return
+     */
+    public static boolean fileIsFile(String filePath) {
+        File f = new File(filePath);
+        if (!f.isFile()) {
+            return false;
+        }
+        return true;
+    }
+
+    /**
+     * 创建文件
+     *
+     * @param filePath 文件地址
+     * @param fileName 文件名
+     * @return
+     */
+    public static boolean createFile(String filePath, String fileName) {
+        String strFilePath = filePath + fileName;
+        File file = new File(filePath);
+        if (!file.exists()) {
+            /** 注意这里是 mkdirs()方法 可以创建多个文件夹 */
+            file.mkdirs();
+        }
+        File subfile = new File(strFilePath);
+        if (!subfile.exists()) {
+            try {
+                boolean b = subfile.createNewFile();
+                return b;
+            } catch (IOException e) {
+                e.printStackTrace();
+            }
+        } else {
+            return true;
+        }
+        return false;
+    }
+
+    /**
+     * 创建文件夹
+     *
+     * @param path 文件夹地址
+     * @return
+     */
+    public static void createDirs(String path) {
+        File file = new File(path);
+        if (!file.exists()) {
+            /** 注意这里是 mkdirs()方法 可以创建多个文件夹 */
+            file.mkdirs();
+        }
+    }
+
+    /**
+     * 遍历文件夹下当前文件
+     *
+     * @param file 地址
+     */
+    public static List<File> getFile(File file) {
+        List<File> list = new ArrayList<>();
+        File[] fileArray = file.listFiles();
+        if (fileArray == null) {
+            return list;
+        } else {
+            for (File f : fileArray) {
+                if (f.isFile()) {
+                    list.add(0, f);
+                }
+            }
+        }
+        return list;
+    }
+
+    /**
+     * 遍历文件夹下所有文件
+     *
+     * @param file 地址
+     */
+    public static List<File> getFile(File file, List<File> list) {
+        File[] fileArray = file.listFiles();
+        if (fileArray == null) {
+            return list;
+        } else {
+            for (File f : fileArray) {
+                if (f.isFile()) {
+                    list.add(0, f);
+                } else {
+                    getFile(f, list);
+                }
+            }
+        }
+        return list;
+    }
+
+    /**
+     * 删除文件或文件夹以及子文件夹和子文件等 【注意】请谨慎调用该方法,避免删除重要文件
+     *
+     * @param file
+     */
+    public static void deleteFileAll(File file) {
+        if (file.exists()) {
+            if (file.isFile()) {// 文件
+                log.info(file.getAbsolutePath() + " 删除中...");
+                file.delete();
+                log.info("删除成功!");
+                return;
+            } else {// 文件夹
+                File[] files = file.listFiles();
+                for (int i = 0; i < files.length; i++) {
+                    deleteFileAll(files[i]);
+                }
+                file.delete();
+            }
+        } else {
+            log.info(file.getAbsolutePath() + " 文件不存在!");
+        }
+    }
+
+    /**
+     * 删除单个文件
+     *
+     * @param path 文件路径
+     */
+    public static void deleteFile(String path) {
+        File file = new File(path);
+        if (file.exists() && file.isFile()) {
+            file.delete();
+        }
+    }
+
+    /**
+     * 删除空文件夹、空的子文件夹
+     *
+     * @param file
+     * @author cielo
+     */
+    public static void deleteEmptyDirectory(File file) {
+        if (file != null && file.exists() && file.isDirectory()) {
+            File[] files = file.listFiles();
+            if (files != null && files.length > 0) {
+                for (int i = 0; i < files.length; i++) {
+                    deleteEmptyDirectory(files[i]);
+                }
+                // 子文件夹里的删除完后,重新获取。判断空的子文件删除后,该文件夹是否为空
+                files = file.listFiles();
+            }
+            if (files == null || files.length == 0) {
+                String absolutePath = file.getAbsolutePath();
+                file.delete();
+                log.info("删除空文件夹!路径:" + absolutePath);
+            }
+        }
+    }
+
+    /**
+     * 打开目录
+     *
+     * @param path
+     */
+    public static void open(String path) {
+        // 打开输出目录
+        try {
+            String osName = System.getProperty("os.name");
+            if (osName != null) {
+                if (osName.contains("Mac")) {
+                    Runtime.getRuntime().exec("open " + path);
+                } else if (osName.contains("Windows")) {
+                    Runtime.getRuntime().exec("cmd /c start " + path);
+                } else {
+                    log.debug("文件输出目录:" + path);
+                }
+            }
+        } catch (IOException e) {
+            e.printStackTrace();
+        }
+    }
+
+    /**
+     * 向文件中添加内容
+     *
+     * @param strcontent 内容
+     * @param filePath   地址
+     * @param fileName   文件名
+     */
+    public static void writeToFile(String strcontent, String filePath, String fileName) {
+        //生成文件夹之后,再生成文件,不然会出错
+        String strFilePath = filePath + fileName;
+        // 每次写入时,都换行写
+        File subfile = new File(strFilePath);
+        RandomAccessFile raf = null;
+        try {
+            /** 构造函数 第二个是读写方式 */
+            raf = new RandomAccessFile(subfile, "rw");
+            /** 将记录指针移动到该文件的最后 */
+            raf.seek(subfile.length());
+            /** 向文件末尾追加内容 */
+            raf.write(strcontent.getBytes());
+            raf.close();
+        } catch (IOException e) {
+            e.printStackTrace();
+        }
+    }
+
+    /**
+     * 修改文件内容(覆盖或者添加)
+     *
+     * @param path    文件地址
+     * @param content 覆盖内容
+     * @param append  指定了写入的方式,是覆盖写还是追加写(true=追加)(false=覆盖)
+     */
+    public static void modifyFile(String path, String content, boolean append) {
+        try {
+            FileWriter fileWriter = new FileWriter(path, append);
+            BufferedWriter writer = new BufferedWriter(fileWriter);
+            writer.append(content);
+            writer.flush();
+            writer.close();
+        } catch (IOException e) {
+            e.printStackTrace();
+        }
+    }
+
+    /**
+     * 读取文件内容
+     *
+     * @param filePath 地址
+     * @param filename 名称
+     * @return 返回内容
+     */
+    public static String getString(String filePath, String filename) {
+        FileInputStream inputStream = null;
+        try {
+            inputStream = new FileInputStream(new File(filePath + filename));
+        } catch (FileNotFoundException e) {
+            e.printStackTrace();
+        }
+        InputStreamReader inputStreamReader = null;
+        try {
+            inputStreamReader = new InputStreamReader(inputStream, Constants.UTF_8);
+        } catch (UnsupportedEncodingException e1) {
+            e1.printStackTrace();
+        }
+        BufferedReader reader = new BufferedReader(inputStreamReader);
+        StringBuffer sb = new StringBuffer("");
+        String line;
+        try {
+            while ((line = reader.readLine()) != null) {
+                sb.append(line);
+                sb.append("\n");
+            }
+        } catch (IOException e) {
+            e.printStackTrace();
+        }
+        return sb.toString();
+    }
+
+    /**
+     * 重命名文件
+     *
+     * @param oldPath 原来的文件地址
+     * @param newPath 新的文件地址
+     */
+    public static void renameFile(String oldPath, String newPath) {
+        File oleFile = new File(oldPath);
+        File newFile = new File(newPath);
+        //执行重命名
+        oleFile.renameTo(newFile);
+    }
+
+    /**
+     * 复制文件
+     *
+     * @param fromFile 要复制的文件目录
+     * @param toFile   要粘贴的文件目录
+     * @return 是否复制成功
+     */
+    public static boolean copy(String fromFile, String toFile) {
+        //要复制的文件目录
+        File[] currentFiles;
+        File root = new File(fromFile);
+        //如同判断SD卡是否存在或者文件是否存在
+        //如果不存在则 return出去
+        if (!root.exists()) {
+            return false;
+        }
+        //如果存在则获取当前目录下的全部文件 填充数组
+        currentFiles = root.listFiles();
+        //目标目录
+        File targetDir = new File(toFile);
+        //创建目录
+        if (!targetDir.exists()) {
+            targetDir.mkdirs();
+        }
+        //遍历要复制该目录下的全部文件
+        for (int i = 0; i < currentFiles.length; i++) {
+            if (currentFiles[i].isDirectory()) {//如果当前项为子目录 进行递归
+                copy(currentFiles[i].getPath() + "/", toFile + currentFiles[i].getName() + "/");
+            } else {//如果当前项为文件则进行文件拷贝
+                copyFile(currentFiles[i].getPath(), toFile + currentFiles[i].getName());
+            }
+        }
+        return true;
+    }
+
+    //文件拷贝
+    //要复制的目录下的所有非子目录(文件夹)文件拷贝
+    public static boolean copyFile(String fromFile, String toFile) {
+        try {
+            InputStream fosfrom = new FileInputStream(fromFile);
+            OutputStream fosto = new FileOutputStream(toFile);
+            byte bt[] = new byte[1024];
+            int c;
+            while ((c = fosfrom.read(bt)) > 0) {
+                fosto.write(bt, 0, c);
+            }
+            fosfrom.close();
+            fosto.close();
+            return true;
+        } catch (Exception ex) {
+            return false;
+        }
+    }
+
+    //文件拷贝
+    public static boolean copyFile(String fromFile, String toFile, String fileName) {
+        try {
+            //目标目录
+            File targetDir = new File(toFile);
+            //创建目录
+            if (!targetDir.exists()) {
+                targetDir.mkdirs();
+            }
+            InputStream fosfrom = new FileInputStream(fromFile);
+            OutputStream fosto = new FileOutputStream(toFile + fileName);
+            byte bt[] = new byte[1024];
+            int c;
+            while ((c = fosfrom.read(bt)) > 0) {
+                fosto.write(bt, 0, c);
+            }
+            fosfrom.close();
+            fosto.close();
+            return true;
+        } catch (Exception ex) {
+            return false;
+        }
+    }
+
+    /**
+     * 获取文件输入流
+     */
+    public static InputStream readFileToInputStream(String path) {
+        InputStream inputStream = null;
+        try {
+            File file = new File(path);
+            inputStream = new FileInputStream(file);
+        } catch (IOException e) {
+            e.getMessage();
+        }
+        return inputStream;
+    }
+
+    /**
+     * 保存文件
+     *
+     * @param inputStream
+     * @param path
+     * @param fileName
+     */
+    public static void write(InputStream inputStream, String path, String fileName) {
+        OutputStream os = null;
+        long dateStr = System.currentTimeMillis();
+        try {
+            // 1K的数据缓冲
+            byte[] bs = new byte[1024];
+            // 读取到的数据长度
+            int len;
+            // 输出的文件流保存到本地文件
+            File tempFile = new File(path);
+            if (!tempFile.exists()) {
+                tempFile.mkdirs();
+            }
+            String newFileName = tempFile.getPath() + File.separator + dateStr + fileName;
+            log.info("保存文件:" + newFileName);
+            os = new FileOutputStream(newFileName);
+            // 开始读取
+            while ((len = inputStream.read(bs)) != -1) {
+                os.write(bs, 0, len);
+            }
+        } catch (IOException e) {
+            log.error("生成excel失败");
+        } catch (Exception e) {
+            log.error("生成excel失败");
+        } finally {
+            // 完毕,关闭所有链接
+            try {
+                if (os != null) {
+                    os.close();
+                }
+                inputStream.close();
+            } catch (IOException e) {
+                log.error("关闭链接失败" + e.getMessage());
+            }
+        }
+    }
+
+    /**
+     * 上传文件
+     *
+     * @param file     文件
+     * @param filePath 保存路径
+     * @param fileName 保存名称
+     */
+    public static void upFile(MultipartFile file, String filePath, String fileName) {
+        try {
+            // 输出的文件流保存到本地文件
+            File tempFile = new File(filePath);
+            if (!tempFile.exists()) {
+                tempFile.mkdirs();
+            }
+            File f = new File(filePath, fileName);
+            file.transferTo(f);//将上传的文件存储到指定位置
+        } catch (Exception e) {
+            e.getMessage();
+        }
+    }
+
+    /**
+     * 读取文件修改时间
+     */
+    public static String getCreateTime(String filePath) {
+        DateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
+        File file = new File(filePath);
+        // 毫秒数
+        long modifiedTime = file.lastModified();
+        // 通过毫秒数构造日期 即可将毫秒数转换为日期
+        Date date = new Date(modifiedTime);
+        String dateString = format.format(date);
+        return dateString;
+    }
+
+    /**
+     * 获取文件类型
+     */
+    public static String getFileType(File file) {
+        if (file.isFile()) {
+            String fileName = file.getName();
+            String fileTyle = fileName.substring(fileName.lastIndexOf(".") + 1, fileName.length());
+            return fileTyle;
+        }
+        return null;
+    }
+
+    /**
+     * 获取文件类型
+     */
+    public static String getFileType(String fileName) {
+        int lastIndexOf = fileName.lastIndexOf(".") + 1;
+        //获取文件的后缀名 jpg
+        String suffix = fileName.substring(lastIndexOf);
+        return suffix;
+    }
+
+    /**
+     * 获取文件大小
+     *
+     * @param data
+     * @return
+     */
+    public static String getSize(String data) {
+        String size = "";
+        if (data != null && !StringUtils.isEmpty(data)) {
+            long fileS = Long.parseLong(data);
+            DecimalFormat df = new DecimalFormat("#.00");
+            if (fileS < 1024) {
+                size = df.format((double) fileS) + "BT";
+            } else if (fileS < 1048576) {
+                size = df.format((double) fileS / 1024) + "KB";
+            } else if (fileS < 1073741824) {
+                size = df.format((double) fileS / 1048576) + "MB";
+            } else {
+                size = df.format((double) fileS / 1073741824) + "GB";
+            }
+        } else {
+            size = "0BT";
+        }
+        return size;
+    }
+
+    private static final int BUFFER_SIZE = 2 * 1024;
+
+    /**
+     * 压缩文件夹
+     *
+     * @param srcDir           压缩文件夹路径
+     * @param outDir           压缩文件路径
+     * @param KeepDirStructure 是否保留原来的目录结构,
+     *                         true:保留目录结构;
+     *                         false:所有文件跑到压缩包根目录下(注意:不保留目录结构可能会出现同名文件,会压缩失败)
+     * @throws RuntimeException 压缩失败会抛出运行时异常
+     */
+    public static void toZip(String outDir, boolean KeepDirStructure, String... srcDir) {
+        try {
+            OutputStream out = new FileOutputStream(new File(outDir));
+            ZipOutputStream zos = null;
+            try {
+                zos = new ZipOutputStream(out);
+                List<File> sourceFileList = new ArrayList<File>();
+                for (String dir : srcDir) {
+                    File sourceFile = new File(dir);
+                    sourceFileList.add(sourceFile);
+                }
+                compress(sourceFileList, zos, KeepDirStructure);
+            } catch (Exception e) {
+                throw new RuntimeException("zip error from ZipUtils", e);
+            } finally {
+                if (zos != null) {
+                    try {
+                        zos.close();
+                    } catch (IOException e) {
+                        e.printStackTrace();
+                    }
+                }
+            }
+        } catch (Exception e) {
+            log.error("压缩失败:{}", e.getMessage());
+        }
+    }
+
+    /**
+     * 递归压缩方法
+     *
+     * @param sourceFile       源文件
+     * @param zos              zip输出流
+     * @param name             压缩后的名称
+     * @param KeepDirStructure 是否保留原来的目录结构,
+     *                         true:保留目录结构;
+     *                         false:所有文件跑到压缩包根目录下(注意:不保留目录结构可能会出现同名文件,会压缩失败)
+     * @throws Exception
+     */
+    private static void compress(File sourceFile, ZipOutputStream zos, String name, boolean KeepDirStructure) throws Exception {
+        byte[] buf = new byte[BUFFER_SIZE];
+        if (sourceFile.isFile()) {
+            zos.putNextEntry(new ZipEntry(name));
+            int len;
+            FileInputStream in = new FileInputStream(sourceFile);
+            while ((len = in.read(buf)) != -1) {
+                zos.write(buf, 0, len);
+            }
+            zos.closeEntry();
+            in.close();
+        } else {
+            File[] listFiles = sourceFile.listFiles();
+            if (listFiles == null || listFiles.length == 0) {
+                if (KeepDirStructure) {
+                    zos.putNextEntry(new ZipEntry(name + "/"));
+                    zos.closeEntry();
+                }
+            } else {
+                for (File file : listFiles) {
+                    if (KeepDirStructure) {
+                        compress(file, zos, name + "/" + file.getName(),
+                                KeepDirStructure);
+                    } else {
+                        compress(file, zos, file.getName(), KeepDirStructure);
+                    }
+                }
+            }
+        }
+    }
+
+    private static void compress(List<File> sourceFileList, ZipOutputStream zos, boolean KeepDirStructure) throws Exception {
+        byte[] buf = new byte[BUFFER_SIZE];
+        for (File sourceFile : sourceFileList) {
+            String name = sourceFile.getName();
+            if (sourceFile.isFile()) {
+                zos.putNextEntry(new ZipEntry(name));
+                int len;
+                FileInputStream in = new FileInputStream(sourceFile);
+                while ((len = in.read(buf)) != -1) {
+                    zos.write(buf, 0, len);
+                }
+                zos.closeEntry();
+                in.close();
+            } else {
+                File[] listFiles = sourceFile.listFiles();
+                if (listFiles == null || listFiles.length == 0) {
+                    if (KeepDirStructure) {
+                        zos.putNextEntry(new ZipEntry(name + "/"));
+                        zos.closeEntry();
+                    }
+                } else {
+                    for (File file : listFiles) {
+                        if (KeepDirStructure) {
+                            compress(file, zos, name + "/" + file.getName(),
+                                    KeepDirStructure);
+                        } else {
+                            compress(file, zos, file.getName(),
+                                    KeepDirStructure);
+                        }
+
+                    }
+                }
+            }
+        }
+    }
+
+    //=================================判断文件后缀==========================
+
+    /**
+     * 允许文件类型
+     *
+     * @param fileType      文件所有类型
+     * @param fileExtension 当前文件类型
+     * @return
+     */
+    public static boolean fileType(String fileType, String fileExtension) {
+        String[] allowExtension = fileType.split(",");
+        return Arrays.asList(allowExtension).contains(fileExtension.toLowerCase());
+    }
+
+    /**
+     * 允许图片类型
+     *
+     * @param imageType     图片所有类型
+     * @param fileExtension 当前图片类型
+     * @return
+     */
+    public static boolean imageType(String imageType, String fileExtension) {
+        String[] allowExtension = imageType.split(",");
+        return Arrays.asList(allowExtension).contains(fileExtension.toLowerCase());
+    }
+
+    /**
+     * 允许上传大小
+     *
+     * @param fileSize 文件大小
+     * @param maxSize  最大的文件
+     * @return
+     */
+    public static boolean fileSize(Long fileSize, int maxSize) {
+        if (fileSize > maxSize) {
+            return true;
+        }
+        return false;
+    }
+
+
+    /**
+     * 读取multipartFile中的内容
+     * @param multipartFile
+     * @return
+     * @throws IOException
+     */
+    public static String getFileContent(MultipartFile multipartFile) throws IOException {
+        BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(multipartFile.getInputStream(), "UTF-8"));
+        String lineTxt = "";
+        while ((lineTxt=bufferedReader.readLine())!=null){
+            return lineTxt;
+        }
+        return null;
+    }
+
+    /**
+     * 读取multipartFile中的内容
+     * @param part
+     * @return
+     * @throws IOException
+     */
+    public static String getFileContent(Part part) throws IOException {
+        BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(part.getInputStream(), "UTF-8"));
+        String lineTxt = "";
+        while ((lineTxt=bufferedReader.readLine())!=null){
+            return lineTxt;
+        }
+        return null;
+    }
+
+}

+ 11 - 0
ureport2-console/src/main/java/com/bstek/ureport/console/util/ListVO.java

@@ -0,0 +1,11 @@
+package com.bstek.ureport.console.util;
+
+import lombok.Data;
+
+import java.util.List;
+
+@Data
+public class ListVO<T> {
+    private List<T>  list;
+
+}

+ 8 - 0
ureport2-console/src/main/java/com/bstek/ureport/console/util/Page.java

@@ -0,0 +1,8 @@
+package com.bstek.ureport.console.util;
+
+import lombok.Data;
+
+@Data
+public class Page {
+    private String keyword="";
+}

+ 12 - 0
ureport2-console/src/main/java/com/bstek/ureport/console/util/PageListVO.java

@@ -0,0 +1,12 @@
+package com.bstek.ureport.console.util;
+
+import lombok.Data;
+
+import java.util.List;
+
+@Data
+public class PageListVO<T> {
+    private List<T> list;
+    PaginationVO pagination;
+
+}

+ 25 - 0
ureport2-console/src/main/java/com/bstek/ureport/console/util/Pagination.java

@@ -0,0 +1,25 @@
+package com.bstek.ureport.console.util;
+
+import com.fasterxml.jackson.annotation.JsonIgnore;
+import lombok.Data;
+
+import java.util.List;
+
+@Data
+public class Pagination extends Page{
+    private long pageSize=20;
+    private String sort="desc";
+    private String sidx="";
+    private long currentPage=1;
+
+
+    @JsonIgnore
+    private long total;
+    @JsonIgnore
+    private long records;
+
+    public <T> List<T> setData(List<T> data, long records) {
+        this.total = records;
+        return data;
+    }
+}

+ 10 - 0
ureport2-console/src/main/java/com/bstek/ureport/console/util/PaginationVO.java

@@ -0,0 +1,10 @@
+package com.bstek.ureport.console.util;
+
+import lombok.Data;
+
+@Data
+public class PaginationVO {
+    private long currentPage;
+    private long pageSize;
+    private int total;
+}

+ 31 - 0
ureport2-console/src/main/java/com/bstek/ureport/console/util/RandomUtil.java

@@ -0,0 +1,31 @@
+package com.bstek.ureport.console.util;
+
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.Random;
+import java.util.UUID;
+
+public class RandomUtil {
+
+    /**
+     * 生成主键id
+     * @return
+     */
+    public static String uuId() {
+        String uuid = UUID.randomUUID().toString();
+        String temp = uuid.substring(0, 8) + uuid.substring(9, 13) + uuid.substring(14, 18) + uuid.substring(19, 23) + uuid.substring(24);
+        return temp;
+    }
+
+    /**
+     * 生成排序编码
+     * @return
+     */
+    public static Long parses() {
+        Date date = new Date();
+        SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmssSSS");
+        Long time = Long.parseLong(sdf.format(date));
+        return time;
+    }
+
+}

+ 44 - 0
ureport2-console/src/main/java/com/bstek/ureport/console/util/RequestUtil.java

@@ -0,0 +1,44 @@
+package com.bstek.ureport.console.util;
+
+import jakarta.servlet.ServletInputStream;
+import jakarta.servlet.http.HttpServletRequest;
+import java.io.IOException;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.Map;
+
+public class RequestUtil {
+
+    //获取request内的参数
+    public static String getPayload(HttpServletRequest request) throws IOException {
+        ServletInputStream is = request.getInputStream();
+        int nRead = 1;
+        int nTotalRead = 0;
+        byte[] bytes = new byte[10240 * 200];
+        while (nRead > 0) {
+            nRead = is.read(bytes, nTotalRead, bytes.length - nTotalRead);
+            if (nRead > 0) {
+                nTotalRead = nTotalRead + nRead;
+            }
+        }
+        String str = new String(bytes, 0, nTotalRead, "UTF8");
+        is.close();
+        return str;
+    }
+
+    /**
+     * body中form-data转map
+     * @param request
+     * @return
+     */
+    public static  Map<String, String> getParamsFromFormDataByNames(HttpServletRequest request){
+        Map<String, String> map =new HashMap<>();
+        Enumeration<String> er = request.getParameterNames();
+        while (er.hasMoreElements()) {
+            String name = (String) er.nextElement();
+            String value = request.getParameter(name);
+            map.put(name, value);
+        }
+        return map;
+    }
+}

+ 86 - 0
ureport2-console/src/main/java/com/bstek/ureport/console/util/UReportJdbcUtil.java

@@ -0,0 +1,86 @@
+package com.bstek.ureport.console.util;
+
+import com.google.common.collect.ImmutableMap;
+import jnpf.database.enums.DbAliasEnum;
+import jnpf.database.model.dbtable.DbTableFieldModel;
+import jnpf.database.model.dto.PrepSqlDTO;
+import jnpf.database.model.entity.DbLinkEntity;
+import jnpf.database.sql.enums.base.SqlComEnum;
+import jnpf.database.sql.util.SqlFastUtil;
+import jnpf.database.util.*;
+import jnpf.util.TenantHolder;
+import lombok.extern.slf4j.Slf4j;
+import net.sf.jsqlparser.JSQLParserException;
+import net.sf.jsqlparser.parser.CCJSqlParserUtil;
+import net.sf.jsqlparser.statement.select.Select;
+import org.springframework.beans.BeanUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+import java.sql.*;
+import java.util.*;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+import java.util.stream.Collectors;
+
+@Component
+@Slf4j
+public class UReportJdbcUtil {
+
+    private static DataSourceUtil dataSourceUtil;
+
+    @Autowired
+    public void setDataSourceUtil(DataSourceUtil dataSourceUtil) {
+        UReportJdbcUtil.dataSourceUtil = dataSourceUtil;
+    }
+
+    public static List<Map<String, String>> getDataTables(Connection conn, DbLinkEntity dbLinkEntity) throws Exception {
+        if(dbLinkEntity == null){
+            if(TenantDataSourceUtil.isTenantAssignDataSource()){
+                // 默认数据库, 租户管理指定租户数据源
+                dbLinkEntity = TenantDataSourceUtil.getTenantAssignDataSource(TenantHolder.getDatasourceId()).toDbLink(new DbLinkEntity());
+                dbLinkEntity.setId("0");
+            }else {
+                dbLinkEntity = new DbLinkEntity();
+                // 默认数据库查询,从配置获取数据源信息
+                BeanUtils.copyProperties(dataSourceUtil, dbLinkEntity);
+                dbLinkEntity.setId("0");
+                // 是系统默认的多租户
+                TenantDataSourceUtil.initDataSourceTenantDbName(dbLinkEntity);
+            }
+        }else{
+            dbLinkEntity.setDbSchema(ConnUtil.getConnectionSchema(conn));
+            dbLinkEntity.setDbName(ConnUtil.getConnectionDbName(conn));
+        }
+        PrepSqlDTO prepSqlDto = SqlComEnum.TABLES.getPrepSqlDto(dbLinkEntity, "");
+        prepSqlDto.withConn(conn);
+        NotTenantPluginHolder.setNotSwitchFlag();
+        List<DbTableFieldModel> dataList = JdbcUtil.queryCustomMods(prepSqlDto, DbTableFieldModel.class);
+        List<Map<String, String>> result = dataList.stream().map(o -> ImmutableMap.of("name", o.getTable(), "type", o.getType() ==0 ? "TABLE" : "VIEW")).collect(Collectors.toList());
+        return result;
+    }
+
+    private static final Pattern p = Pattern.compile("from[\\s]+([\\w\\.]+)");
+
+    public static void checkSqlSafe(String sql, Connection conn, DbLinkEntity dbLinkEntity) throws JSQLParserException {
+        sql = sql.toLowerCase();
+        if (!(CCJSqlParserUtil.parse(sql) instanceof Select)) {
+            throw new RuntimeException("只能使用查询语句");
+        }
+        List<Map<String, String>> tablesList = null;
+        try {
+            tablesList = getDataTables(conn, dbLinkEntity);
+        } catch (Exception throwables) {
+            throwables.printStackTrace();
+        }
+        Set<String> tables = tablesList.stream().map(k -> k.get("name").toLowerCase()).collect(Collectors.toSet());
+
+        Matcher m = p.matcher(sql);
+        while (m.find()) {
+            if (!tables.contains(m.group(1).toLowerCase())) {
+                throw new RuntimeException("非可查询表范围");
+            }
+        }
+    }
+
+}

+ 120 - 0
ureport2-console/src/main/java/com/bstek/ureport/console/word/ExportWordServletAction.java

@@ -0,0 +1,120 @@
+/*******************************************************************************
+ * Copyright 2017 Bstek
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License.  You may obtain a copy
+ * of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ ******************************************************************************/
+package com.bstek.ureport.console.word;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.net.URLEncoder;
+import java.sql.Connection;
+import java.util.Map;
+import java.util.UUID;
+
+import jakarta.servlet.ServletException;
+import jakarta.servlet.http.HttpServletRequest;
+import jakarta.servlet.http.HttpServletResponse;
+
+import jnpf.database.util.DynamicDataSourceUtil;
+import com.bstek.ureport.console.ureport.service.ReportService;
+import com.bstek.ureport.console.ureport.util.UreportWordUtil;
+import org.apache.commons.lang.StringUtils;
+
+import com.bstek.ureport.build.ReportBuilder;
+import com.bstek.ureport.console.BaseServletAction;
+import com.bstek.ureport.console.cache.TempObjectCache;
+import com.bstek.ureport.definition.ReportDefinition;
+import com.bstek.ureport.exception.ReportComputeException;
+import com.bstek.ureport.exception.ReportException;
+import com.bstek.ureport.export.ExportManager;
+import com.bstek.ureport.export.word.high.WordProducer;
+import com.bstek.ureport.model.Report;
+import org.apache.poi.xwpf.usermodel.XWPFDocument;
+import org.springframework.beans.factory.annotation.Autowired;
+
+/**
+ * 导出报表到Word
+ * @author
+ * @since 4月17日
+ */
+public class ExportWordServletAction extends BaseServletAction {
+    @Autowired
+    private ReportService reportService;
+
+    private ReportBuilder reportBuilder;
+    private ExportManager exportManager;
+    private WordProducer wordProducer = new WordProducer();
+
+    @Override
+    public void execute(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
+        String method = retriveMethod(req);
+        if (method != null) {
+            invokeMethod(method, req, resp);
+        } else {
+            buildWord(req, resp);
+        }
+    }
+
+    //临时预览时候的导出word
+    public void buildWord(HttpServletRequest req, HttpServletResponse resp) throws IOException {
+        String token = req.getParameter("token");
+        token = decode(token);
+        String id = req.getParameter("id");
+        id = decode(id);
+        if (StringUtils.isBlank(token) || StringUtils.isBlank(id)) {
+            throw new ReportComputeException("Report file can not be null.");
+        }
+        OutputStream outputStream = null;
+        try {
+            String fullName = null;
+            ReportDefinition reportDefinition = (ReportDefinition) TempObjectCache.getObject(id);
+            if (reportDefinition == null) {
+                reportDefinition = (ReportDefinition) TempObjectCache.getObject(token);
+                fullName = String.valueOf(UUID.randomUUID());
+            } else {
+                fullName = reportService.GetInfo(id).getFullName();
+            }
+            resp.setCharacterEncoding("UTF-8");
+            resp.setHeader("content-Type", "application/x-download");
+            resp.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(fullName + ".docx", "UTF-8"));
+            outputStream = resp.getOutputStream();
+            Map<String, Object> parameters =buildParameters(req);
+            Connection connection = DynamicDataSourceUtil.getCurrentConnection();
+            Report report = reportBuilder.buildReportToConnection(reportDefinition, parameters, connection);
+            UreportWordUtil ureportWordUtil = new UreportWordUtil();
+            XWPFDocument xwpfDocument = ureportWordUtil.build(report);
+            xwpfDocument.write(resp.getOutputStream());
+            xwpfDocument.close();
+        } catch (Exception ex) {
+            throw new ReportException(ex);
+        } finally {
+            outputStream.flush();
+            outputStream.close();
+        }
+    }
+
+    public void setReportBuilder(ReportBuilder reportBuilder) {
+        this.reportBuilder = reportBuilder;
+    }
+
+    public void setExportManager(ExportManager exportManager) {
+        this.exportManager = exportManager;
+    }
+
+    @Override
+    public String url() {
+        return "/word";
+    }
+
+}

+ 127 - 0
ureport2-console/src/main/resources/application.yml

@@ -0,0 +1,127 @@
+# 配置端口
+server:
+  port: 30007
+  compression:
+    enabled: true
+    min-response-size: 102400
+  max-http-request-header-size: 102400
+spring:
+  application:
+    # 应用名称
+    name: jnpf-datareport
+  exclude: com.alibaba.druid.spring.boot.autoconfigure.DruidDataSourceAutoConfigure #排除自动配置,手动配置druid
+  datasource:
+    #数据库类型(可选值 MySQL、SQLServer、Oracle、DM8、KingbaseES、PostgreSQL,请严格按可选值填写)
+    db-type: MySQL
+    host: usky-cloud-mysql
+    port: 3306
+    username: root
+    password: yt123456
+    db-name: jnpf_init
+    db-schema: #金仓达梦选填
+    prepare-url: #自定义url
+
+    # ===================== 动态多数据源 =====================
+    dynamic:
+      primary: master #设置默认的数据源或者数据源组,默认值即为master
+      strict: true #严格匹配数据源,默认false. true未匹配到指定数据源时抛异常,false使用默认数据源
+      druid:
+        # 空闲时执行连接测试
+        test-while-idle: true
+        # 连接测试最小间隔
+        time-between-eviction-runs-millis: 60000
+        # 获取连接等待3秒 根据网络情况设定
+        max-wait: 3000
+        # 初始化4个连接
+        initial-size: 4
+        # 最大20个连接
+        max-active: 20
+        # 最少保持4个空闲连接
+        min-idle: 4
+        # 空闲连接保活, 超过配置的空闲时间会进行连接检查完成保活操作(数据库自身会断开达到空闲时间的连接, 程序使用断开的连接会报错)
+        keep-alive: true
+        # 解除注释后Druid连接池打印SQL语句 忽略日志等级配置
+        #filters: slf4j
+        slf4j:
+          statementLogEnabled: true
+          resultSetLogEnabled: false
+          connectionLogEnabled: false
+          dataSourceLogEnabled: false
+          statementCreateAfterLogEnabled: false
+          statementCloseAfterLogEnabled: false
+          statementExecuteAfterLogEnabled: false
+          #打印SQL替换参数
+          statementExecutableSqlLogEnable: true
+          statementPrepareAfterLogEnabled: false
+          statementPrepareCallAfterLogEnabled: false
+          statementParameterSetLogEnabled: false
+
+  # ===================== Redis配置 =====================
+  # redis单机模式
+  data:
+    redis:
+      database: 1
+      host: usky-cloud-redis
+      port: 6379
+      password: 123456
+      timeout: 3000
+      lettuce: #Lettuce为Redis的Java驱动包
+        pool:
+          max-active: 8 # 连接池最大连接数
+          max-wait: -1ms  # 连接池最大阻塞等待时间(使用负值表示没有限制)
+          min-idle: 0 # 连接池中的最小空闲连接
+          max-idle: 8 # 连接池中的最大空闲连接
+
+# redis集群模式
+#  redis:
+#    cluster:
+#      nodes:
+#        - 192.168.0.225:6380
+#        - 192.168.0.225:6381
+#        - 192.168.0.225:6382
+#        - 192.168.0.225:6383
+#        - 192.168.0.225:6384
+#        - 192.168.0.225:6385
+#    password: 123456 # 密码为空时,请将本行注释
+#    timeout: 3000 # 超时时间(单位:秒)
+#    lettuce: #Lettuce为Redis的Java驱动包
+#      pool:
+#        max-active: 8 # 连接池最大连接数
+#        max-wait: -1ms  # 连接池最大阻塞等待时间(使用负值表示没有限制)
+#        min-idle: 0 # 连接池中的最小空闲连接
+#        max-idle: 8 # 连接池中的最大空闲连接
+
+# 日志配置
+logging:
+  config: classpath:logback-spring.xml
+  level:
+    #自定义第三方包名日志等级
+    com.bstek.ureport.console: debug
+    # 解除注释后Druid连接池打印SQL语句
+    druid.sql.Statement: debug
+#    druid.sql.DataSource: debug
+#    druid.sql.Connection: debug
+#    druid.sql.ResultSet: debug
+log:
+  level:
+    # 等级 TRACE,DEBUG,INFO,WARN,ERROR(不区分大小写)
+    root: ERROR
+  path: log/${spring.application.name}
+config:
+  #是否开启多租户
+  MultiTenancy: false
+  #数据库请求最长执行时间, 防止查询的报表数据过大导致内存溢出, -1不限制 单位:秒
+  queryTimeout: 5
+  #最大处理表格数据量
+  maxRows: 100000
+  #报表内引用的图片文件夹路径
+  imgPath:
+  #Column模式 租户字段
+  MultiTenantColumn: f_tenant_id
+  #用户接口地址
+  userUrl: http://127.0.0.1:30000/api/permission/Users/Current/ReportUserInfo
+
+
+security:
+  # AES加密秘钥
+  security-key: EY8WePvjM5GGwQzn

+ 327 - 0
ureport2-console/src/main/resources/logback-spring.xml

@@ -0,0 +1,327 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<configuration>
+
+    <!--日志格式应用spring boot默认的格式,也可以自己更改-->
+    <include resource="org/springframework/boot/logging/logback/defaults.xml"/>
+    <property name="FILE_LOG_PATTERN" value="[%d{yyyy-MM-dd HH:mm:ss.SSS}] [%-5level] [%thread] [%logger{50}] [%M] [%line] - %msg%n" />
+    <springProperty scope="context" name="SERVICE_NAME" source="spring.application.name" defaultValue="jnpf"/>
+
+    <!--定义日志存放的位置,默认存放在项目启动的相对路径的目录-->
+    <springProperty scope="context" name="LOG_PATH" source="log.path" defaultValue="log/${SERVICE_NAME}"/>
+    <!-- 全局日志等级 -->
+    <springProperty scope="context" name="LOG_LEVEL_ROOT" source="log.level.root" defaultValue="INFO"/>
+    <!-- 服务自定义等级 如需自定义服务日志等级 修改下方的【自定义服务名】与nacos上的log.level.自定义服务名=等级 -->
+    <springProperty scope="context" name="LOG_LEVEL" source="log.level.jnpf-datareport" defaultValue="${LOG_LEVEL_ROOT}"/>
+
+    <!-- 日志记录器,日期滚动记录,level为 ERROR 日志 -->
+    <appender name="FILE_ERROR" class="ch.qos.logback.core.rolling.RollingFileAppender">
+
+        <!-- 正在记录的日志文件的路径及文件名 -->
+        <file>${LOG_PATH}/log_error.log</file>
+
+        <!-- 日志记录器的滚动策略,按日期,按大小记录 -->
+        <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
+
+            <!-- 归档的日志文件的路径,%d{yyyy-MM-dd}指定日期格式,%i指定索引 -->
+            <fileNamePattern>${LOG_PATH}/error/%d{yyyy-MM-dd,aux}/log-error-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
+            <!--日志最大的历史7天-->
+            <maxHistory>7</maxHistory>
+
+            <!-- 除按日志记录之外,还配置了日志文件不能超过2M,若超过2M,日志文件会以索引0开始,
+            命名日志文件,例如log-error-2013-12-21.0.log -->
+            <maxFileSize>10MB</maxFileSize>
+        </rollingPolicy>
+
+        <!-- 追加方式记录日志 -->
+        <append>true</append>
+
+        <!-- 日志文件的格式 -->
+        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
+            <pattern>${FILE_LOG_PATTERN}</pattern>
+            <charset>utf-8</charset>
+        </encoder>
+
+        <!-- 此日志文件只记录error级别的 -->
+        <filter class="ch.qos.logback.classic.filter.LevelFilter">
+            <level>error</level>
+            <onMatch>ACCEPT</onMatch>
+            <onMismatch>DENY</onMismatch>
+        </filter>
+    </appender>
+
+
+    <!-- 日志记录器,日期滚动记录,level为 INFO 日志 -->
+    <appender name="FILE_INFO" class="ch.qos.logback.core.rolling.RollingFileAppender">
+
+        <!-- 正在记录的日志文件的路径及文件名 -->
+        <file>${LOG_PATH}/log_info.log</file>
+
+        <!-- 日志记录器的滚动策略,按日期,按大小记录 -->
+        <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
+
+            <!-- 归档的日志文件的路径,%d{yyyy-MM-dd}指定日期格式,%i指定索引 -->
+            <fileNamePattern>${LOG_PATH}/info/%d{yyyy-MM-dd,aux}/log-info-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
+            <!--日志最大的历史7天-->
+            <maxHistory>7</maxHistory>
+
+            <!-- 除按日志记录之外,还配置了日志文件不能超过2M,若超过2M,日志文件会以索引0开始,
+            命名日志文件,例如log-error-2013-12-21.0.log -->
+            <maxFileSize>10MB</maxFileSize>
+        </rollingPolicy>
+
+        <!-- 追加方式记录日志 -->
+        <append>true</append>
+
+        <!-- 日志文件的格式 -->
+        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
+            <pattern>${FILE_LOG_PATTERN}</pattern>
+            <charset>utf-8</charset>
+        </encoder>
+
+        <!-- 此日志文件只记录info级别的 -->
+        <filter class="ch.qos.logback.classic.filter.LevelFilter">
+            <level>info</level>
+            <onMatch>ACCEPT</onMatch>
+            <onMismatch>DENY</onMismatch>
+        </filter>
+    </appender>
+
+
+    <!-- 日志记录器,日期滚动记录,level为 WARN 日志 -->
+    <appender name="FILE_WARN" class="ch.qos.logback.core.rolling.RollingFileAppender">
+
+        <!-- 正在记录的日志文件的路径及文件名 -->
+        <file>${LOG_PATH}/log_warn.log</file>
+
+        <!-- 日志记录器的滚动策略,按日期,按大小记录 -->
+        <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
+
+            <!-- 归档的日志文件的路径,%d{yyyy-MM-dd}指定日期格式,%i指定索引 -->
+            <fileNamePattern>${LOG_PATH}/warn/%d{yyyy-MM-dd,aux}/log-warn-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
+            <!--日志最大的历史7天-->
+            <maxHistory>7</maxHistory>
+
+            <!-- 除按日志记录之外,还配置了日志文件不能超过2M,若超过2M,日志文件会以索引0开始,
+            命名日志文件,例如log-error-2013-12-21.0.log -->
+            <maxFileSize>10MB</maxFileSize>
+        </rollingPolicy>
+
+        <!-- 追加方式记录日志 -->
+        <append>true</append>
+
+        <!-- 日志文件的格式 -->
+        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
+            <pattern>${FILE_LOG_PATTERN}</pattern>
+            <charset>utf-8</charset>
+        </encoder>
+
+        <!-- 此日志文件只记录warn级别的 -->
+        <filter class="ch.qos.logback.classic.filter.LevelFilter">
+            <level>warn</level>
+            <onMatch>ACCEPT</onMatch>
+            <onMismatch>DENY</onMismatch>
+        </filter>
+    </appender>
+
+    <!-- 日志记录器,日期滚动记录,level为 DEBUG 日志 -->
+    <appender name="FILE_DEBUG" class="ch.qos.logback.core.rolling.RollingFileAppender">
+
+        <!-- 正在记录的日志文件的路径及文件名 -->
+        <file>${LOG_PATH}/log_debug.log</file>
+
+        <!-- 日志记录器的滚动策略,按日期,按大小记录 -->
+        <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
+
+            <!-- 归档的日志文件的路径,%d{yyyy-MM-dd}指定日期格式,%i指定索引 -->
+            <fileNamePattern>${LOG_PATH}/debug/%d{yyyy-MM-dd,aux}/log-debug-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
+            <!--日志最大的历史7天-->
+            <maxHistory>7</maxHistory>
+
+            <!-- 除按日志记录之外,还配置了日志文件不能超过2M,若超过2M,日志文件会以索引0开始,
+            命名日志文件,例如log-error-2013-12-21.0.log -->
+            <maxFileSize>10MB</maxFileSize>
+        </rollingPolicy>
+
+        <!-- 追加方式记录日志 -->
+        <append>true</append>
+
+        <!-- 日志文件的格式 -->
+        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
+            <pattern>${FILE_LOG_PATTERN}</pattern>
+            <charset>utf-8</charset>
+        </encoder>
+
+        <!-- 此日志文件只记录debug级别的 -->
+        <filter class="ch.qos.logback.classic.filter.LevelFilter">
+            <level>debug</level>
+            <onMatch>ACCEPT</onMatch>
+            <onMismatch>DENY</onMismatch>
+        </filter>
+    </appender>
+
+
+    <!-- 日志记录器,日期滚动记录,所有日志 -->
+    <appender name="FILE_ALL" class="ch.qos.logback.core.rolling.RollingFileAppender">
+
+        <!-- 正在记录的日志文件的路径及文件名 -->
+        <file>${LOG_PATH}/log_total.log</file>
+
+        <!-- 日志记录器的滚动策略,按日期,按大小记录 -->
+        <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
+
+            <!-- 归档的日志文件的路径,%d{yyyy-MM-dd}指定日期格式,%i指定索引 -->
+            <fileNamePattern>${LOG_PATH}/total/%d{yyyy-MM-dd,aux}/log-total-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
+            <!--日志最大的历史7天-->
+            <maxHistory>7</maxHistory>
+
+            <!-- 除按日志记录之外,还配置了日志文件不能超过2M,若超过2M,日志文件会以索引0开始,
+            命名日志文件,例如log-error-2013-12-21.0.log -->
+            <maxFileSize>10MB</maxFileSize>
+        </rollingPolicy>
+
+        <!-- 追加方式记录日志 -->
+        <append>true</append>
+
+        <!-- 日志文件的格式 -->
+        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
+            <pattern>${FILE_LOG_PATTERN}</pattern>
+            <charset>utf-8</charset>
+        </encoder>
+    </appender>
+
+
+    <!-- 日志记录器,日期滚动记录,level 根据配置动态输出日志 -->
+    <appender name="FILE_RELEASE" class="ch.qos.logback.core.rolling.RollingFileAppender">
+
+        <!-- 正在记录的日志文件的路径及文件名 -->
+        <file>${LOG_PATH}/log_release.log</file>
+
+        <!-- 日志记录器的滚动策略,按日期,按大小记录 -->
+        <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
+
+            <!-- 归档的日志文件的路径,%d{yyyy-MM-dd}指定日期格式,%i指定索引 -->
+            <fileNamePattern>${LOG_PATH}/release/%d{yyyy-MM-dd,aux}/log-warn-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
+            <!--日志最大的历史7天-->
+            <maxHistory>7</maxHistory>
+
+            <!-- 除按日志记录之外,还配置了日志文件不能超过2M,若超过2M,日志文件会以索引0开始,
+            命名日志文件,例如log-error-2013-12-21.0.log -->
+            <maxFileSize>10MB</maxFileSize>
+        </rollingPolicy>
+
+        <!-- 追加方式记录日志 -->
+        <append>true</append>
+
+        <!-- 日志文件的格式 -->
+        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
+            <pattern>${FILE_LOG_PATTERN}</pattern>
+            <charset>utf-8</charset>
+        </encoder>
+
+        <!-- 此日志文件只记录warn级别的 -->
+        <filter class="ch.qos.logback.classic.filter.LevelFilter">
+            <level>${LOG_LEVEL}</level>
+            <onMatch>ACCEPT</onMatch>
+            <onMismatch>DENY</onMismatch>
+        </filter>
+    </appender>
+    <!-- 异步输出 DEBUG -->
+    <appender name="ASYNC_FILE_DEBUG" class="ch.qos.logback.classic.AsyncAppender">
+        <discardingThreshold>0</discardingThreshold>
+        <queueSize>256</queueSize>
+        <appender-ref ref="FILE_DEBUG"/>
+    </appender>
+    <!-- 异步输出 INFO -->
+    <appender name="ASYNC_FILE_INFO" class="ch.qos.logback.classic.AsyncAppender">
+        <discardingThreshold>0</discardingThreshold>
+        <queueSize>256</queueSize>
+        <appender-ref ref="FILE_INFO"/>
+    </appender>
+    <!-- 异步输出 WARN -->
+    <appender name="ASYNC_FILE_WARN" class="ch.qos.logback.classic.AsyncAppender">
+        <discardingThreshold>0</discardingThreshold>
+        <queueSize>256</queueSize>
+        <appender-ref ref="FILE_WARN"/>
+    </appender>
+    <!-- 异步输出 ERROR -->
+    <appender name="ASYNC_FILE_ERROR" class="ch.qos.logback.classic.AsyncAppender">
+        <discardingThreshold>0</discardingThreshold>
+        <queueSize>256</queueSize>
+        <appender-ref ref="FILE_ERROR"/>
+    </appender>
+    <!-- 异步输出 ALL -->
+    <appender name="ASYNC_FILE_ALL" class="ch.qos.logback.classic.AsyncAppender">
+        <discardingThreshold>0</discardingThreshold>
+        <queueSize>256</queueSize>
+        <appender-ref ref="FILE_ALL"/>
+    </appender>
+
+
+    <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
+        <encoder>
+            <pattern>${CONSOLE_LOG_PATTERN}</pattern>
+            <charset>utf-8</charset>
+        </encoder>
+    </appender>
+
+
+    <!-- 异步输出 控制台 -->
+    <appender name="ASYNC_STDOUT" class="ch.qos.logback.classic.AsyncAppender">
+        <discardingThreshold>0</discardingThreshold>
+        <queueSize>256</queueSize>
+        <appender-ref ref="STDOUT"/>
+    </appender>
+
+
+    <!--<appender name="LOGSTASH" class="net.logstash.logback.appender.LogstashTcpSocketAppender">
+        &lt;!&ndash; 必填:目标:LogStash的 IP:Port &ndash;&gt;
+        <destination>192.168.0.50:50000</destination>
+        &lt;!&ndash; 可选:保持程序存活时间 &ndash;&gt;
+        <keepAliveDuration>5 minutes</keepAliveDuration>
+        &lt;!&ndash; 可选:重连延迟时长 &ndash;&gt;
+        <reconnectionDelay>10 second</reconnectionDelay>
+        &lt;!&ndash; 可选:等待策略 &ndash;&gt;
+        <waitStrategyType>sleeping</waitStrategyType>
+        &lt;!&ndash;  ============ encoder必须配置,有多种可选 ============= &ndash;&gt;
+        &lt;!&ndash; 编码器二:LoggingEventCompositeJsonEncoder &ndash;&gt;
+        <encoder charset="UTF-8" class="net.logstash.logback.encoder.LoggingEventCompositeJsonEncoder">
+            <providers>
+                &lt;!&ndash; 时间戳:时区 &ndash;&gt;
+                <timestamp>
+                    <timeZone>UTC</timeZone>
+                </timestamp>
+                &lt;!&ndash; 模式 &ndash;&gt;
+                <pattern>
+                    <pattern>
+                        {
+                        "severity": "%level",
+                        "service": "${SERVICE_NAME:-}",
+                        "trace": "%X{X-B3-TraceId:-}",
+                        "span": "%X{X-B3-SpanId:-}",
+                        "exportable": "%X{X-Span-Export:-}",
+                        "pid": "${PID:-}",
+                        "thread": "%thread",
+                        "class": "%logger{40}",
+                        "msg": "%message"
+                        &lt;!&ndash;"idx_pre": "elk-original-third-access",&ndash;&gt;
+                        &lt;!&ndash;"json": "#asJson{%message}"  这个asJson可以把对应的字符串作为json对象取出来,这样es可以对json里面的字段索引了&ndash;&gt;
+                        }
+                    </pattern>
+                </pattern>
+            </providers>
+        </encoder>
+    </appender>-->
+
+
+    <root level="${LOG_LEVEL}">
+        <appender-ref ref="ASYNC_STDOUT"/>
+        <appender-ref ref="ASYNC_FILE_ERROR"/>
+        <appender-ref ref="ASYNC_FILE_INFO"/>
+        <appender-ref ref="ASYNC_FILE_WARN"/>
+        <appender-ref ref="ASYNC_FILE_DEBUG"/>
+        <appender-ref ref="ASYNC_FILE_ALL"/>
+        <!--<appender-ref ref="LOGSTASH"/>-->
+    </root>
+
+
+</configuration>

+ 7 - 0
ureport2-console/src/main/resources/mapper/ReportMapper.xml

@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="com.bstek.ureport.console.ureport.mapper.ReportMapper">
+
+
+
+</mapper>

+ 7 - 0
ureport2-console/src/main/resources/mapper/SystemMapper.xml

@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="com.bstek.ureport.console.ureport.mapper">
+
+
+
+</mapper>

+ 7 - 0
ureport2-console/src/main/resources/mapper/UserMapper.xml

@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="com.bstek.ureport.console.ureport.mapper.UserMapper">
+
+
+
+</mapper>

+ 169 - 0
ureport2-console/src/main/resources/template/template.ureport.xml

@@ -0,0 +1,169 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ureport xmlns="http://www.example.org/ureport2" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+	xsi:schemaLocation="http://www.example.org/ureport2 http://www.example.org/ureport2 ">
+	<cell expand="None" name="A1" col="1" row="1">
+		<simple-value><![CDATA[]]></simple-value>
+		<cell-style font-size="10" align="center" valign="middle"></cell-style>
+	</cell>
+	<cell expand="None" name="B1" col="2" row="1">
+		<simple-value><![CDATA[]]></simple-value>
+		<cell-style font-size="10" align="center" valign="middle"></cell-style>
+	</cell>
+	<cell expand="None" name="C1" col="3" row="1">
+		<simple-value><![CDATA[]]></simple-value>
+		<cell-style font-size="10" align="center" valign="middle"></cell-style>
+	</cell>
+	<cell expand="None" name="D1" col="4" row="1">
+		<simple-value><![CDATA[]]></simple-value>
+		<cell-style font-size="10" align="center" valign="middle"></cell-style>
+	</cell>
+	<cell expand="None" name="E1" col="5" row="1">
+		<simple-value><![CDATA[]]></simple-value>
+		<cell-style font-size="10" align="center" valign="middle"></cell-style>
+	</cell>
+	<cell expand="None" name="F1" col="6" row="1">
+		<simple-value><![CDATA[]]></simple-value>
+		<cell-style font-size="10" align="center" valign="middle"></cell-style>
+	</cell>
+
+	<cell expand="None" name="A2" col="1" row="2">
+		<simple-value><![CDATA[]]></simple-value>
+		<cell-style font-size="10" align="center" valign="middle"></cell-style>
+	</cell>
+	<cell expand="None" name="B2" col="2" row="2">
+		<simple-value><![CDATA[]]></simple-value>
+		<cell-style font-size="10" align="center" valign="middle"></cell-style>
+	</cell>
+	<cell expand="None" name="C2" col="3" row="2">
+		<simple-value><![CDATA[]]></simple-value>
+		<cell-style font-size="10" align="center" valign="middle"></cell-style>
+	</cell>
+	<cell expand="None" name="D2" col="4" row="2">
+		<simple-value><![CDATA[]]></simple-value>
+		<cell-style font-size="10" align="center" valign="middle"></cell-style>
+	</cell>
+	<cell expand="None" name="E2" col="5" row="2">
+		<simple-value><![CDATA[]]></simple-value>
+		<cell-style font-size="10" align="center" valign="middle"></cell-style>
+	</cell>
+	<cell expand="None" name="F2" col="6" row="2">
+		<simple-value><![CDATA[]]></simple-value>
+		<cell-style font-size="10" align="center" valign="middle"></cell-style>
+	</cell>
+
+	<cell expand="None" name="A3" col="1" row="3">
+		<simple-value><![CDATA[]]></simple-value>
+		<cell-style font-size="10" align="center" valign="middle"></cell-style>
+	</cell>
+	<cell expand="None" name="B3" col="2" row="3">
+		<simple-value><![CDATA[]]></simple-value>
+		<cell-style font-size="10" align="center" valign="middle"></cell-style>
+	</cell>
+	<cell expand="None" name="C3" col="3" row="3">
+		<simple-value><![CDATA[]]></simple-value>
+		<cell-style font-size="10" align="center" valign="middle"></cell-style>
+	</cell>
+	<cell expand="None" name="D3" col="4" row="3">
+		<simple-value><![CDATA[]]></simple-value>
+		<cell-style font-size="10" align="center" valign="middle"></cell-style>
+	</cell>
+	<cell expand="None" name="E3" col="5" row="3">
+		<simple-value><![CDATA[]]></simple-value>
+		<cell-style font-size="10" align="center" valign="middle"></cell-style>
+	</cell>
+	<cell expand="None" name="F3" col="6" row="3">
+		<simple-value><![CDATA[]]></simple-value>
+		<cell-style font-size="10" align="center" valign="middle"></cell-style>
+	</cell>
+
+	<cell expand="None" name="A4" col="1" row="4">
+		<simple-value><![CDATA[]]></simple-value>
+		<cell-style font-size="10" align="center" valign="middle"></cell-style>
+	</cell>
+	<cell expand="None" name="B4" col="2" row="4">
+		<simple-value><![CDATA[]]></simple-value>
+		<cell-style font-size="10" align="center" valign="middle"></cell-style>
+	</cell>
+	<cell expand="None" name="C4" col="3" row="4">
+		<simple-value><![CDATA[]]></simple-value>
+		<cell-style font-size="10" align="center" valign="middle"></cell-style>
+	</cell>
+	<cell expand="None" name="D4" col="4" row="4">
+		<simple-value><![CDATA[]]></simple-value>
+		<cell-style font-size="10" align="center" valign="middle"></cell-style>
+	</cell>
+	<cell expand="None" name="E4" col="5" row="4">
+		<simple-value><![CDATA[]]></simple-value>
+		<cell-style font-size="10" align="center" valign="middle"></cell-style>
+	</cell>
+	<cell expand="None" name="F4" col="6" row="4">
+		<simple-value><![CDATA[]]></simple-value>
+		<cell-style font-size="10" align="center" valign="middle"></cell-style>
+	</cell>
+
+	<cell expand="None" name="A5" col="1" row="5">
+		<simple-value><![CDATA[]]></simple-value>
+		<cell-style font-size="10" align="center" valign="middle"></cell-style>
+	</cell>
+	<cell expand="None" name="B5" col="2" row="5">
+		<simple-value><![CDATA[]]></simple-value>
+		<cell-style font-size="10" align="center" valign="middle"></cell-style>
+	</cell>
+	<cell expand="None" name="C5" col="3" row="5">
+		<simple-value><![CDATA[]]></simple-value>
+		<cell-style font-size="10" align="center" valign="middle"></cell-style>
+	</cell>
+	<cell expand="None" name="D5" col="4" row="5">
+		<simple-value><![CDATA[]]></simple-value>
+		<cell-style font-size="10" align="center" valign="middle"></cell-style>
+	</cell>
+	<cell expand="None" name="E5" col="5" row="5">
+		<simple-value><![CDATA[]]></simple-value>
+		<cell-style font-size="10" align="center" valign="middle"></cell-style>
+	</cell>
+	<cell expand="None" name="F5" col="6" row="5">
+		<simple-value><![CDATA[]]></simple-value>
+		<cell-style font-size="10" align="center" valign="middle"></cell-style>
+	</cell>
+
+	<cell expand="None" name="A6" col="1" row="6">
+		<simple-value><![CDATA[]]></simple-value>
+		<cell-style font-size="10" align="center" valign="middle"></cell-style>
+	</cell>
+	<cell expand="None" name="B6" col="2" row="6">
+		<simple-value><![CDATA[]]></simple-value>
+		<cell-style font-size="10" align="center" valign="middle"></cell-style>
+	</cell>
+	<cell expand="None" name="C6" col="3" row="6">
+		<simple-value><![CDATA[]]></simple-value>
+		<cell-style font-size="10" align="center" valign="middle"></cell-style>
+	</cell>
+	<cell expand="None" name="D6" col="4" row="6">
+		<simple-value><![CDATA[]]></simple-value>
+		<cell-style font-size="10" align="center" valign="middle"></cell-style>
+	</cell>
+	<cell expand="None" name="E6" col="5" row="6">
+		<simple-value><![CDATA[]]></simple-value>
+		<cell-style font-size="10" align="center" valign="middle"></cell-style>
+	</cell>
+	<cell expand="None" name="F6" col="6" row="6">
+		<simple-value><![CDATA[]]></simple-value>
+		<cell-style font-size="10" align="center" valign="middle"></cell-style>
+	</cell>
+
+	<row row-number="1" height="18"/>
+	<row row-number="2" height="18"/>
+	<row row-number="3" height="18"/>
+	<row row-number="4" height="18"/>
+	<row row-number="5" height="18"/>
+	<row row-number="6" height="18"/>
+
+	<column col-number="1" width="80"/>
+	<column col-number="2" width="80"/>
+	<column col-number="3" width="80"/>
+	<column col-number="4" width="80"/>
+	<column col-number="5" width="80"/>
+	<column col-number="6" width="80"/>
+
+	<paper type="A4" orientation="portrait" paging-mode="fitpage"></paper>
+</ureport>

+ 53 - 0
ureport2-console/src/main/resources/ureport-console-context.xml

@@ -0,0 +1,53 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<beans xmlns="http://www.springframework.org/schema/beans"
+	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
+	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
+		http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd
+	">
+	<import resource="classpath:ureport-core-context.xml"/>
+	<import resource="classpath:ureport-font-context.xml"/>
+	
+	<bean id="ureport.datasourceServletAction" class="com.bstek.ureport.console.designer.DatasourceServletAction"></bean>
+	<bean id="ureport.resourceLoaderServletAction" class="com.bstek.ureport.console.res.ResourceLoaderServletAction"></bean>
+	<bean id="ureport.designerServletAction" class="com.bstek.ureport.console.designer.DesignerServletAction">
+		<property name="reportRender" ref="ureport.reportRender"></property>
+		<property name="reportParser" ref="ureport.reportParser"></property>
+	</bean>
+	
+	<bean id="ureport.searchFormDesignerAction" class="com.bstek.ureport.console.designer.SearchFormDesignerAction"></bean>
+	
+	<bean id="ureport.htmlPreviewServletAction" class="com.bstek.ureport.console.html.HtmlPreviewServletAction">
+		<property name="exportManager" ref="ureport.exportManager"></property>
+		<property name="reportBuilder" ref="ureport.reportBuilder"></property>
+		<property name="reportRender" ref="ureport.reportRender"></property>
+	</bean>
+	<bean id="ureport.exportWordServletAction" class="com.bstek.ureport.console.word.ExportWordServletAction">
+		<property name="exportManager" ref="ureport.exportManager"></property>
+		<property name="reportBuilder" ref="ureport.reportBuilder"></property>
+	</bean>
+	
+	<bean id="ureport.exportPdfServletAction" class="com.bstek.ureport.console.pdf.ExportPdfServletAction">
+		<property name="exportManager" ref="ureport.exportManager"></property>
+		<property name="reportBuilder" ref="ureport.reportBuilder"></property>
+		<property name="reportRender" ref="ureport.reportRender"></property>
+	</bean>
+	
+	<bean id="ureport.exportExcelServletAction" class="com.bstek.ureport.console.excel.ExportExcelServletAction">
+		<property name="exportManager" ref="ureport.exportManager"></property>
+		<property name="reportBuilder" ref="ureport.reportBuilder"></property>
+	</bean>
+	
+	<bean id="ureport.exportExcel97ServletAction" class="com.bstek.ureport.console.excel.ExportExcel97ServletAction">
+		<property name="exportManager" ref="ureport.exportManager"></property>
+		<property name="reportBuilder" ref="ureport.reportBuilder"></property>
+	</bean>
+	
+	<bean id="ureport.imageServletAction" class="com.bstek.ureport.console.image.ImageServletAction"></bean>
+	<bean id="ureport.importExcelServletAction" class="com.bstek.ureport.console.importexcel.ImportExcelServletAction"></bean>
+	
+	<bean id="ureport.chartServletAction" class="com.bstek.ureport.console.chart.ChartServletAction"></bean>
+	
+	<bean id="ureport.httpSessionReportCache" class="com.bstek.ureport.console.cache.HttpSessionReportCache">
+		<property name="disabled" value="${ureport.disableHttpSessionReportCache}"></property>
+	</bean>
+</beans>

+ 179 - 0
ureport2-console/src/main/resources/ureport.xml

@@ -0,0 +1,179 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<beans xmlns="http://www.springframework.org/schema/beans"
+       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
+       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
+        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd
+    ">
+
+    <!-- core -->
+    <bean id="ureport.props" class="com.bstek.ureport.UReportPropertyPlaceholderConfigurer" abstract="true">
+        <property name="ignoreUnresolvablePlaceholders" value="true"></property>
+    </bean>
+
+    <bean id="ureport.propertyPlaceholderConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
+        <property name="location" value="classpath:ureport.properties"></property>
+        <property name="ignoreUnresolvablePlaceholders" value="true"></property>
+    </bean>
+
+    <bean id="ureport.exportManager" class="com.bstek.ureport.export.ExportManagerImpl">
+        <property name="reportRender" ref="ureport.reportRender"></property>
+    </bean>
+
+    <bean id="ureport.reportRender" class="com.bstek.ureport.export.ReportRender">
+        <property name="reportParser" ref="ureport.reportParser"></property>
+        <property name="reportBuilder" ref="ureport.reportBuilder"></property>
+    </bean>
+
+    <bean id="ureport.defaultImageProvider" class="com.bstek.ureport.provider.image.DefaultImageProvider"></bean>
+
+    <!-- 配置保存文件的路径 -->
+    <bean id="ureport.fileReportProvider" class="com.bstek.ureport.provider.report.file.FileReportProvider">
+        <property name="fileStoreDir" value="D:\\ureports"></property>
+        <property name="disabled" value="false"></property>
+    </bean>
+
+    <bean id="ureport.httpImageProvider" class="com.bstek.ureport.provider.image.HttpImageProvider"></bean>
+    <bean id="ureport.httpsImageProvider" class="com.bstek.ureport.provider.image.HttpsImageProvider"></bean>
+
+    <bean id="ureport.reportBuilder" class="com.bstek.ureport.build.ReportBuilder">
+        <property name="hideRowColumnBuilder" ref="ureport.hideRowColumnBuilder"></property>
+    </bean>
+
+    <bean id="ureport.hideRowColumnBuilder" class="com.bstek.ureport.build.HideRowColumnBuilder"></bean>
+
+    <bean id="ureport.reportParser" class="com.bstek.ureport.parser.ReportParser"></bean>
+
+    <bean id="ureport.formParserUtils" class="com.bstek.ureport.parser.impl.searchform.FormParserUtils"></bean>
+    <bean id="ureport.checkboxParser" class="com.bstek.ureport.parser.impl.searchform.CheckboxParser"></bean>
+    <bean id="ureport.gridParser" class="com.bstek.ureport.parser.impl.searchform.GridParser"></bean>
+    <bean id="ureport.radioInputParser" class="com.bstek.ureport.parser.impl.searchform.RadioInputParser"></bean>
+    <bean id="ureport.rextInputParser" class="com.bstek.ureport.parser.impl.searchform.TextInputParser"></bean>
+    <bean id="ureport.resetButtonParser" class="com.bstek.ureport.parser.impl.searchform.ResetButtonParser"></bean>
+    <bean id="ureport.submitButtonParser" class="com.bstek.ureport.parser.impl.searchform.SubmitButtonParser"></bean>
+    <bean id="ureport.selectInputParser" class="com.bstek.ureport.parser.impl.searchform.SelectInputParser"></bean>
+    <bean id="ureport.datetimeInputParser" class="com.bstek.ureport.parser.impl.searchform.DatetimeInputParser"></bean>
+
+    <bean id="ureport.classpathReportProvider" class="com.bstek.ureport.provider.report.classpath.ClasspathReportProvider"></bean>
+
+    <bean id="ureport.fontBuilder" class="com.bstek.ureport.export.pdf.font.FontBuilder"></bean>
+
+    <bean id="ureport.expressionUtils" class="com.bstek.ureport.expression.ExpressionUtils"></bean>
+    <bean id="ureport.utils" class="com.bstek.ureport.Utils">
+        <property name="debug" value="true"></property>
+    </bean>
+    <bean id="ureport.cacheUtils" class="com.bstek.ureport.cache.CacheUtils"></bean>
+
+    <bean id="ureport.countFunction" class="com.bstek.ureport.expression.function.CountFunction"></bean>
+    <bean id="ureport.sumFunction" class="com.bstek.ureport.expression.function.SumFunction"></bean>
+    <bean id="ureport.maxFunction" class="com.bstek.ureport.expression.function.MaxFunction"></bean>
+    <bean id="ureport.minFunction" class="com.bstek.ureport.expression.function.MinFunction"></bean>
+    <bean id="ureport.listFunction" class="com.bstek.ureport.expression.function.ListFunction"></bean>
+    <bean id="ureport.avgFunction" class="com.bstek.ureport.expression.function.AvgFunction"></bean>
+    <bean id="ureport.orderFunction" class="com.bstek.ureport.expression.function.OrderFunction"></bean>
+    <bean id="ureport.WeekFunction" class="com.bstek.ureport.expression.function.date.WeekFunction"></bean>
+    <bean id="ureport.dayFunction" class="com.bstek.ureport.expression.function.date.DayFunction"></bean>
+    <bean id="ureport.monthFunction" class="com.bstek.ureport.expression.function.date.MonthFunction"></bean>
+    <bean id="ureport.yearFunction" class="com.bstek.ureport.expression.function.date.YearFunction"></bean>
+    <bean id="ureport.dateFunction" class="com.bstek.ureport.expression.function.date.DateFunction"></bean>
+    <bean id="ureport.formatNumberFunction" class="com.bstek.ureport.expression.function.FormatNumberFunction"></bean>
+    <bean id="ureport.formatDateFunction" class="com.bstek.ureport.expression.function.FormatDateFunction"></bean>
+    <bean id="ureport.getFunction" class="com.bstek.ureport.expression.function.GetFunction"></bean>
+
+    <bean id="ureport.absFunction" class="com.bstek.ureport.expression.function.math.AbsFunction"></bean>
+    <bean id="ureport.ceilFunction" class="com.bstek.ureport.expression.function.math.CeilFunction"></bean>
+    <bean id="ureport.ChnFunction" class="com.bstek.ureport.expression.function.math.ChnFunction"></bean>
+    <bean id="ureport.ChnMoneyFunction" class="com.bstek.ureport.expression.function.math.ChnMoneyFunction"></bean>
+    <bean id="ureport.CosFunction" class="com.bstek.ureport.expression.function.math.CosFunction"></bean>
+    <bean id="ureport.ExpFunction" class="com.bstek.ureport.expression.function.math.ExpFunction"></bean>
+    <bean id="ureport.floorFunction" class="com.bstek.ureport.expression.function.math.FloorFunction"></bean>
+    <bean id="ureport.log10Function" class="com.bstek.ureport.expression.function.math.Log10Function"></bean>
+    <bean id="ureport.logFunction" class="com.bstek.ureport.expression.function.math.LogFunction"></bean>
+    <bean id="ureport.powFunction" class="com.bstek.ureport.expression.function.math.PowFunction"></bean>
+    <bean id="ureport.randomFunction" class="com.bstek.ureport.expression.function.math.RandomFunction"></bean>
+    <bean id="ureport.roundFunction" class="com.bstek.ureport.expression.function.math.RoundFunction"></bean>
+    <bean id="ureport.sinFunction" class="com.bstek.ureport.expression.function.math.SinFunction"></bean>
+    <bean id="ureport.sqrtFunction" class="com.bstek.ureport.expression.function.math.SqrtFunction"></bean>
+    <bean id="ureport.tanFunction" class="com.bstek.ureport.expression.function.math.TanFunction"></bean>
+    <bean id="ureport.stdevpFunction" class="com.bstek.ureport.expression.function.math.StdevpFunction"></bean>
+    <bean id="ureport.varaFunction" class="com.bstek.ureport.expression.function.math.VaraFunction"></bean>
+    <bean id="ureport.modeFunction" class="com.bstek.ureport.expression.function.math.ModeFunction"></bean>
+    <bean id="ureport.medianFunction" class="com.bstek.ureport.expression.function.math.MedianFunction"></bean>
+
+
+    <bean id="ureport.lengthFunction" class="com.bstek.ureport.expression.function.string.LengthFunction"></bean>
+    <bean id="ureport.lowerFunction" class="com.bstek.ureport.expression.function.string.LowerFunction"></bean>
+    <bean id="ureport.IndexOfFunction" class="com.bstek.ureport.expression.function.string.IndexOfFunction"></bean>
+    <bean id="ureport.replaceFunction" class="com.bstek.ureport.expression.function.string.ReplaceFunction"></bean>
+    <bean id="ureport.substringFunction" class="com.bstek.ureport.expression.function.string.SubstringFunction"></bean>
+    <bean id="ureport.trimFunction" class="com.bstek.ureport.expression.function.string.TrimFunction"></bean>
+    <bean id="ureport.upperFunction" class="com.bstek.ureport.expression.function.string.UpperFunction"></bean>
+
+    <bean id="ureport.pageTotalFunction" class="com.bstek.ureport.expression.function.page.PageTotalFunction"></bean>
+    <bean id="ureport.pageNumberFunction" class="com.bstek.ureport.expression.function.page.PageNumberFunction"></bean>
+    <bean id="ureport.pageAvgFunction" class="com.bstek.ureport.expression.function.page.PageAvgFunction"></bean>
+    <bean id="ureport.pageCountFunction" class="com.bstek.ureport.expression.function.page.PageCountFunction"></bean>
+    <bean id="ureport.pageMaxFunction" class="com.bstek.ureport.expression.function.page.PageMaxFunction"></bean>
+    <bean id="ureport.pageMinFunction" class="com.bstek.ureport.expression.function.page.PageMinFunction"></bean>
+    <bean id="ureport.pageRowsFunction" class="com.bstek.ureport.expression.function.page.PageRowsFunction"></bean>
+    <bean id="ureport.pageSumFunction" class="com.bstek.ureport.expression.function.page.PageSumFunction"></bean>
+
+    <bean id="ureport.parameterFunction" class="com.bstek.ureport.expression.function.ParameterFunction"></bean>
+    <bean id="ureport.parameterIsEmptyFunction" class="com.bstek.ureport.expression.function.ParameterIsEmptyFunction"></bean>
+    <bean id="ureport.jsonFunction" class="com.bstek.ureport.expression.function.JsonFunction"></bean>
+
+    <bean id="ureport.rowFunction" class="com.bstek.ureport.expression.function.RowFunction"></bean>
+    <bean id="ureport.columnFunction" class="com.bstek.ureport.expression.function.ColumnFunction"></bean>
+
+    <!-- console -->
+    <bean id="ureport.datasourceServletAction" class="com.bstek.ureport.console.designer.DatasourceServletAction"></bean>
+    <bean id="ureport.resourceLoaderServletAction" class="com.bstek.ureport.console.res.ResourceLoaderServletAction"></bean>
+    <bean id="ureport.designerServletAction" class="com.bstek.ureport.console.designer.DesignerServletAction">
+        <property name="reportRender" ref="ureport.reportRender"></property>
+        <property name="reportParser" ref="ureport.reportParser"></property>
+    </bean>
+
+    <bean id="ureport.searchFormDesignerAction" class="com.bstek.ureport.console.designer.SearchFormDesignerAction"></bean>
+
+    <bean id="ureport.htmlPreviewServletAction" class="com.bstek.ureport.console.html.HtmlPreviewServletAction">
+        <property name="exportManager" ref="ureport.exportManager"></property>
+        <property name="reportBuilder" ref="ureport.reportBuilder"></property>
+        <property name="reportRender" ref="ureport.reportRender"></property>
+    </bean>
+    <bean id="ureport.exportWordServletAction" class="com.bstek.ureport.console.word.ExportWordServletAction">
+        <property name="exportManager" ref="ureport.exportManager"></property>
+        <property name="reportBuilder" ref="ureport.reportBuilder"></property>
+    </bean>
+
+    <bean id="ureport.exportPdfServletAction" class="com.bstek.ureport.console.pdf.ExportPdfServletAction">
+        <property name="exportManager" ref="ureport.exportManager"></property>
+        <property name="reportBuilder" ref="ureport.reportBuilder"></property>
+        <property name="reportRender" ref="ureport.reportRender"></property>
+    </bean>
+
+    <bean id="ureport.exportExcelServletAction" class="com.bstek.ureport.console.excel.ExportExcelServletAction">
+        <property name="exportManager" ref="ureport.exportManager"></property>
+        <property name="reportBuilder" ref="ureport.reportBuilder"></property>
+    </bean>
+
+    <bean id="ureport.exportExcel97ServletAction" class="com.bstek.ureport.console.excel.ExportExcel97ServletAction">
+        <property name="exportManager" ref="ureport.exportManager"></property>
+        <property name="reportBuilder" ref="ureport.reportBuilder"></property>
+    </bean>
+
+    <bean id="ureport.imageServletAction" class="com.bstek.ureport.console.image.ImageServletAction"></bean>
+    <bean id="ureport.importExcelServletAction" class="com.bstek.ureport.console.importexcel.ImportExcelServletAction"></bean>
+
+    <bean id="ureport.chartServletAction" class="com.bstek.ureport.console.chart.ChartServletAction"></bean>
+
+    <bean id="ureport.httpSessionReportCache" class="com.bstek.ureport.console.cache.HttpSessionReportCache">
+        <property name="disabled" value="false"></property>
+    </bean>
+
+    <!--  自定义接口  -->
+    <bean id="ureport.DataController" class="com.bstek.ureport.console.ureport.controller.DataReportController">
+    </bean>
+
+    <!--font-->
+    <import resource="classpath:ureport-font-context.xml"/>
+
+</beans>

+ 127 - 0
ureport2-console/target/classes/application.yml

@@ -0,0 +1,127 @@
+# 配置端口
+server:
+  port: 30007
+  compression:
+    enabled: true
+    min-response-size: 102400
+  max-http-request-header-size: 102400
+spring:
+  application:
+    # 应用名称
+    name: jnpf-datareport
+  exclude: com.alibaba.druid.spring.boot.autoconfigure.DruidDataSourceAutoConfigure #排除自动配置,手动配置druid
+  datasource:
+    #数据库类型(可选值 MySQL、SQLServer、Oracle、DM8、KingbaseES、PostgreSQL,请严格按可选值填写)
+    db-type: MySQL
+    host: usky-cloud-mysql
+    port: 3306
+    username: root
+    password: yt123456
+    db-name: jnpf_init
+    db-schema: #金仓达梦选填
+    prepare-url: #自定义url
+
+    # ===================== 动态多数据源 =====================
+    dynamic:
+      primary: master #设置默认的数据源或者数据源组,默认值即为master
+      strict: true #严格匹配数据源,默认false. true未匹配到指定数据源时抛异常,false使用默认数据源
+      druid:
+        # 空闲时执行连接测试
+        test-while-idle: true
+        # 连接测试最小间隔
+        time-between-eviction-runs-millis: 60000
+        # 获取连接等待3秒 根据网络情况设定
+        max-wait: 3000
+        # 初始化4个连接
+        initial-size: 4
+        # 最大20个连接
+        max-active: 20
+        # 最少保持4个空闲连接
+        min-idle: 4
+        # 空闲连接保活, 超过配置的空闲时间会进行连接检查完成保活操作(数据库自身会断开达到空闲时间的连接, 程序使用断开的连接会报错)
+        keep-alive: true
+        # 解除注释后Druid连接池打印SQL语句 忽略日志等级配置
+        #filters: slf4j
+        slf4j:
+          statementLogEnabled: true
+          resultSetLogEnabled: false
+          connectionLogEnabled: false
+          dataSourceLogEnabled: false
+          statementCreateAfterLogEnabled: false
+          statementCloseAfterLogEnabled: false
+          statementExecuteAfterLogEnabled: false
+          #打印SQL替换参数
+          statementExecutableSqlLogEnable: true
+          statementPrepareAfterLogEnabled: false
+          statementPrepareCallAfterLogEnabled: false
+          statementParameterSetLogEnabled: false
+
+  # ===================== Redis配置 =====================
+  # redis单机模式
+  data:
+    redis:
+      database: 1
+      host: usky-cloud-redis
+      port: 6379
+      password: 123456
+      timeout: 3000
+      lettuce: #Lettuce为Redis的Java驱动包
+        pool:
+          max-active: 8 # 连接池最大连接数
+          max-wait: -1ms  # 连接池最大阻塞等待时间(使用负值表示没有限制)
+          min-idle: 0 # 连接池中的最小空闲连接
+          max-idle: 8 # 连接池中的最大空闲连接
+
+# redis集群模式
+#  redis:
+#    cluster:
+#      nodes:
+#        - 192.168.0.225:6380
+#        - 192.168.0.225:6381
+#        - 192.168.0.225:6382
+#        - 192.168.0.225:6383
+#        - 192.168.0.225:6384
+#        - 192.168.0.225:6385
+#    password: 123456 # 密码为空时,请将本行注释
+#    timeout: 3000 # 超时时间(单位:秒)
+#    lettuce: #Lettuce为Redis的Java驱动包
+#      pool:
+#        max-active: 8 # 连接池最大连接数
+#        max-wait: -1ms  # 连接池最大阻塞等待时间(使用负值表示没有限制)
+#        min-idle: 0 # 连接池中的最小空闲连接
+#        max-idle: 8 # 连接池中的最大空闲连接
+
+# 日志配置
+logging:
+  config: classpath:logback-spring.xml
+  level:
+    #自定义第三方包名日志等级
+    com.bstek.ureport.console: debug
+    # 解除注释后Druid连接池打印SQL语句
+    druid.sql.Statement: debug
+#    druid.sql.DataSource: debug
+#    druid.sql.Connection: debug
+#    druid.sql.ResultSet: debug
+log:
+  level:
+    # 等级 TRACE,DEBUG,INFO,WARN,ERROR(不区分大小写)
+    root: ERROR
+  path: log/${spring.application.name}
+config:
+  #是否开启多租户
+  MultiTenancy: false
+  #数据库请求最长执行时间, 防止查询的报表数据过大导致内存溢出, -1不限制 单位:秒
+  queryTimeout: 5
+  #最大处理表格数据量
+  maxRows: 100000
+  #报表内引用的图片文件夹路径
+  imgPath:
+  #Column模式 租户字段
+  MultiTenantColumn: f_tenant_id
+  #用户接口地址
+  userUrl: http://127.0.0.1:30000/api/permission/Users/Current/ReportUserInfo
+
+
+security:
+  # AES加密秘钥
+  security-key: EY8WePvjM5GGwQzn

BIN
ureport2-console/target/classes/com/bstek/ureport/console/BaseServletAction.class


BIN
ureport2-console/target/classes/com/bstek/ureport/console/DataReportApplication.class


BIN
ureport2-console/target/classes/com/bstek/ureport/console/MobileUtils.class


Niektóre pliki nie zostały wyświetlone z powodu dużej ilości zmienionych plików