[JavaScript] 실시간 타이머(시계) 만들기[JavaScript] 실시간 타이머(시계) 만들기

Posted at 2019. 12. 5. 19:25 | Posted in JavaScript & jQuery/JavaScript




■ 실시간 타이머(시계) 만들기




# 소스코드

<html>

<head>

<title>:: JavaScript 전광판 효과 ::</title>

<script type="text/javascript">

    document.addEventListener("DOMContentLoaded", function() {


        // 시간을 딜레이 없이 나타내기위한 선 실행

        realTimer();


        // 이후 0.5초에 한번씩 시간을 갱신한다.

        setInterval(realTimer, 500);

    });


    // 시간을 출력

    function realTimer() {

const nowDate = new Date();

const year = nowDate.getFullYear();

const monthnowDate.getMonth() + 1;

const datenowDate.getDate();

const hournowDate.getHours();

const minnowDate.getMinutes();

const secnowDate.getSeconds();

document.getElementById("nowTimes").innerHTML = 

                  year + "-" + addzero(month) + "-" + addzero(date) + "&nbsp;" + hour + ":" + addzero(min) + ":" + addzero(sec);

}


        // 1자리수의 숫자인 경우 앞에 0을 붙여준다.

function addzero(num) {

if(num < 10) { num = "0" + num; }

  return num;

}

</script>

</head>

<body>

    <h1>■ 현재시간 : <span id="nowTimes"></span></h1>

</body>

</html>




# 출력결과







Name __

Password __

Link (Your Website)

Comment

SECRET | 비밀글로 남기기

[JavaScript] 전광판 효과 구현하기[JavaScript] 전광판 효과 구현하기

Posted at 2019. 12. 5. 13:51 | Posted in JavaScript & jQuery/JavaScript




출처① : http://www.dynamicdrive.com/dynamicindex2/crawler/index.htm

출처② : https://balancing425.tistory.com/7

CSS : http://www.dynamicdrive.com/dynamicindex2/crawler/crawler.js





■ 전광판 효과 구현(Marquee 대체)




한때 HTML이 막 유행하던 초창기에 <marquee> 태그가 들어간 싸이트는


뭔가 굉장히 화려한 사이트라고 느껴지던 때가 있었다.


지금은 완전히 묻혔지만.



프로젝트 진행중 marquee와 비슷하지만,


무한 루프처럼 끊이없이 화면에 텍스트 내용이 비춰야 하는

(<marquee> 태그사용시 해당영역에서 모든 내용이 다 사라지고 나서 출력된다.)


상황이 있었기에 필요한 코드를 찾았고 정리해 본다.





# 소스코드

<html>

<head>

<title>:: JavaScript 전광판 효과 ::</title>

<style type="text/css">

    span { margin-right:50px; }

</style>

<script type="text/javascript" src="./crawler.js"></script>

<script type="text/javascript">

document.addEventListener("DOMContentLoaded", function() {

        marqueeInit({

              uniqueid : "mycrawler"

            , style : {

                 "padding" : "2px"

                , "width" : "600px"

                , "height" : "30px"

            }

            , inc : 5                              // 속도

            , mouse : "cursor driven"       // 마우스 사용여부

            , moveatleast : 2                  // 이동속도

            , neutral : 150

            , savedirection : true             // false를 선언하면 마우스 커서가 위치하는 순간 역방향으로 움직인다.

            , random : false                   // 나오는 순서(기본값 : true)

        });

    });

</script>

</head>

<body>

<h1>■ 전광판 효과</h1>

<div class="marquee" id="mycrawler">

    <span>I'm defying gravity And you can't pull me down!</span>

    <span>이제는 나 중력을 벗어나 날아올라 날개를 펼칠거야</span>

    <span>They'll never bring us down!</span>

    <span>아무도 우릴 막지 못할 거야</span>

    <span>Everyone deserves the chance to fly</span>

    <span>그 누구라도 날아오를 자격이 있잖아!</span>

</div>

</select>

</body>

</html>




# 출력결과








Name __

Password __

Link (Your Website)

Comment

SECRET | 비밀글로 남기기

[API] 주소 검색 API(한국지역정보개발원)[API] 주소 검색 API(한국지역정보개발원)

Posted at 2019. 11. 20. 10:34 | Posted in API




참고 : https://www.juso.go.kr/addrlink/devAddrLinkRequestGuide.do?menu=roadApi





■ 주소 검색 API(한국지역정보개발원)




한국지역정보개발원에서 제공하는 도로명주소 API는 JSON 형태로 데이터를 제공해 준다.


제공하는 예제소스에서는 PHP, JSP, ASP등의 샘플을 제공하지만.


실상 JSON으로 데이터를 받을 수 있도록,


JavaScript와, jQuery Ajax를 통해 구현 할 수 있게끔 변경을 해 보았다.



# 소스코드

<!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 GO API ::</title>

<style type="text/css">

