ext direct spring Model Generator and Generator APT

ModelGenerator

自1.2.1版本后支持

ExtDirectSpring包含一个简单代码生成器,根据java类生成对应的JavaScript Model对象代码。生成器可以生成Ext JS 4.x和Sencha Touch 2.x两种类库适用代码。

添加代码生成器到程序需要创建一个@Controller注释的类用ModelGenerator.writeModel把Javascript代码写到返回响应中。注意注解@RequestMapping的属性url,如果程序通过Ext.Loader按需加载,对应的路径需要跟真实要存储的路径一致。

@Controller
public class ModelController {

    @RequestMapping("/app/model/User.js")
    public void user(HttpServletRequest request, HttpServletResponse response) throws IOException {
        ModelGenerator.writeModel(request, response, User.class, OutputFormat.EXTJS4);
        //or for Sencha Touch 2
        //ModelGenerator.writeModel(request, response, User.class, OutputFormat.TOUCH2);
    }
}

1.2.3后ModelGenerator也可以通过一个servlet来实现:

@WebServlet(urlPatterns = "/app/model/User.js")
public class SongModelServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
      ModelGenerator.writeModel(request, response, User.class, OutputFormat.EXTJS4);
    }
}

上面代码生成的Javascript在一行上。调试更加方便writeModel支持第五个参数(debug)。如果设置为true,生成格式化后的代码:ModelGenerator.writeModel(request, 

response, User.class, OutputFormat.EXTJS4, true)。

示例:

package test;

public class User {
    private Integer id;
    private String firstName;
    private String lastName;
    private String email;
    private String city;

    //get and set methods
    //....


}
生成Ext JS代码如下

Ext.define('test.User', {
    extend: 'Ext.data.Model',
    fields: [ {
        name: 'id',
        type: 'int'
    }, {
        name: 'firstName',
        type: 'string'
    }, {
        name: 'lastName',
        type: 'string'
    }, {
        name: 'email',
        type: 'string'
    }, {
        name: 'city',
        type: 'string'
    } ]
});

如果数据类型是下表的数据类型,类的字段不需要标注特殊的注解。如果字段用了一个不支持的数据类型,需要用@ModelField注解字段。在生成的model代码的数据类型为auto。

代码生成器试图转换所有可以访问的公共属性。如果某个字段不想被转换,可以在字段添加@JsonIgnore注释。注释@ModelField和@ModelAssociation优先于@JsonIgnore。如果这两个注解之一存在,字段将会在生成的代码中,不管是否存在@JsonIgnore注解。

默认情况下,生成model对象name属性用被生成类的完全限定名,属性名对应字段的名称。

字段没有@ModelField注释,数据类型根据下面列表映射。

JavaExt JS/Sencha Touch
Byteint
Shortint
Integerint
Longint
java.math.BigIntegerint
byteint
shortint
intint
longint
Floatfloat
Doublefloat
java.math.BigDecimalfloat
floatfloat
doublefloat
Stringstring
java.util.Datedate
java.util.Calendardate
java.util.GregorianCalendardate
java.sql.Datedate
java.sql.Timestampdate
org.joda.time.DateTimedate
org.joda.time.LocalDatedate
Booleanboolean
booleanboolean
Associations (since 1.2.3)

代码生成器如果生成带有关联关系的代码。为了确定生成的关联关系,需要用注释@ModelAssociation注解有关联关系的字段。 

类定义:

public class Book {
    public int id;
    @ModelAssociation(value = ModelAssociationType.HAS_MANY, model = Author.class)
    public List<Author> authors;
}
生成的Ext JS model代码:
Ext.define('Book', {
  extend : 'Ext.data.Model',
  fields : [ {
    name : 'id',
    type : 'int'
  }],
  associations : [ {
    type : 'hasMany',
    model : 'Author',
    associationKey : 'authors',
    foreignKey : 'book_id',
    name : 'authors'
  } ]
});

Validation (since 1.2.2)

代码生成器可以添加校验配置。生成器通过读取javax.validation和javax.validation注解生成对应校验配置。上面代码调用ModelGenerator.writeModel时没有生成任何校验信息。需要添加额外的参数(IncludeValidation.BUILTIN or IncludeValidation.ALL)生成有校验信息代码。

