(八)、MultipartFile

在处理上传文件时,经常用到MultipartFile文件。MultipartFile是spring类型,代表html中from-data方式上传的文件,包含二进制数据+文件名称。

MultipartFile和File可以互相转换

MultipartFile -> File:使用transferTo方法

MultipartFile multipartFile = ...
File file = new File(****);
multipartFile.transferTo(file);

File -> MultipartFile:使用commons-fileupload

File file = new File(***);        
FileItem fileItem = new DiskFileItem("copyfile.txt", Files.probeContentType(file.toPath()), false, file.getName(), (int)file.length(), file.getParentFile());
try (InputStream inputStream = new FileInputStream(file); OutputStream os = fileItem.getOutputStream()) {
    IOUtils.copy(inputStream,os);
    MultipartFile multipartFile = new CommonsMultipartFile(fileItem);
    。。。。。
} catch (IOException e) {
    e.printStackTrace();
}

下面再说一下,在处理文件上传文件时,出于安全性考虑经常会对文件类型做检查,常用的检查方式有:

  • 通过文件名后缀的方式检测
// 截取文件后缀  进行比较即可
String suffix = fileName.substring(fileName.lastIndexOf(".") + 1);
  • 通过文件魔数检测
public enum FileType {
    /**
     * JPEG  (jpg)
     */
    JPEG("JPG", "FFD8FF"),

    /**
     * PNG
     */
    PNG("PNG", "89504E47"),

    /**
     * GIF
     */
    GIF("GIF", "47494638"),

    /**
     * TIFF (tif)
     */
    TIFF("TIF", "49492A00"),

    /**
     * Windows bitmap (bmp)
     */
    BMP("BMP", "424D"),

    /**
     * 16色位图(bmp)
     */
    BMP_16("BMP", "424D228C010000000000"),

    /**
     * 24色位图(bmp)
     */
    BMP_24("BMP", "424D8240090000000000"),

    /**
     * 32色位图(bmp)
     */
    BMP_256("BMP", "424D8E1B030000000000"),

    /**
     * CAD  (dwg)
     */
    DWG("DWG", "41433130"),

    /**
     * Adobe photoshop  (psd)
     */
    PSD("PSD", "38425053"),

    /**
     * Rich Text Format  (rtf)
     */
    RTF("RTF", "7B5C727466"),

    /**
     * XML
     */
    XML("XML", "3C3F786D6C"),

    /**
     * HTML (html)
     */
    HTML("HTML", "68746D6C3E"),

    /**
     * Email [thorough only] (eml)
     */
    EML("EML", "44656C69766572792D646174653A"),

    /**
     * Outlook Express (dbx)
     */
    DBX("DBX", "CFAD12FEC5FD746F "),

    /**
     * Outlook (pst)
     */
    PST("PST", "2142444E"),

    /**
     * doc;xls;dot;ppt;xla;ppa;pps;pot;msi;sdw;db
     */
    OLE2("OLE2", "0xD0CF11E0A1B11AE1"),

    /**
     * Microsoft Word/Excel 注意:word 和 excel的文件头一样
     */
    XLS("XLS", "D0CF11E0"),

    /**
     * Microsoft Word/Excel 注意:word 和 excel的文件头一样
     */
    DOC("DOC", "D0CF11E0"),

    /**
     * Microsoft Word/Excel 2007以上版本文件 注意:word 和 excel的文件头一样
     */
    DOCX("DOCX", "504B0304"),

    /**
     * Microsoft Word/Excel 2007以上版本文件 注意:word 和 excel的文件头一样 504B030414000600080000002100
     */
    XLSX("XLSX", "504B0304"),

    /**
     * Microsoft Access (mdb)
     */
    MDB("MDB", "5374616E64617264204A"),

    /**
     * Word Perfect (wpd)
     */
    WPB("WPB", "FF575043"),

    /**
     * Postscript
     */
    EPS("EPS", "252150532D41646F6265"),

    /**
     * Postscript
     */
    PS("PS", "252150532D41646F6265"),

    /**
     * Adobe Acrobat (pdf)
     */
    PDF("PDF", "255044462D312E"),

    /**
     * Quicken (qdf)
     */
    QDF("qdf", "AC9EBD8F"),

    /**
     * QuickBooks Backup (qdb)
     */
    QDB("qbb", "458600000600"),

    /**
     * Windows Password  (pwl)
     */
    PWL("PWL", "E3828596"),

    /**
     * ZIP Archive
     */
    ZIP("ZIP", "504B0304"),

    /**
     * ARAR Archive
     */
    RAR("ARAR", "52617221"),

    /**
     * WAVE (wav)
     */
    WAV("WAV", "57415645"),

    /**
     * AVI
     */
    AVI("AVI", "41564920"),

    /**
     * Real Audio (ram)
     */
    RAM("RAM", "2E7261FD"),

    /**
     * Real Media (rm) rmvb/rm相同
     */
    RM("RM", "2E524D46"),

    /**
     * Real Media (rm) rmvb/rm相同
     */
    RMVB("RMVB", "2E524D46000000120001"),

    /**
     * MPEG (mpg)
     */
    MPG("MPG", "000001BA"),

    /**
     * Quicktime  (mov)
     */
    MOV("MOV", "6D6F6F76"),

    /**
     * Windows Media (asf)
     */
    ASF("ASF", "3026B2758E66CF11"),

    /**
     * ARJ Archive
     */
    ARJ("ARJ", "60EA"),

    /**
     * MIDI (mid)
     */
    MID("MID", "4D546864"),

    /**
     * MP4
     */
    MP4("MP4", "00000020667479706D70"),

    /**
     * MP3
     */
    MP3("MP3", "49443303000000002176"),

    /**
     * FLV
     */
    FLV("FLV", "464C5601050000000900"),

