ECSide 里加入了 easyList特性。可以通过在xml里配制sql语句来快速的展现列表。

最近我将该功能模块进行了重构,使其可以脱离ecside来使用,从而可以用来简化其他的数据库操作。

具体用法结合下面的例子来讲解:

示例 :
对 USER_INFO 表进行查询。 查询条件为 USERNAME GENDER。

第1步:定义spring文件:

[code] 

 <bean id="testQuery1" class="org.ecside.easyda.DataAccessModel"> 

 <!-- 注入一个标准的数据源 --> 

 <property name="dataSource" ref="test_datasource" /> 

 <property name="sqls"> 

 <map> 

 <!-- 这个key的名字随便取 --> 

 <entry key="queryInfoByNameGender" > 

 <value> 

 select * from user_info 

 where 1=1 

 #{IF:USERNAME!=EMPTY} and username like #{USERNAME} #{/IF} 

 #{IF:GENDER!=EMPTY} and gender=#{GENDER} #{/IF} 

 </value> 

 </entry> 


 </map> 

 </property> 

 </bean> 

[/code]


第2步,在适当的位置(如BO中)执行下列java代码

[code] 

// 这里也可以使用 Ioc 注入。 

DataAccessModel dam=(DataAccessModel)factory.getBean("testQuery1"); 

//parameterMap为传入参数,key为USERNAME GENDER。 

List list=(List)dam.executeQuery("queryInfoByNameGender", parameterMap); 

[/code]


ok,执行完了,执行的每条结果会放入MAP,所有的MAP最后放入LIST
Map的Key是SQL语句执行结果的各个列的名字。

其中 #{USERNAME} #{GENDER} 为参数在传入的参数Map中的key.

其中 #{IF..} 字句用来拼装SQL.。
其语义为 如果满足条件 就把IF内的字符串拼接到有效的SQL语句中。
支持简单的条件:

A<B : #{IF:A#{_L}B}....{/IF} 

A>B : #{IF:A#{_G}B}....{/IF} 

A=B : #{IF:A=B}....{/IF} 

A!=B : #{IF:A!=B}....{/IF} 

A<=B : #{IF:A#{_L}=B}....{/IF} 

A>=B : #{IF:A#{_G}=B}....{/IF}



A为参数(的KEY), B为数值,可以是EMPTY NULL 字符串 数字 等如

#{IF:USERNAME!='admin'}....{/IF} 

#{IF:AGE #{_L}= 18}....{/IF}



注意 < >于号出现在 sql语句中时也请使用 #{_L} #{_G}
#{IF:A=B}....{/IF} 内部 可以是任何语句,也可以使用任何参数。不一定非要是A.
例如 这样也是可以的

#{IF:USERROLE='1'} and (GENDER = ${XXXX} or AGE ${_L} 25 {/IF}



传入参数可以使用组件中提供的getParameterMap方法从request中自动生成,相应的代码很简单:

[code] 

 public static Map getParameterMap(HttpServletRequest request) { 

 Map parameterMap = new HashMap(); 

 Enumeration names = request.getParameterNames(); 

 while (names.hasMoreElements()) { 

 String name = (String) names.nextElement(); 

 String[] s = request.getParameterValues(name); 

 if (s != null) { 

 if (s.length == 1) { 

 parameterMap.put(name, request.getParameterValues(name)[0]); 

 } else { 

 parameterMap.put(name, request.getParameterValues(name)); 

 } 

 } 

 } 

 return parameterMap; 

 } 

[/code]



如果查询叶面的input区域是
姓名:<input type="text" name="i_user_name">
性别:<input type="text" name="i_user_gender">
通过 getParameterMap 取得参数map后,如果想直接调用sql

那么sql需要改动为

[code] 

<entry key="queryInfoByNameGender" > 

 <value> 

 select * from user_info 

 where 1=1 

 #{IF:i_user_name!=EMPTY} and username like #{i_user_name} #{/IF} 

 #{IF:i_user_gender!=EMPTY} and gender=#{i_user_gender} #{/IF} 

 </value> 

</entry> 

[/code]




一个DataAccessModel bean里可以写入多个sql.
可以是 delete update insert select {call...
例如下面这个

[code] 

 <bean id="myEasyDA" class="demo.MyDataAccessModel"> 

 <property name="dataSource" ref="test_datasource" /> 

 <property name="sqls"> 

 <map> 

 <entry key="baseInfo1" > 

 <value> 

 {call CM_CUST_REAL_INFO_P( 

 #{I_SERVICE_KIND}, 

 #{I_SERVICE_NO}, 

 #{I_CITY_CODE}, 

 #{I_SERVICE_ID}, 

 #{I_CUSTOMER_ID}, 


 #{OUT:OUT_F_CUST_NAME}, 

 #{OUT:OUT_F_GENDER}, 

 #{OUT:OUT_F_DUTY}, 

 #{OUT:OUT_F_PRODUCT_NAME}, 

 #{OUT:OUT_F_POINT_VALUE}, 

 #{OUT:OUT_F_STATUS}, 

 #{OUT:ON_FLAG}, 

 #{OUT:OS_PROMPT} 

 )} 

 </value> 

 </entry> 

 <entry key="updateUser" > 

 <value> 

 update user_info set 

 passwd=#{PASSWD} , 

 userrole=#{USERROLE} , 

 email=#{EMAIL}, 

 gender=#{GENDER} 

 WHERE userid=#{USERID} 

 </value> 

 </entry> 

 <entry key="deleteUser" > 

 <value> 

 delete from user_info 

 WHERE userid=#{USERID} 

 </value> 

 </entry> 

 <entry key="getUserMemo" > 

 <value> 

 select MEMO,EMAIL 

 from user_info WHERE userid=#{USERID} 

 </value> 

 </entry> 

 </map> 

 </property> 

 </bean> 

 [/code]


其中 #{OUT:...} 用来标识 存储过程的输出参数。
其中的 demo.MyDataAccessModel 继承自 org.ecside.easyda.DataAccessModel
你可以在这个类里覆盖父类的registerInterceptors方法,为每个sql添加前后拦截器。
代码如下:

[code] 

public class MyDataAccessModel extends DataAccessModel { 


 public void registerInterceptors(){ 

 addInterceptor(new DataAccessInterceptor("updateUser"){ 


 public void before(Map parameterMap, HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { 


 } 


 public void after(Map parameterMap, HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { 

 request.setAttribute(ECSideConstants.C_UPDATE_RESULT_MESSAGE,request.getParameter("USERNAME")); 

 ServletUtil.writeDefaultTextToClient(parameterMap, request, response); 

 } 


 }); 



 addInterceptor(new DataAccessInterceptor("deleteUser"){ 


 public void before(Map parameterMap, HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { 


 } 


 public void after(Map parameterMap, HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { 

 request.setAttribute(ECSideConstants.C_UPDATE_RESULT_MESSAGE,request.getParameter("USERNAME")); 

 ServletUtil.writeDefaultTextToClient(parameterMap, request, response); 

 } 


 }); 

 } 

} 

[/code]




已知不足:
在事务控制方面做的工作几乎为0。
#{IF}功能不够强大,不支持复杂的逻辑判断。
所以目前不适合用在复杂的场合。
另:整个过程输入 输出的sql类型 全是string,所以如果要做类型方面的转换,需要自己在sql语句级别进行。


这篇文章没有提供代码,打算下和 ecside 1.1 final一起推出。

希望大家可以针对这个模块提出些建议和意见 谢谢大家了。