이지우 - 관리자 저작권체험교실 서약서 일괄 다운로드 추가

This commit is contained in:
jiwoo 2024-01-17 12:31:19 +09:00
parent 57158baf69
commit 52a3f301e1
11 changed files with 279 additions and 138 deletions

View File

@ -105,4 +105,6 @@ public interface VEEduMIXService {
List<VEEduAplctVO> selectCndtnList(VEEduAplctVO paramVO); List<VEEduAplctVO> selectCndtnList(VEEduAplctVO paramVO);
List<VEEduAplctVO> selectAdultRsltRprtList(VEEduAplctVO paramVO) throws Exception; List<VEEduAplctVO> selectAdultRsltRprtList(VEEduAplctVO paramVO) throws Exception;
List<VEEduAplctVO> selectExprnAtchFileDownList(VEEduAplctVO paramVO) throws Exception;
} }

View File

@ -261,5 +261,9 @@ public class VEEduMIXDAO extends EgovAbstractDAO {
return tlist; return tlist;
} }
public List<VEEduAplctVO> selectExprnAtchFileDownList(VEEduAplctVO paramVO) throws Exception {
@SuppressWarnings("unchecked")
List<VEEduAplctVO> tlist = (List<VEEduAplctVO>) list("VEEduMIXDAO.selectExprnAtchFileDownList", paramVO);
return tlist;
}
} }

View File

@ -232,4 +232,8 @@ public class VEEduMIXServiceImpl implements VEEduMIXService {
public List<VEEduAplctVO> selectAdultRsltRprtList(VEEduAplctVO paramVO) throws Exception{ public List<VEEduAplctVO> selectAdultRsltRprtList(VEEduAplctVO paramVO) throws Exception{
return vEEduMIXDAO.selectAdultRsltRprtList(paramVO); return vEEduMIXDAO.selectAdultRsltRprtList(paramVO);
} }
public List<VEEduAplctVO> selectExprnAtchFileDownList(VEEduAplctVO paramVO) throws Exception{
return vEEduMIXDAO.selectExprnAtchFileDownList(paramVO);
}
} }

View File

