效果:
在添加图书页,有一个图书分类的下拉框,选择某分类后会自动刷新出子分类。
要点:
JSF有一个"bug":如果页面中包含了下拉框,则提交表单时,JSF会在应用请求值阶段就对下拉框选择的值进行验证(事实上应该在转换完毕后进行验证)。如果这个值不是可选的值之一,则会抛出校验失败的异常。所以
BookBean必须设置在SessionScoped上。
代码:
addBook.xhtml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:c="http://java.sun.com/jsp/jstl/core"
>
<h:head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<title>add Book</title>
</h:head>
<h:body>
<!-- 设置了表单,因此其中用到托管bean是是设置值 -->
<h:form id = "addBookForm">
<h:panelGrid columns="3">
<h:outputLabel value="图书名称:"></h:outputLabel>
<h:inputText id="bookName" value="#{bookBean.bookName}" required="true"></h:inputText>
<h:message for="bookName"></h:message>
<h:outputLabel value="图书书号:"></h:outputLabel>
<h:inputText id="bookNumber" value="#{bookBean.bookNumber}" required="true">
<f:validateRegex pattern="ISBN[0-9]{13}"></f:validateRegex>
</h:inputText>
<h:message for="bookNumber"></h:message>
<h:outputLabel value="作者:"></h:outputLabel>
<h:inputText id="author" value="#{bookBean.author}" required="true"
converter="authorConverter"></h:inputText>
<h:message for="author"></h:message>
<h:outputLabel value="出版时间:"></h:outputLabel>
<h:inputText id="publishDate" value="#{bookBean.publishDate}" required="true">
<f:convertDateTime pattern="yyyy-mm-dd"></f:convertDateTime>
</h:inputText>
<h:message for="publishDate"></h:message>
<h:outputLabel value="价格:">
</h:outputLabel>
<h:inputText id="price" value="#{bookBean.price}" required="true">
<f:convertNumber maxFractionDigits="1"
></f:convertNumber>
</h:inputText>
<h:message for="price"></h:message>
<h:outputLabel value="分类:"></h:outputLabel>
<h:selectOneListbox id="category" value = "#{bookBean.category}" size = "1"
valueChangeListener="#{bookControl.changeCategory}"
οnchange="submit()"
immediate="true"
>
<f:selectItem itemValue="0" itemLabel="请选择"></f:selectItem>
<f:selectItem itemValue="1" itemLabel="计算机"></f:selectItem>
<f:selectItem itemValue="2" itemLabel="文学"></f:selectItem>
<f:selectItem itemValue="3" itemLabel="管理"></f:selectItem>
<f:selectItem itemValue="4" itemLabel="其他"></f:selectItem>
</h:selectOneListbox>
<h:message for="category"></h:message>
<h:outputLabel value="子分类:"></h:outputLabel>
<h:selectOneListbox id="subCategory" value="#{bookBean.subCategory}"
size="1">
<c:forEach var="cat" items="#{bookBean.subCategories}" varStatus="catCount">
<f:selectItem itemValue="#{catCount.count}"
itemLabel="#{cat}"></f:selectItem>
</c:forEach>
</h:selectOneListbox>
<h:message for="subCategory"></h:message>
<h:commandButton value="添加" action="#{bookControl.add}"
></h:commandButton>
<h:commandButton value="取消" immediate="true"></h:commandButton>
</h:panelGrid>
</h:form>
</h:body>
</html>
BookBean.java
package cn.edu.jlu.pojo;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import javax.annotation.PostConstruct;
import javax.enterprise.context.RequestScoped;
import javax.enterprise.context.SessionScoped;
import javax.faces.bean.NoneScoped; //NoneScoped不行,
//因为拿到.xhtml传回的值并设置BookBean后就被删除
import javax.inject.Named;
import javax.faces.bean.ViewScoped;
@Named
@SessionScoped
public class BookBean implements Serializable{
/**
*
*/
private static final long serialVersionUID = 1L;
private String bookName;
private String bookNumber; //pk
private List<String> author;//多个作者
private Date publishDate;
private double price;
private int category = 0;
private int subCategory = 99;
private List<String> subCategories = new ArrayList<String>();
public String getBookName() {
return bookName;
}
public void setBookName(String bookName) {
System.out.println("?????????????");
this.bookName = bookName;
}
public String getBookNumber() {
return bookNumber;
}
public void setBookNumber(String bookNumber) {
this.bookNumber = bookNumber;
}
public List<String> getAuthor() {
return author;
}
public void setAuthor(List<String> author) {
this.author = author;
}
public Date getPublishDate() {
return publishDate;
}
public void setPublishDate(Date publishDate) {
this.publishDate = publishDate;
}
public double getPrice() {
return price;
}
public void setPrice(double price) {
this.price = price;
}
public int getCategory() {
return category;
}
public void setCategory(int category) {
this.category = category;
}
public int getSubCategory() {
return subCategory;
}
public void setSubCategory(int subCategory) {
this.subCategory = subCategory;
}
public List<String> getSubCategories() {
return subCategories;
}
public void setSubCategories(List<String> subCategories) {
this.subCategories = subCategories;
}
}
BookControl.java
package cn.edu.jlu.controller;
import java.io.Serializable;
import java.util.List;
import javax.annotation.PostConstruct;
import javax.enterprise.context.RequestScoped;
import javax.enterprise.context.SessionScoped;
import javax.faces.context.FacesContext;
import javax.faces.event.ActionEvent;
import javax.faces.event.ValueChangeEvent;
import javax.faces.model.SelectItem;
import javax.inject.Inject;
import javax.inject.Named;
import cn.edu.jlu.client.CountBeanClient;
import cn.edu.jlu.client.ListBeanClient;
import cn.edu.jlu.pojo.BookBean;
@Named
@RequestScoped
//SessionScoped的Bean需要支持钝化
public class BookControl implements Serializable{
/**
*
*/
private static final long serialVersionUID = -3508615784767089380L;
@Inject @Named("bookBean")
private BookBean bookBean;
private int count ;
@Inject @Named("bookBean")
BookBean book;
public void changeCategory(ValueChangeEvent e) {
//获取更改后的值
Integer category = (Integer)e.getNewValue();
//System.out.println("选择分类------------"+bookBean.getCategory()+"-->"+category);
//获取bookBean中的子菜单
List<String> sub = bookBean.getSubCategories();
sub.clear();
if(1 == category) {
bookBean.setCategory(1);
sub.add("软件工程");
sub.add("计算机网络");
sub.add("编程语言");
sub.add("其他");
} else if(2 == category) {
bookBean.setCategory(2);
sub.add("小说");
sub.add("散文");
sub.add("诗词");
sub.add("其他");
} else if(3 == category) {
bookBean.setCategory(3);
sub.add("行政管理");
sub.add("金融管理");
sub.add("经商管理");
sub.add("其他");
} else if(4 == category) {
bookBean.setCategory(4);
}
//System.out.println(sub);
}
public String add() {
if(bookBean.getPrice() != 0.0)
return "success";
return "fail";
}
public void confirmToAdd() {
System.out.println("confirmToAdd");
new ListBeanClient().add(bookBean);
}
@PostConstruct
public void sCount() {
count = new CountBeanClient().getCount();
}
public void setCount(int count) {
this.count = count;
}
public int getCount() {
return count;
}
}
作者属性的转换器,将输入的a,b,c转换成一个List
package cn.edu.jlu.biz;
import java.util.ArrayList;
import java.util.List;
import javax.faces.application.FacesMessage;
import javax.faces.component.UIComponent;
import javax.faces.context.FacesContext;
import javax.faces.convert.Converter;
import javax.faces.convert.ConverterException;
import javax.faces.convert.FacesConverter;
@FacesConverter("authorConverter")
public class AuthorConverter implements Converter{
@Override
public Object getAsObject(FacesContext arg0, UIComponent arg1, String arg2) {
//将String转为List arg2是获得的参数
//去掉空格
String ipt = arg2.replace(" ", "");
if(ipt.equals("")) {
FacesMessage message = new FacesMessage(
FacesMessage.SEVERITY_ERROR, "输入有误", "不可为空");
arg0.addMessage("author", message);
throw new ConverterException(message);
}
List<String> result = new ArrayList<String>();
//
String[] authors = ipt.split(",");
if(authors.length == 0) {
FacesMessage message = new FacesMessage(
FacesMessage.SEVERITY_ERROR, "输入有误", "多作者请用逗号间隔");
arg0.addMessage("author", message);
throw new ConverterException(message);
}
for (String s : authors) {
result.add(s);
}
return result;
}
@Override
public String getAsString(FacesContext arg0, UIComponent arg1, Object arg2) {
//将List转为String
List<String> authors = (ArrayList<String>)arg2;
StringBuilder sb = new StringBuilder();
for (String i: authors) {
sb.append(i + ",");
}
//去掉最后一个,
String result = sb.toString();
int index = result.lastIndexOf(",");
result = result.substring(0, index);
return result;
}
}