πŸ“‹ 읡λͺ…κ²Œμ‹œνŒ μ œμž‘

jijiΒ·2023λ…„ 11μ›” 2일
0

Spring Boot Project 🌱

λͺ©λ‘ 보기
5/16

πŸ‘©πŸ»β€πŸ¦° 읡λͺ…κ²Œμ‹œνŒ μ œμž‘. νšŒμ›κ°€μž…, 둜그인 κΈ°λŠ₯은 ν•„μš” μ—†μŒ!

βœ” λͺ©ν‘œ

  • κ²Œμ‹œκΈ€ μž‘μ„± κΈ°λŠ₯ βœ”
    • κ²Œμ‹œκΈ€ ꡬ성 : 제λͺ©, λ‚΄μš© βœ”
    • κ²Œμ‹œκΈ€ μ €μž₯ μ‹œ, id(PK)λ₯Ό Auto-increment ν˜•μ‹μœΌλ‘œ μ €μž₯ βœ”
    • μž‘μ„± 성곡 μ‹œ, μ‘λ‹΅κ°’μœΌλ‘œ μž‘μ„±λœ κ²Œμ‹œκΈ€μ— λŒ€ν•œ 정보 λ°˜ν™˜ βœ”
  • κ²Œμ‹œκΈ€ 전체 쑰회 κΈ°λŠ₯ βœ”
    • id, 제λͺ©, λ‚΄μš© 포함 βœ”
  • νŠΉμ • κ²Œμ‹œκΈ€ 쑰회, μˆ˜μ •, μ‚­μ œ κΈ°λŠ₯ βœ”
    • idλ₯Ό 톡해 μˆ˜ν–‰ βœ”
    • μˆ˜μ • 성곡 μ‹œ, κ²Œμ‹œκΈ€ 정보 λ°˜ν™˜ βœ”

πŸ“Œ 배운점

  • REST API κ·œμΉ™μ„ 지킀며 μ„€κ³„ν•˜κΈ°
    • URL 경둜 및 HTTP λ©”μ„œλ“œ 기반 μš”μ²­ λΌμš°νŒ…
    • Request Body, Query Params, Path Params μ‚¬μš©
  • postman : μš”μ²­λΆ€ν„° μ‘λ‹΅κΉŒμ§€ 전체 과정을 κ²½ν—˜
    • [POST] μ‹œ "status": 406, "error": "Not Acceptable"
      μ—λŸ¬ 원인 : DTO에 @ToString λΆ€μž¬λ‘œ Json파일 λ°˜ν™˜ μ‹œ μ£Όμ†Œ 값이 λ°˜ν™˜λΌμ„œ λ°œμƒ. ➑ DTO에 @DATA μΆ”κ°€
  • JPA의 ORM(객체-RDB Mapping)에 λŒ€ν•œ 이해
  • HTTP μƒνƒœμ½”λ“œμ— λŒ€ν•œ 이해
  • @annotation에 λŒ€ν•œ 이해

πŸ’‘ λΌμš°νŒ…

  • μ›Ή μ• ν”Œλ¦¬μΌ€μ΄μ…˜μ—μ„œ ν΄λΌμ΄μ–ΈνŠΈ μš”μ²­μ„ μ μ ˆν•œ ν•Έλ“€λŸ¬ λ˜λŠ” 컨트둀러둜 μ „μ†‘ν•˜λŠ” ν”„λ‘œμ„ΈμŠ€
  • URLκ³Ό HTTP λ©”μ„œλ“œλ₯Ό 기반으둜 μš”μ²­μ„ μ²˜λ¦¬ν•˜κ³ , μ• ν”Œλ¦¬μΌ€μ΄μ…˜ λ‚΄μ—μ„œ μ μ ˆν•œ λ™μž‘μ„ μˆ˜ν–‰

πŸ‘©πŸ»β€πŸ’» 개발 κ³Όμ •

1. 데이터 λͺ¨λΈ 클래슀 생성

@Setter
@Getter
@ToString
@NoArgsConstructor
@AllArgsConstructor
@EqualsAndHashCode(of = "postId", callSuper = false)
@Builder

@Entity
@Table(name = "tbl_post")
public class Post {
  @Id
  @GeneratedValue(strategy = GenerationType.IDENTITY)
  private Long id;
  @Column(name = "title", nullable = false)
  private String title;
  @Column(name = "content", nullable = false)
  private String content;
}

