了解SEAM框架
1. 阅读SEAM的官方文档
基本完成。
2. 搭建运行Hibernate、TOMCAT6环境下的DEMO:seam-hotel-booking
在此步骤上,需要在tomcat/lib中导入hsql包,同时在tomcat/conf/server.xml中放入
<Contex path="/seam" reloadable="false" docBase="D:\workspace\tomcatTest\WebContent" workDir="D:\workspace\tomcatTest\work" />
<Resource name="jdbc/TestDB" auth="Container" type="javax.sql.DataSource"
maxActive="100" maxIdle="30" maxWait="10000"
username="root" driverClassName="com.mysql.jdbc.Driver"
url="jdbc:mysql://127.0.0.1:3306/test"/>
同时需要在没有代理的浏览器中测试程序。
3. 分析DEMO的框架及技术结构,编写一份文档
通过设计user,hotel,booking表来持久化数据,通过seam组件调用持久层,实现一些DAO层,再通过调用dao层的接口来实现逻辑和数据的传输等。Hiernate实现持久层,seam实现模型层,pages.xml实现控制层 jsf页面实现表示层。
心得:这个部分给我留下整体的概念,让我对这个工程运行有了一定的了解。
SEAM框架学习
1. 根据上一题的DEMO,进行如下修改
A. 完善分页功能,修改查询结果页面,增加上一页,下一页,到指定页码,当前页位置等功能
在实现这个功能时,好好研究了所有的程序代码,对大部分都有了一定的理解后,我开始理解seam组件的功能。逐渐掌握seam框架的原理,这个功能主要注意修改时要在怎么实现数据同步。
B. 完善酒店的属性信息,如增加属性:房间数、等级(五星、四星……),并在酒店信息里显示完整信息
在hotel实体中添加两个属性,然后自动实现表的属性的增加。
C. 在查询结果页面,ACTION位置,增加预订酒店超链接
这部分遇到一个问题,就是seam@begin的作用 它注释标识一个启动长运行对话的方法,在一个方法前没放@begin的时候,seam就不能跨越http请求来维持这个组件的状态。同时要在pages.xml中写页面导向。
D. 增加酒店信息录入界面,只有指定角色或用户才能显示和使用
增加link view= rendered 来判断是否显示录入功能
在录入时要persist(hotel);来录入。
E. 把网站进行国际化改造
对网站进行国际化,利用el表达式来做。
F. 把数据库改为MySQL
这个我做麻烦了,其实不用修改tomcat的配置文档,只需要修改hibernate.cfg.xml就哦了。
心得:这部分学了很长时间,但感觉学到很多以前没有接触到的知识,让我对整体框架有了清楚的认识和掌握。
//$Id: User.java 6987 2007-12-23 19:53:07Z pmuir $
package org.jboss.seam.example.hibernate;
import static org.jboss.seam.ScopeType.SESSION;
import java.io.Serializable;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;
import org.hibernate.validator.Length;
import org.hibernate.validator.NotNull;
import org.hibernate.validator.Pattern;
import org.jboss.seam.annotations.Name;
import org.jboss.seam.annotations.Scope;
@Entity
@Name("user")
@Scope(SESSION)
@Table(name="Customer")
public class User implements Serializable
{
private String username;
private String password;
private String name;
public User(String name, String password, String username)
{
this.name = name;
this.password = password;
this.username = username;
}
public User() {}
@NotNull
@Length(max=100)
public String getName()
{
return name;
}
public void setName(String name)
{
this.name = name;
}
@NotNull
@Length(min=5, max=15)
public String getPassword()
{
return password;
}
public void setPassword(String password)
{
this.password = password;
}
@Id
@Length(min=5, max=15)
@Pattern(regex="^\\w*$", message="not a valid username")
public String getUsername()
{
return username;
}
public void setUsername(String username)
{
this.username = username;
}
@Override
public String toString()
{
return "User(" + username + ")";
}
}
package org.jboss.seam.example.hibernate;
import static org.jboss.seam.ScopeType.EVENT;
import java.util.List;
import org.hibernate.Session;
import org.jboss.seam.annotations.In;
import org.jboss.seam.annotations.Name;
import org.jboss.seam.annotations.Scope;
import org.jboss.seam.faces.FacesMessages;
@Scope(EVENT)
@Name("register1")
public class RegisterHotelAction {
@In
private Hotel hotel;
@In
private Session bookingDatabase;
@In
private FacesMessages facesMessages;
private boolean registered;
public void register1() {
List existing = bookingDatabase
.createQuery(
"select u.name from Hotel u where u.name=#{hotel.name}")
.list();
if (existing.size() == 0) {
bookingDatabase.persist(hotel);
facesMessages
.add("Successfully registered as #{hotel.name}");
registered = true;
} else {
facesMessages.addToControl("name",
"Hotel #{hotel.name} already exists");
}
}
public void invalid() {
facesMessages.add("Please try again");
}
public boolean isRegistered() {
return registered;
}
}
<!DOCTYPE composition PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<ui:composition 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:s="http://jboss.com/products/seam/taglib"
xmlns:a="http://richfaces.org/a4j"
template="template.xhtml">
<!-- content -->
<ui:define name="content">
<div class="section">
<h:form id="main">
<span class="errors">
<h:messages globalOnly="true"/>
</span>
<h:outputText value="#{messages['Search Hotels']}"/>
<fieldset>
<h:inputText id="searchString" value="#{hotelSearch.searchString}" style="width: 165px;">
<a:support event="onkeyup" actionListener="#{hotelSearch.find}" reRender="searchResults" />
</h:inputText>
 
