반응형

autoboxing이란 래퍼(Wrapper) 클래스의 객체로 변환하는 것을 말합니다.

여기서 래퍼클래스란 기본 타입의 데이터를 객체로 취급해야 하는 경우가 있는데 기본 타입의 데이터를 그대로 사용할수는 없고 데이터를 객체로 변환해야 하는데 해당하는 데이터들을 객체로 포장해주는 것을 말합니다.

 

 

아래는 예시입니다.

Integer a = 100;

과 같이 처리하면 Integer는 래퍼 클래스이므로 오토박싱이 일어나면서 new Integer(100)을 알아서 처리해줍니다. 

 


 

unboxing이란 래퍼 유형의 객체를 해당 기본 값으로 변환하는 것을 말합니다.

예를들면 Integer가 int로 변환되는것을 말합니다.

 

Integer a = new Integer(100);
int test = a; //unboxing

래퍼클래스인 Integer a값을 primitivie 변수인 int test에 대입하면 알아서 언박싱되면서 값을 처리해줍니다.

 

 

아래는 primitivie type 과 Wrapper class의 대조 표입니다.

primitivie type Wrapper class
boolean Boolean
byte Byte
char Character
float Float
int Integer
long Long
short Short
double Double

 

참고 사이트

https://www.geeksforgeeks.org/autoboxing-unboxing-java/

 

Autoboxing and Unboxing in Java - GeeksforGeeks

A Computer Science portal for geeks. It contains well written, well thought and well explained computer science and programming articles, quizzes and practice/competitive programming/company interview Questions.

www.geeksforgeeks.org

 

반응형
반응형

일정시간마다 기존에 그려진 차트 데이터에 추가되고 일정 데이터가 쌓이면 기존에 쌓였던 데이터는 지워지는 차트를 구현하게 되었는데 구글차트를 사용하게되어 포스팅을 진행합니다.

 

https://developers.google.com/chart

 

Charts  |  Google Developers

Interactive charts for browsers and mobile devices.

developers.google.com

 

해당 URL에서 데모차트들을 참조하여 시작하였습니다.

 

구글차트는 단순하게 입력하는 데이터의 배열값이 바뀌면 알아서 바뀌어서 처음에 구현할때는 chart의 data부분값을 배열로 따로 처리하여 넣고 빼고를 하였는데, 추가되는 데이터가 애니메이션 효과처럼 추가되는걸 표현하고 싶었고, 구글 차트 중 animation파트를 확인하면서 관련 예제를 기준으로 테스트버전을 만들었습니다.

 

https://developers.google.com/chart/interactive/docs/animation

 

Animation  |  Charts  |  Google Developers

This page describes how to animate modifications made to a chart, instead of applying them instantly. Contents Overview Google charts can animate smoothly in one of two ways, either on startup when you first draw the chart, or when you redraw a chart after

developers.google.com

 

해당 URL에서는 애니메이션이 동작하면서 차트가 그려지는 부분을 예제로 제공합니다.

 

 

세션중 Adding and removing rows 라는 부분이 있는데, 버튼 클릭에 따른 랜덤함수 값에 따른 비교 후 추가해주는 함수부분을 참고하여 만들었습니다.

 


아래는 사용한 테스트용 일정시간마다 데이터를 그리는 구글차트 자바스크립트 코드입니다. 

