1. 프로젝트 생성
2. 스프링부트 버전과 dependency 추가
3. 빌드가 성공하면 먼저 src > main > resources > application.properties(스프링 환경 설정 파일)에 h2 설정 추가
spring.h2.console.enabled=true
spring.datasource.url=jdbc:h2:mem:db;MODE=MYSQL;
spring.datasource.username=sa
spring.datasource.password=
4. 스프링 구조에 맞게 패키지를 나눠서 5개 생성
5. DB로 생성할 Entity Class 작성
① 메모 Entity (작성한 글들이 저장될) : Class
package com.example.memopractice.entity;
import lombok.Getter;
import lombok.NoArgsConstructor;
import javax.persistence.*;
@Getter // Class 모든 필드의 Getter method를 생성
@Entity // Entity임을 선언
@NoArgsConstructor // @NoArgsConstructor : 파라미터가 없는 기본 생성자를 생성
public class Memo extends Timestamped { // 시간 값을 가져오기 위해 Timestamped 상속
@Id // ID임을 선언
@GeneratedValue(strategy = GenerationType.AUTO) // 값 자동 생성 , 생성 전략 : 자동 증감
private Long id;
@Column(nullable = false) // 컬럼 설정 , null값 허용 선택 : 불가
private String title;
@Column(nullable = false)
private String author;
@Column(nullable = false)
private String contents;
@Column(nullable = false)
private String password;
}
+ @Entity 어노테이션 위에 Entity값을 받을 수 있게 @Getter와 기본 생성자를 생성해주는 @NoArgsConstructor을 추가
② Timestamped Entity (작성된 시간, 수정된 시간을 추적할, 공용적인 Entity라 별도로 나누고 상속) : Class
package com.example.memopractice.entity;
import lombok.Getter;
import org.springframework.data.annotation.*;
import org.springframework.data.jpa.domain.support.AuditingEntityListener;
import javax.persistence.*;
import java.time.LocalDateTime;
// @EntityListeners : 삽입, 삭제, 수정, 조회 등의 작업을 할 때 전, 후에 어떠한 작업을 하기 위해 이벤트 처리를 위한 어노테이션
@EntityListeners(AuditingEntityListener.class) // AuditingEntityListener.class : Audit(감시하다) 옵션은 시간에 대해서 자동으로 값을 넣어 주는 기능
@MappedSuperclass // 공통 매핑 정보가 필요할 때, 부모클래스에 선언하고 속성만 상속 받아서 사용 하고 싶을때 사용
@Getter // Class 모든 필드의 Getter method를 생성
public class Timestamped {
@CreatedDate // 생성된 시간 정보
private LocalDateTime createdAt;
@LastModifiedDate // 수정된 시간 정보
private LocalDateTime modifiedAt;
}
6. DB를 생성시켜주고 사용할 메소드를 정의하는 Repository를 생성 : Interface
package com.example.memopractice.repository;
import com.example.memopractice.entity.Memo;
import org.springframework.data.jpa.repository.JpaRepository;
public interface MemoRepository extends JpaRepository <Memo, Long>{
}
7. 일단 여기까지 작성하고 실행해주면 h2-console을 이용해 테이블이 생성된 걸 확인할 수 있다.
8. DTO를 생성한다.
API 명세서를 생각하면서 RequestDto와 ResponseDto, 그리고 Result만 내보낼 ResultDto를 각각 생성
① RequestDto : 요청을 받아올 Dto
package com.example.memopractice.dto;
import lombok.Getter;
@Getter
public class RequestDto {
private String title;
private String author;
private String contents;
private String password;
}
② ResponseDto : 응답으로 글 작성 정보를 내려줄 Dto, 생성시 값을 넣을 수 있게 생성자 작성
package com.example.memopractice.dto;
import com.example.memopractice.entity.Memo;
import lombok.Getter;
import java.time.LocalDateTime;
@Getter
public class ResponseDto {
private Long id;
private String title;
private String author;
private String contents;
private LocalDateTime createdAt;
private LocalDateTime modifiedAt;
// password는 Reponse에 노출하지 않는다.
// Entity -> DTO로 변환 : Entity를 그대로 밖으로 내보내면 안되기 때문에 DTO로 데이터를 필터링하고 필요한 부분만 정리하여 DTO로 내보낸다.
public ResponseDto(Memo memo){
this.id = memo.getId();
this.title = memo.getTitle();
this.author = memo.getAuthor();
this.contents = memo.getContents();
this.createdAt = memo.getCreatedAt();
this.modifiedAt = memo.getModifiedAt();
}
}
③ ResultDto : 응답으로 성공여부를 내려줄 Dto, 생성시 값을 넣을 수 있게 생성자 작성
package com.example.memopractice.dto;
import lombok.Getter;
@Getter
public class ResultDto {
private boolean success;
public ResultDto(boolean result){ // 외부에서 값을 받아와 적용시키기 위해 매개값 생성자
this.success = result;
}
}
9. 요청을 받을 Controller를 생성한다.
요청에 따른 URL을 각각 나누고 서비스를 연결해줄 준비를 한다.
URL등 RESTful 하게 만들수 있도록 신경쓰자
package com.example.memopractice.controller;
import com.example.memopractice.dto.*;
import com.example.memopractice.service.MemoService;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.*;
import java.util.List;
@RestController // @ResponseBody 어노이테이션을 따로 쓰지 않기 위해 @ResponseBody + @Controller인 @RestController 사용
@RequiredArgsConstructor // final변수나 Notnull 표시가된 변수등 필수적인 정보를 세팅하는 생성자를 생성 어노테티션
public class MemoController {
// Controller은 Client에 가장 맞닿아 있어 DB랑 가까운 Entity가 나오지 않게 분리 , Service에서 리팩토링해서 controller로 내보내라
private final MemoService service; // 서비스를 연결 = 주입한다고 표현 DI (dependency Injection)
@GetMapping("/api/memos") // Get방식
public List<ResponseDto> getMemos(){ // 여러 Dto를 List로 Client에 보내기
return service.getMemo();
}
@GetMapping("/api/memos/{id}") // PUT방식
public ResponseDto getMemo(@PathVariable Long id){ // 하나의 Dto를 Client에 보내기
return service.getMemo(id);
}
@PostMapping("/api/memos") // POST방식
public ResponseDto createMemo(@RequestBody RequestDto dto){ // 들어오는건 Request 나가는건 Response로 각각 달리 할 수 있게 함
return service.createMemo(dto);
}
@PutMapping("/api/memos/{id}") // PUT방식
public ResponseDto updateMemo(@PathVariable Long id, @RequestBody RequestDto dto){ // 경로에서 id값 꺼내기. Body에서 값 꺼내기
return service.updateMemo(id, dto);
}
@DeleteMapping("/api/memos/{id}") // Delete방식
public ResultDto deleteMemo(@PathVariable Long id, @RequestBody RequestDto dto){
return service.deleteMemo(id, dto);
}
}
10. Service를 생성한다.
package com.example.memopractice.service;
import com.example.memopractice.dto.*;
import com.example.memopractice.entity.Memo;
import com.example.memopractice.repository.MemoRepository;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.*;
import java.util.ArrayList;
import java.util.List;
@Service // Service임을 선언
@RequiredArgsConstructor // 필수적인 정보를 세팅하는 생성자를 생성 어노테이션
public class MemoService {
private final MemoRepository repository; // Repository 주입
public List<ResponseDto> getMemo() {
List<Memo> memos = repository.findAllByOrderByModifiedAtDesc(); // 10-1 참조 : Repository에 검색 관련 메소드를 정의해야함
// 10-2 참조 : Memo Entity에 Dto값을 받아 객체를 생성할 수 있도록 추가
List<ResponseDto> exportDtoList = new ArrayList<>();
for(Memo memo : memos){ // Entity -> Dto로 변환
ResponseDto tempDto = new ResponseDto(memo);
exportDtoList.add(tempDto);
}
return exportDtoList;
}
public ResponseDto getMemo(Long id) {
Memo memo = repository.findById(id).orElseThrow(()-> new IllegalArgumentException("글이 없어요!")); // 검색결과가 없으면 발생하는 예외를 처리
return new ResponseDto(memo); // Entity -> Dto로 변환
}
public ResponseDto createMemo(RequestDto dto) {
Memo memo = new Memo(dto);
repository.save(memo);
return new ResponseDto(memo);
}
@Transactional
public ResponseDto updateMemo(Long id, RequestDto dto) {
Memo memo = repository.findById(id).orElseThrow(()-> new NullPointerException("글이 없습니다!"));
if(memo.getPassword().equals(dto.getPassword())){
memo.updateMemo(dto); // 10-3 Entity 사항을 업데이트하는 메소드 추가
// repository.save(memo); // @Transactional 어노테이션을 쓰면 이건 생략, 어노테이션을 사용안하려면 이걸 추가
return new ResponseDto(memo);
} else {
throw new IllegalArgumentException("비밀번호가 다릅니다");
}
}
public ResultDto deleteMemo(Long id, RequestDto dto) {
Memo memo = repository.findById(id).orElseThrow(()-> new IllegalArgumentException("글을 찾을 수 없습니다."));
if(memo.getPassword().equals(dto.getPassword())){
repository.delete(memo);
return new ResultDto(true);
} else {
return new ResultDto(false);
}
}
}
10-1. Repository에 검색 관련 메소드 정의
public interface MemoRepository extends JpaRepository <Memo, Long>{
// 결과 필터링을 정의하고 출력할 타입을 정의하는 계층
//추가부분
List<Memo> findAllByOrderByModifiedAtDesc(); // findAllBy(모두찾는다)/OrderBy(-를 기준으로 정렬로)/ModifiedAt(ModifiedAt멤버변수를)/Desc(내림차순)
}
10-2. Memo Entity에 Dto값을 받아 객체를 생성할 수 있도록 "생성자" 추가
public Memo (RequestDto dto){ // 10-2 매개값 받는 생성자 추가
this.title = dto.getTitle();
this.author = dto.getAuthor();
this.contents = dto.getContents();
this.password = dto.getPassword();
}
10-3. Memo Entity에 Dto값을 받아 객체를 수정할 수 있도록 "메소드" 추가
public void updateMemo(RequestDto dto){
this.title = dto.getTitle();
this.author = dto.getAuthor();
this.contents = dto.getContents();
// this.password = dto.getPassword(); // password도 바꾼다면 포함
}
11. 시간 추적 기능을 사용하려면 실행 클래스에 @EnableJpaAuditing 어노테이션을 추가한다.
package com.example.memopractice;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.data.jpa.repository.config.EnableJpaAuditing;
@EnableJpaAuditing // <--- 이걸 추가
@SpringBootApplication
public class MemoPracticeApplication {
public static void main(String[] args) {
SpringApplication.run(MemoPracticeApplication.class, args);
}
}
12. 구현을 완료했다면 테스트는 Postman으로 진행
아래 6가지 사항을 맞춰 각각 요청을 테스트
① method 방식 선택
② URL
③ Request 방식
④ json 문자열 형태로 그대로 값을 전달하고 싶으면 raw선택
⑤ raw 중에도 방식 중 JSON을 선택
⑥ 필요한 정보를 key갑과 value값에 맞춰 기입
그리고 send하면 아래에 Response가 출력된다.
13. DB 변경도 확인
'Experience > 항해99' 카테고리의 다른 글
본수업 22일차 / 스프링 숙련 주차 : 개인 과제 질문편 (0) | 2022.12.08 |
---|---|
본수업 22일차 / 스프링 숙련 주차 시험 (0) | 2022.12.08 |
021 - 본수업 15일차 / 스프링 입문 주차 : 개인 과제 질문편 (2) | 2022.11.30 |
018 - 본수업 12일차 / Spring JPA (Java Persistence API) (1) | 2022.11.26 |
017 - 본수업 11일차 / 1-2 SpringBoot 및 서버 이해 (0) | 2022.11.25 |