2016-07-07 77 views
1

我有一個對象,它是「級別」的對象的列表,我的測試和春天啓動休息控制器在2種方式把它們轉移:protobuf有效載荷大於JSON?

  1. 使用JSON,REST中的控制器我使用類似:

    @RequestMapping(value = "/api/v1/layers/{layername}", method =   RequestMethod.GET, produces = "application/json") 
    public @ResponseBody List<Level> query(@PathVariable String layername, 
           @RequestParam("northEastLat") Float northEastLat, 
           @RequestParam("northEastLng") Float northEastLng, 
           @RequestParam("northWestLat") Float northWestLat, 
           @RequestParam("northWestLng") Float northWestLng, 
    
           @RequestParam("southEastLat") Float southEastLat, 
           @RequestParam("southEastLng") Float southEastLng, 
           @RequestParam("southWestLat") Float southWestLat, 
           @RequestParam("southWestLng") Float southWestLng 
    ) { 
    
    List<Level> poligons=levelService.obtainLevels(layername,southWestLng,southWestLat,northWestLng,northWestLat,northEastLng,northEastLat,southEastLng,southEastLat); 
    int i=1; 
    for (Level p : poligons) { 
    
        System.out.println("poligon" + i++ + " is:" + p.toString()); 
    } 
    
    return poligons; 
    } 
    
  2. 隨着Protostuff的Protobuf格式,我使用類似:

    @RequestMapping(value = "/api/v1/layers/{layername}", method = RequestMethod.GET,produces = "text/plain") 
        public String query(@PathVariable String layername, 
           @RequestParam("northEastLat") Float northEastLat, 
           @RequestParam("northEastLng") Float northEastLng, 
           @RequestParam("northWestLat") Float northWestLat, 
           @RequestParam("northWestLng") Float northWestLng, 
    
           @RequestParam("southEastLat") Float southEastLat, 
           @RequestParam("southEastLng") Float southEastLng, 
           @RequestParam("southWestLat") Float southWestLat, 
           @RequestParam("southWestLng") Float southWestLng 
    ) { 
    
    
    List<Level> poligons=levelService.obtainLevels(layername,southWestLng,southWestLat,northWestLng,northWestLat,northEastLng,northEastLat,southEastLng,southEastLat); 
    LevelList list = new LevelList(poligons); 
    
    byte[] bytes; 
    
    int i=1; 
    for (Level p : poligons) { 
    
        System.out.println("poligon" + i++ + " is:" + p.toString()); 
    } 
    
    Schema<LevelList> schema = RuntimeSchema.getSchema(LevelList.class); 
    LinkedBuffer buffer = LinkedBuffer.allocate(); 
    
    
    
    try 
    { 
        bytes = ProtostuffIOUtil.toByteArray(list, schema, buffer); 
    } 
    finally 
    { 
        buffer.clear(); 
    } 
    
    return new String(bytes); 
    } 
    

級別對象格式爲: [{「wkb_geometry」:「{」type「:」Polygon「,」coordinates「:[[[24.446822,45.34997],[24.706508,45.352485]]]}」,「id」 :199, 「水平」: 「3」, 「類型」:空}

水平目標是:

@Entity(name = "Level") 
@Table(name="Level2G") 
@SecondaryTables({ 
    @SecondaryTable(name="Level3G"), 
    @SecondaryTable(name="Level4G") 
}) 
public class Level implements Serializable { 

private static final long serialVersionUID = 1L; 

// @Column(name = "wkb_geometry",columnDefinition="Geometry") 
//@Type(type = "org.hibernate.spatial.GeometryType") 
@Column(name="wkb_geometry") 
private /*Geometry */ String wkb_geometry; 

@Id 
@Column(name="id") 
private Integer id; 


@Column(name="level") 
private String level; 

@Transient 
private String type; 

public Level() { 
} 

public Level(String wkb_geometry, Integer id, String level) { 
    this.wkb_geometry = wkb_geometry; 
    this.id = id; 
    this.level = level; 
    this.type = "Feature"; 
} 

public Level(String wkb_geometry, Integer id, String level, String type) { 
    this.wkb_geometry = wkb_geometry; 
    this.id = id; 
    this.level = level; 
    this.type = type; 
} 

public Object getWkb_geometry() { 
    return wkb_geometry; 
} 

public void setWkb_geometry(String wkb_geometry) { 
    this.wkb_geometry = wkb_geometry; 
} 

public Integer getId() { 
    return id; 
} 

public void setId(Integer id) { 
    this.id = id; 
} 

public String getLevel() { 
    return level; 
} 

public void setLevel(String level) { 
    this.level = level; 
} 

public String getType() { 
    return type; 
} 

public void setType(String type) { 
    this.type = type; 
} 

@Override 
public String toString() { 
    return "Level{" + 
      "wkb_geometry=" + wkb_geometry + 
      ", id=" + id + 
      ", level='" + level + '\'' + 
      ", type='" + type + '\'' + 
      '}'; 
} 
} 

的LevelList對象只是級別的對象列表

的問題是與Protostuff相比,我得到了比JSON(3.7kb)更大的有效載荷(26 kb)。爲什麼?

對於第二個選項,我也嘗試設置「application/octet-stream」來直接返回字節,但仍然是相同的結果。我還比較了JSON和protobuf的速度;即使有更大的有效載荷,protobuf也有更好的性能。任何想法爲什麼?

+0

第二個選項我試過也會產生=「application/octet-stream」直接返回字節,但結果仍然相同 – Jolie

+0

你可以在這裏複製/粘貼你正在序列化的實際對象嗎?也許一種格式是比其他格式更多的信息序列化? –

+0

我不知道它是否會對您有所幫助,但:https://spring.io/blog/2015/03/22/using-google-protocol-buffers-with-spring-mvc-based-rest-services –

回答

0

您的測試中至少有一個問題。

這種轉變從字節數組的字符串是無效的:

bytes = ProtostuffIOUtil.toByteArray(list, schema, buffer); 
return new String(bytes); 

字符串的此構造方法將嘗試解析字節數組爲UTF-8字符串(最有可能,取決於你的本地設置),但根據定義給出的數據不是有效的UTF-8字符串。

如果你想更好的大小比較,你應該寫在下面的表格測試:

LevelList source = testData(); 
byte[] jsonData = generateJson(source); 
byte[] protobufData = generateProtobuf(source); 
System.out.println("JSON=" + jsonData.size() + " Protobuf=" + protobufData.size()); 

這裏主要的一點是,使您的測試重複性,讓其他人可以重複它。

+0

謝謝。但就像我所說的,對於第二種選擇,我試着還生成=「application/octet-stream」直接返回字節,但仍然是相同的結果。我還比較了json和protobuf的速度,即使更高的有效載荷,protobuf也有更好的速度。任何想法爲什麼? – Jolie

+0

理論上這是不可能的,根據定義,二進制protobuf編碼比JSON更緊湊。 – Kostiantyn

1

Protostuff和Protobuf不是一回事。 Protostuff是一個包裝庫,可以使用許多不同的序列化格式。它還支持您似乎正在使用的運行時模式生成。該運行時模式需要將額外的元數據與消息一起發送給接收方以瞭解消息的模式。我猜想你看到的大量消息大多來自這個運行時模式數據。

對於標準Protobuf,模式不隨消息一起發送,因爲它假定發件人和收件人已經同意編譯到這兩個程序中的.proto文件提供的模式。如果您使用標準.proto文件使用Protobuf,則會發現它生成的消息比JSON小得多。