1. 프로젝트 생성하기(vue-cli)

 1) vue-cli 설치하기.

 - Global로 설치하기

npm install  -g vue-cli


 2) project 생성하기.

mkdir {PROJECT_NAME}


cd {PROJECT_NAME}


vue init webpack-simple


 - vue 명령어

 

 설명

 비고

 init

 generate a new project from a template

 vue init {project template type} {PROJECT_NAME}

 list

 list available official templates

 vue list <-- 아래 내용 참고

 build

 prototype a new project

 

 help

 display help for [cmd] 


 - vue template

 

 설명

비고 

 browserify

 A full-featured Browserify + vueify setup with hot-reload, linting & unit testing.

 

 browserify-simple

 A simple Browserify + vueify setup for quick prototyping.

 

 pwa

 PWA template for vue-cli based on the webpack template

 

 simple

 The simplest possible Vue setup in a single HTML file

 하나의 index.html 파일만 생성해줌.

 webpack

 A full-featured Webpack + vue-loader setup with hot reload, linting, testing & css extraction.

 

 webpack-simple

 A simple Webpack + vue-loader setup for quick prototyping.

 


2. 프로젝트 분석하기

 1) 기본 구조 설명


 2) 상세설명

  (1) main.js

- 프로젝트의 기본이 되는 파일입니다. 프로젝트의 Entry Point 이기도 하다.

  (2) App.vue

- Root 컴포넌트

- Vue를 로드하고 해당 파일을 로드하면서 어플리케이션을 초기화한다.

- 참고로 *.vue 파일은 "HTML 템플릿", 단일 vue 컴포넌트를 정의하는 javascript, 특정 스타일 css 의 조합이다.


  (3) assets

- 외부 자원들에 대한 폴더이다. image, css 등이 들어간다.


 3) 그외 설명

  (1) components

- vue 파일을 저장하는 곳.

- 입맛에 따라 알아서 변경해서 쓰면 된다.


  (2) route

-backend에서 제공하는 라우팅 기능을 제공함.

- index.js 관련해서는 추후 설명할 예정


3. 프로젝트 시작하기

 1) 위에서 생성한 프로젝트 내에서

 2) 우선 npm으로 라이브러리들을 설치해야한다.

npm install


 3) 개발버전으로 프로젝트를 시작하자.

  - compile, ESLint 를 진행하고, 로컬 서버를 동작시켜준다.

  - ESLint, hot-reload 동작(변경된 상태만 변경)

npm run dev


 4) 실서비스 시

  - webpack 설정등에 따라 달라지겠지만, /dist 폴더로 hash 값이 포함된 파일명으로 파일들이 생성됨.

npm run build



참고링크

 - https://medium.com/witinweb/vue-cli-%EB%A1%9C-vue-js-%EC%8B%9C%EC%9E%91%ED%95%98%EA%B8%B0-browserify-webpack-22582202cd52

 - https://blog.storyg.co/vue-js-posts/todos-tutorial

1. Vue란?

 - front-end framework

 - 배우기 쉽다.

 - view에 최적화 되어 있다.

 - MVVM(Model-View-ViewModel) 패턴을 기반으로 디자인


2. 간단하게 시작해보자.

 - index.html 파일을 만들고, 아래 링크를 포함한 페이지를 만들어보자.

https://unpkg.com/vue


or

https://cdn.jsdelivr.net/npm/vue


 1) index.html

<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="UTF-8">
<title>Vue.js Sample</title>
</head>
<body>

<div id="root">
<p>{{ msg }}</p>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue"></script>
<script>
new Vue({
el: '#root',
data: {
msg: 'Hello Vue.js!'
}
})
</script>
</body>
</html>

  - 결과


3. Declarative Rendering

  - 디렉티브는 vue에서 제공하는 속성, v- 로 접두어가 붙는다.


 1) v-if

  - 조건문 사용할 때 사용.

<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="UTF-8">
<title>Vue.js Sample</title>
</head>
<body>

<div id="root">
<div v-if="type === 'LOGIN'">로그인 되었습니다.</div>
<div v-else-if="type === 'LOGOUT'">로그아웃 되었습니다.</div>
<div v-else> 로그인이 필요합니다.</div>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue"></script>
<script>
var app = new Vue({
el: '#root',
data: {
type: "LOGOUT"
}
})
</script>
</body>
</html>


  - template 에도 사용가능

<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="UTF-8">
<title>Vue.js Sample</title>
</head>
<body>

