Spring Boot returns content type solution

background

The front-end students need to return the content type field to return different types according to different file types. In addition, they need to directly open a download link, which actually supports the effect of adaptive preview for browsers like Chrome. https://tool.oschina.net/commons/ There are many content type types in the links here! To get this question, previous partners have written several if else judgment images, documents, etc., but the support is not very comprehensive. Who knows what format type to return later? If else can't solve the problem fundamentally. ps: I don't want to be so tired as a programmer. There must be a solution.

Solution

RestTemplate get contentType of file This article has given me a lot of information. As a big spring guy, there are many solutions. org/springframework/http/converter/ActivationMediaTypeFactory.java is a class that deals with the reading file and the content type corresponding to the file name in detail. This class does not exist above spring boot 2.0 +.
spring-web-5.2.3.RELEASE.jar!/org/springframework/http/mime.types

The last is the suffix of the file, followed by the content type

video/webm					webm
video/x-f4v					f4v
video/x-fli					fli
video/x-flv					flv
video/x-m4v					m4v
video/x-matroska				mkv mk3d mks
video/x-mng					mng
video/x-ms-asf					asf asx
video/x-ms-vob					vob
video/x-ms-wm					wm
video/x-ms-wmv					wmv
video/x-ms-wmx					wmx
video/x-ms-wvx					wvx
video/x-msvideo					avi
video/x-sgi-movie				movie
video/x-smv					smv
x-conference/x-cooltalk				ice

spring-web 5.0+

org.springframework.http.MediaTypeFactory, simple to implement, clearer than the 4.0 + version, can be used independently

/*
 * Copyright 2002-2019 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.springframework.http;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;
import java.util.Collections;
import java.util.List;
import java.util.Locale;
import java.util.Optional;

import org.springframework.core.io.Resource;
import org.springframework.lang.Nullable;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.util.StringUtils;

/**
 * A factory delegate for resolving {@link MediaType} objects
 * from {@link Resource} handles or filenames.
 *
 * @author Juergen Hoeller
 * @author Arjen Poutsma
 * @since 5.0
 */
public final class MediaTypeFactory {

	private static final String MIME_TYPES_FILE_NAME = "/org/springframework/http/mime.types";

	private static final MultiValueMap<String, MediaType> fileExtensionToMediaTypes = parseMimeTypes();


	private MediaTypeFactory() {
	}


	/**
	 * Parse the {@code mime.types} file found in the resources. Format is:
	 * <code>
	 * # comments begin with a '#'<br>
	 * # the format is &lt;mime type> &lt;space separated file extensions><br>
	 * # for example:<br>
	 * text/plain    txt text<br>
	 * # this would map file.txt and file.text to<br>
	 * # the mime type "text/plain"<br>
	 * </code>
	 * @return a multi-value map, mapping media types to file extensions.
	 */
	private static MultiValueMap<String, MediaType> parseMimeTypes() {
		InputStream is = MediaTypeFactory.class.getResourceAsStream(MIME_TYPES_FILE_NAME);
		try (BufferedReader reader = new BufferedReader(new InputStreamReader(is, StandardCharsets.US_ASCII))) {
			MultiValueMap<String, MediaType> result = new LinkedMultiValueMap<>();
			String line;
			while ((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]);
				for (int i = 1; i < tokens.length; i++) {
					String fileExtension = tokens[i].toLowerCase(Locale.ENGLISH);
					result.add(fileExtension, mediaType);
				}
			}
			return result;
		}
		catch (IOException ex) {
			throw new IllegalStateException("Could not load '" + MIME_TYPES_FILE_NAME + "'", ex);
		}
	}

	/**
	 * Determine a media type for the given resource, if possible.
	 * @param resource the resource to introspect
	 * @return the corresponding media type, or {@code null} if none found
	 */
	public static Optional<MediaType> getMediaType(@Nullable Resource resource) {
		return Optional.ofNullable(resource)
				.map(Resource::getFilename)
				.flatMap(MediaTypeFactory::getMediaType);
	}

	/**
	 * Determine a media type for the given file name, if possible.
	 * @param filename the file name plus extension
	 * @return the corresponding media type, or {@code null} if none found
	 */
	public static Optional<MediaType> getMediaType(@Nullable String filename) {
		return getMediaTypes(filename).stream().findFirst();
	}

	/**
	 * Determine the media types for the given file name, if possible.
	 * @param filename the file name plus extension
	 * @return the corresponding media types, or an empty list if none found
	 */
	public static List<MediaType> getMediaTypes(@Nullable String filename) {
		return Optional.ofNullable(StringUtils.getFilenameExtension(filename))
				.map(s -> s.toLowerCase(Locale.ENGLISH))
				.map(fileExtensionToMediaTypes::get)
				.orElse(Collections.emptyList());
	}

}

