scope="singleton">
...
...
...
UserService.queryUser(String scope,Collection[String] paras,int begin,int max)
...
通过上面的结构可以看见,每一个EasyJWeb配置文件的根元素均为
,在
元素下面可以包含0或一个
元素、0或1个
元素、0或1个
元素、0或1个
元素、0或1个
元素,根据项目的性质可以选择使用这些元素,下面将分别对这些元素作简单的介绍。关于EasyJWeb的配置文档的详细定义,请参看DTD和schemle。
这个元素主要用来定义EasyJWeb的一些基本信息及全局信息,包括工作模式、模板位置、附件最大值、初始应用程序,全局拦截器等。其下\包括
等子元素。
用来定义EasyJWeb的基本运行参数,如下面的配置信息:
用来配置伴随EasyJWeb启动而启动执行的应用程序,这些程序一般可以作额外的初始工作,或者是以一个新线程的形式在系统中运行。如下面是EasyJF开源Blog系统中,自动生成静态html文件的程序:
元素下面是EasyJWeb的模块信息,在EasyJWeb中,可以把功能相关或形式的相近的请求处理程序封装到一个模块Module中,元素下面包含0或多个元素,在中将包含具体的Module配置信息,Module是EasyJWeb应用程序中重要的概念,我们将在后面详细介绍元素的详细配置。
元素下面包含0或多个
元素用来定义前台页面表单的信息。在普通的应用中,一般不使用这个配置选项。
元素下面包含0或多个元素,元素一般为业务层对象,关于的配置将在后面专门介绍。
元素主要用来定义应用程序中支持远程javascript脚本访问的业务对象,下面包含0或多个
元素,0或多个
元素,0或多个
元素,我们将在Ajax一章中专门介绍。
Module标签定义了一个Module对象。根据前文对Module对象的讲解,应该能够很直观的了解Module的配置。Module中包含了Page对象(Page一节),控制器(Module一节),拦截器(AOP和拦截器一章),注入的bean(容器一章)分别介绍其配置。
Tip
在一个配置文件中,并不要求包含所有的以上的元素,请根据实际情况配置最小需要的元素。比如如果按照我们推荐的mvc文件分布,则在主文件mvc.xml中,只需要配置包含文件、
、错误处理器以及和Spring等容器集成的基础配置。而在各个子配置文件中只需要
或者
标签。
WebForm是EasyJWeb的一个重要的组件,在这一小节中,将介绍PO和WebForm的toPo方法。在验证一小节中介绍toPO方法中的验证。
PO
PersistenceObject,持久化对象,VO value Object,值对象,TO Translate Object 传输对象,在EasyJWeb中,WebForm扮演了VO和TO,而PO直接由Domain扮演。
toPo方法
在一个带参数的请求中,或者是在一个有表单域的请求中,如何从中取得值,用于保存对象或者处理?在Struts1.x中,使用了一个ActionForm来承载这些数据;struts2.x中,使用Controller作为Command对象来承载这些数据;springMVC中,可以使用带Command对象Controller,使用一个Command对象来承载这些数据;而在EasyJWeb中,是WebForm承载了这些数据,并且使用一个toPo方法来直接将这些数据拷贝到需要持久化的对象中。比如下面一个代码片段演示了保存一个论坛帖子的功能:
public Page doSave(WebForm form, Module module) {
BBSDoc doc = form.toPo(BBSDoc.class);
List attachs = ActionUtil.saveFile(form, webConfig
.getImageDirPath(), false);
doc.setIp(ActionContext.getContext().getRequest(). getRemoteAddr());
List attachList = this.binaryService
.addAttachMent(attachs);
doc.setFiles(attachList);
this.service.addBBSDoc(doc);
return this.doBbsList(form, module);
}
在WebForm中,有两种toPo方法:
WebForm.toPo(Object obj):传入一个对象,直接从WebForm中拷贝值到改对象中。
WebForm.toPo(Class clazz):传入一个类型,WebForm会初始化这个类型的实例再将WebForm中的值拷贝。关于属性的拷贝,有几点注意:1,只会拷贝属性相同的值,比如提交的表单中包括一个name,那么,在持久化对象或者Command对象中,只会拷贝String、Integer的name属性。
使用@FormPO标签来规定拷贝的规则:
inject:
指定可通过toPo自动注入的属性,默认为全部可自动注入;如果设置了该值,则表示除指定可注入的属性以外,其它所有属性都为不能自动注入;在EasyJWeb中,可以直接通在模型(域)对象上通过标签来指定只允许注入哪些属性值。如果一个属性值为可注入的,则可以使用WebForm.toPo(obj)方法,把WebForm中与obj属性名称相同的属性值设置到obj中。需要注入的属性使用逗号(,)作为分逗符。比如: @FormPO(inject="name,bornDate")
public class Person
即在Person类(或者Command对象)中,当使用toPO方法拷贝值的时候,只有name和bornDate属性被拷贝,其余如果有符合的属性,都不准被拷贝。这在很大的层度上提高了应用的安全性。
disInject:
指定不可通过toPO自动注入的属性,当试图通过toPO更新该属性时,将会被忽略,并在日志中提示相关信息。在EasyJWeb中,一个模型(域)对象的属性默认情况下全部都是可注入的,我们可以通过disInject来指定不可注入的属性。多个不可注入的属性使用逗号(,)作为分隔。如上面inject示例,也可以写成下面的形式:
@FormPO(disInject="id,loginTimes")
public class Person
Tip:
在实际应用中,可以根据实际情况选择使用inject及disInject,如果需要拷贝的属性较多,则选择disInject;而拷贝的属性较少,则选择inject。
控制addPo属性的可见性:
前文在介绍WebForm的时候,提到了addPo方法,在这个方法中,其实也有控制标签:
disRead:
指定为disRead的属性在addPo方法中不会被添加到Velocity上下文中。
下面,给一个这些标签的使用的一个范例:
@Entity
@FormPO(name = "person",inject="name,sex,mail,intro",disInject="age",disRead="serialVersionUID,id")
public class Person implements Serializable {
@Id
@GeneratedValue(strategy = GenerationType.TABLE)
private Long id;
@Column(length = 32)
private String name;
@Column(length = 6)
private String sex;
@Column(length = 40)
private String mail;
private int age;
@Column(length = 200)
public String intro;
}
在这个例子中,如果调用WebForm.toPo(Person.class),那么Person中的name、sex、mail将会拷贝,而age不会被拷贝,并且调用WebForm.addPo()方法时,Person的serialVersionUID和id将不会被添加到Velocity上下文中。关于更多@FormPO标签的用法,请参见API doc。
在EasyJWeb中,最常用的方法是通过WebForm.toPo方法在拷贝属性的过程中执行验证,同时,也可以调用FramewokEngine.form2Obj方法执行验证。
EasyJWeb不使用传统的XML配置来完成验证,我们认为,验证应该是和PO或者Command对象紧密相连的,为了避免大量的XML文件的存在,采用了Annotation来完成验证。EasyWeb同时也不推荐使用过多的Annotation,从而造成Annotation泛滥,因此EasyJWeb的验证标签只有一个,即@Validator。
EasyJWeb完善了验证系统,使验证变得更加容易、灵活、统一控制。你可以使用非常简单的标签或配置就能使系统拥有服务器端及客户端验证的功能。
下面以一个简单的示例:
有一个Person模型,如下所示:
包含id、name、sex、borndate、height、mail、homepage等几个属性。
假如我们要让name、sex、heigth、borndate必填,并且borndate必须在1908到2008年之间, mail属性只接收正确的email信息,homepage必须接收url信息。则我们只需要在Domain对象(可以是Entity对象,也可以是传输Command对象)中加入下面的配置信息,即可。
@FormPO(name="person",validators={@Validator(name="required",field="name,sex,heigth,borndate"),@Validator(name="range",field="borndate",value="min:1908-01-01;max:2008-01-01"),@Validator(name="email",field="mail"),@Validator(name="url",field="homepage")})
public class Person{
private Long id;
private String name;
private String sex;
private String mail;
private Integer heigth;
private Date borndate;
public String homepage;
…//setter及getter方法
}
不需要进行复杂的配置,只需要使用符合人类语言习惯的简单标注,就能实现所需要的验证业务逻辑。
@Validator验证标签的使用非常灵活,你只要具有充分的想像力,就能描述出符合特定需要的验证逻辑。比如上面的例子中,我们规定name不允许为空,字符数最小不能少于5个,最大不能超过10个,在进行字符验证前需要清除掉前后的空格。则我们可以使用下面的验证标签:
@Validator(name=”string”,value=”blank;trim;required;min:5;max:10;minMsg:最少不能少于5个字符;maxMsg:最大不能超过10字符”)
private String name;
统一的验证标签@Validator
EasyJWeb中只有一个用于验证的Annotation,即@Validator,通过一个@Validator,就能标签任意类型的验证,使用起来非常简单。@Validator的代码如下所示:
public @interface Validator {
public String name();// 验证器的名称,如required,string,range等
public String value() default "";// 验证器的值,使用;号作为分隔符存放各个参数。如value="required;min:5;max:20"
public String msg() default "";// 默认错误提示信息,当验证无法通过时显示的提示信息
public String field() default "";// 字段名称,对于property及field类型的校验均可用,也是错误对象的主属性名称。可以用于多个字段,此时需要使用,隔开
public String displayName() default "";// 定义对象的显示名称,默认情况下为field的名称,可以通过@Field中的name属性定义。
public ValidateType type() default ValidateType.Property;// 校验类型,默认是对属性进行校验
public boolean required() default false;// 是否必填字段,每个验证器都可以通过设置属性required=true来指定该属性为必填项
public String key() default "";// 多国语言显示值的编码
}
Validators.RequiredValidator-用来定义必填属性,预定义名称required。
Validators.StringValidator-字符串验证器,定义字符串的属性,预定义名称string。
Validators.URLValidator-URL字符串验证器,匹配一个合法的URL,预定义名称url。
Validators.RegexpValidator-正则表达式验证器,匹配指定条件的正则表达式,预定义名称regex。
Validators.EmailValidator-Email字符验证器,匹配正确的email字符串,预定义名称email。
Validators.RangeValidator-范围验证器,用来限制属性必须在指定的范围之内,预定义名称range。
验证器引擎的触发也是非常灵活的,如果是普通的CRUD应用或者是基于普通CRUD应用基础上扩展的应用,则在基本的添删改查中会自动调用验证逻辑。
如果是自定义的Action,可通过调用form.toPo等方法触法验证逻辑。如果是使用IDAO接口进行的调用,则在进行数据持久化之前会调用验证逻辑。
关于内置验证器的更多细节,请参看API doc。
要自定义验证器很简单,只需要实现Validator接口,即可注册到系统中使用。在实际应用中,一般通过使用继承抽象类AbstractValidator来实现自定义的验证器。如下面是最简单的验证器Required的实现:
public class RequiredValidator extends AbstractValidator {
public RequiredValidator() {}
public void validate(TargetObject obj, Object value, Errors errors) {
if (value == null)
addError(obj, value, errors);
else if (value instanceof String) {
}
}
public String getDefaultMessage() {
return "{%0}不能为空!";
}
}
在完成了自定义的验证器后,只需要在容器中声明该bean,并将bean的名字设置为需要调用的验证器的名字即可。比如如果要将上面的RequiredValidator作为notNull验证器使用,则在容器中配置:
即可,然后在Domain或Command对象中可以通过@Validator(name="notNull")来标注使用该验证器。
EasyJWeb中使用了Errors对象来包装在验证过程中出现的错误,该对象提供了三个有用的方法:
int getErrorCount():用来显示出错的个数;
boolean hasError():用来显示是否有错;
String getMessage(String fieldName):用来显示某一个属性的错误;
在页面中显示错误:
$!errors-显示全部验证错误信息。
$!errors.name-显示name属性(字段)的错误信息。
如下面的的Form
请输入姓名:$!errors.name
电子邮箱:$!errors.mail
在代码中获得错误:
在Action中,如果要捕获错误,即得到Errors对象,使用:
FrameworkEngine.getValidatorManager().getErrors()方法来得到一个验证错误对象Errors。通过Errors可以检查是否包含未通过的验证逻辑,从则作相应的处理。
匹配错误的处理:
如果发生匹配错误,有三种处理方式:
1,忽略,在toPo方法中,设置validateRollback为false,则发生匹配错误继续匹配下面的属性。
2,回滚,在toPo方法中,设置validateRollback为true,那么在发生匹配错误时,将已经拷贝了的属性还原到拷贝之前。这在使用JPA作为持久层的时候特别有用,避免了设置flushMode。
3,强制性出错,在中设置validate为true,则在匹配出错时,马上抛出一个框架错误,不会继续向下匹配。
关于错误显示的更多细节,请参看相关API doc。
在EasyJWeb中提供了自定义错误处理机制。如果在控制器中发生了错误,那么可以根据配置,来完成对特定错误的特定处理过程。
要实现错误处理器,需要实现com.easyjweb.interceptor.ExceptionInterceptor接口,该接口定义了一个方法:
boolean handle(Throwable e, Object target, Method method, Object[] args) throws Exception;
其中,e是出现的异常,在自定义的错误处理中,可以判断这个e是否instanceof你需要处理的Excepion,而选择是否处理。Target是异常出现的对象,一般来说会是控制器对象。Method是异常抛出时调用的方法,args是相关参数,这几个参数都是AOP拦截器规定的参数。该方法返回了一个boolean值,如果返回true,则表示异常已经成功处理,不再需要作其它的处理,返回false则,表示把异常交给下一级异常处理器进行处理,如果抛出异常,则表示将直接把异常交给外部程序或发给用户。可以在自定义的错误处理器中完成自定义的错误处理规则。比如根据错误的不同,显示不同的错误页面。如果配合target和method参数,甚至可以将出错页面的导向细化到每一个Action的每一个Method上。
在完成了自定义的错误处理器后,可以直接配置一个Bean,这样EasyJWeb会自动使用该异常处理器来处理在系统运行过程中出现的特定的异常。所有实现ExceptionInterceptor的异常处理器会会构成一个错误处理器链,来协作处理Action中抛出的错误。在这条错误处理器链的最后,是系统级别的DefaultExceptionHandle,可以在容器中配置该处理器,在这个处理器中,如果不配置这个处理器,或者在容器中没有对这个处理器做特别的配置,将显示默认的错误提示页面。在这个处理器中,可以通过配置errorPage属性,来定义自己的出错页面。
EasyJWeb提供了一些有用的工具类来辅助开发,提高开发效率。
CommUtil提供了很多常用的方法,其中分页是重要的一个。CommUtil不光只用在后台控制器中,而且EasyJWeb内置的将CommUtil的一个实例放入了Velocity上下文中,使得可以直接在前台使用$CommUtil来调用。下面介绍CommUtil的几个常用方法:
l $!CommUtil.formatDate(formatStr,Date):
按照规则格式化时间。Date为传入的类型为Date的时间对象,formatStr是格式化样式,使用的是SimpleDateFormat 格式化,比如$!CommUtil.formatDate("yyyy-mm-dd",$date)就可以将date显示为2000-12-29类似的样式,关于格式化字符请参见SimpleDateFormat。
l $!CommUtil.longDate(Date):
完整的时间格式化,样式为yyyy-MM-dd H:m:s。
还有更多的时间格式化样式,比如显示中文时间的等等,请参见CommUtil的API文档。
l CommUtil.null2String(nameStr):
在Action中常用的方法,一般用于从WebForm取得字符串性的属性:
String idStr=CommUtil.null2String(form.get("id"));
if(!"".equals(idStr)){
//...
该方法避免对null的验证。如果是null,返回"";
同时,也提供了一个null2int方法,如果属性为null,返回0。
l $CommUtil.toRowChildList($List,sizePerRow):
将一个List转换成sizePerRow为每行的一个List的List:List
在页面显示的时候特别有用,我们经常遇到在页面上需要把一个list分成几行来显示,不需要太多的VTL,也不需要vmacro,只需要:
$foreach($subList in $!CommUtil.toRowChildList($!infoList,num))
$foreach($info in $!subList)
$info.show()
$end
$end
更多的CommUtil方法请参见API 文档。
EasyJWeb提供了一个比较完整的分页接口和相关工具。IPageList接口定义了一个分页对象的信息,IQuery接口定义了分页查询的方法。
在IPageList中定义了比如当前页,所有页面数,每页大小等信息。
常用的分页组件:
EasyJWeb提供了一个为List对象分页的组件,只需要象下面这样使用:
IPageList pList=new PageList(new ListQuery(resultList));
pList.doList(pageSize,currentPage,null,null);
这样就得到了一个IPageList对象了,这里面有完整的分页信息。同时EasyJWeb提供了CommUtil.saveIPageList2WebForm(IPageList,WebForm),使用该方法可以快速的将分页信息放入Velocity上下文中,并且自动生成翻页需要的html。通用的在页面的分页使用为:
在列表页面上放入一个Form,添加两个hidden域:
第一个是用于保存每页的记录数,第二个保存当前页面,
在需要放置分页的位置添加:
共$!rows条 第$!page/$!pages页 每页$!pageSize条 $!pagination
其中,$rows是所有的条数,$page是当前页数,$pages是总共条数,$pageSize是每页的条数,$pageination是EasyJWeb生成的分页HTML,如下图:

同时,EasyJWeb为JPA+Spring+EasyJWeb的应用提供了一个JPA的分页组件:QueryUtil。只需要把查询的条件包装为IQueryObject的子类,就可以使用
public static IPageList query(IQueryObject queryObject,Class entityType,GenericDAO dao)来完成整个分页过程。
关于更多分页和实现自定义分页请参见相关文档。
tagUtil也是EasyJWeb内置的加入到了Velocity上下文中的用于生成页面标签的工具类。下面列举几个常用的方法:
l String options(final List list,final String valuePoperty,final String titlePoperty,final String value):
用于根据一个list生成多个选择项,其中,list是需要用于生成选择项的对象的列表,比如List;valueProperty是用于生成选择项的value的属性,比如要使用User的id生成,那么就填id;titleProperty:用于生成选择项的名字的属性,比如要使用User的name生成,这里就填name;value,根据value来设置选择项,比如在选择总经理的一个页面中,已经选择了某个user为总经理,那么在修改的时候,要选中这个user,这里只需要传入已经选中的user的id就可以在确定的user的选择项中添加selected="selected"。
在tagUtil里面还有生成分页HTML的方法,在自定义分页HTML样式时,可以参考这些方法。
更多的关于tagUtil的用法请参看API doc。
EasyJWeb内置了一个验证码生成和检查器,如果你的应用需要加入一个验证码,只需要:
1,在mvc.xml里面添加:
action="com.easyjf.cms.mvc.RandomImgCode" defaultPage="" />
2,在页面上需要显示验证码的位置添加类似:
style="cursor:pointer;" alt="点击这里换一个"
onclick="this.src='randomCode.ejf?'+Math.random()";>
3,在接受这个验证码的Action中添加类似代码:
String randomCode = (String) ActionContext.getContext().getSession()
.getAttribute("rand");
if (!randomCode.equals((String) form.get("randCode"))) {
form.addResult("msg", "验证码不正确,请重新输入!");
return this.doRegisterPU(form, module);
}
即可完成整个验证。
如果要生成自定义的验证码,可以参看ImageCode和RandomImgCode的实现。
EasyJWeb提供了一个简单,但功能完整的IoC容器,并且该容器能很好的和其他容器并肩作战,形成一个超级IoC容器。在本章中,我们将详细介绍EasyJWeb容器的使用,并介绍容器间的整合。
EasyJWeb提供了一个内置的IoC容器,该容器不但能做为一个IoC容器配合EasyJWeb一起使用,而且还能通过简单的配置集成Spring、Guice等其他容器,借用其他容器强大的功能,比如事务管理等。同时,EasyJWeb使用@Inject标签等,使得使用容器中的bean更加简单和透明。
IoC(Inversion of Control)中文译为控制反转,业界最初的定义是指框架所拥有的一种管理业务对象的能力,重点在于管理组件中和其依赖的业务对象。随着大家对IoC认识的提高,IoC的概念也更加清晰:IoC作为一种设计模式,意味着在系统开发过程中,组件中业务对象以及组件之间的关系将交由容器去控制,而不是由类自己控制,实现了IoC模式的框架有一种从组件外部把所依赖的业务对象注入到组件中的能力,即"don't call us, we'll call you",也即“不用你找,让我们(框架)来提供给你”;另外,IoC容器还提供定位器Locater功能,使得在应用程序中可以通过统一规范的名称从容器中查找并取出所需要的组件。因此,准确地说,IoC是一种容器框架模式,具有以统一的方式负责组件及业务对象的注册、贮存及查询功能,另外还具有往组件中注入所需要的业务对象的能力。前者叫做定位器,也可以称为依赖查询,后者称为依赖注入DI。
关于IoC的更多资料,可以参见《J2EE without EJB》和EasyJF的《深入Spring》。
EasyJWeb提供了一个简约而不简单的IoC容器。在本小节中,我们首先来看作为一个IoC容器的基本使用方法,在下一小节中将看到该容器更高级的使用。
Bean
在应用开发中,经常会使用到组件、服务或业务对象等词,由于这些词的理解可大可小,不同的角度可以用不同的名称代表同一个东西,为了与传统混乱的定义区别开来,统一使用“Bean”这个名称来标识系统中的部件,这些部件可能是一个功能简单的对象,甚至仅仅是一个String字符串对象,也可以是一个功能强大的组件或服务。
Bean是应用程序中的基本元素,应用程序,就是由一个又一个的Bean组合在一起、像搭积木一样堆出来的。所有的Bean都由核心容器负责管理、创建、销毁,同时Bean之间的相互依赖也由容器中的依赖注入功能自动管理。对于一个具体的应用来说,Bean就是一个DAO对象,一个Service对象,Module对象,工具类等等所有构成应用的对象。
配置一个Bean
在EasyJWeb中配置一个bean是很简单的事情,下面是配置EasyJWeb配置bean的基本样式:
class="com.easyjf.web.exception.DefaultExceptionHandle"
scope="singleton">
Bean都包含在一个标签内。
一个bean由名字,类型,生命周期,bean属性等构成。在上面的配置文件中,我们配置了一个全局默认错误处理器(请参见错误处理一章),该bean的名字为exceptionHandler,类型为DefultExceptionHandle,类型为singleton(单例)。其中为该bean配置了一个属性,该属性是DefultExceptionHandle中的String errorPage属性。
Bean的属性注入类型
EasyJWeb中可以通过属性注入,也可以通过构造方法注入。
使用属性注入时,需要设置属性的setter方法,比如:
publicclass Person implements IPerson {
private String name;
privateintage;
private IPerson father;
private IPerson mother;
public Person(String name,int age,IPerson father,IPerson mother){
this.father=father;
this.mother=mother;
this.name=name;
this.age=age;
}
public IPerson getFather() {
returnfather;
}
publicvoid setFather(IPerson father) {
this.father = father;
}
publicint getHeight() {
returnheight;
}
publicvoid setHeight(int height) {
this.height = height;
}
public IPerson getMother() {
returnmother;
}
publicvoid setMother(IPerson mother) {
this.mother = mother;
}
public String getName() {
returnname;
}
publicvoid setName(String name) {
this.name = name;
}
}
就可以通过属性注入,配置文件如下:
这样,在通过容器得到一个son对象的时候,其name、age、father和mother属性都被注入了配置的值了。
同样,该对象申明了构造方法,我们也可以通过构造方法来注入,配置文件如下:
type=Integer value=10 />
在实际开发中,我们建议最好使用属性注入。
Bean的属性注入
向bean中注入属性,有几种情况,1注入一个简单对象;2注入一个复杂对象;3注入一个bean。
l 注入一个简单对象:
l 注入一个复杂对象:
在EasyJWeb的容器中可以注入List、Map、数组等。
比如注入List:
class="org.springframework.web.context.support.XmlWebApplicationContext">
WEB-INF/classes/application.xml
在类org.springframework.web.support.XmlWebApplicationContext里,configLocations声明为一个List对象。
l 注入一个bean
在上面的例子中已经看到,注入一个bean使用标签ref,指向一个名字为该bean的对象。比如在Person例子中,son这个bean在初始化(从容器中)时,father属性就会去匹配名字为father的bean,然后在将该father bean初始化,并注入。
Bean的类型
在EasyJWeb中,bean有四种类型:singleton、prototype、session和request。Bean的类型通过标签的type来指定。其中:
singleton:表示在一个应用上下文中,只存在一个该bean的实例。主要用于服务等对象。
prototype:每次请求都重新生成一个新的对象。
session:在一个session生命周期内都存在,主要用于比如购物车等对象。
request:在一个请求生命周期内存在,每一次请求重新创建一个新的bean。
Bean的注入
Bean可以通过设置自动注入来自动的完成注入。在标签中,设置属性auto或者inject来设置是否自动注入或者手动注入。如果是自动注入,不用配置property属性,将根据对象的类型从整个容器中寻找匹配bean。如果是inject(默认),则需要通过手动的配置property来完成依赖注入。
同时,EasyJWeb提供了@Inject和@disInject标签来简化注入配置。这两个标签在应用中大量使用。
@Inject使用在bean之内,比如刚才的Person例子,使用@Inject我们可以重写为:
publicclass Person implements IPerson {
private String name;
privateintage;
@Inject(name="father")
private IPerson father;
@Inject(name="mother")
private IPerson mother;
//setter
那么,配置文件中就不需要再为father或者mother配置属性了。
另外,如果我们在配置文件中设置了auto,那么,在bean中不需要注入的对象,就一定要加上@disInject标签,来表明该属性不需要注入,否则会抛出类型bean没有找到的错误。
容器和Module
在EasyJWeb中,Module也是bean。在其中可以直接添加
标签来为Module包装的那个Action注入服务对象。比如:
@Inject(name="personDao")
public void setDao(GenericDAO
dao) {
this.dao = dao;
}
在上面的CrudAction示例中,PersonAction需要一个DAO才能工作,在这里我们声明使用的是GenericDAO
,通过@Inject标签,EasyJWeb会从超级IoC容器中查找名为personDao的对象,并注入到这个Action中,从而使得我们的Action能正常工作。
注意一点,使用EasyJWeb的容器,一定要在EasyJWeb框架启动的环境下才能正常使用。
在EasyJWeb中,包括中央处理器RequestProcessor、验证器Validator、异常处理器ExceptionHandler在类的这些底层核心组件,都是通过EasyJWeb的容器来管理的。因此,你可以非常容易地根据自己的需要,更换EasyJWeb的一些部件。
下面是在EasyJWeb容器中加入Spring容器的配置:
class="org.springframework.web.context.support.XmlWebApplicationContext">
WEB-INF/classes/application.xml
class="com.easyjf.container.impl.SpringContainer">
可以在Spring容器中配置EasyJWeb的中央处理器,甚至可以配置事务等,如下面的Spring配置文件:
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">
expression="execution(* com.easyjf.web.RequestProcessor.process(..))" />
pointcut-ref="easyjwebProcessor" />
transaction-manager="transactionManager">
完成容器的兼容主要是通过适配器模式,有了EasyJWeb提供了InnerContainer接口,你可以实现和你能想到的容器之间的关联。自定义的容器的关联,可以参见SpringInnerContainer的实现。
EasyJWeb内置了对远程javascript脚本调用功能,可以使用javascript直接访问服务端的业务组件。另外EasyJWeb通过使用prototype.js及其它一些来自开源社区ajax特效工具,提供了丰富的Ajax支持。
Ajax不是一个技术,它实际上是几种技术,每种技术都有其独特这处,合在一起就成了一个功能强大的新技术。Ajax包括:
XHTML和CSS
使用文档对象模型(Document Object Model)作动态显示和交互d
使用XML和XSLT做数据交互和操作
使用XMLHttpRequest进行异步数据接收
使用JavaScript将它们绑定在一起
传统的web应用模型工作起来就象这样:大部分界面上的用户动作触发一个连接到Web服务器的HTTP请求。服务器完成一些处理---接收数据,处理计算,再访问其它的数据库系统,最后返回一个HTML页面到客户端。这是一个老套的模式,自采用超文本作为web使用以来,一直都这样用, 但看过《The Elements of User Experience》的读者一定知道,是什么限制了Web界面没有桌面软件那么好用。
这种旧的途径让我们认识到了许多技术,但它不会产生很好的用户体验。当服务器正在处理自己的事情的时候,用户在做什么?没错,等待。每一个动作,用户都要等待。
很明显,如果我们按桌面程序的思维设计Web应用,我们不愿意让用户总是等待。当界面加载后,为什么还要让用户每次再花一半的时间从服务取数据?实际上,为什么老是让用户看到程序去服务器取数据呢? Ajax如何不同凡响.通过在用户和服务器之间引入一个Ajax引擎,可以消除Web的开始-停止-开始-停止这样的交互过程. 它就像增加了一层机制到程序中,使它响应更灵敏,而它的确做到了这一点。
不像加载一个页面一样,在会话的开始,浏览器加载了一个Ajax引擎---采用JavaScript编写并且通常在一个隐藏frame中。这个引擎负责绘制用户界面以及与服务器端通讯。Ajax引擎允许用异步的方式实现用户与程序的交互--不用等待服务器的通讯。所以用户再不不用打开一个空白窗口,看到等待光标不断的转,等待服务器完成后再响应。
通常要产生一个HTTP请求的用户动作现在通过JavaScript调用Ajax引擎来代替. 任何用户动作的响应不再要求直接传到服务器--例如简单的数据校验,内存中的数据编辑,甚至一些页面导航-引擎自己就可以处理它. 如果引擎需要从服务器取数据来响应用户动作-假设它提交需要处理的数据,载入另外的界面代码,或者接收新的数据--引擎让这些工作异步进行,通常使用XML, 不用再担误用户界面的交互。
web脚本远程调用:在基于Web2.0的程序中,在用户注册的时候,我们希望用户在输入完注册用户名后,假如其输入的用户已经存在,则立即显示相应的提示,这样的交互会使得应用程序交互界面变得更加友好。要实现这种功能,可以通过在用户输入完用户名时,触发一个事件,这个事件执行一个程序,自动到服务器端检测这个用户名是否存在,若用户已经存在,则给予相应的提示,让用户可以及时选择其它用户名继续操作。假如我们在服务器端有一个用户处理组件UserService,这个组件中有一个检测用户是否存在的方法boolean checkUserExists(String userName),这个方法用来检测用户名是否存在,若存在则返回true,否则返回false。
引入远程脚本调用,则可以直接在注册页面中使用下面的javascript脚本来判断用户是否存在:
function checkUserExist(username)
{
UserService.checkUserExists(username,function(ret){
if(ret)Element.setValue('userName_Msg',"用户名已存在,请选择其它用户名\!");
})
}
而调用这个函数的是用户名录入框的onChange事件,大致如下:
onChange="checkUserExist(this.value);">
这种模式即为远程脚本调用。在上面的代码中,在checkUserExist函数中,调用了服务器端的UserService.checkUserExists(userName)方法,来判断用户名是否存在,若返回的结果为true,则在id为userName_Msg的span中显示用户存在的提示。
在EasyJWeb中,内置了一个把服务器业务组件暴露给客户端的通过Javascript远程调用的引擎,因此可以像上面的方式轻松在web界面中通过javascript调用服务器组件,实现特定的功能,这就是我们要说的远程脚本调用。
在EasyJWeb的demo中,提供了一个关于EasyJWeb中使用Ajax应用的Demo,名为ajaxDemo.html。你只需要下载最新的EasyJWeb源代码,然后执行bin目录中的build war,即可得到一个可运行的Web应用包,把这个war包拷到Tomcat的webapps目录下,启动web服务器。然后在地址栏中输入http://localhost:8080/easyjf-jweb-0.8.0/ajaxDemo.html,即可看到EasyJWeb中Ajax运用的一些效果。大致如下图所示,详情参考视频教程:

要在EasyJWeb应用程序中使用Ajax功能,需要下面几个步骤:
1、在web.xml文件添加如下的mapping;
easyjf
/ejf/*
2、在模板页面(或客户端html页面)中加入下面的两行:
3、在easyjf-web.xml文件中配置需要暴露给客户端的业务对象;
4、在模板页面(或客户端html页面)中通过下面的方式引用服务器端支持远程脚本访问的业务对象
5、在模板页面(或客户端html页面)中书写支持无刷新的远程脚本调用代码,如下所示:
function login()
{
UserService.login($('userName').value,$('password').value,function(ret)
{
if(ret)alert("登录成功!");
});
}