table { width:100%;border:1px solid #444444;border-collapse:collapse; }

th, td { border: 1px solid #444444; }

tr > td:first-child { text-align:center; }

div#wrap { display:none;border:1px solid #DDDDDD;width:500px;margin-top:5px;padding:5px; }

div#wrap > div { margin-top:10px;margin-left::5px;margin-right:5px;margin-bottom::5px; }

div#wrap a:link { color:#000000;text-decoration:none; }

div#wrap a:hover { color:#0000FF;text-decoration:underline; }

div#totoalOutcome { display:none; }

#closeBtn { float:right;margin-top:-5px;margin-right:-5px; }

#searchAddr { width:380px; }

#zipCode { text-align:center; }

#address, #detail { width:500px; }

</style>

<script type="text/JavaScript" src="https://code.jquery.com/jquery-1.12.4.js"></script>

<script language="javascript">


/// @brief 주소검색창 - 키보드 Enter키 입력

function enterSearch() {

var evt_code = (window.netscape) ? event.which : event.keyCode;

if (evt_code == 13) {

event.keyCode = 0;

getAddr();

}

}


/// @brief 주소검색창 - 데이터 조회

function getAddr() {


// 적용예 (api 호출 전에 검색어 체크)

let keyword = document.getElementById("searchAddr");

if(!checkSearchedWord(keyword)) {

return;

}


jQuery.ajax({

  url : "http://www.juso.go.kr/addrlink/addrLinkApiJsonp.do"

, type : "POST"

, data : {

  confmKey : "발급받은 도로명 주소 API KEY"

, currentPage : document.getElementById("currentPage").value

, countPerPage : document.getElementById("countPerPage").value

, keyword : keyword.value

, resultType : "json"

}

, dataType : "jsonp"

, crossDomain : true

, success : function(jsonStr) {


jQuery("#list").html("");

let errCodejsonStr.results.common.errorCode;

let errDescjsonStr.results.common.errorMessage;


if(errCode == "0") {

if(jsonStr != null) {

makeListJson(jsonStr);

}

} else {

alert(errDesc);

}

}

, error : function(xhr, status, error) {

alert("에러발생");

}

});

}


/// @brief 주소검색창 - 주소지 선택

function makeListJson(jsonStr) {


let htmlStr = "<thead><tr><th style='width:70px;'>우편번호</th><th>주소</th></tr></thead><tbody>";


if(jsonStr.results.common.totalCount > 0) {


jQuery("#totoalOutcome").css("display", "block");

jQuery("#totalCnt").html(jsonStr.results.common.totalCount);


jQuery(jsonStr.results.juso).each(function() {


let zipNo = this.zipNo;                  // 우편번호

let roadAddr = this.roadAddr;        // 도로명 주소

let jibunAddr = this.jibunAddr;       // 지번 주소


htmlStr += "<tr>";

htmlStr += "<td>";

htmlStr += "<a href='javascript:;' onClick='inputTextAddress(\""+zipNo+"\", \""+roadAddr+"\");'>";

htmlStr += zipNo;

htmlStr += "</a>";

htmlStr += "</td>";

htmlStr += "<td>";

htmlStr += "<a href='javascript:;' onClick='inputTextAddress(\""+zipNo+"\", \""+roadAddr+"\");'>";

htmlStr += "도로명 : " + roadAddr;

htmlStr += "</a>";

htmlStr += "<br/>";

htmlStr += "<a href='javascript:;' onClick='inputTextAddress(\""+zipNo+"\", \""+jibunAddr+"\");'>";

htmlStr += "지번 : " + jibunAddr;

htmlStr += "</a>";

htmlStr += "</td>";

htmlStr += "</tr>";

});


pageMake(jsonStr);


} else {

htmlStr += "<tr><td colspan='2'>조회된 데이터가 않습니다.<br/>다시 검색하여 주시기 바랍니다.</td></tr>";

}


htmlStr += "</tbody>";

jQuery("#list").html(htmlStr);

}


/// @brief 주소검색창 - 주소지 삽입

function inputTextAddress(zipcode, address) {

document.getElementById("zipCode").value = zipCode;

document.getElementById("address").value = address;

}


/// @brief 주소검색창 - 열기

function addressWindowOpen() {

jQuery("#wrap").slideDown();

jQuery("#searchAddr").focus();

}


/// @brief 주소검색창 - 닫기

function addressWindowClose() {

jQuery("#wrap").slideUp();

jQuery("#searchAddr").val("");

jQuery("#totoalOutcome").css("display", "none");

jQuery("#list").empty();

jQuery("#pagingList").empty();

jQuery("#currentPage").val("1");

}


/// @brief 주소검색창 - 특수문자 제거

function checkSearchedWord(obj) {


if(obj.value.length > 0) {


// 특수문자 제거

var expText = /[%=><]/;


if(expText.test(obj.value) == true) {

alert("특수문자를 입력 할수 없습니다.") ;

obj.value = obj.value.split(expText).join("");

return false;

}


// 특정문자열(sql예약어의 앞뒤공백포함) 제거

var sqlArray = new Array(

  "OR", "SELECT", "INSERT", "DELETE", "UPDATE", "CREATE"

  , "DROP", "EXEC", "UNION",  "FETCH", "DECLARE", "TRUNCATE"

);

// sql 예약어


var regex = "";

for(var num = 0num < sqlArray.lengthnum++) {


regex = new RegExp(sqlArray[num], "gi") ;


if(regex.test(obj.value)) {

alert("\"" + sqlArray[num]+"\"와(과) 같은 특정문자로 검색할 수 없습니다.");

obj.value = obj.value.replace(regex, "");

return false;

}

}

}

return true ;

}


/// @brief 주소검색창 - 페이징 생성

function pageMake(jsonStr) {


var totaljsonStr.results.common.totalCount; // 총건수

var pageNum = document.getElementById("currentPage").value; // 현재페이지

                var pageBlock = Number(document.getElementById("countPerPage").value); // 페이지당 출력 개수

var paggingStr = "";


// 검색 갯수가 페이지당 출력갯수보다 작으면 페이징을 나타내지 않는다.

if(total > pageBlock) {


var totalPages = Math.floor((total - 1) / pageNum) + 1;

var firstPage = Math.floor((pageNum1) / pageBlock) * pageBlock + 1;


if(firstPage <= 0) { firstPage1; };


var lastPage = (firstPage1) + pageBlock;


if(lastPagetotalPages) { lastPage = totalPages; };

var nextPagelastPage + 1;

var prePage = firstPage - pageBlock;


if(firstPage > pageBlock) {

paggingStr += "<a href='javascript:;' onClick='goPage(" + prePage + ");'>◀</a>";

paggingStr += "&nbsp;";

}


for(let num = firstPage; lastPage >= numnum++) {

if(pageNum == num) {

paggingStr += "<a style='font-weight:bold;color:#0000FF;' href='javascript:;'>" + num + "</a>";

paggingStr += "&nbsp;";

} else {

paggingStr += "<a href='javascript:;' onClick='goPage(" + num + ");'>" + num + "</a>";

paggingStr += "&nbsp;";

}

}


if(lastPage < totalPages) {

paggingStr += "<a href='javascript:;' onClick='goPage(" + nextPage + ");'>▶</a>";

}

}


                jQuery("#pagingList").html(paggingStr);

}


/// @brief 페이징 이동

function goPage(pageNum) {

document.getElementById("currentPage").value = pageNum;

getAddr();

}

</script>

</head>

<body>

<h1>■ 행정안정부 - 주소 검색 API</h1>

<hr/>

현재 페이지 : <input type="number" id="currentPage" value="1" style="text-align:center;"/>

<div style="height:5px;"></div>

페이지당 출력 개수 : <input type="number" id="countPerPage" value="5" style="text-align:center;"/>

<hr/><br/>

<input type="text" id="zipCode" value="" onClick="addressWindowOpen();" placeholder="00000" readonly/>

<input type="button" onClick="addressWindowOpen();" value="우편번호 찾기"/>

<div id="wrap">

<img id="closeBtn" src="./close_box_red.png" onClick="addressWindowClose();"/>

<div>

<input type="text" id="searchAddr" value="" onkeydown="enterSearch();" placeholder="도로명주소, 건물명 또는 지번 입력"/>

<input type="button" onClick="getAddr();" value="주소검색"/>

</div>

<div>

<div id="totoalOutcome">

검색결과 : <span id="totalCnt">0</span>

</div>

<table id="list"></table>

</div>

<div id="pagingList" style='text-align:center;'></div>

</div>

<div style="height:5px;"></div>

<input type="text" id="address" value="" placeholder="도로명 주소, 지번 주소" readonly/>

<div style="height:5px;"></div>

<input type="text" id="detail" value="" placeholder="상세 주소지 입력"/>

</body>

</html>




# 출력결과





'API' 카테고리의 다른 글

[API] 주소 검색 API(한국지역정보개발원)  (0) 2019.11.20

Name __

Password __

Link (Your Website)

Comment

SECRET | 비밀글로 남기기

[JavaScript] AJAX 호출[JavaScript] AJAX 호출

Posted at 2019. 11. 17. 22:35 | Posted in JavaScript & jQuery/JavaScript




참고① : 하루 10분씩 핵심만 골라 마스터하는 Ajax 핸드북

참고② : Ajax 시작하기 



전통적인 방식의 사이트들을 이용할 때에는 텍스트와 그림, 데이터 입력 폼(Form) 등이 하나의 페이지 단위로 처리되었다.


각각의 페이지들도 다른 페이지로 이동하기 전에는 페이지 전체가 하나의 독립된 페이지로 처리되었다.



예를 들면, 폼의 데이터 입력 필드에 값을 기록하고 또 수정하는 등의 작업을 하더라도 우리가 전송 버튼을 누르기 전에는


어떠한 내용도 서버에 보내지 않는다.



입력된 폼을 전송하거나 링크를 통해서 다른 곳으로 이동할 때,


사용자는 반드시 새로운 페이지가 서버로부터 전송되어 화면에 업데이트될 때까지 기다려야 한다.







■ AJAX를 이용하여 XML 데이터 출력하기




# 소스코드 - XML 데이터 생성

 tell_time_xml.php

<?php

header("Content-Type:text/xml");

echo "<?xml version='1.0'?>";

echo "<clock>";

echo "<timeNow>";

echo date("Y-m-d H:i:s");

echo "</timeNow>";

echo "</clock>";

?>




# 소스코드 - AJAX 호출 영역

 ajax_application.html

<html>

<head>

<meta charset="UTF-8">

<title>:: Ajax Demonstration ::</title>

<style type="text/css">

body { text-align:center; }

#showTime {

display:inline-block;

width:250px;

background-color:#FFFFFF;

border:2px solid #000000;

padding:10px;

font:24px normal verdana, helvetic, arial, sans-serif;

}

</style>

<script language="JavaScript" type="text/javascript">

document.addEventListener("DOMContentLoaded", function() {

// HTML 실행이 완료되었을 경우 getServerTime( ) 함수를 실행한다.

getServerTime();

});

function getXMLHTTPRequest() {

let request = false;

// 브라우저(FireFox, Chrome)에 맞는 생성자를 이용해서 객체의 인스턴스를 생성

try {

request = new XMLHttpRequest();

}

// 객체가 존재하지 않는경우 MS방식의 브라우저 이므로 ActiveX객체를 검사하고 생성하는 작업을 수행한다.

catch(err01) {

try {

request = new ActiveXObject("Msxml2.XMLHTTP"); // some versions IE

}

catch(err02) {

try {

request = new ActiveXObject("Microsoft.XMLHTTP"); // some versions IE

}

catch(err03) {

request = false;

}

}

}

return request;

}

// XMLHTTPRequest 객체를 생성하여 http라는 전역 변수에 담아 필요할때 바로 사용한다.

let http = getXMLHTTPRequest();

function getServerTime() {

// xml 형태의 시간정를 가지고 있는 URL 정보

let xmlUrl = "tell_time_xml.php";

// XMLHTTPRequest 객체가 서버와 통신하기 위한 준비과정을 진행한다.

http.open("GET", xmlUrl, true);


                // onreadystatechange 메소드는 useHttpResponse( ) 함수를 호출한다.

                // 해당 함수를 수행하는 것이 아니라 단순하게 어떤 함수가 불릴 것인지만 지정한다.

                // 단순하게 그 함수를 지정하는 것이므로 그 함수로 어떠한 변수도 전달하지 않는다. ( 괄호사용× )

                // 또한 단순하게 함수를 연결하면 되기 때문에 함수 본체를 기입해도 된다.

http.onreadystatechangeuseHttpResponse;

// .open( ); 메소드를 이용해서 XMLHTTPRequest를 준비된 내용을 가지고,

// 서버에 실제 요청을 보내기위해 .send( ); 메소드를 사용한다. 

http.send(null);

}

function useHttpResponse() {

// readyState값이 4인경우 완료됨을 의미한다.

if(http.readyState == 4) {

// HTTP 응답이 "OK"인 경우

if(http.status == 200) {

var timeValue = http.responseXML.getElementsByTagName("timeNow")[0];

document.getElementById("showTime").innerHTML = timeValue.childNodes[0].nodeValue;

}

else {

// 서버가 리턴한 http 상태를 설명한다.

alert("An error has occurred : " + http.statusText);

}

}

// 완료되지 않은경우 버퍼링 이미지를 노출한다.

else {

document.getElementById("showTime").innerHTML = "<img src='http://gph.is/1XRTmuh' style='width:100%;'>";

}

}

</script>

</head>

<body style="background-color:#CCCCCC">

<h1>Ajax Domonstration</h1>

<h2>Getting the server time without page refresh</h2>

<form>

<input type="button" value="Get Server Time" onClick="getServerTime();"/>

</form>

<div id="showTime"></div>

</body>

</html>



# 출력결과









■ AJAX를 이용한 JSON 데이터 전송






작성중





Name __

Password __

Link (Your Website)

Comment

SECRET | 비밀글로 남기기

[JAVA] Java의 역사와 JVM, 알아두어야 하는 상식[JAVA] Java의 역사와 JVM, 알아두어야 하는 상식

Posted at 2019. 11. 6. 19:04 | Posted in JAVA







■ 자바의 역사




자바의 역사는 1991년으로 거슬러 올라간다. 1991년에 "Green"이라는 프로젝트가 생기면서 자바의 모태가 탄생하기 시작했다.


제임스 고스링(James Gosling), 마이크 쉐리든(Mike Sheridan), 패트릭 노튼(Patrick Naughton) 이렇게 3명의 젊은이가


TV와 시청자가 서로 상호 작용을 하는(interactive 한) 것을 만들기 위해서 시작되었다.


지금은 IPTV와 같은 것이 대중화 되어 있지만, 그때만 해도 너무 앞서가는 것이었다.


1992년 고슬링의 사무실 앞에 있는 참나무를 보고 이름을 지은 "Oak"라는 언어다.



그 이후에 1995년 "Oak"라는 언어의 이름이 커피의 한 종류를 뜻하는 "자바 커피"의 이름을 본따 "Java"라고 바뀌면서 자바 기술이 시작하게 되었다.


1995년에 자바 언어를 만들면서 "Write Once, Run Anywhere(WORA)"라는 모토가 만들어졌으며,


여러 플랫폼에서 수행할 수 있는 개발 언어를 목표로 개발되었다.


1996년에 드디어 JDK 1.0이 출시되었으며, 그 이듬해 1997년에 출시한 JDK 1.1DMS 3주만에 22만 다운로드를 기록하면서 폭발적인 성장을 예견하게 되었다.


여기서 JDK라는 단어는 Java Development Kit의 약자다.



1998년 12월 J2SE라는 이름으로 자바의 기본 버전 명칭이 바뀌면서 J2SE 1.2가 출시되었다.


참고로 J2SE는 Java 2 Standard Edition의 약자이며 기존의 JDK를 의미하는 것이다.


왜 이렇게 이름이 바뀌었냐면, 기업 등에서 만드는 시스템을 개발하기 위한 J2EE라는 Enterprise Edition과


블랙베리와 같은 전화기에서 아직도 사용하고 있는 J2ME라는 Micro Edition과 혼동을 막기 위함이었다.



그 이후에 2000년 J2SE 1.3이, 우리나라에서 월드컵이 열린 2002년 J2SE 1.4가 출시되었다. 그리고 2004년 J2SE 5가 출시되었다.


J2SE 1.4 버전까지만 해도 버전 이름이 1.1 ~ 1.4까지 증가하였지만, J2SE 1.5 버전부터는 앞의 1.을 뺀 J2SE 5라고 불리게 되었다.


그 다음에 약간의 개선이 이루어진 Java SE 6가 2006년 출시되었다.


그리고, 2011년 오랜 기간동안의 업그레이드 준비를 마친 Java SE 7이 탄생되었다.



Java SE 6까지는 이제는 역사속으로 사라진 Sun Microsystems라는 회사에서


자바에 대한 주요 스팩을 만들고 Java를 만들어 왔지만, Java SE 7 부터는 Oracle이라는 회사가


Sun Microsystems를 인수하여 지금에 이르고 있다.




※ 자바의 표준 버전의 이름이 JDK, J2SE, Java SE로 변경되어 왔지만 일반적으로 JDK라고 통일하여 불리고 있다.









■ JDK, J2SE, Java SE 외에 자바에서 사용되는 다른 용어




앞서 설명한 각각의 용어는 다음의 약자다.



 ● JDK : Java Development Kit


 ● J2SE : Java 2 Standard Edition


 ● Java SE : Java Standard Edition



여기서 Java 2에서 빠진 것은 Java SE 6가 출시되면서 부터이며,


이렇게 빠진 이유는 마케팅을 위해서라기 보다 쉽게 자바를 부를 수 있도록 Java로 통칭했다고 한다.



그리고, 자바를 개발하기 위해서 설치를 하다 보면, JDK와 JRE로 분리되어 있는 것을 알고 있을 것이다.


여기서 각각의 용어는 다음을 의미한다.



 ● JDK : Java Development Kit


 ● JRE : Java Runtime Environment



각각의 이름에서 알 수 있듯이 JRE는 실행만을 위한 환경이다.


따라서, 이 JRE만 설치하면, 자바를 컴파일하는 등의 각종 프로그램이 제외된 상태로 설치된다.







가장 좌측을 보면 JDK와 JRE로 나뉘어져 있는 것을 볼 수 있다.


즉, JRE는 자바를 실행할 수 있는 환경의 집합이라고 보면 된다.


그리고, JRE에 있는 여러 가지 레고 블록처럼 칸칸이 쌓여 있는 것들은 자바에서 제공하는 라이브러리들이라고 보면 된다.











■ 자바 언어의 다섯가지 특징




#01. 자바는 "단순하고, 객체지향이며, 친숙"해야 한다.



지금 자바를 배우는 사람들은 자바가 단순하지 않은 언어라는 것을 알고 있다.


왜냐하면 수 많은 프레임웍들이 있고, 여러 관련된 사항들을 알아야 프로그램을 작성할 수 있기 때문이다.


(여기서 이야기 하는 단순한 이란 자바에 대한 기본 컨셉을 배우는 것이 어렵지 않다는 것을 의미한다.)




자바는 처음 만들 때부터 객체지향으로 디자인되어 있다.


그리고, 다형성, 캡슐화등 객체지향 언어의 특징들을 지원할 수 있는 구조로 되어 있다.


그리고 다형성, 캡슐화 등 객체지향 언어의 특징을 지원할 수 있는 구조로 되어 있다.


물론 개발하는 사람이 객체지향 프로그램을 작성하지 않으면 이러한 이점은 모두 사라진다.


다시 말해서, 자바를 쓴다고 해서 무조건 객체지향적으로 개발된다는 것은 아니다.




그리고, 자바로 개발할 때에는 처음부터 모든 것을 만들 필요가 없다.


개발하면서 필요한 여러 기능들은 이미 API를 통해제 제공하고 있다.


파일을 읽고 쓰거나 네트워크로 데이터를 주고 받는 I/O, 그래픽, UI등을 개발하기 위한 여러 라이브러리를 통해서


보다 쉽게 개발할 수 있는 환경을 제공한다.




#02. 자바는 "견고하며, 보안상 안전"하다.



자바는 컴파일 할 때와 실행할 때 문법적 오류에 대한 체크를 한다.


메모리 관리 모델이 매우 단순하고, C를 배우고 사용하는 개발자들의 머리를 아프게 하는 포인터의 개념이 없다.


이러한 특징들은 자바를 매우 믿을 수 있고, 견고한 소프트웨어가 될 수 있도록 도와준다.



자바는 기본적으로 분산 환경에서 사용하기 위해서 디자인 되었다.


분산 환경에서 보안은 매우 주용한 부분 중 하나다.


자바 기술은 외부에서 침입이 불가능한 애플리케이션을 만들 수 있도록 해준다.


네트워크 환경에서 클라이언트로 다운로드한 승인받지 않은 프로그램은 실행할 수 없도록 되어 있다.


따라서 바이러스를 생성하거나 파일 시스템을 공격할 수가 없다.




#03. 자바는 "아키텍처에 중립적이어야 하며 포터블"해야 한다.



자바로 작성한 프로그램은 매우 다양한 하드웨어 아키텍처에서 수행 할 수 있도록 되어 있다.


따라서 자바는 아키텍처에 중립적인 바이코드를 생성한다.


따러서, 자바의 버전만 동일하다면, 동일한 프로그램은 어떤 플랫폼에서도 실행 할 수 있다.



아키텍처 중립적이라는 말은 포터블한 시스템의 일부분일 뿐이다.


그래서, 기본 데이터 타입의 크기를 지정해 놓고, 숫자 연산자에 대한 행위들을 정의해 두었다.


따라서, 여러분들이 만드는 프로그램은 어떤 플랫폼에서도 동일한 결과가 나오며,


하드웨어와 소프트웨어 아키텍처에 따른 데이터 타입의 호환성에 문제가 발생하지 않는다.


이러한 호환성과 포터블한 환경을 제공하는 것은 JVM 덕분이다.





#04. 자바는 "높은 성능"을 제공해야 한다.



성능은 항상 고려를 하는 부분이다.


자바는 실행환경에서 최대한의 성능을 낼 수 있도록 되어 있다.


게다가 자동화된 가비지 컬렉터는 낮은 우선순위의 쓰레드로 동작하기 때문에 보다 높은 성능을 낼 수 있다.


그리고, 보다 빠른 성능을 위해서 네이티브한 언어로 작성한 부분을 자바에서 사용할 수도 있도록 되어 있다.

(자바가 이 세상에서 제일 빠른 언어라는 말은 아니다.)




#05. 자바는 "인터프리트 언어이며, 쓰레드를 제공하고, 동적인 언어"이다.



자바 인터프리터는 자바 바이트코드를 어떤 장비에서도 수행할 수 있도록 해준다.


따라서, 기존에 사용하던 무거운 컴파일과 링크와 테스트 사이클을 거쳐야 하는 개발환경보다 빠른 환경을 구축할 수 있다.



자바는 멀티 쓰레드 환경을 제공하기 때문에, 동시에 여러 작업을 수행할 수 있다.


따라서, 사용자에게 매우 빠른 사용 환경을 제공한다.



자바 컴파일러는 컴파일시 매우 엄격한 정적인 점검을 수행한다.


그리고, 실행시에 동적으로 필요한 프로그램을 링크시킨다.


게다가 새로운 코드는 다양한 소스에서 요청에 의해서 연결될 수 있다.



지금까지 간단하게 자바 언어의 특징에 대해서 살표보았다.


이러한 특징들은 자바 개발 초기에 정해진 것으로, 약간은 지금의 상황과 다른 부분이 있다.


하지만, 이 내용간의 근간은 달라지지 않고 계속 유지되고 있으므로, 기억해 두면 좋을 것이다.









■ JIT(Just-In-Time) 컴파일러란?




JIT라는 것은, Just-In-Time의 약자다.


JIT를 사용하는 언어에는 Java와, .NET 등이 있다. 즉, 자바에서만 사용하는 개념이 아니다.


JIT를 좀더 쉬운 말로 하면 "동적 변환(Dynamic Translation)"이라고 보면 된다.


이러한 JIT라는 것을 만든 이유는 프로그램 실행을 보다 빠르게 하기 위해서이다.


명칭이 컴파일러이지만, 실행시에는 적용되는 기술이다.



역사적으로 보면, 컴퓨터 프로그램을 실행하는 방식은 두가지로 나눌 수 있다.


하나는 인터프리터(Interpret) 방식이며, 다른 하나는 정적(Static) 컴파일 방식이다.



인터프리터 방식은 프로그램을 실행할 때마다 컴퓨터가 알아 들을 수 있는 언어로 변환하는 작업을 수행한다.


따라서, 간편하기는 하지만 성능이 매우 느릴 수 밖에 없다.



정적 컴파일 방식은 실행하기 전에 컴퓨터가 알아 들을 수 있는 언어로 변환화는 작업을 미리 실행한다.


따라서, 변환 작업은 딱 한 번만 수행한다.



JIT는 이 두 가지 방식을 혼합한 것이라고 보면 된다.


변환 작업은 인터프리터에 의해서 지속적으로 수행되지만,


필요한 코드의 정보는 캐시에 담아두었다가(메모리에 올려두었다가) 재사용 하게 된다.



여기서 헷갈릴 수 있는 부분은 javac 명령어를 사용하여 컴파일을 하기때문에


그럼 자바는 정적 컴파일 방식 아닌가? 라고 생각 할 수 있는데


자바 프로그래밍 과정에서는 javac라는 명령어를 사용하여 컴파일을 하는 단계에서 만들어진


class라는 파일은 바이트코드(ByteCode)일 뿐이다.



자바의 모토 중에 하나가 "Compile once, Run anywhere"다.


한번 컴파일한 코드로  Linux, Mac OS X, Window 등에서 모두 사용할 수 있다.


다시 말해서, javac란느 명령어를 수행한다는 것은 텍스트로 만드 java파일을 어떤 OS에서도 수행될 수 있도록


바이트코드라는 파일로 만든 것뿐이다.


컴퓨터가 알아먹을 수 있도록 하려면 다시 변환 작업이 필요한데,


이 작업을 JIT 컴파일러에서 한다고 보면 된다.






위 그림에서 "JVM → 기계코드"로 변환되는 부분은 JIT에서 수행하는 것이다.


JIT를 사용하면 반복적으로 수행되는 코드는 매우 빠른 성능을 보인다는 장점이 있지만,


반대로 처음에 시작할 때에는 변환 단계를 거쳐야 하므로 성능이 느리다는 단점이 있다.


하지만, 최근들어 CPU 성능이 많이 좋아졌고, JDK의 성능 개선도 많이 이루어졌기 때문에 방금 이야기한 단점도 많이 개선되었다.









■ 자바를 배우면 꼭 알아야 하는 용어(JVM, GC)




일반적으로 자바를 설명할 때 많이 사용되는 용어들은 다음과 같은 것들이 있다.



 ● JVM : Java Virtual Machine (자바 가상 머신)


 ● GC : Garbage Collector (가비지 컬렉터)



JVM은 작성한 자바 프로그램이 수행되는 프로세스를 의미한다.


다시 말해서, java라는 명령어를 통해서 애플리케이션이 수행되면, 이 JVM 위에서 애플리케이션이 동작한다.


이 JVM에서 여러분들이 작성한 프로그램을 찾고 실행하는 일련의 작업이 진행된다.



자바의 기본 메모리 관리는 개발자가 하지 않아도 된다.


메모리 관리를 JVM이 알아서 하기 때문이다. 이때 JVM 내에서 메모리 관리를 해주는 것을 바로 "가비지 컬렉터"라고 부른다.


Garbage는 우리나라말로 "쓰레기"라는 의미이며, 사용하고 남아 있는 전혀 필요없는 객체들이 여기에 속한다.


아무리 가비지 컬렉터가 쓰레기를 알아서 청소한다고 하더라도, 메모리를 효율적으로 사용하도록 개발하는 것은 중요하다.



일반적으로 사용되는 GC라는 말의 의미는 Garbage Collection(가비지 컬렉션)을 의미한다.


예를 들어, 쓰레기를 청소하는 작업이 수행되면 "가비지 컬렉션이 수행되었다"라고 표현한다.


아니면 짧게 "GC가 발생했다"고 이야기한다.









■ Garbage Collector의 진행방식




자바 프로그래밍 과정에 있어 어떤 객체를 생성하더라도 그 객체는 언젠가는 쓰레기가 되어 메모리에서 지워져야만 한다.


예를 들어 "abc"라는 문자열이 있는데, 더 이상 사용할 일이 없다면 메모리에서 삭제되어야 한다.


만약 지워지지 않으면, 더 이상 상요할 일이 없다면 메모리에서 삭제되어야 한다.


허나 계속 지워지지 않고 있다면, 자바 프로그램은 엄청난 메모리가 필요할 것이다.


그래서, C를 사용하여 개발 할 때에는 메모리를 해제하는 작업을 꼭 해줘야만 한다.


하지만, 자바는 그런 작업을 해줄 필요가 없다.


가비지 컬렉터라는 것이 알아서 쓰레기들을 치워주기 때문이다.


JDK 7부터 공식적으로 사용할 수 있는 G1(Garbage First)라는 가비지 컬렉터를 제외한 나머지 JVM은


다음과 같이 영역을 나누어 힙(Heap)이라는 공간에 객체들을 관리한다.

(여기에서 사용되는 영역에 대한 요어들은 JDK의 벤더에 따라서 조금씩 다르다.)



가장 왼쪽에 있는 Young 영역에는 말 그대로 젊은 객체들이 존재하며, Old 역역에는 늙은 객체들이 자리잡게 된다.


그리고 Perm 이라는 영역에는 클래스나 메소드에 대한 정보가 쌓인다.

(Perm에 저장되는 데이터는 더 많지만, 이정도만 알고 있어도 된다.)



Young 영역은 Eden과 두개의 Survivor 영역으로 나뉘는데, 이 중에서 객체를 생성하자마자 저장되는 장소는 Eden이다. 


일반적으로 자바에서 메모리가 살아가는 과정은 다음과 같다.



 ① Eden 영역에서 객체서 생성된다.


 ② Eden 영역이 꽉 차면 살아있는 Survivor 영역으로 복사되고, 다시 Eden 영역을 채우게 된다.


 ③ Survivor 영역이 꽉 차게 되면 다른 Survivor 영역으로 객체가 복사된다.

    이때, Eden 영역에 있는 객체들 중 살아있는 객체들도 다른 Survivor 영역으로 간다.

    즉, Survivor 영역의 둘 중 하나는 반드시 비어 있어야만 한다.



지금까지 서술한 것을 마이너(Minor) GC 혹은 Young GC라고 부른다.


여기서 GC는 가비지 컬렉터가 아니라 가비지 컬렉션을 의미한다.



그러다가, 오래 살아있는 객체들은 Old 영역으로 이동한다.


지속적으로 이동하다가 Old 영역이 꽉 차면 GC가 발생하는데 이것을 메이저(Major) GC 혹은 FUll GC라고 부른다.



일반적으로 Young GC와 Full GC의 속도를 비교하면 Young GC의 속도가 빠르다.


Young GC는 더 작은 공간이 할당되고, 객체들을 처리하는 방식도 다르기 때문이다.


그렇다고, 전체의 힙 영역을 영 영역으로 만들면 장애로 이어질 확률이 매우 높아진다.



오라클 JDK에서 제공하는 GC의 방식은 크게 4가지 버전이 있으며,


JDK 7.0부터 추가된 G1(Garbage First)를 포함하여 총 5가지의 가비지 컬렉터가 존재한다.


정리하면 다음과 같다.



 ● Serial GC


 ● Parallel Young Generation Collector


 ● Parallel Old Generation Collector


 ● CMS : Concurrent Mark & Sweep Collector


 ● G1 : Garbage First



이중에서 WAS로 사용하는 JVM에서 사용하면 안되는 것은 Serial GC이다.


이 GC 방식은 -client 옵션을 지정했을 때 사용된다.


즉 클라이언트용 장비에 최적화된 GC이기 때문에 WAS에서 이 방식을 사용하면 GC의 속도가 매우 느려져


웹 애플리케이션이 엄청 느려진다.



그 외에 다른 GC 방식들은 서로 장단점이 존재하기 때문에 어떤 GC방식이 가장 적합하다고 이야기하기는 매우 어렵다.


'JAVA' 카테고리의 다른 글

[JAVA] Java의 역사와 JVM, 알아두어야 하는 상식  (0) 2019.11.06

Name __

Password __

Link (Your Website)

Comment

SECRET | 비밀글로 남기기

[Puppeteer] evaluate() 함수에 변수 전달하기[Puppeteer] evaluate() 함수에 변수 전달하기

Posted at 2019. 9. 30. 19:49 | Posted in Node.js/Puppeteer




참고 : https://code-examples.net/ko/q/2bf409f






■ evaluate( ) 함수에 변수 전달하기




이전 [Puppeteer] 퍼펫티어를 이용한 CRAWLING 작업 포스팅에서


티스토리 로그인을 하는 예제를 조금 수정하여 작업을 진행한다.


해당 포스팅에서는 자바스크립트의 코드를 사용 할 수 있게 해주는


evaluate( ) 함수가 존재하고,


해당 evaluate( ) 함수에 변수값을 사용하는데 있어 아래와 같이 사용 한 경우 에러가 발생하였다.



 puppeteer_evaluate.js

const puppeteer = require("puppeteer");

// 사용시 인위적인 딜레이를 주기위한 함수
function delay( timeout ) {
return new Promise(( resolve ) => {
setTimeout( resolve, timeout );
});
}

puppeteer.launch( { headless : true } ).then(async browser => {

const page = await browser.newPage();
await page.goto( "http://magic.wickedmiso.com/manage/", { waitUntil : "networkidle2" } );

let magicId = "tistoryId";      // 티스토리 아이디
let magicPw = "tistoryPw";    // 티스토리 패스워드

await page.evaluate(() => {
        document.getElementById( "loginId" ).value = magicId;
        document.getElementById( "loginPw" ).value = magicPw;
});

await delay(3000);


        // 로그인 SUBMIT 기능

const elementHandle = await page.waitFor( "input" );

await elementHandle.press( "Enter" );

await delay(5000);

        /* 로그인이후 방문 기록 데이터를 콘솔에 띄워본다. */

const emToDay = await page.waitFor( "div.box_blog > dl.count_visitor:nth-child(1) > dd" );

        const txtToDay = await page.evaluate( emToDay => emToDay.textContent, emToDay );

        console.log("-. 오늘 방문자 수", txtToDay);

    

const emYesterDay = await page.waitFor( "div.box_blog > dl.count_visitor:nth-child(2) > dd" );

        const txtYesterDay = await page.evaluate( emYesterDay => emYesterDay.textContent, emYesterDay );

        console.log("-. 어제 방문자 수", txtYesterDay);


const emCumulativ = await page.waitFor( "div.box_blog > dl.count_visitor:nth-child(3) > dd" );

        const txtCumulativ = await page.evaluateemCumulativ => emCumulativ.textContentemCumulativ );

        console.log("-. 누적 방문자 수", txtCumulativ);


});



