【Spring MVC】REST APIにて基本的なリソース検索を行う方法

概要

Rest APIアプリを作成し、GET通信でリソース検索を行う方法についてまとめた。

あわせて読みたい

概要 これから数回にかけてREST APIについて学んだことを載せていく。 今回はREST APIの仕組みとプロジェクト作成方法について紹介する。 尚、RESTとは何かということについては取り扱わない。   仕組み[…]

 

基本的なリソース検索

GETリクエストで送られるクエリパラメータを取得し、リソース検索を行う。

クエリパラメータは個別に取得するケースと、オブジェクトのフィールドにバインドさせて取得するケースがある。
Bean Validationなどの入力チェックを使用できるため、今回はオブジェクトで取得する。(※当記事では入力チェック等は行わない)

あわせて読みたい

概要 Spring MVCにてクライアント側からGETまたはPOSTリクエストを行ってパラメータを取得する方法についてまとめた。   前提 Mavenプロジェクトの作成方法と基本的な画面疎通については以下を参照。 […]

【Spring MVC】基本的なGET/POSTリクエストの方法

 

リクエストクラス

クエリパラメータを取得するためのリクエストクラスを作成する。
後々、Bean Validation用のアノテーションを追加していく。

 

ResourceQuery.java


package com.example.rest_prototype.web.input;

import java.time.LocalDate;

import org.springframework.format.annotation.DateTimeFormat;

import lombok.Data;

/**
 * リソース検索用オブジェクト
 */
@Data
public class ResourceQuery {
	/** 名前 */
	private String name;
	/** とある日付 */
	@DateTimeFormat(iso = DateTimeFormat.ISO.DATE)
	private LocalDate hogeDate;
}

 

@DateTimeFormat(iso = DateTimeFormat.ISO.DATE)
private LocalDate hogeDate;

クエリパラメータの値をデータバインドする場合に、@DataTimeFormatを使用する。
「iso = DateTimeFormat.ISO.DATE」は「pattern = “yyyy-MM-dd”」でもいい。
上記形式で送られた文字列を、LocalDateに変換する。

クエリパラメータで受け取るフィールドに「@JsonFormat(pattern = “yyyy-MM-dd”)」を付与すると、例外がスローされるので注意すること。

 

サービスクラス

リクエストクラスの値をもとに、リソース検索を行う。
抽出条件は以下として、結果のリソースリストを返却する。

・name: nullでない場合、部分一致で検索
・hogeDate: nullでない場合、完全一致で検索

 

ResourceService.java


package com.example.rest_prototype.biz.service;

import java.time.LocalDate;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;

import org.springframework.stereotype.Service;

import com.example.rest_prototype.web.input.ResourceQuery;
import com.example.rest_prototype.web.resources.Resource;

@Service
public class ResourceService {

	/** DBの代わりに仮実装 */
	private static Map<String, Resource> tmpDbMap = new ConcurrentHashMap<>();

	/**
	 * 初期化(仮想DB)
	 */
	static {
		var dto1 = new Resource("1", "りんご", LocalDate.of(2025, 2, 1));
		var dto2 = new Resource("2", "ごりら", LocalDate.of(2024, 6, 5));
		var dto3 = new Resource("3", "らっぱ", LocalDate.of(2023, 5, 10));

		// 初期化
		tmpDbMap.put(dto1.getId(), dto1);
		tmpDbMap.put(dto2.getId(), dto2);
		tmpDbMap.put(dto3.getId(), dto3);
	}

	/**
	 * IDに紐づくリソースを取得
	 * @param id
	 * @return
	 */
	public Resource find(String id) {
		return tmpDbMap.get(id);
	}

	/**
	 * リソース登録
	 * @param resource
	 */
	public void create(Resource resource) {
		tmpDbMap.put(resource.getId(), resource);
	}

	/**
	 * リソース更新
	 * @param resource
	 */
	public void update(Resource resource) {
		tmpDbMap.put(resource.getId(), resource);
	}

