jersey + Spring Boot

SpringBootとglassfishのjerseyを連携させてみた

jerseyって

Jersey

> RestfulなWebApplicationを実現するためのフレームワーク
> JAX-RS — Project Kenaiっていう規格にのっとってる


基本的には役割はSpringMVCと近い感じかと

構築方法

依存関係 (きちんと調べきれてないです)

build.gradle

dependencies {
        compile "org.springframework.boot:spring-boot-starter-aop:$springbootVersion"
        compile "org.springframework.boot:spring-boot-starter-web:$springbootVersion"
        compile "org.springframework:spring-context:$springVersion"
        // jersey本体
        compile "org.glassfish.jersey.core:jersey-server:2.12" 
        // サーブレットのラッパー
        compile "org.glassfish.jersey.containers:jersey-container-servlet:2.12" 
        // springのアノテーションを使う場合必須 @Autowiredとか
        compile "org.glassfish.jersey.ext:jersey-spring3:2.12"
        // media typeとか管理するライブラリ
        compile "org.glassfish.jersey.media:jersey-media-moxy:2.12" 
        // jsonに変換するライブラリ
        compile "org.glassfish.jersey.media:jersey-media-json-jackson:2.12" 
    }


SpringBootそのまま

Main.java

@EnableAutoConfiguration
@Configuration
@ComponentScan(basePackages = "com.hase.sample")
public class Main {
	public static void main(String[] args) {
		SpringApplication.run(Main.class, args);
	}
}


自分はかなりハマった部分で(ドキュメント読まなかったから)
ここで、JacksonFeature.clssを挿しておかないと、POJOJSONに変換できない
調べると、Servletのinit parameterに差し込む方法もあるようだけど、web.xmlは利用していないから使えない

loggerの出力はイマイチ

import org.glassfish.jersey.filter.LoggingFilter;
import org.glassfish.jersey.jackson.JacksonFeature;
import org.glassfish.jersey.server.ResourceConfig;
import org.glassfish.jersey.servlet.ServletContainer;
import org.glassfish.jersey.servlet.ServletProperties;
import org.springframework.boot.context.embedded.ServletRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.filter.RequestContextFilter;


@Configuration
public class JerseyConfiguration extends ResourceConfig {

	public static class JerseyServletConfig extends ResourceConfig {
		public JerseyServletConfig() {
			// filter類はここにいれていく
			register(JacksonFeature.class);
			register(RequestContextFilter.class);
			packages("com.hase.sample");
			register(LoggingFilter.class);
		}
	}

	@Bean
	public ServletRegistrationBean jerseyServlet() {
		ServletRegistrationBean registration =
				new ServletRegistrationBean(new ServletContainer(), "/*");
		registration.addInitParameter(ServletProperties.JAXRS_APPLICATION_CLASS,
				JerseyServletConfig.class.getName());
		return registration;
	}
}

コントローラー

import org.springframework.stereotype.Component;

import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;


@Component
@Path("/")
public class JerseyController {

	@GET
	@Produces(MediaType.APPLICATION_JSON)
	@Path("/hello/{name}")
	public String hello(@DefaultParam("taro") @PathParam("name") String name) {
		return "Hello" + name;
	}
}

VoltDB + Spring (client)

SpringでVoltDBに接続する方法

JDBC clientが用意されているため、通常のデータベースと同じように接続可能


jarを用意する

前回の記事でvoltdbをビルドした際に、voltdbのクライアントサイドのjarが作成されているので持ってくる

voltdb/voltdbclient-4.6.jar 


クラスパスを通す(gradleを利用)

    dependencies {
        compile fileTree(dir: 'libs', include: '*.jar')
    }


datasourceの差し込み

	@Bean
	public DataSource dataSource() {
		DriverManagerDataSource driverManagerDataSource = new DriverManagerDataSource();
		driverManagerDataSource.setDriverClassName("org.voltdb.jdbc.Driver");
		driverManagerDataSource.setUrl("jdbc:voltdb://localhost:21212");
		log.info("connect db ={}",environment.getProperty("voltdb.hostnames"));
		return driverManagerDataSource;
	}


あと、今回SpringのJDBC Templateを利用した


第4回 Spring環境におけるDBアクセス(1) 〜 JdbcTemplate篇 | Developers.IO

	@Bean
	public JdbcTemplate jdbcTemplate() {
		return new JdbcTemplate(dataSource());
	}

voltdbの特徴として、javaでStored Proceduresを定義できるらしいので、その辺うまく活用するには上記方法だけでは厳しいかもしれない

3.2. Designing the Data Access (Stored Procedures)

VoltDBインストールから起動まで

AKB総選挙で使われたという、噂のVoltDBを試してみた

VoltDBって?

PostgreSQL開発者がつくったインメモリデータベース

・インメモリRDB
・シングルスレッドで実行されるため、データの整合性が保証される
トランザクションが使える
・分散する
・従来のシステムの50倍早い(ポスグレとの比較??)
オープンソース

インストール

オープンソース版は自分で持ってきてビルドするっぽい
Building VoltDB · VoltDB/voltdb Wiki · GitHub

必要なライブラリをインストール

wget http://download.fedoraproject.org/pub/epel/6/i386/epel-release-6-8.noarch.rpm

sudo rpm -Uvh epel*.rpm

sudo yum -y install ant ant-nodeps ant-junit ant-scripts ant-javadoc ant-trax \
    gcc gcc-c++ python valgrind ntp python26 git-all python-httplib2 \
    python-setuptools python-devel ccache


