intellij에서 실행 옵션 설정하기

intellij 상에서 spring 프로젝트를 실행할 때, 따로 옵션을 설정해주어야 할 때가 있다.

ex) 개발 시 설정파일을 바꾸어주어야 할 때

  1. 오른쪽 상단의 실행 버튼 왼쪽에 드롭다운 박스를 눌러 Edit Configuration 을 눌러준다
  1. spring boot 섹션에서 밑에있는 Override parameters에 설정해주고자 하는 옵션의 이름과 값을 적어주면 끝!

위의 이미지와 같이 옵션을 주었을 때,

1
$ java -jar app.jar --spring.config.name=application-dev

을 실행한것과 같다

Proxy에 대하여

Proxy

다른사람을 대신/대리 하여 무엇인가를 하는 것 (중개)을 뜻한다

이런 의미에서 프록시 서버란 다른 서버가 하는 일을 대신하여 처리해주는 서버를 지칭하는 말이다

캐시/보안/트래픽 분산 등 여러 장점을 가질 수 있다.

프록시의 종류로는 포워드 프록시(Forward Proxy)와 리버스 프록시(Reverse Proxy)가 있는데,
네트워크 구조의 어떠한 위치에서 역할을 수행하는지에 따라 이름이 바뀐다.

네트워크 통신 구조를 크게 다음과 같이 정의하겠다.

Client(사용자) - Internet(인터넷) - Server(서버)

포워드 프록시(Forward Proxy)

포워드 프록시는, 사용자와 인터넷 사이에 위치해 프록시의 역할을 하는 컴퓨터를 Forward Proxy라고 한다.

특징

캐시

사용자가 요청한 내용의 데이터를 저장하고 있다가. 이후에 똑같은 요청이 오면, 저장하고 있던 값을 응답으로 주는 것

  • 전송 시간 절약
  • 불필요한 외부 전송이 필요 없음
  • 외부 요청 감소 -> 네트워크의 병목현상 방지

익명성

사용자가 보낸 요청을 감춘다

사용자가 서버로 요청을 할 때, 프록시 서버에 대신해서 요청을 하고 응답을 받아달라고 하는 것이다

그렇기 때문에 서버는 Proxy의 존재는 알지라도, 실질적으로 데이터를 요청하는 사용자의 정보를 알지 못한다.

이러한 이유로 해커들이 자신들의 존재를 숨기기 위해 프록시서버를 이용하기도 한다

리버스 프록시(Reverse Proxy)

리버스 프록시는, 서버와 인터넷 사이에 위치해 프록시의 역할을 하는 컴퓨터를 Reverse Proxy라고 한다.

특징

캐시

Forwrad Proxy의 캐시와 동일한 기능을 한다. 사용자가 요청한 데이터를 저장하고 있다가. 실질적인 데이터를 가진 서버에게 요청하지 않고, 저장하고 있던 값을 응답합니다.

보안

Forward Proxy와 다르게 서버의 정보를 감춥니다.

사용자는 서버에 요청을 한다고 생각하지만, 실제로는 Reverse Proxy가 서버의 역할을 ‘대신’해 사용자의 요청을 받고, 받은 요청의 결과를 사용자에게 응답으로 전달합니다

즉, 사용자는 실질적인 서버의 역할을 하는 컴퓨터의 정보는 알지 못하고, 오로지 Proxy Server의 정보만 알게됩니다.

로드밸런싱(Load Balancing; 부하 분산)

로드밸런스 Wiki

둘 이상의 서버 컴퓨터의 앞에서 사용자의 요청을 받아, 서버의 상태에 맞게 요청을 분산시켜주는 역할을 뜻합니다.

대부분 서버의 상태에 따라 최상의 상태인 서버로 요청을 전달해주기 때문에,
로드밸런싱이 적용된 서비싀는사용자가 몰려도 균일한 서비스를 받을 수 있다는 특징이 있습니다.

대표적인 로드밸런싱 알고리즘으로 라운드로빈(Round Robin), 최소 연결(Least Connection), 최소 응답시간(Leas Response Time) 방식이 있습니다.