<html>
  <head>
    <script type="text/javascript" src="https://www.gstatic.com/charts/loader.js"></script>
    <style>
      .chart{
        border: 1px solid orange;
        float: left;
        margin: 30px;
      }
    </style>
  </head>
  <body>
    <div id="chart" class="chart" style="width: 779px; height: 300px"></div>
    <script type="text/javascript">
    //Google Stuff
    google.charts.load('current', {packages: ['corechart']});
    google.charts.setOnLoadCallback(function(){ drawChart(new_option)});
    </script>
    <script type="text/javascript">
      var chartOption = function(target, maxValue, color, name){
        this.name = name;
        this.target = target;
        this.data = null;
        this.chart = null;
        this.options = {
          legend: { position: 'none' },
          vAxis: {minValue:0, maxValue:maxValue},
          hAxis: {
            textStyle: {
              fontSize: 11
            }
          },
          colors: [color],
          animation: {
            duration: 500,
            easing: 'in',
            startup: true
          }
        }
        
      }

      var new_option = new chartOption('chart', 80, '#FF5E00', '온도');
      
      function drawChart(option) {
        var o = option;
        if(o != null){
          //초기값일때만 처리
          if(o.chart == null && o.data == null){
            o.data = new google.visualization.DataTable();
            o.data.addColumn('string', 'time');
            o.data.addColumn('number', o.name);
            o.data.addRow(['', 0]);
            o.chart = new google.visualization.LineChart(document.getElementById(o.target));
          }

          o.chart.draw(o.data, o.options);
        }
      }

      function animateRenewal(option){
        var o = option;
        if (o.data.getNumberOfRows() >= 10) {
          o.data.removeRow(0);
        }


        var value = 0;
        var maxValue = o.options.vAxis.maxValue;
        if(maxValue <= 1){
          value = Number((Math.random() * maxValue).toFixed(1));
        }else {
          value = Math.floor(Math.random() * maxValue);
        }
        o.data.insertRows(o.data.getNumberOfRows(), [[getNowTime(), value]]);
        drawChart(o);
      }

      setInterval(function(){
        animateRenewal(new_option);
      }, 1000);
      
      function getNowTime(){
        var d = new Date();
        var sep = ":";
        var hh = d.getHours();
        var mm = d.getMinutes();
        var ss = d.getSeconds();
        return hh + sep + mm + sep + ss;
      }
      
    </script>
  </body>
</html>

 

동작캡처

 

 

 

 


간단하게 코드 동작 설명을 하겠습니다. 해당 소스들은 구글차트 API 공식 문서가 아니며 제가 사용하기 위해 만든 코드입니다.

 

구글차트를 사용하기 위해 loader.js를 연결하였고 , 아래 2줄부분은 차트를 세팅하고  준비가되면 drawChart 함수에 의해 차트를 그립니다.

<script type="text/javascript" src="https://www.gstatic.com/charts/loader.js"></script> //구글차트 사용을 위해 loader.js 추가
<script type="text/javascript">
    //Google Stuff
    google.charts.load('current', {packages: ['corechart']});
    google.charts.setOnLoadCallback(function(){ drawChart(new_option)});
</script>

 

 

다음으로 drawChart메소드에 사용된 new_option은 chartOption 생성자를 통해 클래스기반의 구글차트에서 사용할 데이터입니다.

1. @param >target : 차트를 그릴 요소의 ID값입니다.

2. @param >maxValue : 차트의 Y축 데이터의 맥스값입니다.

3. @param >color: 차트를 그릴때 사용할 색상입니다.

4. @param >name: 차트의 이름을 만들용도로 사용했습니다.

var chartOption = function(target, maxValue, color, name){
  this.name = name;
  this.target = target;
  this.data = null;
  this.chart = null;
  this.options = {
    legend: { position: 'none' },
    vAxis: {minValue:0, maxValue:maxValue},
    hAxis: {
      textStyle: {
        fontSize: 11
      }
    },
    colors: [color],
    animation: {
      duration: 500,
      easing: 'in',
      startup: true
    }
  }
  
}

var new_option = new chartOption('chart', 80, '#FF5E00', '온도');

객체 내부의 chart, options, data부분은 구글차트의 데이터를 집어넣기 위해 사용했습니다.

 

 

다음으로 drawChart 함수를 보겠습니다.

function drawChart(option) {
  var o = option;
  if(o != null){
    //초기값일때만 처리
    if(o.chart == null && o.data == null){
      o.data = new google.visualization.DataTable();
      o.data.addColumn('string', 'time');
      o.data.addColumn('number', o.name);
      o.data.addRow(['', 0]);
      o.chart = new google.visualization.LineChart(document.getElementById(o.target));
    }

    o.chart.draw(o.data, o.options);
  }
}

처음 객체의 chart, data속성을 확인하고 null이라면 처음 new로 생성된 객체이므로 초기값 세팅을 해줍니다.

이부분에서 그릴 데이터의 옵션, 초기값들을 설정하면서 제목과 그리는 차트이름을 설정합니다.

