提交 e1b9c185 编写于 作者: A Arjen Poutsma

Added defaultViews property.

上级 ef67fc24
...@@ -37,9 +37,10 @@ import org.springframework.core.OrderComparator; ...@@ -37,9 +37,10 @@ import org.springframework.core.OrderComparator;
import org.springframework.core.Ordered; import org.springframework.core.Ordered;
import org.springframework.core.io.ClassPathResource; import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource; import org.springframework.core.io.Resource;
import org.springframework.http.MediaType;
import org.springframework.util.Assert; import org.springframework.util.Assert;
import org.springframework.util.ClassUtils; import org.springframework.util.ClassUtils;
import org.springframework.http.MediaType; import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils; import org.springframework.util.StringUtils;
import org.springframework.web.context.request.RequestAttributes; import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder; import org.springframework.web.context.request.RequestContextHolder;
...@@ -73,7 +74,11 @@ import org.springframework.web.util.WebUtils; ...@@ -73,7 +74,11 @@ import org.springframework.web.util.WebUtils;
* {@code text/html} content type (based on the {@code html} file extension). A request for {@code /view} with a {@code * {@code text/html} content type (based on the {@code html} file extension). A request for {@code /view} with a {@code
* text/html} request {@code Accept} header has the same result. * text/html} request {@code Accept} header has the same result.
* *
* <p>Additionally, this view resolver exposes the {@link #setDefaultViews(List) defaultViews} property, allowing you to
* override the views provided by the view resolvers.
*
* @author Arjen Poutsma * @author Arjen Poutsma
* @author Jeremy Grelle
* @see ViewResolver * @see ViewResolver
* @see InternalResourceViewResolver * @see InternalResourceViewResolver
* @see BeanNameViewResolver * @see BeanNameViewResolver
...@@ -94,6 +99,8 @@ public class ContentNegotiatingViewResolver extends WebApplicationObjectSupport ...@@ -94,6 +99,8 @@ public class ContentNegotiatingViewResolver extends WebApplicationObjectSupport
private ConcurrentMap<String, MediaType> mediaTypes = new ConcurrentHashMap<String, MediaType>(); private ConcurrentMap<String, MediaType> mediaTypes = new ConcurrentHashMap<String, MediaType>();
private List<View> defaultViews;
private List<ViewResolver> viewResolvers; private List<ViewResolver> viewResolvers;
public void setOrder(int order) { public void setOrder(int order) {
...@@ -131,6 +138,13 @@ public class ContentNegotiatingViewResolver extends WebApplicationObjectSupport ...@@ -131,6 +138,13 @@ public class ContentNegotiatingViewResolver extends WebApplicationObjectSupport
} }
} }
/**
* Sets the default views to use when a more specific view can not be obtained from the {@link ViewResolver} chain.
*/
public void setDefaultViews(List<View> defaultViews) {
this.defaultViews = defaultViews;
}
/** /**
* Sets the view resolvers to be wrapped by this view resolver. * Sets the view resolvers to be wrapped by this view resolver.
* *
...@@ -235,16 +249,23 @@ public class ContentNegotiatingViewResolver extends WebApplicationObjectSupport ...@@ -235,16 +249,23 @@ public class ContentNegotiatingViewResolver extends WebApplicationObjectSupport
Collections.sort(requestedMediaTypes); Collections.sort(requestedMediaTypes);
SortedMap<MediaType, View> views = new TreeMap<MediaType, View>(); SortedMap<MediaType, View> views = new TreeMap<MediaType, View>();
List<View> candidateViews = new ArrayList<View>();
for (ViewResolver viewResolver : viewResolvers) { for (ViewResolver viewResolver : viewResolvers) {
View view = viewResolver.resolveViewName(viewName, locale); View view = viewResolver.resolveViewName(viewName, locale);
if (view != null) { if (view != null) {
MediaType viewMediaType = MediaType.parseMediaType(view.getContentType()); candidateViews.add(view);
for (MediaType requestedMediaType : requestedMediaTypes) { }
if (requestedMediaType.includes(viewMediaType)) { }
if (!views.containsKey(requestedMediaType)) { if (!CollectionUtils.isEmpty(defaultViews)) {
views.put(requestedMediaType, view); candidateViews.addAll(defaultViews);
break; }
} for (View candidateView : candidateViews) {
MediaType viewMediaType = MediaType.parseMediaType(candidateView.getContentType());
for (MediaType requestedMediaType : requestedMediaTypes) {
if (requestedMediaType.includes(viewMediaType)) {
if (!views.containsKey(requestedMediaType)) {
views.put(requestedMediaType, candidateView);
break;
} }
} }
} }
......
...@@ -18,23 +18,26 @@ package org.springframework.web.servlet.view; ...@@ -18,23 +18,26 @@ package org.springframework.web.servlet.view;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Locale; import java.util.Locale;
import java.util.Map;
import static org.easymock.EasyMock.*; import static org.easymock.EasyMock.*;
import static org.junit.Assert.assertEquals; import static org.junit.Assert.*;
import static org.junit.Assert.assertSame;
import org.junit.Before; import org.junit.Before;
import org.junit.Test; import org.junit.Test;
import org.springframework.mock.web.MockHttpServletRequest;
import org.springframework.http.MediaType; import org.springframework.http.MediaType;
import org.springframework.mock.web.MockHttpServletRequest;
import org.springframework.web.context.request.RequestContextHolder; import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes; import org.springframework.web.context.request.ServletRequestAttributes;
import org.springframework.web.servlet.View; import org.springframework.web.servlet.View;
import org.springframework.web.servlet.ViewResolver; import org.springframework.web.servlet.ViewResolver;
/** @author Arjen Poutsma */ /**
* @author Arjen Poutsma
*/
public class ContentNegotiatingViewResolverTests { public class ContentNegotiatingViewResolverTests {
private ContentNegotiatingViewResolver viewResolver; private ContentNegotiatingViewResolver viewResolver;
...@@ -109,7 +112,45 @@ public class ContentNegotiatingViewResolverTests { ...@@ -109,7 +112,45 @@ public class ContentNegotiatingViewResolverTests {
verify(viewResolverMock1, viewResolverMock2, viewMock1, viewMock2); verify(viewResolverMock1, viewResolverMock2, viewMock1, viewMock2);
} }
@Test
public void resolveViewNameAcceptHeaderDefaultView() throws Exception {
MockHttpServletRequest request = new MockHttpServletRequest("GET", "/test");
request.addHeader("Accept", "application/json");
RequestContextHolder.setRequestAttributes(new ServletRequestAttributes(request));
ViewResolver viewResolverMock1 = createMock(ViewResolver.class);
ViewResolver viewResolverMock2 = createMock(ViewResolver.class);
List<ViewResolver> viewResolverMocks = new ArrayList<ViewResolver>();
viewResolverMocks.add(viewResolverMock1);
viewResolverMocks.add(viewResolverMock2);
viewResolver.setViewResolvers(viewResolverMocks);
View viewMock1 = createMock("application_xml", View.class);
View viewMock2 = createMock("text_html", View.class);
View viewMock3 = createMock("application_json", View.class);
List<View> defaultViews = new ArrayList<View>();
defaultViews.add(viewMock3);
viewResolver.setDefaultViews(defaultViews);
String viewName = "view";
Locale locale = Locale.ENGLISH;
expect(viewResolverMock1.resolveViewName(viewName, locale)).andReturn(viewMock1);
expect(viewResolverMock2.resolveViewName(viewName, locale)).andReturn(viewMock2);
expect(viewMock1.getContentType()).andReturn("application/xml");
expect(viewMock2.getContentType()).andReturn("text/html;charset=ISO-8859-1");
expect(viewMock3.getContentType()).andReturn("application/json");
replay(viewResolverMock1, viewResolverMock2, viewMock1, viewMock2, viewMock3);
View result = viewResolver.resolveViewName(viewName, locale);
assertSame("Invalid view", viewMock3, result);
verify(viewResolverMock1, viewResolverMock2, viewMock1, viewMock2, viewMock3);
}
@Test @Test
public void resolveViewNameFilename() throws Exception { public void resolveViewNameFilename() throws Exception {
MockHttpServletRequest request = new MockHttpServletRequest("GET", "/test.html"); MockHttpServletRequest request = new MockHttpServletRequest("GET", "/test.html");
...@@ -141,4 +182,45 @@ public class ContentNegotiatingViewResolverTests { ...@@ -141,4 +182,45 @@ public class ContentNegotiatingViewResolverTests {
verify(viewResolverMock1, viewResolverMock2, viewMock1, viewMock2); verify(viewResolverMock1, viewResolverMock2, viewMock1, viewMock2);
} }
@Test
public void resolveViewNameFilenameDefaultView() throws Exception {
MockHttpServletRequest request = new MockHttpServletRequest("GET", "/test.json");
RequestContextHolder.setRequestAttributes(new ServletRequestAttributes(request));
Map<String, String> mediaTypes = new HashMap<String, String>();
mediaTypes.put("json", "application/json");
viewResolver.setMediaTypes(mediaTypes);
ViewResolver viewResolverMock1 = createMock(ViewResolver.class);
ViewResolver viewResolverMock2 = createMock(ViewResolver.class);
List<ViewResolver> viewResolverMocks = new ArrayList<ViewResolver>();
viewResolverMocks.add(viewResolverMock1);
viewResolverMocks.add(viewResolverMock2);
viewResolver.setViewResolvers(viewResolverMocks);
View viewMock1 = createMock("application_xml", View.class);
View viewMock2 = createMock("text_html", View.class);
View viewMock3 = createMock("application_json", View.class);
List<View> defaultViews = new ArrayList<View>();
defaultViews.add(viewMock3);
viewResolver.setDefaultViews(defaultViews);
String viewName = "view";
Locale locale = Locale.ENGLISH;
expect(viewResolverMock1.resolveViewName(viewName, locale)).andReturn(viewMock1);
expect(viewResolverMock2.resolveViewName(viewName, locale)).andReturn(viewMock2);
expect(viewMock1.getContentType()).andReturn("application/xml");
expect(viewMock2.getContentType()).andReturn("text/html;charset=ISO-8859-1");
expect(viewMock3.getContentType()).andReturn("application/json");
replay(viewResolverMock1, viewResolverMock2, viewMock1, viewMock2, viewMock3);
View result = viewResolver.resolveViewName(viewName, locale);
assertSame("Invalid view", viewMock3, result);
verify(viewResolverMock1, viewResolverMock2, viewMock1, viewMock2, viewMock3);
}
} }
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册