In my previous experience:
When using pure servlet, we define servlets so that it will serve requests that match specific urls.
When using struts2, we define a filter so that it will serve requests that match specific urls.
When using springMVC in a traditional xml configuration style, we define a dispatcher servlet so that it will serve requests that match specific urls.
But with spring-boot:
Seems no servlet or filter is defined explicitly. But it still could serve specific urls.
The questions is:
Is it still using servlet? If yes, how it get to serve urls without defining servlet or filter explicitly?
Additional related questions (base on tips from comments):
It seems the implementation of SpringBootServletInitializer will be invoked on deploy, but who is going to invoke it?
As you can see here in details, on startup, while initializing an embedded server (Tomcat by default), Spring Boot creates and registers DispatcherServlet as a servlet.
Spring then, as usual, scans your own classes (including the one you invoke SpringApplication.run() from) and sets corresponding mapping for your controllers, if you have any. For example mapping for /hello here:
#RestController
#EnableAutoConfiguration
public class TestSpring {
#RequestMapping("/hello")
String hello() {
return "Hello World!";
}
public static void main(String[] args) throws Exception {
SpringApplication.run(TestSpring.class, args);
}
}
Related
Set Context path differently for both Webservice and Rest
I have an application which contains both implementation of Webservices and Rest services and I am looking for an solution to set context path for both Webservices and Rest services differently using yml/properties file
How to configure servlet dispatcher to work properly?
I would like to have:
localhost:8080/ws/* - webservice
localhost:8080/web/* - MVC components
servlet:
context-path: "/ws"
It sets globally for both webservices and rest services , How to make it independent to each other with out programming?
Using Spring Boot (with Spring Starter Web) you could achive what are you asking for with the annotation #RequestMapping.
You could put #RequestMapping(value="/ws") on the class declaration of every rest controller and #RequestMapping(value="/web") for web controllers.
For both rest and web controller than you could use other annotations to specify method path, i.e #GetMapping(value="/methodPath").
#Controller
#RequestMapping(value="/web")
public class WebController{
#GetMapping(value="/method")
public String method(){
...
}
}
#RestController
#RequestMapping(value="/ws")
public class RestController{
#GetMapping(value="method")
public String method(){
...
}
}
I am working with Spring Boot 2 and I would like my requests to be handled asynchronously.
In Java EE, one can use Asynchronous Processing for Asynchronous Servlets as in this link. The following is a related example:
#WebServlet(urlPatterns={"/asyncservlet"}, asyncSupported=true)
public class AsyncServlet extends HttpServlet { ... }
and the above allows to use AsyncContext.
But in Spring Boot, I have the following #RequestMapping. How do I make it handle requests in Asynchronous mode and also supporting AsyncContext? How do I leverage the use of an Asynchronous Web Servlet?
#RestController
public class myRestController {
#RequestMapping("{resource}/**")
public void resourceRequest (#PathVariable("resource") String resource) {
// example:
// ... some long running calls such as database communication
// ... convert request through AsyncContext ctx = req.startAsync();
// etc
}
}
Note that returning void is intentional.
I found the following SO answer How to register a servlet with enabled "async-supported" in Spring-Boot? saying that "Spring Boot will automatically register any Servlet beans in your application context with the servlet container. By default async supported is set to true so there's nothing for you to do beyond creating a bean for your Servlet." but I am not using any #WebServlet annotations anywhere in my program, just the #RestController annotation. So how do I ensure that I am benefitting from asyncSupported option?
Problem:
I have a WebFilter which forwards valid urls to either a proxy servlet or a servlet which handles a webpage for the admin to monitor recent requests and more.
The admin servlet is suppost to forward ajax requests to a REST service (after login.jsp from the webpage rendered by controlpannel.jsp ) but apparently the rest service has a different context as the WebFilter and WebServlets ?
Question:
So is it at all possible to forward from my WebServlet to the rest helper servlet (and its resource classes) ?
More specific Information:
This is how I use forwarding:
ServletContext sc = request.getServletContext();
RequestDispatcher dispatcher = sc.getRequestDispatcher(forwardURI);
dispatcher.forward(request, response);
I tried to forward to this uri:
forwardURI = /REST/proxy_client/newer_than
My rest helper servlet:
#Stateless
#ApplicationPath("/REST")
public class RestService extends Application {
#Override
public Set<Class<?>> getClasses() {
final Set<Class<?>> restResourceClasses = new HashSet<Class<?>>();
restResourceClasses.add(ProxyClientResource.class);
return restResourceClasses;
}
}
And this resource class:
#Path("/proxy_client")
#Stateless
public class ProxyClientResource {
#EJB
private ProxyClientBean proxyClientBean;
#GET
#Produces("application/json")
#Path("/newer_than")
public String getNumberOfEntriesNewerThanTimestamp(#QueryParam("timestamp") Expression<Timestamp> indexTimestamp,
#QueryParam("numberOfclients") Integer numberOfclients) {
List<ProxyClient> pageData = proxyClientBean.getElementsNewerThan(numberOfclients, indexTimestamp);
return convertToJSONstring(pageData);
}
Solution attempt:
I found this question about how to call a rest web service from a servlet, but they use a client and no forwarding.
EDIT:
I had a configuration problem (might still have one), so now when I try to forward to my rest helper servlet (the one extending javax.ws.rs.core.Application) I get this error:
RestServlet is currently unavailable
(in the web.xml I call the Servlet RestServlet)
when accessing the REST api directly I get:
HTTP Status 500 - Authenticator.invoke() failed
but I can't find out what this means.
Edit2:
I will try repacing the subclass of Applicaton with a config in web.xml subclassing and #ApplicationPath dont seem to work for me. Also when I try to get the rest ServletsContext I get an error that no class has been specified, which is something you do when using the web.xml config.
Edit3:
I'm deploying my application on HCP and with the underlying problem beeing that I cant even access my REST service I found this SAP discussion.
When I get my REST service working without forwarding I will report back here.
Edit4:
This actually answers the question from Edit3
I had to add jersey 1.19.1 (not 2.x because im using Java EE6 which only supports up to DWP 3.0 not 3.1 as required) to by projects libraries otherwise It would say that I didn't specify a servlet class (but when I tried to add javax.ws.rs.core.Application it would tell me this is no Servlet class even though I have seen this configuration).
My real problem was that the javax.ws.rs.core.Application from the Java ee6 container on SAP Hana Cloud Platform did not work for a unkown reason.
The solution was to download and add the jersey-bundle-1.19.1.jar to WEB-INF/lib and the projects libraries.
There is no problem at all to forward a request from a vanilla servlet to the rest service! If it does not work in your case its most likely your setup or some unexpected reason like it was in my case.
I have a spring MVC 4 application, I want to serve all URLs under "/editor/**" with the same "/editor/index.html" resource.
I am using EmberJS with History API, so a request like /editor/task/1 is not really a URL its merely a history URL that should be sent to /editor/index.html and it will handle it.
I tried using
<mvc:resources mapping="/editor/**" location="/editor/"/>
but this don't work, it sends subsequent URLs like "/editor/task/1" to the servlet and of course it sends a 404 resource not found.
is there a way to serve all the urls with the same resource ?
You should define a controller which returns the same view for all urls matching "/editor/*".
#Controller
public class EditorController {
#RequestMapping("/editor/*")
#GET
public String doGet() {
return "editor/index.html";
}
One of my projects uses Spring MVC to handle URL mappings and dispatch logic. I have now to use a third party library which uses its own HttpServlet as the main entry point for its functionalities, but as it's an optional drop-in replacement for another library I can't just put the <servlet> declaration in the web.xml: I'd rather use a Controller and Spring profiles to switch between such implementations without having to edit the web.xml.
Is there anything offered OOTB by Spring to handle such cases? I don't seem to find it right away.
Thanks in advance!
Since registering the third party servlet in your web.xml is a no-go, I think your best bet would be to create a singleton instance of the servlet in your ApplicationContext, and then create a custom view that delegates to said servlet's service method.
You can see an example of custom views in action in this tutorial.
Answering my own question here just in case my approach can be useful to others.
There are two key factors I needed to consider:
the proper initialization of the servlet
give the servlet full control over the HTTP layer (e.g. setting HTTP headers, etc)
In my specific case there's no need for properly handling the servlet destruction, as it's a no-op.
I ended up writing a dedicated Controller, to be instantiated only if a specific Spring profile is activated, which takes care of instantiating and initializing the Servlet. Then, all the requests will be directly handled in a void handler method, as follows:
public class ServletDelegatingController implements ServletConfig {
private final DelegateServlet delegate = new DelegateServlet();
public void handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception {
delegate.service(request, response);
}
// properly initializes the servlet
public void setServletConfig(ServletConfig servletConfig) {
try {
delegate.init(servletConfig);
} catch (ServletException e) {
throw new IllegalStateException("Failure while initializing the servlet", e);
}
}
}
The delegating-servlet.xml for the DispatcherServlet looks like the following:
<beans profile="custom">
<bean id="cmisServiceFactory"
class="com.foo.ServletDelegatingController"/>
</beans>