前言

最近在弄文件上传、下载、在线预览时经常需要设置请求标头或者响应标头的Content-Type 属性。所以研究了一下spring支持哪些Content-Type,通过研究MediaTypeFactory.getMediaType的源码,可以得知spring是将支持的Content-Type 维护在/org/springframework/http/mime.types文件中。

private static MultiValueMap<String, MediaType> parseMimeTypes() {
        InputStream is = MediaTypeFactory.class.getResourceAsStream("/org/springframework/http/mime.types");

        try {
            BufferedReader reader = new BufferedReader(new InputStreamReader(is, StandardCharsets.US_ASCII));
            Throwable var2 = null;

            try {
                MultiValueMap<String, MediaType> result = new LinkedMultiValueMap();

                label111:
                while(true) {
                    String line;
                    if ((line = reader.readLine()) != null) {
                        if (line.isEmpty() || line.charAt(0) == '#') {
                            continue;
                        }

                        String[] tokens = StringUtils.tokenizeToStringArray(line, " \t\n\r\f");
                        MediaType mediaType = MediaType.parseMediaType(tokens[0]);
                        int i = 1;

                        while(true) {
                            if (i >= tokens.length) {
                                continue label111;
                            }

                            String fileExtension = tokens[i].toLowerCase(Locale.ENGLISH);
                            result.add(fileExtension, mediaType);
                            ++i;
                        }
                    }

                    LinkedMultiValueMap var5 = result;
                    return var5;
                }
            } catch (Throwable var17) {
                var2 = var17;
                throw var17;
            } finally {
                if (reader != null) {
                    if (var2 != null) {
                        try {
                            reader.close();
                        } catch (Throwable var16) {
                            var2.addSuppressed(var16);
                        }
                    } else {
                        reader.close();
                    }
                }

            }
        } catch (IOException var19) {
            throw new IllegalStateException("Could not load '/org/springframework/http/mime.types'", var19);
        }
    }

通过上面查找文件的路径找到了org.springframework:spring-web包下http目录中的mime.types文件
整理spring-web里支持的文件以及对应的Content-Type-LMLPHP

结果打开后居然发现 有多达1838个Content-Type,不过许多都是被注释掉的。过滤掉被注释的最终能被获取出来的一共是982个,本着好记性不如烂笔头的精神,我把这982个Content-Type已经它对应的文件后缀,整理了一下,形成了下面的表格,也方便以后查阅。

mime.types文件:
整理spring-web里支持的文件以及对应的Content-Type-LMLPHP

​spring-web将mime.types文件加载到这个map里
整理spring-web里支持的文件以及对应的Content-Type-LMLPHP

spring-web里支持的文件以及对应的Content-Type

如何获取文件的Content-Type

1、使用spring-web包下MediaTypeFactory

MediaTypeFactory是spring-web包下的工具类,需要在pom引用spring-web包,本例使用的是:

<dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-web</artifactId>
      <version> 2.2.4.RELEASE</version>
    </dependency>

从源码中可以看到MediaTypeFactory一共提供了三个对外方法,支持通过传入文件名或者Resource对象来获取Content-Type:

 public static Optional<MediaType> getMediaType(@Nullable Resource resource) {
        return Optional.ofNullable(resource).map(Resource::getFilename).flatMap(MediaTypeFactory::getMediaType);
    }

    public static Optional<MediaType> getMediaType(@Nullable String filename) {
        return getMediaTypes(filename).stream().findFirst();
    }

    public static List<MediaType> getMediaTypes(@Nullable String filename) {
        Optional var10000 = Optional.ofNullable(StringUtils.getFilenameExtension(filename)).map((s) -> {
            return s.toLowerCase(Locale.ENGLISH);
        });
        MultiValueMap var10001 = fileExtensionToMediaTypes;
        var10001.getClass();
        return (List)var10000.map(var10001::get).orElse(Collections.emptyList());
    }

我们用传入文件名的方式测试一下:

public static void main(String[] args) {
        MediaType mediaType = MediaTypeFactory.getMediaType("测试.pdf").get();
        String mediaTypeString = mediaType.toString();
        System.out.println(mediaTypeString);
    }

输出结果:

application/pdf

2、使用Apache Tika

Apache Tika 是一个内容分析工具包,可以检测上千种文件类型,并提取它们的元数据和文本。tika在设计上十分精巧,单一的接口使它易于使用,在搜索引擎索引,内容分析,翻译等诸多方面得到了广泛使用。

使用Apache Tika首先需要在pom引用:

 <dependency>
      <groupId>org.apache.tika</groupId>
      <artifactId>tika-core</artifactId>
      <version>1.28.4</version>
    </dependency>

获取Content-Type 主要是用到其中detect的通过源码我们可以得知(源码太长了就不放了)detect支持通过传入String(文件名)、URL、File、Path、byte[]、InputStream等类型来解析以获取Content-Type

我们用传入byte[]的方式测试一下:

public static void main(String[] args) {
        File file = new File("D:\\书籍\\电子书\\其它\\自然哲学的数学原理.pdf");
        byte[] fileContent = new byte[(int) file.length()];
        try (FileInputStream inputStream = new FileInputStream(file)) {
            inputStream.read(fileContent);
        } catch (IOException e) {
            e.printStackTrace();
        }
        Tika tika = new Tika();
        String mediaTypeString = tika.detect(fileContent);
        System.out.println(mediaTypeString);
    }

输出结果:

application/pdf

注意tika.detect返回的是String类型,如果想像第一种方式一样得到MediaType对象,还需要转换一下。

 MediaType.parseMediaType(mediaTypeString);
06-17 18:47