<div id="root">
<template v-if="type === 'LOGIN'">
<div>
로그인 되었습니다.
</div>
</template>
<template v-else-if="type === 'LOGOUT'">
<div>
로그아웃 되었습니다.
</div>
</template>
<template v-else>
<div>
로그인이 필요합니다.
</div>
</template>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue"></script>
<script>
var app = new Vue({
el: '#root',
data: {
type: "LOGIN"
}
})
</script>
</body>
</html>




 2) v-show

  - 보여질지, 숨길지에 대해서 설정할 수 있는 값이다.

  - 일단 뷰 렌더링이 진행되고, css로 숨길지 나타낼지를 정한다.

  - 샘플코드

<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="UTF-8">
<title>Vue.js Sample</title>
</head>
<body>

<div id="root">
<div v-show="visible">보이나?</div>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue"></script>
<script>
var app = new Vue({
el: '#root',
data: {
visible: true
}
})
</script>
</body>
</html>

  - v-if는 토글 비용이 높고 v-show는 초기 렌더링 비용이 더 높다. 자주 바꾸기를 원한다면 v-show를, 런타임 시 조건이 바뀌지 않으면 v-if를 권장한다..

 - chrome 개발자 console 창에 'app.visible = false;'를 입력해보면 해당 div가 사라지는 걸 확인 할 수 있다.


 3) v-for

  - for loop

  - 목록 구현할때 많이 쓰이는 디렉티브

  - 샘플 코드

<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="UTF-8">
<title>Vue.js Sample</title>
</head>
<body>

<div id="root">
<ul>
<li v-for="fruit in fruits" :key="fruit">{{ fruit }}</li>
</ul>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue"></script>
<script>
new Vue({
el: '#root',
data: {
fruits: ['apple', 'banana', 'orange']
}
})
</script>
</body>
</html>

  - 결과



 4) 기타

  - v-on, v-bind, v-model 등이 있다.



* 참고

 - https://vuejs.org/v2/guide/index.html , https://kr.vuejs.org/v2/guide/index.html



1. json-schema-validator란?

 - xml의 DTD 와 유사함.

 - Json 스키마(http://json-schema.org/) 포멧이 유효한지 확인해줌.

 - 웹사이트에서 해당 내용을 테스트해볼 수 있다.(링크)


2. library

 - 기존에 jackson을 많이 사용하므로, fasterxml에서 제공하는 jsonSchema 라이브러리를 사용하려고함.

 1) pom.xml

<dependency>
<groupId>com.github.java-json-tools</groupId>
<artifactId>json-schema-validator</artifactId>
<version>2.2.8</version>
</dependency>


3. 간단한 Json 설명

{
"$schema": "http://json-schema.org/draft-04/schema#",
"title": "/etc/fstab", /* JSON에 대한 제목 */
"description": "JSON representation of /etc/fstab", /* JSON에 대한 설명 */
"type": "object", /* 해당 Json의 최상위 객체 타입, http://json-schema.org/latest/json-schema-validation.html#rfc.section.6.1.1 참고 */
"properties": {
"swap": {
"$ref": "#/definitions/mntent" /* 하단 definitions내용을 참조 합니다. */
}
},
"patternProperties": {
"^/([^/]+(/[^/]+)*)?$": {
"$ref": "#/definitions/mntent"
}
},
"required": /* 필수 값에 대한 속성 정의 */ [
"/",
"swap"
],
"additionalProperties": false,
"definitions": {
"mntent": {
"title": "mntent",
"description": "An fstab entry",
"type": "object", /* 객체 타입 */
"properties": {
"device": {
"type": "string"
},
"fstype": {
"type": "string"
},
"options": {
"type": "array",
"minItems": 1, /* 아이템의 최소 단위 */
"items": {
"type": "string"
}
},
"dump": {
"type": "integer",
"minimum": 0,
"maximum": 0 /* 아이템의 최대 단위 */
},
"fsck": {
"type": "integer",
"minimum": 0
}
},
"required": [
"device",
"fstype"
],
"additionalItems": false
}
}
}