ANT_HOMEとJAVA_HOMEの環境変数を登録しておく

vi .bash_profile
export ANT_HOME=/usr/share/ant
export JAVA_HOME=/usr/src/java


ソースを持ってきてビルド

cd /opt
git clone https://github.com/VoltDB/voltdb.git
cd voltdb
git checkout -b tag voltdb-4.6 voltdb-4.6
ant

ここまでで、インストールはできたっぽい

テキトーなddlを用意
ddl.sql

CREATE TABLE votes
(
  phone_number       bigint     NOT NULL
, state              varchar(2) NOT NULL
, contestant_number  integer    NOT NULL
);

ddlコンパイルして、カタログファイルを作成→起動

voltdb compile ddl.sql
voltdb create catalog.jar

起動後、Webの管理画面が立ち上がる
http://localhost:8080




追記

    • backgroundでデーモン起動できる
voltdb create voltdbroot/config_log/catalog.jar --background

SpringMVCで1MB以上のファイルをアップロードする

デフォルトの設定だとServlet側で1MBまでしかアップロードできないという制約がついていて下記エラーが出る

HTTP Status 500 - Request processing failed; nested exception is org.springframework.web.multipart.MultipartException: Could not parse multipart servlet request; nested exception is java.lang.IllegalStateException: org.apache.tomcat.util.http.fileupload.FileUploadBase$SizeLimitExceededException: the request was rejected because its size (2462513) exceeds the configured maximum (1048576)


元のソースを書き換えてFilterでフックするとか、Servletのクラスを継承して書き換えるとかいろいろかいてあったけど、Springの場合はbeanに登録するだけで設定を書き換えられた

    @Bean
    public MultipartConfigElement multipartConfigElement() {
        MultipartConfigFactory factory = new MultipartConfigFactory();
        factory.setMaxFileSize(10 * 1024 * 1024);
        factory.setMaxRequestSize(10 * 1024 * 1024);
        return factory.createMultipartConfig();
    }


MultipartConfigElementがSpring管理下になっていてそこで値をセットしているらしい
org.apache.catalina.connector.Requset.java L2677

MultipartConfigElement mce = getWrapper().getMultipartConfigElement();


このWrapperを追っていくとspringのクラスを呼び出していることがわかる

org.springframework.web.DispatcherServlet.java 


参考
https://blog.safaribooksonline.com/2013/09/30/rest-hypermedia/
http://spring.io/guides/gs/uploading-files/

AndroidでGoogleMapsAPI V2を利用する

AndroidでGoogleMapsを動かすのに苦労したのでメモ

GoogleMapを動かすために必要な定義

Android Studioから自動生成されたので、抜け漏れがあるかも

  1. AndroidマニフェストにMapの利用を宣言する

アプリケーションタグの中に記述します

  1. 現在地を取得するためのパーミッションを追加

地図の利用に必須ではないとは書いてあったが、今後使うので追加
ACCESS_COARSE_LOCATION: Wifi経由での現在地取得
ACCESS_FINE_LOCATION: GPS経由での現在地取得


AndroidManifest.xml

<application ~~>
<meta-data
            android:name="com.google.android.maps.v2.API_KEY"
            android:value="@string/google_maps_key" />
</application>

<!--
         The ACCESS_COARSE/FINE_LOCATION permissions are not required to use
         Google Maps Android API v2, but are recommended.
-->
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
  1. Google Maps API V2 のAPI KEYを登録

keyの登録はrelease/res/values/google_maps_api.xmlに以下のように書いてあった

<string name="google_maps_key_instructions" templateMergeStrategy="replace"><!--

TODO: Before you run your application, you need a Google Maps API key.

To get one, follow this link, follow the directions and press "Create" at the end:

https://console.developers.google.com/flows/enableapi?apiid=maps_android_backend&keyType=CLIENT_SIDE_ANDROID&r=~

You can also add your credentials to an existing key, using this line:~

Once you have your key (it starts with "AIza"), replace the "google_maps_key"
string in this file.
--></string>
<string name="google_maps_key" templateMergeStrategy="preserve">YOUR KEY HERE</string>

ちなみに、ここに記載されているSHA1ハッシュ値は、~/.android/debug.keystoreのものらしい
本番にデプロイするときは、アプリケーション単位にキーを発行して使うのが正しいと思われる
発行したキーをgoogle_maps_keyに入れればいいっぽい


起動してみると、以下のエラーがでた

Failed to load map. Error contacting Google servers. This is probably an authentication issue (but could be due to network errors).

APIキーが認識されていないらしい

この辺を参考に
http://iwave-fe.blogspot.jp/2013/09/google-maps-android-api-v2-nexus7.html
これも一応登録してみる

<uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>


それでもうまくいかず

試行錯誤した結果

AndroidManifest.xmlに直書きで通った

<meta-data
android:name="com.google.android.maps.v2.API_KEY"
android:value="API KEY" />

Android初心者なので、よくわかってないがxmlのvalueが上がかれてない気がする
releaseフォルダにあるから、リリースのときだけxmlが適用されるのかも

うーん。。ここにはこれでいいっぽい感じで書いてあったんだけど。。
http://www.techotopia.com/index.php/Working_with_the_Google_Maps_Android_API_in_Android_Studio

とりあえず、地図は表示された
f:id:hase-xpw:20140727221700p:plain


参考:
http://9ensan.com/blog/smartphone/android/google-maps-android-api-v2-sample/
http://qiita.com/tomo_klotho/items/d2386cb473ed011c9a89