We have seen how content-negotiation works in spring. In this example, we will utilize ParameterContentNegotiationStrategy by turning it on. We will, then, specify a media type in query parameter with the name 'format' e.g. we will send an extra parameter similar to "http:/www.example.com/app?format=xml".
Example
Turning on ParameterContentNegotiationStrategy
@EnableWebMvc
@Configuration
@ComponentScan
public class MyWebConfig extends WebMvcConfigurerAdapter {
@Override
public void configureContentNegotiation (ContentNegotiationConfigurer configurer) {
configurer.favorParameter(true);
}
}
Writing Controller
@Controller
@RequestMapping("user")
public class UserController {
@RequestMapping(produces = MediaType.APPLICATION_XML_VALUE)
@ResponseBody
public User getUserById (@RequestParam("id") long userId) {
//creating dummy user
User user = new User();
user.setId(userId);
user.setName("joe");
user.setEmailAddress("joe@example.com");
return user;
}
@RequestMapping
@ResponseBody
public String getUserStringById (@RequestParam("id") long userId) {
return "joe, id: "+userId;
}
}
@XmlRootElement
public class User implements Serializable {
private Long id;
private String name;
private String password;
private String emailAddress;
.............
}
Writing JUnit tests
In this test, we will make request without 'format' param:
@RunWith(SpringJUnit4ClassRunner.class)
@WebAppConfiguration
@ContextConfiguration(classes = MyWebConfig.class)
public class UserTests {
@Autowired
private WebApplicationContext wac;
private MockMvc mockMvc;
.............
@Test
public void testUserRequestWithoutFormatParam () throws Exception {
MockHttpServletRequestBuilder builder =
MockMvcRequestBuilders.get("/user")
.param("id", "10");
this.mockMvc.perform(builder)
.andExpect(MockMvcResultMatchers.status()
.isOk())
.andDo(MockMvcResultHandlers.print());
}
.............
} Outputmvn -q test -Dtest=UserTests#testUserRequestWithoutFormatParam
MockHttpServletRequest: HTTP Method = GET Request URI = /user Parameters = {id=[10]} Headers = {}
Handler: Type = com.logicbig.example.UserController Method = public java.lang.String com.logicbig.example.UserController.getUserStringById(long)
Async: Async started = false Async result = null
Resolved Exception: Type = null
ModelAndView: View name = null View = null Model = null
FlashMap: Attributes = null
MockHttpServletResponse: Status = 200 Error message = null Headers = {Content-Type=[text/plain;charset=ISO-8859-1], Content-Length=[11]} Content type = text/plain;charset=ISO-8859-1 Body = joe, id: 10 Forwarded URL = null Redirected URL = null Cookies = []
In above output, the test request maps to the handler method which returns String. Now let's use format=xml param with the request:
@RunWith(SpringJUnit4ClassRunner.class)
@WebAppConfiguration
@ContextConfiguration(classes = MyWebConfig.class)
public class UserTests {
@Autowired
private WebApplicationContext wac;
private MockMvc mockMvc;
.............
@Test
public void testUserRequestWithFormatParam () throws Exception {
MockHttpServletRequestBuilder builder =
MockMvcRequestBuilders.get("/user")
.param("format", "xml")
.param("id", "10");
this.mockMvc.perform(builder)
.andExpect(MockMvcResultMatchers.status()
.isOk())
.andDo(MockMvcResultHandlers.print());
}
} Outputmvn -q test -Dtest=UserTests#testUserRequestWithFormatParam
MockHttpServletRequest: HTTP Method = GET Request URI = /user Parameters = {format=[xml], id=[10]} Headers = {}
Handler: Type = com.logicbig.example.UserController Method = public com.logicbig.example.User com.logicbig.example.UserController.getUserById(long)
Async: Async started = false Async result = null
Resolved Exception: Type = null
ModelAndView: View name = null View = null Model = null
FlashMap: Attributes = null
MockHttpServletResponse: Status = 200 Error message = null Headers = {Content-Type=[application/xml]} Content type = application/xml Body = <?xml version="1.0" encoding="UTF-8" standalone="yes"?><user><emailAddress>joe@example.com</emailAddress><id>10</id><name>joe</name></user> Forwarded URL = null Redirected URL = null Cookies = []
As seen in the output, we got xml output in the body.
Output on the browser
For our example, the chrome (Version 59.0.3071.115) will always get xml response that's because by default it sends following 'Accept' headers with GET requests:
Accept:text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8
That means HeaderContentNegotiationStrategy will match the more specific media type (xml). One way to test our code is to turn off HeaderContentNegotiationStrategy on the application side:
@EnableWebMvc
@Configuration
@ComponentScan
public class MyWebConfig extends WebMvcConfigurerAdapter {
@Override
public void configureContentNegotiation (ContentNegotiationConfigurer configurer) {
configurer.favorParameter(true);
configurer.ignoreAcceptHeader(true);
}
}
Now we can have expected results in the browser:
URL: http://localhost:8080/user?id=2
URL: http://localhost:8080/user?id=2&format=xml
Example ProjectDependencies and Technologies Used: - spring-webmvc 4.3.9.RELEASE: Spring Web MVC.
- spring-test 4.3.9.RELEASE: Spring TestContext Framework.
- javax.servlet-api 3.1.0 Java Servlet API
- junit 4.12: JUnit is a unit testing framework for Java, created by Erich Gamma and Kent Beck.
- JDK 1.8
- Maven 3.3.9
|