@Data 의 SetterλŠ” κ·Έ μ˜λ„κ°€ λΆ„λͺ…ν•˜μ§€ μ•Šκ³  객체λ₯Ό μ–Έμ œλ“ μ§€ λ³€κ²½ν•  수 μžˆλŠ” μƒνƒœκ°€ λ˜μ–΄μ„œ 객체의 μ•ˆμ „μ„±μ΄ 보μž₯λ°›κΈ° νž˜λ“€λ‹€.

2. Repository μΈν„°νŽ˜μ΄μŠ€ 생성

public interface BoardRepository extends JpaRepository<Post, Long> {}

JpaRepository

save(S entity) μ €μž₯ or μ—…λ°μ΄νŠΈ
findById(ID id): ID κ°’μœΌλ‘œ 검색
existsById(ID id) ID 값에 ν•΄λ‹Ήν•˜λŠ” 데이터가 μ‘΄μž¬ν•˜λŠ”μ§€ μ—¬λΆ€
findAll()λͺ¨λ“  μ—”ν‹°ν‹°λ₯Ό 검색
count() μ €μž₯된 μ—”ν‹°ν‹°μ˜ 총 수
deleteById(ID id)μ§€μ •λœ ID κ°’ μ‚­μ œ
delete(T entity): μ§€μ •λœ μ—”ν‹°ν‹°λ₯Ό μ‚­μ œ
deleteAll()λͺ¨λ“  μ—”ν‹°ν‹°λ₯Ό μ‚­μ œ

  • Spring Data JPA ν”„λ ˆμž„μ›Œν¬μ—μ„œ μ œκ³΅ν•˜λŠ” μΈν„°νŽ˜μ΄μŠ€, λ°μ΄ν„°λ² μ΄μŠ€μ™€ μƒν˜Έμž‘μš©
  • 기본적인 CRUD(Create, Read, Update, Delete) μž‘μ—…μ„ κ°„μ†Œν™”ν•˜κ³  μΆ”μƒν™”ν•˜λŠ” κΈ°λŠ₯ 제곡

3. κ²Œμ‹œκΈ€ μž‘μ„±

1. Controller 클래슀 생성

  1. ν΄λΌμ΄μ–ΈνŠΈλ‘œλΆ€ν„° HTTP μš”μ²­μ„ λ°›λŠ”λ‹€.
  2. Serviceλ₯Ό 톡해 κ²Œμ‹œκΈ€μ„ μž‘μ„±ν•˜κ³  ν΄λΌμ΄μ–ΈνŠΈμ— 응닡을 λ°˜ν™˜ν•œλ‹€.
@RestController
@RequiredArgsConstructor
@RequestMapping("/api/anonymous")
public class BoardController {
  private final BoardService boardService;

  // κ²Œμ‹œκΈ€ μž‘μ„±
  @PostMapping
  public ResponseEntity<PostResponseDTO> createPost(@RequestBody final Post requestPost) {
    PostResponseDTO dto = boardService.savePost(requestPost);
    return ResponseEntity.ok(dto);
  }

final

  • μ•ˆμ •μ„± : λ§€κ°œλ³€μˆ˜λ₯Ό final 둜 μ„ μ–Έν•˜μ—¬ μ•ˆμ •μ„±μ„ λ†’μž…λ‹ˆλ‹€. μ‹€μˆ˜λ‘œ 값을 μž¬ν• λ‹Ήν•˜κ±°λ‚˜ μˆ˜μ •ν•˜λŠ” 것을 λ°©μ§€ν•©λ‹ˆλ‹€.
  • 가독성 : λ©”μ„œλ“œλ‚˜ λΈ”λ‘λ‚΄μ—μ„œ λ³€κ²½λ˜μ§€ μ•ŠλŠ”λ‹€λŠ” 것을 λͺ…μ‹œμ μœΌλ‘œ λ‚˜νƒ€λƒ…λ‹ˆλ‹€.
  • μŠ€λ ˆλ“œ μ•ˆμ •μ„± : final둜 μ„ μ–Έλœ λ§€κ°œλ³€μˆ˜λŠ” λ‹€λ₯Έ μŠ€λ ˆλ“œμ—μ„œ λ§€κ°œλ³€μˆ˜λ₯Ό μˆ˜μ •ν•˜λ €κ³  μ‹œλ„ν•  수 μ—†μœΌλ―€λ‘œ μŠ€λ ˆλ“œ κ°„ μΆ©λŒμ„ λ°©μ§€ν•©λ‹ˆλ‹€.

2. Service

μ»¨νŠΈλ‘€λŸ¬λ‘œλΆ€ν„° 받은 μš”μ²­μ„ μ²˜λ¦¬ν•˜κ³ , ν•„μš”ν•œ λ°μ΄ν„°λ² μ΄μŠ€ μž‘μ—…μ„ μˆ˜ν–‰ν•˜μ—¬ 응닡을 μƒμ„±ν•˜λŠ” 쀑간 계측 μ—­ν• 

