Fill a form with saved cookies - java

I have an action class that saves my cookies like this:
public String execute() {
// Save to cookie
Cookie name = new Cookie("name", userInfo.getName() );
name.setMaxAge(60*60*24*365); // Make the cookie last a year!
servletResponse.addCookie(name);
}
If I submit my form, I can see the cookies on the browser that has been created and saved. When the user submits, they get redirected to a new page, a page with all the stored information that they just created.
I want the user to be able to go back to the submit page and see all the information in the forms that they just submitted. Is it possible to do this with Struts2, by using the saved Cookies and get the form to fill in with the old data?
This is my form:
<s:textfield
label="Name"
name="name"
key="name"
tooltip="Enter your Name here"/>

To send cookie you can use a cookie-provider interceptor. It allows you to populate cookies in the action via implementing CookieProvider. To apply this interceptor to the action configuration you can override the interceptors config
<action ... >
<interceptor-ref name="defaultStack"/>
<interceptor-ref name="cookieProvider"/>
...
</action>
The CookieProvider has a method to implement,
public class MyAction extends ActionSupport implements CookieProvider {
#Override
public Set<Cookie> getCookies(){
Set<Cookie> cookies = new HashSet<>();
Cookie name = new Cookie("name", userInfo.getName() );
name.setMaxAge(60*60*24*365); // Make the cookie last a year!
name.setPath("/"); //Make it at root.
cookies.add(name);
return cookies;
}
}
In the form
<s:set var="name">${cookie["name"].value}</s:set>
<s:textfield
label="Name"
name="name"
value="%{#name}"
tooltip="Enter your Name here"/>

Related

JSP - set <c:param /> value from input field to pass it in URL

