fix: 更改文件上传和存储方式

This commit is contained in:
萌狼蓝天 2024-11-12 16:57:38 +08:00
parent 98eea20060
commit ef1164f04c
19 changed files with 344 additions and 91 deletions

View File

@ -1,6 +0,0 @@
package com.guaiguailang.harmony.constant;
public class FileUploadFolder {
public static final String USER_AVATER_FOLDER = "userAvatar";
public static final String ACTIVITY_FOLDER = "activity";
}

View File

@ -0,0 +1,8 @@
package com.guaiguailang.harmony.constant;
public class SystemConfigKey {
public static final String SYS_CONFIG_URL_BACK = "back_url";
public static final String SYS_CONFIG_URL_FRONT = "front_url";
public static final String SYS_FILE_SAVE_PATH = "file_save";
}

View File

@ -0,0 +1,4 @@
package com.guaiguailang.harmony.controller;
public class ActivateController {
}

View File

@ -2,15 +2,17 @@ package com.guaiguailang.harmony.controller;
import cn.dev33.satoken.stp.StpUtil;
import com.guaiguailang.harmony.domain.vo.ResponseResult;
import com.guaiguailang.harmony.service.ActivateService;
import com.guaiguailang.harmony.service.FileService;
import com.guaiguailang.harmony.service.UserService;
import com.guaiguailang.harmony.utils.FileUpload;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.core.io.Resource;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
@Tag(name="文件上传接口")
@ -21,7 +23,10 @@ public class UploadController {
@Autowired
private UserService userService;
@Autowired
private ActivateService activateService;
@Autowired
private FileService fileService;
/**
* 修改用户头像
@ -40,5 +45,32 @@ public class UploadController {
}
return ResponseResult.success(imgUrl);
}
/**
* 上传活动头图
* @param file
* @return
*/
@Operation(summary = "活动 头图")
@PostMapping("/activate/profile")
public ResponseResult uploadActivateProfile(@RequestParam("file") MultipartFile file){
if(file.isEmpty()){
return ResponseResult.error("图片为空,请重新选择");
}
String imgUrl = activateService.uploadActivateProfile(file);
if(imgUrl==null){
return ResponseResult.error("图片上传失败");
}
return ResponseResult.success(imgUrl);
}
// 编写Controller 实现根据md5值获取文件
/**
* 根据文件的 MD5 值获取文件的访问路径
* @param fileMd5 文件的 MD5
* @return 文件的访问路径
*/
@Operation(summary = "根据文件的 MD5 值获取文件的访问路径")
@GetMapping("/{fileMd5}")
public ResponseEntity<Resource> getFilePathByMd5(@PathVariable ("fileMd5") String fileMd5) {
return fileService.getFileObj(fileMd5);
}
}

View File

@ -0,0 +1,47 @@
package com.guaiguailang.harmony.domain.entity;
public class SystemConfig {
private long id;
private String key;
private String value;
private String description;
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
public String getKey() {
return key;
}
public void setKey(String key) {
this.key = key;
}
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
}

View File

@ -0,0 +1,18 @@
package com.guaiguailang.harmony.domain.entity;
import lombok.Data;
@Data
public class SystemFile {
private long id;
private String fileName;
private String fileType;
private double fileSize;
private String fileMd5;
private String plate;
private String description;
private String path;
private String url;
}

View File

@ -0,0 +1,13 @@
package com.guaiguailang.harmony.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.guaiguailang.harmony.domain.entity.SystemConfig;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Select;
@Mapper
public interface ConfigMapper extends BaseMapper<SystemConfig> {
@Select("SELECT `value` from system_config where `key`=#{key}")
String getKeyValue(String key);
}

View File