  1. CrudRepositoryλ₯Ό 상속 받은 BoardRepository의 .save()λ₯Ό 톡해 κ²Œμ‹œκΈ€ 정보λ₯Ό DB에 μ €μž₯ν•œλ‹€.
  2. PostResponseDTO둜 λ³€ν™˜ν•˜μ—¬ κ²°κ³Όλ₯Ό λ°˜ν™˜ν•œλ‹€.
@Service
@RequiredArgsConstructor
public class BoardService {
  private final BoardRepository boardRepository;

  public PostResponseDTO savePost(final Post post) {
    return new PostResponseDTO(boardRepository.save(post));
  }
}
  • DTO
    public PostResponseDTO(Post post) {
      this.id = post.getId();
      this.title = post.getTitle();
      this.content = post.getContent();
    }

4. κ²Œμ‹œκΈ€ 전체 쑰회

  • 리슀트둜 λ°˜ν™˜ : .stream.map.collect(Collectors.toList());
// Controller
  @GetMapping
  public ResponseEntity<List<PostResponseDTO>> getPostAll(){
    List<PostResponseDTO> allPostDto = boardService.findAllPost();
    return ResponseEntity.ok(allPostDto);
  }
  
// Service
  public List<PostResponseDTO> findAllPost(){
    List<Post> posts = boardRepository.findAll();
    return posts.stream()
            .map(post -> new PostResponseDTO(post))
            .collect(Collectors.toList());
  }

5. νŠΉμ • κ²Œμ‹œκΈ€ (orElseThrow)

1) 쑰회

  • ?id=1 쿼리λ₯Ό 톡해 받을 경우
    : @GetMapping(params = "postId") κ³Ό @RequestParam
// Controller
  @GetMapping(params = "id")
  public ResponseEntity<PostResponseDTO> getPostsById(@RequestParam("id") final Long postId){
    PostResponseDTO postDto = boardService.findPostById(postId);
    return ResponseEntity.ok(postDto);
  }

  • Optional type λ³€ν™˜ ν•˜κΈ°
    .orElseThrow(() -> new NoSuchElementException("Post not found"));
// Service
  public PostResponseDTO findById(Long postId){
    return new PostResponseDTO(returnPost(postId));
  }

  private Post returnPost(Long postId) {
    return boardRepository.findById(postId)
       .orElseThrow(() -> new NoSuchElementException("Post not found"));
  }

2) μˆ˜μ •

  • URL 경둜 : /api/anonymous/1
  • μˆ˜μ • ν•  λ‚΄μš© : HTTP μš”μ²­μ˜ 본문을 POST둜 맀핑
  @PutMapping("/{postId}")
  public ResponseEntity<PostDTO> updatePost(
      @PathVariable final Long postId,
      @RequestBody final PostUpdateDTO updatedPost) {
    log.info("update post by id - controller : id = "+postId);
    log.info("update post content - controller : content = "+updatedPost.toString());

    PostDTO postDto = boardService.update(postId, updatedPost);
    return ResponseEntity.ok(postDto);
  }
  public PostDTO update(Long postId, PostUpdateDTO updatedPost) {
    Post post = returnPost(postId);
    post.setTitle(updatedPost.getTitle());
    post.setContent(updatedPost.getContent());
    return new PostDTO(post);
  }

3) μ‚­μ œ

  @DeleteMapping("/{postId}")
  public ResponseEntity<Boolean> deletePost(@PathVariable final Long postId) {
    boolean isDeleted = boardService.deletePost(postId);
    return ResponseEntity.ok(isDeleted);
  }
---  
  public boolean deletePost(Long postId) {
    try {
      boardRepository.deleteById(postId);
      return true; // μ‚­μ œ 성곡 μ‹œ true λ°˜ν™˜
    } catch (EmptyResultDataAccessException e) {
      // ν•΄λ‹Ή ID의 κ²Œμ‹œκΈ€μ΄ 이미 μ‚­μ œλœ 경우
      return false; // μ‚­μ œ μ‹€νŒ¨ μ‹œ false λ°˜ν™˜
    }
  }

0개의 λŒ“κΈ€