4. 샘플 소스

 1) Basic ( https://github.com/java-json-tools/json-schema-validator/blob/master/src/main/java/com/github/fge/jsonschema/examples/Example1.java)

 - 소스

final String urlPrefix = "https://raw.githubusercontent.com/java-json-tools/json-schema-validator/"
+ "master/src/main/resources/com/github/fge/jsonschema/examples/";

final JsonNode fstabSchema = JsonLoader.fromURL(new URL(urlPrefix + "fstab.json"));
final JsonNode good = JsonLoader.fromURL(new URL(urlPrefix + "fstab-good.json"));
final JsonNode bad = JsonLoader.fromURL(new URL(urlPrefix + "fstab-bad.json"));
final JsonNode bad2 = JsonLoader.fromURL(new URL(urlPrefix + "fstab-bad2.json"));

final JsonSchemaFactory factory = JsonSchemaFactory.byDefault();

final JsonSchema schema = factory.getJsonSchema(fstabSchema);

ProcessingReport report;

report = schema.validate(good); //SUCCESS
print(report);

report = schema.validate(bad); //FAILURE
print(report);

report = schema.validate(bad2); //FAILURE
print(report);

 - 결과


 

 2) message custom(https://github.com/java-json-tools/json-schema-validator/blob/master/src/main/java/com/github/fge/jsonschema/examples/Example8.java)

 - 소스(valid)

final JsonNode customSchema = JsonLoader.fromURL(new URL(URL_PREFIX + "custom-fmt.json"));
final JsonNode good = JsonLoader.fromURL(new URL(URL_PREFIX + "custom-fmt-good.json"));
final JsonNode bad = JsonLoader.fromURL(new URL(URL_PREFIX + "custom-fmt-bad.json"));

//@formatter:off
final Library library = DraftV4Library
.get()
.thaw()
.addFormatAttribute("uuid", UUIDFormatAttribute.getInstance())
.freeze();
//@formatter:on

final String key = "invalidUUID";
final String value = "Not a valid UUID";
final MessageSource source = MapMessageSource.newBuilder().put(key, value).build();
final MessageBundle bundle = MessageBundles.getBundle(JsonSchemaValidationBundle.class).thaw().appendSource(source).freeze();

final ValidationConfiguration cfg = ValidationConfiguration.newBuilder().setDefaultLibrary("http://my.site/myschema#",
library).setValidationMessages(bundle).freeze();

final JsonSchemaFactory factory = JsonSchemaFactory.newBuilder().setValidationConfiguration(cfg).freeze();

final JsonSchema schema = factory.getJsonSchema(customSchema);

ProcessingReport report;

report = schema.validate(good);
print(report);

report = schema.validate(bad);
print(report);


  - 소스(UUIDFormatAttribute)

private static class UUIDFormatAttribute extends AbstractFormatAttribute {
private static FormatAttribute INSTANCE = new UUIDFormatAttribute();

private UUIDFormatAttribute() {
super("uuid", NodeType.STRING);
}

public static FormatAttribute getInstance() {
return INSTANCE;
}

@Override
public void validate(final ProcessingReport report, final MessageBundle bundle, final FullData data) throws ProcessingException {
final String value = data.getInstance().getNode().textValue();
try {
UUID.fromString(value);

} catch (IllegalArgumentException ignored) {
report.error(super.newMsg(data, bundle, "invalidUUID").put("input", value));
}
}
}

  - 결과


5. 전체소스



 * 참고링크

  - https://github.com/java-json-tools/json-schema-validator

  - http://json-schema.org/latest/json-schema-validation.html

  - http://json-schema-validator.herokuapp.com/

  - http://json-schema.org/example2.html

'프로그래밍 > JAVA' 카테고리의 다른 글

json schema validator 사용하기 - 02  (0) 2018.05.23
AmazonS3Client, deprecated!!!  (0) 2018.05.21
json schema validator 사용하기 - 01  (0) 2018.04.18
시스템 종료 후 File 삭제  (0) 2018.04.12
Java에서 Tuple 사용하기.  (0) 2018.04.11
try-catch-resources  (0) 2018.04.11


1. AppStore Viewer는?

 1) "대한민국" AppStore 내에 있는 "iOS"어플 들 랭킹을 보여주고. 해당 어플의 "댓글"들을 볼수 있는 어플을 만들 예정.

 2) Windows, MAC, Linux 에서 사용할 수 있도록 "Cross-Platform" 데스크톱 앱을 만들 예정.


