搭建文件服务器,Java+Centos7+Nginx

你说的曾经没有我的故事 提交于 2019-12-23 02:12:43

前言

最近试着搭建一个文件服务器,因为在企业应用开发中文件往往都是单独存储在一个服务器中的,与应用服务器相分离,数据库层面引用该文件只需要保存一个文件的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;

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!