- 모놀리식 아키텍처(Monolithic Architecture)

기존의 모놀리식 아키텍처는 모든 것을 최소 필요 사양에 맞게 
규격을 맞추어놓고 하나의 큰 시스템안에 다 때려박아 서비스를 제공하는 아키텍처다.


 서버라든지 인력 등 서비스를 제공&유지하기 위해 최소 조건으로 맞추어져 있다보니,
새로운 서비스를 도입하려고 하면 기존의 운영 인력이 아닌 프로젝트를 위한 새 인력이 필요하게 되고, 그만큼 추가 비용과 시간도 많이 소모된다.

신규 서비스를 위해 투입 된 새 인력은 구조와 로직, 리스크에 대해 파악할 시간이 필요하고, 그러다보면 새로운 서비스의 제공 시기를 놓쳐버릴 수 있다.

 

그리고 여러명의 개발자가 하나의 프로젝트 패키지에서 작업함으로써 발생하는 부작용을 받아들여야 한다.

예를들어, 백 명이 소스 커밋을 했는데 한 명의 실수로 인해 백 명의 소스를 모두 rollback 시켜야 하는 상황 같은 것을 예로 들 수 있다.

 

모놀리식 아키텍처장점은  '개발 > 테스트 > 배포 > 반영'까지가 simple하다는 것이지만, 애플리케이션 확장이 유연하지 못하고, 신규 서비스 추가시 시간과 비용 또 리스크가 많이 발생한다.

 


- 마이크로서비스 아키텍처(Microservice Architecture)

 큰 시스템을 독립적으로 서비스가 가능한 여러개의 작은 시스템으로 나누는 것. 

 각각의 영역이 독립적으로 서비스를 수행하기 때문에 개별적으로 배포가 가능하고, 리스크도 해당 영역에 한정된다.


 결과적으로 애플리케이션의 확장을 용이하게 하고, 개발 속도를 앞당겨 새로운 서비스나 기능에 대한 출시 시간을 앞당길 수 있게 해준다.

 

이커머스 의 경우, 

전시 API Server
상품 API Server
주문 API Server 등 application을 서비스 별로 분할시키는 것..

 


그럼 각각의 서비스에서 발생하는 데이터는 어떻게 처리 ?
- 여러 분산된 API서버들로부터 들어오는 요청을 한 곳으로 모아서 그것을 분석하는 새로운 영역을 만드는 방법이 있음..

 

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

배포전략 (롤링, 카나리, 블루-그린)  (0) 2021.02.25
React 란?  (0) 2020.01.19
REST API  (0) 2020.01.19

리다이렉트와 인터셉트 

세션이나 쿠키 정보가 잘못되었을 때, 리다이렉트나 인터셉트를 이용.

리다이렉트 : 컨트롤러에서 뷰를 분기하는 방법. 
인터셉트 : 컨트롤러 실행 전/후에 특정 작업을 가능하게 하는 방법.


- 리다이렉트 (redirect)

지금의 페이지에서 특정 조건을 만족하지 않으면 다른 페이지로 전환시키는 기능. 

@RequestMapping("/modifyForm") 
public String modifyForm(Model model,  
HttpServletRequest request) { 

HttpSession session = request.getSession(); 
Member member = (Member) sessioin.getAttribute("member"); 

if(member == null){ 
return "redirect:/"; // 회원정보 수정 요청시 회원정보 세션이 없으면 리다이렉트. 
}else{ 
model.setAttribute("member", service.memberSearch(member)); 
} 

return "/member/modifyForm"; 
} 


ModelAndView로 리턴시에는
mav.setViewName("redirect:/");

 

 

- 인터셉트 (intercept)

로그인을 해야지만 이용할수 있는 페이지가 많은 경우 그떄마다 체크해서 redirect를 심어주기 번거로움.
따라서 리다이렉트를 사용해야 하는 경우가 많은 경우 HandlerInterceptor를 이용할 수 있다.

 


spring에서는 HandlerInterceptor를 구현한 HandlerInterceptorAdapter라는 것을 제공. 
HandlerInterceptorAdapter 얘를 상속 받아서 이용하면 됨. 

HandlerInterceptorAdapter에는
preHandle과 posetHandle 그리고 afterCompletion이 있다.
각각 필요에 따라 오버라이딩해서 사용하면 된다. 
 
preHandle() 컨트롤러가 작업을 수행하기 전에 실행. 
posetHandle() : 컨트롤러가 작업을 마친후에 실행.
afterCompletion() : 컨트롤러와 뷰작업을 모두 마친후에 callback됨.


보통 preHandle()을 많이 사용하며 안에서 
session 체크 후 null이면 리다이렉트 시키는 형태로 많이 쓴다. 



