[原创于:http://happydev.iteye.com]
实现对象选择可以直接通过下拉选择框的方式来选择,但这种选择不适合数据量较大的对象选择。
而在企业的Web开发中,经常会用到对关联对象的单选或多选,而关联对象的数据量往往不是下拉选择框可以展现的。
本文提出了一个较为通用的关联对象选择方案。
一、一个较为通用的关联对象选择方案要解决的主要问题
- 可能是单选,也可能会是多选;
- 将对象进行“可选择对象”的封装,以支持是否选中状态的维护;
- 待选对象的数据查询;
- 选择时表现层界面viewId的配置;
- 选择后返回的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="  " />
<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);
}
分享到:
相关推荐
Seam框架是一个全面的Java企业级开发框架,它在2005年由JBoss公司推出,主要用于简化Java EE应用的复杂性,特别是整合了JSF(JavaServer Faces)、EJB、CDI(Contexts and Dependency Injection)等技术。Seam框架的...
在Seam框架中,每个组件都与特定的执行环境或“语境”相关联。这意味着组件可以根据当前的业务流程、用户会话或特定的上下文条件来提供服务。这种设计模式提高了代码的可重用性和灵活性,同时降低了组件之间的耦合度...
Bijection是Seam框架中的一项重要特性,它提供了一种简单的对象间关联管理机制。通过Bijection,开发者可以在不使用传统依赖注入的情况下,实现对象之间的相互引用。这种方式简化了对象管理,降低了耦合度,提高了...
【标题】"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是一个强大的企业级应用开发...通过对这些内容的学习,开发者可以更加深入地理解和掌握Seam框架的核心技术和应用场景,从而提高开发效率和应用质量。
**Seam框架** Seam是一款全面的企业级应用框架,它简化了Java EE的开发流程。Seam整合了JSF(JavaServer Faces)、EJB(Enterprise JavaBeans)和CDI(Contexts and Dependency Injection),提供了一种声明式编程...
- 实现了一个基于Seam框架的问题跟踪系统。 - **工作原理**: - Seam的工作空间管理功能可以有效支持多用户同时在线处理问题的情况。 ##### 1.9 结合Seam和Hibernate的范例:Hibernate预订系统 - **理解代码**: ...
通过理解并熟练运用这些组件,开发者可以更好地驾驭Seam框架,实现复杂的业务逻辑和用户体验。提供的参考资料《Seam 2.0 Reference》中文版(CHM和PDF格式)是深入学习Seam 2.0不可或缺的资源。
3. **数据绑定与转换**:Seam提供了强大的数据绑定功能,可以直接将表单字段与模型对象关联,减少了手动同步数据的必要。此外,Seam还支持自定义数据转换,确保数据在不同格式之间正确地来回转换。 4. **JSF集成**...
在Web显示层框架的选择上,有多种选项如JSF、Spring MVC、Stripes、Struts1.x、Struts2.0、Tapestry、Wicket、Flex、GWT、Seam、Ext等。选择哪个框架取决于项目的特性,如是否需要富客户端交互、对Ajax的支持程度、...