@@ -34,6 +34,12 @@ | |||||
<logback.version>1.2.13</logback.version> | <logback.version>1.2.13</logback.version> | ||||
<spring-security.version>5.7.12</spring-security.version> | <spring-security.version>5.7.12</spring-security.version> | ||||
<spring-framework.version>5.3.39</spring-framework.version> | <spring-framework.version>5.3.39</spring-framework.version> | ||||
<cn.hutool.all.version>5.5.4</cn.hutool.all.version> | |||||
<com.itextpdf.version>5.5.13.2</com.itextpdf.version> | |||||
<itext-asian.version>5.2.0</itext-asian.version> | |||||
<de.odysseus.juel.version>2.1.3</de.odysseus.juel.version> | |||||
<httpclient.version>4.5.13</httpclient.version> | |||||
<net.coobird.version>0.4.8</net.coobird.version> | |||||
</properties> | </properties> | ||||
<!-- 依赖声明 --> | <!-- 依赖声明 --> | ||||
@@ -182,6 +188,49 @@ | |||||
<version>${kaptcha.version}</version> | <version>${kaptcha.version}</version> | ||||
</dependency> | </dependency> | ||||
<!--hutool工具包--> | |||||
<dependency> | |||||
<groupId>cn.hutool</groupId> | |||||
<artifactId>hutool-all</artifactId> | |||||
<version>${cn.hutool.all.version}</version> | |||||
</dependency> | |||||
<dependency> | |||||
<groupId>de.odysseus.juel</groupId> | |||||
<artifactId>juel</artifactId> | |||||
<version>${de.odysseus.juel.version}</version> | |||||
</dependency> | |||||
<dependency> | |||||
<groupId>org.apache.httpcomponents</groupId> | |||||
<artifactId>httpclient</artifactId> | |||||
<version>${httpclient.version}</version> | |||||
</dependency> | |||||
<!--pdf--> | |||||
<dependency> | |||||
<groupId>com.itextpdf</groupId> | |||||
<artifactId>itextpdf</artifactId> | |||||
<version>${com.itextpdf.version}</version> | |||||
</dependency> | |||||
<!--pdf 字体--> | |||||
<dependency> | |||||
<groupId>com.itextpdf</groupId> | |||||
<artifactId>itext-asian</artifactId> | |||||
<version>${itext-asian.version}</version> | |||||
</dependency> | |||||
<!--thumbnailator图片处理--> | |||||
<dependency> | |||||
<groupId>net.coobird</groupId> | |||||
<artifactId>thumbnailator</artifactId> | |||||
<version>${net.coobird.version}</version> | |||||
</dependency> | |||||
<!-- 定时任务--> | <!-- 定时任务--> | ||||
<dependency> | <dependency> | ||||
<groupId>com.ruoyi</groupId> | <groupId>com.ruoyi</groupId> | ||||
@@ -61,6 +61,12 @@ | |||||
<artifactId>ruoyi-generator</artifactId> | <artifactId>ruoyi-generator</artifactId> | ||||
</dependency> | </dependency> | ||||
<!-- 业务模块--> | |||||
<dependency> | |||||
<groupId>com.ruoyi</groupId> | |||||
<artifactId>ruoyi-business</artifactId> | |||||
</dependency> | |||||
</dependencies> | </dependencies> | ||||
<build> | <build> | ||||
@@ -80,17 +86,17 @@ | |||||
</execution> | </execution> | ||||
</executions> | </executions> | ||||
</plugin> | </plugin> | ||||
<plugin> | |||||
<groupId>org.apache.maven.plugins</groupId> | |||||
<artifactId>maven-war-plugin</artifactId> | |||||
<version>3.1.0</version> | |||||
<plugin> | |||||
<groupId>org.apache.maven.plugins</groupId> | |||||
<artifactId>maven-war-plugin</artifactId> | |||||
<version>3.1.0</version> | |||||
<configuration> | <configuration> | ||||
<failOnMissingWebXml>false</failOnMissingWebXml> | <failOnMissingWebXml>false</failOnMissingWebXml> | ||||
<warName>${project.artifactId}</warName> | <warName>${project.artifactId}</warName> | ||||
</configuration> | |||||
</plugin> | |||||
</configuration> | |||||
</plugin> | |||||
</plugins> | </plugins> | ||||
<finalName>${project.artifactId}</finalName> | <finalName>${project.artifactId}</finalName> | ||||
</build> | </build> | ||||
</project> | |||||
</project> |
@@ -100,6 +100,7 @@ | |||||
<orderEntry type="library" name="Maven: org.springframework.security:spring-security-core:5.7.12" level="project" /> | <orderEntry type="library" name="Maven: org.springframework.security:spring-security-core:5.7.12" level="project" /> | ||||
<orderEntry type="library" name="Maven: org.springframework.security:spring-security-crypto:5.7.12" level="project" /> | <orderEntry type="library" name="Maven: org.springframework.security:spring-security-crypto:5.7.12" level="project" /> | ||||
<orderEntry type="library" name="Maven: org.springframework.security:spring-security-web:5.7.12" level="project" /> | <orderEntry type="library" name="Maven: org.springframework.security:spring-security-web:5.7.12" level="project" /> | ||||
<orderEntry type="library" name="Maven: net.coobird:thumbnailator:0.4.8" level="project" /> | |||||
<orderEntry type="library" name="Maven: com.github.pagehelper:pagehelper-spring-boot-starter:1.4.7" level="project" /> | <orderEntry type="library" name="Maven: com.github.pagehelper:pagehelper-spring-boot-starter:1.4.7" level="project" /> | ||||
<orderEntry type="library" name="Maven: org.mybatis.spring.boot:mybatis-spring-boot-starter:2.3.1" level="project" /> | <orderEntry type="library" name="Maven: org.mybatis.spring.boot:mybatis-spring-boot-starter:2.3.1" level="project" /> | ||||
<orderEntry type="library" name="Maven: org.springframework.boot:spring-boot-starter-jdbc:2.5.15" level="project" /> | <orderEntry type="library" name="Maven: org.springframework.boot:spring-boot-starter-jdbc:2.5.15" level="project" /> | ||||
@@ -115,6 +116,7 @@ | |||||
<orderEntry type="library" name="Maven: org.hibernate.validator:hibernate-validator:6.2.5.Final" level="project" /> | <orderEntry type="library" name="Maven: org.hibernate.validator:hibernate-validator:6.2.5.Final" level="project" /> | ||||
<orderEntry type="library" name="Maven: jakarta.validation:jakarta.validation-api:2.0.2" level="project" /> | <orderEntry type="library" name="Maven: jakarta.validation:jakarta.validation-api:2.0.2" level="project" /> | ||||
<orderEntry type="library" name="Maven: org.jboss.logging:jboss-logging:3.4.3.Final" level="project" /> | <orderEntry type="library" name="Maven: org.jboss.logging:jboss-logging:3.4.3.Final" level="project" /> | ||||
<orderEntry type="library" name="Maven: org.projectlombok:lombok:1.18.26" level="project" /> | |||||
<orderEntry type="library" name="Maven: org.apache.commons:commons-lang3:3.12.0" level="project" /> | <orderEntry type="library" name="Maven: org.apache.commons:commons-lang3:3.12.0" level="project" /> | ||||
<orderEntry type="library" name="Maven: com.fasterxml.jackson.core:jackson-databind:2.12.7.1" level="project" /> | <orderEntry type="library" name="Maven: com.fasterxml.jackson.core:jackson-databind:2.12.7.1" level="project" /> | ||||
<orderEntry type="library" name="Maven: com.fasterxml.jackson.core:jackson-core:2.12.7" level="project" /> | <orderEntry type="library" name="Maven: com.fasterxml.jackson.core:jackson-core:2.12.7" level="project" /> | ||||
@@ -122,7 +124,6 @@ | |||||
<orderEntry type="library" name="Maven: commons-io:commons-io:2.19.0" level="project" /> | <orderEntry type="library" name="Maven: commons-io:commons-io:2.19.0" level="project" /> | ||||
<orderEntry type="library" name="Maven: org.apache.poi:poi-ooxml:4.1.2" level="project" /> | <orderEntry type="library" name="Maven: org.apache.poi:poi-ooxml:4.1.2" level="project" /> | ||||
<orderEntry type="library" name="Maven: org.apache.poi:poi:4.1.2" level="project" /> | <orderEntry type="library" name="Maven: org.apache.poi:poi:4.1.2" level="project" /> | ||||
<orderEntry type="library" name="Maven: commons-codec:commons-codec:1.15" level="project" /> | |||||
<orderEntry type="library" name="Maven: org.apache.commons:commons-collections4:4.4" level="project" /> | <orderEntry type="library" name="Maven: org.apache.commons:commons-collections4:4.4" level="project" /> | ||||
<orderEntry type="library" name="Maven: org.apache.commons:commons-math3:3.6.1" level="project" /> | <orderEntry type="library" name="Maven: org.apache.commons:commons-math3:3.6.1" level="project" /> | ||||
<orderEntry type="library" name="Maven: com.zaxxer:SparseBitSet:1.2" level="project" /> | <orderEntry type="library" name="Maven: com.zaxxer:SparseBitSet:1.2" level="project" /> | ||||
@@ -132,6 +133,7 @@ | |||||
<orderEntry type="library" name="Maven: com.github.virtuald:curvesapi:1.06" level="project" /> | <orderEntry type="library" name="Maven: com.github.virtuald:curvesapi:1.06" level="project" /> | ||||
<orderEntry type="library" name="Maven: org.yaml:snakeyaml:1.28" level="project" /> | <orderEntry type="library" name="Maven: org.yaml:snakeyaml:1.28" level="project" /> | ||||
<orderEntry type="library" name="Maven: io.jsonwebtoken:jjwt:0.9.1" level="project" /> | <orderEntry type="library" name="Maven: io.jsonwebtoken:jjwt:0.9.1" level="project" /> | ||||
<orderEntry type="library" name="Maven: javax.servlet:javax.servlet-api:4.0.1" level="project" /> | |||||
<orderEntry type="library" name="Maven: javax.xml.bind:jaxb-api:2.3.1" level="project" /> | <orderEntry type="library" name="Maven: javax.xml.bind:jaxb-api:2.3.1" level="project" /> | ||||
<orderEntry type="library" name="Maven: javax.activation:javax.activation-api:1.2.0" level="project" /> | <orderEntry type="library" name="Maven: javax.activation:javax.activation-api:1.2.0" level="project" /> | ||||
<orderEntry type="library" name="Maven: org.springframework.boot:spring-boot-starter-data-redis:2.5.15" level="project" /> | <orderEntry type="library" name="Maven: org.springframework.boot:spring-boot-starter-data-redis:2.5.15" level="project" /> | ||||
@@ -152,8 +154,16 @@ | |||||
<orderEntry type="library" name="Maven: org.reactivestreams:reactive-streams:1.0.4" level="project" /> | <orderEntry type="library" name="Maven: org.reactivestreams:reactive-streams:1.0.4" level="project" /> | ||||
<orderEntry type="library" name="Maven: org.apache.commons:commons-pool2:2.9.0" level="project" /> | <orderEntry type="library" name="Maven: org.apache.commons:commons-pool2:2.9.0" level="project" /> | ||||
<orderEntry type="library" name="Maven: eu.bitwalker:UserAgentUtils:1.21" level="project" /> | <orderEntry type="library" name="Maven: eu.bitwalker:UserAgentUtils:1.21" level="project" /> | ||||
<orderEntry type="library" name="Maven: javax.servlet:javax.servlet-api:4.0.1" level="project" /> | |||||
<orderEntry type="library" name="Maven: com.itextpdf:itextpdf:5.5.13.2" level="project" /> | |||||
<orderEntry type="library" name="Maven: com.itextpdf:itext-asian:5.2.0" level="project" /> | |||||
<orderEntry type="library" name="Maven: cn.hutool:hutool-all:5.5.4" level="project" /> | |||||
<orderEntry type="module" module-name="ruoyi-generator" /> | <orderEntry type="module" module-name="ruoyi-generator" /> | ||||
<orderEntry type="library" name="Maven: org.apache.velocity:velocity-engine-core:2.3" level="project" /> | <orderEntry type="library" name="Maven: org.apache.velocity:velocity-engine-core:2.3" level="project" /> | ||||
<orderEntry type="module" module-name="ruoyi-business" /> | |||||
<orderEntry type="library" name="Maven: de.odysseus.juel:juel:2.1.3" level="project" /> | |||||
<orderEntry type="library" name="Maven: org.apache.httpcomponents:httpclient:4.5.13" level="project" /> | |||||
<orderEntry type="library" name="Maven: org.apache.httpcomponents:httpcore:4.4.16" level="project" /> | |||||
<orderEntry type="library" name="Maven: commons-logging:commons-logging:1.2" level="project" /> | |||||
<orderEntry type="library" name="Maven: commons-codec:commons-codec:1.15" level="project" /> | |||||
</component> | </component> | ||||
</module> | </module> |
@@ -1,9 +1,11 @@ | |||||
package com.ruoyi.web.controller.common; | package com.ruoyi.web.controller.common; | ||||
import java.util.ArrayList; | |||||
import java.util.List; | |||||
import javax.servlet.http.HttpServletRequest; | |||||
import javax.servlet.http.HttpServletResponse; | |||||
import com.ruoyi.common.config.RuoYiConfig; | |||||
import com.ruoyi.common.core.domain.AjaxResult; | |||||
import com.ruoyi.common.utils.StringUtils; | |||||
import com.ruoyi.common.utils.file.FileUploadUtils; | |||||
import com.ruoyi.common.utils.file.FileUtils; | |||||
import com.ruoyi.framework.config.ServerConfig; | |||||
import org.slf4j.Logger; | import org.slf4j.Logger; | ||||
import org.slf4j.LoggerFactory; | import org.slf4j.LoggerFactory; | ||||
import org.springframework.beans.factory.annotation.Autowired; | import org.springframework.beans.factory.annotation.Autowired; | ||||
@@ -13,22 +15,20 @@ import org.springframework.web.bind.annotation.PostMapping; | |||||
import org.springframework.web.bind.annotation.RequestMapping; | import org.springframework.web.bind.annotation.RequestMapping; | ||||
import org.springframework.web.bind.annotation.RestController; | import org.springframework.web.bind.annotation.RestController; | ||||
import org.springframework.web.multipart.MultipartFile; | import org.springframework.web.multipart.MultipartFile; | ||||
import com.ruoyi.common.config.RuoYiConfig; | |||||
import com.ruoyi.common.core.domain.AjaxResult; | |||||
import com.ruoyi.common.utils.StringUtils; | |||||
import com.ruoyi.common.utils.file.FileUploadUtils; | |||||
import com.ruoyi.common.utils.file.FileUtils; | |||||
import com.ruoyi.framework.config.ServerConfig; | |||||
import javax.servlet.http.HttpServletRequest; | |||||
import javax.servlet.http.HttpServletResponse; | |||||
import java.util.ArrayList; | |||||
import java.util.List; | |||||
/** | /** | ||||
* 通用请求处理 | * 通用请求处理 | ||||
* | |||||
* | |||||
* @author ruoyi | * @author ruoyi | ||||
*/ | */ | ||||
@RestController | @RestController | ||||
@RequestMapping("/common") | @RequestMapping("/common") | ||||
public class CommonController | |||||
{ | |||||
public class CommonController { | |||||
private static final Logger log = LoggerFactory.getLogger(CommonController.class); | private static final Logger log = LoggerFactory.getLogger(CommonController.class); | ||||
@Autowired | @Autowired | ||||
@@ -38,17 +38,14 @@ public class CommonController | |||||
/** | /** | ||||
* 通用下载请求 | * 通用下载请求 | ||||
* | |||||
* | |||||
* @param fileName 文件名称 | * @param fileName 文件名称 | ||||
* @param delete 是否删除 | |||||
* @param delete 是否删除 | |||||
*/ | */ | ||||
@GetMapping("/download") | @GetMapping("/download") | ||||
public void fileDownload(String fileName, Boolean delete, HttpServletResponse response, HttpServletRequest request) | |||||
{ | |||||
try | |||||
{ | |||||
if (!FileUtils.checkAllowDownload(fileName)) | |||||
{ | |||||
public void fileDownload(String fileName, Boolean delete, HttpServletResponse response, HttpServletRequest request) { | |||||
try { | |||||
if (!FileUtils.checkAllowDownload(fileName)) { | |||||
throw new Exception(StringUtils.format("文件名称({})非法,不允许下载。 ", fileName)); | throw new Exception(StringUtils.format("文件名称({})非法,不允许下载。 ", fileName)); | ||||
} | } | ||||
String realFileName = System.currentTimeMillis() + fileName.substring(fileName.indexOf("_") + 1); | String realFileName = System.currentTimeMillis() + fileName.substring(fileName.indexOf("_") + 1); | ||||
@@ -57,13 +54,10 @@ public class CommonController | |||||
response.setContentType(MediaType.APPLICATION_OCTET_STREAM_VALUE); | response.setContentType(MediaType.APPLICATION_OCTET_STREAM_VALUE); | ||||
FileUtils.setAttachmentResponseHeader(response, realFileName); | FileUtils.setAttachmentResponseHeader(response, realFileName); | ||||
FileUtils.writeBytes(filePath, response.getOutputStream()); | FileUtils.writeBytes(filePath, response.getOutputStream()); | ||||
if (delete) | |||||
{ | |||||
if (delete) { | |||||
FileUtils.deleteFile(filePath); | FileUtils.deleteFile(filePath); | ||||
} | } | ||||
} | |||||
catch (Exception e) | |||||
{ | |||||
} catch (Exception e) { | |||||
log.error("下载文件失败", e); | log.error("下载文件失败", e); | ||||
} | } | ||||
} | } | ||||
@@ -72,10 +66,8 @@ public class CommonController | |||||
* 通用上传请求(单个) | * 通用上传请求(单个) | ||||
*/ | */ | ||||
@PostMapping("/upload") | @PostMapping("/upload") | ||||
public AjaxResult uploadFile(MultipartFile file) throws Exception | |||||
{ | |||||
try | |||||
{ | |||||
public AjaxResult uploadFile(MultipartFile file) throws Exception { | |||||
try { | |||||
// 上传文件路径 | // 上传文件路径 | ||||
String filePath = RuoYiConfig.getUploadPath(); | String filePath = RuoYiConfig.getUploadPath(); | ||||
// 上传并返回新文件名称 | // 上传并返回新文件名称 | ||||
@@ -87,9 +79,7 @@ public class CommonController | |||||
ajax.put("newFileName", FileUtils.getName(fileName)); | ajax.put("newFileName", FileUtils.getName(fileName)); | ||||
ajax.put("originalFilename", file.getOriginalFilename()); | ajax.put("originalFilename", file.getOriginalFilename()); | ||||
return ajax; | return ajax; | ||||
} | |||||
catch (Exception e) | |||||
{ | |||||
} catch (Exception e) { | |||||
return AjaxResult.error(e.getMessage()); | return AjaxResult.error(e.getMessage()); | ||||
} | } | ||||
} | } | ||||
@@ -98,18 +88,15 @@ public class CommonController | |||||
* 通用上传请求(多个) | * 通用上传请求(多个) | ||||
*/ | */ | ||||
@PostMapping("/uploads") | @PostMapping("/uploads") | ||||
public AjaxResult uploadFiles(List<MultipartFile> files) throws Exception | |||||
{ | |||||
try | |||||
{ | |||||
public AjaxResult uploadFiles(List<MultipartFile> files) throws Exception { | |||||
try { | |||||
// 上传文件路径 | // 上传文件路径 | ||||
String filePath = RuoYiConfig.getUploadPath(); | String filePath = RuoYiConfig.getUploadPath(); | ||||
List<String> urls = new ArrayList<String>(); | List<String> urls = new ArrayList<String>(); | ||||
List<String> fileNames = new ArrayList<String>(); | List<String> fileNames = new ArrayList<String>(); | ||||
List<String> newFileNames = new ArrayList<String>(); | List<String> newFileNames = new ArrayList<String>(); | ||||
List<String> originalFilenames = new ArrayList<String>(); | List<String> originalFilenames = new ArrayList<String>(); | ||||
for (MultipartFile file : files) | |||||
{ | |||||
for (MultipartFile file : files) { | |||||
// 上传并返回新文件名称 | // 上传并返回新文件名称 | ||||
String fileName = FileUploadUtils.upload(filePath, file); | String fileName = FileUploadUtils.upload(filePath, file); | ||||
String url = serverConfig.getUrl() + fileName; | String url = serverConfig.getUrl() + fileName; | ||||
@@ -124,9 +111,7 @@ public class CommonController | |||||
ajax.put("newFileNames", StringUtils.join(newFileNames, FILE_DELIMETER)); | ajax.put("newFileNames", StringUtils.join(newFileNames, FILE_DELIMETER)); | ||||
ajax.put("originalFilenames", StringUtils.join(originalFilenames, FILE_DELIMETER)); | ajax.put("originalFilenames", StringUtils.join(originalFilenames, FILE_DELIMETER)); | ||||
return ajax; | return ajax; | ||||
} | |||||
catch (Exception e) | |||||
{ | |||||
} catch (Exception e) { | |||||
return AjaxResult.error(e.getMessage()); | return AjaxResult.error(e.getMessage()); | ||||
} | } | ||||
} | } | ||||
@@ -136,12 +121,9 @@ public class CommonController | |||||
*/ | */ | ||||
@GetMapping("/download/resource") | @GetMapping("/download/resource") | ||||
public void resourceDownload(String resource, HttpServletRequest request, HttpServletResponse response) | public void resourceDownload(String resource, HttpServletRequest request, HttpServletResponse response) | ||||
throws Exception | |||||
{ | |||||
try | |||||
{ | |||||
if (!FileUtils.checkAllowDownload(resource)) | |||||
{ | |||||
throws Exception { | |||||
try { | |||||
if (!FileUtils.checkAllowDownload(resource)) { | |||||
throw new Exception(StringUtils.format("资源文件({})非法,不允许下载。 ", resource)); | throw new Exception(StringUtils.format("资源文件({})非法,不允许下载。 ", resource)); | ||||
} | } | ||||
// 本地资源路径 | // 本地资源路径 | ||||
@@ -153,9 +135,7 @@ public class CommonController | |||||
response.setContentType(MediaType.APPLICATION_OCTET_STREAM_VALUE); | response.setContentType(MediaType.APPLICATION_OCTET_STREAM_VALUE); | ||||
FileUtils.setAttachmentResponseHeader(response, downloadName); | FileUtils.setAttachmentResponseHeader(response, downloadName); | ||||
FileUtils.writeBytes(downloadPath, response.getOutputStream()); | FileUtils.writeBytes(downloadPath, response.getOutputStream()); | ||||
} | |||||
catch (Exception e) | |||||
{ | |||||
} catch (Exception e) { | |||||
log.error("下载文件失败", e); | log.error("下载文件失败", e); | ||||
} | } | ||||
} | } | ||||
@@ -1,15 +1,5 @@ | |||||
package com.ruoyi.web.controller.system; | package com.ruoyi.web.controller.system; | ||||
import java.util.Map; | |||||
import org.springframework.beans.factory.annotation.Autowired; | |||||
import org.springframework.web.bind.annotation.GetMapping; | |||||
import org.springframework.web.bind.annotation.PostMapping; | |||||
import org.springframework.web.bind.annotation.PutMapping; | |||||
import org.springframework.web.bind.annotation.RequestBody; | |||||
import org.springframework.web.bind.annotation.RequestMapping; | |||||
import org.springframework.web.bind.annotation.RequestParam; | |||||
import org.springframework.web.bind.annotation.RestController; | |||||
import org.springframework.web.multipart.MultipartFile; | |||||
import com.ruoyi.common.annotation.Log; | import com.ruoyi.common.annotation.Log; | ||||
import com.ruoyi.common.config.RuoYiConfig; | import com.ruoyi.common.config.RuoYiConfig; | ||||
import com.ruoyi.common.core.controller.BaseController; | import com.ruoyi.common.core.controller.BaseController; | ||||
@@ -25,10 +15,15 @@ import com.ruoyi.common.utils.file.FileUtils; | |||||
import com.ruoyi.common.utils.file.MimeTypeUtils; | import com.ruoyi.common.utils.file.MimeTypeUtils; | ||||
import com.ruoyi.framework.web.service.TokenService; | import com.ruoyi.framework.web.service.TokenService; | ||||
import com.ruoyi.system.service.ISysUserService; | import com.ruoyi.system.service.ISysUserService; | ||||
import org.springframework.beans.factory.annotation.Autowired; | |||||
import org.springframework.web.bind.annotation.*; | |||||
import org.springframework.web.multipart.MultipartFile; | |||||
import java.util.Map; | |||||
/** | /** | ||||
* 个人信息 业务处理 | * 个人信息 业务处理 | ||||
* | |||||
* | |||||
* @author ruoyi | * @author ruoyi | ||||
*/ | */ | ||||
@RestController | @RestController | ||||
@@ -127,7 +122,7 @@ public class SysProfileController extends BaseController | |||||
if (!file.isEmpty()) | if (!file.isEmpty()) | ||||
{ | { | ||||
LoginUser loginUser = getLoginUser(); | LoginUser loginUser = getLoginUser(); | ||||
String avatar = FileUploadUtils.upload(RuoYiConfig.getAvatarPath(), file, MimeTypeUtils.IMAGE_EXTENSION, true); | |||||
String avatar = FileUploadUtils.upload(RuoYiConfig.getAvatarPath(), file, MimeTypeUtils.IMAGE_EXTENSION); | |||||
if (userService.updateUserAvatar(loginUser.getUserId(), avatar)) | if (userService.updateUserAvatar(loginUser.getUserId(), avatar)) | ||||
{ | { | ||||
String oldAvatar = loginUser.getUser().getAvatar(); | String oldAvatar = loginUser.getUser().getAvatar(); | ||||
@@ -6,7 +6,7 @@ spring: | |||||
druid: | druid: | ||||
# 主库数据源 | # 主库数据源 | ||||
master: | master: | ||||
url: jdbc:mysql://192.168.0.119:3318/rongxin_base?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8 | |||||
url: jdbc:mysql://localhost:3318/rongxin_base?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8 | |||||
username: nsbjgkwh | username: nsbjgkwh | ||||
password: ns61GK32x% | password: ns61GK32x% | ||||
# 从库数据源 | # 从库数据源 | ||||
@@ -1,7 +1,7 @@ | |||||
# 项目相关配置 | # 项目相关配置 | ||||
ruoyi: | ruoyi: | ||||
# 名称 | # 名称 | ||||
name: RuoYi | |||||
name: RongXin | |||||
# 版本 | # 版本 | ||||
version: 3.9.0 | version: 3.9.0 | ||||
# 版权年份 | # 版权年份 | ||||
@@ -12,4 +12,39 @@ | |||||
<artifactId>ruoyi-business</artifactId> | <artifactId>ruoyi-business</artifactId> | ||||
<dependencies> | |||||
<!-- 系统模块--> | |||||
<dependency> | |||||
<groupId>com.ruoyi</groupId> | |||||
<artifactId>ruoyi-system</artifactId> | |||||
</dependency> | |||||
<!-- 通用工具--> | |||||
<dependency> | |||||
<groupId>com.ruoyi</groupId> | |||||
<artifactId>ruoyi-common</artifactId> | |||||
</dependency> | |||||
<!--hutool工具包--> | |||||
<!--<dependency> | |||||
<groupId>cn.hutool</groupId> | |||||
<artifactId>hutool-all</artifactId> | |||||
</dependency>--> | |||||
<dependency> | |||||
<groupId>de.odysseus.juel</groupId> | |||||
<artifactId>juel</artifactId> | |||||
</dependency> | |||||
<dependency> | |||||
<groupId>org.apache.httpcomponents</groupId> | |||||
<artifactId>httpclient</artifactId> | |||||
</dependency> | |||||
</dependencies> | |||||
</project> | </project> |
@@ -0,0 +1,111 @@ | |||||
<?xml version="1.0" encoding="UTF-8"?> | |||||
<module org.jetbrains.idea.maven.project.MavenProjectsManager.isMavenModule="true" type="JAVA_MODULE" version="4"> | |||||
<component name="FacetManager"> | |||||
<facet type="Spring" name="Spring"> | |||||
<configuration /> | |||||
</facet> | |||||
</component> | |||||
<component name="NewModuleRootManager" LANGUAGE_LEVEL="JDK_1_8"> | |||||
<output url="file://$MODULE_DIR$/target/classes" /> | |||||
<output-test url="file://$MODULE_DIR$/target/test-classes" /> | |||||
<content url="file://$MODULE_DIR$"> | |||||
<sourceFolder url="file://$MODULE_DIR$/src/main/java" isTestSource="false" /> | |||||
<sourceFolder url="file://$MODULE_DIR$/src/main/resources" type="java-resource" /> | |||||
<sourceFolder url="file://$MODULE_DIR$/src/test/java" isTestSource="true" /> | |||||
<excludeFolder url="file://$MODULE_DIR$/target" /> | |||||
</content> | |||||
<orderEntry type="inheritedJdk" /> | |||||
<orderEntry type="sourceFolder" forTests="false" /> | |||||
<orderEntry type="module" module-name="ruoyi-system" /> | |||||
<orderEntry type="module" module-name="ruoyi-common" /> | |||||
<orderEntry type="library" name="Maven: org.springframework:spring-context-support:5.3.39" level="project" /> | |||||
<orderEntry type="library" name="Maven: org.springframework:spring-beans:5.3.39" level="project" /> | |||||
<orderEntry type="library" name="Maven: org.springframework:spring-context:5.3.39" level="project" /> | |||||
<orderEntry type="library" name="Maven: org.springframework:spring-expression:5.3.39" level="project" /> | |||||
<orderEntry type="library" name="Maven: org.springframework:spring-core:5.3.39" level="project" /> | |||||
<orderEntry type="library" name="Maven: org.springframework:spring-jcl:5.3.39" level="project" /> | |||||
<orderEntry type="library" name="Maven: org.springframework:spring-web:5.3.39" level="project" /> | |||||
<orderEntry type="library" name="Maven: org.springframework.boot:spring-boot-starter-security:2.5.15" level="project" /> | |||||
<orderEntry type="library" name="Maven: org.springframework.boot:spring-boot-starter:2.5.15" level="project" /> | |||||
<orderEntry type="library" name="Maven: org.springframework.boot:spring-boot:2.5.15" level="project" /> | |||||
<orderEntry type="library" name="Maven: org.springframework.boot:spring-boot-autoconfigure:2.5.15" level="project" /> | |||||
<orderEntry type="library" name="Maven: org.springframework.boot:spring-boot-starter-logging:2.5.15" level="project" /> | |||||
<orderEntry type="library" name="Maven: ch.qos.logback:logback-classic:1.2.13" level="project" /> | |||||
<orderEntry type="library" name="Maven: ch.qos.logback:logback-core:1.2.13" level="project" /> | |||||
<orderEntry type="library" name="Maven: org.apache.logging.log4j:log4j-to-slf4j:2.17.2" level="project" /> | |||||
<orderEntry type="library" name="Maven: org.apache.logging.log4j:log4j-api:2.17.2" level="project" /> | |||||
<orderEntry type="library" name="Maven: org.slf4j:jul-to-slf4j:1.7.36" level="project" /> | |||||
<orderEntry type="library" name="Maven: jakarta.annotation:jakarta.annotation-api:1.3.5" level="project" /> | |||||
<orderEntry type="library" name="Maven: org.springframework:spring-aop:5.3.39" level="project" /> | |||||
<orderEntry type="library" name="Maven: org.springframework.security:spring-security-config:5.7.12" level="project" /> | |||||
<orderEntry type="library" name="Maven: org.springframework.security:spring-security-core:5.7.12" level="project" /> | |||||
<orderEntry type="library" name="Maven: org.springframework.security:spring-security-crypto:5.7.12" level="project" /> | |||||
<orderEntry type="library" name="Maven: org.springframework.security:spring-security-web:5.7.12" level="project" /> | |||||
<orderEntry type="library" name="Maven: net.coobird:thumbnailator:0.4.8" level="project" /> | |||||
<orderEntry type="library" name="Maven: com.github.pagehelper:pagehelper-spring-boot-starter:1.4.7" level="project" /> | |||||
<orderEntry type="library" name="Maven: org.mybatis.spring.boot:mybatis-spring-boot-starter:2.3.1" level="project" /> | |||||
<orderEntry type="library" name="Maven: org.springframework.boot:spring-boot-starter-jdbc:2.5.15" level="project" /> | |||||
<orderEntry type="library" name="Maven: com.zaxxer:HikariCP:4.0.3" level="project" /> | |||||
<orderEntry type="library" name="Maven: org.springframework:spring-jdbc:5.3.39" level="project" /> | |||||
<orderEntry type="library" name="Maven: org.mybatis.spring.boot:mybatis-spring-boot-autoconfigure:2.3.1" level="project" /> | |||||
<orderEntry type="library" name="Maven: org.mybatis:mybatis:3.5.13" level="project" /> | |||||
<orderEntry type="library" name="Maven: org.mybatis:mybatis-spring:2.1.1" level="project" /> | |||||
<orderEntry type="library" name="Maven: com.github.pagehelper:pagehelper-spring-boot-autoconfigure:1.4.7" level="project" /> | |||||
<orderEntry type="library" name="Maven: com.github.pagehelper:pagehelper:5.3.3" level="project" /> | |||||
<orderEntry type="library" name="Maven: com.github.jsqlparser:jsqlparser:4.5" level="project" /> | |||||
<orderEntry type="library" name="Maven: org.springframework.boot:spring-boot-starter-validation:2.5.15" level="project" /> | |||||
<orderEntry type="library" name="Maven: org.apache.tomcat.embed:tomcat-embed-el:9.0.106" level="project" /> | |||||
<orderEntry type="library" name="Maven: org.hibernate.validator:hibernate-validator:6.2.5.Final" level="project" /> | |||||
<orderEntry type="library" name="Maven: jakarta.validation:jakarta.validation-api:2.0.2" level="project" /> | |||||
<orderEntry type="library" name="Maven: org.jboss.logging:jboss-logging:3.4.3.Final" level="project" /> | |||||
<orderEntry type="library" name="Maven: com.fasterxml:classmate:1.5.1" level="project" /> | |||||
<orderEntry type="library" name="Maven: org.projectlombok:lombok:1.18.26" level="project" /> | |||||
<orderEntry type="library" name="Maven: org.apache.commons:commons-lang3:3.12.0" level="project" /> | |||||
<orderEntry type="library" name="Maven: com.fasterxml.jackson.core:jackson-databind:2.12.7.1" level="project" /> | |||||
<orderEntry type="library" name="Maven: com.fasterxml.jackson.core:jackson-annotations:2.12.7" level="project" /> | |||||
<orderEntry type="library" name="Maven: com.fasterxml.jackson.core:jackson-core:2.12.7" level="project" /> | |||||
<orderEntry type="library" name="Maven: com.alibaba.fastjson2:fastjson2:2.0.57" level="project" /> | |||||
<orderEntry type="library" name="Maven: commons-io:commons-io:2.19.0" level="project" /> | |||||
<orderEntry type="library" name="Maven: org.apache.poi:poi-ooxml:4.1.2" level="project" /> | |||||
<orderEntry type="library" name="Maven: org.apache.poi:poi:4.1.2" level="project" /> | |||||
<orderEntry type="library" name="Maven: org.apache.commons:commons-collections4:4.4" level="project" /> | |||||
<orderEntry type="library" name="Maven: org.apache.commons:commons-math3:3.6.1" level="project" /> | |||||
<orderEntry type="library" name="Maven: com.zaxxer:SparseBitSet:1.2" level="project" /> | |||||
<orderEntry type="library" name="Maven: org.apache.poi:poi-ooxml-schemas:4.1.2" level="project" /> | |||||
<orderEntry type="library" name="Maven: org.apache.xmlbeans:xmlbeans:3.1.0" level="project" /> | |||||
<orderEntry type="library" name="Maven: org.apache.commons:commons-compress:1.19" level="project" /> | |||||
<orderEntry type="library" name="Maven: com.github.virtuald:curvesapi:1.06" level="project" /> | |||||
<orderEntry type="library" name="Maven: org.yaml:snakeyaml:1.28" level="project" /> | |||||
<orderEntry type="library" name="Maven: io.jsonwebtoken:jjwt:0.9.1" level="project" /> | |||||
<orderEntry type="library" name="Maven: javax.servlet:javax.servlet-api:4.0.1" level="project" /> | |||||
<orderEntry type="library" name="Maven: javax.xml.bind:jaxb-api:2.3.1" level="project" /> | |||||
<orderEntry type="library" name="Maven: javax.activation:javax.activation-api:1.2.0" level="project" /> | |||||
<orderEntry type="library" name="Maven: org.springframework.boot:spring-boot-starter-data-redis:2.5.15" level="project" /> | |||||
<orderEntry type="library" name="Maven: org.springframework.data:spring-data-redis:2.5.12" level="project" /> | |||||
<orderEntry type="library" name="Maven: org.springframework.data:spring-data-keyvalue:2.5.12" level="project" /> | |||||
<orderEntry type="library" name="Maven: org.springframework.data:spring-data-commons:2.5.12" level="project" /> | |||||
<orderEntry type="library" name="Maven: org.springframework:spring-tx:5.3.39" level="project" /> | |||||
<orderEntry type="library" name="Maven: org.springframework:spring-oxm:5.3.39" level="project" /> | |||||
<orderEntry type="library" name="Maven: org.slf4j:slf4j-api:1.7.36" level="project" /> | |||||
<orderEntry type="library" name="Maven: io.lettuce:lettuce-core:6.1.10.RELEASE" level="project" /> | |||||
<orderEntry type="library" name="Maven: io.netty:netty-common:4.1.92.Final" level="project" /> | |||||
<orderEntry type="library" name="Maven: io.netty:netty-handler:4.1.92.Final" level="project" /> | |||||
<orderEntry type="library" name="Maven: io.netty:netty-resolver:4.1.92.Final" level="project" /> | |||||
<orderEntry type="library" name="Maven: io.netty:netty-buffer:4.1.92.Final" level="project" /> | |||||
<orderEntry type="library" name="Maven: io.netty:netty-transport-native-unix-common:4.1.92.Final" level="project" /> | |||||
<orderEntry type="library" name="Maven: io.netty:netty-codec:4.1.92.Final" level="project" /> | |||||
<orderEntry type="library" name="Maven: io.netty:netty-transport:4.1.92.Final" level="project" /> | |||||
<orderEntry type="library" name="Maven: io.projectreactor:reactor-core:3.4.29" level="project" /> | |||||
<orderEntry type="library" name="Maven: org.reactivestreams:reactive-streams:1.0.4" level="project" /> | |||||
<orderEntry type="library" name="Maven: org.apache.commons:commons-pool2:2.9.0" level="project" /> | |||||
<orderEntry type="library" name="Maven: eu.bitwalker:UserAgentUtils:1.21" level="project" /> | |||||
<orderEntry type="library" name="Maven: com.itextpdf:itextpdf:5.5.13.2" level="project" /> | |||||
<orderEntry type="library" name="Maven: com.itextpdf:itext-asian:5.2.0" level="project" /> | |||||
<orderEntry type="library" name="Maven: cn.hutool:hutool-all:5.5.4" level="project" /> | |||||
<orderEntry type="library" name="Maven: de.odysseus.juel:juel:2.1.3" level="project" /> | |||||
<orderEntry type="library" name="Maven: org.apache.httpcomponents:httpclient:4.5.13" level="project" /> | |||||
<orderEntry type="library" name="Maven: org.apache.httpcomponents:httpcore:4.4.16" level="project" /> | |||||
<orderEntry type="library" name="Maven: commons-logging:commons-logging:1.2" level="project" /> | |||||
<orderEntry type="library" name="Maven: commons-codec:commons-codec:1.15" level="project" /> | |||||
</component> | |||||
</module> |
@@ -35,6 +35,12 @@ | |||||
<artifactId>spring-boot-starter-security</artifactId> | <artifactId>spring-boot-starter-security</artifactId> | ||||
</dependency> | </dependency> | ||||
<!--thumbnailator图片处理--> | |||||
<dependency> | |||||
<groupId>net.coobird</groupId> | |||||
<artifactId>thumbnailator</artifactId> | |||||
</dependency> | |||||
<!-- pagehelper 分页插件 --> | <!-- pagehelper 分页插件 --> | ||||
<dependency> | <dependency> | ||||
<groupId>com.github.pagehelper</groupId> | <groupId>com.github.pagehelper</groupId> | ||||
@@ -47,18 +53,24 @@ | |||||
<artifactId>spring-boot-starter-validation</artifactId> | <artifactId>spring-boot-starter-validation</artifactId> | ||||
</dependency> | </dependency> | ||||
<!-- lombok --> | |||||
<dependency> | |||||
<groupId>org.projectlombok</groupId> | |||||
<artifactId>lombok</artifactId> | |||||
</dependency> | |||||
<!--常用工具类 --> | <!--常用工具类 --> | ||||
<dependency> | <dependency> | ||||
<groupId>org.apache.commons</groupId> | <groupId>org.apache.commons</groupId> | ||||
<artifactId>commons-lang3</artifactId> | <artifactId>commons-lang3</artifactId> | ||||
</dependency> | </dependency> | ||||
<!-- JSON工具类 --> | <!-- JSON工具类 --> | ||||
<dependency> | <dependency> | ||||
<groupId>com.fasterxml.jackson.core</groupId> | <groupId>com.fasterxml.jackson.core</groupId> | ||||
<artifactId>jackson-databind</artifactId> | <artifactId>jackson-databind</artifactId> | ||||
</dependency> | </dependency> | ||||
<!-- 阿里JSON解析器 --> | <!-- 阿里JSON解析器 --> | ||||
<dependency> | <dependency> | ||||
<groupId>com.alibaba.fastjson2</groupId> | <groupId>com.alibaba.fastjson2</groupId> | ||||
@@ -89,6 +101,12 @@ | |||||
<artifactId>jjwt</artifactId> | <artifactId>jjwt</artifactId> | ||||
</dependency> | </dependency> | ||||
<!-- servlet包 --> | |||||
<dependency> | |||||
<groupId>javax.servlet</groupId> | |||||
<artifactId>javax.servlet-api</artifactId> | |||||
</dependency> | |||||
<!-- Jaxb --> | <!-- Jaxb --> | ||||
<dependency> | <dependency> | ||||
<groupId>javax.xml.bind</groupId> | <groupId>javax.xml.bind</groupId> | ||||
@@ -119,6 +137,25 @@ | |||||
<artifactId>javax.servlet-api</artifactId> | <artifactId>javax.servlet-api</artifactId> | ||||
</dependency> | </dependency> | ||||
<!--pdf--> | |||||
<dependency> | |||||
<groupId>com.itextpdf</groupId> | |||||
<artifactId>itextpdf</artifactId> | |||||
</dependency> | |||||
<!--pdf 字体--> | |||||
<dependency> | |||||
<groupId>com.itextpdf</groupId> | |||||
<artifactId>itext-asian</artifactId> | |||||
</dependency> | |||||
<!-- hutool --> | |||||
<dependency> | |||||
<groupId>cn.hutool</groupId> | |||||
<artifactId>hutool-all</artifactId> | |||||
</dependency> | |||||
</dependencies> | </dependencies> | ||||
</project> | |||||
</project> |
@@ -37,6 +37,7 @@ | |||||
<orderEntry type="library" name="Maven: org.springframework.security:spring-security-core:5.7.12" level="project" /> | <orderEntry type="library" name="Maven: org.springframework.security:spring-security-core:5.7.12" level="project" /> | ||||
<orderEntry type="library" name="Maven: org.springframework.security:spring-security-crypto:5.7.12" level="project" /> | <orderEntry type="library" name="Maven: org.springframework.security:spring-security-crypto:5.7.12" level="project" /> | ||||
<orderEntry type="library" name="Maven: org.springframework.security:spring-security-web:5.7.12" level="project" /> | <orderEntry type="library" name="Maven: org.springframework.security:spring-security-web:5.7.12" level="project" /> | ||||
<orderEntry type="library" name="Maven: net.coobird:thumbnailator:0.4.8" level="project" /> | |||||
<orderEntry type="library" name="Maven: com.github.pagehelper:pagehelper-spring-boot-starter:1.4.7" level="project" /> | <orderEntry type="library" name="Maven: com.github.pagehelper:pagehelper-spring-boot-starter:1.4.7" level="project" /> | ||||
<orderEntry type="library" name="Maven: org.mybatis.spring.boot:mybatis-spring-boot-starter:2.3.1" level="project" /> | <orderEntry type="library" name="Maven: org.mybatis.spring.boot:mybatis-spring-boot-starter:2.3.1" level="project" /> | ||||
<orderEntry type="library" name="Maven: org.springframework.boot:spring-boot-starter-jdbc:2.5.15" level="project" /> | <orderEntry type="library" name="Maven: org.springframework.boot:spring-boot-starter-jdbc:2.5.15" level="project" /> | ||||
@@ -54,6 +55,7 @@ | |||||
<orderEntry type="library" name="Maven: jakarta.validation:jakarta.validation-api:2.0.2" level="project" /> | <orderEntry type="library" name="Maven: jakarta.validation:jakarta.validation-api:2.0.2" level="project" /> | ||||
<orderEntry type="library" name="Maven: org.jboss.logging:jboss-logging:3.4.3.Final" level="project" /> | <orderEntry type="library" name="Maven: org.jboss.logging:jboss-logging:3.4.3.Final" level="project" /> | ||||
<orderEntry type="library" name="Maven: com.fasterxml:classmate:1.5.1" level="project" /> | <orderEntry type="library" name="Maven: com.fasterxml:classmate:1.5.1" level="project" /> | ||||
<orderEntry type="library" name="Maven: org.projectlombok:lombok:1.18.26" level="project" /> | |||||
<orderEntry type="library" name="Maven: org.apache.commons:commons-lang3:3.12.0" level="project" /> | <orderEntry type="library" name="Maven: org.apache.commons:commons-lang3:3.12.0" level="project" /> | ||||
<orderEntry type="library" name="Maven: com.fasterxml.jackson.core:jackson-databind:2.12.7.1" level="project" /> | <orderEntry type="library" name="Maven: com.fasterxml.jackson.core:jackson-databind:2.12.7.1" level="project" /> | ||||
<orderEntry type="library" name="Maven: com.fasterxml.jackson.core:jackson-annotations:2.12.7" level="project" /> | <orderEntry type="library" name="Maven: com.fasterxml.jackson.core:jackson-annotations:2.12.7" level="project" /> | ||||
@@ -72,6 +74,7 @@ | |||||
<orderEntry type="library" name="Maven: com.github.virtuald:curvesapi:1.06" level="project" /> | <orderEntry type="library" name="Maven: com.github.virtuald:curvesapi:1.06" level="project" /> | ||||
<orderEntry type="library" name="Maven: org.yaml:snakeyaml:1.28" level="project" /> | <orderEntry type="library" name="Maven: org.yaml:snakeyaml:1.28" level="project" /> | ||||
<orderEntry type="library" name="Maven: io.jsonwebtoken:jjwt:0.9.1" level="project" /> | <orderEntry type="library" name="Maven: io.jsonwebtoken:jjwt:0.9.1" level="project" /> | ||||
<orderEntry type="library" name="Maven: javax.servlet:javax.servlet-api:4.0.1" level="project" /> | |||||
<orderEntry type="library" name="Maven: javax.xml.bind:jaxb-api:2.3.1" level="project" /> | <orderEntry type="library" name="Maven: javax.xml.bind:jaxb-api:2.3.1" level="project" /> | ||||
<orderEntry type="library" name="Maven: javax.activation:javax.activation-api:1.2.0" level="project" /> | <orderEntry type="library" name="Maven: javax.activation:javax.activation-api:1.2.0" level="project" /> | ||||
<orderEntry type="library" name="Maven: org.springframework.boot:spring-boot-starter-data-redis:2.5.15" level="project" /> | <orderEntry type="library" name="Maven: org.springframework.boot:spring-boot-starter-data-redis:2.5.15" level="project" /> | ||||
@@ -93,6 +96,8 @@ | |||||
<orderEntry type="library" name="Maven: org.reactivestreams:reactive-streams:1.0.4" level="project" /> | <orderEntry type="library" name="Maven: org.reactivestreams:reactive-streams:1.0.4" level="project" /> | ||||
<orderEntry type="library" name="Maven: org.apache.commons:commons-pool2:2.9.0" level="project" /> | <orderEntry type="library" name="Maven: org.apache.commons:commons-pool2:2.9.0" level="project" /> | ||||
<orderEntry type="library" name="Maven: eu.bitwalker:UserAgentUtils:1.21" level="project" /> | <orderEntry type="library" name="Maven: eu.bitwalker:UserAgentUtils:1.21" level="project" /> | ||||
<orderEntry type="library" name="Maven: javax.servlet:javax.servlet-api:4.0.1" level="project" /> | |||||
<orderEntry type="library" name="Maven: com.itextpdf:itextpdf:5.5.13.2" level="project" /> | |||||
<orderEntry type="library" name="Maven: com.itextpdf:itext-asian:5.2.0" level="project" /> | |||||
<orderEntry type="library" name="Maven: cn.hutool:hutool-all:5.5.4" level="project" /> | |||||
</component> | </component> | ||||
</module> | </module> |
@@ -5,7 +5,7 @@ import org.springframework.stereotype.Component; | |||||
/** | /** | ||||
* 读取项目相关配置 | * 读取项目相关配置 | ||||
* | |||||
* | |||||
* @author ruoyi | * @author ruoyi | ||||
*/ | */ | ||||
@Component | @Component | ||||
@@ -13,7 +13,7 @@ import org.springframework.stereotype.Component; | |||||
public class RuoYiConfig | public class RuoYiConfig | ||||
{ | { | ||||
/** 项目名称 */ | /** 项目名称 */ | ||||
private String name; | |||||
private static String name; | |||||
/** 版本 */ | /** 版本 */ | ||||
private String version; | private String version; | ||||
@@ -30,8 +30,7 @@ public class RuoYiConfig | |||||
/** 验证码类型 */ | /** 验证码类型 */ | ||||
private static String captchaType; | private static String captchaType; | ||||
public String getName() | |||||
{ | |||||
public static String getName() { | |||||
return name; | return name; | ||||
} | } | ||||
@@ -0,0 +1,24 @@ | |||||
package com.ruoyi.common.core.domain.pdf; | |||||
import lombok.Data; | |||||
/** | |||||
* @description: | |||||
* @author: zzl | |||||
* @date: Created in 2024-04-30 10:57 | |||||
* @version: 1.0 | |||||
* @modified By: | |||||
*/ | |||||
@Data | |||||
public class BottomItem { | |||||
private static final long serialVersionUID = 1L; | |||||
private String leftItem; | |||||
private String centerItem; | |||||
private String rightItem; | |||||
} |
@@ -0,0 +1,44 @@ | |||||
package com.ruoyi.common.core.domain.pdf; | |||||
import lombok.Data; | |||||
/** | |||||
* @description: | |||||
* @author: zzl | |||||
* @date: Created in 2024-04-30 10:57 | |||||
* @version: 1.0 | |||||
* @modified By: | |||||
*/ | |||||
@Data | |||||
public class PageSet { | |||||
private static final long serialVersionUID = 1L; | |||||
// 纸张类型 | |||||
private String paperType; | |||||
// 纸张宽度 默认 A4, 换算关系 1cm ~ 28.35f | |||||
private float paperWidth = 595.0f; | |||||
// 纸张高度 默认 A4 | |||||
private float paperHeight = 842.0f; | |||||
// 打印方向 1 纵 2横 0缺省 | |||||
private String printDirection = "1"; | |||||
private int tableTotalWidth = 520; | |||||
// 左边距 | |||||
private int marginLeft = 50; | |||||
// 右边距 | |||||
private int marginRight = 50; | |||||
// 上边距 | |||||
private int marginTop = 30; | |||||
// 下边距 | |||||
private int marginBottom = 20; | |||||
} |
@@ -0,0 +1,46 @@ | |||||
package com.ruoyi.common.core.domain.pdf; | |||||
import lombok.Data; | |||||
import java.util.List; | |||||
/** | |||||
* @description: | |||||
* @author: zzl | |||||
* @date: Created in 2024-04-30 10:57 | |||||
* @version: 1.0 | |||||
* @modified By: | |||||
*/ | |||||
@Data | |||||
public class PdfProperty { | |||||
private static final long serialVersionUID = 1L; | |||||
// 顶部大标题 | |||||
private String title; | |||||
// 纸张定义 | |||||
private PageSet pageSet; | |||||
// 肩部:左 中 右 | |||||
private ShoulderItem shoulder; | |||||
// 表行高 | |||||
private float rowHeight; | |||||
// 列宽 百分比 | |||||
private float[] columnWidth; | |||||
// 列标题 | |||||
private String[] header; | |||||
// 水平位置( 0:左 1:中 2:右) | |||||
private int[] aligns; | |||||
// 列表数据 | |||||
private List<String[]> contentList; | |||||
} |
@@ -0,0 +1,24 @@ | |||||
package com.ruoyi.common.core.domain.pdf; | |||||
import lombok.Data; | |||||
/** | |||||
* @description: | |||||
* @author: zzl | |||||
* @date: Created in 2024-04-30 10:57 | |||||
* @version: 1.0 | |||||
* @modified By: | |||||
*/ | |||||
@Data | |||||
public class ShoulderItem { | |||||
private static final long serialVersionUID = 1L; | |||||
private String leftItem; | |||||
private String centerItem; | |||||
private String rightItem; | |||||
} |
@@ -2,7 +2,7 @@ package com.ruoyi.common.enums; | |||||
/** | /** | ||||
* 业务操作类型 | * 业务操作类型 | ||||
* | |||||
* | |||||
* @author ruoyi | * @author ruoyi | ||||
*/ | */ | ||||
public enum BusinessType | public enum BusinessType | ||||
@@ -51,9 +51,14 @@ public enum BusinessType | |||||
* 生成代码 | * 生成代码 | ||||
*/ | */ | ||||
GENCODE, | GENCODE, | ||||
/** | /** | ||||
* 清空数据 | * 清空数据 | ||||
*/ | */ | ||||
CLEAN, | CLEAN, | ||||
/** | |||||
* 打印 | |||||
*/ | |||||
PRINT, | |||||
} | } |
@@ -0,0 +1,490 @@ | |||||
package com.ruoyi.common.utils; | |||||
import java.math.BigDecimal; | |||||
import java.math.RoundingMode; | |||||
import java.text.NumberFormat; | |||||
import java.text.ParseException; | |||||
import java.util.Arrays; | |||||
import java.util.List; | |||||
import java.util.Locale; | |||||
/** | |||||
* 字符串工具类 | |||||
* | |||||
* @author ruoyi | |||||
*/ | |||||
public class DecimalUtils { | |||||
private static final List<String> CN_NUMBERS = Arrays.asList("零", "壹", "贰", "叁", "肆", "伍", "陆", "柒", "捌", "玖"); | |||||
private static final List<String> CN_UNITS = Arrays.asList("", "拾", "佰", "仟"); | |||||
private static final List<String> CN_BIG_UNITS = Arrays.asList("", "万", "亿", "兆"); | |||||
private static final String CN_NEGATIVE = "负"; | |||||
private static final String CN_INTEGER = "整"; | |||||
private static final String CN_FULL = "圆"; | |||||
private static final String CN_DECIMAL_UNIT = "角分"; | |||||
private static final int MAXIMUM_NUMBER = 999999999; | |||||
/** | |||||
* 将金额数字转换为中文大写 | |||||
* @param amount 金额数字,支持最大到999999999.99 | |||||
* @return 中文大写金额字符串 | |||||
*/ | |||||
public static String bigDecimalToChinese(BigDecimal amount) { | |||||
if (amount == null) { | |||||
throw new IllegalArgumentException("金额不能为空"); | |||||
} | |||||
// 检查金额范围 | |||||
if (amount.abs().compareTo(new BigDecimal(MAXIMUM_NUMBER + ".99")) > 0) { | |||||
throw new IllegalArgumentException("金额超出最大范围(999999999.99)"); | |||||
} | |||||
StringBuilder result = new StringBuilder(); | |||||
// 处理负数 | |||||
if (amount.compareTo(BigDecimal.ZERO) < 0) { | |||||
result.append(CN_NEGATIVE); | |||||
amount = amount.abs(); | |||||
} | |||||
// 转换为字符串处理 | |||||
String amountStr = amount.setScale(2, BigDecimal.ROUND_HALF_UP).toString(); | |||||
String[] parts = amountStr.split("\\."); | |||||
String integerPart = parts[0]; | |||||
String decimalPart = parts.length > 1 ? parts[1] : ""; | |||||
// 处理整数部分 | |||||
boolean hasInteger = !"0".equals(integerPart); | |||||
if (hasInteger) { | |||||
result.append(convertIntegerPart(integerPart)).append(CN_FULL); | |||||
} | |||||
// 处理小数部分 | |||||
String decimalStr = convertDecimalPart(decimalPart); | |||||
if (!decimalStr.isEmpty()) { | |||||
// 如果没有整数部分且有小部分,则不显示"零圆" | |||||
if (!hasInteger && decimalStr.charAt(0) != CN_NUMBERS.get(0).charAt(0)) { | |||||
result.append(decimalStr); | |||||
} else { | |||||
// 如果有整数部分或小数部分以零开头,则正常拼接 | |||||
if (!hasInteger) { | |||||
result.append(CN_NUMBERS.get(0)).append(CN_FULL); | |||||
} | |||||
result.append(decimalStr); | |||||
} | |||||
} else { | |||||
// 如果没有小数部分,添加"整" | |||||
result.append(CN_INTEGER); | |||||
} | |||||
return result.toString(); | |||||
} | |||||
private static String convertIntegerPart(String integerPart) { | |||||
StringBuilder sb = new StringBuilder(); | |||||
int length = integerPart.length(); | |||||
int zeroCount = 0; // 连续零的个数 | |||||
for (int i = 0; i < length; i++) { | |||||
int digit = Character.getNumericValue(integerPart.charAt(i)); | |||||
int pos = length - i - 1; // 当前位数 | |||||
int unitPos = pos % 4; // 单位位置(个十百千) | |||||
int bigUnitPos = pos / 4; // 大单位位置(万,亿) | |||||
if (digit == 0) { | |||||
zeroCount++; | |||||
} else { | |||||
if (zeroCount > 0) { | |||||
sb.append(CN_NUMBERS.get(0)); | |||||
zeroCount = 0; | |||||
} | |||||
sb.append(CN_NUMBERS.get(digit)).append(CN_UNITS.get(unitPos)); | |||||
} | |||||
// 添加大单位(万,亿) | |||||
if (unitPos == 0 && bigUnitPos > 0) { | |||||
if (zeroCount < 4) { // 如果当前段不全为零 | |||||
sb.append(CN_BIG_UNITS.get(bigUnitPos)); | |||||
} | |||||
zeroCount = 0; | |||||
} | |||||
} | |||||
// 处理全零的情况 | |||||
if (sb.length() == 0) { | |||||
return CN_NUMBERS.get(0); | |||||
} | |||||
return sb.toString(); | |||||
} | |||||
private static String convertDecimalPart(String decimalPart) { | |||||
StringBuilder sb = new StringBuilder(); | |||||
boolean hasNonZero = false; | |||||
for (int i = 0; i < decimalPart.length() && i < CN_DECIMAL_UNIT.length(); i++) { | |||||
int digit = Character.getNumericValue(decimalPart.charAt(i)); | |||||
if (digit != 0) { | |||||
sb.append(CN_NUMBERS.get(digit)).append(CN_DECIMAL_UNIT.charAt(i)); | |||||
hasNonZero = true; | |||||
} else if (hasNonZero || (i > 0 && sb.length() > 0)) { | |||||
// 如果前面已经有非零数字,或者不是第一位,可以添加零 | |||||
sb.append(CN_NUMBERS.get(0)); | |||||
} | |||||
} | |||||
// 去除末尾的零 | |||||
while (sb.length() > 0 && sb.charAt(sb.length() - 1) == CN_NUMBERS.get(0).charAt(0)) { | |||||
sb.deleteCharAt(sb.length() - 1); | |||||
} | |||||
return sb.toString(); | |||||
} | |||||
//默认除法运算精度 | |||||
private static final int DEF_DIV_SCALE = 10; | |||||
/** | |||||
* 提供精确的加法运算 | |||||
* | |||||
* @param v1 被加数 | |||||
* @param v2 加数 | |||||
* @return 两个参数的和 | |||||
*/ | |||||
public static double add(double v1, double v2) { | |||||
BigDecimal b1 = new BigDecimal(Double.toString(v1)); | |||||
BigDecimal b2 = new BigDecimal(Double.toString(v2)); | |||||
return b1.add(b2).doubleValue(); | |||||
} | |||||
/** | |||||
* 提供精确的加法运算 | |||||
* | |||||
* @param v1 被加数 | |||||
* @param v2 加数 | |||||
* @return 两个参数的和 | |||||
*/ | |||||
public static BigDecimal add(String v1, String v2) { | |||||
BigDecimal b1 = new BigDecimal(v1); | |||||
BigDecimal b2 = new BigDecimal(v2); | |||||
return b1.add(b2); | |||||
} | |||||
/** | |||||
* 提供精确的加法运算 | |||||
* | |||||
* @param v1 被加数 | |||||
* @param v2 加数 | |||||
* @param scale 保留scale 位小数 | |||||
* @return 两个参数的和 | |||||
*/ | |||||
public static String add(String v1, String v2, int scale) { | |||||
if (scale < 0) { | |||||
throw new IllegalArgumentException( | |||||
"The scale must be a positive integer or zero"); | |||||
} | |||||
BigDecimal b1 = new BigDecimal(v1); | |||||
BigDecimal b2 = new BigDecimal(v2); | |||||
return b1.add(b2).setScale(scale, RoundingMode.HALF_UP).toString(); | |||||
} | |||||
/** | |||||
* 提供精确的减法运算 | |||||
* | |||||
* @param v1 被减数 | |||||
* @param v2 减数 | |||||
* @return 两个参数的差 | |||||
*/ | |||||
public static double sub(double v1, double v2) { | |||||
BigDecimal b1 = new BigDecimal(Double.toString(v1)); | |||||
BigDecimal b2 = new BigDecimal(Double.toString(v2)); | |||||
return b1.subtract(b2).doubleValue(); | |||||
} | |||||
/** | |||||
* 提供精确的减法运算。 | |||||
* | |||||
* @param v1 被减数 | |||||
* @param v2 减数 | |||||
* @return 两个参数的差 | |||||
*/ | |||||
public static BigDecimal sub(String v1, String v2) { | |||||
BigDecimal b1 = new BigDecimal(v1); | |||||
BigDecimal b2 = new BigDecimal(v2); | |||||
return b1.subtract(b2); | |||||
} | |||||
/** | |||||
* 提供精确的减法运算 | |||||
* | |||||
* @param v1 被减数 | |||||
* @param v2 减数 | |||||
* @param scale 保留scale 位小数 | |||||
* @return 两个参数的差 | |||||
*/ | |||||
public static String sub(String v1, String v2, int scale) { | |||||
if (scale < 0) { | |||||
throw new IllegalArgumentException( | |||||
"The scale must be a positive integer or zero"); | |||||
} | |||||
BigDecimal b1 = new BigDecimal(v1); | |||||
BigDecimal b2 = new BigDecimal(v2); | |||||
return b1.subtract(b2).setScale(scale, BigDecimal.ROUND_HALF_UP).toString(); | |||||
} | |||||
/** | |||||
* 提供精确的乘法运算 | |||||
* | |||||
* @param v1 被乘数 | |||||
* @param v2 乘数 | |||||
* @return 两个参数的积 | |||||
*/ | |||||
public static double mul(double v1, double v2) { | |||||
BigDecimal b1 = new BigDecimal(Double.toString(v1)); | |||||
BigDecimal b2 = new BigDecimal(Double.toString(v2)); | |||||
return b1.multiply(b2).doubleValue(); | |||||
} | |||||
/** | |||||
* 提供精确的乘法运算 | |||||
* | |||||
* @param v1 被乘数 | |||||
* @param v2 乘数 | |||||
* @return 两个参数的积 | |||||
*/ | |||||
public static BigDecimal mul(String v1, String v2) { | |||||
BigDecimal b1 = new BigDecimal(v1); | |||||
BigDecimal b2 = new BigDecimal(v2); | |||||
return b1.multiply(b2); | |||||
} | |||||
/** | |||||
* 提供精确的乘法运算 | |||||
* | |||||
* @param v1 被乘数 | |||||
* @param v2 乘数 | |||||
* @param scale 保留scale 位小数 | |||||
* @return 两个参数的积 | |||||
*/ | |||||
public static double mul(double v1, double v2, int scale) { | |||||
BigDecimal b1 = new BigDecimal(Double.toString(v1)); | |||||
BigDecimal b2 = new BigDecimal(Double.toString(v2)); | |||||
return round(b1.multiply(b2).doubleValue(), scale); | |||||
} | |||||
/** | |||||
* 提供精确的乘法运算 | |||||
* | |||||
* @param v1 被乘数 | |||||
* @param v2 乘数 | |||||
* @param scale 保留scale 位小数 | |||||
* @return 两个参数的积 | |||||
*/ | |||||
public static String mul(String v1, String v2, int scale) { | |||||
if (scale < 0) { | |||||
throw new IllegalArgumentException( | |||||
"The scale must be a positive integer or zero"); | |||||
} | |||||
BigDecimal b1 = new BigDecimal(v1); | |||||
BigDecimal b2 = new BigDecimal(v2); | |||||
return b1.multiply(b2).setScale(scale, RoundingMode.HALF_UP).toString(); | |||||
} | |||||
/** | |||||
* 提供(相对)精确的除法运算,当发生除不尽的情况时,精确到 | |||||
* 小数点以后10位,以后的数字四舍五入 | |||||
* | |||||
* @param v1 被除数 | |||||
* @param v2 除数 | |||||
* @return 两个参数的商 | |||||
*/ | |||||
public static double div(double v1, double v2) { | |||||
return div(v1, v2, DEF_DIV_SCALE); | |||||
} | |||||
/** | |||||
* 提供(相对)精确的除法运算。当发生除不尽的情况时,由scale参数指 | |||||
* 定精度,以后的数字四舍五入 | |||||
* | |||||
* @param v1 被除数 | |||||
* @param v2 除数 | |||||
* @param scale 表示表示需要精确到小数点以后几位。 | |||||
* @return 两个参数的商 | |||||
*/ | |||||
public static double div(double v1, double v2, int scale) { | |||||
if (scale < 0) { | |||||
throw new IllegalArgumentException("The scale must be a positive integer or zero"); | |||||
} | |||||
BigDecimal b1 = new BigDecimal(Double.toString(v1)); | |||||
BigDecimal b2 = new BigDecimal(Double.toString(v2)); | |||||
return b1.divide(b2, scale, RoundingMode.HALF_UP).doubleValue(); | |||||
} | |||||
/** | |||||
* 提供(相对)精确的除法运算。当发生除不尽的情况时,由scale参数指 | |||||
* 定精度,以后的数字四舍五入 | |||||
* | |||||
* @param v1 被除数 | |||||
* @param v2 除数 | |||||
* @param scale 表示需要精确到小数点以后几位 | |||||
* @return 两个参数的商 | |||||
*/ | |||||
public static String div(String v1, String v2, int scale) { | |||||
if (scale < 0) { | |||||
throw new IllegalArgumentException("The scale must be a positive integer or zero"); | |||||
} | |||||
BigDecimal b1 = new BigDecimal(v1); | |||||
BigDecimal b2 = new BigDecimal(v1); | |||||
return b1.divide(b2, scale, RoundingMode.HALF_UP).toString(); | |||||
} | |||||
/** | |||||
* 提供精确的小数位四舍五入处理 | |||||
* | |||||
* @param v 需要四舍五入的数字 | |||||
* @param scale 小数点后保留几位 | |||||
* @return 四舍五入后的结果 | |||||
*/ | |||||
public static double round(double v, int scale) { | |||||
if (scale < 0) { | |||||
throw new IllegalArgumentException("The scale must be a positive integer or zero"); | |||||
} | |||||
BigDecimal b = new BigDecimal(Double.toString(v)); | |||||
return b.setScale(scale, RoundingMode.HALF_UP).doubleValue(); | |||||
} | |||||
/** | |||||
* 提供精确的小数位四舍五入处理 | |||||
* | |||||
* @param v 需要四舍五入的数字 | |||||
* @param scale 小数点后保留几位 | |||||
* @return 四舍五入后的结果 | |||||
*/ | |||||
public static String round(String v, int scale) { | |||||
if (scale < 0) { | |||||
throw new IllegalArgumentException( | |||||
"The scale must be a positive integer or zero"); | |||||
} | |||||
BigDecimal b = new BigDecimal(v); | |||||
return b.setScale(scale, RoundingMode.HALF_UP).toString(); | |||||
} | |||||
/** | |||||
* 取余数 | |||||
* | |||||
* @param v1 被除数 | |||||
* @param v2 除数 | |||||
* @param scale 小数点后保留几位 | |||||
* @return 余数 | |||||
*/ | |||||
public static String remainder(String v1, String v2, int scale) { | |||||
if (scale < 0) { | |||||
throw new IllegalArgumentException( | |||||
"The scale must be a positive integer or zero"); | |||||
} | |||||
BigDecimal b1 = new BigDecimal(v1); | |||||
BigDecimal b2 = new BigDecimal(v2); | |||||
return b1.remainder(b2).setScale(scale, RoundingMode.HALF_UP).toString(); | |||||
} | |||||
/** | |||||
* 取余数 BigDecimal | |||||
* | |||||
* @param v1 被除数 | |||||
* @param v2 除数 | |||||
* @param scale 小数点后保留几位 | |||||
* @return 余数 | |||||
*/ | |||||
public static BigDecimal remainder(BigDecimal v1, BigDecimal v2, int scale) { | |||||
if (scale < 0) { | |||||
throw new IllegalArgumentException( | |||||
"The scale must be a positive integer or zero"); | |||||
} | |||||
return v1.remainder(v2).setScale(scale, RoundingMode.HALF_UP); | |||||
} | |||||
/** | |||||
* 比较大小 | |||||
* | |||||
* @param v1 被比较数 | |||||
* @param v2 比较数 | |||||
* @return 如果v1 大于v2 则 返回true 否则false | |||||
*/ | |||||
public static boolean compare(String v1, String v2) { | |||||
BigDecimal b1 = new BigDecimal(v1); | |||||
BigDecimal b2 = new BigDecimal(v2); | |||||
int bj = b1.compareTo(b2); | |||||
boolean res; | |||||
res = bj > 0; | |||||
return res; | |||||
} | |||||
/** | |||||
* 将数字格式化为千分位 | |||||
* | |||||
* @param number | |||||
* @return 字符串 | |||||
*/ | |||||
public static String convert(BigDecimal number) { | |||||
if (null == number || number.compareTo(BigDecimal.ZERO) == 0) { | |||||
return ""; | |||||
} | |||||
NumberFormat numberFormat = NumberFormat.getNumberInstance(Locale.ENGLISH); | |||||
// 设置最大分数位数,这里设置为0表示不使用分数 | |||||
numberFormat.setMaximumFractionDigits(2); | |||||
// 设置最小整数位数,这里设置为2表示整数部分至少2位 | |||||
//numberFormat.setMinimumIntegerDigits(2); | |||||
// 设置grouping used属性为false,表示不使用千分位分隔符 | |||||
numberFormat.setGroupingUsed(true); | |||||
return numberFormat.format(number); | |||||
} | |||||
/** | |||||
* 将千分位数字字符串格式化为 BigDecimal | |||||
* @param formattedNumber | |||||
* @return 字符串 | |||||
*/ | |||||
public static BigDecimal convert(String formattedNumber) { | |||||
if (StringUtils.isEmpty(formattedNumber)) { | |||||
return BigDecimal.ZERO; | |||||
} | |||||
try { | |||||
NumberFormat format = NumberFormat.getInstance(Locale.US); | |||||
Number number = format.parse(formattedNumber); | |||||
BigDecimal bigDecimal = new BigDecimal(number.toString()); | |||||
return bigDecimal; | |||||
} catch (ParseException e) { | |||||
e.printStackTrace(); | |||||
return BigDecimal.ZERO; | |||||
} | |||||
} | |||||
public static boolean isZero_s(BigDecimal b) { | |||||
return null == b || b.compareTo(BigDecimal.ZERO) == 0; | |||||
} | |||||
/** | |||||
* 将是0的处理成空 | |||||
* @param number | |||||
* @return BigDecimal | |||||
*/ | |||||
public static String zeroToNull(BigDecimal number) { | |||||
if(number.compareTo(BigDecimal.ZERO) == 0){ | |||||
return null; | |||||
}else{ | |||||
return number.toString(); | |||||
} | |||||
} | |||||
} |
@@ -1,16 +1,21 @@ | |||||
package com.ruoyi.common.utils; | package com.ruoyi.common.utils; | ||||
import java.util.Collection; | |||||
import java.util.List; | |||||
import cn.hutool.core.collection.CollectionUtil; | |||||
import com.alibaba.fastjson2.JSONArray; | import com.alibaba.fastjson2.JSONArray; | ||||
import com.ruoyi.common.constant.CacheConstants; | import com.ruoyi.common.constant.CacheConstants; | ||||
import com.ruoyi.common.core.domain.entity.SysDictData; | import com.ruoyi.common.core.domain.entity.SysDictData; | ||||
import com.ruoyi.common.core.redis.RedisCache; | import com.ruoyi.common.core.redis.RedisCache; | ||||
import com.ruoyi.common.utils.spring.SpringUtils; | import com.ruoyi.common.utils.spring.SpringUtils; | ||||
import java.util.Collection; | |||||
import java.util.LinkedHashMap; | |||||
import java.util.List; | |||||
import java.util.Map; | |||||
import java.util.stream.Collectors; | |||||
/** | /** | ||||
* 字典工具类 | * 字典工具类 | ||||
* | |||||
* | |||||
* @author ruoyi | * @author ruoyi | ||||
*/ | */ | ||||
public class DictUtils | public class DictUtils | ||||
@@ -22,7 +27,7 @@ public class DictUtils | |||||
/** | /** | ||||
* 设置字典缓存 | * 设置字典缓存 | ||||
* | |||||
* | |||||
* @param key 参数键 | * @param key 参数键 | ||||
* @param dictDatas 字典数据列表 | * @param dictDatas 字典数据列表 | ||||
*/ | */ | ||||
@@ -33,7 +38,7 @@ public class DictUtils | |||||
/** | /** | ||||
* 获取字典缓存 | * 获取字典缓存 | ||||
* | |||||
* | |||||
* @param key 参数键 | * @param key 参数键 | ||||
* @return dictDatas 字典数据列表 | * @return dictDatas 字典数据列表 | ||||
*/ | */ | ||||
@@ -49,7 +54,7 @@ public class DictUtils | |||||
/** | /** | ||||
* 根据字典类型和字典值获取字典标签 | * 根据字典类型和字典值获取字典标签 | ||||
* | |||||
* | |||||
* @param dictType 字典类型 | * @param dictType 字典类型 | ||||
* @param dictValue 字典值 | * @param dictValue 字典值 | ||||
* @return 字典标签 | * @return 字典标签 | ||||
@@ -65,7 +70,7 @@ public class DictUtils | |||||
/** | /** | ||||
* 根据字典类型和字典标签获取字典值 | * 根据字典类型和字典标签获取字典值 | ||||
* | |||||
* | |||||
* @param dictType 字典类型 | * @param dictType 字典类型 | ||||
* @param dictLabel 字典标签 | * @param dictLabel 字典标签 | ||||
* @return 字典值 | * @return 字典值 | ||||
@@ -81,7 +86,7 @@ public class DictUtils | |||||
/** | /** | ||||
* 根据字典类型和字典值获取字典标签 | * 根据字典类型和字典值获取字典标签 | ||||
* | |||||
* | |||||
* @param dictType 字典类型 | * @param dictType 字典类型 | ||||
* @param dictValue 字典值 | * @param dictValue 字典值 | ||||
* @param separator 分隔符 | * @param separator 分隔符 | ||||
@@ -124,7 +129,7 @@ public class DictUtils | |||||
/** | /** | ||||
* 根据字典类型和字典标签获取字典值 | * 根据字典类型和字典标签获取字典值 | ||||
* | |||||
* | |||||
* @param dictType 字典类型 | * @param dictType 字典类型 | ||||
* @param dictLabel 字典标签 | * @param dictLabel 字典标签 | ||||
* @param separator 分隔符 | * @param separator 分隔符 | ||||
@@ -209,7 +214,7 @@ public class DictUtils | |||||
/** | /** | ||||
* 删除指定字典缓存 | * 删除指定字典缓存 | ||||
* | |||||
* | |||||
* @param key 字典键 | * @param key 字典键 | ||||
*/ | */ | ||||
public static void removeDictCache(String key) | public static void removeDictCache(String key) | ||||
@@ -228,7 +233,7 @@ public class DictUtils | |||||
/** | /** | ||||
* 设置cache key | * 设置cache key | ||||
* | |||||
* | |||||
* @param configKey 参数键 | * @param configKey 参数键 | ||||
* @return 缓存键key | * @return 缓存键key | ||||
*/ | */ | ||||
@@ -236,4 +241,18 @@ public class DictUtils | |||||
{ | { | ||||
return CacheConstants.SYS_DICT_KEY + configKey; | return CacheConstants.SYS_DICT_KEY + configKey; | ||||
} | } | ||||
public static Map<String, String> dictCacheValueLabelMap(String key) { | |||||
List<SysDictData> dictCache = getDictCache(key); | |||||
if (CollectionUtil.isEmpty(dictCache)) | |||||
return new LinkedHashMap<>(); // safety | |||||
return dictCache.stream().collect(Collectors.toMap(SysDictData::getDictValue, SysDictData::getDictLabel, (a, b) -> a, LinkedHashMap::new)); | |||||
} | |||||
public static String getDictLabelElseOriginValue(String dictType, String dictValue) { | |||||
if (StringUtils.isEmpty(dictValue)) | |||||
return dictValue; | |||||
String res = getDictLabel(dictType, dictValue); | |||||
return StringUtils.isEmpty(res) ? dictValue : res; | |||||
} | |||||
} | } |
@@ -0,0 +1,69 @@ | |||||
package com.ruoyi.common.utils.file; | |||||
import cn.hutool.core.codec.Base64; | |||||
import org.springframework.web.multipart.MultipartFile; | |||||
import java.io.*; | |||||
public class BASE64DecodedMultipartFile implements MultipartFile { | |||||
private final byte[] imgContent; | |||||
private final String header; | |||||
public BASE64DecodedMultipartFile(byte[] imgContent, String header) { | |||||
this.imgContent = imgContent; | |||||
this.header = header.split(";")[0]; | |||||
} | |||||
@Override | |||||
public String getName() { | |||||
return System.currentTimeMillis() + Math.random() + "." + header.split("/")[1]; | |||||
} | |||||
@Override | |||||
public String getOriginalFilename() { | |||||
return System.currentTimeMillis() + (int) Math.random() * 10000 + "." + header.split("/")[1]; | |||||
} | |||||
@Override | |||||
public String getContentType() { | |||||
return header.split(":")[1]; | |||||
} | |||||
@Override | |||||
public boolean isEmpty() { | |||||
return imgContent == null || imgContent.length == 0; | |||||
} | |||||
@Override | |||||
public long getSize() { | |||||
return imgContent.length; | |||||
} | |||||
@Override | |||||
public byte[] getBytes() throws IOException { | |||||
return imgContent; | |||||
} | |||||
@Override | |||||
public InputStream getInputStream() throws IOException { | |||||
return new ByteArrayInputStream(imgContent); | |||||
} | |||||
@Override | |||||
public void transferTo(File dest) throws IOException, IllegalStateException { | |||||
new FileOutputStream(dest).write(imgContent); | |||||
} | |||||
public static MultipartFile base64ToMultipart(String base64) { | |||||
String[] base64Array = base64.split(","); | |||||
String imageString = base64Array.length > 1 ? base64Array[1] : base64Array[0]; | |||||
byte[] imageBytes = Base64.decode(imageString); | |||||
return new BASE64DecodedMultipartFile(imageBytes, "image/png"); | |||||
} | |||||
} |
@@ -0,0 +1,71 @@ | |||||
package com.ruoyi.common.utils.file; | |||||
import org.springframework.web.multipart.MultipartFile; | |||||
import java.io.*; | |||||
/** | |||||
* @description: | |||||
* @author: zzl | |||||
* @date: Created in 2021/8/5 18:38 | |||||
* @version: v1.0 | |||||
* @modified By: | |||||
*/ | |||||
public class ConvertToMultipartFile implements MultipartFile { | |||||
private byte[] fileBytes; | |||||
String name; | |||||
String originalFilename; | |||||
String contentType; | |||||
boolean isEmpty; | |||||
long size; | |||||
public ConvertToMultipartFile(byte[] fileBytes, String name, String originalFilename, String contentType, long size) { | |||||
this.fileBytes = fileBytes; | |||||
this.name = name; | |||||
this.originalFilename = originalFilename; | |||||
this.contentType = contentType; | |||||
this.size = size; | |||||
this.isEmpty = false; | |||||
} | |||||
@Override | |||||
public String getName() { | |||||
return name; | |||||
} | |||||
@Override | |||||
public String getOriginalFilename() { | |||||
return originalFilename; | |||||
} | |||||
@Override | |||||
public String getContentType() { | |||||
return contentType; | |||||
} | |||||
@Override | |||||
public boolean isEmpty() { | |||||
return isEmpty; | |||||
} | |||||
@Override | |||||
public long getSize() { | |||||
return size; | |||||
} | |||||
@Override | |||||
public byte[] getBytes() throws IOException { | |||||
return fileBytes; | |||||
} | |||||
@Override | |||||
public InputStream getInputStream() throws IOException { | |||||
return new ByteArrayInputStream(fileBytes); | |||||
} | |||||
@Override | |||||
public void transferTo(File dest) throws IOException, IllegalStateException { | |||||
new FileOutputStream(dest).write(fileBytes); | |||||
} | |||||
} | |||||
@@ -1,11 +1,5 @@ | |||||
package com.ruoyi.common.utils.file; | package com.ruoyi.common.utils.file; | ||||
import java.io.File; | |||||
import java.io.IOException; | |||||
import java.nio.file.Paths; | |||||
import java.util.Objects; | |||||
import org.apache.commons.io.FilenameUtils; | |||||
import org.springframework.web.multipart.MultipartFile; | |||||
import com.ruoyi.common.config.RuoYiConfig; | import com.ruoyi.common.config.RuoYiConfig; | ||||
import com.ruoyi.common.constant.Constants; | import com.ruoyi.common.constant.Constants; | ||||
import com.ruoyi.common.exception.file.FileNameLengthLimitExceededException; | import com.ruoyi.common.exception.file.FileNameLengthLimitExceededException; | ||||
@@ -13,21 +7,39 @@ import com.ruoyi.common.exception.file.FileSizeLimitExceededException; | |||||
import com.ruoyi.common.exception.file.InvalidExtensionException; | import com.ruoyi.common.exception.file.InvalidExtensionException; | ||||
import com.ruoyi.common.utils.DateUtils; | import com.ruoyi.common.utils.DateUtils; | ||||
import com.ruoyi.common.utils.StringUtils; | import com.ruoyi.common.utils.StringUtils; | ||||
import com.ruoyi.common.utils.uuid.IdUtils; | |||||
import com.ruoyi.common.utils.uuid.Seq; | import com.ruoyi.common.utils.uuid.Seq; | ||||
import org.apache.commons.io.FilenameUtils; | |||||
import org.springframework.web.multipart.MultipartFile; | |||||
import javax.imageio.ImageIO; | |||||
import java.awt.image.BufferedImage; | |||||
import java.io.File; | |||||
import java.io.FileOutputStream; | |||||
import java.io.IOException; | |||||
import java.io.InputStream; | |||||
import java.net.HttpURLConnection; | |||||
import java.net.URL; | |||||
import java.nio.file.Paths; | |||||
import java.util.Objects; | |||||
import static java.util.Arrays.binarySearch; | |||||
/** | /** | ||||
* 文件上传工具类 | * 文件上传工具类 | ||||
* | |||||
* | |||||
* @author ruoyi | * @author ruoyi | ||||
*/ | */ | ||||
public class FileUploadUtils | |||||
{ | |||||
public class FileUploadUtils { | |||||
/** | /** | ||||
* 默认大小 50M | * 默认大小 50M | ||||
*/ | */ | ||||
public static final long DEFAULT_MAX_SIZE = 50 * 1024 * 1024L; | public static final long DEFAULT_MAX_SIZE = 50 * 1024 * 1024L; | ||||
/** | |||||
* 图片压缩红线 kb | |||||
*/ | |||||
public static final long DES_FILE_SIZE = 1024; | |||||
/** | /** | ||||
* 默认的文件名最大长度 100 | * 默认的文件名最大长度 100 | ||||
*/ | */ | ||||
@@ -38,16 +50,58 @@ public class FileUploadUtils | |||||
*/ | */ | ||||
private static String defaultBaseDir = RuoYiConfig.getProfile(); | private static String defaultBaseDir = RuoYiConfig.getProfile(); | ||||
public static void setDefaultBaseDir(String defaultBaseDir) | |||||
{ | |||||
public static void setDefaultBaseDir(String defaultBaseDir) { | |||||
FileUploadUtils.defaultBaseDir = defaultBaseDir; | FileUploadUtils.defaultBaseDir = defaultBaseDir; | ||||
} | } | ||||
public static String getDefaultBaseDir() | |||||
{ | |||||
public static String getDefaultBaseDir() { | |||||
return defaultBaseDir; | return defaultBaseDir; | ||||
} | } | ||||
public static String base64Upload(String img64, String bizPath) { | |||||
try { | |||||
MultipartFile file = BASE64DecodedMultipartFile.base64ToMultipart(img64); | |||||
String filePath = RuoYiConfig.getProfile() + File.separator + bizPath; | |||||
return upload(filePath, file); | |||||
} catch (IOException e) { | |||||
e.printStackTrace(); | |||||
} | |||||
return null; | |||||
} | |||||
/** | |||||
* 根据远程文件url 下载存储到本地 | |||||
* @param urlStr "https://example.com/image.jpg" 远程文件地址 | |||||
* @return bizPath 新的存储位置 | |||||
* @return fileName a.png | |||||
* @throws Exception | |||||
*/ | |||||
public static String saveFile(String urlStr, String bizPath, String fileName) throws Exception { | |||||
// 读取远程文件 | |||||
URL url = new URL(urlStr); | |||||
HttpURLConnection conn = (HttpURLConnection) url.openConnection(); | |||||
conn.setRequestMethod("GET"); | |||||
conn.setConnectTimeout(5000); | |||||
InputStream is = conn.getInputStream(); | |||||
byte[] data = ImageUtils.readInputStream(is); | |||||
bizPath = bizPath + "/" + DateUtils.dateTime(); | |||||
// 创建文件路径 | |||||
getAbsoluteFile(bizPath, fileName).getAbsolutePath(); | |||||
// 创建文件 | |||||
File imageFile = new File(bizPath + "/" + fileName); | |||||
FileOutputStream outStream = new FileOutputStream(imageFile); | |||||
outStream.write(data); | |||||
outStream.close(); | |||||
return getPathFileName(bizPath, fileName); | |||||
} | |||||
/** | /** | ||||
* 以默认配置进行文件上传 | * 以默认配置进行文件上传 | ||||
* | * | ||||
@@ -55,14 +109,10 @@ public class FileUploadUtils | |||||
* @return 文件名称 | * @return 文件名称 | ||||
* @throws Exception | * @throws Exception | ||||
*/ | */ | ||||
public static final String upload(MultipartFile file) throws IOException | |||||
{ | |||||
try | |||||
{ | |||||
public static final String upload(MultipartFile file) throws IOException { | |||||
try { | |||||
return upload(getDefaultBaseDir(), file, MimeTypeUtils.DEFAULT_ALLOWED_EXTENSION); | return upload(getDefaultBaseDir(), file, MimeTypeUtils.DEFAULT_ALLOWED_EXTENSION); | ||||
} | |||||
catch (Exception e) | |||||
{ | |||||
} catch (Exception e) { | |||||
throw new IOException(e.getMessage(), e); | throw new IOException(e.getMessage(), e); | ||||
} | } | ||||
} | } | ||||
@@ -71,18 +121,31 @@ public class FileUploadUtils | |||||
* 根据文件路径上传 | * 根据文件路径上传 | ||||
* | * | ||||
* @param baseDir 相对应用的基目录 | * @param baseDir 相对应用的基目录 | ||||
* @param file 上传的文件 | |||||
* @param file 上传的文件 | |||||
* @return 文件名称 | * @return 文件名称 | ||||
* @throws IOException | * @throws IOException | ||||
*/ | */ | ||||
public static final String upload(String baseDir, MultipartFile file) throws IOException | |||||
{ | |||||
try | |||||
{ | |||||
public static final String upload(String baseDir, MultipartFile file) throws IOException { | |||||
try { | |||||
return upload(baseDir, file, MimeTypeUtils.DEFAULT_ALLOWED_EXTENSION); | return upload(baseDir, file, MimeTypeUtils.DEFAULT_ALLOWED_EXTENSION); | ||||
} catch (Exception e) { | |||||
throw new IOException(e.getMessage(), e); | |||||
} | } | ||||
catch (Exception e) | |||||
{ | |||||
} | |||||
/** | |||||
* 根据文件路径上传 | |||||
* | |||||
* @param baseDir 相对应用的基目录 | |||||
* @param file 上传的文件 | |||||
* @param isPng 是否转透明png | |||||
* @return 文件名称 | |||||
* @throws IOException | |||||
*/ | |||||
public static final String upload(String baseDir, MultipartFile file, boolean isPng) throws IOException { | |||||
try { | |||||
return upload(baseDir, file, MimeTypeUtils.DEFAULT_ALLOWED_EXTENSION); | |||||
} catch (Exception e) { | |||||
throw new IOException(e.getMessage(), e); | throw new IOException(e.getMessage(), e); | ||||
} | } | ||||
} | } | ||||
@@ -90,86 +153,161 @@ public class FileUploadUtils | |||||
/** | /** | ||||
* 文件上传 | * 文件上传 | ||||
* | * | ||||
* @param baseDir 相对应用的基目录 | |||||
* @param file 上传的文件 | |||||
* @param baseDir 相对应用的基目录 | |||||
* @param file 上传的文件 | |||||
* @param allowedExtension 上传文件类型 | * @param allowedExtension 上传文件类型 | ||||
* @return 返回上传成功的文件名 | * @return 返回上传成功的文件名 | ||||
* @throws FileSizeLimitExceededException 如果超出最大大小 | |||||
* @throws FileSizeLimitExceededException 如果超出最大大小 | |||||
* @throws FileNameLengthLimitExceededException 文件名太长 | * @throws FileNameLengthLimitExceededException 文件名太长 | ||||
* @throws IOException 比如读写文件出错时 | |||||
* @throws InvalidExtensionException 文件校验异常 | |||||
* @throws IOException 比如读写文件出错时 | |||||
* @throws InvalidExtensionException 文件校验异常 | |||||
*/ | */ | ||||
public static final String upload(String baseDir, MultipartFile file, String[] allowedExtension) | public static final String upload(String baseDir, MultipartFile file, String[] allowedExtension) | ||||
throws FileSizeLimitExceededException, IOException, FileNameLengthLimitExceededException, | throws FileSizeLimitExceededException, IOException, FileNameLengthLimitExceededException, | ||||
InvalidExtensionException | |||||
{ | |||||
return upload(baseDir, file, allowedExtension, false); | |||||
InvalidExtensionException { | |||||
// 文件名过长 | |||||
int fileNameLength = Objects.requireNonNull(file.getOriginalFilename()).length(); | |||||
if (fileNameLength > FileUploadUtils.DEFAULT_FILE_NAME_LENGTH) { | |||||
throw new FileNameLengthLimitExceededException(FileUploadUtils.DEFAULT_FILE_NAME_LENGTH); | |||||
} | |||||
// 文件大小、文件后缀格式 | |||||
assertAllowed(file, allowedExtension); | |||||
// 大于1M的 图片文件 进行压缩 | |||||
String fileType = getExtension(file); | |||||
if (binarySearch(MimeTypeUtils.IMAGE_EXTENSION, fileType) > 0) { | |||||
String fileName = file.getOriginalFilename(); | |||||
// 压缩成字节数组 | |||||
byte[] imageByte = ImageUtils.compressPicForScale(file.getBytes(), FileUploadUtils.DES_FILE_SIZE); | |||||
// 恢复成MultipartFile,且不重命名 | |||||
file = new ConvertToMultipartFile(imageByte, fileName, fileName, fileType, imageByte.length); | |||||
} | |||||
// 文件重命名 | |||||
String fileName = extractFilename(file); | |||||
// 判断后缀名是否正确 | |||||
int splitIndex = fileName.lastIndexOf("."); | |||||
String fType = fileName.substring(splitIndex + 1); | |||||
if (fType == null || fType.equals("")) { | |||||
fileName = fileName + file.getContentType(); | |||||
} | |||||
if (splitIndex < 0) { | |||||
fileName = fileName + "." + fileType; | |||||
} | |||||
// 创建文件路径 | |||||
String absPath = getAbsoluteFile(baseDir, fileName).getAbsolutePath(); | |||||
// 存储文件 | |||||
file.transferTo(Paths.get(absPath)); | |||||
// 返回文件路径 | |||||
return getPathFileName(baseDir, fileName); | |||||
} | } | ||||
/** | /** | ||||
* 文件上传 | * 文件上传 | ||||
* | * | ||||
* @param baseDir 相对应用的基目录 | |||||
* @param file 上传的文件 | |||||
* @param useCustomNaming 系统自定义文件名 | |||||
* @param baseDir 相对应用的基目录 | |||||
* @param file 上传的文件 | |||||
* @param isPng 是否转透明png | |||||
* @param allowedExtension 上传文件类型 | * @param allowedExtension 上传文件类型 | ||||
* @return 返回上传成功的文件名 | * @return 返回上传成功的文件名 | ||||
* @throws FileSizeLimitExceededException 如果超出最大大小 | |||||
* @throws FileSizeLimitExceededException 如果超出最大大小 | |||||
* @throws FileNameLengthLimitExceededException 文件名太长 | * @throws FileNameLengthLimitExceededException 文件名太长 | ||||
* @throws IOException 比如读写文件出错时 | |||||
* @throws InvalidExtensionException 文件校验异常 | |||||
* @throws IOException 比如读写文件出错时 | |||||
* @throws InvalidExtensionException 文件校验异常 | |||||
*/ | */ | ||||
public static final String upload(String baseDir, MultipartFile file, String[] allowedExtension, boolean useCustomNaming) | |||||
public static final String upload(String baseDir, MultipartFile file, String[] allowedExtension, boolean isPng, boolean isAngle) | |||||
throws FileSizeLimitExceededException, IOException, FileNameLengthLimitExceededException, | throws FileSizeLimitExceededException, IOException, FileNameLengthLimitExceededException, | ||||
InvalidExtensionException | |||||
{ | |||||
InvalidExtensionException { | |||||
// 文件名过长 | |||||
int fileNameLength = Objects.requireNonNull(file.getOriginalFilename()).length(); | int fileNameLength = Objects.requireNonNull(file.getOriginalFilename()).length(); | ||||
if (fileNameLength > FileUploadUtils.DEFAULT_FILE_NAME_LENGTH) | |||||
{ | |||||
if (fileNameLength > FileUploadUtils.DEFAULT_FILE_NAME_LENGTH) { | |||||
throw new FileNameLengthLimitExceededException(FileUploadUtils.DEFAULT_FILE_NAME_LENGTH); | throw new FileNameLengthLimitExceededException(FileUploadUtils.DEFAULT_FILE_NAME_LENGTH); | ||||
} | } | ||||
// 文件大小、文件后缀格式 | |||||
assertAllowed(file, allowedExtension); | assertAllowed(file, allowedExtension); | ||||
String fileName = useCustomNaming ? uuidFilename(file) : extractFilename(file); | |||||
// 大于1M的 图片文件 进行压缩 | |||||
String fileType = getExtension(file); | |||||
if (binarySearch(MimeTypeUtils.IMAGE_EXTENSION, fileType) > 0) { | |||||
String fileName = file.getOriginalFilename(); | |||||
// 压缩成字节数组 | |||||
byte[] imageByte = ImageUtils.compressPicForScale(file.getBytes(), FileUploadUtils.DES_FILE_SIZE); | |||||
// 恢复成MultipartFile,且不重命名 | |||||
file = new ConvertToMultipartFile(imageByte, fileName, fileName, fileType, imageByte.length); | |||||
} | |||||
// 文件重命名 | |||||
String fileName = extractFilename(file); | |||||
// 判断后缀名是否正确 | |||||
int splitIndex = fileName.lastIndexOf("."); | |||||
String fType = fileName.substring(splitIndex + 1); | |||||
if (fType == null || fType.equals("")) { | |||||
fileName = fileName + file.getContentType(); | |||||
} | |||||
if (splitIndex < 0) { | |||||
fileName = fileName + "." + fileType; | |||||
} | |||||
// 创建文件路径 | |||||
String absPath = getAbsoluteFile(baseDir, fileName).getAbsolutePath(); | String absPath = getAbsoluteFile(baseDir, fileName).getAbsolutePath(); | ||||
file.transferTo(Paths.get(absPath)); | |||||
// 存储文件 | |||||
if(isAngle){ // 旋转保存 | |||||
// 创建文件路径 | |||||
File desc = getAbsoluteFile(baseDir, fileName); | |||||
String ex = file.getOriginalFilename().substring(file.getOriginalFilename().lastIndexOf(".")); | |||||
//根据图片角度自动识别翻转 | |||||
//int angle = ImageUtils.getAngle(ImageUtils.getExif(file.getInputStream())); | |||||
// 旋转可能是自动识别手机效果的,此处不是原生,所以写死 | |||||
int angle = 3; | |||||
BufferedImage bf = ImageUtils.getBufferedImg(ImageIO.read(file.getInputStream()), ImageUtils.getWidth(file.getInputStream()), ImageUtils.getHeight(file.getInputStream()), angle); | |||||
ImageIO.write(bf, ex.substring(1), desc); | |||||
}else { // 正常保存 | |||||
file.transferTo(Paths.get(absPath)); | |||||
} | |||||
// 是否有转换透明底的需求 | |||||
if (isPng) { | |||||
//BufferedImage image = ImageIO.read(new File(absPath)); | |||||
//BufferedImage transparentImage = ImageUtils.makeBackgroundTransparent(image); | |||||
//ImageIO.write(transparentImage, "PNG", new File(absPath + "png")); | |||||
ImageUtils.convertToTransparentPng(absPath, absPath); | |||||
} | |||||
// 返回文件路径 | |||||
return getPathFileName(baseDir, fileName); | return getPathFileName(baseDir, fileName); | ||||
} | |||||
/** | |||||
* 编码文件名(日期格式目录 + 原文件名 + 序列值 + 后缀) | |||||
*/ | |||||
public static final String extractFilename(MultipartFile file) | |||||
{ | |||||
return StringUtils.format("{}/{}_{}.{}", DateUtils.datePath(), FilenameUtils.getBaseName(file.getOriginalFilename()), Seq.getId(Seq.uploadSeqType), getExtension(file)); | |||||
} | } | ||||
/** | /** | ||||
* 编编码文件名(日期格式目录 + UUID + 后缀) | |||||
* 编码文件名 | |||||
*/ | */ | ||||
public static final String uuidFilename(MultipartFile file) | |||||
{ | |||||
return StringUtils.format("{}/{}.{}", DateUtils.datePath(), IdUtils.fastSimpleUUID(), getExtension(file)); | |||||
public static final String extractFilename(MultipartFile file) { | |||||
return StringUtils.format("{}/{}_{}.{}", DateUtils.datePath(), | |||||
FilenameUtils.getBaseName(file.getOriginalFilename()), Seq.getId(Seq.uploadSeqType), getExtension(file)); | |||||
} | } | ||||
public static final File getAbsoluteFile(String uploadDir, String fileName) throws IOException | |||||
{ | |||||
public static final File getAbsoluteFile(String uploadDir, String fileName) throws IOException { | |||||
File desc = new File(uploadDir + File.separator + fileName); | File desc = new File(uploadDir + File.separator + fileName); | ||||
if (!desc.exists()) | |||||
{ | |||||
if (!desc.getParentFile().exists()) | |||||
{ | |||||
if (!desc.exists()) { | |||||
if (!desc.getParentFile().exists()) { | |||||
desc.getParentFile().mkdirs(); | desc.getParentFile().mkdirs(); | ||||
} | } | ||||
} | } | ||||
return desc; | return desc; | ||||
} | } | ||||
public static final String getPathFileName(String uploadDir, String fileName) throws IOException | |||||
{ | |||||
public static final String getPathFileName(String uploadDir, String fileName) throws IOException { | |||||
int dirLastIndex = RuoYiConfig.getProfile().length() + 1; | int dirLastIndex = RuoYiConfig.getProfile().length() + 1; | ||||
String currentDir = StringUtils.substring(uploadDir, dirLastIndex); | String currentDir = StringUtils.substring(uploadDir, dirLastIndex); | ||||
return Constants.RESOURCE_PREFIX + "/" + currentDir + "/" + fileName; | return Constants.RESOURCE_PREFIX + "/" + currentDir + "/" + fileName; | ||||
@@ -184,40 +322,30 @@ public class FileUploadUtils | |||||
* @throws InvalidExtensionException | * @throws InvalidExtensionException | ||||
*/ | */ | ||||
public static final void assertAllowed(MultipartFile file, String[] allowedExtension) | public static final void assertAllowed(MultipartFile file, String[] allowedExtension) | ||||
throws FileSizeLimitExceededException, InvalidExtensionException | |||||
{ | |||||
throws FileSizeLimitExceededException, InvalidExtensionException { | |||||
long size = file.getSize(); | long size = file.getSize(); | ||||
if (size > DEFAULT_MAX_SIZE) | |||||
{ | |||||
// 超过默认 50M | |||||
if (size > DEFAULT_MAX_SIZE) { | |||||
throw new FileSizeLimitExceededException(DEFAULT_MAX_SIZE / 1024 / 1024); | throw new FileSizeLimitExceededException(DEFAULT_MAX_SIZE / 1024 / 1024); | ||||
} | } | ||||
String fileName = file.getOriginalFilename(); | String fileName = file.getOriginalFilename(); | ||||
String extension = getExtension(file); | String extension = getExtension(file); | ||||
if (allowedExtension != null && !isAllowedExtension(extension, allowedExtension)) | |||||
{ | |||||
if (allowedExtension == MimeTypeUtils.IMAGE_EXTENSION) | |||||
{ | |||||
// 文件格式校验 | |||||
if (allowedExtension != null && !isAllowedExtension(extension, allowedExtension)) { | |||||
if (allowedExtension == MimeTypeUtils.IMAGE_EXTENSION) { | |||||
throw new InvalidExtensionException.InvalidImageExtensionException(allowedExtension, extension, | throw new InvalidExtensionException.InvalidImageExtensionException(allowedExtension, extension, | ||||
fileName); | fileName); | ||||
} | |||||
else if (allowedExtension == MimeTypeUtils.FLASH_EXTENSION) | |||||
{ | |||||
} else if (allowedExtension == MimeTypeUtils.FLASH_EXTENSION) { | |||||
throw new InvalidExtensionException.InvalidFlashExtensionException(allowedExtension, extension, | throw new InvalidExtensionException.InvalidFlashExtensionException(allowedExtension, extension, | ||||
fileName); | fileName); | ||||
} | |||||
else if (allowedExtension == MimeTypeUtils.MEDIA_EXTENSION) | |||||
{ | |||||
} else if (allowedExtension == MimeTypeUtils.MEDIA_EXTENSION) { | |||||
throw new InvalidExtensionException.InvalidMediaExtensionException(allowedExtension, extension, | throw new InvalidExtensionException.InvalidMediaExtensionException(allowedExtension, extension, | ||||
fileName); | fileName); | ||||
} | |||||
else if (allowedExtension == MimeTypeUtils.VIDEO_EXTENSION) | |||||
{ | |||||
} else if (allowedExtension == MimeTypeUtils.VIDEO_EXTENSION) { | |||||
throw new InvalidExtensionException.InvalidVideoExtensionException(allowedExtension, extension, | throw new InvalidExtensionException.InvalidVideoExtensionException(allowedExtension, extension, | ||||
fileName); | fileName); | ||||
} | |||||
else | |||||
{ | |||||
} else { | |||||
throw new InvalidExtensionException(allowedExtension, extension, fileName); | throw new InvalidExtensionException(allowedExtension, extension, fileName); | ||||
} | } | ||||
} | } | ||||
@@ -230,12 +358,9 @@ public class FileUploadUtils | |||||
* @param allowedExtension | * @param allowedExtension | ||||
* @return | * @return | ||||
*/ | */ | ||||
public static final boolean isAllowedExtension(String extension, String[] allowedExtension) | |||||
{ | |||||
for (String str : allowedExtension) | |||||
{ | |||||
if (str.equalsIgnoreCase(extension)) | |||||
{ | |||||
public static final boolean isAllowedExtension(String extension, String[] allowedExtension) { | |||||
for (String str : allowedExtension) { | |||||
if (str.equalsIgnoreCase(extension)) { | |||||
return true; | return true; | ||||
} | } | ||||
} | } | ||||
@@ -244,15 +369,13 @@ public class FileUploadUtils | |||||
/** | /** | ||||
* 获取文件名的后缀 | * 获取文件名的后缀 | ||||
* | |||||
* | |||||
* @param file 表单文件 | * @param file 表单文件 | ||||
* @return 后缀名 | * @return 后缀名 | ||||
*/ | */ | ||||
public static final String getExtension(MultipartFile file) | |||||
{ | |||||
public static final String getExtension(MultipartFile file) { | |||||
String extension = FilenameUtils.getExtension(file.getOriginalFilename()); | String extension = FilenameUtils.getExtension(file.getOriginalFilename()); | ||||
if (StringUtils.isEmpty(extension)) | |||||
{ | |||||
if (StringUtils.isEmpty(extension)) { | |||||
extension = MimeTypeUtils.getExtension(Objects.requireNonNull(file.getContentType())); | extension = MimeTypeUtils.getExtension(Objects.requireNonNull(file.getContentType())); | ||||
} | } | ||||
return extension; | return extension; | ||||
@@ -1,55 +1,58 @@ | |||||
package com.ruoyi.common.utils.file; | package com.ruoyi.common.utils.file; | ||||
import java.io.ByteArrayInputStream; | |||||
import java.io.FileInputStream; | |||||
import java.io.InputStream; | |||||
import java.net.URL; | |||||
import java.net.URLConnection; | |||||
import java.util.Arrays; | |||||
import org.apache.poi.util.IOUtils; | |||||
import org.slf4j.Logger; | |||||
import org.slf4j.LoggerFactory; | |||||
import com.ruoyi.common.config.RuoYiConfig; | import com.ruoyi.common.config.RuoYiConfig; | ||||
import com.ruoyi.common.constant.Constants; | import com.ruoyi.common.constant.Constants; | ||||
import com.ruoyi.common.utils.StringUtils; | import com.ruoyi.common.utils.StringUtils; | ||||
import net.coobird.thumbnailator.Thumbnails; | |||||
import org.apache.poi.util.IOUtils; | |||||
import org.slf4j.Logger; | |||||
import org.slf4j.LoggerFactory; | |||||
import javax.imageio.ImageIO; | |||||
import java.awt.*; | |||||
import java.awt.image.BufferedImage; | |||||
import java.io.*; | |||||
import java.net.URL; | |||||
import java.net.URLConnection; | |||||
import java.util.Arrays; | |||||
/** | /** | ||||
* 图片处理工具类 | * 图片处理工具类 | ||||
* | * | ||||
* @author ruoyi | * @author ruoyi | ||||
*/ | */ | ||||
public class ImageUtils | |||||
{ | |||||
public class ImageUtils { | |||||
private static final Logger log = LoggerFactory.getLogger(ImageUtils.class); | private static final Logger log = LoggerFactory.getLogger(ImageUtils.class); | ||||
public static byte[] getImage(String imagePath) | |||||
{ | |||||
//以下是常量,按照阿里代码开发规范,不允许代码中出现魔法值 | |||||
private static final Integer ZERO = 0; | |||||
private static final Integer ONE_ZERO_TWO_FOUR = 1024; | |||||
private static final Integer NINE_ZERO_ZERO = 900; | |||||
private static final Integer THREE_TWO_SEVEN_FIVE = 3275; | |||||
private static final Integer TWO_ZERO_FOUR_SEVEN = 2047; | |||||
private static final Double ZERO_EIGHT_FIVE = 0.85; | |||||
private static final Double ZERO_SIX = 0.6; | |||||
private static final Double ZERO_FOUR_FOUR = 0.44; | |||||
private static final Double ZERO_FOUR = 0.4; | |||||
public static byte[] getImage(String imagePath) { | |||||
InputStream is = getFile(imagePath); | InputStream is = getFile(imagePath); | ||||
try | |||||
{ | |||||
try { | |||||
return IOUtils.toByteArray(is); | return IOUtils.toByteArray(is); | ||||
} | |||||
catch (Exception e) | |||||
{ | |||||
} catch (Exception e) { | |||||
log.error("图片加载异常 {}", e); | log.error("图片加载异常 {}", e); | ||||
return null; | return null; | ||||
} | |||||
finally | |||||
{ | |||||
} finally { | |||||
IOUtils.closeQuietly(is); | IOUtils.closeQuietly(is); | ||||
} | } | ||||
} | } | ||||
public static InputStream getFile(String imagePath) | |||||
{ | |||||
try | |||||
{ | |||||
public static InputStream getFile(String imagePath) { | |||||
try { | |||||
byte[] result = readFile(imagePath); | byte[] result = readFile(imagePath); | ||||
result = Arrays.copyOf(result, result.length); | result = Arrays.copyOf(result, result.length); | ||||
return new ByteArrayInputStream(result); | return new ByteArrayInputStream(result); | ||||
} | |||||
catch (Exception e) | |||||
{ | |||||
} catch (Exception e) { | |||||
log.error("获取图片异常 {}", e); | log.error("获取图片异常 {}", e); | ||||
} | } | ||||
return null; | return null; | ||||
@@ -57,17 +60,14 @@ public class ImageUtils | |||||
/** | /** | ||||
* 读取文件为字节数据 | * 读取文件为字节数据 | ||||
* | |||||
* | |||||
* @param url 地址 | * @param url 地址 | ||||
* @return 字节数据 | * @return 字节数据 | ||||
*/ | */ | ||||
public static byte[] readFile(String url) | |||||
{ | |||||
public static byte[] readFile(String url) { | |||||
InputStream in = null; | InputStream in = null; | ||||
try | |||||
{ | |||||
if (url.startsWith("http")) | |||||
{ | |||||
try { | |||||
if (url.startsWith("http")) { | |||||
// 网络地址 | // 网络地址 | ||||
URL urlObj = new URL(url); | URL urlObj = new URL(url); | ||||
URLConnection urlConnection = urlObj.openConnection(); | URLConnection urlConnection = urlObj.openConnection(); | ||||
@@ -75,24 +75,223 @@ public class ImageUtils | |||||
urlConnection.setReadTimeout(60 * 1000); | urlConnection.setReadTimeout(60 * 1000); | ||||
urlConnection.setDoInput(true); | urlConnection.setDoInput(true); | ||||
in = urlConnection.getInputStream(); | in = urlConnection.getInputStream(); | ||||
} | |||||
else | |||||
{ | |||||
} else { | |||||
// 本机地址 | // 本机地址 | ||||
String localPath = RuoYiConfig.getProfile(); | String localPath = RuoYiConfig.getProfile(); | ||||
String downloadPath = localPath + StringUtils.substringAfter(url, Constants.RESOURCE_PREFIX); | String downloadPath = localPath + StringUtils.substringAfter(url, Constants.RESOURCE_PREFIX); | ||||
in = new FileInputStream(downloadPath); | in = new FileInputStream(downloadPath); | ||||
} | } | ||||
return IOUtils.toByteArray(in); | return IOUtils.toByteArray(in); | ||||
} | |||||
catch (Exception e) | |||||
{ | |||||
} catch (Exception e) { | |||||
log.error("获取文件路径异常 {}", e); | log.error("获取文件路径异常 {}", e); | ||||
return null; | return null; | ||||
} | |||||
finally | |||||
{ | |||||
} finally { | |||||
IOUtils.closeQuietly(in); | IOUtils.closeQuietly(in); | ||||
} | } | ||||
} | } | ||||
/** | |||||
* 根据指定大小压缩图片 | |||||
* | |||||
* @param imageBytes 源图片字节数组 | |||||
* @param desFileSize 指定图片大小,单位kb | |||||
* @return 压缩质量后的图片字节数组 | |||||
*/ | |||||
public static byte[] compressPicForScale(byte[] imageBytes, long desFileSize) { | |||||
if (imageBytes == null || imageBytes.length <= ZERO || imageBytes.length < desFileSize * ONE_ZERO_TWO_FOUR) { | |||||
// log.info("图片无需压缩"); | |||||
return imageBytes; | |||||
} | |||||
long srcSize = imageBytes.length; | |||||
double accuracy = getAccuracy(srcSize / ONE_ZERO_TWO_FOUR); | |||||
try { | |||||
while (imageBytes.length > desFileSize * ONE_ZERO_TWO_FOUR) { | |||||
ByteArrayInputStream inputStream = new ByteArrayInputStream(imageBytes); | |||||
ByteArrayOutputStream outputStream = new ByteArrayOutputStream(imageBytes.length); | |||||
Thumbnails.of(inputStream).scale(accuracy).outputQuality(accuracy).toOutputStream(outputStream); | |||||
imageBytes = outputStream.toByteArray(); | |||||
} | |||||
//log.info("图片原大小={}kb | 压缩后大小={}kb", srcSize / ONE_ZERO_TWO_FOUR, imageBytes.length / ONE_ZERO_TWO_FOUR); | |||||
} catch (Exception e) { | |||||
log.error("【图片压缩】msg=图片压缩失败!", e); | |||||
} | |||||
return imageBytes; | |||||
} | |||||
/** | |||||
* 自动调节精度(经验数值) | |||||
* | |||||
* @param size 源图片大小 | |||||
* @return 图片压缩质量比 | |||||
*/ | |||||
private static double getAccuracy(long size) { | |||||
double accuracy; | |||||
if (size < NINE_ZERO_ZERO) { // 900 | |||||
accuracy = ZERO_EIGHT_FIVE; // 0.85 | |||||
} else if (size < TWO_ZERO_FOUR_SEVEN) { // 2047 | |||||
accuracy = ZERO_SIX; // 0.6 | |||||
} else if (size < THREE_TWO_SEVEN_FIVE) { // 3275 | |||||
accuracy = ZERO_FOUR_FOUR; // 0.44 | |||||
} else { | |||||
accuracy = ZERO_FOUR; // 0.4 | |||||
} | |||||
return accuracy; | |||||
} | |||||
/** | |||||
* 将图片转换为具有透明底的PNG图片 | |||||
* | |||||
* @param inputFile 输入图片文件路径 | |||||
* @param outputFile 输出图片文件路径 | |||||
* @throws IOException 如果读写文件时发生错误 | |||||
*/ | |||||
public static void convertToTransparentPng(String inputFile, String outputFile) throws IOException { | |||||
// 读取图片 | |||||
BufferedImage image = ImageIO.read(new File(inputFile)); | |||||
// 创建一个新的图片对象,类型为 BufferedImage.TYPE_INT_ARGB | |||||
BufferedImage newImage = new BufferedImage(image.getWidth(), image.getHeight(), BufferedImage.TYPE_INT_ARGB); | |||||
// 获取新图片的绘制上下文 | |||||
Graphics2D g2d = (Graphics2D) newImage.getGraphics(); | |||||
// 绘制原始图片到新图片上,同时处理每个像素 | |||||
for (int x = 0; x < image.getWidth(); x++) { | |||||
for (int y = 0; y < image.getHeight(); y++) { | |||||
// 获取原始图片的像素颜色 | |||||
int color = image.getRGB(x, y); | |||||
Color originalColor = new Color(color, true); | |||||
// 判断是否为白色,这里设置了一个阈值范围 | |||||
if (originalColor.getRed() > 102 && originalColor.getGreen() > 102 && originalColor.getBlue() > 102) { | |||||
// 如果是白色,则设置为透明 | |||||
g2d.setColor(new Color(0, 0, 0, 0)); | |||||
} else { | |||||
// 如果不是白色,则保持原始颜色 | |||||
g2d.setColor(originalColor); | |||||
} | |||||
// 绘制像素 | |||||
g2d.drawRect(x, y, 1, 1); | |||||
} | |||||
} | |||||
// 释放资源 | |||||
g2d.dispose(); | |||||
// 保存处理后的图片 | |||||
ImageIO.write(newImage, "PNG", new File(outputFile)); | |||||
} | |||||
/** | |||||
* 将图片转换为具有透明底的PNG图片 | |||||
* @param inputFile 输入图片文件 | |||||
* @param outputFile 输出图片文件路径 | |||||
* @throws IOException 如果读写文件时发生错误 | |||||
*/ | |||||
public static void convertToTransparentPng(File inputFile, String outputFile) throws IOException { | |||||
// 读取输入图片 | |||||
BufferedImage image = ImageIO.read(inputFile); | |||||
// 创建一个具有透明背景的BufferedImage | |||||
BufferedImage transparentImage = new BufferedImage( | |||||
image.getWidth(), | |||||
image.getHeight(), | |||||
BufferedImage.TYPE_INT_ARGB | |||||
); | |||||
// 绘制原始图片到透明背景上 | |||||
Graphics2D graphics = transparentImage.createGraphics(); | |||||
graphics.setComposite(AlphaComposite.Src); | |||||
graphics.drawImage(image, 0, 0, null); | |||||
graphics.dispose(); | |||||
// 写入到输出文件 | |||||
ImageIO.write(transparentImage, "PNG", new File(outputFile)); | |||||
} | |||||
public static BufferedImage makeBackgroundTransparent(BufferedImage image) { | |||||
int width = image.getWidth(); | |||||
int height = image.getHeight(); | |||||
BufferedImage transparentImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB); | |||||
Graphics2D g2d = transparentImage.createGraphics(); | |||||
g2d.setComposite(AlphaComposite.Src); | |||||
g2d.drawImage(image, null, 0, 0); | |||||
g2d.dispose(); | |||||
for (int y = 0; y < height; y++) { | |||||
for (int x = 0; x < width; x++) { | |||||
int p = image.getRGB(x, y); | |||||
int a = (p >> 24) & 0xff; | |||||
int r = (p >> 16) & 0xff; | |||||
int g = (p >> 8) & 0xff; | |||||
int b = p & 0xff; | |||||
// Define your background color here | |||||
if (r > 255 && g > 255 && b > 255) { | |||||
// Set fully transparent for background color | |||||
p = (a << 24) | (0 << 16) | (0 << 8) | 0; | |||||
} | |||||
transparentImage.setRGB(x, y, p); | |||||
} | |||||
} | |||||
return transparentImage; | |||||
} | |||||
public static BufferedImage getBufferedImg(BufferedImage src, int width, int height, int ro) { | |||||
int angle = (int) (90 * ro); | |||||
int type = src.getColorModel().getTransparency(); | |||||
int wid = width; | |||||
int hei = height; | |||||
if (ro % 2 != 0) { | |||||
int temp = width; | |||||
width = height; | |||||
height = temp; | |||||
} | |||||
Rectangle re = new Rectangle(new Dimension(width, height)); | |||||
BufferedImage BfImg = null; | |||||
BfImg = new BufferedImage(re.width, re.height, type); | |||||
Graphics2D g2 = BfImg.createGraphics(); | |||||
g2.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR); | |||||
g2.rotate(Math.toRadians(angle), re.width / 2, re.height / 2); | |||||
g2.drawImage(src, (re.width - wid) / 2, (re.height - hei) / 2, null); | |||||
g2.dispose(); | |||||
return BfImg; | |||||
} | |||||
//获得图片的高 | |||||
public static int getHeight(InputStream is) { | |||||
BufferedImage src = null; | |||||
int height = -1; | |||||
try { | |||||
src = ImageIO.read(is); | |||||
height = src.getHeight(); | |||||
} catch (Exception e) { | |||||
System.out.println(e.getMessage()); | |||||
} | |||||
return height; | |||||
} | |||||
//获得图片的宽 | |||||
public static int getWidth(InputStream is) { | |||||
BufferedImage src = null; | |||||
int width = -1; | |||||
try { | |||||
src = ImageIO.read(is); | |||||
width = src.getWidth(); | |||||
} catch (Exception e) { | |||||
System.out.println(e.getMessage()); | |||||
} | |||||
return width; | |||||
} | |||||
public static byte[] readInputStream(InputStream inStream) throws IOException { | |||||
ByteArrayOutputStream outStream = new ByteArrayOutputStream(); | |||||
byte[] buffer = new byte[1024]; | |||||
int len; | |||||
while ((len = inStream.read(buffer)) != -1) { | |||||
outStream.write(buffer, 0, len); | |||||
} | |||||
inStream.close(); | |||||
return outStream.toByteArray(); | |||||
} | |||||
} | } |
@@ -0,0 +1,72 @@ | |||||
package com.ruoyi.common.utils.pdf; | |||||
import com.itextpdf.text.*; | |||||
import com.itextpdf.text.pdf.*; | |||||
import com.ruoyi.common.config.RuoYiConfig; | |||||
import java.io.IOException; | |||||
/** | |||||
* @description: 显示页数 | |||||
* @author: zzl | |||||
* @date: Created in 2024-04-27 9:07 | |||||
* @version: 1.0 | |||||
* @modified By: | |||||
*/ | |||||
public class MyHeaderFooter extends PdfPageEventHelper { | |||||
// 总页数 | |||||
PdfTemplate totalPage; | |||||
Font hfFont; | |||||
{ | |||||
try { | |||||
hfFont = new Font(BaseFont.createFont("STSong-Light", "UniGB-UCS2-H", BaseFont.NOT_EMBEDDED), 8, Font.NORMAL); | |||||
} catch (DocumentException e) { | |||||
e.printStackTrace(); | |||||
} catch (IOException e) { | |||||
e.printStackTrace(); | |||||
} | |||||
} | |||||
// 打开文档时,创建一个总页数的模版 | |||||
public void onOpenDocument(PdfWriter writer, Document document) { | |||||
PdfContentByte cb = writer.getDirectContent(); | |||||
totalPage = cb.createTemplate(30, 16); | |||||
} | |||||
// 一页加载完成触发,写入页眉和页脚 | |||||
public void onEndPage(PdfWriter writer, Document document) { | |||||
PdfPTable table = new PdfPTable(3); | |||||
try { | |||||
table.setTotalWidth(PageSize.A4.getWidth() - 100); | |||||
table.setWidths(new int[]{24, 24, 3}); | |||||
table.setLockedWidth(true); | |||||
table.getDefaultCell().setFixedHeight(-10); | |||||
table.getDefaultCell().setBorder(Rectangle.BOTTOM); | |||||
table.addCell(new Paragraph(RuoYiConfig.getName(), hfFont)); | |||||
table.getDefaultCell().setHorizontalAlignment(Element.ALIGN_RIGHT); | |||||
table.addCell(new Paragraph("第" + writer.getPageNumber() + "页/", hfFont)); | |||||
// 总页数 | |||||
PdfPCell cell = new PdfPCell(Image.getInstance(totalPage)); | |||||
cell.setBorder(Rectangle.BOTTOM); | |||||
table.addCell(cell); | |||||
// 将页眉写到document中,位置可以指定,指定到下面就是页脚 | |||||
table.writeSelectedRows(0, -1, 50, PageSize.A4.getHeight() - 20, writer.getDirectContent()); | |||||
} catch (Exception de) { | |||||
throw new ExceptionConverter(de); | |||||
} | |||||
} | |||||
// 全部完成后,将总页数的pdf模版写到指定位置 | |||||
public void onCloseDocument(PdfWriter writer, Document document) { | |||||
String text = "总" + (writer.getPageNumber()) + "页" ; | |||||
ColumnText.showTextAligned(totalPage, Element.ALIGN_LEFT, new Paragraph(text, hfFont), 2, 2, 0); | |||||
} | |||||
} |
@@ -0,0 +1,70 @@ | |||||
package com.ruoyi.common.utils.pdf; | |||||
import com.itextpdf.text.*; | |||||
import com.itextpdf.text.pdf.*; | |||||
import com.ruoyi.common.config.RuoYiConfig; | |||||
import java.io.IOException; | |||||
/** | |||||
* @description: 显示页数 | |||||
* @author: zzl | |||||
* @date: Created in 2024-04-27 9:07 | |||||
* @version: 1.0 | |||||
* @modified By: | |||||
*/ | |||||
public class MyHeaderFooterRotate extends PdfPageEventHelper { | |||||
// 总页数 | |||||
PdfTemplate totalPage; | |||||
Font hfFont; | |||||
{ | |||||
try { | |||||
hfFont = new Font(BaseFont.createFont("STSong-Light", "UniGB-UCS2-H", BaseFont.NOT_EMBEDDED), 8, Font.NORMAL); | |||||
} catch (DocumentException e) { | |||||
e.printStackTrace(); | |||||
} catch (IOException e) { | |||||
e.printStackTrace(); | |||||
} | |||||
} | |||||
// 打开文档时,创建一个总页数的模版 | |||||
public void onOpenDocument(PdfWriter writer, Document document) { | |||||
PdfContentByte cb = writer.getDirectContent(); | |||||
totalPage = cb.createTemplate(30, 16); | |||||
} | |||||
// 一页加载完成触发,写入页眉和页脚 | |||||
public void onEndPage(PdfWriter writer, Document document) { | |||||
PdfPTable table = new PdfPTable(3); | |||||
try { | |||||
table.setTotalWidth(PageSize.A4.getHeight() - 100); | |||||
table.setWidths(new int[]{24, 24, 3}); | |||||
table.setLockedWidth(true); | |||||
table.getDefaultCell().setFixedHeight(-10); | |||||
table.getDefaultCell().setBorder(Rectangle.BOTTOM); | |||||
table.addCell(new Paragraph(RuoYiConfig.getName(), hfFont)); | |||||
table.getDefaultCell().setHorizontalAlignment(Element.ALIGN_RIGHT); | |||||
table.addCell(new Paragraph("第" + writer.getPageNumber() + "页/", hfFont)); | |||||
// 总页数 | |||||
PdfPCell cell = new PdfPCell(Image.getInstance(totalPage)); | |||||
cell.setBorder(Rectangle.BOTTOM); | |||||
table.addCell(cell); | |||||
// 将页眉写到document中,位置可以指定,指定到下面就是页脚 | |||||
table.writeSelectedRows(0, -1, 50, PageSize.A4.getWidth() - 20, writer.getDirectContent()); | |||||
} catch (Exception de) { | |||||
throw new ExceptionConverter(de); | |||||
} | |||||
} | |||||
// 全部完成后,将总页数的pdf模版写到指定位置 | |||||
public void onCloseDocument(PdfWriter writer, Document document) { | |||||
String text = "总" + (writer.getPageNumber()) + "页" ; | |||||
ColumnText.showTextAligned(totalPage, Element.ALIGN_LEFT, new Paragraph(text, hfFont), 2, 2, 0); | |||||
} | |||||
} |
@@ -0,0 +1,538 @@ | |||||
package com.ruoyi.common.utils.pdf; | |||||
import com.itextpdf.text.*; | |||||
import com.itextpdf.text.pdf.BaseFont; | |||||
import com.itextpdf.text.pdf.PdfPCell; | |||||
import com.itextpdf.text.pdf.PdfPTable; | |||||
import com.itextpdf.text.pdf.PdfWriter; | |||||
import com.itextpdf.text.pdf.draw.DottedLineSeparator; | |||||
import com.itextpdf.text.pdf.draw.LineSeparator; | |||||
import com.ruoyi.common.core.domain.pdf.PageSet; | |||||
import com.ruoyi.common.core.domain.pdf.PdfProperty; | |||||
import com.ruoyi.common.core.domain.pdf.ShoulderItem; | |||||
import com.ruoyi.common.utils.StringUtils; | |||||
import lombok.extern.slf4j.Slf4j; | |||||
import javax.servlet.http.HttpServletResponse; | |||||
import java.io.ByteArrayOutputStream; | |||||
import java.util.List; | |||||
/** | |||||
* pdf处理工具类 | |||||
* | |||||
* @author ruoyi | |||||
*/ | |||||
@Slf4j | |||||
public class PdfUtils<statistic> { | |||||
// 定义全局的字体静态变量 | |||||
private static Font titlefontMax; | |||||
private static Font titlefont; | |||||
private static Font titlefontmin; | |||||
private static Font headfont; | |||||
private static Font keyfont; | |||||
private static Font textfont; | |||||
private static Font bottomfont; | |||||
// 最大宽度 | |||||
public static int maxWidth = 520; | |||||
// 表行高 | |||||
public static float rowHeight = 20f; | |||||
// 表格宽度百分比 | |||||
public static Integer widthPercentage = 100; | |||||
public static int leftspan = 3; | |||||
public static int centerspan = 3; | |||||
public static int rightspan = 3; | |||||
// 行线间距 | |||||
public static float dottedLineSpace = 50f; | |||||
// 静态代码块 | |||||
static { | |||||
try { | |||||
// 不同字体(这里定义为同一种字体:包含不同字号、不同style) | |||||
BaseFont bfChinese = BaseFont.createFont("STSong-Light", "UniGB-UCS2-H", BaseFont.NOT_EMBEDDED); | |||||
titlefontMax = new Font(bfChinese, 20, Font.BOLD); | |||||
titlefont = new Font(bfChinese, 15, Font.BOLD); | |||||
titlefontmin = new Font(bfChinese, 14, Font.BOLD); | |||||
headfont = new Font(bfChinese, 11, Font.NORMAL); | |||||
keyfont = new Font(bfChinese, 10, Font.BOLD); | |||||
textfont = new Font(bfChinese, 10, Font.NORMAL); | |||||
bottomfont = new Font(bfChinese, 11, Font.NORMAL); | |||||
} catch (Exception e) { | |||||
e.printStackTrace(); | |||||
} | |||||
} | |||||
// 通用 初始化 PDF文件 | |||||
public static void initPdf(HttpServletResponse response, PdfProperty pdf) throws Exception { | |||||
// 1. 新建document对象 | |||||
Document document = null; | |||||
PageSet ps = pdf.getPageSet(); | |||||
if (StringUtils.isNull(ps)) { //默认A4纵向 | |||||
document = new Document(PageSize.A4); | |||||
} else { // 自定义 | |||||
if (ps.getPrintDirection().equals("1")) {// 纵向 | |||||
document = new Document(new Rectangle(ps.getPaperWidth(), ps.getPaperHeight()), ps.getMarginLeft(), ps.getMarginRight(), ps.getMarginTop(), ps.getMarginBottom()); | |||||
} else { //2 横向 | |||||
document = new Document(new Rectangle(ps.getPaperWidth(), ps.getPaperHeight()).rotate(), ps.getMarginLeft(), ps.getMarginRight(), ps.getMarginTop(), ps.getMarginBottom()); | |||||
} | |||||
} | |||||
// 2. 创建一个输出流,将输出流与PdfWriter绑定 | |||||
ByteArrayOutputStream baos = new ByteArrayOutputStream(); | |||||
PdfWriter writer = PdfWriter.getInstance(document, baos); | |||||
if (ps.getPrintDirection().equals("1")) {// 纵向 | |||||
writer.setPageEvent(new MyHeaderFooter());// 页眉/页脚 | |||||
} else { //2 横向 | |||||
writer.setPageEvent(new MyHeaderFooterRotate());// 页眉/页脚 | |||||
} | |||||
// 3. 打开文档 | |||||
document.open(); | |||||
document.addTitle(pdf.getTitle() + " PDF打印"); | |||||
// 4. 向文档中添加内容 | |||||
generateComPdf(document, pdf); | |||||
// 5. 关闭文档 | |||||
document.close(); | |||||
// 6. 将PDF输出到浏览器 | |||||
response.setContentType("application/pdf"); | |||||
response.setCharacterEncoding("utf-8"); | |||||
response.setContentLength(baos.size()); | |||||
response.setHeader("Content-Disposition", "inline; filename=example.pdf"); | |||||
response.getOutputStream().write(baos.toByteArray()); | |||||
response.getOutputStream().flush(); | |||||
} | |||||
// 通用 填充 PDF 内容 | |||||
public static void generateComPdf(Document document, PdfProperty pdf) throws Exception { | |||||
// 创建段落:表名 | |||||
createParagraph(document, pdf.getTitle()); | |||||
// 初始参数 | |||||
int columns = pdf.getHeader().length; | |||||
centerspan = columns / 3; | |||||
leftspan = centerspan + columns % 3; | |||||
rightspan = centerspan; | |||||
if (StringUtils.isNotNull(pdf.getPageSet())) { | |||||
maxWidth = pdf.getPageSet().getTableTotalWidth(); | |||||
} | |||||
if (StringUtils.isNotNull(pdf.getRowHeight())) { | |||||
rowHeight = pdf.getRowHeight(); | |||||
} | |||||
// 创建表 | |||||
PdfPTable table = createTable(pdf.getColumnWidth()); | |||||
// 肩部名称 | |||||
ShoulderItem shoulder = pdf.getShoulder(); | |||||
if (StringUtils.isNotNull(shoulder)) { | |||||
createShoulder(table, shoulder); | |||||
} | |||||
// 列标题 | |||||
String[] header = pdf.getHeader(); | |||||
for (String h : header) { | |||||
table.addCell(createCell(h, keyfont, Element.ALIGN_CENTER)); | |||||
} | |||||
// 设置为每页固定表头 < row | |||||
if (StringUtils.isNotNull(shoulder)) { | |||||
table.setHeaderRows(2); | |||||
} else { | |||||
table.setHeaderRows(1); | |||||
} | |||||
// 列水平位置 | |||||
int[] aligns = pdf.getAligns(); | |||||
// 行内容 | |||||
List<String[]> contentList = pdf.getContentList(); | |||||
for (String[] strs : contentList) { | |||||
int i = 0; | |||||
for (String str : strs) { | |||||
if (null == aligns) { | |||||
table.addCell(createCell(str, textfont)); | |||||
} else { | |||||
table.addCell(createCell(str, textfont, aligns[i])); | |||||
} | |||||
i++; | |||||
} | |||||
} | |||||
document.add(table); | |||||
} | |||||
/** | |||||
* 创建单元格(指定字体) | |||||
* | |||||
* @param value | |||||
* @param font | |||||
* @return | |||||
*/ | |||||
public static PdfPCell createCell(String value, Font font) { | |||||
PdfPCell cell = new PdfPCell(); | |||||
cell.setVerticalAlignment(Element.ALIGN_MIDDLE); | |||||
cell.setHorizontalAlignment(Element.ALIGN_CENTER); | |||||
cell.setPhrase(new Phrase(value, font)); | |||||
cell.setFixedHeight(rowHeight); | |||||
cell.setNoWrap(false); // 自动换行 | |||||
return cell; | |||||
} | |||||
/** | |||||
* 创建单元格(指定字体、水平位置) | |||||
* | |||||
* @param value | |||||
* @param font | |||||
* @param align | |||||
* @return | |||||
*/ | |||||
public static PdfPCell createCell(String value, Font font, int align) { | |||||
PdfPCell cell = new PdfPCell(); | |||||
cell.setVerticalAlignment(Element.ALIGN_MIDDLE); | |||||
cell.setHorizontalAlignment(align); | |||||
cell.setPhrase(new Phrase(value, font)); | |||||
cell.setMinimumHeight(rowHeight); | |||||
cell.setNoWrap(false); // 自动换行 | |||||
return cell; | |||||
} | |||||
/** | |||||
* 创建单元格(指定字体、水平位置、跨x列合并) | |||||
* | |||||
* @param value | |||||
* @param font | |||||
* @param align | |||||
* @param colspan | |||||
* @return | |||||
*/ | |||||
public static PdfPCell createCell(String value, Font font, int align, int colspan) { | |||||
PdfPCell cell = new PdfPCell(); | |||||
cell.setVerticalAlignment(Element.ALIGN_MIDDLE); | |||||
cell.setHorizontalAlignment(align); | |||||
cell.setColspan(colspan); | |||||
cell.setPhrase(new Phrase(value, font)); | |||||
cell.setMinimumHeight(rowHeight); | |||||
cell.setNoWrap(false); // 自动换行 | |||||
return cell; | |||||
} | |||||
/** | |||||
* 创建单元格(指定字体、水平位置、跨x行合并) | |||||
* | |||||
* @param value | |||||
* @param font | |||||
* @param align | |||||
* @param rowspan | |||||
* @return | |||||
*/ | |||||
public static PdfPCell createCell2(String value, Font font, int align, int rowspan) { | |||||
PdfPCell cell = new PdfPCell(); | |||||
cell.setVerticalAlignment(Element.ALIGN_MIDDLE); | |||||
cell.setHorizontalAlignment(align); | |||||
cell.setRowspan(rowspan); | |||||
cell.setPhrase(new Phrase(value, font)); | |||||
cell.setMinimumHeight(rowHeight); | |||||
cell.setNoWrap(false); // 自动换行 | |||||
return cell; | |||||
} | |||||
/** | |||||
* 创建单元格(指定字体、水平位置、跨x列合并、设置单元格内边距) | |||||
* | |||||
* @param value | |||||
* @param font | |||||
* @param align | |||||
* @param colspan | |||||
* @param boderFlag | |||||
* @return | |||||
*/ | |||||
public static PdfPCell createCell(String value, Font font, int align, int colspan, boolean boderFlag) { | |||||
PdfPCell cell = new PdfPCell(); | |||||
cell.setVerticalAlignment(Element.ALIGN_MIDDLE); | |||||
cell.setHorizontalAlignment(align); | |||||
cell.setColspan(colspan); | |||||
cell.setPhrase(new Phrase(value, font)); | |||||
cell.setMinimumHeight(rowHeight); | |||||
cell.setNoWrap(false); // 自动换行 | |||||
cell.setPadding(3.0f); | |||||
if (!boderFlag) { | |||||
cell.setBorder(0); | |||||
cell.setPaddingTop(4.0f); | |||||
cell.setPaddingBottom(4.0f); | |||||
} else if (boderFlag) { | |||||
cell.setBorder(0); | |||||
cell.setPaddingTop(2.0f); | |||||
cell.setPaddingBottom(2.0f); | |||||
} | |||||
return cell; | |||||
} | |||||
public static PdfPCell createCellBottom(String value, Font font, int align, int colspan, boolean boderFlag) { | |||||
PdfPCell cell = new PdfPCell(); | |||||
cell.setVerticalAlignment(Element.ALIGN_MIDDLE); | |||||
cell.setHorizontalAlignment(align); | |||||
cell.setColspan(colspan); | |||||
cell.setPhrase(new Phrase(value, font)); | |||||
cell.setMinimumHeight(35f); | |||||
cell.setNoWrap(false); // 自动换行 | |||||
cell.setPadding(3.0f); | |||||
if (!boderFlag) { | |||||
cell.setBorder(0); | |||||
cell.setPaddingTop(4.0f); | |||||
cell.setPaddingBottom(4.0f); | |||||
} else if (boderFlag) { | |||||
cell.setBorder(0); | |||||
cell.setPaddingTop(2.0f); | |||||
cell.setPaddingBottom(2.0f); | |||||
} | |||||
return cell; | |||||
} | |||||
/** | |||||
* 创建单元格(指定字体、水平位置、边框宽度(0表示无边框)、内边距、是否合并2列) | |||||
* | |||||
* @param value | |||||
* @param font | |||||
* @param align | |||||
* @param borderWidth | |||||
* @param paddingSize | |||||
* @param flag | |||||
* @return | |||||
*/ | |||||
public PdfPCell createCell(String value, Font font, int align, float[] borderWidth, float[] paddingSize, boolean flag) { | |||||
PdfPCell cell = new PdfPCell(); | |||||
cell.setVerticalAlignment(Element.ALIGN_MIDDLE); | |||||
cell.setHorizontalAlignment(align); | |||||
cell.setPhrase(new Phrase(value, font)); | |||||
cell.setBorderWidthLeft(borderWidth[0]); | |||||
cell.setBorderWidthRight(borderWidth[1]); | |||||
cell.setBorderWidthTop(borderWidth[2]); | |||||
cell.setBorderWidthBottom(borderWidth[3]); | |||||
cell.setPaddingTop(paddingSize[0]); | |||||
cell.setPaddingBottom(paddingSize[1]); | |||||
cell.setNoWrap(false); // 自动换行 | |||||
if (flag) { | |||||
cell.setColspan(2); | |||||
} | |||||
return cell; | |||||
} | |||||
/** | |||||
* 创建默认列宽,指定列数、水平(居中、右、左)的表格 | |||||
* | |||||
* @param colNumber | |||||
* @param align | |||||
* @return | |||||
*/ | |||||
public static PdfPTable createTable(int colNumber, int align) { | |||||
PdfPTable table = new PdfPTable(colNumber); | |||||
try { | |||||
table.setTotalWidth(maxWidth); | |||||
table.setLockedWidth(true); | |||||
table.setHorizontalAlignment(align); | |||||
table.getDefaultCell().setBorder(1); | |||||
} catch (Exception e) { | |||||
e.printStackTrace(); | |||||
} | |||||
return table; | |||||
} | |||||
/** | |||||
* 创建指定列宽、列数的表格 | |||||
* | |||||
* @param widths | |||||
* @return | |||||
*/ | |||||
public static PdfPTable createTable(float[] widths) { | |||||
PdfPTable table = new PdfPTable(widths.length); | |||||
try { | |||||
table.setTotalWidth(maxWidth); | |||||
table.setWidthPercentage(widthPercentage); | |||||
table.setWidths(widths); | |||||
table.setLockedWidth(true); | |||||
table.setHorizontalAlignment(Element.ALIGN_CENTER); | |||||
table.getDefaultCell().setBorder(1); | |||||
} catch (Exception e) { | |||||
e.printStackTrace(); | |||||
} | |||||
return table; | |||||
} | |||||
/** | |||||
* 创建段落 | |||||
* | |||||
* @return | |||||
*/ | |||||
public static void createParagraph(Document document, String title) throws Exception { | |||||
Paragraph paragraph = new Paragraph(title, titlefont); | |||||
paragraph.setAlignment(1); //设置文字居中 0靠左 1,居中 2,靠右 | |||||
paragraph.setIndentationLeft(12); //设置左缩进 | |||||
paragraph.setIndentationRight(12); //设置右缩进 | |||||
paragraph.setFirstLineIndent(24); //设置首行缩进 | |||||
paragraph.setLeading(20f); //行间距 | |||||
paragraph.setSpacingBefore(5f); //设置段落上空白 | |||||
paragraph.setSpacingAfter(10f); //设置段落下空白 | |||||
document.add(paragraph); | |||||
} | |||||
/** | |||||
* 创建段落 | |||||
* | |||||
* @return | |||||
*/ | |||||
public static void createParagraph(Document document, String title, Font titlefont) throws Exception { | |||||
Paragraph paragraph = new Paragraph(title, titlefont); | |||||
paragraph.setAlignment(1); //设置文字居中 0靠左 1,居中 2,靠右 | |||||
paragraph.setIndentationLeft(12); //设置左缩进 | |||||
paragraph.setIndentationRight(12); //设置右缩进 | |||||
paragraph.setFirstLineIndent(24); //设置首行缩进 | |||||
paragraph.setLeading(20f); //行间距 | |||||
paragraph.setSpacingBefore(5f); //设置段落上空白 | |||||
paragraph.setSpacingAfter(10f); //设置段落下空白 | |||||
document.add(paragraph); | |||||
} | |||||
/** | |||||
* 创建点线 | |||||
* | |||||
* @return | |||||
*/ | |||||
public static void createDottedLine(Document document) throws Exception { | |||||
Paragraph dottedLine = new Paragraph(); | |||||
dottedLine.add(new Chunk(new DottedLineSeparator())); | |||||
dottedLine.setAlignment(1); //设置文字居中 0靠左 1,居中 2,靠右 | |||||
dottedLine.setIndentationLeft(12); //设置左缩进 | |||||
dottedLine.setIndentationRight(12); //设置右缩进 | |||||
dottedLine.setFirstLineIndent(24); //设置首行缩进 | |||||
dottedLine.setLeading(20f); //行间距 | |||||
dottedLine.setSpacingBefore(dottedLineSpace); //设置段落上空白 | |||||
dottedLine.setSpacingAfter(dottedLineSpace); //设置段落下空白 | |||||
document.add(dottedLine); | |||||
} | |||||
/** | |||||
* 创建直线 | |||||
* | |||||
* @return | |||||
*/ | |||||
public static void createLine(Document document) throws Exception { | |||||
Paragraph line = new Paragraph(); | |||||
line.add(new Chunk(new LineSeparator())); | |||||
document.add(line); | |||||
} | |||||
/** | |||||
* 创建表格肩部:左 中 右 | |||||
* | |||||
* @return | |||||
*/ | |||||
public static void createShoulder(PdfPTable table, ShoulderItem shoulder) { | |||||
table.addCell(createCell(shoulder.getLeftItem(), headfont, Element.ALIGN_LEFT, leftspan, false)); | |||||
table.addCell(createCell(shoulder.getCenterItem(), headfont, Element.ALIGN_CENTER, centerspan, false)); | |||||
table.addCell(createCell(shoulder.getRightItem(), headfont, Element.ALIGN_RIGHT, rightspan, false)); | |||||
} | |||||
/** | |||||
* 创建空白的表格 | |||||
* | |||||
* @return | |||||
*/ | |||||
public static PdfPTable createBlankTable(float height) { | |||||
PdfPTable table = new PdfPTable(1); | |||||
table.getDefaultCell().setBorder(0); | |||||
table.addCell(createCell("", keyfont)); | |||||
table.setSpacingAfter(height); | |||||
table.setSpacingBefore(height); | |||||
return table; | |||||
} | |||||
/** | |||||
* 创建空白的段落 | |||||
* | |||||
* @return | |||||
*/ | |||||
public static void createBlankParagraph(Document document, float height) { | |||||
Paragraph p3 = new Paragraph(); | |||||
p3.setSpacingBefore(height); | |||||
p3.setSpacingAfter(height); | |||||
try { | |||||
document.add(p3); | |||||
} catch (DocumentException e) { | |||||
e.printStackTrace(); | |||||
} | |||||
} | |||||
/* DEMO 方法 */ | |||||
public static void generateDemoPDF(Document document) throws Exception { | |||||
// 创建段落:表名 | |||||
createParagraph(document, "这是DEMO标题"); | |||||
// 超链接 | |||||
Anchor anchor = new Anchor("打开百度"); | |||||
anchor.setReference("www.baidu.com"); | |||||
document.add(anchor); | |||||
// 点线 | |||||
Paragraph p2 = new Paragraph(); | |||||
p2.add(new Chunk(new DottedLineSeparator())); | |||||
document.add(p2); | |||||
// 直线 | |||||
Paragraph p1 = new Paragraph(); | |||||
p1.add(new Chunk(new LineSeparator())); | |||||
document.add(p1); | |||||
// 添加空白行 | |||||
//Paragraph p3 = new Paragraph(); | |||||
//p3.add(new Chunk(newLine())); | |||||
Paragraph p3 = new Paragraph(); | |||||
p3.setSpacingBefore(50f); | |||||
p3.setSpacingAfter(50f); | |||||
document.add(p3); | |||||
// 表格 | |||||
PdfPTable table = createTable(new float[]{40, 120, 120, 120, 80, 80}); | |||||
table.addCell(createCell("姓名:张三", headfont, Element.ALIGN_LEFT, 2, false)); | |||||
table.addCell(createCell("日期:2024-01-01", headfont, Element.ALIGN_CENTER, 2, false)); | |||||
table.addCell(createCell("单位:元", headfont, Element.ALIGN_RIGHT, 2, false)); | |||||
table.addCell(createCell("早上9:00", keyfont, Element.ALIGN_CENTER)); | |||||
table.addCell(createCell("中午11:00", keyfont, Element.ALIGN_CENTER)); | |||||
table.addCell(createCell("中午13:00", keyfont, Element.ALIGN_CENTER)); | |||||
table.addCell(createCell("下午15:00", keyfont, Element.ALIGN_CENTER)); | |||||
table.addCell(createCell("下午17:00", keyfont, Element.ALIGN_CENTER)); | |||||
table.addCell(createCell("晚上19:00", keyfont, Element.ALIGN_CENTER)); | |||||
Integer totalQuantity = 0; | |||||
for (int i = 0; i < 5; i++) { | |||||
table.addCell(createCell("起床", textfont)); | |||||
table.addCell(createCell("吃午饭", textfont)); | |||||
table.addCell(createCell("午休", textfont)); | |||||
table.addCell(createCell("下午茶", textfont)); | |||||
table.addCell(createCell("回家", textfont)); | |||||
table.addCell(createCell("吃晚饭", textfont)); | |||||
totalQuantity++; | |||||
} | |||||
table.addCell(createCell("总计", keyfont)); | |||||
table.addCell(createCell("", textfont)); | |||||
table.addCell(createCell("", textfont)); | |||||
table.addCell(createCell("", textfont)); | |||||
table.addCell(createCell(String.valueOf(totalQuantity) + "件事", textfont)); | |||||
table.addCell(createCell("", textfont)); | |||||
document.add(table); | |||||
// 添加图片 | |||||
Image image = Image.getInstance("https://img-blog.csdn.net/20180801174617455?watermark/2/text/aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl8zNzg0ODcxMA==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70"); | |||||
image.setAlignment(Image.ALIGN_CENTER); | |||||
image.scalePercent(40); //依照比例缩放 | |||||
document.add(image); | |||||
// 定位 | |||||
Anchor gotoP = new Anchor("back top"); | |||||
gotoP.setReference("#top"); | |||||
document.add(gotoP); | |||||
} | |||||
} |
@@ -0,0 +1,44 @@ | |||||
package com.ruoyi.common.utils.pdf; | |||||
import com.itextpdf.text.Document; | |||||
import com.itextpdf.text.Element; | |||||
import com.itextpdf.text.Font; | |||||
import com.itextpdf.text.Phrase; | |||||
import com.itextpdf.text.pdf.ColumnText; | |||||
import com.itextpdf.text.pdf.GrayColor; | |||||
import com.itextpdf.text.pdf.PdfPageEventHelper; | |||||
import com.itextpdf.text.pdf.PdfWriter; | |||||
/** | |||||
* @description: 水印文案 | |||||
* @author: zzl | |||||
* @date: Created in 2024-04-27 9:07 | |||||
* @version: 1.0 | |||||
* @modified By: | |||||
*/ | |||||
public class Watermark extends PdfPageEventHelper { | |||||
Font FONT = new Font(Font.FontFamily.HELVETICA, 30, Font.BOLD, new GrayColor(0.95f)); | |||||
private String waterCont;//水印内容 | |||||
public Watermark() { | |||||
} | |||||
public Watermark(String waterCont) { | |||||
this.waterCont = waterCont; | |||||
} | |||||
@Override | |||||
public void onEndPage(PdfWriter writer, Document document) { | |||||
for (int i = 0; i < 5; i++) { | |||||
for (int j = 0; j < 5; j++) { | |||||
ColumnText.showTextAligned(writer.getDirectContentUnder(), | |||||
Element.ALIGN_CENTER, | |||||
new Phrase(this.waterCont == null ? "HELLO WORLD" : this.waterCont, FONT), | |||||
(50.5f + i * 350), | |||||
(40.0f + j * 150), | |||||
writer.getPageNumber() % 2 == 1 ? 45 : -45); | |||||
} | |||||
} | |||||
} | |||||
} |
@@ -0,0 +1,110 @@ | |||||
package com.ruoyi.common.utils.poi; | |||||
import org.apache.poi.ss.usermodel.*; | |||||
import org.apache.poi.ss.util.CellRangeAddressList; | |||||
import org.apache.poi.xssf.usermodel.XSSFDataValidation; | |||||
// Excel 字典sheet助手 | |||||
public final class ExcelDictSheetHelper | |||||
{ | |||||
private final Workbook workbook; | |||||
private Sheet sheet; | |||||
private int currentColumn; | |||||
public ExcelDictSheetHelper(Workbook workbook) | |||||
{ | |||||
this.workbook = workbook; | |||||
} | |||||
private Sheet Sheet() | |||||
{ | |||||
if(null == sheet) | |||||
{ | |||||
int numberOfSheets = workbook.getNumberOfSheets(); | |||||
sheet = workbook.createSheet("__HIDDEN_DICT__"); | |||||
workbook.setSheetHidden(numberOfSheets, true); | |||||
} | |||||
return sheet; | |||||
} | |||||
// 检查下拉列表是否超过字符限制 | |||||
public static boolean CheckValidationLimit(String[] textlist) | |||||
{ | |||||
if(null == textlist || textlist.length == 0) | |||||
return false; | |||||
String str = String.join(",", textlist); | |||||
return str.length() >= 255; | |||||
} | |||||
public void AddValidation(Sheet sheet, String dictType, String[] textlist, int firstRow, int endRow, int firstCol, int endCol) | |||||
{ | |||||
if(null == textlist || textlist.length == 0) | |||||
return; | |||||
try | |||||
{ | |||||
String name = "__HIDDEN_" + dictType; | |||||
currentColumn++; | |||||
// 创建隐藏sheet, 将数组放在一列 | |||||
Sheet hidden = Sheet(); | |||||
for (int i = 0, length = textlist.length; i < length; i++) | |||||
{ | |||||
Row row = hidden.getRow(i); | |||||
if(null == row) | |||||
row = hidden.createRow(i); | |||||
Cell cell = row.createCell(currentColumn - 1); | |||||
cell.setCellValue(textlist[i]); | |||||
} | |||||
String columnNum = GenerateColumnName(currentColumn); | |||||
Name namedCell = workbook.createName(); | |||||
namedCell.setNameName(name); | |||||
// 设置名称引用的公式 | |||||
//System.err.println(String.format("%s!$%s$1:$%s$%d", hidden.getSheetName(), columnNum, columnNum, textlist.length)); | |||||
namedCell.setRefersToFormula(String.format("%s!$%s$1:$%s$%d", hidden.getSheetName(), columnNum, columnNum, textlist.length)); | |||||
DataValidationHelper helper = sheet.getDataValidationHelper(); | |||||
DataValidationConstraint constraint = helper.createFormulaListConstraint(name); | |||||
// 设置数据有效性加载在哪个单元格上,四个参数分别是:起始行、终止行、起始列、终止列 | |||||
CellRangeAddressList regions = new CellRangeAddressList(firstRow, endRow, firstCol, endCol); | |||||
// 数据有效性对象 | |||||
DataValidation dataValidation = helper.createValidation(constraint, regions); | |||||
// 处理Excel兼容性问题 | |||||
if (dataValidation instanceof XSSFDataValidation) { | |||||
dataValidation.setSuppressDropDownArrow(true); | |||||
dataValidation.setShowErrorBox(true); | |||||
} else { | |||||
dataValidation.setSuppressDropDownArrow(false); | |||||
} | |||||
sheet.addValidationData(dataValidation); | |||||
} | |||||
catch(Exception e) | |||||
{ | |||||
e.printStackTrace(); | |||||
} | |||||
} | |||||
public static String GenerateColumnName(int i) | |||||
{ | |||||
String strResult = ""; | |||||
int intRound = i / 26; | |||||
int intMod = i % 26; | |||||
if (intRound != 0) { | |||||
strResult = String.valueOf(((char) (intRound + 64))); | |||||
} | |||||
strResult += String.valueOf(((char) (intMod + 64))); | |||||
return strResult; | |||||
} | |||||
public static int ParseColumnName(String name) | |||||
{ | |||||
int column = -1; | |||||
for (int i = 0; i < name.length(); ++i) | |||||
{ | |||||
int c = name.charAt(i); | |||||
column = (column + 1) * 26 + c - 'A'; | |||||
} | |||||
return column; | |||||
} | |||||
} |
@@ -0,0 +1,66 @@ | |||||
package com.ruoyi.common.utils.translation; | |||||
import java.lang.annotation.ElementType; | |||||
import java.lang.annotation.Retention; | |||||
import java.lang.annotation.RetentionPolicy; | |||||
import java.lang.annotation.Target; | |||||
/** | |||||
* 额外字典翻译字段注解, 用来代替无法使用Excel注解的情况, 优先级大于Excel注解 | |||||
* 优先级(5种): | |||||
* sql [+ referenceProperty]: 单条SQL语句: 建议加上LIMIT 1, 多条时取第一条, 必须指定占位符?. 例如: @Translate(sql = "SELECT * FROM t_finance_book WHERE id = ? LIMIT 1") | |||||
* table + tableKeyColumn + tableValueColumn [+ referenceProperty]: 拼接为 SELECT `tableValueColumn` FROM `table` WHERE `tableKeyColumn` = ? LIMIT 1. 例如: @Translate(table = "t_finance_book", tableValueColumn = "book_name", tableKeyColumn = "id") | |||||
* <p> | |||||
* dictSql + tableKeyColumn + tableValueColumn: 执行查询SQL后, 取tableKeyColumn(), tableValueColumn()作为字典键值. 例如: @Translate(dictSql = "SELECT * FROM t_finance_book", tableValueColumn = "book_name", tableKeyColumn = "id") | |||||
* readConverterExp | |||||
* dictType | |||||
* <p> | |||||
* 前两种方式使用待翻译字段值直查 | |||||
* 后三种都是加载对应键值字典, 然后用待翻译字段值匹配. 如果都指定了, 会按优先级混合在一起, 优先级高的覆盖优先级低的 | |||||
* <p> | |||||
* 关于referenceProperty | |||||
* 如果带翻译字段为Long的其他表ID, 如: | |||||
* private Long bookId; | |||||
* 如果需要翻译bookId | |||||
* 一种方法是将bookId设为String类型 | |||||
* 还有一种方法是声明String类型的属性辅助翻译bookId, 该新属性不需要原来本身就有bookId的值, 如 | |||||
* | |||||
* @author zhao | |||||
* @Translate(table = "t_finance_book", tableKeyColumn = "id", tableValueColumn = "book_name", referenceProperty = "bookId") // 引用bookId属性的值 | |||||
* // @Translate(sql = "SELECT * FROM t_finance_book WHERE id = ? LIMIT 1", referenceProperty = "bookId") // 也可以写成这样 | |||||
* private String bookName; // bookName的值不需要读取, 只写入 | |||||
* private Long typeId; | |||||
* @Translate(dictType = "dict_xxx_type", referenceProperty = "typeId") // 引用typeId属性的值 | |||||
* private String typeName; // typeName的值不需要读取, 只写入 | |||||
*/ | |||||
@Retention(RetentionPolicy.RUNTIME) | |||||
@Target(ElementType.FIELD) | |||||
public @interface Translate { | |||||
/** | |||||
* 如果是字典类型,请设置字典的type值 (如: sys_user_sex) | |||||
*/ | |||||
public String dictType() default "" ; | |||||
/** | |||||
* 读取内容转表达式 (如: 0=男,1=女,2=未知) | |||||
*/ | |||||
public String readConverterExp() default "" ; | |||||
// 查询数据库字典, 字段必须为String, 不能为Long/Integer等数字型 | |||||
// 方式1: SQL, ?号占位 | |||||
public String sql() default "" ; | |||||
// 方式2: 表名 + 对应列名 + 名称列 | |||||
// 拼接为 SELECT tableValueColumn() FROM table() WHERE tableKeyColumn() = ? LIMIT 1 | |||||
public String table() default "" ; // 表名 | |||||
public String tableKeyColumn() default "id" ; // 键的列名 | |||||
public String tableValueColumn() default "name" ; // 值的列名 | |||||
public String referenceProperty() default "" ; // 引用其他类成员属性 | |||||
// 方式3: SQL + 对应列名 + 名称列: 无占位符, 从数据库加载键值对 | |||||
// 执行查询SQL后, 取tableKeyColumn(), tableValueColumn()作为字典键值 | |||||
public String dictSql() default "" ; | |||||
} |
@@ -0,0 +1,58 @@ | |||||
package com.ruoyi.common.utils.translation; | |||||
import com.ruoyi.common.core.domain.BaseEntity; | |||||
import java.util.List; | |||||
import java.util.Map; | |||||
/** | |||||
* zhao: 字段自动字典翻译 | |||||
* 需要翻译的字段必须使用Translate注解或Excel注解标记 | |||||
* 优先级: | |||||
* 注解: Translate优先级大于Excel. 只会使用Translate或Excel其中的一种, 不会混合 | |||||
* 注解属性: readConverterExp优先级大于dictType. readConverterExp和dictType的键值对最终会混合在一起 | |||||
* 字段类型: | |||||
* 如果是String类型, 必须赋值注解的dictType或readConverterExp | |||||
* 如果是其他复合类型/List, 无需赋值dictType或readConverterExp, 仅标记注解即可, 此时将递归翻译(注意不要循环嵌套对象) | |||||
* <p> | |||||
* 数据库表数据字典: 仅Translate注解支持 | |||||
* 字段必须为String类型 | |||||
*/ | |||||
public final class TranslateUtils { | |||||
private TranslateUtils() { | |||||
} | |||||
public static void translateList(List<?> list, Object... args) { | |||||
new Translator().translateList(list, args); | |||||
} | |||||
public static void translate(Object obj, Object... args) { | |||||
new Translator().translate(obj, args); | |||||
} | |||||
public static void translateMapList(List<Map<String, Object>> list, Map<String, String> dictMap) { | |||||
new Translator().translateMapList(list, dictMap); | |||||
} | |||||
public static void translateMap(Map<String, Object> map, Map<String, String> dictMap) { | |||||
new Translator().translateMap(map, dictMap); | |||||
} | |||||
public static <T> void translateObjectList(List<T> list) { | |||||
new Translator().translateObjectList(list); | |||||
} | |||||
public static <T> void translateObject(T object) { | |||||
new Translator().translateObject(object); | |||||
} | |||||
public static <T extends BaseEntity> void translateEntityList(List<T> list, boolean... keepRawField) { | |||||
boolean b = null != keepRawField && keepRawField.length > 0 ? keepRawField[0] : false; | |||||
new Translator().translateEntityList(list, b); | |||||
} | |||||
public static <T extends BaseEntity> void translateEntity(T object, boolean... keepRawField) { | |||||
boolean b = null != keepRawField && keepRawField.length > 0 ? keepRawField[0] : false; | |||||
new Translator().translateEntity(object, b); | |||||
} | |||||
} |
@@ -0,0 +1,465 @@ | |||||
package com.ruoyi.common.utils.translation; | |||||
import cn.hutool.core.collection.CollectionUtil; | |||||
import cn.hutool.core.util.StrUtil; | |||||
import com.ruoyi.common.annotation.Excel; | |||||
import com.ruoyi.common.core.domain.BaseEntity; | |||||
import com.ruoyi.common.utils.DictUtils; | |||||
import com.ruoyi.common.utils.StringUtils; | |||||
import com.ruoyi.common.utils.reflect.ReflectUtils; | |||||
import com.ruoyi.common.utils.spring.SpringUtils; | |||||
import org.springframework.jdbc.core.JdbcTemplate; | |||||
import java.lang.reflect.Field; | |||||
import java.lang.reflect.Modifier; | |||||
import java.util.*; | |||||
public final class Translator { | |||||
private static final String KEY_SQL_KEY = "$__SQL__" ; | |||||
private final List<Object> handledObjects = new ArrayList<>(); | |||||
public Translator() { | |||||
} | |||||
public void translateList(List<?> list, Object... args) { | |||||
if (CollectionUtil.isEmpty(list)) | |||||
return; | |||||
if (startTranslate(list)) | |||||
list.forEach((x) -> translate(x, args)); | |||||
} | |||||
@SuppressWarnings("unchecked") | |||||
public void translate(Object obj, Object... args) { | |||||
if (null == obj) | |||||
return; | |||||
if (obj instanceof BaseEntity) { | |||||
Object o = DEF_PARM(args); | |||||
boolean b = o instanceof Boolean ? (Boolean) o : false; | |||||
translateEntity((BaseEntity) obj, b); | |||||
} else if (obj instanceof Map) { | |||||
Object o = DEF_PARM(args); | |||||
Map<String, String> dictMap = o instanceof Map ? (Map<String, String>) args[0] : null; | |||||
translateMap((Map<String, Object>) obj, dictMap); | |||||
} else if (obj instanceof List) { | |||||
translateList((List<?>) obj, args); | |||||
} else { | |||||
translateObject(obj); | |||||
} | |||||
} | |||||
public <T extends BaseEntity> void translateEntityList(List<T> list, boolean keepRawField) { | |||||
if (CollectionUtil.isEmpty(list)) | |||||
return; | |||||
list.forEach((x) -> translateEntity(x, keepRawField)); | |||||
} | |||||
public <T extends BaseEntity> void translateEntity(T object, boolean keepRawField) { | |||||
if (null == object) | |||||
return; | |||||
translateEntity_r(object, object.getClass(), keepRawField); | |||||
} | |||||
public void translateMapList(List<Map<String, Object>> list, Map<String, String> dictMap) { | |||||
if (CollectionUtil.isEmpty(list)) | |||||
return; | |||||
list.forEach((x) -> translateMap(x, dictMap)); | |||||
} | |||||
public void translateMap(Map<String, Object> map, Map<String, String> dictMap) { | |||||
if (CollectionUtil.isEmpty(map) || CollectionUtil.isEmpty(dictMap)) | |||||
return; | |||||
if (!startTranslate(map)) | |||||
return; | |||||
dictMap.forEach((k, v) -> { | |||||
if (!map.containsKey(k)) | |||||
return; | |||||
Object o = map.get(k); | |||||
if (null == o) | |||||
return; | |||||
Class<?> clazz = o.getClass(); | |||||
if (clazz.equals(String.class)) { | |||||
String str = (String) o; | |||||
if (StringUtils.isEmpty(str)) | |||||
return; | |||||
map.put(k, DictUtils.getDictLabelElseOriginValue(v, str)); | |||||
} else if (canRecursionClassObjectField(clazz)) | |||||
translate(o, dictMap); | |||||
}); | |||||
} | |||||
// 判断是否翻译对象属性 | |||||
private boolean canRecursionClassObjectField(Class<?> clazz) { | |||||
/* if(Object.class.equals(clazz)) // is Object class | |||||
return false; | |||||
if(!Object.class.isAssignableFrom(clazz)) // is internal class, e.g. int long boolean | |||||
return false; | |||||
if(clazz.getPackage().getName().startsWith("java.lang")) // class in java.lang.**, e.g. Long Integer | |||||
return false; | |||||
return true;*/ | |||||
return BaseEntity.class.isAssignableFrom(clazz) // BaseEntity | |||||
|| List.class.isAssignableFrom(clazz) // List | |||||
|| Map.class.isAssignableFrom(clazz) // Map | |||||
; | |||||
} | |||||
public <T> void translateObjectList(List<T> list) { | |||||
if (CollectionUtil.isEmpty(list)) | |||||
return; | |||||
list.forEach(this::translateObject); | |||||
} | |||||
public <T> void translateObject(T object) { | |||||
if (null == object) | |||||
return; | |||||
translateObject_r(object, object.getClass()); | |||||
} | |||||
private <T> void translateObject_r(T object, Class<?> clazz) { | |||||
if (!startTranslate(object)) | |||||
return; | |||||
Field[] declaredFields = clazz.getDeclaredFields(); | |||||
for (Field field : declaredFields) { | |||||
boolean trans = hasTranslateFlag(field); // check translate flag | |||||
if (!trans) | |||||
continue; | |||||
translateField(field, object); | |||||
} | |||||
Class<?> superclass = getSuperClass(clazz); | |||||
if (null != superclass) | |||||
translateObject_r(object, superclass); | |||||
} | |||||
private <T extends BaseEntity> void translateEntity_r(T object, Class<?> clazz, boolean keepRawField) { | |||||
if (!startTranslate(object)) | |||||
return; | |||||
Field[] declaredFields = clazz.getDeclaredFields(); | |||||
for (Field field : declaredFields) { | |||||
boolean trans = hasTranslateFlag(field); // check translate flag | |||||
if (!trans) | |||||
continue; | |||||
translateField(field, object, keepRawField); | |||||
} | |||||
Class<?> superclass = getSuperClass(clazz); | |||||
if (null != superclass) | |||||
translateEntity_r(object, superclass, keepRawField); | |||||
} | |||||
// 解析readConverterExp | |||||
private Map<String, String> parseReadConverterExp(String str) { | |||||
Map<String, String> dict = new LinkedHashMap<>(); | |||||
if (StringUtils.isNotEmpty(str)) { | |||||
List<String> split = StrUtil.split(str, ',', true, true); | |||||
split.forEach((x) -> { | |||||
List<String> arr = StrUtil.split(x, '=', 2, true, true); | |||||
if (CollectionUtil.isEmpty(arr)) | |||||
return; | |||||
dict.put(arr.get(0), arr.size() > 1 ? arr.get(1) : null); | |||||
}); | |||||
} | |||||
return dict; | |||||
} | |||||
// 读取数据库数据作为字典 | |||||
private Map<String, String> loadDBDict(String sql, String keyColumn, String nameColumn) { | |||||
Map<String, String> dict = new LinkedHashMap<>(); | |||||
if (StringUtils.isNotEmpty(sql) && StringUtils.isNotEmpty(keyColumn) && StringUtils.isNotEmpty(nameColumn)) { | |||||
JdbcTemplate jdbcTemplate = SpringUtils.getBean(JdbcTemplate.class); | |||||
try { | |||||
List<Map<String, Object>> list = jdbcTemplate.queryForList(sql); | |||||
if (CollectionUtil.isNotEmpty(list)) { | |||||
for (Map<String, Object> map : list) { | |||||
String key = toString_s(map.get(keyColumn)); | |||||
if (StringUtils.isEmpty(key)) | |||||
continue; | |||||
dict.put(key, toString_s(map.get(nameColumn))); | |||||
} | |||||
} | |||||
} catch (Exception e) { | |||||
e.printStackTrace(); | |||||
} | |||||
} | |||||
return dict; | |||||
} | |||||
// 生成查询SQL | |||||
private String genRelationSQL(String table, String keyColumn, String nameColumn) { | |||||
if (StringUtils.isNotEmpty(table) && StringUtils.isNotEmpty(keyColumn) && StringUtils.isNotEmpty(nameColumn)) { | |||||
return String.format("SELECT `%s` FROM `%s` WHERE `%s` = ? LIMIT 1", nameColumn, table, keyColumn); | |||||
} | |||||
return null; | |||||
} | |||||
// 直接取SQL值 | |||||
private String readDBValue(String sql, String id) { | |||||
if (StringUtils.isNotEmpty(sql) && StringUtils.isNotEmpty(id)) { | |||||
JdbcTemplate jdbcTemplate = SpringUtils.getBean(JdbcTemplate.class); | |||||
try { | |||||
List<Map<String, Object>> list = jdbcTemplate.queryForList(sql, id); | |||||
if (CollectionUtil.isNotEmpty(list)) { | |||||
Map<String, Object> map = list.get(0); | |||||
return toString_s(map.get(map.keySet().iterator().next())); | |||||
} | |||||
} catch (Exception e) { | |||||
e.printStackTrace(); | |||||
} | |||||
} | |||||
return null; | |||||
} | |||||
// 检查是否需要翻译 | |||||
private boolean hasTranslateFlag(Field field) { | |||||
// 静态/不可重赋值 不翻译 | |||||
int modifiers = field.getModifiers(); | |||||
if (Modifier.isStatic(modifiers) || Modifier.isFinal(modifiers)) | |||||
return false; | |||||
return null != field.getAnnotation(Translate.class) || null != field.getAnnotation(Excel.class); | |||||
} | |||||
// 获取翻译来源 | |||||
// 返回: dictType对应的字典键值对和readConverterExp解析后的键值对的组合 | |||||
// 优先级: Translate > Excel | readConverterExp > dictType | |||||
private Map<String, String> getTranslateDict(Field field) { | |||||
Map<String, String> dict = new LinkedHashMap<>(); | |||||
String str; | |||||
Translate translate = field.getAnnotation(Translate.class); // First check Translate annotation | |||||
if (null != translate) { | |||||
// 1. SQL 直查 | |||||
str = translate.sql(); | |||||
if (StringUtils.isNotEmpty(str)) { | |||||
dict.put(KEY_SQL_KEY, str); | |||||
} | |||||
// 2. table + tableKeyColumn + tableValueColumn 直查 | |||||
str = translate.table(); | |||||
if (StringUtils.isNotEmpty(str)) { | |||||
str = genRelationSQL(str, translate.tableKeyColumn(), translate.tableValueColumn()); | |||||
dict.put(KEY_SQL_KEY, str); | |||||
} | |||||
// 3. dict缓存 | |||||
str = translate.dictType(); | |||||
if (StringUtils.isNotEmpty(str)) { | |||||
dict.putAll(DictUtils.dictCacheValueLabelMap(str)); | |||||
} | |||||
// 4. readConverterExp配置 | |||||
str = translate.readConverterExp(); | |||||
if (StringUtils.isNotEmpty(str)) { | |||||
dict.putAll(parseReadConverterExp(str)); | |||||
} | |||||
// 5. 数据库任意表数据 | |||||
str = translate.dictSql(); | |||||
if (StringUtils.isNotEmpty(str)) { | |||||
dict.putAll(loadDBDict(str, translate.tableKeyColumn(), translate.tableValueColumn())); | |||||
} | |||||
} | |||||
if (StringUtils.isNotEmpty(dict)) | |||||
return dict; | |||||
Excel excel = field.getAnnotation(Excel.class); // And then check Excel annotation | |||||
if (null != excel) { | |||||
str = excel.dictType(); | |||||
if (StringUtils.isNotEmpty(str)) { | |||||
dict.putAll(DictUtils.dictCacheValueLabelMap(str)); | |||||
} | |||||
str = excel.readConverterExp(); | |||||
if (StringUtils.isNotEmpty(str)) { | |||||
dict.putAll(parseReadConverterExp(str)); | |||||
} | |||||
} | |||||
return dict; | |||||
} | |||||
private boolean translateField(Field field, Object object) { | |||||
if (field.getType().equals(String.class)) | |||||
return translateField_String(field, object); | |||||
else | |||||
return translateField_Object(field, object); | |||||
} | |||||
private boolean translateField_Object(Field field, Object object) { | |||||
if (field.getType().equals(String.class)) | |||||
return false; | |||||
if (!canRecursionClassObjectField(field.getType())) | |||||
return false; | |||||
Object val = null; | |||||
if (!field.isAccessible()) | |||||
field.setAccessible(true); | |||||
try { | |||||
val = field.get(object); | |||||
} catch (IllegalAccessException e) { | |||||
e.printStackTrace(); | |||||
} | |||||
if (null != val) { | |||||
translate(val); | |||||
return true; | |||||
} | |||||
return false; | |||||
} | |||||
private boolean translateField_String(Field field, Object object) { | |||||
boolean trans = false; | |||||
if (!field.getType().equals(String.class)) | |||||
return false; | |||||
Map<String, String> dict = getTranslateDict(field); | |||||
if (CollectionUtil.isEmpty(dict)) | |||||
return false; | |||||
if (!field.isAccessible()) | |||||
field.setAccessible(true); | |||||
try { | |||||
Object val = getField(object, field); | |||||
if (null != val) { | |||||
String str = (String) val; | |||||
if (StringUtils.isNotEmpty(str)) { | |||||
if (dict.containsKey(KEY_SQL_KEY)) { | |||||
String dbVal = readDBValue(dict.get(KEY_SQL_KEY), str); | |||||
if (StringUtils.isNotEmpty(dbVal)) { | |||||
field.set(object, dbVal); | |||||
trans = true; | |||||
} | |||||
} | |||||
if (!trans && dict.containsKey(str)) { | |||||
field.set(object, dict.get(str)); | |||||
trans = true; | |||||
} | |||||
} | |||||
} | |||||
} catch (IllegalAccessException e) { | |||||
e.printStackTrace(); | |||||
return false; | |||||
} | |||||
return trans; | |||||
} | |||||
private <T extends BaseEntity> boolean translateField(Field field, T entity, boolean keepRawField) { | |||||
if (field.getType().equals(String.class)) | |||||
return translateField_String(field, entity, keepRawField); | |||||
else | |||||
return translateField_Object(field, entity, keepRawField); | |||||
} | |||||
private <T extends BaseEntity> boolean translateField_Object(Field field, T entity, boolean keepRawField) { | |||||
if (field.getType().equals(String.class)) | |||||
return false; | |||||
if (!canRecursionClassObjectField(field.getType())) | |||||
return false; | |||||
Object val = null; | |||||
try { | |||||
val = getField(entity, field); | |||||
} catch (IllegalAccessException e) { | |||||
e.printStackTrace(); | |||||
} | |||||
if (null != val) { | |||||
translate(val, keepRawField); | |||||
return true; | |||||
} | |||||
return false; | |||||
} | |||||
private <T extends BaseEntity> boolean translateField_String(Field field, T entity, boolean keepRawField) { | |||||
boolean trans = false; | |||||
if (!field.getType().equals(String.class)) | |||||
return false; | |||||
Map<String, String> dict = getTranslateDict(field); | |||||
if (CollectionUtil.isEmpty(dict)) | |||||
return false; | |||||
try { | |||||
Object val = getField(entity, field); | |||||
if (keepRawField) | |||||
entity.getParams().put(field.getName(), val); // backup raw value to params | |||||
if (null != val) { | |||||
String str = (String) val; | |||||
if (StringUtils.isNotEmpty(str)) { | |||||
if (dict.containsKey(KEY_SQL_KEY)) { | |||||
String dbVal = readDBValue(dict.get(KEY_SQL_KEY), str); | |||||
if (StringUtils.isNotEmpty(dbVal)) { | |||||
field.set(entity, dbVal); | |||||
trans = true; | |||||
} | |||||
} | |||||
if (!trans && dict.containsKey(str)) { | |||||
field.set(entity, dict.get(str)); | |||||
trans = true; | |||||
} | |||||
} | |||||
} | |||||
} catch (IllegalAccessException e) { | |||||
e.printStackTrace(); | |||||
return false; | |||||
} | |||||
return trans; | |||||
} | |||||
private Object getField(Object obj, Field field) throws IllegalAccessException { | |||||
if (!field.isAccessible()) | |||||
field.setAccessible(true); | |||||
Translate annotation = field.getAnnotation(Translate.class); | |||||
if (null != annotation) { | |||||
String refProp = annotation.referenceProperty(); | |||||
if (StringUtils.isNotEmpty(refProp)) { | |||||
Field refField = ReflectUtils.getAccessibleField(obj, refProp); | |||||
if (null != refField) | |||||
return toString_s(refField.get(obj)); // 转换为String | |||||
} | |||||
} | |||||
return field.get(obj); | |||||
} | |||||
private Class<?> getSuperClass(Class<?> clazz) { | |||||
if (null == clazz) | |||||
return null; | |||||
Class<?> superclass = clazz.getSuperclass(); // translate parent class | |||||
if (null != superclass && !superclass.equals(Object.class)) // check is top or is Object | |||||
return superclass; | |||||
return null; | |||||
} | |||||
// 允许翻译则返回true | |||||
private boolean startTranslate(Object o) { | |||||
if (null == o) | |||||
return false; | |||||
if (o instanceof String) // String类型总是重新翻译 | |||||
return true; | |||||
if (contains_ptr(handledObjects, o)) // 其他类型防止循环递归 | |||||
{ | |||||
return false; | |||||
} | |||||
handledObjects.add(o); | |||||
return true; | |||||
} | |||||
public void Reset() { | |||||
handledObjects.clear(); | |||||
} | |||||
public static <T> boolean contains_ptr(Collection<T> list, T target) { | |||||
if (CollectionUtil.isEmpty(list)) | |||||
return false; | |||||
return list.stream().anyMatch((x) -> x == target); | |||||
} | |||||
public static String toString_s(Object obj) { | |||||
if (null == obj) | |||||
return "" ; | |||||
if (obj instanceof String) | |||||
return (String) obj; | |||||
else | |||||
return obj.toString(); | |||||
} | |||||
public static <T> T DEF_PARM(T... args) { | |||||
return null != args && args.length > 0 ? args[0] : null; | |||||
} | |||||
} |
@@ -73,6 +73,7 @@ | |||||
<orderEntry type="library" name="Maven: org.springframework.security:spring-security-core:5.7.12" level="project" /> | <orderEntry type="library" name="Maven: org.springframework.security:spring-security-core:5.7.12" level="project" /> | ||||
<orderEntry type="library" name="Maven: org.springframework.security:spring-security-crypto:5.7.12" level="project" /> | <orderEntry type="library" name="Maven: org.springframework.security:spring-security-crypto:5.7.12" level="project" /> | ||||
<orderEntry type="library" name="Maven: org.springframework.security:spring-security-web:5.7.12" level="project" /> | <orderEntry type="library" name="Maven: org.springframework.security:spring-security-web:5.7.12" level="project" /> | ||||
<orderEntry type="library" name="Maven: net.coobird:thumbnailator:0.4.8" level="project" /> | |||||
<orderEntry type="library" name="Maven: com.github.pagehelper:pagehelper-spring-boot-starter:1.4.7" level="project" /> | <orderEntry type="library" name="Maven: com.github.pagehelper:pagehelper-spring-boot-starter:1.4.7" level="project" /> | ||||
<orderEntry type="library" name="Maven: org.mybatis.spring.boot:mybatis-spring-boot-starter:2.3.1" level="project" /> | <orderEntry type="library" name="Maven: org.mybatis.spring.boot:mybatis-spring-boot-starter:2.3.1" level="project" /> | ||||
<orderEntry type="library" name="Maven: org.springframework.boot:spring-boot-starter-jdbc:2.5.15" level="project" /> | <orderEntry type="library" name="Maven: org.springframework.boot:spring-boot-starter-jdbc:2.5.15" level="project" /> | ||||
@@ -89,6 +90,7 @@ | |||||
<orderEntry type="library" name="Maven: jakarta.validation:jakarta.validation-api:2.0.2" level="project" /> | <orderEntry type="library" name="Maven: jakarta.validation:jakarta.validation-api:2.0.2" level="project" /> | ||||
<orderEntry type="library" name="Maven: org.jboss.logging:jboss-logging:3.4.3.Final" level="project" /> | <orderEntry type="library" name="Maven: org.jboss.logging:jboss-logging:3.4.3.Final" level="project" /> | ||||
<orderEntry type="library" name="Maven: com.fasterxml:classmate:1.5.1" level="project" /> | <orderEntry type="library" name="Maven: com.fasterxml:classmate:1.5.1" level="project" /> | ||||
<orderEntry type="library" name="Maven: org.projectlombok:lombok:1.18.26" level="project" /> | |||||
<orderEntry type="library" name="Maven: org.apache.commons:commons-lang3:3.12.0" level="project" /> | <orderEntry type="library" name="Maven: org.apache.commons:commons-lang3:3.12.0" level="project" /> | ||||
<orderEntry type="library" name="Maven: com.alibaba.fastjson2:fastjson2:2.0.57" level="project" /> | <orderEntry type="library" name="Maven: com.alibaba.fastjson2:fastjson2:2.0.57" level="project" /> | ||||
<orderEntry type="library" name="Maven: commons-io:commons-io:2.19.0" level="project" /> | <orderEntry type="library" name="Maven: commons-io:commons-io:2.19.0" level="project" /> | ||||
@@ -103,6 +105,7 @@ | |||||
<orderEntry type="library" name="Maven: org.apache.commons:commons-compress:1.19" level="project" /> | <orderEntry type="library" name="Maven: org.apache.commons:commons-compress:1.19" level="project" /> | ||||
<orderEntry type="library" name="Maven: com.github.virtuald:curvesapi:1.06" level="project" /> | <orderEntry type="library" name="Maven: com.github.virtuald:curvesapi:1.06" level="project" /> | ||||
<orderEntry type="library" name="Maven: io.jsonwebtoken:jjwt:0.9.1" level="project" /> | <orderEntry type="library" name="Maven: io.jsonwebtoken:jjwt:0.9.1" level="project" /> | ||||
<orderEntry type="library" name="Maven: javax.servlet:javax.servlet-api:4.0.1" level="project" /> | |||||
<orderEntry type="library" name="Maven: javax.xml.bind:jaxb-api:2.3.1" level="project" /> | <orderEntry type="library" name="Maven: javax.xml.bind:jaxb-api:2.3.1" level="project" /> | ||||
<orderEntry type="library" name="Maven: javax.activation:javax.activation-api:1.2.0" level="project" /> | <orderEntry type="library" name="Maven: javax.activation:javax.activation-api:1.2.0" level="project" /> | ||||
<orderEntry type="library" name="Maven: org.springframework.boot:spring-boot-starter-data-redis:2.5.15" level="project" /> | <orderEntry type="library" name="Maven: org.springframework.boot:spring-boot-starter-data-redis:2.5.15" level="project" /> | ||||
@@ -123,6 +126,8 @@ | |||||
<orderEntry type="library" name="Maven: org.reactivestreams:reactive-streams:1.0.4" level="project" /> | <orderEntry type="library" name="Maven: org.reactivestreams:reactive-streams:1.0.4" level="project" /> | ||||
<orderEntry type="library" name="Maven: org.apache.commons:commons-pool2:2.9.0" level="project" /> | <orderEntry type="library" name="Maven: org.apache.commons:commons-pool2:2.9.0" level="project" /> | ||||
<orderEntry type="library" name="Maven: eu.bitwalker:UserAgentUtils:1.21" level="project" /> | <orderEntry type="library" name="Maven: eu.bitwalker:UserAgentUtils:1.21" level="project" /> | ||||
<orderEntry type="library" name="Maven: javax.servlet:javax.servlet-api:4.0.1" level="project" /> | |||||
<orderEntry type="library" name="Maven: com.itextpdf:itextpdf:5.5.13.2" level="project" /> | |||||
<orderEntry type="library" name="Maven: com.itextpdf:itext-asian:5.2.0" level="project" /> | |||||
<orderEntry type="library" name="Maven: cn.hutool:hutool-all:5.5.4" level="project" /> | |||||
</component> | </component> | ||||
</module> | </module> |
@@ -40,6 +40,7 @@ | |||||
<orderEntry type="library" name="Maven: org.springframework.security:spring-security-core:5.7.12" level="project" /> | <orderEntry type="library" name="Maven: org.springframework.security:spring-security-core:5.7.12" level="project" /> | ||||
<orderEntry type="library" name="Maven: org.springframework.security:spring-security-crypto:5.7.12" level="project" /> | <orderEntry type="library" name="Maven: org.springframework.security:spring-security-crypto:5.7.12" level="project" /> | ||||
<orderEntry type="library" name="Maven: org.springframework.security:spring-security-web:5.7.12" level="project" /> | <orderEntry type="library" name="Maven: org.springframework.security:spring-security-web:5.7.12" level="project" /> | ||||
<orderEntry type="library" name="Maven: net.coobird:thumbnailator:0.4.8" level="project" /> | |||||
<orderEntry type="library" name="Maven: com.github.pagehelper:pagehelper-spring-boot-starter:1.4.7" level="project" /> | <orderEntry type="library" name="Maven: com.github.pagehelper:pagehelper-spring-boot-starter:1.4.7" level="project" /> | ||||
<orderEntry type="library" name="Maven: org.mybatis.spring.boot:mybatis-spring-boot-starter:2.3.1" level="project" /> | <orderEntry type="library" name="Maven: org.mybatis.spring.boot:mybatis-spring-boot-starter:2.3.1" level="project" /> | ||||
<orderEntry type="library" name="Maven: org.springframework.boot:spring-boot-starter-jdbc:2.5.15" level="project" /> | <orderEntry type="library" name="Maven: org.springframework.boot:spring-boot-starter-jdbc:2.5.15" level="project" /> | ||||
@@ -57,6 +58,7 @@ | |||||
<orderEntry type="library" name="Maven: jakarta.validation:jakarta.validation-api:2.0.2" level="project" /> | <orderEntry type="library" name="Maven: jakarta.validation:jakarta.validation-api:2.0.2" level="project" /> | ||||
<orderEntry type="library" name="Maven: org.jboss.logging:jboss-logging:3.4.3.Final" level="project" /> | <orderEntry type="library" name="Maven: org.jboss.logging:jboss-logging:3.4.3.Final" level="project" /> | ||||
<orderEntry type="library" name="Maven: com.fasterxml:classmate:1.5.1" level="project" /> | <orderEntry type="library" name="Maven: com.fasterxml:classmate:1.5.1" level="project" /> | ||||
<orderEntry type="library" name="Maven: org.projectlombok:lombok:1.18.26" level="project" /> | |||||
<orderEntry type="library" name="Maven: com.fasterxml.jackson.core:jackson-databind:2.12.7.1" level="project" /> | <orderEntry type="library" name="Maven: com.fasterxml.jackson.core:jackson-databind:2.12.7.1" level="project" /> | ||||
<orderEntry type="library" name="Maven: com.fasterxml.jackson.core:jackson-annotations:2.12.7" level="project" /> | <orderEntry type="library" name="Maven: com.fasterxml.jackson.core:jackson-annotations:2.12.7" level="project" /> | ||||
<orderEntry type="library" name="Maven: com.fasterxml.jackson.core:jackson-core:2.12.7" level="project" /> | <orderEntry type="library" name="Maven: com.fasterxml.jackson.core:jackson-core:2.12.7" level="project" /> | ||||
@@ -74,6 +76,7 @@ | |||||
<orderEntry type="library" name="Maven: com.github.virtuald:curvesapi:1.06" level="project" /> | <orderEntry type="library" name="Maven: com.github.virtuald:curvesapi:1.06" level="project" /> | ||||
<orderEntry type="library" name="Maven: org.yaml:snakeyaml:1.28" level="project" /> | <orderEntry type="library" name="Maven: org.yaml:snakeyaml:1.28" level="project" /> | ||||
<orderEntry type="library" name="Maven: io.jsonwebtoken:jjwt:0.9.1" level="project" /> | <orderEntry type="library" name="Maven: io.jsonwebtoken:jjwt:0.9.1" level="project" /> | ||||
<orderEntry type="library" name="Maven: javax.servlet:javax.servlet-api:4.0.1" level="project" /> | |||||
<orderEntry type="library" name="Maven: javax.xml.bind:jaxb-api:2.3.1" level="project" /> | <orderEntry type="library" name="Maven: javax.xml.bind:jaxb-api:2.3.1" level="project" /> | ||||
<orderEntry type="library" name="Maven: javax.activation:javax.activation-api:1.2.0" level="project" /> | <orderEntry type="library" name="Maven: javax.activation:javax.activation-api:1.2.0" level="project" /> | ||||
<orderEntry type="library" name="Maven: org.springframework.boot:spring-boot-starter-data-redis:2.5.15" level="project" /> | <orderEntry type="library" name="Maven: org.springframework.boot:spring-boot-starter-data-redis:2.5.15" level="project" /> | ||||
@@ -94,7 +97,9 @@ | |||||
<orderEntry type="library" name="Maven: org.reactivestreams:reactive-streams:1.0.4" level="project" /> | <orderEntry type="library" name="Maven: org.reactivestreams:reactive-streams:1.0.4" level="project" /> | ||||
<orderEntry type="library" name="Maven: org.apache.commons:commons-pool2:2.9.0" level="project" /> | <orderEntry type="library" name="Maven: org.apache.commons:commons-pool2:2.9.0" level="project" /> | ||||
<orderEntry type="library" name="Maven: eu.bitwalker:UserAgentUtils:1.21" level="project" /> | <orderEntry type="library" name="Maven: eu.bitwalker:UserAgentUtils:1.21" level="project" /> | ||||
<orderEntry type="library" name="Maven: javax.servlet:javax.servlet-api:4.0.1" level="project" /> | |||||
<orderEntry type="library" name="Maven: com.itextpdf:itextpdf:5.5.13.2" level="project" /> | |||||
<orderEntry type="library" name="Maven: com.itextpdf:itext-asian:5.2.0" level="project" /> | |||||
<orderEntry type="library" name="Maven: cn.hutool:hutool-all:5.5.4" level="project" /> | |||||
<orderEntry type="library" name="Maven: com.alibaba:druid-spring-boot-starter:1.2.23" level="project" /> | <orderEntry type="library" name="Maven: com.alibaba:druid-spring-boot-starter:1.2.23" level="project" /> | ||||
<orderEntry type="library" name="Maven: com.alibaba:druid:1.2.23" level="project" /> | <orderEntry type="library" name="Maven: com.alibaba:druid:1.2.23" level="project" /> | ||||
<orderEntry type="library" name="Maven: org.springframework.boot:spring-boot-autoconfigure:2.5.15" level="project" /> | <orderEntry type="library" name="Maven: org.springframework.boot:spring-boot-autoconfigure:2.5.15" level="project" /> | ||||
@@ -74,25 +74,22 @@ public class ${ClassName}Controller extends BaseController | |||||
/** | /** | ||||
* ${functionName}导入模板 | * ${functionName}导入模板 | ||||
*/ | */ | ||||
@RequiresPermissions("${permissionPrefix}:view") | |||||
@GetMapping("/importTemplate") | |||||
@ResponseBody | |||||
public AjaxResult importTemplate() { | |||||
@PostMapping("/importTemplate") | |||||
public void importTemplate(HttpServletResponse response) { | |||||
ExcelUtil<${ClassName}> util = new ExcelUtil<${ClassName}>(${ClassName}.class); | ExcelUtil<${ClassName}> util = new ExcelUtil<${ClassName}>(${ClassName}.class); | ||||
return util.importTemplateExcel("${functionName}数据"); | |||||
util.importTemplateExcel(response, "${functionName}数据"); | |||||
} | } | ||||
/** | /** | ||||
* ${functionName}导入 | * ${functionName}导入 | ||||
*/ | */ | ||||
@Log(title = "${functionName}", businessType = BusinessType.IMPORT) | @Log(title = "${functionName}", businessType = BusinessType.IMPORT) | ||||
@RequiresPermissions("${permissionPrefix}:import") | |||||
@PreAuthorize("@ss.hasPermi('${permissionPrefix}:import')") | |||||
@PostMapping("/importData") | @PostMapping("/importData") | ||||
@ResponseBody | |||||
public AjaxResult importData(MultipartFile file, boolean updateSupport) throws Exception { | public AjaxResult importData(MultipartFile file, boolean updateSupport) throws Exception { | ||||
ExcelUtil<${ClassName}> util = new ExcelUtil<${ClassName}>(${ClassName}.class); | ExcelUtil<${ClassName}> util = new ExcelUtil<${ClassName}>(${ClassName}.class); | ||||
List<${ClassName}> list = util.importExcel(file.getInputStream(), 0); | List<${ClassName}> list = util.importExcel(file.getInputStream(), 0); | ||||
String message = ${className}Service.import${ClassName}(list, updateSupport, getSysUser()); | |||||
String message = ${className}Service.import${ClassName}(list, updateSupport, getUsername()); | |||||
return AjaxResult.success(message); | return AjaxResult.success(message); | ||||
} | } | ||||
@@ -142,11 +139,11 @@ public class ${ClassName}Controller extends BaseController | |||||
/** | /** | ||||
* 打印${functionName} | * 打印${functionName} | ||||
*/ | */ | ||||
@RequiresPermissions("${permissionPrefix}:print") | |||||
@PreAuthorize("@ss.hasPermi('${permissionPrefix}:print')") | |||||
@Log(title = "${functionName}", businessType = BusinessType.PRINT) | @Log(title = "${functionName}", businessType = BusinessType.PRINT) | ||||
@GetMapping("/print") | @GetMapping("/print") | ||||
public void printPdf(${ClassName} ${className}, HttpServletResponse response) throws Exception{ | public void printPdf(${ClassName} ${className}, HttpServletResponse response) throws Exception{ | ||||
${className}.setBookId(getSysUser().getLoginBookid()); | |||||
List<${ClassName}> list = ${className}Service.select${ClassName}List(${className}); | List<${ClassName}> list = ${className}Service.select${ClassName}List(${className}); | ||||
TranslateUtils.translateList(list, false); | TranslateUtils.translateList(list, false); | ||||
@@ -171,12 +168,12 @@ public class ${ClassName}Controller extends BaseController | |||||
List<String[]> contentList = Lists.newArrayList(); | List<String[]> contentList = Lists.newArrayList(); | ||||
list.forEach(a ->{ | list.forEach(a ->{ | ||||
String[] str = new String[6]; | String[] str = new String[6]; | ||||
str[0] = a.getBookName(); | |||||
str[1] = a.getOrgCodeCertNum(); | |||||
str[2] = a.getDeptName(); | |||||
str[3] = a.getAccountant(); | |||||
str[4] = a.getAccountantPhone(); | |||||
str[5] = a.getCurrentDay(); | |||||
str[0] = ""; | |||||
str[1] = ""; | |||||
str[2] = ""; | |||||
str[3] = ""; | |||||
str[4] = ""; | |||||
str[5] = ""; | |||||
contentList.add(str); | contentList.add(str); | ||||
}); | }); | ||||
pdf.setContentList(contentList); | pdf.setContentList(contentList); | ||||
@@ -32,10 +32,10 @@ public interface I${ClassName}Service | |||||
* | * | ||||
* @param list ${functionName}数据列表 | * @param list ${functionName}数据列表 | ||||
* @param isUpdateSupport 是否更新支持,如果已存在,则进行更新数据 | * @param isUpdateSupport 是否更新支持,如果已存在,则进行更新数据 | ||||
* @param user 操作用户 | |||||
* @param userName 操作用户 | |||||
* @return 结果 | * @return 结果 | ||||
*/ | */ | ||||
public String import${ClassName}(List<${ClassName}> list, Boolean isUpdateSupport, SysUser user); | |||||
public String import${ClassName}(List<${ClassName}> list, Boolean isUpdateSupport, String userName); | |||||
/** | /** | ||||
* 新增${functionName} | * 新增${functionName} | ||||
@@ -60,16 +60,15 @@ public class ${ClassName}ServiceImpl implements I${ClassName}Service | |||||
* | * | ||||
* @param list ${functionName}数据列表 | * @param list ${functionName}数据列表 | ||||
* @param isUpdateSupport 是否更新支持,如果已存在,则进行更新数据 | * @param isUpdateSupport 是否更新支持,如果已存在,则进行更新数据 | ||||
* @param user 操作用户 | |||||
* @param operName 操作用户 | |||||
* @return 结果 | * @return 结果 | ||||
*/ | */ | ||||
@Override | @Override | ||||
@Transactional | @Transactional | ||||
public String import${ClassName}(List<${ClassName}> list, Boolean isUpdateSupport, SysUser user) { | |||||
public String import${ClassName}(List<${ClassName}> list, Boolean isUpdateSupport, String operName) { | |||||
if (StringUtils.isEmpty(list)) { | if (StringUtils.isEmpty(list)) { | ||||
throw new ServiceException("导入${functionName}数据不能为空!"); | throw new ServiceException("导入${functionName}数据不能为空!"); | ||||
} | } | ||||
String operName = user.getLoginName(); | |||||
int successNum = 0; | int successNum = 0; | ||||
int failureNum = 0; | int failureNum = 0; | ||||
@@ -1,3 +1,39 @@ | |||||
#macro(GET_CHAR_COLUMN_LENGTH $column)## * 如果表列是char/varchar, 获取其最大字符长度, 否则为空字符串 * 参数: 列 * 结果保存在变量名为 $_char_column_length 字符串型 | |||||
#set($_char_column_length="") | |||||
#if($column.columnType.startsWith("char") || $column.columnType.startsWith("varchar")) | |||||
#set($startLeft=$column.columnType.indexOf("(")) | |||||
#if($startLeft != -1) | |||||
#set($endRight=$column.columnType.indexOf(")", $startLeft)) | |||||
#if($endRight != -1) | |||||
#set($startLeft=$startLeft+1) | |||||
#set($_char_column_length=$column.columnType.substring($startLeft, $endRight)) | |||||
#end | |||||
#end | |||||
#end | |||||
#end## GET_CHAR_COLUMN_LENGTH | |||||
#macro(COLUMN_IS_NUMBER $column)## * 检查表列是否是数字型 * 参数: 列 * 结果保存在变量名为 $_column_is_number bool型 | |||||
#set($_column_is_number=$column.columnType.startsWith("decimal") || $column.columnType.startsWith("tinyint") || $column.columnType.startsWith("mediumint") || $column.columnType.startsWith("int") || $column.columnType.startsWith("bigint") || $column.columnType.startsWith("smallint")) | |||||
#end## COLUMN_IS_NUMBER | |||||
#macro(GET_NUMBER_COLUMN_MIN_AND_PRECISION $column)## * 如果表列是数字型, 获取其最小值和浮点数部分精度, 否则为空字符串 * 参数: 列 * 最小值结果保存在变量名为 $_number_column_min 字符串型 * 浮点数部分精度结果保存在变量名为 $_number_column_precision 字符串型 | |||||
#set($_number_column_min="") | |||||
#set($_number_column_precision="") | |||||
#if($column.columnType.contains("unsigned")) | |||||
#set($_number_column_min="0") | |||||
#end | |||||
#set($startLeft=$column.columnType.indexOf("(")) | |||||
#if($startLeft != -1) | |||||
#set($endRight=$column.columnType.indexOf(")", $startLeft)) | |||||
#if($endRight != -1) | |||||
#set($startLeft=$startLeft+1) | |||||
#set($internalText=$column.columnType.substring($startLeft, $endRight)) | |||||
#set($splitIndex=$internalText.indexOf(",")) | |||||
#if($splitIndex != -1) | |||||
#set($splitIndex=$splitIndex+1) | |||||
#set($_number_column_precision=$internalText.substring($splitIndex)) | |||||
#end | |||||
#end | |||||
#end | |||||
#end## GET_NUMBER_COLUMN_MIN_AND_PRECISION | |||||
<template> | <template> | ||||
<div class="app-container"> | <div class="app-container"> | ||||
<el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="68px"> | <el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="68px"> | ||||
@@ -48,20 +84,23 @@ | |||||
<el-col :span="1.5"> | <el-col :span="1.5"> | ||||
<el-button type="primary" plain icon="el-icon-plus" size="mini" @click="handleAdd" v-hasPermi="['${permissionPrefix}:add']">新增</el-button> | <el-button type="primary" plain icon="el-icon-plus" size="mini" @click="handleAdd" v-hasPermi="['${permissionPrefix}:add']">新增</el-button> | ||||
</el-col> | </el-col> | ||||
<!-- | |||||
<el-col :span="1.5"> | <el-col :span="1.5"> | ||||
<el-button type="success" plain icon="el-icon-edit" size="mini" :disabled="single" @click="handleUpdate" v-hasPermi="['${permissionPrefix}:edit']">修改</el-button> | <el-button type="success" plain icon="el-icon-edit" size="mini" :disabled="single" @click="handleUpdate" v-hasPermi="['${permissionPrefix}:edit']">修改</el-button> | ||||
</el-col> | </el-col> | ||||
<el-col :span="1.5"> | <el-col :span="1.5"> | ||||
<el-button type="danger" plain icon="el-icon-delete" size="mini" :disabled="multiple" @click="handleDelete" v-hasPermi="['${permissionPrefix}:remove']">删除</el-button> | <el-button type="danger" plain icon="el-icon-delete" size="mini" :disabled="multiple" @click="handleDelete" v-hasPermi="['${permissionPrefix}:remove']">删除</el-button> | ||||
</el-col> | </el-col> | ||||
--> | |||||
<el-col :span="1.5"> | <el-col :span="1.5"> | ||||
<el-button type="warning" plain icon="el-icon-download" size="mini" @click="handleExport" v-hasPermi="['${permissionPrefix}:export']">导出</el-button> | |||||
<el-button type="info" plain icon="el-icon-upload2" size="mini" @click="handleImport" v-hasPermi="['${permissionPrefix}:import']">导入</el-button> | |||||
</el-col> | </el-col> | ||||
<el-col :span="1.5"> | <el-col :span="1.5"> | ||||
<el-button type="info" plain icon="el-icon-upload2" size="mini" @click="handleImport" v-hasPermi="['${permissionPrefix}:import']">导入</el-button> | |||||
<el-button type="warning" plain icon="el-icon-download" size="mini" @click="handleExport" v-hasPermi="['${permissionPrefix}:export']">导出</el-button> | |||||
</el-col> | </el-col> | ||||
<el-col :span="1.5"> | <el-col :span="1.5"> | ||||
<el-button type="warning" plain icon="el-icon-printer" size="mini" @click="handlePrint()" v-hasPermi="['${permissionPrefix}:export']">打印</el-button> | |||||
<el-button type="success" plain icon="el-icon-printer" size="mini" @click="handlePrint()" v-hasPermi="['${permissionPrefix}:print']">打印</el-button> | |||||
</el-col> | </el-col> | ||||
<right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar> | <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar> | ||||
</el-row> | </el-row> | ||||
@@ -80,21 +119,17 @@ | |||||
#if($column.pk) | #if($column.pk) | ||||
<el-table-column label="${comment}" align="center" prop="${javaField}" /> | <el-table-column label="${comment}" align="center" prop="${javaField}" /> | ||||
#elseif($column.list && $column.htmlType == "datetime") | #elseif($column.list && $column.htmlType == "datetime") | ||||
<el-table-column label="${comment}" align="center" prop="${javaField}" width="180"> | |||||
<template slot-scope="scope"> | |||||
<span>{{ parseTime(scope.row.${javaField}, '{y}-{m}-{d}') }}</span> | |||||
</template> | |||||
</el-table-column> | |||||
<el-table-column label="${comment}" align="center" prop="${javaField}" /> | |||||
#elseif($column.list && $column.htmlType == "imageUpload") | #elseif($column.list && $column.htmlType == "imageUpload") | ||||
<el-table-column label="${comment}" align="center" prop="${javaField}" width="100"> | <el-table-column label="${comment}" align="center" prop="${javaField}" width="100"> | ||||
<template slot-scope="scope"> | <template slot-scope="scope"> | ||||
<div v-if="!!scope.row.${javaField}"><el-tooltip effect="light" :content="item" placement="bottom" v-for="(item, index) in scope.row.${javaField}.split(',')" :key="index"><el-image style="height: 48px; width: 48px; margin: 2px; display: inline-block;" fit="scale-down" :src="$store.getters.baseRoutingUrl + item" :preview-src-list="scope.row.${javaField}.split(',').map((x) => $store.getters.baseRoutingUrl + x)"/></el-tooltip></div> | |||||
<div v-if="!!scope.row.${javaField}"><el-tooltip effect="light" :content="item" placement="bottom" v-for="(item, index) in scope.row.${javaField}.split(',')" :key="index"><el-image style="height: 48px; width: 48px; margin: 2px; display: inline-block;" fit="scale-down" :src="baseRoutingUrll + item" :preview-src-list="scope.row.${javaField}.split(',').map((x) => baseRoutingUrll + x)"/></el-tooltip></div> | |||||
</template> | </template> | ||||
</el-table-column> | </el-table-column> | ||||
#elseif($column.list && $column.htmlType == "fileUpload") | #elseif($column.list && $column.htmlType == "fileUpload") | ||||
<el-table-column label="${comment}" header-align="center" align="left" prop="${javaField}" > | <el-table-column label="${comment}" header-align="center" align="left" prop="${javaField}" > | ||||
<template slot-scope="scope"> | <template slot-scope="scope"> | ||||
<div v-if="!!scope.row.${javaField}"><el-tooltip effect="light" :content="item.substr(item.lastIndexOf('/') + 1)" placement="bottom" v-for="(item, index) in scope.row.${javaField}.split(',')" :key="index"><a :href="$store.getters.baseRoutingUrl + item" target="_blank" style="height: 32px; width: 32px; margin: 2px; display: inline-block; text-align: center;"><img :src="getFileIcon(item)" style="height: 100%;"/></a></el-tooltip></div> | |||||
<div v-if="!!scope.row.${javaField}"><el-tooltip effect="light" :content="item.substr(item.lastIndexOf('/') + 1)" placement="bottom" v-for="(item, index) in scope.row.${javaField}.split(',')" :key="index"><a :href="baseRoutingUrll + item" target="_blank" style="height: 32px; width: 32px; margin: 2px; display: inline-block; text-align: center;"><img :src="getFileIcon(item)" style="height: 100%;"/></a></el-tooltip></div> | |||||
</template> | </template> | ||||
</el-table-column> | </el-table-column> | ||||
#elseif($column.list && "" != $column.dictType) | #elseif($column.list && "" != $column.dictType) | ||||
@@ -124,11 +159,27 @@ | |||||
<pagination v-show="total>0" :total="total" :page.sync="queryParams.pageNum" :limit.sync="queryParams.pageSize" @pagination="getList"/> | <pagination v-show="total>0" :total="total" :page.sync="queryParams.pageNum" :limit.sync="queryParams.pageSize" @pagination="getList"/> | ||||
<!-- 导入EXCEL组件 --> | <!-- 导入EXCEL组件 --> | ||||
<importExcel :visible="importExcelData.visible" :importExcelDatas="importExcelData" :datas="importExcelData.data" @improtExcelChildFn="improtExcelChildFun"></importExcel> | |||||
<el-dialog :title="upload.title" :visible.sync="upload.open" width="400px" append-to-body> | |||||
<el-upload ref="upload" :limit="1" accept=".xlsx, .xls" :headers="upload.headers" :action="upload.url + '?updateSupport=' + upload.updateSupport" :disabled="upload.isUploading" :on-progress="handleFileUploadProgress" :on-success="handleFileSuccess" :auto-upload="false" drag> | |||||
<i class="el-icon-upload"></i> | |||||
<div class="el-upload__text">将文件拖到此处,或<em>点击上传</em></div> | |||||
<div class="el-upload__tip text-center" slot="tip"> | |||||
<div class="el-upload__tip" slot="tip"> | |||||
<el-checkbox v-model="upload.updateSupport" />是否更新已经存在的${functionName} | |||||
</div> | |||||
<span>仅允许导入xls、xlsx格式文件。</span> | |||||
<el-link type="primary" :underline="false" style="font-size: 12px; vertical-align: baseline" @click="importTemplate">下载模板</el-link> | |||||
</div> | |||||
</el-upload> | |||||
<div slot="footer" class="dialog-footer"> | |||||
<el-button type="primary" @click="submitFileForm">确 定</el-button> | |||||
<el-button @click="upload.open = false">取 消</el-button> | |||||
</div> | |||||
</el-dialog> | |||||
<!-- 查看${functionName}对话框 --> | <!-- 查看${functionName}对话框 --> | ||||
<el-dialog :title="title" :visible.sync="viewOpen" width="800px" append-to-body> | <el-dialog :title="title" :visible.sync="viewOpen" width="800px" append-to-body> | ||||
<el-descriptions :column="descColumn" border :labelStyle="{width: `${descLabelWidth}%`}" :contentStyle="{width: `${(100 / descColumn) - descLabelWidth}%`}"> | |||||
<el-descriptions id="printDetail" :column="descColumn" border :labelStyle="{width: `${descLabelWidth}%`}" :contentStyle="{width: `${(100 / descColumn) - descLabelWidth}%`}"> | |||||
#foreach($column in $columns) | #foreach($column in $columns) | ||||
#set($field=$column.javaField) | #set($field=$column.javaField) | ||||
#if($column.insert && !$column.pk) | #if($column.insert && !$column.pk) | ||||
@@ -140,13 +191,14 @@ | |||||
#set($comment=$column.columnComment) | #set($comment=$column.columnComment) | ||||
#end | #end | ||||
#set($dictType=$column.dictType) | #set($dictType=$column.dictType) | ||||
<el-descriptions-item label="${comment}">#if(($column.htmlType == "select" || $column.htmlType == "checkbox" || $column.htmlType == "radio") && "" != $dictType)<el-tooltip effect="light" :content="form.${field}" placement="right"><dict-tag :options="${field}Options" :value="form.${field}"/></el-tooltip>#elseif($column.htmlType == "imageUpload")<div v-if="!!form.${field}"><el-tooltip effect="light" :content="item" placement="bottom" v-for="(item, index) in form.${field}.split(',')" :key="index"><el-image style="height: 64px; width: 64px; margin: 2px; display: inline-block;" fit="scale-down" :src="$store.getters.baseRoutingUrl + item" :preview-src-list="form.${field}.split(',').map((x) => $store.getters.baseRoutingUrl + x)"/></el-tooltip></div>#elseif($column.htmlType == "editor")<el-tooltip placement="bottom" effect="light"><div slot="content" v-html="form.${field}"/><div style="overflow: hidden; text-overflow: ellipsis; white-space: nowrap; max-width: 230px;">{{ form.${field} }}</div></el-tooltip>#elseif($column.htmlType == "fileUpload")<div v-if="!!form.${field}"><el-tooltip effect="light" :content="item.substr(item.lastIndexOf('/') + 1)" placement="bottom" v-for="(item, index) in form.${field}.split(',')" :key="index"><a :href="$store.getters.baseRoutingUrl + item" target="_blank" style="height: 48px; width: 48px; margin: 2px; display: inline-block; text-align: center;"><img :src="getFileIcon(item)" style="height: 100%;"/></a></el-tooltip></div>#else{{ form.${field} }}#end</el-descriptions-item> | |||||
<el-descriptions-item label="${comment}">#if(($column.htmlType == "select" || $column.htmlType == "checkbox" || $column.htmlType == "radio") && "" != $dictType)<el-tooltip effect="light" :content="form.${field}" placement="right"><dict-tag :options="dict.type.dictType" :value="form.${field}"/></el-tooltip>#elseif($column.htmlType == "imageUpload")<div v-if="!!form.${field}"><el-tooltip effect="light" :content="item" placement="bottom" v-for="(item, index) in form.${field}.split(',')" :key="index"><el-image style="height: 64px; width: 64px; margin: 2px; display: inline-block;" fit="scale-down" :src="baseRoutingUrll + item" :preview-src-list="form.${field}.split(',').map((x) => baseRoutingUrll + x)"/></el-tooltip></div>#elseif($column.htmlType == "editor")<el-tooltip placement="bottom" effect="light"><div slot="content" v-html="form.${field}"/><div style="overflow: hidden; text-overflow: ellipsis; white-space: nowrap; max-width: 230px;">{{ form.${field} }}</div></el-tooltip>#elseif($column.htmlType == "fileUpload")<div v-if="!!form.${field}"><el-tooltip effect="light" :content="item.substr(item.lastIndexOf('/') + 1)" placement="bottom" v-for="(item, index) in form.${field}.split(',')" :key="index"><a :href="baseRoutingUrll + item" target="_blank" style="height: 48px; width: 48px; margin: 2px; display: inline-block; text-align: center;"><img :src="getFileIcon(item)" style="height: 100%;"/></a></el-tooltip></div>#else{{ form.${field} }}#end</el-descriptions-item> | |||||
#end | #end | ||||
#end | #end | ||||
#end | #end | ||||
</el-descriptions> | </el-descriptions> | ||||
<!-- 弹框操作按钮 --> | <!-- 弹框操作按钮 --> | ||||
<div slot="footer" class="dialog-footer"> | <div slot="footer" class="dialog-footer"> | ||||
<el-button @click="doPrint">打 印</el-button> | |||||
<el-button @click="cancel">关 闭</el-button> | <el-button @click="cancel">关 闭</el-button> | ||||
</div> | </div> | ||||
</el-dialog> | </el-dialog> | ||||
@@ -166,9 +218,18 @@ | |||||
#end | #end | ||||
#set($dictType=$column.dictType) | #set($dictType=$column.dictType) | ||||
#if($column.htmlType == "input") | #if($column.htmlType == "input") | ||||
#COLUMN_IS_NUMBER($column) | |||||
#if($_column_is_number) | |||||
#GET_NUMBER_COLUMN_MIN_AND_PRECISION($column) | |||||
<el-form-item label="${comment}" prop="${field}"> | <el-form-item label="${comment}" prop="${field}"> | ||||
<el-input v-model="form.${field}" placeholder="请输入${comment}" /> | |||||
<el-input-number v-model="form.${field}" placeholder="请输入${comment}" controls-position="right" #if($_number_column_min != "") :min="${_number_column_min}"#end #if($_number_column_precision != "") :precision="${_number_column_precision}"#end/> | |||||
</el-form-item> | </el-form-item> | ||||
#else | |||||
#GET_CHAR_COLUMN_LENGTH($column) | |||||
<el-form-item label="${comment}" prop="${field}"> | |||||
<el-input v-model="form.${field}" placeholder="请输入${comment}" #if($_char_column_length != "") show-word-limit :maxlength="${_char_column_length}"#end/> | |||||
</el-form-item> | |||||
#end | |||||
#elseif($column.htmlType == "imageUpload") | #elseif($column.htmlType == "imageUpload") | ||||
<el-form-item label="${comment}" prop="${field}"> | <el-form-item label="${comment}" prop="${field}"> | ||||
<image-upload v-model="form.${field}"/> | <image-upload v-model="form.${field}"/> | ||||
@@ -235,7 +296,7 @@ | |||||
</el-form-item> | </el-form-item> | ||||
#elseif($column.htmlType == "textarea") | #elseif($column.htmlType == "textarea") | ||||
<el-form-item label="${comment}" prop="${field}"> | <el-form-item label="${comment}" prop="${field}"> | ||||
<el-input v-model="form.${field}" type="textarea" placeholder="请输入内容" /> | |||||
<el-input v-model="form.${field}" type="textarea" :autosize="{ minRows: 2, maxRows: 3}" #if($_char_column_length != "") :maxlength="${_char_column_length}"#end show-word-limit placeholder="请输入内容" /> | |||||
</el-form-item> | </el-form-item> | ||||
#end | #end | ||||
#end | #end | ||||
@@ -306,7 +367,7 @@ | |||||
<script> | <script> | ||||
import { list${BusinessName}, get${BusinessName}, del${BusinessName}, add${BusinessName}, update${BusinessName}, print${BusinessName} } from "@/api/${moduleName}/${businessName}" | import { list${BusinessName}, get${BusinessName}, del${BusinessName}, add${BusinessName}, update${BusinessName}, print${BusinessName} } from "@/api/${moduleName}/${businessName}" | ||||
import importExcel from "@/components/importExcel/importExcel"; | |||||
import { getToken } from "@/utils/auth" | |||||
export default { | export default { | ||||
name: "${BusinessName}", | name: "${BusinessName}", | ||||
#if(${dicts} != '') | #if(${dicts} != '') | ||||
@@ -348,6 +409,8 @@ export default { | |||||
descLabelWidth: 15, | descLabelWidth: 15, | ||||
// 对话框显示只读的详情 | // 对话框显示只读的详情 | ||||
viewOpen: false, | viewOpen: false, | ||||
// 项目路径 | |||||
baseRoutingUrl: process.env.VUE_APP_BASE_API, | |||||
#foreach ($column in $columns) | #foreach ($column in $columns) | ||||
#if($column.htmlType == "datetime" && $column.queryType == "BETWEEN") | #if($column.htmlType == "datetime" && $column.queryType == "BETWEEN") | ||||
#set($AttrName=$column.javaField.substring(0,1).toUpperCase() + ${column.javaField.substring(1)}) | #set($AttrName=$column.javaField.substring(0,1).toUpperCase() + ${column.javaField.substring(1)}) | ||||
@@ -363,7 +426,7 @@ export default { | |||||
//orderByColumn: "id", | //orderByColumn: "id", | ||||
//isAsc: "desc", | //isAsc: "desc", | ||||
// 翻译字典 | // 翻译字典 | ||||
//toDict: "1", | |||||
//toTranslateDict: "1", | |||||
#foreach ($column in $columns) | #foreach ($column in $columns) | ||||
#if($column.query) | #if($column.query) | ||||
$column.javaField: null#if($foreach.count != $columns.size()),#end | $column.javaField: null#if($foreach.count != $columns.size()),#end | ||||
@@ -389,22 +452,21 @@ export default { | |||||
#end | #end | ||||
}, | }, | ||||
// EXCEL导入 | // EXCEL导入 | ||||
importExcelData: { | |||||
//弹窗显示隐藏 | |||||
visible: false, | |||||
//标题 | |||||
title: "${functionName}导入", | |||||
//上传时附带的额外参数 | |||||
data: {}, | |||||
upload: { | |||||
// 是否显示弹出层(用户导入) | |||||
open: false, | |||||
// 弹出层标题(用户导入) | |||||
title: "", | |||||
// 是否禁用上传 | |||||
isUploading: false, | |||||
// 是否更新已经存在的用户数据 | |||||
updateSupport: 0, | |||||
// 设置上传的请求头部 | |||||
headers: { Authorization: "Bearer " + getToken() }, | |||||
// 上传的地址 | // 上传的地址 | ||||
url: process.env.VUE_APP_BASE_API + "/${moduleName}/${businessName}/importData", | |||||
// 下载模板接口地址 空不显示按钮 | |||||
DownloadTemplateUrl: "/${moduleName}/${businessName}/importTemplate", | |||||
//更新数据文案 空不显示更新按钮 | |||||
updateText: "是否更新已经存在的${functionName}数据", | |||||
// 导入规则说明 (可为空) | |||||
promptText: "1、模板表头不允许变动!<br>2、仅允许导入“xls”或“xlsx”格式文件!", | |||||
url: process.env.VUE_APP_BASE_API + "/${moduleName}/${businessName}/importData" | |||||
}, | }, | ||||
} | } | ||||
}, | }, | ||||
created() { | created() { | ||||
@@ -597,17 +659,96 @@ export default { | |||||
...this.queryParams | ...this.queryParams | ||||
}, `${businessName}_#[[${new Date().getTime()}]]#.xlsx`) | }, `${businessName}_#[[${new Date().getTime()}]]#.xlsx`) | ||||
}, | }, | ||||
/** 打印表单 */ | |||||
doPrint() { | |||||
const originalTitle = document.title; | |||||
try { | |||||
document.title = this.title || '通用附件详情'; | |||||
const printElement = document.getElementById('printDetail'); | |||||
const printFrame = document.createElement('iframe'); | |||||
printFrame.style.position = 'absolute'; | |||||
printFrame.style.width = '0'; | |||||
printFrame.style.height = '0'; | |||||
printFrame.style.border = 'none'; | |||||
printFrame.style.left = '-9999px'; | |||||
printFrame.onload = function() { | |||||
try { | |||||
const frameDoc = printFrame.contentDocument || printFrame.contentWindow.document; | |||||
const contentClone = printElement.cloneNode(true); | |||||
const style = document.createElement('style'); | |||||
style.innerHTML = ` | |||||
@page { | |||||
size: auto; | |||||
margin: 10mm; | |||||
} | |||||
body { | |||||
font-family: Arial, sans-serif; | |||||
line-height: 1.5; | |||||
margin: 0; | |||||
padding: 0; | |||||
} | |||||
.el-descriptions { | |||||
width: 100% !important; | |||||
} | |||||
.el-descriptions-item__label { | |||||
width: ${this.descLabelWidth}% !important; | |||||
} | |||||
.el-descriptions-item__content { | |||||
width: ${(100 / this.descColumn) - this.descLabelWidth}% !important; | |||||
} | |||||
/* 确保图片在打印时显示完整 */ | |||||
img, .el-image { | |||||
max-width: 100% !important; | |||||
height: auto !important; | |||||
} | |||||
`; | |||||
frameDoc.head.appendChild(style); | |||||
frameDoc.body.appendChild(contentClone); | |||||
setTimeout(() => { | |||||
printFrame.contentWindow.focus(); | |||||
printFrame.contentWindow.print(); | |||||
setTimeout(() => { | |||||
document.body.removeChild(printFrame); | |||||
document.title = originalTitle; | |||||
}, 1000); | |||||
}, 500); | |||||
} catch (e) { | |||||
document.body.removeChild(printFrame); | |||||
document.title = originalTitle; | |||||
this.$message.error('打印过程中发生错误'); | |||||
} | |||||
}; | |||||
document.body.appendChild(printFrame); | |||||
} catch (e) { | |||||
document.title = originalTitle; | |||||
this.$message.error('打印过程中发生错误'); | |||||
} | |||||
}, | |||||
/** 打印按钮操作 */ | /** 打印按钮操作 */ | ||||
handlePrint() { | handlePrint() { | ||||
print${BusinessName}(this.queryParams).then(response => {}) | print${BusinessName}(this.queryParams).then(response => {}) | ||||
}, | }, | ||||
/* 导入EXCEL组件 */ | /* 导入EXCEL组件 */ | ||||
improtExcelChildFun(payload) { | |||||
this.$set(this.importExcelData, "visible", payload); | |||||
this.getList(); | |||||
}, | |||||
handleImport() { | handleImport() { | ||||
this.$set(this.importExcelData, "visible", true); | |||||
this.upload.title = "${functionName}导入" | |||||
this.upload.open = true | |||||
}, | |||||
/** 下载模板操作 */ | |||||
importTemplate() { | |||||
this.download('${moduleName}/${businessName}/importTemplate', { | |||||
}, `${businessName}_template_${new Date().getTime()}.xlsx`) | |||||
}, | |||||
// 文件上传中处理 | |||||
handleFileUploadProgress(event, file, fileList) { | |||||
this.upload.isUploading = true | |||||
}, | |||||
// 文件上传成功处理 | |||||
handleFileSuccess(response, file, fileList) { | |||||
this.upload.open = false | |||||
this.upload.isUploading = false | |||||
this.$refs.upload.clearFiles() | |||||
this.$alert("<div style='overflow: auto;overflow-x: hidden;max-height: 70vh;padding: 10px 20px 0;'>" + response.msg + "</div>", "导入结果", { dangerouslyUseHTMLString: true }) | |||||
this.getList() | |||||
}, | }, | ||||
#foreach($column in $columns) | #foreach($column in $columns) | ||||
#if($column.insert && !$column.superColumn && !$column.pk && $column.htmlType == "fileUpload") | #if($column.insert && !$column.superColumn && !$column.pk && $column.htmlType == "fileUpload") | ||||
@@ -615,7 +756,7 @@ export default { | |||||
if(!file) return ''; | if(!file) return ''; | ||||
switch(file.toLowerCase().substr(file.lastIndexOf('.') + 1)) { | switch(file.toLowerCase().substr(file.lastIndexOf('.') + 1)) { | ||||
case 'jpg': case 'png': case 'jpeg': case 'bmp': case 'gif': | case 'jpg': case 'png': case 'jpeg': case 'bmp': case 'gif': | ||||
return this.$store.getters.baseRoutingUrl + file; | |||||
return this.baseRoutingUrll + file; | |||||
case 'doc': case 'docx': | case 'doc': case 'docx': | ||||
return require('@/assets/images/icon_word.jpg'); | return require('@/assets/images/icon_word.jpg'); | ||||
case 'xls': case 'xlsx': | case 'xls': case 'xlsx': | ||||
@@ -625,7 +766,7 @@ export default { | |||||
case 'zip': case 'rar': case '7z': case 'bz2': case 'gz': | case 'zip': case 'rar': case '7z': case 'bz2': case 'gz': | ||||
return require('@/assets/images/icon_zip.jpg'); | return require('@/assets/images/icon_zip.jpg'); | ||||
default: | default: | ||||
return require('@/assets/images/file.png'); | |||||
return require('@/assets/images/icon_rest.jpg'); | |||||
} | } | ||||
}, | }, | ||||
#break | #break | ||||
@@ -42,6 +42,7 @@ | |||||
<orderEntry type="library" name="Maven: org.springframework.security:spring-security-core:5.7.12" level="project" /> | <orderEntry type="library" name="Maven: org.springframework.security:spring-security-core:5.7.12" level="project" /> | ||||
<orderEntry type="library" name="Maven: org.springframework.security:spring-security-crypto:5.7.12" level="project" /> | <orderEntry type="library" name="Maven: org.springframework.security:spring-security-crypto:5.7.12" level="project" /> | ||||
<orderEntry type="library" name="Maven: org.springframework.security:spring-security-web:5.7.12" level="project" /> | <orderEntry type="library" name="Maven: org.springframework.security:spring-security-web:5.7.12" level="project" /> | ||||
<orderEntry type="library" name="Maven: net.coobird:thumbnailator:0.4.8" level="project" /> | |||||
<orderEntry type="library" name="Maven: com.github.pagehelper:pagehelper-spring-boot-starter:1.4.7" level="project" /> | <orderEntry type="library" name="Maven: com.github.pagehelper:pagehelper-spring-boot-starter:1.4.7" level="project" /> | ||||
<orderEntry type="library" name="Maven: org.mybatis.spring.boot:mybatis-spring-boot-starter:2.3.1" level="project" /> | <orderEntry type="library" name="Maven: org.mybatis.spring.boot:mybatis-spring-boot-starter:2.3.1" level="project" /> | ||||
<orderEntry type="library" name="Maven: org.springframework.boot:spring-boot-starter-jdbc:2.5.15" level="project" /> | <orderEntry type="library" name="Maven: org.springframework.boot:spring-boot-starter-jdbc:2.5.15" level="project" /> | ||||
@@ -59,6 +60,7 @@ | |||||
<orderEntry type="library" name="Maven: jakarta.validation:jakarta.validation-api:2.0.2" level="project" /> | <orderEntry type="library" name="Maven: jakarta.validation:jakarta.validation-api:2.0.2" level="project" /> | ||||
<orderEntry type="library" name="Maven: org.jboss.logging:jboss-logging:3.4.3.Final" level="project" /> | <orderEntry type="library" name="Maven: org.jboss.logging:jboss-logging:3.4.3.Final" level="project" /> | ||||
<orderEntry type="library" name="Maven: com.fasterxml:classmate:1.5.1" level="project" /> | <orderEntry type="library" name="Maven: com.fasterxml:classmate:1.5.1" level="project" /> | ||||
<orderEntry type="library" name="Maven: org.projectlombok:lombok:1.18.26" level="project" /> | |||||
<orderEntry type="library" name="Maven: org.apache.commons:commons-lang3:3.12.0" level="project" /> | <orderEntry type="library" name="Maven: org.apache.commons:commons-lang3:3.12.0" level="project" /> | ||||
<orderEntry type="library" name="Maven: com.fasterxml.jackson.core:jackson-databind:2.12.7.1" level="project" /> | <orderEntry type="library" name="Maven: com.fasterxml.jackson.core:jackson-databind:2.12.7.1" level="project" /> | ||||
<orderEntry type="library" name="Maven: com.fasterxml.jackson.core:jackson-annotations:2.12.7" level="project" /> | <orderEntry type="library" name="Maven: com.fasterxml.jackson.core:jackson-annotations:2.12.7" level="project" /> | ||||
@@ -77,6 +79,7 @@ | |||||
<orderEntry type="library" name="Maven: com.github.virtuald:curvesapi:1.06" level="project" /> | <orderEntry type="library" name="Maven: com.github.virtuald:curvesapi:1.06" level="project" /> | ||||
<orderEntry type="library" name="Maven: org.yaml:snakeyaml:1.28" level="project" /> | <orderEntry type="library" name="Maven: org.yaml:snakeyaml:1.28" level="project" /> | ||||
<orderEntry type="library" name="Maven: io.jsonwebtoken:jjwt:0.9.1" level="project" /> | <orderEntry type="library" name="Maven: io.jsonwebtoken:jjwt:0.9.1" level="project" /> | ||||
<orderEntry type="library" name="Maven: javax.servlet:javax.servlet-api:4.0.1" level="project" /> | |||||
<orderEntry type="library" name="Maven: javax.xml.bind:jaxb-api:2.3.1" level="project" /> | <orderEntry type="library" name="Maven: javax.xml.bind:jaxb-api:2.3.1" level="project" /> | ||||
<orderEntry type="library" name="Maven: javax.activation:javax.activation-api:1.2.0" level="project" /> | <orderEntry type="library" name="Maven: javax.activation:javax.activation-api:1.2.0" level="project" /> | ||||
<orderEntry type="library" name="Maven: org.springframework.boot:spring-boot-starter-data-redis:2.5.15" level="project" /> | <orderEntry type="library" name="Maven: org.springframework.boot:spring-boot-starter-data-redis:2.5.15" level="project" /> | ||||
@@ -97,6 +100,8 @@ | |||||
<orderEntry type="library" name="Maven: org.reactivestreams:reactive-streams:1.0.4" level="project" /> | <orderEntry type="library" name="Maven: org.reactivestreams:reactive-streams:1.0.4" level="project" /> | ||||
<orderEntry type="library" name="Maven: org.apache.commons:commons-pool2:2.9.0" level="project" /> | <orderEntry type="library" name="Maven: org.apache.commons:commons-pool2:2.9.0" level="project" /> | ||||
<orderEntry type="library" name="Maven: eu.bitwalker:UserAgentUtils:1.21" level="project" /> | <orderEntry type="library" name="Maven: eu.bitwalker:UserAgentUtils:1.21" level="project" /> | ||||
<orderEntry type="library" name="Maven: javax.servlet:javax.servlet-api:4.0.1" level="project" /> | |||||
<orderEntry type="library" name="Maven: com.itextpdf:itextpdf:5.5.13.2" level="project" /> | |||||
<orderEntry type="library" name="Maven: com.itextpdf:itext-asian:5.2.0" level="project" /> | |||||
<orderEntry type="library" name="Maven: cn.hutool:hutool-all:5.5.4" level="project" /> | |||||
</component> | </component> | ||||
</module> | </module> |
@@ -39,6 +39,7 @@ | |||||
<orderEntry type="library" name="Maven: org.springframework.security:spring-security-core:5.7.12" level="project" /> | <orderEntry type="library" name="Maven: org.springframework.security:spring-security-core:5.7.12" level="project" /> | ||||
<orderEntry type="library" name="Maven: org.springframework.security:spring-security-crypto:5.7.12" level="project" /> | <orderEntry type="library" name="Maven: org.springframework.security:spring-security-crypto:5.7.12" level="project" /> | ||||
<orderEntry type="library" name="Maven: org.springframework.security:spring-security-web:5.7.12" level="project" /> | <orderEntry type="library" name="Maven: org.springframework.security:spring-security-web:5.7.12" level="project" /> | ||||
<orderEntry type="library" name="Maven: net.coobird:thumbnailator:0.4.8" level="project" /> | |||||
<orderEntry type="library" name="Maven: com.github.pagehelper:pagehelper-spring-boot-starter:1.4.7" level="project" /> | <orderEntry type="library" name="Maven: com.github.pagehelper:pagehelper-spring-boot-starter:1.4.7" level="project" /> | ||||
<orderEntry type="library" name="Maven: org.mybatis.spring.boot:mybatis-spring-boot-starter:2.3.1" level="project" /> | <orderEntry type="library" name="Maven: org.mybatis.spring.boot:mybatis-spring-boot-starter:2.3.1" level="project" /> | ||||
<orderEntry type="library" name="Maven: org.springframework.boot:spring-boot-starter-jdbc:2.5.15" level="project" /> | <orderEntry type="library" name="Maven: org.springframework.boot:spring-boot-starter-jdbc:2.5.15" level="project" /> | ||||
@@ -56,6 +57,7 @@ | |||||
<orderEntry type="library" name="Maven: jakarta.validation:jakarta.validation-api:2.0.2" level="project" /> | <orderEntry type="library" name="Maven: jakarta.validation:jakarta.validation-api:2.0.2" level="project" /> | ||||
<orderEntry type="library" name="Maven: org.jboss.logging:jboss-logging:3.4.3.Final" level="project" /> | <orderEntry type="library" name="Maven: org.jboss.logging:jboss-logging:3.4.3.Final" level="project" /> | ||||
<orderEntry type="library" name="Maven: com.fasterxml:classmate:1.5.1" level="project" /> | <orderEntry type="library" name="Maven: com.fasterxml:classmate:1.5.1" level="project" /> | ||||
<orderEntry type="library" name="Maven: org.projectlombok:lombok:1.18.26" level="project" /> | |||||
<orderEntry type="library" name="Maven: org.apache.commons:commons-lang3:3.12.0" level="project" /> | <orderEntry type="library" name="Maven: org.apache.commons:commons-lang3:3.12.0" level="project" /> | ||||
<orderEntry type="library" name="Maven: com.fasterxml.jackson.core:jackson-databind:2.12.7.1" level="project" /> | <orderEntry type="library" name="Maven: com.fasterxml.jackson.core:jackson-databind:2.12.7.1" level="project" /> | ||||
<orderEntry type="library" name="Maven: com.fasterxml.jackson.core:jackson-annotations:2.12.7" level="project" /> | <orderEntry type="library" name="Maven: com.fasterxml.jackson.core:jackson-annotations:2.12.7" level="project" /> | ||||
@@ -74,6 +76,7 @@ | |||||
<orderEntry type="library" name="Maven: com.github.virtuald:curvesapi:1.06" level="project" /> | <orderEntry type="library" name="Maven: com.github.virtuald:curvesapi:1.06" level="project" /> | ||||
<orderEntry type="library" name="Maven: org.yaml:snakeyaml:1.28" level="project" /> | <orderEntry type="library" name="Maven: org.yaml:snakeyaml:1.28" level="project" /> | ||||
<orderEntry type="library" name="Maven: io.jsonwebtoken:jjwt:0.9.1" level="project" /> | <orderEntry type="library" name="Maven: io.jsonwebtoken:jjwt:0.9.1" level="project" /> | ||||
<orderEntry type="library" name="Maven: javax.servlet:javax.servlet-api:4.0.1" level="project" /> | |||||
<orderEntry type="library" name="Maven: javax.xml.bind:jaxb-api:2.3.1" level="project" /> | <orderEntry type="library" name="Maven: javax.xml.bind:jaxb-api:2.3.1" level="project" /> | ||||
<orderEntry type="library" name="Maven: javax.activation:javax.activation-api:1.2.0" level="project" /> | <orderEntry type="library" name="Maven: javax.activation:javax.activation-api:1.2.0" level="project" /> | ||||
<orderEntry type="library" name="Maven: org.springframework.boot:spring-boot-starter-data-redis:2.5.15" level="project" /> | <orderEntry type="library" name="Maven: org.springframework.boot:spring-boot-starter-data-redis:2.5.15" level="project" /> | ||||
@@ -95,6 +98,8 @@ | |||||
<orderEntry type="library" name="Maven: org.reactivestreams:reactive-streams:1.0.4" level="project" /> | <orderEntry type="library" name="Maven: org.reactivestreams:reactive-streams:1.0.4" level="project" /> | ||||
<orderEntry type="library" name="Maven: org.apache.commons:commons-pool2:2.9.0" level="project" /> | <orderEntry type="library" name="Maven: org.apache.commons:commons-pool2:2.9.0" level="project" /> | ||||
<orderEntry type="library" name="Maven: eu.bitwalker:UserAgentUtils:1.21" level="project" /> | <orderEntry type="library" name="Maven: eu.bitwalker:UserAgentUtils:1.21" level="project" /> | ||||
<orderEntry type="library" name="Maven: javax.servlet:javax.servlet-api:4.0.1" level="project" /> | |||||
<orderEntry type="library" name="Maven: com.itextpdf:itextpdf:5.5.13.2" level="project" /> | |||||
<orderEntry type="library" name="Maven: com.itextpdf:itext-asian:5.2.0" level="project" /> | |||||
<orderEntry type="library" name="Maven: cn.hutool:hutool-all:5.5.4" level="project" /> | |||||
</component> | </component> | ||||
</module> | </module> |