I am using Struts 2.0. I have a Java Bean Person having fields perName, perAge, perMail & many more. I want to display a Map of Java Bean {[1, person1], [2, person2]) on JSP and allow the user to update it from the same JSP using text fields. There are lot of variables in the bean and some of them are editable while some of them are not.
For example, perName is not editable while perAge is editable. I don't want to display non editable fields. If I use ediatable fileds only, after updating, I get non editable fields as null (perName is null after update). So I can't specify name attribute as it is changing at run time. So I am putting them in HTTP Session and displaying them. I am specifying name attribute of text field using #session.person[iterator index].perAge. Till this point everything works fine. But if I change the value in any text field & try to update, I get the old session attribute instead of changed one. I want the old session attribute with the new changed values and values of non editable fields should persist within user request. I don't want to use JavaScript. OGNL or expressions are most welcome.
public class PersonDTO implements Serializable {
private String perName;
private int perAge;
public String getPerName() {
return perName;
}
public void setPerName(String perName) {
this.perName = perName;
}
public int getPerAge() {
return perAge;
}
public void setPerAge(int perAge) {
this.perAge = perAge;
}
}
<s:form action="updatePerson" id="updatePerson">
<table>
<tr>
<td>AGE:<s:textfield name="#session.person.perAge" />
</td>
</tr>
<tr>
<td><s:submit id="update" value="Update" />
</td>
</tr>
</table>
</s:form>
Thanks for your support. After a day long GOOGLE, I found that it is not possible to update session directly using Struts tags. You can use session information for display and update session in scriplets but you can't update session directly. You may refer Struts2 form to update object in Session map? for more info. Once again thanks for help!!!
Related
I have the following ViewModel on an ASP.NET MVC:
public CategoryNewViewModel {
public Int32 Type { get ; set; }
public IDictionary<String, String> Descriptions { get; set; }
}
The Description Key is the language and Description Value is the text.
On the view I will need to render N inputs, one for each language ...
When the form is submitted the Descriptions property would become:
"en", "The description in english"
"pt", "A descrição em português"
"fr", "La description en français"
One problem is I am not sure how many inputs I will have on the view.
Does anyone knows if this binding is possible?
I think i find nice way of binding dictionary and it's actually what you need in your situation.
In ASP.NET MVC 4, the default model binder will bind dictionaries using the typical dictionary indexer syntax property[key].
If you have a Dictionary<string, string> in your model, you can now bind back to it directly with the following markup:
<input type="hidden" name="MyDictionary[MyKey]" value="MyValue" />
For example, if you want to use a set of checkboxes to select a subset of a dictionary's elements and bind back to the same property, you can do the following:
#foreach(var kvp in Model.MyDictionary)
{
<input type="checkbox" name="#("MyDictionary[" + kvp.Key + "]")"
value="#kvp.Value" />
}
Stolen from this question =)
After a lot of research on stackoverflow i'm posting this question as i could not find a solution for the issue.
Requirement Scenario : Update a customer from a list of customers based on each customer id as parameter.
Solution tried: Based on the customer Id received from the jsp, pass it to the Action as Struts2 url tag.
Issue Faced - Query String visible on the URL.
http://foo.com/Struts2Example/getCustomerAction?customerId=2
Questions :
Can we not hide the query string if we use struts Url tag?
If we cannot hide the using query string while using Url tag? what is the alternative for the above scenario.
Code for struts.xml,jsp and action below -
<h2>All Customers Details</h2>
<s:if test="customerList.size() > 0">
<table border="1px" cellpadding="8px">
<tr>
<th>Customer Id</th>
<th>First Name</th>
<th>Last Name</th>
<th>Age</th>
<th>Created Date</th>
</tr>
<s:iterator value="customerList" status="userStatus">
<tr>
<td><s:url var="editCustomer" action="getCustomerAction">
<s:param name="customerId" value="%{customerId}" />
</s:url>
<p>
<s:a href="%{editCustomer}">
<s:property value="customerId" />
</s:a>
</p></td>
<td><s:property value="firstname" /></td>
<td><s:property value="lastname" /></td>
<td><s:property value="age" /></td>
<td><s:date name="createdDate" format="dd/MM/yyyy" /></td>
</tr>
</s:iterator>
</table>
</s:if>
<br />
<br />
struts.xml-
<!-- Get Customer Details - To Pre-Populate the form to update a Customer -->
<action name="getCustomerAction" method="getCustomerById"
class="com.hcl.customer.action.CustomerAction">
<result name="success">pages/customerForm.jsp </result>
</action>
Customer Action class-
public class CustomerAction extends ActionSupport implements ModelDriven {
Logger logger = Logger.getLogger(CustomerAction.class);
Customer customer = new Customer();
List<Customer> customerList = new ArrayList<Customer>();
CustomerDAO customerDAO = new CustomerDAOImpl();
public Customer getCustomer() {
return customer;
}
//Set Customer onto Value Stack
public void setCustomer(Customer customer) {
this.customer = customer;
}
public List<Customer> getCustomerList() {
return customerList;
}
//Set Customer List onto Value Stack
public void setCustomerList(List<Customer> customerList) {
this.customerList = customerList;
}
public String execute() throws Exception {
return SUCCESS;
}
public Object getModel() {
return customer;
}
// Edit customer details, it will retrieve the records based on customerId
//SkipValidation is used to skip the validate()
#SkipValidation
public String getCustomerById() {
logger.info("** Customer Id to edit ** " + customer.getCustomerId());
customer = customerDAO.customerById(customer.getCustomerId());
return SUCCESS;
}
Some unordered considerations:
use different Actions (with the execute method only), or different Methods of the same Action, to perform different "actions";
The name of each Action/Method should match the operation performed and be self-explanatory, for example you should have an editCustomer method (or Action) to edit the customer and a getCustomer method (or Action) to obtain the customer;
The GET HTTP method should be used to read data, while the POST HTTP method should be used to send data; every non-reading operation should ideally be performed through POST; using GET to send data is an old bad practice born 20 years ago and never died :/ The reasons to use POST are the hidden URL, a higher load capacity, the ability to send binary data, etc...
That said, an URL like http://foo.com/Struts2Example/getCustomerAction?customerId=2 should be visible (to be bookmarked for example), and ideally should be prettified (REST style, like StackOverflow): something like http://foo.com/Struts2Example/Customer/2/
An URL like http://foo.com/Struts2Example/editCustomerAction?customerId=2 can't work, because you are not passing any other parameter; you know the id of the customer to edit, but not the data to alter...
It would become something like:
http://foo.com/Struts2Example/editCustomerAction?customerId=2&name=foo&lastname=bar&age=42, that would work, but as said (and as ask in your question) should be hidden, and handled through POST.
If you are printing in the source of the page the IDs, then there should be no need to hide them to the user;
What you need to do is to ensure that the user can't change the IDs outside the range you specified;
if you drawed in the page a list of customers with ID {1,2,3} you must block any attempt of the user to alter the id and trying to update the customer with ID = 4... to achieve that, simply store the list of ID in session before populating the page, and check the IDs returned by the page against your list. If they don't match, block the malicious operation.
Hope that helps
An alternative , is to encrypt the userID and send it back to the HTML page. Maintain the Mapping on the client side. When you submit the request , POST the encrypted value. The decryption/encyrption logic will be on the server side.
This will add an overhead on the system but this is a decent enough trade-off to performance when compared to Security.
Also please take a look # jcryption.org/info , its under MIT and GPL Licenses.
A simpler solution is to convert this into "POST" action so that the values are passed inside the HTTP Request Body. If its over HTTPS , it would be encrypted however you can still do the user id lookup using Google Developer Tools or IE9 Developer mode
I have two pages myaccount.xhtml and selectbank.xhtml
In my account page there is one option for recharge account in which user will enter the amount when user will press submit button then it will goto the select bank page using following bean method.
public String gotoPayMethod() {
FacesMessage doneMessage=new FacesMessage("Redirecting to Payment Type Page");
FacesContext.getCurrentInstance().addMessage(null, doneMessage);
return "SelectBank";
}
When user will goto to selectbank there user will have to submit payment method but in this page it shows the amount as null which was entered in the previous page.
Both the pages are using the same bean and the scope of the bean is request scope.
So how can I access that value without passing this values through URL GET method.
Just for my satisfaction I used session scope then it was working but I know thats not the proper way because I start using session scope for each pages then it will not be efficient.
Thanks
Well, if your beans are RequestScoped than you don't have same bean for both pages. These beans are recreated for every request, so you should pass parameters. Change return statement of your gotoPayMethod() to:
return "SelectBank?faces-redirect=true&includeViewParams=true";
and on selectbank.xhtml add:
<f:metadata>
<f:viewParam name="amount" value="#{bean.amount}" />
</f:metadata>
Adapt this to your property and bean name.
If using parameters is not a solution you can add this parameter in the session, and remove it from session in second bean when you retrieve it:
FacesContext.getCurrentInstance().getExternalContext().getSessionMap().put("amount", amount);
((HttpServletRequest)FacesContext.getCurrentInstance().getExternalContext().getRequest()).getSession().removeAttribute("amount");
Second construction for removing the attribute is necessary as Map returned from getSessionMap() is immutable.
You can use the #{flash} object that will keep your data until the next view. This way you won't need to deal with view parameters.
Details from myaccount.xhtml:
<h:form>
<h:outputText value="Enter amount: " />
<h:inputText value="#{flash.amount}" />
<br/>
<h:commandButton value="Go to payment method" action="#{bean.gotoPayMethod}" />
<h:form>
Bean of both views:
#ManagedBean
#RequestScoped
public class Bean {
#ManagedProperty("#{flash}")
private Flash flash;
private int amount = -1;
public Bean () { }
public String getAmount() {
if(amount == -1) {
int val = Integer.parseInt((String)flash.get("amount"));
flash.keep("amount");
amount = val;
}
return amount;
}
public Flash getFlash() {
return flash;
}
public void setFlash(Flash flash) {
this.flash = flash;
}
public String gotoPayMethod() {
//do business job
return "SelectBank?faces-redirect=true";
}
}
Details from selectbank.xhtml:
<h:outputText value="Amount entered by user is #{bean.amount}" />
Your use case is not of simple request/response cycle, the life span is more than one request response which makes it candidate for session scope.
Using hidden variable or GET parameters in URL is not good practice especially for a banking application. Where security is so important dont compromise on small memory foot print.
If flash scope map simplifies the case you can use it, but I would not go for such a thing.
Update: Forgot to mention you can check Conversation scope too.
I am new for JSF. In my project am using #ManagedBean, #RequestScoped. Am using 4 pages in my project. My problem was bean values not maintain in the second, third and fourth pages. Am using getter and setter properly. If i not use #ManagedProperty the bean value maintained properly. But i need to use the
#ManagedProperty. Could you please advise me how to solve this issue. I have copied some sample code for reference.
#ManagedBean
#RequestScoped
public class ArticlePrepToolManagedBean implements Runnable, Serializable {
#ManagedProperty (value="#{param.jidName}")
private String jidName;
#ManagedProperty (value="#{param.aidName}")
private String aidName;
private List<com.elsevier.ArticlePrepTool.db.ItemZipContains> usabilityDetailList = null;
public String getAidName() {
return aidName;
}
public void setAidName(String aidName) {
this.aidName = aidName;
}
public String getJidName() {
return jidName;
}
public void setJidName(String jidName) {
this.jidName = jidName;
}
public List<ItemZipContains> getUsabilityDetailList() {
return usabilityDetailList;
}
public void setUsabilityDetailList(List<ItemZipContains> usabilityDetailList) {
ArticlePrepToolManagedBean.usabilityDetailList = usabilityDetailList;
}
}
My project url is (http://localhost:8080/articlepreptool/) but input for my project is jidName=AEA aidName=10663. that input given by some other webpage that is if user trigger using the following href "PrepTool". Depends on the input i fetched some data in my project DB (using JPA) and list out the data in the first page. But if i goes to next page all previous data stored in that list which i got from DB was cleared that is all list values and variables which set in the bean becomes null. So could you please advise me how to solve this issue.That problem occured only if i used the #ManagedProperty. I used #ManagedProperty to fetch the input values comes through url, because the input values of my project comes through other web page.
A #ManagedProperty("#{param.foo}") basically sets the HTTP request parameter with name "foo" as a bean property directly after bean's construction. If you're retrieving null values for them, then it simply means that those parameters are not present in the HTTP request.
Assuming that you're navigating by a plain link, then you need to fix your links to include the request parameters:
<h:link value="Go to page2" outcome="page2">
<f:param name="jidName" value="#{bean.jidName}" />
<f:param name="aidName" value="#{bean.aidName}" />
</h:link>
This will result in something like:
<a href="page2.xhtml?jidName=foo&aidname=bar">
This way those parameters can be set as bean properties.
Alternatively, instead of #ManagedProperty you could also use <f:viewParam> on all pages and add includeViewParams=true to the outcome. See also ViewParam vs #ManagedProperty(value = "#{param.id}")
If you're navigating by a form submit, then there's really no reason to use them. Or you must be abusing forms instead of links for plain vanilla page-to-page navigation.
So I have been waxing lyrical about a ASP.NET MVC to a friend who is about to start development of a new user interface....
He asked me if you could solve the following problem with ASP.NET MVC:
Imagine a web app that supports plugins. In the current ASP.NET WebForms app the pluggin developer provides a usercontrol and some JQuery.
The IDs of the controls are unique so that the JQuery can always select the correct DOM elements and so that the code behind can deal with the correct control collections.
I suggested that in MVC since we can have any number of forms... each plugin could be implemented as a partialView.
Each partialView would be wrapped by its own form so the relevant Controller Action and therefore would only receive form data defined in the partialView - so from this point of view we dont care about DOM id collisions.
However the HTML would be invalid if ID collision did occur and hence JQuery written by the plugin developer could fail!
I'm not sure how we could get round this...
I dont like the idea of parsing the partialView for collisions when the plugin is added and I dont like the idea of restricting the ids that the plugin developer has access to.
Maybe the the ids could be augmented with a prefix at run time and the model binders could be provided with this prefix?
You could just wrap the contents of the plugin within a DIV or FORM element and give that a unique ID on the page. Then just use jQuery to only select elements that are within this "parent" DIV or FORM element.
You could probably auto generate a GUID to use as the unique ID at runtime, but this would require some effort by the person writing the plugin. Although, you could probably architect it out in a way to make it automatically generate the "parent" DIV and ID, then you could just access the ID within the view as a Property of the Plugin.
Just some thoughts, I haven't built a an ASP.NET MVC plugin based system like this yet, but it doesn't seem too difficult.
Here's an example of a PartialView that uses a custom ViewUserControl base class:
ViewUserControl1.ascx:
<%# Control Language="C#" Inherits="MvcPluginPartialView.PluginViewUserControl" %>
<input class="txtText" type="text" value="<%=this.ID %>" />
<input class="txtButton" type="button" value="Show Alert" />
<script type="text/javascript">
jQuery(function() {
// This is the Unique ID of this Plugin on the Page
var pluginID = "<%=this.ID %>";
// Attach the OnClick event of the Button
$("#" + pluginID + " .txtButton").click(function() {
// Display the content of the TextBox in an Alert dialog.
alert($("#" + pluginID + " .txtText").val());
});
});
</script>
MvcPluginPartialView.PluginViewUserControl:
namespace MvcPluginPartialView
{
public class PluginViewUserControl : ViewUserControl
{
public PluginViewUserControl()
{
this.ID = "p" + Guid.NewGuid().ToString().Replace("-", "");
}
public override void RenderView(ViewContext viewContext)
{
viewContext.HttpContext.Response.Cache.SetExpires(DateTime.Now);
ViewUserControlContainerPage containerPage = new ViewUserControlContainerPage(this);
//this.ID = Guid.NewGuid().ToString();
RenderViewAndRestoreContentType(containerPage, viewContext);
}
internal static void RenderViewAndRestoreContentType(ViewPage containerPage, ViewContext viewContext)
{
string contentType = viewContext.HttpContext.Response.ContentType;
containerPage.RenderView(viewContext);
viewContext.HttpContext.Response.ContentType = contentType;
}
private sealed class ViewUserControlContainerPage : ViewPage
{
public ViewUserControlContainerPage(ViewUserControl userControl)
{
this.Controls.Add(userControl);
}
protected override void Render(System.Web.UI.HtmlTextWriter writer)
{
writer.Write("<div id='" + this.Controls[0].ID + "'>");
base.Render(writer);
writer.Write("</div>");
}
}
}
}
Then to place the View on the page you can use the "Html.RenderPartial" method as usual, plus you can place as many of them on the Page as you want and they'll all work as expected.
<%Html.RenderPartial("ViewUserControl1"); %>
<%Html.RenderPartial("ViewUserControl1"); %>
<%Html.RenderPartial("ViewUserControl1"); %>