ModelGenerator.writeModel(request, response, User.class, OutputFormat.EXTJS4,  IncludeValidation.BUILTIN, false);

上面代码只是添加了校验信息到生成的Ext JS或Sencha Touch代码。

JavaExt JS/Sencha Touch Code
javax.validation.constraints.NotNullpresence
org.hibernate.validator.constraints.NotEmptypresence
javax.validation.constraints.Sizelength
org.hibernate.validator.constraints.Lengthlength
javax.validation.constraints.Patternformat
org.hibernate.validator.constraints.Emailemail
ModelGenerator.writeModel(request, response, User.class, OutputFormat.EXTJS4, IncludeValidation.BUILTIN, false);

上面代码只是增加了校验信息,要想校验起作用,还需要添加校验规则代码。示例: Here is an example: https://github.com/ralscha/extdirectspring-demo/blob/master/src/main/webapp/ux-validations.js 

JavaExt JS/Sencha Touch Code
javax.validation.constraints.DecimalMaxrange
javax.validation.constraints.DecimalMinrange
javax.validation.constraints.Maxrange
javax.validation.constraints.Minrange
javax.validation.constraints.Digitsdigits
javax.validation.constraints.Futurefuture
javax.validation.constraints.Pastpast
org.hibernate.validator.constraints.CreditCardNumbercreditCardNumber
org.hibernate.validator.constraints.NotBlanknotBlank
org.hibernate.validator.constraints.Rangerange
代码生成器根据注解@ModelField和@Model,可以覆盖默认生成选项,生成一些附加信息到model对象源码。

@Model

Attribute   Description
value"Classname" of the model. See Ext.data.Model. If not present full qualified name of the class is used.
idPropertyName of the id property. See Ext.data.Model#idProperty. If not present default value of 'id' is used.
pagingSet this to true if the read method returns an instance of ExtDirectStoreResult. This adds reader: { root: 'records' } to the proxy configuration
readMethodSpecifies the read method. This is a ExtDirect reference in the form action.methodName. See Ext.data.proxy.Direct#api. If only the readMethod is specified generator will write property directFninstead.
createMethodSpecifies the create method. This is a ExtDirect reference in the form action.methodName. See Ext.data.proxy.Direct#api.
updateMethodSpecifies the update method. This is a ExtDirect reference in the form action.methodName. See Ext.data.proxy.Direct#api.
destroyMethodSpecifies the destroy method. This is a ExtDirect reference in the form action.methodName. See Ext.data.proxy.Direct#api.
messageProperty(since 1.3.6) Specifies the messageProperty property in the reader config. See Ext.data.reader.Reader#messageProperty.
disablePagingParameters(since 1.3.8) When set to true the generator sets the paging parameters (pageParam, startParam, limitParam) in the proxy config to undefinded (Ext JS) or false (Touch). Defaults to false
@ModelField

AttributeDescription
valueName of the field. Property name. If not present the name of the property is used.
typeType of the field. Property type. If not specified the library uses the list above to determine the type.
defaultValueDefault value. Property defaultValue.
dateFormatSpecifies the format of date. Property dateFormat. For a list of all supported formats see Sencha Doc: Ext.Date. Will be ignored if the field is not a date field.
useNullIf true null value is used if the value cannot be parsed. If false default values are used (0 for integer and float, "" for string and false for boolean). PropertyuseNull.Only used if type of field is int, float, string or boolean.
mappingTypical use for a virtual field to extract field data from the model object. Property 'mapping' in JS.
persistPrevent the value of this field to be serialized or written with Ext.data.writer.Writer. Typical use for a virtual field. Property 'persist' in JS.
convertFunction which coerces string values in raw data into the field's type. Typical use for a virtual field. Property 'Ext.data.Field.convert' in JS.
@ModelAssociation

