2018년 12월 19일 수요일

[java] 이클립스에 생성한 프로젝트에 Maven 설정 법

[java] 이클립스에 생성한 프로젝트에 Maven 설정 법

[JAVA] 이클립스(eclipse) JAVA 기존 프로젝트에 MAVEN 설정하기

maven을 기존 eclipse 프로젝트 설정하기
참고자료: http://theeye.pe.kr/archives/1583

프로젝트에 마우스 우측 클릭 >> configure >> convert to Maven Project

Create new POM 이름, 설명 입력

  • Name : < maven_pom_name >
  • Description : < maven_pom_project_decription >

이후 깔끔하게 pom.xml 에서 원하는 jar 로딩해서 편히 쓰자!!

참고 자바용 AWS maven은 다음과 같다.

<dependencyManagement>
<dependencies>
 <dependency>
  <groupId>com.amazonaws</groupId>
  <artifactId>aws-java-sdk-bom</artifactId>
  <version>1.11.327</version>
  <type>pom</type>
  <scope>import</scope>
 </dependency>
</dependencies>
</dependencyManagement>

<dependencies>
 <dependency>
  <groupId>com.amazonaws</groupId>
  <artifactId>aws-java-sdk-s3</artifactId>
 </dependency>
 <dependency>
  <groupId>com.amazonaws</groupId>
  <artifactId>aws-java-sdk-dynamodb</artifactId>
 </dependency>
</dependencies>

Written with StackEdit.

2018년 12월 2일 일요일

[Node.js Project] es6 Class Generator - 클래스 생성기 만들

[Node.js Project] es6 Class Generator - 클래스 생성기 만들

개요

es6 형 클래스 생성을 위한 Node.js 모듈 생성 데이터베이스 테이블의 열 이름으로 나열된 열 이름으로 DTO 클래스 생성하는 경우 사용!

물론 이 클래스를 이용하지 않아도 될 경우가 좀더 JS 형식에 맞는 형태 일 수 있으나 필요하여 다음의 조건을 만족하는 클래스 생성기를 만들어 본다.

물론 JS 특성상 구지 클래스를 만들지 않아도 객체 자체를 사용해도 되는 경우가 대부분이다. 하지만! DB 를 다루는 서버 입장에서는 DTO, DAO, SERVICE, CONTROLLER 등으로 계층별로 다룰때 DTO 객체를 정의해서 정형 데이터베이스로 부터 데이터를 처리하는 경우가 많이 있었다.(물론 이 구조가 올바른지는…)
이때 형식이 결정되어 있는 DTO 객체 사용하는 경우에 한하여
이때 쓰이는 class 를 자동 생성

요구사항

  • Node.js 기반으로 js 스크립트에서 실행가능하며 require 또는 import 이용하여 로딩 할 수 있도록 함
  • 함수 호출 하여 사용하도록 한다. 함수 호출 방식은 다음과 같다.
  • 입력: 클래스 이름, 데이터베이스 테이블의 열이름 문자열
    ex) 클래스명: Person,
    필드명: ID, NAME, GENDER, REG_DATE
  • 출력: 이 조건들을 이용하여 만든 클래스 파일
    class Person extends Model {
     constructor(object){
      this._id = obejct[Person.FIELD_ID];
      this._name = obejct[Person.FIELD_NAME];
      this._gender = obejct[Person.FIELD_GENDER];
      this._reg_date = obejct[Person.FIELD_REG_DATE];
     }
     
     /* STATIC FIELD NAME*/
     static get FIELD_ID = 'ID';
     static get FIELD_NAME = 'NAME';
     static get FIELD_GENDER = 'GENDER';
     static get FIELD_REG_DATE = 'REG_DATE';
    
     /*getter & setter*/
     get id() {
      return id;
     }
     set id(id) {
      this._id = _id;
     }
     get name() {
      return this._name;
     }
     set name(name) {
      this._name=_name;
     }
     get gender() {
      return this._sex;
     }
     set gender(sex) {
      this._sex = sex;
     }
     get red_date(reg_date) {
      return this._reg_date;
     }
     set reg_date(reg_date) {
      this._reg_date = reg_date;
     }
     
     
    }
    

구현

  • 위 요구사항을 만족하기 위해 다음과 같이 구현한다.
  • 폴더구조
  • 템플릿
  • genDTO index.js

폴더 구조

  • 폴더 구조는 다음과 같다.
genDTO : 최상위 폴더
├── index.js : 모듈 index.js 
└── template : 템플릿 양식 저장 
    └── es6ClassType1-forRDB.txt : Relational Database DTO 생성을 위한 

