김민주

[K-PaaS] 실습 코드 분석 - edu-msa-board 본문

학부/PBL

[K-PaaS] 실습 코드 분석 - edu-msa-board

7alswn 2023. 9. 16. 23:28

실습 전체 구성도

https://github.com/search?q=org%3APaaS-TA%20edu&type=repositories 

실습 제공 코드 ( 총 5개 )

실습 제공 코드 파일 중 3번째에 해당하는 edu-msa-board 파일을 먼저 분석해 보겠다. (이유는 왠지 가벼워 보여서 ...)

src/main > java/paasta/msa 파일부터!

여기에서 dao, controller, service, common 파일 순서대로 살펴볼 예정 (순서는 제 맘입니다,,ㅎ)

1) dao > BoardDAO.java

정리: 스프링으로 데이터베이스와 상호 작용하는 DAO(Data Access Object) 클래스
package paasta.msa.dao;

import java.util.List;
import java.util.Map;

import org.springframework.stereotype.Repository;

import paasta.msa.common.CommonDAO;

@Repository("boardDAO")
public class BoardDAO extends CommonDAO {

public Map<String, Object> getBoardCount(Map<String, Object> paramMap) throws Exception {
return getSqlSession().selectOne("paasta.msa.service.impl.BoardMapper.getBoardCount", paramMap);
}

public List<Object> getBoardList(Map<String, Object> paramMap) throws Exception {
return getSqlSession().selectList("paasta.msa.service.impl.BoardMapper.getBoardList", paramMap);
}

public List<Object> getBoard(Map<String, Object> paramMap) throws Exception {
return getSqlSession().selectList("paasta.msa.service.impl.BoardMapper.getBoard", paramMap);
}

public int postBoard(Map<String, Object> paramMap) throws Exception {

return getSqlSession().insert("paasta.msa.service.impl.BoardMapper.postBoard", paramMap);
}

public int putBoard(Map<String, Object> paramMap) throws Exception {

return getSqlSession().update("paasta.msa.service.impl.BoardMapper.putBoard", paramMap);
}

public int deleteBoard(Map<String, Object> paramMap) throws Exception {

return getSqlSession().delete("paasta.msa.service.impl.BoardMapper.deleteBoard", paramMap);
}

}

1. @Repository: 스프링에서 관리되는 빈으로 등록되어 있음을 의미

2. getBoardCount

  • 입력으로 paraMap 매개변수를 받아와 DB 쿼리 실행 후 결과를 받아옴
  • getSqlSession().selectOne(...)으로 DB에서 한 개의 결과를 조회
  • paasta.msa.service.impl.BoardMapper.getBoardCount 쿼리 실행 (해당 쿼리는 DB xml 파일에서 정의됨)

3. getBoardList

  • 2번과 동일하게 입력으로 paraMap을 받아와 DB 쿼리 실행 수 결과 리스트 반환
  • getSqlSession().selectList(...)으로 다수의 결과 조회
  • paasta.msa.service.impl.BoardMapper.getBoardList 쿼리 실행

4. postBoard, putBoard, deleteBoard

  • 데이터 삽입, 수정, 삭제를 의미
  • insert, update, delete 메서드 사용
  • 마찬가지로 쿼리는 DB xml 파일에서 정의됨

2) controller > BoardController.java

정리: 웹의 API 엔드포인트를 처리하는 클래스 / 게시판 관련 작업 수행 및 클라이언트에게 json 형식의 응답을 반환하는 역할
package paasta.msa.controller;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.annotation.Resource;

import org.springframework.http.HttpEntity;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import com.fasterxml.jackson.databind.ObjectMapper;

import paasta.msa.common.CommonUtil;
import paasta.msa.service.BoardService;

/**
 * @author JaemooSong
 *
 */