# 에러 출력





evaluate( ) 함수 이기 때문에 해당 함수내에 값을 전달할려면


다른 함수들과 마찬가지로 전달할 값을 오버라이딩 해서 매개변수값을 전달해 주어야 한다.



 puppeteer_evaluate.js

const puppeteer = require("puppeteer");

// 사용시 인위적인 딜레이를 주기위한 함수
function delay( timeout ) {
return new Promise(( resolve ) => {
setTimeout( resolve, timeout );
});
}

puppeteer.launch( { headless : false } ).then(async browser => {

const page = await browser.newPage();
await page.goto( "http://magic.wickedmiso.com/manage/", { waitUntil : "networkidle2" } );

let magicId = "tistoryId";      // 티스토리 아이디
let magicPw = "tistoryPw";    // 티스토리 패스워드
       

        // 함수내에 매개변수를 지정해준다.

     await page.evaluate(( { magicId, magicPw } ) => {
        document.getElementById( "loginId" ).value = magicId;
        document.getElementById( "loginPw" ).value = magicPw;
// document.getElementsByClassName( "btn_login" ).disabled = false;
}, { magicId, magicPw } );


await delay(3000);


        // 로그인 SUBMIT 기능

const elementHandle = await page.waitFor( "input" );

await elementHandle.press( "Enter" );

await delay(5000);

        /* 로그인이후 방문 기록 데이터를 콘솔에 띄워본다. */

const emToDay = await page.waitFor( "div.box_blog > dl.count_visitor:nth-child(1) > dd" );

        const txtToDay = await page.evaluate( emToDay => emToDay.textContent, emToDay );

        console.log("-. 오늘 방문자 수", txtToDay);

    

const emYesterDay = await page.waitFor( "div.box_blog > dl.count_visitor:nth-child(2) > dd" );

        const txtYesterDay = await page.evaluate( emYesterDay => emYesterDay.textContent, emYesterDay );

        console.log("-. 어제 방문자 수", txtYesterDay);


const emCumulativ = await page.waitFor( "div.box_blog > dl.count_visitor:nth-child(3) > dd" );

        const txtCumulativ = await page.evaluateemCumulativ => emCumulativ.textContentemCumulativ );

        console.log("-. 누적 방문자 수", txtCumulativ);


});



