728x90

도커 컴포즈

업무하면서 도커를 적용해야하는 프로젝트가 있다. 아직 풀리지 않은 이슈들도 있는데

그거는 다른 포스팅에서 진행하도록 하고,

우선 도커 컴포즈에 대해 포스팅을 진행한다.

짧은 회고

지금까지 나의 방식은

Dockerfile을 생성해주고, 그 후에

도커 명령어를 통해서 개별 이미지들을 run을 해주어서 빌드를 해줬었다.

근데 이걸 쉘스크립트로 짜도 정말 불편했다.

내가 Vue와 Springboot를 둘다 배포해주어야 하는 상황이었기 때문이다.

Vue 그러니까 npm관련 실행 명령어는 또 Nodejs 공식문서를 봐가면서 습득을 했고

Vue + SpringBoot를 둘다 배포하는데에 성공했다.

일단 흐뭇했음.. 😂

따로 빌드하면서 설정해줄 것은 없어서

VueJs Dockerfile

Dockerize Vue 에서 읽은 내용으로 빌드를 진행

FROM node:lts-alpine

RUN npm install -g http-server

WORKDIR /app

COPY package*.json ./

RUN npm install

COPY . .

RUN npm install -g @vue/cli

RUN npm run build

EXPOSE 8080

CMD [ "http-server", "dist"]

Spring Boot Dockerfile

FROM openjdk:11-jdk

ARG JAR_FILE=build/libs/\*.jar

COPY ${JAR_FILE} app.jar

ENTRYPOINT ["java", "-Dspring.profiles.active=prod", "-jar", "/app.jar"]

그리고 docker-compose는 최 상위 루트에서 yml파일로 만들어주어 실행하도록 한다.

  • docker-compose
    • Vue Dockerfile
    • SpringBoot Dockerfile

이런식으로 진행되어 컴포즈 파일이 두가지를 다 빌드관리를 해주는 것이다.

docker-compose.yml

version: "3.8" # 버전 명시 도커 버전이 19.03.0+ 이면 3.8

services:
  vue:
    volumes:
      - 소스위치 :/app # 소스위치 : vue WORKDIR 과 매칭
    build:
      context: 배포하고자 하는 경로 # 빌드하는 위치
      dockerfile: 도커파일 경로 # 도커파일 명시
    ports:
      - "8080:8080" # 포트 포워딩

  spring:
    build:
      context: 배포하고자 하는 경로
      dockerfile: 도커 파일 경로
    ports:
      - "8081:8081" # 포트 포워딩

이렇게 배포에 성공하였다.

요즘 자바 API설계보다 서버쪽 관리에 업무가 더 치중되어있는것 같다.

도움이 아주 많이 되는것 같다.

네트워크 지식도 점차 쌓여가는 것이 흡족하다.

728x90

'클라우드' 카테고리의 다른 글

OpenSSH  (0) 2022.08.09
[Docker] 도커란  (0) 2022.08.05
728x90

HTTP란?

HTTP(Hyper Text Transfer Protocol) 텍스트 기반 통신 규약으로써,

인터넷에서 데이터를 주고받을 수 있는 프로토콜입니다.

HTTP는 신뢰성 있는 데이터 전송 프로토콜을 사용하는데

TCP 프로토콜에서는 데이터 송수신을 위해 클라이언트와 서버의 소켓이 연결되어 있어야 하며, 데이터가 유실되면 데이터

재전송을 요청함으로써 신뢰성을 보장합니다.

즉, 신뢰성 있는 데이터 전송이 가능하다는 장점으로 인해 HTTP, FTP, TELNET 등 대부분의 응용 계층 프로토콜의

전송 계층으로 사용 됩니다.

이렇기 때문에 인터넷의 결함이나 약점에 대한 걱정 없이 고유의 기능을 구현하는데에만 집중이 가능합니다.

웹 클라이언트와 서버

웹 콘텐츠들은 웹 서버에 존재합니다. 웹 서버는 HTTP로 통신을 한다고 했었기 때문에, HTTP서버 라고도 합니다.

웹 서버는 인터넷의 데이터를 저장하고, 클라이언트가 요청한 데이터를 제공해줍니다.

쉽게 설명하면 프론트단에서 Request(요청) 값을 보내면 서버쪽에서 Response(응답) 객체를 내려주는 원리라고

생각하면 되겠습니다.

이것이 바로 World Wide Web(통칭 WWW) 의 기본 요소입니다.

리소스

웹 서버는 웹 리소스들을 관리하고 제공합니다.