해당 HandlerInterceptorAdapter를 구현한 클래스 는 
스프링 설정파일에서 interceptor태그 추가 

.
.
<interceptors>
	<interceptor>
		<mapping path="member/modifyForm"/>
		<mapping path="member/removeForm"/>
		<!-- 이런 방식도 가능. 
		<mapping path="member/**"/>
		<exclude-mapping path="member/joinForm"/>
		<exclude-mapping path="member/loginForm"/>
		-->
		<beans:bean class="com.package.MemberLoginInterceptor"/> // 매핑에 설정된 경로로 접근하면 무조건 MemberLoginInterceptor부터 탐.
	</interceptor>
</interceptors>
.
.




 

'Web개발' 카테고리의 다른 글

세션(Session)과 쿠키(Cookie)  (0) 2020.04.15
TypeScript 란 ?  (0) 2020.02.01
시맨틱 마크업  (0) 2020.01.28
servlet 버전 별 web.xml 스키마 예제  (0) 2020.01.19
robots.txt 파일  (0) 2020.01.19

세션과 쿠키


웹 서비스를 가능하게 해주는 HTTP프로토콜은 클라이언트와 서버의 관계를 유지하지 않는 특징이 있다.(Connectionless Protocol)

 1. [요청] 클라이언트       >       요청(request) : 서버연결        >      서버
 2. [응답] 클라이언트      < 응답(response) : 응답 후 연결 해제 <       서버 

서버가 응답 후 연결을 끊는 이유는 서버의 자원을 관리하기 위함. 

클라이언트의 요청시마다 서버와 매번 새로운 연결을 생성해야 되서 
일반적인 로그인 상태 유지나 장바구니 등의 기능 구현이 어려움. 

이러한 Connectionless Protocol의 불편을 해결하기 위해 세션과 쿠키를 이용한다.

세션과 쿠키는 클라이언트와 서버의 연결 상태를 유지해주는 방법으로
둘다 사용자의 데이터를 저장한다는 공통점이 있지만,
쿠키는 클라이언트 쪽에서 연결 정보를 관리 
세션은 서버쪽에서 연결 정보를 관리한다는 차이가 있다. 

 

세션


HttpServletRequest 혹은 HttpSession으로 사용가능. 
로그인시 세션에 로그인정보를 생성한다. 
서버에 생성해 놓은 세션을 이용해 회원정보 수정이나 삭제 가능. 

로그아웃시에도 서버에있는 세션에서 로그인 정보를 지움. 

/* HttpServletRequest를 이용한 방법 */
@RequestMapping(value= "/login", method=RequestMethod.POST) 
public String login(Member member, HttpServletRequest request){ 
Member mem = service.memberSearch(member); 

HttpSession session = request.getSession(); 
session.setAttribute("member", mem); // 세션 생성.  

return "/member/loginOk"; 
} 

/* HttpSession을 이용한 방법 */
@RequestMapping(value= "/login", method=RequestMethod.POST) 
public String login(Member member, HttpSession session){ 
Member mem = service.memberSearch(member); 

session.setAttribute("member", mem); // 세션 생성.  

return "/member/loginOk"; 
} 


HttpServletRequest , HttpSession 둘의 차이점은 거의 없으며, 단지 세션객체를 얻는 방법에 차이가 있을 뿐. 

HttpServletRequest 는 파라미터로 HttpServletRequest을 받은 후 getSession()으로 세션을 얻음. 
HttpSession은 파라미터로 HttpSession을 받아 그대로 사용.

 

세션 삭제방법


로그아웃 또는 회원 탈퇴 시 사용.
session.invalidate();



세션 메소드

getId() : 세션 ID를 반환. 
setAttribute() : 세션 객체에 속성을 저장
getAttribute() : 세션 객체에 저장된 속성을 반환
removeAttibute() : 세션 객체에 저장된 속성을 제거
setMaxInactiveInterval() : 세션 객체의 유지시간을 설정
getMaxInactiveInterval() : 세션 객체의 유지시간을 반환
invalidate() : 세션 객체의 모든 정보를 삭제


쿠키 

HttpServletResponse에 쿠키를 담고 있다. 

- 쿠키 생성 및 설정 방법

@RequestMapping("/main") 
public String mallMain(Mall mall, HttpServletResponse response) { 
Cookie genderCookie = new Cookie("gender", mall.getGender()); 

if(mall.isCookieDel()){ 
genderCookie.setMaxAge(0); 
mall.setGender(null); 
}else{ 
genderCookie.setMaxAge(60*60*24*30); //한달동안 쿠키 유지 
} 
response.addCookie(genderCookie); 

return "/mall/main"; 
} 



- 쿠키를 받아서 사용하는 방법

