文件上传工具类

引言

在Web应用系统开发中,文件上传和下载功能是非常常用的功能。下面我就工作中常用的两种场景的文件上传进行封装,以方便后续快速开发及避免再次采坑。

一、根据URL地址,将文件保存到本地服务器

package com.cool.summer.moon.utils;

import org.apache.commons.io.FilenameUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;

public class FileUploadUtil {

    private static final Logger logger = LoggerFactory.getLogger(FileUploadUtil.class);

    /**
     * 上传文件
     *
     * @param url  网络连接地址
     * @param type 文件自定义格式
     * @return 返回文件存储磁盘地址
     */
    public String saveMultipartFile(String url, String type) {
        byte[] imageFromNetByUrl = getImageFromNetByUrl(url);
        // 文件名称,根据type值来判断是什么格式文件,这里需要完善下
        String picName = System.currentTimeMillis() / 1000 + ".jpg";
        // 保存文件
        String s = File.separator;
        String dataDir = "这里填写初始化文件目录";
        String filePath = "";
        if (s.equals("\\")) {  // windows
            filePath = "D:" + s + "data" + s + type + s + System.currentTimeMillis();
        } else {
            filePath = FilenameUtils.getFullPath(dataDir) + type + s + System.currentTimeMillis();
        }
        //这里需要先创建目录,如果不创建则会报错,具体原因还不清楚,算是一个坑
        File temp = new File(filePath);
        if (!temp.exists()) {
            try {
                temp.mkdirs();
            } catch (Exception e) {
                logger.error(e.getMessage(), e);
            }
        }
        //这里才是真正的创建一个空文件
        File files = new File(temp, picName);
        writeImageToDisk(imageFromNetByUrl, files);
        // 返回服务器文件地址
        return files.getAbsolutePath();
    }