@ -0,0 +1,20 @@
package com.guaiguailang.harmony.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.guaiguailang.harmony.domain.entity.SystemFile;
import org.apache.ibatis.annotations.Insert;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select;
@Mapper
public interface FileMapper extends BaseMapper<SystemFile> {
@Select("select * from system_file where `file_md5`=#{md5}")
SystemFile getFileByMd5(String md5);
@Insert("INSERT INTO system_file (`id`, `file_name`, `file_type`, `file_size`, `file_md5`, `plate`, `description`, `path`, `url`) " +
"VALUES (#{id}, #{fileName}, #{ext}, #{fileSize}, #{md5}, #{plate}, #{description}, #{filePath}, #{url})")
void save(@Param("id") long id, @Param("fileName") String fileName, @Param("ext") String ext, @Param("fileSize") double fileSize,
@Param("md5") String md5, @Param("plate") String plate, @Param("description") String description,
@Param("filePath") String filePath, @Param("url") String url);
}

View File

@ -5,10 +5,7 @@ import com.guaiguailang.harmony.domain.dto.ParamUserAdd;
import com.guaiguailang.harmony.domain.entity.SystemRole;
import com.guaiguailang.harmony.domain.entity.UserInfo;
import com.guaiguailang.harmony.domain.vo.UserListNum;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select;
import org.apache.ibatis.annotations.Update;
import org.apache.ibatis.annotations.*;
import java.util.List;
import java.util.Map;
@ -44,4 +41,6 @@ public interface UserMapper extends BaseMapper<UserInfo> {
Integer changeDelete(Long id);
@Update("update user_info set name=#{name},email=#{email},telephone=#{telephone} where id=#{id}")
Integer selfUpdateUserInfo(Long id, String name, String email, String telephone);
@Update("UPDATE user_info set avatar=#{url} where id=#{uid}")
void updateUserAvatar(Long uid, String url);
}

View File

@ -0,0 +1,7 @@
package com.guaiguailang.harmony.service;
import org.springframework.web.multipart.MultipartFile;
public interface ActivateService {
String uploadActivateProfile(MultipartFile file);
}

View File

@ -0,0 +1,8 @@
package com.guaiguailang.harmony.service;
import org.springframework.core.io.Resource;
import org.springframework.http.ResponseEntity;
public interface FileService {
ResponseEntity<Resource> getFileObj(String fileMd5);
}

View File

@ -0,0 +1,18 @@
package com.guaiguailang.harmony.service.impl;
import com.guaiguailang.harmony.service.ActivateService;
import com.guaiguailang.harmony.utils.FileUpload;
import com.guaiguailang.harmony.utils.UtilMD5;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;
@Service
public class ActivateServiceImpl implements ActivateService {
@Autowired
private FileUpload fileUpload;
@Override
public String uploadActivateProfile(MultipartFile file) {
return fileUpload.uploadFile(file,file.getName(),"activate","活动头图");
}
}

View File

@ -1,7 +1,6 @@
package com.guaiguailang.harmony.service.impl;
import cn.dev33.satoken.stp.StpUtil;
import cn.dev33.satoken.util.SaResult;
import com.github.yitter.idgen.YitIdHelper;
import com.guaiguailang.harmony.domain.dto.ParamLogin;
import com.guaiguailang.harmony.domain.entity.SystemRole;

View File

@ -0,0 +1,40 @@
package com.guaiguailang.harmony.service.impl;
import com.guaiguailang.harmony.domain.entity.SystemFile;
import com.guaiguailang.harmony.mapper.FileMapper;
import com.guaiguailang.harmony.service.FileService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.FileSystemResource;
import org.springframework.core.io.Resource;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
@Service
public class FileServiceImpl implements FileService {
@Autowired
private FileMapper fileMapper;
@Override
public ResponseEntity<Resource> getFileObj(String fileMd5) {
SystemFile systemFile = fileMapper.getFileByMd5(fileMd5);
if (systemFile == null) {
return ResponseEntity.notFound().build();
}
String realAddress = systemFile.getPath(); // 真实的文件存储地址
Resource resource = new FileSystemResource(realAddress);
if (resource.exists() && resource.isReadable()) {
return ResponseEntity.ok()
.header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"" + systemFile.getFileName() + "\"")
.contentType(MediaType.APPLICATION_OCTET_STREAM)
.body(resource);
} else {
return ResponseEntity.status(HttpStatus.NOT_FOUND).build();
}
}
}

View File

