728x90
반응형
728x90
반응형
반응형

환경: java 8+

java optional을 사용할 경우

null값을 대비해 기본 값을 return 할 수 있는 아래 두 함수가 있다.

orElse vs orElseGet

 

두 함수 모두 기본 값을 반환 할 수 있는데

orElse는 T객체 그 자체를, orElseGet은 람다식을 넘길 수 있다는 차이가 있다.

//orElse
UserStatistics one = statistics.stream().filter(UserStatistics::isHoldem).findFirst().orElse(new UserStatistics());
//orElseGet
UserStatistics one = statistics.stream().filter(UserStatistics::isHoldem).findFirst().orElseGet(() -> new UserStatistics());

 

또한 메모리/성능 상에서 차이도 있다.

orElse 는 값이 존재하여 else에 설정한 값을 반환하지 않게 될 때에도 이미 만들어 놓는다.

orElseGet은 값이 없어 진짜 필요할 때 실행된다.

 

따라서, 

constant, static variable, or caching result 을 반환할 경우라면 orElse를 사용해도 되지만, 대량 작업을 하거나 새로운 객체를 생성해야할 경우 orElseGet를 사용하는게 좋겠다.


참고

https://medium.com/@ductin.tran/use-java-optional-orelse-and-orelseget-wisely-4eebb50aa12e

 

Use Java Optional OrElse and OrElseGet wisely

1. Introduction

medium.com

 

728x90
반응형

'개발 > java' 카테고리의 다른 글

[pom] http로 repository 연결  (0) 2023.10.23
[pom] element annotationprocessorpaths is not allowed here  (0) 2023.10.23
디자인 패턴  (0) 2023.07.11
[이슈해결] NPE at HSSFSheet.autoSizeColumn  (0) 2023.06.28
[java] lambda stream and final  (0) 2023.02.06
반응형

환경: springboot2.5 이상, mysql 5.7 버전

 

1. spring jpa h2디비 적용 시 테이블 명이 아래와 같을 때 아무 설정을 안 해주면 camel case -> snake로 변형되어 적용된다.

@Table(name = "GlobalAccounts")

즉 위 테이블이 global_accounts 로 변경되어 생성된다.

테이블 명 그대로 적용되어야 한다면 아래 설정을 추가한다.

spring.jpa.hibernate.naming.physical-strategy=org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl

 

2. 프로덕션 코드의 설정파일이 yml 이고 테스트 코드 설정파일이 properties 면 자동으로 설정되지 않는 것다. 도대체 왜지?!!!

https://mageddo.com/tools/yaml-converter 로 굳이 properties -> yml을 변환하여 설정하였다.

그게 싫다면 아래 어노태이션을 매 테스트 클래스마다 넣어야 하는데 매우 별로..

@TestPropertySource(locations = "classpath:application.properties")

 

+ application.properties 와 application.yml 둘 다 있을 경우 yml -> properties 순으로 로딩되어 같은 key값이 있을경우 properties의 값으로 덮어짐

 

3. rownum에 대하여

mysql 8.0 이상에서는 row_number() 윈도우 함수를 사용가능하나 그 이하 버전에서는 지원하지 않는다.

그래서 아래와 같이 session variable을 이용하여 쿼리 내에서 등수를 뽑곤 하는데..

여기서

1. session variable 명이 h2 예약어(rownum) 이면 identifier 에러가 나고

expected identifier [42001-200]

http://www.h2database.com/html/advanced.html

2. 다른 이름으로 바꿔도.. 제대로된 순위가 나오지 않는다..

 

h2에서 등수를 뽑거나,, session variable을 사용하려면 아래 h2함수를 사용해야 하는 것 같다..

http://h2database.com/html/functions.html#set

 

즉.. springboot jpql로 native query를 테스트하려면.. h2 문법도 잘 알아야할 듯하다.

 

4. String value too long 에러

h2의 경우 String에 어마무시한 json을 담을 경우 아래와 같은 에러를 만날 수 있는데,

Caused by: org.h2.jdbc.JdbcSQLDataException: Value too long for column "options CHARACTER VARYING(255)"

String은 기본 255 길이까지 가능이라, 그 이상의 데이터는 최장 길이를 아래와 같이 명시해주어야 한다..

@Column(length = 512)
private String options;
728x90
반응형
반응형

환경: spring jpa 2.5

Native Query 사용 시 `Space is not allowed after parameter prefix ':'`

라는 에러 발생

 

아래 쿼리의 @rownum := @rownum+1 에서 발생

:= 가 문제였음.

