はじめに
OAuth Providerとかをこれから作ることを考えると、やはり何らかのFrameworkを導入するしかなく、検討および調査を行いました。まずJavaのFrameworkとしては、以下が考えられます
- J2EE
- Spring Framework
- Play Framework
3つのフレームワークの比較は、以下のサイトを参考にしました。
たぶん、どれを導入しても良いかと思うのですが、Spring Bootはとても便利そうな印象なので、Spring Frameworkを調査していこうと思います。
他プロジェクトなどでも基本的にGradleを使っているので、Gradle + Spring FrameworkでRESTful Web APIを作成します。
Spring Frameworkの勉強
まったくの初心者なので、以下の順番で勉強していきました。
基本的なWeb APIの作成をGradleを使って作成する
まず、以下のGuideを読んでテスト用のソースのダウンロードをします
https://spring.io/guides/gs/rest-service/#scratch
次に以下のGuideを読んで、IntelliJを使って、ビルドできるようにします。
https://spring.io/guides/gs/intellij-idea/
基本的に、Guide用のリポジトリのinitial/build.gradleを指定してprojectをimportすれば良いです。
IntelliJを使ってGuide通りにコードを書いてgradlew buildすれば、jarファイルができあがり、それを使うとTomcat Servlet Containerが内包されるのでとても便利です。javaは1.8が必要なので以下でjava1.8を使用するように変更しておきました。
$ export JAVA_HOME=$(/usr/libexec/java_home -v 1.8)
データベースへのアクセス
RESTful APIを提供する場合、多くのケースでデータベースにアクセスすることになるかと思います。まずローカル環境でのMy SQLのようなRDSへの接続を試してみます。
公式サイトのガイドでは、Embededのh2databaseを使ったものになるため、Javaの実装は参考になるのですが、MySQLなど汎用的なデータベースと接続する場合の例を他で調べる必要がありました。
せっかくFramework使うのにSQL文使うJdbcTemplateを使う必要はないと判断して、Spring Data JPAを使ってアクセスする方法を試す。
まず、MySQLに接続する場合、build.gradleに以下のライブラリの組み込みが必要です。
compile("org.springframework.boot:spring-boot-starter-data-jpa")
compile("mysql:mysql-connector-java")
MySQLに接続する場合のUser Name / Passwordはsrc/main/resources/application.propertiesに記述するようです
spring.datasource.url=jdbc:mysql://localhost/<Database Name>
spring.datasource.username=<User Name>
spring.datasource.password=<Password>
spring.datasource.driverClassName=com.mysql.jdbc.Driver
MySQLのデータベースにid,name,emailのカラムを持つテーブルを作成し、以下のクラスでデータを対応づける
User.java
@Entity
@Table(name = "users")
public class User {
@Id
@GeneratedValue
private int id;
@Column
private String name;
@Column
private String email;
public User() {
}
public User(int id, String name, String email) {
this.id = id;
this.name = name;
this.email = email;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
}
CRUD処理に関しては、Interfaceが用意されている。今回は名前での検索を行いたいのでfindByNameメソッドを追加する。
UsersRepository.java
public interface UsersRepository extends CrudRepository<User, Integer>{
List<User> findByName(String name);
}
最後にControllerで以下のようにデータを取り出す。強力なのは、@Autowiredで実行時にインターフェースにインスタンスが割り当てられるところです。
UsersController.java
@RestController
@RequestMapping("/users")
public class UsersController {
@Autowired
UsersRepository repository;
@RequestMapping(method= RequestMethod.GET)
public List<User> get(@RequestParam(value="name") String name) {
List<User> users = repository.findByName(name);
return users;
}
}
http://localhost:8080/users?name=imiya
で以下が返されます
[
{
id: 0,
name: "imiya",
email: "imiya@sonymobile.com"
}
]
メソッドシグネチャ
UsersRepositoryインターフェースを記述しただけで、実装は書いていないのにデータが取得できるということに違和感を感じられていることと思います。これはSpring Frameworkのメソッドシグネチャという機能です。
上記のfindByName()例の場合、メソッドの定義から以下のSQLと同等になります。
List<User> findByName(String name);
select u from Users u where u.name = ?1
詳細については以下をご参照下さい
http://docs.spring.io/spring-data/data-jpa/docs/1.4.3.RELEASE/reference/html/jpa.repositories.html#jpa.query-methods
@Query アノテーションを使えば、メソッドに対応するQueryを直接記述することもできます。
public interface UsersRepository extends CrudRepository<User, Integer>{
List<User> findByName(String name);
@Query ("select u from User u")
List<User> findAllUsers();
}