전자정부 프레임워크를 통해 게시판, 블로그 등을 쉬게 생성할 수 있다.
그러나 내 입맞대로 고치기 어려워 관련내용을 남긴다.
컨셉 : 관리는 기존 전자정부프레임워크를 그대로 쓰고 이용자 화면만 별도로 만든다.
먼저 관리자 로그인 한 뒤에 블로그를 생성한다.
기본개념이 블로그를 여러개 만들수 있도록 되어있다.
블로그 추가방법은 아래 링크 참조
https://nobang.tistory.com/entry/%EC%A0%84%EC%9E%90%EC%A0%95%EB%B6%80-%ED%94%84%EB%A0%88%EC%9E%84%EC%9B%8C%ED%81%AC-%EB%B8%94%EB%A1%9C%EA%B7%B8-%EC%B6%94%EA%B0%80
기존로직은 그대로(글쓰기, 글저장, 글목록, 글내용보기) 두고
글목록과 글 내용보기만 별도로 만든다.
1. Controller, Service, DAO, VO 등 서버단
참조 대상
유형 | 대상소스 | 비고 |
Controller | egovframework.com.cop.bbs.EgovBBSAttributeManageController.java | 게시판 관리를 위한 컨트롤러 클래스 |
Service | egovframework.com.cop.bbs.service.EgovBBSAttributeManageService.java | 게시판 관리를 위한 서비스 인터페이스 |
ServiceImpl | egovframework.com.cop.bbs.service.impl.EgovBBSAttributeManageServiceImpl.java | 게시판 관리를 위한 서비스 구현 클래스 |
DAO | egovframework.com.cop.bbs.service.impl.EgovBBSAttributeManageDAO.java | 게시판 관리를 위한 데이터처리 클래스 |
VO | egovframework.com.cop.bbs.service.BoardMaster.java | 게시판 관리를 위한 모델 클래스 |
VO | egovframework.com.cop.bbs.service.BoardMasterVO.java | 게시판 관리를 위한 VO 클래스 |
Blog만 사용할 예정이므로 blog package를 새로 만들고 그 아래에 각 파일들을 위치시킨다.
특이하게 service package에 Board, BoardVO가 위치해있다.(구조는 그대로 가져가기로 했으므로 그대로 사용)
기존서비스는 그대로 사용할 예정이므로 Board, BoardVO는 package경로만 확인한다.
이제 BBS로 되어있는 것을 Blog로 바꾸는 작업이다. 오류를 최소화 하기 위해 아랫단부터 변경한다.
- dao 도 특이하게 service.impl과 같이있다..
package egovframework.blog.service.impl; import java.util.List; import org.springframework.stereotype.Repository; import egovframework.com.cmm.service.impl.EgovComAbstractDAO; import egovframework.blog.service.Board; import egovframework.blog.service.BoardVO; @Repository("BlogArticleDAO") public class BlogArticleDAO extends EgovComAbstractDAO { public List<?> selectArticleList(BoardVO boardVO) { return list("BBSArticle.selectArticleList", boardVO); } public int selectArticleListCnt(BoardVO boardVO) { return (Integer)selectOne("BBSArticle.selectArticleListCnt", boardVO); } public int selectMaxInqireCo(BoardVO boardVO) { return (Integer)selectOne("BBSArticle.selectMaxInqireCo", boardVO); } public void updateInqireCo(BoardVO boardVO) { update("BBSArticle.updateInqireCo", boardVO); } public BoardVO selectArticleDetail(BoardVO boardVO) { return (BoardVO) selectOne("BBSArticle.selectArticleDetail", boardVO); } public void replyArticle(Board board) { insert("BBSArticle.replyArticle", board); } public List selectNoticeArticleList(BoardVO boardVO) { return (List) list("BBSArticle.selectNoticeArticleList", boardVO); } public List<?> selectGuestArticleList(BoardVO vo) { return list("BBSArticle.selectGuestArticleList", vo); } public int selectGuestArticleListCnt(BoardVO vo) { return (Integer)selectOne("BBSArticle.selectGuestArticleListCnt", vo); } /* * 블로그 관련 */ public BoardVO selectArticleCnOne(BoardVO boardVO) { return (BoardVO) selectOne("BBSArticle.selectArticleCnOne", boardVO); } public List selectBlogNmList(BoardVO boardVO) { return (List) list("BBSArticle.selectBlogNmList", boardVO); } public List<?> selectBlogListManager(BoardVO vo) { return list("BBSArticle.selectBlogListManager", vo); } public int selectBlogListManagerCnt(BoardVO vo) { return (Integer)selectOne("BBSArticle.selectBlogListManagerCnt", vo); } public List selectArticleDetailDefault(BoardVO boardVO) { return (List) list("BBSArticle.selectArticleDetailDefault", boardVO); } public int selectArticleDetailDefaultCnt(BoardVO boardVO) { return (Integer)selectOne("BBSArticle.selectArticleDetailDefaultCnt", boardVO); } public List selectArticleDetailCn(BoardVO boardVO) { return (List) list("BBSArticle.selectArticleDetailCn", boardVO); } } |
- service Interface는 select만 남겨놓는다(insert/update/delete는 제거)
package egovframework.blog.service; import java.util.List; import java.util.Map; import egovframework.rte.fdl.cmmn.exception.FdlException; public interface BlogArticleService { Map<String, Object> selectArticleList(BoardVO boardVO); BoardVO selectArticleDetail(BoardVO boardVO); List selectNoticeArticleList(BoardVO boardVO); Map<String, Object> selectGuestArticleList(BoardVO vo); /* * 블로그 관련 */ BoardVO selectArticleCnOne(BoardVO boardVO); List selectBlogNmList(BoardVO boardVO); Map<String, Object> selectBlogListManager(BoardVO boardVO); List selectArticleDetailDefault(BoardVO boardVO); int selectArticleDetailDefaultCnt(BoardVO boardVO); List selectArticleDetailCn(BoardVO boardVO); int selectLoginUser(BoardVO boardVO); } |
- service Impl
package egovframework.blog.service.impl; import java.util.HashMap; import java.util.List; import java.util.Map; import javax.annotation.Resource; import org.springframework.stereotype.Service; import egovframework.blog.service.BlogArticleService; import egovframework.blog.service.Board; import egovframework.com.cmm.service.EgovFileMngService; import egovframework.blog.service.BoardVO; import egovframework.rte.fdl.cmmn.EgovAbstractServiceImpl; import egovframework.rte.fdl.cmmn.exception.FdlException; import egovframework.rte.fdl.idgnr.EgovIdGnrService; import egovframework.rte.fdl.property.EgovPropertyService; @Service("BlogArticleService") public class BlogArticleServiceImpl extends EgovAbstractServiceImpl implements BlogArticleService { @Resource(name = "BlogArticleDAO") private BlogArticleDAO blogArticleDao; @Resource(name = "EgovFileMngService") private EgovFileMngService fileService; @Resource(name = "propertiesService") protected EgovPropertyService propertyService; @Resource(name = "egovNttIdGnrService") private EgovIdGnrService nttIdgenService; @Override public Map<String, Object> selectArticleList(BoardVO boardVO) { List<?> list = blogArticleDao.selectArticleList(boardVO); int cnt = blogArticleDao.selectArticleListCnt(boardVO); Map<String, Object> map = new HashMap<String, Object>(); map.put("resultList", list); map.put("resultCnt", Integer.toString(cnt)); return map; } @Override public BoardVO selectArticleDetail(BoardVO boardVO) { int iniqireCo = blogArticleDao.selectMaxInqireCo(boardVO); boardVO.setInqireCo(iniqireCo); blogArticleDao.updateInqireCo(boardVO); return blogArticleDao.selectArticleDetail(boardVO); } @Override public BoardVO selectArticleCnOne(BoardVO boardVO) { return blogArticleDao.selectArticleCnOne(boardVO); } @Override public List selectArticleDetailDefault(BoardVO boardVO) { return blogArticleDao.selectArticleDetailDefault(boardVO); } @Override public int selectArticleDetailDefaultCnt(BoardVO boardVO){ return blogArticleDao.selectArticleDetailDefaultCnt(boardVO); } @Override public List selectArticleDetailCn(BoardVO boardVO) { return blogArticleDao.selectArticleDetailCn(boardVO); } @Override public List selectNoticeArticleList(BoardVO boardVO) { return blogArticleDao.selectNoticeArticleList(boardVO); } @Override public List selectBlogNmList(BoardVO boardVO) { return blogArticleDao.selectBlogNmList(boardVO); } @Override public Map<String, Object> selectGuestArticleList(BoardVO vo) { List<?> list = blogArticleDao.selectGuestArticleList(vo); int cnt = blogArticleDao.selectGuestArticleListCnt(vo); Map<String, Object> map = new HashMap<String, Object>(); map.put("resultList", list); map.put("resultCnt", Integer.toString(cnt)); return map; } //@Override //public void insertArticle(Board board) throws FdlException { // insert/update는 관리자 화면에서 //} //@Override //public void updateArticle(Board board) { // insert/update는 관리자 화면에서 //} //@Override //public void deleteArticle(Board board) throws Exception { // insert/update는 관리자 화면에서 //} //@Override //public Map<String, Object> selectBlogListManager(BoardVO boardVO) { // insert/update는 관리자 화면에서 //return null; //} @Override public int selectLoginUser(BoardVO boardVO) { // TODO Auto-generated method stub return 0; } } |
- Controller 에서 request받을 경로와 return받을 경로, 사용할 service 경로 등을 수정
package egovframework.blog.web; import java.io.BufferedReader; import java.io.InputStreamReader; import java.net.URL; import java.net.URLEncoder; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import javax.annotation.Resource; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Controller; import org.springframework.ui.ModelMap; import org.springframework.validation.BindingResult; import org.springframework.web.bind.annotation.ModelAttribute; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.multipart.MultipartFile; import org.springframework.web.multipart.MultipartHttpServletRequest; import org.springframework.web.servlet.ModelAndView; import org.springmodules.validation.commons.DefaultBeanValidator; import egovframework.com.cmm.EgovMessageSource; import egovframework.com.cmm.EgovWebUtil; import egovframework.com.cmm.LoginVO; import egovframework.com.cmm.service.EgovFileMngService; import egovframework.com.cmm.service.EgovFileMngUtil; import egovframework.com.cmm.service.FileVO; import egovframework.com.cmm.util.EgovUserDetailsHelper; import egovframework.com.cmm.util.EgovXssChecker; //import egovframework.blog.service.Blog;//관리는 제외 : 블로그게시판 관리를 위한 모델 클래스 //import egovframework.blog.service.BlogVO;//관리는 제외 : 커뮤니티 관리를 위한 VO 클래스 import egovframework.blog.service.Board;//게시물에 대한 데이터 처리 모델 //import egovframework.blog.service.BoardMaster;//관리는 제외 : 게시판 속성정보를 담기위한 엔티티 클래스 //import egovframework.blog.service.BoardMasterVO;//관리는 제외 : 게시판 속성 정보를 관리하기 위한 VO 클래스 import egovframework.blog.service.BoardVO;//게시물 관리를 위한 VO 클래스 import egovframework.blog.service.BlogArticleService; //import egovframework.blog.service.EgovBBSMasterService; // 관리자는 제외 //import egovframework.blog.service.EgovBBSSatisfactionService;// 만족도 제외 import egovframework.com.cop.cmt.service.CommentVO; import egovframework.com.cop.cmt.service.EgovArticleCommentService; import egovframework.com.cop.cmy.service.CommunityVO; import egovframework.com.cop.tpl.service.EgovTemplateManageService; import egovframework.com.cop.tpl.service.TemplateInfVO; import egovframework.rte.fdl.property.EgovPropertyService; import egovframework.rte.fdl.string.EgovStringUtil; import egovframework.rte.ptl.mvc.tags.ui.pagination.PaginationInfo; /** * 게시물 관리를 위한 컨트롤러 클래스 * @author 공통서비스개발팀 이삼섭 * @since 2009.06.01 * @version 1.0 * @see * *
*/ @Controller public class BlogController { private static final Logger LOGGER = LoggerFactory.getLogger(BlogController.class); @Resource(name = "BlogArticleService") private BlogArticleService blogArticleService; // // @Resource(name = "EgovBBSMasterService") // private EgovBBSMasterService egovBBSMasterService; // // @Resource(name = "EgovFileMngService") // private EgovFileMngService fileMngService; // // @Resource(name = "EgovFileMngUtil") // private EgovFileMngUtil fileUtil; // @Resource(name = "propertiesService") protected EgovPropertyService propertyService; // @Resource(name="egovMessageSource") EgovMessageSource egovMessageSource; // @Resource(name = "EgovArticleCommentService") protected EgovArticleCommentService egovArticleCommentService; // // @Resource(name = "EgovBBSSatisfactionService") // private EgovBBSSatisfactionService bbsSatisfactionService; // @Resource(name = "EgovTemplateManageService") private EgovTemplateManageService egovTemplateManageService; // // @Autowired // private DefaultBeanValidator beanValidator; //protected Logger log = Logger.getLogger(this.getClass()); /** * XSS 방지 처리. * * @param data * @return */ protected String unscript(String data) { if (data == null || data.trim().equals("")) { return ""; } String ret = data; ret = ret.replaceAll("<(S|s)(C|c)(R|r)(I|i)(P|p)(T|t)", "<script"); ret = ret.replaceAll("</(S|s)(C|c)(R|r)(I|i)(P|p)(T|t)", "</script"); ret = ret.replaceAll("<(O|o)(B|b)(J|j)(E|e)(C|c)(T|t)", "<object"); ret = ret.replaceAll("</(O|o)(B|b)(J|j)(E|e)(C|c)(T|t)", "</object"); ret = ret.replaceAll("<(A|a)(P|p)(P|p)(L|l)(E|e)(T|t)", "<applet"); ret = ret.replaceAll("</(A|a)(P|p)(P|p)(L|l)(E|e)(T|t)", "</applet"); ret = ret.replaceAll("<(E|e)(M|m)(B|b)(E|e)(D|d)", "<embed"); ret = ret.replaceAll("</(E|e)(M|m)(B|b)(E|e)(D|d)", "<embed"); ret = ret.replaceAll("<(F|f)(O|o)(R|r)(M|m)", "<form"); ret = ret.replaceAll("</(F|f)(O|o)(R|r)(M|m)", "<form"); return ret; } /** * 게시물에 대한 목록을 조회한다. * * @param boardVO * @param sessionVO * @param model * @return * @throws Exception */ @RequestMapping("/blog/selectArticleList.do") public String selectArticleList(@ModelAttribute("searchVO") BoardVO boardVO, ModelMap model) throws Exception { LoginVO user = (LoginVO)EgovUserDetailsHelper.getAuthenticatedUser(); Boolean isAuthenticated = EgovUserDetailsHelper.isAuthenticated(); //KISA 보안취약점 조치 (2018-12-10, 이정은) if(!isAuthenticated) { return "egovframework/com/uat/uia/EgovLoginUsr"; } boardVO.setBbsId(boardVO.getBbsId()); boardVO.setBbsNm(boardVO.getBbsNm()); boardVO.setPageUnit(propertyService.getInt("pageUnit")); boardVO.setPageSize(propertyService.getInt("pageSize")); PaginationInfo paginationInfo = new PaginationInfo(); paginationInfo.setCurrentPageNo(boardVO.getPageIndex()); paginationInfo.setRecordCountPerPage(boardVO.getPageUnit()); paginationInfo.setPageSize(boardVO.getPageSize()); boardVO.setFirstIndex(paginationInfo.getFirstRecordIndex()); boardVO.setLastIndex(paginationInfo.getLastRecordIndex()); boardVO.setRecordCountPerPage(paginationInfo.getRecordCountPerPage()); Map<String, Object> map = blogArticleService.selectArticleList(boardVO); int totCnt = Integer.parseInt((String)map.get("resultCnt")); //공지사항 추출 List noticeList = blogArticleService.selectNoticeArticleList(boardVO); paginationInfo.setTotalRecordCount(totCnt); if(user != null) { model.addAttribute("sessionUniqId", user.getUniqId()); } model.addAttribute("resultList", map.get("resultList")); model.addAttribute("resultCnt", map.get("resultCnt")); model.addAttribute("articleVO", boardVO); model.addAttribute("bbsNm", "Custom Blog Sample"); model.addAttribute("bbsId", "BBSMSTR_000000000002");// 블로그는 1개만 운영하므로 생성된 블로그의 bbsId 사용-- 나중에 property로 model.addAttribute("bbsTmplatCours", "/css/egovframework/com/cop/tpl/egovBaseTemplate.css");//기본 BBS template 지정 : css 경로. 추후 변경 model.addAttribute("paginationInfo", paginationInfo); model.addAttribute("noticeList", noticeList); return "egovframework/com/blog/BlogArticleList"; } /** * 게시물에 대한 상세 정보를 조회한다. * * @param boardVO * @param sessionVO * @param model * @return * @throws Exception */ @RequestMapping("/blog/selectArticleDetail.do") public String selectArticleDetail(@ModelAttribute("searchVO") BoardVO boardVO, ModelMap model) throws Exception { LoginVO user = (LoginVO)EgovUserDetailsHelper.getAuthenticatedUser(); boardVO.setLastUpdusrId(user.getUniqId()); BoardVO vo = blogArticleService.selectArticleDetail(boardVO); model.addAttribute("result", vo); model.addAttribute("sessionUniqId", user.getUniqId()); //비밀글은 작성자만 볼수 있음 if(!EgovStringUtil.isEmpty(vo.getSecretAt()) && vo.getSecretAt().equals("Y") && !user.getUniqId().equals(vo.getFrstRegisterId())) return"forward:/blog/selectArticleList.do"; //---------------------------- // template 처리 (기본 BBS template 지정 포함) //---------------------------- model.addAttribute("bbsTmplatCours", "/css/egovframework/com/cop/tpl/egovBaseTemplate.css");//기본 BBS template 지정 : css 경로. 추후 변경 ////----------------------------- if (egovArticleCommentService != null){ if (egovArticleCommentService.canUseComment(boardVO.getBbsId())) { model.addAttribute("useComment", "true"); } } ////-------------------------- model.addAttribute("bbsId", "BBSMSTR_000000000002");// 블로그는 1개만 운영하므로 생성된 블로그의 bbsId 사용-- 나중에 property로 return "egovframework/com/blog/BlogArticleDetail"; } /********************* * 블로그관련 * ********************/ /** * 블로그 게시물에 대한 상세 타이틀을 조회한다. * * @param boardVO * @param sessionVO * @param model * @return * @throws Exception */ @RequestMapping("/blog/selectArticleBlogDetail.do") public ModelAndView selectArticleBlogDetail(@ModelAttribute("searchVO") BoardVO boardVO, ModelMap model) throws Exception { LoginVO user = (LoginVO)EgovUserDetailsHelper.getAuthenticatedUser(); BoardVO vo = new BoardVO(); boardVO.setPageUnit(propertyService.getInt("pageUnit")); boardVO.setPageSize(propertyService.getInt("pageSize")); PaginationInfo paginationInfo = new PaginationInfo(); paginationInfo.setCurrentPageNo(boardVO.getPageIndex()); paginationInfo.setRecordCountPerPage(boardVO.getPageUnit()); paginationInfo.setPageSize(boardVO.getPageSize()); boardVO.setFirstIndex(paginationInfo.getFirstRecordIndex()); boardVO.setLastIndex(paginationInfo.getLastRecordIndex()); boardVO.setRecordCountPerPage(paginationInfo.getRecordCountPerPage()); List blogSubJectList = blogArticleService.selectArticleDetailDefault(boardVO); vo = blogArticleService.selectArticleCnOne(boardVO); int totCnt = blogArticleService.selectArticleDetailDefaultCnt(boardVO); paginationInfo.setTotalRecordCount(totCnt); ModelAndView mav = new ModelAndView("jsonView"); mav.addObject("blogSubJectList", blogSubJectList); mav.addObject("paginationInfo", paginationInfo); if(vo.getNttCn() != null){ mav.addObject("blogCnOne", vo); } //비밀글은 작성자만 볼수 있음 if(!EgovStringUtil.isEmpty(vo.getSecretAt()) && vo.getSecretAt().equals("Y") && !user.getUniqId().equals(vo.getFrstRegisterId())) mav.setViewName("forward:/blog/selectArticleList.do"); return mav; } /** * 블로그 게시물에 대한 상세 내용을 조회한다. * * @param boardVO * @param sessionVO * @param model * @return * @throws Exception */ @RequestMapping("/blog/selectArticleBlogDetailCn.do") public ModelAndView selectArticleBlogDetailCn(@ModelAttribute("searchVO") BoardVO boardVO, @ModelAttribute("commentVO") CommentVO commentVO, ModelMap model) throws Exception { LoginVO user = (LoginVO)EgovUserDetailsHelper.getAuthenticatedUser(); boardVO.setLastUpdusrId(user.getUniqId()); Boolean isAuthenticated = EgovUserDetailsHelper.isAuthenticated(); //KISA 보안취약점 조치 (2018-12-10, 이정은) if(!isAuthenticated) { throw new IllegalAccessException("Login Required!"); } BoardVO vo = blogArticleService.selectArticleDetail(boardVO); //---------------------------- // 댓글 처리 //---------------------------- CommentVO articleCommentVO = new CommentVO(); commentVO.setWrterNm(user.getName()); PaginationInfo paginationInfo = new PaginationInfo(); paginationInfo.setCurrentPageNo(commentVO.getSubPageIndex()); paginationInfo.setRecordCountPerPage(commentVO.getSubPageUnit()); paginationInfo.setPageSize(commentVO.getSubPageSize()); commentVO.setSubFirstIndex(paginationInfo.getFirstRecordIndex()); commentVO.setSubLastIndex(paginationInfo.getLastRecordIndex()); commentVO.setSubRecordCountPerPage(paginationInfo.getRecordCountPerPage()); Map<String, Object> map = egovArticleCommentService.selectArticleCommentList(commentVO); int totCnt = Integer.parseInt((String)map.get("resultCnt")); paginationInfo.setTotalRecordCount(totCnt); //댓글 처리 END //---------------------------- List blogCnList = blogArticleService.selectArticleDetailCn(boardVO); ModelAndView mav = new ModelAndView("jsonView"); // 수정 처리된 후 댓글 등록 화면으로 처리되기 위한 구현 if (commentVO.isModified()) { commentVO.setCommentNo(""); commentVO.setCommentCn(""); } // 수정을 위한 처리 if (!commentVO.getCommentNo().equals("")) { mav.setViewName ("forward:/cop/cmt/updateArticleCommentView.do"); } mav.addObject("blogCnList", blogCnList); mav.addObject("resultUnder", vo); mav.addObject("paginationInfo", paginationInfo); mav.addObject("resultList", map.get("resultList")); mav.addObject("resultCnt", map.get("resultCnt")); mav.addObject("articleCommentVO", articleCommentVO); // validator 용도 commentVO.setCommentCn(""); // 등록 후 댓글 내용 처리 //비밀글은 작성자만 볼수 있음 if(!EgovStringUtil.isEmpty(vo.getSecretAt()) && vo.getSecretAt().equals("Y") && !user.getUniqId().equals(vo.getFrstRegisterId())) mav.setViewName("forward:/blog/selectArticleList.do"); return mav; } } |
2. JSP 등 클라이언트단
com.cop.bbs에 있는 com.blog관련파일을 blog폴더로 복사하여 사용
3. properties
resources의 message를 blog폴도 아래에도 생성.
com.cop.bbs property 말고 com.cop.blog property를 복사한다
그리고는 경로를 새로 생성한 경로로 호출해본다.
--localhost:8080/egovframework-all-in-one/blog/selectArticleList.do
일단 화면은 나온다.
이제 뭐가 문제인지 따져보자 ㅎ
Controller 안에 method마다 있는 login 관련로직은 모두 제거한다.
모든 사용자가 볼 수 있으므로
LoginVO user = (LoginVO)EgovUserDetailsHelper.getAuthenticatedUser(); Boolean isAuthenticated = EgovUserDetailsHelper.isAuthenticated(); if(!isAuthenticated) { return "egovframework/com/uat/uia/EgovLoginUsr"; } |