@ -11,9 +11,10 @@ import java.io.PrintWriter;
import java.net.URLEncoder; import java.net.URLEncoder;
import java.time.LocalDate; import java.time.LocalDate;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List; import java.util.List;
import java.util.Locale; import java.util.Locale;
import java.util.Map;
import java.util.Properties; import java.util.Properties;
import javax.annotation.Resource; import javax.annotation.Resource;
@ -32,7 +33,6 @@ import org.springframework.ui.ModelMap;
import org.springframework.util.FileCopyUtils; import org.springframework.util.FileCopyUtils;
import org.springframework.web.bind.annotation.ModelAttribute; import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.multipart.MultipartHttpServletRequest; import org.springframework.web.multipart.MultipartHttpServletRequest;
import org.springframework.web.servlet.ModelAndView; import org.springframework.web.servlet.ModelAndView;
@ -525,6 +525,38 @@ String[] order = {
return modelAndView; return modelAndView;
} }
/**
* 저작권 체험교실 운영신청 목록 업로드 파일 체크
* @param model
* @return
* @throws Exception
*/
@RequestMapping(value = "oprtnAplctFileAllChkAjax.do")
public ModelAndView oprtnAplctFileAllChkAjax(VEEduAplctVO vEEduAplctVO
, HttpServletRequest request, HttpServletResponse response) throws Exception {
ModelAndView modelAndView = new ModelAndView();
modelAndView.setViewName("jsonView");
vEEduAplctVO.setEduAplctOrdList(Arrays.asList(vEEduAplctVO.getChk().split(",")));
List<VEEduAplctVO> vEEduAplctVOList = vEEduMIXService.selectExprnAtchFileDownList(vEEduAplctVO);
List<String> atchFileIdList = new ArrayList<String>();
vEEduAplctVOList.forEach( vo -> {
if(vo.getOathAtchFileId() != null) {
atchFileIdList.add(vo.getOathAtchFileId());
}
});
if(atchFileIdList.size() < 1) {
modelAndView.addObject("result", "fail");
modelAndView.addObject("msg", "첨부 파일이 없습니다.");
}else {
modelAndView.addObject("result", "success");
}
return modelAndView;
}
/** /**
* 저작권 체험교실 운영신청 목록 업로드 파일 일괄 다운로드 * 저작권 체험교실 운영신청 목록 업로드 파일 일괄 다운로드
* @param model * @param model
@ -532,70 +564,37 @@ String[] order = {
* @throws Exception * @throws Exception
*/ */
@RequestMapping(value = "oprtnAplctFileAllDownLoad.do") @RequestMapping(value = "oprtnAplctFileAllDownLoad.do")
public void oprtnAplctFileAllDownLoad(@RequestParam Map<String, Object> commandMap public void oprtnAplctFileAllDownLoad(VEEduAplctVO vEEduAplctVO
, HttpServletRequest request, HttpServletResponse response) throws Exception { , HttpServletRequest request, HttpServletResponse response) throws Exception {
//파일 SN을 리스트에 담기
vEEduAplctVO.setEduAplctOrdList(Arrays.asList(vEEduAplctVO.getChk().split(",")));
List<VEEduAplctVO> vEEduAplctVOList = vEEduMIXService.selectExprnAtchFileDownList(vEEduAplctVO);
vEEduAplctVOList = egovCryptoUtil.decryptVEEduAplctVOList(vEEduAplctVOList);
//첨부파일있는 항목만 재배치
String orgnZipNm = "체험교실 신청서.zip";
String downloadType = "A";
//첨부파일있는 항목만 재배치
List<String> atchFileIdList = new ArrayList<String>(); List<String> atchFileIdList = new ArrayList<String>();
//파일 SN을 리스트에 담기 vEEduAplctVOList.forEach( vo -> {
List<String> atchFileSnList = new ArrayList<String>(); if(vo.getOathAtchFileId() != null) {
atchFileIdList.add(vo.getOathAtchFileId());
//split을 이용해 아이디를 각자 배열에 담기
String[] splitIdStr = commandMap.get("atchFileId").toString().split(",");
String[] splitSnStr = commandMap.get("fileSn").toString().split(",");
//zip파일 이름
String orgnZipNm = commandMap.get("orgnZipNm").toString();
//downloadType (A:ID가 여러개고 fileSn이 1개인 경우 || B:ID는 하나이고 fileSn이 여러개인 경우)
String downloadType = commandMap.get("downloadType").toString();
String atchFileId = new String();
String fileSn = new String();
//ID가 여러개고 fileSn이 1개인 경우
if("A".equals(downloadType)) {
fileSn = "0";
for(int i=0; i<splitIdStr.length; i++) {
atchFileIdList.add(splitIdStr[i]);
} }
} });
//ID는 하나이고 fileSn이 여러개인 경우 List<VEEduAplctVO> fileYEduList = new ArrayList<VEEduAplctVO>();
if("B".equals(downloadType)) { vEEduAplctVOList.forEach( vo -> {
atchFileId = splitIdStr[0]; if(vo.getOathAtchFileId() != null) {
for(int i=0; i<splitSnStr.length; i++) { fileYEduList.add(vo);
atchFileSnList.add(splitSnStr[i]);
} }
} });
FileVO fileVO = new FileVO(); FileVO fileVO = new FileVO();
fileVO.setDownloadType(downloadType); fileVO.setDownloadType(downloadType);
if("A".equals(downloadType)) { fileVO.setAtchFileIdList(atchFileIdList);
fileVO.setAtchFileIdList(atchFileIdList);
fileVO.setFileSn(fileSn);
} else if("B".equals(downloadType)) {
fileVO.setAtchFileId(atchFileId);
fileVO.setAtchFileSnList(atchFileSnList);
}
List<FileVO> fvoList = fileService.selectZipFileList(fileVO); // 해당 기능에 맞게 파일 조회 List<FileVO> fvoList = fileService.selectZipFileList(fileVO); // 해당 기능에 맞게 파일 조회
if(fvoList.size() == 0){
response.setContentType("application/x-msdownload");
PrintWriter printwriter = response.getWriter();
printwriter.println("<html>");
printwriter.println("<br><br><br><h2>Could not get file name:<br></h2>");
printwriter.println("<br><br><br><center><h3><a href='javascript: history.go(-1)'>Back</a></h3></center>");
printwriter.println("<br><br><br>&copy; webAccess");
printwriter.println("</html>");
printwriter.flush();
printwriter.close();
return ;
}
// buffer size
int size = 1024; int size = 1024;
byte[] buf = new byte[size]; byte[] buf = new byte[size];
@ -603,39 +602,66 @@ String[] order = {
FileInputStream fis = null; FileInputStream fis = null;
ZipArchiveOutputStream zos = null; ZipArchiveOutputStream zos = null;
BufferedInputStream bis = null; BufferedInputStream bis = null;
int fileCnt = 0;
try { try {
System.out.println("outZipNm : "+ outZipNm);
// Zip 파일생성 // Zip 파일생성
zos = new ZipArchiveOutputStream(new BufferedOutputStream(new FileOutputStream(outZipNm))); zos = new ZipArchiveOutputStream(new BufferedOutputStream(new FileOutputStream(outZipNm)));
for ( FileVO vo : fvoList ){ Iterator<FileVO> fvoIterator = fvoList.iterator();
Iterator<VEEduAplctVO> fileYEduIterator = fileYEduList.iterator();
while (fvoIterator.hasNext() && fileYEduIterator.hasNext() ){
FileVO vo = fvoIterator.next();
VEEduAplctVO eduVO = fileYEduIterator.next();
zos.setEncoding("UTF-8"); zos.setEncoding("UTF-8");
// Create a file object
File file = new File(vo.getFileStreCours() + "/" + vo.getStreFileNm());
// 1. check if the file exists or not
boolean isExists = file.exists();
if(isExists) {
System.out.println("getStreFileNm() " + vo.getStreFileNm());
System.out.println("I find the existFile.txt");
fileCnt++;
} else {
continue;
}
/*String renamedFileName = generateRenamedFileName(vo.getOrignlFileNm());*/
String renamedFileName = eduVO.getScholInsttNm() + "_" + eduVO.getChrgNm() + "_신청서."+ vo.getFileExtsn();
vo.setOrignlFileNm(renamedFileName);
//buffer에 해당파일의 stream을 입력한다. //buffer에 해당파일의 stream을 입력한다.
fis = new FileInputStream(vo.getFileStreCours() + "/" + vo.getStreFileNm()); fis = new FileInputStream(vo.getFileStreCours() + "/" + vo.getStreFileNm());
bis = new BufferedInputStream(fis,size); bis = new BufferedInputStream(fis,size);
//zip에 넣을 다음 entry 가져온다. //zip에 넣을 다음 entry 가져온다.
zos.putArchiveEntry(new ZipArchiveEntry(vo.getOrignlFileNm())); zos.putArchiveEntry(new ZipArchiveEntry(vo.getOrignlFileNm()));
//준비된 버퍼에서 집출력스트림으로 write 한다. //준비된 버퍼에서 집출력스트림으로 write 한다.
int len; int len;
while((len = bis.read(buf,0,size)) != -1) zos.write(buf,0,len); while((len = bis.read(buf,0,size)) != -1) zos.write(buf,0,len);
bis.close(); bis.close();
fis.close(); fis.close();
zos.closeArchiveEntry(); zos.closeArchiveEntry();
}
zos.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
}finally{
if( zos != null ) zos.close();
if( fis != null ) fis.close();
if( bis != null ) bis.close();
} }
zos.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
}finally{
if( zos != null ) zos.close();
if( fis != null ) fis.close();
if( bis != null ) bis.close();
}
File uFile = new File(fvoList.get(0).getFileStreCours(), orgnZipNm); File uFile = new File(fvoList.get(0).getFileStreCours(), orgnZipNm);
long fSize = uFile.length(); long fSize = uFile.length();
@ -690,6 +716,59 @@ String[] order = {
} }
} }
//////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
//
// private function
//
//
//페이징을 위한 처리 step1 - 페이징 기본 정보 설정
private PaginationInfo setPagingStep1(
VEEduAplctVO p_vEEduAplctVO
)throws Exception{
// pageing step1
PaginationInfo paginationInfo = new PaginationInfo();
paginationInfo.setCurrentPageNo(p_vEEduAplctVO.getPageIndex());
paginationInfo.setRecordCountPerPage(p_vEEduAplctVO.getPageUnit());
paginationInfo.setPageSize(p_vEEduAplctVO.getPageSize());
return paginationInfo;
}
//페이징을 위한 처리 step2 - 게시물 리스트 수량 설정 검색 조건 초기화
private VEEduAplctVO setPagingStep2(
VEEduAplctVO p_vEEduAplctVO
, PaginationInfo p_paginationInfo
)throws Exception{
// pageing step2
p_vEEduAplctVO.setFirstIndex(p_paginationInfo.getFirstRecordIndex());
p_vEEduAplctVO.setLastIndex(p_paginationInfo.getLastRecordIndex());
p_vEEduAplctVO.setRecordCountPerPage(p_paginationInfo.getRecordCountPerPage());
if("".equals(p_vEEduAplctVO.getSearchSortCnd())){ //최초조회시 최신것 조회List
p_vEEduAplctVO.setSearchSortCnd("prcs_ord");
p_vEEduAplctVO.setSearchSortOrd("desc");
}
return p_vEEduAplctVO;
}
//페이징을 위한 처리 step3 - 전체 게시물 수량 설정하기
private PaginationInfo setPagingStep3(
List<VEEduAplctVO> p_vEEduAplctVOList
, PaginationInfo p_paginationInfo
)throws Exception{
// pageing step3
int totCnt = 0;
if(p_vEEduAplctVOList.size() > 0) totCnt = p_vEEduAplctVOList.get(0).getTotCnt();
p_paginationInfo.setTotalRecordCount(totCnt);
return p_paginationInfo;
}
private void setDisposition(String filename, HttpServletRequest request, HttpServletResponse response) throws Exception { private void setDisposition(String filename, HttpServletRequest request, HttpServletResponse response) throws Exception {
String browser = getBrowser(request); String browser = getBrowser(request);
@ -741,57 +820,4 @@ String[] order = {
} }
return "Firefox"; return "Firefox";
} }
//////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
//
// private function
//
//
//페이징을 위한 처리 step1 - 페이징 기본 정보 설정
private PaginationInfo setPagingStep1(
VEEduAplctVO p_vEEduAplctVO
)throws Exception{
// pageing step1
PaginationInfo paginationInfo = new PaginationInfo();
paginationInfo.setCurrentPageNo(p_vEEduAplctVO.getPageIndex());
paginationInfo.setRecordCountPerPage(p_vEEduAplctVO.getPageUnit());
paginationInfo.setPageSize(p_vEEduAplctVO.getPageSize());
return paginationInfo;
}
//페이징을 위한 처리 step2 - 게시물 리스트 수량 설정 검색 조건 초기화
private VEEduAplctVO setPagingStep2(
VEEduAplctVO p_vEEduAplctVO
, PaginationInfo p_paginationInfo
)throws Exception{
// pageing step2
p_vEEduAplctVO.setFirstIndex(p_paginationInfo.getFirstRecordIndex());
p_vEEduAplctVO.setLastIndex(p_paginationInfo.getLastRecordIndex());
p_vEEduAplctVO.setRecordCountPerPage(p_paginationInfo.getRecordCountPerPage());
if("".equals(p_vEEduAplctVO.getSearchSortCnd())){ //최초조회시 최신것 조회List
p_vEEduAplctVO.setSearchSortCnd("prcs_ord");
p_vEEduAplctVO.setSearchSortOrd("desc");
}
return p_vEEduAplctVO;
}
//페이징을 위한 처리 step3 - 전체 게시물 수량 설정하기
private PaginationInfo setPagingStep3(
List<VEEduAplctVO> p_vEEduAplctVOList
, PaginationInfo p_paginationInfo
)throws Exception{
// pageing step3
int totCnt = 0;
if(p_vEEduAplctVOList.size() > 0) totCnt = p_vEEduAplctVOList.get(0).getTotCnt();
p_paginationInfo.setTotalRecordCount(totCnt);
return p_paginationInfo;
}
} }