원초적인 이 웹 리소스는 웹 서버 파일 시스템의 정적 파일입니다.

이 정적 파일이라 함은, HTML파일부터 시작하여, 이미지파일 등등 모든 종류의 파일이 여기에 포함됩니다.

이런 정적파일이 주가 되기는 하지만, 무조건적으로 정적 파일일 필요는 없습니다.

이 동적 리소스인 경우에는 사용자마다, 시간, 정보 등등에 따라 각기 다른 콘텐츠들을 제공합니다.

미디어 타입

미디어 타입은 서버에서 메소드인자에 많이 들어간것을 생각해보면 됩니다.

대표적인 예가 바로

setContentType(MediaType.APPLICATION_JSON) 입니다.

인터넷은 수천가지 데이터 타입들을 다루기 때문에, HTTP에서는 웹에서 전송되는 객체 각각에 MIME이라는

데이터 포맷 타입을 붙이게 됩니다. 이 MIME은 전자메일 시스템에서 주로 사용을 했었는데,

각 문서와 함께 올바른 MIME 타입을 전송하도록, 서버가 정확히 설정하는 것이 중요합니다.

브라우저들은 리소스를 내려받았을 때 해야 할 기본 동작이 무엇인지를 결정하기 위해 MIME 타입을 사용합니다.

문법

MIME 타입의 구조는 주타입 / 부타입 으로 이루어져 있습니다.

이러한 예시들이 있습니다.

  • application/json
  • text/html
  • image/jpeg

URI (Uniform Resource Identifier)

웹 리소스는 각기 고유한 이름을 가지고 있기 때문에, 클라이언트는 해당 리소스를 지목하여 호출할 수가 있습니다.

글에대한 리소스 URI라면 이렇게 표현이 가능합니다.

https://lsj8367.github.io/spring/Spring-Filter-Interceptor/

  1. https 프로토콜을 사용해서
  2. lsj8367.github.io 로 이동한 후
  3. spring/Spring-Filter-Interceptor 에 해당하는 리소스를 가져와줘!

하면 이제 해당하는 글에 대한 포스팅을 보여주게 될 것입니다.

728x90

'CS' 카테고리의 다른 글

불 논리 정리 2  (0) 2022.08.09
불 논리 회고  (0) 2022.08.07
불 논리 정리  (0) 2022.08.07
재귀 알고리즘  (0) 2022.08.06
728x90

스테이트 패턴 적용기

모든 코드는 깃허브에 있음을 알린다.

현재 패스트캠퍼스의 디자인 패턴 강의를 수강도 하고있고, 동시에 디자인 패턴에 대한 책도 한권 읽었었다.

그러니까 메인 메소드만 있는곳에서 디자인패턴을 적용하여 연습을 조금 했었다.

그리고 프로젝트에 도입을 했었는데 약간 2% 부족한 패턴이 탄생했었다.

지금에서의 완벽한 디자인패턴

프로젝트를 통해서 유저 포인트를 조건에 따라 변경해주는 로직이 있었다.

스크린샷 2021-10-06 오후 11 19 38

자... 예전의 나는 보잘 것 없었다.

ㅋㅋㅋㅋ 이게 그때 당시의 나에겐 최선이었을지도??

아무튼 각설하고 저 로직을 이제 바꿔보려고 한다.

해당로직의 bean이라는 객체는 단지 저 포인트와 해당 유저의 아이디만 가지고 있는 일종의 DTO이고,

네이밍마저 가독성을 해쳤다.

이제부터 리팩토링 과정을 적어보려고 한다.

리팩토링 과정

스크린샷 2021-10-06 오후 11 31 24

어설프지만 클래스 다이어그램을 그려보았다.

일단 PointState가 최종적으로 저 4개의 랭크들을 주입받아 사용하기 때문에 화살표를 그어주지는 않았다.

예전 방식으로는 저 클래스 하나하나마다 빈을 등록해주고 switch를 배제한대신 if문에 return방식으로 구현했다. 물론 뒷단으로 로직을 빼긴했지만 뒤지다보면 어찌됐든 나오게 되어있는 방식이었다...

일단 어떻게 구현했는지 하나하나 보도록하자

일단 기본 틀이되는 Rank부터 살펴보자

Rank.java

public interface Rank {
    int getRankEnum();
    int giveUserPoint();
}

랭크를 확인할 수 있는 로직과, point를 세팅해주는 로직이 있다.

RankEnum.java

