반응형

https://mvnrepository.com/artifact/org.openpnp/opencv


OpenPnP OpenCV

OpenCV packaged with native libraries and loader for multiple platforms.


LicenseBSD
Used By5 artifacts


VersionRepositoryUsagesDate
3.2.x3.2.0-1Central4(Dec, 2016)
3.2.0-0Central0(Dec, 2016)
2.4.x2.4.13-0Central2(Aug, 2016)
2.4.11-2Central0(Nov, 2015)
2.4.11-1Central0(Oct, 2015)
2.4.9-8Central0(Oct, 2015)


<dependency>

<groupId>org.openpnp</groupId>

<artifactId>opencv</artifactId>

<version>3.2.0-1</version>

</dependency>



pom.xml에 디펜던시에 추가하면 된다.


필자는 spring-boot 사용하고 있고, 아래 config 클래스를 추가하였다.


@Configuration

public class LibLoadingConfig {

    static {

    nu.pattern.OpenCV.loadShared();

        System.loadLibrary(org.opencv.core.Core.NATIVE_LIBRARY_NAME);

    }

}


*** 위 버전중 2.x 버전중에 몇가지가 nu.pattern.OpenCV.loadShared(); 가 먹히질 않음.. ***





반응형
반응형

웹 사이트 개발 시, 주요한 이슈중의 하나를 꼽자면 크로스 도메인(Cross Domain)이 있습니다.

 

최근 대부분의 웹 브라우저는 Javascript(JQuery)를 이용하여 AJAX 등을 통해서 다른 도메인의 서버의 URL 을 호출하여 데이터를 가져오는 경우, 보안 문제를 발생시킵니다.

 

만약 우리 웹 서비스에서만 사용하기 위해 다른 서브 도메인을 가진 API 함수를 제공하는 API 서버를 구축하였는데, 다른 웹 서비스에서 이 API 서버에 접근하여 마음대로 API를 호출하여 사용한다면 문제가 되겠죠.

 

그래서 Javascript 는 동일 출처 정책(Same Origin Policy) 라는 정책을 두어 다른 도메인의 서버에 요청하는 것을 보안 문제로 간주하고 이를 차단합니다. 즉, Javascript는 자신이 속한 동일한 도메인 내에서만 서버 요청을 허용하고, 처리해주겠다는 것인데요. 이것은 www.ozit.co.kr 도메인에서 호출된 AJAX는 www.ozit.co.kr 도메인 내에 있는 URL만을 호출할 수 있다는 의미입니다. 다시말하면 www.ozit.co.kr 도메인에서 www.tistory.com 의 URL을 AJAX로 호출할 수 없다는 의미이죠.

 

이를 다른 말로는 샌드박스(Sandbox)라고도 합니다. 샌드박스는 보호된 영역 안에서만 프로그램을 동작시킬 수 있도록 하며, 외부에 의해 영향을 받지 않도록 하는 모델을 말하는데요. 이 말뜻은 단어에서 유추할 수 있듯이 어린아이들이 뛰어놀 때, 다치지 않고, 그 안에서만 놀 수 있도록 만든 '모래 놀이통'에서 왔습니다.

 

그런데, 하나의 도메인을 가진 웹 서버에서 모든 처리를 하기에는 효율성이나 성능 등 여러 문제로 각 기능별도 여러 서버를 두는 경우가 많은데요. (API 서버, WAS 서버, 파일(이미지) 서버 등등)

물리적으로 분리된 서버이고, 다른 용도로 구축된 서버이니, 당연히 각각 다른 도메인을 가진 서버들일 텐데, 서로간에 AJAX 통신을 할 수 없는 것일까요? 즉, 서로 다른 도메인간의 호출을 의미하는 크로스 도메인 문제를 해결할 수는 없는 것일까요?

(물리적으로 동일한 서버에서도 여러 도메인을 사용할 수 있는데, 이 때에도 동일하게 크로스 도메인 이슈는 발생합니다. 크로스 도메인은 물리적인 서버나 환경의 이슈가 아닌 도메인 이름 자체의 이슈입니다.)

 

참고로 아래에서 설명드릴 방식은 서버측에서 크로스 도메인을 허용하여 문제를 해결하는 방식인데, 서버의 수정 없이 클라이언트 단에서 이를 해결하는 방법 또한 있습니다. 하지만 100% 해결은 불가능합니다. jsonp, document.domain 값 설정, 크롬 브라우저의 특수 옵션 사용 등 몇몇 방법이 있으나, 범용적인 웹 서비스에서 사용이 어렵거나(사용자가 직접 세팅해야 한다거나), 그 기능이 제한적인 경우가 대부분입니다. 실제 서버에서 해결해주는 것이 표준화된 방법이고, 100% 해결 가능한 방법입니다.

 

 

아래는 크로스 도메인 문제가 발생하면 뜨는 오류 메시지입니다.

 

 

XMLHttpRequest cannot load http://www.ozit.co.kr
No 'Access-Control-Allow-Origin' header is present on the requested resource
.
Origin 'http://abc.ozit.co.kr' is therefore not allowed access.

 

 

 

 

 

 

AJAX는 자원 요청시 XMLHttpRequest 를 통해서 처리되기 때문에 위와 같은 오류가 표시되었습니다.

 

 http://abc.ozit.co.kr 도메인의 웹 서비스에서 http://www.ozit.co.kr 도메인으로 AJAX 호출을 하였으나, 접근할 수 없다는 말입니다.

XMLHttpRequest는 http://www.ozit.co.kr 을 불러올 수 없는데, 그 이유가 Access-Control-Allow-Origin 헤더가 요청된 자원(http://www.ozit.co.kr)에 존재하지 않기 때문이라는데요.

 

파이어폭스로 보는 경우, 좀 더 자세한 한글로 된 안내를 보실 수 있는데요.

"교차 원본 요청 차단: 동일 출처 정책으로 인해 http://www.ozit.co.kr 에 있는 원격 자원을 읽을 수 없습니다. 자원을 같은 도메인으로 이동시키거나 CORS를 활성화하여 해결할 수 있습니다." 라고 합니다.

 

