# sql2java **Repository Path**: l0km/sql2java ## Basic Information - **Project Name**: sql2java - **Description**: 轻量级数据库(SQL)访问代码(java)生成器 - **Primary Language**: Java - **License**: BSD-2-Clause - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 17 - **Forks**: 7 - **Created**: 2019-11-19 - **Last Updated**: 2025-06-13 ## Categories & Tags **Categories**: database-dev **Tags**: 数据库 ## README # sql2java sql2java是一个轻量级数据库(SQL)访问代码(java)生成器,是在国外一款同名开源项目([https://sourceforge.net/projects/sql2java](https://sourceforge.net/projects/sql2java))的基础上重写的ORM工具,以maven 插件方式运行,目前在mysql下测试通过已经应用于实际项目开发中 - 生成的表记录的java bean类支持thrift/swift,swagger 注释,生成的java bean对象可以直接用于thrift/swfit服务的数据类型 - 支持表记录内存缓存(cache)机制 - 支持侦听器(listener)机制用于通知表记录增册改事件 - 支持事务(transaction)操作 - 支持自增长键(AUTO_INCREMENT) - 支持自定义扩展模板(velocity),用户可以使用自定义的模板生成扩展代码 - 支持乐观锁(optimisticlock) ### 生成的java代码结构 ![bean](images/sql2java06.png) ### 生成的数据记录类示例 ![bean](images/sql2java05.png) ## 编译项目 编译要求 JDK 1.7,Maven 3.5 以上版本 # 下载源码 git clone https://gitee.com/l0km/sql2java.git cd sql2java # 编译全部 mvn install >sql2java的maven插件已经发布到maven中央仓库,如果只是要运行maven插件无需编译本项目 ## 快速使用说明 ### 创建配置文件 如下创建一个最简的参数配置文件(mysql2java.properties),用于告诉sql2java如何生成java代码, "#"起始的行为注释 # 指定 JDBC driver,告诉sql2java如何连接数据 jdbc.driver=com.mysql.jdbc.Driver # 对于 mysql 数据库,如果 useInformationSchema=false 或没指定,则无法获取表中的注释信息 jdbc.url=jdbc:mysql://localhost:3306/test?characterEncoding=utf8&useInformationSchema=true jdbc.username=root jdbc.password= jdbc.schema=test # 定义生成代码的包名 codewriter.package=sql2java.test ### 生成代码 执行如下maven插件,即开始从数据库中读取表结构信息并生成对应的java代码到当前文件夹下(src/main) $ mvn com.gitee.l0km:sql2java-maven-plugin:generate \ -Dsql2java.classpath=lib/mysql-connector-java-5.1.43-bin.jar \ -Dsql2java.propfile=mysql2java.properties [INFO] Scanning for projects... [INFO] [INFO] ------------------------------------------------------------------------ [INFO] Building sql2java test 0.0.0-SNAPSHOT [INFO] ------------------------------------------------------------------------ [INFO] [INFO] --- sql2java-maven-plugin:1.0.6-SNAPSHOT:generate (default-cli) @ sql2java-test --- database properties initialization [INFO] classpath: [file:/D:/j/sql2java.test/lib/mysql-connector-java-5.1.43-bin.jar] Connecting to root on jdbc:mysql://localhost:3306/test?characterEncoding=utf8&useInformationSchema=true ... Connected. Database server :MySQL. Loading table list according to pattern t_% ... table t_book found table t_user found samePrefix = [t_] Loading columns ... t_book.id INT default value: null t_book.name VARCHAR default value: null t_book.borrower INT default value: null t_book found 3 columns t_user.id INT AUTOINCREMENT default value: null t_user.name VARCHAR default value: null t_user.birthdate DATE default value: null t_user.phone VARCHAR default value: null t_user.address VARCHAR default value: null t_user found 5 columns Database::loadPrimaryKeys Found primary key (seq,name) (1,id) for table 't_book' Found primary key (seq,name) (1,id) for table 't_user' Loading imported keys ... t_book.id -> t_user.id found seq:1 foreign key name:fk_id UPDATE_RULE:NO_ACTION DELETE_RULE:RESTRICT Loading indexes ... Found interesting index phone_UNIQUE on phone for table t_user Loading procedures ... Generating template /templates/velocity/java5g/perschema/constant.java.vm .... writing to src/main\java\sql2java\test\Constant.java java\sql2java\test\Constant.java done. Generating template /templates/velocity/java5g/perschema/database.properties.vm .... writing to src/main\resources/conf\database.properties resources/conf\database.properties done. Generating template /templates/velocity/java5g/perschema/gu.sql2java.irowmetadata.vm .... writing to src/main\resources/META-INF/services\gu.sql2java.IRowMetaData resources/META-INF/services\gu.sql2java.IRowMetaData done. Generating template /templates/velocity/java5g/pertable/bean.java.vm .... writing to src/main\java\sql2java\test\BookBean.java java\sql2java\test\BookBean.java done. Generating template /templates/velocity/java5g/pertable/manager.interface.java.vm .... writing to src/main\java\sql2java\test\IBookManager.java java\sql2java\test\IBookManager.java done. Generating template /templates/velocity/java5g/pertable/metadata.java.vm .... writing to src/main\java\sql2java\test\BookMetaData.java java\sql2java\test\BookMetaData.java done. Generating template /templates/velocity/java5g/pertable/bean.java.vm .... writing to src/main\java\sql2java\test\UserBean.java java\sql2java\test\UserBean.java done. Generating template /templates/velocity/java5g/pertable/manager.interface.java.vm .... writing to src/main\java\sql2java\test\IUserManager.java java\sql2java\test\IUserManager.java done. Generating template /templates/velocity/java5g/pertable/metadata.java.vm .... writing to src/main\java\sql2java\test\UserMetaData.java java\sql2java\test\UserMetaData.java done. [INFO] ------------------------------------------------------------------------ [INFO] BUILD SUCCESS [INFO] ------------------------------------------------------------------------ [INFO] Total time: 1.248 s [INFO] Finished at: 2019-12-16T13:51:20+08:00 [INFO] Final Memory: 13M/308M [INFO] ------------------------------------------------------------------------ >com.gitee.l0km:sql2java-maven-plugin插件已经发布到maven中央仓库,无需编译本项目就可直接运行,上面的例子中没有指定插件的版本,则默认使用最新版本的插件 参数说明: | name | description | | :----------------- | :--------------------------------- | | sql2java.classpath | 指定连接数据库的JDBC driver jar包 | | sql2java.propfile | 指定sql2java生成代码必须的配置文件 | ## 完整示例 参见sql2java演示项目: [sql2java-example: sql2java调用示例 (gitee.com)](https://gitee.com/l0km/sql2java-example) 用户可以在此演示项目的基础上修改完成自己的ORM代码项目结构 ## 实际应用示例 参见开源项目 facelog: [https://gitee.com/l0km/facelog/tree/master/db2](https://gitee.com/l0km/facelog/tree/master/db2 "https://gitee.com/l0km/facelog/tree/master/db2") ## 获取所有参数说明 为了控制java代码的生成方式,sql2java有几十个控制参数,默认情况下大部分可以不用修改,如果需要需要修改,就需要获取这些参数名字及说明,如下执行 maven 插件,显示所有配置说明以及插件本身的参数说明: mvn com.gitee.l0km:sql2java-maven-plugin:help 如下执行 maven 插件,则在当前文件夹下生成一份名为my.properties的默认参数配置文件,你可以在此文件的基础上修改自己的代码生成配置: $ mvn com.gitee.l0km:sql2java-maven-plugin:help -Dsql2java.output=my.properties [INFO] Scanning for projects... [INFO] [INFO] ------------------------------------------------------------------------ [INFO] Building sql2java test 1.0.2 [INFO] ------------------------------------------------------------------------ [INFO] [INFO] --- sql2java-maven-plugin:1.0.2:help (default-cli) @ sql2java-test --- [INFO] OUTPUT PROPRETIES TO J:\sql2java.test\my.properties [INFO] ------------------------------------------------------------------------ [INFO] BUILD SUCCESS [INFO] ------------------------------------------------------------------------ [INFO] Total time: 0.495 s [INFO] Finished at: 2019-11-20T15:25:27+08:00 [INFO] Final Memory: 10M/308M [INFO] ------------------------------------------------------------------------ ## 参数说明 SQL2JAVA的参数配置及说明如下 >参数以`参数名`=`参数值`形式定义,所有`#`开始的行皆为注释行 #______________________________________________ # # (1/8) 数据库访问配置(必填) #______________________________________________ # JDBC驱动类名 #jdbc.driver=org.hsqldb.jdbcDriver # 数据库访问的URL #jdbc.url=jdbc:hsqldb:hsql://localhost # 访问数据库的用户名 #jdbc.username=sa # 访问数据库的密码 #jdbc.password= # 访问的数据库名 #jdbc.schema=null #______________________________________________ # # (2/8) 配置自增长键的检索方式(可选) #______________________________________________ # 此部分配置用于在插入记录时获取自增长键的值 # 对于JDBC 3.0以上支持PreparedStatement.getGeneratedKeys方法 # (DatabaseMetaData.supportsGetGeneratedKeys()返回true)的JDBC 驱动不需要配置此部分 # # generatedkey.retrieve 可选值: # # auto - [默认值]getGeneratedKeys方法自动获取,当使用JDBC 3.0 driver时适用. # # before - 在插入(insert)记录之前获取自增长键值 # # after - 在插入(insert)记录之后获取自增长键值 # # generatedkey.statement用于定义获取自增长键值的SQL语句 # If you set it to before or after you also need to configure the # autogeneratedkey.statement properties. # 占位符用于取代当前表名 # 占位符用于取代当前自增长键字段名 # #generatedkey.retrieve=auto #generatedkey.statement= #______________________________________________ # # (3/8) 生成代码配置(可选) #______________________________________________ # 生成java代码的包名 codewriter.package=gu.sql2java.demo # 生成java代码的文件夹 codewriter.destdir=src/main # 生成扩展java代码的文件夹 #codewriter.destdir.extension= # 生成扩展java代码的包名 #codewriter.package.extension= # 定义被bean.converter.utils.java.vm 模板忽略的字段名 #general.beanconverter.tonative.ignore=create_time,update_time # 生成的java bean是否支持facebook/swift 注释(annotation) #swift.annotation.bean = true # 生成的java bean是否支持swagger 注释(annotation) #swagger.annotation.bean = true # 对于有primitive 类型(Integer,Long,Double...)的字段是否生成primitive类型的setter方法 codewriter.bean.primitiveSetter = true # generate Long setter for Date type # 对于 java.util.Date 类型的字段是否生成 Long类型的setter方法 codewriter.bean.dateLongSetter = true # Date 类型的JSON 序列化类型 : # Long 系统时间(毫秒) # String ISO8601 时间日期格式的字符串 # 当指定了 swift或jackon注解时有效 codewriter.bean.dateSerializeType = Long # 当 dateSerializeType 为 String 的日期格式,默认为IS8601 格式 codewriter.bean.dateStringFormat=yyyy-MM-dd'T'HH:mm:ss.SSSZ # modified,initialized 字段的类型(不要修改) bitstate.type = int # 字节数对应的java类型: # byte[] # java.nio.ByteBuffer # default byte[] if not specialized #binary.type = byte[] # add @JsonRawValue @JsonDeserialize annotation for JSON field #json.jackson.rawvalue = false #set properties file name for database database.properties.env=config_folder database.properties.isdebug=false database.properties.dir=resources/conf database.properties=database.properties #flag for compatible with axis2 #bean.compatible_axis2=true # Property file to use when initializing Velocity #codewriter.velocityprops=somefile # 默认加载模板的路径(不要修改) velocity.templates.loadingpath=/templates/velocity/includes # 为每张表(pertable)和每个方案(perschema)加载子模板的加载起始路径(不要修改) velocity.templates=/templates/velocity/ ############ 扩展模板 ############### # 用户可以通过下面的扩展模板参数,指定自己定义的模板(.vm)文件的位置 # sql2java generator会根据指定的参数执行扩展模板生成代码 # 扩展模板的加载路径 #velocity.templates.loadingpath.extension= # 为每张表(pertable)和每个方案(perschema)加载扩展模板的加载起始路径 #velocity.templates.extension = # sets a prefix to prepend to all generated classes # useful if you are worried about namespace collision with reserved words # or java.lang classes codewriter.classprefix= # 是否为字段生成默认值 codewriter.generate.defaultvalue=true #______________________________________________ # # (4/8) 表和模板过滤配置(可选) #______________________________________________ # # 通过表类型过滤 # 用于指定需要生成代码的表类型(用逗号分隔的表类型列表) # 表类型定义为:TABLE, VIEW, SYSTEM TABLE, SYNONYM jdbc.tabletypes=TABLE, VIEW # 通过表名过滤 # 使用通配%来过滤需要生成代码的表名 # 你可以指定一个逗号分割的通配符过滤列表 # 比如 %_name,ul_% 只对后缀为_name,或前缀为ul_的表名生成代码 # 默认对schema中所有的表生成代码 jdbc.tablenamepattern=% # 表名白名单/名单过滤(此特性暂未启用) # 白名单 # 空格分隔的表名列表,只在此名单中的表才会被生成代码 # 黑名单 # 空格分隔的表名列表,在此名单中的表不会被生成代码 # 白名单和黑名单只能定义一个,如果同时指定了白名单和黑名单则忽略黑名单 # 白名单过滤 tables.include= # 黑名单过滤 tables.exclude= # 模板文件夹名白名单/名单过滤 # 白名单 # 空格分隔的表名列表,只在此名单中的模板文件夹中的模板才会被生成代码 # 黑名单 # 空格分隔的表名列表,在此名单中的模板文件夹中的模板不会被生成代码 # 白名单和黑名单只能定义一个,如果同时指定了白名单和黑名单则忽略黑名单 template.folder.exclude= template.folder.include=java5g # java5g : general bean & manager templates for java5 # (6/8) WHAT SHOULD BE DISPLAYED/NOT DISPLAYED ON THE FRONTEND ? # empty means all fields #______________________________________________ # 逗号分割的字段名列表定义只能本地可见的字段 # A comma separated list of field names in a specified table that can only be accessed locally # Equivalent to defining in the annotation of a field: ' SCOPE@LOCAL@EPOSC ' # Example: # table.user_info.scope.local=private_time,password # 逗号分割的字段名列表定义THRIFT可见的字段 # A comma separated list of field names in a specified table that can be transmitted by RPC # in addition to being accessible locally # Equivalent to defining in the annotation of a field: ' SCOPE@THRIFT@EPOSC ' # Example: # table.user_info.scope.thrift=password # 逗号分割的字段名列表定义JSON可见的字段 # A comma separated list of field names in a specified table that can be serialized by JSON # in addition to being accessible locally # Equivalent to defining in the annotation of a field: ' SCOPE@JSON@EPOSC ' # Example: # table.user_info.scope.json=private_time,password ​ ​ #______________________________________________ ​ # ​ # (7/8) JDBC 类型映射(可选) ​ #______________________________________________ ​ # ​ # jdbc DATE类型映射的java类型,可选值: ​ # java.sql.Date ​ # java.util.Date ​ jdbc2java.date=java.util.Date ​ ​ # jdbc TIME类型映射的java类型,可选值: ​ # java.sql.Time ​ # java.util.Date ​ jdbc2java.time=java.util.Date ​ # jdbc TIMESTAMP类型映射的java类型,可选值: # java.sql.Timestamp # java.util.Date jdbc2java.timestamp=java.util.Date #______________________________________________ # # (8/8) 乐观锁配置(可选) #______________________________________________ # optimisticlock.type 有两个可选项值: # none - 乐观锁机制未启用(default). # timestamp - 乐观锁字段包含 System.currentTimeMillis() 值. # # optimisticlock.column 定义乐观锁的字段名,如果字段名不存在则乐观锁机制不会启用 # 乐观锁的字段类型可以是java.lang.Long or java.lang.String. optimisticlock.type=timestamp optimisticlock.column=version_time ## 数据库字段编解码器 从 3.21.0 开始,sql2java增加了[ColumnCodec](sql2java-base/src/main/java/gu/sql2java/BaseColumnCodec.java)接口用于应用层自定义对数据字段的序列化和反序列化,序列化方法(`ColumnCodec.serialize`)用于将自定义类型数据转换为数据库字段存储类型,反序列化方法(`ColumnCodec.deserialize`)则将字段存储类型转换为自定义数据类型。对于JSON类型的支持使用[JsonColumnCodec](sql2java-base/src/main/java/gu/sql2java/json/JsonColumnCodec.java)实现,应用层可以参照`JsonColumnCodec`基于 [BaseColumnCodec](sql2java-base/src/main/java/gu/sql2java/BaseColumnCodec.java) 实现自定义的数据库字段编解码器。 ## 自定义类型字段支持 从 3.21.0 开始,增加数据库字段注释标记 `ANN@@NNA` 和`TYPE@@EPYT`,应用层定义数据库字段的类型和编解码器,sql2java在生成代码时会自动根据此标记在生成指定类型的Java成员以及`@ColumnCodecConfig`注解。 ### TYPE@@EPYT 定义字段类型,如`ATYPE@net.facelib.eam.interpreter.Rectangle@EPYT`,将字段类型定义为`net.facelib.eam.interpreter.Rectangle` ### ANN@@NNA 定义字段的注解,可定义多个,如`ANN@gu.sql2java.annotations.ColumnCodecConfig(net.facelib.eam.interpreter.sql2java.EamPlayColumnCodec.class)@NNA`,将在Java成员上生成注解`@gu.sql2java.annotations.ColumnCodecConfig(net.facelib.eam.interpreter.sql2java.EamPlayColumnCodec.class)` ### 示例 下面的表中`rect`字段定义了`TYPE@@EPYT`和`ANN@@NNA` ```sql CREATE TABLE IF NOT EXISTS dc_device_channel ( `device_id` int NOT NULL COMMENT 'X@NAME:设备ID@X', `sid` int NOT NULL DEFAULT 0 COMMENT 'X@NAME:物理屏幕ID@x', `area` varchar(32) NOT NULL COMMENT 'X@NAME:显示区域ID@x', `rect` varchar(256) DEFAULT NULL COMMENT 'ANN@gu.sql2java.annotations.ColumnCodecConfig(net.facelib.eam.interpreter.sql2java.EamPlayColumnCodec.class)@NNATYPE@net.facelib.eam.interpreter.Rectangle@EPYTX@NAME:显示区域坐标@x,对应EamPlayer的defineChannel语法', `channel` varchar(32) NOT NULL COMMENT 'X@NAME:频道ID@x,显示区域对应的频道', `run_tasks` text DEFAULT NULL COMMENT 'X@NAME:播放任务@X描述,设备实际播放的任务描述,由设备端写入,对应EamPlayer的definePlanTask和defineTrigger语法', PRIMARY KEY(`device_id`,`sid`,`area`), FOREIGN KEY (device_id) REFERENCES dc_device(id) ON DELETE CASCADE, INDEX (channel) )COMMENT 'X@NAME:设备显示区域频道记录@X' DEFAULT CHARSET=utf8; ``` 生成的java类中对应`rect`的示例 ```java /** comments:X@NAME:显示区域坐标@x,对应EamPlayer的defineChannel语法 */ @ApiModelProperty(value = "X@NAME:显示区域坐标@x,对应EamPlayer的defineChannel语法" ,dataType="Rectangle") @CodegenLength(max=256)@CodegenInvalidValue @ExcelColumn(sort=4) @gu.sql2java.annotations.ColumnCodecConfig(net.facelib.eam.interpreter.sql2java.EamPlayColumnCodec.class) private net.facelib.eam.interpreter.Rectangle rect; ``` getter/setter方法的对应类型为`net.facelib.eam.interpreter.Rectangle` getter方法 ```java @ThriftField(value=7) @JsonProperty("rect") public net.facelib.eam.interpreter.Rectangle getRect(){ return rect; } ``` setter方法 ```java @ThriftField(name="rect") @JsonProperty("rect") public void setRect(net.facelib.eam.interpreter.Rectangle newVal) { modified |= DC_DEVICE_CHANNEL_ID_RECT_MASK; initialized |= DC_DEVICE_CHANNEL_ID_RECT_MASK; if (Objects.equals(newVal, rect)) { return; } rect = newVal; } ``` read/write方法对应的类型为rect字段的数据存储类型 read方法 ```java public String readRect(){ return metaData.columnCodecs[DC_DEVICE_CHANNEL_ID_RECT].serialize(rect,String.class); } ``` write方法 ```java public void writeRect(String newVal){ modified |= DC_DEVICE_CHANNEL_ID_RECT_MASK; initialized |= DC_DEVICE_CHANNEL_ID_RECT_MASK; rect = metaData.columnCodecs[DC_DEVICE_CHANNEL_ID_RECT].deserialize(newVal,metaData.fieldOf(DC_DEVICE_CHANNEL_ID_RECT).getGenericType()); } ``` ### SCOPE@@EPOSC 字段注释标记 `SCOPE@@EPOSC` 用于定义字段可见度,具体格式为 ``` SCOPE@(LOCAL|JSON|THRIFT)@EPOSC ``` 可定义三种可见度 - LOCAL 本地可见 - JSON JSON序列化/反序列化可见 - THRIFT Thrift RPC 序列化/反序列化可见 如下示例,下面的表定义中,`private_time`字段定义了`SCOPE@@EPOSC`注释标记,指定了该字段仅本地可见。也就是说只有服务端本身可以读写该字段。 ```sql CREATE TABLE IF NOT EXISTS dc_device ( `id` int(11) NOT NULL PRIMARY KEY AUTO_INCREMENT COMMENT 'X@NAME:设备id@X', `name` varchar(32) DEFAULT NULL COMMENT 'X@NAME:设备名称@X,用户指定', `physical_address` varchar(32) NOT NULL UNIQUE COMMENT '设备X@NAME:物理地址@X,MAC地址,IMEI或其他设备识别码', `private_time` bigint DEFAULT 0 COMMENT 'SCOPE@LOCAL@EPOSC设备令牌创建的时间戳(毫秒),每次创建设备令牌都会修改此字段', `os_arch` varchar(64) DEFAULT NULL COMMENT 'X@NAME:操作系统平台@X,操作系统名称及版本及硬件架构名称,例如:Windows-x86_64,Linux-x86_64,Android-arm...' ) COMMENT 'X@NAME:前端设备记录@X,前端设备基本信息' DEFAULT CHARSET=utf8; ``` sql2java-generator生成的`DeviceBean`对象中`dc_device.private_time`字段的对应成员`privateTime`定义代码如下: ```java /** comments:设备令牌创建的时间戳(毫秒),每次创建设备令牌都会修改此字段 */ @ApiModelProperty(value = "设备令牌创建的时间戳(毫秒),每次创建设备令牌都会修改此字段" ,dataType="Long") @CodegenDefaultvalue("0")@CodegenInvalidValue("-1") @ExcelColumn(sort=9) @com.alibaba.fastjson.annotation.JSONField(serialize = false,deserialize = false) @com.fasterxml.jackson.annotation.JsonIgnore private Long privateTime; /** * Getter method for {@link #privateTime}.
* Meta Data Information (in progress): * * * @return the value of privateTime */ @JsonIgnore public Long getPrivateTime(){ return privateTime; } ``` 可以看到,`privateTime`成员定义的Jackson注解`@JsonIgnore`和fastjson注解`@JSONField`指定该字段在JSON序列化和反序列化时忽略应该字段。同时`privateTime`的getter方法上也没有thrift字段注解`@ThriftField`,代表应该字段也没有被定义为Thrift成员字段。 swift2thrift-maven-plugin插件生成的IDL中就不会有`privateTime`字段: ```idl struct DeviceBean { 1: required bool _new; 2: required i32 modified; 3: required i32 initialized; 4: optional i32 id; 5: optional string name; 6: optional string physicalAddress; 7: optional string osArch; } ``` ## Boolean字段支持 3.19.0之前不论是`TINYINT,SMALLINT,INT`类型对应的Java类型都是`Integer`,3.19.0版本之后,细分了整数类型字段生成的Java数据类型,如下表 | SQL 类型 | Java字段类型 | 说明 | | -------------------- | ----------------- | ------------------------------------------------------------ | | TINYINT/BOOL/BOOLEAN | `Byte` /`Boolean` | 如果数据库字段注释(COMMENT)中定义了`[NUM,Boolean]`,则生成的Java成员类型为`Boolean`,否则为`Byte` | | SMALLINT | `Short` | | | INT | `Integer` | | 示例: ```sql CREATE TABLE IF NOT EXISTS dc_device ( `id` int(11) NOT NULL PRIMARY KEY AUTO_INCREMENT COMMENT '设备id', `online` boolean DEFAULT false COMMENT '[NUM,Boolean],是否在线标记' ); ``` 如上定义`boolean/bool`或`TINYINT`类型字段在生成的Java Bean中`online`字段将被定义为`Boolean`类型。 > **注意:**在注释中`[NUM,Boolean]`标记必须在字符串起始位置。 ## JSON字段支持 从3.8版本之后,sql2java支持对保存JSON数据的String字段自动序列化和反序列。 ### 开启json.jackson.rawvalue 要开启此特性,需要做如下两步简单的设置 > 开启此特性生成的代码需要fastjson,jackson库的支持 - 修改 sql2java.properties 将`json.jackson.rawvalue`置为`true`,即增加如下设置 ```properties # # add @JsonRawValue @JsonDeserialize annotation for JSON field #json.jackson.rawvalue = true ``` - 修改建表语句 在需要定义为保存JSON数据的字段的注释中增加[JSON_STR,...]前缀,通过此前缀指定该字段要保存JSON数据(只对Java类型为String的字段有效) 示例如下: ```sql CREATE TABLE IF NOT EXISTS dc_device_group ( `id` int(11) NOT NULL PRIMARY KEY AUTO_INCREMENT COMMENT '设备组id', `name` varchar(32) NOT NULL COMMENT '设备组名', `address` varchar(128) DEFAULT NULL COMMENT '设备组详细地址:区/街道门牌', `props` text DEFAULT NULL COMMENT '[JSON_STR,obj]JSON格式的扩展字段(最大64KB),用于定义扩展信息,online_time:开机时间,offline_time:关机时间,close_time:闭站时间,operator:操作人', `create_time` timestamp DEFAULT CURRENT_TIMESTAMP, `update_time` timestamp DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP ) COMMENT '设备组信息' DEFAULT CHARSET=utf8; ``` 上面的示例中`props`字段的注释以`[JSON_STR,obj]`为前缀,即定义该字段为JSON字段,JSON字段的类型为Object 只要做了上面两项目修改,重新执行Sql2java生成代码就可以了。 ### [JSON_STR] 生成代码时会根据`[JSON_STR,...]`来确定JSON字段的类型 | [JSON_STR]格式 | JSON字段类型 | | ------------------------------------- | ------------------------------- | | [JSON_STR,array] | com.alibaba.fastjson.JSONArray | | [JSON_STR,object] | com.alibaba.fastjson.JSONObject | | [JSON_STR,obj] | com.alibaba.fastjson.JSONObject | | [JSON_STR] | com.alibaba.fastjson.JSON | | [JSON_STR,com.mycompany.product.User] | com.mycompany.product.User | ### 生成代码示例 props 字段定义代码: ```java /** comments:[JSON_STR]JSON格式的扩展字段(最大64KB),用于定义扩展信息,online_time:开机时间,offline_time:关机时间,close_time:闭站时间,operator:操作人 */ @ApiModelProperty(value = "[JSON_STR]JSON格式的扩展字段(最大64KB),用于定义扩展信息,online_time:开机时间,offline_time:关机时间,close_time:闭站时间,operator:操作人" ,dataType="String") @CodegenLength(max=65535)@CodegenInvalidValue @com.fasterxml.jackson.annotation.JsonRawValue @com.fasterxml.jackson.databind.annotation.JsonDeserialize(using = gu.sql2java.json.RawJsonDeserializer.class) private com.alibaba.fastjson.JSONObject props; ``` getter/setter方法代码,以String类型对字段进行读写: ```java @ThriftField(value=16) @JsonProperty("props") public String getProps(){ return null == props ? null : props.toJSONString(); } @ThriftField(name="props") @JsonProperty("props") public void setProps(String newVal) { modified |= DC_DEVICE_GROUP_ID_PROPS_MASK; initialized |= DC_DEVICE_GROUP_ID_PROPS_MASK; props = com.alibaba.fastjson.JSONObject.parseObject(newVal,com.alibaba.fastjson.JSONObject.class); } ``` 额外生成的read/write方法代码,提供对JSON对象直接读写: ```java /** * read method for {@link #props}
* @return the JSON value of props */ public com.alibaba.fastjson.JSONObject readProps(){ return props; } /** * write method for {@link #props} with JSON object.
*/ public void writeProps(com.alibaba.fastjson.JSONObject newVal){ modified |= DC_DEVICE_GROUP_ID_PROPS_MASK; initialized |= DC_DEVICE_GROUP_ID_PROPS_MASK; if (Objects.equals(newVal, props)) { return; } props = newVal; } ``` ### 序列化效果 ``` { "modified": 0, "initialized": 65535, "new": false, "id": 5, "name": "连平客运总站", "address": null, "props": { "offline_time": "22:00", "online_time": "8:00", "operator": "unknow" }, "createTime": "2022-07-06T12:41:56.000+0800", "updateTime": "2022-07-06T12:41:56.000+0800" } ``` ## Excel 注解支持 自从3.10开始,sql2java提供基于[apache/poi](https://github.com/apache/poi)实现的数据记录导出为Excel格式数据流或文件的功能.参见[sql2java-excel/README.md](sql2java-excel/README.md). sql2java-excel支持注解方式配置每张表每个字段的Excel导出配置。sql2java-generator在生成Java Bean代码时支持从SQL 表和字段注释COMMENT中根据读取预定义的标记,在Java Bean类代码中生成[@ExcelSheet](sql2java-excel/src/main/java/gu/sql2java/excel/annotations/ExcelSheet.java),[@ExcelColumn](sql2java-excel/src/main/java/gu/sql2java/excel/annotations/ExcelColumn.java)注解。 ### 开启excel.annotation.bean 要开启Excel注解生成特性,需要做如下两步设置 > 开启此特性生成的代码需要sql2java-excel库的支持 - 修改 sql2java.properties 将`excel.annotation.bean`置为`true`,即增加如下设置 ```properties # generate @ExcelSheet,@ExcelColumn annotation if true excel.annotation.bean = true ``` - 修改建表语句 在数据库建表语句的表和字段注释(COMMENT)上根据需要定义特殊的EXCEL 标记,示例如下: 下面的CREATE TABLE SQL语句示例中用到了很多`X@....@X`标记,这些标记内容就是为sql2java-generator在生成JavaBean代码时用于识别生成`@ExcelSheet,@ExcelColumn`注解的特殊标记(tag): ```sql CREATE TABLE IF NOT EXISTS dc_device ( `id` int(11) NOT NULL PRIMARY KEY AUTO_INCREMENT COMMENT 'X@NAME:设备id@X', `group_id` int(11) DEFAULT 1 COMMENT 'X@NAME:所属设备组id@X', `features` int(11) DEFAULT 0 COMMENT 'X@NAME:设备组特性标志@X,应用层定义', `name` varchar(32) DEFAULT NULL COMMENT 'X@NAME:设备名称@X,用户指定', `physical_address` varchar(32) NOT NULL UNIQUE COMMENT '设备X@NAME:物理地址@X,MAC地址,IMEI或其他设备识别码', `address_type`varchar(16) NOT NULL DEFAULT 'MAC' COMMENT '设备物理X@NAME:地址类型@X(MAC,IMEI...),默认6字节MAC地址(HEX)', `iot_card` varchar(32) DEFAULT NULL UNIQUE COMMENT '设备X@NAME:物联网卡编号@X,例如联通叫iccid', `status` varchar(32) NOT NULL DEFAULT 'ENABLE' COMMENT 'X@NAME:设备状态@X,X@VALUES:ENABLE:正常,DISABLE:禁用,MAINTAIN:维护,PENDING:挂起(待审核)@X', `private_time` bigint DEFAULT 0 COMMENT '设备令牌创建的时间戳(毫秒),每次创建设备令牌都会修改此字段', `screen_info` varchar(32) DEFAULT NULL COMMENT 'X@NAME:设备屏幕信息@X,格式示例:15H1080x960--15(英)寸横屏分辨率1080x960,21V960x1080--21(英)寸横屏分辨率960x1080', `fixed_mode` varchar(8) DEFAULT 'FLOOR' COMMENT '设备X@NAME:安装方式@X,X@VALUES:HANG:悬挂,FLOOR:落地@X', `os_arch` varchar(64) DEFAULT NULL COMMENT 'X@NAME:操作系统平台@X,操作系统名称及版本及硬件架构名称,例如:Windows-x86_64,Linux-x86_64,Android-arm...', `network` varchar(32) DEFAULT NULL COMMENT 'X@NAME:网络连接类型@X:4G,WIFI,ETHERNET', `version_info`varchar(32) DEFAULT NULL COMMENT '设备端应用程序的X@NAME:版本@X号,格式由应用层定义', `model` varchar(32) DEFAULT NULL COMMENT 'X@NAME:设备型号@X', `vendor` varchar(32) DEFAULT NULL COMMENT 'X@NAME:设备供应商@X', `device_detail` varchar(512) DEFAULT NULL COMMENT '[JSON_STR,obj]X@NAME:设备产品详细信息@X,以JSON格式定义设备详细信息,JSON字段:X@NAMES:device_name:产品名称,manufacturer:制造商,made_date:生产日期@X,应用层可根据需要扩展', `props` text DEFAULT NULL COMMENT '[JSON_STR,obj]JSON格式的扩展字段(最大64KB),用于定义扩展信息,X@NAMES:last_active_time:上次在线时间,disk_capacity:磁盘容量,status_comment:状态变更说明@X', `plan_id` varchar(64) DEFAULT NULL COMMENT 'X@NAME:当前节目ID@X', `target_id` varchar(64) DEFAULT NULL COMMENT 'X@NAME:目标节目ID@X', `remark` varchar(256) DEFAULT NULL COMMENT 'X@NAME:备注@X', `create_time` timestamp DEFAULT CURRENT_TIMESTAMP COMMENT 'X@NAME:记录创建时间@X', `update_time` timestamp DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT 'X@NAME:记录修改时间@X' ) COMMENT 'X@NAME:前端设备记录@X,前端设备基本信息,X@SHEET:titleFillColor=YELLOW,hideColumns=private_time|props|device_detail@X' DEFAULT CHARSET=utf8; ``` 有了这些标记,sql2java-generator就会为dc_device表生成如下的带有`@ExcelSheet,@ExcelColumn`注解的Java Bean代码: ```java /** * DeviceBean is a mapping of dc_device Table. *
Meta Data Information (in progress): * * @author guyadong */ @ExcelSheet(sheetName="dc_device",title="前端设备记录",titleFillColor="YELLOW",hideColumns={"private_time","props","device_detail"}) public final class DeviceBean extends BaseRow implements Serializable,Constant { private static final long serialVersionUID = -3495281739409382636L; /** comments:设备id */ @ExcelColumn(sort=1,name="设备id") private Integer id; /** comments:所属设备组id */ @ExcelColumn(sort=2,name="所属设备组id") private Integer groupId; /** comments:设备组特性标志,应用层定义 */ @ExcelColumn(sort=3,name="设备组特性标志") private Integer features; /** comments:设备名称,用户指定 */ @ExcelColumn(sort=4,name="设备名称") private String name; /** comments:设备物理地址,MAC地址,IMEI或其他设备识别码 */ @ExcelColumn(sort=5,name="物理地址") private String physicalAddress; /** comments:设备物理地址类型(MAC,IMEI...),默认6字节MAC地址(HEX) */ @ExcelColumn(sort=6,name="地址类型") private String addressType; /** comments:设备物联网卡编号,例如联通叫iccid */ @ExcelColumn(sort=7,name="物联网卡编号") private String iotCard; /** comments:设备状态,ENABLE:正常,DISABLE:禁用,MAINTAIN:维护,PENDING:挂起(待审核) */ @ExcelColumn(sort=8,name="设备状态",readConverterExp="ENABLE=正常, DISABLE=禁用, MAINTAIN=维护, PENDING=挂起(待审核)") private String status; /** comments:设备令牌创建的时间戳(毫秒),每次创建设备令牌都会修改此字段 */ @ExcelColumn(sort=9) private Long privateTime; /** comments:设备屏幕信息,格式示例:15H1080x960--15(英)寸横屏分辨率1080x960,21V960x1080--21(英)寸横屏分辨率960x1080 */ @ExcelColumn(sort=10,name="设备屏幕信息") private String screenInfo; /** comments:设备安装方式,HANG:悬挂,FLOOR:落地 */ @ExcelColumn(sort=11,name="安装方式",readConverterExp="HANG=悬挂, FLOOR=落地") private String fixedMode; /** comments:操作系统平台,操作系统名称及版本及硬件架构名称,例如:Windows-x86_64,Linux-x86_64,Android-arm... */ @ExcelColumn(sort=12,name="操作系统平台") private String osArch; /** comments:网络连接类型:4G,WIFI,ETHERNET */ @ExcelColumn(sort=13,name="网络连接类型") private String network; /** comments:设备端应用程序的版本号,格式由应用层定义 */ @ExcelColumn(sort=14,name="版本") private String versionInfo; /** comments:设备型号 */ @ExcelColumn(sort=15,name="设备型号") private String model; /** comments:设备供应商 */ @ExcelColumn(sort=16,name="设备供应商") private String vendor; /** comments:设备产品详细信息,以JSON格式定义设备详细信息,JSON字段:device_name:产品名称,manufacturer:制造商,made_date:生产日期,应用层可根据需要扩展 */ @ExcelColumns({ @ExcelColumn(sort=17,name="设备产品详细信息"), @ExcelColumn(sort=17,columnName="device_detail.device_name",name="产品名称"), @ExcelColumn(sort=17,columnName="device_detail.manufacturer",name="制造商"), @ExcelColumn(sort=17,columnName="device_detail.made_date",name="生产日期") }) @com.fasterxml.jackson.annotation.JsonRawValue @com.fasterxml.jackson.databind.annotation.JsonDeserialize(using = gu.sql2java.json.RawJsonDeserializer.class) private com.alibaba.fastjson.JSONObject deviceDetail; /** comments:JSON格式的扩展字段(最大64KB),用于定义扩展信息,last_active_time:上次在线时间,disk_capacity:磁盘容量,status_comment:状态变更说明 */ @ExcelColumns({ @ExcelColumn(sort=18), @ExcelColumn(sort=18,columnName="props.last_active_time",name="上次在线时间"), @ExcelColumn(sort=18,columnName="props.disk_capacity",name="磁盘容量"), @ExcelColumn(sort=18,columnName="props.status_comment",name="状态变更说明") }) @com.fasterxml.jackson.annotation.JsonRawValue @com.fasterxml.jackson.databind.annotation.JsonDeserialize(using = gu.sql2java.json.RawJsonDeserializer.class) private com.alibaba.fastjson.JSONObject props; /** comments:当前节目ID */ @ExcelColumn(sort=19,name="当前节目ID") private String planId; /** comments:目标节目ID */ @ExcelColumn(sort=20,name="目标节目ID") private String targetId; /** comments:备注 */ @ExcelColumn(sort=21,name="备注") private String remark; /** comments:记录创建时间 */ @ExcelColumn(sort=22,name="记录创建时间") private java.util.Date createTime; /** comments:记录修改时间 */ @ExcelColumn(sort=23,name="记录修改时间") private java.util.Date updateTime; ////////////////////////////// ///// 。。其他代码。。 //// ////////////////////////////// } ``` ### EXCEL 标记 本节说明说明EXCEL 标记`X@...@X`的定义方式 #### NAME tag `X@NAME:xxxx@X` 为表/字段名字定义标记,定义表或字段在输出EXCEL数据的标题或列名,当出现在表的注释语句(COMMENT)中时它对应生成`@ExcelSheet`的`title`,出现在字段的注释语句(COMMENT)中时它对应生成`@ExcelColumn`的`name`. #### NAMES tag `X@NAMES:a=b,c=d@X`为多符号定义标记,定义表或字段在在输出EXCEL数据时,子成员变量的列名.当出现在表的注释语句(COMMENT)中时它对应生成表成员或子成员字段的`@ExceColumn`注解代码以定义表成员或子成员字段的列名.出现在字段的注释语句(COMMENT)中且该字段被标记为JSON object字段时它对应生成JSON子成员字段的`@ExcelColumn`注解代码以定义JSON子成员字段的列名. 在上面的示例中,`device_detail`字段被定义为JSON object字段,且COMMENT中定义了NAMES tag:`X@NAMES:device_name:产品名称,manufacturer:制造商,made_date:生产日期@X`,相当就定义了该JSON成员中的`device_name,device_name,manufacturer,made_date`子成员字段在输出到EXCEL时对应的列名. > 如果实际该JSON 字段保存的字段不至这三个,还有`location`字段没有定义列名,输出该字段的列名是什么呢?没定义的情况默认就是`locaiton` #### VALUES tag `X@VALUES:a=b,c=d@X`为多值转换定义标记,用于定义在字段的值在输出到EXCEL时实际内容.对应于`@ExcelColumn`的`readConverterExp`. 如上示例中`dc_device.status`字段定义了VALUES tag:`X@VALUES:ENABLE:正常,CLOSED:关闭,MAINTAIN:维护,PENDING:挂起(待审核)@X`,即代表当月`status`字段值为`ENABLE`时,输出到Excel的值为`正常`,以此类推. #### COLUMN tag `X@COLUMN:a=b,c=d@X`为`@ExcelColumn`注解全字段定义标记,`@ExcelColumn`注解定义有数十个可配置的参数字段,`name,readConverterExp`只是常用的字段,所以定义了专用的NAME tag,VALUES tag,对于其他参数,都可以通COLUMN tag来进行定义. #### SHEET tag `X@SHEET:a=b,c=d@X`为`@ExcelSheet`注解全字段定义标记,`@ExcelSheet`注解定义有数十个可配置的参数字段,`name`只是常用的字段,所以定义了专用的NAME tag,对于其他参数,都可以通SHEET tag来进行定义. 上面的示例中dc_device表的注释(COMMENT)中使用了SHEET tag定义了:`@ExcelSheet`的`titleFillColor,hideColumns`:`X@SHEET:titleFillColor=YELLOW,hideColumns=private_time|props|device_detail@X` > 注意在这里,`@ExcelSheet`的`hideColumns`的类型是String数组,在SHEET tag中对于数组类型的字段定义多个元素时要用`|`分割. #### 专用标记优先于原则 即专用标记优先于COLUMN tag,SHEET tag定义 对于一个字段如果使用COLUMN tag,定义了`name`,同时也用NAME tag定义了列名,这种情况下优先使用NAME tag定义的值,对于SHEET tag也是一样的逻辑。 ## Geomerty类型字段支持 ```sql CREATE TABLE dc_spot ( `id` int(11) PRIMARY KEY AUTO_INCREMENT, `name` varchar(255) DEFAULT NULL COMMENT '地点名称', `spot` point DEFAULT NULL COMMENT '经纬度点' ) ENGINE=MyISAM DEFAULT CHARSET=utf8; ``` 从3.18.0版本开始,支持MySQL(above 5.7)的所有空间数据类型([Spatial Data Types](https://dev.mysql.com/doc/refman/5.7/en/spatial-type-overview.html))即几何类型(Geomerty)字段自动生成[JTS](https://www.osgeo.org/projects/jts/) 的 `com.vividsolutions.jts.geom.Geometry` 类型的成员. 如下为MySQL空间数据类型名与JTS 几何对象的对应表 | MySQL空间数据类型名 | JTS类 | | ------------------- | ---------------------------------------------- | | GEOMETRY | com.vividsolutions.jts.geom.Geometry | | POINT | com.vividsolutions.jts.geom.Point | | LINESTRING | com.vividsolutions.jts.geom.LineString | | POLYGON | com.vividsolutions.jts.geom.Polygon | | MULTIPOINT | com.vividsolutions.jts.geom.GeometryCollection | | MULTILINESTRING | com.vividsolutions.jts.geom.GeometryCollection | | MULTIPOLYGON | com.vividsolutions.jts.geom.GeometryCollection | | GEOMETRYCOLLECTION | com.vividsolutions.jts.geom.GeometryCollection | ### 配置参数 为控制生成的代码中对于Geomerty类型字段的getter/setter方法的类型,增加了`codewrite.bean.geometry.serial.type`参数 以下`codewrite.bean.geometry.serial.type`参数的说明 - STRING 【默认值】当`codewrite.bean.geometry.serial.type=STRING` 时,Geomerty类型字段的getter/setter方法的类型为String,即对外使用WKT字符串来表示几何对象 因为String是简单类型,这种方式可读性好,比较通用,符合常规场景下对Geometry类型的处理 生成代码示例: ```java private com.vividsolutions.jts.geom.Point spot; /** 将spot转为WKT字符串返回 */ public String getSpot(){ return null == spot ? null : spot.toText(); } /** 将WKT字符串转为Point保存到spot */ public void setSpot(String newVal){ spot = (null == newVal || newVal.isEmpty())? null : GeometryDataCodec.DEFAULT_INSTANCE.fromWKTUnchecked(newVal,Point.class); } /** 返回sport原始对象 */ public com.vividsolutions.jts.geom.Point readSpot(){ return spot; } /** 修改spot原始对象 */ public void writeSpot(com.vividsolutions.jts.geom.Point newVal){ spot = newVal; } ``` - JTS 当`codewrite.bean.geometry.serial.type=JTS` 时,JTS Geomertry 类型直接用于Geomerty类型字段的getter/setter方法的类型。 生成代码示例: ```java @com.fasterxml.jackson.databind.annotation.JsonDeserialize(using = gu.sql2java.geometry.jackson.GeometryDeserializer.class) @com.fasterxml.jackson.databind.annotation.JsonSerialize(using = gu.sql2java.geometry.jackson.GeometrySerializer.class) @com.alibaba.fastjson.annotation.JSONField(serializeUsing=gu.sql2java.geometry.fastjson.PointCodec.class,deserializeUsing=gu.sql2java.geometry.fastjson.PointCodec.class) private com.vividsolutions.jts.geom.Point spot; /** 返回sport原始对象 */ public com.vividsolutions.jts.geom.Point getSpot(){ return spot; } /** 修改spot原始对象 */ public void setSpot(com.vividsolutions.jts.geom.Point newVal){ spot = newVal; } ``` 不论`codewrite.bean.geometry.serial.type`参数如何选择,Geomerty类型字段生成的Java Bean的对应成员类型都为 JTS Geomerty类型。 ### jackson支持 JTS Geometry对象不是标准的Java Bean不能自动被Jackson执行序列化和反序列化。所以需要为 Geometry对象实现自定义的序列化器和反序列化器。 JTS Geometry类序列化器实现 [gu.sql2java.geometry.jackson.GeometryDeserializer](sql2java-base/src/main/java/gu/sql2java/geometry/jackson/GeometryDeserializer.java) JTS Geometry类反序列化器实现 [gu.sql2java.geometry.jackson.GeometrySerializer](sql2java-base/src/main/java/gu/sql2java/geometry/jackson/GeometrySerializer.java) 如下可以在以使用`@JsonDeserialize`和`@JsonSerialize`注解定义类成员字段的自定义序列化和反序列化器: ```java @com.fasterxml.jackson.databind.annotation.JsonDeserialize(using = gu.sql2java.geometry.jackson.GeometryDeserializer.class) @com.fasterxml.jackson.databind.annotation.JsonSerialize(using = gu.sql2java.geometry.jackson.GeometrySerializer.class) private com.vividsolutions.jts.geom.Point spot; ``` 直接引用自定义序列化和反序列化器示例参见:[GeometryJacksonTest](sql2java-base/src/test/java/gu/sql2java/GeometryJacksonTest.java) ### fastjson支持 JTS Geometry对象不是标准的Java Bean不能自动被fastjson执行序列化和反序列化。所以需要为 Geometry对象实现自定义的序列化器和反序列化器。 fastjson 为JTS Geometry类型自定义的序列化和反序列化实现的基类为[gu.sql2java.geometry.fastjson.GeometryCodec](sql2java-base/src/main/java/gu/sql2java/geometry/fastjson/GeometryCodec.java) 如下为详细的JTS Geometry类与fastjson自定义序列化反序列化类对应表 | JTS Geometry类 | fastjson自定义序列化反序列化类 | | ---------------------------------------------- | ------------------------------------------------------------ | | com.vividsolutions.jts.geom.Geometry | [gu.sql2java.geometry.fastjson.GeometryCodec](sql2java-base/src/main/java/gu/sql2java/geometry/fastjson/GeometryCodec.java) | | com.vividsolutions.jts.geom.Point | [gu.sql2java.geometry.fastjson.PointCodec](sql2java-base/src/main/java/gu/sql2java/geometry/fastjson/PointCodec.java) | | com.vividsolutions.jts.geom.LineString | [gu.sql2java.geometry.fastjson.LineStringCodec](sql2java-base/src/main/java/gu/sql2java/geometry/fastjson/LineStringCodec.java) | | com.vividsolutions.jts.geom.Polygon | [gu.sql2java.geometry.fastjson.PolygonCodec](sql2java-base/src/main/java/gu/sql2java/geometry/fastjson/PolygonCodec.java) | | com.vividsolutions.jts.geom.GeometryCollection | [gu.sql2java.geometry.fastjson.GeometryCollectionCodec](sql2java-base/src/main/java/gu/sql2java/geometry/fastjson/GeometryCollectionCodec.java) | #### 注解引用示例 如下可以在以使用`@JSONField`注解定义类成员字段的自定义序列化和反序列化器: ```java @com.alibaba.fastjson.annotation.JSONField( serializeUsing=gu.sql2java.geometry.fastjson.PointCodec.class, deserializeUsing=gu.sql2java.geometry.fastjson.PointCodec.class) private com.vividsolutions.jts.geom.Point spot; ``` 直接引用自定义序列化和反序列化器示例参见:[gu.sql2java.GeometryFastjsonTest](sql2java-base/src/test/java/gu/sql2java/GeometryFastjsonTest.java) #### GeometryInit [gu.sql2java.geometry.fastjson.GeometryInit](sql2java-base/src/main/java/gu/sql2java/geometry/fastjson/GeometryInit.java) 用于为fastjson指定JTS Geometry类型的全局序列化反序列器,即将上述的所有fastjson自定义序列化反序列化器实例设置为fastjson的全局序列化反序列化器 当需要单独对JTS Geometry进行序列化和反序列化时,可以使用此`GeometryInit.init()`完成全局初始化,以确保fastjson能正确处理JTS Geometry对象 示例如下: ```java @Test public void test2Fastjson() { try { GeometryInit.init(); String wkt = "POINT (1 -1)"; Point point = GeometryDataCodec.DEFAULT_INSTANCE.fromWKT(wkt,Point.class); log("point {}",JSON.toJSONString(point)); assertTrue(wkt.equals(point.toText())); } catch (ParseException e) { e.printStackTrace(); assertTrue(false); } } ``` ## 静态字段过滤 不论是Thrift RPC还是SpringWeb服务,服务方法的输入和输出参数都要通过网络在Server/Client之间传输。实现数据对象传输,发送端需要对数据对象进行序列化(JSON或二进制数据流),接收端需要对收到的数据反序列化还原为原始的数据对象。 从3.32.0版本开始,sql2java增加了静态字段过滤功能,是指在生成sql2java的数据库表记录对象类时,允许指定字段的可见度(ColumnVisibility)。 **可见度**是指字段对数据接收端是否可见,只要控制数据库表对象在序列化/反序列化时忽略不可见字段,数据接收端最终收到数据库对象中就不会包含该字段。 具体实现就是sql2java-generator会根据字段的可见度要求,对于不可见字段,在生成对应字段代码时增加Jackson,Fastjson,Thrift注解(Annotation)指定在表对象序列化/反序列化时忽略该字段。示例参见 **《SCOPE@@EPOSC》**章节 ### 字段可见度定义 sql2java中字段可见度定义对应枚举类型`gu.sql2java.ColumnVisibility` | 枚举变量 | JSON是否可见 | Thrift是否可见 | 说明 | | ----------- | ------------ | -------------- | ------------------------------------------------------------ | | **DEFAULT** | true | true | 默认:全可见 | | **LOCAL** | false | false | 仅本地可见,与远端(Spring WEB,Thrift RPC)交互时不可见 | | **THRIFT** | false | true | Thrift RPC 传输时可见,Thrft RPC 客户端与服务端交互时可见 | | **JSON** | true | false | JSON序列化时可见,Spring WEB 客户端与服务端 交互时可见(Spring WEB是基于jackson实现序列化和反序列化的),使用fastjson对数据库对象进行序列化和反序列化时同样有效。 | ### 定义可见度 定义字段可见度的方式有两种,一种是在建表语句的字段注释中通过字段注释标记`SCOPE@@EPOSC`来定义,参见 **《SCOPE@@EPOSC》**章节 另一种是在sql2java参数配置文件(sql2java.properties)中定义,参见 **《参数说明》**章节`(6/8)`段 ## 注解 ### @Sql2javaLocalConfig 从3.32.6版本开始新增加了`@Sql2javaLocalConfig`注解,定义在服务方法或服务类上,用于定义Sql2java的运行时配置,目前只有一个字段`resetModifiedIfEqual`,如果将指定的Java Bean类型定义在`resetModifiedIfEqual`,则fastjson,jackson反序列化器在对JSON字段成功反序列化为JavaBean对象后,会调用`BasesBean.resetModifiedIfEqual`对解析的对象进行归一化处理,确保只有与数据库已经存在记录不相等的字段对应的modified标记才被置1。 #### RuntimeConfigInterceptor 在spring环境定义在服务类或服务方法上的`@Sql2javaLocalConfig`注解生效需要`RuntimeConfigInterceptor`的配合。`RuntimeConfigInterceptor`负责在HTTP请求解析之前为请求方法安装sql2java运行时配置对象( `gu.sql2java.config.RuntimeConfig`),方法调用结束删除。 `RuntimeConfig`中保存了由`@Sql2javaLocalConfig`注解生成的配置。 #### 启动RuntimeConfig拦截器 如下在Spring服务启动注解(`@SpringBootApplication`)上指定扫描`RuntimeConfigInterceptor`拦截器`FilterInterceptorConfig`所在包就可以启动服务方法拦截器,激活了服务方法上定义的beanfilter过滤器 ```java import org.springframework.boot.autoconfigure.SpringBootApplication; import gu.sql2java.config.spring.FilterInterceptorConfig; /** * 应用服务启动配置 */ @SpringBootApplication(scanBasePackageClasses = {RuntimeConfigInterceptor.class}) public class ApplicationBoot{ //////....///// } ```