main-business/pom.xml
@@ -28,7 +28,10 @@ <artifactId>poi-ooxml</artifactId> <version>5.2.3</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <!-- æ ¸å¿æ¨¡å--> <dependency> main-business/src/main/java/com/ruoyi/business/controller/AccountFileController.java
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,63 @@ package com.ruoyi.business.controller; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.ruoyi.business.entity.AccountFile; import com.ruoyi.business.service.AccountFileService; import com.ruoyi.common.core.domain.AjaxResult; import jakarta.annotation.Resource; import org.springframework.util.CollectionUtils; import org.springframework.web.bind.annotation.*; import java.util.List; /** * è´¢å¡éä»¶ */ @RestController @RequestMapping("/account/accountFile") public class AccountFileController { @Resource private AccountFileService accountFileService; /** * æ°å¢ * @param accountFile * @return */ @PostMapping("/add") public AjaxResult add(@RequestBody AccountFile accountFile) { return AjaxResult.success(accountFileService.save(accountFile)); } /** * å é¤ * @param ids * @return */ @DeleteMapping("/del") public AjaxResult delAccountFile(@RequestBody List<Integer> ids) { if(CollectionUtils.isEmpty(ids)){ return AjaxResult.error("è¯·éæ©è³å°ä¸æ¡æ°æ®"); } //å 餿£éªéä»¶ return AjaxResult.success(accountFileService.removeBatchByIds(ids)); } /** *å页æ¥è¯¢ * @param page * @param accountFile * @return */ @GetMapping("/listPage") public AjaxResult accountFileListPage(Page page, AccountFile accountFile) { return AjaxResult.success(accountFileService.accountFileListPage(page, accountFile)); } } main-business/src/main/java/com/ruoyi/business/entity/AccountFile.java
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,67 @@ package com.ruoyi.business.entity; import com.baomidou.mybatisplus.annotation.*; import io.swagger.annotations.ApiModelProperty; import jakarta.validation.constraints.NotBlank; import lombok.Data; import java.io.Serializable; import java.time.LocalDateTime; /** * è´¢å¡ç®¡ç--éä»¶ * account_file */ @TableName(value = "account_file") @Data public class AccountFile implements Serializable { private static final long serialVersionUID = 1L; /** * åºå· */ @TableId(type = IdType.AUTO) private Long id; @ApiModelProperty(value = "æä»¶åç§°") private String name; @ApiModelProperty(value = "æä»¶è·¯å¾") private String url; @ApiModelProperty(value = "æä»¶å¤§å°") private int fileSize; @ApiModelProperty(value = "è´¢å¡ID") @NotBlank(message = "è´¢å¡idä¸è½ä¸ºç©º!") private Long accountId; /** * ç±»å(æ¶å ¥/æ¯åº) */ @ApiModelProperty(value = "ç±»å(æ¶å ¥/æ¯åº)") private String accountType; @ApiModelProperty(value = "å建æ¶é´") @TableField(fill = FieldFill.INSERT) private LocalDateTime createTime; @ApiModelProperty(value = "ä¿®æ¹æ¶é´") @TableField(fill = FieldFill.INSERT_UPDATE) private LocalDateTime updateTime; @ApiModelProperty(value = "åå»ºç¨æ·") @TableField(fill = FieldFill.INSERT) private Integer createUser; @ApiModelProperty(value = "ä¿®æ¹ç¨æ·") @TableField(fill = FieldFill.INSERT_UPDATE) private Integer updateUser; @ApiModelProperty(value = "ç§æ·ID") @TableField(fill = FieldFill.INSERT) private Long tenantId; } main-business/src/main/java/com/ruoyi/business/mapper/AccountFileMapper.java
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,15 @@ package com.ruoyi.business.mapper; import com.baomidou.mybatisplus.core.mapper.BaseMapper; import com.baomidou.mybatisplus.core.metadata.IPage; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.ruoyi.business.entity.AccountFile; import org.apache.ibatis.annotations.Mapper; import org.apache.ibatis.annotations.Param; @Mapper public interface AccountFileMapper extends BaseMapper<AccountFile> { IPage<AccountFile> accountFileListPage(Page page, @Param("accountFile") AccountFile accountFile); } main-business/src/main/java/com/ruoyi/business/other/controller/TempFileController.java
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,32 @@ package com.ruoyi.business.other.controller; import com.ruoyi.business.other.service.TempFileService; import com.ruoyi.common.core.domain.AjaxResult; import lombok.AllArgsConstructor; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import org.springframework.web.multipart.MultipartFile; @RestController @RequestMapping("/file") @AllArgsConstructor public class TempFileController { private TempFileService tempFileService; @PostMapping("/upload") public AjaxResult uploadFile(MultipartFile file, Integer type) { try { return AjaxResult.success(tempFileService.uploadFile(file, type)); } catch (Exception e) { return AjaxResult.error(e.getMessage()); } } } main-business/src/main/java/com/ruoyi/business/other/mapper/CommonFileMapper.java
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,9 @@ package com.ruoyi.business.other.mapper; import com.baomidou.mybatisplus.core.mapper.BaseMapper; import com.ruoyi.business.other.pojo.CommonFile; public interface CommonFileMapper extends BaseMapper<CommonFile> { } main-business/src/main/java/com/ruoyi/business/other/mapper/TempFileMapper.java
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,9 @@ package com.ruoyi.business.other.mapper; import com.baomidou.mybatisplus.core.mapper.BaseMapper; import com.ruoyi.business.other.pojo.TempFile; public interface TempFileMapper extends BaseMapper<TempFile> { } main-business/src/main/java/com/ruoyi/business/other/pojo/CommonFile.java
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,40 @@ package com.ruoyi.business.other.pojo; import com.baomidou.mybatisplus.annotation.*; import lombok.Data; import java.time.LocalDateTime; /** * éç¨éä»¶ä¸ä¼ 表 */ @Data @TableName("common_file") public class CommonFile { private static final long serialVersionUID = 1L; @TableId(type = IdType.AUTO) private Long id; /** å ³è表主é®D */ private Long commonId; /** æä»¶åç§° */ private String name; /** æä»¶è·¯å¾ */ private String url; /** å ³è表 */ private Integer type; /** å建æ¶é´ */ @TableField(fill = FieldFill.INSERT) private LocalDateTime createTime; /** æ´æ°æ¶é´ */ @TableField(fill = FieldFill.INSERT_UPDATE) private LocalDateTime updateTime; } main-business/src/main/java/com/ruoyi/business/other/pojo/TempFile.java
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,20 @@ package com.ruoyi.business.other.pojo; import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableName; import lombok.Data; import java.time.LocalDateTime; @Data @TableName("temp_file") public class TempFile { private static final long serialVersionUID = 1L; @TableId private String tempId; // ä¸´æ¶æä»¶IDï¼UUIDï¼ private String originalName; // åå§æä»¶å private String tempPath; // 临æ¶åå¨è·¯å¾ private LocalDateTime expireTime; // è¿ææ¶é´ private Integer type; // å ³è表类å } main-business/src/main/java/com/ruoyi/business/other/service/TempFileService.java
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,11 @@ package com.ruoyi.business.other.service; import com.ruoyi.business.other.pojo.TempFile; import org.springframework.web.multipart.MultipartFile; import java.io.IOException; public interface TempFileService { TempFile uploadFile(MultipartFile file, Integer type) throws IOException; } main-business/src/main/java/com/ruoyi/business/other/service/impl/TempFileServiceImpl.java
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,183 @@ package com.ruoyi.business.other.service.impl; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.ruoyi.business.other.mapper.CommonFileMapper; import com.ruoyi.business.other.mapper.TempFileMapper; import com.ruoyi.business.other.pojo.CommonFile; import com.ruoyi.business.other.pojo.TempFile; import com.ruoyi.business.other.service.TempFileService; import com.ruoyi.common.utils.StringUtils; import lombok.extern.slf4j.Slf4j; import org.apache.commons.io.FilenameUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.scheduling.annotation.Scheduled; import org.springframework.stereotype.Service; import org.springframework.web.multipart.MultipartFile; import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; import java.nio.file.StandardCopyOption; import java.time.LocalDate; import java.time.LocalDateTime; import java.time.format.DateTimeFormatter; import java.util.List; import java.util.UUID; @Service @Slf4j public class TempFileServiceImpl extends ServiceImpl<TempFileMapper, TempFile> implements TempFileService { @Autowired private TempFileMapper tempFileMapper; @Autowired private CommonFileMapper commonFileMapper; @Value("${file.upload-dir}") private String uploadDir; @Value("${file.temp-dir}") private String tempDir; // ä¸ä¼ å°ä¸´æ¶ç®å½ @Override public TempFile uploadFile(MultipartFile file,Integer type) throws IOException { // 1. çæä¸´æ¶æä»¶IDåè·¯å¾ String tempId = UUID.randomUUID().toString(); String originalFilename = file.getOriginalFilename(); if(originalFilename == null) throw new IOException("æä»¶åä¸è½ä¸ºç©º"); // URLEncoder urlEncoder = new URLEncoder(); // String encodedFilename = urlEncoder.encode(originalFilename, StandardCharsets.UTF_8); // encodedFilename = encodedFilename.replaceAll("%2E","."); // Path tempFilePath = Paths.get(tempDir, tempId + "_" + encodedFilename); Path tempFilePath = Paths.get(tempDir, tempId + "_" + file.getOriginalFilename()); // 2. ç¡®ä¿ç®å½åå¨ Path parentDir = tempFilePath.getParent(); if (parentDir != null && !Files.exists(parentDir)) { try { // éå½å建ç®å½å¹¶æ£æ¥ç»æ Files.createDirectories(parentDir); } catch (IOException e) { log.error("å建ç®å½å¤±è´¥: {}", parentDir, e); throw new IOException("æ æ³å建ç®å½: " + parentDir, e); } } // if (parentDir != null) { // Files.createDirectories(parentDir); // éå½å建ç®å½ // } // 3. ä¿åæä»¶å°ä¸´æ¶ç®å½ file.transferTo(tempFilePath.toFile()); // 4. ä¿åä¸´æ¶æä»¶è®°å½ TempFile tempFileRecord = new TempFile(); tempFileRecord.setTempId(tempId); tempFileRecord.setOriginalName(file.getOriginalFilename()); tempFileRecord.setTempPath(tempFilePath.toString()); tempFileRecord.setExpireTime(LocalDateTime.now().plusHours(2)); // 2å°æ¶åè¿æ tempFileRecord.setType(type); tempFileMapper.insert(tempFileRecord); return tempFileRecord; } /** * å°ä¸´æ¶æä»¶è¿ç§»å°æ£å¼ç®å½ * * @param businessId ä¸å¡IDï¼éå®å°è´¦IDï¼ * @param tempFileIds ä¸´æ¶æä»¶IDå表 * @param fileType æä»¶ç±»å(æ¥èªFileNameType) * @throws IOException æä»¶æä½å¼å¸¸ */ public void migrateTempFilesToFormal(Long businessId, List<String> tempFileIds, Integer fileType) throws IOException { if (com.baomidou.mybatisplus.core.toolkit.CollectionUtils.isEmpty(tempFileIds)) { return; } // æå»ºæ£å¼ç®å½è·¯å¾ï¼æä¸å¡ç±»å忥æåç»ï¼ String formalDir = uploadDir + LocalDate.now().format(DateTimeFormatter.ISO_LOCAL_DATE); Path formalDirPath = Paths.get(formalDir); // ç¡®ä¿æ£å¼ç®å½åå¨ï¼éå½åå»ºï¼ if (!Files.exists(formalDirPath)) { Files.createDirectories(formalDirPath); } for (String tempFileId : tempFileIds) { // æ¥è¯¢ä¸´æ¶æä»¶è®°å½ TempFile tempFile = tempFileMapper.selectById(tempFileId); if (tempFile == null) { log.warn("ä¸´æ¶æä»¶ä¸åå¨ï¼è·³è¿å¤ç: {}", tempFileId); continue; } // æå»ºæ£å¼æä»¶åï¼å å«ä¸å¡IDåæ¶é´æ³ï¼é¿å å²çªï¼ String originalFilename = tempFile.getOriginalName(); String fileExtension = FilenameUtils.getExtension(originalFilename); String formalFilename = businessId + "_" + System.currentTimeMillis() + "_" + UUID.randomUUID().toString().substring(0, 8) + (StringUtils.hasText(fileExtension) ? "." + fileExtension : ""); Path formalFilePath = formalDirPath.resolve(formalFilename); try { // æ§è¡æä»¶è¿ç§»ï¼ä½¿ç¨ååæä½ç¡®ä¿å®å ¨æ§ï¼ Files.move( Paths.get(tempFile.getTempPath()), formalFilePath, StandardCopyOption.REPLACE_EXISTING, StandardCopyOption.ATOMIC_MOVE ); log.info("æä»¶è¿ç§»æå: {} -> {}", tempFile.getTempPath(), formalFilePath); // æ´æ°æä»¶è®°å½ï¼å ³èå°ä¸å¡IDï¼ CommonFile fileRecord = new CommonFile(); fileRecord.setCommonId(businessId); fileRecord.setName(originalFilename); fileRecord.setUrl(formalFilePath.toString()); fileRecord.setCreateTime(LocalDateTime.now()); fileRecord.setType(fileType); commonFileMapper.insert(fileRecord); // å é¤ä¸´æ¶æä»¶è®°å½ tempFileMapper.deleteById(tempFile); log.info("æä»¶è¿ç§»æå: {} -> {}", tempFile.getTempPath(), formalFilePath); } catch (IOException e) { log.error("æä»¶è¿ç§»å¤±è´¥: {}", tempFile.getTempPath(), e); // å¯éæ©åæ»äºå¡æè®°å½å¤±è´¥æä»¶ throw new IOException("æä»¶è¿ç§»å¼å¸¸", e); } } } @Scheduled(cron = "0 0 3 * * ?") // æ¯å¤©åæ¨3ç¹æ§è¡ public void cleanupExpiredTempFiles() { LambdaQueryWrapper<TempFile> wrapper = new LambdaQueryWrapper<>(); wrapper.lt(TempFile::getExpireTime, LocalDateTime.now()); // expireTime < å½åæ¶é´ List<TempFile> expiredFiles = tempFileMapper.selectList(wrapper); for (TempFile file : expiredFiles) { try { // å é¤ç©çæä»¶ Files.deleteIfExists(Paths.get(file.getTempPath())); // å 餿°æ®åºè®°å½ tempFileMapper.deleteById(file); log.info("å·²æ¸ çè¿æä¸´æ¶æä»¶: {}", file.getTempPath()); } catch (IOException e) { log.error("å é¤æä»¶å¤±è´¥: {}", file.getTempPath(), e); // å¯éæ©è®°å½å¤±è´¥æ¥å¿æéè¯ } } log.info("è¿æä¸´æ¶æä»¶æ¸ ç宿ï¼å ±æ¸ ç {} 个æä»¶", expiredFiles.size()); } } main-business/src/main/java/com/ruoyi/business/service/AccountFileService.java
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,14 @@ package com.ruoyi.business.service; import com.baomidou.mybatisplus.core.metadata.IPage; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.baomidou.mybatisplus.extension.service.IService; import com.ruoyi.business.entity.AccountFile; public interface AccountFileService extends IService<AccountFile> { IPage<AccountFile> accountFileListPage(Page page, AccountFile accountFile); } main-business/src/main/java/com/ruoyi/business/service/impl/AccountFileServiceImpl.java
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,25 @@ package com.ruoyi.business.service.impl; import com.baomidou.mybatisplus.core.metadata.IPage; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.ruoyi.business.entity.AccountFile; import com.ruoyi.business.mapper.AccountFileMapper; import com.ruoyi.business.service.AccountFileService; import lombok.AllArgsConstructor; import org.springframework.stereotype.Service; @AllArgsConstructor @Service public class AccountFileServiceImpl extends ServiceImpl<AccountFileMapper, AccountFile> implements AccountFileService { private AccountFileMapper accountFileMapper; @Override public IPage<AccountFile> accountFileListPage(Page page, AccountFile accountFile) { return accountFileMapper.accountFileListPage(page,accountFile); } } main-business/src/main/resources/mapper/AccountFileMapper.xml
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,20 @@ <?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" > <mapper namespace="com.ruoyi.business.mapper.AccountFileMapper"> <select id="accountFileListPage" resultType="com.ruoyi.business.entity.AccountFile"> SELECT * FROM account_file where 1=1 <if test="accountFile.accountId != null and accountFile.accountId != ''"> AND account_id = #{accountFile.accountId} </if> <if test="accountFile.name != null and accountFile.name != '' "> AND name = #{accountFile.name} </if> <if test="accountFile.accountType != null and accountFile.accountType != '' "> AND account_type = #{accountFile.accountType} </if> </select> </mapper>