EasyJF 官方网站全面升级,同时EasyJF开源团队也将进行全面改组,期待您给我们提出宝贵的意见及建议!

当前位置:首页-教程-EasyJWeb教程

  • EasyJWeb开发者指南
    作者: 大侠  来源:easyjf  发布时间:2007-11-06 11:25:00
  • EasyJWeb开发者指南....................................................................................................... 1
    EasyJWeb综述................................................................................................................. 3
    MVC部分........................................................................................................................ 4
    请求分发.......................................................................................................................... 5
    ActionServlet...................................................................................................... 5
    请求Url............................................................................................................. 5
    核心处理.......................................................................................................................... 7
    IWebAction......................................................................................................... 7
    Page................................................................................................................... 8
    WebForm............................................................................................................ 9
    Module............................................................................................................. 11
    AbstractCmdAction和AbstractPageCmdAction.................................................... 12
    配置文件................................................................................................................. 14
    web.xml............................................................................................................ 14
    零配置............................................................................................................. 16
    easyjf-web.xml.................................................................................................. 16PO和WebForm.............................................................................................................. 19
    验证............................................................................................................................... 21
    Annotation........................................................................................................ 21
    EasyJWeb中的验证........................................................................................... 21
    实现自己的验证器............................................................................................ 22
    验证错误获彼此............................................................................................... 23
    EasyJWeb的错误处理.............................................................................................. 24
    工具类.................................................................................................................... 24
    CommUtil......................................................................................................... 25
    分页................................................................................................................. 25
    tagUtil.............................................................................................................. 26
    验证码............................................................................................................. 26
    容器部分........................................................................................................................ 28
    EasyJWeb的容器..................................................................................................... 28
    IoC................................................................................................................... 28
    EasyJWeb中的容器........................................................................................... 28
    集成其他容器................................................................................................... 32
    EasyJWeb中的AOP........................................................................................................ 35
    AOP和拦截器.................................................................................................. 35
    EasyJWeb中的拦截器....................................................................................... 35
    Ajax支持....................................................................................................................... 35
    Ajax概述......................................................................................................... 35
    远程脚本调用................................................................................................... 36
    快速上手.......................................................................................................... 37
    配置Ajax......................................................................................................... 38
    安全控制.......................................................................................................... 38
    Ajax工具......................................................................................................... 38
    Ajax验证       38
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
    EasyJWeb综述
           EasyJWeb是基于java技术,用于企业级Java Web应用程序快速开发的MVC框架。框架设计构思来源于国内众多项目实践,框架的设计及实现借鉴当前主要流行的开源Web框架,如Rails、Struts、JSF、Tapestry等,吸取其优点及精华,是一个完全由来自的中国开源爱好者开发,文档及注释全部为中文的开源框架。
     
    EasyJWeb由主要由四个部分组成:
    1、核心MVC。EasyJWeb的核心是一个基于模板技术实现的MVC框架;他能让我们用非常简洁的代码写基于Java的Web应用。
    2、容器及通用业务逻辑封装。作为一个旨在让基于Java的Web应用程序开发变得直接、快速、简易的框架,EasyJWeb提供了一个IoC容器,并对企业级应用中的一些通用业务逻辑(如分页、查询、DAO等)进行了抽象及封装,提供了一套可以直接操作、应用企业资源的组件及API。
    3、代码生成引擎及工具。仅仅依靠一个灵活、简易的MVC核心引擎还不能最大限度的提高开发速度,因此EasyJWeb还提供了一个灵活、易用的代码生成引擎及工具,通过使用代码生成引擎,可以快速完成基于JavaEE平台的企业级应用程序生成。如数据库添删改查(CRUD)代码生成、自动页面模版生成、自动配置文件管理等。
    4、EasyJWeb插件体系,项目中的各种实用功能的扩展,可以灵活地通过基于插件的形式安装到EasyJWeb中,提供各种针对性的功能。如ajax实用插件、代码生成插件等。
     
    EasyJWeb的特点:
    1、快速开发支持
    EasyJWeb是首要目标是实现基于JavaEE的Web应用程序快速开发。通过EasyJWeb的核心MVC、通用业务逻辑抽象及封装、代码自动生成、插件体系等几个部分有机组合,能实现企业级的Java Web应用程序开发。
    2、零配置及约定配置
    通过配置可以让程序变得更加的灵活、易维护及扩展,然而配置的滥用会造成维护配置文件过于麻烦。因此,EasyJWeb基于尽可能简化配置的原则,实现了零配置支持,同时为了保证系统的灵活性及可扩展性,还提供了很多的约定配置支持。
    3、优雅的视图支持,页面及程序完全分离。
    EasyJWeb提供了非常优雅的视图支持能力,不但实现了视图页面模板与程序逻辑的完全分离,克服了传统jsp页面难于维护的问题,而且还实现了对页面纯天然的支持能力,使得非常适用于企业级应用中的页面制作人员与程序的分工合作。
    4、超级IoC容器
    作为一个主要用于Java企业级应用程序开发的框架,EasyJWeb实现了IoC容器,提供非常灵活的注入方式,并能支持Spring、Guice等异构容器实现。
    5、Ajax支持
    EasyJWeb内置了对远程javascript脚本调用功能,可以使用javascript直接访问服务端的业务组件。另外EasyJWeb通过使用prototype.js及其它一些来自开源社区ajax特效工具,提供了丰富的Ajax支持。

     MVC部分
    MVC中,M-Model是指模型层,V-View是指视图层,C-Controller是指控制器。作为一个旨在提高开发效率、使Java代码与页面模板完全分离,增强系统的可维护性及可扩展性的MVC框架,EasyJWeb中同样有这三个基本的概念。在EasyJWeb应用程序中,Model层位于系统后台,一般是POJO对象,可以通过使用标签把后台的业务模型对象配置到容器中,让其它层的对象调用。Controller用于控制转发,EasyJWeb中所有的请求都由ActionServlet来负责处理,ActionServlet再调用相应的模块的Action,来实现具体的处理,EasyJWeb中的ActionServlet与模块Action一起共同担当了Controller的角色。最后是视图View,View是用来显示数据,Model层的处理结果将交由View层来,EasyJWeb中的View由单独的模板文件担当,视图模板可以是任何文本格式的信息,如html、xml、java、sql等。

    ActionServlet解析了请求,并从配置文件中得到了适当的控制器,就将包装好了的请求对象发送给该控制器的execute方法。而控制器的作用就在于处理请求并返回一个用户展示处理结果的页面模板对象Page。
    ActionServlet是一个前端控制器。用于在第一次请求到来时初始化框架,并接受每一个浏览器请求,解析请求URL,包装表单属性,并分发给具体的控制器处理。
    请求按照EasyJWeb配置文件中定义或者约定配置来寻找处理器。比如,可以在配置文件中,使用定义了一个请求为/userManage.ejf的请求样式都由userManageAction处理,关于控制器更详细的配置在配置详解一节讲述,easyJWebCommand等在AbstractCmdAction中介绍。在按照约定定位控制器的策略中,控制器需要放在com.easyjweb.action包中。比如,我们需要写一个用户登录的Action,可以在com.easyjweb.action这个包下面,添加一个名为LoginAction的类,这样即可通过/login.ejf来请求这个控制器。
    对于提交的表单,ActionServlet会调用EasyjWeb中的核心处理器,将表单中的所有文字属性,都包装在WebForm中的textElement中,而将表单中包含的上传文件使用FileCommUpload包装为FileItem并放置在WebForm的FileElement中。关于表单的处理将在WebForm一节详细讲述。
    基本请求url模式:
    当一个请求为http://xxx.xxx.com/abc.ejf的请求到来时,解析得到的控制器名字为abc。在这里,在框架内部是去寻找path属性设置为/abc的那个Module,并调用该Module对象对应的IWebAction对象来处理。而对于开发者,他们只需要知道用来处理/abc.ejf这个path的IWebAction是AbcAction。下面是一些请求url的样式例子:
    1、  /module.ejf?easyjwebCommand=command&name=xxx
      2、 /module.ejf
      3、 /module.ejf?easyjwebCommand=command
      4、 /module.ejf?easyjwebCommand=command&cid=1234
      5、/module.ejf?easyJWebCommand=edit&cid=123455&title=111
      6、/module.ejf?title=测试
    第一个样式的意思是请求一个名字为module的模块(Module来)处理请求。如果改Action是AbstractCmdAction的子类的话,则会调用该类中对应的command方法,并且传入一个名为name,值为xxx的参数。关于AbstractCmdAction在后面章节有详细介绍。下面几个url请求类似。
    高级请求url模式:
    在EasyJWeb中,有一个URL路由映射处理器,通过配置这个映射处理器可以非常简单地实现Web应用中类似URLRewrite的需求。映射处理器代码如下所示:
    public interface IPathMappingRuler ... {
    //对请求路径的解析;
     public String getModuleName();//得到模板的名称
    public Map getParams(); //得到模板缺省参数
    public String getCommand();//得到模板命令
    }
         该接口的默认实现是com.easyjf.web.core.PathMappingRulerImpl。在基于EasyJWeb的应用中,每一个交由EasyJWeb框架处理的请求url,都会通过这个映射处理器进行转换。通过使用EasyJWeb缺省URL映射转换器,客户端请求路径/module/command/params将按以下请求规则,作如下的映射处理.
      映射处理前的URL:
      1、 /ejf/module/command/name=xxx
      2、 /ejf/module
      3、 /ejf/module/command
      4、 /ejf/module/command/12345
      5、/ejf/module/edit/12345/title=1111
    6、/ejf/moduel/title=测试
    这些url分别对应上面的6中样式,这种url样式比较直观和规范。
      URL映射转换器的一个最典型的应用示例,就是EasyJWeb中的远程Web脚本处理支持引擎,也即Ajax的部分功能。远程JS脚本调用功能只是EasyJWeb中的一个小小插件,EasyJWeb的Ajax实现只是一个普通的EasyJWeb Module(Action),这个Action即com.easyjf.web.ajax.AjaxEngineAction。
    在EasyJWeb对Ajax的支持中,可以直接通过下面的URL来动态生成远程javascript调用脚本。
     
      
     
    这里只作为一个演示示例,更多关于Ajax的信息参见Ajax一章。

    在这一章中将详细讲解EasyJWeb中核心MVC部分的主要部件,包括IWebAction、WebForm、Page等。
    IWebAction就是EasyJWeb中的控制器接口。凡是实现了IWebAction接口的类都可以作为EasyJWeb的控制器。在该接口的代码为:
    public interface IWebAction {
        public Page execute(WebForm form, Module module) throws Exception;
    }
    execute方法返回一个Page对象,该对象包装了返回的模板等信息,关于Page对象更详细的信息参见Page对象一节。该方法并没有牵涉到任何的Http环境对象,如HttpServletRequest、HttpServletResponse,使得Action及其容易测试。与Http环境相关的对象都包装在一个ActionContext对象中,可以通过ActionContext.getContext().getRequest()等方法来得到需要的对象,ActionContext更多的用法请参看API doc。
    execute方法第一个参数:WebForm,包装了请求中的参数信息和提交的表单中的信息。同时,在处理器中包含了在处理器中得到了,并且需要合成到视图中的数据。第二个参数Module,module对象中包含了很多有用的信息及资源,最常用的一个是Page,可以使用Module.findPage(name)在Action中找到特定名称的Page;另外较重要的一个就是控制器,简单说一个Module对象对应了一个IWebAction对象;另外,Module中还包括了控制器级别的拦截器、所有在一个Module对应Action的注入信息等等,关于Module更详细的内容参见Module一节。
    IWebAction在整个MVC流程中就充当了一个控制器的角色,所有的请求都由ActionServlet分发到一个指定的控制器中处理。一般来说,一个控制器的处理流程为:使用form.get()方法从表单或者请求中得到一些参数或者属性,调用业务对象完成指定的功能,调用form.addResult()方法向Velocity上下文中填入要合成(展示)的数据,最后返回一个Page对象,完成一个流程的处理。
    下面是一个标准的注册的流程示意代码:
    public Page execute(WebForm form, Module module) {
            SystemUser suc = new SystemUser();
            form.toPo(suc);
            su.setLastLoginIP(com.easyjf.web.ActionContext.getContext()
                    .getRequest().getRemoteAddr());
            Long id = this.service.addSystemUser(su);
            if (id != null) {
    form.addResult("msg","注册成功");
            } else {
    form.addResult("msg","注册失败");
    return new Page("registerSu","/user/registerSU.html");
            }
            return module.findPage("registerSuccess");
    }
    该段代码演示了一个完整的控制器处理流程,注意在这里并没有演示出form.get("")来取得请求参数或者提交的表单属性,而使用了form.toPo(obj)方法来合成参数,这是EasyJWeb的一个很重要的方法,其包含了VO到PO的拷贝,数据的验证等功能,关于改方法更多的内容请参见PO一节。
    Page对象充当的就是View的角色,它包装了返回的视图信息。返回的视图可以是任何文本数据格式,比如Html、XML、java代码乃到Velocity模板等。
    Page对象的角色
    在处理器完成一个请求后,返回一个视图对象,EasyJWeb框架通过该Page对象来处理视图模板与程序数据的合成,从而输出动态的内容,用于页面的展示。
    Page的创建
    一个Page对象可以有两种创建方式,一种是在EasyJWeb的配置文件中配置,如下所示:
    path="/systemUser" action="com.easyjweb. demo.mvc.userAction">
     
     
     
     
    Page对象有三种:template、html和null。template是指模板,需要使用Velocity来合成的;而html则不需要合成,其代表一个页面转向,框架使用redirect来直接导向该页面;null两者都不是,他既不合成模板,也不导向,用于在action中直接通过response来给客户端发送数据或者不对客户端作返回的情况。另外,还可以通过contentType来设置模板的输出内容格式,比如"text/xml"、"text/script"等,甚至能直接导向一个流文件。在这种情况下,EasyJWeb不光会使用Velocity来合成视图,还会设置response的类型为设置类型。
    配置好页面后,就可以直接在代码中使用:module.findPage("reg")等来返回一个Page对象了。另外,该项配置+代码等同于在控制器中直接返回一个Page对象,比如:return new Page("succ","/user/success.html","html"),第一个参数为Page的名称,第二个是模板或者html页面的路径,最后一个表示模板的类型,如果省略则默认为template。在IWebAction小节的演示注册的代码中,演示了这两种使用方法。
    Page模板/文件的定位
    无论使用new Page()方法还是使用配置Page对象,page对象都需要一个模板路径path,该路径是相对于框架的模版根路径的.
    在默认的情况下,EasyJWeb都会从/WEB-INF/ view/文件夹中加载资源,意思是如果页面的配置为: ,那么该模板文件应该放在/WEB-INF/ view/user/success.html下。
    同时也可以通过置template-base-path来修改模板加载的根目录。比如下面的配置代码:
    /WEB-INF/template/
    就可以把模板的根路径定为/webapp/WEB-INF/template/,而比如一个模板的path设置为/user/register.html,那么EasyJWeb就会在/webapp/WEB-INF/template/user/register.html处加载该模板文件。注意这点很重要,如果在应用中出现了加载模板文件出错的提示,那么就要检查一下自己的模板文件的位置是否正确。
    页面流重定向
    假如你希望Action的执行结果不要直接输出的浏览器上,而是直接输出到服务器上的一个文件中保存起来(生成静态html是我们在建大型网站中所必须的),或者是输出到互联网上的某一个终端或结点。EasyJWeb给你提供了最简单解决方案,你随时可以根据需要对Action执行结果进行重定向,比如下面的Action中,我们可以把输出结果指定到服务器上d:\myapp\news.html文件中。
    public void doNews(){
    java.io.Writer writer= new OutputStreamWriter(new FileOutputStream(new File("d:\\myapp\\news.html")),"UTF-8");
    ActionContext.getContext().setCustomWriter(writer);
    //执行news命令的一系列逻辑
    page(“news”);//使用news模板来输出结果
    }
    关于ActionContext的更多用法,请参看API doc。
    在EasyJWeb中,WebForm起到了一个VO和TO的作用,将表单数据或者请求中的参数都包装其中,并且返回页面上需要合成的数据也在其中。有了WebForm,让EasyJWeb相对于其它MVC框架,在开发的简易和方便性上有了显著的提升。
    WebForm得到请求参数/表单属性
    首先介绍WebForm对请求参数和表单参数的包装。前面已经提到过,在WebForm中存在两个域:textElement和fileElement,这两个域都是Map对象,分别用来包装文本参数和二进制参数。可以直接使用WebForm.get("poropertyName")来得到文本参数,propertyName表示的是表单或者请求中的参数名,即类似于使用HttpServletRequest.getPrameter方法得到的参数值。而对于二进制的内容,直接使用WebForm.getFileElement来处理。其中的每一个参数都是FileItem对象。关于Common-FileUpload,请参见:http://commons.apache.org/fileupload/。
    下面是一个处理上传的例子:
    public static List saveFile(WebForm form, String path){
                  List cfiles = new ArrayList();
                  Set keys = form.getFileElement().keySet();
                  for (Iterator it = keys.iterator(); it.hasNext();) {
    CFile cfile=new CFile();
                         String fieldName = (String) it.next();
                         FileItem file = (FileItem) form.getFileElement().get(fieldName);
                         if (file.getSize() == 0) {
                                break;
                         }
                         cfile.setName(file.getName());
    //得到InputStream来构造一个File对象;
    cfile.setFile(getFile(file.getInputStream()));
    Urls.add(cfile);
           }
                  return cfiles ;
    }
    WebForm添加页面合成属性
    在EasyJWeb中,需要在页面上合成的数据也是使用WebForm包装,只需要使用WebForm.addResult(“name”,value)方法即可以向Velocity上下文中添加一个名为name,值为value的属性。另外,WebForm也提供了一个简便的WebForm.addPo(obj)来处理多属性的对象的值的添加,该方法配合@FormPO标签,可以控制对对象属性的输出,比如有一个简单的User对象:
    Public class User{
    private String userName;
    private Long id;
    }
    使用form.addPo(user)方法相当于调用了:
    form.addResult("userName",user.getUserName());
    form.addResult("id",user.getId());
    并且可以控制某些属性不能通过addPo方法添加。关于@FormPO标签,请参见PO一节。
    WebForm的生命周期
    首先,当一个请求到达时,框架首先解析出请求的IWebAction,并从Action中得到对应的WebForm的名字。然后直接调用FrameworkEngine.creatWebForm(request, formName)来得到需要的WebForm.WebForm中填满了表单数据后,框架会解析出easyJWebCommand值和传入的参数,也放入WebForm中。到此,框架对WebForm的处理已经结束,然后,WebForm就会传入到IWebAction中,接着就能对其进行适当的操作。在IWebAction中处理完并返回了Page后,框架会得到WebForm中的那个合成页面值的Map,并添加到Velocity的上下文对象中进行页面模版的合成,然后被丢弃。至此,WebForm完成一次生命周期。了解生命周期的主要目的是在于对在WebForm中存在的数据的生命周期的理解。每一次都会有一个新的WebForm产生,但是值得注意的是,WebForm在将数据保存到Velocity上下文时,不光要保存使用addResult方法和addPo方法放入的值,还要向Velocity上下文中保存textElement中的数据,意味着重复的数据可以不用在Action中重复的添加,这在应用中需要特别注意。该项特性和带环境的页面导向、不带环境的页面导向配合使用,会大大的简化一些情况下的操作。
    WebForm.toPo
    上文已经提到过,WebForm.toPo方法是EasyJWeb中很重要的一个方法,将请求和表单中的数据直接拷贝到命令对象(Command Object)中,并完成验证等功能,关于该方法,在PO一节会有更完整的讲解。
    前面介绍了在EasyJWeb中,IWebAction对象实际上起着控制器的作用,但是,同时EasyJWeb也提供了Module来包装一个IWebAction,及其相关的资源和操作等。总的来说,Module就是一个完成一个具体的请求处理所需要的所有资源的集合。
     Module的作用
    一个Module对象包括了一个IWebAction,对该Action所做的拦截器链以及在该Action中可能使用到的所有模版或者页面资源。我们知道ActionServlet解析请求后,会定位到一个控制器上,前面说到这个控制器就是IWebAction,其实这是对于开发者来说的,在EasyJWeb框架内部,这个控制器其实是Module。只是我们在编写控制器代码的时候,控制器是实现的IWebAction接口而已。换句话说,一个Module是包含着IWebAction,而在IWebAction中,却是在调用Module的资源。
    Module还提供了对于一个Action的拦截器链的配置。该拦截器链有别于应用级别的拦截器,它只作用于配置的那个Module的Action上。
    最后,Module为其中的Action所需要的所有Page对象作了配置,在Action中需要哪个页面模版只需要使用module.findPage("pageName")就可以了。
     ModuleAction:
    上面已经说到,Module实际上是包含了Action,而Action中可以通过Module来获得相关的资源,如Page。
    Module为Action提供了拦截器机制,并且为Action准备好了页面模版资源。在Module为IWebAction配置的拦截器分为两种,前拦截器和后拦截器,这将在AOP和拦截器一章中详细介绍。
    在IWebAction中,如果要返回一个Page模版页面,我们前面已经说了,只需要调用module.findPage("pageName")就能得到了。
     Module和页面模版:
    Module为其中的IWebAction对象提供页面模版资源。在上面介绍Page对象时介绍了Page在Module对象中的配置问题。这里再强调一定要注意模板的加载位置的正确性。
     Module的配置
    Module的配置是整个框架配置的关键,特别在引入了容器的概念之后。在这里就只说明Module的普通配置,关于Module和容器的关系和配置放在容器一章中详细介绍。
    下面给出了一个Module的完整配置示例:
               action="com.easyjweb.action.helloAction" scope="request">
       
          
       
        
       
     
    其中的property元素是使用属性注入一个对象,scope是该module作为bean时的生命周期类型,这两个元素在容器一章详细介绍。
    Interceptor是该module中定义的拦截器链,必须实现com.easyjf.web.interceptor.BeforeInterceptor或者com.easyjf.web.interceptor.AfterInterceptor接口,用于前拦截和后拦截。关于拦截及AOP请看相关章节。
    AbstractCmdAction和AbstractPageCmdAction
    前面讲解了IWebAction是控制器需要实现的接口。当然,每一个控制器都实现该接口是比较麻烦的,所以EasyJWeb提供了AbstractCmdAction和AbstractPageCmdAction来提供最大限度的开发简易性和灵活性。
    AbstractCmdAction
    AbstractCmdAction是很类似于spring的MultiActionController的Action,即在一个Action中提供多个处理方法,其使用某一种请求方式来匹配某一个处理方法来处理请求。与MultiActionController稍微不同一点的是,该类没有提供过多可选映射方法的策略和参数的配置,而直接固定了这些策略。使用AbstractCmdAction可以将具有相同或者相关的请求处理方法放在一个Action中,从而达到一种模块化(Module)的效果。
    在请求中使用easyJWebCommand或者cmd传递的参数直,会作为请求执行的方法名的构成。构成的规则为doXxxx()。其中Xxxx表示的是首字母大写后的该值。比如下面给出了一个继承了该类的代码片断:
    public Page doExit(WebForm form, Module module){
    ActionContext.getContext().getSession().removeAttribute("user");
    return new Page("goto","/exit.htm","html");   
    }
     
    public Page doShowLogin(WebForm form, Module module) {
    return module.findPage("login");  
    }
    如果请求的是xxx.ejf?easyJWebCommand=exit或者/ejf/xxx/exit,则会调用doExit方法并返回适当的页面,如果请求的是xxx.ejf?easyJWebCommand=showLogin或者/ejf/xxx/showLogin或者xxx.ejf?cmd=showLogin,则会调用doShowLogin方法并返回适当的页面。
    在1.0版本中,Command类型的Action基类即AbstractCmdAction中,提供了足够的灵活特性。可以根据不同的应用场景,使用不动的方法签名来写Action中的command方法,使用起来非常灵活。
    假如我们在一个模块中要执行一个名为create操作,下面的方法签名都是合法的:
    public Page doCreate(WebForm form,Module module)
    public Page doCreate(WebForm form)
    public Page doCreate(Module module)
    public Page doCreate();
    public void doCreate(WebForm form,Module module)
    public void doCreate(WebForm form)
    public void doCreate(Module module)
    public void doCreate();
    另外,把方法名称改成create,系统也一样能识别。如:
    public Page create(WebForm form,Module module)
    public Page create(WebForm form)
    public Page create(Module module)
    public Page create();
    public void create(WebForm form,Module module)
    public void create(WebForm form)
    public void create(Module module)
    public void create();
    我们可以使用xxx.ejf?easyJWebCommand=create的方式来调用这个方法,也可以使用xxx.ejf?cmd=create的方式来调用,还可以使用/ejf/xxx/create的形式来调用。
    这种灵活的Action中的命名方法,一方面可以使代码更加简洁,易维护,同时也使我们的代码看起来更cool。另外一个主要原因是其使我们可以非常容易书写这些方法的测试代码,不需要任何Web容器,就能运行EasyJWeb的单元测试。
    在Easyjf提供的所有的演示应用中,几乎所有的Action都是继承了AbstractCmdAction。同样,该类也提供了如AbstractCrudAction的doInit,doBefore,doAfter方法,这里就不赘述。
    参见EasyJWeb附带的示例,就能更深入的理解AbstractCmdAction带来的简易性。
    AbstractPageCmdAction
    在AbstractCmdAction的基础上,EasyJWeb提供了另外一个对视图具有自动识别能力的AbstractPageCmdAction。该类能通过应用“惯例代替配置”来智能判断程序中要使用的视图模板,甚至不需要书写方法签名也可以调用视图模板。
    如一个空签名的command方法:
    public void doEdit(){}
    该方法中虽然没有一句代码,也没有明确的视图切换或转向。但AbstractPageCmdAction会根据惯例原则,自动选择edit.html文件作为视图模板。
    另外针对下面的url:person.ejf?cmd=new或/ejf/person/new
    假如PersonAction中没有doNew方法,则AbstractPageCmdAction会根据惯例原则,优先考虑/views/person/目录中是否存在new.html文件,若存在,则将直接返回该模板,即不用写java方法,也能产生动态页面。
    作为一个应用实践之一,在我们开发一般的WEB应用中,我们习惯于把前台及后台分开,比如所有前台展示的放在一个模块Module(即Action)中。网站前台经常会有非常多的页面,而这些页面或多或少都会包含相同或相似逻辑的动态内容,此时若针对每一个页面都写一个Command来处理,显得很麻烦。可以借助Velocity的标签,以及AbstractPageCmdAction中的视图界面智能选择功能,不用写java方法,即加载各种动态页面。
    下面是EasyJF官方网站NewsAction中的代码,类似这样的代码也用于很多EasyJF开源团队所开发的开源及商业项目中:
    public class NewsAction extends AbstractPageCmdAction {
        private Map utils = new HashMap();
        public void setUtils(java.util.Map utils) {
            this.utils = utils;
        }
        public Object doAfter(WebForm form, Module module) {
            java.util.Iterator it = utils.entrySet().iterator();
            if (it != null) {
                while (it.hasNext()) {
                    Map.Entry en = (Map.Entry) it.next();
                    form.addResult((String) en.getKey(), en.getValue());
                }
            }
            return super.doAfter(form, module);
        }
    }
    /news.ejf?cmd=index
    /news.ejf?cmd=technic
    /news.ejf?cmd=download
    可以这么说,前台诸多的动态页面,都不需要书写Java代码,就能实现动态内容生成。如果你借助一些基础引擎,比如EasyJF开发的CMS引擎或者是自己构造一些引擎,完全可以实现不用写Java代码,就能开发出功能比较强的Java Web应用。比如建一个站点、建论坛、百科、Blog、全文检索等。
      EasyJWeb作为一个MVC框架,使用一个Servlet负责转发所有的请求。跟使用其它的任何MVC应用框架一样,要让EasyJWeb工作,首先必须做一定的配置工作。除了要配置web.xml以外,EasyJWeb还自己专门的配置文件,在EasyJWeb专用配置文件中,可以配置
    EasyJWeb的工作模式、模块(Module)信息、表单(Weboform)信息、Bean信息,另外还可以配置拦截器、异常处理、权限处理、AJAX等相关信息。当然,EasyJWeb尽量使配置文件变得简单,甚至在特定应用场景中,只要遵循一定的规则,EasyJWeb的配置可以趋向于零,也就是前面介绍中所说的零配置。即只配置web.xml,而不再需要配置其它的EasyJWeb配置信息。
      要让EasyJWeb工作,首先需要配置Web应用程序中的web.xml文件,在web.xml文件中配置一个servlet,并用这个servlet来处理特定或所有的url请求。我们推荐的web.xml配置如下所示:
     
     
     easyjf
     com.easyjf.web.ActionServlet 
     1
     
     
     easyjf
     *.ejf
     
     
     easyjf
     /ejf/*
     
     
     CharsetFilter
     com.easyjf.web.CharsetFilter
     
       encoding
       UTF-8
     
     
       ignore
       true
     
     
     
     CharsetFilter
     easyjf
     
      
    还可以在web.xml文件中使用下面的信息来指定EasyJWeb专用配置文件的位置:
      
       
       easyjwebConfigLocation
      
        /WEB-INF/easyjf-web1.xml,/WEB-INF/easyjf-web2.xml
       
          
    上面的配置参数将使得EasyJWeb加载的时候,将会从/WEB-INF/easyjf-web1.xml及/WEB-INF/easyjf-web2.xml两个EasyJWeb配置文件中加载配置信息。
    Tip
    另外,也可以在这里只配置一个主EasyJWeb配置文件,并在该配置文件中使用来包含其他的配置文件。在实际应用中,我们建议分模块的使用EasyJWeb配置文件,并在主配置文件中包含这些文件。主文件中配置一些基础的框架配置或者容器配置,比如和spring结合的配置等。这样便于模块的管理和分模块开发集成。我们推荐的配置文件分布:一个主文件mvc.xml,各个模块有各自的配置文件,比如blog-mvc.xml;bbs-mvc.xml等,一个ajax的配置文件ajax.xml,都使用包含到mvc.xml中。
      当然,EasyJWeb尽量使配置文件变得简单,甚至在特定应用场景中,只要遵循一定的规则,EasyJWeb的配置可以趋向于零,也就是前面介绍中所说的零配置。即只配置web.xml,而不再需要配置其它的EasyJWeb配置信息,EasyJWeb就能很好地的工作,并让您的Web应用程序拥有纯MVC框架带来的好处。
      easyjf-web.xml文件是EasyJWeb的默认配置文件,存放在WEB-INF目录下。一个EasyJWeb配置文件的结构大致如下:
     
      true
     
     ...
     
     
     
         scope="singleton" action="com.easyjweb.action.userManageAction"
       defaultPage="list">
      
      
     
     
     
     
       event="" clientValidate="yes" serverValidate="yes"
       alertType="javascript:page">  ...
     
     
     
       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的基本运行参数,如下面的配置信息:
     
     
     
      true
      1024
      512
      用来配置伴随EasyJWeb启动而启动执行的应用程序,这些程序一般可以作额外的初始工作,或者是以一个新线程的形式在系统中运行。如下面是EasyJF开源Blog系统中,自动生成静态html文件的程序:
    false
     
      
      元素下面是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等容器集成的基础配置。而在各个子配置文件中只需要或者标签。

    POWebForm
    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中的验证
    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();// 验证器的名称,如requiredstringrange
        public String value() default "";// 验证器的值,使用;号作为分隔符存放各个参数。如value="required;min:5;max:20"
        public String msg() default "";// 默认错误提示信息,当验证无法通过时显示的提示信息
        public String field() default "";// 字段名称,对于propertyfield类型的校验均可用,也是错误对象的主属性名称。可以用于多个字段,此时需要使用,隔开
        public String displayName() default "";// 定义对象的显示名称,默认情况下为field的名称,可以通过@Field中的name属性定义。
        public ValidateType type() default ValidateType.Property;// 校验类型,默认是对属性进行校验
        public boolean required() default false;// 是否必填字段,每个验证器都可以通过设置属性required=true来指定该属性为必填项
        public String key() default "";// 多国语言显示值的编码
    }
    EasyJWeb内置的Validator验证器
    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验证器使用,则在容器中配置:
    即可,然后在DomainCommand对象中可以通过@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方法中,设置validateRollbackfalse,则发生匹配错误继续匹配下面的属性。
    2,回滚,在toPo方法中,设置validateRollbacktrue,那么在发生匹配错误时,将已经拷贝了的属性还原到拷贝之前。这在使用JPA作为持久层的时候特别有用,避免了设置flushMode
    3,强制性出错,在中设置validate为true,则在匹配出错时,马上抛出一个框架错误,不会继续向下匹配。
    关于错误显示的更多细节,请参看相关API doc。
    EasyJWeb的错误处理
    在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是每页的条数,$pageinationEasyJWeb生成的分页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的容器
    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中的容器
    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         注入一个简单对象:
    直接在bean中使用 即可。
    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")
        private GenericDAO dao;
    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中的AOP
     
    AOP和拦截器
     
    EasyJWeb中的拦截器
     
    Ajax支持
    EasyJWeb内置了对远程javascript脚本调用功能,可以使用javascript直接访问服务端的业务组件。另外EasyJWeb通过使用prototype.js及其它一些来自开源社区ajax特效工具,提供了丰富的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调用服务器组件,实现特定的功能,这就是我们要说的远程脚本调用。

      在EasyJWebdemo中,提供了一个关于EasyJWeb中使用Ajax应用的Demo,名为ajaxDemo.html。你只需要下载最新的EasyJWeb源代码,然后执行bin目录中的build war,即可得到一个可运行的Web应用包,把这个war包拷到Tomcatwebapps目录下,启动web服务器。然后在地址栏中输入http://localhost:8080/easyjf-jweb-0.8.0/ajaxDemo.html,即可看到EasyJWebAjax运用的一些效果。大致如下图所示,详情参考视频教程:

    要在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("登录成功!");
    });
    }
     
     
    Ajax工具
     
    Ajax验证
     

     


  • EasyJWeb-developer-Guide.doc
  • 评论 】 【收藏】 【 推荐给朋友 】 【字体: 】 【关闭
评论:共3条
a
评论人: 匿名用户    评论时间: 2007-11-14 09:17:52
不能下载啊!!!!
评论人: 匿名用户    评论时间: 2007-11-20 13:31:57
不能下载
评论人: 匿名用户    评论时间: 2007-12-06 22:38:41

发表评论:
评论: 
    

Copyright (C) 2005 EasyJF.com 简易java框架网 渝ICP备06004507号
如有意见请与我们联系