2. Stack 소개

 1) Electron

  - Node.js 기반으로 작성된 데스크탑 어플리케이션

  - HTML, CSS, Javascript로 데스크톱 어플을 쉽게 만들 수 있게 해주는 Framework

  - Atom Editor를 개발하기 위하여 시작된 프로젝트이고 Atom Shell이라는 이름으로 시작되었다 Electron으로 변경됨.

  - 웹으로 만들어진 서비스가 있다면 손쉽게 데스크톱 어플로 기존 소스를 재활용하여 개발하기 쉬움.


 2) Angular, Typescript, Bootsrap

  - 구글 검색하면 나오는 그거~


3. 사용할 API

 1) Appstore Rss

  - https://rss.itunes.apple.com/ko-kr

  - https://itunes.apple.com/us/rss/customerreviews/id={앱아이디}/json


4. 환경 세팅하기.

 0) Intellij javascript 세팅 변경



 1) Angular-CLI 설치하기 

  - Angular의 components, pipes, services 등을 효율적으로 생성해주는 Tool 입니다.

npm install -g @angular/cli


 2) Angular2 프로젝트 생성

ng new appstore-viewer

 

 3) Electron 관련 폴더 및 파일 생성(https://electronjs.org/docs/tutorial/quick-start 참고)

cd appstore-viewer && mkdir electron 

  - 아래와 같이 파일 2개를 만든다.


  - 프로젝트는 아래와 같은 구조가 될 것이다.



   (1) electron/package.json

{
"name": "appstore-viewer",
"version" : "0.1.0",
"main" : "electron.js"
}


   (2) electron/electron.js

// appstore-viewer/electron/electron.js

const {app, BrowserWindow} = require('electron')

// Keep a global reference of the window object, if you don't, the window will
// be closed automatically when the JavaScript object is garbage collected.
let win

function createWindow() {
// Create the browser window.
win = new BrowserWindow({
width: 800,
height: 600,
backgroundColor: '#ffffff',
icon: `file://${__dirname}/dist/assets/logo.png`
})

// and load the index.html of the app.
win.loadURL(`file://${__dirname}/index.html`)

// Open the DevTools.
win.webContents.openDevTools()

// Emitted when the window is closed.
win.on('closed', () => {
// Dereference the window object, usually you would store windows
// in an array if your app supports multi windows, this is the time
// when you should delete the corresponding element.
win = null
})
}

// This method will be called when Electron has finished
// initialization and is ready to create browser windows.
// Some APIs can only be used after this event occurs.
app.on('ready', createWindow)

// Quit when all windows are closed.
app.on('window-all-closed', () => {
// On macOS it is common for applications and their menu bar
// to stay active until the user quits explicitly with Cmd + Q
if (process.platform !== 'darwin') {
app.quit()
}
})

app.on('activate', () => {
// On macOS it's common to re-create a window in the app when the
// dock icon is clicked and there are no other windows open.
if (win === null) {
createWindow()
}
})

// In this file you can include the rest of your app's specific main process
// code. You can also put them in separate files and require them here.


   (3) src/index.html

    - 자연스러운 실행을 위하여 base href="/"를 base href="./"로 변경한다.

<!doctype html>
<html lang="ko">
<head>
<meta charset="utf-8">
<title>AppstoreViewer</title>
<base href="./">

<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="icon" type="image/x-icon" href="favicon.ico">
</head>
<body>
<app-root>데이터를 가져오는 중 입니다.</app-root>
</body>
</html>

   (4) package.json에 electron 추가하기

    - electron-prebuilt 을 추가함

    - 컴파일된 Electron 바이너리 npm(Electron을 받아도 되지만, 그렇게되면 매번 바이너리를 다운받아야하므로, 공식문서에서는 해당 npm을 권장하고있음.)

"electron-prebuilt": "^1.4.13"


   (5) 명령어 추가

"scripts": {     "start": "ng build --watch",     "build": "ng build --prod",

    "electron": "cp electron/* dist/ && ./node_modules/.bin/electron dist/"
},

5. 실행하기 

 - 다운로드

npm install --save-dev


 - console창 두개로 명령어를 실행시켜주세요.

npm run start

npm run electron


6. 확인


7. 에러처리

 1) Cannot find module '@angular-devkit/core'

module.js:471

    throw err;

    ^


Error: Cannot find module '@angular-devkit/core'

    at Function.Module._resolveFilename (module.js:469:15)

    at Function.Module._load (module.js:417:25)

    at Module.require (module.js:497:17)

    at require (internal/module.js:20:19)

    at Object.<anonymous> (/Users/hyeonggeunkim/akageun/electron/appstore-viewer/node_modules/@angular-devkit/schematics/src/tree/virtual.js:10:16)

    at Module._compile (module.js:570:32)

    at Object.Module._extensions..js (module.js:579:10)

    at Module.load (module.js:487:32)

    at tryModuleLoad (module.js:446:12)

    at Function.Module._load (module.js:438:3)

  - "@angular/cli": "1.6.4" -> "@angular/cli": "1.6.5" 로 변경

  - https://github.com/angular/angular-cli/issues/9307