@Getter
@NoArgsConstructor
@AllArgsConstructor
public enum RankEnum {
    FIRST(1),
    SECOND(2),
    THIRD(3),
    ANOTHER(-1);

    private int rank;
}

랭크별 enum을 관리하기로 생각해서 따로 빼주었다.

public class First implements Rank {

    @Override
    public int getRankEnum() {
        return RankEnum.FIRST.getRank();
    }

    @Override
    public int giveUserPoint() {
        return 3000;
    }

}

나머지 클래스들은 안에 반환값만 다르기 때문에 First만 가져오겠다.

PointState.java

public class PointState {
    private final Map<Integer, Rank> pointStateMap = new HashMap<>();

    public PointState(List<Rank> ranks) {
        ranks.forEach(rank -> {
            pointStateMap.put(rank.getRankEnum(), rank);
        });
    }

    public Rank getPointStateMap(int rank) {
        return pointStateMap.get(rank);
    }

}

구현체인 PointState이다.

@Configuration
public class RankConfig {

    @Bean
    public PointState pointState() {
        return new PointState(Arrays.asList(new First(), new Second(), new Third(), new Another()));
    }

}

나는 이렇게 Config 클래스에서 런타임때에 초기화를 해주는데 생성자의 형식에 맞게
Rank에 해당하는 4가지 구현체를 넣어주었다.
이제 int형의 랭크 등급에 따라 추가할 포인트값을 받을 수 있게 되었다.

이제는 이게 정상적으로 동작하는지 확인을 해보기 위해 테스트코드를 먼저 짜도록 해보겠다.

테스트코드 작성

PointState.java

@SpringBootTest(classes = RankConfig.class)
class PointStateTest {

    @Autowired
    PointState pointState;

    @Test
    void test() {
        Rank rank = pointState.getPointStateMap(RankEnum.FIRST.getRank());

        assertThat(rank.getRankEnum()).isEqualTo(RankEnum.FIRST.getRank());
        assertThat(rank.giveUserPoint()).isEqualTo(3000);
    }

}

Rank설정을 해준 RankConfig를 가져온 후에 적용시켰다.

그렇지 않으면 마이바티스가 섞여있기 때문에 지금 에러가 발생한다 😱

스크린샷 2021-10-06 오후 11 44 16

정상적으로 통과하는것을 볼 수 있다.

이제 switch 로직을 리팩토링 할 생각이다.

스크린샷 2021-10-06 오후 11 45 29

이렇게 바꾸었고 이제 조건에 분기하여 포인트 값을 할당하지 않고 바로 작업할 수 있게 되었다!!!

정리

스크린샷 2021-10-06 오후 11 19 38

이랬던 로직이

스크린샷 2021-10-06 오후 11 45 29

이렇게 바뀐거 보고 디자인패턴 정말 좋다고 느낀다.

하나하나 배우면서 계속 적용해보고 싶어지는게 당연하달까..

아무튼 좋은 경험이었고 프로젝트 리팩토링이 잘되어가는것 같다 👍

728x90

'Java' 카테고리의 다른 글

일급 컬렉션  (0) 2022.08.09
변수  (0) 2022.08.07
프로젝트 리팩토링  (0) 2022.08.07
디자인 패턴 - Bridge Pattern  (0) 2022.08.07
728x90

템플릿 이슈

제목과 그리고 최상단의 주제인 템플릿 이슈 사항에 대해서 정리한다.

먼저 업무에서 생겼던 이슈사항부터 소개한다.

회사에서 postgreSQL을 사용한다.

그게 중요한 것은 아닌데, 각자의 db마다 방언이 있기 나름이고

테스트에서는 h2DB로 테스트를 하면서 방언도 h2방언을 설정해주었다.

로직중에 특정 date가 현재 시간보다 작은 경우를 쿼리로 찾아야했었는데,

to_date() 함수를 어떻게 적을것인가에 대한 문제였다.

왜 이 문제가 발생했냐면,

일단 기본적으로 여러개의 조건중에 저 하나가 들어가있었고, 문자열로 된 시간형식인 yyyyMMddHHmm 형식을 가지고 비교를

했어야 했기 때문이다.

이슈 파헤치기

일단 queryDsl에서는 서브쿼리나 랜덤 등등 어떤 특정 조건을 만족해야 하는 식들같은 경우엔

하나같이 끝에 Expressions가 붙었다.

대표적인건 뭐 JPAExpressions이다.

image

위 사진은 JPAExpressions의 일부이다.

이런식으로 다 함수들이 들어있을줄 알고 date 함수도 저런곳에 있겠지 하고 실행을 시키려고 했는데

