I believe it has something to do with Struts2 ValueStack, but if you guys could give me a hand with that would be great.
I have the following setup: Spring 3 + Struts 2.
My struts actions are pretty much like this:
#ParentPackage("struts-default")
public class StepOneAction extends ActionSupport {
...
}
Such Action has a method that is my forward:
#Action(value = "/bla", results = { #Result(name = "ble", location = "/bli.jsp") })
public String populate() {
...
return BLE;
}
Finally such Action is #Autowired.
What's puzzling me is that if I open, say Firefox, navigate to the first page - it's a 3 step wizard - fill the form and submit THEN open another browser, say Opera, and navigate to the first page, Opera has the data populated from Firefox.
How's that possible? What am I missing?
The ValueStack is per-request, so I don't see how it could possibly be a factor here.
It sounds like Spring is treating StepOneAction as a singleton, which would account for the behavior you are seeing. Actions need to be instantiated per-request.
Check that you haven't defined a member on the JSP page or Servlet that keep the same value among multiple sessions
Related
I'm currently developing a Struts 2 web application that allow anonymous usage. I want that with anonymous user, the URL will be like:
http://localhost:8080/myapp
But after user logged in, the URL will be personalized base on user name, for example:
http://localhost:8080/myapp/Cuong-Doan
Please suggest me a plugin/technique that can help me to achieve it.
You can try to do it with Tuckey's UrlRewriteFilter. After loging add session attribute, for example loggedUsername=Cuong-Doan. Then analyze this attribute in UrlRewriteFilter rule using session-attribute parameter of condition element. If it is present -> do redirect, add it to the URL using backreferences.
Personalized could be done via setting the parameter specifying the persona. Looking at the URLs in the question I decided to give you imagination about technique used to reproduce SEO optimized URLs. This technique is called "Parameters after action names". For example to map your persona with the action you can use
#Action(value = "/*", params = {"person", "{1}"})
so, after that action is mapped you will get the information about person via the person parameter that could be used in the action.
I want to create a restful link for each user, who registered on my page. For Example: User "testuser" registered on my page and his profile should be accessible through www.mypage.com/users/testuser.
How can i realize something in wicket?
in WebApplication implementation add to init():
mountPage("/users/${id}", UserPage.class);
and in UserPage.class :
public UserPage(PageParameters parameters) {
String id = parameters.get("id").toString();
...
}
Is it possible to introduce a additional url path element? Something like "http://server/users/userid/testuser"? If you have mount your page to the url "users" then the page will be initialized by wicket using the constructor with the PageParameters parameter:
public class UserPage extends WebPage {
public UserPage(PageParameters pars) {
String userId = pars.getParameterValue("userid");
...
}
}
Have a look at mounting pages in wicket 1.5. It describes the methods to 'mount', aka make available, a page on a certain url. Parameters to that page (in your case, the user name) can either be via name or via index (position).
You will be interested in the positioning parameters.
I am creating a wizard-like interface consisting of 3 jsp pages and 3 Struts actions using Struts 1.3. The flow is like below:
page1>action1 ->page2>action2 -> page3>action3
I use a session form bean (an action form with session scope) to share data between requests. The problem I am having is that the data I submitted in page2 is available in action 2, but not in action 3. I am in doubt it might be I don't have a form on page3 to hold those data, or because I call action3 via jQuery post method instead of a regular form submit, but I am really not sure.
I have been digging all the internet for almost a day and still no luck. Could anyone offer some help. Thanks a lot.
The reset() method on the form is being called with each request and thus you are losing state. You can programmatically control this.
public class MyForm extends ActionForm {
boolean reset = true;
private String[] checkboxes = {};
#Override
public void reset(ActionMapping mapping, HttpServletRequest request) {
if (reset) {
this.checkboxes = new String[];
// etc
}
reset = true;
}
public void doNotReset() {
reset = false;
}
}
Have action2 call doNotReset() on the form.
I suppose that you might have assigned a same form to both the action in StrutsConfig.xml and hence it is not giving the ClassCastException. By the way, if you want to access the same form bean which was filled on action 2 stuff, do the following
Look at the strutsConfig file for actionMapping of both the actions (2 and 3). keep the name of form different for separate action (e.g. form2 for action2 and form3 for action3).
In Action3, instead of casting the form, use this form2 = (FormBean2) session.getAttribute("form2");
The reason for above is since both the actions are using the same form, struts might have overwriting it. Hopefully above will solve your problem.
Thank you for all your inputs. Here is how I solved my problem. I don't really like this solution, but it possibly the neatest one I can find.
In page 3 I added hidden fields for what ever property I want to be available in action 3. Struts will store the values in those hidden field and when the form is submitted again, the data will then re-populated to the action form.
It seems to me that Struts works like this: when it loads page 3, it try to populate the form in page 3 with values of myForm. When the form is submitted, the process is reversed, it populate myForm with values from the user's form. The problem is that, before populating myForm with values submitted by user, it resets myForm's properties. And because after reseting, it doesn't find the value for those fields, it leaves it empty.
I don't think it makes sense for Struts to work that way, but... so be it.
How are you accessing the form bean of page2 in action2 as well as in action3.
I suppose you are accessing the wrong way. Are you getting an exception regarding invalidCast or something.
I have to warn you: the question may be rather silly, but I can't seem to wrap my head around it right now.
I have two managed beans, let's say A and B:
class A
{
private Date d8; // ...getters & setters
public String search()
{
// search by d8
}
}
class B
{
private Date d9; //...getters & setters
public String insert()
{
// insert a new item for date d9
}
}
and then I have two JSP pages, pageA.jsp (the search page) and pageB.jsp (the input page).
What I would like to do is placing a commandbutton in pageB so to open the search page pageA passing the parameter d9 somehow, or navigating to pageA directly after b.insert(). What I would like to do is showing the search result after the insertion.
Maybe it's just that I can't see the clear, simple solution, but I'd like to know what the best practice might be here, also...
I though of these possible solutions:
including **A** in **B** and linking the command button with **b.a.search**
passing **d9** as a **hiddenInput** and adding a new method **searchFromB** in **A** (ugly!)
collapsing the two beans into one
JSF 1.1/1.2 raw doesn't provide an easy way to do this. Seam/Spring both have ways around this and there are a couple of things you can do. JSF 2 should also have solutions to this once it is released.
Probably the easiest and most expedient would be to collapse the two beans into one and make it session scoped. The worry, of course, is that this bean will not get removed and stay in session until the session times out. Yay Memory leaks!
The other solution would be to pass the date on as a GET parameter. For instance, you action method could call the
FacesContext.getCurrentInstance().getExternalContext().redirect("pageB?d9=" + convertDateToLong(d9));
and then get the parameter on the other side.
You should configure the navigation flow in faces-config.xml. In ideal scenario you would return a "status" message which would decide the flow. Read more at following link:
http://www.horstmann.com/corejsf/faces-config.html
http://publib.boulder.ibm.com/infocenter/rtnlhelp/v6r0m0/index.jsp?topic=/com.businessobjects.integration.eclipse.doc.devtools/developer/JSF_Walkthrough8.html
As far as passing the values from one page to another is concerned you can use backing beans. More about backing beans here:
http://www.netbeans.org/kb/articles/jAstrologer-intro.html
http://www.coderanch.com/t/214065/JSF/java/backing-beans-vs-managed-beans
Hope i have understood and answered correctly to your question
Way to share values between beans
FacesContext facesContext = FacesContext.getCurrentInstance();
Application app = facesContext.getApplication();
ExpressionFactory elFactory = app.getExpressionFactory();
ELContext elContext = facesContext.getELContext();
ValueExpression valueExp = elFactory.createValueExpression(elContext, expression, Object.class);
return valueExp.getValue(elContext);
In above code "expression" would be something like #{xyzBean.beanProperty}
Since JSF uses singleton instances, you should be able to access the values from other beans. If you find more details on this technique, I am sure you'll get what you are looking for.
Add commandButton action attribute referencing to B'insert method
<h:commandLink action="#{b.insert}" value="insert"/>
In B'insert method,add d9 parameter as request parameter. Then return an arbitrary string from insert method.
FacesContext fc = FacesContext.getCurrentInstance();
fc.getExternalContext().getRequestMap().put("d9", d9);
Then go to faces context and add navigation from B to A with "from-outcome" as the arbitrary String you returned from insert method. But don't add redirect tag to navigation tags as it will destroy the request coming from B and the parameter you added (d9) will be cleared.
<from-outcome>return string of insert method</from-outcome>
<to-view-id>address of A</to-view-id>
Then you might get the "d9" in A class by fetching it from request map at its constructor or in a place where its more appropriate (getters). You might add it into a session scope or place it to a hidden variable if you want to keep track of it later.
in class A, when page is navigated, A should be initialized as it will be referenced.
FacesContext fc = FacesContext.getCurrentInstance();
fc.getExternalContext().getRequestMap().get("d9", d9);
Sorry i cant give full code, as i have no ide at here, its internet machine at work. I could not give details therefore.
In my opinion, the simplest way is 3-rd option - have both query and insert methods in same class. And you can do something like that:
public String query () {
//...
}
public String Insert() {
//insert
return Query(); }
If your classes are managed Beans you can load class A from class B and call A.query() in your insert method at the end. Also class A can have
<managed-bean-scope>session</managed-bean-scope>
parameter in faces-config.xml and it wouldn't be instantiated again when loaded.
I have a wicket web application with Page mounted to bookmarkable alias. The page contains a form object with submit action.
The problem is that though the form belongs to the page the action url doesn't contain page alias, but rather created in cryptic form of wicket action.
Is there a way to adjust that behavior, so link will be like page_alias/submit ?
...
setRenderStrategy(IRequestCycleSettings.ONE_PASS_RENDER);
mountBookmarkablePage("/resetpwd", ResetPasswordPage.class);
...
public ResetPasswordPage(final String id, final PageParameters parameters) {
final Form form = new StatelessForm();
form.add(new Button("submit") {
public void onSubmit() {
...
});
add(form);
If you subclass StatelessForm instead of Form, this will take you part of the way. Rather than having something like
action="myapp/?wicket:interface=:1:eventEditor::IFormSubmitListener::"
with the page containing the form mounted at a bookmarkable URL, you'll get something like, for example,
action="myapp/mount/path/some/params/?wicket:interface=:0:eventEditor::IFormSubmitListener::"
This uses a MixedParamUrlCodingStrategy for the mount in WebApplication.init()
You can then override encodeUrlInHiddenFields() to return true, which will give you a clean URL in the action attribute.
However, all this doesn't really change the way Wicket works with forms, i. e., you still have some Wicket-specific state data in the client's markup. The reason why this is so hard, I believe, is that Wicket is meant to help you build a web app that has state. I noticed that Wicket does a lot of stuff (like comparing submitted form values with what the model's getters return before the setters are called) behind the scenes, that I know too little about to be comfortable when just cutting it out.
You can use Wicket to provide RESTful web services, though, as outlined in this blog post. There's also a project on Google code called wicket-rest that expands on this idea. Note that this seems to work as simple as it does because it just never uses the whole component based UI building stuff.
The guy who wrote this post had a different problem, but it helped me understand Wicket forms a little better anyway.
you can hide a lot of the request mumbo jumbo by using a HybridUrlCodingStrategy like so:
mount(new HybridUrlCodingStrategy("/resetpwd", ResetPasswordPage.class));
Then when the click submit, assuming you don't redirect to a new page, the url would change from
mysite.com/DocRoot/resetpwd
to
mysite.com/DocRoot/resetpwd.1
or if you really want it to be mysite.com/DocRoot/resetpwd/submit you could create a new bookmarkable page, say ResetPasswordResult.class, set your response page to that and mount it at "/resetpwd/submit"
You might look at other encoding strategies to see if their is another that suits you better:
http://cwiki.apache.org/WICKET/url-coding-strategies.html
You can take a look at http://day-to-day-stuff.blogspot.com/2008/10/wicket-extreme-consistent-urls.html and try to adapt that for Forms.