Cannot find module 'msw/node' 에러 해결

 

NEXT.js 14버전 환경에서 jest를 사용한 테스트 환경 구축중에 

api요청등의 문제를 모킹서버로 해결하기 위해 

msw설치후 테스트를 돌렸는데 

 

msw/node 를 찾지 못한다는 에러가 발생을 하였다.

분명 패키지제이슨엔 설치가 되어 있는데도 오류가 발생하고 있어 

chatGpt에 물어봐도 다시 설치하라는 말만 하고 있어 다른 방법을 찾아 보던중

 

https://github.com/mswjs/msw/issues/1786

 

"Cannot find module 'msw/node'" in Jest JSDOM environment · Issue #1786 · mswjs/msw

Prerequisites I confirm my issue is not in the opened issues I confirm the Frequently Asked Questions didn't contain the answer to my issue Environment check I'm using the latest msw version I'm us...

github.com

이곳의 글을 확인 하였고 코멘트에서 해결방법을 찾았다.

 

jest.config.ts 파일의 설정중에 

testEnvironmentOptions: {
    customExportConditions: [""],
  },

이부분을 추가 하면 된다. 

에러가 난 이유를 설명한걸 해석해 보자면

 

JSDOM이 내보내기 조건을 강제하기 때문입니다 browser.

즉, JSDOM은 "타사 패키지가 browser필드를 내보내는 경우 해당 필드를 사용하십시오"라고 말합니다.

그것이 기본값이고 다소 위험한 기본값입니다. 왜? JSDOM은 여전히 ​​Node.js에서 실행되기 때문입니다 .

게다가 JSDOM은 설계상 100% 브라우저 호환성을 가질 수 없으므로 browser내보내기 조건을 강제하면

MSW와 같이 다양한 환경에 대해 다양한 코드를 제공하는 패키지로 작업할 때 테스트가 필요 이상으로 실패하게 됩니다.

이렇게(위와 같은 설정을) 하면 JSDOM이 올바른 동작인 node(또는 ) 내보내기 조건을 사용하게 됩니다 .default

이번 변경 이후 다른 수입 관련 문제가 발생하는 경우 관련이 없으므로 별도로 처리해야 합니다.

모든 사람이 따를 수 있도록 이 권장 사항을 마이그레이션 가이드에도 추가합니다.

 

라고 한다. 

org.springframework.web.reactive.function.client.WebClientRequestException: readAddress(..) failed: Connection reset by peer; 오류 해결

 

현재 프론트엔드로 개발하고 있는데 간헐적으로 서버를 통해 외부 API를 요청할때 오류가 발생하는것을 확인 했다.

여기저기 찾아보니 

WebClinet를 사용해서 외부에 요청을 보낼때 대상서버의 연결이 닫혔을때 나타나는 오류 라고 한다. 

일단 의심이 가는 시나리오는

우리쪽 A서버에서 외부 B서버로 API 요청을 보내고 커넥션을 맺을때 B서버가 중간에 재실행 혹은

별도의 문제로 서버다운이 발생하는 경우라고 생각하여 해당 업체에 문의해본 결과

서버가 내려간적은 없다고 한다. 

 

두번째 시나리오는 B서버가 로드밸런서를 사용해 A서버에서 최초 요청시 B-1에 커넥션을 맺고 통신을 하다

다시 요청시에는 B-2 서버로 요청을 하는 경우

세번째는 로드밸런서 자체의 타임아웃이 A서버보다 빠른 경우

 

확인을 위해 해당 업체에 문의한결과 로드밸런서를 사용중이며 타임아웃이 10분이라고 한다.

 

오류 재현을 위해 테스트해보니 최초 요청 이후 10분후 재요청을 했을 경우에만 동일한 오류가 나는것을 확인하고

세번째 문제가 이유라고 판단 하였고 

다른분들이 작성한 깃이나 블로그의 도움을 받아 수정 할수 있도록 백엔드 팀에 전달하였다.

문제 해결을 위해 참고한 블로그및 사이트들이다.

참고 사이트

https://velog.io/@youngerjesus/Connection-Reset-by-Peer-%EB%AC%B8%EC%A0%9C-%ED%95%B4%EA%B2%B0

 

Connection Reset by Peer 문제 해결

