I was reading this https://spring.io/guides/gs/rest-service/ and I see that in Spring 4 , the #RestController is a combination of #ResponseBody and #Controller and hence its not necessary to mention the #ResponseBody at every method as it was previously. But, in one of the application am working on, we are using Spring 3.x and we have developed spring webservices and annotated the Controller class as #Controller. The sample controller looks like this:
#Controller
public class SomeController {
#RequestMapping(value = "uri/{values}", method = RequestMethod.GET)
public List<SampleClassPOJO> giveSomething(#PathVariable("values") String some){
//logic
return listOfSampleClassPOJO;
}
//Other services
}
and have the following config in the dispatcher servlet xml :
<bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter">
<property name="messageConverters">
<list>
<bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter">
<property name="prettyPrint" value="false"/>
<property name="objectMapper">
<bean class="com.fasterxml.jackson.databind.ObjectMapper"/>
</property>
</bean>
</list>
</property>
</bean>
The dispatcher servlet is referred in the web.xml
<servlet>
<servlet-name>dispatch</servlet-name>
<servlet-class>someCustom.DispatcherServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>dispatch</servlet-name>
<url-pattern>/*</url-pattern>
</servlet-mapping>
And we haven't annotated with #ResponseBody for any of the web services method nor at the class level, but still the response is a json. So, when is the #ResponseBody annotation required?
Now, this has gotten me into a confused state, I tried to search for any example with just the above entry in the dispatcher-servlet.xml and without using the #ResponseBody in the methods of the services, but there are no example as such. Only thing I found was, the above entry along with #RestController annotation in Spring 4.
Can anyone please tell me what is the piece of information that am missing here?
Thanks
Related
I am trying to build a REST API with Spring and Hibernate.
When I run the server it returns no errors, but I can't access my links.
Here is my config file:
spring.xml
<mvc:annotation-driven />
<context:component-scan base-package="org.bloggy.spring" />
<bean id="sessionFactory" class="org.springframework.orm.hibernate5.LocalSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="hibernateProperties">
<props>
<prop key="hbm2ddl.auto">create-drop</prop>
<prop key="hibernate.dialect">org.hibernate.dialect.MySQL5Dialect</prop>
<prop key="show_sql">true</prop>
</props>
</property>
</bean>
<bean id="dataSource"
class="org.apache.commons.dbcp.BasicDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/my_bloggy?createDatabaseIfNotExist=true" />
<property name="username" value="root" />
<property name="password" value="root" />
</bean>
<bean id="txManager"
class="org.springframework.transaction.jta.JtaTransactionManager" />
And that is my web.xml:
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<!-- Processes application requests -->
<servlet>
<servlet-name>appServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>WEB-INF/resources/spring.xml</param-value>
<param-value>WEB-INF/resources/dao.xml</param-value>
<param-value>WEB-INF/resources/service.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>appServlet</servlet-name>
<url-pattern>/api/*</url-pattern>
</servlet-mapping>
Controller:
#Controller
#RequestMapping(value = "users")
public class UserController {
#Autowired
private UserService userService;
#RequestMapping(value = "/", method = RequestMethod.GET)
public List<User> getUsers() {
return userService.listUsers();
}
}
As visible in logs the application MyBloggy doesn't actually initialize any spring beans. There is a problem with cache or the war file deployed on the tomcat. Ideally, At the time of deploying a war all the beans initialized can be seen in the logs unless disabled. Make sure that you are deploying a correct war on the server.
As #Ken mentioned In order to expose your API as a REST AP you need to use #RestController or if you want to use #Controller then use #ResponseBody annotation.
With regards to your issue I think you need to define your RequestMapping as
#Controller
#RequestMapping(value = "api")
public class UserController {
#Autowired
private UserService userService;
#RequestMapping(value = "/users", method = RequestMethod.GET)
public List<User> getUsers() {
return userService.listUsers();
}
}
Or
#Controller
#RequestMapping(value = "api/users")
public class UserController {
#Autowired
private UserService userService;
#RequestMapping(method = RequestMethod.GET)
public List<User> getUsers() {
return userService.listUsers();
}
}
Please see if it works.
You are using #Controller annotation, but if you want expose REST webservice, you need use #RestController or #ResponseBody
#RestController
#RequestMapping(value = "users")
public class UserController
I've been experimenting with Java Servlets for web applications, in this application I was able to hit a Servlet and correctly load a .jsp page, having done this I have moved onto Spring MVC. I've run into a problem where my servlet controller class is called, however it will not load the view.
I've ruled out an the resources not being visible, because it worked correctly with a plain java servlet. I've also read just about every resource/tutorial out there in an effort to attempt to identify the problem without any luck, my problem remains the same. In addition in an effort to trouble-shoot I've added an error page tag () in order to see if when I attempt to hit my page, it would correctly redirect me, but its unable to find the page specified for 404 errors.
Can anyone identify what I've missed?
Web.xml
Variations: Changed url-pattern, init-params, context config location etc.
<servlet>
<servlet-name>LoginServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<load-on-startup>1</load-on-startup>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/LoginServlet-servlet.xml</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>LoginServlet</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
LoginServlet-servlet.xml
Variations: I've tried moving the declarations into different positions as has been suggested on other posts, to no result. In addition typically I've had the prefix set to /WEB-INF/jsp/
<context:component-scan base-package="plan.route.server" />
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/jsp/" />
<property name="suffix" value=".jsp" />
</bean>
<context:annotation-config/>
<mvc:annotation-driven />
LoginServlet.java
Variations: Different requestMapping path, marking the methods not the class, returning string from methods, returning ModelAndView class
package plan.route.server;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.servlet.ModelAndView;
#Controller()
#RequestMapping("/")
public class LoginServlet extends org.springframework.web.servlet.mvc.AbstractController {
#RequestMapping(method = RequestMethod.GET)
public String forwardTo() {
return "index";
}
#Override
protected ModelAndView handleRequestInternal(HttpServletRequest request, HttpServletResponse response)
throws Exception {
return new ModelAndView("login", "login", "login");
}
}
Project setup
Variations: different locations for the servlet xml, .jsp files etc
Can anyone see what I've missed? all I'm trying to do, despite all the variations is load a .jsp page.
Edit: The following error is displayed after my java servlet method is called:
WARNING: No mapping found for HTTP request with URI [/Root/Login] in DispatcherServlet with name 'LoginServlet'
I see one thing that is wrong and is the jsp configuration in LoginServlet-servlet.xml, try change prefix value as follows:
<context:component-scan base-package="plan.route.server" />
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/jsp/" />
<property name="suffix" value=".jsp" />
</bean>
<context:annotation-config/>
<mvc:annotation-driven />
With your configuration Spring is not able to find jsp file, because you specified the wrong path. You have to be folder specific, in your case you have jsp files in /WEB-INF/jsp folder.
EDIT:
I configured your project in my workspace and it works. Try to remove this lines from web.xml:
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/LoginServlet-servlet.xml</param-value>
</init-param>
And your Controller class should be like this:
#Controller
#RequestMapping("/")
public class LoginServlet{
#RequestMapping(method = RequestMethod.GET)
public ModelAndView forwardTo(ModelMap model) {
return new ModelAndView("login", "login", "login");
}
}
And pay attention on how you invoke the controller:
http://localhost:8080/Root/
This is the correct way to call the controller because you named your project Root and the controller is listening to "/" path. I used port 8080 because you tagged the question with tomcat, and this is the default tomcat port, if you use another one change it with the one you use.
In LoginServlet-servlet.xml file try
<property name="prefix" value="/WEB-INF/jsp/"/>
instead of
<property name="prefix" value="/" />
With your current project setup
LoginServlet-servlet.xml
<context:component-scan base-package="plan.route.server" />
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/jsp/" />
<property name="suffix" value=".jsp" />
</bean>
<context:annotation-config/>
<mvc:annotation-driven />
LoginServlet.java
#Controller
#RequestMapping("/")
public class LoginServlet {
#RequestMapping(method = RequestMethod.GET)
public String forwardTo() {
return "index";
}
#RequestMapping(value="/login", method = RequestMethod.GET)
public String forwardToLogin() {
return "login";
}
}
This should work
I am trying to make simple rest service which is used by everybody example it will consume by mobile developer.so I need to send static data to every one .I am trying to send static this data .
{
name:"abcd"
}
in other word if some one hit my system like this
http://192.168.12.61:8080/springfirst/hello .then user get above json.
I follow this like to make
http://www.programming-free.com/2014/03/spring-mvc-40-restful-web-service-json.html
I follow this step
download these jar files(-- jackson-annotations-x.x.x.jar
-- jackson-core-x.x.x.jar
-- jackson-databind-x.x.x.jar) and include in lib folder.
here is my code
web.xml
<web-app id="WebApp_ID" version="2.4"
xmlns="http://java.sun.com/xml/ns/j2ee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee
http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
<display-name>Spring MVC Application</display-name>
<servlet>
<servlet-name>HelloWeb</servlet-name>
<servlet-class>
org.springframework.web.servlet.DispatcherServlet
</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>HelloWeb</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
</web-app>
hello-servelts.xml
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
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">
<context:component-scan base-package="com.tutorialspoint" />
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/jsp/" />
<property name="suffix" value=".jsp" />
</bean>
</beans>
controller.js
package com.tutorialspoint;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
#Controller
#RequestMapping("/hello")
public class HelloController{
#RequestMapping( method = RequestMethod.GET,headers="Accept=application/json")
public String printHello(ModelMap model) {
return "abcd";
}
}
you have configuration problems:
If you register DispatcherServlet in web.xml with out context configuration file path, then you should name the context file as per your servletName-servlet.xml.
So rename hello-servelts.xml as HelloWeb-servlet.xml.
and add #ResponseBody in your controller handler method to return JSON like:
#RequestMapping( method = RequestMethod.GET,headers="Accept=application/json")
public #ResponseBody Map printHello(ModelMap model) {
Map<String,String> json = new HashMap<String,String>();
json.put("name", "abcd");
return json;
}
Here is the working application using ContentNegotiatingViewResolver.
how to make rest service in spring mvc?
Ans, there is different ways are available. I am listing below some of:
To read/write JSON data from HTTP request or response you should use #RequestBody to read from HTTP request and #ResponseBody to write a object as JSON into HTTP response.
Spring provides ContentNegotiatingViewResolver where you can use it to resolve Views by request URL extension OR request ACCEPT header value. for example if URL is /view.html then it will return a view which has text/html content-type. same you can configure it to return JSON as well.
ContentNegotiatingViewResolver configuration for JSON View will look like:
<bean class="org.springframework.web.servlet.view.ContentNegotiatingViewResolver">
<property name="order" value="1" />
<property name="mediaTypes">
<map>
<entry key="json" value="application/json" />
</map>
</property>
<property name="defaultViews">
<list>
<!-- JSON View -->
<bean class="org.springframework.web.servlet.view.json.MappingJackson2JsonView">
</bean>
</list>
</property>
<property name="ignoreAcceptHeader" value="true" />
</bean>
Note: Jackson mapper or any other mapper should be available on buildpath in order to work JSON serialize and deserialize.
If you use Maven, then confirm this dependency available in pom.xml:
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.4.3</version>
</dependency>
SEE ALSO:
How to return object from controller to ajax in spring-mvc
New features in spring mvc 3.1
You can follow this guide which is an official documentation and it is using spring-boot which will do easy your way to start writing services.
You rest service would be something like
#RestController
#RequestMapping("/hello")
public class HelloController{
#RequestMapping( method = RequestMethod.GET,headers="Accept=application/json")
#ResponseBody
public String printHello() {
return "abcd";
}
}
i am facing an issue while invoking spring mvc method which has pathvariable
#RequestMapping(value="/retrieveData/{userId}", method=RequestMethod.POST)
public #ResponseBody
ModelAndView retrieveData(#PathVariable Long userId , HttpSession session) {
i have web.xml servlet mapping as below
<servlet-mapping>
<servlet-name>spring</servlet-name>
<url-pattern>*.html</url-pattern>
</servlet-mapping>
in my jsp , i have my javascript
document.getElementById("form1").action = "retrieveData.html/2";
document.getElementById("form1").submit();
so my question is, will path variable works with url file extension in my case i have *.html , which i eventually want my servlet to map /retrieveData/{userId}
while submitting the page i am getting HTTP Status 400 error. help needed
EDIT:- i have ContentNegotiationManagerFactoryBean configure in my spring context
<bean id="contentNegotiationManager"
class="org.springframework.web.accept.ContentNegotiationManagerFactoryBean">
<property name="favorPathExtension" value="false" />
<property name="favorParameter" value="true" />
<property name="mediaTypes">
<value>
json=application/json
xml=application/xml
</value>
</property>
</bean>
I'm building very basic mvc application with Spring. It has one controller that should invoke validation on request body. The problem is that if I define the mapping in web.xml it stops finding the right controller, but when I modify the servlet application context Spring star making some new bindings on the fly but this time annotation based validation is ignored. How can I controll mappings in web.xml while still invoking annotation based validation?
Here are the details:
The controller:
#Controller
#RequestMapping("/api")
public class UserActionsController {
#RequestMapping(value="/choice", method = RequestMethod.POST)
public #ResponseBody NameValue addUserChoice(#Valid #RequestBody NameValue action)
{
return action;
}
}
This is the servlet application context:
<mvc:annotation-driven/>
<context:component-scan base-package="com.my.package" />
<bean
class="org.springframework.web.servlet.view.ContentNegotiatingViewResolver">
<property name="mediaTypes">
<map>
<entry key="json" value="application/json" />
</map>
</property>
<property name="defaultContentType" value="application/json" />
<property name="defaultViews">
<list>
<bean
class="org.springframework.web.servlet.view.json.MappingJacksonJsonView" />
</list>
</property>
</bean>
Web xml:
<servlet>
<servlet-name>action-api</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>action-api</servlet-name>
<url-pattern>/*</url-pattern>
</servlet-mapping>
The configuration above is working. The problem starts when I try to change web.xml so the controller will only be responsible for "/api/*". I change it to <url-pattern>/api/*</url-pattern>. In that case Spring cannot find the right controller.
(DispatcherServlet:819) - DispatcherServlet with name 'action-api' processing POST request for [/api/choice]
(RequestMappingHandlerMapping:209) - Looking up handler method for path /choice
(RequestMappingHandlerMapping:219) - Did not find handler method for [/choice]
(PageNotFound:1080) - No mapping found for HTTP request with URI [/api/choice] in DispatcherServlet with name 'action-api'
(DispatcherServlet:913) - Successfully completed request
Modifying the servlet application context helps, Spring now able to find the controller, but validation is not invoked anymore.
<bean
class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter">
<property name="alwaysUseFullPath" value="true" />
<property name="messageConverters">
<util:list id="beanList">
<bean class="org.springframework.http.converter.StringHttpMessageConverter"/>
<bean class="org.springframework.http.converter.json.MappingJacksonHttpMessageConverter"/>
</util:list>
</property>
</bean>
<bean
class="org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping">
<property name="alwaysUseFullPath" value="true" />
</bean>
<bean class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
<property name="alwaysUseFullPath" value="true" />
</bean>
Here is the log:
(DispatcherServlet:819) - DispatcherServlet with name 'action-api' processing POST request for [/api/choice]
(RequestMappingHandlerMapping:209) - Looking up handler method for path /choice
(RequestMappingHandlerMapping:219) - Did not find handler method for [/choice]
(DefaultAnnotationHandlerMapping:124) - Mapping [/api/choice] to HandlerExecutionChain with handler [com.my.package.controller.UserActionsController#1f86dbd] and 1 interceptor
(HandlerMethodInvoker:638) - Reading [com.my.package.model.NameValue] as "application/json" using [org.springframework.http.converter.json.MappingJacksonHttpMessageConverter#2059ef]
(HandlerMethodInvoker:173) - Invoking request handler method: public com.my.package.model.NameValue com.citypath.dima.controller.UserActionsController.addUserChoice(com.my.package.model.NameValue)
(AnnotationMethodHandlerAdapter:1037) - Written [com.my.package.model.NameValue#166685b] as "application/json;charset=UTF-8" using [org.springframework.http.converter.json.MappingJacksonHttpMessageConverter#2059ef]
(DispatcherServlet:957) - Null ModelAndView returned to DispatcherServlet with name 'action-api': assuming HandlerAdapter completed request handling
(DispatcherServlet:913) - Successfully completed request
Looks like Spring making some binding on the fly, but this time validators are ignored.
I need to have 2 controllers for, say '/api' and '/something'. How can I define it in web.xml so Spring will be able to locate them and to invoke validation?
Thanks.
Spring #Controllers URLs are always interpreted relative the the Spring Dispatcher Servlet that handles them. So if you map the dispatcher servlet to /api/* in web.xml then the URL to your controller above is /api/api/choice
So you can configure two spring dispatcher servelts in web.xml one mapped to /api in the web.xml and one mapped to /somethingelse in web.xml then you can just remove /api from the #RequestMappings
In my app I am using a single Dispatcher Servlet for api and UI and I use public static final String called URL in my various API controllers to build up the paths to the various resources exposed by the API. Below is an example from my API.
#Controller
#RequestMapping(CompanyPermissionsResourceController.PATH)
public class CompanyPermissionsResourceController extends BaseApiController
{
public static final String PATH = CompanyResourceController.PATH + "/permissions";
Are you sure you are making post request to /api/choice?
#RequestMapping(value="/choice", method = RequestMethod.POST)
Try Changing to
#RequestMapping(value="/choice", method = RequestMethod.GET)
public #ResponseBody NameValue addUserChoice(#Valid #RequestBody NameValue action)
{
return action;
}
I don't think it works like this. Put all the path /api/choice at method level.