알고리즘
해쉬 충돌
같은 hash값이 생성될 경우
int[] arr 사용했을 경우 Yoonseo Seoyoon 두 값이 같은 인덱스에 들어가게 되면서 데이터가 덮어쓰기 되어 기존 데이터가 날아가는 문제가 발생한다
Yoonseo = 148번 index
Seoyoon = 148번 index
해결 방법 1
key, value 표현법을 사용해서 저장
{name: Yoonseo, value: 1}
Java
복사
key, value 표현법(JSON)
리스트[ ]를 만들어서 오브젝트{ }를 넣는다
{Yoonseo:1}
{Seoyoon:2}
→ 해결 방법 2보다 직관적인 방법으로 List로 구현하고 안에서만 루프를 돌면 된다
해결 방법 2
일단 넣고 중복이 발생하면 다른 빈칸을 찾아서 넣기
찾을 때 해당 key가 없는 경우 중복이므로 주변 칸들을 검색하면서 key가 같으면 그 값을 뽑는 방법
해결 방법 1을 사용해 해쉬 충돌 해결하기
private List<Integer>[] table = new ArrayList[size];
Java
복사
public void insert(String key, int value) {
// Listint hashIdx = hash(key);
if (this.table[hashIdx] == null) {
// null일 때 생성this.table[hashIdx] = new ArrayList<>();
}
// Map, Objectthis.table[hashIdx].add()
}
Java
복사
public class HashFunction {
class Node {
private String key;
private Integer value;
public Node(String key, Integer value) {
this.key = key;
this.value = value;
}
public String getKey() {
return key;
}
public Integer getValue() {
return value;
}
}
Java
복사
key와 value를 같이 사용하기 위해서는 Map을 쓰거나 Object를 새로 생성하는 방법이 있음
public void insert(String key, int value) {
int hashIdx = hash(key);
if (this.table[hashIdx] == null) {
this.table[hashIdx] = new ArrayList<>();
}
this.table[hashIdx].add(new Node(key, value));
}
Java
복사
public Integer get(String key) {
// int로는 null을 리턴할 수 없어서 Integer 사용
List<Node> nodes = this.table[hash(key)];
for (Node node : nodes) {
if (key.equals(node.getKey())) {
return node.value;
}
}
return null;
}
Java
복사
public static void main(String[] args) {
HashTable2 ht = new HashTable2();
ht.insert("Yoonseo", 1);
ht.insert("Seoyoon", 2);
int result = ht.get("Yoonseo");
if (result == 1) {
System.out.println("테스트 성공");
} else {
System.out.printf("테스트 실패 value: %d", result);
}
result = ht.get("Seoyoon");
if (result == 2) {
System.out.println("테스트 성공");
} else {
System.out.printf("테스트 실패 value: %d", result);
}
}
Java
복사
// 결과
테스트 성공
테스트 성공
Java
복사
Spring Boot
스프링 프레임워크 기반 프로젝트를 어려운 설정이나, WAS에 대한 설정 없이 바로 개발에 들어갈 수 있도록 만든 프레임워크
WAS(Web Application Server)
동적 컨텐츠를 제공하기 위해 만들어진 애플리케이션 서버 (DB조회, 로직처리가 요구되는 컨텐츠)
JSP,Servlet 구동 환경 제공
컨테이너, 웹컨테이너, 서블릿 컨테이너라고도 부름
컨테이너란? JSP, servlet을 실행시킬 수 있는 소프트웨어
스프링 프레임워크
•
Spring Boot는 개인용 어플리케이션이 아닌 여러 사람이 쓰는 애플리케이션 개발을 목적으로 만들어진 프레임워크
•
자바 언어를 이용해 엔터프라이즈급 개발을 편리하게 만들어주는 오픈소스 경량급 애플리케이션 프레임워크
엔터프라이즈급 개발
제어 역전(IoC)
•
객체의 관리를 컨테이너에 맡겨 제어권이 넘어간 것
•
제어 역전을 통해 의존성 주입, 관점 지향 프로그래밍이 가능해짐
@RestController
public class NoDIController {
// 개발자가 직접 객체를 관리
private MyService service = new MyServiceImpl();
// 객체 관리를 컨테이너가 제어함
@GetMapping("/no-di/hello")
public String getHello() {
return service.getHello();
}
}
Java
복사
의존성 주입(DI)
•
제어 역전의 방법 중 하나로 사용할 객체를 직접 생성하지 않고 외부 컨테이너가 생성한 객체를 주입받아서 사용하는 방식
@RestController
public class DIController {
MyService myService;
@Autowired
public DIController(MyService myService) {
this.myService = myService;
}
@GetMapping("/di/hello")
public String getHello() {
return myService.getHello();
}
}
Java
복사
다른 방식과는 다르게 생성자를 통해 의존성을 주입받는 방식은 래퍼런스 객체 없이는 객체를 초기화할 수 없게 설계가 가능함
@RestController
public class FieldInjectionController {
@Autowired
private MyService myService;
}
// 앞서 UserDaoTest에서 사용했던 방식
Java
복사
@RestController
public class SetterInjectionController {
MyService myService;
@Autowired
public void setMyService(MyService myService) {
this.myService = myService;
}
}
Java
복사
관점 지향 프로그래밍(AOP)
AOP
핵심 기능(비즈니스 로직)과 부가 기능(모니터링, 캐싱, 로깅, 트랜잭션…)을 나누어 개발하는 방식
•
비즈니스 로직에 집중하는 방식
•
TDD가 가능하도록 한다
◦
비즈니스 로직만 테스트 가능
◦
부가 기능은 이미 검증된 구현체를 쓰도록 함
스프링 부트의 장점
•
의존성 관리 기능
•
추가 라이브러리 실행에 필요한 환경 자동 설정
•
내장 WAS(Web Application Server) 제공
•
자체 모니터링 도구(Spring Boot Actuator) 제공
◦
요즘엔 쿠버네티스, 프로메테우스를 주로 사용
스프링 부트의 동작 방식
•
spring-boot-starter-web = Spring MVC
•
최근에는 서비스가 고도화되고 개발자들이 많이 생겨나며 Front End와 Back End가 명시적으로 구분된 형태로 프로젝트가 진행되기 때문에 View단을 많이 고려하지 않는 MC구조를 많이 사용한다
레이어드 아키텍처
애플리케이션의 컴포넌트를 유사 관심사를 기준으로 레이어로 묶어 수평적으로 구성한 구조
•
프레젠테이션 계층
◦
ex) 컨트롤러
◦
상황에 따라 유저 인터페이스 계층이라고도 함
◦
클라이언트와의 접점
◦
클라이언트로부터 데이터오 함께 요청을 받고 처리 결과를 응답으로 전달하는 역할
•
비즈니스 계층
◦
ex) 회원 가입
◦
상황에 따라 서비스 계층이라고도 함
◦
핵심 비즈니스 로직을 구현하는 영역
◦
트랜잭션 처리나 유효성 검사 등의 작업 수행
•
데이터 접근 계층
◦
ex) UserDao
◦
상황에 따라 영속 계층이라고도 함
◦
데이터베이스에 접근해야 하는 작업을 수행
◦
Spring Data JPA에서는 DAO 역할을 리포지토리가 수행하기 때문에 리포지토리로 대체할 수 있음
영속성
데이터를 영구적으로 저장 즉, DB에 저장하는 것
REST
•
자원을 이름으로 구분하여 해당 자원의 상태(정보)를 주고받는 모든 것을 의미
•
HTTP URI 를 통해 자원(Resource)을 명시하고, HTTP Method(POST, GET, PUT DELETE) 를 통해 해당 자원에 대한 CRUD Operation을 적용하는 것
◦
즉 REST는 자원 기반의 구조(ROA, Resource Oriented Architecture) 설계의 중심에 Resource가 있고 HTTP Method를 통해 Resource를 처리하도록 설계된 아키텍쳐를 의미
◦
웹 사이트의 이미지, 텍스트, DB 내용 등의 모든 자원에 고유한 ID인 HTTP URI를 부여한다.
◦
CRUD Operation
▪
Create: 생성(POST)
▪
Read: 조회(GET)
▪
Update: 수정(PUT)
▪
Delete: 삭제(DELETE)
▪
HEAD: header 정보 조회(HEAD)
REST API
•
API
◦
데이터와 기능의 집합을 제공하여 컴퓨터 프로그램간 상호작용을 촉진하며, 서로 정보를 교환가능 하도록 하는 것
•
REST API의 정의
◦
REST 기반으로 서비스 API를 구현한 것
◦
OpenAPI(누구나 사용할 수 있는 공개된 API) 는 대부분 REST API를 제공
REST API의 설계 기본 규칙
•
URI는 자원의 정보를 표시해야 한다.
◦
resource는 동사보다는 명사를, 대문자보다는 소문자를 사용한다
◦
resource의 도큐먼트 이름으로는 단수 명사를 사용해야 한다
◦
resource의 컬렉션 이름으로는 복수 명사를 사용해야 한다
◦
resource의 스토어 이름으로는 복수 명사를 사용해야 한다
GET /Member/1 -> GET /members/1
Java
복사
•
자원에 대한 행위는 HTTP Method(GET, PUT, POST, DELETE) 로 표현한다.
◦
URI에 HTTML Method가 들어가면 안된다
GET /members/delete/1 -> DELETE /members/1
Java
복사
◦
URI에 행위에 대한 동사 표현이 들어가면 안된다(CRUD 기능을 나타내는 것은 URI에 사용하지 않는다.)
GET /members/show/1 -> GET /members/1
GET /members/insert/2 -> POST /members/2
Java
복사
◦
경로 부분 중 변하는 부분은 유일한 값으로 대체한다(즉 :id는 하나의 특정 resource를 나타내는 고유값이다)
▪
Ex) student를 생성하는 route: POST/students
▪
Ex) id=12인 student를 삭제하는 route: DELETE/students/12
REST API 설계 규칙
1.
슬래시 구분자(/)는 계층 관계를 나타내는데 사용한다.
http://restapi.example.com/houses/apartments
Java
복사
2.
URI 마지막 문자로 슬래시를 포함하지 않는다
•
URI에 포함되는 모든 글자는 리소스의 유일한 식별자로 사용되어야 하며 URI가 다르다는 것은 리소스가 다르다는 것이고, 역으로 리소스가 다르며 URI도 달라져야 한다.
http://restapi.example.com/houses/apartments/ (x)
Java
복사
3.
하이픈(-) 은 URI 가독성을 높이는데 사용
•
불가피하게 긴 URI 경로를 사용하게 된다면 하이픈을 사용해 가독성을 높인다.
4.
밑줄(_)은 사용하지 않는다.
•
밑줄은 보기 어렵거나 밑줄 때문에 문자가 가려지기도 하므로 가독성을 위해 밑줄은 사용 x
5.
URI 경로에는 소문자가 적합
•
URI 경로에 대문자 사용은 피하도록 한다
•
RFC 3986(URI 문법 형식)은 URI 스키마와 호스트를 제외하고는 대소문자를 구별하도록 규정하기 때문
6.
파일 확장자는 URI에 포함하지 않는다.
Spring Boot Build
Hello World 실행하기
package com.springboot.hello.controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class HelloController {
@RequestMapping("/hello")
public String hello() {
return "Hello World";
}
}
Java
복사
8080번 포트를 통해 웹 서버가 열린 것을 로그에서 확인할 수 있다
포트 변경 방법
Talend API Tester 설치
실행 화면
default value가 get방식이라서 현재는 post방식으로 호출도 가능함
@RequestMapping(value = "/hello", method = RequestMethod.GET)
public String hello() {
return "Hello World";
}
Java
복사
실행화면
@RequestMapping(value = "/variable1/{variable}")
public String getVariable1(@PathVariable String variable) {
return variable;
}
Java
복사
실행화면
어노테이션의 변수명 지정하는 방법
@RequestMapping(value = "/variable2/{variable}")
public String getVariable2(@PathVariable("variable") String var) {
return var;
}
Java
복사
실행화면
참고