Alibaba cloud oss sdk aliyun-sdk-oss-3.8.1

In the search of mime.types, we found that the content type in oss sdk is very rich.
/aliyun-sdk-oss-3.8.1.jar!/mime.types

#Extentions    MIME type
xlsx    application/vnd.openxmlformats-officedocument.spreadsheetml.sheet
xltx    application/vnd.openxmlformats-officedocument.spreadsheetml.template
potx    application/vnd.openxmlformats-officedocument.presentationml.template
ppsx    application/vnd.openxmlformats-officedocument.presentationml.slideshow
pptx    application/vnd.openxmlformats-officedocument.presentationml.presentation
sldx    application/vnd.openxmlformats-officedocument.presentationml.slide
docx    application/vnd.openxmlformats-officedocument.wordprocessingml.document
dotx    application/vnd.openxmlformats-officedocument.wordprocessingml.template
xlam    application/vnd.ms-excel.addin.macroEnabled.12
xlsb    application/vnd.ms-excel.sheet.binary.macroEnabled.12
apk    application/vnd.android.package-archive

And the processing of spring boot, which is a lot simplified here.

package com.aliyun.oss.internal;

import static com.aliyun.oss.common.utils.LogUtils.getLog;

import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.HashMap;
import java.util.StringTokenizer;

/**
 * Utility class used to determine the mimetype of files based on file
 * extensions.
 */
public class Mimetypes {

    /* The default MIME type */
    public static final String DEFAULT_MIMETYPE = "application/octet-stream";

    private static Mimetypes mimetypes = null;

    private HashMap<String, String> extensionToMimetypeMap = new HashMap<String, String>();

    private Mimetypes() {
    }

    public synchronized static Mimetypes getInstance() {
        if (mimetypes != null)
            return mimetypes;

        mimetypes = new Mimetypes();
        InputStream is = mimetypes.getClass().getResourceAsStream("/mime.types");
        if (is != null) {
            getLog().debug("Loading mime types from file in the classpath: mime.types");

            try {
                mimetypes.loadMimetypes(is);
            } catch (IOException e) {
                getLog().error("Failed to load mime types from file in the classpath: mime.types", e);
            } finally {
                try {
                    is.close();
                } catch (IOException ex) {
                }
            }
        } else {
            getLog().warn("Unable to find 'mime.types' file in classpath");
        }
        return mimetypes;
    }

    public void loadMimetypes(InputStream is) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(is));
        String line = null;

        while ((line = br.readLine()) != null) {
            line = line.trim();

            if (line.startsWith("#") || line.length() == 0) {
                // Ignore comments and empty lines.
            } else {
                StringTokenizer st = new StringTokenizer(line, " \t");
                if (st.countTokens() > 1) {
                    String extension = st.nextToken();
                    if (st.hasMoreTokens()) {
                        String mimetype = st.nextToken();
                        extensionToMimetypeMap.put(extension.toLowerCase(), mimetype);
                    }
                }
            }
        }
    }

    public String getMimetype(String fileName) {
        String mimeType = getMimetypeByExt(fileName);
        if (mimeType != null) {
            return mimeType;
        }
        return DEFAULT_MIMETYPE;
    }

    public String getMimetype(File file) {
        return getMimetype(file.getName());
    }

    public String getMimetype(File file, String key) {
        return getMimetype(file.getName(), key);
    }

    public String getMimetype(String primaryObject, String secondaryObject) {
        String mimeType = getMimetypeByExt(primaryObject);
        if (mimeType != null) {
            return mimeType;
        }

        mimeType = getMimetypeByExt(secondaryObject);
        if (mimeType != null) {
            return mimeType;
        }

        return DEFAULT_MIMETYPE;
    }

    private String getMimetypeByExt(String fileName) {
        int lastPeriodIndex = fileName.lastIndexOf(".");
        if (lastPeriodIndex > 0 && lastPeriodIndex + 1 < fileName.length()) {
            String ext = fileName.substring(lastPeriodIndex + 1).toLowerCase();
            if (extensionToMimetypeMap.keySet().contains(ext)) {
                String mimetype = (String) extensionToMimetypeMap.get(ext);
                return mimetype;
            }
        }
        return null;
    }
}