AttributeValid forDescription
valueallDescribes the type of the association. ModelAssociationType.HAS_MANY, ModelAssociationType.BELONGS_TO or ModelAssociationType.HAS_ONE. 
Corresponds to the type config property.
modelallThe class of the model that this object is being associated with. If not specified the full qualified class name is used. 
Corresponds to the model config property.
autoLoadHAS_MANYTrue to automatically load the related store from a remote source when instantiated. Defaults to false. 
Corresponds to the autoLoad config property.
foreignKeyallThe name of the foreign key on the associated model that links it to the owner model. If missing the lowercased name of the owner class plus "_id" is used. 
Corresponds to the foreignKey config property.
nameHAS_MANYThe name of the function to create on the owner model to retrieve the child store. If not specified, the name of the field is used. 
Corresponds to the name config property.
primaryKeyallThe name of the primary key on the associated model. Default is "id". If the associated model is annotated with @Model(idProperty="..") this value is used. 
Corresponds to the primaryKey config property.
setterNameBELONGS_TO, HAS_ONEThe name of the setter function that will be added to the local model's prototype. Defaults to 'set' + name of the field, e.g. setCategory. 
Corresponds to the setterName config property.
getterNameBELONGS_TO, HAS_ONEThe name of the getter function that will be added to the local model's prototype. Defaults to 'get' + name of the field, e.g. getCategory. 
Corresponds to the getterName config property.
Example

Java classes

@Model(value = "MyApp.Bean", idProperty = "myVerySpecialId", 
        paging = true, readMethod = "beanService.read", 
        createMethod = "beanService.create", updateMethod = "beanService.update", 
        destroyMethod = "beanService.destroy")
public class Bean {

    @ModelField("myVerySpecialId")
    private int id;

    private String firstName;

    @NotEmpty
    private String lastName;

    @ModelField
    private List<Integer> someIds;

    @ModelField(dateFormat = "c")
    @Past
    private Date dateOfBirth;

    @JsonIgnore
    private String password;

    @ModelField
    @JsonIgnore
    @Email
    private String email;

    @ModelField(type = ModelType.STRING, useNull = true)
    private Long something;

    @ModelField(value = "active", defaultValue = "true")
    private boolean flag;

    @ModelField(persist = true)
    @DecimalMax("500000")
    private BigInteger bigValue;

    @ModelField(mapping = "bigValue", persist = false, convert = "function(v, record) { return (record.raw.bigValue > 1000000);}")
    private boolean aBooleanVirtual;

    @ModelAssociation(value = ModelAssociationType.HAS_MANY, model = OtherBean.class, autoLoad = true)
    public List<OtherBean> otherBeans;

    //get/set methods
}


@Model(value = "MyApp.OtherBean")
public class OtherBean {

    private int id;

    private int bean_id;

    @JsonIgnore
    @ModelAssociation(value = ModelAssociationType.BELONGS_TO)
    private Bean bean;

    //get/set methods
}


Sencha Touch 2.x model objects

Ext.define("MyApp.Bean",
{
  extend : "Ext.data.Model",
  config : {
    idProperty : "myVerySpecialId",
    fields : [ {
      name : "myVerySpecialId",
      type : "int"
    }, {
      name : "firstName",
      type : "string"
    }, {
      name : "lastName",
      type : "string"
    }, {
      name : "someIds",
      type : "auto"
    }, {
      name : "dateOfBirth",
      type : "date",
      dateFormat : "c"
    }, {
      name : "email",
      type : "string"
    }, {
      name : "something",
      type : "string",
      useNull : true
    }, {
      name : "active",
      type : "boolean",
      defaultValue : true
    }, {
      name : "bigValue",
      type : "int"
    }, {
      name : "aBooleanVirtual",
      type : "boolean",
      mapping : "bigValue",
      persist : false,
      convert : function(v, record) { return (record.raw.bigValue > 1000000);}
    } ],
    associations : [ {
      type : "hasMany",
      model : "MyApp.OtherBean",
      associationKey : "otherBeans",
      foreignKey : "bean_id",
      primaryKey : "myVerySpecialId",
      autoLoad : true,
      name : "otherBeans"
    } ],
    validations : [ {
      type : "presence",
      field : "lastName"
    }, {
      type : "past",
      field : "dateOfBirth"
    }, {
      type : "email",
      field : "email"
    }, {
      type : "range",
      field : "bigValue",
      max : 500000
    } ],
    proxy : {
      type : "direct",
      idParam : "myVerySpecialId",
      api : {
        read : beanService.read,
        create : beanService.create,
        update : beanService.update,
        destroy : beanService.destroy
      },
      reader : {
        root : "records"
      }
    }
  }
});

