[JXLS] Cannot add merged region to sheet because it overlaps with an existing merged region 오류 해결 방법



제대로 //:3 이렇게 표기도 해준것 같은데


저런 에러가 난다면



셀병합되어진 부분이


//: 표기해준 곳 앞쪽에 또 있는지 확인해 보도록 하자





이런식으로 작성한 경우 NO 쪽에 병합된 셀이 있기 때문에 위와 같은 오류가 난다








이렇게 최초로 병합된셀이 나오는 부분에 :// 를 표기 하면 해당 오류를 해결 할 수 있다.

[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파일로 생성할때 나타나는 에러니까


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



저 에러를 해결 하자



[안드로이드] Error:Execution failed for task ':app:transformClassesWithDexForDebug'. 오류 해결 방법



신나게 코딩하고나서 모바일로 테스트 까지 다 해놓고


APK파일로 묶으려는데 저런 에러가 나서 당황스러운 경우가 있었다.



대체 뭐지.. 뭘까..


하고 뒤쪽의 에러를 더 봤더니



com.android.build.api.transform.TransformException: com.android.ide.common.process.ProcessException: java.util.concurrent.ExecutionException: 

com.android.dex.DexException: Multiple dex files define Lcom/google/zxing/BarcodeFormat;



이런 내용의 로그가 나타났고


저기서 잘 보아야 할것은


Multiple dex files define 


바로 이부분이었다


음... 뭐 다중 어쩌구 파일을 못찾겠다 뭐 이런건지


일단 잘 모르니까 검색을 해보니


역시나 스택오버플로우 형님들이 좋은 답변들을 알려주었다



안드로이드 build.gradle (app 레벨)에 들어가서


몇줄 추가해 주도록 하자


dependencies {
compile 'com.android.support:multidex:1.0.1'
}


디펜던시에서 저 한줄을 추가 해주고



android {

.......
defaultConfig {

.........
multiDexEnabled true
}

.....
}


저렇게 하나 추가해 주도록 하자



그리고 AdnroidManifest.xml에 가서


<application
.....
android:name="android.support.multidex.MultiDexApplication">

......
</application>


어플리케이션단에 추가를 해준다



그럼 해결이 된다!

[톰캣] 서버 실행시 CMD창 바로 사라지는 문제 해결 방법






톰캣의 startup.bat 파일을 실행시킬때


cmd창이 떳다가 바로 사라지는 경우가 있었다.


뭐 에러 메세지라도 보여야 뭐가 잘못된건지 볼텐데


로그도 쌓이지 않고 그냥 사라져 버리는 문제에 대한 해결 방법이다.



일단 일반 cmd 창을 띄우고


톰캣이 설치된 경로로 이동한다



C:\apache-tomcat-7.0.76-windows-x64\apache-tomcat-7.0.76\bin



빈폴더 까지 이동 후


startup.bat  명령어를 입력하면


메세지가 나타나게 되는데


JRE_home environment variable is not defined correctly

a fatal exception has occurred. program will exit


요런 메세지가 나타난다.


JRE_home 가 아니라 JAVA_HOME 가 나타날 수도 있다


혹은 그외의 메세지가 나타날 수도 있으니


해당 메세지를 보고 오류를 해결하면 된다.


JRE_home environment variable is not defined correctly


이런 오류 메세지가 나타날떄의 해결 방법은


톰캣 bin 폴더의 catalina.bat 파일을 편집기로 열어서


JRE_HOME 나 JAVA_HOME의 경로를 


재지정 해주면 된다.



만약 JRE_HOME이나 JAVA_HOME 에 $JRE_HOME$ 이런 식으로


지정이 되어 있다면


시스템변수에 JAVA_HOME이나 JRE_HOME이 정상적으로


등록이 되어 있는지 확인 한다.



나의 경우는 JRE_HOME을 따로 지정하지 않았는데


톰캣 카탈리나에 JRE_HOME이 $JRE_HOME$ 으로 지정이 되어 있어서


시스템 변수에 JRE_HOME을 등록해 주고 난 후 오류를 해결 했다.



.




혹은 톰캣 윈도우를 실행 할때


지정된 서비스가 설치된 서비스로는 없습니다.


라는 메세지가 뜨는 경우


CMD창을 열어서


톰캣 빈폴더로 이동 후


service.bat install tomcat7


이라는 명령어를 입력하면


해결이 된다.








[안드로이드] androidBridge they will not be visible in API 17 오류 해결 방법




none of the methods in the added interface(androidBridge) have been annotated with @android.webkit   they will not be visible in API 17 


이 오류의 해결 방법 입니다.



1. 원인


안드로이드 버전 API 17 이상부터 androidBridge 사용시 메소드에 어노테이션을 사용해야 정상 구동 하도록

바뀌어서 생기는 오류


2. 해결 방법


간단하게 androidBridge에서 사용하는 메소드위에 어노테이션을 추가 하면 됩니다.



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
package com.xxx.xxxx;
 
import android.os.Handler;
import android.util.Log;
import android.webkit.JavascriptInterface;
import android.webkit.WebView;
import java.text.SimpleDateFormat;
import java.util.Date;
 
/**
 * Created by Administrator on 2017-08-03.
 */
 
public class AndroidBridge {
    private final Handler handler = new Handler();
    private WebView mWebView;
    private DBHelper dbHelper;
    private  boolean newtwork;
 
    // 생성자
    public AndroidBridge(WebView mWebView, DBHelper dbHelper, boolean newtwork) {
        this.mWebView = mWebView;
        this.dbHelper = dbHelper;
        this.newtwork = newtwork;
    }
 
    // 네트워크 상태 확인
    @JavascriptInterface
    public void requestNetwork() { // must be final
        handler.post(new Runnable() {
            public void run() {
                Log.d("HybridApp""네트워크 상태 요청");
                mWebView.loadUrl("javascript:getNetwork("+newtwork+")");
            }
        });
    }
 
 
 
    @JavascriptInterface
    public void setMessage(final String arg) { // must be final
        handler.post(new Runnable() {
            public void run() {
                Log.d("HybridApp""setMessage("+arg+")");
                mWebView.loadUrl("javascript:getAndroidMessage('ANDROID -> JAVASCRIPT CALL!!')");
            }
        });
    }
 
 
}
cs


간단하게 다른거 볼 필요 없이


28번라인에 추가한 어노테이션을 29번같은 메소드 위에 선언하기만 하면 해당 오류가 해결 된다.



[centOS] PHP 5.2 make 설치 오류 해결 방법


dereferencing pointer to incomplete type RETVAL_STRINGL((char *) buf->buffer->content, ret, 1);


php 파일 풀고나서 make 명령어를 치면 저런 에러가 뿜어져 나온다



보안관련 문제인지 일단 php에서 5.2버전은 지원을 중단했기 때문에 나타나는 에러다



https://code.google.com/p/php52-backports/issues/detail?id=16

여기서 패치파일 다운 받고


패치파일을 php 소스 경로에다가 옮겨놓은 다음


# patch -p0 < ./libxml29_compat.patch 

이 명령어를 치면 된다


centos 7 patch 명령을 찾을 수 없습니다 라는 메세지가 나타난다면




#sudo yum install patch


이 명령어로 패치 설치한후


위의 명령어를 실행하면 정상 작동이 된다.






[리니지M] 리니지M 드디어 오픈 인게임 리뷰


리니지M이 오픈을 했다


두근거리며 15년전 했던 그 마음으로 설레이며


12시가 되는 순간! 바로 접속을 하였다.


아마 아이폰은 접속이 잘 안되는 것 같다.


난 갤럭시 노트4인데 두번정도 시도 하고 접속을 했다..



크... 배경음악이... 15년전의 그 배경음악이 ㅋㅋㅋㅋ


그리고 몬스터 때리는데 나오는 그 소리도 15년전 그대로다 ㅎㅎ


재밌는건 


튜토리얼 퀘스트를 진행 하다보면


구문룡, 포세이튼, 아오리 같은 유명한 리니지 유저들이 잠깐 NPC로 등장 하는데



<구문룡 빛 포세이든 너의바램 나비 한별 아오리와 함께 발라카스를 잡는다.>



뭔가 기분이 묘해진다 ㅎㅎ


엔씨가 이런 기획은 잘 만든 것 같다.



현재 접속자가 많이 밀려서 친구들은 대기자가 2천명 1천명 이라고 한다.


줄쟁이는 켄라우헬 3섭의 객자 라는 군주 캐릭으로 하고 있고


치킨 혈맹의 군주 이다 



나 블로그에 글 많이 쓸시간 없음 ㅋㅋ 빨리 다시 게임 하러 가야한다.


그럼 즐린!

[React.js] cannot resolve 'react-transition-group' 오류 해결 방법



애니메이션 효과같은것들 적용 하려고 했던 react-transition-group이 서버 구동중 에러가 난다.


cannot resolve 'react-transition-group' 라는 에러메세지가 뜨길래


분명히 해당 패키지도 받았고 제대로 추가 시켰는데 왜 못찾는거지?


하고 검색을 해 보았다.


NPM에 올라온 글을 확인해 보니


This package is deprecated and will no longer work with React 16+. We recommend you use CSSTransitionGroup from react-transition-group instead.

In particular, its version 1.1.1 is a drop-in replacement for the last released version of react-addons-css-transition-group.

Run npm install --save react-transition-group@1.1.1, and replace the imports in your code


1
2
3
4
5
// Old 
import CSSTransitionGroup from 'react-addons-css-transition-group';
 
// New 
import CSSTransitionGroup from 'react-transition-group/CSSTransitionGroup';
cs



라고 올라와 있었다


내용인 즉슨


리액트 16 이상 버전 부터는 기존에 사용하던걸 지원하지 않고 아얘 동작도 되지 않게 되었으니


새로운 다른걸 써라~


라고 하는 것이다.


쟤네가 설치하라는거 설치 하고 임포트 문장도 아랫것 처럼 바꾸면


오류는 해결이 된다.

react-router v4  browserHistory.push 오류 해결 방법


리엑트 라우터가 버전3에서 버전4로 올라감에 따라 


엄청나게 많은 것들이 변했다.


지금 새로운 프로젝트를 만들고 새로운 버전의


패키지들을 받은 후 코딩을 하려면 불과 한달전에 공부했던 코드들이 동작하지 않게 되었다.



망할.. 예전 webpack 버전1에서 2버전으로 올라가면서 바뀐거 찾아내느라 생고생 했는데



이젠 react-router가 문제다




Link를 사용하지 않고 바로 함수 내에서 리다이렉트를 시키는 방법으로


v3에서는 



1
browserHistory.push('/');
cs


이렇게 사용 하였으나


v4에선


Uncaught (in promise) ReferenceError: browserHistory is not defined


브라우저 콘솔창에 위와 같은 에러 메세지가 나타난다.


해결방법


생각보다 간단했다. 위의 코드 대신에


1
this.props.history.push('/');
cs



이렇게 사용해주면 된다.


물론 상단에 리엑트 라우터를 임포트시킬 필요는 없다.


그냥 기능이 넘어와 버린건지 정확하게는 알 수 없지만


깃터브를 뒤져보니 아래와 같은 의견을 찾았다.


걍 이전버전에서는 됐는데 v4에선 안된다 라는 말 같다.





@wyze @timdorr first of all thanks for the v4. I have a few questions and I could not find any solutions for this anywhere, so asking here.

In the earlier versions of the react-router, we could push the the URL using browserHistroy.push() method. When you use browserHistroy the query which you pass, will be transformed to the search key in the history object. The below is an example which used to work in earlier versions.

let query = {
  reportType: 'summary',
  timeZone: 'UTC'
}
  browserHistroy.push({
    pathname: 'some_path',
    query
  })

This will resolve the URL to - test.com/some_path/?reportType=summary&timeZone=UTC

In the current version (v4), it is not possible to pass the query object to the history.push() method.

  histroy.push({
    pathname: 'some_path',
    query
  })

This will resolve the URL to - test.com/some_path/

How to get this working with v4.

+ Recent posts