https://stackoverflow.com/questions/9847580/how-to-detect-safari-chrome-ie-firefox-and-opera-browser?rq=1  에서 본 내용을 간단하게 정리해봄.




결과


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

How to detect browser.  (0) 13:00:00
IOS 버전 관련 처리  (0) 2018.07.20
[Jquery] .each에서 break, continue 구현하기.  (0) 2018.07.02
How to create dynamic a form!  (0) 2018.06.07
javascript replaceAll 사용하기  (0) 2018.03.08
Timer 구현하기  (0) 2017.01.25

1. IOS Useagent


Mozilla/5.0 (iPhone; CPU iPhone OS 11_0 like Mac OS X) AppleWebKit/604.1.34 (KHTML, like Gecko) Version/11.0 Mobile/15A5341f Safari/604.1


2. 하고싶은 것

 - 11.4 버전 이상일 경우를 체크하고 싶다.


 - 소스

function osVersion(){
var mt = (navigator.appVersion).match(/OS (\d+)_(\d+)_?(\d+)?/);

if (mt === undefined || mt === null || nt === '') {
return false;
}

var version = [
parseInt(mt[1], 10),
parseInt(mt[2], 10),
parseInt(mt[3] || 0, 10)
];

return parseFloat(version.join('.'))
}

 - 사용법

if (osVersion() > 11.4) {
alert("에러");
}


* IOS 인지 아닌지에 대한 처리는 없습니다. 관련 소스는 추가해서 사용하세요 ^_^

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

How to detect browser.  (0) 13:00:00
IOS 버전 관련 처리  (0) 2018.07.20
[Jquery] .each에서 break, continue 구현하기.  (0) 2018.07.02
How to create dynamic a form!  (0) 2018.06.07
javascript replaceAll 사용하기  (0) 2018.03.08
Timer 구현하기  (0) 2017.01.25

(작성일 기준으로 1.2.8 버전이 최신버전)


자바(with Spring)를 개발하다보면 Class를 추가/변경 하는 작업을 많이 한다. 그럴때마다 서버를 리스타트하는 일은 엄청나게 번거로운 일이다. 그래서 자동으로 reload 시켜주는 걸 찾아봤다.


1. 설치하기

 - pom.xml

<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>springloaded</artifactId>
<version>1.2.8.RELEASE</version>
</dependency>
</dependencies>
</plugin>
</plugins>


 - jar 다운로드(이 경우에는 다운로드한 경로를 따로 복사해 놓으세요.)

http://mvnrepository.com/artifact/org.springframework/springloaded/1.2.8.RELEASE


4. Spring Boot

 1) maven 명령어로 실행

spring-boot:run 을 실행시킨다.


 2) vm option 추가

-javaagent:<pathTo>/springloaded-{VERSION}.jar -noverify


  (1) Intelli J 일 경우

 - File -> Setting -> Build, Execution, Deployment -> Compiler

Build project automatically 체크!!




  (2) Eclipse 일 경우

    - 추후 작성


5. Spring Framework + Tomcat

 - 추후 작성


6. Daemon 실행

java -javaagent:<pathTo>/springloaded-{VERSION}.jar -noverify SomeJavaClass


7. 테스트 결과

 1) 전역변수 추가 -> 안됨.

  - 테스트 코드(변경 전)

@RequestMapping(value = "/")
public ResponseEntity<String> test() {
return new ResponseEntity<String>("INDEX", HttpStatus.OK);
}

  - 테스트코드(변경 후)

private String ma = "test222";

@RequestMapping(value = "/")
public ResponseEntity<String> test() {
LOG.info("test : {} ", ma);
return new ResponseEntity<String>("INDEX", HttpStatus.OK);
}


  - 결과


 2) @Controller 추가 -> 안됨.

@Controller
public class Test {
@RequestMapping(value = "/test")
public ResponseEntity<String> test2() {
return new ResponseEntity<String>("INDEX 2", HttpStatus.OK);
}
}

 

 3) @RequestMapping 추가 -> 안됨.

@RequestMapping(value = "/test")
public ResponseEntity<String> test2() {
return new ResponseEntity<String>("INDEX 2", HttpStatus.OK);
}

   - 404가 뜬다.


 4) Class 추가 - 됨!!

  - 테스트 코드

public enum TestCd {
BOOK, NOTE;
}

  - 잘 추가/수정 된다.


 5) 지역변수 -> 됨!

@RequestMapping(value = "/")
public ResponseEntity<String> test() {

String testValue = "test test test";
LOG.info("test : {} ", testValue);

return new ResponseEntity<String>("INDEX", HttpStatus.OK);
}

 - 잘 추가/수정 된다.