존재하지가 않았다.

검색해본 결과 또 Template 류가 나오게 되었는데

DateTemplate 라는 곳에서 date관련 기능들을 사용할 수

있다고 해서 찾아보게 되었다.

image

DateTemplate 를 만드려면

ExpressionsdateTemplate() 메소드를 사용해서 만들 수 있었다.

image

메소드의 인자들이다.

그래서 나도 똑같이 넣어주기 위해서

DateTemplate date = Expressions.dateTemplate(
    LocalDateTime.class, "template???",
            genesisReservation.reservationEndDt,
            Expressions.constant("yyyyMMddHHmm")
)

이렇게 코드를 작성해주었다.

근데 작성하고 보니까 저기값은 String의 값인데

어떻게 넣어줘야하는지 감이 잡히질 않았다.

그래서 뒤지게된 JpaQueryFactory

image

JpaQueryFactory 의 내부중 일부를 가져왔다.

JPAQueryFactory는 생성자에 별도 템플릿을 주지 않으면

JPAProvider를 통한 JpQLTemplate를 가져온다.

여기보면 비슷하게 생긴 JPQLTemplates가 있다.

저길 타고 들어가보니 또 Templates를 상속받고 있었다.

JPQLTemplate에는 이제 익숙한 부분 쿼리문들이 메소드로 쭉 이어져 있었는데

그중의 일부를 보면

image

이렇게 생긴것들이 쭉 있다.

그래서 함수를 가져다가 저 조건에 맞게 쓰면 되는구나!

하고 유레카를 외쳤다. 굉장히 오래걸렸었다...😅

다시 돌아와서 템플릿 자리에 이렇게 바꿔주었다.

DateTemplate date = Expressions.dateTemplate(
    LocalDateTime.class, "to_date({0}, {1})",
            genesisReservation.reservationEndDt,
            Expressions.constant("yyyyMMddHHmm")
)

따옴표를 써서 형식을 넣어줄거다 라고하면

to_date({0}, {1})

이렇게 해주면 잘되지만,

to_date({0}, '{1}')

이러면 형식을 맞춰주지 않으면 에러가 발생한다.

image

to_date({0}, '{1s}')

이럴경우엔 또 잘 실행이 되는데

string을 넣을 경우에 s를 붙이고 따옴표로 완성시키면 되는것인가 하면서 아직도 궁금한데 이부분은 해결하지 못했다.

마무리

이제 해결했으니까 본론으로 돌아와 querydsl을 다시 작성한다면,

@RequiredArgsConstructor
public class Test {
    private final JPAQueryFactory JpaQueryFactory;
    public void test() {
        DateTemplate toDate = Expressions.dateTemplate(
            LocalDateTime.class, "to_date({0}, {1})",
            genesisReservation.reservationEndDt,
            Expressions.constant("yyyyMMddHHmm")
        );

        return jpaQueryFactory.selectFrom(table)
                    .join(joinTable)
                        .on("조인조건")
                            .where("조건".and(toDate.lt(LocalDateTime.now())))
                     .fetch();
    }
}

제목 없음

이런식으로 잘 들어오게 된다.

값도 테스트에서 비교하면 가정법 검증이 잘된다.

사이드 프로젝트에서의 이슈 사항

비슷하지만 다른 이슈였다.

사이드 프로젝트에서는 현재 MariaDB를 사용한다.

여기서는 다른 db와 다르게 rand() 를 사용한다.

postgreSQL, h2DB는 random()을 사용하는데

이것도 마찬가지로 템플릿에 대한 이슈였다.

JPAQueryFactory에서 조금 다른걸 설명하고 싶은데

일단 조회쿼리는 JPAQuery<>를,

수정쿼리는 JPAUpdateClause, 삽입 JPAInsertClause,
삭제 JPADeleteClause를 사용한다.

그래서 나는 조회쿼리를 사용해야 했기 때문에 JPAQuery 클래스
안쪽을 찾아보았다.

image

자 이렇게 보면 아까 위에서 설명했던 JPQLTemplates가 기본값으로

설정되어있기 때문에 그 템플릿을 사용하여 실행해서

그 끝쪽에 있는 Templates에는

image

이미지 처럼 들어있었다.

그러니까 NumberExpressions의 random이 먹통이었던 것이다.

아무리 방언을 따른다고 해도 템플릿에 저장되어 있는것은

그대로 가는것 같다.

생각한 결론은,

그러면 bean으로 등록하면 되지 않을까?

