SpringBoot으로 웹 API 서버 손잡이 만들기(Java, Maven)
repository와 서비스는 인터페이스와 실행 클래스를 분리합니다.
최종 소스 코드의 URL입니다.
디렉토리 구성은 다음과 같습니다.
.
├── HELP.md
├── demo.iml
├── mvnw
├── mvnw.cmd
├── pom.xml
├── src
│ ├── main
│ │ ├── java
│ │ │ └── com
│ │ │ └── example
│ │ │ └── demo
│ │ │ ├── DemoApplication.java
│ │ │ ├── configuration
│ │ │ │ ├── DataSourceConfiguration.java
│ │ │ │ └── DataSourceConfigurationProperties.java
│ │ │ ├── controller
│ │ │ │ └── MovieRestController.java
│ │ │ ├── domain
│ │ │ │ ├── Director.java
│ │ │ │ ├── Movie.java
│ │ │ │ └── MovieList.java
│ │ │ ├── repository
│ │ │ │ ├── MovieRepository.java
│ │ │ │ ├── MovieRepositoryImpl.java
│ │ │ │ └── mybatis
│ │ │ │ ├── MovieMapper.java
│ │ │ │ └── MovieMapper.xml
│ │ │ └── service
│ │ │ ├── MovieService.java
│ │ │ └── MovieServiceImpl.java
│ │ └── resources
│ │ ├── application.yml
│ │ ├── static
│ │ └── templates
│ └── test
│ └── java
│ └── com
│ └── example
│ └── demo
│ └── DemoApplicationTests.java
└── target
├── classes
│ ├── application.yml
│ └── com
│ └── example
│ └── demo
│ ├── DemoApplication.class
│ ├── configuration
│ │ ├── DataSourceConfiguration.class
│ │ └── DataSourceConfigurationProperties.class
│ ├── controller
│ │ └── MovieRestController.class
│ ├── domain
│ │ ├── Director.class
│ │ ├── Movie.class
│ │ └── MovieList.class
│ ├── repository
│ │ ├── MovieRepository.class
│ │ ├── MovieRepositoryImpl.class
│ │ └── mybatis
│ │ ├── MovieMapper.class
│ │ └── MovieMapper.xml
│ └── service
│ ├── MovieService.class
│ └── MovieServiceImpl.class
├── generated-sources
│ └── annotations
├── generated-test-sources
│ └── test-annotations
└── test-classes
└── com
└── example
└── demo
└── DemoApplicationTests.class
39 directories, 35 files
미리 준비하다
컨디션
프레임 생성
Spring Initializa demo를 사용합니다.zip을 다운로드하고 적당한 곳에서 해동하세요.
다음과 같이 설정합니다.
MySQL 준비
다음 구성으로 작성됩니다.
인증 관계
DB 관계
새 DB 생성
CREATE DATABASE moviedb;
moviedb 선택
USE moviedb;
외부 키워드가 있는 테이블 만들기
director table 만들기
CREATE TABLE director
(director_id char(10) PRIMARY KEY ,
director_name varchar(20));
무비 테이블 만들기CREATE TABLE movies
(movie_id CHAR(10) PRIMARY KEY,
movie_name VARCHAR(50),
director_id CHAR(10),
CONSTRAINT director_id_fk FOREIGN KEY (director_id) REFERENCES director(director_id));
테이블에 값 삽입
director에 삽입
INSERT INTO director VALUES('D01', '新海誠');
INSERT INTO director VALUES('D02', '藤井道人');
INSERT INTO director VALUES('D03', 'クリストファー・ノーラン');
무비에 삽입INSERT INTO movies VALUES('M01', '君の名は。', 'D01');
INSERT INTO movies VALUES('M02', '天気の子', 'D01');
INSERT INTO movies VALUES('M03', '言の葉の庭', 'D01');
INSERT INTO movies VALUES('M04', '新聞記者', 'D02');
INSERT INTO movies VALUES('M05', 'デイアンドナイト', 'D02');
INSERT INTO movies VALUES('M06', 'ダークナイト', 'D03');
INSERT INTO movies VALUES('M07', 'インセプション', 'D03');
INSERT INTO movies VALUES('M07', 'インセプション', 'D03');
절차.
1. 새 항목
2. pom.xml 편집
dependencies 탭에 다음 내용을 추가합니다.
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-dbcp2</artifactId>
</dependency>
resources 라벨을build 라벨에 추가합니다.<resources>
<resource>
<directory>src/main/java</directory>
<includes>
<include>**/*.xml</include>
</includes>
</resource>
<resource>
<directory>src/main/resources</directory>
</resource>
</resources>
추가 후,pom.xml->Maven->를 오른쪽 단추로 눌러서 '프로젝트 다시 불러오기' 를 선택하십시오3. application.yml 만들기
demo/src/main/java/resources/application.properties 이름을 바꾸고 ("팩스"를 오른쪽 단추로 누르면) lication을 적용합니다.yml로 주세요.
기술한 설정은 다음과 같다.
# JDBCの接続設定
dbcp2.jdbc:
driver-class-name: com.mysql.jdbc.Driver
url: jdbc:mysql://localhost:3306/moviedb?characterEncoding=UTF-8
username: root
password: password
initial-size: 1
max-idle: 3
min-idle: 1
# mybatisの設定
mybatis:
mapper-locations: classpath:com/example/demo/repository/mybatis/*.xml
4. domain 만들기
demo/src/main/java/com/example/demo/에domain 패키지를 만듭니다.
domain 패키지 아래에 Director 클래스, Movie 클래스, MovieList 클래스를 생성합니다.
Director 클래스
package com.example.demo.domain;
public class Director {
private String directorId;
private String directorName;
public Director() {
}
public Director(String directorId, String directorName) {
this.directorId = directorId;
this.directorName = directorName;
}
public String getDirectorId() {
return directorId;
}
public void setDirectorId(String directorId) {
this.directorId = directorId;
}
public String getDirectorName() {
return directorName;
}
public void setDirectorName(String directorName) {
this.directorName = directorName;
}
}
Movie 클래스
package com.example.demo.domain;
public class Movie {
private String movieId;
private String movieName;
private Director director;
public Movie() {
}
public Movie(String movieId, String movieName) {
this.movieId = movieId;
this.movieName = movieName;
}
public String getMovieId() {
return movieId;
}
public void setMovieId(String movieId) {
this.movieId = movieId;
}
public String getMovieName() {
return movieName;
}
public void setMovieName(String movieName) {
this.movieName = movieName;
}
public Director getDirector() {
return director;
}
public void setDirector(Director director) {
this.director = director;
}
}
MoviesList
package com.example.demo.domain;
import java.util.List;
public class MovieList {
private List<Movie> movieList;
public List<Movie> getMovieList() {
return movieList;
}
public void setMovieList(List<Movie> movieList) {
this.movieList = movieList;
}
}
5. Repository 생성
demo/src/main/java/com/example/demo/에서 Repository 패키지를 만듭니다.
repository와 mybatis를 통해 mysql와java를 연결할 수 있습니다.
5-1 Mapper.xml 만들기
포장 아래에 mybatis 포장을 만듭니다.
Mybatis 패키지의 설정은 MyBatis의 설정 파일, Movies Mapper입니다.xml을 만듭니다.
#{} Java 전송 변수를 표시합니다.
라벨 설명
<?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.example.demo.repository.mybatis.MovieMapper">
<resultMap id="Director" type="com.example.demo.domain.Director">
<id property="directorId" column="DIRECTOR_ID"/>
<result property="directorName" column="DIRECTOR_NAME"/>
</resultMap>
<resultMap id="Movie" type="com.example.demo.domain.Movie">
<id property="movieId" column="MOVIE_ID"/>
<result property="movieName" column="MOVIE_NAME"/>
<association property="director" resultMap="Director"/>
</resultMap>
<select id="find" resultMap="Movie">
SELECT M.MOVIE_ID, M.MOVIE_NAME, D.DIRECTOR_ID, D.DIRECTOR_NAME
FROM MOVIE M INNER JOIN DIRECTOR D USING (DIRECTOR_ID)
<where>
<if test="movieName != null">
M.MOVIE_NAME LIKE CONCAT('%', #{movieName}, '%')
</if>
<if test="directorName != null">
AND D.DIRECTOR_NAME LIKE CONCAT('%', #{directorName}, '%')
</if>
</where>
ORDER BY M.MOVIE_ID ASC
</select>
<select id="get" resultMap="Movie">
SELECT M.MOVIE_ID, M.MOVIE_NAME, D.DIRECTOR_ID, D.DIRECTOR_NAME
FROM MOVIE M INNER JOIN DIRECTOR D USING (DIRECTOR_ID)
WHERE MOVIE_ID = #{movieId}
</select>
<select id="lock" resultMap="Movie">
SELECT M.MOVIE_ID, M.MOVIE_NAME, D.DIRECTOR_ID, D.DIRECTOR_NAME
FROM MOVIE M INNER JOIN DIRECTOR D USING (DIRECTOR_ID)
WHERE MOVIE_ID = #{movieId}
FOR UPDATE
</select>
<insert id="add" parameterType="com.example.demo.domain.Movie" keyProperty="movieId">
<!-- selectKeyによってmovieIdを新しく設定する -->
<selectKey keyProperty="movieId" resultType="string" order="BEFORE">
<!-- MOVIE_IDのAUTO INCREMENTを実装 -->
SELECT COALESCE(CONCAT('M', LPAD(RIGHT(MAX(MOVIE_ID), 2) + 1, 2, '0')), 'M01') FROM MOVIE
</selectKey>
INSERT INTO MOVIE (MOVIE_ID , MOVIE_NAME, DIRECTOR_ID) VALUES (#{movieId}, #{movieName}, #{director.directorId});
</insert>
<update id="set" parameterType="com.example.demo.domain.Movie">
UPDATE MOVIE
<set>
<if test="movieName != null">
MOVIE_NAME = #{movieName},
</if>
<if test="director.directorId != null">
DIRECTOR_ID = #{director.directorId},
</if>
</set>
WHERE MOVIE_ID = #{movieId}
</update>
<delete id="remove" parameterType="com.example.demo.domain.Movie">
DELETE FROM MOVIE
WHERE MOVIE_ID = #{movieId}
</delete>
</mapper>
5-2 Mapper 인터페이스 만들기
mybatis 패키지 아래에 Movies Mapper 인터페이스를 만듭니다.
추상적인 방법을 정의하다.
메서드 이름은 Movies Mapper입니다.SQL의 태그를 xml로 기술하는 id = "정의의 이름입니다.
@Param의 Movies Mapperxml의 매개 변수와 연결됩니다.
package com.example.demo.repository.mybatis;
import com.example.demo.domain.Movie;
import java.util.List;
import org.apache.ibatis.annotations.Param;
public interface MovieMapper {
List<Movie> find(@Param("movieName") String movieName, @Param("directorName") String directorName);
Movie get(@Param("movieId") String movieId);
Movie lock(@Param("movieId") String movieId);
int add(Movie movie);
int set(Movie movie);
int remove(Movie movie);
}
5-3 Repository 인터페이스 생성
패키지 아래에 Movies Repository 인터페이스를 만듭니다.
추상적인 방법을 정의하다.
package com.example.demo.repository;
import com.example.demo.domain.Movie;
import java.util.List;
public interface MovieRepository {
List<Movie> findList(String movieName, String directorName);
Movie findOne(String movieId);
Movie lock(String movieId);
void insert(Movie movie);
void update(Movie movie);
void delete(Movie movie);
}
5-4 RepositoryImpl 클래스 생성
실행 클래스 Repository Impl 클래스를 만들고 패키지 아래에 Movies Repository 인터페이스를 설치합니다.
모방에 따라 리포지토리에서 DI를 진행한다.
SqlSession Template 클래스를 사용하면 Mapper 인터페이스를 읽고 MySQL을 조작하는 방법을 사용할 수 있습니다.
package com.example.demo.repository;
import com.example.demo.domain.Movie;
import com.example.demo.repository.mybatis.MovieMapper;
import java.util.List;
import org.mybatis.spring.SqlSessionTemplate;
import org.springframework.stereotype.Repository;
@Repository
public class MovieRepositoryImpl implements MovieRepository {
private final SqlSessionTemplate sqlSessionTemplate;
public MovieRepositoryImpl(SqlSessionTemplate sqlSessionTemplate) {
this.sqlSessionTemplate = sqlSessionTemplate;
}
@Override
public List<Movie> findList(String movieName, String directorName) {
List<Movie> movie = this.sqlSessionTemplate.getMapper(MovieMapper.class).find(movieName, directorName);
return movie;
}
@Override
public Movie findOne(String movieId) {
Movie movie = this.sqlSessionTemplate.getMapper(MovieMapper.class).get(movieId);
if (movie == null){
throw new RuntimeException("movie not found");
}
return movie;
}
@Override
public Movie lock(String movieId) {
Movie movie = this.sqlSessionTemplate.getMapper(MovieMapper.class).lock(movieId);
if (movie == null){
throw new RuntimeException("movie not found");
}
return movie;
}
@Override
public void insert(Movie movie) {
this.sqlSessionTemplate.getMapper(MovieMapper.class).add(movie);
}
@Override
public void update(Movie movie) {
int affected = this.sqlSessionTemplate.getMapper(MovieMapper.class).set(movie);
if (affected != 1){
throw new RuntimeException("failed");
}
}
@Override
public void delete(Movie movie) {
int affected = this.sqlSessionTemplate.getMapper(MovieMapper.class).remove(movie);
if (affected != 1){
throw new RuntimeException("failed");
}
}
}
6 서비스 작성
demo/src/main/java/com/example/demo/부하에 서비스 패키지를 만듭니다.
비즈니스 논리와 거래 관리를 진행하다.
6-1 서비스 인터페이스 만들기
서비스 팩 구성에서 MovieService 인터페이스를 만듭니다.
package com.example.demo.service;
import com.example.demo.domain.Movie;
import com.example.demo.domain.MovieList;
public interface MovieService {
MovieList find(String movieName, String directorName);
Movie get(String movieId);
void add(Movie movie);
void set(Movie movie);
void remove(String movieId);
}
6-2 ServiceImpl 클래스 만들기
서비스 인터페이스(6-1)가 설치된 클래스를 만듭니다.
@Service 근사법에 따라 DI를 진행합니다.
@Transactional 변형에 따라 DB 작업에 오류가 발생할 경우 롤백 작업을 수행합니다.
package com.example.demo.service;
import com.example.demo.domain.Movie;
import com.example.demo.domain.MovieList;
import com.example.demo.repository.MovieRepository;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@Service
public class MovieServiceImpl implements MovieService{
private final MovieRepository repository;
public MovieServiceImpl(MovieRepository repository) {
this.repository = repository;
}
@Override
public MovieList find(String movieName, String directorName) {
MovieList movieList = new MovieList();
movieList.setMovieList(this.repository.findList(movieName, directorName));
return movieList;
}
@Override
public Movie get(String movieId) {
Movie movie = this.repository.findOne(movieId);
return movie;
}
@Override
@Transactional(rollbackFor = Throwable.class)
public void add(Movie movie) {
this.repository.insert(movie);
}
@Override
@Transactional(rollbackFor = Throwable.class)
public void set(Movie movie) {
this.repository.lock(movie.getMovieId());
this.repository.update(movie);
}
@Override
@Transactional(rollbackFor = Throwable.class)
public void remove(String movieId) {
this.repository.delete(this.repository.findOne(movieId));
}
}
7 RestController 작성
demo/src/main/java/com/example/demo/아래에 controller 패키지를 만듭니다.
RestController 작성
Controller 패키지 아래에 Movies RestController 클래스를 만듭니다.
초대 정보
Controller 클래스의 에뮬레이션 허용
package com.example.demo.controller;
import com.example.demo.domain.Movie;
import com.example.demo.domain.MovieList;
import com.example.demo.service.MovieService;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PatchMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("api/movie")
public class MovieRestController {
private final MovieService service;
public MovieRestController(MovieService service) {
this.service = service;
}
@GetMapping(path = "", produces = "application/json")
public MovieList find(@RequestParam(name = "movieName", required = false) String movieName,
@RequestParam(name = "directorName", required = false) String directorName){
return this.service.find(movieName, directorName);
}
@GetMapping(path = "/{movieId}", produces = "application/json")
public Movie get(@PathVariable String movieId){
return this.service.get(movieId);
}
@PostMapping(path = "", produces = "application/json")
public void add(@RequestBody Movie movie){
this.service.add(movie);
}
@PatchMapping(path = "/{movieId}", produces = "application/json")
public void update(@PathVariable String movieId, @RequestBody Movie movie){
movie.setMovieId(movieId);
this.service.set(movie);
}
@DeleteMapping(path = "/{movieId}", produces = "application/json")
public void remove(@PathVariable String movieId){
this.service.remove(movieId);
}
}
8configuration 만들기
MySQL에 대한 연결 설정을 만듭니다.
demo/src/main/java/com/example/demo/아래에 configuration 패키지를 만듭니다.
Dat a S o u ceConfiguration Properties 만들기
패키지 구성에서 Dat a So u ceConfiguration Prooperties를 만듭니다.
application.yml를 불러오면 자신의 속성을 설정할 수 있습니다.
package com.example.demo.configuration;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.context.properties.ConstructorBinding;
@ConstructorBinding
@ConfigurationProperties(prefix = "dbcp2.jdbc")
public class DataSourceConfigurationProperties {
private final String url;
private final String driverClassName;
private final String username;
private final String password;
private final int initialSize;
private final int maxIdle;
private final int minIdle;
public DataSourceConfigurationProperties(String url, String driverClassName, String username, String password,
int initialSize, int maxIdle, int minIdle) {
this.url = url;
this.driverClassName = driverClassName;
this.username = username;
this.password = password;
this.initialSize = initialSize;
this.maxIdle = maxIdle;
this.minIdle = minIdle;
}
public String getUrl() {
return url;
}
public String getDriverClassName() {
return driverClassName;
}
public String getUsername() {
return username;
}
public String getPassword() {
return password;
}
public int getInitialSize() {
return initialSize;
}
public int getMaxIdle() {
return maxIdle;
}
public int getMinIdle() {
return minIdle;
}
}
데이터 원본 파일 만들기
Dat a S o u ceConfiguration Prooperties를 읽고 설정을 반영합니다.
package com.example.demo.configuration;
import javax.sql.DataSource;
import org.apache.commons.dbcp2.BasicDataSource;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
@EnableConfigurationProperties(DataSourceConfigurationProperties.class)
public class DataSourceConfiguration {
private final DataSourceConfigurationProperties properties;
public DataSourceConfiguration(DataSourceConfigurationProperties properties) {
this.properties = properties;
}
@Bean
public DataSource dataSource(){
BasicDataSource dataSource = new BasicDataSource();
dataSource.setDriverClassName(this.properties.getDriverClassName());
dataSource.setUrl(this.properties.getUrl());
dataSource.setUsername(this.properties.getUsername());
dataSource.setPassword(this.properties.getPassword());
dataSource.setInitialSize(this.properties.getInitialSize());
dataSource.setMaxIdle(this.properties.getMaxIdle());
dataSource.setMinIdle(this.properties.getMinIdle());
return dataSource;
}
}
이상이면 완성동작 확인
부팅
Intellij를 사용하여 demo/src/main/java/com/example/demo/부하 실행 클래스, DemoApplication 클래스를 실행합니다.
http://localhost:8080/api/movie에 접근한 후 mysql에 저장된 데이터를 표시하면 성공합니다.
CRUD
curl 명령을 사용하여 동작 확인
READ(get)
단일 검색
입력
curl -H "Content-Type: application/json" "localhost:8080/api/movie/M01"
출력{
"movieId": "M01",
"movieName": "君の名は。",
"director": { "directorId": "D01", "directorName": "新海誠" }
}
모두 검색
입력
curl -H "Content-Type: application/json" "localhost:8080/api/movie"
출력{
"movieList": [
{
"movieId": "M01",
"movieName": "君の名は。",
"director": { "directorId": "D01", "directorName": "新海誠" }
},
{
"movieId": "M02",
"movieName": "天気の子",
"director": { "directorId": "D01", "directorName": "新海誠" }
},
{
"movieId": "M03",
"movieName": "言の葉の庭",
"director": { "directorId": "D01", "directorName": "新海誠" }
},
{
"movieId": "M04",
"movieName": "新聞記 者",
"director": { "directorId": "D02", "directorName": "藤井道人" }
},
{
"movieId": "M05",
"movieName": "デイアンドナイト",
"director": { "directorId": "D02", "directorName": "藤井道人" }
},
{
"movieId": "M06",
"movieName": "ダークナイト",
"director": {
"directorId": "D03",
"directorName": "クリストファー・ノーラン"
}
},
{
"movieId": "M07",
"movieName": "インセプション",
"director": {
"directorId": "D03",
"directorName": "クリストファー・ノーラン"
}
}
]
}
CREATE(post)
영화 추가
입력
curl -X POST \
-H "Content-Type: application/json" "localhost:8080/api/movie" \
-d '{"movieName":"テネット", "director": {"directorId":"D03"}}'
확인curl -H "Content-Type: application/json" "localhost:8080/api/movie/M08"
결과{
"movieId": "M08",
"movieName": "テネット",
"director": {
"directorId": "D03",
"directorName": "クリストファー・ノーラン"
}
}
UPDATE(patch)
영화
입력
curl -X PATCH \
-H "Content-Type: application/json" "localhost:8080/api/movie/M08" \
-d '{"movieName":"秒速5センチメートル", "director": {"directorId":"D01"}}'
확인curl -H "Content-Type: application/json" "localhost:8080/api/movie/M08"
결과{
"movieId": "M08",
"movieName": "秒速5センチメートル",
"director": { "directorId": "D01", "directorName": "新海誠" }
}
DELETE(delete)
영화 삭제
입력
curl -X DELETE -H "Content-Type: application/json" "localhost:8080/api/movie/M08"
확인curl -H "Content-Type: application/json" "localhost:8080/api/movie/M08"
출력{
"timestamp": "2021-05-02T22:17:32.490+00:00",
"status": 500,
"error": "Internal Server Error",
"message": "",
"path": "/api/movie/M08"
}
Reference
이 문제에 관하여(SpringBoot으로 웹 API 서버 손잡이 만들기(Java, Maven)), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://zenn.dev/msksgm/articles/java-springboot-api-server텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)