My question is - if I'm using a gatekeeper servlet to forward pages to other servlets, is it better to let the second servlet refer to the parameters or create attributes for them to refer to?
Say I have a form of:
<form action=www.ermehgerdpuppies.com/Gatekeeper id = puppyForm>
<select name=puppyList>
<option value=cutePuppyServlet_12>CutePuppy
<option value=uglyPuppyServlet_14>UglyPuppy
</select></form>
I submit this form which gets to the Gatekeeper servlet:
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
if (request.getParameterMap().containsKey("puppyList"))
{
String qString = request.getParameter("puppyList");
String[] qsArray = qString.split("_");
request.setAttribute("merPuppy", qsArray[1]);
RequestDispatcher rd = getServletContext().getRequestDispatcher(qsArray[0]);
rd.forward(request, response);
}
}
Which then goes to the cutePuppyServlet (for this example, it goes to cutePuppy)
Now in my cutePuppyServlet.java, I can either refer to the data this way:
request.getParameter("puppyList");
OR
request.getAttribute("merPuppy");
With parameter, I can check if it exists in order to prevent blowing everything up. My question is, which is better for maintainability? Should I just stick with forwarding the parameter or should I create an attribute?
Advantages of using a parameter for the inner servlet:
The nested servlet can stand on its own without the parent servlet, if need be.
Developers are more aware of parameters (I don't know why, but I rarely see request attributes used)
Less code because the container passes them in from client implicitly.
Advantages of using a request attribute:
Includes, forwards, etc. will include them because the request does not change, though its URL may.
This is what attributes are actually meant for, messaging passing between components. Therefore, you are adhering to the servlet design.
At the end of the day, it's not going to matter much. I would pick attributes because I care more about doing things the standard way (even if it is a standard that nobody cares about or follows) than doing it quickly.
If data is already available as a parameter, and is always accessible in your design (that is: your entire request cycle can access the request parameters), and you see no design benefit in setting it as an attribute, then access it as a parameter and forget about setting it as an attribute.
"Less is more", I guess that's the point I'm trying to get across.
I think that the main differentiation is that the "value" part in the pair in attributes can be a Java Object, whereas with parameters it can only be a String.
Related
I have a situation where I need the following RequestMapping:
#RequestMapping(value={"/{section}"})
...method implementation here...
#RequestMapping(value={"/support"})
...method implementation here...
There is an obvious conflict. My hope was that Spring would resolve this automatically and map /support to the second method, and everything else to the first, but it instead maps /support to the first method.
How can I tell Spring to allow an explicit RequestMapping to override a RequestMapping with a PathVariable in the same place?
Edit 2: It seems that it would work if the /support mapping came before the /{section} mapping. Unfortunately we have dozens of controllers containing numerous methods with RequestMapping. How can I make sure that the controller with the /{section} mapping is initialized last? Or would a pre-interceptor be the way to go?
Edit 1: This is simplified, I know that having those two RequestMapping alone wouldn't make much sense)
Using Spring you can extend the org.springframework.web.HttpRequestHandler to support your scenario.
Implement the method:
#Override
public void handleRequest(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {}
Use it to analyze the incoming request, determine if the request url is part of your special subset of request url's and forward to the appropriate location.
Ex:
#Override
public void handleRequest(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
/** You will want to check your array of values and have this data cached **/
if (urlPath.contains("/sectionName")) {
RequestDispatcher requestDispatcher = request.getRequestDispatcher("sections" + "/" + urlPath);
requestDispatcher.forward(request, response);
}
}
And setup your sections such as:
#RequestMapping(value={"/sections/{sectionName}"})
This will not interfere with any of your pre-existing controller mappings.
If 2 these methods are defined in 2 different controllers your problem is that you have 2 controllers mapped to same URL. You do not control the order of controllers initialization right now, so the order is random.
I think you need /support mapping to be initialized before /{section}.
To achieve this try to define that controller "section" depends on controller "support". If this will not help try to put both methods together to one controller and put method mapped to "support" before "section"
I this does not work here is other suggestion. What "section" is? If it can accept limited number of values it should be defined as enum. I believe that in this case everything will work as required if support and section methods are in one controller or in separate controllers.
Good luck.
This not seems to be a problem, this is a valid mapping. If you have a look to http://static.springsource.org/spring/docs/current/spring-framework-reference/html/mvc.html#mvc-ann-requestmapping-uri-templates
In the section 16.3.2 Mapping Requests With #RequestMapping exists two methods doing exactly the same that you are trying.
To be sure that your classes are being compiled try to add a #RequestMapping("/someprefix") at class level to see if the URL is being exposed as you want.
I verify your example locally using the version 3.1.0.RELEASE and no issue were present.
As a workaround (and also to provide a well-understand REST URI add some context to your second mapping:
#RequestMapping(value={"client/support"}) // i.e: if you are working with clients
public ModelAndView getsupport(#PathVariable Long supportId){
// do your code here something here
}
Of course that this is valid if this is the unique controller present in the system, otherwise you must use RequestMapping at class level as I suggested above.
I hope this helps.
I am not seeing this behavior with Spring 3.1.2, it could potentially have been a bug with an older Spring version. Here is a gist which runs through without any issues for me - https://gist.github.com/3802254
I have a Http Upload Servlet (http-post) and a user can upload an XML file along with some form fields. I have put on some validation checks to see if there was a bad request (eg. null value). So I used the following code chunk to perform that.
String myID = request.getParameter("ID");
if (myID .equalsIgnoreCase("")|| myID ==null)
response.setStatus(HttpServletResponse.SC_BAD_REQUEST);
else
myBean.setMyId(myID );
Now that I set the response.setStatus, I wanted to see what response.getStatus would look like, but I did not find any method in the HttpServletResponse class (my response is HttpServletResponse) that could show me the status. I needed to output the status as a field called Server Response as a response to the upload. Please help me with suggestions.
The servlet APIs don't provide a way to do this directly, but there are ways you could do this.
The clean way would be to create a Filter to wrap the real HttpServletResponse object with a wrapper class that allows you to get the status.
The hacky / non-portable way would be to look at the actual implementation class for the HttpServletResponse and see if there is an additional public method. (Or even a non-public method or field that you could access reflectively ... though that would be a really bad idea, IMO)
If by "output the status as a field", you mean show the status code in HTML, a typical way to do this in a webapp is for your request handling logic (controller) to store the status code somewhere (model) so that it can be retrieved and shown in whatever mechanism creates the HTML (view), hence the MVC pattern. Don't consider the HttpServletResponse as a place to store the data you need to render a view. It's nothing but your conduit back to the user. Data needed for view rendering should go somewhere else, like in a request attribute, maybe.
I've been intermixing JSPs and Servlets in the web app I'm building and I'm starting to find that my more complex JSPs end up containing a lot of code, which flies in the face of all the MVC lessons that have been pounded into me. I know I can do this by just forwarding to the JSP, but this seems like a stupid hack.
What I'd like to do is use a servlet to do processing and then send a set of values to the JSP to render the HTML and return the response. Something along the lines of:
public class MyServlet extends HttpServlet {
public void doGet(HttpServletRequest req, HttpServletResponse resp)
throws IOException {
// ... Do some processing
resp.getWriter.print(renderJSP("mypage.jsp", values));
}
}
I've been poking around Sun's documentation and found this: http://java.sun.com/developer/technicalArticles/javaserverpages/servlets_jsp/
It seems like the JSP Model 2 architecture is exactly what I want to implement, but I cannot find an example of how one can set that up. For technical reasons, I cannot use one of the more advanced template frameworks like Struts.
Is this possible or a lost cause?
Put the object(s) in the request, forward the request to the jsp page and then use the object(s) in the jsp to render the response.
In your servlet,
MyObject obj = ... //build somehow
request.setAttribute("myObject", obj);
RequestDispatcher rd = request.getRequestDispatcher("WEB-INF/jsp/my.jsp");
rd.forward(request, response);
If your result JSP should not be accessed directly from a URL you should hide it inside the WEB-INF directory where it can be accessed only through the forward directive.
Then on your jsp you can have,
<% MyObject obj = (MyObject) request.getAttribute("myObject"); %>
To retrieve the object and used it as needed.
As others suggested, eventually it would be a good idea to learn to use JSTL and maybe an MVC framework like Spring MVC. The tutorial can be found here.
Put Java objects in the Request/Response/Session and use a javax.servlet.RequestDispatcher in your servlet, something like that:
RequestDispatcher dispatcher = request.getRequestDispatcher("/test.jsp");
dispatcher.forward(request,response);
A forward is server-side and the target servlet/JSP receives the same request/response objects as the original servlet/JSP. Therefore, you can pass data between them using request.setAttribute().
The other option is to use response.sendRedirect(String location) which is client-side (this method sends a temporary redirect response to the client) so the location URL receives a new request from the client, and the only way to pass data is through the session or with web parameters (url?name=value).
This is basically what MVC frameworks do (and no, it's not a hack).
You describe forwarding to the JSP as a hack, but really, that's exactly what the MVC frameworks do (Spring MVC and Struts, at least).
The "model" is the request attributes, which the servlet populates; then the JSP just retrieves them to show. You can wrap that in a "ModelAndView" like Spring MVC does, but it's really about it.
You can get more sophisticated on the JSP, of course, parsing request parameters, session attributes or servlet context ("global") attributes. I've found, in general, it's cleaner to let the front controller/servlet marshall all those into request attributes and have the page just pull from them. If you're using JSTL, the difference between request and session can be even blurrier.
I always wondered why there exists no removeParameters() method in Servlet API.
What could be the motive behind this design?
Here is a scenario: I am posed with a challenge in a proprietary MVC framework that I am compelled to use. This framework uses a Controller Servlet that hosts an algorithm in it's post method:
doPost() {
//create instance of action - just like struts action
action.init
action.preexecution
if(redirection state is not set)
action.process
action.postprocess
action.finish
}
The only way I can skip process of any particular action would be by setting a redirection url. The Controller Servlet is FINAL. Now, when I do a requestdispatcher.forward from say the preexecution method of an action, the controller will go ahead and execute the rest of the methods and not skip the rest. I cannot change this behavior, neither can I set the redirect, coz I need to do a forward. It works fine as long as I am not forwarding request to the same action. When a request is forwarded to the same action, the http parameters are all the same. This would take it into a never ending loop. Hence, I am compelled to add extra parameters indicating that it is a repeat request and should be treated differently.
Not sure if my problem made sense, but thought this is a good forum to post the same.
Umm... because it would serve no purpose? Request parameters are sent by the client to the server. The server is free to ignore them, but what practical effect would you expect such a removeParameter() method to have?
Edit: Request parameters are meant for the communication between server and client. For server-internal communication, you can use request attributes, which can be set and removed.
EDIT: McDowell reminded me of HttpServletRequestWrapper, so I'm changing the below to make it a little less work... Thanks McD!
You can decorate the request to "hide" parameters you don't want and/or add extra parameters.
Something like (off the top of me head -- no compiling so the API might be a tweak off...)
public class MyParameterHider extends HttpServletRequestWrapper {
public MyParameterHider(HttpServletRequest request) {
super(request);
}
public String getParameter(String name) {
if ("parameterToHide".equals(name))
return null;
return realRequest.getParameter(name);
}
// similar for getParameterNames and getParameterMap - don't include the hidden parm
// all other methods are strictly pass-through and are automatically
// handled by HttpServletRequestWrapper
}
In your forward, just wrap the request in a ParameterHider when calling doFilter:
dispatcher.forward(new MyParameterHider(request), response);
Patterns FTW!
Hope this helps!
I'm writing a very simple web framework using Java servlets for learning purposes. I've done this before in PHP, and it worked by consulting the request URI, then instantiating the appropriate class and method.
This worked fine in PHP, as one can do something like $c = new $x; $x->$y;. I'm unsure however of how to translate this to Java, or even if this is an appropriate way to go about it.
So far, I've tried:
Router router = new Router(request.getPathInfo());
String className = router.route(); //returns com.example.controller.Foo
Class c = Class.forName(className);
Object x = c.newInstance();
Foo y = (Foo) x;
y.doSomething();
This seems fine for a couple of routes, but doesn't seem like it would scale well, nor would it allow for sourcing routes from a configuration file.
How should I make it work?
Get hold of actions in a Map<String, Action> where the String key represents less or more a combination of request method and request pathinfo. I've posted similar answer before here: Java Front Controller
You can fill such a map either statically (hardcoding all actions) or dynamically (convention over configuration, looking up classes in a certain package, or scanning the entire classpath for classes with a certain annotation or implementing a certain interface).
And just stick to Servlet. The Filter isn't there for. At highest use it to forward the request to the controller Servlet. In the Servlet, just implement HttpServlet#service().
I would use a Servlet Filter as Front Controller. The router would connect paths with request dispatchers. In the doFilter method you would convert ServletRequest to HttpServletRequest, extract the request path and match it against the registered mappings. The result of this mapping is a request dispatcher you would dispatch the request with.
In pseudo code:
doFilter(ServletRequest request, ServletResponse response) {
httpServletRequest = (HttpServletRequest) request;
path = httpServletRequest.getRequestURI();
dispatcher = router.getTarget(path);
dispatcher.dispatch(request, response);
}
Depending on your need the default routing mechanism of the Servlet API could be sufficient.
Not quite sure what you're after but you might want to take a look at Java servlets. Granted many web frameworks are abstracted above plain servlets, but it's a jolly good place to start learning about Java web apps if you ask me (which indirectly you did ;) )
Download the Java servlet specification here: Java Servlet Spec - it's quite interesting.
How should you make it work? However you want it to. If you're just doing it for learning purposes, whatever you do will be fine.
I would suggest having all your actions implement the same interface though (maybe extend Servlet) so that you don't have to compile in all different classes.
Then you can essentially do what you're doing, except that your cast to Foo becomes a cast to Servlet and then you don't have to have a special case for all your different classes.
You can then also load up the routes from configuration (maybe an XML file).
Essentially what you're doing is implemented by the Struts 1 framework so it might be worthwhile reading up on that (it's open-source so you can also look at the source if you want).