였다.

그래서 바로 QuerydslConfiguration 설정을 진행해주었다.

일단 우리는 Hibernate를 사용해서

기본값은 HQLTemplates 였고, 그래서

상속받아서 구현해주었다.

import com.querydsl.core.types.Ops;
import com.querydsl.jpa.HQLTemplates;

public class MariaDBTemplates extends HQLTemplates {
    public static final MariaDBTemplates DEFAULT = new MariaDBTemplates();

    protected MariaDBTemplates() {
        this(DEFAULT_ESCAPE);
        add(Ops.MathOps.RANDOM, "rand()");
        add(Ops.MathOps.RANDOM2, "rand({0})");
    }

    public MariaDBTemplates(char escape) {
        super(escape);
    }
}

이렇게 구현해주고 나니 이제 빈을 등록해주면 되었다.

@Configuration
public class QuerydslConfig {
    @PersistenceContext
    private EntityManager entityManager;

    @Bean
    public JPAQueryFactory jpaQueryFactory() {
        return new JPAQueryFactory(entityManager);
    }

    @Bean
    public JPAQuery<NewBook> jpaQuery() {
        return new JPAQuery<>(entityManager, MariaDBTemplates.DEFAULT);
    }
}

이렇게 새책 테이블에 관한 random값을 사용할 수 있을것 같았고,

바로 querydsl을 짜러 갔다.

생성자 주입으로 먼저
private final JPAQuery<NewBook> jpaQuery;

를 받아준 뒤에 로직은 그대로 두면 되겠거니 해서

그대로 두었다.

정상적으로 실행된다!!!!

컴퓨터를 옮기고 작업에 추가를 해줘야겠다.

위대로 설정하면 안된다. 상황 설명해주겠다.

현재 프로젝트는 위 설정처럼 진행했다.

그럴때 나오는 로그가 신박하다.

정리했을 처음처럼 random은 한번은 잘 출력되는데 문제는 그 이후부터이다.

스크린샷 2021-09-28 오후 11 54 47

이런식으로 새로고침을 할 때마다 random이 계속 호출된다.

그러니까 이 where절과 order by만 N + 1이 되는 것이다.

이게 일회성인지는 모르겠지만, 싱글톤 빈 주입으로 진행을 해주게 되면

계속 저걸로 영구적으로 바뀌어서 그런지 계속 추가가 된다.

처음은 몇줄 안되서 이렇겠지만 심각한 문제를 발생시킬것이다.

그 해결책은, 일단 빈주입이 아니라 쓰는 부분에만 특별하게 new를 해줘서 커스텀 해주는것이다.

@Override
public List<NewBook> selectRandom(int limit) {
    JPAQuery<NewBook> jpaQuery = new JPAQuery<>(entityManager, MariaDBTemplates.DEFAULT);
    return jpaQuery.from(newBook)
            .orderBy(NumberExpression.random().asc())
                .limit(limit)
            .fetch();
}

이런식으로 사용처에만 할당해주니까 정상적으로 rand()를 한번만 출력해주게 되었다.

결론

이제 조금씩 문서도 찾고, 라이브러리를 직접 뒤져가면서 학습해보니 결국 원초적인 지식이 가장 중요했다.

더 좋은 방법이 있다면 댓글로 남겨주셔도 좋습니다. 🙏

이렇게 보면 또 마이바티스처럼 되는 경향이 있다.

좀 더 데이터를 더럽고 간단하게 정제하고 자바쪽에서 부하를 걸어주는 방식을 계속 생각해야한다.

아무튼 오늘도 성장했다.

728x90
728x90

모든 코드는 여기

불 논리

NAND 게이트

Nand 게이트는 유니버셜 로직 게이트라고도 부르는데

이 게이트 하나만으로 모든 바이너리 동작을 제어할 수가 있다.

Nand게이트는 다음과 같은 불 함수를 계산한다.

a b Nand(a, b)
0 1 0
0 1 1
1 0 1
1 1 0

기본 논리 게이트

Not

단일 입력 Not게이트 Converter라고 불리며 input값의

반대값으로 Output을 내준다.

in out
0 1
1 0

And

And는 곱연산으로서, 입력 값이 둘다 1일 경우에만 1을 출력해준다.

a b And(a, b)
0 0 0
0 1 0
1 0 0
1 1 1

Or

Or는 합연산으로, 입력값 2개중 1개가 1이라면 1을 출력해준다.

a b Or(a, b)
0 0 0
0 1 1
1 0 1
1 1 1