관련문서

 - https://github.com/spring-projects/spring-loaded

 - https://andromedarabbit.net/spring-loaded%EC%99%80-gradle%EC%9D%84-%EC%9D%B4%EC%9A%A9%ED%95%B4-%ED%95%AB%EC%8A%A4%EC%99%91-%EC%A7%80%EC%9B%90%ED%95%98%EA%B8%B0/

 - http://www.holaxprogramming.com/2015/05/29/spring-boot-and-loaded/





1. 사용기
- 구매할 때 이곳저곳 여러 쇼핑몰을 검색해봤는데, 신세계몰이 조금 저렴해서 거기서 주문함
- 거실 tv가 아닌 개인 모니터에 연결해서 넷플릭스 등을 연결해서 봄
- 화질은 좀 별로지만 편해서 종종 사용하는 중
- 금액대비 쓸만함
- 네이버에서 야구 볼때도 사용함. (Mac에서 크롬사용하여 야구를 켬!!) tving으로 사용할 때도 있음. 화질은 심각함ㅋㅋㅋ


'개인 > Review' 카테고리의 다른 글

chromecast  (0) 2018.07.17
네이버 웨일 리뷰  (0) 2016.12.09
앱코 k935p 무접점 키보드  (0) 2016.10.20

1. X Stream

 - IntStream 은 int를 지정한 범위 내에서 반복문을 동작함

 - LongStream dms Long을 지정한 범위 내에서 반복문을 동작함


2. range, rangeclosed

 - range는 endExclusive 값 전까지만 반복

 - rangeClosed는 endExclusive 를 포함하여 반복


3. IntStream

 - 소스

public class IntRangeTest {

public static void main(String[] args) {
int startNum = 1;
int endNum = 9;

intRangeTest(startNum, endNum);
System.out.println("\n");
intRangeClosedTest(startNum, endNum);

System.out.println("\n");
}

private static void intRangeTest(int startNum, int endNum) {
System.out.print("IntRange Test 1 : ");
IntStream.range(startNum, endNum).forEach(System.out::print);

System.out.println();

System.out.print("IntRange Test 2 : ");
for (int i = startNum; i < endNum; i++) {
System.out.print(i);
}
}

private static void intRangeClosedTest(int startNum, int endNum) {
System.out.print("IntRangeClosed Test 1 : ");
IntStream.rangeClosed(startNum, endNum).forEach(System.out::print);

System.out.println();

System.out.print("IntRangeClosed Test 2 : ");
for (int i = startNum; i <= endNum; i++) {
System.out.print(i);
}
}
}


 - 결과



4. LongStream

 - 소스

public class LongRangeTest {

public static void main(String[] args) {
long startNum = 1L;
long endNum = 9L;

longRangeTest(startNum, endNum);
System.out.println("\n");
longRangeClosedTest(startNum, endNum);

System.out.println("\n");
}

private static void longRangeTest(long startNum, long endNum) {
System.out.print("LongRange Test 1 : ");
LongStream.range(startNum, endNum).forEach(System.out::print);

System.out.println();

System.out.print("LongRange Test 2 : ");
for (long i = startNum; i < endNum; i++) {
System.out.print(i);
}
}

private static void longRangeClosedTest(long startNum, long endNum) {
System.out.print("LongRangeClosed Test 1 : ");
LongStream.rangeClosed(startNum, endNum).forEach(System.out::print);

System.out.println();

System.out.print("LongRangeClosed Test 2 : ");
for (long i = startNum; i <= endNum; i++) {
System.out.print(i);
}
}
}

 

 - 결과

<!-- 리사이즈 변경 불가 -->
<textarea style="resize: none;"></textarea>
<!-- vertical horizontal 둘다 가능 -->
<textarea style="resize: both;"></textarea>
<!-- vertical 둘다 가능 -->
<textarea style="resize: vertical;"></textarea>
<!-- horizontal 둘다 가능 -->
<textarea style="resize: horizontal;"></textarea>


업무 중에 엑셀 다운로드 기능에 "암호 걸기"가 필요해짐.


1. pom.xml에 필요한 dependencyt 추가

<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi</artifactId>
<version>3.16</version>
</dependency>


2. 샘플

 - 아래와 같이 설정해주면 잘 나온다.

EncryptionInfo encryptionInfo = new EncryptionInfo(EncryptionMode.agile);
Encryptor encryptor = encryptionInfo.getEncryptor();
encryptor.confirmPassword(password);


 - 결과


