Struts 2: how to send url parameters in Action? - java

I try to send url parameter to Action class as described here: How to access url parameters in Action classes Struts 2
If I do like next, it works and I can get pageLevel in Action class
<s:form action="index?pageLevel=99">
<s:checkboxlist label="Select" list="colors" name="yourColor" value="defaultColor" />
<s:submit value="Submit" />
</s:form>
But next does not work
<s:form action="index?pageLevel=<%=level%>">
And this does not work too
<c:set var="pageLevel" scope="page" value="<%=level%>" />
<s:form action="index?pageLevel=${pageLevel}">
I get error
SEVERE: Servlet.service() for servlet jsp threw exception
org.apache.jasper.JasperException: /start.jsp (line: 86, column: 0)
According to TLD or attribute directive in tag file, attribute action
does not accept any expressions
Jsp page contains
<%# taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
How can I do it?

Have a 'level' property in your index action with its getter an setter
Something like:
public class Index extends ActionSupport {
private String level;
public String getLevel() {
return this.getLevel();
}
public void setLevel(String level) {
this.level = level;
}
}
Set 'level' as a hidden parameter in the form.
Assuming your action name is "index" and the request parameter is "pageLevel":
<s:form action="index">
<s:checkboxlist label="Select" list="colors" name="yourColor" value="defaultColor" />
<s:hidden name="level" value="%{#parameters.pageLevel}" />
<s:submit value="Submit" />
</s:form>

Try this
<s:form action="index">
<s:checkboxlist label="Select" list="colors" name="yourColor" value="defaultColor" />
<s:hidden name="pageLevel" value="%{pageLevel}"/>
<s:submit value="Submit" />
</s:form>

Related

Spring MVC form radio input not updating model

I'm creating a web application using Spring MVC framework and forms.
I'm having trouble getting my form to update the field position in my PlayerModel. It simply doesn't save the value when I submit the form (check the controller inline comment on the submit() function).
If I select either radio button (with values 1 and 2) and submit, the model reaches the controller with value 0.
Despite having read countless similar questions/answers here on StackOverflow, I am unable to get this to work. What am I doing wrong here?
[EDIT]
I figured out the problem. For some reason, the value of the name attribute in the radio input is being used to match with the model attribute, instead of using path.
<input type="radio" id="index1" value="1" path="position" name="index" />
So it is trying to match index with the model, which of course does not exist, instead of using the position value in the path attribute.
Shouldn't it be the other way around?
playerView.jsp
<%# taglib prefix="spring" uri="http://www.springframework.org/tags"%>
<%# taglib prefix="form" uri="http://www.springframework.org/tags/form"%>
<html>
<head>
</head>
<body>
<form:form action="/game/playerView" method="POST" modelAttribute="playerModel">
<table>
<tr>
<th>
<input type="radio" id="index1" value="1" path="position" name="index" />
<input type="radio" id="index2" value="2" path="position" name="index"/>
</th>
</tr>
<tr>
<td><input type="submit" value="Submit"/></td>
</tr>
</table>
</form:form>
</body>
</html>
GameController.java
#Controller
#SessionAttributes("playerModel")
public class GameController {
#RequestMapping(value = "playerView", method = RequestMethod.GET)
public ModelAndView hello(ModelMap map) {
PlayerModel playerModel = new PlayerModel();
playerModel.setPosition(0);
map.addAttribute("playerModel", playerModel);
return new ModelAndView("playerView", "playerModel", playerModel);
}
#RequestMapping(value = "playerView", method = RequestMethod.POST)
public ModelAndView submit(#ModelAttribute("playerModel") PlayerModel playerModel, BindingResult result, ModelMap model){
playerModel.getPosition(); // returns 0
model.addAttribute("playerModel", playerModel);
return new ModelAndView("playerView", "playerModel", playerModel);
}
}
PlayerModel.java
#Resource
public class PlayerModel {
private int position;
public int getPosition() {
return position;
}
public void setPosition(int position) {
this.position = position;
}
}
You are using Spring-MVC form tag therefore please do not use this <input type="radio" id="index1" value="1" path="position" name="index" /> insted of use like this (For more details)
<tr>
<td>Sex:</td>
<td>
Male: <form:radiobutton path="sex" value="M"/> <br/>
Female: <form:radiobutton path="sex" value="F"/>
</td>
</tr>
and there is no path variable in HTML <input type="radio"> ,
path should be used in the spring type declaration.
eg :
<form:input path="firstName"/> this code is changed to <input name="firstName" type="text"/> by Spring

Displaying SimpleCaptcha in Struts 2 Form

