Monthly Archives: March 2010

Struts2 + extremTable 简单分页

我们都知道分页查询包括数据库端分页和UI前端分页。

  1.如果数据量很小,则无须数据库分页,让extremeTable直接进行UI分页即可。

  2.如果数据量比较大,则应该进行数据库分页,并让extremeTable配合。数据库分页大家有自己的方案,这里就不提;我们只说一下extremeTable应该如何配合。

    a.
首先,extremeTable显示的“记录总条数”不能等于它即将处理的items数,因为items只代表当页记录。那怎么显示一个记录总条数呢?     

          

        i.Struts2里应该先忽悠一下,强行指定记录总条数。

	
//在action里添加这样一个"totalRows"属性
	public int getTotalRows() {
		return 记录总条数;
	}
      
 // "totalRows"  对应的是org.extremecomponents.table.core.TableConstants.TOTAL_ROWS 这个常量。 通过下面的设置,我们将让extremeTable标签从http context中读取"totalRows"。

       ii.让extremeTable标签从http context中读取 "totalRows"

                <@ec.table

                  items="records"

                  …

                 
retrieveRowsCallback="limit"

              >

         必须做这个设置,否则extremeTable将把 records.size()当作总记录数。

    b.未完待续

   

一个Trim Interceptor

很多人想要这个东西,都说可以Interceptor来自动trim掉输入,但为什么就没有人整出来呢?

既然没人弄,那我就弄一个呗。不过,其实,这个类基本是从’Apache Struts 2 Web Application Development’中抄来的,我另外做了一点修改。

public class TrimInterceptor extends MethodFilterInterceptor {

	private List<String> excluded = new ArrayList<String>();

	protected String doIntercept(ActionInvocation invocation) throws Exception {
		Map<String, Object> parameters = invocation.getInvocationContext().getParameters();

		for (String param : parameters.keySet()) {
			if (isIncluded(param)) {
				String[] vals = (String[]) parameters.get(param);
				boolean allNull = true;
				for (int i = 0; i < vals.length; i++) {
					vals[i] = StringUtils.trimToNull(vals[i]);
					allNull = allNull && (vals[i] == null);
				}
				if(allNull){
					parameters.put(param, null);
				}
				
			}
		}

		return invocation.invoke();
	}

	private boolean isIncluded(String param) {
		for (String exclude : excluded) {
			if (param.startsWith(exclude)) {
				return false;
			}
		}

		return true;
	}

	public void setExcludedParams(String excludedParams) {
		for (String s : StringUtils.split(excludedParams, ",")) {
			excluded.add(s.trim());
		}
	}

}

//struts.xml

<interceptor class="com.xxx.TrimInterceptor" name="trim"/>
....
                <interceptor-ref name="servletConfig"/>
                 <interceptor-ref name="trim"/> 
                <interceptor-ref name="params"/>

在Struts2 + Freemarker环境中使用 自定义的JSP Tag

比如说,使用 jmesa这个标签库。FTL应该这样写:

1. 声明一下标签库

<#assign ec=JspTaglibs["/WEB-INF/tld/jmesa.tld"]>

2. 使用extremetTable标签

<@jmesa.tableFacade id="users_table" 
items=users var="user">

                  <@jmesa.htmlTable width="100%">

                    <@jmesa.htmlRow>

                      <@jmesa.htmlColumn property="loginId" title="Login Id"/>

                      <@jmesa.htmlColumn property="firstName" title="First Name"/>

                      <@jmesa.htmlColumn property="lastName" title="Last Name"/>

                    </@jmesa.htmlRow>

                  </@jmesa.htmlTable>

                </@jmesa.tableFacade>

    a.要写 "<@jmesa.tableFacade>",而不是 "<jmesa:tableFacade>"

    b.类集变量的表达式是不带引号的users,而不是"users",也不是 "${users}"

Struts2中如何用Select标签来映射Enum类型?

假设

  Role是枚举类型,

  而 candidateRoles= Role.values()

如果要设定user的roles,则select标签就应该这样写

<@s.select   name="user.roles" list="candidateRoles"  multiple="true"   />

  1. 使用candidateRoles作为候选项

  2. name的表达式也直接使用Role类型,同时,不要指定 listKey 和 listValue标签

  3. 这样的标签在增/改时都会展现所有侯选Roles,并且,在“修改”页面会自动选中当前已有的Roles.

[Hibernate]我建议不要在entity中使用原始类型作为成员的类型

使用原始类型,如

   private int age;

它的致命缺点是: age永远不会为空值,这会使hibernate防空值的功能形同虚设。

具体来说,

   假说 age 的 nullable = false, 那如果setAge()没被调用,我们就会预期hibernate在运行时报错,防止age为空的数据进入数据库。

   然而,实际的结果是:JRE会把age的值为0,然后把 age=0 的数据插入数据库,而age = 0并不是我们想要的东西。

  而如果使用 private Integer age,就没有这个问题。

Spring 为Hibernate做的packagesToScan 倒底是怎么被解析的?

首先,Spring用AntPathMatcher 来解析路径,这个好办,毕竟Ant风格的路径大家都熟

但在调用这个Matcher之前,Spring 会先将你在XML中写的路径转变成Ant风格的路径。那,是怎么转换的呢?

经过试验,我的结论如下

 

  

   <property name="packagesToScan" value="
com.xxx.model" />, 会转换成"classpath*:com/xxx/
model**/*.class",这个路径可以找出com/xxx/model根目录下的类文件

      <property name="packagesToScan" value="com.xxx.model
.*" />, 会转换成"classpath*:com/xxx/
model/***/*.class",这个路径可以找出com/xxx/model根目录下一级子目录中的类文件,如com/xxx/model/son/Hi.class

      <property name="packagesToScan" value="com.xxx.model
." />(注意最后的点) , 会转换成"classpath*:com/xxx/model
/**/*.class",这个路径可以找出com/xxx/model根目录下及其子孙目录下所有的类文件. 一般来讲,这些就是我们要的文件。