참조(Reference)

우아한Tech 유튜브 채널 제이미님의 발표

spring-swagger2

spring-swagger2

Swagger?

스프링 프레임워크 상에 작성한 API를 쉽게 문서화 시켜주는 라이브러리 입니다.

Swagger의 사용

Swagger 설정

Swagger를 사용하기 위해서는 먼저 swagger 라이브러리를 추가해주어야 합니다.

본인의 프로젝트 설정에 맞춰 등록하시면 됩니다.

mvn repository에 들어가서 해당하는 라이브러를 찾습니다.

  • springfox swagger2
  • springfox swagger-ui
1
2
3
4
5
// build.gradle
// springfox-swager2
compile group: 'io.springfox', name: 'springfox-swagger2', version: '3.0.0'
// springfox-swager-ui
compile group: 'io.springfox', name: 'springfox-swagger-ui', version: '3.0.0'
1
2
3
4
5
6
7
8
9
10
11
12
13
<!-- pom.xml-->
<!-- springfox-swagger2-->
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<version>3.0.0</version>
</dependency>
<!-- springfox-swager-ui-->
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
<version>3.0.0</version>
</dependency>

의존성을 추가하였으면 Swagger 라이브러리의 설정을 위한 클래스를 생성합니다

설정 클래스에 들어가야될 필수 어노테이션으로 @Configuration@EnableSwagger2이 필요합니다

1
2
3
4
5
@Configuration
@EnableSwagger2
public class SwaggerConfig{
// ...
}

이 후, 2개의 메서드를 작성해주어야 합니다.

  • ApiInfo 타입을 반환하는 apiInfo() 메서드
  • Docket 타입을 반환하는 api() 메서드
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
@Configuration
@EnableSwagger2
public class SwaggerConfig{
private ApiInfo apiInfo(){
return new ApiInfoBuilder()
.title("API의 타이틀 정보")
.version("API 버전 정보")
.description("API에 대한 설명")
.build();
}

public Docket api(){
return new Docket(DocumentationType.SWAGGER_2)
.grouName("My-Group")
.apiInfo(apiInfo()) // 위에서 작성한 apiInfo 메서드의 리턴값을 사용
.select()
.apis(RequestHandlerSelectors.basePackage("com.example.board.Controller"))
.paths(PatheSelectors.any())
.build();
}
}

apiInfo 메서드에서 반환하는 값은, Swagger에서 메인으로 보여질 정보를 설정한 객체를 반환합니다.

api 메서드에서는

  • api 그룹 이름
  • 이동 경로
  • 보여질 api

등이 설정됩니다

Swagger는 설정 클래스만 만든다고 완성이 되는 것이 아니라, 작성한 api 클래스에서 swagger를 적용하겠다는 어노테이션을 작성해주어야 합니다.

어노테이션의 이름은 @ApiOperation()으로 괄호에 속성값들이 들어가게 됩니다.

1
2
3
4
5
6
// Some Controller
@GETMappingi("/board")
@ApiOperation(value = "간단한 설명을 적어줍니다", response = BoardDTO.class)
public ResponseEntity<Map<String, Object>> getBoardList(){
// get boardlist
}

@ApiOperation()어노테이션을 swagger에서 보여줄 api에 작성해주면 사용하기 위한 설정은 끝이 납니다.

기본적으로 속성은

  • value : 해당 메서드(api 호출시 반응하는)에 대한 간단한 설명
  • response : 성공적으로 메서드가 작동 시 반환하는 클래스의 타입

두가지는 적어주는 것이 좋습니다.

vlaue 옵션 적용 결과

reponse 옵션 적용 결과

위의 이미지는 value 속성을 설정해주었을 때,

아래 이미지는 reponse 속성을 설정해주었을 때 이미지와 같이 보이게 됩니다

Swagger 페이지 접속

http://ip주소/swagger-ui.html

위의 주소로 접속하면 위에서 설정한 값들이 보이게 됩니다

