SpringMVC 3.2.4 Request method 'PUT' not supported - java

Just started working with Java and Spring, coming from a C# background and I am having trouble getting a 'PUT' request to work.
I am on Spring 3.2.4 running on Jetty 9.0.6.
I have a simple controller with the following method
#RequestMapping(value = "/{id}", method = RequestMethod.PUT)
public ResponseEntity<String> update(#PathVariable Integer id, #RequestBody Employee employee) {
HttpHeaders headers = new HttpHeaders();
headers.set("content-location", "/api/employees/" + id);
return new ResponseEntity<>("", headers, HttpStatus.OK);
}
When this request is executed, I get the following error:
Oct 31, 2013 10:16:16 AM org.springframework.web.servlet.mvc.support.DefaultHandlerExceptionResolver handleHttpRequestMethodNotSupported
WARNING: Request method 'PUT' not supported
If I change the RequestMethod to 'POST' it works fine.
Does Spring support 'PUT' requests? How do I get it to recognize the 'PUT'
Joe
EDIT
Turns out I was being stupid. Affe clued me in when he mentioned the url.
I was accessing it like 'api/employees?id=32' when it should have been 'api/employees/32'
In the hopes this helps someone else, here is the web descriptor, the servlet and the controller.
Web Descriptor
<web-app xmlns='http://java.sun.com/xml/ns/javaee'
xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance'
xsi:schemaLocation='http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd'
version='3.0'>
<display-name>timesheet-app</display-name>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<servlet>
<servlet-name>mvc-dispatcher</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>mvc-dispatcher</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
</web-app>
MVC-Dispatcher-Servlet
<?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"
xsi:schemaLocation='http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.1.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd'>
<!-- Scans the classpath of this application for #Components to deploy as beans -->
<context:component-scan base-package='org.timesheets.web' />
<!-- Configures the #Controller programming model -->
<mvc:annotation-driven />
<!-- Handles HTTP GET requests for /resources/** by efficiently serving up static resources in the ${webappRoot}/resources/ directory -->
<mvc:resources mapping="/resources/**" location="/resources/" />
<!-- Resolves view names to protected .jsp resources within the /WEB-INF/views directory -->
<bean class='org.springframework.web.servlet.view.InternalResourceViewResolver'>
<property name='prefix' value='/WEB-INF/views/' />
<property name='suffix' value='.jsp' />
</bean>
</beans>
Controller
#Controller
#RequestMapping("/api/employees")
public class EmployeeController {
#RequestMapping(method = RequestMethod.GET)
public #ResponseBody List<Employee> get() {
List<Employee> employees = new ArrayList<>();
for(int i = 1; i <= 10; i++){
employees.add(new Employee(i, "Test " + i, "Department " + i));
}
return employees;
}
#RequestMapping(value = "/{id}", method = RequestMethod.GET)
public #ResponseBody Employee get(#PathVariable Integer id) {
return new Employee(1, "Test", "IT");
}
#RequestMapping(method = RequestMethod.POST)
public ResponseEntity<String> create(#RequestBody Employee employee) {
HttpHeaders headers = new HttpHeaders();
headers.set("content-location", "/api/employees/32");
return new ResponseEntity<>("", headers, HttpStatus.CREATED);
}
#RequestMapping(value = "/{id}", method = RequestMethod.PUT)
public ResponseEntity<String> update(#PathVariable Integer id, #RequestBody Employee employee) {
HttpHeaders headers = new HttpHeaders();
headers.set("content-location", "/api/employees/" + id);
return new ResponseEntity<>("", headers, HttpStatus.OK);
}
}

The problem was as #Affe pointed out that it could not find the url in the mapping because I was requesting the wrong url!
I was accessing the url like '/api/employees?id=32' instead of '/api/employees/32', though I would have thought the parameter binding would still pick it up.

Related

404 error in java spring mvc

I am building a Java Spring web application and getting a 404 error when running it from Eclipse, the manager section in tomcat shows the app as deployed and the console is not showing any error either.
Can anyone please help here and tell the missing links?
Dispatacher Servlet
Links for Spring beans here - removed to make it clean
<mvc:default-servlet-handler/>
<context:component-scan base-package="net.kzn.onlineshopping.controller"/>
<bean id ="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name ="prefix" value ="/WEB-INF/views/"/>
<property name ="suffix" value =".jsp"/>
</bean>
<!-- loading static resources -->
<mvc:annotation-driven/>
<mvc:resources location="/assets/" mapping="/resources/**"/>
</beans>
Page Controller
package net.kzn.onlineshopping.controller;
....Spring imports...
#Controller
public class PageController {
#RequestMapping(value= {"/","/home","/index"})
public ModelAndView index() {
ModelAndView mv = new ModelAndView("page");
mv.addObject("title","Home");
mv.addObject("userClickHome","true");
return mv;
}
#RequestMapping(value= "/about")
public ModelAndView about() {
ModelAndView mv = new ModelAndView("page");
mv.addObject("title","About us");
mv.addObject("userClickAbout","true");
return mv;
}
#RequestMapping(value= "/contact")
public ModelAndView contact() {
ModelAndView mv = new ModelAndView("page");
mv.addObject("title","Contact us");
mv.addObject("userClickContact","true");
return mv;
}
}
Code below for Web.xml file
<display-name>Archetype Created Web Application</display-name>
<!-- Configuring front Controller -->
<servlet>
<servlet-name>dispatcher</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>dispatcher</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
</web-app>

How do I add a servlet to spring framework java web application?

I thought this would be pretty straightforward, but apparently I'm missing something, and I can't seem to figure out what it is.
I'm trying to add a servlet to an existing web application written using java and spring. Here's what I did:
I added the following to web.xml:
<servlet>
<servlet-name>SettingServlet</servlet-name>
<display-name>SettingServlet</display-name>
<description>Provides a rest endpoint for getting and setting settings.</description>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/SettingServlet-servlet.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>SettingServlet</servlet-name>
<url-pattern>/setting/*</url-pattern>
</servlet-mapping>
Then I created the following file (.../WEB-INF/SettingServlet-servlet.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:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd"
>
<bean id="settingController"
class="com.my.package.path.SettingController"
p:settingService-ref="settingService"/>
</beans>
Then I created the following Controller (com.my.package.path.SettingController.java):
#Controller
#RequestMapping("/setting")
public class SettingController {
private SettingService settingService;
public void setSettingService(final SettingService settingService) {
Validate.notNull(settingService, "SettingController::settingService cannot be null");
this.settingService = settingService;
}
#ResponseBody
#RequestMapping(value = "/{name}", method = RequestMethod.GET)
#Secured({ "ROLE_ADMINISTRATOR", "ROLE_CURIOUS_GEORGE" })
public ResponseEntity<String> getSettingRequest(#PathVariable("name") final String name, #RequestParam("setting_family") final String settingFamily) {
final String jsonBody = "{\"setting\":\"" + name + "\", \"Setting Family\":\"" + settingFamily + "\", \"value\":\"test\"}";
return new ResponseEntity<String>(jsonBody, HttpStatus.OK);
}
}
WHAT AM I DOING WRONG? :( I get a 404 not found exception when trying to do a GET request at /setting/fruit?setting_family=foods
as you declared url pattern to your dispatcher as "/setting/*" and then in controller you declared "/setting" as a root requestMapping for this controller, you should be able to access your controller using this url: /setting/setting/fruit?setting_family=foods
:)

JSON response from SpringMVC controller is not working

I want to response JSON object or array from Spring MVC controller. From these two beingjavaguys and mkyoung tutorial, i tried.
I could success only in when the response is string. But when the response is in object or in list, it doesn't work for me.
//It works
#RequestMapping(value = "/angular", method = RequestMethod.GET)
public #ResponseBody String getAllProfiles( ModelMap model ) {
String jsonData = "[{\"firstname\":\"ajitesh\",\"lastname\":\"kumar\",\"address\":\"211/20-B,mgstreet\",\"city\":\"hyderabad\",\"phone\":\"999-888-6666\"},{\"firstname\":\"nidhi\",\"lastname\":\"rai\",\"address\":\"201,mgstreet\",\"city\":\"hyderabad\",\"phone\":\"999-876-5432\"}]";
return jsonData;
}
Output is:
But the problem is in it,
#RequestMapping(value = "mkyoung", method = RequestMethod.GET)
public #ResponseBody Shop getShopInJSON() {
Shop shop = new Shop();
shop.setName("G");
shop.setStaffName(new String[] { "mkyong1", "mkyong2" });
return shop;
}
It shows,
HTTP ERROR 406
Problem accessing /mkyoung.html. Reason:
Not Acceptable
But if i change it toString() ,
It works but not with right output
#RequestMapping(value = "mkyoung", method = RequestMethod.GET)
public #ResponseBody String getShopInJSON() {
Shop shop = new Shop();
shop.setName("G");
shop.setStaffName(new String[] { "mkyong1", "mkyong2" });
return shop.toString();
}
But i need JSON object or array of object as response. What is the probelm ? I have added jsckson dependency in my pom.xml
<dependency>
<groupId>org.codehaus.jackson</groupId>
<artifactId>jackson-mapper-asl</artifactId>
<version>1.9.10</version>
</dependency>
UPDATE:
Now i am sending request from angular js by adding
headers: {
"Content-Type": "application/json"
}
My dispatcher-servlet.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:mvc="http://www.springframework.org/schema/mvc"
xmlns:util="http://www.springframework.org/schema/util"
xsi:schemaLocation="http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-4.0.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd">
<mvc:annotation-driven />
<context:component-scan base-package="com.sublime.np.controller" />
<bean id="tilesConfigurer"
class="org.springframework.web.servlet.view.tiles3.TilesConfigurer">
<property name="definitions">
<list>
<value>/WEB-INF/defs/general.xml</value>
</list>
</property>
</bean>
<bean id="viewResolver"
class="org.springframework.web.servlet.view.UrlBasedViewResolver">
<property name="viewClass"
value="org.springframework.web.servlet.view.tiles3.TilesView" />
</bean>
</beans>
As Sotirios Delimanolis's Answer suggesion.
$http({
url: '/mkyoung.html',
method: 'GET',
data: id,
headers: {
"Content-Type": "application/json"
}
}).success(function(response){
$scope.response = response;
console.log($scope.response);
/* $scope.hideTable = false;
$scope.hideButton = false ; */
}).error(function(error){
$scope.response = error;
console.log("Failed");
});
But it shows same error.
Also add jackson core
<dependency>
<groupId>org.codehaus.jackson</groupId>
<artifactId>jackson-core-asl</artifactId>
<version>2.5.1</version>
</dependency>
For List use method return type Object
#RequestMapping(value = "mkyoung", method = RequestMethod.GET)
public #ResponseBody Object getShopInJSON() {
Shop shop = new Shop();
shop.setName("G");
shop.setStaffName(new String[] { "mkyong1", "mkyong2" });
Shop shop1 = new Shop();
shop1.setName("G1");
shop1.setStaffName(new String[] { "mkyong1", "mkyong2" });
List<Shop> shops = new ArrayList<Shop>();
shops.add(shop1);
shops.add(shop);
return shops;
}
Given #ResponseBody with a POJO type return type, a default MVC configuration with #EnableWebMvc or <mvc:annotation-driven />, and Jackson on the classpath, Spring will try to serialize the POJO to JSON and write it to the response body.
Since it's writing JSON, it's going to attempt to write application/json as the Content-type header. The HTTP specification requires that the server only responds with content types that are part of the Accept header in the request.
It seems you're sending your request with an inappropriate Accept header that doesn't contain application/json. Fix that.
Note that you are sending your request to
/mkyoung.html
Spring, by default, uses content negotiation based on some extensions. For example, with .html, Spring will think the request should produces text/html content, which is contrary to the application/json you want to send.
Since your handler is already mapped to
#RequestMapping(value = "/mkyoung", method = RequestMethod.GET)
just send the request to the corresponding URL, ending in /mkyoung. (Get rid of the .html extension.)