I am trying to implement SimpleCaptcha with Struts 2, so far the image is displaying. However, it is displaying at the top of the <s:form>.
register.jsp:
<%# taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<%# taglib prefix="s" uri="/struts-tags"%>
<head>
...
<s:head />
</head>
<body>
<b>REGISTER</b>
<p>Please fill up the form below.</p>
<s:form action="register" method="post">
<s:textfield label="Enter username" key="userId" maxlength="25"
size="30" />
<s:textfield label="Enter email" key="userEmail1" type="email"
placeholder="someone#domain.com" size="30" />
<s:textfield label="Re-enter email" key="userEmail2" type="email"
placeholder="someone#domain.com" size="30" />
<s:password label="Enter password" key="userPassword1" size="30" />
<s:password label="Re-enter password" key="userPassword2"
size="30" />
<img src="<c:url value='simple-captcha.png' />" />
<br />
Cannot read? Refresh page for new CAPTCHA.
<s:textfield label="Enter CAPTCHA" key="captchaAnswer" size="30" />
<s:submit value="Register" />
</s:form>
</body>
How do I make the image appear above the Enter CAPTCHA textfield as specified in the code?
The image should be generated by the captcha action. Then you provide the URL to this action in <img> tag. To implement captcha in your project follow steps below
Add the jar to your web project classpath: simplecaptcha-1.2.1.jar.
Typically inside web-inf/lib folder.
Add new action class RegisterAction
Note: The following code is using convention plugin to map actions and for simplicity DMI is used to invoke some methods of the action class when form is submitted. To turn on DMI use a constant in struts.xml:
<constant name="struts.enable.DynamicMethodInvocation" value="true"/>
RegisterAction.java:
public class RegisterAction extends ActionSupport {
private String userId;
private String userEmail1;
private String userEmail2;
private String userPassword1;
private String userPassword2;
private String captchaResponse;
private InputStream inputStream;
//getters and setters
public String create() {
//RegisterAction is the form bean of the current action and captchaResponse is the field of user input
String answer = (String) ActionContext.getContext().getSession().get("CorrectAnswer");
if (answer == null || getCaptchaResponse()==null || !answer.equals(getCaptchaResponse())){
addFieldError("captchaResponse", getText("error.captcha"));
}
return SUCCESS;
}
#Action(value = "captcha", results = {#Result(type="stream", params = {"contentType", "image/jpeg"})})
public String captcha() {
try {
Captcha captcha = new Captcha.Builder(200, 50).addText(new DefaultTextProducer()).gimp(new DropShadowGimpyRenderer()).build();
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
//write the image
CaptchaServletUtil.writeImage(outputStream, captcha.getImage());
//store the answer for this in session
ActionContext.getContext().getSession().put("CorrectAnswer", captcha.getAnswer());
//return image
inputStream = new ByteArrayInputStream(outputStream.toByteArray());
return SUCCESS;
} catch (Exception e) {
e.printStackTrace();
throw e;
}
}
}
RegisterAction.properties contains the following value for the error key:
RegisterAction.properties:
error.captcha=Invalid value of shown text!
so we check either pass successfully or add to errors error regarding captcha.
Add register.jsp Typically in web-inf\content
register.jsp:
<!DOCTYPE html>
<%# taglib prefix="s" uri="/struts-tags"%>
<%# taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<html>
<head>
<meta charset="UTF-8">
<title>Register</title>
</head>
<body>
<b>REGISTER</b>
<p>Please fill up the form below.</p>
<s:form action="register" method="post">
<s:textfield label="Enter username" key="userId" maxlength="25"
size="30" />
<s:textfield label="Enter email" key="userEmail1" type="email"
placeholder="someone#domain.com" size="30" />
<s:textfield label="Re-enter email" key="userEmail2" type="email"
placeholder="someone#domain.com" size="30" />
<s:password label="Enter password" key="userPassword1" size="30" />
<s:password label="Re-enter password" key="userPassword2"
size="30" />
<tr><td>
<img id="captchaImg" src="<s:url action='captcha'/>" alt="Captcha Image" height="45">
<img src="<c:url value='/images/reload.jpg' />" alt="Reload" onclick="document.forms[0].captchaImg.src='<s:url action='captcha'/>'+'?id='+Math.random();" style="cursor:pointer"/>
<s:textfield label="Enter CAPTCHA" key="captchaResponse" size="30" requiredLabel="*"/>
<tr><td>
Cannot read? Refresh page for new CAPTCHA.
</td></tr>
<s:submit method="create" value="Register" />
</s:form>
</body>
</html>
This will construct the Captcha and the text field to enter the value and Struts error message to show errors in captchaResponse field, plus the refresh icon.
NOTE: a good trick we used here is the javascript Math.random() function, this way prevent certain browsers like Firefox to cache the URL and keep posting the same Captcha image, this enforce it to get the new value without doing any more effort.
Here is how it will looks like:
For more details refer to the web site : SimpleCaptcha
This is just to show how I went about the solution. I was unaware you can put <tr><td> inside the <s:form>. Thanks to Roman C, I got the CAPTCHA image to display where I wanted it to.
register.jsp:
<%# taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<%# taglib prefix="s" uri="/struts-tags"%>
<head>
...
<s:head />
</head>
<body>
<b>REGISTER</b>
<p>Please fill up the form below.</p>
<s:form action="register" method="post">
<s:textfield label="Enter username" key="userId" maxlength="25"
placeholder="someone" size="30" />
<s:textfield label="Enter email" key="userEmail1"
placeholder="someone#domain.com" size="30" />
<s:textfield label="Confirm email" key="userEmail2"
placeholder="someone#domain.com" size="30" />
<s:password label="Enter password" key="userPassword1" size="30" />
<s:password label="Confirm password" key="userPassword2"
size="30" />
<tr>
<td></td>
<td>
<img src="<c:url value='simple-captcha.png' />" />
<br />
Cannot read? Press F5 to refresh.
</td>
</tr>
<s:textfield label="Enter code" key="captchaAnswer" size="30" />
<s:submit value="Register" />
</s:form>
</body>
RegisterAction.java:
import nl.captcha.Captcha;
...
public class RegisterAction extends ActionSupport implements SessionAware, Message {
private static final long serialVersionUID = 1L;
private Map<String, Object> session;
private String userId;
private String userEmail1;
private String userEmail2;
private String userPassword1;
private String userPassword2;
private String captchaAnswer;
#Override
public String execute() throws Exception {
// business logic to insert user into database
return SUCCESS;
}
#Override
public void validate() {
Captcha captcha = (Captcha) session.get(Captcha.NAME);
if(!captcha.isCorrect(getCaptchaAnswer())) {
addFieldError("captchaAnswer", INCORRECT_CAPTCHA);
}
// other validations
}
#Override
public void setSession(Map<String, Object> session) {
this.session = session;
}
// getters and setters
}
struts.xml:
<struts>
<constant name="struts.devMode" value="true" />
<package name="default" extends="struts-default">
<action name="register" class="com.mypackage.action.RegisterAction">
<result name="success">/login.jsp</result>
<result name="input">/register.jsp</result>
</action>
<!-- other actions -->
</package>
</struts>
web.xml:
(The <init-param> is optional.)
<servlet>
<servlet-name>SimpleCaptcha</servlet-name>
<servlet-class>nl.captcha.servlet.SimpleCaptchaServlet</servlet-class>
<init-param>
<param-name>captcha-width</param-name>
<param-value>200</param-value>
</init-param>
<init-param>
<param-name>captcha-height</param-name>
<param-value>50</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>SimpleCaptcha</servlet-name>
<url-pattern>/simple-captcha.png</url-pattern>
</servlet-mapping>
<filter>
<filter-name>struts2</filter-name>
<filter-class>org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>struts2</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
OUTPUT:

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}" />

