JSF Converter in JBoss Seam

折腾了两天,终于在JBoss Seam中搞定了JSF Converter。

在这个程序中,产品(Product)和分类(Category)是多对多的关系,关系维护方为产品,在创建产品时,允许选择多个分类,因为Product.categories是一个List属性,同时产品选择<select />标签也是由从Action中查询出来的所有Category的List,所以在页面上,需要在页面渲染、用户提交后的category进行转换。

显示时,我们以Category.id为<option />的value值,而Category.title为label。

Entity如下(省略setter和getter):

Category.java

@Entity
@Table(name = "category")
public class Category extends BaseEntity {
 
	@Id
	@GeneratedValue
	@Column(name = "id", unique = true, nullable = false, length = 10)
	private Integer id;
 
	@Column(name = "title")
	@NotNull
	@Length(min = 4, max = 64, message = "{invalid.length}")
	private String title;
 
	@ManyToMany(mappedBy = "categories")
	private List<product> products = new ArrayList</product><product>();
}
</product>

Product.java

@Entity
@Table(name = "product")
public class Product extends BaseEntity {
 
	@Id
	@GeneratedValue
	@Column(name = "id", nullable = false, unique = true, length = 10)
	private Integer id;
 
	@Column(name = "title")
	@NotNull
	@Length(min = 4, max = 64)
	private String title;
 
	@Column(name = "price")
	@NotNull
	private Float price;
 
	@ManyToMany(cascade = { CascadeType.MERGE, CascadeType.REFRESH }, fetch = FetchType.LAZY)
	@JoinTable(name = "category_product", joinColumns = { @JoinColumn(name = "product_id", referencedColumnName = "id") }, inverseJoinColumns = { @JoinColumn(name = "category_id", referencedColumnName = "id") })
	private List<category> categories = new ArrayList</category><category>();
}
</category>

如果persistence.xml中,hibernate.hbm2ddl.auto的属性配置为create-drop,那么在JBoss启动时,这两个Entity会生成三张表,除了product和category外,还有一张关联表:category_product。

xhtml页面代码如下:

                <ui :define name="label">Category</ui>
                <h :selectManyListbox id="categories" value="#{productEditAction.product.categories}" converter="categoryConverter" >
                  <s :selectItems var="cat" value="#{productEditAction.categories}" label="#{cat.title}"></s>
                </h>

其中,#{productEditAction.categories}表示系统中所有的分类,是一个List<category>列表。

JSF Converter代码:

import javax.faces.component.UIComponent;
import javax.faces.context.FacesContext;
import javax.faces.convert.ConverterException;
 
import net.ymeng.studyseam.entity.Category;
import net.ymeng.studyseam.service.InventoryService;
 
import org.jboss.seam.annotations.In;
import org.jboss.seam.annotations.Name;
import org.jboss.seam.annotations.faces.Converter;
 
/**
 * @author yangtze
 * 
 */
@Name("categoryConverter")
@Converter(id = "categoryConverter")
public class CategoryConverter implements javax.faces.convert.Converter {
 
	@In(create = true, value = "inventoryServiceImpl")
	private InventoryService inventoryService;
 
	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * javax.faces.convert.Converter#getAsObject(javax.faces.context.FacesContext
	 * , javax.faces.component.UIComponent, java.lang.String)
	 */
	public Object getAsObject(FacesContext context, UIComponent component,
			String value) {
		if (value != null && !"".equals(value)) {
			Integer catId = Integer.valueOf(value);
			Category cat = inventoryService.findCategoryById(catId);
			return cat;
		}
 
		return null;
	}
 
	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * javax.faces.convert.Converter#getAsString(javax.faces.context.FacesContext
	 * , javax.faces.component.UIComponent, java.lang.Object)
	 */
	public String getAsString(FacesContext context, UIComponent component,
			Object value) {
		if (value instanceof Category) {
			return String.valueOf(((Category) value).getId());
		} else {
			throw new ConverterException("Unsupported valued! Value is: "
					+ value + "\tType is: " + value.getClass());
		}
	}
}

其中getAsString方法在页面显示时会自动调用,将传入的对象value转换为字符串输出,因为这里用作option值的是Category.id,所以我们在此方面中取出分类的id并返回。

而getAsObject方法是在用户提交时,将option的值转换为Integer,并从Service层中查找对应的Category实例、返回。

所以对于提交后的保存动作,我们就不需要再做任何处理,Product.categories中已经是转换好的List<Category>,直接persist/merge即可。

如果在转换类中使用@Converter注解,就不再需要在faces-config.xml中进行converter的配置了,Seam会自动帮你完成这个配置。

《JSF Converter in JBoss Seam》有3个想法

  1. 不错的示例,关于converter找了半小时的资料了,你这个例子最详细了

  2. 终于找到了,虽然知道hibernate中那种多对多的写法,在seam中想写却不知道怎么写,现在看见了,呵呵,谢谢了

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注