practice

maven dependence

<dependency>
  <groupId>com.aliyun.oss</groupId>
  <artifactId>aliyun-sdk-oss</artifactId>
  <version>3.8.1</version>
</dependency>
<dependency>
  <groupId>commons-io</groupId>
  <artifactId>commons-io</artifactId>
  <version>20030203.000550</version>
</dependency>
<parent>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-parent</artifactId>
  <version>2.2.4.RELEASE</version>
  <relativePath/> <!-- lookup parent from repository -->
</parent>

Source code

If you feel that the response types in mime.types are not rich enough, you can add them to the classpath for full coverage.

package com.wangji92.github.study.controller;

import com.aliyun.oss.internal.Mimetypes;
import lombok.extern.slf4j.Slf4j;
import org.apache.catalina.connector.ClientAbortException;
import org.apache.commons.io.IOUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.Resource;
import org.springframework.core.io.ResourceLoader;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.MediaTypeFactory;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.InputStream;
import java.io.OutputStream;

/**
 * File operation demonstration
 *
 * @author Little brother Wang
 * @date 27-02-2020
 */
@RestController
@RequestMapping("/api/fileOperation")
@Slf4j
public class FileOperationController {

    @Autowired
    private ResourceLoader resourceLoader;

    @Autowired
    private HttpServletRequest httpServletRequest;

    @Autowired
    private HttpServletResponse httpServletResponse;

    /**
     * content type https://tool.oschina.net/commons/
     * Access path: http://127.0.0.1:8080/api/fileoperation/downloadfile? Writeattachment = false & filename = test.mp3
     * http://127.0.0.1:8080/api/fileOperation/downLoadFile?writeAttachment=false&fileName=demo.jpg
     * @param fileName
     * @param writeAttachment
     */
    @RequestMapping("/downLoadFile")
    public void downLoadByType(@RequestParam(required = false) String fileName, @RequestParam boolean writeAttachment) {
        if (StringUtils.isEmpty(fileName)) {
            fileName = "demo.jpg";
        }
        /**
         * Alibaba cloud and spring can provide a variety of Alibaba cloud services, and more of them can be copied to the classpath for new expansion
         * Alicloud-sdk-oss-3.8.1.jar! / mime.types
         * spring spring-web/5.2.3.RELEASE/spring-web-5.2.3.RELEASE.jar!/org/springframework/http/mime.types
         * @see  org.springframework.http.converter.ActivationMediaTypeFactory#loadFileTypeMapFromContextSupportModule  This exists in spring web version 4.3
         * @see  org.springframework.http.MediaTypeFactory#parseMimeTypes()  This is also available. You can customize it to handle it according to the format
         */
        // Use the processing methods provided by Alibaba cloud
        String contentType = Mimetypes.getInstance().getMimetype(fileName);
        log.info("aliyun oss  mediaType {}", contentType);

        // Using the processing provided by spring
        if (MediaTypeFactory.getMediaType(fileName).isPresent()) {
            MediaType mediaType = MediaTypeFactory.getMediaType(fileName).get();
            log.info("spring mediaType {}", mediaType.toString());
        }
        httpServletResponse.addHeader(HttpHeaders.CONTENT_TYPE, contentType);

        if (writeAttachment) {
            httpServletResponse.addHeader(HttpHeaders.CONTENT_DISPOSITION, "attachment;filename=" + fileName);
        }
        OutputStream outputStream = null;
        InputStream inputStream = null;
        try {
            outputStream = httpServletResponse.getOutputStream();
            Resource resource = resourceLoader.getResource("classpath:" + fileName);
            inputStream = resource.getInputStream();
            IOUtil.copy(inputStream, httpServletResponse.getOutputStream());
        } catch (ClientAbortException e) {
            log.info("ClientAbortException ");
        } catch (Exception e) {
            log.error("fileDownLoad error", e);
        } finally {
            IOUtil.shutdownStream(outputStream);
            IOUtil.shutdownStream(inputStream);
        }
    }


}

Effect

summary

When you encounter problems, think more and think more about solutions, the code is simpler.

Published 367 original articles, won praise 174, visited 850000+
His message board follow

Keywords: Java Spring SDK Apache

Added by phpfre@k* on Sun, 01 Mar 2020 07:36:03 +0200