위 코드를 실행시켜보면.


이제 위와 같은 에러가 나타나지 않는것을 확인 할 수 있다.


출력결과는 아래와 같다.




# 실행 결과



다시한번 evaluate( )는 함수임을 기억하자.










# 참고




티스토리의 아이디, 패스워드 입력창의 경우


키보드 입력으로 판단되지 않았기 때문에.


로그인 버튼이 활성화 되지 않은 것을 확인 되었다.


이때는 Puppeteer의 키보드 입력과 같은 이벤트를 발생시켜서 처리할 수 있게끔 작업을 진행해 주어야 한다.






Name __

Password __

Link (Your Website)

Comment

SECRET | 비밀글로 남기기

[Ubunt] CRON을 이용한 반복작업 수행하기[Ubunt] CRON을 이용한 반복작업 수행하기

Posted at 2019. 9. 29. 15:49 | Posted in Linux/Ubuntu




참고 : https://soooprmx.com/archives/6786

참고 : https://webdir.tistory.com/174

참고 : https://blog.naver.com/tyboss/70048237053

참고 : https://jhnyang.tistory.com/68




리눅스에 크론의 사용법에는 /etc/crontab을 직접 수정하는 방법과


crontab -e 로 등록하는 방법 두가지로 나뉘며


두 방식은 설정하는 방법과 동작이 다르다.


