Search

To Do List - BackEnd (SpringBoot)

To Do List REST API ์„œ๋ฒ„ ๊ตฌํ˜„

1.
To Do List ํ…Œ์ด๋ธ” ์ •์˜
2.
Spring Boot REST API ๊ตฌํ˜„
3.
API ๋ช…์„ธ์„œ ์ž๋™ ์ƒ์„ฑ - OpenAPI(Swagger)
4.
API ํ…Œ์ŠคํŠธ

To Do List ํ…Œ์ด๋ธ” ์ •์˜

todos.sql

DROP TABLE IF EXISTS `todos`; CREATE TABLE `todos` ( `no` BIGINT NOT NULL AUTO_INCREMENT PRIMARY KEY COMMENT 'PK', `id` VARCHAR(64) NOT NULL COMMENT 'UK', `name` TEXT NOT NULL COMMENT 'ํ• ์ผ', `status` BOOLEAN NOT NULL DEFAULT false COMMENT '์ƒํƒœ', `seq` INT NOT NULL DEFAULT 0 COMMENT '์ˆœ์„œ', `created_at` TIMESTAMP NOT NULL DEFAULT current_timestamp COMMENT '๋“ฑ๋ก์ผ์ž', `updated_at` TIMESTAMP NOT NULL DEFAULT current_timestamp COMMENT '์ˆ˜์ •์ผ์ž' );
SQL
๋ณต์‚ฌ

Spring Boot REST API ๊ตฌํ˜„

์š”์ฒญ ๋ฉ”์†Œ๋“œ
์š”์ฒญ ๊ฒฝ๋กœ
ํ•ญ๋ชฉ
Response
๋น„๊ณ 
GET
/todos
ํ• ์ผ ๋ชฉ๋ก
{ โ€œlistโ€ : [], โ€œpaginationโ€ : }
GET
/todos?page=&size=
ํ• ์ผ ๋ชฉ๋ก ํŽ˜์ด์ง•
{ โ€œlistโ€ : [], โ€œpaginationโ€ : }
GET
/todos/{id}
ํ• ์ผ ์กฐํšŒ
{ }
POST
/todos
ํ• ์ผ ๋“ฑ๋ก
โ€œSUCCESSโ€ 201 โ€FAILโ€ 400
PUT
/todos
ํ• ์ผ ์ˆ˜์ •
โ€œSUCCESSโ€ 200 โ€FAILโ€ 400
DELETE
/todos/{id}
ํ• ์ผ ์‚ญ์ œ
โ€œSUCCESSโ€ 200 โ€FAILโ€ 400
โ€ข
domain
โ—ฆ
Todos.java
โ€ข
Mapper
โ—ฆ
TodoMapper.xml
โ—ฆ
BaseMapper.java
โ—ฆ
TodoMapper.java
โ€ข
Service
โ—ฆ
BaseService.java
โ—ฆ
TodoService.java
โ—ฆ
TodoServiceImpl.java
โ€ข
Controller
โ—ฆ
TodoController.java
โ—ฆ
@CrossOrigin("*")
โ—ฆ
@RestController
โ–ช
sp-crud

API ๋ช…์„ธ์„œ ์ž๋™ ์ƒ์„ฑ - OpenAPI(Swagger)

// Springdoc openapi implementation 'org.springdoc:springdoc-openapi-starter-webmvc-ui:2.7.0'
SQL
๋ณต์‚ฌ

build.gradle

