2-4. @Param 어노테이션과 댓글 목록
댓글의 목록과 페이징 처리는 기존의 게시물 페이징 처리와 유사하지만, 추가적으로 특정한 게시물의 댓글들만을 대상으로 하기 때문에 추가로 게시물의 번호가 필요하게 된다.
MyBatis는 두 개 이상이 데이터를 파라미터로 전달하기 위해서는
1) 별도의 객체로 구성하거나,
2) Map을 이용하는 방식,
3) @Param을 이용해서 이름을 사용하는 방식이다.
@Param의 속성값은 MyBatis에서 SQL을 이용할 때 '#{}'의 이름으로 사용이 가능하다.
페이징 처리는 기존과 동일하게 Criteria를 이용한다. 여기에 추가적으로 해당 게시물의 번호는 파라미터를 전달하도록 ReplyMapper를 구성한다.
1) ReplyMapper 인터페이스
public List<ReplyVO> getListWithPaging(
@Param("cri") Criteria cri,
@Param("bno") Long bno);
XML로 처리할 때에는 지정된 'cri'와 'bno'를 모두 사용할 수 있다.
댓글도 페이징 처리를 해 줄 수 있는데, 조금 뒤쪽에서 이것을 처리하고 지금은 특정 게시물의 댓글을 가져오는 것을 작성한다.
2) ReplyMapper.xml 의 일부
XML에서 '#{bno}'가 @Param("bno")와 매칭되어서 사용되는 점에 주목해야 한다.
테스트 코드에서는 현재 데이터베이스에 추가되어 있는 댓글들의 게시물 번호로 확인한다.
3) ReplyMapperTests의 일부
@Test
public void testList() {
Criteria cri = new Criteria();
// 3145745L
List<ReplyVO> replies = mapper.getListWithPaging(cri, bnoArr[0]);
replies.forEach(reply -> log.info(reply));
}
3. 서비스 영역과 Controller 처리
서비스 영역과 Controller 의 처리는 기존의 BoardService와 동일하게 ReplyService 인터페이스와 ReplyServiceImpl 클래스를 작성한다.
1) ReplyService 인터페이스
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 modify(ReplyVO vo);
public int remove(Long rno);
public List<ReplyVO> getList(Criteria cri, Long bno);
}
2) ReplyService를 구현하는 ReplyServiceImpl 클래스에는 @Service 어노테이션과 @Log4j를 적용한다.
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.Log4j;
@Service
@Log4j
public class ReplyServiceImpl implements ReplyService {
@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 modify(ReplyVO vo) {
log.info("modify............" + vo);
return mapper.update(vo);
}
@Override
public int remove(Long rno) {
log.info("remove........." + rno);
return mapper.delete(rno);
}
@Override
public List<ReplyVO> getList(Criteria cri, Long bno) {
log.info("get Reply List of a Board " + bno);
return mapper.getListWithPaging(cri, bno);
}
}
ReplyServiceImpl은 ReplyMapper에 의존적인 관계이기 때문에 위의 코드와 같이 @Setter를 이용해서 처리하거나 스프링 4.3의 생성자와 자동주입을 이용해서 아래와 같이 처리할 수 있다.
- @AllArgsConstructor 을 써서 이렇게 사용하거나
- 이렇게만 사용하거나
3-1. ReplyController의 설계
ReplyController는 앞의 예제에서 SampleController와 유사하게 @RestController 어노테이션을 이용해서 설계하며 다음과 같은 URL을 기준으로 동작할 수 있게 작성한다.
작업 | URL | HTTP 전송방식 |
등록 | /replies/new | POST |
조회 | /replies/:rno | GET |
삭제 | /replies/:rno | DELETE |
수정 | /replies/:rno | PUT or PATCH |
페이지 | /replies/pages/:bno/:page | GET |
REST 방식으로 동작하는 URL을 설계할 때는 PK를 기준으로 작성하는 것이 좋다. PK 만으로 조회, 수정, 삭제가 가능하기 때문이다. 다만 댓글의 목록은 PK를 사용할 수 없기 때문에 파라미터로 필요한 게시물의 번호와 페이지 번호 정보들을 URL에서 표현하는 방식을 사용한다.
1) ReplyController는 ReplyService 타입의 객체인 ReplyServiceImpl 객체를 주입받도록 설계한다.
package org.zerock.controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.zerock.service.ReplyService;
import lombok.AllArgsConstructor;
import lombok.extern.log4j.Log4j;
@RequestMapping("/replies/")
@RestController
@Log4j
@AllArgsConstructor // 스프링 4.3 이상
public class ReplyController {
private ReplyService service;
}
3-2. 등록 작업과 테스트
REST 방식으로 처리할 때 주의해야 하는 점은 브라우저나 외부에서 서버를 호출할 때 데이터의 포맷과 서버에서 보내주는 데이터의 타입을 명확히 설계해야 하는 것이다. 예를 들어 댓글 등록의 경우 브라우저에서는 JSON 타입으로 된 댓글 데이터를 전송하고, 서버에서는 댓글의 처리 결과가 정상적으로 되었는지 문자열로 결과를 알려 주도록 한다.
1) ReplyController 일부
@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);
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'를 반환하도록 한다. 테스트를 위해서 프로젝트를 '/' 경로로 실행하고, 크롬 확장 프로그램등을 이용해서 테스트를 진행할 수 있다.
테스트 시에는 POST 방식으로 전송하고, 'Content - Type'은 'application/json'으로 지정해야 한다. 실제 전송되는 데이터는 존재하는 게시물 번호와 댓글 내용, 댓글 작성자를 JSON 문법에 맞게 작성하도록 주의한다. 게시물의 번호는 기존에 존재하는 번호이어야 하므로 주의가 필요하다.
(반드시 서버를 실행 시킨 후에 해야 된다)
3-3. 특정 게시물의 댓글 목록 확인
특정 게시물의 댓글 목록을 확인하는 작업은 아래와 같이 작성한다.
1) ReplyController 클래스의 일부
@GetMapping(value = "/pages/{bno}/{page}",
produces = {
MediaType.APPLICATION_XML_VALUE,
MediaType.APPLICATION_JSON_UTF8_VALUE})
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을 이용해서 파라미터로 처리하고 브라우저에서 아래와 같이 테스트 해본다.
테스트 결과는 XML 타입으로 댓글 데이터들이 나오는 것을 확인할 수 있다. 만일 JSON 타입을 원한다면 마지막에 '.json'을 추가하면 된다!
3-4. 댓글 삭제 / 조회
RestController의 댓글의 수정/삭제/조회는 위와 유사한 방식으로 JSON이나 문자열을 반환하도록 설계한다.
1) ReplyController 클래스의 일부
@DeleteMapping(value = "/{rno}",
produces = {
MediaType.APPLICATION_XML_VALUE})
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);
}
3-5. 댓글 수정
댓글 수정은 JSON 형태로 전달되는 데이터와 파라미터로 전달되는 댓글 번호를 처리하기 때문에 아래와 같이 처리한다.
1) ReplyController의 일부
@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){
vo.setRno(rno);
log.info("rno : " + rno);
log.info("modify : " + vo);
return service.modify(vo) == 1
? new ResponseEntity<>("success", HttpStatus.OK)
: new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR);
}
댓글 수정은 'PUT' 방식이나 'PATCH' 방식을 이용하도록 처리하고, 실제 수정되는 데이터는 JSON 포맷이므로 @RequestBody를 이용해서 처리한다. @RequestBody로 처리되는 데이터는 일반 파라미터나 @PathVariable 파라미터를 처리할 수 없기 때문에 직접 처리해 주는 부분을 주의해야 한다.
'Spring' 카테고리의 다른 글
[26] REST 방식과 Ajax를 이용하는 댓글처리 - 이벤트 처리와 HTML 처리 (0) | 2020.01.04 |
---|---|
[25] REST 방식과 Ajax를 이용하는 댓글 - Ajax 댓글 처리 3 (0) | 2019.12.31 |
[23] REST 방식과 Ajax를 이용하는 댓글 처리 - Ajax 댓글 처리 (0) | 2019.12.30 |
[22] REST 방식과 Ajax를 이용하는 댓글처리 - REST 방식으로 전환 (0) | 2019.12.27 |
[21] 기본적인 웹 게시물 관리 - 검색처리 (0) | 2019.12.26 |