2
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【Spring Boot + MyBatis】はじめてREST APIを作成してみる

Posted at

はじめに

3年目で転職活動をしていた時、「APIを作成したことはあるか」と聞かれたことがありました。
実務経験も個人開発の経験もなく、Java/SpringBootで作ってみたいと思ったのがきっかけです。

まずUdemyで学習を行いました。
Web API 開発入門:Spring Boot と OpenAPI で始めるスキーマ駆動開発
特にAPIの設計は初めてだったので勉強になりました。
この教材はIntelliJ、Gradleだったので、使い慣れたEclipse、Mavenで作成してみたのが今回の記事になります。

設計

機能 HTTPメソッド エンドポイント ステータスコード
一覧取得 GET /manual-api 200 OK
400 Bad Request
詳細取得 GET /manual-api/{id} 200 OK
404 Not Found
登録 POST /manual-api 201 Created
400 Bad Request
更新 PUT /manual-api/{id} 200 OK
400 Bad Request
404 Not Found
削除 DELETE /manual-api/{id} 204 No Content
404 Not Found

実装例

ManualController.java
@RestController
public class ManualController {

	@Autowired
	ManualsMapper manualsMapper;

    // 一覧取得
    @GetMapping("/manual-api")
    public ResponseEntity<List<Manuals>> getList() {
        List<Manuals> manualList = manualsMapper.getList();
        return ResponseEntity.ok(manualList);
    }

    // 詳細取得
    @GetMapping("/manual-api/{manualId}")
    public ResponseEntity<Manuals> getDetail(@PathVariable int manualId) {
        Manuals manual = manualsMapper.getDetail(manualId);
        return ResponseEntity.ok(manual);
    }

    // 登録
    @PostMapping("/manual-api")
    public ResponseEntity<Manuals> create(@RequestBody Manuals manual) {
    	// 登録
    	manualsMapper.create(manual);
        return ResponseEntity.ok(manual);
    }

    // 更新
    @PutMapping("/manual-api/{manualId}")
    public ResponseEntity<Manuals> update(@PathVariable int manualId, @RequestBody Manuals manual) {
    	// マニュアルID
    	manual.setManualId(manualId);
    	// 更新
    	manualsMapper.update(manual);
        return ResponseEntity.ok(manual);
    }

    // 削除
    @DeleteMapping("/manual-api/{manualId}")
    public ResponseEntity<Void> delete(@PathVariable int manualId) {
    	manualsMapper.delete(manualId);
        return ResponseEntity.noContent().build();
    }
}
Manuals.java
@Data
public class Manuals {

	// マニュアルID
	private int manualId;

	// 社員ID
	private int userId;

	// 表示順
	private int displayOrder;

	// タイトル
	private String title;

	// 掲載開始日
	private LocalDate startDate;

	// 掲載終了日
	private LocalDate endDate;

	// 内容
	private String content;

	// リンク
	private String link;

	// レコード登録者
    private String createdBy;

    // レコード登録日
    private LocalDateTime createdAt;

    // レコード更新者
    private String updatedBy;

    // レコード更新日
    private LocalDateTime updatedAt;
}
ManualsMapper.java
@Mapper
public interface ManualsMapper {

	// 一覧取得
    public List<Manuals> getList();

    // 詳細取得
    public Manuals getDetail(int manualId);

    // 登録
    public void create(Manuals manual);

    // 更新
    public void update(Manuals manual);

    // 削除
    public void delete(int manualId);
}
ManualsMapper.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.manualapi.ManualsMapper">

	<!-- 一覧取得 -->
    <select id="getList" resultMap="ManualMap">
        SELECT * FROM manuals
    </select>

 	<!-- 詳細取得 -->
    <select id="getDetail" resultMap="ManualMap">
        SELECT * FROM manuals
        WHERE manual_id = #{manualId}
    </select>

	<!-- マッピング -->
    <resultMap id="ManualMap" type="com.manualapi.Manuals">
        <result property="manualId" column="manual_id" />
        <result property="userId" column="user_id" />
        <result property="displayOrder" column="display_order" />
        <result property="title" column="title" />
		<result property="startDate" column="start_date" />
		<result property="endDate" column="end_date" />
		<result property="content" column="content" />
		<result property="link" column="link" />
        <result property="createdBy" column="created_by" />
        <result property="createdAt" column="created_at" />
        <result property="updatedBy" column="updated_by" />
        <result property="updatedAt" column="updated_at" />
    </resultMap>

	<!-- 登録 -->
    <insert id="create" useGeneratedKeys="true" keyProperty="manualId">
		INSERT INTO manuals
		(
			user_id,
			display_order,
			title,
			start_date,
			end_date,
			content,
			link,
			created_by,
			created_at
		)
		VALUES
		(
			#{userId},
			#{displayOrder},
			#{title},
			#{startDate},
			#{endDate},
			#{content},
			#{link},
			#{createdBy},
			CURRENT_TIMESTAMP
		)
    </insert>

    <!-- 更新 -->
    <update id="update">
		UPDATE manuals SET
    		user_id = #{userId},
			display_order = #{displayOrder},
			title = #{title},
			start_date = #{startDate},
			end_date = #{endDate},
    		content = #{content},
			link = #{link},
			updated_by = #{updatedBy},
			updated_at = CURRENT_TIMESTAMP
    	WHERE
			manual_id = #{manualId}
    </update>

	<!-- 削除 -->
	<delete id="delete">
		DELETE FROM manuals
		WHERE
			manual_id = #{manualId}
    </delete>
</mapper>

application.propertiesのポートを8081にします。
(アプリケーションが8080を使用するため)

application.properties
# DB設定値は省略
server.port=8081

入力チェックははじめAPI側に書いていましたが、画面側プロジェクトで行うようにしたため記載はありません。
また、画面入力値をエンティティへのセットするのも画面側プロジェクトで行うようにしました。

エラーハンドリング

CustomControllerAdvice.java
@RestControllerAdvice
public class CustomControllerAdvice {

    @ResponseStatus(HttpStatus.BAD_REQUEST)
    @ExceptionHandler({ HttpMessageNotReadableException.class, MethodArgumentNotValidException.class })
    public Map<String, Object> handleError400() {
    	Map<String, Object> errorMap = new HashMap<String, Object>();
    	errorMap.put("message", "リクエストが正しくありません。");
    	errorMap.put("status", HttpStatus.BAD_REQUEST);
		return errorMap;
    }

    @ResponseStatus(HttpStatus.NOT_FOUND)
    @ExceptionHandler({ NoResourceFoundException.class })
    public Map<String, Object> handleError404() {
    	Map<String, Object> errorMap = new HashMap<String, Object>();
    	errorMap.put("message", "該当するエンドポイントがありませんでした。");
    	errorMap.put("status", HttpStatus.NOT_FOUND);
		return errorMap;
    }
}

動作確認

Postmanが有名ですが、Postmanの不具合で立ち上がらなかったため、Chrome拡張機能のTalend API Testerを使用しました。
Postmanと同じように使えました。
スクリーンショット 2024-04-14 11.41.47.png

スクリーンショット 2024-04-14 11.39.57.png

さいごに

記事を書くにあたって改めて見てみて、設計書通り作成できてなかったことに気づき修正しました。
初心者向けに分かりやすく説明したものではなく、動作確認できたものを羅列するだけになってしまったため、説明できるように理解を深めていきたいです。

参考記事

【頑張れば5分で作れる】Spring Boot + MyBatisで超簡単なCRUD処理のREST APIを作る【VSCode】
SpringBootに入門するための助走本(Zenn改訂版)Chapter 04 簡単なWebAPIを作ってみよう編

2
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?