@RestController
public class BoardController {

@Resource(name = "boardService")
private BoardService boardService;

@RequestMapping(value = "/board", method = RequestMethod.GET)
public Map<String, Object> getBoards(@RequestParam(required = false) String searchType,
@RequestParam(required = false) String searchValue, @RequestParam(required = false) Integer page,
@RequestParam(required = false) Integer pagePerCount) {

Map<String, Object> paramMap = new HashMap<String, Object>();
Map<String, Object> result = new HashMap<String, Object>();
Map<String, Object> resultData = new HashMap<String, Object>();

Map<String, Object> boardCount = null;
List<Object> boardList = null;

// parameter Setting
try {
paramMap.put("searchType", searchType);
paramMap.put("searchValue", searchValue);
paramMap.put("page", CommonUtil.nvl(page, 1));
paramMap.put("pagePerCount", CommonUtil.nvl(pagePerCount, 15));
paramMap.put("offset", ((int)paramMap.get("page") - 1) * (int)paramMap.get("pagePerCount"));
} catch (Exception e) {
result.put("result", "ERROR");
result.put("errMsg", "input parameter error.");
e.printStackTrace();
return result;
}

// Select BoardList
try {

// select BoardCount
boardCount = boardService.getBoardCount(paramMap);
long count = 0;

if(boardCount != null) {
count = (Long)boardCount.get("COUNT");
resultData.put("boardCount", count);
}

// select BoardList
if(count != 0) {
boardList = (List<Object>)boardService.getBoardList(paramMap);
resultData.put("boardList", boardList);
}

resultData.put("page", paramMap.get("page"));
resultData.put("pagePerCount", paramMap.get("pagePerCount"));

result.put("result", "SUCCESS");
result.put("resultData", resultData);
} catch (Exception e) {
result.put("result", "ERROR");
result.put("errMsg", e.getMessage());
e.printStackTrace();
}

return result;
}

@SuppressWarnings("unchecked")
@RequestMapping(value = "/board/{boardSeq}", method = RequestMethod.GET)
public Map<String, Object> getBoard(@PathVariable("boardSeq") int boardSeq) {

Map<String, Object> paramMap = new HashMap<String, Object>();
Map<String, Object> result = new HashMap<String, Object>();
Map<String, Object> resultData = new HashMap<String, Object>();

List<Object> boardList = null;

// parameter Setting
paramMap.put("boardSeq", boardSeq);

try {
// select Board
boardList = (List<Object>)boardService.getBoard(paramMap);
if(boardList != null && boardList.size() == 1) {
resultData = (Map<String, Object>)boardList.get(0);

} else {
throw new Exception("일치하는 게시물이 없습니다.");
}

result.put("result", "SUCCESS");
result.put("resultData", resultData);
} catch (Exception e) {
result.put("result", "ERROR");
result.put("errMsg", e.getMessage());
e.printStackTrace();
}

return result;
}

@SuppressWarnings("unchecked")
@RequestMapping(value = "/board", method = RequestMethod.POST)
public Map<String, Object> postBoard(HttpEntity<String> httpEntity) {

ObjectMapper mapper = new ObjectMapper();
String jsonString = httpEntity.getBody();

Map<String, Object> paramMap = new HashMap<String, Object>();
Map<String, Object> result = new HashMap<String, Object>();
Map<String, Object> resultData = new HashMap<String, Object>();

// parameter Setting
try {
if(jsonString ==  null || "".equals(jsonString)) {
jsonString = "{}";
}
Map<String, String> jsonMap = mapper.readValue(jsonString, Map.class);


String boardTitle = jsonMap.get("boardTitle");
String boardText = jsonMap.get("boardText");
String writeUserId = jsonMap.get("writeUserId");
String writeUserName = jsonMap.get("writeUserName");

// null String check
if(CommonUtil.isEmptyString(boardTitle)) {
throw new Exception("게시물 제목은 필수 입력값입니다.");
} else if(CommonUtil.isEmptyString(boardText)) {
throw new Exception("게시물 내용은 필수 입력값입니다.");
} else if(CommonUtil.isEmptyString(writeUserId)) {
throw new Exception("사용자 ID는 필수 입력값입니다.");
} else if(CommonUtil.isEmptyString(writeUserName)) {
throw new Exception("사용자 명은 필수 입력값입니다.");
}

paramMap.put("boardTitle", boardTitle);
paramMap.put("boardText", boardText);
paramMap.put("writeUserId", writeUserId);
paramMap.put("writeUserName", writeUserName);
} catch (Exception e) {
result.put("result", "ERROR");
result.put("errMsg", e.getMessage());
e.printStackTrace();

return result;
}

try {

int insertCount = boardService.postBoard(paramMap);
if(insertCount != 1) {
throw new Exception("게시물 생성에 실패하였습니다.");
}

result.put("result", "SUCCESS");
result.put("boardSeq", paramMap.get("boardSeq"));
result.put("resultData", resultData);
} catch (Exception e) {
result.put("result", "ERROR");
result.put("errMsg", e.getMessage());
e.printStackTrace();
}

return result;
}

@SuppressWarnings("unchecked")
@RequestMapping(value = "/board/{boardSeq}", method = RequestMethod.PUT)
public Map<String, Object> putBoard(@PathVariable("boardSeq") int boardSeq, HttpEntity<String> httpEntity) {

ObjectMapper mapper = new ObjectMapper();
String jsonString = httpEntity.getBody();

Map<String, Object> paramMap = new HashMap<String, Object>();
Map<String, Object> result = new HashMap<String, Object>();
Map<String, Object> resultData = new HashMap<String, Object>();

// parameter Setting
try {
if(jsonString ==  null || "".equals(jsonString)) {
jsonString = "{}";
}
Map<String, String> jsonMap = mapper.readValue(jsonString, Map.class);

String boardTitle = jsonMap.get("boardTitle");
String boardText = jsonMap.get("boardText");
String writeUserId = jsonMap.get("writeUserId");

// 수정 요청 Data가 없는 경우
if(CommonUtil.isEmptyString(boardTitle) && CommonUtil.isEmptyString(boardText)) {
result.put("result", "SUCCESS");
return result;
}

paramMap.put("boardSeq", boardSeq);
paramMap.put("boardTitle", boardTitle);
paramMap.put("boardText", boardText);
paramMap.put("writeUserId", writeUserId);
} catch (Exception e) {
result.put("result", "ERROR");
result.put("errMsg", e.getMessage());
e.printStackTrace();

return result;
}

try {

int updateCount = boardService.putBoard(paramMap);
if(updateCount != 1) {
throw new Exception("게시물 수정에 실패하였습니다.");
}

result.put("result", "SUCCESS");
result.put("resultData", resultData);
} catch (Exception e) {
result.put("result", "ERROR");
result.put("errMsg", e.getMessage());
e.printStackTrace();
}

return result;
}

@RequestMapping(value = "/board/{boardSeq}/{writeUserId}", method = RequestMethod.DELETE)
public Map<String, Object> deleteBoard(@PathVariable("boardSeq") int boardSeq, @PathVariable("writeUserId") String writeUserId, HttpEntity<String> httpEntity) {

Map<String, Object> paramMap = new HashMap<String, Object>();
Map<String, Object> result = new HashMap<String, Object>();
Map<String, Object> resultData = new HashMap<String, Object>();

// parameter Setting
paramMap.put("boardSeq", boardSeq);
paramMap.put("writeUserId", writeUserId);

try {

int deleteCount = boardService.deleteBoard(paramMap);
if(deleteCount == 0) {
throw new Exception("게시물 삭제에 실패하였습니다.");
}
// TODO 게시물 코멘트 삭제
result.put("result", "SUCCESS");
result.put("resultData", resultData);
} catch (Exception e) {
result.put("result", "ERROR");
result.put("errMsg", e.getMessage());
e.printStackTrace();
}

return result;
}
}

