[SpringBoot] #SpringBoot와 MyBatis를 이용한 REST API
💡 STEP 1 : DB 준비
REST API에서 사용할 DB를 먼저 생성한다.
💡 STEP 2 : 프로젝트 생성
File > New > Spring Starter Project를 클릭 후 아래 이미지와 같이 입력 후 Finish를 누르면 프로젝트가 생성된다.
💡 STEP 3 : Dependency 추가
pom.xml에 다음 3개의 Dependency를 추가해준다.
<!-- AspectJ -->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
</dependency>
<!-- Commons DBCP 2 : DataSource 객체를 생성할 때 필요 -->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-dbcp2</artifactId>
</dependency>
참고로 원하는 Dependency는 아래의 사이트에서 편하게 찾을 수 있다.
💡 STEP 4 : application.properties 수정
src/main/resources에 application.properties가 있는데, 아래와 같이 추가해준다.
[application.properties]
#server setting
server.port=8080
server.servlet.context-path=/모든API앞에 붙을 이름/
# datasource setting
spring.datasource.type=org.apache.commons.dbcp2.BasicDataSource
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/사용하는 DB이름?serverTimezone=Asia/Seoul
spring.datasource.username=DB이름
spring.datasource.password=DB비밀번호
# mybatis setting
mybatis.mapper-locations=mappers/**/*.xml
mybatis.type-aliases-package=com.spring.example.dto
mybatis.config-location=classpath:mybatis-config.xml
# logging setting
logging.level.com.spring.example=debug
💡 STEP 5 : mybatis-config.xml 추가
application.properties가 있는 디렉터리(src/main/resources)에 mybatis-config.xml 파일을 추가한다.
mybatis-config.xml에서 mybatis 설정을 해줄 수 있는데 아래는 언더바 표기법을 카멜 표기법으로 변경해주는 설정이다.
아무 설정이 필요 없다면 <configuration> 안을 비워두면 된다.
[mybatis-config.xml]
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<settings>
<setting name="mapUnderscoreToCamelCase" value="true"/>
</settings>
</configuration>
💡 STEP 6 : 패키지 생성
src/main/java 디렉터리에 다음과 같이 패키지를 추가한다.
💡 STEP 7 : '프로젝트 이름 Applitcaion.java'에 Annotation 추가
com.spring.example패키지에 보면 '프로젝트 이름 Applitcaion.java'파일이 있을 것이다.
기본적으로 @SpringBootApplication Annotation이 있는데,
그 위에 다음과 같이 @MapperScan(basePackages = "com.spring.example.model.repo")를 추가한다.
[ExampleApplication.java]
package com.spring.example;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@MapperScan(basePackages = "com.spring.example.model.repo")
@SpringBootApplication
public class ExampleApplication {
public static void main(String[] args) {
SpringApplication.run(ExampleApplication.class, args);
}
}
💡 STEP 8 : com.spring.example.aop에 LoggingAspect.java 추가
다음과 같이 작성하면 com.spring.example.model에 속한 method가 실행될 때마다
console에서 호출된 method명과 매개변수를 확인할 수 있다.
[LoggingAspect.java]
package com.spring.example.aop;
import java.util.Arrays;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
//LoggingAspect를 빈으로 선언한다.
@Component
//이 클래스가 aspect임을 선언한다.
@Aspect
public class LoggingAspect {
private static Logger logger = LoggerFactory.getLogger(LoggingAspect.class);
/**
* 메서드 선언 전에 동작해야 하므로 @Before advicce로 구성한다. point cut의 구성은 아래와 같다. 리턴 타입: * 이므로
* 모든 리턴 타입에 대해 적용된다. 클래스명: com.spring.example.model 패키지로 시작하고 .. 이므로 하위의 모든 경로,
* 클래스에 적용된다. 메서드명: * 이므로 모든 메서드 이름에 적용된다. 파라미터:.. 이므로 파라미터의 개수, 타입에 상관없이 적용된다.
* @param jp JoinPoint를 통해 joinpoint의 다양한 정보에 접근할 수 있다.
*/
@Before(value = "execution(* com.spring.example.model..*.*(..))")
public void logging(JoinPoint jp) {
// getSignature: 메서드의 선언부 정보를 반환한다.
// args: 메서드에 전달된 파라미터 정보를 배열로 반환한다.
logger.debug("메서드선언부:{} 전달 파라미터:{}", jp.getSignature(), Arrays.toString(jp.getArgs()));
}
}
💡 STEP 9 : com.spring.example.dto에 DTO 추가
다음으로는 DB에서 받은 Data를 저장할 DTO를 com.spring.example.dto에 생성할 것이다.
DTO의 경우 되도록이면 DB의 테이블명과 칼럼명을 맞춰주는 것이 좋다.
생성자, getter/setter, toSring()의 경우 Alt + Shift + S를 이용하면 편하게 생성할 수 있다.
[Car.java]
package com.spring.example.dto;
public class car {
private Integer id;
private String name;
private String type;
private Integer price;
public car() {
}
public car(Integer id, String name, String type, Integer price) {
super();
this.id = id;
this.name = name;
this.type = type;
this.price = price;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public Integer getPrice() {
return price;
}
public void setPrice(Integer price) {
this.price = price;
}
@Override
public String toString() {
StringBuilder builder = new StringBuilder();
builder.append("car [id=").append(id).append(", name=").append(name).append(", type=").append(type)
.append(", price=").append(price).append("]");
return builder.toString();
};
}
💡 STEP 10 : com.spring.example.model.repo에 Repo파일 추가
현재 나는 Car 테이블에 있는 모든 인스턴스를 가져올 것이기 때문에 다음과 같이 작성했다.
Repo는 interface로 작성해야 한다는 것을 명심하자.
[CarRepo.java]
package com.spring.example.model.repo;
import java.util.List;
import com.spring.example.dto.Car;
public interface CarRepo {
List<Car> search();
}
💡 STEP 11 : com.spring.example.model.repo.service에 Service 추가
interface인 CarService와 이 interface를 구현하는 CarServiceImpl을 추가한다.
CarService의 경우 Repo와 동일하게 작성하면 된다.
[CarService.java]
package com.spring.example.model.service;
import java.util.List;
import com.spring.example.dto.Car;
public interface CarService {
List<Car> search();
}
CarServiceImpl에는 @Service Annotation을 까먹지 말고 추가해야 한다.
추가로 Update와 같이 DB의 데이터를 변경할 때는 @Transactional을 추가해야 한다.
[CarServiceImpl.java]
package com.spring.example.model.service;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.spring.example.dto.Car;
import com.spring.example.model.repo.CarRepo;
@Service
public class CarServiceImpl implements CarService {
private CarRepo repo;
public CarRepo getRepo() {
return repo;
}
@Autowired
public void setRepo(CarRepo repo) {
this.repo = repo;
}
@Override
public List<Car> search() {
return repo.search();
}
}
💡 STEP 12 : mappers폴더에 car.xml 추가
src/main/resources 디렉터리에 mappers라는 폴더를 생성한 뒤 car.xml을 생성한다.
car.xml에는 원하는 쿼리문을 작성하면 되는데, 나 같은 경우 Car테이블의 모든 인스턴스를 가져올 것이다.
그래서 search라는 id를 가지게 했고, resultType을 아까 생성한 Car DTO로 지정했다.
[car.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.spring.example.model.repo.CarRepo">
<select id="search" resultType="Car">
select * from car;
</select>
</mapper>
💡 STEP 13 : com.spring.example.controller에 RestController 추가
이제 작성한 코드를 기반으로 Controller만 작성하면 REST API를 이용할 수 있다.
나 같은 경우 DB에서 값을 가져오는 것이기 때문에 GET Method를 사용했다.
또한, 가져오는 값이 하나가 아니기 때문에 List <Car>를 이용해 ArrayList로 받아오도록 했다.
정상적으로 받아왔을 경우엔 결과와 함께 상태 코드 200을 반환한다.
정상적으로 받아오지 못했을 경우에는 상태 코드 204를 반환한다.
[CarRestController.java]
package com.spring.example.controller;
import java.util.List;
import javax.servlet.http.HttpSession;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.validation.BindException;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ModelAttribute;
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.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.servlet.HandlerExceptionResolver;
import com.spring.example.dto.Car;
import com.spring.example.model.service.CarService;
@CrossOrigin(origins = { "*" })
@RestController
public class CarRestController {
@Autowired
private CarService cService;
@GetMapping("/car")
public ResponseEntity<?> searchBook() { // <?> 리턴 타입이 return에서 정해짐
List<Car> cars = cService.search();
if (cars != null && !cars.isEmpty()) {
// ResponseEntity : 자바 객체를 JSON 문자열로 바꿔주고 클라이언트에 응답을 줌
// HttpStatus.OK(상태코드, 200번) : 클라이언트에서 정상적으로 판단하는 상태코드
return new ResponseEntity<List<Car>>(cars, HttpStatus.OK);
}
// HttpStatus.NO_CONTENT(상태코드 204번)
return new ResponseEntity<Void>(HttpStatus.NO_CONTENT);
}
}
💡 STEP 14 : 테스트
테스트는 Postman을 이용하면 보기 쉽게 테스트할 수 있다.
Postman API Platform | Sign Up for Free
Postman is an API platform for building and using APIs. Postman simplifies each step of the API lifecycle and streamlines collaboration so you can create better APIs—faster.
www.postman.com
Postman을 이용해 GET을 해보면 다음과 같이 DB에서 정상적으로 데이터를 불러오는 것을 알 수 있다.
💡 디렉터리 구조
코드를 정상적으로 작성했다면 다음과 같은 디렉터리 구조를 가진다.
'Backend > Spring' 카테고리의 다른 글
[Spring] #Spring의 개념 (0) | 2022.03.21 |
---|