3. 전체소스

import lombok.extern.slf4j.Slf4j;
import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
import org.apache.poi.openxml4j.opc.OPCPackage;
import org.apache.poi.poifs.crypt.EncryptionInfo;
import org.apache.poi.poifs.crypt.EncryptionMode;
import org.apache.poi.poifs.crypt.Encryptor;
import org.apache.poi.poifs.filesystem.POIFSFileSystem;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.junit.Test;

import java.io.*;
import java.security.GeneralSecurityException;
import java.util.Arrays;
import java.util.List;

@Slf4j
public class ExcelTest {

@Test
public void 엑셀파일에_암호걸기() {
final String password = "1234";
final String savePath = "c:\\temp\\excel2.xlsx";

List<String> tmpData = Arrays.asList("Java", "JavaScript", "Python", "GoLang");

try (Workbook wb2 = new XSSFWorkbook();
ByteArrayOutputStream fileOut = new ByteArrayOutputStream();
FileOutputStream fos = new FileOutputStream(savePath);) {

Sheet sheet1 = wb2.createSheet("Sheet1");

//Write Excel File
for (int i = 0; i < tmpData.size(); i++) {
String data = tmpData.get(i);

Row row = sheet1.createRow(i);
Cell cell = row.createCell(0);

cell.setCellValue(data);

}

wb2.write(fileOut);

InputStream filein = new ByteArrayInputStream(fileOut.toByteArray());
OPCPackage opc = OPCPackage.open(filein);

POIFSFileSystem fileSystem = new POIFSFileSystem();

EncryptionInfo encryptionInfo = new EncryptionInfo(EncryptionMode.agile);
Encryptor encryptor = encryptionInfo.getEncryptor();
encryptor.confirmPassword(password);

opc.save(encryptor.getDataStream(fileSystem));
fileSystem.writeFilesystem(fos);

log.info("Create Excel File!!");

} catch (IOException e) {
log.error(e.getMessage(), e);

} catch (InvalidFormatException e) {
log.error(e.getMessage(), e);

} catch (GeneralSecurityException e) {
log.error(e.getMessage(), e);
}

}

}


1. History 명령어란?

- 이전에 입력한 명령어 이력을 볼 수 있는 명령어


2. 사용하기

 1) history

- 기본 명령어로 순차적으로 입력했던 명령어 리스트를 보여준다.


history




 2) 최근 N개 검색

- history n

- 최근 입력한 n 개의 명령어 이력을 보여준다.


history 5

- 최근 5개의 명령어를 보여준다.


 3) 이력 중 문자열 검색

- history |grep {검색할 문자열}

- {검색할 문자열}에 대한 명령어만 리스트로 노출된다.


history |grep cd


 4) 기존 이력 삭제

- 기존에 입력했던 명령어 목록 삭제


history -c


 5) 명령어 이력을 파일로 만들기

- 입력된 이력을 특정 파일로 저장


history -w tmp_history.txt


 6) 기존에 입력했던 명령어 재실행

- history 명령어로 출력한 앞에 번호로 명령어 재 실행

- !{이력번호}


!506


 7) 바로 전 입력한 명령어 실행

- !!


!!




3. Tip

 1) 명령어 수행시간 추가

- 명령어 입력 시간 추가


(1) /etc/profile 수정

vi /etc/profile


(2)  아래 내용 추가

#Add Date to .bash_history

HISTTIMEFORMAT="%Y-%m-%d %H:%M:%S : "

export HISTTIMEFORMAT


(3) 적용

source /etc/profile


'OS > Linux' 카테고리의 다른 글

History 명령어 사용하기.  (0) 2018.07.05
Linux bash Shell directory exists check  (0) 2018.04.02
[AWS] SCP로 EC2에서 파일/폴더 가져오기  (0) 2018.01.18
echo 결과 file 생성  (0) 2017.06.13
Install redis on Centos 7  (0) 2017.04.18
Centos User Add(+Aws EC2)  (0) 2017.04.03

1. 현상

 - 아래와 같은 소스를 사용할 경우

@PropertySource(value = {"classpath:common.properties"})

 - 아래와 같이 호출할 경우,한글이 깨진다.

@Autowired
private Environment env;


private void test(){
env.getRequiredProperty("test");
}


2. 해결법

@PropertySource(value = {"classpath:common.properties"}, encoding = "UTF-8")


간단한 해결 법이지만 기억하기 위해 기록해 놓는다.

