코테에서 언어를 javascript로 선택하니 입력값은 알아서 입력해 주지만, 그걸 받아서 처리하는건 내 몫이다. 

 

정작 console.log(); 로 출력이나 자주 해봤지, cofirm()이나 prompt()를 제외하고

JS에서 입력받는 값을 컨트롤해 본 적이 없었다. 

 

프로그래머스처럼 간단히 핵심 로직만 구현할 수 있게 해주면 좋을텐데,

아쉬움으로 뒤로하고, Js환경에서 코테시 그 입력값을 받아 로직을 처리하기 위한 핵심 부분은 다음과 같다. 

 

아래 예제는 공백을 사이에 두고 두 숫자를 한 라인에 입력 받은 후, 그 합을 출력하는 예제다. 

const readline = require("readline");
const rl = readline.createInterface({
    input : process.stdin,
    output : process.stdout
});
    
let input = [];

rl.on('line', function(line){
	input = line.split(' ').map((number) => Number(number));
})
.on('close', function() {
	console.log(input[0] + input[1]);
	process.exit();
});

 

 

여러 줄을 입력받아 처리할 때는 다음과 같이 작성한다.

 

const readline = require("readline");
const rl = readline.createInterface({
	input : process.stdin,
    output : process.stdout
    });
    
let input = [];

rl.on('line', function(line){
    input.push(line);
})
.on('close', function() {
	// TODO input을 이용한 서비스 로직 작성
	process.exit();
});

 

 

 

1.1 HTTP (Hypertext Transfer Protocol)

전 세계의 웹 브라우저, 웹 서버 , 웹 어플리케이션은 모두 HTTP를 통해 서로 통신한다.

현대 인터넷의 '공용어'라고 볼 수 있다.

 

1.2 웹 클라이언트와 서버

웹 콘텐츠는 웹 서버에 존재하고,

웹 클라이언트는 원하는 웹 콘텐츠를 얻기위해 서버에게 HTTP요청을 보내고

서버는 HTTP 응답으로 반환함으로써 요청한 데이터를 제공한다.

 

1.3 리소스 

웹 서버는 웹 리소스를 관리하고 제공하며, 웹 리소스는 웹 콘텐츠의 원천이다.

리소스는 이미지나, 텍스트와 같은 정적 파일 뿐만아니라, 동적인 콘텐츠도 모두 리소스이다. 

예를들어 인터넷 검색 엔진 또한 리소스라고 할 수 있다.

 

 1.3.1 미디어 타입

미디어에 대한 타입 구분을 위해

MIME 타입이라는 (다목적인터넷 메일 확장: Multipurpose Internet Mail Extenshions) 데이터 포맷 라벨을 이용한다.

원래 예전에 서로 다른 메일 시스템 사이에서 메시지를 주고받을때 겪는 문제점 해결을 위해 나온 기술인데, 이메일에서 워낙 잘 동작했기에, HTTP 통신에서 미디어 타입 구분을 위해 채택되었다. 

 

슬래시(/)로 구분된 주 타입과 부 타입으로 구성된다. 

Content-type: image/jpeg

Content-type: image/png

Content-type: text/html 

 

 

 1.3.2 URI (Uniform Resource Identifier)

통합 자원 식별자. (인터넷 주소)

웹 서버의 리소스는 모두 이름을 갖고 있고, 클라이언트는 인터넷 주소를 통해 특정 리소스를 고유하게 식별하고 위치를 지정할 수 있다.

 URI에는 두 가지가 있는데 그것이, URL과 URN이다.

 

 1.3.3URL (Uniform Resource Locator) 

 통합 자원 지시자. 특정 서버의 리소스에 대한 구체적인 위치를 서술한다.

오늘날 대부분의 URI는 URL이다.

예를들어 http://www.yahoo.com/image/logo.gif  

 

