In my spring webapp, I have an ajax servlet that answer json (using jackson):
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context" xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:util="http://www.springframework.org/schema/util" xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.2.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.2.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-3.2.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.2.xsd">
<context:component-scan base-package="com.myapp.ajax" />
<util:list id="messageConvertersList">
<bean class="org.springframework.http.converter.json.MappingJacksonHttpMessageConverter">
<property name="supportedMediaTypes">
<list>
<value>application/json;charset=UTF-8</value>
</list>
</property>
</bean>
</util:list>
<bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter">
<property name="messageConverters" ref="messageConvertersList" />
</bean>
<bean id="handlerMapping" class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping" />
<mvc:interceptors>
<mvc:interceptor>
<mvc:mapping path="/**" />
<bean id="localeChangeInterceptor" class="org.springframework.web.servlet.i18n.LocaleChangeInterceptor">
<property name="paramName" value="lang" />
</bean>
</mvc:interceptor>
</mvc:interceptors>
<bean id="localeResolver" class="org.springframework.web.servlet.i18n.SessionLocaleResolver" />
<bean id="handlerExceptionResolver" class="com.myapp.ajax.AjaxExceptionHandlerResolver">
<property name="exceptionHandler">
<bean class="com.myapp.ajax.AjaxExceptionHandler" />
</property>
<property name="messageConverters" ref="messageConvertersList" />
</bean>
I have the following ajax service:
#RequestMapping(value = "getLoggedUser")
#ResponseBody
public DtoUser getLoggedUser() {
return authenticationService.getLoggedUser();
}
When the user is logged in it returns something like:
{ userName : "jojo", email : "john.doe#email.com", firstName : "John", lastName : "Doe" }
When the user is not logged in, the expected behavior is to return
null
But it returns an empty response which is not a valid JSON response (and additionally with a bad Content-type header)
Why is this happening ?
Do I have solutions to obtain the expected behaviour ?
When the user is not logged in, the expected behavior is to return null
That's my expected behaviour because in both Java and Javascript/JSON, null is a valid value, which have a different mean than nothing, empty or error/exception.
I would expect that Spring answer the null response instead of handling it specifically.
In that case, the expected convertion for null (Java) would be null (JSON)
My expected conversion table:
Java Exception => HTTP Error Code
null => null
empty map / object => {}
void => no response
Why is this happening ?
For Spring, a controller returning null mean "No response" and not "a response which value is null". This rule applies to all controller methods including ones with #ResponseBody annotation.
This allow to write manually to the response without having something appended to the response later:
if (mySpecialCase) {
Writer writer = response.getWriter();
writer.write("my custom response");
return null;
} else {
return myObject;
}
So when returning null Spring write nothing to the response, nor Content-type header nor body.
Do I have solutions to obtain the expected behaviour ?
I made the following dirty hack: add a filter on my ajax path that write null to the response when no response have been commited.
public class AjaxEmptyResponseFilter implements Filter {
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
chain.doFilter(request, response);
if (!response.isCommitted()) {
response.setCharacterEncoding("UTF-8");
response.setContentType("application/json");
Writer writer = response.getWriter();
writer.write("null");
writer.close();
response.flushBuffer();
}
}
}
This solution handle methods answering null and method answering nothing (void) the same way.
Do you have a session filter?
I think, you can bind a global ajax event for errors and make your respective validation there.
here is a example on a similar case: How to handle expired session using spring-security and jQuery?
Related
I 'm using Spring 3.0.1.RELEASE for my webapp (and i have no way for upgrading it) and i'm trying to render some images from database on web-page.
I have following simple Spring configs:
spring-application.xml:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:task="http://www.springframework.org/schema/task"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task-3.0.xsd">
<task:annotation-driven />
<context:annotation-config />
<context:spring-configured />
<context:component-scan base-package="com.me" />
<bean id="hibernateSessionFactory" class="com.me.dbaccess.HibernateSessionFactory">
<constructor-arg ref="sessionFactory"/>
</bean>
</beans>
spring-mvc.xml:
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd">
<mvc:annotation-driven/>
<bean id="tilesViewResolver" class="com.me.util.TilesExposingBeansViewResolver">
<property name="viewClass" value="com.me.util.TilesExposingBeansView"/>
<property name="exposeContextBeansAsAttributes" value="true"/>
</bean>
<bean id="tilesConfigurer"
class="org.springframework.web.servlet.view.tiles2.TilesConfigurer">
<property name="definitions">
<list>
<value>/WEB-INF/config/tiles-defs.xml</value>
</list>
</property>
</bean>
</beans>
I have following controller:
#Controller
public class PhotoController {
#RequestMapping("/carPhoto.html")
#ResponseBody
public byte[] getCarPhoto(
#RequestParam(UrlParameters.PHOTO_ID) Integer photoId,
#RequestParam(UrlParameters.PHOTO_TYPE) String photoType) {
//return image's bytes array from db by photo Id and Type;
}
}
And finally, I have simple jsp-page:
<%#page contentType="text/html; charset=utf-8"%>
<%#taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<img id="photoImage" src="<c:url value="/carPhoto.html?photoType=1&photoId=22556793"/>" />
If I open this page - I can see this image without any problems.
But if I copy image "src" attribute and paste it in browser's address bar (Firefox 19.0.2) - then browser offers me to save carPhoto.html, instead of just render the image.
Should I perform some additional setup?
The problem is, that you have to specify the mime type (and if your image is larger you will need to specify its length too).
An other solution () is to return a Spring ResponseEntity or HttpEntity (HttpEntity is enough if you always return http status code 200, ResponseEntity (a subclass of HttpEntity) is for example needed if you want to return other http status codes, like not found).
#Controller
public class PhotoController {
#RequestMapping("/carPhoto.html")
#ResponseBody
public HttpEntity<byte[]> getCarPhoto(
#RequestParam(UrlParameters.PHOTO_ID) Integer photoId,
#RequestParam(UrlParameters.PHOTO_TYPE) String photoType) {
byte[] image = image's bytes array from db by photo Id and Type;
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.IMAGE_JPEG); //or what ever type it is
headers.setContentLength(image.length);
return new HttpEntity<byte[]>(image, headers);
}
}
There are several ways. Easiest is to use #ResponseBody with a byte[] as your return type, set your Content-Type and such, the write the bytes to the output stream using the HttpServletResponse.
A more elegant solution (IMO) would be to return a ModelAndView, then set the View on that to a custom view that sets the proper headers (Content-Type and such) and writes out the bytes to the HttpServletResponse's output stream.
i have problem with build my own webservice based on cxf/camel.
My webservice should do something like this:
I am on DomainA from which i send POST data to my webservice (CXF)
my CXF code is:
#Path("/")
#ProduceMime({ "application/json" })
public class SSO {
#POST
#Path("/user")
#ProduceMime({ "application/json" })
public String user(#FormParam("id") String token) {
}
}
My CXF code receive my id variable.
Now i want to send this variable to other url http://localhost:8080/myWebSite and wait for response from the url and after get the response send it to DomainA
my beans.xml is:
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:osgi="http://www.springframework.org/schema/osgi"
xmlns:jaxrs="http://cxf.apache.org/jaxrs"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
http://cxf.apache.org/jaxrs http://cxf.apache.org/schemas/jaxrs.xsd
http://www.springframework.org/schema/osgi http://www.springframework.org/schema/osgi/spring-osgi.xsd">
<import resource="classpath:META-INF/cxf/cxf.xml" />
<import resource="classpath:META-INF/cxf/osgi/cxf-extension-osgi.xml" />
<bean id="cxfSSO" class="com.esb.cxf.SSO" />
<jaxrs:server id="sso" address="/sso">
<jaxrs:serviceBeans>
<ref bean="cxfSSO" />
</jaxrs:serviceBeans>
</jaxrs:server>
</beans>
The easiest way is going to be a Spring RestTemplate, as this hides a huge amount of the complexity that you'd otherwise have to deal with.
The Spring documentation describes the basics, but be aware that you'll want to build the request as a MultiValueMap<String, String> so that it will be sent to the service as application/x-www-form-urlencoded.
I have used this code as the basis of my development so far : Ajax Simplifications from springsource.
Here is the html & jquery/javascript code:
<c:url var="Controller" value="/ControllerUrl" />
...
var previewDialog = $("<div></div>").dialog({
//all the dialog setttings
});
$(".opener").click(function() {
previewDialog.load("${Controller}",function(data) {
previewDialog.dialog('open');
});
return false;
});
And the controller :
#RequestMapping(value = "/ControllerUrl", method = RequestMethod.GET)
public String previewDialog(Model model) {
MyClass myClass = new MyClass();
myClass.setTitle("SUCCESS");
model.addAttribute(myClass);
return "dialogContent";
}
This is all almost working, except in dialogContent.jsp (which is indeed opened in my dialog) "SUCCESS" is not printed:
<div id="divContent">
Title : ${myClass.title} <br>
</div>
What am I missing/doing wrong ?
Secondly, what is the besy way to submit json data to server in this context - I attempted using $.ajax() and $.postJSON() but ran into problems as they work differently to the $.load() statement.
Thanks in advance.
Can you try:
In the Controller:
return new ModelAndView("view-name", "myclass", myClass);
In your JSP:
${myClass.title}
The trouble is that this would till return HTML rather than just plain text.
Also, you can probably return json or xml by changing your controller as follows:
#RequestMapping(value = "/ControllerURL", method = RequestMethod.GET, headers="Accept=application/xml, application/json")
public #ResponseBody DealManager homeXmlJson(Locale locale, Model model) {
MyClass myClass = new MyClass();
myClass.setTitle("SUCCESS");
return myClass;
}
Then when you call it using $.getJSON it should return a json representation of the object from which you should be able to extract the title.
Use a tool like REST-Client to see what is returned when you pass different Accept parameters to the controller URL. the parameter being:
Accept: text/html, Accept: application/json, Accept: application/xml
You will have to configure your rest context as well. Here is an example of one I'm using:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean
class="org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping" />
<bean
class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter">
<property name="messageConverters">
<list>
<ref bean="jsonConverter" />
<ref bean="marshallingConverter" />
<!-- <ref bean="atomConverter" /> -->
</list>
</property>
</bean>
<!-- Handle JSON Conversions -->
<bean id="jsonConverter"
class="org.springframework.http.converter.json.MappingJacksonHttpMessageConverter">
<property name="supportedMediaTypes" value="application/json" />
</bean>
<!-- Handle XML Conversion -->
<bean id="marshallingConverter"
class="org.springframework.http.converter.xml.MarshallingHttpMessageConverter">
<constructor-arg ref="jaxbMarshaller" />
<property name="supportedMediaTypes" value="application/xml" />
</bean>
<bean id="jaxbMarshaller" class="org.springframework.oxm.jaxb.Jaxb2Marshaller">
<property name="classesToBeBound">
<list>
<value>com.pack1.app.domain.MyEntity</value>
<value>com.pack1.app.service.MyEntityTwo</value>
</list>
</property>
</bean>
</beans>
I have an application with Spring 3.0.5.RELEASE trying to get the full content of a post using #RequestBody. The method is called, but the string passed is always empty. I have checked, by placing breakpoints, that the StringHttpMessageConverter is called, but the inner HttpInputMessage is empty.
I've seen this issue with both Jetty and Tomcat, so I'm discarding it's a problem with the container.
Here is my sample controller:
#Controller
#RequestMapping("/")
public class SubscriptionController {
#RequestMapping(value = "/requestbody", method = RequestMethod.POST)
public ModelAndView mycustomAction(#RequestBody String body) {
// body is always empty
Logger.getLogger(this.getClass()).debug("REQUEST BODY '" + body + "'");
return new ModelAndView("empty");
}
}
My application context is defined as follows:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd">
<!-- Enable auto detection of controllers -->
<context:component-scan base-package="com.big.viajerotelcel.controller" />
<!--
use annotation driven mvc and one single validator with JSR-303
standard
-->
<mvc:annotation-driven />
<!--
Message source for this context, loaded from localized "messages_xx"
files
-->
<bean id="messageSource"
class="org.springframework.context.support.ReloadableResourceBundleMessageSource">
<property name="basenames" value="classpath:i18n/messages" />
<property name="defaultEncoding" value="UTF-8" />
</bean>
<!-- Declare the Interceptor -->
<mvc:interceptors>
<bean class="org.springframework.web.servlet.i18n.LocaleChangeInterceptor"
p:paramName="locale" />
</mvc:interceptors>
<!-- Declare the Resolver -->
<bean id="localeResolver"
class="org.springframework.web.servlet.i18n.SessionLocaleResolver" />
<!-- will load Tiles definitions! -->
<bean id="tilesConfigurer"
class="org.springframework.web.servlet.view.tiles2.TilesConfigurer">
<property name="definitions">
<list>
<value>/WEB-INF/general.xml</value>
</list>
</property>
</bean>
<!-- Tiles view resolver -->
<bean id="viewResolver"
class="org.springframework.web.servlet.view.UrlBasedViewResolver">
<property name="viewClass"
value="org.springframework.web.servlet.view.tiles2.TilesView" />
</bean>
<!-- Configure the multipart resolver -->
<bean id="multipartResolver"
class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<!--
one of the properties available; the maximum file size in bytes (5MB)
-->
<property name="maxUploadSize" value="5120000" />
</bean>
<!-- Adding these lines has no effect, the StringHttpMessageConverter is called either way -->
<!-- <bean id="stringHttpMessageConverter" class="org.springframework.http.converter.StringHttpMessageConverter"/>-->
<!-- -->
<!-- <bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter">-->
<!-- <property name="messageConverters">-->
<!-- <list>-->
<!-- <ref bean="stringHttpMessageConverter"/>-->
<!-- </list>-->
<!-- </property>-->
<!-- </bean>-->
</beans>
I'm testing this using curl as follows:
curl -d asd=123 -d qwe=456 http://localhost:8080/requestbody
Any ideas or help is more than welcomed!
Here is a code snippet of ServletServerHttpRequest, which extends HttpInputMessage. I am pretty positive this is the implementation that you are using in your code:
public InputStream getBody() throws IOException {
return this.servletRequest.getInputStream();
}
In other words, the request body is meant to be read as the input stream of the HttpServletRequest object.
The request's input stream is not valid in several situations, but I can't find the correct documentation for it at the moment. For example, if you call request.getParameter() on a post request, tomcat has to read the input stream in order to interpret the parameters, thus afterwards when you read the input stream, it is empty because it has reached the end already.
Perhaps you are invoking getParameter somewhere in an interceptor or perhaps a filter defined in web.xml. Another option is that Spring is doing that for you, for example, if your controller has some other method with complex #RequestMappings (such as reading param values, or header values).
I have two suggestions for you:
Add a servlet filter (before spring gets a chance to act), and wrap the request with your own wrapper (just extend HttpServletRequestWrapper). This way you can put breakpoints or log messages at some methods of the request object and see who's calling them.
Use a pojo object parameter, and setup the bindings. It seems like a much cleaner way to read post data.
How are you POSTing messages to this URL? Are you positive that the HTTP request contains what you think it does? I suggest removing any web browsers from the picture and drop down to something low-level like curl which lets you send any type of HTTP message yourself.
Had a similar problem - the string received by spring controller was always empty. Tinkered with my spring config but with no result. Finally the problem was that the client was actually was not sending anything body!(due to some typo of mine)
If found with a similar error, its worth checking once if the client's payload is actually non-empty.
Another reason that your XML may not be getting marshalled into your JAXB object is related to the namespaces in the XML.
Versions of java after 1.8.101 are more strict about parsing namespaced XML.
See JAXB doesn't unmarshall after updating java from 1.8.0_77 to 1.8.0_121
In my case I was seeing a request body with all nulls and no exception being thrown to indicate that the XML parsing had failed.
If we develop REST using Spring MVC, it will support XML and JSON data. I have wrote ContentNegotiationViewResorver in my spring config bean app-servlet.xml
<bean
class="org.springframework.web.servlet.view.ContentNegotiatingViewResolver"
p:order="1">
<property name="mediaTypes">
<map>
<entry key="xml" value="application/xml" />
<entry key="json" value="application/json" />
</map>
</property>
<property name="defaultViews">
<list>
<bean class="org.springframework.web.servlet.view.xml.MarshallingView">
<property name="marshaller">
<bean class="org.springframework.oxm.xstream.XStreamMarshaller"
p:autodetectAnnotations="true" />
</property>
</bean>
<bean
class="org.springframework.web.servlet.view.json.MappingJacksonJsonView" />
</list>
</property>
</bean>
And my spring REST Controller is:
#Controller
#RequestMapping("/rest/customers")
class CustomerRestController {
protected Log log = LogFactory.getLog(CustomerRestController.class);
#RequestMapping(method = POST)
#ResponseStatus(CREATED)
public void createCustomer(#RequestBody Customer customer,
HttpServletResponse response) {
log.info(">>>" + customer.getName());
response.setHeader("Location", String.format("/rest/customers/%s",
customer.getNumber()));
}
#RequestMapping(value = "/{id}", method = GET)
#ResponseBody
public Customer showCustomer(#PathVariable String id) {
Customer c = new Customer("0001", "teddy", "bean");
return c;
}
#RequestMapping(value = "/{id}", method = PUT)
#ResponseStatus(OK)
public void updateCustomer(#RequestBody Customer customer) {
log.info("customer: " + customer.getName());
}
I set #XStreamAlias("customer") annotation in my customer domain class.
But when I try access http://localhost:8080/rest/customers/teddy.xml it always response JSON data.
I set #XmlRootElement(name="customer") annotation in my customer domain class.
But when I try access http://localhost:8080/rest/customers/teddy.json it always response XML data.
Is there some thing wrong ?
I think "xml" content type should be mapped to "text/xml" not to "application/xml". Also, to force content type resolvers based on extension, you can try to set the "favorPathExtension" property of "ContentNegotiatingViewResolver" to true(though it should have been true by default!)
EDIT: I have now added a working sample at this GIT location - git://github.com/bijukunjummen/mvc-samples.git, if you bring up the endpoint, using mvn tomcat:run, the json is served at http://localhost:8080/mvc-samples/rest/customers/teddy.json and xml at http://localhost:8080/mvc-samples/rest/customers/teddy.xml. This uses JAXB2 not XStream, as I am familiar with JAXB. One thing I noticed was that when my JAXB annotations were not correct in Customer class, Spring was serving out JSON and not XML the way you saw it(You can replicate it by removing the XMLRootElement annotation from Customer class), once I fixed up my annotations, I got back XML as expected. So it could be that there is something wrong with your XStream configuration.
EDIT 2: You are right!! I did not notice, once I got back xml, I assumed that json is working now. I see the problem, in AnnotationMethodHandlerAdapter, the handling for #ResponseBody is a little strange, it completely ignores the ViewResolvers, and uses the registered MessageConverters instead completely bypassing the ContentNegotiatingViewResolver, one workaround for now is to use #ModelAttribute annotation for response, instead of #ResponseBody, this way the view Resolvers are getting called. Try now using the project at git#github.com:bijukunjummen/mvc-samples.git and see if it works for you. This could be a Spring bug, you may try and bring it up in the Spring forum and see what they recommend.
What Accept headers are sent to your server?
Make sure the content type you would like to request is in this list.
Spring 3.1 solves the problem you mention using the new produces element on the #RequestMapping annotation. This allows you to control the HttpMessageConverter that Spring applies to your object.
I wrote a blog post about it:
http://springinpractice.com/2012/02/22/supporting-xml-and-json-web-service-endpoints-in-spring-3-1-using-responsebody/
I had the same problem. I assume you're using Spring 3 and you've used <mvc:annotation-driven/>. I'm not entirely sure, but I think this creates some conflict based on the message converters that the mvc namespace configures.
Using the oxm namespace worked for me:
#XmlRootElement(name="person")
class Person {
private String firstName;
private String lastName;
}
#Controller
#RequestMapping("person")
class PersonController {
#RequestMapping("list")
public #ResponseBody Person getPerson() {
Person p = new Person();
p.setFirstName("hello");
p.setLastName("world");
return p;
}
}
Content Configuration (mvc and internal view resolver are in another context):
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context" xmlns:oxm="http://www.springframework.org/schema/oxm"
xmlns:p="http://www.springframework.org/schema/p" xmlns:util="http://www.springframework.org/schema/util"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/oxm http://www.springframework.org/schema/oxm/spring-oxm-3.0.xsd http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-3.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd">
<oxm:jaxb2-marshaller id="jaxbMarshaller">
<oxm:class-to-be-bound name="package.Person" />
</oxm:jaxb2-marshaller>
<bean
class="org.springframework.web.servlet.view.ContentNegotiatingViewResolver">
<property name="defaultContentType" value="text/html" />
<property name="ignoreAcceptHeader" value="true" />
<property name="favorPathExtension" value="true" />
<property name="mediaTypes">
<map>
<entry key="json" value="application/json" />
<entry key="xml" value="application/xml" />
</map>
</property>
<property name="defaultViews">
<list>
<bean class="org.springframework.web.servlet.view.json.MappingJacksonJsonView" />
<bean class="org.springframework.web.servlet.view.xml.MarshallingView">
<property name="marshaller" ref="jaxbMarshaller" />
</bean>
</list>
</property>
</bean>
</beans>
This example uses JAXB, so you'd need jaxb-api and jaxb-impl on the classpath.
Also, just a tip, you don't need the app-servlet.xml. In your web.xml, set the config to null and let the Context Listener load them for you:
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/spring/mvc-context.xml, /WEB-INF/spring/content-negotiation-context.xml</param-value>
</context-param>
<servlet>
<servlet-name>app</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value/>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>app</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
Well I got a solution but I don't know if it's the right way in your method show customer:
#RequestMapping(value = "/{id}", method = GET)
#ResponseBody
public Customer showCustomer(#PathVariable String id) {
Customer c = new Customer("0001", "teddy", "bean");
return c;
}
In this part, we are using MVC of spring and in the controller we should be return a view, so I removed the annotation #ResponseBody and I return a String with the name of the view because in our XML we added a ContentNegotiatingViewResolver and when we have ResponseBody the contentnegociationviewresolver is ignored because is waiting for a view but we returned the object so the method should be like that:
#RequestMapping(value = "/{id}", method = GET)
public String showCustomer(#PathVariable String id, ModelMap model) {
Customer c = new Customer("0001", "teddy", "bean");
model.addAttribute("customer",c);
return "myView";
}
well that works for me, if you have problems you can add to your app-servlet.xml
this bean, but I don't think that you have to add this.
<bean
class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix">
<value>/WEB-INF/views/</value>
</property>
<property name="suffix">
<value>.jsp</value>
</property>
</bean>
I got the answers from mkyong.com
Accessing the controller using a browswer will send a typical browser Accept header. It will not match any view resolver and default to the first one (application/xml) or it matches because application/xml is in the Accept list.
I can recommend using RestClient http://code.google.com/p/rest-client/ to have complete control over what Accept header (if one at all) you want to send.
I don't recommend using text/xml as the default character set is US-ASCII and not UTF-8. This might create funky encoding problems down the road. You can always specify the encoding but appliation/xml has a UTF-8 default encoding.