해당 포스팅은 /etc/crontab 에서 직접 수정하여 사용하는 방법을 다룬다.







■ 크론이란?



-. CRON은 유닉스 사용자로 하여금 특정한 명령이나 스크립트를 지정한 시간 / 날짜에 자동으로 실행하게 해주는 프로그램의 이름이다.


-. 주기적으로 시스템 백업 스크립트를 실행하는 등 시스템 관리자에 의해 많이 사용되며, 그 외에도 특정한 작업을 스케줄링하기 위해 사용될 수 있다.


-. 최근에는 자동으로 인터넷에 접속해서 이메일을 다운로드 받는 등의 용도로 쓰이기도 한다.




# 실행된 크론 이력 확인하기

 $ ps aux | grep crond




-. CRON은 일종의 데몬이다. 즉 한 번 실행되면 시스템에 상주하며 필요할 때마다 동작한다.


-. 비슷한 예로 웹서버도 일종의 데몬으로 웹페이지에 대한 요청이 들어올 때만 작동한다.


-. 데몬 크론은 crond라는 이름을 갖는데, 설정 파일 혹은 crontab에 기록된 날짜나 시간이 될 때까지 기다린 다음 동작을 시작한다.


-. 대부분의 유닉스 배포판에서 crond는 이미 포함되어 있고, 시작 스크립트에 기록되어 있다.








