I'm quite new to Spring MVC. Today when I learn #ResponseBody, I have some questions about HttpMessageConverters:
<bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter">
<property name="messageConverters">
<list>
<bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter"/>
<bean class="org.springframework.http.converter.ByteArrayHttpMessageConverter"/>
<bean class="org.springframework.http.converter.xml.SourceHttpMessageConverter"/>
<bean class="org.springframework.http.converter.FormHttpMessageConverter"/>
<bean class="org.springframework.http.converter.StringHttpMessageConverter"/>
</list>
</property>
</bean>
As above, we could declare a list of different converters. So it means we could choose one of them as response body converter.
But how to choose the one to use? For example, in functionA() to return JSON and then in functionB() to return XML.
My way is to force Content-Type of response, is it a correct way? Or does a better solution exist?
public #ResponseBody User getUser(HttpServletResponse response) {
response.setContentType("application/xml");
// SOME CODES HERE
return user;
}
But how to choose the one to use? For example, in functionA() to
return JSON and then in functionB() to return XML
You can use RequestMapping's produces attribute for that:
#RequestMapping(value = "/a", produces = "application/json")
public #ResponseBody Something functionA () { ... }
And:
#RequestMapping(value = "/b", produces = "application/xml")
public #ResponseBody Something functionB () { ... }
Also, you can omit the produces and Be more liberal in what you accept from clients. With this approach you let the client choose between XML, JSON or whatever through a process called Content Negotiation using Accept header. In fact, if client fire a request like:
GET /a HTTP/1.1
Accept: application/json
functionA will return a JSON representation of the return value, and if client send this request:
GET /a HTTP/1.1
Accept: application/xml
functionA will return an XML representation of the return value.
Use
#RequestMapping(value = "/url1", produces = "application/json")
for json and use
#RequestMapping(value = "/url2", produces = "application/xml")
for xml output
Related
I am new to String, and now facing some staring issues with Spring MVC.
In my application I have view resolver which maps view names to respective JSP files.
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix"><value>/WEB-INF/pages/</value></property>
<property name="suffix"><value>.jsp</value></property>
<property name="order" value="1" />
</bean>
It is working as expected, but now need to call a method in controller and show returned string in view.
my URL of request looks like http://localhost:8015/demo/greet
And the method in my controller to server this request is
#RequestMapping("/greet")
public String user(User user) {
return "Hi User";
}
When i call this url from browser, given method in browser get invoked, and when it returns a string, InternalResourceViewResolver try to find a page /WEB-INF/pages/greet.jsp, and as it doesn't exist, user gets 404 error. How can i send raw String from my controller method to browser?
Just change your controller code as below
#RequestMapping("/greet")
public #ResponseBody String user(User user) {
return "Hi User";
}
See documentation of ResponseBody here
Try:
#RequestMapping("/greet")
public #ResponseBody String user(User user) {
return "Hi User";
}
I am trying to run a simple controller with a method that will receive
A String with a value
A file (MultipartFile object)
After some investigation (Sending Multipart File as POST parameters with RestTemplate requests) I ended up adding into my web.xml
<filter>
<filter-name>multipartFilter</filter-name>
<filter-class>org.springframework.web.multipart.support.MultipartFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>multipartFilter</filter-name>
<url-pattern>/REST/*</url-pattern>
</filter-mapping>
My application context file
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<property name="maxUploadSize">
<value>104857600</value>
</property>
<property name="maxInMemorySize">
<value>4096</value>
</property>
</bean>
The controller looks like
#Controller
#RequestMapping("/image")
public class ImageController extends RestApiController {
private static final Logger log = LoggerFactory.getLogger(ImageController.class);
#RequestMapping(value="/simple", method = RequestMethod.POST, consumes="multipart/form-data")
public #ResponseBody boolean save(
#RequestParam(value = "file", required = false) MultipartFile file,
#RequestParam(value = "name", required = false) String name) {
//Some code here
return true;
}
So far I have been able to run unit tests against the controller with no problem, but I seem to be stuck when it comes to create a real http request.
I have tried with POSTMAN, but after some investigation seems that it does not set the multipart/form-data header properly, I have tried removing it, and the problem persists.
I have also tried with CURL
curl http://127.0.0.1:8080/content/REST/image/simple -F "file=#/home/jmoriano/Pictures/simple.jpeg" -F "name=someName" -v
I have also tried with a RestTemplate object
public Boolean update() {
RestTemplate restTemplate = new RestTemplate();
try {
FormHttpMessageConverter formConverter = new FormHttpMessageConverter();
formConverter.setCharset(Charset.forName("UTF8"));
restTemplate.getMessageConverters().add(formConverter);
restTemplate.setRequestFactory(new HttpComponentsClientHttpRequestFactory());
HttpHeaders httpHeaders = new HttpHeaders(); httpHeaders.setAccept(Collections.singletonList(MediaType.parseMediaType("application/json")));
MultiValueMap<String, Object> parts = new LinkedMultiValueMap<String, Object>();
parts.add("file", new FileSystemResource("/home/jmoriano/Pictures/simple.jpeg"));
parts.add("name", "name");
return restTemplate.postForObject("http://127.0.0.1:8080/content/REST/image/simple", parts, Boolean.class);
} catch (Exception e) {
e.printStackTrace();
log.error("Ouch!", e);
}
return false;
}
Just to be clear, the problem is not in the "name" parameter, that one works fine, however the MultipartFile is empty.
By debugging the code, I managed to check the MultiPartFilter class which receives an HttpServletRequest object, such object has its "parts" attribute already empty there. So the problem seems to be related with the way I am making the request... seems that my postman/curl/java attempts have failed... do you see anything incorrect in my config?
I think you should put the bean multipartResolver to your dispathcher-servlet.xml
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver" />
in the link you show above they use this bean, too.
<bean id="multipartResolver"
class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<property name="maxUploadSize">
<value>104857600</value>
</property>
<property name="maxInMemorySize">
<value>4096</value>
</property>
</bean>
I want to return a JSON response from the server in a spring application.
Following is my code snippet.
#RequestMapping(value="getCustomer.action", method = RequestMethod.GET)
public #ResponseBody Customer getValidCustomer(Model model) {
System.out.println("comes");
Customer customer2 = (Customer) customerService
.getCustomer("vvmnbv#jgfj.ghfjg");
System.out.println(customer2.getEmail());
return customer2;
}
But I'm getting an error client-side.
You need to:
Add Jackson JSON Mapper to the classpath
Add <mvc:annotation-driven> to your config
Return Map<Integer, String>
Read: http://blog.safaribooksonline.com/2012/03/28/spring-mvc-tip-returning-json-from-a-spring-controller/
Since you already have an answer with some specifics in it I thought I would just contribute with an example. Here you go:
#RequestMapping(value = "/getfees", method = RequestMethod.POST)
public #ResponseBody
DomainFeesResponse getFees(
#RequestHeader(value = "userName") String userName,
#RequestHeader(value = "password") String password,
#RequestHeader(value = "lastSyncDate", defaultValue = "") String syncDate) {
return domainFeesHelper.executeRetreiveFees(userName, password, syncDate);
}
Just a little summary: As you know you will need the Jackson library in the class path so that Objects can be converted to JSON.
#ResponseBody tells spring to convert its return value and write it to the HTTP Response automatically. There is no other configuration required.
The sample *-servlet.xml configuration is given below.
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
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">
<context:component-scan base-package="org.smarttechies.controller" />
<mvc:annotation-driven />
<bean class="org.springframework.web.servlet.view.ContentNegotiatingViewResolver">
<property name="mediaTypes">
<map>
<entry key="html" value="text/html"></entry>
<entry key="json" value="application/json"></entry>
<entry key="xml" value="application/xml"></entry>
</map>
</property>
<property name="viewResolvers">
<list>
<bean class="org.springframework.web.servlet.view.UrlBasedViewResolver">
<property name="viewClass" value="org.springframework.web.servlet.view.JstlView"/>
<property name="prefix" value="/WEB-INF/jsp/"/>
<property name="suffix" value=".jsp"/>
</bean>
</list>
</property>
</bean>
</beans>
Then deploy the application into server and send the request by setting the “Accept” header to “application/json” to get the response in JSON format or “application/xml” to get the response in XML format.
The detailed post explaining about the spring REST is available at http://smarttechie.org/2013/08/11/creating-restful-services-using-spring/
//I have created a class for converting simple string into json convertable format
and returned it to the JSP page where it parsed into json and used like
public class Json {
public static String Convert(Object a,Object b){
return " \""+a.toString()+"\" : \""+b.toString()+"\",";
}
public static String ConvertLast(Object a,Object b){
return " \""+a.toString()+"\" : \""+b.toString()+"\" }";
}
public static String ConvertFirst(Object a,Object b){
return "{ \""+a.toString()+"\" : \""+b.toString()+"\",";
} }
//Controller code ignore the data that i put into the conver(),convertLast() and convertFirst() methods
String json = Json.ConvertFirst("apId", appointment.getId())
+ Json.Convert("appDate",
format.format(appointment.getAppointmentdate()))
+ Json.Convert("appStart", formathourse.format(appointment
.getAppointmentstarttime()))
+ Json.Convert("appEnd", formathourse.format(appointment
.getAppointmentendtime()))
+ Json.Convert("PatientId", appointment.getPatientId()
.getId())
+ Json.Convert("PatientName", appointment.getPatientId()
.getFname()
+ " "
+ appointment.getPatientId().getLname())
+ Json.Convert("Age", appointment.getPatientId().getAge())
+ Json.Convert("Contact", appointment.getPatientId()
.getMobile())
+ Json.Convert("Gender", appointment.getPatientId()
.getSex())
+ Json.ConvertLast("Country", appointment.getPatientId()
.getCountry());
return json;}
/JSP JQuery Code
var app=jQuery.parseJSON(response);
$("#pid").html(app.PatientId);
$("#pname").html(app.PatientName);
$("#pcontact").html(app.Contact);
Trying to understand a sample code...
I am returning a modelview successfully from my AthuenticationController like this
modelAndView = new ModelAndView("redirect:/home/");
....
return modelAndView;
and my browser url is changed to /home/ but its showing a 404 page
I have a HomePageController and it has methods
#RequestMapping(method = RequestMethod.GET)
public String loadHome
and
#RequestMapping(method = RequestMethod.GET, value = "/main")
public String reloadHome
but System.out.println("Message") is not executing in any of the above methods.
When authenticated I want to load a home.jsp page? It is in WEB-INF/jsp/...
<bean id="viewResolver"
class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/jsp/"></property>
<property name="suffix" value=".jsp"></property>
</bean>
login.html page thats from WEB-INF/jsp/ is loading fine
Here is the update Now it is opeining WEB-INF/jsp/home.jsp page in browser but the url is still the old one...
You need to change request mapping
#RequestMapping(value = "/home", method = RequestMethod.GET)
public String loadHome
instead of this
modelAndView = new ModelAndView("redirect:/home/");
....
return modelAndView;
try this one :
modelAndView = new ModelAndView("home");
....
return modelAndView;
I currently have my web.xml configured to catch 404s and send them to my spring controller which will perform a search given the original URL request.
The functionality is all there as far as the catch and search go, however the trouble begins to arise when I try to return a view.
<bean class="org.springframework.web.servlet.view.ContentNegotiatingViewResolver" p:order="1">
<property name="mediaTypes">
<map>
<entry key="json" value="application/json" />
<entry key="jsp" value="text/html" />
</map>
</property>
<property name="defaultContentType" value="application/json" />
<property name="favorPathExtension" value="true" />
<property name="viewResolvers">
<list>
<bean class="org.springframework.web.servlet.view.BeanNameViewResolver" />
<bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/jsp/" />
<property name="suffix" value="" />
</bean>
</list>
</property>
<property name="defaultViews">
<list>
<bean class="org.springframework.web.servlet.view.json.MappingJacksonJsonView" />
</list>
</property>
<property name="ignoreAcceptHeader" value="true" />
</bean>
This is a snippet from my MVC config file.
The problem lies in resolving the view's path to the /WEB-INF/jsp/ directory. Using a logger in my JBoss setup, I can see that when I test this search controller by going to a non-existent page, the following occurs:
Server can't find the request
Request is sent to 404 error page (in this case my search controller)
Search controller performs search
Search controller returns view name (for this illustration, we'll assume test.jsp is returned)
Based off of server logger, I can see that org.springframework.web.servlet.view.JstlView is initialized once my search controller returns the view name (so I can assume it is being picked up correctly by the InternalResourceViewResolver)
Server attempts to return content to browser resulting in a 404!
A couple things confuse me about this:
I'm not 100% sure why this isn't resolving when test.jsp clearly exists under the /WEB-INF/jsp/ directory.
Even if there was some other problem, why would this result in a 404? Shouldn't a 404 error page that results in another 404 theoretically create an infinite loop?
Thanks for any help or pointers!
Controller class [incomplete]:
#Controller
public class SiteMapController {
//--------------------------------------------------------------------------------------
#Autowired(required=true)
private SearchService search;
#Autowired(required=true)
private CatalogService catalog;
//--------------------------------------------------------------------------------------
#RequestMapping(value = "/sitemap", method = RequestMethod.GET)
public String sitemap (HttpServletRequest request, HttpServletResponse response) {
String forwardPath = "";
try {
long startTime = System.nanoTime() / 1000000;
String pathQuery = (String) request.getAttribute("javax.servlet.error.request_uri");
Scanner pathScanner = new Scanner(pathQuery).useDelimiter("\\/");
String context = pathScanner.next();
List<ProductLightDTO> results = new ArrayList<ProductLightDTO>();
StringBuilder query = new StringBuilder();
String currentValue;
while (pathScanner.hasNext()) {
currentValue = pathScanner.next().toLowerCase();
System.out.println(currentValue);
if (query.length() > 0)
query.append(" AND ");
if (currentValue.contains("-")) {
query.append("\"");
query.append(currentValue.replace("-", " "));
query.append("\"");
}
else {
query.append(currentValue + "*");
}
}
//results.addAll(this.doSearch(query.toString()));
System.out.println("Request: " + pathQuery);
System.out.println("Built Query:" + query.toString());
//System.out.println("Result size: " + results.size());
long totalTime = (System.nanoTime() / 1000000) - startTime;
System.out.println("Total TTP: " + totalTime + "ms");
if (results == null || results.size() == 0) {
forwardPath = "home.jsp";
}
else if (results.size() == 1) {
forwardPath = "product.jsp";
}
else {
forwardPath = "category.jsp";
}
}
catch (Exception ex) {
System.err.println(ex);
}
System.out.println("Returning view: " + forwardPath);
return forwardPath;
}
}
1 . I'm not 100% sure why this isn't resolving when test.jsp clearly exists under the /WEB-INF/jsp/
directory.
This is because you did configure your view resolver with suffix = "" so the file must be named test (no extension).
2 . Even if there was some other problem, why would this result in a 404? Shouldn't a 404 error page that
results in another 404 theoretically create an infinite loop?
I'm pretty sure this's the result of some protection against the infinite redirect loop in spring MVC.
Note: in controllers, spring expect a view name as a result so test not test.jsp (or better, use ModelAndView)
I am posting this as answer because it is too long but it is probably not an answer.
http://localhost:8080/webapp/servlet-mapping-url/controller-mapping/method-mapping
if your controller's method which handles the request does not return a view name string or a view object or write directly to output stream, spring dispatcher should resolve the view name to /WEB-INF/jsp/controller-mapping/method-mapping.jsp
This means the jsp must be under a folder, named /WEB-INF/jsp/controller-mapping/. However, if a view name or view object is return by the controller method, spring dispatcher will uses that instead.
Ther are other many possible mapping combination but this is the most common one. If you could show your controller class, it will be easier.
Update
If you are using DefaultAnnotationHandlerMapping, you should always annotated your class with #RequestMapping(value = "/mapping-string"). Otherwise spring dispatcher will try to pick it up when nothing else is matched.
Since the controller is mapped, you will have to change the method mapping to value = {"", "/"}
For the returning view name, you don't need to put .jsp.
If the returning view name is home then the spring dispatcher will resolve to /WEB-INF/jsp/home.jsp
If the returning view name is path/home then the spring dispatcher will resolve to /WEB-INF/jsp/path/home.jsp
P.S. You used a word forwardPath but it isn't really a forward. It is just a view name.
#Controller
#RequestMapping(value = "/sitemap")
public class SiteMapController {
#RequestMapping(value = {"", "/"}, method = RequestMethod.GET)
public String sitemap (HttpServletRequest request, HttpServletResponse response) {
...
if (results == null || results.size() == 0) {
forwardPath = "home";
}
else if (results.size() == 1) {
forwardPath = "product";
}
else {
forwardPath = "category";
}
...
return forwardPath;
}
}
Try to set order for your ViewResolver. For Example:
#Bean
public ViewResolver getViewResolver(){
InternalResourceViewResolver resolver = new InternalResourceViewResolver();
resolver.setViewClass(JstlView.class);
resolver.setPrefix("/WEB-INF/jsp/");
resolver.setSuffix(".jsp");
resolver.setOrder(1);
return resolver;
}