    /**
     * 根据地址获得数据的字节流
     *
     * @param strUrl 网络连接地址
     * @return
     */
    public static byte[] getImageFromNetByUrl(String strUrl) {
        try {
            URL url = new URL(strUrl);
            HttpURLConnection conn = (HttpURLConnection) url.openConnection();
            conn.setRequestMethod("GET");
            conn.setConnectTimeout(5 * 1000);
            InputStream inStream = conn.getInputStream();//通过输入流获取图片数据
            byte[] btImg = readInputStream(inStream);//得到图片的二进制数据
            return btImg;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 从输入流中获取数据
     *
     * @param inStream 输入流
     * @return
     * @throws Exception
     */
    public static byte[] readInputStream(InputStream inStream) throws Exception {
        ByteArrayOutputStream outStream = new ByteArrayOutputStream();
        byte[] buffer = new byte[1024];
        int len = 0;
        while ((len = inStream.read(buffer)) != -1) {
            outStream.write(buffer, 0, len);
        }
        inStream.close();
        return outStream.toByteArray();
    }

    /**
     * 将图片写入到磁盘
     *
     * @param img     图片数据流
     * @param newFile 新的文件
     */
    public static void writeImageToDisk(byte[] img, File newFile) {
        try {
            FileOutputStream fops = new FileOutputStream(newFile);
            fops.write(img);
            fops.flush();
            fops.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

二、根据上传的文件,将文件保存到本地服务器

package com.utils;


import com.cool.summer.moon.FileTypeUtil;
import org.apache.commons.fileupload.disk.DiskFileItem;
import org.apache.commons.io.FilenameUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.commons.CommonsMultipartFile;

import java.io.File;
import java.io.IOException;

public class FileUploadUtil {

    public static final Logger logger = LoggerFactory.getLogger(FileUploadUtil.class);

    /**
     * 保存上传的文件
     *
     * @param file
     * @return
     */
    public String saveMultipartFile(MultipartFile file) {
        if (!file.isEmpty()) {
            return save(file);
        }
        return null;
    }

    private String save(MultipartFile file) {
        // 文件名称
        String picName = file.getOriginalFilename();
        CommonsMultipartFile cf = (CommonsMultipartFile) file;
        DiskFileItem fi = (DiskFileItem) cf.getFileItem();
        File newFile = (File) fi.getStoreLocation();
        logger.info("图片----------" + newFile);
        // 文件格式
        String fileType = FileTypeUtil.getFileType(newFile);
        if (StringUtils.isBlank(fileType) || !FileTypeUtil.isImage(newFile, fileType)) {
            throw new RuntimeException("图片格式错误或内容不规范");
        }
        // 校验图片大小
        Long picSize = file.getSize();
        if (picSize.compareTo(20971520L) > 0) {
            throw new RuntimeException("文件超出20M大小限制");
        }
        // 保存文件
        String s = File.separator;
        String dataDir = "这里填写配置的服务器路径";
        String filePath = "";
        if (s.equals("\\")) {  // windows
            filePath = "D:" + s + "data" + s + "image" + s + fileType + s + System.currentTimeMillis() + s + picName;
        } else {
            filePath = FilenameUtils.getFullPath(dataDir) + fileType + s + System.currentTimeMillis() + s + picName;
        }
        File files = new File(filePath);
        if (!files.exists()) {
            try {
                files.mkdirs();
            } catch (Exception e) {
                throw new RuntimeException("文件目录不存在");
            }
        }
        try {
            // 转存文件
            file.transferTo(files);
        } catch (IllegalStateException | IOException e) {
            logger.error(e.getMessage(), e);
        }
        return filePath;
    }
}

三、公共工具类

package com.utils;


import java.awt.image.BufferedImage;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStream;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;

import javax.imageio.ImageIO;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import tool.util.StringUtil;

/**
 * 校验一个file文件是否是真实的文件类型
 * (避免是用户在上传时将后缀修改掉,伪装
 * 其他类型的文件进行上传操作)
 *
 * @author RDuser
 */
public class FileTypeUtil {
    private static final Logger LOG = LoggerFactory.getLogger(FileTypeUtil.class);

    public static final Map<String, String> FILE_TYPE_MAP = new HashMap<>();

    /**
     * 图片类型
     */
    public static final String FILE_TYPE_GIF = "gif";
    public static final String FILE_TYPE_JPEG = "jpeg";
    public static final String FILE_TYPE_PNG = "png";
    public static final String FILE_TYPE_JPG = "jpg";
    /**
     * pdf类型
     */
    public static final String FILE_TYPE_PDF = "pdf";
    /**
     * excel类型
     */
    public static final String FILE_TYPE_XLS = "xls";
    public static final String FILE_TYPE_XLSX = "xlsx";
    /**
     * word类型
     */
    public static final String FILE_TYPE_DOC = "doc";
    public static final String FILE_TYPE_DOCX = "docx";

    public FileTypeUtil() {
    }

    static {
        getAllFileType();  //初始化文件类型信息     
    }

    private static void getAllFileType() {
        FILE_TYPE_MAP.put("jpg", "FFD8FF"); //JPEG (jpg)
        FILE_TYPE_MAP.put("jpeg", "FFD8FF");
        FILE_TYPE_MAP.put("png", "89504E47");  //PNG (png)     
        FILE_TYPE_MAP.put("gif", "47494638");  //GIF (gif)     
        FILE_TYPE_MAP.put("tif", "49492A00");  //TIFF (tif)     
        FILE_TYPE_MAP.put("bmp", "424D"); //Windows Bitmap (bmp)     
        FILE_TYPE_MAP.put("dwg", "41433130"); //CAD (dwg)     
        FILE_TYPE_MAP.put("html", "68746D6C3E");  //HTML (html)     
        FILE_TYPE_MAP.put("rtf", "7B5C727466");  //Rich Text Format (rtf)     
        FILE_TYPE_MAP.put("xml", "3C3F786D6C");
        FILE_TYPE_MAP.put("rar", "52617221");
        FILE_TYPE_MAP.put("psd", "38425053");  //Photoshop (psd)     
        FILE_TYPE_MAP.put("eml", "44656C69766572792D646174653A");  //Email [thorough only] (eml)     
        FILE_TYPE_MAP.put("dbx", "CFAD12FEC5FD746F");  //Outlook Express (dbx)     
        FILE_TYPE_MAP.put("pst", "2142444E");  //Outlook (pst)     
        FILE_TYPE_MAP.put("xlsx", "504B0304");
        FILE_TYPE_MAP.put("xls", "D0CF11E0");  //MS Word     
        FILE_TYPE_MAP.put("doc", "D0CF11E0");  //MS Excel 注意:word 和 excel的文件头一样
        FILE_TYPE_MAP.put("pdf", "255044462D312E");
    }

    public static final String getFileType(File file) {
        String filetype = null;
        InputStream is = null;
        byte[] b = new byte[50];
        try {
            is = new FileInputStream(file);
            is.read(b);
            filetype = getFileTypeByStream(b);
            is.close();
        } catch (FileNotFoundException e) {
            LOG.error("FileNotFoundException", e);
        } catch (IOException e) {
            LOG.error("IOException", e);
        } finally {
            try {
                if (is != null) {
                    is.close();
                }
            } catch (IOException e) {
                LOG.error("IO关闭异常", e);
            }
        }
        return filetype;
    }

    public final static String getFileTypeByStream(byte[] b) {
        String filetypeHex = String.valueOf(getFileHexString(b));
        Iterator<Entry<String, String>> entryiterator = FILE_TYPE_MAP.entrySet().iterator();
        while (entryiterator.hasNext()) {
            Entry<String, String> entry = entryiterator.next();
            String fileTypeHexValue = entry.getValue();
            if (filetypeHex.toUpperCase().startsWith(fileTypeHexValue)) {
                return entry.getKey();
            }
        }
        return null;
    }

    /**
     * 判断上传 类型是否 是jpg/png/gif/pdf 类型
     *
     * @param file
     * @return
     */
    public static boolean checkFileType(File file) {
        String fileType = getFileType(file);
        if (StringUtil.isBlank(fileType)) {
            return false;
        }
        return isImage(file, fileType);
    }

    /**
     * 是否为图片类型
     *
     * @param file
     * @param fileType
     * @return
     */
    public static boolean isImage(File file, String fileType) {
        if ("jpeg".equals(fileType) || "jpg".equals(fileType) || "png".equals(fileType) || "gif".equals(fileType)) {
            if (fileIsImage(file)) {
                return true;
            }
        }
        return false;
    }

    @SuppressWarnings("resource")
    public static Boolean fileIsImage(File file) {
        InputStream is = null;
        BufferedReader reader = null;
        FileReader fr = null;
        try {
            fr = new FileReader(file);
            // 将文件转换成输入流
            is = new FileInputStream(file);
            //用image IO读取文件,如果文件file不是图片,则为null
            BufferedImage image = ImageIO.read(is);
            if (image != null) { // 如果image不为空,则说明file文件是图片
                reader = new BufferedReader(fr);
                String exits = null;
                while ((exits = reader.readLine()) != null) {
                    exits = shiftD(exits);
                    if (exits.indexOf("eval") > -1 || exits.indexOf("<?php") > -1) {
                        return false;
                    }
                }
                return true;
            }
        } catch (Exception e) {
            LOG.error("fileIsImage方法异常", e);
        } finally {
            try {
                if (is != null) {
                    is.close();
                }
                if (reader != null) {
                    reader.close();
                }
                if (fr != null) {
                    fr.close();
                }
            } catch (IOException e) {
                LOG.error("fileIsImage IO关闭异常", e);
            }
        }
        return false;
    }

    public static String shiftD(String str) {
        int size = str.length();
        char[] chs = str.toCharArray();
        for (int i = 0; i < size; i++) {
            if (chs[i] <= 'Z' && chs[i] >= 'A') {
                chs[i] = (char) (chs[i] + 32);
            }
        }
        return new String(chs);
    }

    /**
     * 是否为pdf
     *
     * @param fileType
     * @return
     */
    public static boolean isPdf(String fileType) {
        if ("pdf".equals(fileType)) {
            return true;
        }
        return false;
    }

    /**
     * 是否为excel
     *
     * @param fileType
     * @return
     */
    public static boolean isExcel(String fileType) {
        if ("xlsx".equals(fileType) || "xls".equals(fileType)) {
            return true;
        }
        return false;
    }

    /**
     * 是否为word
     *
     * @param fileType
     * @return
     */
    public static boolean isWord(String fileType) {
        if ("doc".equals(fileType) || "docx".equals(fileType)) {
            return true;
        }
        return false;
    }

    /**
     * TODO 根据 FILE_TYPE_MAP 的value值获取key
     *
     * @param fileType
     * @param
     * @return
     */
    public static String getFileTypeStr(String fileType) {
        Iterator<Entry<String, String>> entryiterator = FILE_TYPE_MAP.entrySet().iterator();
        while (entryiterator.hasNext()) {
            Entry<String, String> entry = entryiterator.next();
            String fileTypeHexValue = entry.getValue();
            if (fileType.equalsIgnoreCase(fileTypeHexValue)) {
                return entry.getKey();
            }
        }
        return "";
    }

    public static final String getFileHexString(byte[] b) {
        StringBuilder stringBuilder = new StringBuilder();
        if (b == null || b.length <= 0) {
            return null;
        }
        for (int i = 0; i < b.length; i++) {
            int v = b[i] & 0xFF;
            String hv = Integer.toHexString(v);
            if (hv.length() < 2) {
                stringBuilder.append(0);
            }
            stringBuilder.append(hv);
        }
        return stringBuilder.toString();
    }
}  

结束语

上面的代码在真正应用到程序中需要根据环境进行修改,但是绝对没有坑,如果能够帮助大家希望帮忙点个赞。

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值