plugins { id 'java' id 'war' id 'org.springframework.boot' version '3.4.1' id 'io.spring.dependency-management' version '1.1.6' } group = 'com.aloha' version = '0.0.1-SNAPSHOT' java { toolchain { languageVersion = JavaLanguageVersion.of(17) } } configurations { compileOnly { extendsFrom annotationProcessor } } repositories { mavenCentral() } dependencies { implementation 'org.springframework.boot:spring-boot-starter-web' implementation 'org.mybatis.spring.boot:mybatis-spring-boot-starter:3.0.4' compileOnly 'org.projectlombok:lombok' developmentOnly 'org.springframework.boot:spring-boot-devtools' runtimeOnly 'com.mysql:mysql-connector-j' annotationProcessor 'org.projectlombok:lombok' providedRuntime 'org.springframework.boot:spring-boot-starter-tomcat' testImplementation 'org.springframework.boot:spring-boot-starter-test' testImplementation 'org.mybatis.spring.boot:mybatis-spring-boot-starter-test:3.0.4' testRuntimeOnly 'org.junit.platform:junit-platform-launcher' // Springdoc openapi implementation 'org.springdoc:springdoc-openapi-starter-webmvc-ui:2.7.0' } tasks.named('test') { useJUnitPlatform() }
SQL
๋ณต์‚ฌ

SwaggerConfig.java

import org.springdoc.core.models.GroupedOpenApi; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import io.swagger.v3.oas.models.OpenAPI; import io.swagger.v3.oas.models.info.Info; @Configuration public class SwaggerConfig { @Bean public GroupedOpenApi publicApi() { return GroupedOpenApi.builder() .group("aloha") // ๊ทธ๋ฃน๋ช… ์„ค์ • .pathsToMatch("/**") // ๊ฒฝ๋กœ ์„ค์ • .build(); } @Bean public OpenAPI springShopOpenAPI() { return new OpenAPI() .info(new Info().title("์ƒํ’ˆ ๊ด€๋ฆฌ Proejct API") .description("์ƒํ’ˆ ๊ด€๋ฆฌ ํ”„๋กœ์ ํŠธ API ์ž…๋‹ˆ๋‹ค.") .version("v0.0.1")); } }
Java
๋ณต์‚ฌ

๊ธฐ๋ณธ ๊ฒฝ๋กœ

PageHelper ๋ฅผ ์ด์šฉํ•œ ํŽ˜์ด์ง• ์ฒ˜๋ฆฌ

builde.gradle

// pagehelper implementation 'com.github.pagehelper:pagehelper-spring-boot-starter:2.1.0'
Java
๋ณต์‚ฌ

application.properites

# PageHelper ์„ค์ • pagehelper.helperDialect=mysql pagehelper.reasonable=true pagehelper.supportMethodsArguments=true pagehelper.params=count=countSql
Java
๋ณต์‚ฌ

Pagination.java

import lombok.Data; /** * [ํŽ˜์ด์ง•] * โœ… ํŽ˜์ด์ง€ ํ•„์ˆ˜ ์ •๋ณด * - ํŽ˜์ด์ง€ ๋ฒˆํ˜ธ : page * - ํŽ˜์ด์ง€๋‹น ๊ฒŒ์‹œ๊ธ€ ์ˆ˜ : size * - ๋…ธ์ถœ ํŽ˜์ด์ง€ ๊ฐœ์ˆ˜ : count * - ์ „์ฒด ๋ฐ์ดํ„ฐ ๊ฐœ์ˆ˜ : total * * โญ ํŽ˜์ด์ง€ ์ˆ˜์‹ ์ •๋ณด * - ์‹œ์ž‘ ๋ฒˆํ˜ธ : start * - ๋ ๋ฒˆํ˜ธ : end * - ์ฒซ ๋ฒˆํ˜ธ : first * - ๋งˆ์ง€๋ง‰ ๋ฒˆํ˜ธ : last * - ์ด์ „ ๋ฒˆํ˜ธ : prev * - ๋‹ค์Œ ๋ฒˆํ˜ธ : next * - ๋ฐ์ดํ„ฐ ์ˆœ์„œ ๋ฒˆํ˜ธ : index */ @Data public class Pagination { // ํŽ˜์ด์ง• ๊ธฐ๋ณธ๊ฐ’ private static final long PAGE_NUM = 1; // ํ˜„์žฌ ํŽ˜์ด์ง€ ๋ฒˆํ˜ธ ๊ธฐ๋ณธ๊ฐ’ private static final long SIZES = 10; // ํŽ˜์ด์ง€๋‹น ๊ฒŒ์‹œ๊ธ€ ์ˆ˜ ๊ธฐ๋ณธ๊ฐ’ private static final long COUNT = 10; // ๋…ธ์ถœ ํŽ˜์ด์ง€ ๊ฐœ์ˆ˜ ๊ธฐ๋ณธ๊ฐ’ // โœ… ํ•„์ˆ˜ ์ •๋ณด private long page; private long size; private long count; private long total; // โญ ์ˆ˜์‹ ์ •๋ณด private long start; private long end; private long first; private long last; private long prev; private long next; private long index; // ์ƒ์„ฑ์ž public Pagination() { this(0); } // ๋ฐ์ดํ„ฐ ๊ฐœ์ˆ˜ public Pagination(long total) { this(PAGE_NUM, total); } // ํ˜„์žฌ ๋ฒˆํ˜ธ, ๋ฐ์ดํ„ฐ ๊ฐœ์ˆ˜ public Pagination(long page, long total) { this(page, SIZES, COUNT, total); } // ํ•„์ˆ˜ ์ •๋ณด public Pagination(long page, long size, long count, long total) { this.page = page; this.size = size; this.count = count; this.total = total; calc(); } // setter // * ๋ฐ์ดํ„ฐ ๊ฐœ์ˆ˜ ์ง€์ • ํ›„, ํŽ˜์ด์ง€ ์ˆ˜์‹ ์žฌ๊ณ„์‚ฐ public void setTotal(long total) { this.total = total; calc(); } // ํŽ˜์ด์ง• ์ฒ˜๋ฆฌ ์ˆ˜์‹ public void calc() { // ์ฒซ ๋ฒˆํ˜ธ this.first = 1; // ๋งˆ์ง€๋ง‰ ๋ฒˆํ˜ธ this.last = (this.total - 1) / size + 1; // ์‹œ์ž‘ ๋ฒˆํ˜ธ this.start = ( (page-1) / count ) * count + 1; // ๋ ๋ฒˆํ˜ธ this.end = ( (page-1) / count + 1 ) * count; if( this.end > this.last ) this.end = this.last; // ์ด์ „ ๋ฒˆํ˜ธ this.prev = this.page - 1; // ๋‹ค์Œ ๋ฒˆํ˜ธ this.next = this.page + 1; // ๋ฐ์ดํ„ฐ ์ˆœ์„œ ๋ฒˆํ˜ธ this.index = (this.page - 1) * this.size; } }
Java
๋ณต์‚ฌ