@RequestMapping("/index") 
public String mallIndex(Mall mall,  
@CookieValue(value="gender", required=false) Cookie genderCookie,  
HttpServletRequest request) { 

if(genderCookie != null) 
mall.setGender(genderCookie.getValue()); 

return "/mall/index"; 
} 


@CookieValue 어노테이션의 value속성은 쿠키의 이름을 나타내는데, value에 명시한 쿠키가 없을 경우 익셉션이 발생한다.
익셉션을 막는 방법이 바로 rquired 속성. 기본값이 true인데 true인 경우 value에 해당하는 값이 없으면 익셉션 발생.
따라서 required 속성을 false로 해서 쿠키값이 없어도 익셉션이 발생하지 않도록 한다. 

실무에선 세션이 보안이 강해서 좀 더 많이 쓰이지만, 보안이 중요한 데이터가 아닌경우 쿠키 이용. 

 

 

출처 : 인프런 스프링 프레임웤 강좌

'Web개발' 카테고리의 다른 글

리다이렉트(redirect)와 인터셉트(intercept)  (0) 2020.04.15
TypeScript 란 ?  (0) 2020.02.01
시맨틱 마크업  (0) 2020.01.28
servlet 버전 별 web.xml 스키마 예제  (0) 2020.01.19
robots.txt 파일  (0) 2020.01.19

JPA- Entity 객체와 Table 맵핑. 

어노테이션 설명

@Entity

-  DB Table과 맵핑할 Entity 객체라는 선언이다.

- default생성자가 필수 이며, final클래스, enum, interface, inner클래스에서는 사용할 수 없다.

 

@Table

- Table 어노테이션의 name속성에 실제로 매핑시킬 DB Table명을 명시해준다. 

 생략시 JPA가 알아서 class의 이름과 매핑되는 Table명을 찾아 매핑시킨다. 

 

@Id

 - Table에서 기본키(PK)로 사용되는 컬럼에 @Id 어노테이션으로 식별자라는것을 선언한다.

@Id 어노테이션은 필수 이며, 복합키를 가진 테이블의 경우 별도의 클래스를 만든 후

@Id어노테이션 대신 @EmbeddedId 어노테이션을 사용해서 명시해야 한다.  

 

@Column

Entity의 속성과 매핑시킬 컬럼의 컬럼명을name속성을 이용해 명시해준다. 생략 가능하다.

 

 

 

복합키를 가진 Entity 생성하는 방법.

BOOK테이블은 PK가 복합키(book_code, book_name)로 구성되어 있다 .

따라서 별도의 bookId 클래스를 생성하고.

Book Entity에선 @EmbeddedId 어노테이션을 이용하여 키를 명시해 주고 있다. 

복합키용 클래스 생성시에는 상단에 @Embeddeable 어노테이션을 추가해줘야 한다. 

 

 

추가로 복합키는 equals()와 hashCode() 메서드를 추가로 필수 구현해주어야 한다. (아래 이미지 참조)

이유는 영속성 켄텍스트에서 식별자를 키로 이용해 관리하며, 식별자를 비교할때 사용되는 메서드가 equlas와 hashCode이기 때문이다.

 

*영속성 컨텍스트란

Entity를 영구 저장하는 환경으로 entityManager를 이용해서 Entity를 저장하거나 조회하면 EntityManager는 영속성 컨텍스트에 Entity를 저장한다.

 

*참고문헌 : 자바 ORM표준  JPA 프로그래밍

'JPA' 카테고리의 다른 글

JPA 와 ORM에 대해.  (0) 2020.04.12

- ORM(Object Relational Mapping) - 객체 관계 매핑

 

ORM은 RDB의 Table 과 자바 객체를 매핑시켜 좀 더 객체지향적인 개발을 가능하게 해주는 기술이다. 

 

- ORM Framework

DB Table과 자바 객체를 맵핑시켜 CRUD에 필요한 SQL을 자동으로 생성시켜주는 기술을 가진 프레임웤을 말한다.

그 중 하나가 JPA이다. 

 

- JPA (Java Persistence API)

JPA는 자바진영에서 사용하는 ORM 표준 기술이며, Hibernate 기반이다.

(* Hibernate 가장 많이 사용되고 있고, 가장 오래된 ORM기술).

 

Table과 자바 객체를 맵핑시켜서 SQL을 자동생성 시켜준다 ?

그렇다..

현재 본인도 myBatis를 이용한 프레임웤 환경에서 DAO(Data Access Object)를 이용해 쿼리들이 잔뜩 들어있는 .xml 매퍼에서 데이터를 조회해오고, 결과를 저장하고 있는데,,

이러한 방식은 객체지향적이라기 보다는 데이터 베이스관점으로 치우처진 개발이다.

 

물론 myBatis 방식이, SQL에 집중할 수 있는다는 장점을 가지고 있으나,

