이 포스팅은 인프런 강의 중 쥬쥬님의 '쥬쥬와 함께 하루만에 시작하는 백엔드 - 스프링, 도커, AWS' 에 올라온
코드 및 사진 이미지 모두 해당 강의를 참고하였습니다.
(인프런)쥬쥬와 함께 하루만에 시작하는 백엔드 - 스프링, 도커, AWS링크
Lombok을 설정하면 직접 getter, setter, ToString, 생성자를 생성하지 않고 어노테이션만 작성하더라도 코드를 자동완성할 수 있다.
build.gradle에
configurations {
compileOnly {
extendsFrom annotationProcessor
}
}
dependencies {
...
compileOnly 'org.projectlombok:lombok'
annotationProcessor 'org.projectlombok:lombok'
...
}
를 추가한 후, Settings/Build, Exception .../Annotaion Process에 들어가 Enable annotaion processing을 선택하면 롬복을 위한 설정이 끝난다.
Enable annotation processing가 무슨 역할인지 chatGPT에게 물어본 결과.
//기존 자바코드
@RestController
public class TestResponseApi {
@GetMapping("/test/response/string")
public String stringResponse() {
return "This is String";
}
@GetMapping("/test/response/json")
public TestRequestBody jsonResponse(){
return new TestRequestBody("jyujyu", 20);
}
public static class TestRequestBody{
String name;
Integer age;
public TestRequestBody(String name, Integer age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public Integer getAge() {
return age;
}
}
}
기존에는 이렇게 생성자, getter를 코드로 작성해주어야 해서 코드가 길고 중요한 부분만 보기 힘들었다. 이를 롬복을 활용할 경우,
//롬복 사용 코드
@RestController
public class TestLombokApi {
@GetMapping("/test/lombok")
public TestLombokResponseBody testLombok(){
return new TestLombokResponseBody("jyujyu", 20);
}
@Getter//게터
@AllArgsConstructor //생성자
public static class TestLombokResponseBody {
String name;
Integer age;
}
}
위 코드처럼 게터와 생성자를 직접 생성하지 않고도 어노테이션만 추가하여 중요한 부분만 한눈에 확인하기 편해졌다.
이는 Postman을 사용하여 롬복을 통해 보낸 http 요청이 잘 왔는지,
확인하는 화면이다.
게터와 생성자를 생성하는 어노테이션이 잘 동작함을 확인할 수 있다.
@Getter
@Table(name = "test")
@Entity
public class TestEntity {
@Id @GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
private Integer age;
}
model 패키지에 엔터티 클래스를 생성한 후 이렇게 작성한다.
그러면 연결된 h2 데이터베이스에
이렇게 Test라는 테이블이 생성되고,
age, id, name이 잘 생성되었음을 확인할 수 있다.
그런데 이 코드에서 @Id @GeneratedValue(strategy = GenerationType.IDENTITY)라는 코드가 어떤 역할을 하는지 궁금해서 찾아보니, 아래와 같은 답변을 받을 수 있었다. 물론 이 답변이 맞는지 다시 구글링해서 2차 검증을 했다.
테이블을 생성할 때, 고유키 인 primary key가 필요하기 때문에 @Id 라는 에너테이션을 붙이는 것이며
@GeneratedValue는 어떤식으로 기본 키 생성을 할 것인지 정하는 것이다.
@GeneratedValue 4가지 전략
- GenerationType.IDENTITY : 데이터베이스에 의존하여 기본 키 값을 자동으로 생성한다. (mysql의 autoincrement와 같은 기능)
- GenerationType.SEQUENCE : 데이터베이스 시퀀스를 사용하여 기본 키 값을 생성한다. (Oracle 등에서 사용되는데, 시퀀스 객체를 통해 기본 키 값을 미리 생성 후, 해당 값을 엔터티에 할당하는 것.)
But, 시퀀스를 지원하지 않는 데이터베이스에서는 사용불가.
- GenerationType.TABLE : 별도의 테이블을 만들어 그 안에 기본 키 값을 저장하고, 이를 통해 기본 키 값을 생성. (모든 데이터베이스에서 사용 가능하며, 기본 키를 저장하고 관리하는 테이블을 따로 생성하여 ID 값을 관리)
- GenerationType.AUTO : JPA가 사용하는 데이터베이스에 따라 자동으로 적절한 기본 키 생성 전략(위 3가지 중 하나)을 선택. (예상하지 못하 전략이 선택될 수 있으며, 성능이 떨어질 가능성 존재.)
public interface TestRepository extends JpaRepository<TestEntity, Long> {
//Long은 TestEntity의 @Id필드 타입
}
이렇게 데이터를 저장할 수 있는 Repository를 생성한다.
@AllArgsConstructor//생성자 역할을 lombok을 사용해 대신
@Service
public class TestService {
private final TestRepository testRepository;
public void create(String name, Integer age){
TestEntity testEntity = new TestEntity(name, age);
testRepository.save(testEntity);
}
}
그 후, 이렇게 엔터티를 레포지토리에 저장할 수 있도록 Service 클래스를 구현하는 코드를 작성한다.
@AllArgsConstructor
@RestController
public class TestEntityApi {
private final TestService testService;
@GetMapping("/test/entity/create")
public void createTestEntity(){
testService.create("jyujyu", 20);
}
}
실제 이것이 잘 동작하는지 확인하기 위해
데이터를 넣는 test api를 생성해 확인해보았다.
Postman에서 API 호출을 확인했을 때, API가 반환하는 값이 없기 때문에 아무 값도 표시되지 않지만, 200 OK 상태 코드를 통해 호출이 성공적으로 이루어졌음을 확인할 수 있다.
이후 H2 데이터베이스를 조회하여, name 필드에 "jyujyu", age 필드에 20이 정확히 저장된 것을 확인할 수 있다.
@AllArgsConstructor
@RestController
public class TestEntityApi {
private final TestService testService;
/*
@GetMapping("/test/entity/create")
public void createTestEntity(){
testService.create("jyujyu", 20);
}
*/
@PostMapping("/test/entity/create")
public void createTestEntity(
@RequestBody CreateTestEntityRequest request
){
testService.create(request.getName(), request.getAge());
}
@AllArgsConstructor
@Getter
public static class CreateTestEntityRequest{
private final String name;
private final Integer age;
}
}
앞에서는 GET 요청을 통해 레포지토리에 데이터를 저장하는 서비스를 호출하는 코드를 작성했지만, 이번에는 POST 요청을 사용하여 데이터를 저장하는 방법을 구현해보았다.
이전 코드에서는 서버로부터 별도의 데이터 입력 없이 미리 지정된 값을 사용하여 데이터를 저장했다. 그러나 POST 요청을 사용하면 클라이언트가 JSON 형태로 데이터를 직접 전달할 수 있으며, 서버는 이 데이터를 받아 데이터베이스에 저장할 수 있다.
새로 작성된 코드는 클라이언트로부터 이름과 나이를 JSON 형태로 받아, 이를 서비스 계층의 create 메서드에 전달한다.
이를 위해 @RequestBody 애노테이션을 사용하여 요청 본문에 포함된 데이터를 CreateTestEntityRequest 객체로 매핑하고, 이 객체를 통해 전달된 값을 기반으로 새로운 엔티티를 생성하여 레포지토리에 저장한다.
{
"name": "backend",
"age": 20
}
Postman을 사용하여 PostMapping을 통해 JSON 문서로 name 필드에 "backend", age 필드에 20이 들어가도록 요청을 보냈다.
이를 H2 데이터베이스에 들어가 잘 데이터가 들어갔는지 확인해보았다.
name 필드에 "backend", age필드에 20이 잘 들어갔음을 확인할 수 있다.
Service코드에
public void delete(Long id){
TestEntity testEntity = testRepository.findById(id).get();
testRepository.delete(testEntity);
}
코드를 추가한다.
이는 서비스 계층에서 레포지토리를 통해 데이터베이스에 접근하여, 특정 엔터티를 삭제하도록 하는 코드이다.
그런 다음, API 코드에도 DeleteMapping을 추가했다.
@DeleteMapping("/test/entity/{id}")
public void deleteTestEntity(
@PathVariable Long id
){
testService.delete(id);
}
Postman을 사용하여 PostMapping을 통해 JSON 문서로 name 필드에 "backend", age 필드에 20이 들어가도록 요청을 보냈다.
이렇게 데이터가 잘 저장된 것을 확인할 수 있다.
이제 추가한 delete 코드를 테스트하기 위해, Postman에서 DeleteMapping을 사용하여 ID가 1번인 값을 삭제하도록 요청했다.
id가 1번인 값을 지우도록 요청을 보냈다.
그런 다음, h2 데이터베이스에 들어가 확인해 보면
이렇게 아이디가 1인 엔터티가 성공적으로 삭제되었음을 확인할 수 있다.
public void update(Long id, String name, Integer age){
TestEntity testEntity = testRepository.findById(id).orElseThrow(); //orElseThrow()는 아이디가 없을 경우 예외처리
testEntity.changeNameAndAge(name, age);
testRepository.save(testEntity);
}
Service 클래스에 id와 name값을 업데이트 해주는 코드를 추가해준다.
아이디를 받아와서 없을 경우에는 에러 처리를 해주고,
아이디가 있을 경우에는 엔터티의 이름과 나이를 변경해주는 코드이다.
그리고 이 변경된 엔터티를 다시 저장한다.
다음으로, 엔터티 클래스에 들어가 아래와 같은 메서드를 추가해준다.
public void changeNameAndAge(String name, Integer age){
this.name = name;
this.age = age;
}
이 메서드는 엔터티의 name과 age 필드를 수정하는 역할을 한다.
이제 이 기능을 구현하기 위해 API 클래스에 PutMapping 메서드를 추가해준다.
Api 클래스에
@PutMapping("/test/entity/{id}")
public void putTestEntity(
@PathVariable Long id,
@RequestBody CreateTestEntityRequest request
){
testService.update(id, request.getName(), request.getAge());
}
이 코드는 생성할 때 사용했던 request body와 path variable을 동시에 사용하는 방식으로, 클라이언트가 수정할 엔터티의 ID와 함께 새로 업데이트할 이름과 나이를 전달할 수 있다.
다시 postman에 들어가 entity를 생성해준 후, h2 콘솔에 들어가
데이터가 잘 들어간 것을 확인한다.
그런 다음 이것을 수정하기 위해
postman에 들어가 put 요청으로 url에
바꿀 엔터티의 Id값인 1을 적고,
body는 바꾸고 싶은 name과 age필드의 값을 JSON 형식으로 작성하여 보낸다.
200 OK가 뜬 것을 확인한 후,
H2 데이터베이스에 들어가 확인하면
이렇게 NAME과 AGE가 성공적으로 바뀐 것을 확인할 수 있다.