图像上传功能优化

优化之前的图片上传模块

控制层代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
/** 设置上传文件的最大值 10MB */
public static final int MAX_AVATAR_SIZE = 10*1024*1024;
/** 设置允许接收的文件类型 */
public static final List<String> AVATAR_TYPE = new ArrayList<>();
static {
AVATAR_TYPE.add("image/jpeg");
AVATAR_TYPE.add("image/png");
AVATAR_TYPE.add("image/bmp");
AVATAR_TYPE.add("image/gif");
}


/**
* MultiPartFile是SpringMVC提供的一个接口,这个接口为我们包装了获取文件类型的数据,任何类型的File都可以接受
* SpringBoot整合了SpringMVC,只需要在处理请求的方法参数列表上申明一个MultiPartFile的参数
* SpringBoot会自定将接受的文件数据赋值给这个参数
* @param file
* @param session
* @return
*/
@RequestMapping("/alert_avatar")
public JsonResult<String> alertAvatar(MultipartFile file,HttpSession session){
if(file==null){
System.out.println("=============");
throw new FileEmptyException("文件为空异常");
}
if(file.getSize()>MAX_AVATAR_SIZE){
throw new FileSizeException("文件超出大小限制");
}
if(!AVATAR_TYPE.contains(file.getContentType())){
throw new FileTypeException("文件类型错误");
}
//规定文件存储路径 .../upload/xxx.xx
String parent = session.getServletContext().getRealPath("upload");
File dir = new File(parent);
//parent文件夹不存在则创建
if(!dir.exists()){
dir.mkdirs();
}
//获取文件名称
String fileName = file.getOriginalFilename();
String[] splits = fileName.split("\\.");
//文件后缀
String suffix = splits[splits.length-1];
//生成随机的文件名(为避免不同用户文件名重复导致数据被覆盖丢失
String uuid = UUID.randomUUID().toString().toUpperCase();
String newFileName = uuid+"."+suffix; //新的文件名
System.out.println(newFileName);
//存储路径
File dest = new File(dir,newFileName);
try {
file.transferTo(dest);
} catch (IOException e) {
throw new FileUploadIOException("文件读写错误");
}

Integer uid = getUidFromSession(session);
System.out.println(dest.getPath());
String avatar = "/upload/"+newFileName;
userService.alertAvatar(uid,avatar);

userService.alertAvatar(uid,avatar);
return new JsonResult<>(OK,"用户头像修改成功",avatar);
}

用户图像在数据库中存在的形式

image-20230815105556661

获取根目录路径方式

1
String parent = session.getServletContext().getRealPath("upload");

存在问题

通过上面方式获取的图像目录路径在SpringBoot内嵌环境下拿到的是其内嵌Tomcat的临时文件路径,每次启动项目,Tomcat都会创建一个新的临时文件夹,从而导致当前登录无法获取历史上传图像路径

问题分析

SpringBoot启动后,会将COMMON_DOC_ROOTS设置成以下三个位置,如果这三个位置找不到,则会创建临时目录地址

1
private static final String[] COMMON_DOC_ROOTS = { "src/main/webapp", "public","static" };

SpringBoot 内嵌 Tomcat创建的临时目录

image-20230815110643974

解决方法一:手动指定存储路径

1.手动指定固定磁盘路劲去存储文件,不使用String parent = session.getServletContext().getRealPath("upload");而使用固定路径String parent = "G:/upload/";

2.定制对应的配置类,配置Tomacat虚拟目录

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
package com.bang.store.configure;

import com.bang.store.interceptor.LoginInterceptor;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

import java.util.ArrayList;
import java.util.List;

//注解,让SpringBoot识别
@Configuration
public class LoginInterceptorConfigure implements WebMvcConfigurer {

@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
/** 更改配置SpringBoot文件上传虚拟目录 */
registry.addResourceHandler("/upload/**").addResourceLocations("file:G:/upload/");
}
}

注意事项

  • addResourceLocations("file:G:/upload/")里面的参数必须要写成"file:+路径"的形式,该路径为你上传图片存储的位置
  • addResourceLocations("file:G:/upload/")路径最后面的斜杠必须加

3.控制层代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
/** 设置上传文件的最大值 10MB */
public static final int MAX_AVATAR_SIZE = 10*1024*1024;
/** 设置允许接收的文件类型 */
public static final List<String> AVATAR_TYPE = new ArrayList<>();
static {
AVATAR_TYPE.add("image/jpeg");
AVATAR_TYPE.add("image/png");
AVATAR_TYPE.add("image/bmp");
AVATAR_TYPE.add("image/gif");
}

