diff --git a/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/view/ContentNegotiatingViewResolver.java b/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/view/ContentNegotiatingViewResolver.java index c27eee3497..674aac4851 100644 --- a/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/view/ContentNegotiatingViewResolver.java +++ b/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/view/ContentNegotiatingViewResolver.java @@ -56,19 +56,26 @@ import org.springframework.web.util.WebUtils; * *
The {@code ContentNegotiatingViewResolver} does not resolve views itself, but delegates to other {@link * ViewResolver}s. By default, these other view resolvers are picked up automatically from the application context, - * though they can also be set explicitely by using the {@link #setViewResolvers(List) viewResolvers} property. + * though they can also be set explicitly by using the {@link #setViewResolvers(List) viewResolvers} property. * Note that in order for this view resolver to work properly, the {@link #setOrder(int) order} * property needs to be set to a higher precedence than the others (the default is {@link Ordered#HIGHEST_PRECEDENCE}.) * *
This view resolver uses the requested {@linkplain MediaType media type} to select a suitable {@link View} for a - * request. This media type is determined by using the following criteria:
true
, the {@link
- * #setMediaTypes(Map) mediaTypes} property is inspected for a matching media type.true
, the {@link #setMediaTypes(Map) mediaTypes} property is inspected for a matching media type.true
, the {@link #setMediaTypes(Map) mediaTypes} property is inspected for a matching media
+ * type. The default name of the parameter is format
and it can be configured using the
+ * {@link #setParameterName(String) parameterName} property.For example, if the request path is {@code /view.html}, this view resolver will look for a view that has the
* {@code text/html} content type (based on the {@code html} file extension). A request for {@code /view} with a {@code
@@ -78,7 +85,7 @@ import org.springframework.web.util.WebUtils;
* override the views provided by the view resolvers.
*
* @author Arjen Poutsma
- * @author Jeremy Grelle
+ * @author Rostislav Hristov
* @see ViewResolver
* @see InternalResourceViewResolver
* @see BeanNameViewResolver
@@ -95,6 +102,10 @@ public class ContentNegotiatingViewResolver extends WebApplicationObjectSupport
private boolean favorPathExtension = true;
+ private boolean favorParameter = false;
+
+ private String parameterName = "format";
+
private int order = Ordered.HIGHEST_PRECEDENCE;
private ConcurrentMap For instance, when this flag is For instance, when this flag is The default implementation will check the {@linkplain #setMediaTypes(Map) media types} property for a
+ * defined mapping.
+ *
+ * This method can be overriden to provide a different algorithm.
+ *
+ * @param parameterValue the parameter value (i.e. {@code pdf}).
+ * @return the media type, if any
+ */
+ protected MediaType getMediaTypeFromParameter(String parameterValue) {
+ parameterValue = parameterValue.toLowerCase(Locale.ENGLISH);
+ return mediaTypes.get(parameterValue);
+ }
public View resolveViewName(String viewName, Locale locale) throws Exception {
RequestAttributes attrs = RequestContextHolder.getRequestAttributes();
diff --git a/org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/view/ContentNegotiatingViewResolverTests.java b/org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/view/ContentNegotiatingViewResolverTests.java
index d78c0a8e0f..9eb0e93f90 100644
--- a/org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/view/ContentNegotiatingViewResolverTests.java
+++ b/org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/view/ContentNegotiatingViewResolverTests.java
@@ -66,6 +66,17 @@ public class ContentNegotiatingViewResolverTests {
assertEquals("Invalid content type", Collections.singletonList(new MediaType("application", "xhtml+xml")),
result);
}
+
+ @Test
+ public void getMediaTypeParameter() {
+ viewResolver.setFavorParameter(true);
+ viewResolver.setMediaTypes(Collections.singletonMap("html", "application/xhtml+xml"));
+ MockHttpServletRequest request = new MockHttpServletRequest("GET", "/test");
+ request.addParameter("format", "html");
+ Listtrue
(the default), a request for {@code /hotels.pdf} will result in
* an {@code AbstractPdfView} being resolved, while the {@code Accept} header can be the browser-defined {@code
@@ -123,6 +134,26 @@ public class ContentNegotiatingViewResolver extends WebApplicationObjectSupport
this.favorPathExtension = favorPathExtension;
}
+ /**
+ * Indicates whether a request parameter should be used to determine the requested media type, in favor
+ * of looking at the {@code Accept} header. The default value is {@code false}.
+ *
+ * true
, a request for {@code /hotels?format=pdf} will result in
+ * an {@code AbstractPdfView} being resolved, while the {@code Accept} header can be the browser-defined {@code
+ * text/html,application/xhtml+xml}.
+ */
+ public void setFavorParameter(boolean favorParameter) {
+ this.favorParameter = favorParameter;
+ }
+
+ /**
+ * Sets the parameter name that can be used to determine the requested media type if the
+ * {@link #setFavorParameter(boolean)} property is {@code true}. The default parameter name is {@code format}.
+ */
+ public void setParameterName(String parameterName) {
+ this.parameterName = parameterName;
+ }
+
/**
* Sets the mapping from file extensions to media types.
*
@@ -200,6 +231,21 @@ public class ContentNegotiatingViewResolver extends WebApplicationObjectSupport
return mediaTypes;
}
}
+ if (favorParameter) {
+ if (request.getParameter(parameterName) != null) {
+ String parameterValue = request.getParameter(parameterName);
+ MediaType mediaType = getMediaTypeFromParameter(parameterValue);
+ if (mediaType != null) {
+ if (logger.isDebugEnabled()) {
+ logger.debug("Requested media type is '" + mediaType + "' (based on parameter '" +
+ parameterValue + "')");
+ }
+ List