개인 프로젝트에서 nginx를 웹서버로 사용하고 있다. 그 뒤에는 2대의 WAS를 사용하고 있고, nginx upstream 기능을 사용하여 로드 밸런싱을 했다. 그러다 보니 배포시에 아래 upstream 내 server를 주석처리하고 nginx 를 reload 하고 다 배포하고 또 주석 처리하고 nginx reload하고.... 다 처리하고 다시 reload하고... 휴.... 반복 해야 한다. 


upstream.conf

upstream project_was {
least_conn;
server 127.0.0.1:8081 weight=1;
server 127.0.0.1:8080 weight=1;
}


생각보다 이 작업이 시간도 많이 걸리고 사람이 작업을 하다 보니, 실수가 종종 나오곤 했다. 좋은 방법이 없나 고민을 하기 시작했다!



매일 반복적으로 처리하는 업무의 경우, 최대한 자동화를 진행해야 보다 쾌적한 하루를 보낼 수 있다.


위 글처럼 언제나... 귀찮은 일을 반복하는 걸 싫어하기 때문에 방법 찾아보았다.


1.....?

 - Nginx Plus를 구매!

 - https://www.nginx.com/products/pricing/

 - 비싸다.......


다시!!


1. Nginx Upstream 파일을 만들자!

 - 위 upstream.conf 파일도 어찌 보면 단순 텍스트 파일이다.

 

 1) 배포할 서버를 제외하고 Argument로 활성화 시킬 서버를 넣고 위 파일을 새롭게 생성한다.

  - Argument

USE_HOST_INFO_STR=$1

  - 파일 생성

HOSTS=(${USE_HOST_INFO_STR//,/' '})

SERVER_TEXT_TMPL='server HOST weight=1;'
UPSTM_NM_TEXT_TMPL='upstream UPSTM_NM '

UPSTM_NM="tmp_upstream"
BASIC_NGINX_CONF_PATH="/etc/nginx/"
UPSTREAM_CONF_FILE_NM=$UPSTM_NM".conf"

RTN_CONF_STR="${UPSTM_NM_TEXT_TMPL/UPSTM_NM/$UPSTM_NM} { \n"
RTN_CONF_STR+=" least_conn; \n "
for host in ${HOSTS[@]}
do
RTN_CONF_STR+="${SERVER_TEXT_TMPL/HOST/$host} \n"
done
RTN_CONF_STR+="} \n"

echo -e $RTN_CONF_STR > $BASIC_NGINX_CONF_PATH$UPSTREAM_CONF_FILE_NM


2. nginx -t 명령어로 conf파일 valid 체크를 한다.

if nginx -t ; then
echo "=======OK========"
systemctl reload nginx.service
else
echo "=======ERROR========"
exit -1;
fi


3. 전체파일

#!/bin/sh

USE_HOST_INFO_STR=$1

function create_conf_file
{
HOSTS=(${USE_HOST_INFO_STR//,/' '})

SERVER_TEXT_TMPL='server HOST weight=1;'
UPSTM_NM_TEXT_TMPL='upstream UPSTM_NM '

UPSTM_NM="tmp_upstream"
BASIC_NGINX_CONF_PATH="/etc/nginx/"
UPSTREAM_CONF_FILE_NM=$UPSTM_NM".conf"

RTN_CONF_STR="${UPSTM_NM_TEXT_TMPL/UPSTM_NM/$UPSTM_NM} { \n"
RTN_CONF_STR+=" least_conn; \n "
for host in ${HOSTS[@]}
do
RTN_CONF_STR+="${SERVER_TEXT_TMPL/HOST/$host} \n"
done
RTN_CONF_STR+="} \n"

echo -e $RTN_CONF_STR > $BASIC_NGINX_CONF_PATH$UPSTREAM_CONF_FILE_NM
}

function valid_check
{
if nginx -t ; then
echo "=======OK========"
systemctl reload nginx.service
else
echo "=======ERROR========"
exit -1;
fi
}

create_conf_file
valid_check


위 작업을 하면서 쉘 스크립트 작성은 오래 걸리지 않았다. 그러나 프로젝트를 진행하면서 배포를 자동화 해 놓으니 너무 너무 편했다. 


결론!!!!!!!!!!!


 - 반복적인 작업을 자동화하는 습관이 필요하다.

 - 조금만 머리를 쓰면 몸이 편하다!

 - 한번 배포할 때 30초에서 1분 정도 소비되던 반복 작업을 빼니, 좀 더 프로젝트에 집중 할 수 있었다.




* 참고로 위에 스크립트를 업무에 가져다 쓰실 경우 sleep을 충분히 주시기 바랍니다. ^_^ 


+ Recent posts