-
[4 -ch17 댓글 처리 ② ] 서비스 영역과 Controller 처리 (@RequestBody, @PathVariable, consumes, produces )Back-End/Spring Legacy 2022. 9. 1. 17:10
게시판에서 게시글을 클릭했을 때 나오는 게시글 상세보기 페이지에서 댓글을 처리하려고 한다. 영속계층, 서비스/ 컨트롤러, javascript로 ajax 처리, 화면 처리 순서대로 작업할 예정이다.
https://wonisdaily.tistory.com/71
앞 페이지에서 영속계층 구현은 완료하였다.
ReplyService 설계
서비스 클래스에서는 크게 작업할 거 없이 ReplyMapper mapper를 객체로 생성해서 mapper.insert(vo)와 같이 mapper에 연결을 시켜준다.
<ReplyService 인터페이스>
등록, 삭제, 수정은 반환형이 int형 , 댓글 조회는 반환형이 ReplyVO
package org.zerock.service; import java.util.List; import org.zerock.domain.Criteria; import org.zerock.domain.ReplyVO; public interface ReplyService { public int Register(ReplyVO vo); //댓글 추가 public ReplyVO get(Long rno); //댓글 조회 public int remove(Long rno); //댓글 삭제 public int modify(ReplyVO vo); //댓글 수정 public List<ReplyVO> getList(Criteria cri, Long bno); //게시글 번호에 해당하는 댓글 조회 }
위의 인터페이스를 구현하는 클래스를 따로 만들어줘서 오버라이딩!
<ReplyServiceImpl 클래스>
package org.zerock.service; import java.util.List; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.zerock.domain.Criteria; import org.zerock.domain.ReplyVO; import org.zerock.mapper.ReplyMapper; import lombok.Setter; import lombok.extern.log4j.Log4j2; @Service @Log4j2 public class ReplyServiceImpl implements ReplyService{ //아래처럼 setter를 이용하거나 위에 @AllArgsConstructor 어노테이션을 추가만 해도 된다. @Setter(onMethod_ = @Autowired) private ReplyMapper mapper; @Override public int Register(ReplyVO vo) { log.info("register..."+ vo); return mapper.insert(vo); } @Override public ReplyVO get(Long rno) { log.info("get..."+ rno); return mapper.read(rno); } @Override public int remove(Long rno) { log.info("remove..."+ rno); return mapper.delete(rno); } @Override public int modify(ReplyVO vo) { log.info("modify..."+ vo); return mapper.update(vo); } @Override public List<ReplyVO> getList(Criteria cri, Long bno) { log.info("get Reply List of a Board "+bno ); return mapper.getListWithPaging(cri,bno); } }
consumes와 produces의 차이
Mapping을 할 때 받고싶은 데이터를 명시하면 오류상황을 줄일 수 있다. 이걸 위해 사용하는 것 중 하나가 Media Types이다. 들어오는 데이터와 나가는 데이터를 정하여 처리를 할 수 있다. consumes는 들어오는 데이터 타입을 정의할 때 이용한다. 예를 들어 내가 json타입을 받고 싶다면 아래와 같은 처리가 가능하다.
@PostMapping(path = "/pets", consumes = MediaType.APPLICATION_JSON_VALUE) public void addPet(@RequestBody Pet pet) { // ... }
이렇게 처리를 하게 되면 해당 uri를 호출하는 쪽에서 해더에 보내는 데이터가 json이라는 것을 명시해야 한다.
content-Type:application/json
produces는 반환하는 데이터 타입을 정의한다.
@GetMapping(path = "/pets/{petId}", produces = MediaType.APPLICATION_JSON_VALUE) @ResponseBody public Pet getPet(@PathVariable String petId) { // ... }
이럴 경우 반환 타입이 json으로 강제된다. 내가 보내야 하는 타입이 정해져 있으므로 해당 부분을 정의하면 된다.
즉) 요약해보자면
consumes는 클라이언트가 서버에게 보내는 데이터 타입을 명시한다.
produces는 서버가 클라이언트에게 반환하는 데이터 타입을 명시한다.
ReplyController 설계
REST 방식으로 동작하는 URL을 설계할 때는 PK를 기준으로 작성하는 것이 좋다. PK만으로 조회, 수정, 삭제가 가능하기 때문이다. 다만 댓글 목록은 PK를 사용할 수 없기 때문에 파라미터로 필요한 게시물의 번호(bno)와 페이지 번호(page) 정보들을 URL에서 표현하는 방식을 사용한다.
<등록 작업>
REST 방식으로 처리할 때 주의해야 하는 점은 브라우저나 외부에서 서버를 호출할 때 데이터 포맷과 서버에서 보내주는 데이터의 타입을 명확히 설계해야 하는 것이다. 예를 들어 댓글 등록의 경우 브라우저에서는 JSON 타입으로 된 댓글 데이터를 전송하고(클라이언트가 서버에게), 서버에서는 댓글 처리 결과가 정상적으로 되었는지(서버에서 클라이언트에게) 문자열로 결과를 알려주도록 한다.
@RestController @RequestMapping("/replies") @Log4j2 @AllArgsConstructor public class ReplyController { private ReplyService service; //1. 댓글 추가 //@RequestBody는 요청(request) 내용(body)을 처리한다. 일반적인 파라미터 전달방식 사용 불가 //@RequestBody를 적용해 json 데이터를 ReplyVo 타입으로 변환하도록 설정 //consumes : 클라이언트가 서버에게 보내는 데이터 타입을 명시한다. //produces : 서버가 클라이언트에게 반환하는 데이터 타입을 명시한다. @PostMapping(value="/new", consumes = "application/json", produces = {MediaType.TEXT_PLAIN_VALUE}) public ResponseEntity<String> create(@RequestBody ReplyVO vo){ log.info("ReplyVO : " + vo); int insertCount = service.Register(vo); log.info("Reply Insert Count : " + insertCount); //만약 insetCount의 값이 1이면 성공, 아니면 에러! return insertCount == 1 ? new ResponseEntity<>("success", HttpStatus.OK) : new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR); }
create()는 @PostMapping으로 POST 방식으로만 동작하도록 설계하고, consumes와 produces를 이용해 JSON 방식의 데이터만 처리하도록 하고, 문자열을 반환하도록 설계한다. create()의 파라미터는 @RequestBody를 적용해서 JSON 데이터를 ReplyVO 타입으로 변환하도록 지정한다.
create()는 내부적으로 ReplyServiceImpl을 호출해서 register()를 호출하고, 댓글이 추가된 숫자를 확인해서 브라우저에서 '200 OK' 혹은 '500 Internal Server Error'를 반환하도록 한다.
postman으로 headers와 body에 다음과 같은 내용을 추가해 테스트해본다.
< 특정 게시물 댓글 목록 확인 >
//2. 특정 게시물 댓글 목록 확인 //@PathVariable : url 호출 시 전달된 매개변수 값 page를 int형 변수 page에 저장하겠다. //매핑해줄 때 value에 있는 url의 {bno}값을 전달받아 아래 service.getList의 매개변수로 전달하겠다. @GetMapping(value="/pages/{bno}/{page}") public ResponseEntity<List<ReplyVO>> getList( @PathVariable("page") int page, @PathVariable("bno") Long bno){ log.info("getList............"); Criteria cri = new Criteria(page,10); log.info(cri); return new ResponseEntity<>(service.getList(cri, bno),HttpStatus.OK); }
ReplyController의 getList()는 Criteria를 이용해 파라미터를 수집하는데, '/{bno}/{page}의 'page' 값은 Criteria를 생성해서 직접 처리해야한다. 게시물의 번호는 @PathVariable을 이용해 파라미터로 처리했다.
<댓글 삭제/조회 >
//3. 댓글 조회 //@PathVariable : url 호출 시 파라미터로 전달받은 value를 메서드의 파라미터로 받을 수 있게 해주는 어노테이션이다 //즉) url 호출 시 전달된 매개변수 "rno" 값을 Long rno에 저장한다. @GetMapping(value="/{rno}") public ResponseEntity<ReplyVO> get(@PathVariable("rno") Long rno){ log.info("get : " + rno); return new ResponseEntity<>(service.get(rno),HttpStatus.OK); } //4. 댓글 삭제 @DeleteMapping(value = "/{rno}") public ResponseEntity<String> remove(@PathVariable("rno") Long rno){ log.info("remove : " + rno); return service.remove(rno) == 1 ? new ResponseEntity<>("success", HttpStatus.OK) : new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR); }
< 댓글 수정 >
댓글 수정은 JSON 형태로 전달되는 데이터와 파라미터로 전달되는 댓글 번호(rno)를 처리하기 때문에 아래와 같이 처리한다.
//4. 댓글 수정 //consumes : 클라이언트가 서버에게 보내는 데이터 형태 //produces : 서버가 클라이언트에게 보내는 데이터 형태 //@RequestBody : 클라이언트가 예를들어 웹페이지에서 보내는 json형태의 데이터를 ReplyVO로 형변환 하겠다. //즉) 객체 형태로 사용이 가능하다. //@PathVariable : url을 통해 전달된 매개변수 값을 지정한 형태의 값으로 저장해서 사용하겠다. @RequestMapping(method= {RequestMethod.PUT, RequestMethod.PATCH}, value="/{rno}" ,consumes="application/json" ,produces = {MediaType.TEXT_PLAIN_VALUE}) public ResponseEntity<String> modify(@RequestBody ReplyVO vo, @PathVariable("rno") Long rno){ //url을 통해 입력받은 rno (댓글번호) 값을 vo에 저장한다. vo.setRno(rno); log.info("rno : " +rno); log.info("modify : " +vo); //해당하는 rno의 값의 내용들을 수정해준다. return service.modify(vo) == 1 ? new ResponseEntity<>("success", HttpStatus.OK) : new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR); }
댓글 수정은 'PUT' 방식이나 'PATCH'방식을 이용하도록 처리하고, 실제 수정되는 데이터는 JSON 포맷이므로 @RequestBody를 이용해서 처리한다. @RequestBody로 처리되는 데이터는 일반 파라미터나 @PathVariable 파라미터를 처리할 수 없기 때문에 직접 처리해줘야한다.
반응형'Back-End > Spring Legacy' 카테고리의 다른 글
[4-ch17 댓글 처리 ④] 댓글의 페이징 처리 (인덱스 생성, 화면 처리) (0) 2022.09.06 [4-ch17 댓글 처리 ③] jQuery와 Ajax 처리, JavaScript 모듈화 (0) 2022.09.01 [Spring REST] @RequestBody와 @RequestParam 차이 (0) 2022.09.01 [4-ch17 댓글 처리 ① ] sql 댓글 테이블 생성과 영속 영역 설계 (MyBatis) (0) 2022.09.01 [4-ch16 REST 방식] @RestController, ResponseEntity, @RequestParam , 어노테이션과 JSON 알아보기 (0) 2022.08.31