JSP file: /WEB-INF/jsp/customers/edit.jsp
<%--
Examples of:
* Form.renderAsText to display the form as plain text.
* Enum properties as radio buttons.
* Many-to-one relationship as inputSelect
* Input password with equals validation.
* Multiple field as map (collection or array are also supported).
* Multiple submit buttons
--%>
<tags:layout>
<jsp:attribute name="js">
<c:if test="${empty action.customer.id}">
<script>
// bind javascript validations
$$('form')[0].bindValidations();
</script>
</c:if>
</jsp:attribute>
<jsp:body>
<l:form action="Customers" event="save" separateErrors="true" renderAsText="${!empty action.customer.id}">
<c:if test="${!empty action.customer.id}">
<div class="important">This is the same form used for user input, but setting renderAsText=true</div>
</c:if>
<div class="buttonBar">
<c:if test="${empty action.customer.id}">
<l:button type="submit"/>
<l:button type="submit" value="Refresh" event="edit"/>
</c:if>
<l:url title="goback" action="Customers" event="list"/>
</div>
<l:messages/>
<c:if test="${!empty action.customer.id}">
<l:inputHidden name="customer.id" />
</c:if>
<l:inputText name="customer.firstName"/>
<l:inputText name="customer.lastName"/>
<l:inputText name="customer.idCard"/>
<l:inputText name="customer.email" autocomplete="false"/>
<l:inputPassword name="customer.password" value=""/>
<l:inputPassword name="confirmPassword" value="" />
<l:inputCheckbox name="customer.phoneSupport" labelPos="left"/>
<l:inputSelect label="customerType" name="customer.customerType.id" options="${action.customerTypes}" />
<c:forTokens items="EUROPE,ASIA,AMERICA" delims="," var="index">
<l:inputText name="prices[${index}]" label="prices.${index}" />
</c:forTokens>
<hr/>
<l:inputRadio name="customer.creditType"/>
</l:form>
</jsp:body>
</tags:layout>
Class: Customer.java
/*
* Copyright 2002-2006 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.loom.demo.model;
import javax.persistence.Basic;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.EnumType;
import javax.persistence.Enumerated;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.Lob;
import javax.persistence.ManyToOne;
import org.loom.annotation.validation.RequiredValidation;
import org.loom.annotation.validation.StringValidation;
/**
* This class uses one example of hibernate validations
* @author Ignacio Coloma
*/
@Entity
public class Customer {
public enum CreditType {
GOOD,
FAIR,
NEEDS_IMPROVEMENT,
POOR
}
@Id @GeneratedValue
private Integer id;
@Basic(optional = false)
@Column(length=40)
private String firstName;
@Column(length=80)
@RequiredValidation(on="save")
private String lastName;
@Basic(optional = false)
@Column(length=80)
private String idCard;
@StringValidation(mask=StringValidation.EMAIL_MASK)
private String email;
private boolean phoneSupport;
@StringValidation(minLength=5, maxLength=10)
private String password;
@Enumerated(EnumType.STRING)
private CreditType creditType = CreditType.FAIR;
@ManyToOne
@RequiredValidation(propertyPath="id")
private CustomerType customerType;
/** comment */
@Lob
@Basic(fetch=FetchType.LAZY)
@Column(length=80)
private String comments;
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getIdCard() {
return idCard;
}
public void setIdCard(String idCard) {
this.idCard = idCard;
}
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
public CreditType getCreditType() {
return creditType;
}
public void setCreditType(CreditType creditType) {
this.creditType = creditType;
}
public CustomerType getCustomerType() {
return customerType;
}
public void setCustomerType(CustomerType customerType) {
this.customerType = customerType;
}
public boolean isPhoneSupport() {
return phoneSupport;
}
public void setPhoneSupport(boolean phoneSupport) {
this.phoneSupport = phoneSupport;
}
public String getComments() {
return comments;
}
public void setComments(String comments) {
this.comments = comments;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
}
Class: CustomersAction.java
/*
* Copyright 2002-2006 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.loom.demo.action;
import java.math.BigDecimal;
import java.util.HashMap;
import java.util.Map;
import javax.ws.rs.QueryParam;
import org.loom.action.AbstractAction;
import org.loom.annotation.Event;
import org.loom.annotation.RetrieveEntity;
import org.loom.annotation.validation.NestedAnnotations;
import org.loom.annotation.validation.NumberValidation;
import org.loom.annotation.validation.RequiredValidation;
import org.loom.annotation.validation.StringValidation;
import org.loom.demo.model.Customer;
import org.loom.demo.model.CustomerType;
import org.loom.exception.LocaleAwareException;
import org.loom.exception.MissingRequiredPropertyException;
import org.loom.paged.PagedListCriteria;
import org.loom.paged.PagedListCriteriaFactory;
import org.loom.paged.PagedListData;
import org.loom.paged.PagedListDataFactory;
import org.loom.persistence.ExtendedEntityManager;
import org.loom.resolution.Resolution;
import org.loom.util.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
/**
* Example of:
*
* Pagination done in the web layer
* Validations indicated in the action class.
* Throwing locale-aware exceptions
*
* @author icoloma
*/
public class CustomersAction extends AbstractAction {
/** service class */
@Autowired
private ExtendedEntityManager transactionalService;
/** the paged list of customers */
private PagedListData<Customer> customers;
/**
* The instance that is being edited.
* This is an example of validations specified on the action class in addition of the model class
*/
@NestedAnnotations(on="save")
@StringValidation(propertyPath="lastName", maxLength=80, minLength=5, on="save")
@RetrieveEntity(on="edit")
private Customer customer;
/** example of a Map property */
@NumberValidation(precision=11, scale=2)
@RequiredValidation(on="save")
private Map<String, BigDecimal> prices = new HashMap<String, BigDecimal>();
/**
* Edit an existing customer
*/
public Resolution edit() {
return forward();
}
/**
* Example of returning a custom type (here, CustomerType) instead of Option
* to fill a <select> tag
*/
public Iterable<CustomerType> getCustomerTypes() {
return transactionalService.findAll(CustomerType.class);
}
/**
* Example of LocaleAwareThrowable-to-error conversion.
* If the Exception gets thrown, it will be displayed as an input validation error.
*/
public Resolution save(
@StringValidation(maxLength=10, on="save")
@QueryParam("confirmPassword")
String confirmPassword
) {
if (StringUtils.isEmpty(customer.getPassword())) {
throw new MissingRequiredPropertyException("customer.password");
}
if (!customer.getPassword().equals(confirmPassword)) {
throw new LocaleAwareException("The values of password and confirm password must be the same", "error.custom.equalsFailed").addTranslatedArg("property1", "password").addTranslatedArg("property2", "confirmPassword");
}
if (customer.getId() == null) {
if (!transactionalService.find("from Customer c where c.firstName=? and c.lastName=?", customer.getFirstName(), customer.getLastName()).isEmpty()) {
throw new LocaleAwareException("There is already a customer with name " + customer.getFirstName() + " " + customer.getLastName(), "error.custom.customerNameExists").addArg("customer", customer);
}
}
this.customer = transactionalService.merge(customer);
return forward("edit.jsp");
}
/**
* Example of manual conversion from List to PagedListData
* This is not recommended; if possible, pagination should be done by the database layer
* (see the example in MortgagesAction)
*/
@Event(defaultEvent=true)
public Resolution list() {
PagedListCriteria criteria = PagedListCriteriaFactory.create(getRequest());
criteria.setPageSize(5); // to showcase the pagination
customers = PagedListDataFactory.create(criteria, transactionalService.findAll(Customer.class));
return forward();
}
public PagedListData<Customer> getCustomers() {
return customers;
}
public Customer getCustomer() {
return customer;
}
public Map<String, BigDecimal> getPrices() {
return prices;
}
public void setCustomer(Customer customer) {
this.customer = customer;
}
}