Spring MVC, tomcat url 404 error

I have problem with spring-mvc/tomcat, and more specifically with Url
When I'm trying to execute: http://localhost:8080/HelloWeb/index.html
WARNING: No mapping found for HTTP request with URI [/HelloWeb/index.html] in DispatcherServlet with name 'HelloWeb'
HelloWeb-servlet.xml:
<context:component-scan base-package="pl.solsoft.web"/>
<bean id="freemarkerConfig" class="org.springframework.web.servlet.view.freemarker.FreeMarkerConfigurer">
<property name="templateLoaderPath" value="/WEB-INF/pages"/>
</bean>
<bean id="viewResolver" class="org.springframework.web.servlet.view.freemarker.FreeMarkerViewResolver">
<property name="cache" value="true"/>
<property name="prefix" value=""/>
<property name="suffix" value=".ftl"/>
</bean>
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/pages/"/>
<property name="suffix" value=".jsp"/>
</bean>
StudentController:
#Controller
public class StudentController{
private static List<User> userList=new ArrayList<User>();
static {
userList.add(new User("Bill", "Gates"));
userList.add(new User("Kasia", "K"));
}
#RequestMapping(value = "/index", method = RequestMethod.GET)
public String index (#ModelAttribute("model") ModelMap model){
model.addAttribute("userList", userList);
return "index";
}
#RequestMapping(value = "/add", method = RequestMethod.POST)
public String add(#ModelAttribute("user") User user){
if (null != user && null != user.getName()
&& null != user.getLastName() && !user.getName().isEmpty()
&& !user.getLastName().isEmpty()) {
synchronized (userList) {
userList.add(user);
}
}
return "redirect:index.html";
}
}
web.xml:
<display-name>HW</display-name>
<welcome-file-list>
<welcome-file>index.html</welcome-file>
<welcome-file>index.jsp</welcome-file>
</welcome-file-list>
<servlet>
<servlet-name>HelloWeb</servlet-name>
<servlet-class> org.springframework.web.servlet.DispatcherServlet </servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>HelloWeb</servlet-name>
<url-pattern>*.html</url-pattern>
</servlet-mapping>
Thank U for all tips
What if you add .html to your RequestMappings e.g. #RequestMapping(value="/index.html")
In your web.xml, you've mapped the DispatcherServlet to handle requests matching *.html. But your StudentController is not mapped to handle such requests.
Modify the value in #RequestMapping to include .html extension.
#RequestMapping(value = "/index.html", method = RequestMethod.GET)
public String index (#ModelAttribute("model") ModelMap model){
......
return "index";
}
#RequestMapping(value = "/add.html", method = RequestMethod.POST)
public String add(#ModelAttribute("user") User user){
.....
return "redirect:index.html";
}
Now try to access your page by going to http://localhost:8080/HelloWeb/index.html
-----------Edit-----------------------------
Verify the Controller is getting initialized by Spring. To do that, create a no-arg constructor and try to print something to the console.
#Controller
public class StudentController{
public StudentController(){
System.out.println("Hey, I'm in StudentController");
}
}
I do not see <mvc:annotation-driven/>
in your servlet config. Can you add and check. Thanks.
If you are trying to deploy your HTML files as simple static files, you should configure them as such. Add this to your dispatcher servlet, making sure you have the proper namespace declared:
<mvc:resources mapping="*.html" location="/" />
You don't need a controller method to serve this file. If you want additional logic on the back-end, you can have your request to /index do its thing and then redirect to your file, or just convert index.html to a .jsp file. Right now, your controller is most likely trying to find a JSP view named index.html, which does not exist.