	/**
	 * リソース削除
	 * @param id
	 */
	public void delete(String id) {
		tmpDbMap.remove(id);
	}

	/**
	 * 全リソース参照
	 * @return
	 */
	public List<Resource> findAll() {
		return new ArrayList<>(tmpDbMap.values());
	}

	/**
	 * リソースの条件検索
	 * @param param
	 * @return
	 */
	public List<Resource> findByParam(ResourceQuery param) {
		// 検索結果
		return findAll().stream().filter(r -> {
			boolean nameRes = param.getName() == null || r.getName().contains(param.getName());
			boolean hogeDateRes = param.getHogeDate() == null || r.getHogeDate().equals(param.getHogeDate());

			return nameRes && hogeDateRes;
		}).collect(Collectors.toList());
	}

}

 

コントローラークラス

クライアントから送信されたクエリパラメータをもとに、リソース検索を行う。

 

Rest05Controller.java


package com.example.rest_prototype.web.controller.rest05;

import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

import com.example.rest_prototype.biz.service.ResourceService;
import com.example.rest_prototype.web.input.ResourceQuery;
import com.example.rest_prototype.web.resources.Resource;

@RestController
public class Rest05Controller {

	/** ビジネスロジック */
	@Autowired
	private ResourceService service;

	@GetMapping(value = "rest05/")
	public List<Resource> get(ResourceQuery queryParam) {
		// 検索結果
		List<Resource> resList = service.findByParam(queryParam);

		return resList;
	}

}

 

@RestController

対象コントローラーのすべてのハンドラメソッドの戻り値が、@ResponseBodyを付与したケースと同じにするアノテーション。
各ハンドラメソッドの戻り値は、直接レスポンスボディを返却することになる。

 

@GetMapping(value = “rest05/”)
public List<Resource> get(ResourceQuery queryParam) {

引数にリクエストクラスを指定している。
上記のように実装すると、クエリパラメーターの値がリクエストクラスのフィールドにバインドされる。

 

動作確認

サーバーを起動して、Talend API Testerを使用して動作確認を行う。
Talend API Testerの使用方法については以下を参照。

あわせて読みたい

概要 GUIのツールを使用してシンプルにREAT APIアプリにリクエストを送りたいと思い、Talend API Testerを使用してみた。 いろいろと便利だったため、基本的な使用方法について簡単にまとめた。   事[…]

Talend API Testerを使用してREST APIにリクエストする方法

 

検索結果

GET通信を行い、動作確認を行う。
URIに指定するクエリパラメータ毎に、以下のような結果になる。

 

クエリパラメータなし

 

リクエスト


http://localhost:8080/rest_prototype/rest05/

 

結果


[{"id":"1","name":"りんご","hogeDate":"2025-02-01"},{"id":"2","name":"ごりら","hogeDate":"2024-06-05"},{"id":"3","name":"らっぱ","hogeDate":"2023-05-10"}]

 

nameのみ指定

 

リクエスト


http://localhost:8080/rest_prototype/rest05/?name=ご

 

結果


[{"id":"1","name":"りんご","hogeDate":"2025-02-01"},{"id":"2","name":"ごりら","hogeDate":"2024-06-05"}]

 

name、hogeDateを指定

 

リクエスト


http://localhost:8080/rest_prototype/rest05/?name=ご&hogeDate=2025-02-01

 

結果


[{"id":"1","name":"りんご","hogeDate":"2025-02-01"}]

 

まとめ

 

☑ クエリパラメータで取得するフィールドの日付変換には、@DateTimeFormatを使用する

☑ @RestControllerをクラスレベルに付与することで、ハンドラメソッドに@ResponseBodyの実装が不要になる

☑ ハンドラメソッドの引数にリクエストクラスを指定することで、クエリパラメータの値をバインドできる

 

スポンサーリンク