GoogleMap API ジオコーダーを Java で使う

Javascript からの Geocorder の利用が、1回で連続して変換できるのが 10件 に制限されているので、大量データの変換に不向きなので、調べて実装しました。



package mapaddress.dbupdate;

import java.util.*;
import java.io.*;

import com.google.maps.GeoApiContext;
import com.google.maps.*;
import com.google.maps.model.GeocodingResult;
import com.google.maps.model.LatLng;
import java.net.InetSocketAddress;
import java.net.Proxy;
import java.net.SocketAddress;
import org.apache.ibatis.session.SqlSession;

//import com.google.maps.GeoApiContextBuilder;
/**
 * GoogleMap API ジオコーダー用クラス
 */
public class Geocorder {

  /**
   * プロキシ設定
   */
  private final String PROXY_HOST = "?????????";
  private final int PROXY_PORT = 0;

  private final String API_KEY = "???????????????????????????????";

  private GeoApiContext context;

  private String addr;
  private double lat;
  private double lon;
  private String zip = "";

  /**
   * デフォルトコンストラクタ
   */
  public Geocorder() {
    context = new GeoApiContext.Builder()
            .apiKey(API_KEY)
            .build();
  }

  /**
   * APIキー指定コンストラクタ
   */
  public Geocorder(String apikey) {
    context = new GeoApiContext.Builder()
            .apiKey(apikey)
            .build();
  }

  /**
   * プロキシ用コンストラクタ
   *
   * @param isUseProxy
   */
  public Geocorder(boolean isUseProxy) {

    if (isUseProxy) {
      SocketAddress addr = new InetSocketAddress(this.PROXY_HOST, this.PROXY_PORT);
      Proxy proxy = new Proxy(Proxy.Type.HTTP, addr);
      context = new GeoApiContext.Builder()
              .apiKey(API_KEY)
              .proxy(proxy)
              .build();
    }
    else {
      context = new GeoApiContext.Builder()
              .apiKey("????????????????????????????????????????")
              .build();
    }
  }

  /**
   * @return the addr
   */
  public String getAddr() {
    return addr;
  }

  /**
   * @param addr the addr to set
   */
  public void setAddr(String addr) {
    this.addr = addr;
  }

  /**
   * @return the lat
   */
  public double getLat() {
    return lat;
  }

  /**
   * @param lat the lat to set
   */
  public void setLat(double lat) {
    this.lat = lat;
  }

  /**
   * @return the lon
   */
  public double getLon() {
    return lon;
  }

  /**
   * @param lon the lon to set
   */
  public void setLon(double lon) {
    this.lon = lon;
  }

  /**
   * @return the zip
   */
  public String getZip() {
    return zip;
  }

  /**
   * @param zip the zip to set
   */
  public void setZip(String zip) {
    this.zip = zip;
  }

  /**
   * 正ジオコーダーの実行
   */
  public void execGeoCorder() {

    try {
      GeocodingResult results[] = this.getResults(this.addr);
      //LatLng latLng = results[0].geometry.location; // とりあえず一番上のデータを使う

      if (results != null && results.length > 0) {
        //if (results.length > 0) {
        LatLng latLng = results[0].geometry.location; // とりあえず一番上のデータを使う
        System.out.println("緯度 : " + latLng.lat);
        System.out.println("経度 : " + latLng.lng);
        int len = results[0].addressComponents.length;
        String zip = results[0].addressComponents[len - 1].longName;
        System.out.println("ZIP : " + zip);

        this.lat = latLng.lat;
        this.lon = latLng.lng;
        if (zip != null && !zip.equals("")) {
          this.zip = zip;
        }

      }

    }
    catch (Exception e) {
      e.printStackTrace();
    }

  }

  /**
   * 正ジオコーダー応答取得
   *
   * @param address
   * @return
   * @throws InterruptedException
   * @throws IOException
   */
  public GeocodingResult[] getResults(String address) throws InterruptedException, IOException {

    GeocodingApiRequest req = GeocodingApi.newRequest(context)
            .address(address)
            // .components(ComponentFilter.country("JP"))
            .language("ja");

    try {
      GeocodingResult[] results = req.await();
      if (results == null || results.length == 0) {
        // ZERO_RESULTSはresults.length==0の空配列がsuccessful扱いで返ってくる
        System.out.println("zero results.");
      }
      //results[0].geometry;

      return results;

    }
    catch (Exception e) {
      System.out.println("error.");
      System.out.println(e);
      return null;
    }
  }

  /**
   * 逆ジオコーダーの実行
   */
  public void execRVGeoCorder(String lat_lon) {
    
      try {
      GeocodingResult results[] = this.getRVResults(lat_lon);
      //LatLng latLng = results[0].geometry.location; // とりあえず一番上のデータを使う

      if (results != null && results.length > 0) {
        
        int len = results[0].addressComponents.length;
        String zip = results[0].addressComponents[len - 1].longName;
        System.out.println("ZIP : " + zip);
        this.addr = results[0].formattedAddress.replaceAll("日本、", "");
        System.out.println("ADDR : " + this.addr);
        if (zip != null && !zip.equals("")) {
          this.zip = zip;
        }

      }

    }
    catch (Exception e) {
      e.printStackTrace();
    }


  }