저는 LineChart를 사용했습니다.

처음만 초기값부분을 타고 이후에는 chart.draw동작만 처리합니다.

 

 

마지막으로 볼 부분은 animateRenewal함수입니다.

function animateRenewal(option){
  var o = option;
  if (o.data.getNumberOfRows() >= 10) {
    o.data.removeRow(0);
  }


  var value = 0;
  var maxValue = o.options.vAxis.maxValue;
  if(maxValue <= 1){
    value = Number((Math.random() * maxValue).toFixed(1));
  }else {
    value = Math.floor(Math.random() * maxValue);
  }
  o.data.insertRows(o.data.getNumberOfRows(), [[getNowTime(), value]]);
  drawChart(o);
}

setInterval(function(){
  animateRenewal(new_option);
}, 1000);

해당 함수에는 일정시간마다 반복하면서 데이터를 만들기 위해 만들었습니다.

실제 DB데이터에서 데이터를 가져와서 넣을분들은 이부분을 ajax 비동기처리하여 값을 가져오시고 마지막에 처리한 data.insertRows()메소드, data.removeRow()후 drawChart를 사용하시면 됩니다.

 

insertRows 메소드에 대해 간단히 설명드리면

첫번째 파라미터에 현재 구글차트에 들어간 데이터에 넣을 위치(index)값이며,

두번째 파라미터는 처리할 값입니다. 0번째값은 표기할 값 1번째값은 실제 값입니다. ex) 15:40:30  34도

 

removeRow 메소드는 입력하신 index값의 데이터를 지워줍니다.

저는 제일 과거의 데이터만 삭제하기 위해 0만 지워주도록 했습니다.

 

setInterval 메소드를 1초마다 동작시켜서 1초마다 랜덤함수로 데이터를 가져와 animateRenewal함수를 계속 동작시켜서 계속 그리도록 처리하였습니다.

반응형
반응형

mysql에서 시간 날짜등을 표현할때 원하는 형태로 표기하기 위해 date_format 함수를 많이 사용하는데,

매번 포맷형식이 자바와 다르고 대소문자에 따라 다른 결과가 나오고 헷갈려 포스팅을 진행합니다.

바로 사용법에 대해 알아보겠습니다.

 


 

- 함수 사용법

DATE_FORMAT(시간값, 원하는 포맷);

첫번째 파라미터에는 원하는 컬럼, 데이터를 넣고 두번째 파라미터값에는 원하는 출력 형태의 포맷 문자열을 넣습니다.

사용하는 포맷의 대,소문자를 유의하면서 사용해야 합니다. 표기되는 결과가 달라질 수 있습니다.

바로 사용예시를 보겠습니다.

 


now()

select now()

now() 결과

 

바로 now() 함수를 사용하면 현재 시스템의 시간을 출력해줍니다.

 

그럼 이걸 원하는 형태로 바꿔서 날짜만 표기해보겠습니다.

 

 

 

 

날짜만 표기하기

select date_format(now(), '%Y-%m-%d')

YYYY-mm-dd

 

%Y 년도 - Year(4자리 표기)
%y 년도 (뒤에 2자리 표기)
%M 월 - 월 이름(January ~ December)
%m 월 - 월 숫자(00 ~ 12)
%d 일(00 ~ 31)

 

 

 

날짜 + 시간 표기하기

select date_format(now(), '%Y.%m.%d %H:%i:%s')

YYYY.mm.dd HH:mm:ss

기본형태와 차이를 주기 위해 날짜 구분자를 .으로 바꿔봤습니다.

대소문자를 항상 주의하여 사용해야 합니다. 잘못된 표기법으로 나올 수 있습니다.

 

%H 시간 24시간(00 ~ 23)
%h 시간 12시간(00 ~ 12)
%i 분 (00 ~ 59)
%s 초 (00 ~ 59)

 

 

 

 

문자열 날짜 변경

select date_format('2020/02/06 15:16:50', '%Y.%m.%d %H:%i:%s')

'2020/02/06 15:16:50'으로 입력된 문자열이 '2020.02.06 03:16:50'으로 정상적으로 변경되어 파싱된 걸 볼 수 있습니다.

 


 

 

