1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

Spring Boot でアプリを作成してみた【REST API 開発】

Last updated at Posted at 2023-11-18

プロジェクトを作成する

  • Project: Maven

  • Language: Java

  • SpringBoot: 3.0.12

  • Group: simple_spring_restapi

  • Artifact: simple_spring_restapi

  • Name : simple_spring_restapi

  • Description: Demo project for Spring Boot

  • Package name: simple_spring_restapi

Dependencies

  • Spring Boot DevTools
  • Spring Web

Dockerを作成する

① .devcontainerフォルダとdevcontainer.jsonとdocker-compose.ymlを作成する

.devcontainer / devcontainer.json
{
  "name": "workspace",
  "dockerComposeFile": "docker-compose.yml",
  "service": "workspace",
  "workspaceFolder": "/home/vscode/workspace",
  "remoteUser": "vscode",
  "shutdownAction": "stopCompose",
  "customizations": {
    "vscode": {
      "extensions": [
        "vscjava.vscode-java-pack",
        "vscjava.vscode-spring-initializr",
        "vscjava.vscode-gradle"
      ]
    }
  }
}

② docker/workspaceファイルとDockerfileを作成する

.devcontainer/Dockerfile
# イメージのベースとなるイメージを指定
FROM ubuntu:22.04

# イメージのベースとなるイメージを指定(Mac用)
# FROM arm64v8/alpine:latest

# イメージに追加するファイルを指定
ARG USERNAME=vscode
ARG USER_GROUP_NAME=workspace
ARG USER_UID=1000
ARG USER_GID=1000

ARG PKG="git vim curl unzip zip"

# イメージの起動時に実行するコマンドを指定
SHELL [ "/bin/bash","-c" ]