8. 참고 페이지

 - http://www.blog.bdauria.com/?p=806

 - https://github.com/RobWin/angular2-electron-demo/blob/master/package.json

 - https://angularfirebase.com/lessons/desktop-apps-with-electron-and-angular/

 - https://msp-typescript.gitbooks.io/typescript-angular2-electron/content/chapter1.html

 - https://github.com/MSP-typescript/AngularCLI-Electron-Boilerplate

 - https://www.flaticon.com/free-icon/library_100153 (무료아이콘)

'프로그래밍 > 개인프로젝트' 카테고리의 다른 글

[AppStore Viewer] 1. 세팅하기.  (0) 2018.04.17
[Github] Github 페이지 활용하기.  (0) 2017.02.06
텔레그램 봇 활용하기 -1  (0) 2016.08.23

1. Test Skip하고 싶다.

 - 오래걸리는 작업을 넘기고 싶다.


2. Skip하는 법

 1) 명령어

mvn [install....] -DskipTests 


or

mvn [install....] -Dmaven.test.skip=true


 2) pom.xml

<properties>
<maven.test.skip>true</maven.test.skip>
</properties>


'프로그래밍 > Maven' 카테고리의 다른 글

Maven Test Skip 하는 법  (0) 2018.04.17
[Maven] Plugin 개발하기.  (0) 2018.04.09
Maven Central에 Library Upload하기!!  (0) 2017.02.21
[MAVEN] Exec Maven Plugin 사용하기  (0) 2016.12.01

1. Multi Job

 - 한개의 Application 에서 여러개의 Job을 만들기


2. Job을 2개 만든다.

 1) 이전 글에서 만든 Job

/**
* Basic Configuration
*
* @author akageun
*/
@Configuration
public class BasicConfiguration {
private static final Logger LOG = LoggerFactory.getLogger(BasicConfiguration.class);

private static final String BASIC_JOB_NM = "BASIC_JOB";
private static final String BASIC_STEP_NM = "BASIC_TASKLET_STEP";

@Autowired
public JobBuilderFactory jobBuilderFactory;

@Autowired
public StepBuilderFactory stepBuilderFactory;

/**
* Basic Job Configuration
*
* @return
*/
@Bean(name = BASIC_JOB_NM)
public Job basicJob() {
//@formatter:off
return jobBuilderFactory
.get(BASIC_JOB_NM)
.incrementer(new RunIdIncrementer())
.start(basicTaskletStep())
.build();
//@formatter:on
}

/**
* Basic Step Configuration
*
* @return
*/
@Bean(name = BASIC_STEP_NM)
public Step basicTaskletStep() {
//@formatter:off
return stepBuilderFactory
.get(BASIC_STEP_NM)
.tasklet((stepContribution, chunkContext) -> {
LOG.info("Tasklet Run!!");

return RepeatStatus.FINISHED;
})
.build();
//@formatter:on
}
}


 2) 새로 만든 Multi Job


import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.batch.core.Job;
import org.springframework.batch.core.Step;
import org.springframework.batch.core.configuration.annotation.JobBuilderFactory;
import org.springframework.batch.core.configuration.annotation.StepBuilderFactory;
import org.springframework.batch.core.launch.support.RunIdIncrementer;
import org.springframework.batch.repeat.RepeatStatus;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
* MULTI BASIC Configuration
*
* @author akageun
*/
@Configuration
public class MultiBasicTestConfiguration {
private static final Logger LOG = LoggerFactory.getLogger(MultiBasicTestConfiguration.class);

private static final String MULTI_BASIC_JOB_NM = "MULTI_BASIC_JOB";
private static final String MULTI_BASIC_STEP_NM = "MULTI_BASIC_TASKLET_STEP";

@Autowired
public JobBuilderFactory jobBuilderFactory;

@Autowired
public StepBuilderFactory stepBuilderFactory;

/**
* MULTI_BASIC Job Configuration
*
* @return
*/
@Bean(name = MULTI_BASIC_JOB_NM)
public Job multiBasicJob() {
//@formatter:off
return jobBuilderFactory
.get(MULTI_BASIC_JOB_NM)
.incrementer(new RunIdIncrementer())
.start(multiBasicTaskletStep())
.build();
//@formatter:on
}

/**
* MULTI_BASIC Step Configuration
*
* @return
*/
@Bean(name = MULTI_BASIC_STEP_NM)
public Step multiBasicTaskletStep() {
//@formatter:off
return stepBuilderFactory
.get(MULTI_BASIC_STEP_NM)
.tasklet((stepContribution, chunkContext) -> {
LOG.info("Tasklet Multi Job Run!!");

return RepeatStatus.FINISHED;
})
.build();
//@formatter:on
}
}