좀 더 자세하게 변경 양식을 보고 싶다면 아래 링크를 참고해주세요.

https://www.w3schools.com/sql/func_mysql_date_format.asp

 

MySQL DATE_FORMAT() Function

MySQL DATE_FORMAT() Function ❮ MySQL Functions Definition and Usage The DATE_FORMAT() function formats a date as specified. Syntax DATE_FORMAT(date, format) Parameter Values Parameter Description date Required. The date to be formatted format Required. The

www.w3schools.com

 

반응형
반응형

자세한 mybatis mysql 연결 설정법은 이번 글에서 포스팅하지 않겠습니다.

일반적으로 mybatis를 통해 연결하는게 아닌 터널링을 통해 접근하는법을 포스팅입니다.

 

@WebListener 어노테이션은 WAS서버에게 해당 클래스가 리스너임을 명시해줍니다.

 

ServletContextListener 클래스를 상속받으며 인터페이스를 상속받았으므로 2개의 클래스를 재정의하여

사용하시면 됩니다.

 

contextInitialized, contextDestroyed 메소드가 존재합니다.

 

contextInitialized : 해당 메소드는 was가 시작되면서 dispatcherServlet보다 먼저 시작되는 메소드입니다.

contextDestroyed : 해당 메소드는 was가 종료되면 종료되기 직전에 실행되는 메소드입니다.

 

@WebListener를 시작하기전 pom.xml에 라이브러리를 추가합니다.

 

pom.xml

<!-- WebListnener annotation-->
<dependency>
  <groupId>javax.servlet</groupId>
  <artifactId>javax.servlet-api</artifactId>
  <version>4.0.1</version>
  <scope>provided</scope>
</dependency>

<!-- jsch 터널링을 위해 필요합니다. -->
<dependency>
  <groupId>com.jcraft</groupId>
  <artifactId>jsch</artifactId>
  <version>0.1.53</version>
</dependency>

 

SSH 연결 class를 정의합니다.

SSHConnection.java

import java.util.Properties;

import com.jcraft.jsch.JSch;
import com.jcraft.jsch.Session;

public class SSHConnection {
	private final static String HOST = "SSH연결을 할 IP";
	private final static Integer PORT = 포트; //기본포트는 22
	private final static String SSH_USER = "연결 USER값"; //ex) root
	private final static String SSH_PW = "연결 비밀번호값"; //ex) 1234
	
	private Session session;
	
	public void closeSSH() {
		session.disconnect();
	}
	
	public SSHConnection() {
		try {
			Properties config = new Properties();
			config.put("StrictHostKeyChecking", "no");
			JSch jsch = new JSch();
			session = jsch.getSession(SSH_USER, HOST, PORT);
			session.setPassword(SSH_PW);
			session.setConfig(config);
			session.connect();
			session.setPortForwardingL(3316, "127.0.0.1", 3306); //127.0.0.1/3316으로 접근한 포트를 연결HOST/3306으로 포트포워딩
		}catch(Exception e) {
			e.printStackTrace();
		}
	}
	
}

 

 

위에서 정의한 클래스를 사용하는 클래스를 정의합니다.

MyContextListener.java @WebListener

import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import javax.servlet.annotation.WebListener;

@WebListener
public class MyContextListener implements ServletContextListener {
	
	private SSHConnection sshConnection;

	@Override
	public void contextInitialized(ServletContextEvent sce) {
		System.out.println("init start!");
		try {
			sshConnection = new SSHConnection();
		}catch(Exception e) {
			e.printStackTrace();
		}
	}

	@Override
	public void contextDestroyed(ServletContextEvent sce) {
		System.out.println("init destory!");
		sshConnection.closeSSH();
	}
}

 

contextInitialized 메소드는 was가 동작하면 바로 실행되면서 앞 서 만든 SSHConnection 클래스를 통해 터널링을 할 준비를 합니다.

 

mybatis정보 (mybatis-context.xml)