같은 도메인을 사용한다면 당연히 문제가 해결되겠지만, 그러지 못하는 경우라면 CORS를 활성화 시키면 되겠군요.

CORS를 간단히 설명드리자면 Cross-Origin Resource Sharing 의 약자이며, 웹 페이지의 제한된 자원을 외부의 도메인에서의 요청(접근)을 허용해주는 매커니즘입니다. CORS는 브라우저와 서버간의 Cross-Origin 요청을 허용할지 안할지에 대한 여부를 안전하게 결정하도록 상호작용할 수 있는 방법을 정의합니다.

 

 

참고 : CORS (Cross-origin resource sharing)

http://en.wikipedia.org/wiki/Cross-origin_resource_sharing

 

 

설명이 이것저것 잡다하게 많은데요, 실제 이를  해결하는 방법은 어렵지 않습니다.

크로스 도메인 요청을 허용할 웹 서버에서 크로스 도메인 이슈를 문제 삼지 않을 도메인을 지정해주면 됩니다.

 

들어오는 모든 요청에 대해 처리해주기 위해 Filter 를 하나 만들어야 될 것 같습니다.

필터(Filter) 이름은 SimpleCORSFilter 로 하기로 하고 SimpleCORSFilter class 를 Filter interface를 구현하여, 생성하도록 합니다.

그리고 이 필터를 웹서비스의 web.xml 에 등록하여 줍니다.

 

 

- web.xml -

<filter>
    <filter-name>cors</filter-name>
    <filter-class>com.company.project.util.domain.SimpleCORSFilter</filter-class>
