Added defaultViews property.
This commit is contained in:
parent
ef67fc245f
commit
e1b9c18536
|
|
@ -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;
|
||||||
* {@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
|
||||||
|
|
||||||
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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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
|
||||||
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;
|
||||||
|
|
||||||
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 {
|
||||||
|
|
||||||
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 {
|
||||||
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);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue