Category Archives: Source

source, example, sample
로직이 포함된 내용을 소스기반으로 설명합니다.

[Source | Java] InputStream to String

Java에서 InputStream객체를 String으로 변환하는 코드를 정리한다.


작성일 : 2021-04-23


// Define
InputStream is = {SomeData};

1> BufferedReader 객체사용

InputStreamReader isr = new InputStreamReader(is);
BufferedReader br = new BufferedReader(isr);
StringBuffer sb = new StringBuffer();
String line;
while((line = br.readLine()) != null) {
	sb.append(line);
	sb.append('\r');
}
br.close();
// Result
String str = sb.toString();

2> StringBuffer 객체사용

StringBuffer sb = new StringBuffer();
byte[] b = new byte[4096];
int length;
while((length = is.read(b)) != -1) {
	sb.append(new String(b, 0, length));
}
// Result
String str = sb.toString();

3>  ByteArrayOutputStream 객체사용

ByteArrayOutputStream baos = new ByteArrayOutputStream();
byte[] b = new byte[4096];
int length;
while((length = is.read(b)) != -1) {
	baos.write(b, 0, length);
}
baos.flush();
// Result
String str = new String(baos.toByteArray());

[Source | Nodejs] 이메일 발송

Nodejs에서 이메일 발송코드를 정리한다.


작성일 : 2021-04-22


1> nodemailer 설치

npm install nodemailer

2> 코드작성

let transporter = nodemailer.createTransport({
   host: "OPENDOCS_SMTP_HOST",   // SMTP Host
   port: 465,
   secure: true,                 // true for 465, false for other ports
   auth: {
      user: "OPENDOCS_USERID",   // User ID
      pass: "OPENDOCS_USERPW"    // User Password
   }
});

let info = await transporter.sendMail({
   from: '"OPENDOCS" <corp@opendocs.co.kr>',     // Sender Address
   to: "opendocs@naver.com, opendocs@kakao.com", // Receiver List
   subject: "Hello ✔", // Subject line
   text: "Hello world?", // plain text body
   html: "<b>Hello world?</b>" // html body
});

[Source | C++] 키워드 목록

C++키워드의 경우 변수명으로 사용이 불가능하다. 키워드 목록을 정리해보자.


작성일 : 2021-04-20


asmautobool
breakcasecatch
 charclassconst
const_cast continue default
 deletedodouble
dynamic_castelseenum
 explicitexportextern
falsefloatfor
 friendgotoif
inlinentlong
 mutablenamespacenew
operatorprivateprotected
 publicregisterreinterpret_cast
returnshortsigned
sizeofstaticstatic_cast
structswitchtemplate
thisthrowtrue
trytypedeftypeid
typenameunionunsigned
usingvirtualvoid
volatilewchar_twhile

[Source | MyBatis] DB 부하를 줄이기 위한 쿼리캐싱 기능

거의 바뀌지 않거나 고정된 값을 디비에서 자주 쿼리해야할 경우가 있다. 이때 마이바티스에서 제공하는 쿼리캐싱 기능 사용법을 알아보자.


작성일 : 2021-04-06

https://mybatis.org/mybatis-3/ko/sqlmap-xml.html#cache
공식문서에 잘 설명이 되어있다.


1> 캐싱적용시 고려해야하는 사항들

* flush / set 하는 시점을 명확히 정의 해야한다.
--> 단순히 부하를 줄인다고 여기저기 사용했다가 갑자기 이상한 데이터로 에러가 발생할 수 있고 추적 또한 어렵다.
* 마이바티스의 경우 쿼리 단위로 캐싱을 해줘 문제가 되지 않지만 Redis나 Memcached, ehcache등을 사용한다면 값저장시 키값을 잘 정의해야한다.
--> 보통 키값에 prefix(객체명+'_')를 주어 구분한다.
* 데이터가 자주 변경되는 경우 사용여부를 다시한번 고려해보자.
--> 변경시 flush하고 확인시 다시 set해줘야 하기 때문에 불필요한 절차만 추가할 뿐이다.

2> 적용예제

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.opendocs.www.repository.categorys.CategorysDaoMapper">
    
   <!-- Configuration Caching -->
   <cache eviction="FIFO" flushInterval="60000" size="512" readOnly="true"/>

   <!-- Insert Query Flush Cache --> 
   <insert id="insert" parameterType="categorys">
      INSERT INTO opendocs_www.categorys (uid, pid, name, status, created_at) 
         VALUES(#{uid}, #{pid}, #{name}, #{status}, now())
   </insert>

   <!-- Select Query Use Cache --> 
   <select id="select" parameterType="categorys" resultType="categorys">
      SELECT uid, pid, name, status, created_at, updated_at 
      FROM opendocs_www.categorys T1 
   </select>
	
   <!-- Update Query Flush Cache --> 
   <update id="update" parameterType="categorys">
      UPDATE opendocs_www.categorys
      <set>
         <if test="1 == 1">updated_at = now(),</if>
         <if test="pid != null">pid = #{pid},</if>
         <if test="name != null">name = #{name},</if>
         <if test="status != null">status = #{status},</if>
      </set> 
      WHERE uid = #{uid}
   </update>
	
   <!-- Delete Query Flush Cache --> 
   <delete id="delete" parameterType="categorys">
      DELETE FROM opendocs_www.categorys WHERE uid = #{uid}
   </delete>
	
</mapper>
위의 예제는 select시 캐싱하고 insert, update, delete시 캐싱된 데이터를 지운다.
<cache/>를 선언하게 되면 다음 속성을 선언한 것과 같으며 특정쿼리가 캐싱되지 않기를 원한다면 useCache="false"를 선언해주면 된다.
<select ... flushCache="false" useCache="true"/>
<insert ... flushCache="true"/>
<update ... flushCache="true"/>
<delete ... flushCache="true"/>

2-1> eviction : 캐싱전략

* LRU - 가장 오랜시간 사용하지 않는 객체를 제거
* FIFO - 캐시에 들어온 순서대로 객체를 제거
* SOFT - 가비지 컬렉터의 상태와 강하지 않은 참조(Soft References )의 규칙에 기초하여 객체를 제거
* WEAK - 가비지 컬렉터의 상태와 약한 참조(Weak References)의 규칙에 기초하여 점진적으로 객체 제거

2-2> flushInterval : 플러시 주기 (밀리세컨드 단위 1초 = 1000)

* 밀리세컨드 단위로 1초이면 1000
* 기본값없음 (미선언시 쿼리수행시만 동작)

2-3> size : 캐싱 사이즈

* 메모리 상황을 고려한 적정한 사이즈
* 기본값 1024

2-4> readOnly : 읽기전용 여부

* 모든 호출자에게 캐시된 객체의 같은 인스턴스(변경불가)를 리턴
* 사용시 성능 향상
* 기본값 false

3> 다른 캐싱방법

상황에 맞추어 아래 캐싱방법도 고려하여 보자.

  • Memcached
  • Redis
  • ehcache

[Source | MySQL or MariaDB] 데이터베이스 생성 및 접속 설정

데이터 베이스를 MySQL / MariaDB로 선택하여 프로젝트를 진행할 경우 디비생성 및 접속권한을 부여하는 방법을 설명한다.


작성일 : 2021-02-23

1> 데이터베이스 생성

create database {디비명} collate '{문자셋}';
# Ex)
create database ProjectDB collate 'utf8_general_ci';

2> 사용자 추가

create user '{사용자ID}'@'{접속IP}' identified by '{비밀번호}';
# Ex)
create user 'opendocs'@'localhost' identified by 'passOpd';

3> 권한부여 및 적용

# 권한부여
grant all privileges on {디비명}.* to '{사용자ID}'@'{접속IP}';
Ex)
grant all privileges on projectDB.* to 'opendocs'@'localhost';
# 권한적용
flush privileges;