When I go to the first url, it calls my home() method in the controller but when I go to the second url it does not call my homeTest() method. Why is that?
I get 404 error.
http://localhost:9083/MYAPP/foo ------ first url
http://localhost:9083/MYAPP/foo/bar ------ second url
web.xml
<servlet>
<servlet-name>springServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/spring/appServlet/servlet-context.xml</param-value>
</init-param>
<load-on-startup>2</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>springServlet</servlet-name>
<url-pattern>/foo/*</url-pattern>
</servlet-mapping>
Controller:
#RequestMapping(value="/foo", method = RequestMethod.GET)
public String home(Model model){
return "home";
}
#RequestMapping(value="/foo/bar", method = RequestMethod.GET)
public String homeTest(Model model){
return "home";
}
You need to configure your RequestMappingHandlerMapping.
The official documentation goes into detail about handler mappings and some of their properties. The relevant one here is alwaysUseFullPath:
alwaysUseFullPath If true, Spring uses the full path within the current Servlet context to find an appropriate handler. If false
(the default), the path within the current Servlet mapping is used.
For example, if a Servlet is mapped using /testing/* and the
alwaysUseFullPath property is set to true, /testing/viewPage.html
is used, whereas if the property is set to false, /viewPage.html is
used
In short, when trying to find a mapping for /foo/bar, it removes the part that was matched by the Servlet environment, the /foo, and only uses the /bar to find a handler. You have no handler mapped to /bar.
By setting the property above to true, it will use the full path.
You can configure this in a #Configuration annotated WebMvcConfigurationSupport subclass, by overriding requestMappingHandlerMapping
#Override
public RequestMappingHandlerMapping requestMappingHandlerMapping() {
RequestMappingHandlerMapping handlerMapping = super.requestMappingHandlerMapping();
handlerMapping.setAlwaysUseFullPath(true);
return handlerMapping;
}
Or whatever mechanism is appropriate for your configuration (there's an XML equivalent for example).
There's a special case for the exact match of /foo. It's not particularly relevant here.
Just change:
<url-pattern>/foo/*</url-pattern>
To
<url-pattern>/foo/**</url-pattern>
Related
/spring/fetchAllUsers URL which am trying
web.xml
<servlet>
<servlet-name>user</servlet-name>
<servlet-class> org.springframework.web.servlet.DispatcherServlet </servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:springContext/dataSource.xml</param-value>
</init-param>
<load-on-startup>3</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>user</servlet-name>
<url-pattern>/spring/</url-pattern>
</servlet-mapping>
Controller Code
#RequestMapping(value = "/getAllUsers", method = RequestMethod.POST)
#ResponseBody
#Transactional(propagation=Propogation.REQUIRED,rollBackFor=Exception.class)
public String fetchAllUsers(){
setInputStream(userDelegate.fetchAllUsers());
return success;
Details:
And I have mvc annotation driven and mvc default servlet handler in user-servlet.xml
Getting 404 error code when try to access this URl when doing migration from struts to spring
Break point is not hit when this URL is hit and no errors in console as well.Please suggest on the above issue
According to your servlet mapping only one url is allowed localhost:8080/context/spring/ that is not mapped with your controller.
When we defined a servlet-mapping, we are using SimpleUrlHandlerMapping. To understand servlet url mapping let define a servlet mapping :
<servlet-mapping>
<servlet-name>user</servlet-name>
<url-pattern>/spring/*</url-pattern>
</servlet-mapping>
Now the handler will actually use the * part to find the controller. It will not search /spring/createUser, it will only search for /createUser to find a corresponding Controller.
#RequestMapping("/createUser")
In your case You need to either change your url to localhost:8080/spring/spring/createUser or remove prefix from Controller #RequestingMapping(/createUser).
since your servlet url mapping has already include /spring you don't need to include it in #RequestMapping.
try this:
#RequestMapping(value = "/createUser/", method = RequestMethod.POST)
Spring interprets urls /spring/createUser/ and /spring/createUser differently(atleast in POST methods that i just tested).
Change your #RequestMapping url to /spring/createUser.
Also mind that the url you call is /spring/createUser without a trailing slash("/").
Your method
#RequestMapping(value = "/spring/createUser", method = RequestMethod.POST)
Hope this helps.
I am having difficulty getting requests mapped to the correct servlet when the servlet-mapping url-pattern uses a wildcard. I want all requests that begin with "/profile-api" to be mapped to a new REST service I'll be writing soon.
From web.xml:
<!-- default servlet -->
<servlet-mapping>
<servlet-name>professional</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
<!-- profile api -->
<servlet-mapping>
<servlet-name>profile-api</servlet-name>
<url-pattern>/profile-api/*</url-pattern>
</servlet-mapping>
Pseudo-code from the controller that allows a third-party system to update a user's "email communication opt-in status" (OptinResponse is a domain class that will ultimately be transformed to JSON and returned to caller):
#Controller
#RequestMapping("/profile-api")
public class ProfileAPIController {
#RequestMapping(method = RequestMethod.GET, value="/setoptin/{userID}")
public #ResponseBody OptinResponse setOptinStatus(#PathVariable String userID) {
return new OptinResponse("200", "Successfully set optin status for user: " + userID);
}
}
I would expect a request to "{localhost}/profile-api/setoptin/12345" to be correctly routed to the ProfileAPIController, but it is not.
Changing the servlet-mapping url-pattern to be more specific but still generic also fails:
<servlet-mapping>
<servlet-name>profile-api</servlet-name>
<url-pattern>/profile-api/setoptin/*</url-pattern>
</servlet-mapping>
The ONLY way I have been able to get my request routed as intended is to include the full, exact path:
<servlet-mapping>
<servlet-name>profile-api</servlet-name>
<url-pattern>/profile-api/setoptin/12345</url-pattern>
</servlet-mapping>
Obviously, that's unacceptable, as the user id must be variable.
In all cases, the request is instead mapped to the default "professional" servlet. I have tried reordering the servlet-mapping nodes to no avail. I have "alwaysUseFullPath" set to "true" in the AnnotationMethodHandlerAdapter bean in the servlet config (but have tried it as "false", too). I feel as though I'm overlooking something simple, but can't see the forest for the trees.
Basically I have a mapping like /A/B/something whose mapping is given as:
#Controller
#RequestMapping("/B")
public class BController {
...
#RequestMapping(value = "/something", method = RequestMethod.POST)
public ModelAndView func1()....
func1() gets called.
In web.xml, the definition is given only for A.
So its something like:
<servlet>
<servlet-name>A</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<load-on-startup>2</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>A</servlet-name>
<url-pattern>/A/*</url-pattern>
</servlet-mapping>
In applicationcontext.xml, there is component scan for this BController.
<context:component-scan base-package="BController" />
So, my question is:
How does servlet know to move from /A's mapping to /B's mapping. How
is func1() getting called?
If applicationcontext.xml directly takes /B into
consideration, why is func1() not getting called after I delete /A from the call ( If I call /B/something from my application, it
gives an error. )?
Any help is appreciated.
Thanks :)
The spring DispatcherServlet is a central component which dispatches all requests to the registered handlers (the controllers). In your case, it has been mapped to the /A relative path:
<url-pattern>/A/*</url-pattern>
The line above basically tells the web container, that each and every request which starts with /A relative to the host should be handled by the spring DispatcherServlet. From this point further, it's up to Spring to handle the mappings.
#RequestMapping("/B")
The line above adds up to the DispatcherServlet, so to this point it maps to /A/B
#RequestMapping(value = "/something")
Similar to the previous request mapping, the line above adds up to the class level mapping, so the method func1 will finally be called with the following call:
POST <yourhost>/A/B/something
Hope that helps.
I wanna use the same restful webservice path to produce xml or json, or a xml with xsl header.
Is it possible using any framework(jersey or resteasy) in java?
Eg:
#Path("/person")
public class PersonService {
#GET
#Path("/find")
public Person find(#QueryParam("name") String name, #QueryParam("outputformat") String outputformat) {
// do some magic to change output format
return dao.findPerson(name);
}
}
Maybe you can write a servlet filter that takes the query string and uses it to set the request's accept header accordingly, then jersey should dispatch to whatever method is annotated with #Consumes that matches.
For example, servlet filter intercepts request "?outputFormat=xml" and sets the Accept header to "application/xml". Then, jersey should dispatch to whichever method in your resource is annotated with: #Consumes("application/xml")
This question might help: REST. Jersey. How to programmatically choose what type to return: JSON or XML?
You could also easily customize Jersey ServletContainer and you won't require another param to pass along. You could negotiate representation using .json or .xml in your URL.
public class MyServletContainer extends ServletContainer {
#Override
protected void configure(ServletConfig servletConfig, ResourceConfig resourceConfig, WebApplication webApplication) {
super.configure(servletConfig, resourceConfig, webApplication);
resourceConfig.getMediaTypeMappings().put("json", MediaType.APPLICATION_JSON_TYPE);
resourceConfig.getMediaTypeMappings().put("xml", MediaType.APPLICATION_XML_TYPE);
}
}
In your web.xml, you could define the custom servlet as shown below.
<servlet>
<servlet-name>Jersey Web Application</servlet-name>
<servlet-class>com.sun.jersey.MyServletContainer</servlet-class>
<init-param>
<param-name>javax.ws.rs.Application</param-name>
<param-value>com.sun.jersey.MyWebApplication</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
You could use Jersey and use the annotation #Produces({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML}). You would need to add a mapping feature for POJOs in your application as well. The include in the web.xml file would be
<filter>
<init-param>
<param-name>com.sun.jersey.api.json.POJOMappingFeature</param-name>
<param-value>true</param-value>
</init-param>
</filter>
Other configurations would be necessary, but it is all in the documentation http://jersey.java.net/nonav/documentation/latest/user-guide.html
At first in my web server I only had one REST servlet. Something like:
#Path("/")
public class Controller {
#GET
#Produces({ MediaType.TEXT_HTML })
public Response get(#Context UriInfo info) throws Exception {
...
}
#GET
#Path("resource1")
#Produces({ MediaType.TEXT_HTML })
public Response resource1() throws Exception {
...
}
...
}
And the web.xml:
<servlet>
<servlet-name>rest</servlet-name>
<servlet-class>com.sun.jersey.spi.container.servlet.ServletContainer</servlet-class>
<init-param>
<param-name>com.sun.jersey.config.property.packages</param-name>
<param-value>xpto.mypack1;xpto.mypack2</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>rest</servlet-name>
<url-pattern>/*</url-pattern>
</servlet-mapping>
But then I wanted to add some static html to the server, so I updated the servlet mapping to
/rest/*
and the #Path directive of Controller servlet class from "/" to "/rest". Everything works fine but the sub-resources or methods of controller with the #path directive that stopped working.. ie:
/ works fine since I have an index.html page at root
/rest works fine, it invokes the get method of my servlet
/rest/resource1 returns 404 http code...
Any help? I already tried a list of combinations of / after and before each #Path directive, with no success... Many thanks
One update:
I used the trace util and got the following results:
for /[app-name]/rest (it works):
X-Jersey-Trace-002 accept right hand path java.util.regex.Matcher[pattern=/rest(/.*)? region=0,11 lastmatch=/rest]: "/rest" -> "/rest" : ""
X-Jersey-Trace-003 accept resource: "rest" -> #Path("/rest") xpto.mypack.Controller
X-Jersey-Trace-000 accept root resource classes: "/rest"
X-Jersey-Trace-001 match path "/rest" -> "/application.wadl(/.)?", "/rest(/.)?"
for /[app-name]/rest/resource1 (it doesn't work):
X-Jersey-Trace-002 matched exception mapper: com.sun.jersey.api.NotFoundException#4fd41dc3 -> xpto.myclass
X-Jersey-Trace-003 mapped exception to response: com.sun.jersey.api.NotFoundException#4fd41dc3 -> 404 (Not Found)
X-Jersey-Trace-000 accept root resource classes: "/resource1"
X-Jersey-Trace-001 match path "/resource1" -> "/application.wadl(/.)?", "/rest(/.)?"
I hope it helps someone to help me..
If you define your servlet mapping as /rest/*, don't repeat /rest in the #Path annotation of your resources. I.e. all you need to do is keep the controller as is (in your question above) and just change the servlet mapping. The URL at which the resources are available is:
<application_context_path>/<servlet_mapping>
So, if you change the #Path annotation from #Path("/") to #Path("rest") and you also change the servlet mapping to /rest, then your resources would be available at:
<application_context_path>/rest/rest/*