XDoclet下生成struts配置的基本任务手册

    技术2022-05-11  68

    最近用appfuse发现里面使用xdoclet真是方便,虽然以前也用,但是没有像appfuse那样什么都使用xdoclet生成。现在写程序真是方便啊。本想把自己的收获写下来,但是发现网上高人早已编写完成(又晚了一步,呵呵,快成迟来大师了),现转贴如下: 任何人都想过自动生成的代码,自己去写个分析器不是件容易的事,而XDoclet给我们机会建立自己的代码生成器。     XDoclet最早用来对付EJB,因为生成EJB的本地和远程接口以及对应的HOME和描述符是一件简单但是枯燥的事,本来我以为,只有JBuilder这样的集成编辑器可以很好的简化工作,后来知道XDoclet也能够完成得不错。         我最早用XDoclet是因为学习hibernate,hibetnate的描述文件并不复杂,关键的部分不多,可是一旦对POJO修改,就必须要劳师动众的找到对应的描述符来修改,增加了一次出错的机会,而使用了XDoclet就可以做到同步的修改。         还有就是struts,首先是配置文件,许多人操作同一个文件会产生冲突,有了XDoclet我们就不怕了,还有validate文件也一样,有了XDoclet就会解决大部分冲突问题。             之所以起这么一个名字,主要因为XDoclet和Ant结合得很紧,尽管实际上做的工作并没有直接的联系,但XDoclet除了Ant接口就只有些Maven接口插件了,所以XDoclet几乎是完全依赖Ant的。 本篇文章的目录结构如下,因为只是为了说明问题,在我的ant的build文件中并没有包括路径名的引用,一切是直接的方式。 ├─classes ├─doc ├─gen ├─lib │      commons-collections-2.1.jar │      commons-logging-1.0.3.jar │      commons-validator.jar │      log4j-1.2.8.jar │      servlet.jar │      struts.jar │      xdoclet-1.2.1.jar │      xdoclet-apache-module-1.2.1.jar │      xdoclet-ejb-module-1.2.1.jar │      xdoclet-hibernate-module-1.2.1.jar │      xdoclet-web-module-1.2.1.jar │      xdoclet-xdoclet-module-1.2.1.jar │      xjavadoc-1.0.3.jar ├─merge ├─src ├─todo └─web 只列出lib中的文件,每一个的作用在后面慢慢描述。 build.xml 开头增加 <path id="xdoclet.classpath">     <fileset dir="lib">         <include name="*.jar"/>     </fileset>     <pathelement location="classes"/> </path> ************************************************************************************************** 1,最简单的todolist 每一篇讲XDoclet都送这里开始,有很多原因的。XDoclet的灵感来自JavaDoc,JavaDoc把文档写在代码里,缓解了困扰编程领域多年的文档与程序同步问题。这里有个很有趣的事,就是UNIX业界的人们传递下来这样一个传统,就是代码是最好的文档,保持文档的同步实在是费力不讨好的事,所以他们提出这样一个好主意,不过JavaDoc更聪明,文档是程序注释的一部分,而且可以提取出来。 来吧,看这个任务。 <target name="todolist" description="todolist">     <taskdef name="documentdoclet" classname="xdoclet.modules.doc.DocumentDocletTask" classpathref="xdoclet.classpath"/>     <documentdoclet destdir="todo" >         <fileset dir="src">                <include name="**/*.java" />          </fileset>          <info header="Todo list" projectname="XDoclet in Action" tag="todo"/>     </documentdoclet> </target> 然后src写这么一个文件 package xdoclet; public class TodoListTest { /** * @todo 我有许多工作要做,只是测试,忽略吧 */   public TodoListTest() {   }   /**    * @todo 我还不知道名字 ,只是测试,忽略吧    *    */   public String getYourName(){        return null;   } } 注意要按照javadoc的写法。还要注意ant中的子任务系统,其中info就是我们定义的documentdoclet任务的子任务,我们以后会看到很多类似的情况. 然后运行ant todolist 结果就是一个结构类似javadoc,但是只包括todo标签的html文档,呵呵,可以看看项目里有哪些待办的事。 2,web.xml和taglib 作servlet映射是个讨厌的工作,当你接收别的项目的时候,这个项目的servlet怎么用可能比较麻烦,可能当时web.xml的映射找不到了,这时怎么办呢? 看这个文件 package com.xdocletbook.blog.servlet; import java.io.IOException; import javax.servlet.ServletConfig; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.apache.log4j.Level; import org.apache.log4j.Logger; /** * @web.servlet * name="HomePage" * @web.servlet-init-param * name="LogLevel" * value="${LOG_LEVEL}" * @web.servlet-mapping * url-pattern="/home" * * @web.security-role *     role-name="${OwnerRole}" * @web.security-role-ref *     role-name="blogowner" *     role-link="${OwnerRole}" */ public class HomePageServlet     extends HttpServlet {   private static Logger LOGGER = Logger.getLogger(HomePageServlet.class);   public void init() throws ServletException {     String logLevel = getInitParameter("LogLevel");     if (logLevel != null && logLevel.length() > 0) {       LOGGER.setLevel(Level.toLevel(logLevel));     }   }   public void service(HttpServletRequest request, HttpServletResponse response) throws       ServletException, IOException {     LOGGER.debug("Displaying home page");     request.getRequestDispatcher("jsp/home.jsp").forward(request, response);   } } 然后配置build.xml增加如下任务 <target name="generate-web">        <taskdef name="webdoclet" classname="xdoclet.modules.web.WebDocletTask" classpathref="xdoclet.classpath"/>        <!-- Generate servlet and JSP Tag "stuff" -->        <webdoclet destdir="gen" mergeDir="merge">               <fileset dir="src">                     <include name="**/*.java" />                 </fileset>          <deploymentdescriptor destdir="web" distributable="false" />           </webdoclet>  </target> 然后运行ant generate-web 结果就是这样一个web.xml <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE web-app PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN" "http://java.sun.com/dtd/web-app_2_3.dtd"> <web-app >     <!--     To use non XDoclet filters, create a filters.xml file that     contains the additional filters (eg Sitemesh) and place it in your     project's merge dir.  Don't include filter-mappings in this file,     include them in a file called filter-mappings.xml and put that in     the same directory.     -->     <!--     To use non XDoclet filter-mappings, create a filter-mappings.xml file that     contains the additional filter-mappings and place it in your     project's merge dir.     -->     <!--     To use non XDoclet listeners, create a listeners.xml file that     contains the additional listeners and place it in your     project's merge dir.     -->      <servlet>          <servlet-name>StrutsActionServlet</servlet-name>          <servlet-class>org.apache.struts.action.ActionServlet</servlet-class>     </servlet>    <servlet>       <servlet-name>HomePage</servlet-name>      <servlet-class>com.xdocletbook.blog.servlet.HomePageServlet</servlet-class>       <init-param>          <param-name>LogLevel</param-name>          <param-value>1</param-value>       </init-param>       <security-role-ref>          <role-name>blogowner</role-name>          <role-link>aOwner</role-link>       </security-role-ref>    </servlet>       <servlet-mapping>          <servlet-name>StrutsActionServlet</servlet-name>           <url-pattern>*.do</url-pattern>     </servlet-mapping>    <servlet-mapping>       <servlet-name>HomePage</servlet-name>       <url-pattern>/home</url-pattern>    </servlet-mapping>    <!--    To specify mime mappings, create a file named mime-mappings.xml, put it in your project's mergedir.    Organize mime-mappings.xml following this DTD slice:    <!ELEMENT mime-mapping (extension, mime-type)>    -->    <!--    To specify error pages, create a file named error-pages.xml, put it in your project's mergedir.    Organize error-pages.xml following this DTD slice:    <!ELEMENT error-page ((error-code | exception-type), location)>    -->   <!--   To add taglibs by xml, create a file called taglibs.xml and place it   in your merge dir.   -->    <!--    To set up security settings for your web app, create a file named web-security.xml, put it in your project's mergedir.    Organize web-security.xml following this DTD slice:    <!ELEMENT security-constraint (display-name?, web-resource-collection+, auth-constraint?, user-data-constraint?)>    <!ELEMENT web-resource-collection (web-resource-name, description?, url-pattern*, http-method*)>    <!ELEMENT web-resource-name (#PCDATA)>    <!ELEMENT url-pattern (#PCDATA)>    <!ELEMENT http-method (#PCDATA)>    <!ELEMENT user-data-constraint (description?, transport-guarantee)>    <!ELEMENT transport-guarantee (#PCDATA)>    <!ELEMENT login-config (auth-method?, realm-name?, form-login-config?)>    <!ELEMENT auth-method (#PCDATA)>    <!ELEMENT realm-name (#PCDATA)>    <!ELEMENT form-login-config (form-login-page, form-error-page)>    <!ELEMENT form-login-page (#PCDATA)>    <!ELEMENT form-error-page (#PCDATA)>    -->    <security-role>       <role-name>aOwner</role-name>    </security-role> </web-app> 仔细看这个文件,你一定诧异struts的配置信息怎样得来,这是XDoclet的另一种方式,对于第三方的Servlet,我们没有办法再处理原代码,所以我们有了merge选项,看<webdoclet destdir="gen" mergeDir="merge">这一句就知道了,在merge目录里我们有两个文件:     servlets.xml     <servlet>          <servlet-name>StrutsActionServlet</servlet-name>          <servlet-class>org.apache.struts.action.ActionServlet</servlet-class>     </servlet>         servlet-mappings.xml     <servlet-mapping>          <servlet-name>StrutsActionServlet</servlet-name>           <url-pattern>*.do</url-pattern>     </servlet-mapping>         还要注意的是${LOG_LEVEL},这个是说要引用ant 中的变量,所以我的build.xml前面中增加了这两项 <property name="LOG_LEVEL" value="1"/> <property name="OwnerRole" value="aOwner"/> 所以,我们就可以动态的改变部署的Log级别 struts自动配置 Struts中有两样比较重要的类,Action和Form。 对于Action,我们需要配置Action的映射和Forward属性,对于Form我们也需要注册名字和校验参数,以下就是我们能用XDoclet做到的。 对于Action我们写这样一个Java文件 package com.xdocletbook.blog.servlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.apache.struts.action.Action; import org.apache.struts.action.ActionForm; import org.apache.struts.action.ActionForward; import org.apache.struts.action.ActionMapping; /** * Simple class to test Jakarta Struts generation (Jakarta Struts 1.2 beta 2 only). * * @struts.action *    path="/struts/foo" *    name="userForm" *     input="jsp/createBlog.jsp" * * @struts.action-forward *    name="success" *    path="/struts/getAll.do" *    redirect="false" * * * @struts.action-exception * type="com.xdocletbook.blog.exception.ApplicationException" * key="app.exception" * path="jsp/error.jsp" * * @struts.action-form name="blog.Create" */ public final class StrutsAction extends Action {     public ActionForward execute(ActionMapping mapping, ActionForm form,                                  HttpServletRequest request, HttpServletResponse response)     {         return mapping.findForward("success");     } } 关键部分就是注释部分。 看我们增加build.xml一个任务, <target name="generate-web">        <taskdef name="webdoclet" classname="xdoclet.modules.web.WebDocletTask" classpathref="xdoclet.classpath"/>        <!-- Generate servlet and JSP Tag "stuff" -->        <webdoclet destdir="gen" mergeDir="merge">               <fileset dir="src">                     <include name="**/*.java" />                 </fileset>          <strutsconfigxml version="1.1"/>             </webdoclet>  </target> 运行ant generate-web,我们就在gen得到了struts-config.xml 其中关键内容如下     <action       path="/struts/foo"       type="com.xdocletbook.blog.servlet.StrutsAction"       name="userForm"       scope="request"       input="jsp/createBlog.jsp"       unknown="false"       validate="true"     >       <exception         key="app.exception"         type="com.xdocletbook.blog.exception.ApplicationException"         path="jsp/error.jsp"       />      <forward         name="success"         path="/struts/getAll.do"         redirect="false"       />     </action> 如果我们有许多Action,就可以随时生成这样一个文件,不必在意有人改过这个文件。同时你也不必担心不小心忘了改这个文件,因为你改了 Java时,许多默认的属性也跟这改了。 看到这里,许多用过workshop的一定感觉到页面流不就是这样吗?当通过图形界面定义流程时,看看页面流的源码你就会发现,注释中有一些 特殊的标记,这说明workshop的注释有着xdoclet一样的功能,只不过workshop提供了很好的界面,而不需要自己写注释,而且workshop提供了 更好的语法检查,呵呵,只是将许多action写到一起,是有些乱。 Struts的另一个主要的部分就是Form了,虽然我一开始觉得Form有些麻烦,对付动态的Form有些无能为力,但是结合一些相关的插件后,效果 确实不错。 这是我们的Form文件,我们还使用ValidatorForm来做自动验证。 package com.xdocletbook.blog.servlet; import java.io.Serializable; import org.apache.struts.validator.ValidatorForm; /** * * @struts.form *     name="blog.Create" */ public class BlogCreateForm     extends ValidatorForm     implements Serializable {   private String name;   private String owner;   private String email;   public BlogCreateForm() {}   public String getName() {     return this.name;   }   /**    * @struts.validator    * type="required"    */   public void setName(String name) {     this.name = name;   }   public String getOwner() {     return this.owner;   }   /**    * @struts.validator    * type="required"    */   public void setOwner(String owner) {     this.owner = owner;   }   public String getEmail() {     return this.email;   }   /**    *    @struts.validator    *    type="required"    *    @struts.validator           *    type="email"    */   public void setEmail(String email) {     this.email = email;   } } 然后运行ant generate-web 这样struts-config.xml就有了  <form-beans>     <form-bean       name="blog.Create"       type="com.xdocletbook.blog.servlet.BlogCreateForm"     />     <! --          If you have non XDoclet forms, define them in a file called struts-forms.xml and          place it in your merge directory.     -->   </form-beans> 这里有一个陷阱,就是Struts XDoclet处理form-beans时,只处理类型是Form的,对于类型是ValidatorForm的Form如果你不把对应的类文件放 到classpath下,XDoclet就会忽略它,所以struts的包一定要放到类路径下,让XDoclet有机会知道ValidatorForm是Form的子类。 还有每一个setXXX方法,有一些表示限制的注释,这些帮助我们生成了 validation.xml <?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE form-validation PUBLIC "-//Apache Software Foundation//DTD Commons Validator Rules Configuration 1.0//EN" "http://jakarta.apache.org/commons/dtds/validator_1_0.dtd"> <form-validation>   <!--    Define global validation config in validation-global.xml   -->   <formset>       <form name="blog.Create">               <field property="name"                      depends="required">                   <arg0 key="blog.Create.name"/>               </field>               <field property="owner"                      depends="required">                   <arg0 key="blog.Create.owner"/>               </field>               <field property="email"                      depends="required,email">                   <arg0 key="blog.Create.email"/>               </field>       </form>   </formset> </form-validation>  

    最新回复(0)