■ 크론 세팅하기




VIM을 사용하여 crontab을 수정한다.


 $ sudo vim /etc/crontab



위와 같이 crontab 창이 열리면


# m h dom mon dow user command 라는 주석 아래로


실행 명령들이 쭉 적혀있는 것을 볼 수 있다.


작성 방법은 아래와 같다.



 crontab 설정방법

설명

 * * * * *(실행주기) 사용자계정 명령어 /home/사용자계정/실행파일.sh

샘플

 00 * * * * saak sh /home/saak/shell_script.sh

※ 샘플의 명령은 매시 정각마다 shell_script.sh 파일을 saak 사용자의 권한으로 실행한다라는 의미이다.



위와 같이 작성해 주면 되는데.


실행주기를 뜯하는 에스터리스크( * )기호와

 

명령 권한을 가지는 사용자 계정


실행 명령어 혹은 실행될 스크립트 파일을 지정해준다.

(되도록이면 쉘 스크립트.sh 파일을 만들어서 진행을 해주는것이 좋다.)




# CRON 환경변수 설명

순 서

설    명

Minute

 · 분(Minute)을 나타내며, 몇 분에 실행될 것인지를 정의한다.

 · 00 ~ 59 사이의 숫자값을 사용한다.

Hour

 · 시(Hour)을 나타내며, 몇 시에 실행될 것인지를 정의한다.

 · 00 ~ 23 사이의 숫자값을 사용한다.