Xor

배타적 논리합 이라고 불리며, 두 입력값이 서로 다를 경우 1

그렇지 않으면 0을 출력한다.

a b Xor(a, b)
0 0 0
0 1 1
1 0 1
1 1 0

멀티플렉서(Multiplexer)

멀티플렉서는 3입력 게이트로 selector 비트를 이용하여

나머지 두개 데이터 비트 입력중 하나를 선택.

a b sel Mux(a, b)
0 0 0 0
0 1 0 0
1 0 0 1
1 1 0 1
0 0 1 0
0 1 1 1
1 0 1 0
1 1 1 1

image

디멀티플렉서

이름만봐도 멀티플렉서의 정반대 기능을 수행한다고 알 수 있다.

디멀티플렉서는 선택한 비트에 따라 출력선 중 하나를 선택해 입력 신호를 보낸다.

sel a b
0 in 0
1 0 in

image (1)

멀티비트

멀티비트는 버스라는 멀티배열에 대한 연산을 수행하게 되어있다.

이 연산들은 쭉 같은 논리연산을 나열하여 비트의 쌍마다 연산을 수행해주는 것이다.

여기서는 16비트에 대한 연산을 진행했다.

AND 연산으로 예를 들어보겠다.

원래 하나의 비트 XY에 대하여 결과값을 AND(X,Y) 했던것을 16개를 동시에 진행한다고

생각하면 된다.

아래의 모든 예시는 전부 16비트 연산으로 이루어져있다.

AND16

X0 ~ X15 Y0 ~ Y15 AND16(X,Y)
0000000000000000 0000000000000000 0000000000000000
0000000000000000 1111111111111111 0000000000000000
1111111111111111 0000000000000000 0000000000000000
1111111111111111 1111111111111111 1111111111111111

기본 게이트의 연산과 같은데 갯수만 늘어난 것이므로 설명은 생략하도록 하겠다.

OR16

X0 ~ X15 Y0 ~ Y15 OR16(X,Y)
0000000000000000 0000000000000000 0000000000000000
0000000000000000 1111111111111111 1111111111111111
1111111111111111 0000000000000000 1111111111111111
1111111111111111 1111111111111111 1111111111111111

NOT16

IN NOT16(X,Y)
0000000000000000 1111111111111111
1111111111111111 0000000000000000

MUX16 멀티플렉서

X Y SEL MUX16(X,Y,SEL)
0000000000000000 0000000000000000 0 0000000000000000
0000000000000000 0000000000000000 1 0000000000000000
0000000000000000 1111111111111111 0 0000000000000000
0000000000000000 1111111111111111 1 1111111111111111
1111111111111111 0000000000000000 0 1111111111111111
1111111111111111 0000000000000000 1 0000000000000000
1111111111111111 1111111111111111 0 1111111111111111
1111111111111111 1111111111111111 1 1111111111111111

다입력

입력이 여러개인 다입력 게이트이다.

다입력에는 다입력/멀티비트 도 같이 묶어서 정리하겠다.

Or8Way

image

Or8Way의 논리게이트 인터페이스는 다음과 같다.

Mux4Way

image

이것의 멀티비트라고 한다면

이 같은 그림이 16개가 같이 수행된다고 생각하면 된다.

셀렉터가 2개이기 때문에

A B C D SEL[2] MUX16(X,Y,SEL)
0000000000000000 0000000000000000 0000000000000000 0000000000000000 00 0000000000000000
0000000000000000 0000000000000000 0000000000000000 0000000000000000 01 0000000000000000
0000000000000000 0000000000000000 0000000000000000 0000000000000000 10 0000000000000000
0000000000000000 0000000000000000 0000000000000000 0000000000000000 11 0000000000000000
0001001000110100 1001100001110110 1010101010101010 0101010101010101 00 0001001000110100
0001001000110100 1001100001110110 1010101010101010 0101010101010101 01 1001100001110110
0001001000110100 1001100001110110 1010101010101010 0101010101010101 10 1010101010101010
0001001000110100 1001100001110110 1010101010101010 0101010101010101 11 0101010101010101

sel 0번째로 a,b 그리고 c,d 를 연산 한후에
나온 결과값 o1, o2를 sel 1번째로 연산하여 결과값을 출력해주는 구조이다.

Mux8Way

image

4Way의 구조를 2개로 만들어서 결과값을 도출해주는 8입력 멀티플렉서이다.

