For example I have an Action Class called UsersAction where I have some methods like: login, logout, register, and so on.
And I have written validate() method as follows:
#Override
public void validate() {
if ("".equals(username)) {
addFieldError("username", getText("username.required"));
}
if ("".equals(email)) {
addFieldError("email", getText("email.required"));
} else if (!Utils.isValidEmail(email)) {
addFieldError("email", getText("invalid.email.address"));
}
if ("".equals(phone)) {
addFieldError("phone", getText("phone.required"));
}
if ("".equals(password)) {
addFieldError("password", getText("password.required"));
}
}
The problem is that this solution works only when register action is called, anyway it wont work on login or logout cause it will check if the fields aren't null or email is correct and always will give an error. Okay, the solution for logout was to add #SkipValidation annotation above it, but I don't know how to tell to it that login have only 2 fields username and password and that it's not necessary to check email and phone too. I don't want to write an Action Class for each action in part, cause the purpose of Struts 2 is not this.
Create validateMethodName methods, where methodName is the name of the method, e.g.,
validateLogin() { ... }
Otherwise provide some form of contextual information to your validate method.
Using annotations, annotate your action method login with
#Action(value="login", results = {
#Result(name="input", location = "/login.jsp")
},interceptorRefs = #InterceptorRef(value="defaultStack", params = {"validation.validateAnnotatedMethodOnly", "true"}))
#Validations(requiredFields = {
#RequiredFieldValidator(type = ValidatorType.FIELD, fieldName = "username", message = "${getText("username.required")}"),
#RequiredFieldValidator(type = ValidatorType.FIELD, fieldName = "password", message = "${getText("password.required")}")
})
it will only validate username and passsword fields. Similar do the other action methods.
References:
Convention plugin
Validation
Validatin annotation
Related
I'm actually writing a java code in the setupRender() method. Depending of a value provided by the server side, i would like to display an Alert dialog box to the user. By clicking on ok, the application should be closed.
I have not already found how to display an Alert dialog box with tapestry. Do somebody know how to procedd?
Thanks
It's not quite clear to me what you are trying to achieve, but perhaps the following two suggestions are useful.
Suggestion 1 - Display a message using AlertManager
In the page class, inject AlertManager and add the message to it.
public class YourPage {
#Inject
AlertManager alertManager;
Object setupRender() {
// ...
alertManager.alert(Duration.UNTIL_DISMISSED, Severity.INFO, "Love Tapestry");
}
}
Then use the <t:alerts/> component in the page template file to have the message displayed.
Note: The user may dismiss the message, that is, make it disappear. But it doesn't 'close the application' (whatever it is that you mean by that).
Suggestion 2 - Redirect to another page
The setupRender method can return different things. For example, it could return another page class, causing a redirect to that page. On that page, you could have the messages displayed and the session subsequently invalidated (if that's what you meant by 'application should be closed'.
public class YourPage {
Object setupRender() {
// ...
return AnotherPage.class;
}
}
public class AnotherPage {
#Inject
Request request;
void afterRender() {
Session session = request.getSession(false);
session.invalidate();
}
}
See the Tapestry docs for details about what setupRender() can return.
Suggestion 3 - Use JavaScript to display Alert and trigger Component Event
This approach uses JavaScript to display an Alert and subsequently trigger a component event via ajax. The event handler takes care of invalidating the session.
Note: Closing the current browser windows/tab with JavaScript isn't as easy as it used to be. See this Stackoverflow question for details.
YourPage.java
public class YourPage {
boolean someCondition;
void setupRender() {
someCondition = true;
}
#Inject
private JavaScriptSupport javaScriptSupport;
#Inject
ComponentResources resources;
public static final String EVENT = "logout";
void afterRender() {
if (someCondition) {
Link link = resources.createEventLink(EVENT);
JSONObject config = new JSONObject(
"msg", "See ya.",
"link", link.toAbsoluteURI()
);
javaScriptSupport.require("LogoutAndCloseWindow").with(config);
}
}
#Inject Request request;
#OnEvent(value = EVENT)
void logout() {
Session session = request.getSession(false);
if (session != null) session.invalidate();
}
}
YourPage.tml
<!DOCTYPE html>
<html
xmlns:t="http://tapestry.apache.org/schema/tapestry_5_4.xsd"
xmlns:p="tapestry:parameter">
<h1>Hit the Road Jack</h1>
</html>
LogoutAndCloseWindow.js
define(["jquery"], function($) {
return function(config) {
alert(config.msg);
$.ajax({
type: "GET",
url: config.link
});
window.close(); // Legacy. Doesn't work in current browsers.
// See https://stackoverflow.com/questions/2076299/how-to-close-current-tab-in-a-browser-window
}
})
Not getting sessin value in vaadin framework
Used below :
private void setCurrentUsername(String username){
VaadinService.getCurrentRequest().getWrappedSession().setAttribute("LOGGED_IN_AS_USER",username);
userSubMenu.setText(username);
}
public static String getCurrentUsername() {
//log.info("User:::::::::::::::::" + (String) VaadinService.getCurrentRequest().getWrappedSession().getAttribute("LOGGED_IN_AS_USER"));
return (String) VaadinService.getCurrentRequest().getWrappedSession().getAttribute("LOGGED_IN_AS_USER");
}
getting value as null when flow going to other class
You could try using VaadinSession.getCurrent().getSession() instead?
iIf you are using this for a user interface i.e a user logging in. Don't forget that when your app first builds/ when the user first enters it they will of course have a null value(including any sub pages).
Try adding a ViewChangeListener to the page that the user now enters (apologies for any errors in coding i'm not currently able to gain access to my machine) into:
#Override
public void enter(ViewChangeListener.ViewChangeEvent event) {
this.username = VaadinSession.getCurrent().getAttribute("LOGGED_IN_AS_USER");
}
I am making a Java project with vaadin. Right now I have a user registration form looking like that:
public class RegistrationComponent extends CustomComponent implements View {
public static final String VIEW_NAME = "Registration";
public RegistrationComponent(){
Panel panel = new Panel("Registration Form");
panel.setSizeUndefined();
FormLayout content = new FormLayout();
CheckBox checkBox1, checkBox2, checkBox3;
checkBox1 = new CheckBox("Check Box 1");
checkBox2 = new CheckBox("Check Box 2");
checkBox3 = new CheckBox("Check Box 3");
checkBox1.setRequired(true);
checkBox2.setRequired(true);
TextField mailTextField = new TextField("Email Address");
TextField passwordTextField = new TextField("Password");
TextField confirmPasswordTextField = new TextField("Confirm Password");
final Button submitButton = new Button("Submit");
content.addComponent(mailTextField);
content.addComponent(passwordTextField);
content.addComponent(confirmPasswordTextField);
content.addComponent(checkBox1);
content.addComponent(checkBox2);
content.addComponent(checkBox3);
content.addComponent(submitButton);
content.setSizeUndefined(); // Shrink to fit
content.setMargin(true);
panel.setContent(content);
setCompositionRoot(panel);
//listeners:
submitButton.addClickListener(new Button.ClickListener() {
public void buttonClick(Button.ClickEvent event) {
//
}
});
}
#Override
public void enter(ViewChangeListener.ViewChangeEvent event){
//
}
}
Of course, the form doesn't do anything other than being displayed.
What I wanna do, is make Vaadin display error messages next to fields if some requirements are not met. The requirements themselves are not that important (lets say I want email field to contain at least 8 characters). What I wanna know, is: is there any simple built-in way to do that? I was here:
https://vaadin.com/api/com/vaadin/data/Validator.html
but I dont understand how to use a validator, or even if that is what I want to use. I've been looking all over google for usage examples, but so far with no success. Thanks for help!
Vaadin 7
The following applies to Vaadin 7. The validate() method has been removed in Vaadin 8.
All Field types in Vaadin implement the Validatable interface which has the addValidator method that accepts an implementation of Validator as parameter.
So to add a validator that checks the length of the value of a TextField, you would do this:
TextField textField = new TextField();
textField.addValidator(
new StringLengthValidator(
"Must be between 2 and 10 characters in length", 2, 10, false));
Vaadin fields have built-in functionality for displaying the validation errors to the user. By default, the field will be highlighted in red and an exclamation mark will appear next to the field, hovering over this will show a more detailed message to the user.
Automatic Validation
By default, the field will now validate on the next server request which contains a changed value for the field to the server. If the field is set to 'immediate', this will happen when the field looses focus. If the field is not immediate, validation will happen when some other UI action triggers a request back to the server.
Explicit Validation
Sometimes, you may want to exercise more control over when validation happens and when validation errors are displayed to the user. Automatic validation can be disabled by setting validationVisible to false.
textField.setValidationVisible(false);
When you are ready to validate the field (e.g. in a button click listener) you can explicitly call the validate (you can also use commit() if it is a buffered field) method on the TextField instance to trigger validation. validate will throw an InvalidValueException if the value is invalid. If you want to use the builtin display of validation errors included in the TextField component you will also have to set validationVisible back to true.
try {
textField.validate();
} catch (Validator.InvalidValueException ex) {
textField.setValidationVisible(true);
Notification.show("Invalid value!");
}
Note that once validationVisbible is set back to true, validation will happen implicitly so you must remember to set it back to false on the next request if you want to maintain explicit control over validation.
Validation Messages
Individual validation messages can be extracted from the instance of Validator.InvalidValueException which is thrown when validate() or commit() is called.
try {
textField.validate();
} catch (Validator.InvalidValueException ex) {
for (Validator.InvalidValueException cause: ex.getCauses()) {
System.err.println(cause.getMessage());
}
}
Validators
Validators implement the Validator interface and there are several useful validators shipped with Vaadin. Check out the API docs for more information on these: https://vaadin.com/api/7.4.5/com/vaadin/data/Validator.html
Custom validators are easy to implement, here is an example taken from the Book of Vaadin:
class MyValidator implements Validator {
#Override
public void validate(Object value)
throws InvalidValueException {
if (!(value instanceof String &&
((String)value).equals("hello")))
throw new InvalidValueException("You're impolite");
}
}
final TextField field = new TextField("Say hello");
field.addValidator(new MyValidator());
field.setImmediate(true);
layout.addComponent(field);
Problem solved,
Apparently I wasn't looking deep enough before. Here it comes:
field.addValidator(new StringLengthValidator("The name must be 1-10 letters (was {0})",1, 10, true));
all details here:
https://vaadin.com/book/-/page/components.fields.html
Vaadin 8
Using Vaadin 8 com.vaadin.data.Binder easily you can validate your fields. See Binding Data to Forms in the manual.
Create a TextField and a binder to validate the text field.
public class MyPage extends VerticalLayout{
TextField investorCode = new TextField();
Binder<MyBean> beanBinder = new Binder<MyBean>();
//Info : MyBean class contains getter and setter to store values of textField.
public MyPage (){
investorCode.addValueChangeListener(e->valueChange(e));
addComponent(investorCode);
bindToBean();
}
private void bindToBean() {
beanBinder.forField(investorCode)
.asRequired("Field cannot be empty")
.withValidator(investorCode -> investorCode.length() > 0,"Code shold be atleast 1 character long").bind(MyBean::getInvestorCode,MyBean::setInvestorCode);
}
//rest of the code .....
private void valueChange(ValueChangeEvent<String> e) {
beanBinder.validate();
}
}
Call validate() from binder will invoke the validation action.
beanBinder.validate();
to validate the filed. You can call this from anywhere in the page. I used to call this on value change or on a button click.
Problem: Checkboxes values are not being bound to my form, properly. The result is that all my boolean values are null (at least the ones not being bound), and the existing ones are not being updated with values changed by the user.
Details: I'm aware that checkboxes are not submitted to the server if they are not selected. However, I do see the values in the request when hooking up an Eclipse debugger. The data is populated using jQuery/Datatable, but the data is posted back to the server using a form submit.
Spring MVC Version: 3.2.8
I'm assuming its configuration, but I'm not seeing where I am wrong. Here is a small code snippet of what I'm doing in my controller.
#Controller
public class CheckboxController {
...
#RequestMapping(value = "saveCheckboxes*", method = RequestMethod.POST)
public String saveCheckboxes(#ModelAttribute(SESSION_FORM_KEY) CheckboxForm form, BindingResult result, ModelMap model) {
// VALIDATE HERE...
if ( !result.hasErrors() ) {
// SAVE
}
else {
// DON'T SAVE (alert user)
}
}
}
So Spring MVC is used to binding request inputs to my form. The form is defined below, which has a list of summary objects with a boolean property.
public class CheckboxForm {
private List<Summary> summaries;
...
}
public class Summary {
private boolean selected;
...
}
I use jQuery/Datatables to populate my online grid of data. The inputs are created dynamically using a callback within datatables.
var tableWidget = (function($) {
init = function() {
...
"aoColumnDefs": [
{ "aTargets": [0], "sName": "", "mData": "selected" "stype": "html", "sClass": "center", "mRender": renderCheckbox, "bSortable":false, "sWidth": "50px" }
...
};
renderCheckbox = function(source, type, row) {
var $name = 'checkboxForm.summaries['+row.index+'].selected';
return createCheckbox($name, source);
};
createCheckbox = function(name, checked) {
var $checked = (checked === true) ? ' checked="checked"' : '';
return '<input type="checkbox" name="'+name+'" value="true"'+$checked+'/><input type="hidden" name="_'+name+'" value="on"/>';
}
...
))(jQuery);
After all of this, I hooked up the debugger and traced it into the WebDataBinder. I found that it seems to throw and exception in the method:
public boolean isWritableProperty(String propertyName)
saying the property cannot be evaluated. This happens for each property returned. However, I can confirm that what is in the request is the very inputs that I am expecting.
First, unless you know why avoid relative URL in #RequestMapping methods. It is a common cause of errors.
Next, as you directly generate your checkboxes without all the bells and whistles that adds spring:checkbox, you wont't get automatic error messages, and could experience problems in getting last checkboxes values if they are unchecked, as they will not be transmitted by browser and Spring will never see them giving a shorter list (or even an empty list if all are unchecked).
That being said, your problem is that you use checkboxForm.summaries[index].selected where Spring would expect only summaries[index].selected. Remove checkboxFormand your controller should affect values to the #ModelAttribute CheckboxForm form.
I have a Swing GUI where I am restricting the user registration so that the username and the password cannot be the same. I am using JoptionPane for the task with the following code:
public void actionPerformed(ActionEvent e) {
String username = tuser.getText();
String password1 = pass1.getText();
String password2 = pass2.getText();
String workclass = wclass.getText();
Connection conn = null;
try {
if(username.equalsIgnoreCase(password1)) {
JOptionPane.showMessageDialog(null,
"Username and Password Cannot be the same. Click OK to Continue",
"Error", JOptionPane.ERROR_MESSAGE);
System.exit(0);
}
...
The problem is that I had to use System.exit(0); without it, the next code was getting executed. Even after the JOptionPane poped up, the registration was succeeding. I do not need the system to exit, but I need the user to be kept on the registration page after the validation. What is the best way to do this? Is there other convenient ways of doing this rather than using the JOptionPane?
Replace
System.exit(0);
with
return;
if you do not want the rest of the method to be performed
You need to place your code within endless loop, and break it upon successful result. Something like:
while(true)
{
// get input from user
if(vlaidInput) break;
}
place that next code into else part may be it works
if(username.equalsIgnoreCase(password1))
{
JOptionPane.showMessageDialog(null, "Username and Password Cannot be the same. Click OK to Continue","Error",JOptionPane.ERROR_MESSAGE);
}
else
{
//place that next code
// username and password not equals, then it will execute the code
}
First of all, it is best if the UI and business logic (in this case, validation) are separated. Have them separate sort of suggest a better way of handling interaction on its own. Thus, it makes sense to create a separate class UserValidation with method boolean isValid(). Something like this:
public class UserValidation {
private final String name;
private final String passwd;
private final String passwdRpt;
public UserValidation(final String name, final String passwd, final String passwdRpt) {
this.name = name;
this.passwd = passwd;
this.passwdRpt = passwdRpt;
}
public boolean isValid() {
// do your validation logic and return true if successful, or false otherwise
}
}
Then the action code would look like this:
public void actionPerformed(ActionEvent e) {
if (new UserValidation(tuser.getText(), pass1.getText(), pass2.getText()).isValid()) {
// do everything needed is validation passes, which should include closing of the frame of dialog used for entering credentials.
}
// else update the UI with appropriate error message -- the dialog would not close by itself and would keep prompting user for a valid entry
}
The suggested approach gives you a way to easily unit test the validation logic and use it in different situations. Please also note that if the logic in method isValid() is heavy than it should be executed by a SwingWorker. The invocation of SwingWorker is the responsibility of the action (i.e. UI) logic.