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 <mime type> <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.