3. 실행

 1) application.yml 내 옵션 설정

spring:
batch:
job:
enabled: true

 - 위와 같이 설정할 경우 해당 App내에 모든 Job이 실행된다.


 2) application 내 옵션

spring:
batch:
job:
enabled: false
names: BASIC_JOB,MULTI_BASIC_JOB

- 위와같이 설정할 경우 names에 들어있는 Job들만 실행된다. (Job들은 콤마(,)로 구분된다)


 3) jar파일 실행

java -jar ./BATCH_STUDY.jar --spring.batch.job.names=BASIC_JOB,MULTI_BASIC_JOB


 4) intellij 실행


4. 결과


5. 전체소스보기 : 바로가기


1. embedded-redis

 - 개발 버전, 프로토 타이핑 등에서 간단하게 사용하기 편함.


2. pom.xml

 - https://github.com/kstyrc/embedded-redis 로 사용할 예정

<!-- embedded-redis -->
<dependency>
<groupId>com.github.kstyrc</groupId>
<artifactId>embedded-redis</artifactId>
<version>0.6</version>
</dependency>


3. Redis Configuration

 - application.yml

spring:
redis:
host: localhost
port: 6379
database: 0

 - Start 및 stop 설정 필요

import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import redis.embedded.RedisServer;

import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import java.io.IOException;

/**
* Embedded Redis Configration
*
* @author akageun
*/
@Component
public class EmbeddedRedisConfiguration {

@Value("${spring.redis.port}")
private int redisPort;

private RedisServer redisServer;

@PostConstruct
public void startRedis() throws IOException {
redisServer = new RedisServer(redisPort);
redisServer.start(); //Redis 시작
}

@PreDestroy
public void stopRedis() {
redisServer.stop(); //Redis 종료
}

}


 - Template 설정


import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.jedis.JedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.StringRedisSerializer;

/**
* Redis Configuration
*
* @author akageun
*/
@Configuration
public class RedisConfig {

@Value("${spring.redis.host}")
private String redisHost;

@Value("${spring.redis.port}")
private int redisPort;

@Value("${spring.redis.database}")
private int redisDatabase;

/**
* Factory
*
* @return
*/
@Bean
public JedisConnectionFactory jedisConnectionFactory() {
JedisConnectionFactory jedisConnectionFactory = new JedisConnectionFactory();
jedisConnectionFactory.setHostName(redisHost);
jedisConnectionFactory.setPort(redisPort);
jedisConnectionFactory.setDatabase(redisDatabase);
jedisConnectionFactory.setUsePool(true);
return jedisConnectionFactory;
}

/**
* redis Template
*
* @return
*/
@Bean
public RedisTemplate<String, Object> redisTemplate() {
RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
redisTemplate.setKeySerializer(new StringRedisSerializer());
redisTemplate.setValueSerializer(new StringRedisSerializer());
redisTemplate.setConnectionFactory(jedisConnectionFactory());

return redisTemplate;
}
}


4. 사용

 - RedisTemplate 사용

@Autowired
private RedisTemplate redisTemplate;


- Code

redisTemplate.opsForValue().set("test", "test1111");
redisTemplate.opsForValue().get("test");


정말 간단하다.

1. 기본 세팅 해보기

 1) JOB 세팅하기

@Autowired
public JobBuilderFactory jobBuilderFactory;

/**
* Basic Job Configuration
*
* @return
*/
@Bean(name = BASIC_JOB_NM)
public Job basicJob() {
//@formatter:off
return jobBuilderFactory
.get(BASIC_JOB_NM)
.incrementer(new RunIdIncrementer())
.start(basicTaskletStep())
.build();
//@formatter:on
}

 2) STEP

(1) 기본 소스

@Autowired
public StepBuilderFactory stepBuilderFactory;

