文件上传,存储至本地目录中
 
 - 一、代码
 - 1、工具类(敏感后缀过滤)
 - 2、文件上传,存储至本地
 - 3、文件下载
 
 
   - 二、效果演示
 -  
  
 
 
 
 
  
 
一、代码
 
1、工具类(敏感后缀过滤)
 
import org.apache.commons.lang3.StringUtils;
import org.springframework.web.multipart.MultipartFile;
import java.io.InputStream;
import java.util.HashMap;
import java.util.Iterator;
public class FileTypeFilter {
    
    private static String[] forbidType = {"jsp","php"};
    
    final static HashMap<String, String> FILE_TYPE_MAP = new HashMap<>();
    static {
        FILE_TYPE_MAP.put("3c25402070616765206c", "jsp");
        FILE_TYPE_MAP.put("3c3f7068700a0a2f2a2a0a202a205048", "php");
       
    }
    
    private static String getFileTypeBySuffix(String fileName) {
        return fileName.substring(fileName.lastIndexOf(".") + 1, fileName.length());
    }
    
    public static void fileTypeFilter(MultipartFile file) throws Exception {
        String suffix = getFileType(file);
        for (String type : forbidType) {
            if (type.contains(suffix)) {
                throw new Exception("上传失败,非法文件类型:" + suffix);
            }
        }
    }
    
    private static String getFileType(MultipartFile file) throws Exception {
        String fileExtendName = null;
        InputStream is;
        try {
            
            is = file.getInputStream();
            byte[] b = new byte[10];
            is.read(b, 0, b.length);
            String fileTypeHex = String.valueOf(bytesToHexString(b));
            Iterator<String> keyIter = FILE_TYPE_MAP.keySet().iterator();
            while (keyIter.hasNext()) {
                String key = keyIter.next();
                
                if (key.toLowerCase().startsWith(fileTypeHex.toLowerCase().substring(0, 5))
                        || fileTypeHex.toLowerCase().substring(0, 5).startsWith(key.toLowerCase())) {
                    fileExtendName = FILE_TYPE_MAP.get(key);
                    break;
                }
            }
            
            if (StringUtils.isBlank(fileExtendName)) {
                String fileName = file.getOriginalFilename();
                return getFileTypeBySuffix(fileName);
            }
            is.close();
            return fileExtendName;
        } catch (Exception exception) {
            throw new Exception(exception.getMessage(), exception);
        }
    }
    
    private static String bytesToHexString(byte[] src) {
        StringBuilder stringBuilder = new StringBuilder();
        if (src == null || src.length <= 0) {
            return null;
        }
        for (int i = 0; i < src.length; i++) {
            int v = src[i] & 0xFF;
            String hv = Integer.toHexString(v);
            if (hv.length() < 2) {
                stringBuilder.append(0);
            }
            stringBuilder.append(hv);
        }
        return stringBuilder.toString();
    }
}
 
2、文件上传,存储至本地
 
import lombok.extern.slf4j.Slf4j;
import org.apache.tomcat.util.buf.HexUtils;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.FileCopyUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.MultipartHttpServletRequest;
import javax.servlet.http.HttpServletRequest;
import java.io.*;
import java.security.MessageDigest;
import java.text.SimpleDateFormat;
import java.util.Date;
@Slf4j
@RestController
@RequestMapping("/file")
public class FileUploadController {
    private static String FILE_NAME_REGEX = "[^A-Za-z\\.\\(\\)\\-()\\_0-9\\u4e00-\\u9fa5]";
    
    @Transactional
    @PostMapping(value = "/upload")
    public String upload(HttpServletRequest request) {
        MultipartHttpServletRequest multipartRequest = (MultipartHttpServletRequest) request;
        
        MultipartFile file = multipartRequest.getFile("file");
        if (file == null) {
            throw new NullPointerException("请选择文件上传!");
        }
        
        String fileName = file.getOriginalFilename();
        try {
            
            FileTypeFilter.fileTypeFilter(file);
            
            MessageDigest md5 = MessageDigest.getInstance("MD5");
            byte[] digest = md5.digest(file.getBytes());
            String fileMd5 = HexUtils.toHexString(digest);
            if (fileMd5.equals("xxxxxxxx")) {
                
            }
            
            int begin = fileName.lastIndexOf(".");
            String fileSuffix = fileName.substring(begin + 1);
            log.info("文件名称:{}", fileName);
            log.info("文件大小:{}", file.getBytes().length);
            log.info("文件类型:{}", file.getContentType());
            log.info("文件md5 算法:{}", fileMd5);
            log.info("文件后缀:{}", fileSuffix);
            
            String filePath = "/opt/test";
            
            File upFile = uploadLocal(file, filePath);
            if (upFile == null) {
                return "上传存储失败";
            }
            String savePath = upFile.getPath().replace("\\", "/");
            log.info("【存储】文件目录:{}", upFile.getName());
            log.info("【存储】文件路径:{}", savePath);
            return "成功";
        } catch (Exception e) {
            return "失败";
        }
    }
    