1. getBoards

  • 게시판 목록을 검색하는 GET 요청 처리
  • @RequestMapping - /board 엔드포인트에 대한 GET 요청 처리
  • @RequestParam - 쿼리 파라미터를 받아와 paramMap에 저장
  • boardService - 게시판 목록, 게시물 수 검색 후 json 형식으로 결과 반환

2. getBoard

  • 게시물 하나를 검색하는 GET 요청 처리
  • @RequestMapping - /board/{boardSeq} GET 요청 처리
  • boardSeq를 받아와 해당 게시물을 검색하고 결과를 json 형식으로 반환

3. postBoard

  • 새로운 게시물을 생성하는 POST 요청 처리
  • @RequestMapping - /board 엔드포인트에 대한 POST 요청 처리
  • 요청 바디에서 json 데이터 파싱 후 boardService를 사용해 게시물 생성, 결과는 json 형식으로 반환

4. putBoard

  • 게시물 수정하는 PUT 요청 처리
  • @RequestMapping - /board/{boardSeq} PUT 요청 처리
  • 요청 바디에서 json 데이터 파싱 후 boardService를 사용해 게시물 수정, 결과는 json 형식으로 반환

5. deleteBoard

  • 게시물 삭제하는 DELETE 요청 처리
  • @RequestMapping - /board/{boardSeq}/{writeUserId} 엔드포인트에 대한 DELETE 요청 처리
  • 경로 변수인 boardSeqwriteUserId를 받아와서 게시물 삭제, 결과는 json 형식으로 반환

