浏览 5828 次
锁定老帖子 主题:一个基于guice的开发平台
精华帖 (11) :: 良好帖 (0) :: 新手帖 (0) :: 隐藏帖 (0)
|
|
---|---|
作者 | 正文 |
发表时间:2008-08-26
首先说一下包含哪些第三方开源框架,在以前公司的项目中,都是本人搭建开发平台。 两年当中一之使用WebWork.Spring Hibernate这样的组合,现在肯定有人会说,那你用guice代替spring很简单啊,因为guice发布了一个plugin,可以直接应用到struts2中,而我用webwork迁移到struts2基本只需要用半小时就可全部搞定。当然我也试了,一切OK。但是发现一个问题,Guice Injector对象是在当用户访问一个Action之后才进行实例的,所以如果用户没有访问任何Action时候,你又象在Action之前通过Guice inject你需要的对象时候,是无奈的。什么时候会遇到这样的问题呢?HibernateSessionInView时候就会遇到。Spring提供的HibernateSessionInView实现是在Filter里,并且是在启动项目时候就将HibernateSessionFactory创建,所以在Filter里可直接引用SessionFactory,而我现在遇到的问题就是我是先到Filter然后才到Action,而第一次到Filter时Guice无法给我inject SessionFactory,所以,我又有了一个想法,把webwork也抛弃了吧,用了这么长时间的webwork对它的内部实现已经很清楚了,于是,我开始了自己的MVC层+guice+Hibernate的整合。保留webwork的经典Interceptor,自己的MVC也有这个机制,实现了的Interceptor有:1.Action CleanUp Interceptor 清理ActionContext. 2.Action Exception Interceptor 异常跳转 3.Action TokenValidator Interceptor Token验证 4.Action Params Interceptor httpServletRequest参数绑定 5.Action Result Interceptor result跳转 6.Action ReqSet Interceptor httpServletRequest.setAttribute 这6个拦截 而Action也没有定义在xml文件中了,而是以Annotation的方式来实现的 具体代码如下: @Action(name = "cpny", namespace = "/hr") public class SysCompanyAction extends ActionSupport<SysCompany> {} 正如大家看见的 这样定义一个Action,就可以用http://localhost/hr/cpny.action来访问默认执行execute方法 而webwork方便大家的也在于只要是Action的属性,并提供getter setter方法 都可以从http参数中自动求值,这点我也是基于Annotation实现的,只是起的名字有点怪,呵呵。 @ReqGet private Long id; @ReqGet private String _cpnyName; @ReqGet @ModelDriver @ReqSet private SysCompany sysCompany; id将从request参数中获取,并自动进行类型转换 _cpnyName也如此,而sysCompany则使用@ModelDriver 将request参数中的值封装为sysCompany对象。假设request中存在如下请求参数id=1&_cpnyName=javaeye&sysCompany.id=1&sysCompany.cpnyId=google 则会正确匹配并装换成功,sysCompany如果包含其他对象则可以sysCompany.object.id=1这样的形式 如同ognl。还一点需要和大家解释在webwork中使用valueStack的方式将整个Action压入stack中在用ww标签进行求值,而这一步我没有实现,因为如果那样我还需要写一套类似ww的标签,显得有些麻烦,本人比较懒,所以采用JSTL,那当然需要在request里setAttribute所以我用@ReqSet来代表在action执行完毕以后将这些属性自动set进去。这样大家就可在页面上用<c:out value="${sysCompany.id}"/>形式访问了 接下来到执行完成以后的页面跳转了,同样采用Annotation定义 @PageFlow(result = { @Result(name = "input", path = "/view/sys/editCompany.jsp", type = Dispatcher.Forward) }) public String input() throws Exception { if (id != null) { this.sysCompany = this.sysCompanyService.getCompanyById(id); } return "input"; } 大家一看就明白,也和webwork的xml类似。@Result可定义多个,针对有不同结果返回的方法。 而guice可直接在Action里Inject @Inject private SysCompanyService sysCompanyService; 免去了烦人的setter方法,呵呵 这样整个action无论是inject 还是从request获取参数都不再需要setter getter方法了,清爽了好多。 接着是也许我的一个创新,但是估计会招来骂声,就是DAO与Service的关系。以往的应用都是dao提供基本操作方法,Service调用Dao。Action调用Service.再平常不过了。而我在这里把DAO“省”去了。 大家先看看代码吧 @Singleton public class SysCompanyService { @Inject private SysCompanyDao sysCompanyDao; @Transactional(type=TransactionType.READ_ONLY) @FinderByCriteria(value=SysCompany.class,orderBy=@OrderBy(column="id")) public Page<SysCompany> getResultPage( @FirstResult int start , @MaxResults int limit, @LIKE(column="cpnyNameZh") String _cpnyName, @By(group="asd") String sort, @Order(group="asd") boolean isAsc ) { return null; } @Transactional(type = TransactionType.READ_ONLY) @FinderById(SysCompany.class) public SysCompany getCompanyById(@PK Long id) { return null; } @Transactional(type = TransactionType.READ_WRITE) @Persistence(PersistenceType.SAVEORUPDATE) public void saveCompany(@PO SysCompany sysCompany) { } @Transactional(type = TransactionType.READ_WRITE) @Persistence(PersistenceType.DELETE) public void deleteCompany(@PO SysCompany sysCompany) { }; @Transactional(type = TransactionType.READ_WRITE) public void deleteCompanyById(Long id) { this.deleteCompany(this.sysCompanyDao.getById(id)); } } 这样写的方式完全来源于基于guice Annotation的持久层框架warp-persistence 我只是做了一些扩展 比如@Persistence 需要指定PersistenceType参数携带@PO就能进行相应持久化操作 @FinderById需要指定PO.class,参数携带@PK 就能通过id查询对象。这样简单的操作 还有一个是@FinderByCriteria 做得过于复杂,不过是一个创新。至于能不能用在项目上不说,但是是我学习Annotation的一个阶段,而且我不再需要写任何dao 只需要声明一下Annotation,并且Service还是 @Singleton的。 现在重点解释一下@FinderByCriteria @Transactional(type=TransactionType.READ_ONLY) @FinderByCriteria(value=SysCompany.class,orderBy=@OrderBy(column="id")) public Page<SysCompany> getResultPage( @FirstResult int start , @MaxResults int limit, @LIKE(column="cpnyNameZh") String _cpnyName, @By(group="myOrderBy") String sort, @Order(group="myOrderBy") boolean isAsc ) { return null; } @FinderByCriteria(value=SysCompany.class,orderBy=@OrderBy(column="id"))第1个参数为查询的PO.class,而后面可任意追加一些固定的条件和排序方法,以上为追加了固定的按id进行ASC排序的条件 接着@FirstResult int start ,@MaxResults int limit,指名需要进行分页操作,并传入参数,@LIKE(column="cpnyNameZh") String _cpnyName,表示对cpnyNameZh进行模糊查询 @By(group="myOrderBy") String sort,@Order(group="myOrderBy") boolean isAsc,则接收用户需要以哪个字段进行升或降序的排序方式 注意中间一个参数group="myOrderBy" 表示@By ,@Order 是一组 by接收需要排序的字段而isAsc接收升或降序方式 这样在后台生成的SQL语句则是 select * from ( select this_.id as id0_0_, this_.CPNY_ID as CPNY2_0_0_, this_.CPNY_NAME_EN as CPNY3_0_0_, this_.CPNY_NAME_KO as CPNY4_0_0_, this_.CPNY_NAME_ZH as CPNY5_0_0_, this_.CREATED as CREATED0_0_, this_.CREATEDBY as CREATEDBY0_0_, this_.UPDATED as UPDATED0_0_, this_.UPDATEDBY as UPDATEDBY0_0_, this_.USE_YN as USE10_0_0_ from SYS_COMPANY this_ where this_.CPNY_NAME_ZH like ? order by this_.CPNY_NAME_ZH asc, this_.id asc ) where rownum <= ? 说得有些乱,不知道各位理解没理解。发帖只是想让各位高手批评批评。我有哪些没考虑到的或者哪些不应该这样做的。 声明:ITeye文章版权属于作者,受法律保护。没有作者书面许可不得转载。
推荐链接
|
|
返回顶楼 | |
发表时间:2008-08-26
以下帖出Action代码
@Action(name = "cpny", namespace = "/hr") public class SysCompanyAction extends ActionSupport<SysCompany> { @Inject private SysCompanyService sysCompanyService; @ReqGet private Long id; @ReqGet private String _cpnyName; @ReqGet @ModelDriver @ReqSet private SysCompany sysCompany; /** * 不执行任何操作 跳转至/view/sys/company.jsp */ @PageFlow(result = { @Result(name = "success", path = "/view/sys/company.jsp", type = Dispatcher.Redirect) }) public String execute() throws Exception { return "success"; } /** * 获取list json输出 ajax不需要配置@PageFlow * @return * @throws Exception */ public String list() throws Exception { page = this.sysCompanyService.getResultPage(start, limit, _cpnyName,sort,isAsc()); if (page != null) { List<SysCompany> companyList = page.getResultList(); JSONObject root = new JSONObject(); JSONArray arrayItems = new JSONArray(); if (companyList != null) { for (SysCompany cpny : companyList) { JSONObject Item = new JSONObject(); Item.put("ID", cpny.getId().toString()); Item.put("cpnyId", StringUtils.defaultIfEmpty(cpny .getCpnyId(), "")); Item.put("cpnyNameZh", StringUtils.defaultIfEmpty(cpny .getCpnyNameZh(), "")); Item.put("cpnyNameEn", StringUtils.defaultIfEmpty(cpny .getCpnyNameEn(), "")); Item.put("cpnyNameKo", StringUtils.defaultIfEmpty(cpny .getCpnyNameKo(), "")); arrayItems.add(Item); } root.put("Items", arrayItems); root.put("totalCount", Integer.toString(page.getTotalRecord())); } writeTextByAction(root.toString()); } return null; } /** * 通过id获取对象 至修改 添加页面 * @return * @throws Exception */ @PageFlow(result = { @Result(name = "input", path = "/view/sys/editCompany.jsp", type = Dispatcher.Forward) }) public String input() throws Exception { if (id != null) { this.sysCompany = this.sysCompanyService.getCompanyById(id); } return "input"; } /** * 持久化一个对象 * @return * @throws Exception */ @PageFlow(result = { @Result(name = "saveSuccess", path = "/hr/cpny.dhtml", type = Dispatcher.Redirect) }) @Token public String save() throws Exception { if (this.sysCompany != null) { bind(this.sysCompany); this.sysCompanyService.saveCompany(this.sysCompany); } return "saveSuccess"; } /** * 通过id删除一个对象 * @return * @throws Exception */ @PageFlow(result = { @Result(name = "deleteSuccess", path = "/hr/cpny.dhtml", type = Dispatcher.Redirect) }) public String delete() throws Exception { if (id != null) { this.sysCompanyService.deleteCompanyById(id); } return "deleteSuccess"; } } 以下帖出@LIKE @EQ 代码 @LE @LT @GE @GT @BETWEEN等都是同理 /** * <p> * 在使用@FinderByCriteria查询时候在方法中使用<br/> * 标识需要进行模糊条件查询<br/> * column:配置entity里需要进行约束的字段名称<br/> * ignoreCase:配置是否忽略大小写 默认为false<br/> * not:配置条件是否为反向默认为false<br/> * ignoreBank:配置是否忽略空对象或者空字符串 默认为true<br/> * reloation:配置当前约束是否存在和其他约束的连接约束关系 默认为Relation.NULL<br/> * or:如果当前约束reloation=Relation.OR,则配置or策略配置,须和reloation一起使用<br/> * and:如果当前约束reloation=Relation.AND,则配置and策略配置,须和reloation一起使用<br/> * matchMode:配置模糊匹配策略 默认为Match.ANYWHERE<br/> * </p> * @author zhenjia <a href='mailto:zhenjiaWang@gmail.com'>email</a> * @since JDK1.5 * @version 1.0 $Date:200808 * */ @Target(ElementType.PARAMETER) @Retention(RetentionPolicy.RUNTIME) public @interface LIKE { /** * * @return 返回需要进行模糊条件约束字段 */ String column(); /** * * @return 返回是否忽略大小写 */ boolean ignoreCase() default false; /** * * @return 返回是否为反向条件 */ boolean not() default false; /** * * @return 返回是否忽略空白字符串 */ boolean ignoreBank() default true; /** * @see Relation * @return 返回连接关系 */ Relation relation() default Relation.NULL; /** * @see OR * @return 返回OR策略 */ OR or() default @OR(group = ""); /** * @see AND * @return 返回AND策略 */ AND and() default @AND(group = ""); /** * @see Match * @return 返回模糊匹配方式 */ Match matchMode() default Match.ANYWHERE; } /** * <p> * 在使用@FinderByCriteria查询时候在方法中使用<br/> * 标识需要进行等于条件查询<br/> * column:配置entity里需要进行约束的字段名称<br/> * ignoreCase:配置是否忽略大小写 默认为false<br/> * not:配置条件是否为反向默认为false<br/> * ignoreBank:配置是否忽略空对象或者空字符串 默认为true<br/> * reloation:配置当前约束是否存在和其他约束的连接约束关系 默认为Relation.NULL<br/> * or:如果当前约束reloation=Relation.OR,则配置or策略配置,须和reloation一起使用<br/> * and:如果当前约束reloation=Relation.AND,则配置and策略配置,须和reloation一起使用<br/> * </p> * @author zhenjia <a href='mailto:zhenjiaWang@gmail.com'>email</a> * @since JDK1.5 * @version 1.0 $Date:200808 * */ @Target(ElementType.PARAMETER) @Retention(RetentionPolicy.RUNTIME) public @interface EQ { /** * * @return 返回需要EQ约束的字段 */ String column(); /** * * @return 返回是否忽略大小写 */ boolean ignoreCase() default false; /** * * @return 返回是否为反向条件 */ boolean not() default false; /** * * @return 返回是否忽略空白字符串 */ boolean ignoreBank() default true; /** * @see Relation * @return 返回连接关系 */ Relation relation() default Relation.NULL; /** * @see OR * @return 返回OR策略 */ OR or() default @OR(group = ""); /** * @see AND * @return 返回AND策略 */ AND and() default @AND(group = ""); } service代码已经在主帖中给出 |
|
返回顶楼 | |
发表时间:2008-08-27
看得人挺多。就没一个能给我一点意见吖。。。
|
|
返回顶楼 | |
发表时间:2008-08-27
有点像T5
|
|
返回顶楼 | |
发表时间:2008-08-27
jessdy 写道 有点像T5
T5?今天首页的那个新闻? 。。一直不知道那个是什么东西。。。。有时间去看看 |
|
返回顶楼 | |
发表时间:2008-08-27
的确像T5,但是本质上是webwork。
Annotation使用的稍微有些多了。还是很棒。 |
|
返回顶楼 | |
发表时间:2008-08-27
侵入~侵入~~侵入~~~
其实guice不太适合做应用,而适合做框架或者内核使用。因为它的依赖注入是以一种侵入的紧耦合的方式进行的~而框架之类的内部是必然紧耦合的。 |
|
返回顶楼 | |
发表时间:2008-08-27
fireflyc 写道 其实guice不太适合做应用,而适合做框架或者内核使用。因为它的依赖注入是以一种侵入的紧耦合的方式进行的~而框架之类的内部是必然紧耦合的。
非常精辟!但guice松耦合也未尝不可,自己定义一种配置文件格式,然后内部用guice,就和spring一样了。 |
|
返回顶楼 | |
发表时间:2008-08-27
jasongreen 写道 fireflyc 写道 其实guice不太适合做应用,而适合做框架或者内核使用。因为它的依赖注入是以一种侵入的紧耦合的方式进行的~而框架之类的内部是必然紧耦合的。
非常精辟!但guice松耦合也未尝不可,自己定义一种配置文件格式,然后内部用guice,就和spring一样了。 恩,我也提供了一个专门的XML配置文件,配置GUICE的每个module,而用guiceAop实现的Interceptor也是基于interface 可自己实现。 |
|
返回顶楼 | |
发表时间:2008-10-16
不错·不错
guice有一个针对servlet的jar,里面有RequestScoped和SessionScoped 两个annotation专门针对request,session的域注入。 想问一下LZ,关于request和session这2个scope你是怎么处理的呢? |
|
返回顶楼 | |