function _excelDown(fileName, sheetName, Object, thlist, tdkeylist){
const excelarray = Object.array;
var thlist = thlist;
var tdkeylist = tdkeylist;
var html = ''; html += '<html xmlns:x="urn:schemas-microsoft-com:office:excel">';
html += ' <head>';
html += ' <meta http-equiv="content-type" content="application/vnd.ms-excel; charset=UTF-8">';
html += ' <xml>';
html += ' <x:ExcelWorkbook>';
html += ' <x:ExcelWorksheets>';
html += ' <x:ExcelWorksheet>';
html += ' <x:Name>' + sheetName + '</x:Name>';
html += ' <x:WorksheetOptions><x:Panes></x:Panes></x:WorksheetOptions>';
html += ' </x:ExcelWorksheet>';
html += ' </x:ExcelWorksheets>';
html += ' </x:ExcelWorkbook>';
html += ' </xml>';
html += ' </head>';
html += ' <body>';
// ----------------- 시트 내용 부분 -----------------
html += "<table >";
html += " <thead>";
html += " <tr>";
for ( var i = 0; i < thlist.length; i ++) {
html += "<th>";
html += thlist[i];
html += "</th>";
}
html += "</tr>";
html += " </thead>";
html += " <tbody>";
for (var i = 0; i < Object.array.length; i ++) {
html += " <tr>";
for(var j = 0; j < tdkeylist.length; j ++) {
html += " <td>";
if(tdkeylist[j] == "CA")
{
html += moment(Object.array[i][tdkeylist[j]]).format('YYYY-MM-DD');
}
else if(tdkeylist[j] == "PD") {
if (parseInt(Object.array[i].PD/60)==0)
html += ((Object.array[i][tdkeylist[j]])%60)+"s";
else
html += parseInt((Object.array[i][tdkeylist[j]])/60)+"m "+(parseInt(parseInt(Object.array[i][tdkeylist[j]])%60))+"s"
}
else
{
html += Object.array[i][tdkeylist[j]];
}
html += " </td>" ;
}
html += " </tr>";
}
html += " </tbody>";
html += "</table>";
// }
//시트 내용 부분 -----------------
html += ' </body>'; html += '</html>';
// 데이터 타입
var data_type = 'data:application/vnd.ms-excel';
var ua = window.navigator.userAgent; var blob = new Blob([html], {type: "application/csv;charset=utf-8;"});
if ((ua.indexOf("MSIE ") > 0 || !!navigator.userAgent.match(/Trident.*rv\:11\./)) && window.navigator.msSaveBlob)
{ // ie이고 msSaveBlob 기능을 지원하는 경우
navigator.msSaveBlob(blob, fileName);
}
else { // ie가 아닌 경우 (바로 다운이 되지 않기 때문에 클릭 버튼을 만들어 클릭을 임의로 수행하도록 처리)
var anchor = window.document.createElement('a');
anchor.href = window.URL.createObjectURL(blob);
anchor.download = fileName; document.body.appendChild(anchor); anchor.click();
// 클릭(다운) 후 요소 제거
document.body.removeChild(anchor);
}
}
function exceldownload(Object)
{ // 대상 테이블을 가져옴
var table = document.getElementById("data-table-combine");
if(table){ // CASE 대상 테이블이 존재하는 경우
var thlist = []; // th 들어갈 배열
var tdkeylist = []; // tr을 추출하기위해 배열의 식별 값을 가져옴
for(var i = 0; i < $('#memDiv1 th').length; i ++) {
if($('#memDiv1 th').eq(i).text() != "") {
thlist.push($('#memDiv1 th').eq(i).text())
tdkeylist.push($('#memDiv1 th').eq(i).attr('name'))
}
}
// 엑셀다운 (엑셀파일명, 시트명, 내부데이터HTML)
_excelDown("oasis_excel.xls", "Sheet", Object, thlist, tdkeylist)
}
}
1. 먼저 화면 구성을 해준다. 버튼을 눌렀을 경우 onclick으로 함수가 실행되도록 한다.(로그아웃도 동일)
2. HTML script - get메소드를 쓰기 때문에 location 을 바꿔주어서 백엔드에서 로직이 실행되도록 한다.
// 회원탈퇴 기능
function withdrawal(i18nconvert) {
var answer;
//페이지를 이동하기 전에 confirm()을 사용해 다시 한번 확인한다.
//확인을 선택하면 answer에 true, 취소를 선택하면 false 값이 들어간다.
answer = confirm(i18nconvert("layout_withdrawal_confirm"));
//확인을 선택한 경우 자바스크립트를 호출할 때 같이 넘어온 url이라는 변수에 들어있는 주소로 페이지 이동
if(answer == true){
location = '/auth/withdrawal';
}
else {
return false;
}
}
// 로그아웃 기능
function logout(i18nconvert) {
var answer;
//페이지를 이동하기 전에 confirm()을 사용해 다시 한번 확인한다.
//확인을 선택하면 answer에 true, 취소를 선택하면 false 값이 들어간다.
answer = confirm(i18nconvert("layout_signout_confirm"));
//확인을 선택한 경우 자바스크립트를 호출할 때 같이 넘어온 url이라는 변수에 들어있는 주소로 페이지 이동
if(answer == true){
location = '/auth/logout';
}
else {
return false;
}
}
3. 백엔드쪽에서 로그아웃은 쿠키가 삭제되도록, 회원탈퇴는 DB에서 데이터가 삭제되도록 한다.
- 라우터가 실행될 때, 그전에 먼저 실행되서 어떻게 할건지를 설정해준다. ( 예를들어 로그인이 안되어있을 경우 이런 페이지로 가겠다. ) 사실 라우터마다 설정들을 다 해줄 순 있지만, 굳이 반복되는 코드를 여러번 쓰는것보단 미들웨어로 한번에 처리하면 사용하기에도 편리하다.
먼저, middleware.js라는 파일을 만들고 exports 되는 함수들을 정의한 다음에
2. script부분에서 input을 parsley로 형식을 검사한 후에 loginAjax를 실행하도록 하였다.
function login(form, companyNumber, agentInfo, password) {
var CNU = document.getElementsByName(companyNumber)[0].value;
var ANU = document.getElementsByName(agentInfo)[0].value.split("/")[0];
var ANA = document.getElementsByName(agentInfo)[0].value.split("/")[1];
var PW = document.getElementsByName(password)[0].value;
var validateCNU = $('#'+form).parsley();
if(validateCNU.isValid() == true) {
loginAjax(CNU,ANU,ANA,PW);
}
event.preventDefault();
}
3. loginAjax() 함수로 백엔드에 데이터를 보낸 후 성공할 경우 어떻게 할건지를 정의한다.
2. 클라이언트 javascript 데이터 검증부분에선 먼저 버튼에 onclick에 붙어있는 함수들을 선언한다. parsley를 사용해 input에 제대로 된 데이터가 들어갔는지 먼저 검증하고 맞으면 아래 함수를 실행하도록 되어있다.
// 이메일 전송 기능
function emailSend(email) {
var EA = document.getElementsByName(email)[0].value;
var validateEA = $('#'+email).parsley();
if(validateEA.isValid() == true) {
emailSendAjax(EA);
}
else {
return alert("{{__('register_email_valid_msg')}}");
}
}
// 이메일 인증 기능
function emailCer(cerNum) {
var CEA = document.getElementsByName(cerNum)[0].value;
var validateCEA = $('#'+cerNum).parsley();
if(validateCEA.isValid() == true) {
emailCerAjax(CEA);
}
else {
alert("{{__('register_auth_enter')}}");
}
}
3. 클라이언트 javascript 함수 실행부분에선 검증된 데이터가 들어왔을 때, ajax로 백엔드에 데이터를 전송하도록 하였다.
2. searchAddr() 함수는 아래와 같다. /address 팝업창을 띄어주고 주소를 받는 콜백함수를 지정했다.
// 주소 검색 기능
function searchAddr(){
// 호출된 페이지(jusopopup.jsp)에서 실제 주소검색URL(https://www.juso.go.kr/addrlink/addrLinkUrl.do)를 호출하게 됩니다.
var pop = window.open("/address","pop","width=570,height=420, scrollbars=yes, resizable=yes");
// 모바일 웹인 경우, 호출된 페이지(jusopopup.jsp)에서 실제 주소검색URL(https://www.juso.go.kr/addrlink/addrMobileLinkUrl.do)를 호출하게 됩니다.
//var pop = window.open("/popup/jusoPopup.jsp","pop","scrollbars=yes, resizable=yes");
}
/** API 서비스 제공항목 확대 (2017.02) **/
function jusoCallBack(roadFullAddr,roadAddrPart1,addrDetail,roadAddrPart2,engAddr, jibunAddr, zipNo, admCd, rnMgtSn, bdMgtSn
, detBdNmList, bdNm, bdKdcd, siNm, sggNm, emdNm, liNm, rn, udrtYn, buldMnnm, buldSlno, mtYn, lnbrMnnm, lnbrSlno, emdNo){
// 팝업페이지에서 주소입력한 정보를 받아서, 현 페이지에 정보를 등록합니다.
document.getElementsByName('addr1')[0].value = roadAddrPart1+roadAddrPart2;
document.getElementsByName('addr2')[0].value = addrDetail;
}
3. /address 랜더링 부분 (node.js) 에선 먼저 get 메소드로 승인키를 보내고, post 메소드로 입력한 주소를 담게 하도록 구현하였다. ( address_pop.html로 랜더링 하였다. )
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Juso Search</title>
</head>
<script language="javascript">
//opener관련 오류가 발생하는 경우 아래 주석을 해지하고, 사용자의 도메인정보를 입력합니다. ("주소입력화면 소스"도 동일하게 적용시켜야 합니다.)
//document.domain = "abc.go.kr";
function init() {
var url = location.href;
var confmKey = "{{juso}}";//승인키
// resultType항목 추가(2016.10.06)
var resultType = "4"; // 도로명주소 검색결과 화면 출력유형, 1 : 도로명, 2 : 도로명+지번+상세보기(관련지번, 관할주민센터), 3 : 도로명+상세보기(상세건물명), 4 : 도로명+지번+상세보기(관련지번, 관할주민센터, 상세건물명)
var inputYn = '{{locals.inputYn}}';
if(inputYn != "Y") {
document.form.confmKey.value = confmKey;
document.form.returnUrl.value = url;
document.form.resultType.value = resultType; // resultType항목 추가(2016.10.06)
document.form.action="https://www.juso.go.kr/addrlink/addrLinkUrl.do"; // 인터넷망
//document.form.action="https://www.juso.go.kr/addrlink/addrMobileLinkUrl.do"; //모바일 웹인 경우, 인터넷망
document.form.submit();
}
else {
var roadFullAddr = '{{locals.roadFullAddr}}';
var roadAddrPart1 = '{{locals.roadAddrPart1}}';
var addrDetail = '{{locals.addrDetail}}';
var roadAddrPart2 = '{{locals.roadAddrPart2}}';
var engAddr = '{{locals.engAddr}}';
var jibunAddr = '{{locals.jibunAddr}}';
var zipNo = '{{locals.zipNo}}';
var admCd = '{{locals.admCd}}';
var rnMgtSn = '{{locals.rnMgtSn}}';
var bdMgtSn = '{{locals.bdMgtSn}}';
/** API 서비스 제공항목 확대 (2017.02) **/
opener.parent.jusoCallBack(
roadFullAddr,
roadAddrPart1,
addrDetail,
roadAddrPart2,
engAddr,
jibunAddr,
zipNo,
admCd,
rnMgtSn,
bdMgtSn
);
window.close();
}
}
</script>
<body onload="init();">
<form id="form" name="form" method="post">
<input type="hidden" id="confmKey" name="confmKey" value=""/>
<input type="hidden" id="returnUrl" name="returnUrl" value=""/>
<input type="hidden" id="resultType" name="resultType" value=""/>
<!-- 해당시스템의 인코딩타입이 EUC-KR일경우에만 추가 START-->
<!--
<input type="hidden" id="encodingType" name="encodingType" value="EUC-KR"/>
-->
<!-- 해당시스템의 인코딩타입이 EUC-KR일경우에만 추가 END-->
</form>
</body>
</html>
react에서는 react-daum-post라는 node모듈이 있는데, 이렇게 Jquery에서 힘들게 구현해보고 리액트의 라이브러리가 괜히 편한게 아니라는걸 깨달았다. (적어도 이 방식보단 쉽다고 느꼈다.) 참고로 JQuery에서 팝업을 띄우는 이 방식은 https가 아닌 http에서는 안전하지 않은 사이트라며 "무시하고보내기" 라는 버튼을 눌러야 실행된다. 사용자 입장에서 불안할 수도 있다고 생각하였다.