Client 가 요청을 보냈는데 서버쪽에서 연결이 닫혔다고 다시 연결하라는 RST (Reset) 패킷을 보내는 경우에 이 에러가 발생한다.Connection prematurely closed BEFORE response 이렇게 쓰기도 한다. Client-Server 연

velog.io

https://jskim1991.medium.com/spring-boot-how-to-solve-webclient-connection-reset-by-peer-error-b1fa38e4106a

 

[Spring Boot] How to solve WebClient Connection reset by peer error

I had a requirement to fetch user data from an external system. It was implemented using WebClient as part of declarative http client…

jskim1991.medium.com

https://github.com/reactor/reactor-netty/issues/1774

 

Connection reset by peer exception · Issue #1774 · reactor/reactor-netty

We have a micro service based spring boot architecture where we are using spring webclient (which internally uses reactor netty) for internal communication between services. The issue that we faced...

github.com

 

 

해결방법

일단 해결 방법은 B서버 로드밸런서의 타임아웃시간에 도달하기 전에 우리쪽에서 먼저 연결을 해제하고

다시 커넥트를 거는것으로 해결 하였고 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
@Configuration
public class HttpProxyConfiguration {
 
    @Value("${tracker.url}")
    private String trackerUrl;
 
    @Bean
    TrackerClient trackerClient(WebClient.Builder builder) {
        ConnectionProvider provider = ConnectionProvider.builder("fixed")
                .maxConnections(500)
                .maxIdleTime(Duration.ofSeconds(20))
                .maxLifeTime(Duration.ofSeconds(60))
                .pendingAcquireTimeout(Duration.ofSeconds(60))
                .evictInBackground(Duration.ofSeconds(120)).build();
 
        HttpClient httpClient = HttpClient.create(provider);
        httpClient.warmup().block();
 
        var reactorClientHttpConnector = new ReactorClientHttpConnector(httpClient);
 
        var wc = builder.baseUrl(trackerUrl)
                .clientConnector(reactorClientHttpConnector)
                .build();
 
        var wca = WebClientAdapter.forClient(wc);
        return HttpServiceProxyFactory.builder()
                .clientAdapter(wca)
                .build()
                .createClient(TrackerClient.class);
    }
}
cs

 

이 코드를 참조하여 문제를 수정한것을 확인 할 수 있었고

위 코드의 각 부분의 설명을 보자면

  1. @Value("${tracker.url}"): 이 어노테이션은 tracker.url이라는 이름의 프로퍼티 값을 trackerUrl 변수에 주입(inject)합니다. 이 프로퍼티 값은 외부 트래커 서비스의 기본 URL을 포함하며, 애플리케이션 구성 파일(예: application.properties 또는 application.yml)에서 정의됩니다.
  2. TrackerClient trackerClient(WebClient.Builder builder) 메서드: 이 메서드는 TrackerClient 인터페이스의 구현체를 생성하고 구성합니다. 이 인터페이스는 외부 트래커 서비스와의 통신을 위한 메서드를 정의합니다.
  3. ConnectionProvider 설정: ConnectionProvider는 WebClient의 네트워크 연결을 관리하는 데 사용됩니다. 여기서는 최대 연결 수, 최대 유휴 시간, 연결의 최대 수명, 대기 중인 연결 획득 타임아웃 등을 설정합니다. 이 설정은 서비스와의 통신 중 발생할 수 있는 다양한 시나리오를 관리하기 위한 것입니다.
  4. HttpClient 생성 및 설정: HttpClient.create(provider)를 사용하여 ConnectionProvider를 사용하는 HttpClient 인스턴스를 생성합니다. httpClient.warmup().block() 호출은 HttpClient를 "온기"시키며, 네트워크 연결을 미리 설정하여 첫 번째 요청의 지연 시간을 줄이는 데 도움이 됩니다.
  5. WebClient 구성 및 생성: WebClient.Builder 인스턴스에 기본 URL, 클라이언트 커넥터 등을 설정하여 WebClient 인스턴스를 생성합니다. 이 WebClient 인스턴스는 TrackerClient의 HTTP 요청을 실행하는 데 사용됩니다.
  6. HttpServiceProxyFactory를 사용한 TrackerClient 생성: 마지막으로, HttpServiceProxyFactory와 WebClientAdapter를 사용하여 WebClient를 기반으로 하는 TrackerClient 인스턴스를 생성합니다. 이를 통해 외부 트래커 서비스와의 통신을 위한 프록시 클라이언트를 얻게 됩니다.

 