    /**
     * 1F8B0800000000000000
     */
    GZ("GZ", "1F8B08"),

    /**
     * CSS
     */
    CSS("CSS", "48544D4C207B0D0A0942"),

    /**
     * JS
     */
    JS("JS", "696B2E71623D696B2E71"),

    /**
     * Visio
     */
    VSD("VSD", "d0cf11e0a1b11ae10000"),

    /**
     * WPS文字wps、表格et、演示dps都是一样的
     */
    WPS("WPS", "d0cf11e0a1b11ae10000"),

    /**
     * torrent
     */
    TORRENT("TORRENT", "6431303A637265617465"),

    /**
     * JSP Archive
     */
    JSP("JSP", "3C2540207061676520"),

    /**
     * JAVA Archive
     */
    JAVA("JAVA", "7061636B61676520"),

    /**
     * CLASS Archive
     */
    CLASS("CLASS", "CAFEBABE0000002E00"),

    /**
     * JAR Archive
     */
    JAR("JAR", "504B03040A000000"),

    /**
     * MF Archive
     */
    MF("MF", "4D616E69666573742D56"),

    /**
     * EXE Archive
     */
    EXE("EXE", "4D5A9000030000000400"),

    /**
     * ELF Executable
     */
    ELF("ELF", "7F454C4601010100"),

    /**
     * Lotus 123 v1
     */
    WK1("WK1", "2000604060"),

    /**
     * Lotus 123 v3
     */
    WK3("WK3", "00001A0000100400"),

    /**
     * Lotus 123 v5
     */
    WK4("WK4", "00001A0002100400"),

    /**
     * Lotus WordPro v9
     */
    LWP("LWP", "576F726450726F"),

    /**
     * Sage(sly.or.srt.or.slt;sly;srt;slt)
     */
    SLY("SLY", "53520100"),

    NOT_EXITS_ENUM("", "");

    private String fileTypeName;

    private String magicNum;

    FileType(String fileTypeName, String magicNum) {
        this.fileTypeName = fileTypeName;
        this.magicNum = magicNum;
    }

    private String getFileTypeName() {
        return fileTypeName;
    }

    private String getMagicNum() {
        return magicNum;
    }

    private static FileType getFileTypeByFileTypeName(String fileTypeName) {
        if (StringUtils.isNotBlank(fileTypeName)) {
            for (FileType type : values()) {
                if (StringUtils.equalsIgnoreCase(type.getFileTypeName(), fileTypeName)) {
                    return type;
                }
            }
        }
        return NOT_EXITS_ENUM;
    }

    @Nullable
    private static String bytesToHexStr(byte[] bytes) {
        if (bytes == null || bytes.length <= 0) {
            return null;
        }
        StringBuilder builder = new StringBuilder();
        for (byte value : bytes) {
            int v = value & 0xFF;
            String hv = Integer.toHexString(v);
            if (hv.length() < 2) {
                builder.append(0);
            }
            builder.append(hv);
        }
        return builder.toString();
    }

    public static boolean isEqualsFileType(byte[] bytes, Set<String> fileTypeList) {
        if (CollectionUtils.isEmpty(fileTypeList)) {
            return false;
        }
        String magicNum = bytesToHexStr(bytes);
        if (!StringUtils.isBlank(magicNum)) {
            magicNum = magicNum.toUpperCase();
            for (String f : fileTypeList) {
                FileType fileType = getFileTypeByFileTypeName(f);
                if (fileType == NOT_EXITS_ENUM) {
                    continue;
                }
                if (magicNum.startsWith(fileType.getMagicNum().toUpperCase())) {
                    return true;
                }
            }
        }
        return false;
    }
}

注意:魔数有一个问题就是,有些文件的魔数前缀相同。并且,黑客也会修改文件头,所以这样也不会做到绝对安全。不过这样已经能减少很多安全问题了。

  • mime-type校验

什么是MIME TYPE?

首先我们要知道浏览器是如何处理内容的,在浏览器中显示的内容有HTML、XML、GIF、FLASH…,浏览器就是通过MIME TYPE区分它们,决定用什么形式来显示的,也就是该资源的媒体类型。在HTTP中,MIME类型被定义在Content-Type header中。

常见的MIME类型
超文本标记语言文本 :.html,.html text/html
普通文本: .txt text/plain
RTF文本: .rtf application/rtf
GIF图形: .gif image/gif
JPEG图形: .ipeg,.jpg image/jpeg
au声音文件: .au audio/basic
MIDI音乐文件: mid,.midi audio/midi,audio/x-midi
RealAudio音乐文件: .ra, .ram audio/x-pn-realaudio
MPEG文件: .mpg,.mpeg video/mpeg
AVI文件: .avi video/x-msvideo
GZIP文件: .gz application/x-gzip
TAR文件: .tar application/x-tar

常用jar包

使用jmimemagic包,进行检测

MultipartFile uploadFile = ********;
// 创建一个临时文件
File tempFile = File.createTempFile(********);
FileUtils.copyInputStreamToFile(uploadFile.getInputStream(), tempFile);
MagicMatch magicMatch = Magic.getMagicMatch(tempFile, true, false);
String mimeType = magicMatch.getMimeType();

使用tika包,进行检测

// 获取mime type
AutoDetectParser parser = new AutoDetectParser();
parser.setParsers(new HashMap<MediaType, Parser>());
Metadata metadata = new Metadata();
metadata.add(TikaMetadataKeys.RESOURCE_NAME_KEY, file.getName());
 try (InputStream stream = new FileInputStream(file)) {
     parser.parse(stream, new DefaultHandler(), metadata, new ParseContext());
} catch(Exception e) {
    e.printStackTrace();
}       
return metadata.get(HttpHeaders.CONTENT_TYPE);
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值