
REST(Representational State Transfer)자원을 이름으로 구분하여 해당 자원의 상태를 주고받는 모든 것을 의미합니다.
- 준다. Client To Server = Request
- 받는다. Server To Client = Response
대부분의 백엔드 개발자의 입사 공고는 다음과 같다.
우대 or 자격요건 : REST API 가능
REST API의 기본적인 메서드
메서드의 종류와 uri만 보고도 얘가 뭘 하고 싶어하는지 의도를 알 수 있어야함 (알잘딱깔센)
- POST로 tp01/board
- GET으로 tp01/board
- GET으로 tp01/board/423
- DELETE로 tp01/board
- PUT으로 tp01/board
답 :
1. POST니까 INSERT문이고 board로 끝났으니 게시판 글쓰는거 같네
2. GET이니까 가져오는거고 board로 끝났으니 게시판 전체 가져오는거 같네
3. GET인데 board뒤에 숫자가 하나 더있으니 특정한 게시판 하나를 가져오는거 같네
4. DELETE인데 board로 끝났으니 게시판 전체를 날리는건가? (애매함)
5. PUT으로 board로 끝났으니 게시판 전체를 전체 고치는건가 뭐지? (애매함)
벌써 4번 5번이 애매하다. 그러니까 Restful 하지 않는 실수가 있는것이다.
그러니 4번 5번은 특정한 값만 날려야 하므로 tp01/board/423 처럼 특정한 파라미터를 받아 바꾸거나 지워야 한다.
REST한 구조는 파라미터를 받아야함 (Controller부터 만지자)
@RestController
public class BoardRestController {
// 토큰값에서 가져온거 쓰기
private int ur_no;
private String ur_id;
private String ur_name;
private void init(HttpServletResponse response) throws IOException {
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
if (authentication != null && authentication.getPrincipal() instanceof MemberDetails) {
MemberDetails userDetails = (MemberDetails) authentication.getPrincipal();
this.ur_no = userDetails.getUr_no();
this.ur_id = userDetails.getUsername();
this.ur_name = userDetails.getUr_name();
} else {
response.sendRedirect("/member/login");
}
}
@Autowired
private BoardService boardService;
@Autowired
private BoardLogService boardLogService;
// 게시판 개수 가져오기
@GetMapping("/api/board/countBoard")
public int getCountBoard() {
int cnt = boardService.getBoardCount();
return cnt;
}
// 데이터 하나 가져오기
@GetMapping("/api/board/{bd_no}")
public Map<String, Object> getBoard(@PathVariable("bd_no") int bd_no,
HttpServletResponse response) throws IOException {
init(response);
Map<String, Object> mapJson = new HashMap<>();
List<BoardDTO> list = boardService.getBoard(bd_no);
if(!list.isEmpty()) {
int curHit = boardService.getCurrentBoardHit(bd_no);
BoardDTO boardDTO = new BoardDTO();
int increasedHit = curHit + 1;
boardDTO.setBd_hit(increasedHit);
boardDTO.setBd_no(bd_no);
boardService.upHit(boardDTO);
if(boardLogService.createBoardClickLog(boardDTO, ur_id)) {
mapJson.put("log", "success");
}
} else { //게시글 없을 때
mapJson.put("result", "fail");
mapJson.put("message", "잘못된 접근입니다.");
mapJson.put("redirectUrl", "/board/main");
return mapJson;
}
mapJson.put("result", "success");
mapJson.put("count", list.size());
mapJson.put("list", list);
return mapJson;
}
// 게시판 작성
@PostMapping("/api/board")
public Map<String, Object> writeBoard(@RequestBody BoardDTO boardDTO, HttpServletResponse response)
throws IOException {
Map<String, Object> mapJson = new HashMap<>();
init(response);
boardDTO.setUr_no(ur_no);
boardDTO.setUr_name(ur_name);
if (boardService.upsertBoard(boardDTO)) {
mapJson.put("result", "success");
mapJson.put("message", "글이 등록 되었습니다.");
mapJson.put("redirectUrl", "/board/main");
if(boardLogService.createBoardWriteLog(boardDTO, ur_id)) {
mapJson.put("log", "success");
}
} else {
mapJson.put("result", "fail");
mapJson.put("message", "다시 시도하세요.");
}
return mapJson;
}
// 게시판 수정
@PutMapping("/api/board/{bd_no}")
public Map<String, Object> modifyBoard(@PathVariable("bd_no") int bd_no, @RequestBody BoardDTO boardDTO,
HttpServletResponse response) throws IOException {
Map<String, Object> mapJson = new HashMap<>();
init(response);
boardDTO.setBd_no(bd_no);
boardDTO.setUr_no(ur_no);
boardDTO.setUr_name(ur_name);
if (boardService.upsertBoard(boardDTO)) {
mapJson.put("result", "success");
mapJson.put("message", "글이 수정 되었습니다.");
mapJson.put("redirectUrl", "/board/detail?bd_no=" + bd_no);
if(boardLogService.createBoardModifyLog(boardDTO, ur_id)) {
mapJson.put("log", "success");
}
} else {
mapJson.put("result", "fail");
mapJson.put("message", "다시 시도하세요.");
}
return mapJson;
}
@DeleteMapping("/api/board/{bd_no}")
public Map<String, Object> deleteBoard(@PathVariable("bd_no") int bd_no, HttpServletResponse response)
throws IOException {
init(response);
Map<String, Object> mapJson = new HashMap<>();
BoardDTO boardDTO = new BoardDTO();
boardDTO.setBd_no(bd_no);
boardDTO.setUr_no(ur_no);
if (boardService.deleteBoard(boardDTO)) {
mapJson.put("result", "success");
mapJson.put("message", "글이 삭제되었습니다.");
mapJson.put("redirectUrl", "/board/main");
if(boardLogService.createBoardDeleteLog(boardDTO, ur_id)) {
mapJson.put("log", "success");
}
} else {
mapJson.put("result", "fail");
mapJson.put("message", "다시 시도하세요.");
}
return mapJson;
}
// 데이터 가져오기
@GetMapping("/api/board")
public Map<String, Object> getBoards() {
Map<String, Object> mapJson = new HashMap<>();
// JWT 토큰 없으면 뱉기
List<BoardDTO> list = boardService.getAllBoards();
mapJson.put("result", "success");
mapJson.put("count", boardService.getBoardCount());
mapJson.put("list", list);
return mapJson;
}
}
자원을 @GetMapping, @PutMapping 등으로 구분해놓음
Controller 다음 Service로 가보자
@Service
@Transactional
public class BoardService {
@Autowired
BoardRepository boardRepository;
// 게시판 전체 개수 가져오기
public int getBoardCount() {
int cnt = (int) boardRepository.count();
return cnt;
}
// 게시판 데이터 가져오기
public List<BoardDTO> getAllBoards() {
List<BoardEntity> entityList = boardRepository.findAll();
List<BoardDTO> list = new ArrayList<>();
for(BoardEntity boardEntity : entityList) {
list.add(BoardConverter.EntityToDTO(boardEntity));
}
return list;
}
// 게시판 하나 가져오기
public List<BoardDTO> getBoard(int bd_no) {
BoardEntity boardEntity = boardRepository.findById(bd_no).orElse(null);
BoardDTO boardDTO = BoardConverter.EntityToDTO(boardEntity);
if(boardEntity == null) {
return Collections.emptyList();
}
return Collections.singletonList(boardDTO);
}
public boolean upsertBoard(BoardDTO boardDTO) {
//List<BoardEntity> list = getBoard(boardDTO.getBd_no());
BoardEntity boardEntity = BoardConverter.DTOToEntity(boardDTO);
if (boardEntity != null) { //upsert 둘다 진행...
boardRepository.save(boardEntity);
return true;
}
return true;
}
public boolean deleteBoard(BoardDTO boardDTO) {
int bd_no = boardDTO.getBd_no();
int ur_no = boardDTO.getUr_no();
BoardEntity boardEntity = boardRepository.findById(bd_no).get();
if (boardEntity.getUr_no() == ur_no) { // 있는 게시글인지 확인
boardRepository.deleteById(bd_no);
return true;
}
return false;
}
// 게시판 조회수 가져오기
public int getCurrentBoardHit(int bd_no) {
BoardEntity boardEntity = boardRepository.findById(bd_no).orElse(null);
if(boardEntity != null) {
int hit = boardEntity.getBd_hit();
return hit;
}
return 0;
}
// 게시판 조회수 올리기
public boolean upHit(BoardDTO boardDTO) {
BoardEntity boardEntity = boardRepository.findById(boardDTO.getBd_no()).orElse(null);
boardEntity.setBd_hit(boardDTO.getBd_hit());
boardRepository.save(boardEntity);
return true;
}
}
Service 에서 Repository로 가보자
package kr.spring.board.repository;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
import kr.spring.board.entity.BoardEntity;
@Repository
public interface BoardRepository extends JpaRepository <BoardEntity, Integer> {
//특별한 것만 만들기
}
JPA 형태라 Config를 해서 Entity로 받는다 Entity 클래스로 가보자
@Entity
@Table(name = "TP01BOARD")
public class BoardEntity {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private int bd_no;
@Column
private int ur_no;
@Column
private String ur_name;
@Column
private String bd_name;
@Column
private String bd_info;
@Column
private String bd_type;
@Column
private int bd_auth = 4;
@Column
private int bd_hit = 0;
@Column
private Date bd_reg_date;
public BoardEntity() {
}
//Getters Setters
public int getBd_no() {
return bd_no;
}
public void setBd_no(int bd_no) {
this.bd_no = bd_no;
}
public int getUr_no() {
return ur_no;
}
public void setUr_no(int ur_no) {
this.ur_no = ur_no;
}
public String getUr_name() {
return ur_name;
}
public void setUr_name(String ur_name) {
this.ur_name = ur_name;
}
public String getBd_name() {
return bd_name;
}
public void setBd_name(String bd_name) {
this.bd_name = bd_name;
}
public String getBd_info() {
return bd_info;
}
public void setBd_info(String bd_info) {
this.bd_info = bd_info;
}
public String getBd_type() {
return bd_type;
}
public void setBd_type(String bd_type) {
this.bd_type = bd_type;
}
public int getBd_auth() {
return bd_auth;
}
public void setBd_auth(int bd_auth) {
this.bd_auth = bd_auth;
}
public int getBd_hit() {
return bd_hit;
}
public void setBd_hit(int bd_hit) {
this.bd_hit = bd_hit;
}
public Date getBd_reg_date() {
return bd_reg_date;
}
public void setBd_reg_date(Date bd_reg_date) {
this.bd_reg_date = bd_reg_date;
}
public List<Object> toList() {
return Arrays.asList(bd_no, ur_no, ur_name, bd_name, bd_info, bd_type, bd_auth, bd_hit, bd_reg_date);
}
}
나는 다중 DB를 사용하기 위해서 Configuration이 있는데, 이는 복잡하기 때문에 생략 합니다.
ajax로 api를 요청하면 그 자원을 받게끔 설정 하는 것이다.
<script type="text/javascript">
$(function(){
//ajax 시작
$('#board_contents').empty();
$.ajax({
type: "get",
url: "${pageContext.request.contextPath}/api/board",
success: function (response) {
let boardStart = '<div>총 : '+response.count+' 개</div>';
boardStart += '<table><tr>';
boardStart += '<th>번호</th>';
boardStart += '<th>내용</th>';
boardStart += '<th>작성자</th>';
boardStart += '<th>작성일</th>';
boardStart += '<th>조회수</th>';
boardStart += '</tr>';
$('#board_contents').append(boardStart);
$(response.list).each(function (index, item) {
let output = '<tr>';
output += '<td>'+item.bd_no+'</td>';
output += '<td><a href="${pageContext.request.contextPath}/board/detail?bd_no='+item.bd_no+'">'+item.bd_name+'</a></td>';
output += '<td>'+item.ur_name+'</td>';
output += '<td>'+item.bd_reg_date+'</td>';
output += '<td>'+item.bd_hit+'</td>';
output += '</tr>';
$('#board_contents').append(output);
});
let boardEnd = '</table>';
$('#board_contents').append(boardEnd);
},
error: function() {
alert('ajax 실패');
}
});
});
</script>