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 */ 016package org.springframework.web.reactive.accept; 017 018import java.util.ArrayList; 019import java.util.Collections; 020import java.util.List; 021import java.util.Locale; 022import java.util.Map; 023import java.util.concurrent.ConcurrentHashMap; 024 025import org.springframework.http.MediaType; 026import org.springframework.http.MediaTypeFactory; 027import org.springframework.util.Assert; 028import org.springframework.util.StringUtils; 029import org.springframework.web.server.NotAcceptableStatusException; 030import org.springframework.web.server.ServerWebExchange; 031 032/** 033 * Resolver that checks a query parameter and uses it to lookup a matching 034 * MediaType. Lookup keys can be registered or as a fallback 035 * {@link MediaTypeFactory} can be used to perform a lookup. 036 * 037 * @author Rossen Stoyanchev 038 * @since 5.0 039 */ 040public class ParameterContentTypeResolver implements RequestedContentTypeResolver { 041 042 /** Primary lookup for media types by key (e.g. "json" -> "application/json") */ 043 private final Map<String, MediaType> mediaTypes = new ConcurrentHashMap<>(64); 044 045 private String parameterName = "format"; 046 047 048 public ParameterContentTypeResolver(Map<String, MediaType> mediaTypes) { 049 mediaTypes.forEach((key, value) -> this.mediaTypes.put(formatKey(key), value)); 050 } 051 052 private static String formatKey(String key) { 053 return key.toLowerCase(Locale.ENGLISH); 054 } 055 056 057 /** 058 * Set the name of the parameter to use to determine requested media types. 059 * <p>By default this is set to {@literal "format"}. 060 */ 061 public void setParameterName(String parameterName) { 062 Assert.notNull(parameterName, "'parameterName' is required"); 063 this.parameterName = parameterName; 064 } 065 066 public String getParameterName() { 067 return this.parameterName; 068 } 069 070 071 @Override 072 public List<MediaType> resolveMediaTypes(ServerWebExchange exchange) throws NotAcceptableStatusException { 073 String key = exchange.getRequest().getQueryParams().getFirst(getParameterName()); 074 if (!StringUtils.hasText(key)) { 075 return MEDIA_TYPE_ALL_LIST; 076 } 077 key = formatKey(key); 078 MediaType match = this.mediaTypes.get(key); 079 if (match == null) { 080 match = MediaTypeFactory.getMediaType("filename." + key) 081 .orElseThrow(() -> { 082 List<MediaType> supported = new ArrayList<>(this.mediaTypes.values()); 083 return new NotAcceptableStatusException(supported); 084 }); 085 } 086 this.mediaTypes.putIfAbsent(key, match); 087 return Collections.singletonList(match); 088 } 089 090}