이렇게 정리될수 있으며 ConnectionProvider의 옵션은

  • builder("fixed"): 연결 풀의 이름을 "fixed"로 설정합니다. 이 이름은 로깅이나 디버깅 시 해당 연결 풀을 식별하는 데 사용될 수 있습니다.
  • maxConnections(500): 연결 풀이 동시에 유지할 수 있는 최대 연결 수를 500개로 설정합니다. 이는 애플리케이션이 동시에 열 수 있는 최대 연결 수를 의미하며, 이 한도를 초과하는 연결 요청은 대기 상태가 될 수 있습니다.
  • maxIdleTime(Duration.ofSeconds(20)): 연결이 유휴 상태(즉, 데이터를 전송하지 않는 상태)로 있을 수 있는 최대 시간을 20초로 설정합니다. 유휴 시간이 이 값을 초과하면 연결이 자동으로 종료됩니다.
  • maxLifeTime(Duration.ofSeconds(60)): 연결이 생성된 후 유지될 수 있는 최대 시간을 60초로 설정합니다. 이 시간이 지나면, 연결은 사용 여부에 관계없이 종료됩니다.
  • pendingAcquireTimeout(Duration.ofSeconds(60)): 연결을 획득하기 위해 대기하는 최대 시간을 60초로 설정합니다. 연결 풀에서 사용 가능한 연결을 얻기 위해 이 시간을 초과하여 대기하는 요청은 실패하게 됩니다.
  • evictInBackground(Duration.ofSeconds(120)): 비활성 연결을 정리하는 배경 작업의 실행 간격을 120초로 설정합니다. 이 설정은 연결 풀에서 오래되거나 더 이상 필요하지 않은 연결을 주기적으로 제거하는 데 사용됩니다.

위와 같다.

기존코드는 위의 옵션에 대한 별도의 설정이 없었기에 해당 오류가 발생하였었다.

write /var/lib/docker/tmp/GetImageBlob3644316352: no space left on device 오류 해결

 

현상

요청사항 수정후 개발서버 브런치에 머지까지 끝냈는데 

해당 화면에 수정된 내용이 반영이 되지 않는 현상이 있었다.

젠킨스에 접속해 로그를 확인해봤다.

동일 스텝에서 성공적으로 돌아갔을때와 실패했을때를 비교해보니 

실패한 경우의 로그에서 no space left on device 라는 로그가 있었고 

확인해보니 디스크 공간 부족이 이유 였다. 

이 메시지는 젠킨스 빌드 도중에 Docker 이미지를 작성하거나 가져오려고 할 때 발생하는 오류라고 한다.

이 오류의 핵심은 "no space left on device"로, 이는 Docker가 실행 중인 서버의 디스크 공간이 부족하여

더 이상 데이터를 저장할 수 없을때 나타나는 이유라고 한다. 

해결방법

1. 디스크 공간 확인:

먼저 서버에서 사용 가능한 디스크 공간을 확인하세요. df -h 명령어를 사용하면 현재 디스크 사용량과 사용 가능한 공간을 볼 수 있습니다.

2. 불필요한 Docker 이미지 및 컨테이너 정리:

Docker 이미지와 컨테이너는 시간이 지남에 따라 상당한 양의 디스크 공간을 차지할 수 있습니다. 불필요한 이미지, 컨테이너, 볼륨, 네트워크를 정리하여 공간을 확보할 수 있습니다. 다음 명령어를 사용할 수 있습니다:
불필요한 컨테이너 정리: docker container prune
사용하지 않는 이미지 정리: docker image prune -a
사용하지 않는 볼륨 정리: docker volume prune
사용하지 않는 네트워크 정리: docker network prune
위의 모든 것을 한 번에 정리: docker system prune -a


3.디스크 확장: 