템플릿

  • 템플릿은 %s 와 같은 형식 지정자로 구성하여 다음을 구성한다.

es6ClassType1-forRDB.txt

/* eslint-disable no-underscore-dangle,camelcase */  
const Model = require('./Model');  
  
const async = require('async');  
  
class %s extends Model {  
    constructor(object) {  
        super(object);  
        if (object) {  
            %s  
        }  
    }// constructor()  
  
    /* STATIC FIELD NAMES */  
    %s  
  
    /* getter & setter */  
    %s  
  
}// end of class  
module.exports = %s;  
|;|this._%s = object[%s.FIELD_%s]; 
|;|static get FIELD_%s() { return '%s'; }  
|;|get %s() { return this._%s; }  
    set %s(value){ this._%s = value; }
  • 마지막 부분은 각각 설명하면 다음과 같다.

    • this.%s = object[%s.FIELD%s] : 생성자 내부 필드 지정 부분
    • static get FIELD_%s() { return ‘%s’; } : static field 필드 템플릿
    • get %s() { return this.%s; } : getter 템플릿
      set %s(value){ this.
      %s = value; } : setter 템플릿
  • 순서에 유의하여 변환 변수 대입하여 js 용 sprintf 에 대입하여 처리하도록 하자! 순서대로 잘 넣어야 한다.

  • 여기서 Model extends 부분의 클래스는 다음과 같다.

Model.js

const logger = require(`${__dirname}/../../lib/logger`)();  
  
/**  
 * SMC PRO 클래스  
  */  
class Model {  
  /**  
 * SMCPRO 생성자  
  * @param object  
 */  constructor(object) {  
  
 }  
  /**  
 * 필드 이름  
  * @param fieldName  
 * @returns {*}  
 */  
 get(fieldName) {  
  return this[`_${fieldName.toLowerCase()}`];  
 }  
  /**  
 * * @param fieldName  
 * @param value  
 */  
 set(fieldName, value) {  
  this[`_${fieldName.toLowerCase()}`] = value;  
 }  
  static fields(Class) {  
  const arrFields = [];  
  let fields = null;  
  if (Class) {  
  fields = Object.getOwnPropertyNames(Class);  
  for (const idx in fields) {  
  if (fields[idx].indexOf('FIELD') !== -1) {  
  arrFields.push(Class[fields[idx]]);  
 } } } else {  
  fields = Object.getOwnPropertyNames(this);  
  for (const idx in fields) {  
  if (fields[idx].indexOf('FIELD') !== -1) {  
  arrFields.push(this[fields[idx]]);  
 } } }  return arrFields;  
 }  
  values(Class) {  
  const arrValues = [];  
  
  const fields = Object.getOwnPropertyNames(Class);  
  for (const idx in fields) {  
  if (fields[idx].indexOf('FIELD') !== -1) {  
  arrValues.push(this.get(Class[fields[idx]]));  
 } }  
  return arrValues;  
 }  
  checkFields(fields) {  
  let isCheckResult = true;  
  for (const idx in fields) {  
  if (this.get(fields[idx]) === null || this.get(fields[idx]) === undefined) {  
  isCheckResult = false;  
  break;  
 } }  return isCheckResult;  
 }}// end of class  
  
  
module.exports = Model;  
  • Model.js의 class Model 는 다음 메소드를 미리 구현해 두었다.
    • get(fieldName) : 하위 클래스에 FIELD 로 정의된 정적 변수를 이용하여 실제 객체 내용에 접근하여 값 리턴
    • set(fieldName, value) : 하위 클래스에 FIELD 로 정의된 정적 변수를 이용하여 실제 객체 내용에 접근하여 값 대입
    • 그 밖에 기본 클래스 다룰때 필요한 메소드 구현 해둠

genDTO index.js

  • 이 모듈에서 사용하는 의존성 패키지는 다음과 같다.
const sprintf = require('sprintf-js').sprintf;  
const fs = require('fs');  
  
const dtoClassFieldsName = [];  
  