3) service > BoardService.java

정리: 게시판 서비스 추상화, 다른 클래스에서 해당 인터페이스를 구현하여 실제로 서비스를 구현할 수 있도록 하는 코드
package paasta.msa.service;

import java.util.List;
import java.util.Map;

public interface BoardService {

public Map<String, Object> getBoardCount(Map<String, Object> paramMap) throws Exception;

public List<Object> getBoardList(Map<String, Object> paramMap) throws Exception;

public List<Object> getBoard(Map<String, Object> paramMap) throws Exception;

public int postBoard(Map<String, Object> paramMap) throws Exception;

public int putBoard(Map<String, Object> paramMap) throws Exception;

public int deleteBoard(Map<String, Object> paramMap) throws Exception;
}

1. getBoardCount(Map<String, Object> paramMap) : 게시판 글 수 조회

  • paramMap 매개변수를 받아와 게시판 관련 정보를 담고 있는 맵 객체를 전달받음
  • 이를 기반으로 게시글 수를 조회하고 결과를 맵으로 반환

2. getBoardList(Map<String, Object> paramMap) : 게시판 글 목록 조회

  • paramMap 매개변수를 받아와 게시판 관련 정보를 담고 있는 맵 객체를 전달받음
  • 이를 기반으로 게시글 목록을 조회하고 결과를 리스트로 반환

3. getBoard(Map<String, Object> paramMap) : 특정 게시글의 상세 정보 조회

  • paramMap 매개변수를 받아와 게시판 관련 정보를 담고 있는 맵 객체를 전달받음
  • 이를 기반으로 특정 게시글의 상세 정보를 조회하고 결과를 리스트로 반환

4. postBoard(Map<String, Object> paramMap) : 새로운 게시글 등록

  • paramMap 매개변수를 받아와 새로운 게시글의 관련 정보를 담고 있는 맵 객체를 전달받음
  • 이를 기반으로 게시글을 등록하고 결과로 등록된 게시글의 개수를 반환

5. putBoard(Map<String, Object> paramMap) : 기존 게시글 수정

  • paramMap 매개변수를 받아와 수정할 게시글의 관련 정보를 담고 있는 맵 객체를 전달받음
  • 이를 기반으로 게시글을 수정하고 결과로 수정된 게시글의 개수를 반환

6. deleteBoard(Map<String, Object> paramMap) : 게시글 삭제

  • paramMap 매개변수를 받아와 삭제할 게시글의 관련 정보를 담고 있는 맵 객체를 전달받음
  • 이를 기반으로 게시글을 삭제하고 결과로 삭제된 게시글의 개수를 반환

4) service > impl > BoardServicempl.java

정리: 게시판 서비스의 구체적인 구현 클래스, BoardService 인터페이스 구현
Spring 애플리케이션 내에서 게시판 서비스를 제공하는 핵심적인 역할 수행
- boardDA0를 통해 DB와의 상호작용을 처리하고, apiProperties를 통해 애플리케이션의 설정 정보에 접근 및 활용 가능
package paasta.msa.service.impl;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;

import javax.annotation.Resource;

import org.springframework.stereotype.Service;

import com.fasterxml.jackson.databind.ObjectMapper;

import paasta.msa.dao.BoardDAO;
import paasta.msa.service.BoardService;