<bean id="dataSource" class="org.apache.commons.dbcp2.BasicDataSource" destroy-method="close" >
  <property name="driverClassName" value="com.mysql.jdbc.Driver" />
  <property name="url" value="jdbc:mysql://127.0.0.1:3316/databaseName" />
  <property name="username" value="username" />
  <property name="password" value="password" />
  <property name="validationQuery" value="SELECT 1 FROM DUAL" />
  <property name="testWhileIdle" value="true" />
</bean>

<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">     
  <property name="dataSource" ref="dataSource" />
  <property name="mapperLocations" value="classpath:mapper/**/*.xml" />
  <property name="configLocation" value="/WEB-INF/mybatis/mybatis-config.xml" />
  <property name="transactionFactory">
  	<bean class="org.apache.ibatis.transaction.managed.ManagedTransactionFactory" />
  </property>
</bean>

<bean id="sqlSession" class="org.mybatis.spring.SqlSessionTemplate">
	<constructor-arg index="0" ref="sqlSessionFactory" />
</bean>

3316으로 접근합니다.

하지만 터널링 처리로 인해 3306의 SSH 연결한 3306의 mysql에서 데이터를 가져와서 데이터를 뿌려줍니다.

 

 

결과페이지

local에서 was를 돌렸지만 SSH 터널링으로 인해 연결한 120서버(예시)의 mysql 3306포트의 데이터를 조회하여 결과를 가져왔습니다.

login.jsp

 

 

page 결과

반응형
반응형

바쁘신분들을 위해...

chrome, IE 모두 new Date를 사용하려면 replace 정규식을 활용하여

-, .등으로 구분된 날짜값을 /으로 변경처리한다.

var timedate = "2020-01-31 13:46:55";
new Date(timedate.replace(/[.-]/gi, "/")); //정상동작
//"2020/01/31 13:46:55";

air datepicker 라이브러리를 활용하여 달력을 제어할 일이 있었는데, 여기서 날짜등을 제한할때,

new Date() 메소드를 활용하여 특정 프로퍼티에 넣어주면 제한이 되었다.

 

년월일까지만 있는 경우에는 전혀 문제없이 달력이 동작하였는데,

어느날 버그 신고가 있어 확인해보니 제한 날짜를 입력해주는 부분이

(yyyy-MM-dd HH:mm:ss) 형태였다.

 

 

new Date 사용예시

IE와 크롬에서 결과값을 콘솔에 찍은 사진인데 날짜형태의 yyyy-MM-dd는 문제가 없다.

var str_date = "2020-01-31";
console.log(new Date(str_date));

 

 

 

 

날짜 "." 구분자

하지만 "."구분자는 문제가 있다.

var str_date = "2020.01.31";
console.log(new Date(str_date));

 

IE에서 표준이 아닌듯하다... 인식하지 못한다.

 

 

 

날짜 시간의 구분자 "-"

먼저 사용예제로 보여주었다 "-" 구분자도 시분초까지 있는 경우 문제가 발생한다.

var str_date = "2020-01-31 13:51:55";
console.log(new Date(str_date));

 

크롬은 언제나 잘 동작한다... 크롬짱

 

구분자 "/"

그럼 크롬과 IE에서 모두 동작하려면 어떻게 해야할까?

바로 구분자를 "/"으로 날짜부분을 처리하면 된다.

var str_date = "2020/01/31 13:51:55";
console.log(new Date(str_date));

 

"2020/01/31 13:51:55" new Date() 결과

 

 

 

정규식을 통한 크로스 브라우징

보통 날짜부분은 "-", ".", "/" 으로 구분을 많이 하는데 모두 동작하게 하려면, 정규식을 사용하면 된다.

var str_date = "2020-01-31 13:51:55"; //"2020.01.31 13:51:55" 
str_date = str_date.replace(/[.-]/gi, "/") //. 또는 -으로 되어있는 부분을 치환한다.
console.log(new Date(str_date));

 

.구분자 -구분자 모두 replace 시켜서 두 브라우저 모두 동작한다.

반응형
반응형

Object는 key, value로 구성된 객체인데, 이 Object가 배열안에 n개로 들어있고, key값이 어떻게 되어있는지 모를때 차례대로 특정 key를 구하고 key에 해당하는 value값을 구하는 예제를 보겠습니다.

 

숫자로 들어갈 값은 랜덤함수로 처리하였습니다.