@ -3,7 +3,6 @@ package com.guaiguailang.harmony.service.impl;
import cn.dev33.satoken.stp.StpUtil;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.github.yitter.idgen.YitIdHelper;
import com.guaiguailang.harmony.constant.FileUploadFolder;
import com.guaiguailang.harmony.domain.dto.ParamUserAdd;
import com.guaiguailang.harmony.domain.dto.ParamUserList;
import com.guaiguailang.harmony.domain.entity.*;
@ -309,19 +308,10 @@ return ResponseResult.error("删除失败");
*/
@Override
public String uploadUserAvater(MultipartFile file) {
// 获取用户获取用户信息
String url = fileUpload.uploadFile(file,file.getName(),"user","用户头像");
Long uid = Long.parseLong(StpUtil.getLoginId().toString());
UserInfo userInfo = userMapper.getUserById(uid);
// 调用文件上传工具类,传入文件保存到的文件夹文件名
//设置文件名是为了替换旧的头像文件
String imgUrl= fileUpload.uploadFile(file, FileUploadFolder.USER_AVATER_FOLDER,userInfo.getUsername());
if(imgUrl!=null) {
userInfo.setAvatar(imgUrl);
userMapper.updateById(userInfo);
log.info("头像上传成功:" + imgUrl);
return imgUrl;
}
return null;
userMapper.updateUserAvatar(uid,url);
return url;
}

View File