Dom

 · 일(Day of Month)을 나타내며, 몇 일에 실행될 것인지를 정의한다.

 · 1 ~ 31 사이의 숫자값을 사용한다.

Month

 · 월(Month)을 나타내며, 몇 월에 실행될 것인지를 정의한다.

 · 1 ~ 12 사이의 숫자값을 사용한다.

 · 숫자 이외의 월의 영문자를 사용할 수 있다.
   ( 1월 : jan, 2월 : feb, 3월 : mar, 4월 : apr, 5월 : may, 6월 : jun,

     7월 : jul, 8월 : aug, 9월 : sep, 10월 : oct, 11월 : nov, 12월 : dec )

Dow

 · 요일(Day of Week)을 나타내며, 실행될 것인지를 정의한다.

 · 0 ~ 6 사이의 숫자값을 사용한다.

 · 숫자 이외의 요일의 영문자를 사용할 수 있다.
   ( 일요일 : sun, 월요일 : mon, 화요일 : tue, 수요일 : wed, 목요일 : thu, 금요일 : fri, 토요일 : sat )

Usr

 · 명령을 실행할 사용자를 지정한다.

 · user-name 사용자 이름을 입력한다.

 · 되도록이면 root(관리자)보단 권한을 가지고 있는 사용자를 지정하는 것이 좋다.

Cmd

 · 실행할 명령을 작성한다.




모든 설정이 완료되면 CRON을 한번 재시작 시켜준다.


 $ sudo service cron reload

 $ sudo service cron restart










■ 크론 실행주기 사용예제




크론의 실행주기 (Minute), (Hour), (Dom), (Month), 요일(Dow)의 값을 설정할때.

몇가지 방법을 통해 실행주기를 설정할 수 있다.

먼저 CRON에서 연산기호를 사용하는 방법을 알아보자.



# CRON 연산기호 사용방법

기 호

설    명

*

 · 각 필드 자리에 에스터리스크( * ) 기호가 오면 해당 필드의 모든 값을 의미한다.
   예를 들어 Hour 필드에 *가 오면 매 시간, Month 필드는 매 일, Dow 필드의 *는 매월을 의미한다.

-

 · 하이픈( - ) 기호는 숫자와 숫자 사이에 사용되어 해당 숫자들 사이의 값을 구한다.

   예를 들어 1-10이라고 표현하면 1부터 10사이의 모든 값을 의미한다.

,

 · 콤마( , ) 기호는 지정한 값의 구분을 위해 사용된다.

 · 주로 불규칙한 값을 지정할때 사용된다.

   예를 들어 Hour 필드에 2, 3 ,5라고 입력하면 2시, 3시 5시에 실행된다.

/

 · 슬래시( / ) 기호는 연결된 설정 값 범위에서 특정 주기로 나눌 때 사용합니다.



위의 기호를 확인 했다면 아래의 예를 살펴보도록 하자.



① 9시부터 17시 사이의 시간에 매 15분간격으로 실행

실행주기

      */15    9-17    *    *    *



② 매월 1~15일 20~25일 그리고 17일의 정오에 실행

실행주기

     *    12    1-15,17,20-25    *    *



③ 10일, 12일, 14일, 16일 17시마다 실행

실행주기

     *    17    10-16/2    *    *



④ 매일 평일 오후1시에 실행

실행주기

     *    13    *    *    mon,tue,wed,thu,fri
     *    13    *    *    1,2,3,4,5
     *    13    *    *    1-5



⑤ 매달 16일이나, 매주 월요일 1시에 실행

실행주기

     *    1    16    *    *
     *    1    *    *    mon

※ 해당 예제와 같이 요일, 날짜등이 동시에 설정된 경우에는 두 조건 중 한 조건을 만족하면 실행된다.
   매달 16일과, 월요일이라는 두개의 설정을 하나로 압축한 예제이다.









Name __

Password __

Link (Your Website)

Comment

SECRET | 비밀글로 남기기

[CodeIgniter] 컨트롤러(Controllers) 사용방법[CodeIgniter] 컨트롤러(Controllers) 사용방법

Posted at 2019. 7. 31. 16:39 | Posted in PHP/CodeIgniter




참고 : http://www.ciboard.co.kr/user_guide/kr/general/controllers.html





■ 컨트롤러란 무엇인가?



컨트롤러는 URL과 상호작용하는 클래스 파일이라고 할 수 있다.


파일명(File.php)과 클래스(File)명의 첫글자는 항상 대문자 이여야 한다.


클래스명은 컨트롤러 파일명과 동일해야 한다.



 ./application/controllers/Blog.php

<?php

if(!defined("BASEPATH")) { exit("No direct script access allowed"); }


class Blog extends CI_Controller {

public function index() {

echo "사악미소의 현대마법의 IT공방";

}

}


/* END of file Blog.php */

/* Location : ./application/controllers/Blog.php */




# 출력결과 : http://code-igniter.com/index.php/blog/










■ 함수 호출하기




이전 예제에서 호출된 함수는 index( )였는데, index( ) 함수는 URI에서 두번째 새그먼트가 전달되지 않은 경우 기본적으로 실행이 된다.


이번에는 URI에 새그먼트 값을 추가하여 Blog라는 클래스에 comments( )라는 함수를 호출해 보자.


 ./application/controllers/Blog.php

<?php

if(!defined("BASEPATH")) { exit("No direct script access allowed"); }


class Blog extends CI_Controller {

public function index() {

echo "사악미소의 현대마법의 IT공방";

}

public function comments() {

echo "방문해 주셔서 감사합니다";

}

}


/* END of file Blog.php */

/* Location : ./application/controllers/Blog.php */




# 출력결과 : http://code-igniter.com/index.php/blog/comments