서버의 디스크 공간이 지속적으로 부족한 경우, 디스크를 확장하는 것을 고려해야 할 수 있습니다. 이는 서버의 구성과 사용 중인 클라우드 서비스 제공업체에 따라 달라질 수 있습니다.
로그 파일과 임시 파일 확인: 디스크 공간을 많이 사용하는 다른 원인으로는 크기가 큰 로그 파일이나 임시 파일이 있을 수 있습니다. 이러한 파일들을 정기적으로 확인하고 필요하지 않은 경우 삭제하여 공간을 확보하세요.
저장 정책 검토: Docker 및 Jenkins와 같은 도구들의 저장 정책을 검토하고 조정하여, 필요 이상으로 많은 데이터가 저장되지 않도록 할 수 있습니다.

 

 

라고 GPT가 알려주고 있다. 

 

얼마전 예전에 공부용으로 만들어 뒀던 프로젝트에서 사용하는

MLab mongoDB 서비스가 atlas로 통합된다고

atlas로 마이그레이션 하지 않으면 데이터가 다 날아갈 것이라는 내용의 메일이 날아 왔었다.

 

당장 데이터가 날아간다는데 부랴부랴 마이그레이션 문서 찾아서 하라는대로 해서 

 

데이터를 옮겨놓고 클러스터 만들어서 굴려놓긴 했는데 

서비스하는곳이 바뀌면서 접속 URL이 달라져버렸다

 

기존엔

 

mongodb://[사용자]:[비밀번호]@ds145389.mlab.com:45389/[DB]

이런식이었는데

Atlas로 바뀌면서

mongodb+srv://[사용자]:[비밀번호]@cheesustudy.ujge0.mongodb.net/[DB]?retryWrites=true&w=majority

이렇게 형식이 많이 바뀌었다

url만 바꾸면 되는줄 알고

nodejs db 커넥트 하는 부분에서 URL을 바꿨는데

에러가 뜬다

 

대충 에러 내용은 접속 url형식이 +srv << 이렇게 된건 못쓴다는 내용이었다.

 

구글링을 해보니 mongoose 예전 버전에서는 저 url방식으로 접속이 불가능 하다는 것.

 

다른 방법은 없고 일단 몽구스 버전부터 올려야 했다.

 

3년전인가 4년전에 만들어 놓고 놔뒀던 소스라 잘 될까 했는데

 

역시 안된다.

몽구스 버전 업데이트를 하는데 의존성에 엮여있는것들이 나오고

 

그것들도 버전이 낮아서 제대로 안된다는 내용..;;

 

어차피 예전에 쓰던 노트북에 있던 프로젝트였고

 

현재 집에서 쓰는 데스크탑에선 셋팅한적이 없으므로 아얘 

 

데스크탑에서 새로 셋팅을 하기로 했다.

 

node설치하고 npm으로 새로 싹다 받아서 

 

예전에 깃에 올려뒀던 소스 받고 몽구스 버전만 바꾸어 주었다.

 

혹시 나처럼 mlab 쓰다가 atlas로 강제 이전하게 되었는데

 

디비 접속 오류 나는 사람은 그냥 싹 밀고 버전업 하면 될 것이다.

 

 

 

[달빛조각사] 달빛 조각사 서버

 

 

현재 사전 예약을 받고 있는 달빛 조각사의 서버가

 

엘릭서(Elixir)로 만들어 졌다고 한다.

 

출처: 네이버 포스트

 

https://m.post.naver.com/viewer/postView.nhn?volumeNo=19418083&memberNo=11255530

 

송재경 개발 ‘달빛조각사’, NDC에서 첫 정보공개

[BY 게임인사이트] 엑스엘게임즈가 개발 중인 모바일 MMORPG 달빛조각사가 NDC에서 모습을 드러냈다. 201...

m.post.naver.com

.

 

 

판타지 소설 좋아하는 사람들한테 엘릭서는

 

능력치를 영구히 증가시켜주거나 반시체도 살려내는 마법의 물약으로

 

알고 있는 사람이 더 많을텐데 

 

엘릭서(Elixir)는 얼랭(Erlang) 가상머신(VM) 위에서 동작하는

 

함수형, 동시성 프로그래밍 언어이다.

 

 

 

 

 

2019 개발자 컨퍼런스(NDC)에서 공개한 내용이라고 하는데

 

와 엘릭서로 게임서버를 만들줄이야..

 