RUN apt-get update \
    && apt-get install -y ${PKG} \
    && apt-get clean \
    && rm -rf /var/lib/apt/lists/* \
    && grouapp --gid ${USER_GID} ${USER_GROUP_NAME} \
    && useradd --uid ${USER_UID} --shell /bin/bash --gid ${USER_GID} -m{USERNAME} \
    && echo %${USER_GROUP_NAME} ALL=\(ALL\) NOPASSWORD:ALL > /etc/sudoers.d/${USER_GROUP_NAME} \
    && chmod 0440 /etc/sudoers.d/${USER_GROUP_NAME}

## JAVAの環境構築
ARG JAVA _VARSION=18.0.2-amzn
ARG GRADLE_VARSION=7.5

RUN su ${USERNAME} --command \
    'curl -s "https//get.sdkman.io" | bash \
    && source "${HOME}/.sdkman/bin/sdkman-init.sh" \
    && sdk install java "${JAVA_VARSION}" \
    && sdk install gradle "${GRADLE_VARSION}"'

③ docker-compose.ymlを編集する

docker-compose.yml
version: '3.9'

services:
  workspace:
    container_name: ${PROJECT_NAME:default}-workspace
    build:
      context: ./docker/workspace
      args:
        USERNAME: ${USERNAME:-vscode}
        USER_GROUP_NAME: ${USER_GROUP_NAME:-workspace}
        USER_UID: ${USER_UID:-1000}
        USER_GID: ${USER_GID:-1000}
    tty: true
    volumes:
      - ../:/home/${USERNAME:-vscode}/workspace:cached
    ports:
      - '8080:8080'

④ .devcontainerに.envを作成する

.devcontainer/.env

PROJECT_NAME=simple-spring-restapi

USERNAME=vscode
USER_GROUP_NAME=workspace
USER_UID=1000
USER_UID=1000

⑤ docker compose.yml buildを行う

docker compose.yml build

コントローラーを作成する

① src/main/java/simple_spring_restapiにcontrollersフォルダとTodoController.javaファイルを作成する

controller / TodoController.java
package simple_spring_restapi.controller;

import java.net.URI;
import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.servlet.support.ServletUriComponentsBuilder;

import jakarta.validation.Valid;
import simple_spring_restapi.models.TodoItem;
import simple_spring_restapi.services.TodoService;

@RequestMapping(path = TodoController.BASE_URL)
@RestController
public class TodoController {
    public static final String BASE_URL = "/api/v1/todos";
    @Autowired
    private TodoService _todoService;

    @GetMapping(path = "")
    public ResponseEntity<List<TodoItem>> getTodoItems() {
        List<TodoItem> todoItems = _todoService.getTodoItems();
        return ResponseEntity.ok(todoItems);
    }

    @GetMapping(path = "/{id}")
    public ResponseEntity<TodoItem> getTodoItems(@PathVariable int id) {
        TodoItem found = _todoService.getTodoItemById(id);
        return ResponseEntity.ok(found);
    }

    @PostMapping(path="")
    public ResponseEntity<todoItem> creteTodoItems(@Valid @RequestBody TodoItem newTodoItem) {
        TodoItem saveTodoItem = _todoService.saveTodoItem(newTodoItem);
        URI location = ServletUriComponentsBuilder.fromCurrentRequest().path("/{id}");
             .bulidAndExpand(saveTodoItem.getId()).toUri();
        return ResponseEntity.created(location).body(newTodoItem);
    }

    @PutMapping(path = "/{id}")
    public ResponseEntity<?> updateTodoItems(@RequestBody TodoItem newTodoItem, @PathVariable int id) {
        _todoService.updateTodoItems(id, newTodoItem);
        return ResponseEntity.noContent().build();
    }

    @DeleteMapping(path = "/{id}")
    public ResponseEntity<?> removeTodoItems(@PathVariable int id) {
        _todoService.deleteTodoItem(id);
        return ResponseEntity.noContent().build();
    }

}

② build.grandleファイルにimplementation 'org.springdoc:springdoc-openapi-ui:1.6.9'を加えて、
swagger-uiが使用できるようにする

build.grandle
//省略
dependencies {
//省略
	implementation 'org.springdoc:springdoc-openapi-ui:1.6.9'
}

③ src/main/java/simple_spring_restapiにmodelsフォルダとTodoItem.javaファイルを作成する

TodoItem.java
package simple_spring_restapi.models;

import jakarta.persistence.Column;
import jakarta.annotation.GeneratedValue;
import jakarta.persistence.Id;
import jakarta.validation.constraints.NotBlank;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@NoArgsConstructor
@AllArgsConstructor
@Entity
@Table(name = "todos", schema = "business")
public class TodoItem {
    @Id
    @GeneratedValue(strategy = GenerationType.Auto)
    @Column(name = "id", nullable = false)
    private int id;
    @NotBlank(message = "Title must not be blank.")
    @Column(name = "id", nullable = false)
    private String title;

}

④ resouces/application.propertiesをapplication.yamlに変更する

application.yaml

spring:
  jpa:
    database: POSTGRESQL
    hibernate:
      ddl-auto: update
      show-sql: true
    properties:
      hibernate:
        hbm2dll: create_namespaces:true

  datasource:
    url: jdbc:postgresql://${POSTGRES_HOST:-postgres}:${POSTGRES_PORT:5432}/ ${POSTGRES_DB:-dev}
    username: ${POSTGRES_USER:-postgres}
    password: ${POSTGRES_PASSWORD:-postgres}
    driver-class-name: org.postgresql.Driver

⑤ src/main/java/javnautas.fakeapiusにbusinessフォルダとserviceフォルダとFakeApiService.javaファイルを作成する

service/FakeApiService.java


⑥ src/main/java/javnautas.fakeapius/appv1.dtoにFakeApi Controller.javaファイルを作成する

⑦ SpringDoc OpenAPI Starter WebMVC UI で、Spring Boot アプリケーションの RESTful API の OpenAPI ドキュメントを生成する

build.gradle
// 省略
implementation 'org.springdoc:springdoc-openapi-starter-webmvc-ui:2.2.0'
// 省略

⑧ Swagger UIを開き、fake-apiの定義を読み込み、HTML 形式で API のドキュメントを生成する

⑨ instructureにentitiesフォルダとProductoEntity.javaを作成する

SpringDoc OpenAPI Starter WebMVC UI
※ SpringDoc OpenAPI Starter WebMVC UI は、Spring Boot アプリケーションの RESTful API の OpenAPI ドキュメントを生成するための Spring Boot Starter

servicesを作成する

① src/main/java/simple_spring_restapiにservicesフォルダとTodoServices.javaファイルを作成する

② src/main/java/simple_spring_restapi/servicesに
TodoServiceImplWithoutRepo.javaファイルを作成する

エラーハンドラーの追加する

① src/main/java/simple_spring_restapiにerrorsフォルダとNotFoundException.javaファイルを作成する

② src/main/java/simple_spring_restapi/errorsにBadRequestException.javaファイルを作成する

③ src/main/java/simple_spring_restapi/errorsにRestResponseEntityExceptionHandler.javaファイルを作成する

④ src/main/java/simple_spring_restapi/errorsにErrorResponse.javaファイルを作成する

⑤ src/main/java/simple_spring_restapi/errorsにHttpException.javaファイルを作成する

モデルバリデーションの追加

① build.grandleファイルに
implementation 'org.springframework.boot:spring-boot-starter-validation:2.7.3'
compileOnlyorg.projectlombok:lombok:1.18.24'を加えて、modelヴァリデーションが使用できるようにする

build.grandle
//省略
dependencies {
//省略
implementation 'org.springframework.boot:spring-boot-starter-validation:2.7.3'
	compileOnly 'org.projectlombok:lombok:1.18.24'
}

データアクセスレイヤーの追加

① .devcontainerフォルダとdevcontainer.jsonとdocker-compose.ymlに追加する

docker-compose.yml
version: '3.9'

services:
  workspace:
    container_name: ${PROJECT_NAME:default}-workspace
    build:
      context: ./docker/workspace
      args:
        USERNAME: ${USERNAME:-vscode}
        USER_GROUP_NAME: ${USER_GROUP_NAME:-workspace}
        USER_UID: ${USER_UID:-1000}
        USER_GID: ${USER_GID:-1000}
    tty: true
    volumes:
      - ../:/home/${USERNAME:-vscode}/workspace:cached
    ports:
      - '8080:8080'

  postgres:
    container_name: ${PROJECT_NAME:default}-postgres
    image: postgres:14.2
    environment:
      POSTGRES_USER: ${POSTGRES_USER:-postgres}
      POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-postgres}
      POSTGRES_DB: ${POSTGRES_DB:-dev}
    volumes:
      - ./data/db:/var/lib/postgresql/data
    ports:
      - ${POSTGRES_PORT:-5432}:5432
    restart: always

  pgadmin4:
    container_name: ${PROJECT_NAME:default}-pgadmin4
    restart: always
    image: dpage/pgadmin4
    environment:
      PGADMIN_DEFAULT_EMAIL: ${PGADMIN_DEFAULT_EMAIL:-pgadmin4@pgadmin.com}
      PGADMIN_DEFAULT_PASSWORD: ${PGADMIN_DEFAULT_PASSWORD:-password}
    volumes:
      - ./pgadmin:/var/lib/pgadmin
    ports:
      - 8080:80
    depends_on:
      - postgres

② .envを編集する

.env
PROJECT_NAME=simple-spring-restapi

# workspace
USERNAME=vscode
USER_GROUP_NAME=workspace
USER_UID=1000
USER_UID=1000

# postgres
POSTGRES_USER=postgres
POSTGRES_PASSWORD=postgres
POSTGRES_DB=dev

# pgadmin4
PGADMIN_DEFAULT_EMAIL=pgadmin4@pgadmin.com
PGADMIN_DEFAULT_PASSWORD=password

③ resources/application.propertiesを編集する

application.properties ⇨ application.ymlに変更する

resources/application.yml
spring:
  jpa:
    database: POSTGRESQL
    hibernate:
      ddl-auto: update
      show-sql: true
    properties:
      hibernate:
        hbm2dll: create_namespaces:true

  datasource:
    url: jdbc:postgresql://${POSTGRES_HOST:-postgres}:${POSTGRES_PORT:5432}/ ${POSTGRES_DB:-dev}
    username: ${POSTGRES_USER:-postgres}
    password: ${POSTGRES_PASSWORD:-postgres}
    driver-class-name: org.postgresql.Driver

④ build.grandleファイルにコードを加える

build.grandle
//省略
dependencies {
//省略
implementation 'org.springframework.boot:spring-boot-starter-data-jpa:2.7.3'
implementation 'org.postgresql:postgresql:42.5.0'
}

⑤ TodoItem.javaを編集する

models / TodoItem.java
package simple_spring_restapi.models;

import jakarta.persistence.Column;
import jakarta.annotation.GeneratedValue;
import jakarta.persistence.Id;
import jakarta.validation.constraints.NotBlank;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@NoArgsConstructor
@AllArgsConstructor
@Entity
@Table(name = "todos", schema = "business")
public class TodoItem {
    @Id
    @GeneratedValue(strategy = GenerationType.Auto)
    @Column(name = "id", nullable = false)
    private int id;
    @NotBlank(message = "Title must not be blank.")
    @Column(name = "id", nullable = false)
    private String title;

}

⑥ repositoriesフォルダとTodoRepositories.java を作成する

repositories/TodoRepositories.java
package simple_spring_restapi.repositories;

import org.springframework.stereotype.Repository;

import com.juniordevmind.simplespringrestapi.models.TodoItem;

@Repository
public interface TodoRepositories extends JpaRepository<TodoItem, Integer> {

}

⑦ src/main/java/simple_spring_restapi/services/TodoServiceImpl.javaファイルを作成する

services/TodoServiceImpl.java
package simple_spring_restapi.services;

import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Primary;
import org.springframework.stereotype.Service;
import org.webjars.NotFoundException;

import com.juniordevmind.simplespringrestapi.models.TodoItem;

import simple_spring_restapi.repositories.TodoRepositories;

@Service
public class TodoServiceImpl implements TodoService {

    @Autowired
    private TodoRepository _todoRepository;

    @Override
    public TodoItem getTodoItemsById(int id) {
        return _findTodoItemById(id);
    }

    @Override
    public List<TodoItem> getTodoItems() {
        return _todoRepository.findAll();
    }

    @Override
    public Todo removeTodoItemById(int id) {
        _todoRepository.deleteById(id);
    }

    @Override
    public TodoItem saveTodoItem(TodoItem todoItem) {
        return _todoRepository.save(todoItem);
    }

    @Override
    public TodoItem updateTodoItem(int id, TodoItem todoItem) {
        return _todoRepository.save(todoItem);
    }

    private TodoItem _findTodoItemById(int id) throws NotFoundException {
        Optional<TodoItem> found = _todoRepository.findById(id);
        if (!found.isPresent()) {
            throw new NotFoundException("The todo item is not available");
        }
        return found.get();
    }
}

参考サイト

【Spring Boot】REST API 開発 - Dockerとvscodeを使った、Javaの開発環境構築 #1
【Spring Boot】REST API 開発 - Spring Boot プロジェクトの生成 #2
【Spring Boot】REST API 開発 - コントローラーの立ち上げ #2.5

【Spring Boot】REST API 開発 - モデルバリデーションの追加 #6
【Spring Boot】REST API 開発 - データアクセスレイヤーの追加 #7

1
1
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
1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?