Might be a bit of a noob question, but can I access a variable stored on the session from within a struts Form object?
public class MyForm extends ActionForm {...}
We have developed and maintained a very large project using Struts 1. I know your problem, we have an ActionContext class, with an ActionContextFilter, the filter binds the request and response objects to current thread using a ThreadLocal member (and obviously it unbinds them at the end of the process).
Now we can access request, response and ... using ActionContext.getCurrentContext().getRequest() and ActionContext.getCurrentContext().getResponse().
I believe the same thing can help you alot.
By the whole idea was from Clinton Begin's (the author of iBatis) sample PetStore; He have built a good extension around Struts 1 in that sample. I recommend you to review the whole work.
You need to set value to the form either in actionServlet (or) JSP. I don't think you can directly access request here (unless you do some customization).
You can retrieve an attribute in the session by using the HttpServletRequest:
request.getSession(false).getAttribute("yourAttributeName");
Have'nt tried at home but you may use:
private HttpServletRequest request;
public void reset(ActionMapping mapping, HttpServletRequest request) {
this.request = request;
}
and store the request in a local field for later use as described above.
Related
I am writing one application, on that i am setting user object into a session and i cannot able to get that session into another controller. And i want to maintain that session throughout the application(Until the user logout). So how can i get the session object into another controller and throughout the application. And what are the steps that i need to follow to maintain the session throughout the application.
Setting into session:
public ResponseEntity<Object> getCustMenus(HttpSession session){
UserInformation userInformationSession = luser.getRolesData();
session.setAttribute("userInfo", userInformationSession);
}
Getting the session:
UserInformation userInformation=(UserInformation) session.getAttribute("userInfo");
System.out.println("-----"+userInformation.getUserName()+"----------username");
I came across your question, because I'm also facing the same problem.
I think we can rely on Tomcat's request handling mechanism - each request is running in a single thread.
So I can have
Static map where key is the request Thread object and value is the Httpsession or even HTTpRequest object. Map
Filter with url set to /* which means each request passes through this filter. The filter will add the current thread and request object to the static map.
map.put(Thread.currentThread(), httpRequest);
As the map is a static field of some class it will be accessible to all threads and if you need to share an object between different controllers though lifecycle of a request you can put it in this map, e.g. put in httpsession as an attribute and get it anywhere you want.
In filter remove the thread from map when request is done.
map.remove(Thread.currentThread());
In case we use WeakHashMap I suppose we can skip step 3.
I haven't tried this approach yet, but I think it should work. I will share results when I try it.
I found complete answers in another discussion. Get the HttpServletRequest (request) object from Java code
The most useful part of the discussion for me was posted by skaffman. Please find it below.
Spring provides the RequestContextFilter for just this purpose. It uses ThreadLocal, and allows the code to fetch the current request via RequestContextHolder. Note that this filter does not require you to use any other part of Spring:
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.
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 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 would like to know if there is some way to share a variable or an object between two or more Servlets, I mean some "standard" way. I suppose that this is not a good practice but is a easier way to build a prototype.
I don't know if it depends on the technologies used, but I'll use Tomcat 5.5
I want to share a Vector of objects of a simple class (just public attributes, strings, ints, etc). My intention is to have a static data like in a DB, obviously it will be lost when the Tomcat is stopped. (it's just for Testing)
I think what you're looking for here is request, session or application data.
In a servlet you can add an object as an attribute to the request object, session object or servlet context object:
protected void doGet(HttpServletRequest request, HttpServletResponse response) {
String shared = "shared";
request.setAttribute("sharedId", shared); // add to request
request.getSession().setAttribute("sharedId", shared); // add to session
this.getServletConfig().getServletContext().setAttribute("sharedId", shared); // add to application context
request.getRequestDispatcher("/URLofOtherServlet").forward(request, response);
}
If you put it in the request object it will be available to the servlet that is forwarded to until the request is finished:
request.getAttribute("sharedId");
If you put it in the session it will be available to all the servlets going forward but the value will be tied to the user:
request.getSession().getAttribute("sharedId");
Until the session expires based on inactivity from the user.
Is reset by you:
request.getSession().invalidate();
Or one servlet removes it from scope:
request.getSession().removeAttribute("sharedId");
If you put it in the servlet context it will be available while the application is running:
this.getServletConfig().getServletContext().getAttribute("sharedId");
Until you remove it:
this.getServletConfig().getServletContext().removeAttribute("sharedId");
Put it in one of the 3 different scopes.
request - lasts life of request
session - lasts life of user's session
application - lasts until applciation is shut down
You can access all of these scopes via the HttpServletRequest variable that is passed in to the methods that extend from the HttpServlet class
Depends on the scope of the intended use of the data.
If the data is only used on a per-user basis, like user login info, page hit count, etc. use the session object
(httpServletRequest.getSession().get/setAttribute(String [,Object]))
If it is the same data across multiple users (total web page hits, worker threads, etc) use the ServletContext attributes. servlet.getServletCongfig().getServletContext().get/setAttribute(String [,Object])). This will only work within the same war file/web applicaiton. Note that this data is not persisted across restarts either.
Another option, share data betwheen contexts...
share-data-between-servlets-on-tomcat
<Context path="/myApp1" docBase="myApp1" crossContext="true"/>
<Context path="/myApp2" docBase="myApp2" crossContext="true"/>
On myApp1:
ServletContext sc = getServletContext();
sc.setAttribute("attribute", "value");
On myApp2:
ServletContext sc = getServletContext("/myApp1");
String anwser = (String)sc.getAttribute("attribute");
Couldn't you just put the object in the HttpSession and then refer to it by its attribute name in each of the servlets?
e.g:
getSession().setAttribute("thing", object);
...then in another servlet:
Object obj = getSession.getAttribute("thing");
Here's how I do this with Jetty.
https://stackoverflow.com/a/46968645/1287091
Uses the server context, where a singleton is written to during startup of an embedded Jetty server and shared among all webapps for the life of the server. Can also be used to share objects/data between webapps assuming there is only one writer to the context - otherwise you need to be mindful of concurrency.