View File

@ -8047,4 +8047,19 @@ VALUES
a.LCTR_DIV_CD = '20' a.LCTR_DIV_CD = '20'
<iterate open="(" close=")" conjunction="," property="rsltList" prepend="AND a.edu_aplct_ord IN" > #rsltList[]#</iterate> <iterate open="(" close=")" conjunction="," property="rsltList" prepend="AND a.edu_aplct_ord IN" > #rsltList[]#</iterate>
</select> </select>
<select id="VEEduMIXDAO.selectExprnAtchFileDownList" parameterClass="VEEduAplctVO" resultClass="VEEduAplctVO">
/* 임시.*NOT_SQL_LOG.* VEEduMIXDAO.selectExprnAtchFileDownList */
SELECT
A.edu_aplct_ord AS eduAplctOrd,
A.schol_instt_nm AS scholInsttNm,
A.chrg_nm AS chrgNm,
A.oath_atch_file_id AS oathAtchFileId
FROM VE_EDU_APLCT A
WHERE A.edu_aplct_ord IN
<iterate property="eduAplctOrdList" open="(" close=")" conjunction=",">
#eduAplctOrdList[]#
</iterate>
</select>
</sqlMap> </sqlMap>

View File

@ -309,6 +309,18 @@
</td> </td>
</tr> </tr>
<c:if test="${!empty info.oathAtchFileId}">
<tr>
<th scope="row">
<p>서약서</p>
</th>
<td>
<c:import url="/cmm/fms/selectBBSFileInfs.do" charEncoding="utf-8">
<c:param name="param_atchFileId" value="${info.oathAtchFileId}" />
</c:import>
</td>
</tr>
</c:if>
</tbody> </tbody>
</table> </table>
</div> </div>

