This commit is contained in:
JSYOO 2021-09-15 14:03:24 +09:00
commit 1810cabe6d
35 changed files with 788 additions and 286 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

View File

@ -1,12 +1,17 @@
package nlib.bbs.service;
import java.util.List;
import nlib.cmm.service.PagingVO;
import nlib.util.StringUtil;
public class ArticleVO extends PagingVO {
private String articleId; /* 게시글ID */
private String mngOrgCd; /* 관리문화원코드 */
private String mngOrgNm; /* 관리문화원명 */
private String bdType; /* 게시판유형 */
private String bdTypeName; /* 게시판유형명 */
private String title; /* 제목 */
private String content; /* 내용 */
@ -18,12 +23,27 @@ public class ArticleVO extends PagingVO {
private int viewCnt; /* 조회수 */
private String bdAttachFileId; /* 첨부파일아이디 */
private String attachYn; /* 첨부파일존재여부 */
private String regId; /* 등록자아이디 */
private String regNm; /* 등록자명 */
private String regDd; /* 등록일자 */
private String modId; /* 등록자아이디 */
private String modDd; /* 등록일자 */
private int rno; /* 글번호 */
// 검색관련
private String searchType; /* 검색대상구분 */
private String searchKeyword; /* 검색어 */
// 첨부파일
private List<AttachFileVO> attachFiles = null; /* 첨부파일목록 */
public int getAttachFileCnt() {
if(attachFiles == null) return 0;
return attachFiles.size();
}
public String getArticleId() {
return articleId;
@ -115,6 +135,57 @@ public class ArticleVO extends PagingVO {
public void setModDd(String modDd) {
this.modDd = modDd;
}
public String getRegNm() {
return regNm;
}
public void setRegNm(String regNm) {
this.regNm = regNm;
}
public int getRno() {
return rno;
}
public void setRno(int rno) {
this.rno = rno;
}
public String getSearchType() {
return searchType;
}
public void setSearchType(String searchType) {
this.searchType = searchType;
}
public String getSearchKeyword() {
return searchKeyword;
}
public String getEscapeSearchKeyword() {
return StringUtil.getSqlSearchKeyword(searchKeyword);
}
public void setSearchKeyword(String searchKeyword) {
this.searchKeyword = searchKeyword;
}
public String getAttachYn() {
return attachYn;
}
public void setAttachYn(String attachYn) {
this.attachYn = attachYn;
}
public String getMngOrgNm() {
return mngOrgNm;
}
public void setMngOrgNm(String mngOrgNm) {
this.mngOrgNm = mngOrgNm;
}
public String getBdTypeName() {
return bdTypeName;
}
public void setBdTypeName(String bdTypeName) {
this.bdTypeName = bdTypeName;
}
public List<AttachFileVO> getAttachFiles() {
return attachFiles;
}
public void setAttachFiles(List<AttachFileVO> attachFiles) {
this.attachFiles = attachFiles;
}
}

View File

@ -0,0 +1,167 @@
package nlib.bbs.service;
/**
* <pre>
* @Class Name : AttachFileVO.java
*
* @Description : 첨부파일 정보 VO
*
*
* @프로젝트명: 지방문화원 통합자료관리시스템 구축사업 (2021)
*
* </pre>
*
* @ ------------ -------- ---------------------------
* @ 수정일 수정자 수정내용
* @ ------------ -------- ---------------------------
* @ 2021. 9. 14. KNKIM 최초 생성
*
*
* @author 이씨플라자 * DIGITALSHIP KNKIM
* @since 2021. 9. 14.
* @version 1.0
*
*/
public class AttachFileVO {
private String subPathKey; /* 첨부파일서브경로 */
private String fileMask; /* 첨부파일아이디 */
private String fileId; /* 업무 아이디 */
private int fileSeq; /* 파일 번호 */
private String fileName; /* 파일 이름 */
private int fileSize; /* 파일 사이즈 */
private String fileTypeCd; /* 파일 유형(디지털화사용) */
private int downloadCount; /* 파일 다운로드 횟수 */
private String downloadExpireDate; /* 파일 만료 날짜 */
private int downloadLimitCount; /* 파일 다운로드 제한 횟수 */
private String deleteYn; /* 삭제 여부 */
private String streamingUrl; /* 스트리밍URL */
private String content; /* 내용주기 */
private String atchTypeCd; /* 첨부파일유형 */
private String regDd; /* 등록 날짜 */
public String getFileMask() {
return fileMask;
}
public void setFileMask(String fileMask) {
this.fileMask = fileMask;
}
public String getFileId() {
return fileId;
}
public void setFileId(String fileId) {
this.fileId = fileId;
}
public String getFileName() {
return fileName;
}
public void setFileName(String fileName) {
this.fileName = fileName;
}
public String getFileTypeCd() {
return fileTypeCd;
}
public void setFileTypeCd(String fileTypeCd) {
this.fileTypeCd = fileTypeCd;
}
public String getDownloadExpireDate() {
return downloadExpireDate;
}
public void setDownloadExpireDate(String downloadExpireDate) {
this.downloadExpireDate = downloadExpireDate;
}
public String getDeleteYn() {
return deleteYn;
}
public void setDeleteYn(String deleteYn) {
this.deleteYn = deleteYn;
}
public String getStreamingUrl() {
return streamingUrl;
}
public void setStreamingUrl(String streamingUrl) {
this.streamingUrl = streamingUrl;
}
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}
public String getAtchTypeCd() {
return atchTypeCd;
}
public void setAtchTypeCd(String atchTypeCd) {
this.atchTypeCd = atchTypeCd;
}
public String getRegDd() {
return regDd;
}
public void setRegDd(String regDd) {
this.regDd = regDd;
}
public int getFileSeq() {
return fileSeq;
}
public void setFileSeq(int fileSeq) {
this.fileSeq = fileSeq;
}
public int getFileSize() {
return fileSize;
}
public void setFileSize(int fileSize) {
this.fileSize = fileSize;
}
public int getDownloadCount() {
return downloadCount;
}
public void setDownloadCount(int downloadCount) {
this.downloadCount = downloadCount;
}
public int getDownloadLimitCount() {
return downloadLimitCount;
}
public void setDownloadLimitCount(int downloadLimitCount) {
this.downloadLimitCount = downloadLimitCount;
}
public String getSubPathKey() {
return subPathKey;
}
public void setSubPathKey(String subPathKey) {
this.subPathKey = subPathKey;
}
}

View File

@ -37,34 +37,10 @@ import nlib.util.StringUtil;
*
*/
@Mapper("ancmntDAO")
public interface AncmntDAO {
public interface AncmntDAO extends BoardDAO {
/*
* 게시글 목록을 조회한다.
* BoardDAO 상속 내용과 동일
*/
public List<ArticleVO> listArticles(ArticleVO ArticleVO) throws Exception;
/**
* 게시글 건수를 조회한다.
*/
public int countArticles(ArticleVO ArticleVO) throws Exception;
/**
* 조회수를 증가시킨다.
*
* @param
* @return
* @throws Exception
*/
public int updateRead(ArticleVO notiVO) throws Exception;
/**
* 게시글 상세 내용을 조회한다.
*
* @param
* @return
* @throws Exception
*/
public ArticleVO selectArticle(ArticleVO notiVO) throws Exception;
}

View File

@ -10,54 +10,19 @@ import org.springframework.stereotype.Service;
import nlib.bbs.service.ArticleVO;
import nlib.bbs.service.BoardService;
import nlib.util.StringUtil;
@Service("ancmntService")
public class AncmntServiceImpl implements BoardService
public class AncmntServiceImpl extends BoardServiceImpl
{
private static final Logger log = LoggerFactory.getLogger(AncmntServiceImpl.class);
static Logger log = LoggerFactory.getLogger(AncmntServiceImpl.class);
@Resource(name="ancmntDAO")
private AncmntDAO ancmntDAO;
AncmntDAO ancmntDAO;
/*
* 게시글 목록을 조회한다.
*/
public List<ArticleVO> listArticles(ArticleVO articleVO) throws Exception {
return ancmntDAO.listArticles(articleVO);
}
/**
* 게시글 건수를 조회한다.
*/
public int countArticles(ArticleVO articleVO) throws Exception {
return ancmntDAO.countArticles(articleVO);
}
/**
* 조회수를 증가시킨다.
*
* @param
* @return
* @throws Exception
*/
public int updateRead(ArticleVO articleVO) throws Exception {
return ancmntDAO.updateRead(articleVO);
}
/**
* 게시글 상세 내용을 조회한다.
*
* @param
* @return
* @throws Exception
*/
public ArticleVO selectArticle(ArticleVO articleVO) throws Exception {
updateRead(articleVO);
return ancmntDAO.selectArticle(articleVO);
@Override
public BoardDAO getBoardDAO() {
return ancmntDAO;
}
}

View File

@ -10,13 +10,14 @@ import egovframework.com.cmm.service.impl.EgovComAbstractDAO;
import egovframework.rte.psl.dataaccess.mapper.Mapper;
import nlib.cmm.service.NotificationVO;
import nlib.bbs.service.ArticleVO;
import nlib.bbs.service.AttachFileVO;
import nlib.cmm.service.NlibProperty;
import nlib.user.service.NlibLoginVO;
import nlib.util.StringUtil;
/**
* <pre>
* @Class Name : AncmntDAO.java
* @Class Name : BoardDAO.java
*
* @Description : 공지사항 정보 제공 DAO
*
@ -67,4 +68,15 @@ public interface BoardDAO {
* @throws Exception
*/
public ArticleVO selectArticle(ArticleVO notiVO) throws Exception;
/**
* 첨부파일 목록을 조회한다.
*
* @param
* @return
* @throws Exception
*/
public List<AttachFileVO> listAttachFiles(String attachFileId) throws Exception;
}

View File

@ -1,70 +1,68 @@
package nlib.bbs.service.impl;
import java.util.List;
import javax.annotation.Resource;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import nlib.bbs.service.BoardServiceApi;
import nlib.restful.service.DataApiReqVO;
import nlib.restful.service.DataApiResVO;
import nlib.bbs.service.ArticleVO;
import nlib.bbs.service.BoardService;
import nlib.util.StringUtil;
@Service("boardService")
public class BoardServiceImpl implements BoardServiceApi
public abstract class BoardServiceImpl implements BoardService
{
private static final Logger log = LoggerFactory.getLogger(BoardServiceImpl.class);
static Logger log = LoggerFactory.getLogger(BoardServiceImpl.class);
@Resource(name = "boardDAO")
private BoardDAOApi boardDAO;
public DataApiResVO listNotices(DataApiReqVO reqVO) {
return boardDAO.listNotices(reqVO);
}
public DataApiResVO selectNotice(DataApiReqVO reqVO) {
return boardDAO.selectNotice(reqVO);
}
public DataApiResVO listFAQs(DataApiReqVO reqVO) {
return boardDAO.listFAQs(reqVO);
}
public DataApiResVO selectFAQ(DataApiReqVO reqVO) {
return boardDAO.selectFAQ(reqVO);
}
public abstract BoardDAO getBoardDAO();
/*
* 묻고답하기 목록 조회한다.
*
* (non-Javadoc)
* @see nlib.bbs.service.BoardService#listQnAs(nlib.restful.service.DataApiReqVO)
* 게시글 목록을 조회한다.
*/
public DataApiResVO listQnAs(DataApiReqVO reqVO) {
return boardDAO.listQnAs(reqVO);
public List<ArticleVO> listArticles(ArticleVO articleVO) throws Exception {
return getBoardDAO().listArticles(articleVO);
}
public DataApiResVO selectQnA(DataApiReqVO reqVO) {
return boardDAO.selectQnA(reqVO);
/**
* 게시글 건수를 조회한다.
*/
public int countArticles(ArticleVO articleVO) throws Exception {
return getBoardDAO().countArticles(articleVO);
}
public DataApiResVO insertQnA(DataApiReqVO reqVO) {
return boardDAO.insertQnA(reqVO);
/**
* 조회수를 증가시킨다.
*
* @param
* @return
* @throws Exception
*/
public int updateRead(ArticleVO articleVO) throws Exception {
return getBoardDAO().updateRead(articleVO);
}
public DataApiResVO verifyWriter(DataApiReqVO reqVO) {
return null;
}
/**
* 게시글 상세 내용을 조회한다.
*
* @param
* @return
* @throws Exception
*/
public ArticleVO selectArticle(ArticleVO articleVO) throws Exception {
public DataApiResVO updateQnA(DataApiReqVO reqVO) {
return boardDAO.updateQnA(reqVO);
}
// 게시글 조회
ArticleVO retVO = getBoardDAO().selectArticle(articleVO);
// 첨부파일 조회
if(StringUtil.isNotEmpty(retVO.getBdAttachFileId())) retVO.setAttachFiles(getBoardDAO().listAttachFiles(retVO.getBdAttachFileId()));
// 조회수 증가
updateRead(articleVO);
public DataApiResVO deleteQnA(DataApiReqVO reqVO) {
return boardDAO.deleteQnA(reqVO);
return retVO;
}
}

View File

@ -0,0 +1,70 @@
package nlib.bbs.service.impl;
import javax.annotation.Resource;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import nlib.bbs.service.BoardServiceApi;
import nlib.restful.service.DataApiReqVO;
import nlib.restful.service.DataApiResVO;
@Service("boardService")
public class BoardServiceImplApi implements BoardServiceApi
{
private static final Logger log = LoggerFactory.getLogger(BoardServiceImplApi.class);
@Resource(name = "boardDAO")
private BoardDAOApi boardDAO;
public DataApiResVO listNotices(DataApiReqVO reqVO) {
return boardDAO.listNotices(reqVO);
}
public DataApiResVO selectNotice(DataApiReqVO reqVO) {
return boardDAO.selectNotice(reqVO);
}
public DataApiResVO listFAQs(DataApiReqVO reqVO) {
return boardDAO.listFAQs(reqVO);
}
public DataApiResVO selectFAQ(DataApiReqVO reqVO) {
return boardDAO.selectFAQ(reqVO);
}
/*
* 묻고답하기 목록 조회한다.
*
* (non-Javadoc)
* @see nlib.bbs.service.BoardService#listQnAs(nlib.restful.service.DataApiReqVO)
*/
public DataApiResVO listQnAs(DataApiReqVO reqVO) {
return boardDAO.listQnAs(reqVO);
}
public DataApiResVO selectQnA(DataApiReqVO reqVO) {
return boardDAO.selectQnA(reqVO);
}
public DataApiResVO insertQnA(DataApiReqVO reqVO) {
return boardDAO.insertQnA(reqVO);
}
public DataApiResVO verifyWriter(DataApiReqVO reqVO) {
return null;
}
public DataApiResVO updateQnA(DataApiReqVO reqVO) {
return boardDAO.updateQnA(reqVO);
}
public DataApiResVO deleteQnA(DataApiReqVO reqVO) {
return boardDAO.deleteQnA(reqVO);
}
}

View File

@ -47,23 +47,11 @@ public class AncmntController extends NlibCommonController
public String listAncmnts(
HttpServletRequest req,
@RequestParam Map<String, String> paramMap,
ArticleVO articleVO,
ArticleVO searchArticleVO,
ModelMap model
) throws Exception {
int pageIndex = StringUtil.toNumber(paramMap.get("pageIndex"), 1);
int pageSize = StringUtil.toNumber(paramMap.get("pageSize"), DEFUALT_PAGE_SIZE);
log.debug("listAncmnt > pageIndex = " + pageIndex);
log.debug("listAncmnt > pageSize = " + pageSize);
ArticleVO searchArticleVO = new ArticleVO();
searchArticleVO.setPageIndex(pageIndex);
searchArticleVO.setPageSize(pageSize);
model.addAttribute("searchArticleVO", searchArticleVO);
model.addAttribute("pageSize", pageSize);
model.addAttribute("pageIndex", pageIndex);
model.addAttribute("searchArticle", searchArticleVO);
return "nlib/bbs/listAncmnts";
}
@ -75,22 +63,17 @@ public class AncmntController extends NlibCommonController
* @return
*/
@RequestMapping(value="/bbs/listAncmntsAjax.do")
public ResponseEntity<String> listAncmntsAjax(HttpServletRequest req,
Authentication authentication, @RequestBody Map<String, String> paramMap) throws Exception {
public ResponseEntity<String> listAncmntsAjax(
HttpServletRequest req,
Authentication authentication,
@RequestBody ArticleVO searchArticleVO) throws Exception {
int pageIndex = StringUtil.toNumber(paramMap.get("pageIndex"), 1);
int pageSize = StringUtil.toNumber(paramMap.get("pageSize"), DEFUALT_PAGE_SIZE);
if(searchArticleVO.getPageIndex() < 1) searchArticleVO.setPageIndex(1);
if(searchArticleVO.getPageSize() < 1) searchArticleVO.setPageSize(DEFUALT_PAGE_SIZE);
log.debug("listNotificationsAjax > pageIndex = " + pageIndex);
log.debug("listNotificationsAjax > pageSize = " + pageSize);
List<ArticleVO> list = ancmntService.listArticles(searchArticleVO);
ArticleVO searchNotificationtVO = new ArticleVO();
searchNotificationtVO.setPageIndex(pageIndex);
searchNotificationtVO.setPageSize(pageSize);
List<ArticleVO> list = ancmntService.listArticles(searchNotificationtVO);
int totRecordCount = ancmntService.countArticles(searchNotificationtVO);
int totRecordCount = ancmntService.countArticles(searchArticleVO);
//-------------------------------
// JSON변환 응답 처리
@ -107,41 +90,22 @@ public class AncmntController extends NlibCommonController
}
// /**
// * 알림 상세 내용 조회한다.
// *
// * @param req
// * @return
// */
// @RequestMapping("/cmm/selectNotificationAjax.do")
// public ResponseEntity<String> selectNotificationAjax(HttpServletRequest req, Authentication authentication, @RequestBody Map<String, String> paramMap) throws Exception {
//
// String notiId = paramMap.get("notiId"); // 알림ID
// String pageIndex = paramMap.get("pageIndex");
// String pageSize = paramMap.get("pageSize");
//
// log.debug("selectNotificationAjax > notiId = " + notiId);
//
// ArticleVO paramNotiVO = new ArticleVO();
// paramNotiVO.setNotiId(notiId);
// paramNotiVO.setRecvUserId(getMbInfoId(req));
// paramNotiVO.setPageIndex(pageIndex);
// paramNotiVO.setPageSize(pageSize);
//
// // 읽음처리 상세내용 조회
// ArticleVO articleVO = ancmntService.selectNotification(paramNotiVO);
//
// //-------------------------------
// // JSON변환 응답 처리
// //-------------------------------
// // JS-GRID 페이징 처리를 포함한 응답값 처리
// // {data: [{...}],
// // itemsCount: 255
// // }
// HashMap<String, Object> retMap = new HashMap<String, Object>();
// retMap.put("data", articleVO);
//
// return makeResponseEntityJson(retMap);
// }
//
/**
* 알림 상세 내용 조회한다.
*
* @param req
* @return
*/
@RequestMapping("/bbs/selectAncmntArticle.do")
public String selectAncmntArticle(HttpServletRequest req, Authentication authentication, ArticleVO searchArticleVO, ModelMap model) throws Exception {
// 읽음처리 상세내용 조회
ArticleVO articleVO = ancmntService.selectArticle(searchArticleVO);
model.addAttribute("searchArticle", searchArticleVO);
model.addAttribute("article", articleVO);
return "nlib/bbs/selectAncmntArticle";
}
}

View File

@ -2,7 +2,6 @@ package nlib.cmm.fileupload;
import java.io.File;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
@ -13,7 +12,6 @@ import javax.servlet.http.HttpServletResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
@ -28,8 +26,8 @@ import org.springframework.web.servlet.ModelAndView;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import egovframework.com.cmm.EgovWebUtil;
import egovframework.com.cmm.service.FileVO;
import nlib.bbs.service.AttachFileVO;
import nlib.cmm.exception.ErrorMessage;
import nlib.cmm.service.NlibProperty;
import nlib.util.FileUtil;
@ -63,19 +61,16 @@ public class FileUploadController {
private static final Logger log = LoggerFactory.getLogger(FileUploadController.class);
@Resource(name="nlibProperty")
NlibProperty nlibProperty;
/**
* 첨부파일이 저장되는 최상위 위치
*/
private String FILEUPLOAD_BASE_PATH = nlibProperty.getProperty("fileupload.base.path");
private String FILEUPLOAD_BASE_PATH = NlibProperty.getProperty("fileupload.base.path");
/**
* 첨부파일 임시 저장 위치
*/
private String FILEUPLOAD_TEMP_SUBPATH = nlibProperty.getProperty("fileupload.temp.subpath");
private String FILEUPLOAD_TEMP_SUBPATH = NlibProperty.getProperty("fileupload.temp.subpath");
/**
* 경로 부적합 오류 메시지
@ -121,7 +116,7 @@ public class FileUploadController {
ErrorMessage errorMessage = new ErrorMessage("ERROR", message);
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(errorMessage);
}
String subPath = nlibProperty.getProperty(subPathKey);
String subPath = NlibProperty.getProperty(subPathKey);
if(StringUtil.isEmpty(subPath)) {
message = "첨부파일이 저장되는 하위 위치정보값을 찾을 수 없습니다.";
log.error(message + " : 매개변수 subPathKey의 속성값 부재");
@ -222,16 +217,16 @@ public class FileUploadController {
* @return
* @throws Exception
*/
@RequestMapping(value="/fileupload/downloadFiles.do")
public ModelAndView download(@RequestParam HashMap<Object, Object> params, ModelAndView mv) throws Exception {
@RequestMapping(value="/fileupload/downloadAttachFile.do")
public ModelAndView downloadAttachFile(AttachFileVO attachFileVO, ModelAndView mv) throws Exception {
// TODO 권한 설정 기능 추가 필요
String fid = (String) params.get("fid");
String fname = (String) params.get("fname");
String subPath = nlibProperty.getProperty((String) params.get("subPathKey"));
String subPath = NlibProperty.getProperty(attachFileVO.getSubPathKey());
String fullPath = FILEUPLOAD_BASE_PATH + "/" + subPath + "/" + attachFileVO.getFileId() + "-" + attachFileVO.getFileSeq();
log.debug("downloadAttachFile > fullPath = " + fullPath);
String fullPath = FILEUPLOAD_BASE_PATH + "/" + subPath + "/" + fid;
if(FileUtil.isNotValid(fullPath)) {
throw new Exception(MSG_NOT_VALID_FILE_PATH);
}
@ -243,7 +238,7 @@ public class FileUploadController {
mv.setViewName("downloadView"); // dispatcher-servlet.xml내 BeanNameViewResolver 정의
mv.addObject("downloadFile", file);
mv.addObject("fname", fname);
mv.addObject("fname", attachFileVO.getFileName());
return mv;
}

View File

@ -0,0 +1,64 @@
package nlib.cmm.fileupload;
/**
* <pre>
* @Class Name : AttachFileVO.java
*
* @Description : 첨부파일 정보 VO
*
*
* @프로젝트명: 지방문화원 통합자료관리시스템 구축사업 (2021)
*
* </pre>
*
* @ ------------ -------- ---------------------------
* @ 수정일 수정자 수정내용
* @ ------------ -------- ---------------------------
* @ 2021. 9. 14. KNKIM 최초 생성
*
*
* @author 이씨플라자 * DIGITALSHIP KNKIM
* @since 2021. 9. 14.
* @version 1.0
*
*/
public class FileVO {
private String subPathKey; /* 첨부파일서브경로 */
private String fileMask; /* 첨부파일아이디 */
private String fileId; /* 업무 아이디 */
private int fileSeq; /* 파일 번호 */
private String fileName; /* 파일 이름 */
public String getSubPathKey() {
return subPathKey;
}
public void setSubPathKey(String subPathKey) {
this.subPathKey = subPathKey;
}
public String getFileMask() {
return fileMask;
}
public void setFileMask(String fileMask) {
this.fileMask = fileMask;
}
public String getFileId() {
return fileId;
}
public void setFileId(String fileId) {
this.fileId = fileId;
}
public int getFileSeq() {
return fileSeq;
}
public void setFileSeq(int fileSeq) {
this.fileSeq = fileSeq;
}
public String getFileName() {
return fileName;
}
public void setFileName(String fileName) {
this.fileName = fileName;
}
}

View File

@ -15,6 +15,7 @@ public class NotificationVO extends PagingVO {
private String recvUserId; /* 알림대상자 회원아이디 */
private String readYn; /* 알림확인여부 */
private int totCnt = 0; /* 알림건수(최근1개월) */
private int rno = 0; /* 행번호 */
public String getNotiId() {
return notiId;
@ -88,5 +89,11 @@ public class NotificationVO extends PagingVO {
public void setNotiTypeNm(String notiTypeNm) {
this.notiTypeNm = notiTypeNm;
}
public int getRno() {
return rno;
}
public void setRno(int rno) {
this.rno = rno;
}
}

View File

@ -2,8 +2,10 @@ package nlib.cmm.service;
public class PagingVO {
public final int DEFAULT_PAGE_SIZE = NlibProperty.getInt("list.paging.page.size", 10);
int pageIndex = 1; /* 페이지 번호 */
int pageSize = NlibProperty.getInt("list.paging.page.size", 10); /* 페이지 크기 (1페이지당 보여줄 자료건수) */
int pageSize = DEFAULT_PAGE_SIZE; /* 페이지 크기 (1페이지당 보여줄 자료건수) */
int totRecordCount; /* 총건수 */
public int getPageIndex() {
@ -11,7 +13,8 @@ public class PagingVO {
}
public void setPageIndex(int pageIndex) {
this.pageIndex = pageIndex;
if(pageIndex < 1) pageIndex = 1;
else this.pageIndex = pageIndex;
}
public void setPageIndex(String sPageIndex) {
@ -27,7 +30,8 @@ public class PagingVO {
}
public void setPageSize(int pageSize) {
this.pageSize = pageSize;
if(pageSize < 1) pageSize = DEFAULT_PAGE_SIZE;
else this.pageSize = pageSize;
}
public void setPageSize(String sPageSize) {

View File

@ -5,7 +5,7 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Repository;
import nlib.bbs.service.impl.BoardDAO;
import nlib.bbs.service.impl.BoardDAOApi;
import nlib.restful.DataApi;
import nlib.restful.service.DataApiReqVO;
import nlib.restful.service.DataApiResVO;

View File

@ -79,7 +79,6 @@ public class CollectionController extends NlibCommonController
// REQ VO 구성
//-------------------------------
DataApiReqVO reqVO = new DataApiReqVO();
reqVO.setAuthKey(createAuthKey(req, authentication));
reqVO.setPageIndex(pageIndex);
reqVO.setPageSize(pageSize);
reqVO.addInfoItem("searchKeyword", searchKeyword);
@ -143,7 +142,6 @@ public class CollectionController extends NlibCommonController
// REQ VO 구성
//-------------------------------
DataApiReqVO reqVO = new DataApiReqVO();
reqVO.setAuthKey(createAuthKey(req, authentication));
reqVO.setPageIndex(pageIndex);
reqVO.setPageSize(pageSize);
reqVO.addInfoItem("boardNo", "QNA"); // 게시판ID
@ -203,7 +201,6 @@ public class CollectionController extends NlibCommonController
// REQ VO 구성
//-------------------------------
DataApiReqVO reqVO = new DataApiReqVO();
reqVO.setAuthKey(createAuthKey(req, authentication));
reqVO.setPageIndex(pageIndex);
reqVO.setPageSize(pageSize);
reqVO.addInfoItem("searchKeyword", searchKeyword);

View File

@ -181,4 +181,14 @@ public class StringUtil extends StringUtils {
return url + delim + name + "=" + getString(value, "");
}
public static String getSqlSearchKeyword(String str) {
if(isNotEmpty(str)) {
String ret = str.replaceAll("\\%", "\\\\%");
return ret.replaceAll("_", "\\\\_");
}
return str;
}
}

View File

@ -18,6 +18,8 @@
<typeAlias alias="SecUserVO" type="nlib.security.SecUserVO" />
<typeAlias alias="NotificationVO" type="nlib.cmm.service.NotificationVO" />
<typeAlias alias="ArticleVO" type="nlib.bbs.service.ArticleVO" />
<typeAlias alias="AttachFileVO" type="nlib.bbs.service.AttachFileVO" />
</typeAliases>
</configuration>

View File

@ -3,12 +3,68 @@
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="nlib.bbs.service.impl.AncmntDAO">
<sql id="search_condition">
<![CDATA[
FROM BD_NLIB_ANCMNT S
WHERE S.OPEN_YN = 'Y'
AND DATE_FORMAT(NOW(), '%Y%m%d') BETWEEN IFNULL(S.POST_START_DATE,'00010101') AND IFNULL(S.POST_END_DATE, '99991231')
]]>
<if test='searchType != null and searchType.equals("T")'>
<if test="searchKeyword != null and !searchKeyword.equals('')">
AND S.TITLE LIKE CONCAT('%', #{escapeSearchKeyword}, '%')
</if>
</if>
<if test='searchType != null and searchType.equals("C")'>
<if test="searchKeyword != null and !searchKeyword.equals('')">
AND S.CONTENT LIKE CONCAT('%', #{escapeSearchKeyword}, '%')
</if>
</if>
</sql>
<select id="listArticles" parameterType="ArticleVO" resultType="ArticleVO">
SELECT
A.ANCMNT_ID AS ARTICLE_ID
, A.MNG_ORG_CD
, B.DEPT_NM AS MNG_ORG_NM
, A.TITLE
, A.NOTI_YN
, A.OPEN_YN
, A.POST_START_DATE
, A.POST_END_DATE
, A.VIEW_CNT
, CASE WHEN A.BD_ATTACH_FILE_ID IS NOT NULL OR A.BD_ATTACH_FILE_ID != '' THEN 'N' ELSE 'Y' END AS ATTACH_YN
, DATE_FORMAT(A.REG_DD, '%Y-%m-%d') AS REG_DD
, A2.RNO
, C.USER_NM AS REG_NM
FROM BD_NLIB_ANCMNT A
INNER JOIN (
SELECT S.ANCMNT_ID
, ROW_NUMBER() OVER() AS RNO
<include refid="search_condition" />
ORDER BY S.REG_DD DESC
LIMIT #{pageStartRowNum}, #{pageSize}
) AS A2
USING(ANCMNT_ID)
JOIN SM_DEPT B
ON B.ORG_CD = A.MNG_ORG_CD
LEFT OUTER JOIN SM_USER C
ON A.REG_ID = C.USER_ID
ORDER BY A.REG_DD DESC
</select>
<select id="countArticles" parameterType="ArticleVO" resultType="Integer">
SELECT COUNT(1)
<include refid="search_condition" />
</select>
<select id="selectArticle" parameterType="ArticleVO" resultType="ArticleVO">
<![CDATA[
SELECT
A.ANCMNT_ID
A.ANCMNT_ID AS ARTICLE_ID
, A.MNG_ORG_CD
, B.DEPT_NM
, B.DEPT_NM AS MNG_ORG_NM
, A.TITLE
, A.CONTENT
, A.NOTI_YN
@ -16,40 +72,39 @@
, A.POST_START_DATE
, A.POST_END_DATE
, A.VIEW_CNT
, CASE WHEN A.BD_ATTACH_FILE_ID IS NOT NULL OR A.BD_ATTACH_FILE_ID != '' THEN 'N' ELSE 'Y' END AS ATTACH_YN
, A.BD_ATTACH_FILE_ID
, DATE_FORMAT(A.REG_DD, '%Y-%M-%D') AS REG_DD
, DATE_FORMAT(A.REG_DD, '%Y-%m-%d') AS REG_DD
, C.USER_NM AS REG_NM
FROM BD_NLIB_ANCMNT A
INNER JOIN (
SELECT S.ANCMNT_ID
FROM BD_NLIB_ANCMNT S
WHERE OPEN_YN = 'Y'
AND DATE_FORMAT(NOW(), '%Y%m%d') BETWEEN IFNULL(POST_START_DATE,'00010101') AND IFNULL(POST_END_DATE, '99991231')
ORDER BY S.ANCMNT_ID DESC
LIMIT #{pageStartRowNum}, #{pageSize}
) AS A2
USING(ANCMNT_ID)
JOIN SM_DEPT B
ON B.ORG_CD = A.MNG_ORG_CD
WHERE 1=1
ORDER BY A.ANCMNT_ID DESC
LEFT OUTER JOIN SM_USER C
ON A.REG_ID = C.USER_ID
WHERE A.ANCMNT_ID = #{articleId}
]]>
</select>
<select id="countArticles" parameterType="ArticleVO" resultType="Integer">
<![CDATA[
SELECT COUNT(1)
FROM BD_NLIB_ANCMNT A
WHERE OPEN_YN = 'Y'
AND DATE_FORMAT(NOW(), '%Y%m%d') BETWEEN IFNULL(POST_START_DATE,'00010101') AND IFNULL(POST_END_DATE, '99991231')
]]>
</select>
<select id="selectArticle" parameterType="ArticleVO" resultType="ArticleVO">
<![CDATA[
SELECT A.*
FROM BD_NLIB_ANCMNT A
WHERE ANCMNT_ID = #{articleId}
]]>
<select id="listAttachFiles" parameterType="String" resultType="AttachFileVO">
SELECT
A.FILE_MASK
, A.FILE_ID
, A.FILE_SEQ
, A.FILE_NAME
, A.FILE_SIZE
, A.FILE_TYPE_CD
, A.DOWNLOAD_COUNT
, A.DOWNLOAD_EXPIRE_DATE
, A.DOWNLOAD_LIMIT_COUNT
, DATE_FORMAT(A.REG_DATE, '%Y-%m-%d') AS REG_DD
, A.DELETE_YN
, A.STREAMING_URL
, A.CONTENT
, A.ATCH_TYPE_CD
FROM J_ATTACHFILE A
WHERE A.FILE_ID = #{attachFileId}
ORDER BY A.FILE_SEQ
</select>
<update id="updateRead" parameterType="ArticleVO">

View File

@ -40,9 +40,11 @@
, IF(A.READ_DD IS NULL, 'N', 'Y') AS READ_YN
, DATE_FORMAT(A.REG_DD, '%Y-%M-%D') AS REG_DD
, COUNT(A.NOTI_ID) OVER(PARTITION BY 1) AS TOT_CNT
, A2.RNO
FROM SM_NOTIFICATION A
INNER JOIN (
SELECT S.NOTI_ID
, ROW_NUMBER() OVER() AS RNO
FROM SM_NOTIFICATION S
WHERE S.RECV_USER_ID = #{recvUserId}
AND S.REG_DD > DATE_SUB(NOW(), INTERVAL 1 MONTH)

View File

@ -83,6 +83,7 @@ fileupload.temp.subpath = /temp
# \ubb3b\uace0\ub2f5\ud558\uae30 \uac8c\uc2dc\ud310 \uc11c\ube0c\uc704\uce58 : \ucca8\ubd80\ud30c\uc77c \ucd5c\uc0c1\uc704 \uc704\uce58 \uc774\ud558\uc758 \uc704\uce58 \uc815\ubcf4\ub97c \uc124\uc815
fileupload.bbs.qna.subpath = /bbs/qna
fileupload.bbs.ancmnt.subpath = /bbs/ancmnt
# \uba54\uc77c \uacbd\ub85c
mailing.sender.membership.template = C:/iams/workspace/nlib/src/main/webapp/mail/mail_template.html

View File

@ -63,11 +63,19 @@
var pageIndex = ( filter && filter.pageIndex ? filter.pageIndex : $("#pageIndex").val());
var pageSize = ( filter && filter.pageSize ? filter.pageSize : $("#pageSize").val());
var searchType = $("#searchType").val();
var searchKeyword = $("#searchKeyword").val();
$("#pageIndex").val(pageIndex);
var inputData = {
"pageIndex" : pageIndex
, "pageSize": pageSize};
, "pageSize" : pageSize
, "searchType" : searchType
, "searchKeyword" : searchKeyword
};
//--------------------------------------
@ -116,12 +124,11 @@
//======================================
fields: [
{ title:"ID", name: "articleId" , type: "text", width: 200, align: "left" },
{ title:"알림방법", name: "notiMethod" , type: "text", width: 100, align: "center"},
{ title:"구분코드", name: "notiTypeCd" , type: "text", width: 100, align: "center"},
{ title:"구분", name: "notiTypeNm" , type: "text", width: 100, align: "center"},
{ title:"번호", name: "rno" , type: "text", width: 200, align: "center" },
{ title:"제목", name: "title" , type: "text", width: 200, align: "left" },
{ title:"확인여부", name: "readYn" , type: "text", width: 100, align: "center"},
{ title:"날짜", name: "regDd" , type: "text", width: 100, align: "center"}
{ title:"등록자", name: "regNm" , type: "text", width: 100, align: "center"},
{ title:"등록일", name: "regDd" , type: "text", width: 100, align: "center"},
{ title:"첨부", name: "bdAttachFileId" , type: "text", width: 100, align: "center"}
]
});
@ -137,47 +144,17 @@
// 선택한 글 상세 보기로 이동
function fn_viewDetail(articleId, selectedRow) {
var $selectedRow = $(selectedRow);
var reqUrl = "${pageContext.request.contextPath}/bbs/selectAncmntAjax.do";
var inputData = { "articleId" : articleId };
//--------------------------------------
// 요청 처리
//--------------------------------------
$.ajax({
type: "post",
contentType: "application/json; charset=utf-8",
url: reqUrl,
dataType: "json",
data: JSON.stringify(inputData),
}).done(function(response){
var jsonObj = JSON.parse(response);
$("#jsGrid").find('table tr.answer').remove();
//alert("DDDDDDDD remove = " + $("#jsGrid")[0].scrollHeight);
$("#jsGrid").jsGrid("rowByItem", $selectedRow).data("JSGridItem")["readYn"] = jsonObj.data.readYn;
$selectedRow.find('td').eq(GRID_INDEX_OF_READYN).text(jsonObj.data.readYn);
$selectedRow.after("<tr class='answer'><td colspan='7'>" + jsonObj.data.content
+ "<br/>" + jsonObj.data.content
+ "<br/>" + jsonObj.data.content
+ "<br/>" + jsonObj.data.content
+ "<br/>알림확인여부=" + jsonObj.data.readYn
+ "<br/>알림일자=" + jsonObj.data.regDd
+ "</td></tr>");
});
$("#jsGrid").closest('.ui-jqgrid-bdiv').width($("#jsGrid").closest('.ui-jqgrid-bdiv').width() + 1);
function fn_viewDetail(articleId) {
$("#articleId").val(articleId);
$("#articleForm").submit();
}
// 그리드 데이터 조회 호출
function fn_searchArticle(pageSize, pageIndex) {
$("#jsGrid").jsGrid("search"
, {'pageSize' : (pageSize ? pageSize : fn_getIntValue("pageSize", ${pageSize}) ),
'pageIndex' : (pageIndex ? pageIndex : fn_getIntValue("pageIndex", ${pageIndex}))
, {'pageSize' : (pageSize ? pageSize : fn_getIntValue("pageSize", ${searchArticle.pageSize}) ),
'pageIndex' : (pageIndex ? pageIndex : fn_getIntValue("pageIndex", ${searchArticle.pageIndex}))
}
);
}
@ -193,15 +170,21 @@
&nbsp;<br/>
<form name="articleForm" id="articleForm" method="post">
<form name="articleForm" id="articleForm" method="post" action="${pageContext.request.contextPath}/bbs/selectAncmntArticle.do">
<!-- 검색조건 -->
<input type="text" name="pageSize" id="pageSize" value="${pageSize }" />
<input type="text" name="pageSize" id="pageSize" value="${searchArticle.pageSize }" />
<input type="text" name="itemsCount" id="itemsCount" value="0" />
<input type="text" name="pageIndex" id="pageIndex" title="페이지번호" value="${pageIndex }" size="5" maxlength="5" />
<input type="button" name="btnSearch" id="btnSearch" title="새로고침" value="새로고침" />
<input type="text" name="pageIndex" id="pageIndex" title="페이지번호" value="${searchArticle.pageIndex }" size="5" maxlength="5" />
<select name="searchType" id="searchType">
<option value="T" <c:if test='${searchArticle.searchType == "T" }'>selected</c:if> >제목</option>
<option value="C" <c:if test='${searchArticle.searchType == "C" }'>selected</c:if> >내용</option>
</select>
<input type="text" name="searchKeyword" id="searchKeyword" title="검색어" value="${searchArticle.searchKeyword }" maxlength="20" />
<input type="text" name="articleId" id="articleId" title="게시글번호" value="" readonly />
<input type="button" name="btnSearch" id="btnSearch" title="검색" value="검색" />
<br/>
<div id="jsGrid" name="jsGrid" style="height: 100%"></div>

View File

@ -0,0 +1,155 @@
<%
/**
* <pre>
* @Class Name : selectAncmntArticle.jsp
*
* @Description : 공지사항 상세내용을 조회한다.
*
*
* @프로젝트명: 지방문화원 통합자료관리시스템 구축사업 (2021)
*
* </pre>
*
* @ ------------ -------- ---------------------------
* @ 수정일 수정자 수정내용
* @ ------------ -------- ---------------------------
* @ 2021. 9. 14. KNKIM 최초 생성
*
*
* @author 이씨플라자 * DIGITALSHIP KNKIM
* @since 2021. 9. 14.
* @version 1.0
*
*/
%>
<%@ page language="java" contentType="text/html; charset=UTF-8" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ taglib prefix="ui" uri="http://egovframework.gov/ctl/ui" %>
<%@ taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions" %>
<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %>
<%@ taglib prefix="spring" uri="http://www.springframework.org/tags" %>
<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form" %>
<%@ taglib prefix="validator" uri="http://www.springmodules.org/tags/commons-validator" %>
<c:set var="pageTitle">공지사항 - 상세조회</c:set>
<!DOCTYPE html>
<html lang="ko">
<head>
<title>${pageTitle}</title>
<script type="text/javaScript" language="javascript">
// 목록으로 이동
function fn_list() {
$("#articleForm").attr("action", "${pageContext.request.contextPath}/bbs/listAncmnts.do");
$("#articleForm").submit();
}
// 파일 다운로드
function fn_downloadFile(fileId, fileSeq, fileName) {
if(fileId == null || fileId.trim().length < 1) {
alert("파일정보를 확인해 주시기 바랍니다.[1]");
return;
}
if(fileSeq < 1) {
alert("파일정보를 확인해 주시기 바랍니다.[2]");
return;
}
if(fileName == null || fileName.trim().length < 1) {
alert("파일정보를 확인해 주시기 바랍니다.[3]");
return;
}
$("#fileId").val(fileId);
$("#fileSeq").val(fileSeq);
$("#fileName").val(fileName);
$("#downloadFileForm").submit();
}
</script>
</head>
<body>
<h1>${pageTitle }</h1>
메시지 : <span style="color:red;">${message }</span>
<br />
<form name="articleForm" id="articleForm"
action="${pageContext.request.contextPath}/board/listNotices.do"
method="post">
<!-- HIDDEN 영역 : 시작 -->
<input type="text" name="pageIndex" id="pageIndex" title="페이지번호" value="${searchArticle.pageIndex}" readonly />
<input type="text" name="pageSize" id="pageSize" title="목록에 보여줄 글개수" value="${searchArticle.pageSize}" readonly />
<input type="text" name="searchType" id="searchType" title="검색구분" value="${searchArticle.searchType}" readonly />
<input type="text" name="searchKeyword" id="searchKeyword" title="검색어" value="${searchArticle.searchKeyword}" readonly />
<input type="text" name="articleId" id="articleId" title="선택글번호" value="${searchArticle.articleId}" readonly />
<!-- HIDDEN 영역 : 종료 -->
<table class="table_content" style="width:100% !important; margin-top: 20px;">
<tr>
<th>유형</th>
<td>
<c:if test='${article.notiYn == "Y"}'>공지</c:if>
<c:if test='${article.notiYn != "Y"}'>일반</c:if>
</td>
<th>작성일</th>
<td>${article.regDd }</td>
</tr>
<tr>
<th rowspan="1">제목</th>
<td colspan="3">${article.title}</td>
</tr>
<tr>
<th rowspan="1">질문내용</th>
<td colspan="3">${article.content}</td>
</tr>
<c:if test="${article.attachFileCnt > 0}">
<tr>
<td colspan="4">
<%
// 파일정보 : 저장파일ID=원파일명
%>
<c:forEach var="attachFile" items="${article.attachFiles }">
<a href="javascript:void(0);" onclick="fn_downloadFile('${attachFile.fileId}', ${attachFile.fileSeq}, '${attachFile.fileName}')">${attachFile.fileName} (${attachFile.fileSize} byte(s))</a><br/>
</c:forEach>
</td>
</tr>
</c:if>
<c:if test="${article.attachFileCnt < 1}">
<td colspan="4">첨부파일 없음
</td>
</c:if>
</table>
<br/>
<!-- 관련 작업 버튼 -->
<button type="button" name="btnList" id="btnList" class="float"
onclick="fn_list()">목록</button>
</form>
<br />
<!-- 첨부파일 다운로드용 폼 -->
<form name="downloadFileForm" id="downloadFileForm"
action="${pageContext.request.contextPath}/fileupload/downloadAttachFile.do"
method="post">
<input type="text" name="subPathKey" id="subPathKey" value="fileupload.bbs.ancmnt.subpath" readonly />
<input type="text" name="fileId" id="fileId" value="" readonly />
<input type="text" name="fileSeq" id="fileSeq" value="" readonly />
<input type="text" name="fileName" id="fileName" value="" readonly />
</form>
</body>
</html>

View File

@ -6,7 +6,7 @@
<li><a href="#" onclick="javascript:location.href='${pageContext.request.contextPath}/inform/selectGreeting.do';">인사말</a></li>
<li><a href="#" onclick="javascript:location.href='${pageContext.request.contextPath}/inform/selectNCultureOperationInfo.do';">이용안내</a></li>
<li><a href="#" onclick="javascript:location.href='${pageContext.request.contextPath}/board/listNotices.do';">공지사항</a></li>
<li><a href="#" onclick="javascript:location.href='${pageContext.request.contextPath}/board/listAncmnts.do';">공지사항(DB)</a></li>
<li><a href="#" onclick="javascript:location.href='${pageContext.request.contextPath}/bbs/listAncmnts.do';">공지사항(DB)</a></li>
<li><a href="#" onclick="javascript:location.href='${pageContext.request.contextPath}/board/listFAQs.do';">자주하는질문</a></li>
<li><a href="#" onclick="javascript:location.href='${pageContext.request.contextPath}/bbs/listQnAs.do';">묻고답하기</a></li>
<li><a href="#" onclick="javascript:location.href='${pageContext.request.contextPath}/inform/selectNCultureLocationInfo.do';">찾아오시는길</a></li>

View File

@ -11,7 +11,7 @@
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
<link rel="shortcut icon" href="#">
<link href="${pageContext.request.contextPath}/css/nlib.css" rel="stylesheet" type="text/css" />
<script src="${pageContext.request.contextPath}/js/jquery/jquery.min.js"></script>
<script src="${pageContext.request.contextPath}/js/nlib.js"></script>

BIN
src/main/webapp/favicon.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 431 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 746 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

View File

@ -0,0 +1 @@
{"name":"","short_name":"","icons":[{"src":"/android-chrome-192x192.png","sizes":"192x192","type":"image/png"},{"src":"/android-chrome-512x512.png","sizes":"512x512","type":"image/png"}],"theme_color":"#ffffff","background_color":"#ffffff","display":"standalone"}

View File

@ -0,0 +1 @@
Tue Sep 14 2021 08:25:17 GMT+0900 (대한민국 표준시)

View File

@ -8,8 +8,10 @@
<script src="/nlib/js/jquery/jquery.min.js"></script>
<script src="/nlib/js/nlib.js"></script>
<script>
</script>
</head>
<body>

View File