Deferred Result in Spring MVC returning incorrect response

I am using spring mvc 3.2.4 and jquery 1.9.0 for long polling. My application is deployed on Tomcat 7.0.42. My spring configuration files are as below:
Application Web.xml
<web-app xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee"
version="3.0">
<welcome-file-list>
<welcome-file>index.html</welcome-file>
</welcome-file-list>
<servlet>
<servlet-name>app</servlet-name>
<servlet-class>
org.springframework.web.servlet.DispatcherServlet
</servlet-class>
<load-on-startup>1</load-on-startup>
<async-supported>true</async-supported>
</servlet>
<servlet-mapping>
<servlet-name>app</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
<listener>
<listener-class>
org.springframework.web.context.ContextLoaderListener
</listener-class>
</listener>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>
/WEB-INF/app-servlet.xml
</param-value>
</context-param>
</web-app>
Spring Configration xml as:-
<?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:mvc="http://www.springframework.org/schema/mvc"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.2.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.2.xsd">
<context:annotation-config/>
<mvc:annotation-driven/>
<mvc:default-servlet-handler/>
<context:component-scan base-package="com.webchat"/>
<bean id="defferedResult" class="com.exp.DeferredResultContainer"></bean>
</beans>
Controller for Posting data looks as
#RequestMapping(value = "/postComment", method = RequestMethod.POST)
public #ResponseBody String postComment(HttpServletRequest request) {
deferredResultContainer.updateAllResults(request.getParameter("comment"));
return "success";
}
Deferred Result container class
public class DeferredResultContainer {
private final Set<DeferredResult<String>> deferredResults = Collections.synchronizedSet(new HashSet<DeferredResult<String>>() );
public void put(DeferredResult<String> deferredResult){
deferredResults.add(deferredResult);
}
public void updateAllResults(String value){
for (DeferredResult<String> deferredResult : deferredResults){
deferredResult.setResult(value);
}
}
public void remove(DeferredResult<String> deferredResult){
deferredResults.remove(deferredResult);
}
public int determineSize(){
return deferredResults.size();
}
}
Controller for Deferred Result looks as
#RequestMapping(value = "/getComments", method = RequestMethod.GET)
#ResponseBody
public DeferredResult<String> getComments() throws Exception{
final DeferredResult<String> deferredResult= new DeferredResult<String>();
deferredResultContainer.put(deferredResult);
deferredResult.onTimeout(new Runnable() {
#Override public void run() {
deferredResultContainer.remove(deferredResult);
}
});
deferredResult.onCompletion(new Runnable() {
#Override public void run() {
deferredResultContainer.remove(deferredResult);
}
});
return deferredResult;
}
When I am trying to long poll it through ajax i am getting following response :-
{"setOrExpired":false}
And onCompletion method is also not getting executed.
To Simply things below controller gives perfect response as
{"1":"2"}
#RequestMapping(value = "/test1", method = RequestMethod.GET)
#ResponseBody
public Map test1() throws Exception{
Map m1 = new HashMap<String, Object>();
m1.put("1", "2");
return m1;
}
Once i change it to below and add Deferred result i get response as
{"setOrExpired":true}
#RequestMapping(value = "/test", method = RequestMethod.GET)
#ResponseBody
public DeferredResult<Map> test() throws Exception{
DeferredResult<Map> result = new DeferredResult<Map>();
Map m1 = new HashMap<String, Object>();
m1.put("1", "2");
result.setResult(m1);
return result;
}
Polling code
$(document).ready(function() {
longPoll();
function longPoll(){
$.support.cors = true;
var path = "http://localhost:8080/WebChatExp/rest";
$.ajax({
url: path + "/getComments",
cache:false,
success: function(data){
//To Do
alert("Data" + JSON.stringify(data));
},
error: function(err, status, errorThrown ) {
},
type: "GET",
dataType: "json",
complete: longPoll,
timeout: 60000 // timeout every one minute
});
}
I have searched various examples but cannot figure out if any extra configuration is required for deferred result. Please advise.
The response body you are getting
{"setOrExpired":true}
indicates that Spring serialized your DeferredResult (which has various properties including setOrExpired) to JSON instead of handling it with a DeferredResultMethodReturnValueHandler. In other words, it used another HandlerMethodReturnValueHandler, most likely RequestResponseBodyMethodProcessor (which handles #ResponseBody), to handle the value returned from your #RequestMapping annotated handler method. (The simplest way to test this is to see what happens when you remove the #ResponseBody annotation.)
Looking at the 3.2.x source code of RequestMappingHandlerAdapter, which registers the default HandlerMethodReturnValueHandler instances, the DeferredResultMethodReturnValueHandler is registered before RequestResponseBodyMethodProcessor and therefore will handle the DeferredResult return value first.
Since you're seeing different behavior, we must assume your configuration is not what you've shown here. (Note that <mvc:annotation-driven/> registers a RequestMappingHandlerAdapter.)
Also note that you are currently loading the configuration in /WEB-INF/app-servlet.xml twice, once by the ContextLoaderListener and once by the DispatcherServlet.
Get rid of your ContextLoaderListener and the corresponding context-param entirely. They are not needed in your example.
I know is impossible to be the problem in this case (spring mvc 3.2.4) but just for future references:
I get the same issue with spring boot 2.2.0.BUILD-SNAPSHOT (spring 5.1.5).
This error happens when you try to return DeferredResult using webflux instead of the traditional spring mvc app. Remember, in the new webflux api you should use mono/flux, not DeferredResult.

Categories

Resources