a b c d e f g h sel out
0000000000000000 0000000000000000 0000000000000000 0000000000000000 0000000000000000 0000000000000000 0000000000000000 0000000000000000 000 0000000000000000
0000000000000000 0000000000000000 0000000000000000 0000000000000000 0000000000000000 0000000000000000 0000000000000000 0000000000000000 001 0000000000000000
0000000000000000 0000000000000000 0000000000000000 0000000000000000 0000000000000000 0000000000000000 0000000000000000 0000000000000000 010 0000000000000000
0000000000000000 0000000000000000 0000000000000000 0000000000000000 0000000000000000 0000000000000000 0000000000000000 0000000000000000 011 0000000000000000
0000000000000000 0000000000000000 0000000000000000 0000000000000000 0000000000000000 0000000000000000 0000000000000000 0000000000000000 100 0000000000000000
0000000000000000 0000000000000000 0000000000000000 0000000000000000 0000000000000000 0000000000000000 0000000000000000 0000000000000000 101 0000000000000000
0000000000000000 0000000000000000 0000000000000000 0000000000000000 0000000000000000 0000000000000000 0000000000000000 0000000000000000 110 0000000000000000
0000000000000000 0000000000000000 0000000000000000 0000000000000000 0000000000000000 0000000000000000 0000000000000000 0000000000000000 111 0000000000000000
0001001000110100 0010001101000101 0011010001010110 0100010101100111 0101011001111000 0110011110001001 0111100010011010 1000100110101011 000 0001001000110100
0001001000110100 0010001101000101 0011010001010110 0100010101100111 0101011001111000 0110011110001001 0111100010011010 1000100110101011 001 0010001101000101
0001001000110100 0010001101000101 0011010001010110 0100010101100111 0101011001111000 0110011110001001 0111100010011010 1000100110101011 010 0011010001010110
0001001000110100 0010001101000101 0011010001010110 0100010101100111 0101011001111000 0110011110001001 0111100010011010 1000100110101011 011 0100010101100111
0001001000110100 0010001101000101 0011010001010110 0100010101100111 0101011001111000 0110011110001001 0111100010011010 1000100110101011 100 0101011001111000
0001001000110100 0010001101000101 0011010001010110 0100010101100111 0101011001111000 0110011110001001 0111100010011010 1000100110101011 101 0110011110001001
0001001000110100 0010001101000101 0011010001010110 0100010101100111 0101011001111000 0110011110001001 0111100010011010 1000100110101011 110 0111100010011010
0001001000110100 0010001101000101 0011010001010110 0100010101100111 0101011001111000 0110011110001001 0111100010011010 1000100110101011 111 1000100110101011

DMux4Way

반대인 디 멀티플렉서이다.

여기부터는 실습에서도 멀티비트는 하지 않았기에 하나만 쓰도록 하겠다.

이건 입력을 1개를 받아서 4개의 결과값을 도출해주는 정반대 플렉서이다.

image

in sel a b c d
0 00 0 0 0 0
0 01 0 0 0 0
0 10 0 0 0 0
0 11 0 0 0 0
1 00 1 0 0 0
1 01 0 1 0 0
1 10 0 0 1 0
1 11 0 0 0 1

DMux8Way

image

이것도 Mux8Way와 반대의 특성을 가지고 있으며 4Way 2개가 붙어진 것이다.

in sel a b c d e f g h
0 000 0 0 0 0 0 0 0 0
0 001 0 0 0 0 0 0 0 0
0 010 0 0 0 0 0 0 0 0
0 011 0 0 0 0 0 0 0 0
0 100 0 0 0 0 0 0 0 0
0 101 0 0 0 0 0 0 0 0
0 110 0 0 0 0 0 0 0 0
0 111 0 0 0 0 0 0 0 0
1 000 1 0 0 0 0 0 0 0
1 001 0 1 0 0 0 0 0 0
1 010 0 0 1 0 0 0 0 0
1 011 0 0 0 1 0 0 0 0
1 100 0 0 0 0 1 0 0 0
1 101 0 0 0 0 0 1 0 0
1 110 0 0 0 0 0 0 1 0
1 111 0 0 0 0 0 0 0 1

정리

이렇게 1장 불 논리가 끝이났다.

처음 구현을 시작했을 때에는 NAND 게이트로 쭉쭉 구현을 진행했는데

특징이라고 한다면 컴파일 자체가 가령 Or를 구현해야 한다고 치면

Or만 써서 바로 구현할 수가 없게 해놨다.

이런 함수를 하나씩 쓰려면 그 전의 동작을 알게끔 한것인가?

하는 생각이 들었다.