var arr = [];
for(i=1; i<11; i++){
  var keyName = "count"+i
  var count = Math.floor(Math.random()*1000);
  var obj = new Object();
  obj[keyName] = count;
  arr.push(obj);
}

arr.forEach(function(value){
  console.log(value);
});

 

해당 소스가 있다고 가정하고 콘솔창을 확인해보면, 아래 그림처럼 한줄씩 객체 데이터가 표현되는걸 볼 수 있습니다.

여기서 각각 해당 Object값의 키 값을 구하고 그 키를 활용하여 value값을 출력해보겠습니다.

forEach문을 통해 출력

 

Object.keys();

Object.keys(obj); //parameter의 obj는 key를 찾고자 하는 Object

Object.keys 메소드를 활용하면 현재 Object의 key값들을 보여주는데, 메소드를 통해 구하고 각각의 value값을 출력하면 됩니다.

 

출력 예제

arr.forEach(function(value){
  var obj_key = Object.keys(value); //key를구하고
  var obj_value = value[obj_key]; //key를 활용하여 value값을 구한다.
  console.log(obj_key + " : " + obj_value); //출력
});

출력결과

아까와는 다르게 Object형으로 찍히는게 아닌 String형태로 찍힌 결과를 볼 수 있습니다.

반응형
반응형

mysql 사용 도중 code의 값이 꼬여서 다른 테이블에 존재하는 code값을 읽어와

pk값이 같은 데이터끼리 update를 해줄 일이 생겼다.

 

일반적인 조건문에 따른 update처리는 해봤지만 join문이 들어간 update를 찾아보니

set전에 일반적인 select의 join문을 사용하면 되는 것을 확인하였다.

 

Join문을 활용한 Update

update 
	table1 t1
	[INNER JOIN | LEFT OUTER JOIN] table2 t2
	on t1.joinColumn = t2.joinColumn
set
	t1.changeColumn = t2.changeColumn
where
	t1.의 조건문
	and t2.의 조건문

 

위 와 같은 문법을 활용하여 update를 처리하면 된다.

 

 

사용예시)

r_board와 r_board_detail 테이블이 있다고 가정하겠다.

r_board

d_no

d_code

d_title

d_name

1

2

테스트1

홍길동

2

2

테스트2

홍길자

3

2

테스트3

홍길순

4

2

테스트4

홍길준

 

r_board_detail

d_no

d_code

d_read

d_update_dt

1

1

50

2020-01-22 09:10:23

2

1

65

2020-01-22 09:15:42

3

2

43

2020-01-22 12:09:55

4

2

55

2020-01-22 14:10:01

 

 

r_board code값을 일치시키는 update문을 구성하겠다.

update 
	r_board b1
    	INNER JOIN r_board_detail b2
	on b1.d_no = b2.d_no
set
	b1.d_code = b2.d_code

 

처리 후에는 r_board의 code값이 r_board_detail 테이블과 동일하게 바뀐 모습을 볼 수 있다.

반응형
반응형
<form>
    <input type="text" name="user_name">
    <button id="save">저장</button>
</form>

과 같은 코드가 있을때 jquery를 활용하여

 

아래처럼 클릭이벤트에 따른 ajax동작을 정의하고, 비동기처리를 하려고 한다.

$("#save").click(function(){
 ...ajax 동작
})

ajax에서는 user_name값을 파라미터로 가지고 컨트롤러로 넘겨서 DB에 저장하는 로직을 구성하였는데,

컨트롤러에 요청이 2번씩 가는 현상을 한번씩 볼 수 있다.

 

form태그 내부의 button이 default동작인 submit으로 동작하면서 form동작 + ajax동작이 동시에 일어났기 때문이다.

 

가장 간단한 해결책은 button을 submit이 아닌 button이라고 지정을 해주는 것이다.

 


type="button" 지정하기

<button type="button" id="save">저장</button>

 


 

또는 form태그 내부의 모든 버튼이 submit 동작을 하지 않도록 form태그에 속성을 추가하면 된다.

form태그 자동 submit 끄기 (autocomplete="off")

<form autocomplete="off">
   ...
</form>
반응형