why do i get org.apache.jasper.JasperException: PWC6049: Attempted a bean operation on a null object

I get org.apache.jasper.JasperException: PWC6049: Attempted a bean operation on a null object when i click the submit button and the request goes to the following jsp:
<jsp:useBean id="namebean" class="BeanTesters.Bean">
<jsp:setProperty name="namebean" property="name" param="Name" />
</jsp:useBean>
<%--Now check if the text-field data has been stored--%>
<jsp:getProperty name="beanname" property="name" />
HTML code :
<form method="get" action="straighttojsp.jsp">
<input type="text" name="Name" /> <br />
<input type="submit" value="Submit data"/>
</form>
Bean class :
package BeanTesters;
public class Bean {
private String name = null;
public void setName(String n) {
name = n;
}
public String getName() {
return name;
}
}
Why do i get this exception ?
You're setting property in bean namebean and trying to retrieve it back from bean beanname, which apparently is null

Recieving 'null' values from a jsp page into Struts 2 Action

I have a jsp page and struts 2 Action class . When I submit the form in the jsp , I am getting null values into the action.
The JSP code looks like :
<s:form id="user" name="user" action="initUserAdmin">
<s:textfield name="userName" cssClass="txtbox" size="30" />
<div class="btn"><a href='<s:url action="searchUserAdmin"/>'
title="Search" id="button" class="btn" ><span>Search</span></a></div>
</s:form>
The struts.xml has this part
<action name="*UserAdmin" method="{1}" class="com.mphasis.im.web.action.UserAction">
<result name="init" type="tiles">user</result>
<result name="search" type="tiles">user</result>
<result name="reset" type="tiles">user</result>
<result name="createNew" type="tiles">createNewUser</result>
</action>
And the Action class has this :
public class UserAction extends BaseAction
{
public String userName;
public String getUserName()
{
return userName;
}
public void setUserName(String userName)
{
this.userName = userName;
}
public String search()
{
searchProcessed = true;
System.out.println("******** inside search ******");
System.out.println("username = "+ userName);
return TilesConstants.SEARCH;
}
And the output comes as below when I type a string in the text box in jsp page.
******** inside search ******
username = null
What might be the problem ? Am I missing something ?
<a href='<s:url action="searchUserAdmin"/>'
title="Search" id="button" class="btn" >
It's just a href to the URL of action and with no parameter. Therefore, the 'userName' in the action is null.
<s:form id="user" name="user" action="initUserAdmin">
<s:textfield name="userName" cssClass="txtbox" size="30" />
<div class="btn"><a href='javascript:submitme()'
title="Search" id="button" class="btn" ><span>Search</span></a></div>
</s:form>
Javascript
function submitme(){
document.user.submit()
}
Also in the action mapping you provided the action name you are using there is UserAdmin whereas in the form action you are using initUserAdmin.They must be the same

Categories