/**
* Basic Step Configuration
*
* @return
*/
@Bean(name = BASIC_STEP_NM)
public Step basicTaskletStep() {
//@formatter:off
return stepBuilderFactory
.get(BASIC_STEP_NM)
.tasklet((stepContribution, chunkContext) -> {
LOG.info("Tasklet Run!!");

return RepeatStatus.FINISHED;
})
.build();
//@formatter:on
}

(2) Tasklet

 - org.springframework.batch.core.step.tasklet.Tasklet 로 구현함.

 - 샘플소스

@Component
public class TaskletStep implements Tasklet {

@Override
public RepeatStatus execute(StepContribution contribution, ChunkContext chunkContext) throws Exception {

LOG.info("Tasklet Run!!");

return RepeatStatus.FINISHED;
}
}

- 위 소스를 간단하게 Step 내 소스처럼 변경 가능하다.


2. 실행해보기

 - java -jar로 실행해보기

java -jar path/batch_file_name.jar --spring.batch.job.names=BASIC_JOB


 - intellij 에서 실행해보기


3. 소스 확인하기

 - 바로가기 

1. 파일 삭제

 - 시스템이 종료될 때 파일 삭제하고 싶음


2. Thread를 생성해서 처리함.

 - jdk1.8 미만

Runtime.getRuntime().addShutdownHook(new Thread() {

@Override
public void run() {
new File("").delete(); //File Delete Code

}
});


 - jdk 1.8 이상

Runtime.getRuntime().addShutdownHook(new Thread(() -> {
new File("").delete(); //File Delete Code
}));

3. Apache Commons-io를 사용

 - 코드 샘플

try {
FileUtils.forceDeleteOnExit(new File("fileName"));
} catch (IOException e) {
e.printStackTrace();
}

 - 메소드

/**
* Schedules a file to be deleted when JVM exits.
* If file is directory delete it and all sub-directories.
*
* @param file file or directory to delete, must not be {@code null}
* @throws NullPointerException if the file is {@code null}
* @throws IOException in case deletion is unsuccessful
*/
public static void forceDeleteOnExit(final File file) throws IOException {
if (file.isDirectory()) {
deleteDirectoryOnExit(file);
} else {
file.deleteOnExit();
}
}


'프로그래밍 > JAVA' 카테고리의 다른 글

AmazonS3Client, deprecated!!!  (0) 2018.05.21
json schema validator 사용하기 - 01  (0) 2018.04.18
시스템 종료 후 File 삭제  (0) 2018.04.12
Java에서 Tuple 사용하기.  (0) 2018.04.11
try-catch-resources  (0) 2018.04.11
public static void main(String[] args){}  (0) 2018.04.03

1. Spring Batch

 1) Spring batch란? 

  - Spring Batch는 Job과 Step으로 구성되어 있음.

  - 하나의 Spring Batch안에는 여러 Job이 존재 할 수 있고, 그 Job 안에는 여러 개의 Step 또는 Tasklet을 존재 할 수 있음.

  - Job -> Step -> ItemReader - ItemProcessor - ItemWriter


#https://docs.spring.io/spring-batch/trunk/reference/htmlsingle/#domain 에서 가져온 이미지 입니다.


  2) 장점

   - 간단하게 대용량 배치를 만들 수 있다.

   - 이미 만들어진 많은 모듈들을 사용해서 손쉽게 구현가능(CSV 파싱, DB에서 가지고 오기, S3 등에 파일업로드 등)

  

  3) 단점

    - 어렵다.(배우면 된다.)


2. Class 설명

  1) ItemReader

  - Step 안에서 데이터를 가져오는 역할을 하는 Class이다.

  - 하나의 아이템이 리턴되거나 null

package org.springframework.batch.item;

