Response을 커스텀하는 이유 -> 기존에 쓰던 ResponeEntity클래스를 통해 리턴해주면 형식을 수정할 수 없음
예외처리 하기
Advice : Exception을 관리하는 중앙관리소
Exception : 예외처리를 위해 우리가 커스텀으로 만드는 Exception
예외처리를 하는 이유 -> 명확한 오류의 이유를 알려주기 위함
패키지 entity - 클래스 Board
package com.example.mentoring.entity;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
@Data //Getter+Setter
@NoArgsConstructor //빈생성자
@AllArgsConstructor //모든 인스턴스를 받는 생성자
@Entity //Board가 Entity인 것을 명시해준다.
public class Board {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY) //인스턴스를 생성하면, 자동으로 인덱스를 붙여라
private long id;
private String title;
private String content;
private String writer;
}
패키지 repository - 인터페이스 BoardRepository
package com.example.mentoring.repository;
import com.example.mentoring.entity.Board;
import org.springframework.data.jpa.repository.JpaRepository;
public interface BoardRepository extends JpaRepository<Board,Long> {
}
패키지 controller - 클래스 BoardController
package com.example.mentoring.controller;
import com.example.mentoring.entity.Board;
import com.example.mentoring.response.Response;
import com.example.mentoring.service.BoardService;
import lombok.RequiredArgsConstructor;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.*;
@RequiredArgsConstructor
@RestController
public class BoardController {
private final BoardService boardService;
//전체 게시물 조회
@ResponseStatus(HttpStatus.OK)
@GetMapping("/boards")
public Response getBoards(){
return Response.success(boardService.getBoards());
}
//단건 게시글 조회
@ResponseStatus(HttpStatus.OK)
@GetMapping("/boards/{id}")
public Response getBoard(@PathVariable ("id") Long id){
return Response.success(boardService.getBoard(id));
}
// HttpStatus.OK == 200, HttpStatus.CREATED == 201
// POST 게시글 작성
// 매개변수로 게시글이 들어온다 -> 들어온 게시글을 데이터베이스에 저장해준다.
// @RequestBody 를 붙이는 이유 -> JSON 타입으로 데이터가 들어오는데, 이걸 자바에서 인식할 수 있게, 자바 클래스로 매핑 시켜준다.
// REST API -> JSON 형식으로 데이터를 받아야한다.
// @RequestBody Entity entity -> JSON 형식인 데이터를, 자바 타입으로 바꿔준다.
@ResponseStatus(HttpStatus.CREATED)
@PostMapping("/boards")
public Response save(@RequestBody Board board){
return Response.success(boardService.save(board));
}
//게시글 수정
@ResponseStatus(HttpStatus.OK)
@PutMapping("/boards/{id}")
public Response editBoard(@PathVariable ("id") Long id, Board updateBoard){
return Response.success(boardService.editBoard(id,updateBoard));
}
//게시글 삭제
@ResponseStatus(HttpStatus.OK)
@DeleteMapping("boards/{id}")
public Response deleteBoard(@PathVariable ("id") Long id){
boardService.deleteBoard(id);
return Response.success("삭제 완료");
}
}
패키지 service - 클래스 BoardService
package com.example.mentoring.service;
import com.example.mentoring.entity.Board;
import com.example.mentoring.exception.BoardNotFoundException;
import com.example.mentoring.exception.WriterNotFoundException;
import com.example.mentoring.repository.BoardRepository;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.List;
@RequiredArgsConstructor
@Service
public class BoardService {
private final BoardRepository boardRepository;
@Transactional(readOnly = true)
public List<Board> getBoards() {
return boardRepository.findAll();
}
@Transactional(readOnly = true)
public Board getBoard(Long id) {
Board board = boardRepository.findById(id).orElseThrow(BoardNotFoundException::new);
return board;
}
@Transactional
public Board save(Board board) {
// 작성자가 없을 때 예외 터뜨려보기
if(board.getWriter().equals(" ")) {
throw new WriterNotFoundException();
}
return boardRepository.save(board);
}
@Transactional
// Transactional 을 붙이면 더티체킹이 일어나서, 저장하지 않아도 메서드가 성공적으로 끝나면 저장이 된다.
public Board editBoard(Long id, Board update){
//기존 게시물을 꺼내온다.
Board board = boardRepository.findById(id).get();
//기존 게시물에, updateBoard 정보를 덮어씌어준다.
board.setTitle(update.getTitle());
board.setContent(update.getContent());
return board;
}
@Transactional
public void deleteBoard(Long id){
boardRepository.deleteById(id);
}
}
패키지 advice - 클래스 ExceptionAdvice
package com.example.mentoring.advice;
import com.example.mentoring.exception.BoardNotFoundException;
import com.example.mentoring.exception.WriterNotFoundException;
import com.example.mentoring.response.Response;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestControllerAdvice;
@RestControllerAdvice // @RestController + @Advice
public class ExceptionAdvice {
// ExceptionAdvice == Exception을 관리하는 통제소 == 실패한 경우 실패 메시지를 리턴해주기 위한 RestController
// 404 NotFound 에러
@ExceptionHandler(BoardNotFoundException.class)
@ResponseStatus(HttpStatus.NOT_FOUND)
public Response boardNotFoundException() {
return Response.failure(404, "게시글을 찾을 수 없습니다.");
}
// 404 NotFound
@ExceptionHandler(WriterNotFoundException.class)
@ResponseStatus(HttpStatus.NOT_FOUND)
public Response writerNotFoundException() {
return Response.failure(404, "작성자를 입력해주세요.");
}
}
패키지 exception - 클래스 BoardNotFoundException, 클래스 WriterNotFoundException
package com.example.mentoring.exception;
public class BoardNotFoundException extends RuntimeException{
}
package com.example.mentoring.exception;
public class WriterNotFoundException extends RuntimeException{
}
패키지 response - 클래스 Failure, 클래스 Response, 인터페이스 Result, 클래스 Success
package com.example.mentoring.response;
import lombok.AllArgsConstructor;
import lombok.Getter;
@Getter
@AllArgsConstructor
public class Failure implements Result{
private String msg;
}
package com.example.mentoring.response;
import com.fasterxml.jackson.annotation.JsonInclude;
import lombok.AccessLevel;
import lombok.AllArgsConstructor;
import lombok.Getter;
@JsonInclude(JsonInclude.Include.NON_NULL)
@AllArgsConstructor(access = AccessLevel.PRIVATE)
@Getter
public class Response {
private boolean success;
private int code;
private Result result;
public static Response success() {
// 데이터가 없이 성공 반환해주는 경우
return new Response(true, 0, null);
}
public static <T> Response success(T data) {
// 데이터를 포함해서 성공 반환해주는 경우
return new Response(true, 0, new Success<>(data));
}
public static Response failure(int code, String msg) {
// 에러 발생시 반환해주는 경우
return new Response(false, code, new Failure(msg));
}
}
package com.example.mentoring.response;
interface Result{
}
package com.example.mentoring.response;
import com.fasterxml.jackson.annotation.JsonInclude;
import lombok.AllArgsConstructor;
import lombok.Getter;
@JsonInclude(JsonInclude.Include.NON_NULL) // null 값을 가지는 필드는, JSON 응답에 포함되지 않음
@Getter
@AllArgsConstructor
public class Success<T> implements Result {
private T data;
}
'활동' 카테고리의 다른 글
우아한테크코스 5기 - 2주차 후기 (0) | 2022.11.08 |
---|---|
교내 SW 프로그램 경진 대회 수상 및 후기 (1) | 2022.11.04 |
우아한테크코스 5기 - 1주차 후기 (2) | 2022.10.31 |
우아한테크코스5기 - 프리코스 시작전 다짐 (0) | 2022.10.26 |
[멘토링]스프링 CRUD게시판 만들기 (0) | 2022.07.18 |