JDBC는 java에서 Java.sql패키지에 내장되어 있는 DB 프로그래밍을 하기 위한 API이다. JDBC는 Java Application으로부터 사용되는 JDBC Driver Manager와 DBMS에 의존하는 JDBC Driver를 분리함으로써 DBMS에 의존하지 않고 개발이 가능하다는 장점이 있다. MySQL, Oracel 등 사용하는 DB의 Driver를 설치한 뒤 JDBC Driver Manager에 등록하면 Application에서 수행되는 SQL형태의 Query를 Driver가 DBMS가 이해할 수 있는 Query로 변환하여 전달한다. JDBC로 특정 쿼리문이 수행되기까지의 과정이 있다. 1. JDBC Driver 로드 2. DB 연결 3. Create a statement 4. 쿼리 처..
ORM ORM에 들어가기 앞서, Persistence 속성에 대해 먼저 알아보자. 영속성(Persistence) 특성은 프로그램이 종료되더라도 사라지지않는 비휘발성 데이터라는 특성을 말한다. 만약, 영속성 특성이 없는 데이터(휘발성)는 메모리상에서만 존재하기 때문에 프로그램이 종료되면 모두 날라간다. 1) Object Persistence(영구적인 객체) 메모리 상의 데이터를 file system, RDB(관계형 데이터베이스) or 객체 DB를 활용하여 영구적으로 저장(영속성) - java에서는 JDBC사용 - Spring JDBC - Hibernate, Mybatis 등의 프레임워크 이용 2) Persistence Layer 프로그램 상의 아키텍처에서 데이터에 영속성을 부여하는 계층이다. - JDBC를..
QuerySQL은 [SELECT * FROM TABLE;] 과 같은 쿼리를 java코드로 구현할 수 있는 기술이다. 복잡한 쿼리들도 구현이 가능한데, Spring Data JPA에서는 그것이 힘들었다. 그리고 java코드로 구현하기 때문에 컴파일 시 java코드로 구현한 쿼리에 대한 오류를 사전에 해소할 수 있다. 아래는 QueryDSL을 사용하기 위해 build.gradle을 세팅해준 것이다. //queryDSL이라고 되어 있는 부분이 해당한다. // queryDSL buildscript { ext { queryDslVersion = "5.0.0" } } plugins { id 'org.springframework.boot' version '2.6.6' id 'io.spring.dependency-ma..
h2는 java기반의 오픈소스 RDBMS이다. 가볍게 사용할 수 있기 때문에 개발 단계의 테스트 db로서 많이 이용된다고 한다. h2 설치파일을 다운받아서 하는 방법도 있지만, 나는 코드상으로만 이용하고자 한다. builc.gradle에 아래 추가 dependencies { // jdbc implementation 'org.springframework.boot:spring-boot-starter-jdbc' // jpa implementation 'org.springframework.boot:spring-boot-starter-data-jpa' // spring boot implementation 'org.springframework.boot:spring-boot-starter-web' implementa..
oidc는 OpenID Connect의 약자로, OAuth2.0기반으로 사용자에 대한 인증을 처리하는 프로토콜이다. 인증/인가의 개념에서 "인증"에 집중된다는 것이 기존의 OAuth2.0과의 차이점이라고 볼 수 있다. oidc는 OAuth2.0기반이기 때문에 비슷하게 처리가 되는데, 여기서 접속을 위한 토큰을 받을 때 id_token을 추가로 전달받는다. (이때 받은 id_token을 활용) 한 예로, OAuth2.0에서 토큰을 요청할 때 필요한 정보를 명시를 하는데, 이러한 정보들이 응답으로 받을 id_token안에 포함되어서 전달되는 시스템도 존재한다. 그렇기에, 단순히 유저 인증만을 하거나 정보들을 알고자 하는 설계라면 oidc사용을 하는 것이 좋다.
Docker(도커)는 컨테이너 기반의 오픈소스 가상화 플랫폼이다. 컨테이너는 해운산업의 혁명적인 운송방식으로, 각 컨테이너들에 다양한 화물을 넣을 수 있으며 규격화 되어 있다. 이것을 IT적으로 표준 패키징과 배포 형식으로 생각해도 된다. 컨테이너를 사용함으로써 얻는 이점은 아래와 같다. - 운반 용량을 크게 늘림 - 비용을 절감 - 규모의 경제를 이루기 쉬움(규격화 되어 있기 때문) - 다루기 쉽다(규격화 되어 있기 때문에 규격에 맞는 방식 하나만 있어도 가능) 해운산업말고도 우리가 웹 애플리케이션 등을 서비스하기 위해 이용하고 있는 서버에도 적용할 수 있다. 다양한 프로그램, 실행환경을 컨테이너로 추상화하고 동일한 인터페이스를 제공하여 프로그램의 배포 및 관리를 용이하게 해준다. (위에서 말한 표준 ..
기본적으로 JWT양식을 작성할 때에는 탈취당했을 때를 대비하여(탈취를 안당하면 가장 좋지만) 보안상 문제가 되지 않는 수준까지의 정보만 담아야 한다. (비밀번호 같은 것을 Payload에 담게 된다면 큰일이겠지...) 만료시간 : 15분 아래 각 부분마다 base64인코딩 1. 헤더(Header) { "typ": "JWT", "alg": "HS256" } 2. 정보(Payload) { "iss": "우리 도메인", "iat": "현재 시각" "exp": "현재 시각 + 15분", "공개 클레임(public claim)": true, "userId": "유저 id", } 3개의 등록된 클레임(iss, iat, exp) 1개의 공개 클레임 1개의 비공개 클레임(userId) 3. 서명(Signature) 헤..
진짜 뭔놈의 에러가 이렇게 많지.... o.s.b.d.LoggingFailureAnalysisReporter application.properties에 아래 두 문구를 추가 spring.autoconfigure.exclude=org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration server.port=9090 Consider defining a bean of type 'com.study.study_project.mapper.UserMapper' in your configuration. application 파일에 아래 오너테이션 추가(매퍼 경로) @MapperScan(basePackages = {"com.study.study_pro..
JWT를 사용했을 때, DB나 Cache를 두지 않았다고 가정을 해보자.(완전히 stateless한 서버를 구성) 중복 로그인 처리 웹 서비스를 운영 중에 있을때, 사용자가 동시에 여러 곳에서 로그인을 할 수 없게 하려고 한다. ex) 기존에 A가 로그인을 한 상태에서 B가 로그인을 시도하면 A를 만료시킴 만약 세션을 서버에서 관리하고 있다면 서버에 저장되어 있는 해당 사용자의 세션을 초기화시키면 된다. 그러나 JWT를 이용한다면 서버는 현재 아무런 정보가 없는 상황이다. 따라서, 위 예시에서 B가 로그인을 시도해도 중복 로그인인지 확인할 수 있는 방법이 없다. (그렇다고 누군가 중복 로그인을 한 것 같다는 소식이 들려왔을 때 전체 토큰 세션을 날려버릴 순 없다...) 보통 만료시점을 넣어두지만 만료시점..
세션 Client가 Server로 로그인 요청을 하면 Server에서 세션을 생성하고 로그인이 정상적으로 처리되었다는 응답을 하게 된다. 그렇게 로그인이 성공한다. 현 상황에서 세션은 유지되고 있다. 이후, Client에서 서비스 요청 등을 Server로 하게되면 인증된 유저인지 확인하기 위해 Session을 읽는다. 해당 유저가 확인이 되면 정상 응답을 Client로 해준다. 만약 서버가 1대인 서비스라면 신경쓸 일이 적지만, 보통은 서버를 여러대로 둔다. 그런 상황에서 각 서버들이 Session 동기화가 되어야 한다. 근데 그런 방법이 정말 복잡하다. 서버가 Session 을 읽어야하는데 트래픽이 많아지면 무리가 발생한다. 보통 쿠키랑 세션을 함께 쓰는데, CORS문제가 발생할 수도 있다. 이러한 문..
참고 : https://nahwasa.com/entry/%EC%8A%A4%ED%94%84%EB%A7%81%EB%B6%80%ED%8A%B8-Spring-Security-%EA%B8%B0%EB%B3%B8-%EC%84%B8%ED%8C%85-%EC%8A%A4%ED%94%84%EB%A7%81-%EC%8B%9C%ED%81%90%EB%A6%AC%ED%8B%B0 Spring Security는 프로젝트에 있어서 로그인한 유저를 관리해주는 프레임워크다. 여기에서 관리란 애플리케이션의 보안(인증과 권한, 인가 등)을 말한다. 현재 프로젝트에서 적용할 사항은 아래와 같다. 1. ID, Passwd를 이용한 로그인(인증) 2. 사용자에 대한 권한부여(접근 제어) 3. 세션 관리 4. 위 정보들에 대한 보관 및 관리 Spring..
layered architecture layered architecture는 가장 일반적인 아키텍처 패턴이다. 대부분의 Java 애플리케이션에 대한 표준으로 널리 알려져 있기도 하다. 널리 알려진 이유는 많은 회사의 조직 구조와 밀접하게 일치하기 때문일지도 모른다. layered architecture는 수평 계층으로 구성되며, 각 계층은 특정 역할을 수행하도록 설계한다. 많은 방법이 있겠지만 지금은 4가지의 계층으로만 표현을 해보겠다. 1. Presentation Layer(프레젠테이션 계층)은 모든 사용자의 인터페이스 및 브라우저 통신을 처리 2. Business Layer(비지니스 계층)은 요청과 관련된 특정 비즈니스 규칙을 실행 3. Persistence Layer(지속성 계층)은 데이터를 저장하..
REST REST란 무엇일까? 업무를 하다보면 REST API를 만들어야 한다고 하지만 REST가 무엇인지에 대해서는 깊게 생각해보지 않은 것 같다. REST를 풀면 아래와 같다. REpresentational State Transfer 다른 곳에서는 REST를 아래와 같이 말한다. a way of providing interoperability between computer systems on the Internet (컴퓨터간의 상호 운용성을 제공하는 방법 중 하나) API를 다뤄보기 때문에 무슨 의미인지 감은 대강 잡히나, 여전히 다른 누군가에게 설명해줄 수 있을 만큼 이해하지는 못했다. 그래서 REST를 공부하기 전에 역사를 먼저 살펴보자 *WEB(1991) 인터넷에서 정보를 어떻게 공유할 것인지에..
람다식 사용법 ■ 람다식이란? 람다식은 메소드를 간결하게 표현하는 것으로 Java8부터 지원한다. 람다식을 사용하게 되면 코드가 간결해지는 것을 볼 수 있는데, 메서드를 람다식으로 표현하면 메서드의 이름과 반환타입이 없어지기 때문에 익명 함수라고도 한다. 모든 메소드는 클래스에 포함 되어야 하고 객체를 생성한 뒤 호출하지만, 람다식은 그러한 과정 없이 람다식 자체만으로 메소드의 역할을 대신할 수 있다는 것이 큰 장점이다. ■ 작성법 // 기존 방식 반환타입 메소드 이름(매개변수) { 처리 할 문장 } // 람다식 (매개변수) -> {처리 할 문장} 위의 작성법으로 간단한 예제를 만들어보자 int sum(int i, int j) { return i + j; } 이 메소드를 아래와 같이 변경할 수 있다. (..
제네릭 사용법 ■ 제네릭이란? Java에서 데이터 타입을 일반화하는 것을 의미 제네릭은 클래스나 메소드에서 사용할 내부 데이터 타입을 컴파일 시 지정 ■ 제네릭을 사용하는 이유 클래스나 메소드 내부에서 사용되는 객체의 타입 안정성을 높임 반환 값에 대한 타입 변환 및 타입 검사에 들어가는 노력 감소 JDK 1.5 이전에는 여러 타이비을 사용하는 클래스나 메소드에 인수나 반환 값으로 Object 타입을 사용 > 이 경우 반환된 Object 객체를 다시 원하는 타입으로 타입 변환을 해야하며, 이를 통한 오류가 발생할 가능성이 있음 따라서 제네릭을 사용하면 컴파일 시 미리 타입이 정해지므로, 타입 검사나 타임 변환의 작업을 생략 가능 ■ 제네릭의 선언 및 생성 Java에서 제네릭은 클래스와 메소드에만 선언할 ..
스트림(Stream) / 버퍼(Buffer) / 채널(Channel) 기반의 I/O ■ I/O란? I/O(Input/Output)은 입력과 출력으로, 간단히 입출력이라고 부른다. 입출력은 프로그램간 데이터를 주고 받는 행위를 말하는데, 기본적으로 키보드로 입력을 하는 것, 프로그래밍(System.out.println())을 통한 출력 등 컴퓨터 내부 또는 외부 장치를 통해 실현된다. 스트림(Stream) 스트림은 흐름이라는 뜻이다. 입출력에 비유하자면, 입력부터 출력까지의 흐름이며, 입력이 출력까지 가는 통로(?)로 생각하면 된다. 통로라고 생각해보면, 흐름은 단방향으로 이루어 진다는 것을 알 수 있다. 만약, 여러 개를 보내게 된다면 선입선출(FIFO)방식으로 진행이 된다. 버퍼(Buffer) 버퍼는 ..
애노테이션 정의하는 방법 ■ 애노테이션이란? 애노테이션은 Java5부터 등장한 기능으로 주석이라는 뜻을 가지고 있다. 그러나 우리가 알고 있는 주석의 의미와는 다르게 인터페이스를 기반으로 한 문법이며 특별한 의미를 부여하거나 기능을 하는 코드를 작성할 수 있다. ■ 애노테이션 정의 방법 public @interface Test { ... } @interface는 애노테이션 타입을 선언하는 키워드이다. 애노테이션 타입 선언을 일반적인 인터페이스(interface) 선언과 구분하기 위해 interface앞에 @를 붙인다. ■ 애노테이션 필드 애노테이션 안에 필드와 같은 요소들을 정의할 수 있다. - 요소의 타입은 기본형, Striing, enum, 애노테이션, Class만 가질 수 있음 - 매개변수 선언을 ..
enum 정의하는 방법 ■ enum이란? enum은 열거형이라고 부른다. 상수를 관리하는 키워드이며, 다수의 상수를 선언할 때 관련된 상수를 편리하게 선언하기 위해 사용한다. 또한, 정의된 값 이외는 허용하지 않는 특성을 가지고 있다. ※ java.lang.Enum 클래스 사용 ■ enum 정의 enum Test {ONE, TWO, THREE, ...} 위의 예시처럼 enum 키워드와 열거형 이름을 설정하고 상수명을 입력한다. enum을 정의하는 방법은 크게 3가지 정도로 나눌 수 있다. 1. 별도 java 파일 // 첫 번째 java(Enumtest.java) 파일 public enum Fruit { APPLE, BANANA, MANGO } // 두 번째 java 파일 public class Test ..
Thread 클래스와 Runnable 인터페이스 ■ 쓰레드란? 컴퓨터로 프로그램을 실행시키는 것이 하나의 프로세스이다. 프로세스는 프로그램을 수행하는 데 필요한 데이터와 메모리 등의 자원과 쓰레드로 구성이 되어 있는데, 이때 쓰레드는 프로세스의 자원을 이용해서 실제 작업을 수행하는 역할을 한다. 하나의 프로세스는 하나 이상의 쓰레드를 가지고 있으며, 둘 이상의 쓰레드를 가진 프로세스를 멀티쓰레드 프로세스라고 한다. 멀티쓰레드를 잘 사용하면 자원을 효율적으로 사용할 수 있으며, 작업이 분리되어 프로그램 코드가 간결해진다. 이때, 교착상태와 같은 문제들을 잘 고려해야 한다. 보통, 사람들이 한 번에 여러 가지 일을 처리할 때 멀티 태스킹이 된다고 곧 잘 말하곤 하는데, 이 부분과 같이 멀티쓰레드도 카카오톡에..
자바에서 예외 처리 방법(try, catch, throw, throws, finally) ■ 예외처리란? 프로그램이 실행되고 있는 도중에 발생할 수 있는 예외 발생에 대한 처리를 작성한 것 ■ 목적 프로그램 실행 중의 예외 발생으로 인한 프로그램의 비정상적인 종료를 막고 상태를 유지하는 것 ■ Java에서의 예외처리 방법 1. try - catch - finally (예외가 발생한 메소드내에서 직접 처리) // try - catch - finally try { // 예외 발생 가능성이 존재하는 코드 }catch(예외 타입 매개변수명) { // 예외 타입의 예외가 발생한 경우 처리할 코드 }finally { // 항상 처리할 코드 } ※ Java 예외 타입 예시 - ArithmeticException - ..
인터페이스 ■ 인터페이스란? 객체의 사용 방법을 정의 코드와 객체의 중간 다리 역할이며, 코드에서 인터페이스의 메소드를 호출하면 인터페이스는 객체의 메소드를 호출하는 구조 사용자는 객체의 내부 구조를 몰라도 인터페이스의 메소드만 알면 사용 가능 ■ 인터페이스를 왜 사용할까? - 설계시 미리 선언해두면 개발할 때 기능 구현에 초점을 맞출 수 있다. - 프로젝트 시 개개인의 능력과 관계없이 메소드의 이름과 매개변수의 선언 등의 규칙이 유지된다. - 공통 인터페이스와 추상 클래스를 선언해 놓으면, 선언과 구현을 구분할 수 있다. ■ 인터페이스와 추상 클래스의 차이? 가장 큰 차이점은 인터페이스는 모든 메소드가 추상 메소드이고, 추상 클래스는 클래스 내 추상 메소드가 하나 이상 포함되는 경우이다. 조금 더 자세..
package 키워드 ■ package란? Java에서 클래스를 구분짓는 클래스들의 모음 ■ 왜 사용할까? - 명명 규칙을 통한 네이밍 충돌 방지(클래스명의 고유성 보장) - 클래스, 인터페이스 등을 더 쉽게 찾고 사용하기 위해서 ※ 명명규칙 - corp 이름 또는 도메인 등은 고유하기 때문에 이러한 이름으로 많이 사용 - 웹 사이트 주소일 경우 주소를 반대로 기재 - 소스 파일들을 점(.)으로 구분 - lowercase로 작성 ■ 선언 방법 // 패키지 선언 예시 package com.test 패키지를 선언할 때에는 반드시 코드의 처음에 해야한다. import 키워드 ■ import란? 다른 패키지안의 클래스에 접근하기 위해 사용하는 키워드 ■ 특징 - 클래스 이름을 명시하면 특정 클래스에 접근 - 별..
자바 상속의 특징 ■ 상속이란? - 기존의 클래스를 재사용하는 새로운 클래스를 생성 - 재활용의 개념이며, 더 적은양의 코드로 새로운 클래스의 생성이 가능 ■ 사용법 // extends 키워드를 기억하자 class Child extends Parent { // 내용 } 위의 사용법에서 Child가 생성하고자 하는 클래스이며, Parent는 기존에 있던 클래스이다. Child와 Parent는 서로 상속 관계에 있으며, Child를 자손 클래스라고 하고 Parent를 조상 클래스라고 한다. 크게 보면 Child안에 Parent가 있다고 생각하면 된다. 자손 클래스는 조상 클래스의 모든 멤버를 상속받으므로, 조상 클래스에 멤버변수가 추가되면 자손 클래스에도 추가된다. 하지만, 자손 클래스에 멤버변수를 추가해도..
클래스 정의하는 방법 ■ 클래스란? - 객체를 정의하는 틀 또는 설계도와 같은 의미 - Java에서는 이러한 클래스를 가지고, 여러 객체를 생성하여 사용 ■ 구성 - 생성자, 객체의 상태를 나타내는 필드와 객체의 행동을 나타내는 메소드로 구성 * 생성자 : 변수에 초기값을 넣어 초기화를 시키는 것 처럼 클래스도 동일한 방식으로 생성해 초기화를 해주는 역할 * 필드 : 클래스에 포함된 변수 * 메소드 : 어떠한 특정 작업을 수행하기 위한 명령문의 집합 ■ 접근제어자 - 각 접근제어를 위한 키워드에 따라 객체 또는 메서드가 접근될 수 있는 범위를 지정 * 접근제어자는 public, protected, default, private로 총 4가지이다. 접근제어자 클래스 내부 패키지 하위 클래스 그 외 publi..
item3. private 생성자나 열거 타입으로 싱글턴임을 보증하라 * 싱글턴이란? - 인스턴스를 오직 하나만 생성할 수 있는 클래스 - 싱글턴은 무상태(stateless)객체나 설계상 유일해야 하는 시스템 컴포넌트를 예로 들 수 있음 ※ stateless object : 인스턴스 변수가 없는 객체 // stateless 예제 class Stateless { void test(); { System.out.println("test"); } } 그런데, 클래스를 싱클턴으로 만들면 이를 사용하는 클라이언트를 테스트하기가 어려워질 수 있다. > 타입을 인터페이스로 정의한 다음 그 인터페이스를 구현해서 만든 싱글턴이 아니라면 싱글턴 인스턴스를 가짜(mock) 구현으로 대체할 수 없기 때문이다. ※ mock : ..
연산자 - 연산자(operator)는 산술연산자 +, -, *와 같이 연산을 수행하는 기호나 키워드 ※ 피연산자 - 연산에 적용되는 변수나 값 산술 연산자 - 숫자를 표현하는 피연산자를 사용 - 참과 거짓으로 나뉘는 boolean 타입에서는 사용이 불가 - +, -, *, /, % 등 // 산술 연산자 사용 int a = 1 + 2 int b = 2 - 1 int c = 2 * 2 int d = 4 / 2 int e = 3 % 2 // type casting이 발생하는 경우 double f = 3 / 2 // 논리적으로 예외가 발생하는 경우 double g = 4 / 0 // 0으로 나눌 수 없음 비트 연산자 - Binary Operator : &(AND), |(OR), ^(XOR), >>(R SHIFT..
item 61. 박싱된 기본 타입보다는 기본 타입을 사용하라 1. 기본 타입 - int, double, boolean과 같은 타입 2. 참조 타입(박싱된 기본 타입) - Integer, Double, Boolean과 같이 기본 타입에 대응하는 참조 타입 ※ 앞 전에 배웠던 레퍼런스 타입(Wrapper Class)와 동일 기본 타입 박싱된 기본 타입 byte Byte short Short int Integer long Long float Float double Double char Char boolean Boolean ※ 동일하게 앞 전에 배웠던 오토박싱과 오토언박싱을 사용하면 두 타입의 경계를 왔다갔다 하면서 사용할 수 있지만 두 개의 타입에는 분명한 차이가 존재 1) 같은 값이여도 다르게 식별될 수 있..
프리미티브 타입과 레퍼런스 타입 프리미티브 타입(Primitive type)이란? - 다양한 언어에 Default로 정의 되어있는 데이터 타입 - 변수에 값 자체를 저장 ex) int, char 등 레퍼런스 타입(Reference Type) - 프리미티브 타입을 제외한 모든 타입 - 메모리상에 객체가 존재하는 위치를 저장 ex) Class, Interface, Array 등 - 프리미티브 타입을 레퍼런스 타입으로 사용하기 위해 Wrapper Class사용 ※ Wrapper Class - 프리미티브 변수를 객체로 다루어야 할 때 사용 - 정수형을 예시로 들면, parseInt와 헷갈릴 수 있음 => Wrapper Class는 valueOf 사용 - JDK 1.5부터 오토박싱(autoboxing), 언박싱(..
item 59. 라이브러리를 익히고 사용하라 1. Java.util.Random - 무작위의 Bollean, Int, Long, Float, Double 등의 난수를 얻는 데 사용 - 값의 범위는 0~명시한 수 ※ Math.random()과의 차이점 : Math는 0.0~1.0 사이의 Double형 난수를 얻는데만 사용 예시) 흔하지만 문제가 심각한 코드! static Random rnd = new Random(); static int random(int n) { return Math.abs(rnd.nextInt()) % n; } 위의 예시에는 총 3가지의 문제를 가지고 있음 1) n이 그리 크지 않은 2의 제곱수라면 얼마 지나지 않아 같은 수열이 반복 2) n이 2의 제곱수가 아니라면 몇몇 숫자가 평균..