저거 서버 뻑나거나 서버 개발자 그만둬버리면

 

다음 개발자 뽑기 좀 빡셀 것 같다

 

엘릭서가 유명한 언어긴 하지만 다른 언어들에 비해서

 

능숙히 다룰줄 아는 사람이 적은데 ㄷㄷ

 

문제는 달빛조각사를 개발한

 

엑스엘게임즈의 김민욱 서버개발 담당자 조차 

 

달빛조각사를 개발하면서 처음으로 접한 언어라고 한다;;

 

물론 아주 대단하신 개발자 분이시고 경험도 많으시니 큰 문제는 생기지 않겠지만

 

음... 사실 개발자 입장에서 처음 접한 언어로의 개발은 가능하긴 한데

 

갑자기 생긴 이슈에 대해선 대처 속도가 느릴 수 밖에 없기에

 

오픈하거나 업데이트 이후 발생하는 오류 처리 속도(여기선 정기점검의 연장 가능성)를

 

얼마나 빠르게 제어할 수 있을지가 궁금하다.

 

 

포스팅을 읽어 보니

 

또한 자동 코딩 포맷팅 기능과 더불어 빠른 컴파일 속도, 경량화된 프로세스(ligh-weight process), 마이크로 서비스, 빠른 이터레이션, 메모리 문제로부터의 해방(단, 메모릭 릭은 해결하지 못함), 타이밍 문제로 인한 고생이 덜하다는 것 등이 강점이다.

 

 

라는 문구가 있는데 저기서 - 메모리 릭은 해결하지 못함 -  이부분이... ㄷㄷㄷ

 

저 포스팅은 올해 4월에 포스팅된 글이니 지금은 아마 전부 해결 했겠지 하는 믿음을 가져 본다...;;;

 

 

마지막으로

 

엘릭서는 높은 가용성을 가지고 있고 높은 생산성을 가지고 있는 언어 이기 때문에

 

초기 단계에 있는 게임의 빠른 대규모 업데이트라던지 새로운 컨텐츠의 꾸준한 증가를 기대 해 볼 수 있을 것 같다.

 

 

 

 

 

[검은사막 모바일] 게임 튕김 해결 방법





검은사막 플레이 하다 튕기는거 해결 방법 입니다.



핸드폰 디스플레이 해상도 설정을 좀 낮춰서 FHD로 하면



튕김현상 많이 사라짐

[테라M] 에러코드 65538 계정연동 오류, 푸쉬알림 오류



현재 아이폰에서 발생하는 대표적인 오류 두가지는 


에러코드 65538 계정연동 오류, 푸쉬알림 오류 이 두가지일 것이다


푸쉬알림 오류는 일종의 권환오류중 하나라고 생각되어 진다.


녹스에서도 동일한 오류가 발생하고 아이폰에서 발생한다는 점에서


개인적인 뇌피셜로는 권한관련 오류일듯 한데


이건 금방 고쳐질것 같다. 게임하는데 지장도 없으니 큰 문제도 없는데


문제는


에러코드 65538이다


로그인 오류 : 앱에 로그인하시는데 오류가 발생했습니다. 나중에 다시 시도하세요



라는 문구가 나타나는데


안드로이드에서 계정연동 후


아이폰기기로 다시 계정 연동할때 나타나는 에러다



안드로이드에서 키워놓은거 폰바꿔서 아이폰으로 연동하려는데


그게 안되면


얼마나 빡치겠는가.



개인적인 해결 방법은



안드로이드에서 계정 연동을 먼저 했다 아이폰으로


옮겨야 하는경우




1. 아이폰에 설치된 테라의 캐쉬데이터를 전부 지우고 다시 연동을 시도 한다



2. 1번이 안되면  PC에 녹스 설치후 녹스에 테라M을 설치한 다음 녹스에서 페북 연동을해 캐릭터를 가져온다.

   그리고 그 이후 아이폰에서 페이스북 연동을 이용해 캐릭터 정보를 가져온다.(이때 녹스에서 페북연동을 해지하지 않습니다. 그냥

녹스만 종료하고 연동 ㄱㄱ)




위의 두가지 방법이 전부 안된다면...








첫 번째,

