001/* 002 * Copyright 2002-2017 the original author or authors. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * https://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016 017package org.springframework.web.accept; 018 019import java.util.Map; 020import javax.servlet.ServletContext; 021 022import org.springframework.core.io.Resource; 023import org.springframework.http.MediaType; 024import org.springframework.util.Assert; 025import org.springframework.util.StringUtils; 026import org.springframework.web.HttpMediaTypeNotAcceptableException; 027import org.springframework.web.context.request.NativeWebRequest; 028 029/** 030 * Extends {@code PathExtensionContentNegotiationStrategy} that also uses 031 * {@link ServletContext#getMimeType(String)} to resolve file extensions. 032 * 033 * @author Rossen Stoyanchev 034 * @since 3.2 035 */ 036public class ServletPathExtensionContentNegotiationStrategy extends PathExtensionContentNegotiationStrategy { 037 038 private final ServletContext servletContext; 039 040 041 /** 042 * Create an instance without any mappings to start with. Mappings may be 043 * added later when extensions are resolved through 044 * {@link ServletContext#getMimeType(String)} or via JAF. 045 */ 046 public ServletPathExtensionContentNegotiationStrategy(ServletContext context) { 047 this(context, null); 048 } 049 050 /** 051 * Create an instance with the given extension-to-MediaType lookup. 052 */ 053 public ServletPathExtensionContentNegotiationStrategy( 054 ServletContext servletContext, Map<String, MediaType> mediaTypes) { 055 056 super(mediaTypes); 057 Assert.notNull(servletContext, "ServletContext is required"); 058 this.servletContext = servletContext; 059 } 060 061 062 /** 063 * Resolve file extension via {@link ServletContext#getMimeType(String)} 064 * and also delegate to base class for a potential JAF lookup. 065 */ 066 @Override 067 protected MediaType handleNoMatch(NativeWebRequest webRequest, String extension) 068 throws HttpMediaTypeNotAcceptableException { 069 070 MediaType mediaType = null; 071 if (this.servletContext != null) { 072 String mimeType = this.servletContext.getMimeType("file." + extension); 073 if (StringUtils.hasText(mimeType)) { 074 mediaType = MediaType.parseMediaType(mimeType); 075 } 076 } 077 if (mediaType == null || MediaType.APPLICATION_OCTET_STREAM.equals(mediaType)) { 078 MediaType superMediaType = super.handleNoMatch(webRequest, extension); 079 if (superMediaType != null) { 080 mediaType = superMediaType; 081 } 082 } 083 return mediaType; 084 } 085 086 /** 087 * Extends the base class 088 * {@link PathExtensionContentNegotiationStrategy#getMediaTypeForResource} 089 * with the ability to also look up through the ServletContext. 090 * @param resource the resource to look up 091 * @return the MediaType for the extension, or {@code null} if none found 092 * @since 4.3 093 */ 094 public MediaType getMediaTypeForResource(Resource resource) { 095 MediaType mediaType = null; 096 if (this.servletContext != null) { 097 String mimeType = this.servletContext.getMimeType(resource.getFilename()); 098 if (StringUtils.hasText(mimeType)) { 099 mediaType = MediaType.parseMediaType(mimeType); 100 } 101 } 102 if (mediaType == null || MediaType.APPLICATION_OCTET_STREAM.equals(mediaType)) { 103 MediaType superMediaType = super.getMediaTypeForResource(resource); 104 if (superMediaType != null) { 105 mediaType = superMediaType; 106 } 107 } 108 return mediaType; 109 } 110 111}