HttpServletRequest stored in model gets replaced - java

I'm working on a legacy code (Spring 2.5.x, Java 1.5), where controller passes Http Servlet Request to view like this:
public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception {
Map attributes = new HashMap();
attributes.put("httpRequest", request);
return new ModelAndView("/path/to/page.jsp", attributes);
}
However what happens is that httpRequest attribute does indeed exist in the JSP Page context, but it contains current request (JSP page) and not the original (controller). The passed request is being used to extract some information from the URL. It appears that I can get around that problem by using a bunch of "javax.servlet.forward.*" attributes. This however puzzles me as it is pretty simple thing and I'd be happy to get it to work anyways or at least know exactly why it doesn't work now. Anybody has any ideas?

To begin with, it is a bad idea to store the request as attribute of request. If you need specific data for the current request, you can retrieve it directly using ${requestContext}, if you need to access to the URL, use ${requestContext.requestURL}. If you need to access to parts of this URL to display it in client side, it would be better to parse the url in server side (controller) by first obtaining it using StringBuffer url = request.getRequestURL(); and then setting the required data as attributes.

Related

How to handle a POST request with a Servlet API

I am trying to make an API with Jetty Server, and I have this simple GET request:
#GET
public String helloWorld(){
return "Hello world";
}
In order to make a POST request, I assume that one must save the input to the Jetty server. I have tried to research for quite a while, but found nothing.
I imagine something like this:
#POST
public void Save(String stringToSave) {
// Save to DB?
}
You could likely google this but let me give you a quick overview. A Servlet is a chunk of code that is normally run during an HTTP action - GET, POST, etc. It is the original technology of the JavaEE world, having been released in the late 1990's.
A simple Java servlet, using modern annotations, would look something like:
#WebServlet(name = "SampleServlet", urlPatterns = "/sampleServlet")
public class SampleServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// called when an HTTP POST is sent
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// called when an HTTP GET is sent
}
}
The important parts to note are that the class extends HttpServlet and that you have to write code to pull data out of the request and push it into the response. This isn't bad to do but it does have to be done.
JAX-RS is a newer standard, aimed simplifying the creation of REST services. It too is a chunk of code that runs during an HTTP interaction.
A simple example of this would be:
#Path("/sampleService")
public class SampleService{
#Consumes({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML})
#Produces({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML})
#POST
#Path("/v1/hello")
public Response sayHello( SomeObject someobject ) {
The code here is both simpler and a bit more complex. The use of annotations helps determine the path that the service exists on a URL (in this case /sampleService/v1/hello), the HTTP method, and the Content-Type for both the request and response. Additionally, if the SomeObject object is defined correctly, the JAX-RS framework will automatically deserialize the incoming JSON or XML payload into an object for you.
The Response object contains the HTTP response code (perhaps a teapot) and a response body. In this example, the body will be automatically serialized back to the requestor in a way that matches the Accept header of the HTTP request (i.e., JSON for an application/json Accept header and XML for application/xml).
Note that while not directly related the JAX-RS framework takes advantage of the Servlet framework. Indeed in JAX-RS you can access the HttpServletRequest and HttpServletResponse object in your methods.
Which way is "better"? In general I would recommend using JAX-RS where possible as it is the newer standard and is a bit easier to implement. However, if you do any work in the JavaEE world you're very likely to run into Servlet code so it's important to understand it too.
Note that both Servlets and JAX-RS require an application server of some sort. Jetty is one of those. Another very common one is Tomcat. The application server sets up the environment for your code and listens for incoming HTTP messages. When it gets one it looks to see if it knows how to handle the URL and routes to the appropriate place. In the servlet world the server routes solely on the URL. In the JAX-RS world the server routes on the URL and, if specified by the #Consumes annotation, the HTTP Content-Type header too.
There is much more but let's start there and see if it answers what you're after.

Cloud Endpoints: Access Paramters in Servlet Filter

I'm trying to build an api with Google Cloud Endpoints.
As Cloud Endpoints does not provide authentication beside Googles own OAuth I try to build my own. Therefore I want to access the parameters provided for the API (for example #Named("token") token) inside a servlet filter.
Unfortunately I cannot find any of the provided information inside the httpRequest. Is that normal? Is there a possibility to access the parameters?
I would appreciate if someone could help me!
UPDATE:
With the infos from jirungaray I tried to build an authentication using headers but ran into the same problem. Used a REST-Client to send some headers as I could not figure out how to do this with the API Explorer. Inside my filter I try to access the token from the headers:
#Override
public void doFilter(
ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
HttpServletRequest httpRequest = (HttpServletRequest) request;
String authToken = httpRequest.getHeader(Constants.AUTH_TOKEN);
...
chain.doFilter(request, response);
}
The reason why I try to do something like this, is that I'm using Guice for Dependency Injection and want my token to be injected inside another object.
With Guice I have the following Provider using the token to inject a FacebookClient (using the token) per request.
#Provides
public FacebookClient getFacebookClientProvider(#Named("fbToken") Provider<String> fbToken) {
return new DefaultFacebookClient(fbToken.get(), Version.VERSION_2_2);
}
As described in the Guice wiki (SevletModule) this uses a sevlet filter to get the information from the request.
Is there any solution to achieve this kind of DI with Cloud Endpoints?
Philip,
Yes, it does makes sense you are getting an empty request. Your endpoint calls are first handled by Google (they receive the API calls) and then those are processed and sent to a handler in your app. As this is all done in the background it's very easy to miss that your endpoints aren't actually getting the same request you sent, they get a completely different request sent from Google's infrastructure.
Even though your approach should work including tokens info in url makes them easier to sniff, even if you use SSL or encrypt your params the token is there in plain sight.
For what you are trying to achieve I recommend you include the token as a header in your request and retrieve that header by accessing the HTTPRequest directly on the endpoint, this is injected automatically if you include an HTTPServletRequest param in you endpoint method.
eg.
public APIResponse doSomething(SomeComplexRquestModel request,
HttpServletRequest rawRequest) {
}
If you still feel you should go with your original approach just comment and I'll help you debug the issue.

passing data btw classes using request.setParameter, request.getParameter

I have 2 java classes and I want to transfer data between them.
I take user id as parameter in a previous jsp form, and in a java class, using setAttribute I create a atribute named st_id.
then in another java clas I want to retrieve this data, but I get null.pointer exception.
first java file;
public class Signin implements Action {
public String process(HttpServletRequest request, HttpServletResponse response) throws Exception {
Student stu = new StDAO().getUser(request.getParameter("st_id").toString());
request.setAttribute("st_id", request.getParameter("st_id").toString());
...
second;
public class addCourseStu implements Action{
#Override
public String process(HttpServletRequest request, HttpServletResponse response) throws Exception {
TakeCourseDAO pf = new TakeCourseDAO();
String s= (String) request.getAttribute("st_id");
So s is null, it's not my intention.
A request exists from the time the web browser sends it to the web server until the web server (via the servlet) has made its response.Every request for a servlet has its own accessibilty scope. From a servlet, you can:
add new attributes to the request's scope
obtain exisiting attributes from the request's scope
remove exisiting attributes from the request's scope
As you are getting null it is quite obvious that the attribute is not accessed within the scope.
You can try alternatives like Session scope or Application scopes which ever suits you
It is not entirely clear what you want to do but I gather that you want to maintain some state on the server between two requests right?
Look into sessions & cookies for this.
What you do here is weird as it seems you are setting an attribute on an incoming request in the first file.

Code to get a Java servlet to act as a proxy?

I have two Java web applications that have a single servlet that gets mapped to a specific URL:
red.war/
WEB-INF/classes
com.me.myorg.red.RedServlet (maps to http://red.example.com/doStuff)
blue.war/
WEB-INF/classes
com.me.myorg.blue.BlueServlet (maps to http://blue.example.com/doStuff)
I want to put these application (I'm calling them my "backend apps") behind a "proxy app" (servlet) that will decide which of these two apps will ultimately service a client-side request.
This proxy web app would take an incoming HTTP request, and determines which of the 2 "backend apps" (red or blue) to forward the request onto. The request would then be forwarded on to either http://red.example.com/doStuff (and then processed by RedServlet#doGet(...)) or http://blue.example.com/doStuff (and then processed by BlueServlet#doGet(...)). The returned response from the backend app (again, either RedServlet#doGet(...) or BlueServlet#doGet(...)) would then be returned to the proxy servlet, and ultimately returned to the client.
In other words, in pseudo-code:
public class ProxyServlet extends HttpServlet {
#Override
public doGet(HttpServletRequest request, HttpServletResponse response) {
String forwardingAddress;
if(shouldBeRed(request))
forwardingAddress = "http://red.example.com/doStuff";
else
forwardingAddress = "http://blue.example.com/doStuff";
PrintWriter writer = response.getWriter();
writer.write(getResponseFromBackend(forwardingAddress, request));
}
private String getResponseFromBackend(String addr, HttpServletRequest req) {
// Somehow forward req to addr and get HTML response...
}
}
Is this possible? If so, how and what code would I need to write to make it work?
You could use a RequestDispatcher to forward your request in the following way:
RequestDispatcher dispatcher = httpRequest.getRequestDispatcher(forwardingAddress);
// here you have the choice whether to use include(..) or forward(..) see below
if(useInclude)
dispatcher.include(httpRequest, httpResponse);
else
dispatcher.forward(httpRequest, httpResponse);
... where useInlcude is set to your choice with the following options:
includeThis is probably what you want to do: Load the content from the forwardingAdress into your response.
This means you could even include multiple targets into a single response.
The client will not even realize this procedure nor does he need to be able to see the target document.
forwardSend a forward to the forwardingAddress. This will tell the client to submit a new request to the specified URL.
If you do it in a browser with developer tools, you will see a second request.
The client must be able to see and load the target URL.
You can only forward to a single target.
See, the following links, too:
RequestDispatcher javadoc, especially for the notes:
forward should be called before the response has been committed to the client (before response body output has been flushed). If the response already has been committed, this method throws an IllegalStateException. Uncommitted output in the response buffer is automatically cleared before the forward.
include: The request and response parameters must be either the same objects as were passed to the calling servlet's service method or be subclasses of the ServletRequestWrapper or ServletResponseWrapper classes that wrap them.
URLRewriteFilter examplealthough this example is implemented using a Filter instead of a Servlet the behavior is the same (Note: this example is part of a framework of mine and hence contains some overhead in the parent classes. Just have a look at the relevant section...)
Since there is not yet an approved answer I try to write how I see the solution to this request use apache-http-commons library. In addition I suggest to add a flush on writer.
public class ProxyServlet extends HttpServlet {
#Override
public doGet(HttpServletRequest request, HttpServletResponse response) {
String forwardingAddress;
if(shouldBeRed(request))
forwardingAddress = "http://red.example.com/doStuff";
else
forwardingAddress = "http://blue.example.com/doStuff";
PrintWriter writer = response.getWriter();
writer.write(getResponseFromBackend(forwardingAddress, request));
**writer.flush();**
}
private String getResponseFromBackend(String addr, HttpServletRequest req) {
HttpClient client = new HttpClient();
HttpMethod method = new GetMethod(url);
client.executeMethod(method);
String body=method.getResponseBodyAsString();
return body;
}
}

Accessing a HashMap of custom objects in request scope after a redirect

I have a HashMap of custom objects being passed to a JSP using RequestDispatcher and I am able to access the object and its properties using JSTL.
However the code fails in case the parameter is sent using response.sendRedirect() .
I am not sure what the reason is and how to make it work?
The response.sendRedirect() basically instructs the client (the webbrowser) to send a new request on the given URL. You'll also see this being reflected by a change in the browser address bar.
A new request does of course not contain the attribtues of the previous (or any other) request. That would otherwise have broken the whole concept of "request scope".
To preprocess a GET request, you need to do the job in doGet() method of a servlet and then redirect to the URL of that servlet instead.
E.g.
response.sendRedirect(request.getContextPath() + "/foo");
and
#WebServlet("/foo")
public class FooServlet extends HttpServlet {
#Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
Map<String, Foo> foos = fooService.map();
request.setAttribute("foos", foos);
request.getRequestDispatcher("/WEB-INF/foo.jsp").forward(request, response);
}
}
Note that this problem is in no way related to having a hashmap of custom objects in the request scope.
See also:
Our servlets wiki page
You can not share a request attribute in response.sendRedirect as it creates a new request.
But, if you want that HashMap, in response.sendRedirect, you can put that in session like
request.getSession().setAttribute("myMap", [HashMap object]);
and can share between the servlet and JSP. This works in both RequestDispatcher and sendRedirect.

Categories

Resources