I just took over a freemarker project.
The controller classes extend the abstract class squirrel.web.SquProcessor, and use squirrel.web.PageData to transfer values.
But now, I want to use the HttpServletRequest and HttpServletResponse in the controller classes.
How to get them?
FreeMarker is unaware of servlets or HTTP (barring the included FreemarkerServlet that was added to ease migrating from JSP). You see in templates what the controller class has exposed to FreeMarker. Exposing highly technical things like servlet request/response object is not very clean; ideally the template should only get application-domain objects and some helpers to generate URL-s and such.
Related
Thymeleaf dropped template expressions like #session, #httpServletRequest etc. in Version 3.1 (https://www.thymeleaf.org/doc/articles/thymeleaf31whatsnew.html).
We used those a lot in relatively large applications. I wrote an interceptor to populate those attributes at every request since I don't want to add them in every Controller needed (like described in the migration guide).
Does anybody know a better way of achieving this?
This is already the best method to populate attributes at each request, compared to the earlier methods defined in the Spring framework documentations.
I learned that #ControllerAdvice can be used in this case (see https://spring.io/blog/2013/11/01/exception-handling-in-spring-mvc).
Classes annotated with #ControllerAdvice, can have methods annotated with #ModelAttribute to populate attributes over multiple Controllers (all of them if not specified otherwise).
In my case:
#ControllerAdvice
public class CommonDataAdvice {
#Autowired
private HttpServletRequest request;
#ModelAttribute("request")
public HttpServletRequest populateRequest(){
return request;
}
}
Came across spring boot code snippet which has HttpServletResponse passed has an argument in the controller method
public void someApiMethod(#RequestBody MyRequest req, HttpServletResponse response) {
//some code
response.setStatus(HttpStatus.NO_CONTENT.value());
}
The same could have been achieved using ResponseEntity and I feel there is no need of passing HttpServletResponse here.Kindly advise on which is the best approach and why, considering this code is written for rest API ?
Better solution is to use #ResponseStatus for there is no real reason to add non-API arguments, such as HttpServletResponse or ResponseEntity in controller methods. Only path variables, request params, request body & headers should be the set of controller parameters for majority of cases. Plus it is more readable, maintainable, and still is usable by Swagger etc.
#ResponseStatus(code = HttpStatus.NO_CONTENT)
public void someApiMethod(#RequestBody MyRequest req) {
//some code
}
Spring boot (and in particular Spring MVC which is a part of spring boot in this case) provides an abstraction over low-level HttpResponse which is a part of the servlet specification.
In a nutshell, this abstraction saves you from thinking in terms of Http Protocol and allows concentrating on a business logic which is a good thing.
So if you can avoid HttpServletResponse - do it by all means (and this is what you'll usually do in your applications).
You can create objects (and spring will convert them for you if its REST), you can return ResponseEntity which is "status" + "body" - spring will do all the conversions.
So consider these techniques first.
Now, sometimes you have to manipulate the response at the low level, well in this case you have to work with HttpServletResponse object.
Example of this if you want to return a binary data that cannot be easily converted. For instance, if you want to prepare a zip file and send it back as a result of HTTP request, you'll have to get a more fine-grain low-level control, in this case, it's better to start off with HttpServletResponse param passed into controller method.
It depends on your particular use case.
If you can implement your use case without directly accessing the HttpServletResponse object, do so by any means. It is the cleaner approach.
You might have a scenario in which you need to access the HttpServletResponse. Such an example would be when you need to stream content back to the client, so you need direct access to the response output stream. In recent versions of Spring this can also be achieved via StreamingResponseBody, which avoids the need to directly access the response outout stream.
I believe it is a better approach to return a ResponseEntity and use that as per your suspicious.
ResponseEntity is easier to handle and a more "elegant" solution, more consistent with Spring design.
I have a normal Java class in a Spring MVC 3.06 web application.
In this class I would like to inject or get hold of the HttpServletRequest object in a method.
I know I can pass this around, but I was wondering how can I get hold of the request without passing it in to the method. Perhaps using annotations or similar?
Also, what are the "real" concerns with getting hold of the request this way, except some peoples opinions of it being ugly coding. I mean, is it unstable to access it this way?
Preferably non application server dependent way.
I have seen
(HttpServletRequest) RequestContextHolder.getRequestContext().getExternalContext().getNativeRequest()
but this doesn't seem to work for Spring MVC 3.06 . RequestContextHolder doesn't have the method getRequestContext().
Use
((ServletRequestAttributes)RequestContextHolder.getRequestAttributes()).getRequest();
I'm not sure where you got RequestContextHolder.getRequestContext(), that's completely wrong.
is it unstable to access it this way?
No, it's stable enough, assuming you're always running the code as part of an HttpServlet request thread. The main issue is that yes, it's ugly, and it makes your code hard to test. That is reason enough not to use it.
If you must use it, then decouple it from your code, e.g.
public void doSomething() {
HttpServletRequest request = ((ServletRequestAttributes)RequestContextHolder.getRequestAttributes()).getRequest();
doSomething(request);
}
void doSomething(HttpServletRequest request) {
// put your business logic here, and test this method
}
#Context HttpServletRequest httpServletRequest =null;
use this
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'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).