View File

@ -140,12 +140,40 @@ input:read-only {
} }
} }
function fileChk() {
var chkLen = $(listForm).find("input[name=chk]:checked").length;
if(chkLen ==0){
alert("선택된 항목이 없습니다.");
return;
}
var downForm = new FormData(document.getElementById("listForm"));
$.ajax({
type:"POST",
url: "<c:url value='/kccadr/oprtn/cpyrgExprnClsrm/oprtnAplctFileAllChkAjax.do'/>",
data: downForm,
dataType:'json',
async: false,
processData: false,
contentType: false,
cache: false,
success:function(returnData){
console.log('returnData : ', returnData);
if(returnData.result == 'fail'){
alert(returnData.msg);
}else{
fileDownLoad();
}
},
error:function(request , status, error){
alert("code:"+request.status+"\n"+"message:"+request.responseText+"\n"+"error:"+error);
}
});
}
function fileDownLoad() { function fileDownLoad() {
/* alert("개발전"); var downForm = document.listForm;
return; */ downForm.action = "<c:url value='/kccadr/oprtn/cpyrgExprnClsrm/oprtnAplctFileAllDownLoad.do'/>";
var listForm = document.listForm; downForm.submit();
listForm.action = "<c:url value='/kccadr/oprtn/cpyrgExprnClsrm/oprtnAplctFileAllDownLoad.do'/>";
listForm.submit();
} }
function fncCreate() { function fncCreate() {
@ -167,6 +195,8 @@ input:read-only {
value="<c:out value="${vEEduAplctVO.searchSortOrd}" />" /> value="<c:out value="${vEEduAplctVO.searchSortOrd}" />" />
<input type="hidden" name="eduAplctOrd" value="" /> <input type="hidden" name="eduAplctOrd" value="" />
<input type="hidden" name="aprvlCd" id="aprvlCd" value="" /> <input type="hidden" name="aprvlCd" id="aprvlCd" value="" />
<input type="hidden" name="eduAplctOrdList" id="eduAplctOrdList" value="" />
<div class="cont_wrap"> <div class="cont_wrap">
<div class="box"> <div class="box">
<!-- cont_tit --> <!-- cont_tit -->
@ -305,7 +335,7 @@ input:read-only {
<c:if test="${vEEduAplctVO.pageUnit == '100'}">selected</c:if>>100줄</option> <c:if test="${vEEduAplctVO.pageUnit == '100'}">selected</c:if>>100줄</option>
</select> </select>
<button type="button" class="btn_type06" style="height:40px; border:1px solid #3a72db; font-size:16px; border-radius:5px; vertical-align:middle;" <button type="button" class="btn_type06" style="height:40px; border:1px solid #3a72db; font-size:16px; border-radius:5px; vertical-align:middle;"
onclick="fileDownLoad();">첨부파일 다운로드</button> onclick="fileChk();">첨부파일 다운로드</button>
<button type="button" class="btn_down_excel" <button type="button" class="btn_down_excel"
onclick="excelDownLoad();">엑셀 다운로드</button> onclick="excelDownLoad();">엑셀 다운로드</button>
</div> </div>

View File

@ -332,6 +332,18 @@
</td> </td>
</tr> </tr>
<c:if test="${!empty info.oathAtchFileId}">
<tr>
<th scope="row">
<p>서약서</p>
</th>
<td>
<c:import url="/cmm/fms/selectBBSFileInfs.do" charEncoding="utf-8">
<c:param name="param_atchFileId" value="${info.oathAtchFileId}" />
</c:import>
</td>
</tr>
</c:if>
</tbody> </tbody>
</table> </table>
</div> </div>

View File

@ -131,6 +131,41 @@
, $("#listForm") , $("#listForm")
); );
} }
function fileChk() {
var chkLen = $(listForm).find("input[name=chk]:checked").length;
if(chkLen ==0){
alert("선택된 항목이 없습니다.");
return;
}
var downForm = new FormData(document.getElementById("listForm"));
$.ajax({
type:"POST",
url: "<c:url value='/kccadr/oprtn/cpyrgExprnClsrm/oprtnAplctFileAllChkAjax.do'/>",
data: downForm,
dataType:'json',
async: false,
processData: false,
contentType: false,
cache: false,
success:function(returnData){
console.log('returnData : ', returnData);
if(returnData.result == 'fail'){
alert(returnData.msg);
}else{
fileDownLoad();
}
},
error:function(request , status, error){
alert("code:"+request.status+"\n"+"message:"+request.responseText+"\n"+"error:"+error);
}
});
}
function fileDownLoad() {
var downForm = document.listForm;
downForm.action = "<c:url value='/kccadr/oprtn/cpyrgExprnClsrm/oprtnAplctFileAllDownLoad.do'/>";
downForm.submit();
}
</script> </script>
<title>교육과정관리</title> <title>교육과정관리</title>
</head> </head>
@ -276,6 +311,7 @@
<option value='30' <c:if test="${adjReqMgrVO.pageUnit == '30'}">selected</c:if>>30줄</option> <option value='30' <c:if test="${adjReqMgrVO.pageUnit == '30'}">selected</c:if>>30줄</option>
<option value='100' <c:if test="${adjReqMgrVO.pageUnit == '100'}">selected</c:if>>100줄</option> <option value='100' <c:if test="${adjReqMgrVO.pageUnit == '100'}">selected</c:if>>100줄</option>
</select> </select>
<button type="button" class="btn_type06" style="height:40px; border:1px solid #3a72db; font-size:16px; border-radius:5px; vertical-align:middle;" onclick="fileChk();">첨부파일 다운로드</button>
<button type="button" class="btn_down_excel" onclick="excelDownLoad();">엑셀 다운로드</button> <button type="button" class="btn_down_excel" onclick="excelDownLoad();">엑셀 다운로드</button>
</div> </div>
</div> </div>

View File

@ -143,7 +143,7 @@
<li> <li>
<div class="wrap"> <div class="wrap">
<div class="title"> <div class="title">
<p><img src="/offedu/visitEdu/usr/publish/images/content/mypage_icon03.png" alt="체험교실 마이페이지 아이콘"> 찾교(체험교실)</p> <p><img src="/offedu/visitEdu/usr/publish/images/content/mypage_icon03.png" alt="체험교실 마이페이지 아이콘">체험교실</p>
</div> </div>
<div class="inner_text" style="text-align: left;"> <div class="inner_text" style="text-align: left;">
<a href="#" onclick="fn_goExprnListForm(20)"> <a href="#" onclick="fn_goExprnListForm(20)">

View File

@ -66,7 +66,7 @@
<th scope="row"> <th scope="row">
<p>교육일정</p> <p>교육일정</p>
</th> </th>
<td>연중</td> <td>(신청) 2월말~3월초, (운영) 3월~11월</td>
</tr> </tr>
<tr> <tr>
<th scope="row"> <th scope="row">