/**
* MultiPartFile是SpringMVC提供的一个接口,这个接口为我们包装了获取文件类型的数据,任何类型的File都可以接受
* SpringBoot整合了SpringMVC,只需要在处理请求的方法参数列表上申明一个MultiPartFile的参数
* SpringBoot会自定将接受的文件数据赋值给这个参数
* @param file
* @param session
* @return
*/
@RequestMapping("/alert_avatar")
public JsonResult<String> alertAvatar(MultipartFile file,HttpSession session){
if(file==null){
System.out.println("=============");
throw new FileEmptyException("文件为空异常");
}
if(file.getSize()>MAX_AVATAR_SIZE){
throw new FileSizeException("文件超出大小限制");
}
if(!AVATAR_TYPE.contains(file.getContentType())){
throw new FileTypeException("文件类型错误");
}
//规定文件存储路径 .../upload/xxx.xx
// String parent = session.getServletContext().getRealPath("upload");
String parent = "G:/upload/";
File dir = new File(parent);
//parent文件夹不存在则创建
if(!dir.exists()){
dir.mkdirs();
}
//获取文件名称
String fileName = file.getOriginalFilename();
String[] splits = fileName.split("\\.");
//文件后缀
String suffix = splits[splits.length-1];
//生成随机的文件名(为避免不同用户文件名重复导致数据被覆盖丢失
String uuid = UUID.randomUUID().toString().toUpperCase();
String newFileName = uuid+"."+suffix; //新的文件名
System.out.println(newFileName);
//存储路径
File dest = new File(dir,newFileName);
try {
file.transferTo(dest);
} catch (IOException e) {
throw new FileUploadIOException("文件读写错误");
}

Integer uid = getUidFromSession(session);
System.out.println(dest.getPath());
String avatar = "/upload/"+newFileName;
userService.alertAvatar(uid,avatar);

userService.alertAvatar(uid,avatar);
return new JsonResult<>(OK,"用户头像修改成功",avatar);
}

解决方法二:新建文件夹

在项目根目录下新建public文件夹,这样在SpringBoot项目启动时不会去创建临时文件夹

image-20230815112923608

此时可以通过String parent = session.getServletContext().getRealPath("upload");获取文件存取根路径

1.定制对应的配置类,配置Tomacat虚拟目录

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
package com.bang.store.configure;

import com.bang.store.interceptor.LoginInterceptor;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

import java.util.ArrayList;
import java.util.List;

//注解,让SpringBoot识别
@Configuration
public class LoginInterceptorConfigure implements WebMvcConfigurer {

@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
/** 更改配置SpringBoot文件上传虚拟目录 */
registry.addResourceHandler("/upload/**").addResourceLocations("file:G:/store/public/upload/");
}
}

2.控制层代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
/** 设置上传文件的最大值 10MB */
public static final int MAX_AVATAR_SIZE = 10*1024*1024;
/** 设置允许接收的文件类型 */
public static final List<String> AVATAR_TYPE = new ArrayList<>();
static {
AVATAR_TYPE.add("image/jpeg");
AVATAR_TYPE.add("image/png");
AVATAR_TYPE.add("image/bmp");
AVATAR_TYPE.add("image/gif");
}

/**
* MultiPartFile是SpringMVC提供的一个接口,这个接口为我们包装了获取文件类型的数据,任何类型的File都可以接受
* SpringBoot整合了SpringMVC,只需要在处理请求的方法参数列表上申明一个MultiPartFile的参数
* SpringBoot会自定将接受的文件数据赋值给这个参数
* @param file
* @param session
* @return
*/
@RequestMapping("/alert_avatar")
public JsonResult<String> alertAvatar(MultipartFile file,HttpSession session){
if(file==null){
System.out.println("=============");
throw new FileEmptyException("文件为空异常");
}
if(file.getSize()>MAX_AVATAR_SIZE){
throw new FileSizeException("文件超出大小限制");
}
if(!AVATAR_TYPE.contains(file.getContentType())){
throw new FileTypeException("文件类型错误");
}
//规定文件存储路径 .../upload/xxx.xx
String parent = session.getServletContext().getRealPath("upload");
// String parent = "G:/upload/";
File dir = new File(parent);
//parent文件夹不存在则创建
if(!dir.exists()){
dir.mkdirs();
}
//获取文件名称
String fileName = file.getOriginalFilename();
String[] splits = fileName.split("\\.");
//文件后缀
String suffix = splits[splits.length-1];
//生成随机的文件名(为避免不同用户文件名重复导致数据被覆盖丢失
String uuid = UUID.randomUUID().toString().toUpperCase();
String newFileName = uuid+"."+suffix; //新的文件名
System.out.println(newFileName);
//存储路径
File dest = new File(dir,newFileName);
try {
file.transferTo(dest);
} catch (IOException e) {
throw new FileUploadIOException("文件读写错误");
}

Integer uid = getUidFromSession(session);
System.out.println(dest.getPath());
String avatar = "/upload/"+newFileName;
userService.alertAvatar(uid,avatar);

userService.alertAvatar(uid,avatar);
return new JsonResult<>(OK,"用户头像修改成功",avatar);
}

参考资料

博客1

博客2

博客3

博客4