I am using servlet to get request from frontend.
Am i able to make single servlet which could do multiple operation based on url pattern?
Here will be my url mapping
<servlet>
<servlet-name>Hello</servlet-name>
<servlet-class>HelloWorld</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>Hello</servlet-name>
<url-pattern>/HelloServlet</url-pattern>
<url-pattern>/HelloServletOne</url-pattern>
<url-pattern>/HelloServletTwo</url-pattern>
</servlet-mapping>
That means if i hit to the url as framed below it should invoke its own functionalities.
URL:/HelloServlet: it should do function 1
URL:/HelloServletOne: it should do function 2
URL:/HelloServletTwo: it should do function 3 etc.
How can i achive this by extending servlet.?
Code/link examples are much appreciated.
Regarding your url-pattern you need to know what URL was called. Because a request can be made due to different http-methods (GET, POST etc.) you can use parts of the FrontController Pattern
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class HelloServlet extends HttpServlet {
private static final String SERLVET = "HelloServlet";
private static final String SERLVET_ONE = "HelloServletOne";
private static final String SERLVET_TWO = "HelloServletTwo";
#Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
processRequest(req, resp);
}
#Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
processRequest(req, resp);
}
private void processRequest(HttpServletRequest req, HttpServletResponse resp) {
String path = req.getServletPath();
switch (path) {
case SERLVET:
// ... call your function1
break;
case SERLVET_ONE:
// ... call your function2
break;
case SERLVET_TWO:
// ... call your function3
break;
default:
break;
}
// do something else
}
}
The getServletPath method may only work for explicit url-patterns like you have given. For other information on the URL check this link
You can handle multiple requests by the same servlet by making a contract to have a request parameter like 'ACTION'. Then in your forms add this as hidden field with values like 'ACTION_1' and 'ACTION_2' and 'ACTION_3'. So, in doPost() you can check this parameter value and can invoke respective handling methods in same servlet.
class YourServlet extends HttpServlet{
public void doPost(HttpReq req, HttpResp resp){
String action = reg.getParameter('ACTION');
if('ACTION_1'.equals(action)){
doAction_1();
}
if('ACTION_2'.equals(action)){
doAction_2()
}
if('ACTION_3'.equals(action)){
doAction_3()
}
else {
defaultAction();
}
}
}
I made into.
HttpServletRequest.getRequestURI() returns the URL pattern including /* with query parameter if exist, and HttpServletRequest.getPathInfo() returns the part matched by /* (or null for exact match).
Here in my case i need getPathInfo() where it will returns
HelloServlet,HelloServletOne or HelloServletTwo based on request.
Thanks.
You should not use three different Servlet for this purpose. You should use different methods of Servlet to achieve this.
Use doGet method for get data.
Use doPost method for insert data.
Use doPut method for update data.
Use doDelete method for delete data.
Please refer servlet api documentation for more details.
EDIT:
Read more about this here.
It says the url mapping you have provided must work if you are working with servlet api version 2.5 or greater.
Also, please make sure that you have provided fully qualified name of servlet class in <servlet-name>.
Related
I am trying to do the following: I create a servlet to handle all requests, and if the url contains the word "hello", then set the response code to 403, otherwise forward the request to an html page. Here is my servlet:
#WebServlet("/*")
public class AllRequestsHandlerServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String url = request.getRequestURL().toString();
if(url.contains("hello")) {
response.setStatus(HttpServletResponse.SC_FORBIDDEN);
} else {
RequestDispatcher dispatcher = request.getRequestDispatcher("/static-html-page.html");
dispatcher.forward(request, response);
}
}
}
But after forwarding, since this servlet handles the forwarded request too, it causes an infinite loop. How can I avoid that?
This will never work because /* maps to every request - including your forward to /static-html-page.html and path mappings take priority over all other mappings.
There are a couple of ways around this. The simplest (assuming no other content in the web app) would be:
rename /static-html-page.html to /static-html-page.jsp
change the mapping from /* to /
That does mean that /static-html-page.jsp would be directly accessible. If you don't want that, move it under /WEB-INF. request.getRequestDispatcher("/WEB-INF/static-html-page.html") will still work.
I am developing a shopping cart using servlets, have two servlets :
1. ShopingCart.java
2. TotalAmount.java
In ShopingCart.java i have created sessions and synchronise them using
synchronized(session) // lock session protect this from multiple threads
{
TotalAmount cart = (TotalAmount)session.getAttribute("Cart");
if(cart == null) // new sesssion, just create a cart
{
cart = new TotalAmount();
session.setAttribute("Cart", cart);
}
// I have to call cart.display();
and my display method in TotalAmount.java contains (request,response) as parameters.
so, how can i pass the request and response to display method?
yes, i need request and response parameters in display method to save some variable data in session in TotalAmount.java
Please Help..
I can pass the request and response to display method of TotalAmount.java by calling
Display(request,response);
As I already have the object of TotalAmount in ShopingCart.java
As per Java EE specification, servlet are independents and the only official way to interact with one is via their service(ServletRequest req, ServletResponse res) or doXXX method.
If you want to call a specific method of another servlet you have 2 broad solutions :
make the objects know each other by dependancy injection (Java EE CDI, Spring framework, etc.) - clean and neat provided you have one DI mechanism
manually register them via static method - say you want to access Servlet2 from Servlet1
class Servlet1 implement HttpServlet {
private static Servlet2 servlet2 = null;
public static void setServlet2(Servlet2 servlet2) {
this.servlet2 = servlet2;
}
// ... other code
servlet2.display(...);
// ...
}
class Servlet2 implements HttpServlet {
#Override
public void init(ServletConfig config) {
Servlet1.setServlet2(this);
// ... other init code eventually
}
// ...
}
It should work but is not very nice because of the static misuse.
forward to the other servlet and pass a request attribute to indicate that a special action is requested (assuming Servlet2 is named "Servlet2" in web.xml)
in Servlet1 :
request.setAttribute("DISPLAY", true);
request.getServletContext().getNamedDispatcher("Servlet2").forward(req, resp);
in Servlet2 :
public void service(ServletRequest req, ServletResponse resp) {
if (req.getAttribute("DISPLAY") != null) {
display(req, resp);
}
else {
super.service(req, resp); // or directly your code
}
}
Still a nice solution because attribute will not be set in a direct call (of course, you can use req.getRequestDispatcher("/Servlet2URL") instead of getServletContext().getNamedDispatcher("Servlet2"))
I am learning JSP and Servlets. Consider the following code inside the doPost method of a Servlet which forwards a HTTP request to a JSP -
RequestDispatcher view = request.getRequestDispatcher("/MyWebApp/MvcView.jsp");
I wonder what will happen if someone wants this servlet to forward the request to another jsp instead of the one above ? Does one have to change this code manually every time in their application ? How can one free oneself of all this manual work ?
One simple solution is to set the url as a parameter for your servlet:
<servlet>
<servlet-name>YourServlet</servlet-name>
<servlet-class>com.you.YourServlet</servlet-class>
<init-param>
<param-name>url</param-name>
<param-value>/MyWebApp/MvcView.jsp</param-value>
</init-param>
</servlet>
and the in the servlet:
public class YourServlet {
protected String url = null;
public void init(ServletConfig servletConfig) throws ServletException {
this.url = servletConfig.getInitParameter("url");
}
public void service(ServletRequest request, ServletResponse response)
throws ServletException, IOException {
RequestDispatcher view = request.getRequestDispatcher(url);
}
}
then there is no need to recompile servlet code to chage the url.
A request to an Action can be validated using the Interceptors. Also, Direct request to a JSP page can be avoided using an empty action declaration. It is something like this;
<action name="home" >
<result>home.jsp</result>
</action>
I want to validate this calling to the JSP page. As I feel that a simple approach can be adding an Action (ActionSupport) with an Interceptor which checks the action name( and do some validation using session etc). But I've a doubt that whether it reduces the performance,because that action class doesn't do anything and just execute its execute() only(useless task...), and where there should be an empty Action .(BUT: as I ve read some docs on Struts2, it is said that even though we don't add an Action calss,the framework itself adds and action class which returns "success" therefore,adding an action class or not ourselves, doesn't affect newly )
Any way, I d like to know what your best approaches are to validate or authorized access to some JSP pages.( number of pages can be many.. not only to one jsp page)
Added:
Example:
Lets say that, there are some restricted pages where all users can't have access,for example user's account page can be visited only to logged in users.There can be more such type of pages. If a request comes to a such page,the user has to be validated.Then, if the request comes through a empty/anonymous action (as explained in above code snip -only action name-no real class) how to validate such requests to JSP pages? Should an action class be used for this?
If your attention is to secure some part of your application so as only Authenticated as well authorize use can access that part, than you have two option
Use an interceptor based authentication
User a security API like Spring -security
Interceptor based authentication is quite easy. here is an example how to do this, but such authentication is not recommended for a production based and real life application since its really a very simple case.
if you are looking for a complete authentication system, i suggest you to look at Spring security.Its quite easy and configurable, all you need to tell the underlying spring mechanism which all areas and under secure tag and Spring security will intercept them before your action get called and only successful and authorize action will get called by spring security.
//This is for authorization
package com.kogent.action;
import java.io.IOException;
import java.util.List;
import java.util.regex.Pattern;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.struts2.dispatcher.Dispatcher;
import org.apache.struts2.dispatcher.mapper.ActionMapping;
import org.apache.struts2.dispatcher.ng.ExecuteOperations;
import org.apache.struts2.dispatcher.ng.InitOperations;
import org.apache.struts2.dispatcher.ng.PrepareOperations;
import org.apache.struts2.dispatcher.ng.filter.FilterHostConfig;
import org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter;
public class SessionController extends StrutsPrepareAndExecuteFilter {
protected PrepareOperations prepare;
protected ExecuteOperations execute;
protected List<Pattern> excludedPatterns = null;
public void init(FilterConfig filterConfig) throws ServletException {
InitOperations init = new InitOperations();
try {
FilterHostConfig config = new FilterHostConfig(filterConfig);
init.initLogging(config);
Dispatcher dispatcher = init.initDispatcher(config);
init.initStaticContentLoader(config, dispatcher);
prepare = new PrepareOperations(filterConfig.getServletContext(),
dispatcher);
execute = new ExecuteOperations(filterConfig.getServletContext(),
dispatcher);
this.excludedPatterns = init.buildExcludedPatternsList(dispatcher);
postInit(dispatcher, filterConfig);
} finally {
init.cleanup();
}
}
/**
* Callback for post initialization
*/
protected void postInit(Dispatcher dispatcher, FilterConfig filterConfig) {
}
public void doFilter(ServletRequest req, ServletResponse res,
FilterChain chain) throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) req;
HttpServletResponse response = (HttpServletResponse) res;
try {
prepare.setEncodingAndLocale(request, response);
prepare.createActionContext(request, response);
prepare.assignDispatcherToThread();
if (excludedPatterns != null
&& prepare.isUrlExcluded(request, excludedPatterns)) {
chain.doFilter(request, response);
} else {
request = prepare.wrapRequest(request);
ActionMapping mapping = prepare.findActionMapping(request,
response, true);
if (mapping == null) {
boolean handled = execute.executeStaticResourceRequest(
request, response);
if (!handled) {
chain.doFilter(request, response);
}
} else {
//here you have to identify the whether the user have access to requested resource or not
//allow him if he was access.
//if(someCondition)
execute.executeAction(request, response, mapping);
//else{
//redirect the user how do you want it to be.
ActionMapping modfiedActionMapping = new ActionMapping();
modfiedActionMapping.setName("someActionName");
modfiedActionMapping.setNamespace("someNameSpace");
execute.executeAction(request, response, modfiedActionMapping);
//}
}
}
} finally {
prepare.cleanupRequest(request);
}
}
public void destroy() {
prepare.cleanupDispatcher();
}
}
<filter>
<filter-name>struts2</filter-name>
<filter-class>Point to your customized filter</filter-class>
</filter>
I've got this issue, recently I read about the REST arquitecture and it makes a perfect sense, so I'd like to achieve a RESTful web application.
Now, I'm following the Front Controller pattern that means that all of the URL mappings go to the controller.java servlet, I map the by specific URLs, not by using the /* wildcard,
the controller implements the four HTTP methods POST,GET,PUT,DELETE, each method calls the controllers service method and there I determine based on the HttpServletRequest and pathInfo the action to execute.
Controller.java
#Override
protected void service(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
IAction action;
View view;
try {
action = ActionFactory.produceAction(req);
view = action.execute(req, resp);
switch (view.getDispatchMethod()) {
case REDIRECT:
resp.sendRedirect(resp.encodeURL(view.getResource()));
break;
case FORWARD:
req.getRequestDispatcher(view.getResource()).forward(req, resp);
break;
case INCLUDE:
req.getRequestDispatcher(view.getResource()).include(req,resp);
break;
default:
}
} catch (ActionFailedException uae) {
req.setAttribute("ActionName", "Action");
req.setAttribute("FailCause", uae.getMessage());
req.getRequestDispatcher(VIEW_FAIL.getResource()).forward(req, resp);
}
}
#Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
this.service(req, resp);
}
#Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
this.service(req, resp);
}
#Override
protected void doPut(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
this.service(req, resp);
}
#Override
protected void doDelete(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
this.service(req, resp);
}
I've run into a particular issue when loading a specific order by the URI /orders/*, it is mapped to the controller servlet, the the action is executed and I load the appropriate order the action returns a View.java class
//ommited accessors and mutators for brevety.
public class View {
public enum DispatchMethod {
INCLUDE, FORWARD, REDIRECT
}
private DispatchMethod dispatchMethod;
private String resource;
public View(DispatchMethod dispatchMethod, String resource) {
this.dispatchMethod = dispatchMethod;
this.resource = resource;
}
}
Then the request is dispatched according to the getDispatchMethod() of the returned view.
Now, here is where the loop gets triggered, I use the following URL, myapp/orders/78965 /orders/* gets mapped to controller.java the appropriate action is executed and the correct order is found by the pathInfo() the returned view is new View(View.DispatchMethod.FORWARD,"order_details.jsp") the problem is that with the three available dispatch methods REDIRECT,FORWARD and INCLUDE a request is re-triggered on the URL and so on and on and on I never reach the order_details.jsp that renders the data.
So, how would you avoid the looping, as I'd like to preserve the URI displaying the order number I use the forward method, also, I'd like to do it using servlets, I've heard of the UrlRewriteFilter maybe in the future, but right now, how would it be done using "Plain Vanilla" since I'm using the Front Controller pattern, will it be necessary to add an additional servlet in the /orders/ URI ?
Any help or insights is truly appreciated.
EDIT 1:
Pasted the source code of the controller, a very basic one, I have my suspicions that the way the service method calls all of the overriden do[Method] of the servlet is triggering the loop and that it may be solved by splittig them.
Implementing a RESTful HTTP interface in Java is a lot easier using a JAX-RS implementation like RESTEasy or Jersey.
Using a Front Controller to dispatch requests to the right resource is a good approach, it's exactly the approach taken by these JAX-RS frameworks. I fear you may be re-inventing the wheel here by writing a bespoke URL parsing and dispatching mechanism when this can be taken off-the-shelf.
JAX-RS is a lightweight way to expose resources. By using a couple of simple annotations you can expose a REST interface without any plumbing required. For example:
public class Order {
#GET
#Path("/orders/{orderId}")
#Produces("text/html")
public void getOrder(#Context HttpServletResponse response,
#Context HttpServletRequest request,
#PathParam("orderId") String orderId) throws ServletException, IOException {
// ... create view and add to request here
request.getRequestDispatcher("orders.jsp").forward(request, response);
}
}
You can see how simple it is to attach this class to a URL path (using the #Path annotation), and how easily you can parse values from the URL using #PathParam. Since you get all the plumbing/dispatching/parsing off-the-shelf, you can concentrate on the bits of your app that are specific to your domain (such as what an order contains).