1.요청은 JSON 으로 통일, 응답도 JSON 으로 통일
2.POST, PUT 요청은 추가된 ROW 혹은 수정된 ROW 를 응답해줘야 한다. 그래야 PK 를 알 수 있다. 인서트 업데이트된 데이터가 있어야 프론트가 알 수 있다.
3. 화면에 필요한 데이터만 전달해야 한다. 그래서 DTO 가 필요하다. → DTO 를 만드는 책임은 서비스가 갖는다. 서비스에서 DTO 를 만들면 커넥션 시간이 줄어든다.
1. 요청 BODY 수정
💡
요청 BODY에 @RequestBody 어노테이션 붙이기
Post 와 Put 매핑에 붙인다.
@PutMapping("/api/users/{id}")
public String update(@RequestBody UserRequest.UpdateDTO requestDTO){
User sessionUser = (User) session.getAttribute("sessionUser");
User user = userService.회원조회(sessionUser.getId(),requestDTO);
session.setAttribute("sessionUser",user);
return "redirect:/";
}
2. 응답 BODY 수정
💡
응답은 ReposnseEntity.ok(new ApiUtil()) 를 사용한다.
@RestController
public class UserController {
private final UserService userService;
private final HttpSession session;
@PutMapping("/api/users/{id}") //회원 수정은 세션 id 를 받기 때문에 주소에 id가 필요없다. 하지만 프론트 입장에선 필요하다. 또 관리자가 수정을 해야한다면 구분이 필요하다.
public ResponseEntity<?> update(@RequestBody @PathVariable Integer id, UserRequest.UpdateDTO requestDTO){
User sessionUser = (User) session.getAttribute("sessionUser");
User newSessionUser = userService.회원조회(sessionUser.getId(),requestDTO);
session.setAttribute("sessionUser",newSessionUser);
return ResponseEntity.ok(new ApiUtil(newSessionUser));
}
}
UserController
package shop.mtcoding.blog.user;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpSession;
import lombok.RequiredArgsConstructor;
import org.springframework.dao.DataIntegrityViolationException;
import org.springframework.dao.EmptyResultDataAccessException;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;
import shop.mtcoding.blog._core.errors.exception.Exception400;
import shop.mtcoding.blog._core.errors.exception.Exception401;
import shop.mtcoding.blog._core.utils.ApiUtil;
@RequiredArgsConstructor
@RestController
public class UserController {
private final UserService userService;
private final HttpSession session;
// TODO: 회원정보 조회 API 필요 -> @GetMapping("/api/users/{id}")
@GetMapping("/api/users/{id}")
public ResponseEntity<?> userinfo(@PathVariable Integer id){
User user = userService.회원조회(id);
return ResponseEntity.ok(new ApiUtil(user));
}
@PutMapping("/api/users/{id}")
public ResponseEntity<?> update(@PathVariable Integer id, @RequestBody UserRequest.UpdateDTO reqDTO) {
User sessionUser = (User) session.getAttribute("sessionUser");
User newSessionUser = userService.회원수정(sessionUser.getId(), reqDTO);
session.setAttribute("sessionUser", newSessionUser);
return ResponseEntity.ok(new ApiUtil(newSessionUser));
}
@PostMapping("/join")
public ResponseEntity<?> join(@RequestBody UserRequest.JoinDTO reqDTO) {
User user = userService.회원가입(reqDTO);
return ResponseEntity.ok(new ApiUtil(user));
}
@PostMapping("/login")
public ResponseEntity<?> login(@RequestBody UserRequest.LoginDTO reqDTO) {
User sessionUser = userService.로그인(reqDTO);
session.setAttribute("sessionUser", sessionUser);
return ResponseEntity.ok(new ApiUtil(null));
}
@GetMapping("/logout")
public ResponseEntity<?> logout() {
session.invalidate();
return ResponseEntity.ok(new ApiUtil(null));
}
}
UserService
@Transactional
public User 회원가입(UserRequest.JoinDTO reqDTO){ // ssar
// 1. 유저네임 중복검사 (서비스 체크) - DB연결이 필요한 것은 Controller에서 작성할 수 없다.
Optional<User> userOP = userJPARepository.findByUsername(reqDTO.getUsername());
if(userOP.isPresent()){
throw new Exception400("중복된 유저네임입니다");
}
// 2. 회원가입
return userJPARepository.save(reqDTO.toEntity());
}
BoardController
package shop.mtcoding.blog.board;
import jakarta.servlet.http.HttpSession;
import lombok.RequiredArgsConstructor;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import shop.mtcoding.blog._core.utils.ApiUtil;
import shop.mtcoding.blog.user.User;
import java.util.List;
@RequiredArgsConstructor // final이 붙은 친구들의 생성자를 만들어줘
@RestController // new BoardController(IoC에서 BoardRepository를 찾아서 주입) -> IoC 컨테이너 등록
public class BoardController {
private final BoardService boardService;
private final HttpSession session;
// TODO: 글목록조회 API 필요 -> @GetMapping("/")
@GetMapping("/")
public ResponseEntity<?> main(){
List<Board> boardList = boardService.글목록조회();
return ResponseEntity.ok(new ApiUtil(boardList));
}
// TODO: 글상세보기 API 필요 -> @GetMapping("/api/boards/{id}/detail")
@GetMapping("/api/boards/{id}/detail")
public ResponseEntity<?> detail(@PathVariable Integer id){
User sessionUser = (User) session.getAttribute("sessionUser");
Board board = boardService.글상세보기(id, sessionUser);
return ResponseEntity.ok(new ApiUtil(board));
}
// TODO: 글조회 API 필요 -> @GetMapping("/api/boards/{id}")
@GetMapping("/api/boards/{id}")
public ResponseEntity<?> findOne(@PathVariable Integer id){
Board board = boardService.글조회(id);
return ResponseEntity.ok(new ApiUtil(board));
}
@PostMapping("/api/boards")
public ResponseEntity<?> save(@RequestBody BoardRequest.SaveDTO reqDTO) {
User sessionUser = (User) session.getAttribute("sessionUser");
Board board = boardService.글쓰기(reqDTO, sessionUser);
return ResponseEntity.ok(new ApiUtil(board));
}
@PutMapping("/api/boards/{id}")
public ResponseEntity<?> update(@PathVariable Integer id, @RequestBody BoardRequest.UpdateDTO reqDTO) {
User sessionUser = (User) session.getAttribute("sessionUser");
Board board = boardService.글수정(id, sessionUser.getId(), reqDTO);
return ResponseEntity.ok(new ApiUtil(board));
}
@DeleteMapping("/api/boards/{id}")
public ResponseEntity<?> delete(@PathVariable Integer id) {
User sessionUser = (User) session.getAttribute("sessionUser");
boardService.글삭제(id, sessionUser.getId());
return ResponseEntity.ok(new ApiUtil(null));
}
}
BoardService
@Transactional
public Board 글수정(int boardId, int sessionUserId, BoardRequest.UpdateDTO reqDTO){
// 1. 조회 및 예외처리
Board board = boardJPARepository.findById(boardId)
.orElseThrow(() -> new Exception404("게시글을 찾을 수 없습니다"));
// 2. 권한 처리
if(sessionUserId != board.getUser().getId()){
throw new Exception403("게시글을 수정할 권한이 없습니다");
}
// 3. 글수정
board.setTitle(reqDTO.getTitle());
board.setContent(reqDTO.getContent());
return board;
} // 더티체킹