</filter>
<filter-mapping>
    <filter-name>cors</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>

 

 

 필터 이름은 cors이며, com.company.project.util.domain 패키지 내에 SimpleCORSFilter 클래스를 구현하였습니다.

 모든 URL 패턴(/*)에 대해 필터가 적용되도록 하였습니다.

 

 

 

- SimpleCORSFilter.java -

 

package com.company.project.util.domain;

 

import java.io.IOException;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletResponse;

import org.springframework.stereotype.Component;

 

@Component
public class SimpleCORSFilter implements Filter {
 
    public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {

        HttpServletResponse response = (HttpServletResponse) res;


        response.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE");
        response.setHeader("Access-Control-Max-Age", "3600");
        response.setHeader("Access-Control-Allow-Headers", "x-requested-with");
        
        response.setHeader("Access-Control-Allow-Origin", "*");

     


        chain.doFilter(req, res);
    }

    public void init(FilterConfig filterConfig) {}

    public void destroy() {}

}

 

위의 필터는 web.xml 에 정의한 URL 패턴에 의해서 이 웹 서버로 오는 모든 요청이 이 메서드를 지나치게 됩니다. 이 메서드를 한 번 지나고 나면 결과를 내려받는 HTML 페이지 Header에 Access-Control 과 관련된 4개의 라인이 추가되게 됩니다.

 

* response.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE");

 - POST, GET, OPTIONS, DELETE 요청에 대해 허용하겠다는 의미입니다.

 

* response.setHeader("Access-Control-Max-Age", "3600");
 - HTTP Request 요청에 앞서 Preflight Request 라는 요청이 발생되는데, 이는 해당 서버에 요청하는 메서드가 실행 가능한지(권한이 있는지) 확인을 위한 요청입니다. Preflight Request는 OPTIONS 메서드를 통해 서버에 전달됩니다. (위의 Methods 설정에서 OPTIONS 를 허용해 주었습니다.)

 여기서 Access-Control-Max-Age 는 Preflight request를 캐시할 시간입니다. 단위는 초단위이며, 3,600초는 1시간입니다. Preflight Request를 웹브라우저에 캐시한다면 최소 1시간동안에는 서버에 재 요청하지 않을 것입니다.

 

* response.setHeader("Access-Control-Allow-Headers", "x-requested-with");
 이는 표준화된 규약은 아니지만, 보통 AJAX 호출이라는 것을 의미하기 위해 비공식적으로 사용되는 절차입니다. JQuery 또한 AJAX 요청 시, 이 헤더(x-requested-with)를 포함하는 것을 확인하실 수 있습니다. 여기서는 이 요청이 Ajax 요청임을 알려주기 위해 Header 에 x-request-width를 설정합니다. Form을 통한 요청과 Ajax 요청을 구분하기 위해 사용된 비표준 규약지만, 많은 라이브러리에서 이를 채택하여 사용하고 있습니다. (참고로 HTML5 부터는 Form 과 Ajax 요청을 구분할 수 있는 Header가 추가되었습니다.)

 

* response.setHeader("Access-Control-Allow-Origin", "*");
 이 부분이 가장 중요한 부분입니다. * 는 모든 도메인에 대해 허용하겠다는 의미입니다. 즉 어떤 웹사이트라도 이 서버에 접근하여 AJAX 요청하여 결과를 가져갈 수 있도록 허용하겠다는 의미입니다.

 만약 보안 이슈가 있어서 특정 도메인만 허용해야 한다면 * 대신 특정 도메인만을 지정할 수 있습니다.

 

 

response.addHeader("Access-Control-Allow-Origin", "*");

 

대신 

 

response.addHeader("Access-Control-Allow-Origin", "http://www.ozit.co.kr");
response.addHeader("Access-Control-Allow-Origin", "http://abc.ozit.co.kr");
response.addHeader("Access-Control-Allow-Origin", "http://test.ozrank.co.kr");

 

 

이렇게 쓰면

 

www.ozit.co.kr, abc.ozit.co.kr, test.ozrank.co.kr 이렇게 3개의 도메인에 대해서만 크로스 도메인을 허용하겠다는 의미입니다.

 

 



출처: http://ooz.co.kr/232 [이러쿵저러쿵]

반응형
반응형

이 잘못된 나타난 이유는: Red Hat 시스템 glibc 버전 매우 낮기 때문에

 

1, 보기 glibc 지원 시스템 버전

 

2, 보기 시스템에 설치된glibc

 

그래서 한 고려 컴파일 glibc 이 문제를 해결하는, 본문 사용하는 것은 glibc-2.14.tar.xz 이 버전.

 

1, 다운로드glibc-2.14.tar.xz

$ wget http://ftp.gnu.org/gnu/glibc/glibc-2.14.tar.xz

 

2, 압축을 풀

$ tar xvJf glibc-2.14.tar.xz

 

3, 지금 glibc 소스 디렉토리 건립 build 목록 및 진입 build 목록

$ cd glibc-2.14 $ mkdir build $ cd build/

 

4, 설정 및 번역 및 설치

$ ../configure --prefix=/opt/glibc-2.14 $ make -j4 $ make install

 

5, 환경 변수 설정

$ vim ~/.bashrc

마지막 다음 두 추가

LD_LIBRARY_PATH=/opt/glibc-2.14/lib:$LD_LIBRARY_PATH export LD_LIBRARY_PATH

 

5-1. 또는

  1. vi .bash_profile
  2. export LD_LIBRARY_PATH=/opt/glibc-2.14/lib:$LD_LIBRARY_PATH
  3. source .bash_profile

 


출처 : http://www.programkr.com/blog/MMzMxEDMwYTw.html

반응형
반응형

예제에 앞서 REST 에 대한 정의는 Representational state transfer 이다. RESTFul을 이용하는 이유에 대해서는 굳이 설명을 하지 않아도 될 듯 하다. 간단히 내 생각을 이야기 하자면, 우선 cloud 가 아닌 단일 Web Application만 생각해 볼때 현재 개발 추세가 Back-end 의 중요성 보다는 Front-end 의 UI/UX 디자인의 비중이 좀더 커가고 있다. 예전에 그저 model을 던저 주고 JSP 에서 그 모델을 JSP 페이지 쪽에 던져 주어 content를 만드는 방법에서 이제는 Front-end 가 로딩 되어진 상태에서 asynchronous 방식으로 content를 서버쪽에서 받아와 보여주는 방식을 선호 하게 되었다. 이렇게 하여 우선 Front-end의 로딩 속도를 빨리 가져 갈수 있다. 머 사실 어찌 되었던 간에 Back-end 데이타 가져 오는 데 걸리는 시간은 같지만…. 그래도 페이지 전체가 먼저 보여 졌을 때랑, 그렇지 않고 back-end 데이타를 기다리는 동안 페이지르 볼 수 없는 것이랑은 느낌이 틀리니. 이런 이유로 RESTFul Web Service 의 비중도 커졌고 이에 대한 개발도 좀더 구체화 되었다.

먼저 내가 사용한 개발 환경은:

  • Spring Boot 1.4.3.RELEASE (Spring Framework 4.3.5.RELEASE 가 사용 되어 진다.)
  • Java 1.7 version으로 세팅 (1.8로 해도 무난)
  • Postman – RESTFul 개발시 test 를 위해 사용 되어 지는 GUI 이다. Mac OS, Windows, Chrome browser 용으로 설치 하면 된다.
  • Eclipse

자 그럼 시작에 앞서 아래 5가지의 HTTP request method type 들에 대해서 알아 보자.

  • GET – 데이타를 검색하여 해당 값을 받아 올때 사용한다. (CRUD 에서 Retrieve 할 때 사용)
  • POST – 새롭게 데이타를 생성 할 때 사용 한다. (CRUD 에서  Create 할 때 사용)
  • PUT – 데이타를 업데이트 할 때 사용 한다. (CRUD 에서  Update 할 때 사용)
  • PATCH – PUT 과 마찬가지로 데이타를 업데이트 할 때 사용하지만 PUT 과 달리 전체 Entity 데이타의 업데이트가 아닌 부분의 값을 업데이트 할 때 사용한다.
  • DELETE – 데이타를 삭제 할 때 사용한다. (CRUD 에서  Delete 할 떄 사용)

이렇게 HTTP request method type 에 대해 Front-end 개발자와 Back-end 개발자 사이에 확실한 이해를 하고 넘어 가야 한다. 물론 Back-end 개발자의 경우 Front-end 개발자가 사용 할 수 있도록 정확한 문서를 제공해야 한다.

먼저 아래와 같이 Eclipse 를 이용하여 sbrest 라고 하는 프로젝트를 만들고 pom.xml 을 설정하자.

그러면 이제 Customer Entity 를 이용한 CRUD 를 하는 간단한 RESTFul 을 만들어 보자. 우선 아래와 같이 Customer entity를 만든다.

Spring framework 4.0 이후 버전에서는 Entity class 에서 @Table annotation 을 사용 하지 않으면 기본적으로 class 이름과 같은 table 을 맵핑한다. 따라서 class 이름과 다른 table 이름을 사용 한다면 @Table(name = “tbl_customer”) 처럼 명시 하여 주어야 한다. 또 한 가지는 class의 property 들도 @Column annotation을 사용 하지 않는 다면 기본적으로 property 이름을 이용하여 table column 이름과 맵핑을 하게 된다. 위에서는 firstname과 lastname이 이 경우에 해당한다.

다음으로 Spring Data JPA 를 이용하여 아래와 같이 간단하게 Repository 인터페이스와 Service 를 만들자.

 

 

여기 까지 간단하게 Customer entity 에 대한 CRUD 오퍼레이션을 하는 Repository와 Service 를 만들어 보았다. 이제 RESTFul 을 만들어 보자. 개인적으로 @RestController 들을 따로 package를 만들어 관리를 하는 것을 선호 한다. 따라서 아래와 같이 rest package를  만들어 그곳에 Rest Controller 들을 정의 한다.

위와 같이 RestCustomerConstroller.java 를 만들고 @RestController annotation을 설정 하여 Rest Controller를 만들었다. 먼저 GET/POST/PUT/PATCH/DELETE 를 이용한 Rest 코드 부터 하나 하나 알아 보겠다.

 

GET – To retrieve data

GET 을 이용 하는 경우는 Data를 검색할 때 사용 한다.

위에서 보면 전체 customer list를 가져오거나 @PathVariable을 이용하여 customer ID 를 보내 특정 customer 를 검색하여 데이타를 받는 경우이다. method = RequestMethod.GET 을 @RequestMapping 에 정의 하면 된다. 리턴은 ReponseEntity<T> 클래스를 이용하여 검색이 되지 않았을 경우에는 HttpStatus.NOT_FOUND 를 넘겨 주고, 검색이 되었을 경우에는 검색한 결과 object을 HttpStatus.OK 와 함께 넘겨 준다. 이때 Spring 에서는 자동으로 jackson-databind 를 이용하여 JSON 포맷으 데이타를 넘겨 준다.

 

POST – To create data

POST 를 이용 하는 경우는 Data를 새롭게 만들 때 사용 한다.

POST 는 새로운 Data를 생성 할 때 사용 하는 방법으로 method = RequestMethod.POST 로 설정을 해 준다. argument 들로 Customer 객체를 @RequestBody 를 이용하여 받아 왔다. Front-end 쪽에서 JSON 포맷으로 Customer 데이타를 보내 주면 된다. 이 떄 Front-end 개발자는 POST 이기 때문에 새로운 객체를 생성해야 하는 것으로 알고 데이타를 보내 주어야 한다. 두번 째 argument 로 UriComponentBuilder 를 설정 했다. 이유는 Customer를 생성하고 HttpHeaders 객체의 location 정보를 넣어 주기 위함이다. 이렇게 해 주면 Front-end 쪽 개발자는 새로운 데이타가 성공적으로 생성 (HttpStatus.CREATED) 되었을 경우 header 정보에서 location 값을 찾아 redirect 해 줄 수 있게 된다.

위에서 보면 만약 새롭게 생성하려고 하는 데이타가 이미 존재 하는 경우라면 HttpStatus.CONFLICT를 ResponseEntity<Void> 를 통해 리턴해 준다.

 

PUT –  To update data

PUT 을 이용 하는 경우는 존재 하는 Data를 업데이트 할 때 사용 한다.

 

PATCH – To update partial data

PATCH 는 부분적이 Data를 업데이트 할 때 사용 한다. 즉 Front-end 쪽에서 객체 전체 업데이트가 아닌 부분만 업데이트 할 때 업데이트 하는 부분만 RESTFul 에 보내 준다. PUT 과 PATCH 는 공통적으로 update 할 때 사용 하지만 PATCH 가 부분 데이타를 업데이트 한다는 점에서 PUT 과 차이가 있다.

위에서 method = RequestMethod.PATCH 를 설정해 주었고 업데이트 하려는 Customer의 ID와 Customer 객체를 받았다. 받은 Customer 객체의 경우 실제 업데이트 하려는 property 에만 값이 들어 있고 나머지는 null 이 들어 있게 된다. PATCH 가 성공적으로 되었으면 업데이트된 Customer 와 HttpStatus.OK 를 ResponseEntity<Customer> 에 넣어 보내 주고, 그렇지 않을 경우에는 HttpStatus.NOT_FOUND 를 넘겨준다. CustomerServiceImpl.java 의 patchCustomer 메소드를 참고 하기 바란다.

 

DELETE – To delete data

DELETE 를 이용 하는 경우는  Data를 삭제 할 때 사용 한다.

method = RequestMethod.DELETE 를 이용 하고 성공했을 경우 ResponseEntity<Void> 에 HttpStatus.OK 를 넣어 주고 그렇지 않을 경우 HttpStatus.NOT_FOUND 를 넣어 넘겨주었다.

 

지금 까지 RESTFul controller 를 개발 하는 방법을 설명 하였다. 아래는 최종 파일 이다.

이렇게 하여 간단하게 Spring Boot 을 이용한 REST web application을 만들어 보았다.

 

최종 프로젝트는 위와 같을 것이다. 자 그러면 이제 Postman 을 이용하여 위에서 만든 RESTFul web application을 테스트 해 보자. 아직 Postman을 설치 하지 않았다면 아래 사이트에 가서 각자의 환경에 맞게 다운 받아 설치를 하자.

Postman

 

TEST

자 그러면 먼저 Spring Boot application을 실행 하자.

그리고 이제 Postman을 실행 하자. 원하면 Sign up을 해서 자신이 test 한 것을 저장할 수 있다.

먼저 Data 가 아무 것도 없으니 CREATE method 를 이용하여 생성 해 보자.

위와 같이 POST 로 http://localhost:8080/customer 를 호출 하였다. 이때 Body 에는 javascript의 AJAX 를 이용하여 업데이트 한다는 가정으로 raw 와 JSON (application/json) 을 설정하고 JSON 데이타를 타입한 후에 Send 버튼을 눌러 호출 하면 된다. 이렇게 하면 아래 보는 것과 같이 Status: 201 Created 가 넘어 오는 것을 확인 할 수 있다. 다른 이름을 이용하여 하나 더 만들어 보자.

그 다음으로 위에서 생성한 데이타를 검색해 보자.

위에서는 http://localhost:8080/customer 를 GET 방식을 이용하여 Send 를 눌렀다. 그리고 나면 아래와 같이 Status: 200 OK 와 생성한 Customer 리스트를 볼 수 있다.

위에서는 http://localhost:8080/customer/2 를 GET 방식을 이용하여 Send 를 눌렀다. 그리고 나면 아래와 같이 Status: 200 OK 와 id 값이 2 인 Customer 검색 결과가 리턴 된다.

이번엔 PUT을 이용한 Update 이다.

보는 것과 같이 Front-end 쪽에서는 객체 전체 데이타를 update 하기 위해 보내 주었다. 위와 같이 PUT으로 설정해서 Send 를 누르면 업데이트 된 결과 값이 Status: 200 OK 와 함께 넘어 온다.

이제 PATCH 를 보자.

위에서 보면 front-end 에서는 lastname 만 넣어 PATCH 를 이용하여 request를 보냈다. 이렇게 하면 back-end 쪽에서는 부분 업데이트로 알고 lastname 만 업데이트 해 주었다. 리턴된 결과를 보면 Status: 200 OK 와 lastname 이 업데이트된 JSON 데이타 결과 같이 넘어 왔다.

마지막으로 아래 DELETE 를 해 보자.

DELETE 를 이용 http://localhost:8080/customer/2 를 호출 하여보면 ID 가 2 인 Customer 가 삭제 되고 Status: 200 OK 가 넘어 왔다.

 

이상 Spring Boot 을 이용한 RESTFul web service 를 만들어 보았다.

 

** DOWNLOAD this project

 

** Reference


반응형
반응형

깃 주소


https://github.com/shuhei/Rectify



반응형

'JAVA/SPRING > JAVA' 카테고리의 다른 글

[JUnit] 단위 테스트 도구 시작하기 1  (0) 2018.07.20
[펌]Java로 OTP 구현하기  (0) 2018.01.16
Maven으로 javadoc API 문서 만들기  (0) 2017.12.04
Eclipse 한글화  (0) 2017.12.01
[SFTP] jsch Pipe closed 익셉션 관련  (0) 2017.12.01
반응형

단 50줄이면 Java에서 OTP를 구현할 수 있습니다.


제가 OTP를 구현해야겠다고 생각한 계기는,
'클라이언트와 서버 간 REST 통신시, 해커로부터 데이터 변조 공격을 막기 위해서 일회용 비밀번호(OTP)를 사용하면 어떨까?' 라는 생각에서 출발했습니다.
(적용은 안했지만, 누군가에게 도움이 되길 바라며...)

OTP (One Time Password)
고정된 패스워드 대신 무작위로 생성되는 일회용 패스워드를 이용하는 사용자 인증 방식.


은행에서 OTP 단말기나, OTP 카드를 사용해보신 분이라면 한 번쯤 생각해보셨을 겁니다.

'서버랑 통신하는건가..?'

사실, OTP는 단말기와 서버가 통신하는게 아닙니다.

미리 정의된 비밀키와 시간 정보를 토대로 Hash 처리하여 비밀번호를 만들어냅니다.

핵심은 시간입니다. 시간은 변하므로, 일정 시간(정하기 나름) 마다 비밀번호가 바뀌죠.

그리고, 똑같은 알고리즘으로 단말기에서 비밀번호를 생성하고, 서버에서 검증합니다.

같은 시간대에 만들어졌으므로 단말기와 서버에서 만든 패스워드는 동일합니다.


그럼 이제 OTP를 만들고 검증하는 클래스를 생성하고, 아래와 같이 상수를 정의합니다.

 private static final long DISTANCE = 30000; // 30 sec
 private static final String ALGORITHM = "HmacSHA1";
 private static final byte[] SECRET_KEY = "define your secret key here".getBytes();


그리고 비밀키와 시간에 따라 Hash 처리하여 패스워드를 생성하는 메소드를 아래와 같이 정의합니다.

 private static long create(long time) throws Exception {
  byte[] data = new byte[8];
  
  long value = time;
  for (int i=8; i-- > 0; value >>>= 8) {
   data[i] = (byte) value;
  }
  
  Mac mac = Mac.getInstance(ALGORITHM);
  mac.init(new SecretKeySpec(SECRET_KEY, ALGORITHM));
  
  byte[] hash = mac.doFinal(data);
  int offset = hash[20-1] & 0xF;
  
  long truncatedHash = 0;
  for (int i=0; i<4; ++i) {
   truncatedHash <<= 8;
   truncatedHash |= hash[offset+i] & 0xFF;
  }
  
  truncatedHash &= 0x7FFFFFFF;
  truncatedHash %= 1000000;
  
  return truncatedHash;
 }


마지막으로, OTP 클래스를 외부에서 사용할 수 있도록 public으로 create(), vertify() 메소드를 아래와 같이 정의합니다.

 public static String create() throws Exception {
  return String.format("%06d", create(new Date().getTime() / DISTANCE));
 }
 
 public static boolean vertify(String code) throws Exception {
  return create().equals(code);
 }

 

테스트 코드는 다음과 같습니다.

  String code = OTP.create();
  
  System.out.println("Created OTP : " + code);
  
  System.out.println("Vertify OTP : " + OTP.vertify(code));


30초(DISTANCE)마다 비밀번호가 변경되는 것을 확인할 수 있습니다.

 

참조 글

http://terms.naver.com/entry.nhn?docId=1380773&cid=40942&categoryId=32854

http://zero-gravity.tistory.com/m/post/221

http://www.javacodegeeks.com/2011/12/google-authenticator-using-it-with-your.html/comment-page-1/#comment-14663



출처: http://silentsoft.tistory.com/9

반응형
반응형

https://encodent.com/bitcoin 


비트코인 논문에 관심이 있으신 분은 참고바랍니다.


9페이지 가량의 논문입니다.

반응형
반응형

Tomcat의 로그파일중 catalina.out은 하나의 파일에 계속 로그가 누적됨으로

파일의 크기가 무지막지하게 커지는 현상을 볼수있다.

차후 파일의 크기가 일정크기를 벗어났을때 에러도 발생하기때문에 정기적으로 Tomcat을 내리고 삭제해주는 작업을 해야되는

불편함이 있어서 파일을 다른 로그처럼 날짜별로 생성하고 싶었다.


그래서 검색을 했더니 log4j나 몇가지 다른 방법으로 설정하는 방법이 존재하는거 같았다.

하지만 Apache의 rotatelogs를 이용하는게 제일 쉽고 간단해 보였다.


방법은 /Tomcat설치폴더/bin/catalina.sh 파일의 내용중

  shift

  touch "$CATALINA_OUT"

  if [ "$1" = "-security" ] ; then

    if [ $have_tty -eq 1 ]; then

      echo "Using Security Manager"

    fi

    shift

    eval "\"$_RUNJAVA\"" "\"$LOGGING_CONFIG\"" $LOGGING_MANAGER $JAVA_OPTS $CATALINA_OPTS \

      -Djava.endorsed.dirs="\"$JAVA_ENDORSED_DIRS\"" -classpath "\"$CLASSPATH\"" \

      -Djava.security.manager \

      -Djava.security.policy=="\"$CATALINA_BASE/conf/catalina.policy\"" \

      -Dcatalina.base="\"$CATALINA_BASE\"" \

      -Dcatalina.home="\"$CATALINA_HOME\"" \

      -Djava.io.tmpdir="\"$CATALINA_TMPDIR\"" \

      org.apache.catalina.startup.Bootstrap "$@" start \

      >> "$CATALINA_OUT" 2>&1 "&"

  else

    eval "\"$_RUNJAVA\"" "\"$LOGGING_CONFIG\"" $LOGGING_MANAGER $JAVA_OPTS $CATALINA_OPTS \

      -Djava.endorsed.dirs="\"$JAVA_ENDORSED_DIRS\"" -classpath "\"$CLASSPATH\"" \

      -Dcatalina.base="\"$CATALINA_BASE\"" \

      -Dcatalina.home="\"$CATALINA_HOME\"" \

      -Djava.io.tmpdir="\"$CATALINA_TMPDIR\"" \

      org.apache.catalina.startup.Bootstrap "$@" start \

      >> "$CATALINA_OUT" 2>&1 "&"

  fi

이부분에서 몇가지 부분을 아래와 같이 변경한다.

  shift

  #touch "$CATALINA_OUT"

  if [ "$1" = "-security" ] ; then

    if [ $have_tty -eq 1 ]; then

      echo "Using Security Manager"

    fi

    shift

    eval "\"$_RUNJAVA\"" "\"$LOGGING_CONFIG\"" $LOGGING_MANAGER $JAVA_OPTS $CATALINA_OPTS \

      -Djava.endorsed.dirs="\"$JAVA_ENDORSED_DIRS\"" -classpath "\"$CLASSPATH\"" \

      -Djava.security.manager \

      -Djava.security.policy=="\"$CATALINA_BASE/conf/catalina.policy\"" \

      -Dcatalina.base="\"$CATALINA_BASE\"" \

      -Dcatalina.home="\"$CATALINA_HOME\"" \

      -Djava.io.tmpdir="\"$CATALINA_TMPDIR\"" \

      org.apache.catalina.startup.Bootstrap "$@" start \

      2>&1 "&" | /apache설치위치/bin/rotatelogs "$CATALINA_OUT"-%Y-%m-%d 86400 540 &

  else

    eval "\"$_RUNJAVA\"" "\"$LOGGING_CONFIG\"" $LOGGING_MANAGER $JAVA_OPTS $CATALINA_OPTS \

      -Djava.endorsed.dirs="\"$JAVA_ENDORSED_DIRS\"" -classpath "\"$CLASSPATH\"" \

      -Dcatalina.base="\"$CATALINA_BASE\"" \

      -Dcatalina.home="\"$CATALINA_HOME\"" \

      -Djava.io.tmpdir="\"$CATALINA_TMPDIR\"" \

      org.apache.catalina.startup.Bootstrap "$@" start \

      2>&1 "&" | /apache설치위치/bin/rotatelogs "$CATALINA_OUT"-%Y-%m-%d 86400 540 &

  fi

위의 빨간색 글자부분이 변경된 부분이다.

우선 touch "$CATALINA_OUT" 부분을 주석처리한다.

주석처리하지 않으면 아래와같이 파일크기가 0인 catalina.out 이라는 파일이 계속 생성되어 있는것을 볼수 있다.

그다음으로 Apache가 설치된 경로를 확인한다.

이는 날짜별 파일 생성을 위해 rotatelogs를 사용하는데 Apache의 설치경로 아래에 bin폴더에 존재하기 때문이다.

그리고 나서

>> "$CATALINA_OUT" 2>&1 "&" 

부분이 두군데 있는데 두군데 모두를 

2>&1 "&" | /apache설치위치/bin/rotatelogs "$CATALINA_OUT"-%Y-%m-%d 86400 540 &

로 변경해준다.


당연히 "apache설치위치"는 실제 위치를 기재해야된다.

그리고 뒷쪽의 옵션이 %Y-%m-%d 86400 540 이렇게 붙는데

%Y-%m-%d는 날짜 표현(상세 표현 방법은 아래 표 참조)

%A

(지역화된) 완전한 요일 이름

%a

(지역화된) 3-문자 요일 이름

%B

(지역화된) 완전한 달 이름

%b

(지역화된) 3-문자 달 이름

%c

(지역화된) 날짜와 시간

%d

2-자리 일

%H

2-자리 시간 (24 시간 시계)

%I

2-자리 시간 (12 시간 시계)

%j

3-자리 날짜수

%M

2-자리 분

%m

2-자리 달

%p

(지역화된) 12 시간 시계의 am/pm

%S

2-자리 초

%U

2-자리 주일수 (주의 첫번재 날은 일요일)

%W

2-자리 주일수 (주의 첫번재 날은 월요일)

%w

1-자리 요일수 (주의 첫번째 날은 일요일)

%X

(지역화된) 시간

%x

(지역화된) 날짜

%Y

4-자리 연도

%y

2-자리 연도

%Z

시간대 이름

%%

문자그대로 `%'

86400는 로테이션 시간을 초단위로 표현 (86400은 24시간 즉 매일)

540은 표준시와 한국시간과의 시간차를 표현


이제 catalina.out 로그는 날짜별로 생성되어 진다.

아래 참고사이트에 가면 더 다양한 설정 방법 및 옵션을 확인 가능하다.

참고 사이트 : http://adminid.kr/unixlinux/102231

                  http://httpd.apache.org/docs/current/programs/rotatelogs.html



출처: http://savour.tistory.com/316 [사랑향기-아이들의 키만큼 커져가는 행복(서진연)]

반응형
반응형


 나는 개발할 때 Chrome 개발자도구의 console을 굉장히 자주 사용하는데(대부분의 개발자들이 그럴 것이라 생각한다), 오늘은 크롬 개발자도구의 편리한 기능과 잘 쓰진 않지만 알아두면 좋은 기능들을 한 번 정리해 보고자 한다.

Console Open

  • Windows / Linux: Ctrl+Shift+J
  • Mac: Cmd+Opt+J
  • 개발자 도구가 열린 상태: ESC

Console Clear

  • clear() 입력
  • Ctrl+L

Log Options

 console 오른쪽 상단위 톱니바퀴를 누르면 옵션을 볼 수 있다. 주로 사용하는 기능은 다음과 같다.

  • Hide network: 404 또는 500 오류 등은 보여주지 않는다.
  • Log XMLHttpRequst: XML Request를 기록
  • Preserve log: refresh나 탐색하는 동안 log기록을 유지
  • Show timestamps: log행 마다 timestamp를 보여 준다.


그룹화하여 console message 출력하기

 console.group(),  console.groupEnd() 명령어를 사용하면 메세지들을 그룹화 하여 보여줄 수 있다. 또한 이 그룹들은 중첩도 가능하다. 또 그룹이 축소된 상태로 보이게 하고 싶다면 console.group()대신 console.Collapsed()를 사용할 수도 있다.

특정 상황에서만 console message 출력하기

 console.assert()를 사용하면 첫번째 매개변수가 false일때만 두번째 매개변수를 출력한다.

CSS로 출력 스타일 변경하기

 %c와 css style을 이용하면 출력되는 색이나 글자 크기를 바꿀 수 있다.

DOM Element를 Javascript 객체로 나타내기

 console로 DOM Element를 출력해보면 보통 다음과 같이 HTML 형식으로 표현되는 것을 볼 수 있다.

 그러나 개발하다보면 해당 element의 속성을 보고싶은 경우가 있는데 이때 console.dir()를 사용하면 해당 element를 javascript객체로 표현해준다.

객체 정보를 표로 보기

 object나 배열을 console.table()을 사용하면 표로 볼 수 있다.

실행 시간 측정 하기

 console.time()과 console.timeEnd()를 사용하면 실행하는데 걸린 시간을 표시해준다. 따로 new Date() 함수등을 사용할 필요가 없어 편리하다.

$_

 $_를 사용하면 가장 마지막으로 사용했던 selector나 평가식을 반환하다.

Shortcut Selector

 console에서 DOM Element를 선택할때 단축 선택자를 사용할 수 있다. 단축 선택자는 세 종류가 있다.

  • $(): 일치하는 첫 번째 요소를 반환, document.querySelector()와 같다.
  • $$(): 일치하는 모든 요소의 배열을 반환, document.querySelectorAll()과 같다.
  • $x(): Xpath와 일치하는 요소의 배열을 반환한다.
  • $0-4: console에서는 마지막으로 불러왔던 요소 5개를 저장해둔다. 가장 최신은 $0, 가장 오래된 항목은 $4이다.

이벤트가 발생 했을 때 콘솔을 출력하고 싶을 때

 monitorEvents(element, eventType)을 사용하면 특정 이벤트가 발생 했을 때 coonsole에 보여줄 수 있다. unmonitorEvents(element)를 사용하면 이벤트 수신을 해제한다. 또 특정 객체에 연결되어있는 eventListener들을 보고싶다면 getEventListeners(element)를 사용하면 된다.

객체를 클립보드에 복사하기

 copy(object)를 사용하면 지정된 객체의 문자열 표현을 클립보드에 복사할 수 있다.

특정 함수가 호출 되었을 때 디버그 실행하기

 debug(function)을 사용하면 해당 함수가 실행되었을때 sources 패널 내부에서 단계적으로 디버그를 할 수 있도록 해준다.

함수에 전달된 인수를 보고 싶을 때

 monitor(function) 함수를 실행하면 지정된 함수가 실행 되었을 때 함수 이름과 인수를 출력해준다.

ES6 Template literals 응용하기

 chrome은 대부분의 ES6 문법을 지원하기 때문에 template literals를 그대로 사용할 수 있는데, console.log와 조합하면 꽤나 편리하게 사용이 가능하다. 특히 문자열과 변수를 함께 사용해야하는 경우 편리하다. 예를 들어보자. 보통 문자열 중간에 변수 값을 표현하려면 다음과 같이 많이 사용한다.

 template literals은 ``(backtick)과 ${object}를 사용하여 표현할 수 있다. 따라서 다음과 같이 console.log()에 다음과 같이 표현할 수 있다.



출처: http://dev-momo.tistory.com/entry/알마두면-쓸만한-Chrome-Console-기능 [Programming Note]

반응형
반응형

안녕하세요. 이번 시간에는 History API에 대해 알아보겠습니다.

제 블로그를 보시면 페이지가 깜빡이지 않는데도 내용도 바뀌고 주소도 바뀝니다. 물론 리액트 기술을 사용하였기 때문에 가능한 일이지만, 실제로는 하나의 페이지로 만들어진 웹입니다. 싱글 페이지 애플리케이션(SPA)이라고 하죠.

SPA의 단점은 주소가 바뀌지 않는다는 것입니다. 초창기에는 주소 뒤에 #(해쉬) #!(해쉬뱅)을 붙이고 뒤에 하위 주소를 넣었습니다. www.zerocho.com/#!/category/javascript처럼요. 하지만 이 방식은 뭔가 찜찜합니다. #!이라는 주소에 무언가 의미가 있는 것도 아니고 이질적인 느낌이 듭니다. 또한 서버는 # 뒷 부분을 제대로 된 주소라고 생각하지 않습니다.

undefined

따라서 해쉬뱅 대신 브라우저에서 제공하는 주소 API를 사용해 주소를 바꾸게 되었습니다. 바로 History API입니다. 요즘 웬만한 SPA의 라우터들은 이 API를 사용하고 있습니다. IE도 10부터 가능합니다.

이 API는 기존 history 객체(window.history)를 그대로 활용합니다. 따라서 자바스크립트로 뒤로가기(history.back())와 앞으로 가기(history.forward()), 지정한 위치로 가기(history.go(인덱스))를 모두 사용할 수 있습니다. 하지만 SPA일 경우를 가정하고 있기 때문에 이번 시간에는 위 메소드는 사용하지 않습니다.

주소 내역은 하나의 목록입니다. 뒤로가기, 앞으로가기는 목록 안에서 이동하는 것입니다. 따라서 목록에 새로운 주소를 추가하면 페이지를 이동한 셈이 됩니다. 목록에 주소를 추가하기 위한 메소드가 HTML5에서 생겼습니다.

바로 history.pushState()와 history.replaceState()입니다. 예제를 보며 사용방법을 익혀봅시다. html 파일을 만들어 다음 코드를 입력하세요. 저는 일부러 book 폴더를 만든 후 그 안에 파일을 생성했습니다.

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8" />
    <title>History API</title>
</head>
<body>
<div id="state"></div>
<button id="pushState">pushState</button>
<button id="replaceState">replaceState</button>
<script>
  document.querySelector('#pushState').addEventListener('click', function () {
    history.pushState({ data: 'pushpush' }, 'title을 pushState로', '/pushpush')
  });
  document.querySelector('#replaceState').addEventListener('click', function () {
    history.replaceState({ data: 'replace' }, 'title을 replaceState로', '/replace');
  });
  window.addEventListener('popstate', function () {
    console.log('popstate', history.state);
    document.querySelector('#state').innerHTML = JSON.stringify(history.state);
  });
</script>
</body>
</html>

undefined

웹스톰을 통해 실행한 것이라 주소가 좀 지저분합니다. 아마 여러분은 그냥 /book/history.html일 것입니다. 

html에 두 개의 버튼이 있습니다. pushState와 replaceState인데요. pushState를 누르면 주소가 바뀝니다. 그리고 뒤로가기 버튼이 활성화됩니다. 페이지는 새로 갱신되지 않았는데 주소만 바뀐 효과가 나타난 것이죠.

undefined

코드를 보시면 pushState 버튼을 눌렀을 때 history.pushState({data:'pushpush'}, 'title을 pushState로', '/pushpush')하도록 되어있습니다. 첫 번째 인자는 바뀐 주소와 함께 저장할 데이터 객체이고, 두 번째 인자는 바꿀 제목, 세 번째 인자는 바꿀 주소입니다. 

주소와 함께 데이터도 저장할 수 있기 때문에 매우 유용합니다. 이 데이터에 바뀔 페이지의 정보들을 담아두고 클라이언트에서 정보를 활용해 새로운 페이지를 렌더링하면 됩니다. 정보는 history.state로 접근할 수 있습니다. 

두 번째 인자는 제목인데 브라우저에서 아직 제목 바꾸는 것까지는 구현하지 않았습니다. 그냥 빈 문자열을 넣어 두는 정도로 하시면 됩니다.

세 번째 인자는 바뀔 주소입니다. 위의 예시에서는 /pushpush를 주었기 때문에 절대 경로로 처리가 되었습니다. 만약 그냥 pushpush나 ./pushpush로 줬다면 상대경로로 처리가 되어 주소가 localhost:63342/book/pushpush가 되었을 것입니다.

뒤로 가기를 누르면 원래 주소로 돌아갑니다. 앞으로가기를 눌러서 /pushpush로 되돌아 갈 수도 있습니다.

원래 주소에서 replaceState를 눌러봅시다.

undefined

이번에는 뒤로가기가 활성화되지 않고 주소만 바꿉니다. pushState와의 차이점을 아시겠나요?

pushState는 주소 목록에 새로운 주소를 추가합니다. /book/history.html을 이전 주소로 두고, 새로운 주소로 /pushpush를 추가한 것입니다. 이전 주소가 남아있기 때문에 뒤로가기로 /book/history.html로 되돌아갈 수 있습니다.

하지만 replaceState는 이전 주소를 없애고 바꿀 주소를 넣습니다. /book/history.html이라는 주소 기록을 지우고 /replace를 추가하는 것입니다. 따라서 /book/history.html에 더는 접근할 수 없습니다.

pushState와 replaceState를 활용하여 프레임워크 없이 싱글 페이지 애플리케이션을 만들어보세요! 페이지 주소에 대한 데이터는 다시 말씀드리지만 history.state에 들어있기 때문에 언제든지 사용할 수 있습니다.

아, pushState와 replaceState로 주소를 바꾼 후, 뒤로가기나 앞으로가기를 했을 때 발생하는 이벤트가 있습니다. 바로 popstate 이벤트입니다. 예제처럼 윈도우에 이벤트 리스너를 연결해 두면 뒤로가기나 앞으로가기를 눌렀을 때 이벤트가 발생합니다. pushState를 여러 번 눌렀다가 뒤로가기를 해보면 #state에 history.state 정보가 뜹니다.

undefined

주의할 점은 pushState와 replaceState를 할 때는 이벤트가 발생하지 않는다는 것입니다. pushState 또는 replaceState를 한 후, 뒤로가기나 앞으로가기를 눌렀을 때만 발생합니다. popstate 이벤트 발생 후 history.state에 접근하면 이전 state를 가져올 수 있습니다. 따라서 이전 페이지도 그 정보들을 활용해 다시 렌더링할 수 있습니다.

History API, 별 거 아니죠? 다만 새로고침을 눌렀을 경우에는 없는 페이지라고 뜨기 때문에 이 부분은 서버사이드 렌더링으로 해결하셔야 합니다. SPA에서 주소를 자연스럽게 바꿀 수 있다는 것은 대단한 장점입니다. 물론 리액트 라우터나 앵귤러 라우터는 이를 이미 활용하고 있지만, 내부 원리를 알았다는 것에 의의를 두시면 됩니다.


출처 : https://www.zerocho.com/category/HTML/post/599d2fb635814200189fe1a7

반응형

+ Recent posts