I want to validate forms in Struts 2 using validate functions in the action class.
I found this example : http://www.javatpoint.com/struts-2-custom-validation-workflow-interceptor
However, I want to have multiple functions (actions) in the same class. And I want to have a validation function for each of these functions. How can we do this?
Edit:
The validate() function in the example gets invoked automatically since it is one of the Validateable interface functions. If I have validate functions with other names they won't be invoked
Create validateXxx methods where Xxx is the name of the related action method.
(Whether or not this is the best option depends on the particular validations you need.)
validations using XML validation file
The naming convention of the XML validation file should be ActionClass-Validation.xml. Here our Action Class name is "Login.java" and the XML validation file name is "Login-Validation.xml".
The Login-Validation.xml file contains the following code.
view source
print?
<validators>
<field name="userName">
<field-validator type="requiredstring">
<message>User Name is required.</message>
</field-validator>
</field>
<field name="password">
<field-validator type="requiredstring">
<message key="password.required" />
</field-validator>
</field>
</validators>
The field element contains the name of the form property that needs to be validated. The filed-validator element inside the field element contains the type of validation that needs to be performed.
Here you can either specify the error message directly using the message element or you can use the properties file to define all the error messages and use the key attribute to specify the error key.
Note the properties file should also have the same name as the Action class.
The Login Action class contains the following code.
view source
print?
public class Login extends ActionSupport {
private String userName;
private String password;
public Login() {
}
public String execute() {
return SUCCESS;
}
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
}
The login.jsp page contains the following code.
<%#page contentType="text/html" pageEncoding="UTF-8"%>
<%#taglib uri="/struts-tags" prefix="s" %>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Login Page</title>
<s:head />
</head>
<body>
<s:form action="LoginAction">
<s:textfield name="userName" label="User Name" />
<s:password name="password" label="Password" />
<s:submit value="Login" />
</s:form>
</body>
</html>
Related
I have jsp page which contains one text box which is accepting only integers. That means i have command object which is having integer property. when user enter string in the box.how spring reacts.
Use Spring form tag library. When Spring binds a property and there is a type mismatch it adds a field error to the model with error code typeMismatch
Example
//form object
public class Person{
private int age;
//getters and setters
}
#Controller
#RequestMapping("/person")
public class PersonController{
#RequestMapping(method = RequestMethod.GET)
public String showPersonForm(Model model){
Person person = new Person();
model.addAttribute("person" , person";
return "person";
}
#RequestMapping(method = RequestMethod.POST)
public String savePerson(Person person , BindingResult bindingResult){
if(bindingResult.hasErrors()){
return "person";
}
//return success url
}
}
//person.jsp
<%# taglib prefix="spring" uri="http://www.springframework.org/tags"%>
<%# taglib prefix="form" uri="http://www.springframework.org/tags/form"%>
<form:form method="post" modelAttribute="person" >
<form:input path="age" type="text" />
<form:errors path="age" />
<input type="submit"/>
</form:form>
You will need to define a MessageSource bean in your application context to allow for resolution of your error messages for example using Java Config
#Bean
public MessageSource messageSource(){
ResourceBundleMessageSource resourceBundleMessageSource = new ResourceBundleMessageSource();
resourceBundleMessageSource.setBasenames("errors");
return resourceBundleMessageSource;
}
The errors.properties file should be in the root of the application context
//errors.properties
typeMismatch=The value you entered is invalid #for all type mismatches
typeMismatch.age=The age you have entered is invalid #for field specific type mismatched
I've searched a lot and haven't found a solution.
I'm using JSF 2.1 and RichFaces 4.2.3 and want to validate the login data of the user
I have two input fields.
One Username and one Password, both with #NotEmpty
login.xhtml
<html
xmlns="http://www.w3.org/1999/xhtml"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:rich="http://richfaces.org/rich"
xmlns:a4j="http://richfaces.org/a4j"
xmlns:mt="http://java.sun.com/jsf/composite/components">
<h:body>
<ui:composition template="/protected/user/login-template.xhtml">
<ui:define name="panel-navigation">
<ui:include src="/protected/user/login-left-menu.xhtml" />
</ui:define>
<ui:define name="contentbody">
<h:form>
<div id="content">
<div class="subcolumns">
<div class="c65l">
<div class="subcl">
<p class="sum-error-message" />
<fieldset>
<h3>
<h:outputText value="#{styleguideMessages.login}" />
</h3>
<p>
<h:outputText value="#{messages.login_text}" />
</p>
<div class="subcolumns">
<mt:inputText
id="loginName"
value="#{authenticationPM.loginName}"
label="#{messages.general_label_loginname}"
required="true" />
<div class="c33r validation"></div>
</div>
<div class="subcolumns">
<mt:inputText
id="password"
value="#{authenticationPM.password}"
label="#{styleguideMessages.db_password}"
required="true"
secret="true" />
<div class="c33r validation"></div>
</div>
<div class="subcolumns">
<h:commandLink
id="loginButton"
action="#{authenticationPM.doLogin}"
value="#{styleguideMessages.login}"
title="#{styleguideMessages.login}"
styleClass="button last" />
</div>
</fieldset>
</div>
</div>
</div>
</div>
<mt:commandButton
id="login"
action="#{authenticationPM.doLogin}"
value="hidden"
style="visibility:hidden" />
</h:form>
<script
src="#{facesContext.externalContext.requestContextPath}/js/lib/loginEnter.js"
type="text/javascript"
charset="utf-8"></script>
</ui:define>
</ui:composition>
AuthentificationPM.java
import *;
#Named
#SessionScoped
public class AuthenticationPM extends AbstractPM implements Serializable {
/**
* The user name from the login.
*/
private String userName;
/**
* password.
*/
private String password;
/**
* Returns the login name.
*
* #return String
*/
#NotNull
#Pattern(regexp = "^[^\"/\\[\\]:;|=,+?*<>]*$", message = "{user.loginname.pattern}")
public String getLoginName() {
return userName;
}
/**
* Returns the password.
*
* #return String
*/
#NotNull
public String getPassword() {
return password;
}
/**
* Sets the login name.
*
* #param loginName
* - the login name of the user
*/
public void setLoginName(String loginName) {
this.userName = loginName;
}
/**
* Sets the password.
*
* #param password
* - the password of the user
*/
public void setPassword(String password) {
this.password = password;
}
}
If one of those (say the password) is not filled, the validation fails and a message is shown (as it should).
Now I delete the username and type in a password.
The validation fails because the username is empty.
It cleans the password field and displays a message for the username.
And now the error happens: the former entered username reappeares!
How can I prevent this behaviour?
I know that after process validation, the update model values and invoke application are skipped and the render response is executed. As described here. The render response takes the values stored in the ui component (at apply requests) and uses them to rerender instead of deleting the invalid value.
I've tried this solution as well as this idea. Both ways don't find my component.
Any help or ideas are very appreciated.
Greetings,
Kevin
If you just erase the username from the inputfield, the value should be submitted as an empty string, which would be a legit replacement for the username and also matches the pattern defined.
I can only assume, that you have configured
<context-param>
<param-name>javax.faces.INTERPRET_EMPTY_STRING_SUBMITTED_VALUES_AS_NULL</param-name>
<param-value>true</param-value>
</context-param>
in your web.xml. So, when you try to submitt an empty field, it is interpreted as null, which will not match your #NotNull Annotation on the username attribute. So, the setting of the value is canceled and it will maintain its prior state, cause it's SessionScoped - which is the username that has been entered once.
At least this is the only szenario a (String-)value is not updated when an empty string is submitted I can imagine.
Having this value set to true allows to reproduce the behavior you are describing.
You might ask, why this does not apply for your textbox where you are entering the password when erasing it? Since you are using secret="true" the text-box will not show any information about the string entered (i.e. the length), even if the backing bean attribute is not set to null (after removing the password) and still contains the wrong password.
But be aware that simply removing this attribute might screw functionality where other devs are relying on to get null instead of the empty string. So you should maybe consider to remove the #NotNull annotation and check for null manually.
I'm working on a JSP tag. Here is the old line that starts looping through items in a model:
<c:forEach var="toc" items="${requestScope[formKey].model.sharingTocs}">
But the code has been refactored so the model path (model.sharingTocs above) is now dynamic rather than fixed. It is now passed into the tag via a JSP #attribute:
<%#attribute name="path" required="true"%>
So ${path} now evaluates to "model.sharingTocs".
How can items now be assigned?
Well. Good question.
This is a solution: writing a custom jstl tag to Evaluate a property expression of a bean:
<mytag:eval bean="${requestScope['formKey']}" propertyExpression = "${path}" var="items" />
And ForEach:
<c:forEach var="toc" items="${items}">
</c:forEach>
Sample code of mytag:eval JSTL tag ( Classic model )
public class EvalTag extends TagSupport
{
private Object bean;
private String propertyExpression; //Ex: 'model.sharingTocs'
private String var;
//............
#Override
public int doEndTag() throws JspException {
try {
// Use reflection to eval propertyExpression ('model.sharingTocs') on the given bean
Object propObject = SomeLibs.eval ( this.bean, this.propertyExpression);
this.pageContext.getRequest().setAttribute(this.var, propObject);
// You can add propObject into Other scopes too.
} catch (Exception ex) {
throw new JspTagException(ex.getMessage(), ex);
}
return EVAL_PAGE;
}
//............
// SETTERS here
}
A lib you can use to eval propertyExpression of a bean is Apache bean utils.
http://commons.apache.org/proper/commons-beanutils/apidocs/org/apache/commons/beanutils/package-summary.html#standard.nested
If you are using spring you can utilise the spring tag library, it also assumes you are inside a form:form tag.
<%# taglib prefix="spring" uri="http://www.springframework.org/tags" %>
<%# attribute name="path" required="false" %>
<spring:bind path="${path}">
<c:forEach var="item" items="${status.value}">
${item}
</c:forEach>
</spring:bind>
It's been quite a while since I asked this question but (with new knowledge gained since) I think this ought to work:
<c:set var="itemsPath" value="requestScope[formKey].${path}"/>
<c:forEach var="toc" items="${itemsPath}">
i.e. set up an intermediary JSTL variable with the full path to the items and evaluate that one instead.
I'am new to Spring MVC, following the "Spring in Action" book, creating my own project from scratch. I get the following exception when trying to reach 'reward.jsp':
java.lang.IllegalStateException: Neither BindingResult nor plain target object for bean name 'reward' available as request attribute
Contents of my classes:
reward.jsp
<%# taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<%# taglib uri="http://www.springframework.org/tags/form" prefix="sf"%>
<html>
<head>
<title>Rewards</title>
</head>
<body>
<h1>Rewards module</h1>
<h2>Add reward</h2>
<sf:form action="add" method="post" modelAttribute="reward">
Reward name:<sf:input path="name" />
Point value:<sf:input path="pointValue" />
<input type="submit" value="Add">
</sf:form>
<br />
<h2>Reward list</h2>
<table>
<c:forEach var="reward" items="${rewardList}">
<tr>
<td>${reward.name}</td>
<td>${reward.pointValue}</td>
<td>delete</td>
</tr>
</c:forEach>
</table>
It works just fine when I delete form inputs.
RewardController.java
#Controller
public class RewardController {
#Autowired
private RewardService rewardService;
#RequestMapping("/reward")
public String listRewards(Map<String, Object> model) {
model.put("rewardList", rewardService.listReward());
return "reward";
}
#RequestMapping(value = "/add", method = RequestMethod.POST)
public String addReward(#ModelAttribute("reward") Reward reward,
BindingResult result) {
rewardService.addReward(reward);
return "redirect:/reward";
}
#RequestMapping("/delete/{rewardId}")
public String deleteContact(#PathVariable("rewardId") long rewardId) {
rewardService.removeReward(rewardId);
return "redirect:/reward";
}
}
Change your listRewards method, so that it add the form backing object to the model map model.put("reward", new Reward()).
#RequestMapping("/reward")
public String listRewards(Map<String, Object> model) {
model.put("rewardList", rewardService.listReward());
model.put("reward", new Reward())
return "reward";
}
In the struts.xml:
<action name="User_UserFormSubmit" class="actions.UserManager">
<result name="input" >/jsp/user_form.jsp</result>
<result name="success" type="redirectAction"> success_register</result>
</action>
My class:
public class UserManager extends ActionSupport implements ModelDriven<User>{
private User user = new User();
#Override
public User getModel() {
return user;
}
public String validate() {
addActionError("blabla");
}
public String execute() {
return SUCCESS;
} ...
then in the jsp:
<s:property value="getActionErrors()"/>
I expect in the input result :
<li> blabla </li>
I succefully arrived to user_form.jsp, but the actionError does not appear
I tried without the "implements ModelDriven" and it work
The model driven erase the actionErrors (I supposed)
I want to use validate and modeldriven ¿any idea?
Not a big fan of model driven... but here is an example.
Before the example please note that using validate() does not make much sense in terms of ModelDriven. The reason is that the Model should be used over several actions and so the validation should probably be consistent. You don't use model driven just to make property names a bit shorter (to do that you use the struts2 push tag). As such validation should be done with xml as the model is bigger than any one action. Each action which uses that model uses the Visitor validator. This validator merely looks up the xml validation file for the model. The following example however will use the validate() method in the action to save time.
The following example will use the struts2-conventions-plugin to reduce the example size (adding it to your project is simply a matter of adding one jar).
create: com.quaternion.action.AddUser
package com.quaternion.action;
import com.opensymphony.xwork2.ActionSupport;
import com.opensymphony.xwork2.ModelDriven;
public class AddUser extends ActionSupport implements ModelDriven<User>{
User user = new User();
#Override
public User getModel() {
return user;
}
#Override
public void validate(){
if (user.age != 12) {
super.addActionError("bla bla bla");
}
}
}
create: com.quaternion.action.User
package com.quaternion.action;
public class User {
public String name;
public int age;
}
create: /WEB-INF/content/add-user-input.jsp
<%#taglib prefix="s" uri="/struts-tags"%>
<%#page contentType="text/html" pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<title>Form</title>
</head>
<body>
<h1>Form</h1>
<s:actionerror/>
<s:form action="add-user">
<s:textfield name="name"/>
<s:textfield name="age"/>
<s:submit/>
</s:form>
</body>
</html>
create: /WEB-INF/content/add-user-success.jsp
<%#taglib prefix="s" uri="/struts-tags"%>
<%#page contentType="text/html" pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<title>Success</title>
</head>
<body>
<h1>Success</h1>
</body>
</html>
To test:
Add /add-user-input as the action name on your context path. If you enter an age of 12 you will get the success page, if you enter anything else you will get an action error. This has been tested to work. It is possible a typo was made, but the main thing to take away is there is an error in your application, using both conventions or xml there should be no issues with what you are doing.
You can also validate with #validations too, you have access to model driven object in the validator.
#Action(value = "save-user")
#Validations(
stringLengthFields = {
#StringLengthFieldValidator(fieldName = "name", trim = true, key = "validate.required.string.length"),
#StringLengthFieldValidator(fieldName = "age", trim = true, key = "validate.required.string.length"),
#StringLengthFieldValidator(fieldName = "address.addLine1", trim = true, key = "validate.required.string.length")
})
public String save() {