ReplyController
package shop.mtcoding.blog.reply;
import jakarta.servlet.http.HttpSession;
import lombok.RequiredArgsConstructor;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;
import shop.mtcoding.blog._core.utils.ApiUtil;
import shop.mtcoding.blog.user.User;
@RequiredArgsConstructor
@RestController
public class ReplyController {
private final ReplyService replyService;
private final HttpSession session;
@DeleteMapping("/api/replies/{id}")
public ResponseEntity<?> delete(@PathVariable Integer id){
User sessionUser = (User) session.getAttribute("sessionUser");
replyService.댓글삭제(id, sessionUser.getId());
return ResponseEntity.ok(new ApiUtil(null));
}
@PostMapping("/api/replies")
public ResponseEntity<?> save(@RequestBody ReplyRequest.SaveDTO reqDTO){
User sessionUser = (User) session.getAttribute("sessionUser");
Reply reply = replyService.댓글쓰기(reqDTO, sessionUser);
return ResponseEntity.ok(new ApiUtil(reply));
}
}
ReplyService
@Transactional
public Reply 댓글쓰기(ReplyRequest.SaveDTO reqDTO, User sessionUser) {
Board board = boardJPARepository.findById(reqDTO.getBoardId())
.orElseThrow(() -> new Exception404("없는 게시글에 댓글을 작성할 수 없어요"));
Reply reply = reqDTO.toEntity(sessionUser, board);
return replyJPARepository.save(reply);
}
Share article