select * from 
(select seasonid, profileid, score, @rownum := @rownum+1 as ranking
from Season, (SELECT @rownum :=0)r

 

해결: \\를 추가하여 해결

@rownum \\:= @rownum+1

 

728x90
반응형
반응형

7. 경계조건

테스트 작성 시 경계 조건을 생각하는데 도움이 될 방법 CORRECT

 

7.1 Conformance 준수

특정 양식을 준수해야할 경우, N * M 가지의 경우의 수 고려

  • 이메일
  • 전화번호
  • 문서 등
헤더 데이터 트레일러
O O O
O O X
O X O
X O O
O X X
X O X
X X O
X X X
  • 처음 입력될 때 검증하면 매번 검증할 필요 없음
    • controller단이나 mapping될 때

 

7.2 ORDERING 순서

  • sorting
  • asc, desc 로 나열 시 맨 처음 값이 제일 큰지/작은지/최신순인지 등 확인 필요

 

7.3 RANGE 범위

경계 범위, 바깥 값 검증

  • int 인데 음수로 들어올 경우?
  • MAX + 1 이 들어올 경우?

primitive obsession(기본형의 과도한 사용)을 피하고 object로 만들어야 한다.

그리고 그 내부에서 검증로직과 경계값에 대한 조건을 가지고 있는게 좋다.

  • 예시: Bearing.java /  Rectangle.java : object안에서 범위에 대한 제약을 다룬다(넘는 경우 예외 포함).
  • RectangleTest.java : 공통 검증 로직을 @After 에서

cf. primitive obsession이란

  • 관련된 데이터를 묶지 못하고 흩어놓아 사용하는 것
  • 이 경우 각각의 데이터에 대한 정보를 외부에 공개하게 됨
  • 함수를 만들때도 각각의 데이터를 파라미터로 넘겨주어야 하기에 파라미터의 갯수가 늘어남
  • 이 때 관련된 데이터를 하나의 구조체(객체)로 묶어 사용해야한다.

https://medium.com/the-sixt-india-blog/primitive-obsession-code-smell-that-hurt-people-the-most-5cbdd70496e9

 

Primitive Obsession — code smell that hurt people the most

Most of the time, developers are aware of common code imperfections and most of the time know how to deal with them like long method…

medium.com

 

7.3.1 커스텀 매처 생성하는 법

hamcrest assertThat

public static <T> void assertThat(T actual, Matcher<? super T> matcher)

 TypeSafeMatcher를 상속받아서 매처 인스턴스를 반환하는 정적 팩토리 매서드(static @Factory method)를 제공하는 방식으로 커스텀 매쳐를 만들 수 있음(ConstrainsSidesTo.java, RectangleTest.java)

 

7.3.2 불변 함수를 내장하여 범위 테스트

sparseArray라는 자료구조를 직접 구현

  • 내부 배열에 저장된 값을 검증하는 테스트 코드를 작성할 때
  • 불필요하게 내부 구현 사항을 노출하기보다
  • 검증 함수를 만들어서 활용하는게 낫다(테스트 코드에서도 쓰고, 필요시 로직에서도 쓰고; checkInvariants())
    • 이 때 코드의 어느 부분에 문제가 있는지 더 쉽게 파악 가능

 

cf. sparseArray

0이 데이터보다 훨씬 많이 있는 array. 0을 실제 저장하지 않고 데이터가 있는 값만을 특별한 형식으로 저장하여 메모리를 효율적으로 사용하려는 방법을 취함.

A sparse array is an array of data in which many elements have a value of zero. This is in contrast to a dense array, where most of the elements have non-zero values or are “full” of numbers. A sparse array may be treated differently than a dense array in digital data handling.

https://developer88.tistory.com/entry/SparseArray-%EA%B0%80-%EB%AC%B4%EC%97%87%EC%9D%B8%EA%B0%80%EC%9A%94

https://www.geeksforgeeks.org/what-is-meant-by-sparse-array/

 

What is meant by Sparse Array? - GeeksforGeeks

A Computer Science portal for geeks. It contains well written, well thought and well explained computer science and programming articles, quizzes and practice/competitive programming/company interview Questions.

www.geeksforgeeks.org

 

경계 대상이 인덱스일 경우 아래 사항 고려

  • 시작과 마지막 인덱스가 같으면 안됨
  • 시작이 마지막보다 크면 안됨
  • 인덱스는 음수가 아니어야 함
  • 인덱스가 허용된 값보다 크면 안됨
  • 갯수가 기대값과 같아야 함

 

7.4 Reference 참조

  • 외부 의존성이 있는지
    • 특정 상태에 있는 객체를 의존하는지
  • pre-condition(사전조건) / post-condition(사후조건; 코드가 참을 유지해야하는 조건; assertion; 메서드 반환 )이 있는지 확인
    • 가정이 맞을 때
    • 가정에 맞지 않을 때
      • side effect 확인

 

7.5 Existence 존재

  • null, 0, empty
  • 기대하는 파일이 없을 때
  • 네트워크 다운

 

7.6 Cardinality 기수 / 갯ㅅ

  • 0, 1, N(다수; 경계조건)
    • N은 비즈니스 요구사항에 따라 바뀔 수
  • 0 -> 1 -> N 에 관한 테스트코드

 

7.7 Time 시간

  • 상대적 시간(시간 순서)
    • 테스트 호출 순서 무관
    • 언제든지 반복가능한 테스트
  • 절대적 시간(측정된 시간)
    • 너무 오래걸리지 않는 테스트
    • timeout / 무한대기 고려
  • 동시성/동기화

 

728x90
반응형
반응형

5. 좋은 테스트의 조건 FIRST

5.1 FIRST

https://santim0ren0.medium.com/clean-code-unit-test-3e4b9ee63cb3

5.2 First: 빠르다

  • 테스트를 빠르게 유지해야 함
  • 하루에 서너번 실행하기도 버겁다면 잘못된 것
  • 지속적이고 종합적인, 빠른 피드백을 주지못하면 테스트의 가치가 떨어짐
  • 테스트가 느리다면, 디비와 같은 외부 의존성을 줄여라
    • 외부 의존성은 테스트를 느리게 할 뿐만 아니라 디비에서 값이 변하면 테스트 결과도 변할 것이기에 테스트 자가 불안해짐
    • 책의 예시
      • before: given절에서 테스트를 위한 데이터를 실 디비에서 가져옴
      • after:
        • 1. 디비 조회 결과를 받아서 함수에 주입해주는 방식으로(method argument) 테스트하고자하는 함수를 분리
        • 2. 테스트 코드에선 (디비 결과라고 가정된) 해시맵/리스트를 만들어 테스트
        • 3. 테스트가 빨라졌고 느린 것에 의존하는 코드도 최소화되어 더 나아졌다고 할 수 있음

 

5.3 Independent/Isolated: 고립시킨다

  • 단위테스트: 검증하려는 작은 양의 코드에 집중
  • 최소의 의존성
    • 테스트를 깨뜨리지 않는/ 느리게 하지 않는 / 가용성 / 접근성
  • 다른 단위 테스트에 의존하지 않도록
  • 순서나 시간에 관계없이 실행되어야
  • SRP: 테스트가 하나 이상의 이유로 깨진다면 테스트를 분할하라

 

5.4 Repeatable: 반복 가능해야한다

  • 실행할 때마다 같은 결과 보장
  • 직접 통제할 수 없는 외부 환경에 있는 항목들과 격리
  • 시간을 다뤄야 한다면? 
    • java8.time.Clock 객체를 주입받아(생성자나 setter로 생성시 주입) / 책의 예시

 

5.5 Self validating: 스스로 검증 가능하다

  • 테스트 결과를 수동으로(로그를 눈으로 읽는다거나)하는 방식은 시간이 많이 들고 리스크가 있음
    • -> 자동화 해야
  • CI(지속적 통합;저장소 감지하여 빌드와 테스트)/CD(지속적 배포;)

 

5.6 Timely: 적시에 하다

  • 단위 테스트를 언제 작성하는가?
    • 단위 테스트는 좋은 습관.
    • 절대 미루지말라. 한번 미루면 다시 테스트를 작성하기는 힘들어진다.
  • 팀 내 규칙을 세우라
    • ex. 테스트되지 않은 코드는 반영하지 않는다, CI 환경에 확인할 수 있도록 한다..
  • 옛날 코드에 대한 테스트는 시간 낭비가 될 수도
    • 코드에 큰 결함이 없고 당장 변경 예정이 없다면 그 노력을 신규 코드에

 

728x90
반응형
반응형

4. 테스트 조직

4.1 테스트 코드를 작성할 때 AAA

Arrange: 테스트 코드 실행 전 준비; 객체 생성

Act:테스트 코드 실행

Assert: 실행한 코드가 기대한 대로 동작하는지 확인

After: 때에 따라 필요; 테스트 실행 시 어떤 자원을 할당했다면 clean up 필

=> 각 구분을 구별하기 위해 빈 줄을 삽입

 

  1. Given/When/Then
    • Given
      • 테스트를 위해 주어진 상태
      • 테스트 대상에게 주어진 조건
      • 테스트가 동작하기 위해 주어진 환경
    • When
      • 테스트 대상에게 가해진 어떠한 상태
      • 테스트 대상에게 주어진 어떠한 조건
      • 테스트 대상의 상태를 변경시키기 위한 환경
    • Then
      • 앞선 과정의 결과

 

4.2 단위 테스트를 작성할 때는 먼저 전체적인 시각에서 시작해야

개별 메서트를 테스트하긴 하는 것이 아니라

  • 입금
  • 출금
  • 잔액확인

클래스의 종합적인 동작을 테스트 하는 관점에서 테스트를 작성해야함

  • 입금 -> 잔액 확인 -> 출금 -> 잔액 확인 등의 흐름으로 클래스 전체를 테스트

 

4.3 테스트와 프로덕션 코드의 관계

테스트 코드와 프로덕션 코드는 분리되어야

1. 테스트를 프로덕션 코드와 같은 디렉터리/패키지에 넣기

-> x; 테스트코드를 따로 분리하기 어려움

2. 테스트를 별도 디렉터리로 분리하지만 프로덕션 코드와 같은 패키지에 넣기

-> 주로 채택; test의 디렉터리 구조가 src 디렉터리를 반영; 테스트 클래스는 패키지 수준의 접근 권한을 가짐

3. 테스트를 별도의 디렉터리와 유사한 패키지에 유지

-> 테스트 코드를 프로덕션 코드의 패키지와 다르게하면 public 인터페이스만 활용하여 테스트코드 작성하게 되미. 많은 개발자가 의도적으로 설계할 때 이 정책을 채택

4.3.2 내부 데이터 노출 vs 내부 동작 노출

  • public method가 아닌 함수(비공개 코드; private method)를 호출하는 테스트는 구현 세부 사항과 결속이 심해져 테스트가 깨질 수 있음.
  • 내부의 세부 사항을 테스트하는 것은 저품질로 이어짐
    • ex. 코드의 작은 변화가 수많은 테스트를 깨면(과도하게 내부 구현 사항을 알고 있기에) -> 개발자는 당황 -> 테스트가 더 많이 깨질수록 개발자는 리팩토링이 꺼려짐 -> 코드의 퇴화
  • 테스트를 위해 내부 데이터를 노출하는 것은 테스트와 프로덕션 코드 사이에 과도한 결합을 초래
    • 테스트를 위해 getter 생성
  • private method를 테스트하고 싶은 충동이 든다면.. 설계에 문제가 있는 것(클래스의 SRP위배)
    • -> 의미있는 private method를 추출하여 별도의 클래스로 분리

 

4.4 집중적인 단일 목적 테스트의 가치

테스트는 주요 동작을 단위로 적당하게 나눠야

  • 테스트가 실패할 경우 실패한 테스트 이름이 표시되기에 어느 동작에 문제가 있는지 파악 가능
  • 실패한 테스트를 해독하는 시간을 줄일 수 있음
  • 테스트가 실패할 경우 테스트가 중지되기 때문에 모든 케이스가 실행됨을 보장가능

 

4.5 문서로서의 테스트

4.5.1 일관성 있는 이름으로 테스트를 문서화

  • 어떤 맥락에서 일련의 행동을 호출했을 어떤 결과가 나오는지 명시
  • 단어 일곱개를 넘어가면.. 너무 긴 이름
  • given-when-then 의 양식을 쓸수도
    • givenSomethingWhenDoingThisBehaviorThenSomeResultOccurs
    • 근데 너무 길다.. -> given절 생략
    • doingSomeOperationGeneratesSomeResult
  • 다른 사람에게 의미있게 만들기!

4.5.2 테스트를 의미있게 만들기

  • 테스트가 무슨 일을 하는지 바로 파악할 수 있도록 이름을 개선
  • 지역 변수 이름 개선
  • 의미있는 상수 도입
  • 햄크래스트 단언
  • 커다란 테스트를 나눠 집중적인 테스트 만들기
  • 공통 초기화/정리가 필요한 경우 @Before/@After 사용
  • 테스트 공통화

4.6 @Before/@After

  • @Before는 중복된 초기화가 있을 경우 공통화를 위해 사
    • @Before은 매번 테스트 메서드 실행에 앞서 실행됨
    • 초기화가 늘어갈 경우 @Before 메스드를 여러개로 분할
      • 이 경우 실행 순서를 보장하지 않음
      • 일정한 순서가 필요하다면 단일 @Before 메서드로 결합하여야 함
  • @After는 각 테스트를 한 후에 실행
    • 테스트가 실패하더라고 실행됨
    • 테스트에 발생하는 부산물을 정리

4.6.1 BeforeClass & AfterClass

@BeforeClass 모든 테스트 실행하기 전 한번만

@AfterClass 모든 테스트 실행 후 한번만

 

4.7 테스트를 의미있게 유지; 항상 통과하도록

4.7.1 단위 테스트는 빨라야 

  • 외부 자원에 접근 시 목객체 활용하여 빠르게
  • 필요하다고 생각하는 테스트만 실행
    • BUT 주기적으로 전체 테스트를 돌려 문제를 바로 찾을 수 있도록(묵히지 않도록)
    • 이게 힘들다면 변경되는 클래스 단위/함수 단위의 테스트라도 실행해서 테스트가 통과되도록 유지해야
    • -> 견딜 수 잇는 만큼 많은 테스트 실행하

4.7.2 테스트 제외

테스트 실패 시 주석처리말고 @Ignore 

테스트 돌리면 몇 개의 테스트가 skip 되었는지 알려

728x90
반응형
반응형

RDBMS

장점

  • Relation 기반
  • 높은 신뢰성
  • 비교적 높은 성능
  • 비교적 다양한 기능
  • 관리편의성

단점

  • 단일 장비.. RDB 데이터가 많을 경우 확장성이 떨어짐

 

> 개선하기 위해 나온

NO SQL

장점

  • 관계없는 데이터 처리에 최적화
  • 높은 확장성을 가지는 경우 많음(여러 장비가 동시에 투입되는 것을 고려하고)
  • Schemaless

단점 

  • 제한적인 일관성
  • Join, Transction 미지원
  • 관리비용이 큰 경우 있음

 

데이터가 커지면

수직확장 = 장비증설

  • 고비용
  • 확장 시 서비스 중단(일부 중단 안 해도 되는 게 있으나 비싸)
  • 확장 한계(슬롯에 꽂아)
  • 관리 편의성

수평확장 = 분할(partitioning)/ 분산(distribution)

  • 데이터 자체를 종류별로 쪼개서
  • 다 다른 장비에 담음

 

분할

테이블 분할(수평/수직)

  • 수평은 row단위로
  • 수직은 column단위로

DB분할(테이블 위치 분산)

  • 수평/수직으로 해결이 안될 때..

 

분산

분산 환경이란 무엇인가?

  • 여러 대의 서버가 네트워크로 연결된 것(이중화)
  • 분산 시 지연, 대역폭, 패킷 손실 있을 수 있음
    • 불일치 발생할 수도; 네트워크 이상일 수도 있고 장비 이상 혹은 공격받았을 때도 있음
  • ACID 보장이 어렵다
    • 한 장비에 문제가 생겼을 경우 동기화가 불가할 때 데이터가 틀어질 수도 -> 따로 컨트롤 필요
  • 데이터 복제(slave)
    • 무결성 보장이 어렵
  • 디비가 나눠져 있으면 조인이 어렵다...

위치 분산(테이블을 쪼갠다)

디비를 먼저 쪼개고 그 디비를 다른 장비에

 

샤딩 sharding

  • 수평분할을 이용한 분산
  • 각 샤드는 테이블 별 동일한 스키마, 중복되지 않은 값을 가짐
  • 샤드에 데이터를 나누는 기준이 필요 -> shared key

range shard

  • 규칙을 정하고 범위를 나눠 분산(key 1~1000 / 1001 ~ 2000.... etc)
  • 부하가 불균형
    • 범위별로 잘 쓰는 사람 안 쓰는 사람들이 있을 수 있는데 보통 이를 재배치해서 해소함
  • 허나 재배치 기준을 잡기가 어려움 -> 잘 안 씀

modulus shard

  • shard key를 해시(해시 함수가 mod)
  • 부하가 비교적 균등
  • 확장과 재배치 어려움

hash map shard

  • 해시된 값을 기준으로 배치 룰을 별도로 만들어
  • 부하가 비교적 균등
  • 샤드별 비중도 지정 가능(3번 샤드가 성능이 좋으면 3번으로 더 가게 할 수 있음)
  • 데이터 불균형 시 데이터 재배치 어려움
  • 해쉬맵을 바꾼다고 해서 다시 재배치해야 하는데,, 그 비용이 큼

index shard

  • 샤드 정보(사용자 위치)를 별도 저장소에 저장
  • 신규 가입자 배치 조절 가능(3번에 더 가게 할 수 있음)
  • 확장은 쉬우나 재배치 어려움(4번 추가 가능; 비중을 조절할 수 있음)
  • 유저와 샤드를 매핑해 둠
  • 샤드별로 카운드 둬서 가장 적은 카운트로 신규 이용자 받을 수

directory shard

  • 샤딩을 위한 추상화된 서비스를 사용
  • index shard와 유사

샤딩을 적용할 수 있는 경우

  • 샤드 간 transaction/join이 발생하지 않는 데이터
  • 데이터를 보는 관점이 하나인 데이터
    • 사용자의 입장? 사용자-구매내역- 연결된 데이터는 한 샤드에 
    • 판매자의 입장?
    • 해당 서비스의 주된 관점을 기준으로.. 샤딩
    • 주된 관점이 아닌 한 성능상 손해..
  • 쓰기 부하 분산이 필요한 경우
    • 읽기 부하는 master-slave로 쉽게 분산 가능
    • 쓰기는 여러 군데에서 동시에서 쓰면 일관성 보장이 힘들어짐 그래서 일반적으로 쓰기 장비가 하나만 둠
    • 그 한 장비에서 쓰기가 엄청 많이 들어올 경우 테이블을 나눠놓으면 쓰기 부하가 분산됨
  • 데이터 크기나 사용량이 편중되지 않은 경우
    • 특정 데이터가 엄청 커지면 부적합...

샤딩을 적용하기 어려운 경우

  • 샤드 간 transaction이 빈번할 때
  • 데이터를 보는 관점이 여러 개인 데이터
  • 여러 샤드와 공통으로 관계를 맺는 데이터
  • 특정 부분만 access가 집중되는 데이터

 

읽기 복제(replica)

  • 동일 스키마, 동일 데이터의 복제본(전체/부분)
  • 읽기 부하 분산 가능(slave에서 조회 시)
  • 쉽고 간단하게 증설 가능
  • 디비보다 캐시가 더 빠르다!

 

NOSQL

1. 확장성/가용성

  • 모든 데이터가 RDB수준(ACID)으로 필요하지 않을 때
  • 신뢰성을 희생해서라도 확장성/가용성 증대

2. 다양한 데이터 형태

  • 관계가 필요 없는 데이터
    • 세션정보
    • key-value type
    • document, json
    • column store

3. 스키마 없음; 스키마가 필요한 경우에만 지정 가능(스키마 수정이 빈번할 경우)

4. 트랜잭션 없음; 약하게...

5. 조인 없음; 지원을 해도 제한이 있음

6. 제한된 액션(기본적인 CRUD +..)

7. 인덱스가 기존 디비보다 다양치 못함(미약)

 

mongoDB

  • document store / json 타입 저장
  • 장애가 발생해도 쉽게
  • dba 관리 힘들어(성능 향상이 힘들어)
  • 범용성 지향(인덱스 있고 조인도 힘들지만 되고 트랜잭션도 강화 중)
  • 개발 편의성 좋음
  • schemaless 데이터가 많을 경우 / json
  • 트랜젝션이 별로 없으면 유리

단점

  • 최소 권장 3대 ~ 권장 세팅 5대
  • 장비의 비용이 듦..
  • 초기부터 늘려서 사용해야.. 더 비쌀 수도 있음

 

카프카

  • 실시간으로 기록 스트림을 게시, 구독, 저장 및 처리할 수 있는 분산형 데이터 스트리밍 플랫폼
  • 데이터의 송신보장
  • 분산 시스템으로 온라인 상태에서 간단하게 중개인 추가 가능
  • 병렬로 처리하기 위해 파티션으로 나눠서 처리
  • 파티션을 복제 - 다른 서버/노드가 장애 발생 서버의 역할을 대신 고속성을 유지하면서 데이터의 송신 보장이 가능

 

분산의 타이밍

  • 서비스 시작 전 - 저장소 선택 기준
  • 성능 한계 도달 전 - 확장

저장소 선택 기준

1. 데이터의 크기: 얼마나 큰/많은 데이터

2. 데이터 온도: 얼마나 자주 액세스

3. 데이터 타입: 어떤 형태(key-value, document....)

4. 일관성: ACID

5. 부하 특성: 언제 얼마나 CRUD 부하가 발생하는가(read/write)

확장은 언제?

  • 개별 장비의 한계에 도달할 때 -> 키워야..
  • 증설보다 확장이 유리할 때

확장 방법

  • 샤드 - 어떻게 나눌지 미리 결정(초기에 같이 고민; 샤드가 가능하도록 디비 구성; 쓰기 분산 고민스러우면 초기에 샤드를 고려해)
  • 읽기 복제본 추가(중간 확장 시 가장 쉬움, 이중화가 되어 있기 때문에 어느 정도 되어 있음)
  • 디비 분산

 

보관기간은 기획자와 선상의해야 하며

파티셔닝 요청 시 기준이 되는 컬럼은 Datetime으로 하는 게 좋다..

timestamp는 2038년까진가 한계가 있는 값..

아카이브 저장소 - 백업용 디비; 안쓰는 디스크에 데이터 몰아둠.. 근데 쓰기만하고 읽지는 않더라..

 

샤딩 반영 시 관점이 다른 데이터를 가져올 때

1. common db 방식: 샤드에 갱신한 정보를 common db에도 업데이트; 다양한 관점에서 조회 가능

2. 캐시: 주요한 걸 캐시에 올려두고 상세는 별도로 조회해서 조합

3. 순환조회: 전체 샤드를 대상으로 조회하고 조합함.. 성능이 구려 서비스에 적용하진 않고 보통 통계 등에 사용


참고: 샤딩 vs 수평 파티셔닝

https://develaniper-devpage.tistory.com/100

 

[DataBase] 5. 파티셔닝/ 샤딩

1. 파티셔닝(Partitioning)/샤딩(Sharding) 데이터베이스를 여러개로 나누어 분산시키는 기술용어로, 서비스 크기의 증가에 따라 DB의 크기가 증가하면서 성능을 향상시키기 위한 것이다. 자료가 매우

develaniper-devpage.tistory.com

 

728x90
반응형

'개발 > sql' 카테고리의 다른 글

[mysql] merge into..?  (0) 2024.05.17
[mysql] 유저의 등수 구하기 rank under v8  (0) 2024.02.06
[형상관리] flyway vs liquibase  (0) 2022.07.08
[mysql] jsonpath  (0) 2022.05.27
[sql] case vs if  (0) 2022.05.02
반응형

요즘.. 디자인 패턴의 중요도 낮아짐

  • 개발환경 성숙: 프래임워크, 라이브러리 사용
    • 직접 구현할 필요 없음
  • 아키텍쳐의 변화: 모노리틱 -> MSA
    • 복잡성이 떨어지게 됨(구조같은데 좀 더 심플해짐)
  •  개발 언어의 변화(자바 1.8~)
    • 디자인패턴을 쓰지 않아도 해결할 수 있음(ex. 람다 등)

 

디자인 패턴?

소프트웨어 디자인 과정에서 자주 혹은 공통적으로 발생하는 문제들에 대해 재사용 가능한 해결책 혹은 형식화 된 가장 좋은 관행

 

알고리즘과의 차이점?

  • 실질적인 문제를 해결하기 위한 절차나 방법을 의미
    • 속도와 효율성(리소스)을 중요시(목표가 여기에 있음)
  • 패턴은 해결책에 대한 더 상위 수준의 설명 / 설계 구조 등 / 유지보수에 초점

 

바이블?ㅋ

왜 패턴?

  • 개발자 간의 원활한 협업이 가능
  • 소프트웨어의 구조를 파악하기 용이함
  • 재사용을 통해 개발 시간 단축
  • 설계 변경이 있을 경우 비교적 원활하게 조치가 가능

 

패턴에 대한 비판

  • 비 효율적인 해결책일 수 있음
    • Strategy패턴은 간단한 익명(람다) 함수로 구현할 수 있음
    • 많은 사람들이 이렇게 통합된 패턴들을 도그마처럼 신봉하여 패턴을 프로젝트의 맥락에 따라 적용하지 않고 문자 그대로 구현
    • 더 간단한 코드로도 문제 해결이 되는 상황에도 모든 곳에 패턴을 적용하려고 하는 패턴병에 걸리지 않도록 조심해야
    • 디자인 패턴은 모든 상황의 해결책이 아닌 코딩 방법론일 뿐이며 디자인 패턴에 얽매이지 말자

유지보수 쉽고 가독성 좋고 짧고 중복없고 객체지향 원칙에 맞는지 가 더 중요

 

객체지향 5대 원칙(SOLID)

> 높은 응집도와 낮은 결합도

  • SRP 단일 책임 원칙
    • proxy, aop
  • OCP 개방 폐쇄 원칙
    • 옵저버 패턴, if문 제거, 변경 발생 시 클래스 추가로 수정에는 닫혀있고 확장에는 열려있게
  • LSP 리스코프 치환
    • 다형성에 관한 원칙 제공; 상위 타입의 코드로 이뤄진 메서드에서 하위 타입으로 대신해도 메서드에는 아무 문제가 없어야 함
    • List list = new ArrayList(); <<- 받을 때 인터페이스로 하는게 맞다
  • ISP 인터페이스 분리 원칙
    • 거대 인터페이스를 쪼개서 기능별 인터페이스 분리
  • DIP 의존 역전 원칙
    • 인터페이스 호출; 구현체 변경으로 기능 변경 가능하도록 추상화에 의존해야함(구체화 의존 노노)

 

디자인 패턴 종류(23개)

https://m.hanbit.co.kr/channel/category/category_view.html?cms_code=CMS8616098823 

 

[Design pattern] 많이 쓰는 14가지 핵심 GoF 디자인 패턴의 종류

디자인 패턴을 활용하면 단지 코드만 ‘재사용’하는 것이 아니라, 더 큰 그림을 그리기 위한 디자인도 재사용할 수 있습니다. 우리가 일상적으로 접하는 문제 중 상당수는 다른 많은 이들이 접

m.hanbit.co.kr

생성 패턴

특정 객체가 생성되거나 변경되어도 프로그램 구조에 영향을 최소화 할 수 있도록 유연성 제공(ocp와 비슷)

 

추상 팩토리 패턴

  • (interface를 통해) 연관된 객체를 묶는데 초점

1. if else로 분기 겁나 많고 거기 안에서 로직 마니마니

2. switch..로 하고 거기 안에서 클래스호출(빈 등록이 계속되는 문제)

3. 중간 매소드인 팩토리 클래스를 만듦, 타입을 넘기고 거기 안에서 return service

맵으로 서비스를 가질 수 있음(Map<String, VehicleService> <- 빈 이름과 interface를 구현한 해당 빈)

나머지들이 그 interface를 구현

 

팩토리 매서드 패턴

  • 추상 팩토리 패턴과의 차이점
    • 팩토리 메서드 패턴은 어떤 객체를 생성할지에 집중
    • 추상 팩토리 패턴은 연관된 객체들을 모아둔다는 것에 집중(Factory)
  • 객체 생성을 서브클래스로 분리하여 위임(캡슐화)

 

빌더 패턴(@Builder)

  • 문제
    • 자바 빈즈 패턴(facet): data/getter/setter 사용
    • 점층적 생성자 패턴(생성자 파라미터 갯수별로 생성자 만드는거)
      • : 인자가 많아지면 생성자도 많아지지고
        • 3개 이상은 생성자 사용하지 말고 빌더를..
      • : 순서도 헷갈림
  • 빌더 패턴의 장점
    • 필요한 데이터만 설정
    • 유연성을 확보
    • 가독성을 확보
    • 불변성을 확보
      • 그 후에 set하면 안됨?? setter가 있으면 되고 없으면 안되고(setter를 선언하면 안되겠지)

 

프로토타입 패턴

  • JPA -> entity를 내리면 영속성이 유지될 수 있음
  • 별도의 dto 리턴(model mapper, mapstruct)하므로써 영속성을 끊는게 맞고
  • 변환하는 걸 프로토타입 패턴이라고 함
    • OSIV default true 

https://bangpurin.tistory.com/36

 

[jpa] OSIV란; spring.jpa.open-in-view

OSIV에 대한 이해를 하려면 영속성 컨텍스트가 뭔지 알아야한다. 이전 글을 참고하자. 2022.01.27 - [개발/spring] - [jpa] 영속성 컨텍스트 in spring [jpa] 영속성 컨텍스트 in spring 영속성 컨텍스트? 엔티티

bangpurin.tistory.com

Member member = memberService.saveMember(snsType, token);
member.setSnsType("kakao"); /////<<<<<<<-- 여기서 실수하면 반영됨 상하로 트랜잭션이 있어서
memberService.emptyLogic();

=> dto 리턴 시 해결!

 

싱글톤 패턴

  • 한 클래스마다 인스턴스를 하나만 생성하여 어디서든 참조
  • 병렬로 여러 스레드에서 돌릴 경우 조심
  • 직접 구현할 일 적음(스프링 빈)
  • 장점
    • 새로운 인스턴스를 계속해서 생성하지 않으므로 메모리 낭비가 적음
  • 단점
    • 코드량 많고, 테스트 어렵고, 자식 클래스 만들기 어렵, 클라이언트가 구체 클래스에 의존(dip 위반)
    • 스프링이 모두 해결해 줌!
public class SingletonService {
    private static final SingletonService instance = new SingletonService();

    public static SingletonService getInstance() {
        return instance;
    }

    // 생성자를 private으로 적용시켜 외부에서 인스턴스 생성을 막는다
    private SingletonService() {

    }
}

구조 패턴

클래스나 객체를 조합하여 더 큰 구조를 만들 수 있게 해줌

 

어댑터 패턴

  • 타사의 라이브러리를 호출부의 변경 없이 사용하고 싶을 경우
  • Array.AsList(), Collections.enumeration(), Collections.list() 등도 어댑터 패턴을 활용한 예시
@Service
@Primary //얘랑 동일한 빈이 있어도 이게 우선이다라고 해줘야(override)
public class MailAdapter implements MailSenderA {
    private final MailSolutionB mailSolutionB;

    @Override
    public void send(MailSolutionA.MailParam mailParam) {
        MailSolutionB.MailParam param = MailSolutionB.MailParam.builder().mailTitle(mailParam.getTitle())
                .mailBody(mailParam.getBody()).receiverEmail(mailParam.getEmail()).build();
        mailSolutionB.sendApi(param);
    }
}
  • 위 처럼 A -> B로 바꿀 때, 기존 호출부를 그대로 두고
  • A를 쏘는 것 처럼 보이지만 사실 B로 쏘는 것
  • Interface를 써야 구현체를 교체할 수 있음 그래야 primary로 오버라이딩이 가능
  • 모든 부분을 다 고치지 않고 한 곳만 고칠 때 좋음

 

브릿지 패턴

  • 기능의 구현 클래스를 런타임 때 자유롭게 지정이 가능
    • 주입을 set을 이용하여 동적으로 받음
  • 기능과 구현을 분리하여 구현이 변경되더라도 기능 클래스 부분에 대한 변경은 필요 없음
if (StringUtils.isNotEmpty(member.getAccountNumber())) {
    paymentService.setPaymentMethod(new CardMethodService()); // <<-- 서비스 주입을 런타임에
} else if (StringUtils.isNotEmpty(member.getPhoneNumber())) {
    paymentService.setPaymentMethod(new PhoneMethodService());
}
paymentService.pay1(order.getAmount(), member);

 

컴포지트 패턴

  • 일반적으로 직접 구현하지 않음
  • 클라이언트 전체와 부분을 구별하지 않고 동일한 인터페이스로 사용
  • 트리구조와 상당히 유사한 성격을 가지고 있다
  • 하지만 기능이 너무 다른 클래스들에는 공통 인터페이스를 제공하기 어려움

 

데코레이터 패턴

  • 일반적으로 직접 구현하지 않음
  • 기존 코드를 수정하지 않고도 행동을 확장 가능
  • 객체를 여러 데코레이터로 래핑하여 여러 행동들을 합성 가능
  • 데코레이터를 너무 많이사용하면 코드가 필요 이상으로 복잡해짐
  • file, buffered reader 등등 New로 만들어서 래핑해서 합성하는 것

 

퍼사드 패턴

  • 복잡한 로직들을 숨기고 간단한 인터페이스 함수만을 호출(추상화)
  • 우리는 이미 MVC패턴을 통해서 퍼사드 패턴을 알게 모르게 사용하고 있다.

 

플라이웨이트 패턴

  • 일반적으로 직접 구현하지 않음
  • 인스턴스가 필요할 때마나 매번 생성하는게 아니라 가능한 공유해서 메모리를 절약
    • 캐시, 레디스.. 디비 접근 최소화
  • String 객체를 생성하는 리터럴 방식의 String Constant Pool이 대표적인 플라이웨이트 패턴을 적용한 예시
  • https://www.baeldung.com/java-string-constant-pool-heap-stack
@Test
void 스트링_플라이웨이트패턴_테스트() {
    String str1 = "Hello";
    String str2 = "Hello";
    String str3 = new String("Hello");

    // 서로 같다!
    Assertions.assertSame(str1, str2);

    // 서로 다르다!
    Assertions.assertNotSame(str1, str3);

    // 서로 같다!
    Assertions.assertSame(str1, str3.intern());

    /*
        클래스가 JVM에 로드되면 모든 리터럴은 constant pool에 위치하게 된다.
        그리고 리터럴을 통해 같은 문자를 생성한다면 풀 안의 같은 상수를 참조하게 되는데 이를 String interning이라고 한다.
        String을 리터럴로 생성될 때 intern()이라는 메서드가 호출되고 이 intern() 메서드는
        constant pool에 같은 문자가 존재하는지 확인 후 존재한다면 그 참조 값을 가지게 된다.
     */
}
@Test
void Integer_플라이웨이트패턴_테스트() {
    Integer integer1 = Integer.valueOf("123");
    Integer integer2 = Integer.valueOf("123");

    // 서로 같다!
    Assertions.assertSame(integer1, integer2);


    Integer integer3 = Integer.valueOf("128");
    Integer integer4 = Integer.valueOf("128");

    // 서로 다르다!
    Assertions.assertNotSame(integer3, integer4);

    //직접 Integer.valueOf 함수 까보기!
    //-128 ~ 127 까지는 캐싱이라 같고 그 이외 값은 캐싱안하고 새롭게 인스턴스 생성이라 다름
}

 

프록시 패턴

  • SRP와 연관
  • 공통되는 로직 빼서 모듈화
  • AOP(aspect oriented programming; cglib etc..)
    • OOP로 독립적으로 분리하기 어려운 부가 기능을 모듈화 하는 방식
    • oop를 더 oop스럽게 해주는 방법
    • 객체지향을 더 객체지향스럽게 만들어 주는 프로그래밍
  • transactional, cache, test에 사용하는..
  • spring 큰 특징 : DI, AOP(aspect), PSA(portable service abstraction)
import com.example.pattern.order.service.OrderService;
import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.context.annotation.Configuration;
import org.springframework.objenesis.SpringObjenesis;

@Configuration
public class ProxyConfig {
    private final SpringObjenesis objenesis = new SpringObjenesis();

    @Bean
    @Primary //order service말고 프락시를 빈으로 등록하도록 해야 aop 적용
    public OrderService orderServiceProxy() {
        return (OrderService) createCGLibProxy(OrderService.class, new MethodCallLogInterceptor());
    }

    private Object createCGLibProxy(Class<? extends Object> targetClass, MethodInterceptor interceptor) {
        // Create the proxy
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(targetClass);
        enhancer.setCallback(interceptor);
        return enhancer.create();
    }
}

행동 패턴

반복적으로 사용되는 객체들의 커뮤니케이션을 패턴화, 결합도를 최소화 하는 것이 목적

 

책임 연쇄 패턴

스프링 필터 사용(필터 체인)

  • 검증 절차는 자유롭게 추가될 수 있어야 하고, 순서도 자유롭게 변경할 수 있어야 할 때 
  • 기존 클라이언트 코드를 수정하지 않고 앱에 새 핸들러를 도입 가능
@Configuration
public class FilterConfig {
    //    @Bean
//    @Order(0)
    public FilterRegistrationBean userAgentCheckFilter() {
        FilterRegistrationBean registrationBean = new FilterRegistrationBean(new UserAgentCheckFilter());
        registrationBean.addUrlPatterns("/orders/*");
        return registrationBean;
    }

    //    @Bean
//    @Order(1)
    public FilterRegistrationBean memberCheckFilter() {
        FilterRegistrationBean registrationBean = new FilterRegistrationBean(new MemberCheckFilter());
        registrationBean.addUrlPatterns("/orders/*");
        return registrationBean;
    }
}

 

커맨드 패턴

  • 잘 사용하지 않음
  • 기존 클라이언트 코드를 수정하지 않고 새로운 커맨드들을 도입 가능
  • 요청부와 동작부를 분리시켜 주기 때문에 결합도를 낮출 수 있음
  • 보통 비동기
@Test
void 혜택_발송_스레드_테스트() throws InterruptedException {
    int numberOfThreads = 5;
    CountDownLatch latch = new CountDownLatch(numberOfThreads);
    //ExecutorService 객체가 Invoker를 의미
    ExecutorService executorService = Executors.newFixedThreadPool(numberOfThreads);
    for (int i = 0; i < numberOfThreads; i++) {
        //Runnable 구현 객체가 Command를 의미;
        // runnable interface 특징? 구현할 함수가 1개, callable과 디르게 반환타입이 없음
        //CouponApiService 객체가 Receiver를 의미
        Runnable doThread = new CouponService(new CouponApiService());
        //위 대신 lambda로 대체가능
        executorService.execute(() -> {
            doThread.run();
            latch.countDown();
        });
    }
    latch.await();
}

Runnable -> void

Callable -> return 있음

 

반복자 패턴

  • 잘 사용하지 않음
  • 혜택이 아이템을 어떻게 구현하였는지 호출하는 쪽에서는 알 필요가 없음
    • 즉 캡슐화가 잘 되어 있음
  • 내부 구현을 외부로 노출시키지 않으면서도 모든 항목에 접근 가능
  • 적용 시 덜 효율적이거나 과도하지는 않은지 확인

 

옵저버 패턴

  • 한 객체의 상태가 변경되어 다른 객체들을 변경해야 할 필요성이 생겼을 때 사용(Pub/Sub 패턴이라고도 함)
  • message push, pull 하는 방식을 통해 결합도를 낮출 수/없앨 수 있음 
    • rabbitMQ, kafka 등
  • 느슨한 결합으로 객체간의 의존성 제거
  • 너무 많이 사용하게 되면 상태 관리가 힘듦
private final ApplicationEventPublisher eventPublisher;

//함수 내부에서 호출 publish
   eventPublisher.publishEvent(new OrderEvent(order.getId(), OrderType.CREATE));
   
//

import com.example.pattern.order.model.OrderEvent;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.event.EventListener;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;

@Component
@Slf4j
@Async
public class OrderListener {
    @EventListener
    public void onApplicationEvent(OrderEvent event) {
        log.info("주문이벤트 Published [orderId : {}, orderType : {}]", event.getOrderId(), event.getOrderType().toString());
        log.info("이후 리뷰 알림 발송이 시작됩니다.");
        log.info("이후 정산 API 호출이 시작됩니다.");
    }
}

 

중재자 패턴

  • 옵저버 패턴
    • 1개의 publish에 대해 N개의 subcriber가 존재하고, observer가 pulling 이나 push방식을 통해 관리
  • 중재자 패턴
    • M개의 publisher와 N개의 subcriber 사이에서 1개의 mediator를 통해 통신

 

메멘토 패턴

  • 상태정보 저장 관련 메모리에 들고 있을 일 없음; 잘 사용하지 않음
  • 캡슐화를 위반하지 않고 객체의 state 스냅샷을 생성할 수 있음
  • 메멘토를 너무 자주 생성하면 많은 Ram을 소모할 수 있음

 

상태 패턴

  • 잘 사용하지 않음

 

전략 패턴

  • 하나의 메시지와 책임을 정의하고 이를 수행할 수 있는 다양한 전략을 만든 후, 다형성을 통해 전략을 선택해 구현을 실행
  • 유사한 패턴들
    • 팩토리, 추상 팩토리, 브릿지, 커맨드 패턴 등 이미 사용 중
  • 특징
    • OCP 준수, 하지만 과도하게 복잡해질 수 있음

 

템플릿 메서드 패턴

  • 잘 사용하지 않음, 요즘은 implement
    • interface는 내부 instance를 둘 수 없음 -> 필요 시 abstract class 를 사용
  • 상속을 통해 슈퍼 클래스의 기능을 확장할 때 사용하는 대표적인 방법
  • 변하지 않는 기능은 슈퍼 클래스에 만들어 두고, 확장할 기능은 서브 클래스에서 만듦
  • 단점
    • 알고리즘 변경 시 거의 모든 클래스에 수정이 가해질 수 있음
    • 상속의 단점.. 결합이 커서 
public abstract class Review { //abstract 사용예시
    public void review() {
        //부모 클래스에서 알고리즘의 골격을 정의
        login();
        selectBooks();
        putContent();
        selectEvaluation();
    }

    public void login() {
        log.info("로그인 성공!");
    }

    public void selectBooks() {
        log.info("리뷰 대상 상품 선택");
    }

    public void selectEvaluation() {
        log.info("별점 선택");
    }

    public abstract void putContent(); //

}

 

방문자 패턴

  • 잘 사용하지 않음
  • 맴버는 맴버 클래스로, 리워드는 리워드 클래스로.. 둘을 섞지 않는다
  • OCP : 다른 클래스를 변경하지 않으면서 새로운 행동 도입 가능
  • SRP : 같은 행동의 여러 버전을 같은 클래스로 이동할 수 있음
public class PointBenefit implements Benefit {
    @Override
    public void getBenefit(GoldMember member) {
        log.info("골드 멤버를 위한 포인트 제공 혜택");
    }

    @Override
    public void getBenefit(VIPMember member) {
        log.info("VIP 멤버를 위한 포인트 제공 혜택");
    }

    @Override
    public void getBenefit(SilverMember member) {
        log.info("실버 멤버를 위한 포인트 제공 혜택");
    }
}
public class GoldMember implements Member {
//    public void point() {
//        log.info("골드 멤버를 위한 포인트 제공 혜택");
//    }
//    public void discount() {
//        log.info("골드 멤버를 위한 할인 혜택");
//    }

    @Override
    public void getBenefit(Benefit benefit) {
        benefit.getBenefit(this);
    }
}
728x90
반응형
반응형

환경: java8

엑셀 다운로드 기능을 서버에 배포하면 NPE가 나면서 안되는 현상, 특이사항으로는 배포 시 되는 서버가 있고 안되는 서버가 있었음

org.apache.poi.hssf.usermodel.HSSFSheet.autoSizeColumn(HSSFSheet.java:1937)

 

에러 발생 코드

workbook.getSheetAt(0).autoSizeColumn(colIndex);

 

소스 상 딱히 null이 날 곳이 없었다.

 

되는 곳이 있고 안되는 곳이 있어, 환경의 문제에서 나온게 아닌가 싶어 구글링 하던 중 아래 글들을 보게된다.

설마 싶어 되는 서버와 안되는 서버의 자바 내 폰트 설정파일을 확인해보니

진짜 폰트 설정 파일(fontconfig.properties)이 있는 곳에서는 되고 없는 곳에서는 안되었다..

 

서버 담당자한테 말했더니 아래를 설치해주셨고, 설정 파일이 생기면서 이슈 해결

sudo yum install fontconfig dejavu-sans-fonts dejavu-serif-fonts
vi /usr/local/jdk8/jre/lib/fontconfig.properties

-----------

version=1
sequence.allfonts=default

참고

https://m.blog.naver.com/PostView.naver?isHttpsRedirect=true&blogId=amabile29&logNo=222292712456 

 

OpenJDK8 version upgrade - Font Issue

OpenJDK에는 폰트 파일이 있지 않아서 업그레이드 후 Excel 파일 생성 등 폰트가 필요한 부분에서 에...

blog.naver.com

 

https://github.com/adoptium/adoptium-support/issues/70

 

There was no fonts in Linux version · Issue #70 · adoptium/adoptium-support

From @JamesMung on October 23, 2018 3:54 JDK Version ; jdk8u181-b13 When I use jasper print PDF in Windows is fine, but for Linux found the error as follow: Caused by: net.sf.jasperreports.engine.J...

github.com

 

728x90
반응형

'개발 > java' 카테고리의 다른 글

[java] orElse vs orElseGet  (0) 2023.10.11
디자인 패턴  (0) 2023.07.11
[java] lambda stream and final  (0) 2023.02.06
[google admob] ssv 콜백 적용  (0) 2023.01.06
[Date] java8 이하에서 날짜 timezone 변환  (0) 2022.11.04
반응형

이슈

- build 시 intelliJ면 아래와 같은 에러가 남

- gradle 일 경우 에러 안 남

 

해결

- interface일 경우 @PathVariable에 name 을 명시

 

참고

https://shanepark.tistory.com/331

728x90
반응형

+ Recent posts