论坛首页 Java企业应用论坛

xyz,pojo的mvc框架,替代webwork一Action多CURD操作干净实现

浏览 26578 次
该帖已经被评为良好帖
作者 正文
   发表时间:2006-10-20  
http://sourceforge.net/projects/jxyz sourceforge的框架源码
在我用过的web 开发框架中,在我享受他们给我带来的便利时,却不得不忍受着他们给我带来的折磨。Struts的FormBean,jsf的不成熟的jsp标签绑定,tapestry的陡峭的学习曲线,等等等等,等用了webwork,似乎一切都结束了,他的简单的结构,出色的aop,ognl支持,和web环境的脱离,似乎意味着我们结束了开发噩梦,然而,不,事实并非如此。当webwork讥笑struts必须继承org.apache.struts.action.Action类的同时,他自己却必须实现com.opensymphony.xwork.Action接口,在pojo肆虐的当今,这无疑是五十步笑百步,还有,webwork对struts FormBean的改造,是使用ModelDriven拦截器来实现的,然而,ModelDriven只支持一个java对象,如果你的Action中想支持一个以上的Model,对不起,你自己做去吧。同时,Action的结构混乱,传入和传出的对象,属性无法区分,这一点,SpringMvc做的不错,SpringMvc也似乎是理论上最完美的mvc,可惜,SpringMvc对web框架的耦合和对jstl的偏爱以及过于灵活导致的复杂性让我和他不能走得过近。而且,这些所谓j2ee的框架一概带有java推崇的不厌其烦的xml配置文件,看看红的发紫的Rails On Ruby吧,那是怎样的利用命名规范来达到减少配置文件的,来降低复杂性的,是怎样利用代码生成来减少编程工作量的。而且,这些框架可以说,一个一个比赛着高大全,webwork,800多个类,spring,2000多个类,tapestry,甚至还带有自己的ioc容器,和jboss seam的100多个类的框架相比,无疑是过于复杂了,牛刀杀鸡了。当然,这些并不意味着我是一个ro r或者seam迷,毕竟,ror在易用性上站了优势,却在组件化上处于劣势,seam的jsf和ejb也不是一个轻量级的选择。
所以,我这自己开发的这个mvc框架有以下几个特点。
1. Pojo。任何一个java类都可以做Action(logic),为了改造现在常用的ssh,tsh,wsh框架成sh,支持spring bean做Action(logic)
2. 0配置,根据命名规范来查找Action类和view
3. 和web环境松耦合,从理论上讲可以用在swing里
4. 支持tdd开发,框架本身就是以tdd开发方式开发
5. 代码少,一般mvc需要5个类,xyz只要3个,还可以通过GenericDAO,GenericLogic来减少重复代码
6. 对开发者来说,一切实现都可以自己定制,由于hivemind支持迭代开发

我们来写一个java logic类:
package test.logic;

import xyz.frame.annotations.Out;
import xyz.frame.annotations.Read;

public class InLogic {
@Read
@Out
private String in;
public void in(){
System.out.println("in--"+in);
}

}
再写一个测试类:
package test;

import java.util.HashMap;
import java.util.Map;

import xyz.frame.core.LogicContext;
import xyz.frame.core.LogicProxy;

