前后端分离的springboot项目上传文件时,文件的存储位置问题以及如何绕过springsecurity权限验证实现前端访问上传的静态图片
在前后端分离的Springboot 项目中前端上传文件时比如图片时,在开发环境里,文件如果直接存储在后端的/src/resource/static文件夹下是可以直接访问的,但在生产环境里一旦打包完成,jar包是只读的不允许写入。
那么合适的存储位置只剩下数据库、云存储服务、本地磁盘。数据库储存大文件没有优势而且性能问题也是棘手问题,一旦大批量图片访问请求来袭,数据库和我总得死一个。云储存服务十个很诱人的且理论上的最优选项,但是呢咱普通人没必要搞这么破费的东西。那么最后只剩下本地磁盘这个选项了。
那么本地磁盘的哪个路径合适呢?个人觉得如果不是多个项目集中统一存放,那么跟后端服务位置一样就是最方便的选择。而且开发环境一般是windows系统而生产环境一般都是Linux系统,不同系统环境下该怎么保证写入的地址最后在两个系统都是可用的呢?这时候就可以考虑jvm给咱们提供的便利,作为跨平台的开发语言jvm为我们提供了一个获取当前系统环境的函数System,而System.getProperty(“user.dir”)不管在哪个系统都可以获取到当前软件启动的路径。比如我的项目位置在D:\workspace\intellij\project\smallnovel,那么调用System.getProperty(“user.dir”)这个函数就可以得到当前的项目位置D:\workspace\intellij\project\smallnovel,所以就可以设置D:\workspace\intellij\project\upload为文件上传位置。在Linux系统里,项目位置/app/smallnovel1.0.jar那么调用System.getProperty(“user.dir”)得到/app,因此可以设置/app/upload。这样就可以规避开发环境和生产环境不同带来的路径问题。
那么首先先去设置一个好听的路径名,在application.yml文件中自定义文件上传路径
smallnovel:
file:
# 文件上传配置
upload:
# 上传路径
path: /upload
接着编写一个工具类用于获取具体存储位置
@Component
public class PathInfoUtils {
private static final Logger log = LoggerFactory.getLogger(PathInfoUtils.class);
//注入上传路径
@Value("${smallnovel.file.upload.path}")
private String uploadPath;
public String getUploadPath() {
String systemPath = System.getProperty(SystemConfigConst.SYSTEM_USER_DIR);
log.info("项目启动目录: {}", systemPath);
String parentPath = Paths.get(systemPath).getParent().toString();
String result = parentPath.replace("\\","/") + uploadPath + SystemConfigConst.IMAGE_UPLOAD_DIRECTORY;
log.info("The upload path: {}", result);
return result;
}
public String getImageUploadPath() {
String imageUploadDirectory = uploadPath + SystemConfigConst.IMAGE_UPLOAD_DIRECTORY;
log.info("The image upload directory for vue: {}", imageUploadDirectory);
return imageUploadDirectory;
}
}
后端只需要调用getUploadPath()就会获取到一个位置D:\workspace\intellij\project\upload\image作为文件的存储地址,如果是Linux系统会返回/app/upload/image。
但是直接把这个地址发给前端又是极其不安全的做法,那么可以考虑调用getImageUploadPath()给前端只返回\upload\image,前端拼接图片地址得到http://localhost:8080/upload/image/xxx.jpg,发送后端请求由后端来做路由转发
@Configuration
public class WebConfig implements WebMvcConfigurer {
private final PathInfoUtils pathInfoUtils;
public WebConfig(PathInfoUtils pathInfoUtils) { this.pathInfoUtils = pathInfoUtils; }
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
// 映射规则:/upload/image/** 指向 D盘的/upload/image/**
registry.addResourceHandler("/upload/image/**")
.addResourceLocations("file:"+pathInfoUtils.getUploadPath());
}
}
将请求里带/upload/image/**转发到磁盘指定的位置,这样就安全多了。
当然如果项目中还引入了springsecurity那么还需要做相关的放行配置。
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http
.csrf(CsrfConfigurer::disable)
.securityMatcher(EndpointRequest.toAnyEndpoint())
.authorizeHttpRequests(auth->auth.requestMatchers("/upload/image/**").permitAll() )
.authorizeHttpRequests(requests -> requests.anyRequest().hasRole("ENDPOINT_ADMIN"))
.httpBasic(Customizer.withDefaults());
return http.build();
}
这样只要前端访问http://localhost:8080/upload/image/xxx.jpg就可以正常访问到上传的照片啦。到此就解决了前后端分离项目的基础——文件存储位置指定的问题了。
更多推荐




所有评论(0)