@Service("boardService")
public class BoardServiceImpl implements BoardService {

@Resource(name = "boardDAO")
private BoardDAO boardDAO;

@Resource(name = "apiProperties")
private Properties apiProperties;

public Map<String, Object> getBoardCount(Map<String, Object> paramMap) throws Exception {
return boardDAO.getBoardCount(paramMap);
}

public List<Object> getBoardList(Map<String, Object> paramMap) throws Exception {
return boardDAO.getBoardList(paramMap);
}

public List<Object> getBoard(Map<String, Object> paramMap) throws Exception {
return boardDAO.getBoard(paramMap);
}

public int postBoard(Map<String, Object> paramMap) throws Exception {
return boardDAO.postBoard(paramMap);
}

public int putBoard(Map<String, Object> paramMap) throws Exception {
return boardDAO.putBoard(paramMap);
}

public int deleteBoard(Map<String, Object> paramMap) throws Exception {
return boardDAO.deleteBoard(paramMap);
}
}

1. ObjectMapper

  • Jackson 라이브러리를 사용해 json 데이터를 객체로 변환하고 객체를 json으로 직렬화 하는 데 사용
  • 웹 어플리케이션에서 json 데이터와 자바 객체 간 변환을 쉽게 처리할 수 있음

2. @Service("boardService")

  • 해당 클래스가 서비스 빈으로 등록되어야 함을 나타냄 (스프링한테 전달하는 게 목적인 듯)
  • "boardService": 빈의 이름(identifier)을 지정, 다른 클래스에서 inject 할 때 사용됨

3. @Resource(name = "boardDAO"), @Resource(name = "apiProperties")

  • 해당 클래스가 필요로 하는 의존성을 주입받는 방법을 나타냄
  • "boardDAO", "apiProperties": 리소스 이름. 스프링 컨테이너에서 미리 정의된 빈들을 주입받음
  • 이러한 주입은 객체 간의 느슨한 결합을 유지하고, 코드의 재사용성과 유지보수성을 높이는 데 도움 됨.

4. getBoardCount, getBoardList, getBoard, postBoard, putBoard, deleteBoard

  • BoardService 인터페이스에서 선언된 메서드를 구현한 것
  • 각 메서드는 게시판 관련 작업을 수행하고, 실제 비즈니스 로직은 boardDAO를 통해 DB에 접근하고 실행됨
  • ex) getBoardCount 메서드는 게시판 글 수를 조회하기 위해 boardDAO.getBoardCount(paramMap)를 호출하고, 결과를 반환

5) common > AuthAspect.java

정리: 
package paasta.msa.common;

import java.math.BigInteger;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Properties;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

@Component
@Aspect
public class AuthAspect {

@Resource(name = "apiProperties")
private Properties apiProperties;

@SuppressWarnings("deprecation")
public Object targetMethod(ProceedingJoinPoint jointPoint) {
    HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.currentRequestAttributes()).getRequest();

String apiKey = request.getHeader("apiKey");
String timestamp = request.getHeader("timestamp");

String apiMasterKey = apiProperties.getProperty("ApiMasterKey");
String salt = apiProperties.getProperty("ApiKeySalt");
String makeKey = null;
     Object result = null;

if (timestamp != null && !"".equals(timestamp)) {
MessageDigest md = null;
try {
md = MessageDigest.getInstance("SHA-256");
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
md.update(salt.getBytes());
md.update(timestamp.getBytes());
makeKey = String.format("%064x", new BigInteger(1, md.digest()));
}

if (apiKey == null || "".equals(apiKey) 
|| (!apiKey.equals(apiMasterKey)) && !apiKey.equals(makeKey)) {
        HttpServletResponse response = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getResponse();
        response.setHeader("Content-Type", "text/plain;charset=UTF-8");
        response.setStatus(HttpStatus.UNAUTHORIZED.value(), "API key not authorized");
} else {
        try {
result = jointPoint.proceed();
} catch (Throwable e) {
e.printStackTrace();
}
}

        return result;
    }
}

1. 

2.

6) common > CommonDAO.java

7) common > CommonUtil.java

8) common > PaastaExcepHndlr.java

9) common > PaastaOthersExcepHndlr.java

'학부 > PBL' 카테고리의 다른 글

Ch1. 블록체인의 큰 그림  (0) 2023.04.26