I'm creating a web shop in JSP for a school project.
On each product page, there's a button to add it to the cart.
Originally, there is only one item added to the cart when we press the "Add" button.
I send the productId to add to the controller by adding it as parameter in the url as you can see here :
<div class="product-page">
<div class="product">
<h1>${product.title}</h1>
<img src="${product.imageUrl}"/>
<div class="price"><p>${product.price}€</p></div>
</div>
<c:url var="addLineToCart" value="/product/addLineCart">
<c:param name="productId" value="${product.id}" />
</c:url>
<a id="addToCart" type="submit" href="${addLineToCart}"><spring:message code="addCart"/></a>
What I'd like to do, is to add an input field to specify the amount of items to add in the cart. I did it here :
<div class="product-page">
<div class="product">
<h1>${product.title}</h1>
<img src="${product.imageUrl}"/>
<div class="price"><p>${product.price}€</p></div>
</div>
<input type="number" name="quantity" value="1"/>
<c:url var="addLineToCart" value="/product/addLineCart">
<c:param name="productId" value="${product.id}" />
</c:url>
<a id="addToCart" type="submit" href="${addLineToCart}"><spring:message code="addCart"/></a>
My problem is that I don't know how to pass the value from the input field in the <c:param/> property in order to add it in the URL too.
Here is how my controller looks like assuming I get the quantity to add via the URL :
#Controller
#RequestMapping(value="/product")
#SessionAttributes({Constants.CURRENT_CART})
public class ProductController {
private ProductDAO productDAO;
#Autowired
public ProductController(ProductDAO productDAO){
this.productDAO = productDAO;
}
#ModelAttribute(Constants.CURRENT_CART)
public Cart cart()
{
return new Cart();
}
#RequestMapping (method = RequestMethod.GET)
public String home(ModelMap model, #RequestParam("product") int productId, #ModelAttribute(value=Constants.CURRENT_CART) Cart cart){
Product product = productDAO.getById(productId);
model.addAttribute("product", product);
model.addAttribute("title", "Produit");
model.addAttribute("cart", cart);
return "integrated:product";
}
#GetMapping("/addLineCart")
public String addLineCart(#ModelAttribute(value=Constants.CURRENT_CART) Cart cart, #RequestParam("productId") int productId, #RequestParam("quantity") int quantity, ProductService productService)
{
Product product = productService.searchProduct(productId,productDAO);
cart.addProduct(product, quantity);
return "redirect:/product?product=" + productId;
}
}
Thanks for your help.
The easiest way is to wrap the fields in a HTML <form> tag and submit the data to your controller. You should also replace GET with a POST since your browser might decide to cache the response to some combinations of productId and quantity and your application might exhibit some unwanted behavior as result of that (don't forget to change your #GetMapping in your controller with a #PostMapping also).
There is also the option of submiting this to the server with JavaScript as an Ajax request, or to change the value of the URL in your existing link to include the quantity when you click it and before making the request to the server, but using a form with a POST action is the easiest and cleanest solution.
Finally, <c:url> and <c:param> are server side tags. They get evaluated at the server to produce your final HTML that gets sent to the client browser. You can't get your input value from the browser into your <c:param> because you are running client code at this point, no longer server code.

Why submitting a form with Ajax it's not setting model data using ModelDriven in Struts 2?

I have following situation in code:
Action class:
#NameSpace("/")
public class MyAction extends ActionSupport implements ModelDriven<Car> {
private Car car = new Cart();
#Override
public Car getModel() {
return car;
}
#Action(value = "pageAction", results = {name = SUCCESS, location = "myPage", type="tiles"})
public String showPage() {
return SUCCESS;
}
#Action(value = "formSubmitAction", results = {name = SUCCESS, location = "results.jsp"})
public String formSubmitAction() {
System.out.println(car);
// everything has default values (nulls)
return SUCCESS;
}
}
View for myPage location:
<s:form
namespace="/"
action="pageAction"
method="post" >
<s:push value="model">
<s:textfield name="color" />
<s:textfield name="manufacturer" />
<sj:submit
href="formSubmitAction"
targets="output" />
</s:push>
</s:form>
<div id="output"></div>
results.jsp:
renders empty content into div#output
<s:property value="%{model}" />
<s:property value="%{model.color}" />
<s:property value="%{model.manufacturer}" />
I wonder why is that happening? Model data is not updated after submit.
I'm using struts2-jquery submit tag.
When I'm using simple form submit without Ajax the model is being updated,
but I want to load data asynchronously with Ajax.
How can I achieve that?
The solution is to add ID to form and to sj:submit tag. But I don't know why submit tag inside form wasn't working properly. The correct code is below:
<s:form
id="formId"
namespace="/"
action="pageAction"
method="post" >
<s:push value="model">
<s:textfield name="color" />
<s:textfield name="manufacturer" />
<sj:submit
formIds="formId"
href="formSubmitAction"
targets="output" />
</s:push>
</s:form>
EDIT
As it turns out you only have to add ID to form, and everything works :)
look at link in the comment below
The modelDriven interceptor pushes a model on top of the valueStack. So you can access model properties directly.
<s:property value="%{color}" />
<s:property value="%{manufacturer}" />

Unable to implement Struts 2 token interceptor with hyperlink

I tried to implement token interceptor with the <s:url .. tag but its showing error on the first click. i.e.
The form has already been processed or no token was supplied, please try again.
I want to implement this interceptor, because if users already deleted a row and refresh the page once again then the same action should not perform once again.
<s:url id="linkdelete" action="DeleteLatestUpload.action" namespace="/admin/insecure/upload">
<s:param name="latestUploadId" value="latestUploadId"></s:param>
<s:token name="token"></s:token>
</s:url>
Clear current Uploads
and my struts.xml:
<action name="DeleteLatestUpload" class="v.esoft.actions.UploadExcel" method="deleteUploads">
<interceptor-ref name="token"></interceptor-ref>
<interceptor-ref name="basicStack"></interceptor-ref>
<result name="success" type="tiles"> uploadforward</result>
<result name="invalid.token" type="tiles">uploadforward </result>
</action>
The s:token tag merely places a hidden element that contains the
unique token.
There's not need to use token with url, because the form should be submitted. If you want to pass some token as a parameter then you need to use s:param tag.
Define the parameter
private String token;
public String getToken() {
return token;
}
public void setToken(String token) {
this.token = token;
}
public String execute() throws Exception {
Map<String, Object> context = ActionContext.getContext().getValueStack().getContext();
Object myToken = context.get("token");
if (myToken == null) {
myToken = TokenHelper.setToken("token");
context.put("token", myToken);
}
token = myToken.toString();
return SUCCESS;
}
in the JSP
<s:url var="linkdelete" namespace="/admin/insecure/upload" action="DeleteLatestUpload" ><s:param name="struts.token.name" value="%{'token'}"/><s:param name="token" value="%{token}"/></s:url>
The most simple way to use token with url is to use <s:token/> tag to set token value into session and retrieve it in <s:param> tag.
<s:token/>
<s:url var="..." action="...">
<s:param name="struts.token.name" value="'token'"/>
<s:param name="token" value="#session['struts.tokens.token']"/>
</s:url>

passing property value using javascript

I am new to struts 2. I have a jsp page which will send a column ID to another jsp page which will send it to the action class where i will get the comments entered by user and return it to my second jsp page to display it as a popup to the user. problem is my javascript is not accepting the value of the column.
//THIS IS WHERE THE PROBLEM IS IN THE JAVA SCRIPT
<display:column title="Commentaire" sortable="true" sortProperty="Commentaire" class="alerte_td_commentaire">
<s:if test="#attr.row.Commentaire != null && #attr.row.Commentaire != ''">
<a href='#' onclick='javascript:var xx = (%{#attr.row.id}).val(); CommenatireToGet(xx);'><img src='/img/icons/ico_comment.png'></a>
</s:if>
</display:column>
//THIS IS MY SECOND JSP PAGE
function CommenatireToGet(value){
$('#divShowCommAcqui').dialog('option', 'position', 'center');
$('#divShowCommAcqui').dialog('open');
var path = buildURL("/valorisation/ajax/CommenatireToGet.do");
$.getJSON(
path,
{idAlerte:value},
function(json){
$('#commentaireAqui').val=getElementbyId(json.hello);
}
)
};
//THIS IS MY ACTION CLASS
public String getComment() throws ServiceException{
jsonData = new LinkedHashMap<String, Object>();
idAlerte= (Integer) getActionSession("idAlerte");
Alerte alerte =svc.retrieve(idAlerte);
if (alerte !=null){
jsonData.put("hello",alerte.getCommentaire());
}
return SUCCESS;
}
//THIS IS MY STRUS TAG
<action name="CommenatireToGet" class="ihm.valorisation.AlerteAction" method="getComment">
<result name="success" type="json">
<param name="root">jsonData</param>
</result>
</action>
You can't use OGNL expressions anywhere in the JSP, only in Stuts2 tag's attributes, even not all of them. So, change
<a href='#' onclick='javascript:var xx = (%{#attr.row.id}).val(); CommenatireToGet(xx);'><img src='/img/icons/ico_comment.png'></a>
to
<a href='#' onclick='CommenatireToGet(<s:property value="%{#attr.row.id}"/>);'><img src='/img/icons/ico_comment.png'></a>

User login with JSF 2.0 [duplicate]

This question already has answers here:
Performing user authentication in Java EE / JSF using j_security_check
(4 answers)
Closed 6 years ago.
I am trying - with JSF 2.0 - to implement in a neat way the login/remember me/logout management. Since the traditional <form action="j_security_check" ... way lacks of flexibility I decided to follow a different path, but I found a problem.
Declarative security is properly set both in the application server through <security-domain> and in web.xml through <security-constraint>, <login-config> and <form-login-page>.
The login page:
<h:form id="loginForm">
<h:panelGrid columns="2" cellspacing="5">
<h:outputText value="Username" />
<h:inputText value="#{loginBean.username}" />
<h:outputText value="Password:" />
<h:inputText value="#{loginBean.password}" />
<h:outputLabel value=""/>
<h:commandButton value="Login" action="#{loginBean.login}" />
</h:panelGrid>
</h:form>
And the simple LoginBean#login():
public String login( )
{
HttpServletRequest request = (HttpServletRequest)FacesContext.getCurrentInstance( ).getExternalContext( ).getRequest( );
try {
request.login( username, password );
}
catch ( ServletException e ) {
FacesContext.getCurrentInstance().addMessage( "Unknown login...
return null;
}
return "i_dont_know_where_you_were_going";
}
Everything works fine, but after a successful login I don't know how to forward the user to its original request. Since the login page is automatically interposed between the client request and "any" secured resource I need a way to understand where to redirect the action. request.getRequestURL( ) doesn't help, probably because of a RequestDispatcher#forward() (which overwrites the request url) intervention. Do you think this is an appropriate way to manage the login process? If so, any hint about the problem?
Thanks a lot!
Add something like the following line to your login view. It stores the requested page during the login.
<f:param name="redirect" value="#{requestScope['javax.servlet.forward.request_uri']}" />
Then get the requested uri in your login bean.
FacesContext context = FacesContext.getCurrentInstance();
String redirect = context.getExternalContext().getRequestParameterMap().get("redirect");
Add ?faces-redirect=true to the string and return it.
The above answer worked perfectly, just pointing out to the unwary .. f:param name should be inside something like the commandButton ...
<p:commandButton value="Entrar" icon="ui-icon-disk" action="#{userMB.login}" update="avisos,mensagens" ajax="false">
<f:param name="redirect" value="#{requestScope['javax.servlet.forward.request_uri']}" />
</ p: commandButton>
This seems to work only when placed between the button (Mojarra 2.2, Glassfish 4). You will need these two <f:param tags javax.servlet.forward.request_uri and javax.servlet.forward.query_string to ensure you accurately redirect back to all types of URL (with or without query strings). Make sure you have something similar to the snippet below in your login page i.e. the page you specified in your web.xml for login
(<form-login-page>/login.xhtml</form-login-page>).
<h:commandButton value="Login" action="#{securityController.login()}">
<f:param name="redirect" value="#{requestScope['javax.servlet.forward.request_uri']}" />
<f:param name="query_string" value="#{requestScope['javax.servlet.forward.query_string']}" />
</h:commandButton>
You can then retrieve both parameters in the backing bean after form submission as below
public String login() {
try {
String nextPage = "/index.xhtml"; // have a default value in case the user goes to login page directly.
ExternalContext ctx = FacesContext.getCurrentInstance().getExternalContext();
Map<String, String> map = ctx.getRequestParameterMap();
String redirect = map.get("redirect");
String queryString = map.get("query_string");
HttpServletRequest request = (HttpServletRequest) ctx.getRequest();
request.login(this.username, this.password);
// here login is successful otherwise it would've thrown exception
// now let's check the kind of URL our user was going to
if (redirect != null && !redirect.isEmpty()) { // if redirect is null, return the default page
// please use faces-redirect = true to ensure URL change in the browser
if (queryString != null) {
nextPage = redirect + "?" + queryString + "&faces-redirect=true";
} else { // there is no query string, nextPage = redirect
nextPage = redirect + "&faces-redirect=true";
}
// Caveat: You may not need the next lines of code.
// I discovered that the `redirect` string has my context path
// value in it and so it was'nt redirecting. Remove the context path
if (nextPage.contains(request.getContextPath())) {
nextPage = nextPage.substring(request.getContextPath().length());
}
}
} catch (ServletException ex) {
Logger.getLogger(SecurityController.class.getName()).log(Level.SEVERE, null, ex);
// invalid username or password
return "/login.xhtml?failed=true"; // or login error page
}
return nextPage;
}
I hope this helps someone.

Categories