public class InTest extends MainTest {
public void testIn(){
System.out.println("=================simple Out Test begin=========");
try {
Map params = new HashMap();
//自己添加东西
params.put("first",new String[]{"first"});
Map extraContext = new HashMap();

extraContext.put(LogicContext.PARAMETERS, params);

//由于logic config可能需要合并,所以个namespace可能需要修改
LogicProxy proxy =
logicProxyFacory.createLogicProxy(
"/test/logic",
"FirstLogic",
"testIn",
extraContext);

proxy.setExecuteResult(true);
assertEquals(proxy.execute(), "ok");
System.out.println("----------------------------------------------------------------------");
System.out.println("----------------------------------------------------------------------");
Map inparams = new HashMap();
//自己添加东西
inparams.put("in",new String[]{"in"});
Map inextraContext = new HashMap();

inextraContext.put(LogicContext.PARAMETERS, inparams);

//由于logic config可能需要合并,所以个namespace可能需要修改
LogicProxy inproxy =
logicProxyFacory.createLogicProxy(
"/test/logic",
"InLogic",
"in",
inextraContext);

inproxy.setExecuteResult(true);
assertEquals(inproxy.execute(), "ok");
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}

通过web调用的url如下:http://.../test/logic/InLogic!in.xyz?in=myin
结果的View可以是jsp,velocity,freemark,fastm,excel,jasper,chart等,如果使用jsp做缺省的view,结果就把in用in做id放到request里面了,当然需要在conf/xyz.hivemind.xml里面保证
<service-point id="NullResultMaker" interface="ResultMaker">
<invoke-factory>
<construct class="impl.NullResultMaker">
<set-service property="nullResult" service-id="NullResult"/>
</construct>
</invoke-factory>
</service-point>

<service-point id="NullResult" interface="Result">
<invoke-factory>
<construct class="xyz.frame.web.view.DispatcherResult">
</construct>
</invoke-factory>
</service-point>

Jsp就是/test/logic/InLogic!in.ok.jsp
In==<%=(String)request.getAttribute(“in“)%>

上面方法不返回值,如果返回值,想把返回值放到request里可面,可以。
package test.logic;

import xyz.frame.annotations.Out;

public class Return {
@Out(key="return")
public Integer showTest(){
System.out.println("test==");
return new Integer(100);
}
}

如果想通过参数来做:
package test.logic;

import java.util.Date;

import test.ognl.property.User;
import xyz.frame.annotations.Out;
import xyz.frame.annotations.Read;

public class ModelParaMethod {

public void showTest(
@Read User user,
@Read(key="test") @Out(key="test")int test,
@Read(key="integer") Integer integer,
@Read(key="date") @Out(key="date")Date date,
@Read(key="double") double dl) {
System.out.println("read user== " + user);
System.out.println("read test== " + test);
System.out.println("read integer== " + integer);
System.out.println("read date== " + date);
System.out.println("read dl== " + dl);
}

}

如果想使用改造ssh,wsh,tsh框架,去掉struts,webwork,tapestry这些,就要支持spring bean做logic,或者说,支持接口做logic
接口:
package test.logic;

public interface IDemo {
public void showTest();
} 实现:
package test.logic.impl;

import test.logic.IDemo;
import test.ognl.property.User;
import xyz.frame.annotations.Out;
import xyz.frame.annotations.Read;

public class DemoImpl implements IDemo {
@Read
@Out
public String test="测试";

@Read(create=true)
@Out
private User user=new User();

public void showTest() {
System.out.println("Spring read test== " + test);
System.out.println("Spring read user== " + user);
}

public String toString(){
return super.toString()+":test=="+test+",you==";
}
} Spring bean配置:
<bean id="IDemo" class="test.logic.impl.DemoImpl"/>

测试:
package test;

import java.util.HashMap;
import java.util.Map;

import xyz.frame.core.LogicContext;
import xyz.frame.core.LogicProxy;

public class SpringSimpleTest extends MainTest {


public void testSipleOut(){
System.out.println("=================simple Out Test begin=========");
try {
Map params = new HashMap();
//自己添加东西
params.put("test",new String[]{"test 总喜欢咱 我要输出!"});
params.put("you",new String[]{"哈立德撒罗杰斯防空洞!"});
Map extraContext = new HashMap();

extraContext.put(LogicContext.PARAMETERS, params);

//由于action config可能需要合并,所以个namespace可能需要修改
LogicProxy proxy =
logicProxyFacory.createLogicProxy(
"/test/logic",
"Spring:IDemo",
"showTest",
extraContext);

proxy.setExecuteResult(true);
assertEquals(proxy.execute(), "ok");
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}

使用hibernate扩展包支持GenericDAO,GenericLogic,减少代码量
Domain文件:
在、test/domain/目录利用hibernate工具生成Test.java&Test.hbm.xml
Dao接口:
package test.dao;

import test.domain.Test;
import xyz.ext.dao.IGenericDAO;

public interface ITestDAO extends IGenericDAO<Test,Integer>{

}
Dao实现:
package test.dao.impl;

import test.dao.ITestDAO;
import test.domain.Test;
import xyz.ext.dao.impl.GenericDAOHibernateImpl;

public class TestDAOImpl extends GenericDAOHibernateImpl<Test,Integer> implements ITestDAO{

}
Logic类:
package test.logic;

import test.dao.ITestDAO;
import test.domain.Test;

import xyz.ext.dao.IGenericDAO;
import xyz.ext.logic.GenericLogic;
import xyz.frame.annotations.Read;

public class TestLogic extends GenericLogic<Test,Integer>{
@Read(object="Spring:testDAO")
private ITestDAO dao;

@Override
public IGenericDAO<Test, Integer> getIGenericDAO() {
return dao;
}

}

Testcase:
package test;

import java.util.HashMap;
import java.util.Map;

import xyz.frame.core.LogicContext;
import xyz.frame.core.LogicProxy;

public class ModelTest extends MainTest {
public void testModel(){
System.out.println("=================simple Out Test begin=========");
try {
Map params = new HashMap();
//自己添加东西
params.put("name",new String[]{"userName"});
params.put("id",new String[]{"2"});
Map extraContext = new HashMap();

extraContext.put(LogicContext.PARAMETERS, params);

//由于logic config可能需要合并,所以个namespace可能需要修改
LogicProxy proxy =
logicProxyFacory.createLogicProxy(
"/test/logic",
"TestLogic",
"doInsert",
extraContext);

proxy.setExecuteResult(true);
assertEquals(proxy.execute(), "ok");
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}

运行testcase,Test表里面加了一条数据


   发表时间:2006-10-20  
引用
为了改造现在常用的ssh,tsh,wsh框架成sh,支持spring bean做Action(logic)

ssh,tsh,wsh是什么东西
0 请登录后投票
   发表时间:2006-10-20  
wolfsquare 写道
引用
为了改造现在常用的ssh,tsh,wsh框架成sh,支持spring bean做Action(logic)

ssh,tsh,wsh是什么东西


偶猜的...
struts/spring/hibernate
tapestry/...
webwork/...
0 请登录后投票
   发表时间:2006-10-20  
ssh是struts+spring+hibernate
tsh是tapestry+spring+hibernate
wsh是webwork+spring+hibernate
0 请登录后投票
   发表时间:2006-10-20  
到底是人玩框架还是框架玩人!
郁闷ing~~~~~
0 请登录后投票
   发表时间:2006-10-20  
galaxystar 写道
到底是人玩框架还是框架玩人!
郁闷ing~~~~~
不是啊,是我在开发过程中发现现存的框架都不能完全满足需要才自己做的这个东西啊,而且,每一个需求都是先写测试,再实现的,完全是从实际中来的,你可以down下source看看再说吗
0 请登录后投票
   发表时间:2006-10-20  
乱花渐欲迷人眼
0 请登录后投票
   发表时间:2006-10-20  
zhouxuanyi 写道

当webwork讥笑struts必须继承org.apache.struts.action.Action类的同时,他自己却必须实现com.opensymphony.xwork.Action接口,在pojo肆虐的当今,这无疑是五十步笑百步


1. 新的 xwork 版本 action 定义是 Object
zhouxuanyi 写道
还有,webwork对struts FormBean的改造,是使用ModelDriven拦截器来实现的,然而,ModelDriven只支持一个java对象,如果你的Action中想支持一个以上的Model,对不起,你自己做去吧


2.
  property driven
   
   public class FooAction {
       private Object o1;
       private Object o2   
   }   
   

zhouxuanyi 写道

同时,Action的结构混乱,传入和传出的对象,属性无法区分

3. Action 结构混乱? 难道楼主是将所有的相关业务放在一个 action 里 ?
0 请登录后投票
   发表时间:2006-10-20  
其实,我把文章发在这里,是想让大家看一下,提点建议,我在xyz的aop支持上一直很摇摆,不知道该怎么做好:
第一个解决方案:使用webwork那样的方式
<logic class="xxx">
   <interceptor ref="aaa"/>
</logic>
但是这与我的0配置思路不一致,而且,为了读取配置文件,写的类就需要十几个,在我这个只有80个类的框架是否复杂了,和简单的思路又不一致
第二个解决方案:使用java注解
@before( class="a.b.C")
@after(class="d.e.F")
public class Test{
   @before(class="g.i.H")
   @after(class="j.k.L")
   public void test(){
   }
}
但是这样是编程式的拦截,不是申明式的拦截,过于繁琐,不好改变
所以现在使用spring的aop,没有做,想让大家讨论一下,这3种解决方案的优劣和喜好
0 请登录后投票
   发表时间:2006-10-20  
Feiing 写道
zhouxuanyi 写道

当webwork讥笑struts必须继承org.apache.struts.action.Action类的同时,他自己却必须实现com.opensymphony.xwork.Action接口,在pojo肆虐的当今,这无疑是五十步笑百步


1. 新的 xwork 版本 action 定义是 Object
zhouxuanyi 写道
还有,webwork对struts FormBean的改造,是使用ModelDriven拦截器来实现的,然而,ModelDriven只支持一个java对象,如果你的Action中想支持一个以上的Model,对不起,你自己做去吧

我们用的最新的webwork2.2.4的xwork还是需要实现接口的

2.
  property driven
   
   public class FooAction {
       private Object o1;
       private Object o2   
   }   
   

就是不想使用propertydriven啊,那样必须user.name,user.passwd,而支持多个java对象model driven时,可以name,passwd啊
zhouxuanyi 写道

同时,Action的结构混乱,传入和传出的对象,属性无法区分

3. Action 结构混乱? 难道楼主是将所有的相关业务放在一个 action 里 ?

对,就是由于放到一起会导致结构混乱,另外,webwork的拦截器是类的,而不是spring那样方法的,为了方便拦截器配置,我们开发时一个动作一个类,导致类和配置文件大量膨胀啊,如果用xyz,就可以0配置了,而且,输入输出可以写在method的参数里,这样,不会导致混乱啊
0 请登录后投票
论坛首页 Java企业应用版

跳转论坛:
Global site tag (gtag.js) - Google Analytics