前言
最近试着搭建一个文件服务器,因为在企业应用开发中文件往往都是单独存储在一个服务器中的,与应用服务器相分离,数据库层面引用该文件只需要保存一个文件的url即可;
大致流程就是,前端请求文件服务器接口,接口逻辑处理保存该文件到服务器中,并返回可以访问该文件的url给前端;
技术栈
后端Java,SpringBoot2.2.2.RELEASE
服务器Centos7,Nginx
后端处理详情
- 分环境开发部署,开发环境和测试环境,因为开发环境下使用的是Windows系统,文件路径与Linux系统不太一样,而且记录日志的方式也不一样,开发环境下日志我就直接输出在控制台,生产环境下日志记录到文件,所以利用Maven的profiles部署两个环境
<profiles>
<profile>
<!-- 开发环境 -->
<id>dev</id>
<properties>
<profiles.active>dev</profiles.active>
</properties>
<activation>
<activeByDefault>true</activeByDefault>
</activation>
</profile>
<profile>
<!-- 生产环境 -->
<id>pro</id>
<properties>
<profiles.active>pro</profiles.active>
</properties>
</profile>
</profiles>
分环境的不同配置,日志和存储路径
spring:
#指定当前的环境------在pom文件中取值使用@profiles.active@
profiles:
active: @profiles.active@
#日志配置文件位置
logging:
config: classpath:log4j/${spring.profiles.active}/log4j2.xml
---
spring:
profiles: dev
# 开发环境下第一层文件存储目录,windows下文档路径 / 和 \ 都可以
filePath: K:/forFileUpload/
---
spring:
profiles: pro
# 生产环境下第一层文件存储目录
filePath: /fei/fileupload/
不同环境的日志文件
- 避免文件名重复,使用UUID重命名文件名;根据日期每天生成一个次级文件夹;这都是具体接口的处理逻辑
package com.fei.fileupload.web;
import com.fei.common.data.ApiResult;
import com.fei.common.log.Loggable;
import com.fei.fileupload.model.FileModel;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
import java.io.File;
import java.io.IOException;
import java.time.LocalDate;
import java.util.UUID;
/**
* @Author: xiaoshijiu
* @Date: 2019/12/19
* @Description: 搭建文件服务器,接收文件入口
*/
@RestController
@RequestMapping("/file")
public class FileUpload implements Loggable {
@Value("${filePath}")
private String filePath;
@Value("${spring.profiles:dev}")
private String profiles;
@Value("${serverAddress}")
private String serverAddress;
@PostMapping("/upload")
public ApiResult<FileModel> getFile(MultipartFile file) throws IOException {
if (file.isEmpty()) {
return ApiResult.fail("失败,文件不存在!!");
}
getLog().info("文件的大小是:{}", file.getSize());
getLog().info("文件的类型是:{}", file.getContentType());
String fileName = file.getOriginalFilename();
getLog().info("文件的名称是:{}", fileName);
// 文件名处理(避免文件重名覆盖),使用UUID
String exname = fileName.substring(fileName.lastIndexOf("."));
fileName = UUID.randomUUID().toString().replace("-", "") + exname;
// 每天一个文件夹,第二层目录
String fileDatePath = LocalDate.now().toString();
String DateFileName = fileDatePath + "/" + fileName;
String endFilePath = filePath + DateFileName;
File fileTotlePath = new File(filePath + fileDatePath);
// 总路径不存在,新建(这里路径必须要确保存在,以免下面转换的时候报FileNotFoundException)
if (!fileTotlePath.exists()) {
fileTotlePath.mkdirs();
}
// 将file转换到指定目录
file.transferTo(new File(endFilePath));
FileModel fileModel;
if ("dev".equals(profiles)) {
fileModel = new FileModel(endFilePath);
getLog().info("文件最终url是:{}", endFilePath);
} else {
fileModel = new FileModel(serverAddress + DateFileName);
getLog().info("文件最终url是:{}", serverAddress + DateFileName);
}
return ApiResult.ok(fileModel);
}
}
- 新版SpringBoot配置接受的最大文件大小(跟之前版本不太一样,有一个新的类
DataSize
)
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Value("${fileMaxSize:10}")
private Long fileMaxSize;
/**
* 接受文件大小配置
*/
@Bean
public MultipartConfigElement multipartConfigElement() {
MultipartConfigFactory factory = new MultipartConfigFactory();
// 文件最大
// DataSize.ofMegabytes(10L),10MB
factory.setMaxFileSize(DataSize.ofMegabytes(fileMaxSize));
// 设置总上传数据总大小
factory.setMaxRequestSize(DataSize.ofMegabytes(fileMaxSize));
return factory.createMultipartConfig();
}
}
- 拦截器过滤ip,给指定的ip放行访问;因为有的公司搭建的文件服务器,可能只是为了供公司内网使用,这时候我们就需要对请求的客户端ip进行过滤
package com.fei.fileupload.interceptor;
import com.fei.common.exception.NotAuthException;
import com.fei.common.server.iputil.GetClientIp;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* @Author: xiaoshijiu
* @Date: 2019/12/20
* @Description: ip拦截器,文件服务器只供内部使用,所以需要拦截ip。选择性放行
*/
public class IpInteceptor implements HandlerInterceptor {
@Value("${permissionURL}")
private String permissionURL;
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response,
Object handler) throws Exception {
// 获取ip
String ipAdrress = GetClientIp.getIpAdrress(request);
if (ipAdrress.contains(permissionURL)) {
return true;
}
// 抛出去一个异常,供捕获返回
throw new NotAuthException("对不起你没有权限,不允许访问!!");
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
ModelAndView modelAndView) throws Exception {
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response,
Object handler, Exception ex) throws Exception {
}
}
拦截器配置,注意这里配置拦截器的时候:最好要以 getIpInterceptor() 和 @Bean 的形式配置拦截器 不然在拦截器里面不能使用 @value 取值
因为@Bean 的形式,spring管理bean,能够依赖注入
package com.fei.fileupload.config;
import com.fei.fileupload.interceptor.IpInteceptor;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.web.servlet.MultipartConfigFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.util.unit.DataSize;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import javax.servlet.MultipartConfigElement;
/**
* @Author: xiaoshijiu
* @Date: 2019/12/19
* @Description: Web的一些配置
*/
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Bean
public IpInteceptor getIpInterceptor() {
return new IpInteceptor();
}
/**
* 注意事项:这里最好要以 getIpInterceptor() 和 @Bean 的形式配置拦截器 不然在拦截器里面不能使用 @value 取值
* @Bean 的形式,spring管理bean,能够依赖注入
*/
@Override
public void addInterceptors(InterceptorRegistry registry) {
// 添加拦截器,指定拦截请求和排除请求
registry.addInterceptor(getIpInterceptor()).addPathPatterns("/**")
.excludePathPatterns("/error");
}
}
- 大致后端情况就这么多,还有一些其他的像什么全局异常处理Controller等啊,就不需要介绍了
服务器Nginx配置
网上也有些人使用的是Tomcat加设置虚拟目录的形式,达到可以在线访问指定目录的效果;但是在处理静态资源这一块,Nginx比Tomcat效率要高很多,也是第一选择;
安装好Nginx,在/usr/local/nginx/conf里面找到nginx.conf
加上一组location,进行映射,访问ip:port/file/xx.jpg
就相当于访问/fei/fileupload/
下面的xx.jpg
location /file/ {
alias /fei/fileupload/;
}
最后
至此,文件服务器搭建完毕,前端请求Java的接口,经过处理保存到指定目录,并返回可以访问的url;
来源:CSDN
作者:xiaoshijiu333
链接:https://blog.csdn.net/shijiujiu33/article/details/103655415