1. 설정>게임센터로 가서 현재 로그인하고 있는 Apple ID를 선택한 뒤 로그아웃합니다. 그리고 다시 로그인하세요.

2. iPhone/iPad를 강제로 재시동합니다(iPhone, iPad 또는 iPod touch 재시동하기 - Apple 지원에서 "강제로 재시동하기"를 참조하세요. 사과로고가 보일 때까지 홈버튼+잠자기버튼을 계속 누르고 있으면 강제 재시동이 됩니다.)

3. 설정>일반>날짜와 시간에서 "자동으로 설정(Set Automatically)"을 켬으로 합니다.

이 방법이 듣지 않는 사용자는 다른 방법을 다시 적용해 보세요.

 

두 번째,

1. iPhone/iPad에서 현재 구동중인 모든 앱을 닫습니다.

2. 에어플레인 모드로 변경합니다.

3. 전원을 껐다가 몇 분 기다린 뒤 다시 iPhone/iPad의 전원을 켭니다.

4. 설정>게임센터에서 현재 로그인되어 있는 Apple ID를 선택한 뒤 로그아웃합니다.

5. 에어플레인 모드를 해제하고, 다시 wifi를 활성화합니다.

6. 설정>게임센터에서 다시 로그인합니다.




OR


간단히는 설정>재설정>모든 설정 재설정


OR


아예 다른 Apple ID로 게임센터를 로그인하는 것만으로 문제가 해결되었다는 사람도 있습니다;


위의 방법까지 안된다면....

저도 방법이 없네요 ㅠ_ㅠ


하지만 게임 에러해결 전문가로 방법은 계속 찾아보도록 하겠습니다.


[테라M] 녹스로 테라M 돌릴때 버벅거림 팅김 검색결과 안나오는 현상 해결 방법



녹스로 테라M 하고싶은데 구글검색하면 안뜨는 현상 팅김 등 현상  해결하는 팁입니다.




1) 휴대폰 모델 변경: 시스템 설정 > 속성 > 휴대폰모델 설정 에서 모델 변경(samsung galaxy s6 edge,SM-G9350 등 모델)


2) apk 파일 수동 설치 방법

- 다운로드 받은 apk 파일을 녹스 프로그램 화면 위로 드래그.

- apk 수동설치가 자동 진행되고, 앱이 설치됨


3) 브라우저 권한동의 방법

   nox 내 브라우저를 여시면 권한동의 메시지가 뜰 것입니다.

   동의해주시고 nox 재실행 부탁드립니다.

- nox 화면에 있는 구글플레이 실행하여 꼭 업데이트하셔야 합니다.


4) 구글 플레이 스토어 캐시 삭제

- 설정 > 어플리케인션 > 전체(오른쪽으로 드래그) 보기

- 구글 플레이 스토어 선택

- 데이타 지우기 / 캐시 지우기 진행


5) 해상도 변경 : 1280 x720

(변경후 녹스 재시작)


6)녹스시스템설정> 고급설정 > 그래픽모드- 스피드모드


7)성능설정-중



마지막으로 녹스에 할당되는 메모리 용랴은 2기가 이상으로 해주셔야 합니다.

[JXLS] JAVA SPRING 데이터 엑셀출력 및 셀병합, merge 하는 방법







웹프로젝트를 개발하다보면


테이블이나 어떤 데이터들을 엑셀로 다운받는 기능을 만들어야 하는 경우가 있다.



일단 엑셀로 만드는게 POI만 쓰면 진짜 더럽게 귀찮아진다.


그렇다고 제이쿼리 excel export를 쓰자니


페이징처리된 테이블의 데이터들을 뽑기가 애매하고


1만로우쯤 되었을때 그걸 다 테이블에 append 시키기도 오바같다



그래서 찾다찾다 찾아낸것이


JXLS


일단 jxls는 poi 기반으로 만들어졌다.


사용법은


정말 간단하다.


그냥 마이바티스에서 db데이터 뽑아서


페이지로 날려주는 그 모델


해쉬맵데이터 형식으로뽑은걸 그대로 사용하면 된다


엑셀에 위치 지정이나 반복되는것은 


미리 엑셀 템플릿을 만들어 놓으면


그대로 들어간다.



일단 셋팅 방법부터 알아보도록 하자.