그리고 마지막으로는 결국 구현이 다 되어서 BUILTIN이라는 기능으로

tools - builtInChips 안의 자바 클래스파일들 이 있으면

해당 기능을 사용할 수 있었다.

마지막으로는 그것으로 구현해두고 나머지는 주석처리를 진행했다.

이진수를 다루면서 완전 밑바닥을 체험하니 재밌기도 하고 어렵기도 했다.

728x90

'CS' 카테고리의 다른 글

불 논리 회고  (0) 2022.08.07
HTTP  (0) 2022.08.07
재귀 알고리즘  (0) 2022.08.06
[알고리즘] 그리디  (0) 2022.08.04
728x90

필터와 인터셉터

사이드 프로젝트를 하면서, 그리고 최근 회사의 프로젝트를 진행하면서

로깅처리와 더불어 어떠한 인증에 관한 것을 처리할 때 항상 필터를 구현했다.

이 필터가 뭔가 했더니 내가 옛날에도 들었었던 지식이지만 그냥 넘어가는 경우였고,

하다못해 스프링 동작과정에 정리해도

필터와 인터셉터에 관한 내용은 빼먹고 업로드를 한 것같다.

image

스프링 mvc의 기본 흐름에 대한 조금 더 구체적인 그림을 가져왔다.

다른 플로우차트를 찾아보려고 했지만 없더라.

실행

일단 서블릿 Request요청이 오게되면 바로 Filter로 가게된다.

여기서 무조건 동작을 받아서 처리를 해주고 이 필터들이 쭉 이어진것이 바로 필터체인이다.

image

필터 내부의 설명에서 보는것과 같이 doFilter 이 메소드에서 필터링을 수행하기 때문에

필터를 하나하나 등록해주게 되면 스프링은 요청을 받을때 저 필터들을 쭉쭉 통과해 나간다.

그다음에 DispatcherServlet으로 가게 되는 것이다.

서버를 실행시키면 Servlet이 올라오는 동안 init이 실행될 것이고

그 후에 doFilter가 수행될 것이다.

필터

이 필터는 아까도 말했듯, DispatcherServlet 이전에 실행되기 때문에 뭔가를 걸러주거나, 요청내용을 변경, 그리고 말했던 로깅처리 등을 진행할 수도있다.

public interface filter {
    public default void init(FilterConfig filterConfig) throws ServletException{}// - 필터 인스턴스 초기화

    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException;// - 전/후 처리

    public default void destroy() {}// - 필터 인스턴스 종료
}

이런식으로 세가지의 구성으로 되어있다.

image

doFilter에 있는 ServletRequest 객체는 매개변수 이름, 값 속성 등을

포함하는 데이터를 제공해준다.

web.xml에서 정리할 수도 있고, 나는 스프링 부트를 쓰기 때문에

javax.servlet.Filter를 구현해 주었다.

인터셉터

인터셉터는 말 그대로 가로채기이다.

필터는 스프링 외적으로 존재해서 스프링과는 상관없는 자원에 동작한다.

인터셉터는 DispatcherServlet 이 컨트롤러를 호출하기 전,후에 가로채려고 하기 때문에

스프링 컨텍스트 내부에서 Controller에 관한 요청, 응답에 대해 관여할 수 있다.

인터셉터는 여러 개를 사용할 수 있고 로그인 체크, 권한체크, 프로그램 실행시간 계산작업 로그확인 등의 처리가 가능하다.

  • preHandler()
    • 컨트롤러 메서드가 실행되기 전
  • postHanler()
    • 컨트롤러 메서드 실행직 후 view페이지 렌더링 되기 전
  • afterCompletion()
    • view페이지가 렌더링 되고 난 후

image

동작과정을 보면 이해가 될 수 있다.

지금 내 사이드 프로젝트에서 로그인 세션 null체크 기능이 잡다하게 중복이 되어있다.

도대체 학원에선 왜 이렇게 해도 뭐라안했을까 싶은 그런 로직들..

이 개념을 좀 도입해서 로깅처리와 로그인 기능을 좀 더 단순하게 구성을 해야겠다.

조바심 느끼지말고 남하고 비교하지말고 어제의 나보다만 성장해있으면 되는것 같다.

728x90

'Spring' 카테고리의 다른 글

Service Layer에 대한 생각  (0) 2022.08.10
Validaion  (0) 2022.08.09
Jasypt  (0) 2022.08.07
Spring -> Spring Boot 마이그레이션 2  (0) 2022.08.06

+ Recent posts