    private File uploadLocal(MultipartFile mf, String bizPath) {
        String toDay = new SimpleDateFormat("yyyy-MM-dd").format(new Date());
        try {
            String ctxPath = "";
            String fileName;
            String fileDir = ctxPath + File.separator + bizPath + File.separator + toDay;
            File file = new File(fileDir);
            if (!file.exists()) {
                
                file.mkdirs();
            }
            log.info("上传目录:{}", file.getPath());
            
            String orgName = mf.getOriginalFilename();
            if (!StringUtils.hasText(orgName)) {
                throw new NullPointerException("请选择文件上传!");
            }
            orgName = getFileName(orgName);
            if (orgName.contains(".")) {
                fileName = orgName.substring(0, orgName.lastIndexOf(".")) + "_" + System.currentTimeMillis() + orgName.substring(orgName.lastIndexOf("."));
            } else {
                fileName = orgName + "_" + System.currentTimeMillis();
            }
            String savePath = file.getPath() + File.separator + fileName;
            File saveFile = new File(savePath);
            FileCopyUtils.copy(mf.getBytes(), saveFile);
            return saveFile;
        } catch (IOException e) {
            log.error(e.getMessage(), e);
        }
        return null;
    }
    
    public static String getFileName(String fileName) {
        
        int unixSep = fileName.lastIndexOf('/');
        
        int winSep = fileName.lastIndexOf('\\');
        
        int pos = (winSep > unixSep ? winSep : unixSep);
        if (pos != -1) {
            
            fileName = fileName.substring(pos + 1);
        }
        
        fileName = fileName.replace("=", "").replace(",", "").replace("&", "")
                .replace("#", "").replace("“", "").replace("”", "");
        
        fileName = fileName.replaceAll("\\s", "");
        fileName = fileName.replaceAll(FILE_NAME_REGEX, "");
        return fileName;
    }
}
 
3、文件下载
 
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.net.URLEncoder;
@Slf4j
@RestController
@RequestMapping("/file")
public class FileDownloadController {
    
    @GetMapping(value = "/download")
    public void download(String loadType, HttpServletResponse response) {
        // 文件路径
        String filePath = "/opt/test/xxxx-xx-xx";
        // 文件名称
        String fileName = "1 - 副本.JPG";
        // 文件类型
        String contentType = "image/png";
        // 文件大小
        Integer fileSize = 17408;
        fileLoad(response, filePath, fileName, contentType, fileSize, loadType);
    }
    public void fileLoad(HttpServletResponse response, String filePath, String fileName, String contentType, Integer fileSize, String loadType) {
        File file = new File(filePath);
        if (!file.exists()) {
            response.setStatus(404);
            throw new RuntimeException("文件[" + fileName + "]不存在..");
        }
        InputStream inputStream = null;
        OutputStream outputStream = null;
        // 其余处理略
        try {
            inputStream = new BufferedInputStream(new FileInputStream(filePath));
            log.info("下载文件,{},大小:{}.kb", fileName, fileSize / 1024);
            // 设置强制下载不打开
            response.setContentType(contentType);
            String dis = "1".equals(loadType) ? "attachment" : "inline";
            response.addHeader("Content-Disposition", dis + ";fileName=" + URLEncoder.encode(fileName, "UTF-8"));
            response.addHeader("content-length", String.valueOf(fileSize));
            
            outputStream = response.getOutputStream();
            byte[] buf = new byte[1024];
            int len;
            while ((len = inputStream.read(buf)) > 0) {
                outputStream.write(buf, 0, len);
            }
            response.flushBuffer();
        } catch (IOException e) {
            log.error("读取文件失败" + e.getMessage());
            response.setStatus(404);
            e.printStackTrace();
        } finally {
            if (inputStream != null) {
                try {
                    inputStream.close();
                } catch (IOException e) {
                    log.error(e.getMessage(), e);
                }
            }
            if (outputStream != null) {
                try {
                    outputStream.close();
                } catch (IOException e) {
                    log.error(e.getMessage(), e);
                }
            }
        }
    }
}
 
二、效果演示
 
1、上传
 
1.1、postMan 请求
 

 
1.2、上传效果
 

 
2、下载
 
2.1、下载效果
 