스킴이라고 불리는 프로토콜(http://) 부분과 서버의 인터넷 주소(www.yahoo.com), 그리고 리소스를 가리키는 (image/logo.gif) 세가지 부분으로 구성된다. 

 

 1.3.4.URN (Uniform Resource Name)

 통합 자원 이름. 리소스에 대해 위치에 영향을 밪지 않는 유일무이한 이름 역할을 한다.  

위치 독립적이여서 위치를 바꾸더라도 정상적으로 동작한다. But, 아직 실험중이고 인프라가 충분하지 않아 널리 채택되지 않았다.

 

1.4 트랜잭션

 HTTP요청 명령과 HTTP 응답 결과로 구성된다.

 

 1.4.1 메서드

  모든 HTTP 요청 메시지는 한 개의 요청 메서드를 갖는다.

GET, POST, DELETE, PUT, HEAD 5가지가 있다.

  

 1.4.2 상태코드 

 모든 HTTP 응답은 상태코드와 함께 반환된다.

  200 정상, 4## 클라이언트 오류, 5## 서버 오류

 

1.5 메시지

HTTP요청과 응답 메시지의 구조는 크게 세가지로 나뉘어진다. 

 -시작줄 : 요청에 대한 내용이나, 응답인 경우 HTTP 응답 결과에 대한 상태코드를 담는다.

 - 헤더 : 헤더는 콜론(:)으로 구분되어 하나의 이름과 하나의 값으로 구성된다.요청에 대한 인코딩 정보나 응답시 미디어 타입에 대한 MIME 타입이 있다.

 - 본문 : 요청의 본문은 클라이언트로 부터 데이터를 실어보내며, 응답의 본문은 클라이언트로 데이터를 반환한다.

 

1.6 TCP 커넥션

 1.6.1 TCP/IP

HTTP는 어플리케이션 계층의 프로토콜이며, 전송과 네트워크 계층의 프로토콜은 TCP/IP이다.

TCP가 다음을 제공한다.

 - 오류 없는 데이터 전송

 - 순서에 맞는 데이터 전달 (항상 보낸 순서대로 도착)

 - 조각나지 않는 데이터 스트림(언제든 어떤 크기로든 보낼수 있다)

 

TCP/IP는 어떤 네트웤이나 하드웨어에 상관없이, 신뢰성있는 의사소통을 제공해주는 패킷 교환 네트워크 프로토콜의 집합이다. 

 

일단 TCP 커넥션이 맺어지면, 클라이언트와 서버 컴퓨터 간에 교환되는 메시지가 없어지거나 파괴되거나 순서가 뒤바뀌어 수신되는 일은 결코 없다.

 

1.7 IP주소, 포트번호

URL이 리소스에 대한 주소기 때문에, IP주소와 포트번호는 URL을 이용해서 알 수 있다. 

URL에 포트가 빠진 경우 기본값 80이라고 가정하면 되며, 호스트명(www.netscape.com)은 DNS에 의해 IP('207.200.83.29')로 변환될 수 있다.

 

1.8 웹의 구성요소

 프록시, 캐시, 게이트웨이, 터널, 에이전트

 

 

 

출처

도서 : HTTP 완벽 가이드 - 인사이트

 

- 의존성 주입(Dependency Injection) 이란

하나의 객체가 다른 객체에 의존성을 제공하는 기술을 말한다.

 

'의존성' 은

A가 작업을 하는데 B가 필요한 경우, A는 B에 의존한다고 말하며 이를 의존성을 갖는다고 할 수 있다.

 

- 의존성 주입 방법

Spring Framework 에서 제공하는 의존성 주입 방법에는 세가지가 있다. 

 1. 생성자

 2. 필드

 3. Setter

 

1. 생성자를 이용하는 방법.

@Controller
class OwnerController {
private OwnerRepository owners;

public OwnerControlelr(OwnerRepository owners) {
    this.owners = owners;
}
.
.
.
}

 

 

2. 필드 이용 방법

@Controller
class OwnerController {

@Autowired
private OwnerRepository owners;
.
.
.
}

 

3. Setter 이용 방법

@Controller
class OwnerController {

private OwnerRepository owners;

@Autowired
public void setOwners(OwnerRepository owners) {
    this.owners = owners;
}
.
.
.
}

 

@Autowired
는 생성자에도 사용할 수 있고, 필드, Setter에도 사용할 수 있다.

 

그러나 스프링 버전 4.3 부터는
어떠한 클래스에 생성자가 하나 뿐이고, 생성자로 주입받는 레퍼런스 변수들이 빈으로 등록되어 있다면
자동으로 주입받을 수 있도록 기능을 제공해주어 @Autowired 어노테이션이 생략 가능해졌다. 

 

**순환참조의 경우(A가 B를 참조하고, B가 A를 참조하는 경우)에는 생성자를 이용해 의존성을 주입하는 경우 오류가 발생한다. 따라서 이 때는 필드나, Setter를 이용하는데, 흔히 발생하지는 않지만, 가능성이 있는 케이스가 있으므로 알아두면 좋다.

 

 

 

- 참고

백기선님의 인프런 강좌 - 스프링 입문

 최근 서비스 업체들은  'MSA(마이크로서비스)'와 더 자주 '배포(Deployment)'하는 방식으로 변화하고 있는 추세다.

마이크로서비스 아키텍처로 앱을 만들면서 더욱 빠른 속도와 민첩성을 얻을 수 있게 되었고, 이러한 개발 속도의 증가는 는 이전에 비해 더 자주 '배포'가 일어날 수 밖에 없는 기반을 만들어 주었다.

 

이에 대표적인 배포 전략들에 대해 알아보겠다.

 

1. 롤링

 - 일반적으로 많이 이용되고 있는 배포 방식이다. 

 - 서버를 구 버전에서 새 버전으로 하나 씩 점진적으로 배포해 나아가는 방식이다.

 - 배포 중 서비스 중인 인스턴스의 수가 일시적으로 감소하므로 서버 처리 용량에 대한 고려가 필요하다.

2. 카나리

 - 일부 사용자 혹은 지정된 서버들에만 새 배전을 배포하여, 신 버전에 대한 검증 이후

 전체 사용자 또는 전 서버들에 새 버전을 모두 배포하는 방식이다. 

 

3. 블루-그린

  - 서비스 환경과 동일한 환경을 각각 준비해 놓은 상태에서, 

서로 다른 환경에 구 버전과 신 버전을 배포해 놓고, 이후 사용자의 트래픽을 일시에 구 버전에서 신 버전으로 변경시키는 배포 전략이다.

 

 - 빠른 롤백이 가능하고, 내부 트래픽인 경우 운영 서비스에 영향을 주지 않으면서 새버전에 대한 테스트를 진행해 볼 수 있다는 장점이 있는 반면 시스템 자원이 두 배로 필요하다.

4. A/B 테스팅

  카나리 배포 방법과 비슷한데, A/B테스팅의 초점은 신 버전에 대한 이용자의 반응을 측정 하는데에 있다. 

일부 사용자 혹은 서버들에만 신 버전을 배포하여 사용자의 반응을 보고 이후 전체 사용자나 전 서버들에 배포하는 방식이다.

 

'IT기술' 카테고리의 다른 글

마이크로서비스 아키텍처(Microservice Architecture)  (0) 2020.04.23
React 란?  (0) 2020.01.19
REST API  (0) 2020.01.19

- 인터셉터(Interceptor) 란 ?


컨트롤러에 들어오는 요청 HttpRequest와 컨트롤러가 응답하는 HttpResponse를 가로채는 역할을 한다. 
예를들어 관리자만 접근할 수 있는 페이지의 경우, 페이지에 접근하기 전에 관리자 인증을 유도하는 용도로 활용할 수 있다. 
주로 로그인과 같은 권한 체크에 유용하게 사용된다. 

이와 유사한 역할을 하는 것이 'Filter'인데 Filter와 Interceptor는 비슷한 역할을 하지만 호출 시점에 차이가 있다. 

1. 호출 시점. 
Filter는 DispatcherServlet 이 실행되기 전, Interceptor는 DispatcherServlet이 실행된 후에 호출된다. 

2. 설정 위치
Filter는 web.xml에서 설정하고, Interceptor는 spring-servlet.xml에서 설정한다. 

 

Interceptor 구현 방법은 2가지가 있는데, 하나는 HandlerInterceptor인터페이스를 구현하는 방법과 
다른 하나는 HandlerInterceptorAdapter 클래스를 상속 받는 방법이 있다. 

메서드는 Controller의 실행 직전, 직후에 실행되는 preHandle()과 postHandle()이 있고, 
뷰를 렌더링 한 후의 콜백 핸들러 실행 결과에 따라 호출되는 afterCompletion()이 있다. 

'Java' 카테고리의 다른 글

자바 람다(Lamda) 기초  (0) 2021.02.13
자바 스트림(Stream)  (0) 2021.02.09
자바 HashMap 탐색 entrySet(), keySet(), Iterator()  (0) 2021.02.03
자바 Primitive Type과 Reference Type  (0) 2020.02.26
자바 [getOrDefault, putIfAbsent]  (0) 2020.01.22

 - 람다(Lamdda) 란 ? 


자바 8부터 등장하는 개념으로, 
기존에 메소드 사용을 위해서는 클래스를 먼저 만들고, 클래스 안에 메소드를 정의해야만 객체화 이후 사용이 가능했다.


하지만, 람다는 별도의 정의없이 보다 선언적인 메소드 사용을 가능하게 만드는 표현식이다.

람다의 핵심은 ( 파라미터 -> {실행코드;} );

메소드와 동일한 기능을 하지만 정의하지 않고, 바로 사용 가능한 것이 핵심이다. 

대부분 스트림(Stream)이나 ForEach 등을 사용할 때 주로 사용하며 아무 곳에서나 사용은 불가능하다.

아래는 ForEach문에 사용되는 Lambda의 예제로 파라미터가 1개 일 경우와 2개일 경우다.

 

'Java' 카테고리의 다른 글

자바 인터셉터(Interceptor)  (0) 2021.02.14
자바 스트림(Stream)  (0) 2021.02.09
자바 HashMap 탐색 entrySet(), keySet(), Iterator()  (0) 2021.02.03
자바 Primitive Type과 Reference Type  (0) 2020.02.26
자바 [getOrDefault, putIfAbsent]  (0) 2020.01.22

- 스트림(Stream) 이란?

 

자바8 이전에는 배열이나 컬렉션 안의 각 요소들에 접근하기 위해 for나 Iterator 등을 사용했는데,

자바8 부터는 Stream을 이용해서 보다 간결하고 가독성 높은 코드로 각 요소들에 접근하고, 컨트롤하는 것이 가능해졌다.

또 하나의 장점은 병렬처리가 가능하다는 점으로, 쓰레드를 이용해 많은 요소들을 빠르게 처리할 수 있다.

 

스트림은 선언, 가공, 반환 세 부분으로 이뤄진다. 

// 스트림 선언 방법
Stream<타입> stream명 = Arrays.stream(배열명);
Stream<타입> stream명 = 리스트명.stream();
Stream<타입> stream명 = Stream.of('값', '값'....);

 

가공부에서는 제공하는 메소드들을 이용해 요소들을 원하는 형태로 가공하며,

반환부를 통해 원하는 타입으로 다시 반환 받을 수 있다. 

 

다음은 리스트 'langs' 를 sorted() 메소드를 이용해 정렬(가공) 후, 다시 리스트로 반환하는 코드이다.

langs.stream().sorted(Comparator.reverseOrder()).collect(Collectors.toList());

 

장점으로는 사용하기 편하고, 코드가 짧아지며 그러므로 가독성이 높아진다는 것. 
단점으로는 디버깅이 어려움. 그리고 한번 사용하면 close되기 때문에 재활용이 불가능하다는 단점이 있다. 

스트림(Stream)을 이용하면 배열이나 컬렉션(List, Map, Set)등을 사용해 원하는 값을 얻고자 할 경우,
For문의 도배를 줄일 수 있고, 이미 정의되어 있는 많은 메소드들을 이용하여 원하는 값을 쉽게 가져올 수 있다. 
다만, 디버깅이 어렵다는 단점이 있다. 

디버깅이 어려운 이유는 스트림은 한번에 모든 것이 수행되기 때문에, 에러나기 직전에 디버깅을 거는것이 불가능하다. 
따라서 스트림 안에서 에러 발생 시, 모두 분해 후 재 조립하는 과정을 거쳐야 한다. 

 

 

- 제공하는 함수들

filter 
sorted
allMatch : return boolean
anyMatch : return boolean
noneMatch : return boolean
max(Comparator.comparing(객체::값)) : return Optionnal<객체>
min(Comparator.comparing(객체::값)) : return Optionnal<객체>
collect(Collectors.groupingBy(객체::값)) : return Map<그룹핑 값, List<객체>>

.

.

 

예제 )

