`
happylo
  • 浏览: 47375 次
  • 性别: Icon_minigender_1
  • 来自: 长沙
社区版块
存档分类
最新评论

基于Seam框架关联对象选择

阅读更多

[原创于:http://happydev.iteye.com]


实现对象选择可以直接通过下拉选择框的方式来选择,但这种选择不适合数据量较大的对象选择。

而在企业的Web开发中,经常会用到对关联对象的单选或多选,而关联对象的数据量往往不是下拉选择框可以展现的。

本文提出了一个较为通用的关联对象选择方案。


一、一个较为通用的关联对象选择方案要解决的主要问题

  1. 可能是单选,也可能会是多选;
  2. 将对象进行“可选择对象”的封装,以支持是否选中状态的维护;
  3. 待选对象的数据查询;
  4. 选择时表现层界面viewId的配置;
  5. 选择后返回的viewId的配置;


二、基础框架设计

/**
 * 可选择对象封装模板
 * @author happydev
 *
 * @param <T>
 */
public class SelectableItem <T>{
	public SelectableItem(boolean selected, Object id, String itemInfo, T item){
		this.selected = selected;
		this.id = id;
		this.itemInfo = itemInfo;
		this.item = item;
	}
	/**
	 * 是否已被选择
	 */
	private boolean selected = false;
	
	public boolean isSelected() {
		return selected;
	}

	public void setSelected(boolean selected) {
		this.selected = selected;
	}
	private Object id;
	
	private String itemInfo;
	
	private T item;

	public Object getId() {
		return id;
	}

	public void setId(Object id) {
		this.id = id;
	}

	public String getItemInfo() {
		return itemInfo;
	}

	public void setItemInfo(String itemInfo) {
		this.itemInfo = itemInfo;
	}

	public T getItem() {
		return item;
	}

	public void setItem(T item) {
		this.item = item;
	}

}

/**
 * 对象选择基础封装模板类
 * @author happydev
 *
 * @param <T>
 */
public abstract class BaseSelector<T> {
	@In
	EntityManager entityManager;
	
	private String ret;
	protected String selIds;
	private boolean submited = false;
	private boolean selectOne = false;
	
	/**
	 * 选择复选框ajax事件,处理选中或取消操作
	 * @param item
	 */
	public void onChange(SelectableItem<T> item){
		if (selectOne && item.isSelected()){
			//如果是单选,则要将已选中的其它项取消
			for (SelectableItem<T> t : selectableItems){
				if (t.isSelected() && t != item){
					t.setSelected(false);
				}
			}
		}
	}
	
	/**
	 * 开始单个对象选择
	 * @param ret,选择结束后需要返回的viewId
	 * @param selIds,已被的对象id字符串,用','分隔
	 * @return,返回选择页面的viewId
	 */
	public String startSelOne(String ret, String selIds){
		selectOne = true;
		return startSel(ret, selIds);
	}
	/**
	 * 开始多个对象选择
	 * @param ret,选择结束后需要返回的viewId
	 * @param selIds,已被的对象id字符串,用','分隔
	 * @return,返回选择页面的viewId
	 */
	public String startSelMany(String ret, String selIds){
		selectOne = false;
		return startSel(ret, selIds);
	}
	
	public String startSel(String ret, String selIds){
		this.ret = ret;
		this.selIds = selIds;
		submited = false;
		return getViewId();
	}
	
	/**
	 * 抽象方法,返回选择页面的viewId
	 * @return
	 */
	protected abstract String getViewId();
	
	/**
	 * 选择结束
	 * @return,选择结束后需要返回的viewId
	 */
	public String ok(){
		if (ret == null || ret.length() < 1){
			return "/welcome/welcome.xhtml";
		}
		submited = true;
		return ret;
	}
	/**
	 * 选择取消
	 * @return,选择结束后需要返回的viewId
	 */
	public String cancel(){
		if (ret == null || ret.length() < 1){
			return "/welcome/welcome.xhtml";
		}
		selectableItems = null;//清空
		return ret;
	}
	/**
	 * 抽象方法,取得对象的标签(名称)
	 * @param obj
	 * @return
	 */
	protected abstract String getObjectName(T obj);
	/**
	 * 抽象方法,取得对象的Id
	 * @param obj
	 * @return
	 */
	protected abstract Object getObjectId(T obj);
	
	/**
	 * 取得已被选择的Id字符串,用','分隔
	 */
	public String getSelectedStr(){
		 List<T> l = getSelectedList();
		 StringBuilder sb = new StringBuilder();
		 for (int i = 0; i < l.size() ; i++){
			 sb.append(getObjectName(l.get(i)));
			 if ( i != l.size() -1){
				 sb.append(",");
			 }
		 }
		 return sb.toString();
	}

	/**
	 * 取得已被选择的对象列表
	 * @return
	 */
	public List<T> getSelectedList(){
		List<T> l = new ArrayList<T>();
		for (SelectableItem<T> item : getSelectableItems()){
			if (item.isSelected()){
				l.add(item.getItem());
			}
		}
		return l;
	}
	
	private List<SelectableItem<T>> selectableItems = null;
	
	private void init(){
		List<Long> l_selIds =new ArrayList<Long>();
		if (selIds != null && selIds.length() > 0){
			String[] arr = selIds.split(",");
			if (arr != null){
				for (String id : arr){
					l_selIds.add(Long.parseLong(id));
				}
			}
		}
		List<T> list = getAllObjectToSelect();
		for (T p : list){
			selectableItems.add(new SelectableItem<T>(l_selIds.contains(getObjectId(p)), getObjectId(p),getObjectName(p),p));
		}
	}
	/**
	 * 抽象方法,取得所有可被选择的对象列表
	 * @return
	 */
	protected abstract List<T> getAllObjectToSelect();
	
	public List<SelectableItem<T>> getSelectableItems() {
		if (selectableItems == null){
			selectableItems = new ArrayList<SelectableItem<T>>();
			init();
		}
		return selectableItems;
	}

	public boolean isSubmited() {
		return submited;
	}

	public void setSubmited(boolean submited) {
		this.submited = submited;
	}
	public boolean isSelectOne() {
		return selectOne;
	}


}
 

  

三、具体的实现示例

角色选择器具体的实现代码:

@Name("roleSelector")
@Scope(value = ScopeType.CONVERSATION)
public class RoleSelector extends BaseSelector<Role>{
	@Override
	protected List<Role> getAllObjectToSelect() {
		return entityManager.createQuery("select o from Role o").getResultList();
	}

	@Override
	protected Object getObjectId(Role obj) {
		return obj.getId();
	}

	@Override
	protected String getObjectName(Role obj) {
		return obj.getRoleName();
	}

	@Override
	protected String getViewId() {
		return "/f_sel/role_sel.xhtml";
	}

}

 


角色选择页面代码:

		<s:div styleClass="message" id="selectedStr">
			<h:outputText value="当前选中(单选):#{roleSelector.selectedStr}" rendered="#{roleSelector.selectOne}" />
			<h:outputText value="当前选中(多选):#{roleSelector.selectedStr}" rendered="#{not roleSelector.selectOne}" />
		</s:div>
		<h:form id="selectForm">
            <rich:datascroller align="left" for="peopleList" maxPages="20" rendered="#{roleSelector.selectableItems.size>20}"/>
            <rich:spacer height="30" rendered="#{roleSelector.selectableItems.size>20}"/>
            <rich:dataTable width="100%" id="peopleList" rows="20" columnClasses="col"
                value="#{roleSelector.selectableItems}" var="item">
                <f:facet name="header">
                    <rich:columnGroup>
                        <h:column>
                            <h:outputText styleClass="headerText" value="选择" />
                        </h:column>
                        <h:column>
                            <h:outputText styleClass="headerText" value="角色名称" />
                        </h:column>
                    </rich:columnGroup>
                </f:facet>

                <h:column>
					<h:selectBooleanCheckbox value="#{item.selected}">
						<a4j:support event="onclick" reRender="selectedStr,selectForm" action="#{roleSelector.onChange(item)}"/>
					</h:selectBooleanCheckbox>
                </h:column>
                <h:column>
					<h:outputText value="#{item.item.roleName}" />
	            </h:column>
            </rich:dataTable>
			<div class="actionButtons">
				<h:commandButton value="确定" action="#{roleSelector.ok}" styleClass="buttonStyle">
					<s:conversationId/>
				</h:commandButton>
				<h:outputText value="&#160;&#160;" />
				<s:button value="取消" action="#{roleSelector.cancel}" styleClass="buttonStyle"/>
			</div>
        </h:form>

 用户编辑界面中分配角色的链接代码:

					<s:decorate template="/layout/display.xhtml">
						<ui:define name="label">分配角色</ui:define>
						<h:outputText value="#{userHome.instance.getAllRoleStr()}" rendered="#{not roleSelector.submited}" />
						<h:outputText value="#{roleSelector.selectedStr}" rendered="#{roleSelector.submited}" />
						<h:outputText value=" | " />
						<h:commandLink action="#{roleSelector.startSelMany('/f_sys/user.xhtml', userHome.instance.getAllRoleIds())}" view="/f_sel/role_sel.xhtml" value="选择">
							<s:conversationId/>
						</h:commandLink>
					</s:decorate>

 

在用户对象保存时对所选择角色的保存:

		if (roleSelector.isSubmited()) {
			List<Role> l = roleSelector.getSelectedList();
			instance.setRoles(l);
		}

 







分享到:
评论
3 楼 rockwell 2010-02-28  
能发一份完整的代码给我吗?有关roleSelector和用户对象保存管理的生命周期管理有些不清楚?希望能解释一下!先谢了!
2 楼 lanfei 2009-03-17  
可以将你这个示例的代码发给我吗?
1 楼 lanfei 2009-03-17  
非常感谢!!!

相关推荐

    seam框架相关知识总结

    Seam框架是一个全面的Java企业级开发框架,它在2005年由JBoss公司推出,主要用于简化Java EE应用的复杂性,特别是整合了JSF(JavaServer Faces)、EJB、CDI(Contexts and Dependency Injection)等技术。Seam框架的...

    Seam - 语境相关的组件

    在Seam框架中,每个组件都与特定的执行环境或“语境”相关联。这意味着组件可以根据当前的业务流程、用户会话或特定的上下文条件来提供服务。这种设计模式提高了代码的可重用性和灵活性,同时降低了组件之间的耦合度...

    Seam入门

    Bijection是Seam框架中的一项重要特性,它提供了一种简单的对象间关联管理机制。通过Bijection,开发者可以在不使用传统依赖注入的情况下,实现对象之间的相互引用。这种方式简化了对象管理,降低了耦合度,提高了...

    seam级连菜单20080610.rar

    【标题】"seam级连菜单20080610.rar" 指的是一款基于Seam框架的级联菜单实现方案,发布于2008年6月10日。Seam是一个Java EE全栈框架,它将JSF(JavaServer Faces)、EJB3、CDI(Contexts and Dependency Injection)...

    Jboss Seam中文版

    ### JBoss Seam中文版知识点详解 #### JBoss Seam简介 JBoss Seam是一个强大的企业级应用开发...通过对这些内容的学习,开发者可以更加深入地理解和掌握Seam框架的核心技术和应用场景,从而提高开发效率和应用质量。

    seam+spring+hibernate+richfaces配置

    **Seam框架** Seam是一款全面的企业级应用框架,它简化了Java EE的开发流程。Seam整合了JSF(JavaServer Faces)、EJB(Enterprise JavaBeans)和CDI(Contexts and Dependency Injection),提供了一种声明式编程...

    seam2.0 中文文档

    - 实现了一个基于Seam框架的问题跟踪系统。 - **工作原理**: - Seam的工作空间管理功能可以有效支持多用户同时在线处理问题的情况。 ##### 1.9 结合Seam和Hibernate的范例:Hibernate预订系统 - **理解代码**: ...

    jboss Seam2.0 语境相关的组件文档

    通过理解并熟练运用这些组件,开发者可以更好地驾驭Seam框架,实现复杂的业务逻辑和用户体验。提供的参考资料《Seam 2.0 Reference》中文版(CHM和PDF格式)是深入学习Seam 2.0不可或缺的资源。

    seam in action

    3. **数据绑定与转换**:Seam提供了强大的数据绑定功能,可以直接将表单字段与模型对象关联,减少了手动同步数据的必要。此外,Seam还支持自定义数据转换,确保数据在不同格式之间正确地来回转换。 4. **JSF集成**...

    基于SSH的web开发

    在Web显示层框架的选择上,有多种选项如JSF、Spring MVC、Stripes、Struts1.x、Struts2.0、Tapestry、Wicket、Flex、GWT、Seam、Ext等。选择哪个框架取决于项目的特性,如是否需要富客户端交互、对Ajax的支持程度、...

Global site tag (gtag.js) - Google Analytics