上传的文件存放在硬盘上面,不直接存放到数据库中,数据库中只存放文件的相对路径。通过配置虚拟路径,允许前端访问服务器硬盘上面某个指定文件夹下面的文件。
比如,将前端传过来的文件存放在服务器上面的 D:/mm/imgs文件夹下面,同时配置虚拟路径/upLoadImg,对应D:/mm/imgs文件夹。则当想访问D:/mm/imgs文件夹下面的123.jpg时,就可以在浏览器中输入:http://ip:端口/context-path/uploadImg/123.jpg来访问。
# 配置上传图片的虚拟路径
live.picture.url=/live_picture/**
live.picture.location=D:/rpm/imgs/
/**
* 配置虚拟路径
*/
@Configuration
public class UploadFileConfig implements WebMvcConfigurer {
private Logger logger = LoggerFactory.getLogger(this.getClass());
@Value("${live.picture.url}")
private String url;
@Value("${live.picture.location}")
private String location;
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
logger.debug("url = {}, location = {}", url, location);
registry.addResourceHandler(url).addResourceLocations("file:" + location);
}
}
文件怎样分布,希望文件能随机分布在某个指定文件夹下面的各个子文件夹里面,这里使用的方案是传智播客视频里面某位老师讲的一种方法。先用文件名加上uuid组成一个字符串,然后求该字符串的hashcode(1个int值),然后求这个hashcode的16进制字符串(最长是8个字符,因为1个字节是2个16进制字符),然后根据16进制字符串获取路径,假设16进制字符串位a012,则路径位a/0/1/2/。
/**
* 根据文件名获取hashCode生成的路径
* @param fileName 文件名
*/
private String getHashCodePathByFileName(String fileName){
// 生成的字符串最长也只可能是8个字符,1个字节是2个字符,比如说10对应的就是 00 00 00 0A
String hashStr = Integer.toHexString(fileName.hashCode());
StringBuilder sb = new StringBuilder();
for(int i = 0; i < hashStr.length(); i++){
sb.append(hashStr.charAt(i));
sb.append("/");
}
return sb.toString();
}
数据库中只存放文件的相对路径
/**
* 向数据库中添加上传图片信息
* @param basicInfoId id
* @param fileName 文件名
*/
private void addUploadImgBean(int basicInfoId, String fileName, String suffix) {
UploadImgBean uploadImgBean = new UploadImgBean();
uploadImgBean.setBasicInfoId(basicInfoId);
uploadImgBean.setFileName(fileName + "." + suffix);
uploadImgBean.setUrl(getHashCodePathByFileName(fileName) + fileName + "." + suffix);
uploadImgMapper.addUploadImg(uploadImgBean);
}
Controller中的代码
/**
* 上传图片
* @param basicInfoId basicInfoId
* @param multipartFiles 上传过来的文件
*/
@PostMapping("/live/img")
public void upload(int basicInfoId, @RequestParam("file")MultipartFile[] multipartFiles){
uploadImgService.uploadImgs(multipartFiles, basicInfoId);
}
Service中的代码
@Service
public class UploadImgService {
private Logger logger = LoggerFactory.getLogger(this.getClass());
@Value("${live.picture.location}")
private String parentDirPath;
@SuppressWarnings("SpringJavaInjectionPointsAutowiringInspection")
@Autowired
private UploadImgMapper uploadImgMapper;
/**
* 上传图片
* @param multipartFiles 前端传递过来的文件组成的数组
*/
public void uploadImgs(MultipartFile[] multipartFiles, int basicInfoId){
if(multipartFiles == null || multipartFiles.length == 0){
return;
}
for(MultipartFile multipartFile : multipartFiles){
if(multipartFile.isEmpty()){
continue;
}
String originalFileName = multipartFile.getOriginalFilename();
String[] strArr = originalFileName.split("\\.");
String fileName = strArr[0] + "_" + UUIDUtils.generateUUID();
String suffix = strArr[1];
if(! ("jpg".equals(suffix) || "png".equals(suffix) || "gif".equals(suffix) || "jpeg".equals(suffix))){
throw new UploadImgException(ResultEnum.UPLOAD_IMG_FORMAT_INVALID.getCode(),
ResultEnum.UPLOAD_IMG_FORMAT_INVALID.getMsg());
}
File destFile = generateFileByFileName(fileName, suffix);
try {
multipartFile.transferTo(destFile);//写入硬盘的文件中
addUploadImgBean(basicInfoId, fileName, suffix);//将相对路径保存到数据库中
} catch (IOException e) {
e.printStackTrace();
logger.debug(e.toString());
}
}
}
/**
* 根据basicInfoId查询上传的图片信息
* @param basicInfoId id
* @return 给定basicInfoId下面的所有上传图片信息
*/
public List<UploadImgBean> getUploadImgBean(int basicInfoId){
return uploadImgMapper.getUploadImgBeansByBasicInfoId(basicInfoId);
}
/**
* 根据图片id删除上传的图片
* @param id 图片id
*/
public void deleteUploadImg(int id){
UploadImgBean uploadImgBean = uploadImgMapper.getUploadImgBeanById(id);
//删除硬盘上面的文件
File file = new File(this.parentDirPath + uploadImgBean.getUrl());
file.delete();
//删除数据库中存储的信息
uploadImgMapper.deleteUploadImgBeanById(id);
}
/**
* 向数据库中添加上传图片信息
* @param basicInfoId id
* @param fileName 文件名
*/
private void addUploadImgBean(int basicInfoId, String fileName, String suffix) {
UploadImgBean uploadImgBean = new UploadImgBean();
uploadImgBean.setBasicInfoId(basicInfoId);
uploadImgBean.setFileName(fileName + "." + suffix);
uploadImgBean.setUrl(getHashCodePathByFileName(fileName) + fileName + "." + suffix);
uploadImgMapper.addUploadImg(uploadImgBean);
}
/**
* 根据文件名生成文件,文件是放在随机生成的文件夹下面的
* @param fileName 文件名
* @param suffix 文件后缀
*/
private File generateFileByFileName(String fileName, String suffix){
// 生成的字符串最长也只可能是8个字符,1个字节是2个字符,比如说10对应的就是 00 00 00 0A
StringBuilder sb = new StringBuilder();
sb.append(this.parentDirPath);
sb.append(getHashCodePathByFileName(fileName));
File dir = new File(sb.toString());
if(! dir.exists()){
dir.mkdirs();
}
File file = new File(dir, fileName + "." + suffix);
if(! file.exists()){
try {
file.createNewFile();
} catch (IOException e) {
e.printStackTrace();
}
}
return file;
}
/**
* 根据文件名获取hashCode生成的路径
* @param fileName 文件名
*/
private String getHashCodePathByFileName(String fileName){
// 生成的字符串最长也只可能是8个字符,1个字节是2个字符,比如说10对应的就是 00 00 00 0A
String hashStr = Integer.toHexString(fileName.hashCode());
StringBuilder sb = new StringBuilder();
for(int i = 0; i < hashStr.length(); i++){
sb.append(hashStr.charAt(i));
sb.append("/");
}
return sb.toString();
}
}