diff --git a/doc/docs/guide/quicklyDistribution.md b/doc/docs/guide/quicklyDistribution.md index 3ea87cbf..fce4e5d6 100644 --- a/doc/docs/guide/quicklyDistribution.md +++ b/doc/docs/guide/quicklyDistribution.md @@ -1,8 +1,9 @@ ``` 第一步,下载zip包,解压 - 第二步,conf->bootstrap.yml,修改mysql连接 + 第二步,conf->bootstrap.yml,修改mysql连接等信息 第三步,启动bin目录下start.sh - 第四步,访问 http://localhost:9095 + 第四步,访问 http://localhost:9095 admin 123456 + 第五步,修改"数据源->mysql数据源"用户名密码 ``` ## 下载发行版 @@ -21,10 +22,10 @@ ![bootstrap.png](../picture/quickly/img_2.png)
**注**:请确认你的Mysql是否支持远程连接,登陆用户是否有DDL权限
-## 上传功能 +## OSS配置 -使用上传功能,必须修改此内容,注意路径格式,比如Win是 \ ,linux是 /
-![file.png](../picture/quickly/img_15.png)
+OSS底层已支持minio、amazonS3、dfs,都配置的情况下优先级minio->amazonS3->nfs
+![file.png](../picture/quickly/img.png)
## 启动 @@ -38,9 +39,7 @@ aj-report-XXX --> bin --> start.bat
如果start.bat启动有问题的话,可以尝试以下方法解决。
修改第4行的JAVA_HOME,改成你自己的JAVA_HOME,并去掉**rem**注释,双击启动
-![java.png](../picture/quickly/img_7.png)
-**注**:如果你JAVA_HOME目录存在空格,将bat文件最下面的JAVA_HOME添加""号 -![img.png](../picture/quickly/img_8.png)
+![java.png](../picture/quickly/img_7.png) ## 访问 diff --git a/doc/docs/guide/quicklySeparate.md b/doc/docs/guide/quicklySeparate.md index 7917ce58..f30599d9 100644 --- a/doc/docs/guide/quicklySeparate.md +++ b/doc/docs/guide/quicklySeparate.md @@ -15,6 +15,8 @@ java -jar BASE_API: '"./"',改成自己后端的api npm install npm run build + +使用nginx转发 ``` ## linux部署后端 @@ -24,8 +26,8 @@ npm run build - [Apache Maven] 3.5
- [Node.js] v14.16.0
- [Jdk] 1.8
- 请在你的Windows上先准备好maven、node.js、jdk
- **注**:已知 **Jdk11** (部分小版本)存在兼容性问题,请不要使用openJdk,环境问题请看 **常见问题** 大类
+ +**注**:已知 **Jdk11** (部分小版本)存在兼容性问题,请不要使用openJdk,环境问题请看 **常见问题** 大类
### 克隆源码 @@ -36,46 +38,39 @@ git clone https://gitee.com/anji-plus/report.git
### 修改mysql连接 report-core --> src --> main --> resources --> bootstrap.yml
-![bootstrap.png](../picture/quickly/img_2.png)
将图中关于mysql的连接配置信息换成你使用的IP
-**注**:aj_report库是存放底层基础信息的库,flyway启动时会自动建立,如果你在这里修改了库,将会出错
-**注**:请确认你的Mysql是否支持远程连接,登陆用户是否有DDL权限
- -### 上传功能 -使用上传功能,必须修改此内容,注意路径格式,比如Win是 \ ,linux是 /
-![file.png](../picture/quickly/img_15.png)
+![bootstrap.png](../picture/quickly/img_2.png)
-### maven打包 +**注 :** -**打包之前如果系统用的不止mysql数据源,需要自己在pom文件中加入对应的数据库的驱动,登陆系统之后,数据源提示无驱动,则选择通用JDBC数据源,这里不做演示了**
-使用 maven package
-**注**:不要使用maven install
-**注**:此方式不会打包 lib目录下的驱动,详情可查看 **数据源 扩展**
-![img10](../picture/quickly/img_10.png)
- -### linux启动jar包 +``` +1、aj_report库是存放底层基础信息的库,flyway启动时会自动建立,如果你在这里修改了库,将会出错 +2、请确认你的Mysql是否支持远程连接,登陆用户是否有DDL权限 +``` -将上步生成的jar包上传至linux,使用java -jar命令启动
-**注**:请确保你的linux有jdk
+### OSS配置 -## 本地启动前端 +OSS底层已支持minio、amazonS3、dfs,都配置的情况下优先级minio->amazonS3->nfs
+![file.png](../picture/quickly/img.png)
-### 前端编译 +### maven打包 -进入前端目录:report-ui
-![img11](../picture/quickly/img_11.png)
-执行 npm install
+直接使用 maven package 打包,打包完成如图所示
-### 修改config +![img10](../picture/quickly/img_10.png)
+**注 :** -目录地址:report-ui --> config --> dev.env.js
-修改你的BASE_API地址
+``` +1、打包之前如果系统用的不止mysql数据源,需要自己在pom文件中加入对应的数据库的驱动,登陆系统之后,数据源提示无驱动,则选择通用JDBC数据源,这里不做演示了 +2、不要使用 maven install +3、此方式不会打包 lib目录下的驱动,详情可查看 "数据源->扩展" +``` -### 启动前端 +### linux启动jar包 -report-ui目录:
-执行 npm run dev
+将上步生成的jar包上传至linux,使用java -jar命令启动
+**注**:请确保你的linux有jdk1.8
## 前端build @@ -88,14 +83,18 @@ report-ui目录:
### 修改config 目录地址:report-ui --> config --> prod.env.js
-修改你的BASE_API地址,改成自己后端的api
+将BASE_API地址,改成你后端的api地址
-### build +### 打包 -reoprt-ui目录:
执行 npm run build
生成的前端dist目录文件在report-ui下面
+ ![img12](../picture/quickly/img_12.png)
+### 前端部署 + +使用nginx做转发 + diff --git a/doc/docs/guide/quicklySource.md b/doc/docs/guide/quicklySource.md index 9c272a68..14770b10 100644 --- a/doc/docs/guide/quicklySource.md +++ b/doc/docs/guide/quicklySource.md @@ -9,8 +9,10 @@ cd aj-report-xxxx vim conf/bootstrap.yml 修改数据库连接、上传文件的路径以及地址 sh bin/start.sh -访问 -http://serverip:9095 +访问:http://serverip:9095 +admin 123456 + +修改:"数据源->mysql数据源"用户名密码 ``` ## 编译环境 @@ -37,7 +39,8 @@ git clone https://gitee.com/anji-plus/report.git
编译完成后是放在当前目录下的build文件夹中:aj-report-xxxx.zip
**注:** 如果Win10部署的话,如图用git执行sh build.sh就行了。Linux就直接去report目录下执行sh build.sh就行。
-**特别注意:** 如果是Win10编译,那么几个启动脚本的格式则是win的格式,放linux上执行会报错的,反之放linux编译在win10启动也会报错,需要转格式。
+**特别注意:** +如果是Win10编译,那么几个启动脚本的格式则是win的格式,放linux上执行会报错的,反之放linux编译在win10启动也会报错,需要转格式。
## 修改mysql连接 @@ -50,10 +53,10 @@ git clone https://gitee.com/anji-plus/report.git
![bootstrap.png](../picture/quickly/img_2.png)
**注**:请确认你的Mysql是否支持远程连接,登陆用户是否有DDL权限
-## 上传功能 +## OSS配置 -使用上传功能,必须修改此内容,注意路径格式,比如Win是 \ ,linux是 /
-![file.png](../picture/quickly/img_15.png) +OSS底层已支持minio、amazonS3、dfs,都配置的情况下优先级minio->amazonS3->nfs
+![file.png](../picture/quickly/img.png)
## 启动 diff --git a/doc/docs/picture/quickly/img.png b/doc/docs/picture/quickly/img.png new file mode 100644 index 00000000..9e2c477d Binary files /dev/null and b/doc/docs/picture/quickly/img.png differ diff --git a/doc/docs/picture/quickly/img_15.png b/doc/docs/picture/quickly/img_15.png deleted file mode 100644 index dbdb455a..00000000 Binary files a/doc/docs/picture/quickly/img_15.png and /dev/null differ diff --git a/report-core/README.md b/report-core/README.md index 0ad3e4fb..c2001c56 100644 --- a/report-core/README.md +++ b/report-core/README.md @@ -1 +1,41 @@ ## 后端springboot + +### 采用redis缓存 + +#### 1.pom文件 +```java + + com.anji-plus + spring-boot-gaea + 2.0.5.RELEASE + + + org.springframework.boot + spring-boot-starter-data-redis + + + +``` +删除exclusions内容,因为底层默认支持redis +删除ehcache相关依赖 + +#### 2.删除 package com.anjiplus.template.gaea.business.cache +CacheHelper底层默认实现为RedisCacheHelper。 +@ConditionalOnMissingBean 注解起到的作用 +```java +package com.anji.plus.gaea; + +@Configuration +@EnableConfigurationProperties({GaeaProperties.class}) +public class GaeaAutoConfiguration { + @Bean + @ConditionalOnClass({RedisAutoConfiguration.class}) + @ConditionalOnMissingBean + public CacheHelper cacheHelper() { + return new RedisCacheHelper(); + } +} +``` + +#### 3.bootstrap.yml加上对应的redis配置即可 + diff --git a/report-core/pom.xml b/report-core/pom.xml index 7118783c..7a41ea41 100644 --- a/report-core/pom.xml +++ b/report-core/pom.xml @@ -61,6 +61,12 @@ test + + org.springframework + spring-mock + 2.0.8 + + org.springframework.cloud spring-cloud-context @@ -76,7 +82,7 @@ com.anji-plus spring-boot-gaea - 2.0.3.RELEASE + 2.0.5.RELEASE org.springframework.boot @@ -85,6 +91,12 @@ + + com.anji-plus + spring-boot-starter-gaea-oss + 2.0.5.RELEASE + + com.baomidou mybatis-plus-boot-starter @@ -94,6 +106,7 @@ mysql mysql-connector-java + 8.0.28 com.alibaba @@ -115,7 +128,7 @@ org.apache.httpcomponents httpclient - 4.5.10 + 4.5.13 diff --git a/report-core/src/main/java/com/anjiplus/template/gaea/business/code/ResponseCode.java b/report-core/src/main/java/com/anjiplus/template/gaea/business/code/ResponseCode.java index f0fe7039..0cefc8b1 100644 --- a/report-core/src/main/java/com/anjiplus/template/gaea/business/code/ResponseCode.java +++ b/report-core/src/main/java/com/anjiplus/template/gaea/business/code/ResponseCode.java @@ -118,7 +118,8 @@ public interface ResponseCode { String FILE_SUFFIX_UNSUPPORTED = "2002"; String FILE_UPLOAD_ERROR = "2003"; String FILE_ONT_EXSIT = "2004"; - String LIST_IS_EMPTY = "2005"; + String FILE_OPERATION_FAILED = "file.operation.failed"; + String PUSHCODE_NEED_UNIQUE = "3001"; String RECEIVER_IS_EMPTY = "3002"; String DATA_SOURCE_CONNECTION_FAILED = "4001"; diff --git a/report-core/src/main/java/com/anjiplus/template/gaea/business/filter/TokenFilter.java b/report-core/src/main/java/com/anjiplus/template/gaea/business/filter/TokenFilter.java index 8022cf44..74ded384 100644 --- a/report-core/src/main/java/com/anjiplus/template/gaea/business/filter/TokenFilter.java +++ b/report-core/src/main/java/com/anjiplus/template/gaea/business/filter/TokenFilter.java @@ -231,7 +231,7 @@ public class TokenFilter implements Filter { } private void error(HttpServletResponse response) throws IOException { - ResponseBean responseBean = ResponseBean.builder().code("50008").message("The Token has expired").build(); + ResponseBean responseBean = ResponseBean.builder().code("User.credentials.expired").message("The Token has expired").build(); response.setContentType(ContentType.APPLICATION_JSON.getMimeType()); response.getWriter().print(JSONObject.toJSONString(responseBean)); } diff --git a/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/accessuser/service/impl/AccessUserServiceImpl.java b/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/accessuser/service/impl/AccessUserServiceImpl.java index 96619603..d2164b19 100755 --- a/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/accessuser/service/impl/AccessUserServiceImpl.java +++ b/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/accessuser/service/impl/AccessUserServiceImpl.java @@ -5,6 +5,7 @@ import com.alibaba.fastjson.JSONObject; import com.anji.plus.gaea.bean.TreeNode; import com.anji.plus.gaea.cache.CacheHelper; import com.anji.plus.gaea.constant.BaseOperationEnum; +import com.anji.plus.gaea.constant.GaeaConstant; import com.anji.plus.gaea.exception.BusinessException; import com.anji.plus.gaea.exception.BusinessExceptionBuilder; import com.anji.plus.gaea.curd.mapper.GaeaBaseMapper; @@ -163,7 +164,7 @@ public class AccessUserServiceImpl implements AccessUserService { } else { // 生成用户token String uuid = GaeaUtils.UUID(); - token = jwtBean.createToken(loginName, uuid); + token = jwtBean.createToken(loginName, uuid, 0, GaeaConstant.TENANT_CODE); cacheHelper.stringSetExpire(tokenKey, token, 3600); } diff --git a/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/dashboard/service/impl/ReportDashboardServiceImpl.java b/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/dashboard/service/impl/ReportDashboardServiceImpl.java index fd3f2117..8cf36c49 100644 --- a/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/dashboard/service/impl/ReportDashboardServiceImpl.java +++ b/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/dashboard/service/impl/ReportDashboardServiceImpl.java @@ -80,13 +80,13 @@ public class ReportDashboardServiceImpl implements ReportDashboardService, Initi @Autowired private ReportService reportService; - @Value("${customer.file.downloadPath:''}") + @Value("${spring.gaea.subscribes.oss.downloadPath:}") private String fileDownloadPath; - @Value("${customer.file.dist-path:''}") + @Value("${customer.file.tmp-path:.}") private String dictPath; - private final static String ZIP_PATH = "/zip/"; + private final static String ZIP_PATH = "/tmp_zip/"; private final static String JSON_PATH = "dashboard.json"; private Map queryServiceImplMap = new HashMap<>(); @@ -331,7 +331,7 @@ public class ReportDashboardServiceImpl implements ReportDashboardService, Initi GaeaFile gaeaFile = gaeaFileService.selectOne(queryWrapper); String uploadPath; if (null == gaeaFile) { - GaeaFile upload = gaeaFileService.upload(imageFile, fileName); + GaeaFile upload = gaeaFileService.upload(imageFile); log.info("存入图片: {}", upload.getFilePath()); uploadPath = upload.getUrlPath(); }else { @@ -395,13 +395,9 @@ public class ReportDashboardServiceImpl implements ReportDashboardService, Initi queryWrapper.eq(GaeaFile::getFileId, fileName); GaeaFile gaeaFile = gaeaFileService.selectOne(queryWrapper); if (null != gaeaFile) { - String fileType = gaeaFile.getFileType(); - path = path + "/image/" + fileName + "." + fileType; - //path = /app/disk/upload/zip/UUID/image - - //原始文件的路径 - String filePath = gaeaFile.getFilePath(); - FileUtil.copyFileUsingFileChannels(filePath, path); + byte[] file = gaeaFileService.getFile(gaeaFile.getFileId()); + path = path + "/image/"; + FileUtil.byte2File(file, path, gaeaFile.getFileId().concat(".").concat(gaeaFile.getFileType())); } } diff --git a/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/file/controller/param/GaeaFileParam.java b/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/file/controller/param/GaeaFileParam.java index 7d6bd835..cac2f1ba 100644 --- a/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/file/controller/param/GaeaFileParam.java +++ b/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/file/controller/param/GaeaFileParam.java @@ -4,6 +4,7 @@ package com.anjiplus.template.gaea.business.modules.file.controller.param; import com.anji.plus.gaea.annotation.Query; import com.anji.plus.gaea.constant.QueryEnum; import com.anji.plus.gaea.curd.params.PageParam; +import lombok.Data; import java.io.Serializable; @@ -13,6 +14,7 @@ import java.io.Serializable; * @author peiyanni * @since 2021-02-18 14:48:29 */ +@Data public class GaeaFileParam extends PageParam implements Serializable { /** 模糊查询 */ diff --git a/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/file/service/GaeaFileService.java b/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/file/service/GaeaFileService.java index 4082ca7e..0581399c 100644 --- a/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/file/service/GaeaFileService.java +++ b/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/file/service/GaeaFileService.java @@ -18,16 +18,6 @@ import java.io.File; */ public interface GaeaFileService extends GaeaBaseService { - /** - * 文件上传 - * - * @param multipartFile 文件 - * @param file 文件 - * @param customFileName 自定义文件名,默认给null - * @return - */ - GaeaFile upload(MultipartFile multipartFile, File file, String customFileName); - /** * 文件上传 * @@ -41,10 +31,9 @@ public interface GaeaFileService extends GaeaBaseService download(HttpServletRequest request, HttpServletResponse response, String fileId); + + /** + * 获取文件 + * @param fileId + * @return + */ + byte[] getFile(String fileId); } diff --git a/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/file/service/impl/GaeaFileServiceImpl.java b/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/file/service/impl/GaeaFileServiceImpl.java index fed43689..4a1588a5 100644 --- a/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/file/service/impl/GaeaFileServiceImpl.java +++ b/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/file/service/impl/GaeaFileServiceImpl.java @@ -4,59 +4,51 @@ import com.anji.plus.gaea.constant.BaseOperationEnum; import com.anji.plus.gaea.curd.mapper.GaeaBaseMapper; import com.anji.plus.gaea.exception.BusinessException; import com.anji.plus.gaea.exception.BusinessExceptionBuilder; +import com.anji.plus.gaea.oss.exceptions.GaeaOSSException; +import com.anji.plus.gaea.oss.exceptions.GaeaOSSTypeLimitedException; +import com.anji.plus.gaea.oss.ossbuilder.GaeaOSSTemplate; +import com.anji.plus.gaea.oss.utils.ResponseUtil; import com.anjiplus.template.gaea.business.code.ResponseCode; import com.anjiplus.template.gaea.business.modules.file.dao.GaeaFileMapper; import com.anjiplus.template.gaea.business.modules.file.entity.GaeaFile; import com.anjiplus.template.gaea.business.modules.file.service.GaeaFileService; -import com.anjiplus.template.gaea.business.modules.file.util.FileUtils; -import com.anjiplus.template.gaea.business.modules.file.util.StringPatternUtil; -import com.anjiplus.template.gaea.business.util.FileUtil; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.toolkit.Wrappers; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; +import org.apache.http.entity.ContentType; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; -import org.springframework.http.CacheControl; -import org.springframework.http.MediaType; +import org.springframework.cloud.context.config.annotation.RefreshScope; import org.springframework.http.ResponseEntity; +import org.springframework.mock.web.MockMultipartFile; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; -import org.springframework.transaction.interceptor.TransactionAspectSupport; import org.springframework.web.multipart.MultipartFile; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.File; -import java.net.URLEncoder; -import java.util.ArrayList; -import java.util.Arrays; +import java.io.FileInputStream; import java.util.List; import java.util.UUID; -import java.util.stream.Collectors; /** - * (GaeaFile)ServiceImpl - * - * @author peiyanni - * @since 2021-02-18 14:48:26 + * 文件管理服务实现 + * @author: Raod + * @since: 2022-08-31 */ @Service @Slf4j +@RefreshScope public class GaeaFileServiceImpl implements GaeaFileService { - @Value("${customer.file.dist-path:''}") - private String dictPath; - - @Value("${customer.file.white-list:''}") - private String whiteList; - - @Value("${customer.file.excelSuffix:''}") - private String excelSuffix; - - @Value("${customer.file.downloadPath:''}") + @Value("${spring.gaea.subscribes.oss.downloadPath:''}") private String fileDownloadPath; + @Autowired + private GaeaOSSTemplate gaeaOSSTemplate; + @Autowired private GaeaFileMapper gaeaFileMapper; @@ -65,70 +57,6 @@ public class GaeaFileServiceImpl implements GaeaFileService { return gaeaFileMapper; } - - @Override - @Transactional(rollbackFor = Exception.class) - public GaeaFile upload(MultipartFile multipartFile, File file, String customFileName) { - try { - String fileName = ""; - if (null != multipartFile) { - fileName = multipartFile.getOriginalFilename(); - }else { - fileName = file.getName(); - } - - if (StringUtils.isBlank(fileName)) { - throw BusinessExceptionBuilder.build(ResponseCode.FILE_EMPTY_FILENAME); - } - - String suffixName = fileName.substring(fileName.lastIndexOf(".")); - String fileInstruction = fileName.substring(0, fileName.lastIndexOf(".")); - //白名单校验(不区分大小写) - List list = new ArrayList<>(Arrays.asList(whiteList.split("\\|"))); - list.addAll(list.stream().map(String::toUpperCase).collect(Collectors.toList())); - if (!list.contains(suffixName)) { - throw BusinessExceptionBuilder.build(ResponseCode.FILE_SUFFIX_UNSUPPORTED); - } - // 生成文件唯一性标识 - String fileId; - if (StringUtils.isBlank(customFileName)) { - fileId = UUID.randomUUID().toString(); - } else { - fileId = customFileName; - } - String newFileName = fileId + suffixName; - // 本地文件保存路径 - String filePath = dictPath + newFileName; - String urlPath = fileDownloadPath + "/" + fileId; - - GaeaFile gaeaFile = new GaeaFile(); - gaeaFile.setFilePath(filePath); - gaeaFile.setFileId(fileId); - gaeaFile.setUrlPath(urlPath); - gaeaFile.setFileType(suffixName.replace(".", "")); - gaeaFile.setFileInstruction(fileInstruction); - gaeaFileMapper.insert(gaeaFile); - - //写文件 将文件保存/app/dictPath/upload/下 - java.io.File dest = new java.io.File(dictPath + newFileName); - java.io.File parentFile = dest.getParentFile(); - if (!parentFile.exists()) { - parentFile.mkdirs(); - } - if (null != multipartFile) { - multipartFile.transferTo(dest); - }else { - FileUtil.copyFileUsingFileChannels(file, dest); - } - // 将完整的http访问路径返回 - return gaeaFile; - } catch (Exception e) { - TransactionAspectSupport.currentTransactionStatus().setRollbackOnly(); - log.error("file upload error: {}", e); - throw BusinessExceptionBuilder.build(ResponseCode.FILE_UPLOAD_ERROR); - } - } - /** * 文件上传 * @@ -137,66 +65,138 @@ public class GaeaFileServiceImpl implements GaeaFileService { */ @Override public GaeaFile upload(MultipartFile multipartFile) { - return upload(multipartFile, null, null); + String originalFilename = multipartFile.getOriginalFilename(); + + if (StringUtils.isBlank(originalFilename)) { + throw BusinessExceptionBuilder.build(ResponseCode.FILE_EMPTY_FILENAME); + } + // 文件后缀 .png + String suffixName = originalFilename.substring(originalFilename.lastIndexOf(".")); + // 生成文件唯一性标识 + String fileId = UUID.randomUUID().toString(); + + // 生成在oss中存储的文件名 402b6193e70e40a9bf5b73a78ea1e8ab.png + String fileObjectName = fileId + suffixName; + // 生成链接通过fileId http访问路径 http://10.108.3.121:9089/meta/file/download/402b6193e70e40a9bf5b73a78ea1e8ab + String urlPath = fileDownloadPath + "/" + fileId; + + // 上传文件 + try{ + gaeaOSSTemplate.uploadFileByInputStream(multipartFile, fileObjectName); + }catch (GaeaOSSTypeLimitedException e){ + log.error("上传失败GaeaOSSTypeLimitedException", e); + throw BusinessExceptionBuilder.build(ResponseCode.FILE_SUFFIX_UNSUPPORTED, e.getMessage()); + }catch (GaeaOSSException e){ + log.error("上传失败GaeaOSSException", e); + throw BusinessExceptionBuilder.build(ResponseCode.FILE_UPLOAD_ERROR, e.getMessage()); + } + + // 保存到文件管理中 + GaeaFile gaeaFile = new GaeaFile(); + gaeaFile.setFileId(fileId); + gaeaFile.setFilePath(fileObjectName); + gaeaFile.setUrlPath(urlPath); + gaeaFile.setFileType(suffixName.replace(".", "")); + gaeaFile.setFileInstruction(originalFilename); + insert(gaeaFile); + + return gaeaFile; + } + + private MultipartFile getMultipartFile(File file){ + FileInputStream fileInputStream; + MultipartFile multipartFile; + try { + fileInputStream = new FileInputStream(file); + multipartFile = new MockMultipartFile(file.getName(),file.getName(), + ContentType.APPLICATION_OCTET_STREAM.toString(),fileInputStream); + } catch (Exception e) { + log.error("file转MultipartFile失败", e); + throw BusinessExceptionBuilder.build(ResponseCode.FILE_OPERATION_FAILED, e.getMessage()); + } + return multipartFile; } /** * 文件上传 * * @param file 文件 - * @param customFileName 自定义文件名 * @return */ @Override - public GaeaFile upload(File file, String customFileName) { - return upload(null, file, customFileName); + public GaeaFile upload(File file) { + return upload(getMultipartFile(file)); } @Override public ResponseEntity download(HttpServletRequest request, HttpServletResponse response, String fileId) { try { - String userAgent = request.getHeader("User-Agent"); - boolean isIeBrowser = userAgent.indexOf("MSIE") > 0; - //根据fileId,从gaea_file中读出filePath + // fileId必填 + if(StringUtils.isBlank(fileId)){ + throw BusinessExceptionBuilder.build(ResponseCode.FILE_ONT_EXSIT); + } + // 根据fileId,从gaea_file中读出filePath LambdaQueryWrapper queryWrapper = Wrappers.lambdaQuery(); queryWrapper.eq(GaeaFile::getFileId, fileId); GaeaFile gaeaFile = gaeaFileMapper.selectOne(queryWrapper); if (null == gaeaFile) { throw BusinessExceptionBuilder.build(ResponseCode.FILE_ONT_EXSIT); } - //解析文件路径、文件名和后缀 - String filePath = gaeaFile.getFilePath(); - if (StringUtils.isBlank(filePath)) { + + String userAgent = request.getHeader("User-Agent"); + boolean isIEBrowser = userAgent.indexOf("MSIE") > 0; + // 在oss中存储的文件名 402b6193e70e40a9bf5b73a78ea1e8ab.png + String fileObjectName = gaeaFile.getFileId().concat(".").concat(gaeaFile.getFileType()); + String originalFilename = gaeaFile.getFileInstruction(); + if (StringUtils.isBlank(fileObjectName) || StringUtils.isBlank(originalFilename)) { throw BusinessExceptionBuilder.build(ResponseCode.FILE_ONT_EXSIT); } - String filename = filePath.substring(filePath.lastIndexOf(File.separator)); - String fileSuffix = filename.substring(filename.lastIndexOf(".")); - - //根据文件后缀来判断,是显示图片\视频\音频,还是下载文件 - File file = new File(filePath); - ResponseEntity.BodyBuilder builder = ResponseEntity.ok(); - builder.contentLength(file.length()); - if (StringPatternUtil.stringMatchIgnoreCase(fileSuffix, "(.png|.jpg|.jpeg|.bmp|.gif|.icon)")) { - builder.cacheControl(CacheControl.noCache()).contentType(MediaType.IMAGE_PNG); - } else if (StringPatternUtil.stringMatchIgnoreCase(fileSuffix, "(.flv|.swf|.mkv|.avi|.rm|.rmvb|.mpeg|.mpg|.ogg|.ogv|.mov|.wmv|.mp4|.webm|.wav|.mid|.mp3|.aac)")) { - builder.header("Content-Type", "video/mp4; charset=UTF-8"); - } else { - //application/octet-stream 二进制数据流(最常见的文件下载) - builder.contentType(MediaType.APPLICATION_OCTET_STREAM); - filename = URLEncoder.encode(filename, "UTF-8"); - if (isIeBrowser) { - builder.header("Content-Disposition", "attachment; filename=" + filename); - } else { - builder.header("Content-Disposition", "attacher; filename*=UTF-8''" + filename); - } + if (!originalFilename.endsWith(".".concat(gaeaFile.getFileType()))) { + originalFilename = originalFilename.concat(".").concat(gaeaFile.getFileType()); } - return builder.body(FileUtils.readFileToByteArray(file)); + + // 调用文件存储工厂,读取文件,返回字节数组 + byte[] fileBytes = gaeaOSSTemplate.downloadFile(fileObjectName); + + // 根据文件后缀来判断,是显示图片\视频\音频,还是下载文件 + return ResponseUtil.writeBody(originalFilename, fileBytes, isIEBrowser); } catch (Exception e) { - log.error("file download error: {}", e); - return null; + log.error("file download error", e); + throw BusinessExceptionBuilder.build(ResponseCode.FILE_OPERATION_FAILED, e.getMessage()); } } + /** + * 获取文件 + * + * @param fileId + * @return + */ + @Override + public byte[] getFile(String fileId) { + // fileId必填 + if(StringUtils.isBlank(fileId)){ + throw BusinessExceptionBuilder.build(ResponseCode.FILE_ONT_EXSIT); + } + // 根据fileId,从gaea_file中读出filePath + LambdaQueryWrapper queryWrapper = Wrappers.lambdaQuery(); + queryWrapper.eq(GaeaFile::getFileId, fileId); + GaeaFile gaeaFile = gaeaFileMapper.selectOne(queryWrapper); + if (null == gaeaFile) { + throw BusinessExceptionBuilder.build(ResponseCode.FILE_ONT_EXSIT); + } + + // 在oss中存储的文件名 402b6193e70e40a9bf5b73a78ea1e8ab.png + String fileObjectName = gaeaFile.getFileId().concat(".").concat(gaeaFile.getFileType()); + String originalFilename = gaeaFile.getFileInstruction(); + if (StringUtils.isBlank(fileObjectName) || StringUtils.isBlank(originalFilename)) { + throw BusinessExceptionBuilder.build(ResponseCode.FILE_ONT_EXSIT); + } + + // 调用文件存储工厂,读取文件,返回字节数组 + return gaeaOSSTemplate.downloadFile(fileObjectName); + } + /** * 批处理操作后续处理 * 删除本地已经存在的文件 @@ -209,13 +209,7 @@ public class GaeaFileServiceImpl implements GaeaFileService { public void processBatchAfterOperation(List entities, BaseOperationEnum operationEnum) throws BusinessException { if (operationEnum.equals(BaseOperationEnum.DELETE_BATCH)) { // 删除本地文件 - entities.forEach(gaeaFile -> { - String filePath = gaeaFile.getFilePath(); - File file = new File(filePath); - if (file.exists()) { - file.delete(); - } - }); + entities.forEach(gaeaFile -> gaeaOSSTemplate.deleteFile(gaeaFile.getFileId().concat(".").concat(gaeaFile.getFileType()))); } } diff --git a/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/reportexcel/service/impl/ReportExcelServiceImpl.java b/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/reportexcel/service/impl/ReportExcelServiceImpl.java index b25832d6..fd17950a 100644 --- a/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/reportexcel/service/impl/ReportExcelServiceImpl.java +++ b/report-core/src/main/java/com/anjiplus/template/gaea/business/modules/reportexcel/service/impl/ReportExcelServiceImpl.java @@ -7,6 +7,7 @@ import com.alibaba.fastjson.serializer.SerializerFeature; import com.anji.plus.gaea.constant.BaseOperationEnum; import com.anji.plus.gaea.curd.mapper.GaeaBaseMapper; import com.anji.plus.gaea.exception.BusinessException; +import com.anji.plus.gaea.exception.BusinessExceptionBuilder; import com.anji.plus.gaea.utils.GaeaAssert; import com.anji.plus.gaea.utils.GaeaBeanUtils; import com.anjiplus.template.gaea.business.code.ResponseCode; @@ -14,8 +15,7 @@ import com.anjiplus.template.gaea.business.enums.ExportTypeEnum; import com.anjiplus.template.gaea.business.modules.dataset.controller.dto.DataSetDto; import com.anjiplus.template.gaea.business.modules.dataset.controller.dto.OriginalDataDto; import com.anjiplus.template.gaea.business.modules.dataset.service.DataSetService; -import com.anjiplus.template.gaea.business.modules.file.dao.GaeaFileMapper; -import com.anjiplus.template.gaea.business.modules.file.entity.GaeaFile; +import com.anjiplus.template.gaea.business.modules.file.service.GaeaFileService; import com.anjiplus.template.gaea.business.modules.report.dao.ReportMapper; import com.anjiplus.template.gaea.business.modules.report.dao.entity.Report; import com.anjiplus.template.gaea.business.modules.reportexcel.controller.dto.ReportExcelDto; @@ -23,7 +23,6 @@ import com.anjiplus.template.gaea.business.modules.reportexcel.dao.ReportExcelMa import com.anjiplus.template.gaea.business.modules.reportexcel.dao.entity.ReportExcel; import com.anjiplus.template.gaea.business.modules.reportexcel.service.ReportExcelService; import com.anjiplus.template.gaea.business.modules.reportexcel.util.CellType; -import com.anjiplus.template.gaea.business.modules.reportexcel.util.XlsSheetUtil; import com.anjiplus.template.gaea.business.modules.reportexcel.util.XlsUtil; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import org.apache.commons.lang3.StringUtils; @@ -34,8 +33,15 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Service; -import java.io.*; -import java.util.*; +import java.io.File; +import java.io.IOException; +import java.io.OutputStream; +import java.nio.file.Files; +import java.nio.file.Paths; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; /** * TODO @@ -54,18 +60,17 @@ public class ReportExcelServiceImpl implements ReportExcelService { @Autowired private DataSetService dataSetService; + @Autowired + private GaeaFileService gaeaFileService; + @Autowired private ReportMapper reportMapper; - @Value("${customer.file.dist-path:''}") + @Value("${customer.file.tmp-path:.}") private String dictPath; - @Value("${customer.file.downloadPath:''}") - private String fileDownloadPath; - - @Autowired - private GaeaFileMapper gaeaFileMapper; + private final static String ZIP_PATH = "/tmp_zip/"; @Override @@ -139,26 +144,30 @@ public class ReportExcelServiceImpl implements ReportExcelService { reportExcelDto.setJsonStr(report.getJsonStr()); String jsonStr = analysisReportData(reportExcelDto); List lists=(List ) JSON.parse(jsonStr); - OutputStream out; + OutputStream out = null; + File file = null; try { - String fileId = UUID.randomUUID().toString(); - String filePath = dictPath + File.separator + fileId + ".xlsx"; - String urlPath = fileDownloadPath + java.io.File.separator + fileId; - - GaeaFile gaeaFile = new GaeaFile(); - gaeaFile.setFilePath(filePath); - gaeaFile.setFileId(fileId); - gaeaFile.setUrlPath(urlPath); - gaeaFile.setFileType("xlsx"); - gaeaFile.setFileInstruction(reportCode + ".xlsx"); - - out = new FileOutputStream(filePath); + String fileName = report.getReportCode(); + File dir = new File(dictPath + ZIP_PATH); + if (!dir.exists()){ + dir.mkdirs(); + } + String filePath = dir.getAbsolutePath() + File.separator + fileName + ".xlsx"; + file = new File(filePath); + out = Files.newOutputStream(Paths.get(filePath)); XlsUtil.exportXlsFile(out, true, lists); + gaeaFileService.upload(file); - gaeaFileMapper.insert(gaeaFile); - logger.info("导出成功:{}", gaeaFile); } catch (IOException e) { logger.error("导出失败", e); + }finally { + try { + out.close(); + file.delete(); + } catch (IOException e) { + throw BusinessExceptionBuilder.build(ResponseCode.FILE_OPERATION_FAILED, e.getMessage()); + } + } } return true; diff --git a/report-core/src/main/java/com/anjiplus/template/gaea/business/util/FileUtil.java b/report-core/src/main/java/com/anjiplus/template/gaea/business/util/FileUtil.java index 5532b53d..a0ac7365 100644 --- a/report-core/src/main/java/com/anjiplus/template/gaea/business/util/FileUtil.java +++ b/report-core/src/main/java/com/anjiplus/template/gaea/business/util/FileUtil.java @@ -1,7 +1,7 @@ package com.anjiplus.template.gaea.business.util; -import com.anji.plus.gaea.code.ResponseCode; import com.anji.plus.gaea.exception.BusinessExceptionBuilder; +import com.anjiplus.template.gaea.business.code.ResponseCode; import lombok.extern.slf4j.Slf4j; import org.springframework.web.multipart.MultipartFile; @@ -42,7 +42,7 @@ public class FileUtil { log.info("链接下载图片:{},临时路径:{}", urlPath, path); } catch (IOException e) { log.error("根据链接下载失败", e); - throw BusinessExceptionBuilder.build(ResponseCode.FAIL_CODE, e.getMessage()); + throw BusinessExceptionBuilder.build(ResponseCode.FILE_OPERATION_FAILED, e.getMessage()); } } @@ -66,14 +66,14 @@ public class FileUtil { outputChannel.transferFrom(inputChannel, 0, inputChannel.size()); } catch (IOException e) { log.error("复制文件失败", e); - throw BusinessExceptionBuilder.build(ResponseCode.FAIL_CODE, e.getMessage()); + throw BusinessExceptionBuilder.build(ResponseCode.FILE_OPERATION_FAILED, e.getMessage()); } finally { try { inputChannel.close(); outputChannel.close(); } catch (IOException e) { log.error("", e); - throw BusinessExceptionBuilder.build(ResponseCode.FAIL_CODE, e.getMessage()); + throw BusinessExceptionBuilder.build(ResponseCode.FILE_OPERATION_FAILED, e.getMessage()); } } } @@ -106,7 +106,7 @@ public class FileUtil { outputStream.close(); } catch (Exception e) { log.error("写入文件失败", e); - throw BusinessExceptionBuilder.build(ResponseCode.FAIL_CODE, e.getMessage()); + throw BusinessExceptionBuilder.build(ResponseCode.FILE_OPERATION_FAILED, e.getMessage()); } } @@ -132,20 +132,20 @@ public class FileUtil { return sbf.toString(); } catch (IOException e) { log.error("读文件失败", e); - throw BusinessExceptionBuilder.build(ResponseCode.FAIL_CODE, e.getMessage()); + throw BusinessExceptionBuilder.build(ResponseCode.FILE_OPERATION_FAILED, e.getMessage()); } finally { if (null != isr) { try { isr.close(); } catch (IOException e) { - throw BusinessExceptionBuilder.build(ResponseCode.FAIL_CODE, e.getMessage()); + throw BusinessExceptionBuilder.build(ResponseCode.FILE_OPERATION_FAILED, e.getMessage()); } } if (reader != null) { try { reader.close(); } catch (IOException e1) { - throw BusinessExceptionBuilder.build(ResponseCode.FAIL_CODE, e1.getMessage()); + throw BusinessExceptionBuilder.build(ResponseCode.FILE_OPERATION_FAILED, e1.getMessage()); } } } @@ -185,14 +185,14 @@ public class FileUtil { compress(srcFile, zipOut, baseDir); } catch (IOException e) { log.error("压缩文件夹失败", e); - throw BusinessExceptionBuilder.build(ResponseCode.FAIL_CODE, e.getMessage()); + throw BusinessExceptionBuilder.build(ResponseCode.FILE_OPERATION_FAILED, e.getMessage()); } finally { if (null != zipOut) { try { zipOut.close(); } catch (IOException e) { log.error("", e); - throw BusinessExceptionBuilder.build(ResponseCode.FAIL_CODE, e.getMessage()); + throw BusinessExceptionBuilder.build(ResponseCode.FILE_OPERATION_FAILED, e.getMessage()); } out = null; } @@ -201,7 +201,7 @@ public class FileUtil { out.close(); } catch (IOException e) { log.error("", e); - throw BusinessExceptionBuilder.build(ResponseCode.FAIL_CODE, e.getMessage()); + throw BusinessExceptionBuilder.build(ResponseCode.FILE_OPERATION_FAILED, e.getMessage()); } } } @@ -246,14 +246,14 @@ public class FileUtil { } catch (IOException e) { log.error("压缩文件夹失败", e); - throw BusinessExceptionBuilder.build(ResponseCode.FAIL_CODE, e.getMessage()); + throw BusinessExceptionBuilder.build(ResponseCode.FILE_OPERATION_FAILED, e.getMessage()); } finally { if (null != bis) { try { bis.close(); } catch (IOException e) { log.error("", e); - throw BusinessExceptionBuilder.build(ResponseCode.FAIL_CODE, e.getMessage()); + throw BusinessExceptionBuilder.build(ResponseCode.FILE_OPERATION_FAILED, e.getMessage()); } } } @@ -264,23 +264,26 @@ public class FileUtil { decompress(new ZipFile(zipFile), dstPath); } catch (IOException e) { log.error("", e); - throw BusinessExceptionBuilder.build(ResponseCode.FAIL_CODE, e.getMessage()); + throw BusinessExceptionBuilder.build(ResponseCode.FILE_OPERATION_FAILED, e.getMessage()); } } public static void decompress(MultipartFile zipFile, String dstPath) { try { - File file = new File(dstPath + File.separator + zipFile.getOriginalFilename()); - if (!file.getParentFile().exists()) { - file.getParentFile().mkdirs(); + File dir = new File(dstPath); + if (!dir.exists()){ + dir.mkdirs(); } + String path = dir.getPath(); + String absolutePath = dir.getAbsolutePath(); + File file = new File(dir.getAbsolutePath() + File.separator + zipFile.getOriginalFilename()); zipFile.transferTo(file); decompress(new ZipFile(file), dstPath); //解压完删除 file.delete(); } catch (IOException e) { log.error("", e); - throw BusinessExceptionBuilder.build(ResponseCode.FAIL_CODE, e.getMessage()); + throw BusinessExceptionBuilder.build(ResponseCode.FILE_OPERATION_FAILED, e.getMessage()); } } @@ -326,14 +329,14 @@ public class FileUtil { } } catch (IOException e) { log.error("解压失败", e); - throw BusinessExceptionBuilder.build(ResponseCode.FAIL_CODE, e.getMessage()); + throw BusinessExceptionBuilder.build(ResponseCode.FILE_OPERATION_FAILED, e.getMessage()); } finally { if (null != in) { try { in.close(); } catch (IOException e) { log.error("", e); - throw BusinessExceptionBuilder.build(ResponseCode.FAIL_CODE, e.getMessage()); + throw BusinessExceptionBuilder.build(ResponseCode.FILE_OPERATION_FAILED, e.getMessage()); } } @@ -342,7 +345,7 @@ public class FileUtil { out.close(); } catch (IOException e) { log.error("", e); - throw BusinessExceptionBuilder.build(ResponseCode.FAIL_CODE, e.getMessage()); + throw BusinessExceptionBuilder.build(ResponseCode.FILE_OPERATION_FAILED, e.getMessage()); } } } @@ -350,7 +353,7 @@ public class FileUtil { zip.close(); } catch (IOException e) { log.error("解压失败", e); - throw BusinessExceptionBuilder.build(ResponseCode.FAIL_CODE, e.getMessage()); + throw BusinessExceptionBuilder.build(ResponseCode.FILE_OPERATION_FAILED, e.getMessage()); } } @@ -371,7 +374,7 @@ public class FileUtil { ins.close(); } catch (Exception e) { log.error("获取流文件失败", e); - throw BusinessExceptionBuilder.build(ResponseCode.FAIL_CODE, e.getMessage()); + throw BusinessExceptionBuilder.build(ResponseCode.FILE_OPERATION_FAILED, e.getMessage()); } } @@ -399,8 +402,49 @@ public class FileUtil { }); } catch (IOException e) { log.error("删除文件失败", e); - throw BusinessExceptionBuilder.build(ResponseCode.FAIL_CODE, e.getMessage()); + throw BusinessExceptionBuilder.build(ResponseCode.FILE_OPERATION_FAILED, e.getMessage()); + } + } + + /** + * byte 转file + */ + public static File byte2File(byte[] buf, String filePath, String fileName){ + BufferedOutputStream bos = null; + FileOutputStream fos = null; + File file = null; + try{ + File dir = new File(filePath); + if (!dir.exists()){ + dir.mkdirs(); + } + file = new File(filePath + File.separator + fileName); + fos = new FileOutputStream(file); + bos = new BufferedOutputStream(fos); + bos.write(buf); + }catch (Exception e){ + log.error("", e); + throw BusinessExceptionBuilder.build(ResponseCode.FILE_OPERATION_FAILED, e.getMessage()); + } + finally{ + if (bos != null){ + try{ + bos.close(); + }catch (IOException e){ + log.error("", e); + throw BusinessExceptionBuilder.build(ResponseCode.FILE_OPERATION_FAILED, e.getMessage()); + } + } + if (fos != null){ + try{ + fos.close(); + }catch (IOException e){ + log.error("", e); + throw BusinessExceptionBuilder.build(ResponseCode.FILE_OPERATION_FAILED, e.getMessage()); + } + } } + return file; } diff --git a/report-core/src/main/resources/bootstrap-dev.yml b/report-core/src/main/resources/bootstrap-dev.yml index ad947c14..f8383dc7 100644 --- a/report-core/src/main/resources/bootstrap-dev.yml +++ b/report-core/src/main/resources/bootstrap-dev.yml @@ -4,8 +4,17 @@ spring: url: jdbc:mysql://10.108.26.197:3306/aj_report?characterEncoding=UTF-8&serverTimezone=Asia/Shanghai&useSSL=false username: root password: appuser@anji + gaea: + subscribes: + oss: #文件存储 + enabled: true + ##允许上传的文件后缀 + file-type-while-list: .png|.jpg|.gif|.icon|.pdf|.xlsx|.xls|.csv|.mp4|.avi|.jpeg + # 用于文件上传成功后,生成文件的下载公网完整URL + downloadPath: http://127.0.0.1:9095/file/download + nfs: + path: D:\\aaa\\ + + + -customer: - file: - dist-path: D:\Workspace\AJ-Report\report-core\upload - downloadPath: http://127.0.0.1:9095/file/download diff --git a/report-core/src/main/resources/bootstrap-prod.yml b/report-core/src/main/resources/bootstrap-prod.yml index 17071c3d..d2b38dd9 100644 --- a/report-core/src/main/resources/bootstrap-prod.yml +++ b/report-core/src/main/resources/bootstrap-prod.yml @@ -4,7 +4,3 @@ spring: url: jdbc:mysql://10.108.26.197:3306/aj_report?characterEncoding=UTF-8&serverTimezone=Asia/Shanghai&useSSL=false username: root password: appuser@anji - -customer: - file: - dist-path: /app/disk/upload/ \ No newline at end of file diff --git a/report-core/src/main/resources/bootstrap.yml b/report-core/src/main/resources/bootstrap.yml index 2d3581a3..eb251e49 100644 --- a/report-core/src/main/resources/bootstrap.yml +++ b/report-core/src/main/resources/bootstrap.yml @@ -22,6 +22,14 @@ spring: url: jdbc:mysql://10.108.26.197:3306/aj_report?characterEncoding=UTF-8&serverTimezone=Asia/Shanghai&useSSL=false username: root password: appuser@anji + + #如果要使用redis,请参考report-core目录下的README.md文件中写的进行调整 +# redis: +# host: 127.0.0.1 +# port: 6379 +# password: root +# database: 1 + #数据源连接池配置 druid: initial-size: 10 # 初始化时建立物理连接的个数。初始化发生在显示调用init方法,或者第一次getConnection时 @@ -46,6 +54,31 @@ spring: placeholder-replacement: false init-sqls: - CREATE DATABASE IF NOT EXISTS `aj_report` DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci; + gaea: + subscribes: + oss: #文件存储 都配置的情况下优先级minio->amazonS3->nfs + enabled: true + ##允许上传的文件后缀 + file-type-while-list: .png|.jpg|.gif|.icon|.pdf|.xlsx|.xls|.csv|.mp4|.avi|.jpeg|.aaa + # 用于文件上传成功后,生成文件的下载公网完整URL + downloadPath: http://10.108.26.197:9095/file/download + nfs: + #上传对应本地全路径,目录必须是真实存在的,注意 Win是 \ 且有盘符,linux是 / 无盘符 + path: /app/disk/upload/ + #若要使用minio文件存储,请启用以下配置 + #minio: + # url: http://127.0.0.1 + # port: 9000 + # access-key: minioreport + # secret-key: minioreport + # bucket-name: aj-report + #若要使用amazonS3文件存储,请启用以下配置 + #amazonS3: + # url: http://127.0.0.1 + # access-key: access-key + # secret-key: secret-key + # bucket-name: AJ-Report + #若minio和amazonS3都没有,使用服务器高可用的nfs共享盘 mybatis-plus: configuration: @@ -64,18 +97,11 @@ logging: # 本应用自定义参数 customer: - # 开发测试用本地文件,如果是生产,请考虑使用对象存储 - file: - #上传对应本地全路径,目录必须是真实存在的,注意 Win是 \ 且有盘符,linux是 / 无盘符 - dist-path: /app/disk/upload/ - #dist-path: D:\Download - white-list: .png|.jpg|.jpeg|.gif|.icon|.pdf|.xlsx|.xls|.csv|.mp4|.avi - excelSuffix: .xlsx|.xls|.csv - #上传对应下载的下载链接路径 http://serverip:9095/file/download - downloadPath: http://10.108.26.197:9095/file/download - # 跳过token验证和权限验证的url清单 skip-authenticate-urls: /gaeaDict/all, /login, /static, /file/download/, /index.html, /favicon.ico, /reportShare/detailByCode + file: + #导入导出临时文件夹 默认.代表当前目录,拼接/tmp_zip/目录 + tmpPath: . user: ##新增用户默认密码 default: diff --git a/report-core/src/main/resources/i18n/messages_en_US.properties b/report-core/src/main/resources/i18n/messages_en_US.properties index 43cf12ef..9b373895 100644 --- a/report-core/src/main/resources/i18n/messages_en_US.properties +++ b/report-core/src/main/resources/i18n/messages_en_US.properties @@ -9,8 +9,9 @@ user.old.password.error=user old password error 1013=The code does not allow duplication 2001=File names are not allowed to be empty 2002=Unsupported suffix type -2003=File upload failed +2003=File upload failed:{0} 2004=File does not exist +file.operation.failed=File operation failed\uFF1A{0} field.not.null={} can not be null field.not.empty={} can not be empty @@ -37,16 +38,16 @@ Rule.field.value.is.required=Rule field value is required Rule.field.value.type.error=Rule field value type error Rule.fields.check.error=Rule fields check error Component.load.check.error={0} Component not load -4001=Data source connection failed +4001=Data source connection failed {0} 4002=Data source type is not currently supported -4003=execute sql error -4004=Incomplete parameter replacement values -4005=execute js error -4006=analysis data error +4003=execute sql error, {0} +4004=Incomplete parameter replacement values {0} +4005=execute js error {0} +4006=analysis data error {0} 4007=The report code does not allow duplication 4008=The set code does not allow duplication -4009=The source code does not allow duplication +4009=The source code does not allow duplication {0} 4010=Can't auto find match driver class -4011=execute javaBean error +4011=execute javaBean error {0} report.share.link.invalid=report share link invalid diff --git a/report-core/src/main/resources/i18n/messages_zh_CN.properties b/report-core/src/main/resources/i18n/messages_zh_CN.properties index a8e54261..7222ba5c 100644 --- a/report-core/src/main/resources/i18n/messages_zh_CN.properties +++ b/report-core/src/main/resources/i18n/messages_zh_CN.properties @@ -8,8 +8,9 @@ user.old.password.error=\u65E7\u5BC6\u7801\u4E0D\u6B63\u786E 1013=\u7F16\u7801\u4E0D\u5141\u8BB8\u91CD\u590D 2001=\u6587\u4EF6\u540D\u4E0D\u5141\u8BB8\u4E3A\u7A7A 2002=\u6587\u4EF6\u7C7B\u578B\u4E0D\u652F\u6301 -2003=\u6587\u4EF6\u4E0A\u4F20\u5931\u8D25 +2003=\u6587\u4EF6\u4E0A\u4F20\u5931\u8D25\uFF1A{0} 2004=\u6587\u4EF6\u4E0D\u5B58\u5728 +file.operation.failed=\u6587\u4EF6\u64CD\u4F5C\u5931\u8D25\uFF1A{0} field.not.null={}\u4E0D\u80FD\u4E3Anull field.not.empty={}\u4E0D\u80FD\u4E3A\u7A7A\u5B57\u7B26\u4E32 @@ -38,17 +39,17 @@ Rule.field.value.type.error=\u89C4\u5219\u5B57\u6BB5\u503C\u7C7B\u578B\u9519\u8B Rule.fields.check.error=\u89C4\u5219\u53C2\u6570\u6821\u9A8C\u4E0D\u901A\u8FC7 Component.load.check.error={0}\u7EC4\u4EF6\u672A\u52A0\u8F7D -4001=\u6570\u636E\u6E90\u8FDE\u63A5\u5931\u8D25 +4001=\u6570\u636E\u6E90\u8FDE\u63A5\u5931\u8D25\uFF0C{0} 4002=\u6570\u636E\u6E90\u7C7B\u578B\u6682\u4E0D\u652F\u6301 -4003=\u6267\u884Csql\u5931\u8D25 -4004=\u53C2\u6570\u66FF\u6362\u503C\u4E0D\u5168 -4005=\u6267\u884Cjs\u5931\u8D25 -4006=\u89E3\u6790\u6570\u636E\u5931\u8D25 +4003=\u6267\u884Csql\u5931\u8D25\uFF0C{0} +4004=\u53C2\u6570\u66FF\u6362\u503C\u4E0D\u5168\uFF0C{0} +4005=\u6267\u884Cjs\u5931\u8D25\uFF0C{0} +4006=\u89E3\u6790\u6570\u636E\u5931\u8D25\uFF0C{0} 4007=\u62A5\u8868\u7F16\u7801\u4E0D\u5141\u8BB8\u91CD\u590D 4008=\u6570\u636E\u96C6\u7F16\u7801\u4E0D\u5141\u8BB8\u91CD\u590D 4009=\u6570\u636E\u6E90\u7F16\u7801\u4E0D\u5141\u8BB8\u91CD\u590D -4010=\u9A71\u52A8\u5305\u4E0D\u5B58\u5728 -4011=\u6267\u884CjavaBean\u5931\u8D25 +4010=\u9A71\u52A8\u5305\u4E0D\u5B58\u5728\uFF0C{0} +4011=\u6267\u884CjavaBean\u5931\u8D25\uFF0C{0} 6001={0} 7001=\u89E3\u6790\u5931\u8D25 diff --git a/report-ui/src/utils/request.js b/report-ui/src/utils/request.js index 77453695..a985ccc8 100644 --- a/report-ui/src/utils/request.js +++ b/report-ui/src/utils/request.js @@ -27,8 +27,8 @@ service.interceptors.response.use( * code为非20000是抛错 可结合自己业务进行修改 */ const res = response.data - // 50008:非法的token; 50012:其他客户端登录了; 50014:Token 过期了; - if (res.code == '50008' || res.code == '50012' || res.code == '50014') { + // User.credentials.expired:非法的token; 50012:其他客户端登录了; 50014:Token 过期了; + if (res.code == 'User.credentials.expired' || res.code == '50012' || res.code == '50014') { MessageBox.confirm( '你已被登出,可以取消继续留在该页面,或者重新登录', '重新登录', diff --git a/report-ui/src/views/excelreport/designer/index.vue b/report-ui/src/views/excelreport/designer/index.vue index 64e05f1d..319a32a1 100644 --- a/report-ui/src/views/excelreport/designer/index.vue +++ b/report-ui/src/views/excelreport/designer/index.vue @@ -25,7 +25,7 @@ -
+ -
- 个人/商业使用须遵循Apache2.0开源协议。 +
+ 个人/商业使用须遵循Apache2.0开源协议。 禁止将AJ-Report产品用于违法违规业务。
diff --git a/report-ui/src/views/layout/components/Sidebar/index.vue b/report-ui/src/views/layout/components/Sidebar/index.vue index 170228c3..84fa6f68 100644 --- a/report-ui/src/views/layout/components/Sidebar/index.vue +++ b/report-ui/src/views/layout/components/Sidebar/index.vue @@ -3,7 +3,7 @@
- V0.9.8.1 + V0.9.8.5
-
+ -
- 个人/商业使用须遵循Apache2.0开源协议。 +
+ 个人/商业使用须遵循Apache2.0开源协议。 禁止将AJ-Report产品用于违法违规业务。