Ext.define("MyApp.OtherBean",
{
  extend : "Ext.data.Model",
  config : {
    fields : [ {
      name : "id",
      type : "int"
    }, {
      name : "bean_id",
      type : "int"
    } ],
    associations : [ {
      type : "belongsTo",
      model : "MyApp.Bean",
      associationKey : "bean",
      foreignKey : "bean_id",
      primaryKey : "myVerySpecialId",
      setterName : "setBean",
      getterName : "getBean"
    } ]
  }
});

ModelGeneratorAPT
自1.3.1以上

ExtDirectSpring包含一个以ModelGenerator为基础的APT处理器。该处理器在编译时创建的Javascript模型文件。 
在Maven项目中添加以下配置到pom.xml中。插件apt-maven-plugin在maven生命周期generate-resources时自动运行。在命令行运行mvn generate-resources可以触发生命周期generate-resources阶段的运行。

<plugin>
  <groupId>com.mysema.maven</groupId>
  <artifactId>apt-maven-plugin</artifactId>
  <version>1.0.8</version>
  <executions>					
    <execution>
      <id>modelgen</id>
      <goals>
        <goal>process</goal>
      </goals>
      <configuration>
        <processor>ch.ralscha.extdirectspring.generator.ModelAnnotationProcessor</processor>
        <outputDirectory>src/main/webapp/app</outputDirectory>  
        <options>
           <!-- Add options here. See description below -->
        </options>      
      </configuration>
    </execution>					
  </executions>			
</plugin>

ModelAnnotationProcessor创建一个Javascript文件为每一个注解了@Model的Java类到输出目录。
当注解@Model没有包含一个value属性,处理器直接生成Javascript文件到输出目录,用类名作为文件名。
src/main/webapp/app/Club.js

@Entity
@Model
public class Club extends AbstractPersistable {
  ...
}

当存在一个value属性时,根据设置的值处理器创建文件和子目录。处理器会忽略掉字符串的第一部分(MyApp),文件名是字符串的最后一部分(Team),创建子目录用字符串中间的部分(model)。
src/main/webapp/app/model/Team.js

@Entity
@Model(value = "MyApp.model.Team")
public class Club extends AbstractPersistable {
  ...
}

src/main/webapp/app/model/part/Team.js

@Entity
@Model(value = "MyApp.model.part.Team")
public class Club extends AbstractPersistable {
  ...
}

Options

ModelAnnotationProcessor支持下面的这些选项

The ModelAnnotationProcessor supports these options

OptionDescription
<debug>true</debug>Writes the Javascript in a pretty, readable format. DEFAULT
<debug>false</debug>Writes the Javascript on one line.
<outputFormat>extjs4</outputFormat>Writes the model class in ExtJs4 format.DEFAULT
<outputFormat>touch2</outputFormat>Writes the model class in Touch2 format.
<includeValidation>none</includeValidation>Does not include any validation code.DEFAULT
<includeValidation>builtin</includeValidation>Includes validation code but only validations that are built into Ext JS and Sencha Touch.
<includeValidation>all</includeValidation>Includes all validation code.
<createBaseAndSubclass>true</createBaseAndSubclass>(since 1.3.2)Creates two files (base and subclass). It does not overwrite the subclass file if it exists. Example
/* ModelBase.js */
Ext.define('MyApp.model.ModelBase', {
extend: 'Ext.data.Model',
fields: [ ... ]
});

/* Model.js */
Ext.define('MyApp.model.Model', {
extend: 'MyApp.model.ModelBase
});
<useSingleQuotes>true</useSingleQuotes> (since 1.3.2)Writes single quotes instead of double quotes (default)
<surroundApiWithQuotes>true</surroundApiWithQuotes>(since 1.3.2)Surrounds the values of the proxy/api object with quotes
proxy : {
    type : "direct",
    api : {
      read : "userService.read",
      destroy : "userService.destroy"
    }
  }


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值