本节将介绍如何通过OperaMasks Studio快速开发一个基于Hibernate框架和Spring框架的多表CRUD(Create, Read, Update, Delete)应用

Step By Step

2.3.2. Step By Step

注:下列步骤中,如无特殊说明,均采用默认选项。

  1. 创建数据库表。此示范需要两个表,分别是费用表FEE及费用明细表FEE_DETAIL。它们之间存在一对多的主外键关系,数据库使用SQL Server 2000,创建表的SQL脚本如下

    create table FEE (
        id int primary key, 
        topic varchar(200),
        userName varchar(100),
        applyDate datetime
    );
    
    create table FEE_DETAIL (
        id int primary key, 
        name varchar(100),
        amount float,
        feeId int references FEE(id)
    );
    
    delete from FEE_DETAIL;
    delete from FEE;
    
    insert into FEE values(1, '深圳至北京差旅费', 'Kevin','2008-6-1');
    insert into FEE values(2, '部门活动经费', 'Kevin', '2008-10-20');
    
    insert into FEE_DETAIL values (1, '深圳至北京机票', 1000, 1);
    insert into FEE_DETAIL values (2, '北京至深圳机票', 1500, 1);
    insert into FEE_DETAIL values (3, '吃饭', 800, 2);
    insert into FEE_DETAIL values (4, '打保龄球', 600, 2) ;
  2. 创建Apusic工程,工程名为:AdvanceCRUD。

  3. 创建web模块。将其IoVC默认命名空间设置为 com.demo.beans。

    • 选择工程,右键->新建->Web模块

    • 配置Web模块的基本信息,保持默认即可

      图 2.1. 配置Web模块基本信息


    • 配置OperaMasks支持及View类型,注意此处将IoVC默认命名空间设置为 com.demo.beans,其他保持默认

      图 2.2. 配置Web应用细节


  4. 添加Hibernate支持。

    • 选中工程,右键->Apusic Tools->添加工程持久属性,弹出向导。

      图 2.3. 打开添加Hibernate支持向导


    • 持久单元类型选择“Hibernate”,如下

      图 2.4. 添加Hibernate支持


    • 选择Hibernate配置文件的指定方式和数据源。

      图 2.5. 选择配位文件及指定数据源


  5. 添加Spring支持。

    • 选中工程,右键->Apusic Tools->添加Spring支持

      图 2.6. 打开添加Spring支持向导


    • 选择Spring版本及需要的库,保持默认即可。

      图 2.7. 选择Spring版本及类库


    • 指定Spring配置文件生成方式,并导入Hibernate配置文件,保持默认即可。

      图 2.8. Spring配置文件生成方式


  6. 在web模块的web/src目录下创建两个包,分别为com.demo.entities、com.demo.services,用于存放实体类、业务实现类。

    图 2.9. 新建包


  7. 从数据库反向生成实体。

    • 选中刚建立的包com.demo.entities,右键->Apusic Tools->打开模型视图。

      图 2.10. 打开模型视图


    • 在模型视图的编辑区空白处点击右键->增强功能->数据库至代码同步。

      图 2.11. 数据库至代码同步


    • 在弹出的对话框中选择FEE和FEE_DETAIL表,点击确定。

      图 2.12. 数据库反向


    • 可看到生成的实体类,如下

      图 2.13. 生成的实体类


      生成的Fee.java的代码如下

      package com.demo.entities;
      
      import java.util.Date;
      import java.util.HashSet;
      import java.util.Set;
      import javax.persistence.CascadeType;
      import javax.persistence.Column;
      import javax.persistence.Entity;
      import javax.persistence.FetchType;
      import javax.persistence.Id;
      import javax.persistence.OneToMany;
      import javax.persistence.Table;
      import javax.persistence.Temporal;
      import javax.persistence.TemporalType;
      
      /**
       * Fee generated by Apusic Studio
       */
      @Entity
      @Table(name = "FEE", schema = "dbo", catalog = "CRUD")
      public class Fee implements java.io.Serializable {
      	private int id;
      
      	private String topic;
      
      	private String userName;
      
      	private Date applyDate;
      
      	private Set<FeeDetail> feeDetails = new HashSet<FeeDetail>(0);
      
      	public Fee() {
      	}
      
      	public Fee(int id) {
      		this.id = id;
      	}
      
      	public Fee(int id, String topic, String userName, Date applyDate,
      			Set<FeeDetail> feeDetails) {
      		this.id = id;
      		this.topic = topic;
      		this.userName = userName;
      		this.applyDate = applyDate;
      		this.feeDetails = feeDetails;
      	}
      
      	@Id
      	@Column(name = "id", unique = true, nullable = false)
      	public int getId() {
      		return this.id;
      	}
      
      	public void setId(int id) {
      		this.id = id;
      	}
      
      	@Column(name = "topic", length = 200)
      	public String getTopic() {
      		return this.topic;
      	}
      
      	public void setTopic(String topic) {
      		this.topic = topic;
      	}
      
      	@Column(name = "userName", length = 100)
      	public String getUserName() {
      		return this.userName;
      	}
      
      	public void setUserName(String userName) {
      		this.userName = userName;
      	}
      
      	@Temporal(TemporalType.TIMESTAMP)
      	@Column(name = "applyDate", length = 23)
      	public Date getApplyDate() {
      		return this.applyDate;
      	}
      
      	public void setApplyDate(Date applyDate) {
      		this.applyDate = applyDate;
      	}
      
      	@OneToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER, mappedBy = "fee")
      	public Set<FeeDetail> getFeeDetails() {
      		return this.feeDetails;
      	}
      
      	public void setFeeDetails(Set<FeeDetail> feeDetails) {
      		this.feeDetails = feeDetails;
      	}
      }
      

      生成的FeeDetail.java代码如下

      package com.demo.entities;
      
      import javax.persistence.Column;
      import javax.persistence.Entity;
      import javax.persistence.FetchType;
      import javax.persistence.Id;
      import javax.persistence.JoinColumn;
      import javax.persistence.ManyToOne;
      import javax.persistence.Table;
      
      /**
       * FeeDetail generated by Apusic Studio
       */
      @Entity
      @Table(name = "FEE_DETAIL", schema = "dbo", catalog = "CRUD")
      public class FeeDetail implements java.io.Serializable {
      	private int id;
      
      	private Fee fee;
      
      	private String name;
      
      	private Double amount;
      
      	public FeeDetail() {
      	}
      
      	public FeeDetail(int id) {
      		this.id = id;
      	}
      
      	public FeeDetail(int id, Fee fee, String name, Double amount) {
      		this.id = id;
      		this.fee = fee;
      		this.name = name;
      		this.amount = amount;
      	}
      
      	@Id
      	@Column(name = "id", unique = true, nullable = false)
      	public int getId() {
      		return this.id;
      	}
      
      	public void setId(int id) {
      		this.id = id;
      	}
      
      	@ManyToOne(fetch = FetchType.EAGER)
      	@JoinColumn(name = "feeId")
      	public Fee getFee() {
      		return this.fee;
      	}
      
      	public void setFee(Fee fee) {
      		this.fee = fee;
      	}
      
      	@Column(name = "name", length = 100)
      	public String getName() {
      		return this.name;
      	}
      
      	public void setName(String name) {
      		this.name = name;
      	}
      
      	@Column(name = "amount", precision = 53, scale = 0)
      	public Double getAmount() {
      		return this.amount;
      	}
      
      	public void setAmount(Double amount) {
      		this.amount = amount;
      	}
      }
  8. 映射实体。

    • 双击打开Hibernate配置文件,并切换到“映射”标签页。

      图 2.14. 打开Hibernate Cfg编辑器


    • 选中Fee.java文件及FeeDetail.java文件,将其拖拽到编辑器配置映射区域,如下,

      图 2.15. 添加映射


      此处也可以点击“添加”按钮查找并添加映射文件。

    • 点击Save按钮,或者Ctrl+s保存配置文件,并点击“同步”按钮进行同步。

      图 2.16. Hibernate配置文件同步


  9. 生成Spring DAO业务实现。

    • 打开模型视图,在编辑区空白处点击右键->增强功能->生成业务实现

      图 2.17. 打开生成业务实现向导


      或是选中包com.demo.entities,右键->Apusic Tools->生成业务实现

      图 2.18. 打开生成业务实现向导


    • 选择需要生成的业务实现的类型,此处选择Spring Service实现,依照默认即可,点击下一步

      图 2.19. 选择生成Spring DAO实现


    • 选择实体类及输出包,如下

      图 2.20. 选择实体类及输出包


      此处指定输出包为先前创建的 com.demo.services包,如下

      图 2.21. 选择输出包


    • 点击“完成”,生成业务实现接口与类,如下

      图 2.22. 生成的业务实现接口与类


  10. 创建Faces页面及其托管Bean。

    • 创建用于显示主界面的Faces页面,将其命名为fee.xhtml,步骤如下

      1. 在web节点右键->新建->Faces页面

        图 2.23. 新建Faces页面


      2. 输入文件名为fee,如下

        图 2.24. 设置Faces文件名及路径


      3. 选择Faces模板,保持默认即可

        图 2.25. 选择Faces模板


      4. 选择生成托管Bean,同样保持默认

        图 2.26. 布局模板设置


      5. 将fee.xhtml的内容设置为

        <?xml version="1.0" encoding="UTF-8"?>
        <!DOCTYPE HTML PUBLIC "" "">
        <f:view xmlns="http://www.w3.org/1999/xhtml" xmlns:f="http://java.sun.com/jsf/core"
        	xmlns:w="http://www.apusic.com/jsf/widget" xmlns:layout="http://www.apusic.com/jsf/layout"
        	xmlns:h="http://java.sun.com/jsf/html" xmlns:ajax="http://www.apusic.com/jsf/ajax"
        	renderKitId="AJAX">
        	<w:head>
        		<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
        	</w:head>
        	<w:page title="Fee CRUD">
        		<w:form>
        			<w:dataGrid paged="true" rows="10"
        			 toolBarPosition="both" height="209" id="grid">
        				<w:outputColumn id="id"></w:outputColumn>
        				<w:outputColumn id="topic" header="主题">
        				</w:outputColumn>
        				<w:outputColumn id="userName" header="用户名">
        				</w:outputColumn>
        				<w:outputColumn id="applyDate" header="申请时间">
        				</w:outputColumn>
        				<w:toolBar target="grid">				
        					<w:button id="create" value="添加"/>
        					<w:button id="modify" value="更改"/>
        					<w:button id="remove" value="删除"/>
        					<w:button id="refresh" value="刷新"/>
        				</w:toolBar>
        				<w:pagingToolbar target="grid"/>		
        			</w:dataGrid>
        		</w:form>
        		<layout:window width="600" height="430" id="dialog" resizable="true">
        			<ajax:updater url="feeEdit.xhtml"
        			 style="width: 100%; height: 100%"></ajax:updater>
        		</layout:window>
        	</w:page>
        </f:view>
      6. 将其托管Bean类--包com.demo.beans下的FeeBean类的内容改为

        package com.demo.beans;
        
        import java.io.Serializable;
        import java.util.List;
        
        import org.operamasks.faces.annotation.Action;
        import org.operamasks.faces.annotation.Bind;
        import org.operamasks.faces.annotation.DataModel;
        import org.operamasks.faces.annotation.ManagedBean;
        import org.operamasks.faces.annotation.ManagedBeanScope;
        import org.operamasks.faces.annotation.ManagedProperty;
        import org.operamasks.faces.component.grid.impl.UIDataGrid;
        import org.operamasks.faces.component.layout.impl.UIWindow;
        
        import com.demo.entities.Fee;
        import com.demo.services.IFeeService;
        
        /** 
         * This managed bean is generated automatically
         */
        @ManagedBean(name="feeBean", scope=ManagedBeanScope.SESSION)
        public class FeeBean implements Serializable {
        
        	@Bind
        	private UIDataGrid grid;
        	
        	@ManagedProperty("#{feeService}")
        	private IFeeService service;
        
        	@ManagedProperty("#{feeEditBean}")
        	private FeeEditBean editBean;
        	
        	@Bind(id="dialog", attribute="binding")
        	private UIWindow dialog;
        	
        	public UIDataGrid getGrid() {
        		return grid;
        	}
        
        	public void setGrid(UIDataGrid grid) {
        		this.grid = grid;
        	}
        
        	public UIWindow getDialog() {
        		return dialog;
        	}
        
        	public void setDialog(UIWindow dialog) {
        		this.dialog = dialog;
        	}
        
        	@Action(id="create")
        	public void create(){
        		editBean.setFeeBean(this);
        		editBean.shouldCreate();
        		dialog.show();
        	}
        
        	@Action(id="modify")
        	public void modify(){
        		Object[] values = grid.getSelectedValues();
        		if(values == null || values.length ==0) {
        			return;
        		}
        		Fee instane = (Fee) values[0];
        		editBean.setFeeBean(this);
        		editBean.shouldUpdate(instane);
        		editBean.getDetailGrid().reload();
        		dialog.show();
        	}
        
        	@Action(id="remove")
        	public void remove(){
        		Object[] values = grid.getSelectedValues();
        		if(values == null || values.length ==0) {
        			return;
        		}
        		Fee instane = (Fee) values[0];
        		service.remove(instane);
        		grid.reload();
        	}
        
        	@Action(id="refresh")
        	public void refresh(){
        		grid.reload();
        	}
        	
        	@Action(id="grid", event="ondblclick")
        	public void grid_dblclick() {
        		modify();
        	}
        	
        	@DataModel(id="grid")
        	private List<Fee> getGridValues(){				
        		return service.findAll();
        	}
        }

        此时编译FeeBean类会报告出错,暂时无须理睬。

    • 类似上述操作,创建Faces页面,命名为feeEdit.xhtml,内容为

      <?xml version="1.0" encoding="UTF-8"?>
      <!DOCTYPE HTML PUBLIC "" "">
      <f:view xmlns="http://www.w3.org/1999/xhtml" xmlns:f="http://java.sun.com/jsf/core"
      	xmlns:w="http://www.apusic.com/jsf/widget" xmlns:layout="http://www.apusic.com/jsf/layout"
      	xmlns:h="http://java.sun.com/jsf/html" xmlns:ajax="http://www.apusic.com/jsf/ajax"
      	renderKitId="AJAX">
      	<w:head>
      		<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
      	</w:head>
      	<w:page title="Fee Edit">
      		<w:form>
      			<div align="center">
      			<layout:panelGrid columns="2">
      				<layout:cell colspan="1" rowspan="1">
      					<h:outputLabel for="id"></h:outputLabel>
      				</layout:cell>
      				<layout:cell colspan="1" rowspan="1">
      					<w:numberField id="id"></w:numberField> 
      				</layout:cell>
      				<layout:cell colspan="1" rowspan="1">
      					<h:outputLabel for="topic" value="主题">
      					</h:outputLabel>
      				</layout:cell>
      				<layout:cell colspan="1" rowspan="1">
      					<w:textField id="topic"></w:textField> 
      				</layout:cell>
      				<layout:cell colspan="1" rowspan="1">
      					<h:outputLabel for="userName" value="用户名">
      					</h:outputLabel>
      				</layout:cell>
      				<layout:cell colspan="1" rowspan="1">
      					<w:textField id="userName"></w:textField> 
      				</layout:cell>
      				<layout:cell colspan="1" rowspan="1">
      					<h:outputLabel for="applyDate" value="申请日期">
      					</h:outputLabel>
      				</layout:cell>
      				<layout:cell colspan="1" rowspan="1">
      					<w:dateField id="applyDate"/> 
      				</layout:cell>
      			</layout:panelGrid>
      			</div>
      			<w:editDataGrid paged="true" rows="10"
      			 id="detailGrid" height="200" toolBarPosition="both">
      			    <w:outputColumn id="id">
      					<w:numberField id="idEdit" allowBlank="true" />
      				</w:outputColumn>
      				<w:outputColumn id="name" header="名称">
      					<w:textField id="nameEdit" allowBlank="true" />
      				</w:outputColumn>
      				<w:outputColumn id="amount" header="账目">
      					<w:numberField id="amountEdit" allowBlank="true" />
      				</w:outputColumn>
      				<w:toolBar target="detailGrid">
      					<w:button id="addDetail" value="添加明细"/>
      					<w:button id="deleteDetail" value="删除明细"/>
      				</w:toolBar>
      				<w:pagingToolbar target="detailGrid" />
      			</w:editDataGrid>
      			<div style="position:absolute; bottom:0px;right:5px;z-index:0">
      			<layout:panelGrid columns="2">
      				<w:button id="save" value="保存"/>
      				<w:button id="cancel" value="取消"/>
      			</layout:panelGrid>
      			</div>
      		</w:form>
      	</w:page>
      </f:view>

      将其托管Bean--FeeEditBean的内容设置为

      package com.demo.beans;
      
      import java.io.Serializable;
      import java.util.ArrayList;
      import java.util.Date;
      import java.util.List;
      
      import org.operamasks.faces.annotation.Action;
      import org.operamasks.faces.annotation.Bind;
      import org.operamasks.faces.annotation.DataModel;
      import org.operamasks.faces.annotation.ManagedBean;
      import org.operamasks.faces.annotation.ManagedBeanScope;
      import org.operamasks.faces.annotation.ManagedProperty;
      import org.operamasks.faces.component.grid.impl.UIEditDataGrid;
      
      import com.demo.entities.Fee;
      import com.demo.entities.FeeDetail;
      import com.demo.services.IFeeDetailService;
      import com.demo.services.IFeeService;
      
      
      /**
       * This managed bean is generated automatically
       */
      @ManagedBean(name = "feeEditBean", scope = ManagedBeanScope.SESSION)
      public class FeeEditBean implements Serializable {
      
      	/**
      	 * Inject the 'HEADER' service
      	 */
      	@ManagedProperty("#{feeService}")
      	private IFeeService service;
      	
      	/**
      	 * Inject the 'DETAIL' service
      	 */
      	@ManagedProperty("#{feeDetailService}")
      	private IFeeDetailService detailService;
      	
      	/**
      	 * the updated object handler
      	 */
      	private Fee updatedInstance = null;
      
      	/**
      	 * the 'HEADER' ManagedBean
      	 */
      	private FeeBean instance;	
      	
      	/**
      	 * the 'HEADER' property
      	 */
      	@Bind(id = "id", attribute = "value")
      	private int id;
      	/**
      	 * the 'HEADER' property
      	 */
      	@Bind(id = "topic", attribute = "value")
      	private String topic;
      	/**
      	 * the 'HEADER' property
      	 */
      	@Bind(id = "userName", attribute = "value")
      	private String userName;
      	/**
      	 * the 'HEADER' property
      	 */
      	@Bind(id = "applyDate", attribute = "value")
      	private Date applyDate;
      	
      	/**
      	 * the handler of the detail datagrid
      	 */
      	@Bind(id = "detailGrid", attribute = "binding")
      	private UIEditDataGrid detailGrid;
      
      	/**
      	 * the added data of detail datagrid
      	 */
      	@Bind(id = "detailGrid", attribute = "addedData")
      	private FeeDetail[] addedData;
      
      	/**
      	 * the modified data of detail datagrid
      	 */
      	@Bind(id = "detailGrid", attribute = "modifiedData")
      	private FeeDetail[] modifiedData;
      
      	/**
      	 * the removed data of detail datagrid
      	 */
      	@Bind(id = "detailGrid", attribute = "removedData")
      	private FeeDetail[] removedData;
      
      	/**
      	 * the type of the detail datagrid
      	 */
      	@Bind(id = "detailGrid", attribute = "bindBean")
      	private Class detailBindBean = FeeDetail.class;
      
      	@Action(id = "save")
      	public void save() {
      		Fee obj = null;
      		if (updatedInstance != null) {
      			obj =  updatedInstance;			
      		} else {
      			obj = new Fee();			
      		}
      		obj.setId (id);
      		obj.setTopic (topic);
      		obj.setUserName (userName);
      		obj.setApplyDate (applyDate);
      		if(updatedInstance != null) {
      			service.modify(obj);
      		}
      		else {
      			service.create(obj);
      		}
      		if (addedData != null) {
      			for (FeeDetail detail : addedData) {				
      				detail.setFee(obj);
      				detailService.create(detail);
      			}
      		}
      		if (modifiedData != null) {
      			for (FeeDetail detail : modifiedData) {
      				detail.setFee(obj);
      				detailService.modify(detail);
      			}
      		}
      		if (removedData != null) {
      			for (FeeDetail detail : removedData) {
      				detail.setFee(obj);
      				detailService.remove(detail);
      			}
      		}
      		instance.getDialog().close();
      		instance.getGrid().reload();		
      	}
      
      	@Action(id = "cancel")
      	public void cancel() {
      		instance.getDialog().close();
      	}
      
      	public void shouldCreate() {
      		this.updatedInstance = null;
      		this.id = 0;
      		this.topic = null;
      		this.userName = null;
      		this.applyDate = null;
      		this.detailGrid.reload();
      	}
      
      	public void shouldUpdate(Fee instance) {
      		if (instance != null) {
      			this.updatedInstance = instance;
      			this.id = instance.getId();
      			this.topic = instance.getTopic();
      			this.userName = instance.getUserName();
      			this.applyDate = instance.getApplyDate();
      			this.detailGrid.reload();
      		}
      	}
      
      	public FeeBean getFeeBean() {
      		return instance;
      	}
      
      	public void setFeeBean(FeeBean instance) {
      		this.instance = instance;
      	}
      
      	public UIEditDataGrid getDetailGrid() {
      		return detailGrid;
      	}
      
      	public void setDetailGrid(UIEditDataGrid detailGrid) {
      		this.detailGrid = detailGrid;
      	}
      
      	@DataModel(id = "detailGrid")
      	private List<FeeDetail> getDetailGridValues() {		
      		if (updatedInstance != null) {	
      			return new ArrayList<FeeDetail>(updatedInstance.getFeeDetails());
      		}
      		return new ArrayList<FeeDetail>();
      	}
      
      	@Action(id = "addDetail")
      	public void addDetail() {
      		detailGrid.appendRow();
      	}
      
      	@Action(id = "deleteDetail")
      	public void deleteDetail() {
      		detailGrid.remove();
      	}
      }
  11. 在Apusic上部署。

    在fee.xhtml上点击右键->运行方式->在Apusic服务器上运行

    图 2.27. 部署运行应用


  12. 查看结果。

    图 2.28. 运行结果


[下一页]