  public GeocodingResult[] getRVResults(String lat_lon) throws InterruptedException, IOException {
    
    

    GeocodingApiRequest req = GeocodingApi.newRequest(context)
            .address(lat_lon)
            // .components(ComponentFilter.country("JP"))
            .language("ja");

    try {
      GeocodingResult[] results = req.await();
      if (results == null || results.length == 0) {
        // ZERO_RESULTSはresults.length==0の空配列がsuccessful扱いで返ってくる
        System.out.println("zero results.");
      }
      //results[0].geometry;

      return results;

    }
    catch (Exception e) {
      System.out.println("error.");
      System.out.println(e);
      return null;
    }
  }

  public static void main(String[] args) {
    
    Geocorder G = new Geocorder(false);  
    G.execRVGeoCorder("31.62457 131.8521498");
    System.out.println(G.addr);
    


  }

}

ここで教えていただきました : http://developers.goalist.co.jp/entry/2017/10/16/150000

逆ジオコーダーも必要あるので、試したところ、Javascript の住所指定と同じく、緯度 + ” ” + 経度 を住所として渡せば出来ました。

運航港地図 と 施設港地図

社内用船スケジュールアプリに、昨年追加した、googleMap利用の港地図の二つを一般公開しました。

社内用との違いは、データの変更が出来ないことで、見るだけ専用となってます。

< URL >

運航港地図: http://dfp.saoline.co/vesselsch2018/pdestso

施設港地図 : http://dfp.saoline.co/vesselsch2018/pfacilso

< 画面絵 >

運航港地図

施設港地図

< ご利用上の注意 >

運航港地図を船舶運航業務等で利用された結果生ずる、いかなる有形無形の損害については、開発者は一切の責任を負わないこととします。

データ内容につきましては、出来る限り最新の状況に追従させてますが、間に合わないこともあり、ご容赦下さい。

JAVA 改良版 クラス指定デバッグ出力メソッド (JSON)

デバッグする時、NetBeansのデバッグで止めてチェックしたりするのが、じゃまくさく、時間かかるので、止めてみて終了させる必要ない場合用に、System.out.println() で見れるようにしてます。

昔作った、obj.getClass().getDeclaredFields()でのループ型で配列がとれない欠点があり、JSON出力にしてます。
null, getterのないフィールドがとれない欠点がありますが、PHPの var_dump() みたいなこと出来て便利です。

[ 出力例 ]


===============================
Time : 2019-01-08 19:16:29.204
Class : vesselsch.Polygon
Comment : ポリゴン追加
-------------------------------
{
  "lats": [
    35.68114829375634,
    35.680799702175534,
    35.6783595184685,
    35.67561015535696,
    35.67561015535696,
    35.67700460322533,
    35.677771539167104,
    35.678956789306746,
    35.679026509354955,
    35.68114829375634,
    35.68114829375634
  ],
  "lons": [
    139.97815035776364,
    139.98261355356442,
    139.98287104562985,
    139.98201273874508,
    139.9794378180908,
    139.97892283395993,
    139.9801244635986,
    139.9801244635986,
    139.97840784982907,
    139.97815035776364,
    139.97815035776364
  ],
  "id_poly": 0,
  "nm_poly": "1916",
  "cd_unlo": "JPFNB",
  "tp_poly": "CY",
  "nm_route": "",
  "cnt_corner": 0,
  "latmid": 0.0,
  "lonmid": 0.0,
  "m_depth": 0.0
}

[ コード例 ]


      // JSONデコードはリフレクションで行う //  
      Polygon PL = new Polygon();
      Gson gson = new GsonBuilder().setPrettyPrinting().create();
      Type type = new TypeToken<Polygon>() {
      }.getType();
      PL = gson.fromJson(jsn, type);
      // デバッグ出力 //
      FieldValuePrint fvp = new FieldValuePrint(PL, "ポリゴン追加");

[ 出力用クラス ]


package vesselsch;

import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import org.apache.commons.lang.time.DateFormatUtils;

/**
 * 指定クラスJSON出力
 * @author 田中尚
 */
public class FieldValuePrint {
  
  private Object obj;
  private String comment;
  
  /**
   * 引数付コンストラクタ
   * @param obj クラスオブジェクト 
   */
  public FieldValuePrint(Object obj) {  
    this.obj = obj;
    this.printToJSON();
  }
  
  /**
   * 引数付コンストラクタ
   * @param obj クラスオブジェクト
   * @param comment コメント
   */
  public FieldValuePrint(Object obj, String comment) {  
    this.obj = obj;
    this.comment = comment;
    this.printToJSON();
  }
  
  /**
   * クラスのフィールド名、フィールド値一覧チェック出力
   *
   */
  public void printToJSON() {

    // JSON出力 //
    Gson gsondbg = new GsonBuilder().setPrettyPrinting().create();
    System.out.println("===============================");
    System.out.println("Time : " + DateFormatUtils.format(new java.util.Date(), "yyyy-MM-dd HH:mm:ss.SSS"));
    System.out.println("Class : " + this.obj.getClass().getCanonicalName());
    if (this.comment != null) {
      System.out.println("Comment : " + this.comment);
    }
    System.out.println("-------------------------------");
    System.out.println(gsondbg.toJson(this.obj));

  }

}

[ 送信データ画面例 ]