비슷하고 반복적인 무수히 많은 CRUD 쿼리를 작성하는데에 많은 시간과 비용이 소모되고 있다. 

또한 테이블 객체에 컬럼이 추가되거나 기존 컬럼에 변경이 생기는 경우,

관련된 모든 SQL 쿼리들을 찾아 모조리 수정해줘야 한다는 점에서 생산성이 떨어진다고 할 수 있다.

 

JPA 장점

JPA를 이용하면 반복적인 CRUD 쿼리 작성에 대한 수고를 없앨 수 있고, 

마치 자바 컬렉션에 데이터를 저장하듯 JPA객체에 저장할 데이터를 전달만 하면되기 때문에 생산성 향상과 유지보수에 용이하다. 

또한, MySql이나 Oracle DB 벤더에 의존적이지 않고 독립성이 있어, 프로젝트 진행 중 혹은 서비스 운영중 DBMS시스템 변경에 대해서도 유연하게 대처할 수 있다. 

 spring framework자체에서도 스프링 데이터 JPA라는 기술로 적극 지원하고 있고,

국내는 myBatis 이용률이 앞도적으로 높은편이지만, 전 세계적인 추세로는 ORM 기술에 대한 비중이 훨씬 높다.

 

 

 

 

 

'JPA' 카테고리의 다른 글

JPA- Entity 객체와 Table 맵핑 방법(복합키 매핑)  (0) 2020.04.12

자바에서 데이터를 다룰 때 사용하는 데이터 타입은 

기초 타입(Primitive Type)레퍼런스 타입(Reference Type)으로 나뉜다. 

 

기초 타입은 언어에서 사전에 정의해 놓은 데이터 타입으로 

저장공간에 실제 리터럴 형태의 값이 저장된다.

 

반면에, 레퍼런스 타입은 실제 값이 아닌 해당 값을 참조하는 참조값(주소값)이 메모리상에 저장된다는 차이점이 있다.

 

기초타입에는 총 8개의 타입[int, char, short, long, float, double, boolean, byte]이 있고, 이 이외에는 모두 레퍼런스 타입에 해당한다.

한빛미디어 : 뇌를 자극하는 자바프로그래밍

 

 

두개의 문자열을 입력받은 후 , 각각의 문자열 속에 중복되는 문자가 존재하면 YES출력 아니면 NO를 출력하는 문제이다.

 

- 풀이방법

문자열을 char배열로 변환하여 map에 넣은 후, key값이 존재하면 YES를 출력 아니면 NO를 출력하도록 했다.

 

static String twoStrings(String s1, String s2) {
    int result = 0;
    HashMap<String, Integer> map = new HashMap<String, Integer>();
        
    for(char c : s1.toCharArray()){
        if(!map.containsKey(""+c)){
            map.put(""+c, 1);
        }
    }

    for(char c : s2.toCharArray()){
        if(map.containsKey(""+c)){
            result++;
        }
    }

    return (result == 0) ? "NO" : "YES";
}

 

 

유일하게 번역기 안돌리고 그냥 풀리다니.. 반갑구나 반가워요~~

 

두 개의 String 배열을 인자로 받는데, 

첫번째 String 배열 안에 두번째 String 배열 내의 모든 요소들이 존재하면 Yes를 출력, 아니면 No를 출력하는 문제이다.

 

풀이 방법은

hashMap을 이용해서 일단 첫번째 String 배열 내의 모든 요소들을 key로 해서 집어 넣는다.

value는 1로 넣으면서, 중복 문자가 있다면 value의 숫자를 1씩 증가시키면서 넣어주었다.

 

그리고, 두번째 String 배열 내의 모든 요소들을 루프로 돌면서 map안에 key가 존재하는지, 존재하면 value를 1씩 차감시켰고, 존재하지 않거나 value가 0보다 작아지는 경우 No를 출력하도록 했다.

 

static void checkMagazine(String[] magazine, String[] note) {
    // 1. 잡지에 나오는 문자열에 note의 문자열이  모두 포함되어있으면 YES else No 출력
        
    HashMap<String, Integer> map = new HashMap<String, Integer>();

    for(int i=0; i<magazine.length; i++){
       if(!map.containsKey(magazine[i])){
           map.put(magazine[i], 1);
       }else{
           map.put(magazine[i], map.get(magazine[i])+1);
       }
    }

        
    for(int i=0; i<note.length; i++){
        if(!map.containsKey(note[i])){
            System.out.println("No");
            return;
        }else{
            if(map.get(note[i]) > 0){
                map.put(note[i], map.get(note[i])-1);
            }else{
                System.out.println("No");
                return;
            }
        }
    }
    System.out.println("Yes");
    return;
}

 

 

+ Recent posts