赞
踩
在之前的博文《geometry:MySQL的空间数据类型(Spatial Data Type)与JTS(OSGeo)类型之间的序列化和反序列化》中,实现了对MySQL数据库存储的WKB数据到JTS Geometry对象之间的转换。
当我们从数据库中得到的Geometry对象后,我们需要把它提供给前端时,就需要将它转为JSON格式,或从前端将JSON数据反序列化为Geometry对象。本文说明使用JSON工具库Fastjson如何实现这个过程。
JTS Geometry对象不是标准的Java Bean不能自动被Fastjson执行序列化和反序列化。所以我们需要为 Geometry对象实现自定义的序列化器和反序列化器。
我的实现方式就是将Geometry对象序列化为字符串,即WKT(Well-Known Text)字符串。
<dependency>
<groupId>com.vividsolutions</groupId>
<artifactId>jts</artifactId>
<version>1.13</version>
</dependency>
为所有Geometry类实现的序列化和反序列化
import com.alibaba.fastjson.JSONException; import com.alibaba.fastjson.parser.DefaultJSONParser; import com.alibaba.fastjson.parser.deserializer.ObjectDeserializer; import com.alibaba.fastjson.serializer.JSONSerializer; import com.alibaba.fastjson.serializer.ObjectSerializer; import com.vividsolutions.jts.geom.Geometry; import com.vividsolutions.jts.io.ParseException; import com.vividsolutions.jts.io.WKTReader; import java.io.IOException; import java.lang.reflect.Type; /** * JTS几何对象FASTJSON序列化反序列化实现<br> * 参见 <a href="https://www.osgeo.org/projects/jts/">JTS Topology Suite</a> * @author guyadong * @param <T> */ public class GeometryCodec<T extends Geometry> implements ObjectSerializer, ObjectDeserializer { /** * 将geometry类型序列化为WKT JSON字符串 */ @SuppressWarnings("unchecked") @Override public void write(JSONSerializer jsonSerializer, Object object, Object fieldName, Type fieldType, int features) throws IOException { T geom = (T) object; jsonSerializer.write(geom.toString()); } /** * 将WKT字符串反序列为{@link Geometry} */ @SuppressWarnings("unchecked") @Override public T deserialze(DefaultJSONParser parser, Type type, Object fieldName) { Object value = parser.parse(); if (value == null) { return null; } else { String wkt = (String) value; WKTReader reader = new WKTReader(); try { return (T) reader.read(wkt); } catch (ParseException e) { throw new JSONException(e.getMessage(),e); } } } @Override public int getFastMatchToken() { return 0; } }
基于GeometryCodec实现Point的序列化和反序列化器
import com.vividsolutions.jts.geom.Point;
/**
* @author guyadong
*/
public class PointCodec extends GeometryCodec<Point>{
public static final PointCodec INSTANCE = new PointCodec();
public PointCodec() {
}
}
这个类很简单,如果只为了创建Point对应的序列化和反序列化实例,其实可以用new GeometryCodec<Point>()
来代替,
但定义了这个类,还可以以注解形式使用在类成员字段上,定义成员字段的序列化和反序列化方式
例如:
@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;
import static org.junit.Assert.*; import org.junit.Test; import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.parser.ParserConfig; import com.alibaba.fastjson.serializer.SerializeConfig; import com.vividsolutions.jts.geom.Point; public class GeometryFastjsonTest { @Test public void test() { try { /** JSON 格式字符串,保存WKT格式的坐标数据 */ String jsonWKT = "\"POINT (1.75 -1.222)\""; System.out.printf("jsonWKT \t%s\n",jsonWKT); SerializeConfig.globalInstance.put(Point.class, PointCodec.INSTANCE); ParserConfig.global.putDeserializer(Point.class, PointCodec.INSTANCE); /** 反序列化为Point对象 */ Point deserialized = JSON.parseObject(jsonWKT,Point.class); System.out.printf("deserialized\t%s\n",deserialized.toText()); /** 序列化为JSON 字符串 */ String serialized = JSON.toJSONString(deserialized); System.out.printf("serialized \t%s\n",serialized); assertTrue(jsonWKT.equals(serialized)); } catch (Exception e) { e.printStackTrace(); assertTrue(false); } } }
输出
jsonWKT “POINT (1.75 -1.222)”
deserialized POINT (1.75 -1.222)
serialized “POINT (1.75 -1.222)”
完整代码参见我的码云仓库:https://gitee.com/l0km/sql2java/tree/dev/sql2java-base/src/main/java/gu/sql2java/geometry/fastjson
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。