전자정부 기준이로 설명 한다.




1. pom.xml  


pom.xml의 dependency 부분에 아래 코드를 넣어 주도록 하자.



1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
<!-- 엑셀 다운로드 -->
        
        <dependency>
              <groupId>net.sf.jxls</groupId>
               <artifactId>jxls-core</artifactId>
             <version>1.0.6</version>
        </dependency>
       <dependency>
            <groupId>org.jxls</groupId>
            <artifactId>jxls-poi</artifactId>
            <version>1.0.13</version>
        </dependency>
        <dependency>
            <groupId>org.jxls</groupId>
            <artifactId>jxls</artifactId>
            <version>2.4.2</version>
        </dependency>
        <dependency>
            <groupId>org.apache.poi</groupId>
            <artifactId>poi</artifactId>
            <version>3.14</version>
        </dependency>
        <dependency>
            <groupId>org.apache.poi</groupId>
            <artifactId>poi-ooxml</artifactId>
            <version>3.14</version>
        </dependency>
        <dependency>
            <groupId>org.jxls</groupId>
            <artifactId>jxls-jexcel</artifactId>
            <version>1.0.6</version>
        </dependency>
cs




위에서 말했듯 jxls는 poi를 사용하기 때문에 poi도 받아주어야 한다.





2. 엑셀만들고 다운로드 받는 클래스


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
package 패키지 경로;
 
import java.io.BufferedInputStream;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Map;
 
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
 
import net.sf.jxls.exception.ParsePropertyException;
import net.sf.jxls.transformer.XLSTransformer;
 
import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
import org.apache.poi.ss.usermodel.Workbook;
 