@ -1,6 +1,11 @@
package com.guaiguailang.harmony.utils;
import com.github.yitter.idgen.YitIdHelper;
import com.guaiguailang.harmony.constant.SystemConfigKey;
import com.guaiguailang.harmony.domain.entity.SystemFile;
import com.guaiguailang.harmony.mapper.ConfigMapper;
import com.guaiguailang.harmony.mapper.FileMapper;
import jakarta.servlet.ServletContext;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
@ -8,7 +13,11 @@ import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.security.MessageDigest;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.UUID;
/**
@ -17,20 +26,20 @@ import java.util.UUID;
@Component
public class FileUpload {
@Value("${server.servlet.context-path}")
private String contextPath;
@Value("${server.port}")
private String serverPort;
@Value("${server.address}")
private String serverAddress;
@Autowired
private ServletContext servletContext;
private ConfigMapper configMapper;
@Autowired
private FileMapper fileMapper;
public String uploadFile(MultipartFile file,String fileName,String plate,String description) {
// 校验文件是否重复
String md5 = UtilMD5.getFileMD5(file);
SystemFile systemFile = fileMapper.getFileByMd5(md5);
if(systemFile!=null){
return getAccessPath(md5);
}
// 没有上传过该文件继续操作
public String uploadFile(MultipartFile file, String folder) {
// 获取图片的原始名字
String originalFilename = file.getOriginalFilename();
@ -39,87 +48,78 @@ public class FileUpload {
}
// 获取文件的后缀和新文件名
String ext = "." + originalFilename.substring(originalFilename.lastIndexOf('.') + 1);
String uuid = UUID.randomUUID().toString().replace("-", "");
String fileName = uuid + ext;
String ext = "." + originalFilename.substring(originalFilename.lastIndexOf('.') + 1);// 扩展名
String saveFileName = md5 + ext;
// 构建目标文件路径
String pre = getResourcePath(folder);
String filePath = pre + fileName;
String pre = getResourcePath();
String filePath = pre + saveFileName;
// 获取文件大小单位MB
double fileSize = file.getSize() / (1024.0 * 1024.0);//MB
// 上传图片
try {
file.transferTo(new File(filePath));
String url = getAccessPath(md5);
// 返回访问链接
return getAccessPath(folder, fileName);
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
public String uploadFile(MultipartFile file, String folder, String fileName) {
// 获取图片的原始名字
String originalFilename = file.getOriginalFilename();
if (originalFilename == null || originalFilename.isEmpty()) {
throw new IllegalArgumentException("文件名不能为空");
}
// 获取文件的后缀和新文件名
String ext = "." + originalFilename.substring(originalFilename.lastIndexOf('.') + 1);
fileName = fileName + ext;
// 构建目标文件路径
String pre = getResourcePath(folder);
String filePath = pre + fileName;
// 上传图片
try {
file.transferTo(new File(filePath));
// 返回访问链接
return getAccessPath(folder, fileName);
fileMapper.save(YitIdHelper.nextId(),fileName,ext,fileSize,md5,plate,description,filePath,url);
return url;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
private String getResourcePath(String folder) {
/**
* 获取文件存储路径
* @return 文件存储路径末尾包含/
*/
/**
* 获取文件存储路径
* @return 文件存储路径末尾包含/
*/
private String getResourcePath() {
// 获取操作系统的名称
String osName = System.getProperty("os.name");
String win = "win";
// 获取项目的根目录
String projectRoot = System.getProperty("user.dir");
// 根据操作系统生成正确的路径
String staticPath;
// 获取当前日期的年份和月份
LocalDateTime now = LocalDateTime.now();
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy/MM");
String datePath = now.format(formatter);
// 保存地址
if (osName.toLowerCase().startsWith(win)) {
staticPath = projectRoot + "\\src\\main\\resources\\static\\" + folder + "\\";
staticPath = configMapper.getKeyValue(SystemConfigKey.SYS_FILE_SAVE_PATH) + "\\" + datePath.replace("/", "\\") + "\\";
} else {
staticPath = projectRoot + "/src/main/resources/static/" + folder + "/";
staticPath = configMapper.getKeyValue(SystemConfigKey.SYS_FILE_SAVE_PATH) + "/" + datePath + "/";
}
System.out.println("路径: " + staticPath);
// 如果目录不存在就创建目录
// 创建目录
File dir = new File(staticPath);
if (!dir.exists()) {
dir.mkdirs();
}
return staticPath;
}
private String getAccessPath(String folder, String fileName) {
// 构建访问路径
return "http://" + serverAddress + ":" + serverPort + contextPath + "static/" + folder + "/" + fileName;
/**
* 获取图片访问路径
* @param fileMd5 文件名(MD5)
* @return 文件在线访问路径
*/
public String getAccessPath(String fileMd5) {
String url;
if (System.getProperty("os.name").toLowerCase().startsWith("win")) {
url =configMapper.getKeyValue(SystemConfigKey.SYS_CONFIG_URL_BACK)+"\\upload\\"+fileMd5;
} else {
url =configMapper.getKeyValue(SystemConfigKey.SYS_CONFIG_URL_BACK)+"/upload/"+fileMd5;
}
return url;
}

View File

@ -0,0 +1,51 @@
package com.guaiguailang.harmony.utils;
import org.springframework.web.multipart.MultipartFile;
import java.io.FileInputStream;
import java.io.InputStream;
import java.security.MessageDigest;
public class UtilMD5 {
public static String getFileMD5(String filePath) {
try {
MessageDigest md5 = MessageDigest.getInstance("MD5");
FileInputStream fis = new FileInputStream(filePath);
byte[] buffer = new byte[1024];
int length;
while ((length = fis.read(buffer)) != -1) {
md5.update(buffer, 0, length);
}
byte[] digest = md5.digest();
StringBuilder sb = new StringBuilder();
for (byte b : digest) {
sb.append(Integer.toString((b & 0xFF) + 0x100, 16).substring(1));
}
return sb.toString();
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
// 新增的方法支持直接对 MultipartFile 获取 MD5
public static String getFileMD5(MultipartFile file) {
try {
MessageDigest md5 = MessageDigest.getInstance("MD5");
InputStream is = file.getInputStream();
byte[] buffer = new byte[1024];
int length;
while ((length = is.read(buffer)) != -1) {
md5.update(buffer, 0, length);
}
byte[] digest = md5.digest();
StringBuilder sb = new StringBuilder();
for (byte b : digest) {
sb.append(Integer.toString((b & 0xFF) + 0x100, 16).substring(1));
}
return sb.toString();
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
}

View File

@ -0,0 +1,5 @@
<?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.guaiguailang.harmony.mapper.ConfigMapper">
</mapper>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 834 KiB

After

Width:  |  Height:  |  Size: 43 KiB