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.
Related
I am currently doing an internship where I have an existing java project that essentially processes strings and gives you an output with informations about it. I am now told to do an web interface for it, with an input field, a button to send a request, and a field for displaying the output. I was given the advice to look into REST web services. Since I have never done anything web related before, I read tons of materials, and am now a bit confused. Please tell me if I got the following points correctly.
For the webservice, I can use JAX-RS, so I will use a class like that:
#Path( "result/{input}" )
public class ResultResource
{
#GET
#Produces( MediaType.TEXT_PLAIN )
public String message(#PathParam("input") String input)
{
return myApplication.processInput(input);
}
}
Now I am unsure: Can I create the web interface (button, input fields) with a jsp file or a html file? So that when the button is clicked, the url "..result/input" is called and I somehow have to read the result from the page and display it in my results field.
To make it runnable on a server, I have to deploy my REST-servlet above on tomcat / jetty.
Would be pleased to get some answers, because I am a bit lost.
You can do this in a jsp file, you just use normal html for your form and button etc.
In your form do action="/yourServlet?param=yourInput" method="post".
And then in your servlet you can make a doPost method which will get your parameter like:
public void doPost(HttpServletRequest request,
HttpServletResponse response) throws ServletException, IOException
{
String input = request.getParameter("yourInput");
doSomething(input);
}
and then do whatever you want it to. You can then send it back to the desired page with
request.getRequestDispatcher("/yourPage.jsp").forward(request, response);
This should also be in your doPost. Your response here can be what you did to your input and you can then make a result field in yourPage.
To make it runnable you can indeed put in on a tomcat server.
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.
I created a spring-based Java web application,
for each request, an instance of 'controller class' will be created to handle the request.
in the business logic, I want to do some logging with a UNIQUE ID automatically assigned to each request so that I can track what the program exactly did.
the log may be like this(2 requests at same time):
[INFO] request #XXX: begin.
[INFO] request #XXX: did step 1
[INFO] request #YYY: begin.
[INFO] request #XXX: did step 2
[INFO] request #YYY: did step 1
[INFO] request #XXX: end.
[INFO] request #YYY: end.
from the log, I can realize:
req #XXX: begin-step1-step2-end
req #YYY: begin-step1-end
I hope the logging can be called easily everywhere in the code,
so I don't want to add a parameter of "requestId" to every java function,
It's perfect if the logging tool can be called in a static way:
LOG.doLog("did step 1");
any idea of how can I do this? thank you :)
You can also try using MDC class of Log4j. The MDC is managed on a per thread basis.
If you are using a ServletRequestListner then you can set the unique Id in the requestInitialized.
import org.apache.log4j.MDC;
import java.util.UUID;
public class TestRequestListener implements ServletRequestListener {
protected static final Logger LOGGER = LoggerFactory.getLogger(TestRequestListener.class);
public void requestInitialized(ServletRequestEvent arg0) {
LOGGER.debug("++++++++++++ REQUEST INITIALIZED +++++++++++++++++");
MDC.put("RequestId", UUID.randomUUID());
}
public void requestDestroyed(ServletRequestEvent arg0) {
LOGGER.debug("-------------REQUEST DESTROYED ------------");
MDC.clear();
}
}
Now anywhere in the code if you do a log either debug, warn or error. Whatever you had put in the MDC will be printed out. You need to configure you log4j.properties. Notice the %X{RequestId}. This referes to the key name which is inserted in the requestInitialized() above.
log4j.appender.A1.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss.SSSS} %p %C %X{RequestId} - %m%n
I also found this link to be helpful -> What is the difference between Log4j's NDC and MDC facilities?
You have three different problems to solve:
Generate an unique id for each request
Store the id and access it everywhere in the code
Log the id automatically
I would suggest this approaches
Use a Servlet filter or a ServletRequestListener (as suggested by M. Deinum) or a Spring Handler Interceptor to intercept the request in a general way, there you can create a unique id, maybe with an UUID
You can save the id as an attribute of the request, in this case the id would propagate just in the controller layer, not in the services. So you can solve the problem using a ThreadLocal variable or asking Spring to do the magic with the RequestContextHolder: the RequestContextHolder will allow you to access the request of that specific thread, and the request attributes as well, in the service layer. The RequestContextHolder use ThreadLocal variable to store the request. You can access the request in this way:
ServletRequestAttributes attr = (ServletRequestAttributes) RequestContextHolder.currentRequestAttributes();
// Extract the request
HttpServletRequest request = attr.getRequest();
There is an interesting article (2018 alternative), if you are using log4j, on the customization of the pattern layout of the logger. However, youncan simply create a proxy of your logging system interface and append manually the id to every logged string.
You can also use the "Fish Tagging" in Log4j 2. It is the same idea like MDC and NDC (thread-basis) as described in https://logging.apache.org/log4j/2.x/manual/thread-context.html
Here you can use either the Thread Context Stack or the Thread Context Map. An example for the Map looks like this:
//put a unique id to the map
ThreadContext.put("id", UUID.randomUUID().toString()
//clear map
ThreadContext.clearMap();
And for the pattern in log4j2.xml you can also use the %X{KEY} tag.
To put a new id to the map (for example for every incoming request) you can do that in an ServletRequestListener implementation how Sharadr described it.
If you don't mind using spring 4.1.3 or later, you can wrap your request into a custom subclass of ContentCachingRequestWrapper class.
public class MyHTTPServletRequestWrapper extends ContentCachingRequestWrapper {
private UUID uuid;
public MyHTTPServletRequestWrapper (HttpServletRequest request) {
super(request);
uuid = UUID.randomUUID();
}
public UUID getUUID() {
return uuid;
}
}
In your spring controller, add the request to the method's param, and cast it to your custom wrapper:
#RequestMapping(value="/get", method = RequestMethod.GET, produces="application/json")
public #ResponseBody String find(#RequestParam(value = "id") String id, HttpServletRequest request) {
MyHTTPServletRequestWrapper wrappedRequest = (WGHTTPServletRequestWrapper)request;
System.out.println(wrappedRequest.getUUID());
...
}
You will need to user filter though, to connect the dots:
public class RequestLoggingFilter extends GenericFilterBean {
#Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
HttpServletRequest requestToCache = new MyHTTPServletRequestWrapper((HttpServletRequest) request);
System.out.println(((WGHTTPServletRequestWrapper)requestToCache).getUUID());
chain.doFilter(requestToCache, response);
}
}
You will find that the printlin from RequestLoggingFilter.doFilter() and from controllers getId() will produce the same UUID.
You will just need to play around to use the UUID in appropriate places, but at least you have the value in your controller where is the start of your business logic.
You could use the #Scope annotation to load a new instance of the service for each request.
See official documentation here
If you want to inject this in a non-request aware service, you should use proxyMode option. more info here (from this stack question)
You must use a database sequence (if your database is ORACLE) as follows
create sequence "sequence_Name";
String uniqueString=sessionFactory.getCurrentSession(). createSQLQuery("SELECT \"sequence_Name\".nextval FROM dual").list().get(0);
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;
}
}
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.