public static void main (String[] args) {
	List<String> langs = Arrays.asList("Java", "Scala", "React", "Swift", "Angular");
		
	// forEach() 순차 접근
	langs.stream().forEach(System.out::println);
		
	// sorted() 정렬
	langs = langs.stream().sorted().collect(Collectors.toList());
		
	// sorted(Comparator.reverseOrder()) 역순 정렬
	langs = langs.stream().sorted(Comparator.reverseOrder()).collect(Collectors.toList());
		
	// filter( input Param -> method ) 필터
	langs = langs.stream().filter( name -> name.contains("a")).collect(Collectors.toList());
		
		
	List<People> peoples = People.getPeopleList();
/* peoples
People[name:홍길동, age:17, gender:1]
People[name:홍길자, age:18, gender:2]
People[name:홍길남, age:13, gender:1]
People[name:홍길순, age:15, gender:2] */
		
		
	// 조건이 모두 match 하는지 (return : boolean으로 anyMatch, noneMatch도 있음.)
	peoples.stream().allMatch( person -> person.getName().contains("홍"));

	// 특정 속성 값에 대해 최대값을 가지는 요소 구하기.
	Optional<People> maxPeople = peoples.stream().max(Comparator.comparing(People::getAge));
	if(maxPeople.isPresent()) {
		System.out.println("나이가 많은 사람은?");
		System.out.println(maxPeople.toString()); // Optional[People[name:홍길자, age:18, gender:2]]
	}
    
    // 그룹핑
    Map<Integer, List<People>> groupByGender = People.getPeopleList().stream().collect(Collectors.groupingBy(People::getGender));
    System.out.println("남/여 목록");
    groupByGender.forEach((gender, peopleList) -> {
    System.out.println(gender);
    peopleList.forEach(System.out::println);
    });
	
/* 남/여 목록
1
People[name:홍길동, age:17, gender:1]
People[name:홍길남, age:13, gender:1]
2
People[name:홍길자, age:18, gender:2]
People[name:홍길순, age:15, gender:2] */
}

 

import java.util.*;

class Solution {
    public boolean solution(String[] phone_book) {
        
        Map<String, String> hm = new HashMap<String, String>();
        
        for(int i=0; i<phone_book.length-1; i++){
            for(int j=i+1; j<phone_book.length; j++){
                if(phone_book[i].startsWith(phone_book[j])) return false;
                if(phone_book[j].startsWith(phone_book[i])) return false;
            }
        }
        return true;
    }
}

 

+ Recent posts