const init = function () {  
  const templateData = fs.readFileSync(`${__dirname}/template/es6ClassType1-forRDB.txt`, 'utf-8').split('|;|');  
  const templateClassTotal = templateData[0];  
  const templateFieldDefiniation = templateData[1];  
  const templateStaticFieldDefiniation = templateData[2];  
  const templateGetterSetterDefiniation = templateData[3];  
  
  // console.log('template: ', templateData);  
  
  function GenDTO() {  
  // 객체 생성  
  }  
  
  const instance = new GenDTO();  
  
  instance.genClass = function (className, fieldNames, dtoDirPath) {  
  console.log('인자 검사 수행');  
  if (!className || !fieldNames) {  
    throw new Error('Parameters Error');  
  } else if (!Array.isArray(fieldNames) && typeof fieldNames !== 'string') {  
   throw new Error('Parameters Error - fieldNames type invalid');  
 }  console.log('인자 전처리 작업');  
  if (typeof fieldNames === 'string') {  
     fieldNames = fieldNames.split(',');  
     fieldNames.forEach(function (elem, idx) {  
     fieldNames[idx] = elem.trim();  
 }); }  if (!dtoDirPath) {  
     dtoDirPath = './';  
 }  // 처리작업 수행  
  console.log('클래스 생성 ... 시작');  
  const result = instance.doGenClass(className, fieldNames);  
  fs.writeFileSync(`${dtoDirPath}/${className}.js`, result);  
  console.log('클래스 생성 ... 완료');  
 };  
  instance.doGenClass = function (className, fieldNames) {  
  const classNameResult = className;  
  
  const fieldDefinitionResult = instance.doGenFieldDefinition(className, fieldNames);  
  const staticFieldDefinitionResult = instance.doGenStaticFieldDefinition(className, fieldNames);  
  const getterSetterDefinitionResult = instance.doGenGetterSetterDefinition(className, fieldNames);  
  
  return sprintf(templateClassTotal, classNameResult, fieldDefinitionResult, staticFieldDefinitionResult, getterSetterDefinitionResult, classNameResult);  
 };  
  instance.doGenFieldDefinition = function (className, fieldNames) {  
  // console.log('doGenFieldDefinition');  
 // console.log('className>>', className); // console.log('fieldNames>>', fieldNames);  let result = '';  
  let tabHead = '';  
  fieldNames.forEach((elem, idx) => {  
  result += sprintf(`${tabHead}${templateFieldDefiniation}`, elem.toLowerCase(), className, elem);  
  if (idx === 0) {  
  tabHead = '            ';  
 } });  return result;  
 };  
  instance.doGenStaticFieldDefinition = function (className, fieldNames) {  
  // console.log('doGenStaticFieldDefinition');  
 // console.log('className>>', className); // console.log('fieldNames>>', fieldNames);  let result = '';  
  let tabHead = '';  
  fieldNames.forEach((elem, idx) => {  
  result += sprintf(`${tabHead}${templateStaticFieldDefiniation}`, elem, elem);  
  if (idx === 0) {  
  tabHead = '    ';  
 } });  return result;  
 };  
  instance.doGenGetterSetterDefinition = function (className, fieldNames) {  
  // console.log('doGenStaticFieldDefinition');  
 // console.log('className>>', className); // console.log('fieldNames>>', fieldNames);  let result = '';  
  let tabHead = '';  
  fieldNames.forEach((elem, idx) => {  
  result += sprintf(`${tabHead}${templateGetterSetterDefiniation}`, elem.toLowerCase(), elem.toLowerCase(), elem.toLowerCase(), elem.toLowerCase());  
  if (idx === 0) {  
  tabHead = '    ';  
 } });  return result;  
 };  
  return instance;  
};  
  
module.exports = init();

배포

  • git: TBD
    • 이 부분 Model.js 의존 관계 해결할 경우 수행 하도록 하겠습니다.

결론

  • 이러한 방식을 통해 차후 프로젝트 생성 내가 주로 하는 패턴 구성으로 각종 설정만 달리하여 구성 요소 자동 생성하는 프로젝트 생성기로 확장해도 될 것 같댜.(필요하다 시급히!! 매번 직접 설치 후 설정 변경 너무 힘들고 귀찮아…)
    • 이쯤에서 다른 프로젝트 생성기에서 나오는 express-generator 속을 보고 싶다.
  • Model 부분은 상속받는 코드도 마찬가지로 생성해주는 기능이 있어야 할 것 같다.
  • es6에서 인정하는 객체의 정의가 불충분 할 것 같은데… 이부분 알아보자
    • 객체의 조건: 생성자, 소멸자, 복사 생성자, 대입연산자, getter&setter, 비교연산자 오버라이딩 등(C++ 기준), 더 필요한 것은 없을까?
  • 성능에 대해서는 고려하지 않고 내 편한대로 우선 만든 것.
  • 차후 안정화와 사용에 문제가 전혀 되지 않으면 나중에는 npm으로 배포 도전하겠다.

