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

前言

最近試着搭建一個文件服務器,因爲在企業應用開發中文件往往都是單獨存儲在一個服務器中的,與應用服務器相分離,數據庫層面引用該文件只需要保存一個文件的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;

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章