环境:
Richfaces 4.3.3.Final
Seam 2.3.1.Final
JBOSS AS 7.1.1.Final
a4j commandButton 和 commandLink 的disable 刷新问题导致 a:param 无效
Q 如果之前的一个a4j commandButton或 commandLink 是disable状态的.再a4j请求要求刷新这个button时那么button下面的所有参数将不会刷新,也就是说你在刷一个disabe的commandButton 下的a:param那么param的值不会更新,当你再点击这个按钮时将不是你想要的值.
A:没啥办法,用onclick判断下return false;吧.等seam解决吧
文件上传: rich:fileUpload 和 s:fileUpload冲突
Q:
使用s:fileUpload要在seam的组件描述符中设置web:multipart-filter 的disabled设为False; 并设置Form 的 enctype="multipart/form-data"
而 rich:fileUpload 要在seam的组件描述符中设置 web:multipart-filter 的disabled设为True;并设置 web:ajax4jsf-filter , 这就冲突了!
A:
只能使用一种上传方式,要么s:fileUpload 要么 rich:fileUpload但这样并不完美,
待实验:
不知道如果 rich:fileUpload 的Form 不设置enctype="multipart/form-data" 并把web:multipart-filter 的disabled设为False可以不.
另外有没有办法使用 url-pattern 把两种请求分开处理,这就需要使用其中的一种不发送.seam的请求..
现在我仅使用 rich:fileUpload 我的配置:
<web:multipart-filter create-temp-files="true" max-request-size="1000000" disabled="true" url-pattern="*.seam"/>
<web:ajax4jsf-filter force-parser="true" enable-cache="false" url-pattern="*.seam"/>
数据分页,过滤,查询,排序 使用 AJAX 页面参数
Q:
Seam-gen生成的数据分页,过滤,排序 都是普通请求的,并且使用页面参数来保存数据状态,
A
如果数据量不大可以使用RICHFACES的分页,过滤,排序 .
要使用数据库分页
页面描述符中的页面参数在AJAX请求也是有效的.只要修改下原来的模板页就可以使数据的分页,过滤,查询都成为AJAX请求的了,并且也可使用页面参数来保存数据状态,
我的修改
sort.xhtml
<ui:composition xmlns="http://www.w3.org/1999/xhtml"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:s="http://jboss.org/schema/seam/taglib"
xmlns:a="http://richfaces.org/a4j">
<!--
params:
propertyPath: Query order str
propertyLabel: title
entityList: inherited to EntityQuery
-->
<a:commandLink styleClass="columnHeader" render="dataListResult,#{render}"
execute="@this" immediate="true"
value="#{propertyLabel} #{entityList.orderColumn == propertyPath ? (entityList.orderDirection == 'desc' ? messages.down : messages.up) : ''}">
<a:attachQueue requestDelay="0"/>
<f:param name="sort" value="#{propertyPath}"/>
<f:param name="dir" value="#{entityList.orderColumn == propertyPath and entityList.orderDirection == 'asc' ? 'desc' : 'asc'}"/>
</a:commandLink>
</ui:composition>
DataScroller.xhtm 只实现了上一页和下一页,待实现页码选择
<!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:s="http://jboss.org/schema/seam/taglib"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:a="http://richfaces.org/a4j"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:rich="http://richfaces.org/rich" xmlns:h="http://java.sun.com/jsf/html">
<!--
params:
render: render fo request
entityList: entityQuery oper
-->
<span class="rf-ds">
<a:commandButton immediate="true" execute="@this"
action="#{entityList.first}"
render="dataListResult,#{render}"
styleClass="rf-ds-btn rf-ds-btn-fastrwd"
disabled="#{not entityList.previousExists}"
value="#{messages.left}#{messages.left}">
<a:attachQueue requestDelay="0"/>
</a:commandButton>
<!-- entityList.previousExists" -->
<a:commandButton immediate="true" execute="@this"
render="dataListResult,#{render}"
action="#{entityList.previous}"
disabled="#{not entityList.previousExists}"
styleClass="rf-ds-btn rf-ds-btn-prev"
value="#{messages.left}">
<a:attachQueue requestDelay="0"/>
</a:commandButton>
<a:commandButton immediate="true" execute="@this"
render="dataListResult,#{render}"
styleClass="rf-ds-btn rf-ds-btn-prev"
action="#{entityList.next}"
disabled="#{not entityList.nextExists}"
value="#{messages.right}">
<a:attachQueue requestDelay="0"/>
</a:commandButton>
<a:commandButton immediate="true" execute="@this"
render="dataListResult,#{render}"
styleClass="rf-ds-btn rf-ds-btn-fastrwd"
disabled="#{not entityList.nextExists}"
action="#{entityList.last}"
value="#{messages.right}#{messages.right}">
<a:attachQueue requestDelay="0"/>
</a:commandButton>
</span>
</ui:composition>
排序使用:
<rich:column>
<f:facet name="header">
<ui:include src="/layout/a4jSort.xhtml">
<ui:param name="entityList" value="#{personList}"/>
<ui:param name="propertyLabel" value="#{messages.person_field_name}"/>
<ui:param name="propertyPath" value="person.name"/>
</ui:include>
</f:facet>
<h:outputText value="#{_person.name}"/>
</rich:column>
过滤使用:
<h:form styleClass="edit">
<rich:collapsiblePanel header="#{messages.search_conditions}" switchType="client">
<s:decorate template="/layout/display.xhtml">
<ui:define name="label">#{messages.person_field_credentialsNO}</ui:define>
<h:inputText value="#{personList.person.credentialsNumber}"/>
</s:decorate>
<s:decorate template="/layout/display.xhtml">
<ui:define name="label">#{messages.person_field_name}</ui:define>
<h:inputText value="#{personList.person.name}"/>
</s:decorate>
<s:decorate template="/layout/display.xhtml">
<ui:define name="label">#{messages.search_match}</ui:define>
<h:selectOneRadio id="logic" value="#{personList.restrictionLogicOperator}"
styleClass="radio">
<f:selectItem itemLabel="#{messages.search_match_and}" itemValue="and"/>
<f:selectItem itemLabel="#{messages.search_match_or}" itemValue="or"/>
</h:selectOneRadio>
</s:decorate>
</rich:collapsiblePanel>
<div class="actionButtons">
<a:outputPanel id="searchButton">
<a:commandButton value="#{messages.search}"
execute="@form" render="dataListResult">
<a:attachQueue requestDelay="0"/>
</a:commandButton>
</a:outputPanel>
<s:button id="reset" value="#{messages.reset}" includePageParams="false"/>
</div>
</h:form>
分页使用:
<f:facet name="footer">
<a:outputPanel rendered="#{not empty personList.resultList}">
<ui:include src="/layout/pageA4jNavigation.xhtml">
<ui:param name="entityList" value="#{personList}"/>
</ui:include>
</a:outputPanel>
</f:facet>
用于保存状态的页面参数:
<param name="firstResult" value="#{personList.firstResult}"/>
<param name="sort" value="#{personList.orderColumn}"/>
<param name="dir" value="#{personList.orderDirection}"/>
<param name="logic" value="#{personList.restrictionLogicOperator}"/>
<param name="name" value="#{personList.person.name}"/>
<param name="credentialsNumber" value="#{personList.person.credentialsNumber}"/>
待实验:
richfaces的extendedDataTable可以通过设置clientRows来使用AJAX动态加载分页数据,但是数据要在一个LIST中,是否可以实现一个LIST来动态的从数据库中查询分页数据
数据AJAX验证 刷新问题
Q:
seam提供了一个模板来验证数据 但是如果你的保存,修改,取消是AJAX请求的话,用例子中的方法会有刷新问题,表现为虽然你使用Render来刷的输入框,但是输入框仍然为上一次的值
A:
要解决这个需要把a:ajax的 bypassUpdates="true" 去掉,也就是使用默认值false,并在保存的AJAX请求时刷新下所有的输入框,如果你很介意这个的话也可是使用Richfaces的验证来替换Seam的数据验证,但是要多写些代码 rich:messages的for 和 rich:vaild 另外还要去掉errors变红的css因为刷新区域不一样.
另外无论是Seam的验证还是Richfaces的验证,都可以进行JPA验证 ,验证消息的国际化文件是 ValidationMessages.properties 键值:
javax.validation.constraints.AssertFalse.message = must be false
javax.validation.constraints.AssertTrue.message = must be true
javax.validation.constraints.DecimalMax.message = must be less than or equal to {value}
javax.validation.constraints.DecimalMin.message = must be greater than or equal to {value}
javax.validation.constraints.Digits.message = numeric value out of bounds (<{integer} digits>.<{fraction} digits> expected)
javax.validation.constraints.Future.message = must be in the future
javax.validation.constraints.Max.message = must be less than or equal to {value}
javax.validation.constraints.Min.message = must be greater than or equal to {value}
javax.validation.constraints.NotNull.message = 不允许为空
javax.validation.constraints.Null.message = must be null
javax.validation.constraints.Past.message = must be in the past
javax.validation.constraints.Pattern.message = must match "{regexp}"
javax.validation.constraints.Size.message = 长度必须在 {min} 和 {max} 之间
org.hibernate.validator.constraints.CreditCardNumber.message = invalid credit card number
org.hibernate.validator.constraints.Email.message = not a well-formed email address
org.hibernate.validator.constraints.Length.message = length must be between {min} and {max}
org.hibernate.validator.constraints.NotBlank.message = may not be empty
org.hibernate.validator.constraints.NotEmpty.message = may not be empty
org.hibernate.validator.constraints.Range.message = must be between {min} and {max}
org.hibernate.validator.constraints.SafeHtml.message = may have unsafe html content
org.hibernate.validator.constraints.ScriptAssert.message = script expression "{script}" didn't evaluate to true
org.hibernate.validator.constraints.URL.message = must be a valid URL
对话ID不能传递
Q:
ajax 刷新位置的不同可能会引发对话ID不能被正确存储到jsf树的根上,导致下一次操作时无法取得对话ID
A:有几种情况各不相同
1.刷新FORM内的一个区域, 那么将无法正确存储对话ID,区域中的链接或按钮将无法取得对话ID
2.刷新区域内有一个FORM或直接刷新FORM,那么可以正确存储对话ID
3.刷新区域没有没有嵌套在一个FORM中,这个又比较复杂 , 正常情况下 如果一个链接或按钮没有Form的话是无法进行提交操作的,但是Richfaces4的A:commandLink和a:commladbutton如果不在一个FORM中,但是在其它地方有FORM的话也可以进行提交操作 而这种情况下如果你的页面中没有JSTL 标签库 的话对话ID也是可以正常存储的 但也有也又不行,这取
使用 JSTL 标签库引起对话ID不能自动传递
Q:
默认情况下Seam会把对话ID放在JSF组件树中进行传递.但是如果你的页面中使用的JSTL的标签,即c:set c:if 等 那么这个对话ID将无法传递(不知道为什么!)
A:
使用别的标签来替代JSTL
AJAX请求中处理 persist , update的返回值
Q:
Richfaces的DataTable的Demo中有一个Editing的例子是使用#{facesContext.maximumSeverity==null} 来判断是否关闭panel的.但是这种方法无法判断消息的等级.
A:通过Seam的HOME中 persist , update的返回值来决定是否要关闭Panel,和是否结束对话
先要扩展下EntityHome:
package com.dgsoft.common;
import com.dgsoft.house.property.model.Developer;
import org.jboss.seam.annotations.End;
import org.jboss.seam.annotations.Logger;
import org.jboss.seam.annotations.Transactional;
import org.jboss.seam.annotations.intercept.BypassInterceptors;
import org.jboss.seam.framework.EntityHome;
import org.jboss.seam.log.Log;
/**
* Created with IntelliJ IDEA.
* User: cooperlee
* Date: 5/8/13
* Time: 9:51 AM
*/
public class EntityHomeAdapter<E> extends EntityHome<E> {
@Logger
protected Log log;
private String lastState = "";
@BypassInterceptors
public String getLastState() {
return lastState;
}
protected boolean verifyUpdateAvailable() {
return true;
}
protected boolean verifyPersistAvailable() {
return true;
}
protected boolean verifyRemoveAvailable() {
return true;
}
@Transactional
@End
public String updateEnd() {
return this.update();
}
@Transactional
@End
public String persistEnd() {
return this.persist();
}
@Transactional
@End
public String removeEnd() {
return this.remove();
}
@Override
public void create() {
super.create();
lastState = "";
}
@Override
public String update() {
lastState = "";
if (verifyUpdateAvailable()) {
lastState = super.update();
}
return lastState;
}
@Override
public String persist() {
lastState = "";
if (verifyPersistAvailable())
lastState = super.persist();
return lastState;
}
@Override
public String remove() {
lastState = "";
if (verifyRemoveAvailable())
lastState = super.remove();
return lastState;
}
@Override
public E find() {
lastState = "";
return super.find();
}
@Override
protected E loadInstance() {
lastState = "";
return super.loadInstance();
}
@Override
protected E createInstance() {
lastState = "";
return super.createInstance();
}
public void refresh(){
if (isIdDefined() && isManaged()){
getEntityManager().refresh(getInstance());
}
}
}
在保存和更新的AJAX提交按钮上加上:
<a:commandButton execute="@form"
render="developerListTable,developerEditPanel_inputs,developerEditPanel_title"
value="#{messages.save}" action="#{developerHome.persistEnd}"
rendered="#{!developerHome.managed}"
data="#{developerHome.lastState}"
oncomplete="if (event.data == 'persisted'){#{rich:component('developerEditPanel')}.hide();}">
<a:attachQueue requestDelay="0"/>
</a:commandButton>