// MakeExcel이라는 클래스를 만들고 그 안에 downliad라는 메소드를 생성한다.
public class MakeExcel {
    public void download(HttpServletRequest request, HttpServletResponse response,
                    Map<String, Object> bean, String fileName, String templateFile, String string)
                    throws ParsePropertyException, InvalidFormatException {
 
        // 받아오는 매개변수 bean는 디비에서 뽑아온 데이터
        // fileName 은 다운로드 받을때 지정되는 파일명
        // templateFile 는 템플릿 엑셀 파일명이다.
        
        // tempPath는 템플릿 엑셀파일이 들어가는 경로를 넣어 준다.
        String tempPath = request.getSession().getServletContext().getRealPath("/WEB-INF/excel");
        
 
        // 별도로 다운로드 만들기 귀찮으까 이런식으로 만들어서 바로 엑셀 생성후 다운 받게 
        try {
 
            InputStream is = new BufferedInputStream(new FileInputStream(tempPath + "\\" + templateFile));
            XLSTransformer xls = new XLSTransformer();
            
            
            Workbook workbook = xls.transformXLS(is, bean);
            
            
            response.setHeader("Content-Disposition""attachment; filename=\"" + fileName + ".xlsx\"");
            
            OutputStream os = response.getOutputStream();
            
            workbook.write(os);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
cs



3. 엑셀 다운로드 요청 및 데이터가져오는 메소드



1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
 @RequestMapping(value = "/downExcel.do")
        public void listExcel(HttpServletRequest request,
                HttpServletResponse response, VO vo,
                ModelMap modelMap) throws Exception, Exception {
 
            
            // 그냥 평소에 마이바티스에서 데이터 뽑는 방법으로 데이터를 가져온다.
            List<VO> dataList = trs01Service.selectGroupList(groupVO);
            
            
            // 받은 데이터를 맵에 담는다.
            Map<String, Object> beans = new HashMap<String, Object>();
            beans.put("dataList", dataList);
            
            // 엑셀 다운로드 메소드가 담겨 있는 객체
            MakeExcel me = new MakeExcel();
 
            me.download(request, response, beans, "다운받을때지정될 엑셀파일명""엑셀템플릿 파일 명.xlsx""무시해도됨");
        }
cs





이렇게 하면 자바에서 할 건 끝났다.



막 예전에 POI에서 셀위치 지정하고 했던것들은 하지 않아도 된다!!



저 템플릿위치에 아래 4번에서 만든 템플릿 엑셀파일을 넣어놓고


3번에서 만든 메소드를 호출하면 해당 데이터를 담은 엑셀을 다운로드 받게 된다.


정말 너무너무 간단하다.




4. 템플릿 엑셀 예제





위 그림과 같이 JSTL 쓰던것 처럼 적어주면 된다.


저렇게 적으면 콜렉션일 경우 자동으로 반복까지 해준다.


그냥 저렇게만 만들어 두면 저 위치부터 아래로 쭉쭉 엑셀데이터가 입력 되는 것이다.



엄청나다.





5. 셀병합, merge






이런식으로 셀병합을 하고 이름옆에 3줄로 다른 정보를 반복시켜야 하는 경우가 있다.



그냥 4번에 있는식으로 템플릿만들어서 적으면 에러난다.


java.lang.NullPointerException

at net.sf.jxls.util.Util.shiftColumnUp(Util.java:335) ~[jxls-core-1.0.6.jar:?]

at net.sf.jxls.util.Util.shiftUncoupledCellsUp(Util.java:315) ~[jxls-core-1.0.6.jar:?]

at net.sf.jxls.util.Util.duplicateRow(Util.java:246) ~[jxls-core-1.0.6.jar:?]

at net.sf.jxls.controller.SheetTransformationControllerImpl.duplicateRow(SheetTransformationControllerImpl.java:140) ~[jxls-core-1.0.6.jar:?]

at net.sf.jxls.transformer.CollectionRowTransformer.processRowCollections(CollectionRowTransformer.java:106) ~[jxls-core-1.0.6.jar:?]

at net.sf.jxls.transformer.CollectionRowTransformer.transform(CollectionRowTransformer.java:66) ~[jxls-core-1.0.6.jar:?]



이런 에러가 막 뿜어져 나올 것이다.


왜 에러가 나느냐..


템플릿을 잘못 만들었기 때문이다.


이걸 보는 여러분들도 템플릿으로 이것저것 에러뿜어가면서 테스트 하다보면


알수 있을 이유이다


그냥 해결방법만 간단하게 말하면





이런식으로 셀병합한 위치에 들어가는 데이터 옆에 //:숫자  를 넣어 주면 된다.


만약 데이터가 3칸을 병합해서 세줄단위로 넘어가야 하는 경우


0 , 1, 2  로 세서 숫자 2를 넣어주면 된다.



머지를 하지 않더라도


2줄단위로 반복하거나 3줄단위로 반복하게 하는 경우에도 동일하게 적용하면 된다.



JXLS의 가장 좋은 장점은 데이터 넣는곳 템플릿에 스타일 넣어주면 그 스타일도 같이 반복이 된다.


아주 훌륭하다


[안드로이드] duplicate entry 에러 해결 방법



Error:Execution failed for task 에러를 해결하니 이번엔 중복에러가 나타났다



duplicate entry: com/google/zxing/aztec/AztecDetectorResult.class


이런 에러인데


AztecDetectorResult 클래스가 중복이 되었다 뭐 그런 이야기다



구글의 라이브러리를 이것저것 참조하다보면 저런 에러가 흔히 나타나는듯 하다.


나같은 경우는


QR코드를 읽는 라이브러리와


안드로이드 카메라로 촬영한 이미지의 문자를 인식하는 라이브러리를 사용하던 중에


이것저것 끌어오다가 나타난 에러였다.



어느부분에서 중복되었는지 찾기가 쉽지는 않지만


어차피 앞쪽의 경로를 보면 대충 사이즈는 나오니까 잘 찾아보도록 하자









안드로이드 스튜디오의 프로젝트보기로 (안드로이드 보기론 안보임)


저 두군데를 뒤져보면 중복되는 녀석들이 나타난다



단순히 build.gradle에서 컴파일 명령을 지우는 것 만으로는 해결이 되지 않기 때문에


직접 저기서 파일 자체를 삭제 해주어야 한다.



물론 아무거나 지우다 일어나는 일은 책임 못진다.



build.gradle에서 명령줄만 삭제 해보고 



정상 동작 한다면 그떄 지우고 APK파일로 구동시켜 보도록 하자.




단순히 빌드할땐 나타나지 않다가 APK파일로 생성할때 나타나는 에러니까


정상동작하는걸 확인 후 삭제하는 것으로 



저 에러를 해결 하자



+ Recent posts