Spring MVC MultipartFile problems - java

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>

Related

#ResponseBody to choose different response format

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

Spring MVC- returning string value from controller

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";
}

Spring MVC resolving error code

I am creating a login form in Spring MVC. My spring version is 4.0.6.
I have configured my properties file ApplicationResources.properties like below
<bean id="messageSource"
class="org.springframework.context.support.ReloadableResourceBundleMessageSource">
<property name="basenames">
<list>
<value>classpath:ApplicationResources</value>
</list>
</property>
</bean>
I am able to read value of lables defined in property file by using tag lib like below
<spring:message code="ui.label.username" />
But I am facing problem with validation below is the controller class method.
#RequestMapping(value = "/doLogin.spr" , method=RequestMethod.POST)
public String login(#Valid LoginForm loginForm, BindingResult bindingResult, HttpServletRequest request, Model model) {
try{
if(bindingResult.hasErrors()){
model.addAttribute("command", loginForm);
return "login" ;
}
User user = loginService.login(loginForm.getUserName(), loginForm.getPassword());
return "login" ;
}catch (Exception e) {
// TODO: handle exception
return "login" ;
}
}
In my validator I am validating field like below
ValidationUtils.rejectIfEmptyOrWhitespace(errors, "userName", "app.ui.userName.error");
In my property file I have defined labels like below.
app.ui.userName.error.loginForm.userName=First UserName
app.ui.userName.error.userName=Second UserName
app.ui.userName.error.java.lang.String=String UserName
app.ui.userName.error=Simple error
On JSP I am trying to access error like below
<form:errors path="userName"/>
But I am not able to see error message on my UI. What could be problem here.

Spring MVC simple case

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;

spring mvc forward to jsp

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;
}

Categories