/**
* Strategy interface for providing the data. <br>
*
* Implementations are expected to be stateful and will be called multiple times
* for each batch, with each call to {@link #read()} returning a different value
* and finally returning <code>null</code> when all input data is exhausted.<br>
*
* Implementations need <b>not</b> be thread-safe and clients of a {@link ItemReader}
* need to be aware that this is the case.<br>
*
* A richer interface (e.g. with a look ahead or peek) is not feasible because
* we need to support transactions in an asynchronous batch.
*
* @author Rob Harrop
* @author Dave Syer
* @author Lucas Ward
* @since 1.0
*/
public interface ItemReader<T> {

/**
* Reads a piece of input data and advance to the next one. Implementations
* <strong>must</strong> return <code>null</code> at the end of the input
* data set. In a transactional setting, caller might get the same item
* twice from successive calls (or otherwise), if the first call was in a
* transaction that rolled back.
*
* @throws ParseException if there is a problem parsing the current record
* (but the next one may still be valid)
* @throws NonTransientResourceException if there is a fatal exception in
* the underlying resource. After throwing this exception implementations
* should endeavour to return null from subsequent calls to read.
* @throws UnexpectedInputException if there is an uncategorised problem
* with the input data. Assume potentially transient, so subsequent calls to
* read might succeed.
* @throws Exception if an there is a non-specific error.
* @return T the item to be processed
*/
T read() throws Exception, UnexpectedInputException, ParseException, NonTransientResourceException;

}


 2) ItemProcessor

  - Step 안에서 가져온 데이터를 가공하는 역할을 하는 Class이다.

  - Chunk 사이즈 만큼 Item들이 List로 들어온다.

package org.springframework.batch.item;

/**
* Interface for item transformation. Given an item as input, this interface provides
* an extension point which allows for the application of business logic in an item
* oriented processing scenario. It should be noted that while it's possible to return
* a different type than the one provided, it's not strictly necessary. Furthermore,
* returning null indicates that the item should not be continued to be processed.
*
* @author Robert Kasanicky
* @author Dave Syer
*/
public interface ItemProcessor<I, O> {

/**
* Process the provided item, returning a potentially modified or new item for continued
* processing. If the returned result is null, it is assumed that processing of the item
* should not continue.
*
* @param item to be processed
* @return potentially modified or new item for continued processing, null if processing of the
* provided item should not continue.
* @throws Exception
*/
O process(I item) throws Exception;
}


 3) ItemWriter

  - Step 안에서 데이터를 쓰는 역할을 하는 Class이다.

package org.springframework.batch.item;

import java.util.List;

/**
* <p>
* Basic interface for generic output operations. Class implementing this
* interface will be responsible for serializing objects as necessary.
* Generally, it is responsibility of implementing class to decide which
* technology to use for mapping and how it should be configured.
* </p>
*
* <p>
* The write method is responsible for making sure that any internal buffers are
* flushed. If a transaction is active it will also usually be necessary to
* discard the output on a subsequent rollback. The resource to which the writer
* is sending data should normally be able to handle this itself.
* </p>
*
* @author Dave Syer
* @author Lucas Ward
*/
public interface ItemWriter<T> {

/**
* Process the supplied data element. Will not be called with any null items
* in normal operation.
*
* @param items items to be written
* @throws Exception if there are errors. The framework will catch the
* exception and convert or rethrow it as appropriate.
*/
void write(List<? extends T> items) throws Exception;

}


3. 간단 용어 설명

  1) Item 

   - 데이터의 가장 작은 구성 요소를 말함.


 2) Chunk

   - commit-interval

   - ItemReader 읽은 데이터를 Processor 통해 가공 한 후 ItemWriter 넘겨지는 갯수를 의미함.

   - 트랜젝션이 걸려 있다면 한 트랜젝션 안에서 처리할 Item의 수이다.


4. 옵션

     (1) 옵션 설명

- spring.batch.initializer.enabled : Spring Batch 실행시에 Database 내 Table create 등 실행여부

- spring.batch.job.enabled : Spring Batch 실행시에 Context내 모든 Job들 실행 여부

- spring.batch.job.names : 실행할 Job 리스트, 콤마(,)로 구분한다.

- spring.batch.schema : db 스키마 초기화 sql파일 위치 (바로가기)

- spring.batch.table-prefix : 테이블명 앞에 붙일 명칭


     (2) 설정

  - application.properties

spring.batch.initializer.enabled=false
spring.batch.job.enabled=false
spring.batch.job.names=test1,test2,test3
spring.batch.schema=org/springframework/batch/core/schema-h2.sql
spring.batch.table-prefix=tmp_


  - application.yml

spring:
batch:
schema: org/springframework/batch/core/schema-h2.sql
table-prefix: tmp_
initializer:
enabled: false
job:
enabled: false
names: test1,test2,test3


* 참고페이지

 - https://projects.spring.io/spring-batch/

 - https://docs.spring.io/spring-batch/3.0.x/reference/html/index.html

 - https://docs.spring.io/spring-batch/trunk/reference/html/listOfReadersAndWriters.html


+ Recent posts