그럼 위와 같이 새로운 메세지가 출력되는 것을 확인 할 수 있다.








■ URI 세그먼트 값을 함수에 전달하기




 ./application/controllers/Products.php

<?php

if(!defined("BASEPATH")) { exit("No direct script access allowed"); }


class Products extends CI_Controller {

public function shoes($sandals, $id) {

echo sprintf("sandals : %s", $sandals);

echo "<br/>";

echo sprintf("id : %s", $id);

}

}


/* END of file Products.php */

/* Location : ./application/controllers/Products.php */





# 출력결과 : http://localhost/index.php/products/shoes/sandals/123










■ 기본 컨트롤러 정의



코드이그나이터에서는 새그먼트 없이 사이트의 루트 URI만 요청될때 실행되는 기본 컨트롤러를 지정할 수 있다.


기본 컨트롤러를 지정하려면 ../application/config/routes.php 파일의 $route[ 'default_controller' ] 의 값을 설정해 주면된다.


 ./application/config/routes.php

<?php

if(!defined("BASEPATH")) { exit("No direct script access allowed"); }


      /* 주 석 생 략 */


$route['default_controller'] = "First";

$route['404_override'] = "";

$route['translate_uri_dashes'] = FALSE;



이제 First.php 파일을 controllers 디렉토리에 생성하고.


아래와 같은 코드를 작성해 보자.



 ./application/controllers/Blog.php

<?php

if(!defined("BASEPATH")) { exit("No direct script access allowed"); }


class First extends CI_Controller {

public function index() {

echo "https://www.google.co.kr";

}

}


/* END of file First.php */

/* Location : ./application/controllers/First.php */





# 출력결과 : https://localhost




단순히 http://localhost라는 기본 주소를 입력하는 것만으로도


http://localhost/index.php/first 를 호출한것과 같은 결과를 얻을 수 있다.









■ 함수요청 재맵핑하기




일반적으로 URI의 두번째 새그먼트는 컨트롤러내의 어떤 함수를 실행할 것인가를 결정하낟.


이런 일반루틴을 재정의 하여 원하는 액션으로 바꿀 수 있다.



 http://code-igniter.com/index.php/rmapping/zerg 

<?php

if(!defined("BASEPATH")) { exit("No direct script access allowed"); }


class Rmapping extends CI_Controller {

public function _remap($method) {

if($method === "zerg") {

$this->zerg();

} else if($method === "protoss") {

$this->protoss();

} else {

$this->terran();

}

}

public function zerg() {

echo "군단의 심장";

}

public function protoss() {

echo "공허의 유산";

}

public function terran() {

echo "자유의 날개";

}

}


/* END of file Rmapping.php */

/* Location : ./application/controllers/Rmapping.php */




# 출력결과 : http://localhost/index.php/rmapping/zerg




위와 같이 출력되는 것을 확인 할 수 있다.




※ 참고


../application/config/routes.php 페이지의 


$route['default_controller'] 값을 "Rmapping" 으로 변경하고 사용하게 되면



# 출력결과 : http://localhost/index.php/rmapping/protoss









■ Private 접근제어 함수



PHP에는 public, private, protected 라는 3가지 접근 제어자가 존재한다.


접근제어자

기     능

public

 · class 밖에서도 함수에 접근이 가능하다.

 · 아무것도 명시하지 않으면 기본값이 public으로 선언된다.

private

 · 클래스 내부에서만 접근이 가능하다.

 · 상속이 불가능 하다.

protected

 · 클래스 내부에서만 접근이 가능하다.

 · 상속이 가능하다.







<?php

if(!defined("BASEPATH")) { exit("No direct script access allowed"); }


class Access extends CI_Controller {

public function index() {

echo "접 근 가 능";

}

private function _utility() {

echo "접 근 불 가";

}

}


/* END of file Access.php */

/* Location : ./application/controllers/Access.php */




# 출력결과 : http://localhost/index.php/Access/index




# 출력결과 : http://localhost/index.php/Access/_utility



위와같이 URI의 새그먼트 값으로 _utility 함수를 호출하려고 하는경우


페이지를 찾을 수 없다는 404 Page Not Found


에러가 발생하는것을 확인 할 수 있다.








■ 클래스 생성자




컨트롤러에서 생성자를 사용하고자 한다면 생성자아래 반드시 아래의 코드가 들어있어야 한다.


 parent :: __construct( );


그렇지 않으면 직접 구현한 모든 생성자가 부모 controoler의 생성자를 재정의 하기 때문에


반드시 부모 controller를 수동으로 호출해 주어야 한다.



생성자는 클래스가 초기화될 때 어떤 기본값들을 설정해야 한다거나 어떤 프로세스를 수행해야 할때 유용하다.


생성자는 리턴값이 있어서는 안된다.



 

<?php

if(!defined("BASEPATH")) { exit("No direct script access allowed"); }


class Products extends CI_Controller {

public function __construct() {

parent::__construct();

}

}


/* END of file Products.php */

/* Location : ./application/controllers/Products.php */










Name __

Password __

Link (Your Website)

Comment

SECRET | 비밀글로 남기기

[PHP] DB접속 테스트하기[PHP] DB접속 테스트하기

Posted at 2019. 7. 30. 17:00 | Posted in PHP/PHP Setting




참고 : https://blog.naver.com/diceworld/220292090236




■ PHP  데이터 베이스 접속 테스트




# 소스코드

<?php


error_reporting(E_ALL);

ini_set("display_errors", 1);

date_default_timezone_set('Asia/Seoul');


$conn = mysqli_connect("접속IP주소", "아이디", "비밀번호", "데이터베이스명", "포트");


if( empty($conn) == true ) {


      echo ( "#############################################################################" );

              echo ( "</br> default DBMS 접속 호스트 정보가 정확하지 않습니다. </br>\n\n" );

          exit ( "#############################################################################" );


} else {


      echo ( "#############################################################################" );

          echo ( "</br> default DBMS 접속에 성공하였습니다. </br>\n\n" );

          echo ( "-----------------------------------------------------------------------------" );

          echo ( "<pre>" );

          print_r ( $conn );

          echo ( "</pre>" );

          exit ( "#############################################################################" );


}

mysqli_close( $conn );


?>





# 출력결과









'PHP > PHP Setting' 카테고리의 다른 글

[PHP] DB접속 테스트하기  (0) 2019.07.30
[PHP] Windows 환경에서 Apache 및 PHP 설치하기  (0) 2018.08.18

Name __

Password __

Link (Your Website)

Comment

SECRET | 비밀글로 남기기

[MariaDB] Ubuntu MariaDB 시간 변경[MariaDB] Ubuntu MariaDB 시간 변경

Posted at 2019. 7. 30. 15:22 | Posted in MySQL/MariaDB




참고 : https://jootc.com/p/201905052779




■ 우분투 마리아DB 시간대 변경




 MariaDB> SELECT @@system_time_zone, NOW() FROM DUAL;




 $ sudo vim /etc/mysql/mariadb.conf.d/50-server.cnf


      /* 이 하 생 략 */


[mysqld]


user = mysql

pid-file = /var/run/mysqld/mysqld.pid

socket = /var/run/mysqld/mysqld.sock

port = 3306

basedir = /usr

datadir = /var/lib/mysql

tmpdir = /tmp

lc-messages-dir = /usr/share/mysql

skip-external-locking


default-time-zone = "+9:00"


      /* 이 하 생 략 */





 MariaDB> SELECT @@system_time_zone, NOW() FROM DUAL;








Name __

Password __

Link (Your Website)

Comment

SECRET | 비밀글로 남기기