2018년 11월 29일 목요일

[Node.js] ExcelJS 엑셀 다루는 믿을만한 모듈 - 서버에서 다운로드 기능 구현(파일 쓰기 저장 없이) - TBD

[Node.js] ExcelJS 엑셀 다루는 믿을만한 모듈 - 서버에서 다운로드 기능 구현(파일 쓰기 저장 없이) - TBD

개요

  • 엑셀 다룰때 여러가지 모듈을 사용했으나 가장 믿을만한! 가장 확실한 모듈을 찾음!
  • 사용법은 링크 아래 문서(사용법 문서정리 정말 잘 되어 있음) 가보면 정말 잘 나와 있다.
  • 기본 사용법을 익히기
  • 추가 응용 기능 NodeJS Express 다운로드 기능 구현

npm & git

$ npm install exceljs --save

기본 사용법

  • 구동 흐름은 다음으로 생각됨

    Excel.WorkBook() -> workBook.addSheet -> sheet.columns 추가 ->
    sheet.addRow 추가 -> workBook.xlsx.write or 다른 작업 수행

파일 읽기

  • 엑셀 파일 읽기 기능

  • 예시 데이터: test2.xlsx

    • sheet01
      ex-sheet02
    • sheet02
      ex-sheet01
  • 수행 코드

const Excel = require('exceljs');

const workbook = new Excel.Workbook();  
  
/// 파일 읽기 수행  
workbook.xlsx.readFile('test2.xlsx').then(function(){
 // 읽어 작업 하는 객체는 workbook 으로 진행하면 됨
});

파일 생성

  • 엑셀 파일 생성 기능
const Excel = require('exceljs');

  • 파일 매칭시 JSON으로 연결되는 부분이 중요했다.
  • 다른 여타 excel

파일 쓰기

  • json 배열을 엑셀 파일 정적 파일 출력

  • 수행 코드

const Excel = require('exceljs');


  • 주의할 내용은 sheet.columns 배열 처리 부분으로 배열 자체를 한번 대입 시켜줄때 내부 헤더 객체로 변환됨.
  • sheet.columns = [] 후에 sheet.columns.push({…}) 형태로 추가할 경우 제대로 헤더가 작동하지 않는 경우가 있음
    • 이때 발생하는 에러

    (node:9828) UnhandledPromiseRejectionWarning: Unhandled promise rejection (rejection id: 2): TypeError: column.equivalentTo is not a function
    (node:9828) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.

    • 요런 에러가 발생함… 알아내는데 한참 걸렸다는거…
      • 혹시나 해서 디버깅도구 이용하여 미리 헤더 배열을 완성시킨 상태에서 대입 시킨 것과 미리 배열 할당한 상태에서 push 를 이용해 동적으로 추가하는 경우 비교한 결과
      • 전자의 경우가 제대로 내부 객체(추가 필드가 정의됨)로 완성된다는 것. //TODO

응용 기능 구현

NodeJS Express 서버 구현하는 사람이라면 아무래도 ExcelJS 패키지 기능을 이용하여 요청/응답에 맞는 서비스를 제공하고 싶을 것이다. 특히 업무 중에 엑셀 다운로드 API 를 구현해야할 필요가 있었다.

서버에서 다운로드 기능 구현(파일 쓰기/저장 없이) 구현해 보자!

자료 수집

  • Express에 의한 엑셀 다운로드 기능 구현
  • 웹상에서 node express 다운로드 구현 가능성에 대해 단서 를 찾음
    // Create the workbook and populate it with data...
    res.attachment("test.xlsx")
    workbook.xlsx.write(res)
    .then(function() {
    
    res.end()
    
    });
    
    • 여기서 res.attachment 는 어떤 내용인가?

      res.attachment([filename]), res.download(path, [filename], [callback]) : 클라이언트에게 파일을 표시하지 말고 다운로드 받으라고 전송함. filename을 주면 파일 이름이 명시되며, res.attachment는 헤더만 설정하므로 다운로드를 위한 node 코드가 따로 필요핟.
      출처: http://luckyyowu.tistory.com/346

    • 핵심은! res 객체에 workbook 객체의 write 메소드를 쓰는 부분
    • 파일 출력 대상을 res로 하는 패턴!!! stream 처리!
    • 그리고 마무리는 res.end()

구현

  • 위 단서 코드를 이용하여 실제 다운로드 API 에 사용되도록 구현해 본다.
  • rest api 구현하는 Node.js + Express 기본 패턴에서

  • TBD

결론

  • TBD…