<a:commandButton id="findHotels" value="#{messages['Find Hotels']}" action="#{hotelSearch.find}" reRender="searchResults"/>
 
<a:status>
<f:facet name="start">
<h:graphicImage value="/img/spinner.gif"/>
</f:facet>
</a:status>
<br/>
<h:outputText value="#{messages['Maximum results']}"/> 
<h:selectOneMenu value="#{hotelSearch.pageSize}" id="pageSize">
<f:selectItem itemLabel="5" itemValue="5"/>
<f:selectItem itemLabel="10" itemValue="10"/>
<f:selectItem itemLabel="20" itemValue="20"/>
</h:selectOneMenu>
</fieldset>
</h:form>
</div>
<a:outputPanel id="searchResults">
<div class="section">
<s:link value="进入录入界面" view="/input.xhtml" rendered="#{identity.username.equals(identity.password)}"/>
<h:outputText value="No Hotels Found" rendered="#{hotels != null and hotels.rowCount==0}"/>
<h:dataTable id="hotels" value="#{hotels}" var="hot" rendered="#{hotels.rowCount>0}">
<h:column>
<f:facet name="header">#{messages['Name']}</f:facet>
#{hot.name}
</h:column>
<h:column>
<f:facet name="header">#{messages['Address']}</f:facet>
#{hot.address}
</h:column>
<h:column>
<f:facet name="header">#{messages['City']}, #{messages['State']}</f:facet>
#{hot.city}, #{hot.state}, #{hot.country}
</h:column>
<h:column>
<f:facet name="header">#{messages['zip']}</f:facet>
#{hot.zip}
</h:column>
<h:column>
<f:facet name="header">#{messages['Action']}</f:facet>
<s:link id="viewHotel" value="View Hotel" action="#{hotelBooking.selectHotel(hot)}"/>
</h:column>
<h:column>
<f:facet name="header">#{messages['Book']}</f:facet>
<s:link id="bookHotel" value="Book Hotel" action="#{hotelBooking.bookHotel(hot)}"/>
</h:column>
</h:dataTable>
<s:link value="上一页" action="#{hotelSearch.lastPage}" rendered="#{hotelSearch.lastPageAvailable}"/> 
<h:column>当前在第#{hotelSearch.getPage()}页</h:column> 
<s:link value="下一页" action="#{hotelSearch.nextPage}" rendered="#{hotelSearch.nextPageAvailable}"/> 
<h:form id="go"> <h:inputText id="searchPage" value="#{hotelSearch.page}" style="width: 15px;">
<a:support event="onkeyup" actionListener="#{hotelSearch.go}" reRender="searchResults" />
</h:inputText>
 
<a:commandButton id="findPage" value="#{messages['go']}" action="#{hotelSearch.go}" reRender="searchResults"/>
 
</h:form>
</div>
</a:outputPanel>
<div class="section">
<h:outputText value="#{messages['Current Hotel Bookings']}"/> 
</div>
<div class="section">
<h:form id="bookings">
<h:outputText value="#{messages['No Bookings Found']}" rendered="#{bookings.rowCount==0}"/>
<h:dataTable id="bookings" value="#{bookings}" var="book" rendered="#{bookings.rowCount>0}">
<h:column>
<f:facet name="header">#{messages['Name']}</f:facet>
#{book.hotel.name}
</h:column>
<h:column>
<f:facet name="header">#{messages['Address']}</f:facet>
#{book.hotel.address}
</h:column>
<h:column>
<f:facet name="header">#{messages['City']}, #{messages['State']}</f:facet>
#{book.hotel.city}, #{book.hotel.state}
</h:column>
<h:column>
<f:facet name="header">#{messages['Check in date']}</f:facet>
<h:outputText value="#{book.checkinDate}"/>
</h:column>
<h:column>
<f:facet name="header">#{messages['Check out date']}</f:facet>
<h:outputText value="#{book.checkoutDate}"/>
</h:column>
<h:column>
<f:facet name="header">#{messages['Confirmation number']}</f:facet>
#{book.id}
</h:column>
<h:column>
<f:facet name="header">#{messages['Action']}</f:facet>
<h:commandLink id="cancel" value="Cancel" action="#{bookingList.cancel}"/>
</h:column>
</h:dataTable>
</h:form>
</div>
</ui:define>
<!-- sidebar -->
<ui:define name="sidebar">
</ui:define>
</ui:composition>