swagger는 보이는 것 뿐만 아니라, 클릭으로 기능이 제대로 작동하는지 까지 테스트 할 수 있습니다.

마크다운 문서 내부에 링크 적용하기

마크다운 문서를 이용하면서 외부링크를 연결하는것이 아닌, 문서 내부의 특정 헤더에 연결을 하고싶은 경우가 있다.

마크다운 문서 내부의 헤드에 링크를 연결하고 싶은경우는 다음과 같이 사용하면 된다

1
[보여지는 내용](#연결할-헤드의-내용)

예시는 다음과 같다

1
2
3
4
5
6
[띄어쓰기는 '-'로](#마크다운-내부에서-헤드-링크)
[영어는 소문자로](#use-link-in-markdown-document)


## 마크다운 내부에서 헤드 링크
#### Use link in Markdown document

예시와 같이, 띄어쓰기는 ‘-‘로 대치를 하고, 영문의 경우엔 전부 소문자를 써야한다
또한 몇단계의 헤드던 링크는 헤더의 레벨에 상관 없이 하나의 #만 사용하여 링크를 건다

결과물은 아래와 같이 나오게된다

띄어쓰기는 ‘-‘로

영어는 소문자로


















마크다운 내부에서 헤드 링크







NOTICE

현재, 프레임 워크 또는 테마의 문제로 마지막 헤드에는 링크가 걸리지 않는 문제가 있습니다.

Lombok 플러그인

Lombok

자바에서 Model(DTO, VO, Domain) 오브젝트를 만들때, getter/setter 등 반복적으로 만드는 코드를 어노테이션의 선언을 통해 간단하게 해결해주는 라이브러리

MIT 라이센스(MIT LICENSE)를 따른다

Lombok 사용

라이브러리 의존성 추가

기본적으로 mvn repository 에서 제공하는 사용법을 따르면 편하다

Maven을 사용하는 경우

의존성 추가를 위해 다음 내용을 pom.xml에 추가

1
2
3
4
5
6
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.12</version>
<scope>provided</scope>
</dependency>

Gradle을 사용하는 경우

build.gradle에 의존성을 추가

1
providedCompile group: 'org.projectlombok', name: 'lombok', version: '1.18.12'

Model클래스에 어노테이션 선언

어노테이션의 종류

  • @Data : Data어노테이션은 다음의 어노테이션들 모두 포함한다

    • @ToString : 모든 필드에 대한 toString() 메서드 생성
    • @EqualsAndHashCode : equals와 hashcode 메서드 생성
    • @Getter : 모든 필드에 대한 getter생성
    • @Setter : final로 선언된 필드들에 대하여 setter를 생성
    • @RequiredArgsConstructor : final로 선언된 필드를 인자로 갖는 생성자를 생성한다
  • @NoArgsConstructor : 기본 생성자(인자를 갖지 않는) 생성

  • @AllArgsConstructor : 모든 필드를 인자로 갖는 생성자 생성

  • @builder : 객체의 생성을 도와주는 메서드를 생성 Builder 어노테이션 사용법

  • @NonNull : 객체 생성시 해당 필드의 null체크를 한다. 해당 필드가 null로 넘어오면, NullPointerException 예외를 발생시킨다

Builder 어노테이션의 사용법

1
2
3
4
5
6
7
// Model class
@Builder
public class Member{
private int id;
private String name;
private String password;
}

위와 같이 선언된 모델클래스의 객체를 생성할 때,

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class MemberController{
// another methods ...

@GetMapping
public void createMember(@RequestBody MemberDTO dto){
Member member = Member.builder()
.id(dto.getId())
.name(dto.getName())
.password(dto.getPassword())
.build();
}

// another methods ...
}

References

Project Lombok 공식 홈페이지

갓대희님의 티스토리 블로그

Vue EventBus 사용

EventBus 컴포넌트 생성

EventBus.js로 Event Bus를 담당할 컴포넌트를 생성한다

1
2
3
4
5
6
// @/utils/EventBus.js
import Vue from 'vue';

const eventbus = new Vue();

export default eventbus;

이렇게 파일을 생성하면 기본적인 준비는 끝

발행

$emit() 을 이용해 이벤트를 발행할 수 있다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// 이벤트를 발행할 Vue 컴포넌트
// Emit.vue
<template>
<Button @click="emitEvent">
이벤트 발행
</Button>
</template>
<script>
import Eventbus from '@/utils/EventBus'
export default{
methods:{
emitEvent(){
// 발행할 이벤트의 이름과 함께, 넘겨주소 싶다면 변수를 추가해줄 수 있다.
Eventbus.$emit('myEvent', '변수를 넘겨줄께요');
}
}
}
</script>

위의 코드에서는 myEvent라는 이벤트 이름과 함께, ‘변수를 넘겨줄께요’라는 String 변수를 인자로 이벤트를 발행하였다

구독

이벤트의 구독은 $on 을 통해 이벤트 구독할 수 있다.

더해서, vue의 template에서 @myEvent 처럼, 클릭이벤트를 등록하듯이 이벤트를 등록할 수 있다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
// 이벤트를 구독할 Vue 컴포넌트
// Receive.vue
<template>
<div>
<h1>
{{receive}}
</h1>
</div>
</template>
<script>
import Eventbus from '@/utils/EventBus'
export default{
data(){
return {
receive:''
}
},
created(){
EventBus.$on('myEvent', (arg)=>{
this.receive = arg;
});
}
}
</script>

Emit.vue 에서 ‘이벤트 발행’ 버튼을 클릭해 이벤트를 발행한 후,

이벤트를 구독하는 컴포넌트인 Receive.vue 컴포넌트를 실행하게 되면, created hook에서 이벤트를 구독하고 receive 변수에 넘겨주었던 String 인자가 할당되어, 화면에 표시된다

삭제

이벤트의 삭제는 $off를 이용한다.

위의 예제에서, 컴포넌트가 삭제될 때 발행한 이벤트를 삭제하고 싶다면

1
2
3
4
5
<script>
beforeDestory(){
EventBus.$off('myEvent');
}
</script>

이벤트가 계속해서 남아있는게 싫다면, 이벤트를 구독 후 삭제한다

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<script>
//...
methods:{
eventHandler(){
// 이벤트 구독
EventBus.$on('myEvent', (arg)=>{
this.receive = arg;
});
// 이벤트 삭제
EventBus.$off('myEvent');
}
}
//...
</script>

리눅스의 퍼미션과 설정 방법

리눅스 파일 정보 보기

리눅스를 기반으로 하는 운영체제에서는 ls(list) 명령어가 있습니다.

ls명령어에 -al 옵션을 주어 ls -al 명령어를 이용하면 파일의 해당 디렉토리에 존재하는 파일들의 상세정보를 볼 수 있습니다

drwxr-xr-x 2 root root 4096 Apr 22 16:59 my-file

파일type 퍼미션 링크수 소유자 소유그룹 용량 생성날짜 파일이름

  • 파일 Type

    • d : directory
    • l : 링크 파일
    • - : 일반 파일
  • 퍼미션 : 해당 파일 or 디렉토리에 어떠한 퍼미션이 부여되어 있는지 표시

  • 링크 수 : 해당 파일이 링크된 수 (링크 : windows운영체제의 바로가기와 같음)

  • 소유자 : 해당 파일의 소유자 이름

  • 소유 그룹 : 해당 파일을 소유한 그룹의 이름. 기본값으로 소유자가 속한 그룹으로 지정된다

  • 용량 : 파일의 용량

  • 생성 날짜 : 파일이 생성된 날짜

  • 파일이름 : 파일의 이름

Permission

파일의 권한 등을 설정해, 허가되지 않은 사용자가 읽거나 수정하지 못하도록 한다

퍼미션의 종류

  • 읽기(r : Read) : 읽기권한
  • 쓰기(w : Write) : 쓰기권한
  • 실행(x : eXecute) : 실행권한

퍼미션의 사용자 설정

  • 소유자 : 파일 소유자에 대한 퍼미션
  • 그룹 : 파일의 소유그룹에 대한 퍼미션
  • 공개 : 모든 사용자들에 대한 퍼미션

소유자 - 그룹 - 공개 순으로 rwx가 반복되어 나타난다

즉, rwx가 한묶음로 3개가 나타나며, 이는 각각 소유자, 그룹, 공개에 대한 파일권한이 된다

Permission 변경

리눅스에 기반 운영체제에서는 chmod 명령어를 이용해 파일의 permission을 변경할 수 있다

1
chmod [변경할 퍼미션의 값] [변경할 파일]

퍼미션의 값은 다음과 같이 나타낸다

  • 읽기(r) : 4
  • 쓰기(w) : 2
  • 실행(x) : 1

제일 오른쪽 자리인 실행 권한 자리부터 2^0, 2^1, 2^2 을 나타낸다

이를 합산하여, 각 사용자에 맞는 권한을 연속해서 적어주면 된다

예를 들어, MyProgram.java를 소유자에 모두 허용( rwx ), 그룹과 공개에는 읽기와 실행만 허용(r-x) 하고싶다면

  • rwx : 4 + 2 + 1 = 7
  • r-x : 4 + 0 + 1 = 5

이므로, 소유자-소유 그룹-공개 순으로 755를 권한으로 주면 된다

완성된 명령어는 다음과 같다

1
chmod 755 MyProgram.java

chmod에는 -R 옵션이 있는데, 해당 옵션은 recursive 즉, 지정한 파일부터 하위 폴더 및 파일까지 모두 권한을 변경하는 옵션이다

파일의 소유자 변경하기

소유자 변경은 chown 명령어를 통해 할 수 있다

1
chown [변경할 소유자] [변경할 파일]
1
chown secondUser MyProgram.java

또한, 소유자에는 소유그룹을 넣어줄 수 도 있다.

1
chown anotherUserGroup MyProgram.java

위와같이 명령어를 사용한다면, MyProgram.java의 소유권은 anotherUserGroup의 소유가 된다.

Reference

conory님의 블로그

JAVA 해싱 알고리즘 사용하기

해싱알고리즘

해싱알고리즘은 해시 함수를 기반으로 하는 암호화 알고리즘 중 하나입니다.

해싱 알고리즘이 암호화에 사용되는 이유는 해시함수의 특성에서 비롯됩니다.

해시함수 구현

Java에서는 기본적으로 해시 알고리즘을 사용하는 라이브러리를 제공하고 있습니다

java.security.MessageDigest에 해당 라이브러리가 존재하며, 이를 이용하여 문자열에 해시 처리가 가능합니다.

MessageDigest의 문서

MessageDigest에서는 MD5, SHA-1, SHA-256을 사용하고 있으며, SHA-1의 사용은 권장하지 않으므로

1
2
3
4
5
6
7
8
/**
* 가장 기본적인 형태의 해시함수 구현
*/
public byte[] hasing(String src) throws NoSuchAlgorithmException {
MessageDigest md = MessageDigest.getInstance("SHA-256"); // 해시 알고리즘에서 사용할 알고리즘의 종류를 적어준다.
md.update(msg.getBytes());
return md.digest();
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
/**
* 위와 형태가 비슷하지만 암호화의 결과물로 나온 바이트 타입의 배열을 16진수로 바꾸어 알아보기 힘들게 한다
*/
public String hasing(String src) throws NoSuchAlgorithmException {
MessageDigest md = MessageDigest.getInstance("SHA-256");
md.update(msg.getBytes());
StringBuilder sb = new StringBuilder();
for(byte b : md.digest()){
// 바이트를 2자리의 16진수로 바꾸는데, 남는자리가 생긴다면 0을 추가한다
sb.append(String.format("%02x", b));
}

return sb.toString();
}

Floyd-Warshall Algorithm, 플로이드-와샬

요약

  • A지점에서 B지점으로 가는 경로가 존재하고, A->K && K->B 가 가능한 K지점이 존재할 때, 둘 중 적은 비용으로 이동이 가능한 경로를 찾는 알고리즘
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
public class Floyd_Warshall{

static int INF = Integer.MaxValue;
static int N;
static int[][] map;

public static void main(String[] args){
init();
}

public static void flo_war(){
for(int k = 0; k < N; k++){
for(int i = 0; i < N; i++){
for(int j = 0; j < N; j++){
if( i != j ){
// map[i][j] 는 현재까지 찾은 i에서 j로가는 가장 적은 비용
map[i][j] = Integer.min(map[i][j], map[i][k] + map[j][k]);
}
}
}
}
}

public static void init(){
Scanner sc = new Scanner(System.in);
N = sc.nextInt();
map = new int[N][N];
for(int i = 0; i < N; i++){
for(int j = 0; j < M; j++){
map[i][j] = sc.nextInt();
// 자기 자신에게 돌아오는 길을 없음을 나타낸다
if(map[i][j] == 0) map[i][j] = INF;
if(i==j) map[i][j] = 0;
}
}
}

}

설명

다중 출발점에서 다중 도착점으로 가는 최소시간(거리)를 구하는 알고리즘으로
O(n^3)의 시간복잡도를 갖는다
위와 같은 시간복잡도를 갖는 이유는 출발점, 도착점에 대해 갈 수 있는 모든 다른점에 대해 최솟값을 찾기 때문이다
그렇기 때문에, 알고리즘의 작동만 이해한다면 매우 간단한 수준의 알고리즘이다.

Spring Bean

Spring Bean

빈 (Bean)

Spring IoC 컨테이너가 관리하는 자바 객체를 빈(Bean)이라 한다.

개발자가 new 연산자로 생성하는 객체는 빈이라고 할 수 없다.

Spring IoC 컨테이너에 빈을 등록하는 법

방법은 다양하지만 크게 두가지 방법이 있다.

  1. Component Scanning
  2. 빈 설정파일에 직접 빈을 등록

Component Scan

@ComponentScan 어노테이션과 @Component 어노테이션을 사용해서 빈을 등록하는 방법

SpringBoot 프로젝트 생성시 기본적으로 만들어지는 xxxApplication 클래스에 선언된 @SpringBootApplication 어노테이션을 보면, @ComponentScan어노테이션이 내부에 선언되어 있다.
그렇기 때문에, application 실행 시 이 클래스가 있는 패키지와 모든 하위패키지를 검사해 @Component 어노테이션을 사용하는 클래스를 찾고, 해당 클래스의 객체를 생성해 컨테이너의 빈에 등록한다

@ComponentScan

어느 지점부터 컴포넌트를 찾을지 알려주는 역할
해당 어노테이션이 선언되어있는 클래스의 패키지에서부터 모든 하위 패키지의 클래스를 찾아보며 @Component 또는 이를 사용하는 다른 어토네이션이 붙은 클래스를 찾는다

@Component어노테이션을 사용하는 어노테이션

  • @Controller
  • @Service
  • @Repository

@Component

찾아서 빈으로 등록할 클래스를 의미

1
2
3
4
@Component
public class MemberController{
// do something ...
}

빈 설정파일에 직접 빈을 등록

빈 설정파일은 xml과 자바 설정파일로 작성할 수 있으며, 자바 설정파일을 많이 사용한다

자바 설정파일은 자바 클래스를 생성해 작성이 가능하며, xxxCongifuration과 같이 명명하고, 클래스에 @Configuration 어노테이션을 선언 한 다음, 내부에 @Bean 어노테이션을 사용해 빈(Bean)을 정의한다

1
2
3
4
5
6
7
8
@Configuration
public class MemberConfiguration {
@Bean
public MemberController memberController(){
// 리턴되는 객체가 IoC 컨테이너에 빈으로 등록된다
return new MemberController();
}
}

@Configuration 어노테이션 또한 @Component를 사용하기 때문에 @ComponentScan의 스캔 대상이 되고, 빈 설정파일이 읽힐 때 그안에 정의한 빈들이 IoC컨테이너에 등록이 된다