반응형
반응형

1. 라이브러리 jar 파일


quart 라이브러리


http://www.quartz-scheduler.org/


quartz-all-1.6.6.jar




quart - struts1 연동 라이브러리


http://demo.jgsullivan.com/struts/download.html


jgs-struts-0.3-dev.jar


jgs-quartz-0.1d.jar




2. Quart 참조 링크


anyframework


http://dev.anyframejava.org/docs/anyframe/4.2.0/reference/htmlsingle/anyframe.html#tech_ss_sec001








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
==============================================================
 
QuartzTest.java
 
==============================================================
 
01 package kr.co.rastech.common.quartz;
02 
03 import java.text.SimpleDateFormat;
04 import java.util.Date;
05 
06 import org.apache.commons.logging.Log;
07 import org.apache.commons.logging.LogFactory;
08 import org.quartz.Job;
09 import org.quartz.JobExecutionContext;
10 import org.quartz.JobExecutionException;
11 
12 
13 public class QuartzTest implements Job{
14 
15     private Log logger = LogFactory.getLog(this.getClass());
16 
17     @Override
18     public void execute(JobExecutionContext arg0) throws JobExecutionException {
19         long now = System.currentTimeMillis();
20 
21         SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss a");
22 
23 
24         String nowDateTime = sdf.format(new Date(now));
25 
26         logger.debug(nowDateTime + " : test");
27     }
28 
29 }
 
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
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
web.xml
 
 
 
==============================================================
 
 
 
    <servlet>
 
        <servlet-name>ActionServlet</servlet-name>
 
        <servlet-class>org.apache.struts.action.ActionServlet</servlet-class>
 
        <init-param>
 
            <param-name>config</param-name>
 
            <param-value>/WEB-INF/config/struts-config.xml</param-value>
 
        </init-param>
 
        <load-on-startup>1</load-on-startup>
 
    </servlet>
 
    
 
    <servlet-mapping>
 
        <servlet-name>ActionServlet</servlet-name>
 
        <url-pattern>*.do</url-pattern>
 
    </servlet-mapping>
 
    
 
    <servlet>
 
        <servlet-name>QuartzInitializer</servlet-name>
 
        <servlet-class>org.quartz.ee.servlet.QuartzInitializerServlet</servlet-class>
 
        <init-param>
 
            <param-name>shutdown-on-unload</param-name>
 
            <param-value>true</param-value>
 
        </init-param>
 
        <init-param>
 
        <param-name>start-scheduler-on-load</param-name>
 
      <param-value>true</param-value>
 
    </init-param>
 
        <load-on-startup>3</load-on-startup>
 
    </servlet>
 
    
 
==============================================================
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
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
struts-config.xml
 
 
 
/WEB-INF/config/struts-config.xml위치
 
==============================================================
 
 
 
<struts-config>
 
 
 
    <action-mappings>
 
        <action path="/test" forward="/index.jsp"></action>
 
 
 
    </action-mappings>
 
 
 
    <!-- Quartz framework 2010.08.09 -->
 
    <plug-in className="com.jgsullivan.struts.plugins.QuartzPlugIn">
 
        <set-property property="configPath" value="/WEB-INF/quartz-config.xml"/>
 
    </plug-in>
 
</struts-config>
 
==============================================================
 
 
 
quartz-config.xml
 
 
 
/WEB-INF/quartz-config.xml위치
 
==============================================================
 
 
 
<?xml version="1.0" encoding="UTF-8"?>
 
 
 
<quartz-config>
 
    <trigger-group>
 
        <trigger name="secondTrigger" className="org.quartz.CronTrigger">
 
            <set-property property="timeZone" value="Pacific/Marquesas" />
 
            <set-property property="cronExpression" value="* * * * * ?" />
 
        </trigger>
 
    </trigger-group>
 
 
 
 
 
    <job-group>
 
        <job name="dumbJob" className="kr.co.rastech.common.quartz.QuartzTest" />
 
    </job-group>
 
</quartz-config>
cs

 

※ 시간을 아무리설정해도 잘안맞는다 싶으면 timeZone을 서버컴시간으로 바꿔야합니다.

    [<set-property property="timeZone" value="Pacific/Marquesas" />]

    이부분을 삭제하면 default로 서버컴시간이 설정됩니다.

※ WAS가 이중화 되어있으면 2번씩 실행 될수 있으니 아이피 체크해야 합니다.



출처: http://thdnf1004.tistory.com/entry/quart-연동-스케쥴링 [야근없는 세상을 위해~]

반응형
반응형

java에서 exel 파일 만들때 병합이라든지 폰트등 세세한 설정을 보여주는 예제 입니다.


일단 아래와 같은 파일을 생성하는 소스 입니다.





스프링에 엑셀 다운 받는 기능 추가는 다음 링크 참조 http://huskdoll.tistory.com/570


배경색 종류는 다음 링크 참조하세요. http://huskdoll.tistory.com/607



내용은 소스의 주석을 참고하여 주시기 바랍니다.



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
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
Row row = null;
Cell cell = null;
int rowCount = 0;
int cellCount = 0;
 
//1.셀 스타일 및 폰트 설정
CellStyle styleOfBoardFillFontBlackBold16 = workbook.createCellStyle();
//정렬
styleOfBoardFillFontBlackBold16.setAlignment(CellStyle.ALIGN_CENTER); //가운데 정렬
styleOfBoardFillFontBlackBold16.setVerticalAlignment(CellStyle.VERTICAL_CENTER); //높이 가운데 정렬
//배경색
styleOfBoardFillFontBlackBold16.setFillForegroundColor(IndexedColors.PALE_BLUE.getIndex());
styleOfBoardFillFontBlackBold16.setFillPattern(CellStyle.SOLID_FOREGROUND);
//테두리 선 (우,좌,위,아래)
styleOfBoardFillFontBlackBold16.setBorderRight(HSSFCellStyle.BORDER_THIN);
styleOfBoardFillFontBlackBold16.setBorderLeft(HSSFCellStyle.BORDER_THIN);
styleOfBoardFillFontBlackBold16.setBorderTop(HSSFCellStyle.BORDER_THIN);
styleOfBoardFillFontBlackBold16.setBorderBottom(HSSFCellStyle.BORDER_THIN);
//폰트 설정
Font fontOfGothicBlackBold16 = workbook.createFont();
fontOfGothicBlackBold16.setFontName("나눔고딕"); //글씨체
fontOfGothicBlackBold16.setFontHeight((short)(16*20)); //사이즈
fontOfGothicBlackBold16.setBoldweight(Font.BOLDWEIGHT_BOLD); //볼드 (굵게)
styleOfBoardFillFontBlackBold16.setFont(fontOfGothicBlackBold16);
 
//2.셀 스타일 및 폰트 설정
CellStyle styleOfBoardFillFontRedBold14 = workbook.createCellStyle();
//정렬
styleOfBoardFillFontRedBold14.setAlignment(CellStyle.ALIGN_CENTER); //가운데 정렬
styleOfBoardFillFontRedBold14.setVerticalAlignment(CellStyle.VERTICAL_CENTER); //높이 가운데 정렬
//배경색
styleOfBoardFillFontRedBold14.setFillForegroundColor(IndexedColors.PALE_BLUE.getIndex());
styleOfBoardFillFontRedBold14.setFillPattern(CellStyle.SOLID_FOREGROUND);
//테두리 선 (우,좌,위,아래)
styleOfBoardFillFontRedBold14.setBorderRight(HSSFCellStyle.BORDER_THIN);
styleOfBoardFillFontRedBold14.setBorderLeft(HSSFCellStyle.BORDER_THIN);
styleOfBoardFillFontRedBold14.setBorderTop(HSSFCellStyle.BORDER_THIN);
styleOfBoardFillFontRedBold14.setBorderBottom(HSSFCellStyle.BORDER_THIN);
//폰트 설정
Font RedBold14 = workbook.createFont();
RedBold14.setFontName("나눔고딕"); //글씨체
RedBold14.setColor(HSSFColor.RED.index);
RedBold14.setFontHeight((short)(14*20)); //사이즈
RedBold14.setBoldweight(Font.BOLDWEIGHT_BOLD); //볼드 (굵게)
styleOfBoardFillFontRedBold14.setFont(RedBold14);
 
//3.셀 스타일 및 폰트 설정
CellStyle styleOfBoardFillFontBlack11 = workbook.createCellStyle();
//정렬
styleOfBoardFillFontBlack11.setAlignment(CellStyle.ALIGN_CENTER); //가운데 정렬
styleOfBoardFillFontBlack11.setVerticalAlignment(CellStyle.VERTICAL_CENTER); //높이 가운데 정렬
//배경색
styleOfBoardFillFontBlack11.setFillForegroundColor(IndexedColors.LAVENDER.getIndex());
styleOfBoardFillFontBlack11.setFillPattern(CellStyle.SOLID_FOREGROUND);
//테두리 선 (우,좌,위,아래)
styleOfBoardFillFontBlack11.setBorderRight(HSSFCellStyle.BORDER_THIN);
styleOfBoardFillFontBlack11.setBorderLeft(HSSFCellStyle.BORDER_THIN);
styleOfBoardFillFontBlack11.setBorderTop(HSSFCellStyle.BORDER_THIN);
styleOfBoardFillFontBlack11.setBorderBottom(HSSFCellStyle.BORDER_THIN);
//폰트 설정
Font Black11 = workbook.createFont();
Black11.setFontName("나눔고딕"); //글씨체
Black11.setFontHeight((short)(11*20)); //사이즈
styleOfBoardFillFontBlack11.setFont(Black11);
 
//4.셀 스타일 및 폰트 설정(일반 텍스트)
CellStyle styleOfBoardFontBlack11 = workbook.createCellStyle();
//정렬
styleOfBoardFontBlack11.setAlignment(CellStyle.ALIGN_CENTER); //가운데 정렬
styleOfBoardFontBlack11.setVerticalAlignment(CellStyle.VERTICAL_CENTER); //높이 가운데 정렬
//테두리 선 (우,좌,위,아래)
styleOfBoardFontBlack11.setBorderRight(HSSFCellStyle.BORDER_THIN);
styleOfBoardFontBlack11.setBorderLeft(HSSFCellStyle.BORDER_THIN);
styleOfBoardFontBlack11.setBorderTop(HSSFCellStyle.BORDER_THIN);
styleOfBoardFontBlack11.setBorderBottom(HSSFCellStyle.BORDER_THIN);
//폰트 설정 (위 폰트 사용)
styleOfBoardFontBlack11.setFont(Black11);
 
//4.셀 스타일 및 폰트 설정(금액)
CellStyle styleOfBoardMoneyFontBlack11 = workbook.createCellStyle();
//정렬
styleOfBoardMoneyFontBlack11.setAlignment(CellStyle.ALIGN_RIGHT); //우측 정렬
styleOfBoardMoneyFontBlack11.setVerticalAlignment(CellStyle.VERTICAL_CENTER); //높이 가운데 정렬
//테두리 선 (우,좌,위,아래)
styleOfBoardMoneyFontBlack11.setBorderRight(HSSFCellStyle.BORDER_THIN);
styleOfBoardMoneyFontBlack11.setBorderLeft(HSSFCellStyle.BORDER_THIN);
styleOfBoardMoneyFontBlack11.setBorderTop(HSSFCellStyle.BORDER_THIN);
styleOfBoardMoneyFontBlack11.setBorderBottom(HSSFCellStyle.BORDER_THIN);
//폰트 설정 (위 폰트 사용)
styleOfBoardMoneyFontBlack11.setFont(Black11);
//천단위 쉼표, 금액
styleOfBoardMoneyFontBlack11.setDataFormat(HSSFDataFormat.getBuiltinFormat("#,##0"));
             
//Sheet 생성
Sheet sheet = workbook.createSheet("도서정보");
 
//눈금선 없애기
sheet.setDisplayGridlines(false);
 
//첫줄 개행
rowCount++;
 
//열 생성
row = sheet.createRow(rowCount++);
cellCount = 0; //셀 카운트 초기화
 
//셀 병합
sheet.addMergedRegion(new CellRangeAddress(1,4,0,1)); //열시작, 열종료, 행시작, 행종료 (자바배열과 같이 0부터 시작)
sheet.addMergedRegion(new CellRangeAddress(1,1,2,6));
 
//셀 생성
cell = row.createCell(cellCount++);
cell.setCellStyle(styleOfBoardFillFontBlackBold16); //위에서 설정한셀 스타일 셋팅
cell.setCellValue("A문고 상태");
 
//라인을 그리기 위해 실행 (병합이 되어도 테두리 라인을 그리기 위해 셀을 생성하고 스타입을 셋팅)
cell = row.createCell(cellCount++);
cell.setCellStyle(styleOfBoardFillFontBlackBold16);
 
cell = row.createCell(cellCount++);
cell.setCellStyle(styleOfBoardFillFontRedBold14);
cell.setCellValue("도서 정보");
 
cell = row.createCell(cellCount++);
cell.setCellStyle(styleOfBoardFillFontRedBold14);
 
cell = row.createCell(cellCount++);
cell.setCellStyle(styleOfBoardFillFontRedBold14);
 
cell = row.createCell(cellCount++);
cell.setCellStyle(styleOfBoardFillFontRedBold14);
 
cell = row.createCell(cellCount++);
cell.setCellStyle(styleOfBoardFillFontRedBold14);
 
//2열 작성
row = sheet.createRow(rowCount++);
cellCount = 0;
 
cell = row.createCell(cellCount++);
cell.setCellStyle(styleOfBoardFillFontBlackBold16);
 
cell = row.createCell(cellCount++);
cell.setCellStyle(styleOfBoardFillFontBlackBold16);
 
cell = row.createCell(cellCount++);
cell.setCellStyle(styleOfBoardFillFontBlack11);
cell.setCellValue("ID");
 
cell = row.createCell(cellCount++);
cell.setCellStyle(styleOfBoardFillFontBlack11);
cell.setCellValue("도서명");
 
cell = row.createCell(cellCount++);
cell.setCellStyle(styleOfBoardFillFontBlack11);
cell.setCellValue("작가");
 
cell = row.createCell(cellCount++);
cell.setCellStyle(styleOfBoardFillFontBlack11);
cell.setCellValue("가격");
 
cell = row.createCell(cellCount++);
cell.setCellStyle(styleOfBoardFillFontBlack11);
cell.setCellValue("수량");
 
//3열 작성
row = sheet.createRow(rowCount++);
cellCount = 0;
 
cell = row.createCell(cellCount++);
cell.setCellStyle(styleOfBoardFillFontBlackBold16);
 
cell = row.createCell(cellCount++);
cell.setCellStyle(styleOfBoardFillFontBlackBold16);
 
cell = row.createCell(cellCount++);
cell.setCellStyle(styleOfBoardFontBlack11);
cell.setCellValue("b1");
 
cell = row.createCell(cellCount++);
cell.setCellStyle(styleOfBoardFontBlack11);
cell.setCellValue("레미제라블");
 
cell = row.createCell(cellCount++);
cell.setCellStyle(styleOfBoardFontBlack11);
cell.setCellValue("빅토르 위고");
 
cell = row.createCell(cellCount++);
cell.setCellStyle(styleOfBoardMoneyFontBlack11);
cell.setCellValue(3000);
 
cell = row.createCell(cellCount++);
cell.setCellStyle(styleOfBoardMoneyFontBlack11);
cell.setCellValue(32);
 
//4열 작성
row = sheet.createRow(rowCount++);
cellCount = 0;
 
cell = row.createCell(cellCount++);
cell.setCellStyle(styleOfBoardFillFontBlackBold16);
 
cell = row.createCell(cellCount++);
cell.setCellStyle(styleOfBoardFillFontBlackBold16);
 
cell = row.createCell(cellCount++);
cell.setCellStyle(styleOfBoardFontBlack11);
cell.setCellValue("a32");
 
cell = row.createCell(cellCount++);
cell.setCellStyle(styleOfBoardFontBlack11);
cell.setCellValue("홍길동");
 
cell = row.createCell(cellCount++);
cell.setCellStyle(styleOfBoardFontBlack11);
cell.setCellValue("허균");
 
cell = row.createCell(cellCount++);
cell.setCellStyle(styleOfBoardMoneyFontBlack11);
cell.setCellValue(8000);
 
cell = row.createCell(cellCount++);
cell.setCellStyle(styleOfBoardMoneyFontBlack11);
cell.setCellValue(15);


추가: 셀 표시형식(날짜)

CellStyle style = workbook.createCellStyle();

style.setDataFormat((short) 0xe);


출처: http://huskdoll.tistory.com/795

반응형
반응형

이번 포스팅에서는 일반 프로젝트의 Export > Runnable Jar 파일과 같이 실행 가능한 Jar 파일을 Maven을 통해서 생성하는 방법에 대해 알아보도록 하겠습니다.


※ 해당 포스팅은 이전 포스팅의 다중 모듈 프로젝트를 기반으로 진행됩니다!



 MANIFEST.MF (수동)

실행 가능한 Jar 파일을 생성하기 위해서 Main 클래스가 존재하는 Jar 파일을 열어 MANIFEST.MF를 수정해야 하는 아주 귀찮은 과정을 거쳐야 합니다.

저기 보이는 MANIFEST.MF 파일을 메모장으로 열어 class path를 설정하여 모듈과 라이브러리들을 등록하고 Main 클래스도 적어 주어야 합니다.


바로 이렇게 말이죠! 게다가 프로젝트에 사용되는 다른 모듈들의 build 된 Jar 파일들을 모두 lib경로로 옮겨야 합니다! 이 작업을 매번 빌드할 때마다 수행하게 되면 굉장히 시간 낭비가 될 것입니다.


하지만 저희에게는 Maven이 있습니다!



 Maven Plugin (자동!)

Maven에서는 build를 위한 편리한 plugin들을 제공하고 있습니다. 이 plugin을 이용하여 자동으로 MANIFEST를 설정할 수 있으며 빌드된 모듈들을 자동으로 이동시킬 수 있습니다.


1
2
3
4
5
6
7
8
9
10
11
<project ...>
 
<build>
        <plugins>
        <!-- 이곳에 사용할 plugin 삽입 -->
        </plugins>
</build>
 
...
 
</project>
cs

우선 위의 코드처럼 plugin을 넣을 수 있는 부분을 Main class가 있는 모듈의 pom.xml에 적습니다.


1
2
3
4
5
6
7
8
9
10
11
12
13
<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-jar-plugin</artifactId>
    <configuration>
        <archive>
            <manifest>
                <addClasspath>true</addClasspath>
                <classpathPrefix>lib/</classpathPrefix>
                <mainClass>org.planb.dms.core.DmsMain</mainClass>
            </manifest>
        </archive>
    </configuration>
</plugin>
cs

그다음 plugins 태그 안에 위의 maven-jar-plugin을 삽입해 주도록 합시다. 이 플러그인을 삽입함으로써 MANIFEST에 3가지 작업을 수행합니다.


1. addClasspath - true : maven-jar-plugin이 class-path 요소를 MANIFEST.MF 파일에 추가합니다.

2. classpathPrefix : 해당 module과 종속관계를 가지고 있는 항목들을 해당 모듈의 jar 경로의 lib 디렉토리로 설정합니다. 다시 말해서 사용되는 라이브러리나 모듈들의 경로를 lib 디렉토리로 설정합니다.

3. mainClass : MANIFEST에 Main class 이름을 설정합니다. 이로써 java -jar 모듈이름.jar 형식으로 jar 실행이 가능해집니다.



그다음으로 라이브러리들과 모듈들을 자동으로 lib 폴더를 복사하는 plugin을 사용해 보도록 하겠습니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-dependency-plugin</artifactId>
    <executions>
        <execution>
            <id>copy</id>
            <phase>install</phase>
            <goals>
                <goal>copy-dependencies</goal>
            </goals>
            <configuration>
                <outputDirectory>
                    ${project.build.directory}/lib
                </outputDirectory>
            </configuration>
        </execution>
    </executions>
</plugin>
cs

위의 플러그인은 maven-dependency-plugin 입니다. 해당 모듈과 의존성 관계를 맺고 있는 모든 항목을 해당 모듈 디렉토리의 lib 폴더로 복사하게 됩니다. phase 태그에서 install로 지정되어 maven의 goal이 install 단계일 때 해당 플러그인의 기능이 수행됩니다.


저의 경우 dms-core 모듈에 Main 클래스가 존재하니 위의 과정을 dms-core 모듈의 pom.xml에 적용하였습니다.


다음으로 Maven Build Configuration에서 goals를 clean install로 설정하고 Run을 클릭! (자세한 내용은 이전 포스팅에서 확인해 주세요) 성공적으로 build가 되었다면 해당 모듈의 디렉토리를 열어보도록 합시다.


해당 모듈의 디렉토리에 가보면 target 폴더가 생성되어 있습니다. 들어가 보시면 위의 사진과 같이 해당 모듈의 jar 파일과 lib 폴더가 생성되어있을 것입니다. (아니라면 플러그인을 잘못 등록하셨거나 빌드가 잘못된 것일 수도)


그럼 이제 cmd 창을 열어 해당 디렉토리에 접근한 뒤 다음 명령어를 통해 jar 파일을 실행시킬 수 있습니다.

java -jar 모듈이름.jar 



 마무리

InteiliJ의 경우 Maven 프로젝트를 IDE 내에서 실행시키는 기능을 제공해주고 있는데 eclipse는 그게 되는지조차 모르겠습니다. 다음에 한 번 확인해 본 뒤에 포스팅해보도록 하겠습니다.



출처: http://boxfoxs.tistory.com/332 [박스여우 - BoxFox]

반응형
반응형

1. []으로 싸주면 문자자체로 인식하는 것들.

 *  ⇒ [*]
 +  ⇒ [+]
 $  ⇒ [$]
 |  ⇒ [|]              


2. \\를 붙여줘야 하는 것들.

 ( ⇒ \\(
 ) ⇒ \\)
 { ⇒ \\{
 } ⇒ \\}
 ^ ⇒ \\^
 [ ⇒ \\[
 ] ⇒ \\]


 3. 자바의 특수문자는 \을 쓴다.

  " ⇒ \"


 4. 나머지 부호들은 괜찮은 듯 하다.

확인된 것.

 ! # % & @ ` : ; - . < > , ~ '

 

ex ) 위에 놈들 다 지워 보자.

     String c = "!\"#$%&(){}@`*:+;-.<>,^~|'[]";
     c = c.replaceAll("!\"#[$]%&\\(\\)\\{\\}@`[*]:[+];-.<>,\\^~|'\\[\\]", "");
http://mean79.tistory.com/60

 

java replace 실행시 주의사항들

  public static String getSTRFilter(String str){
   int str_length = str.length();
   String strlistchar   = "";
   String str_imsi   = ""; 
   String []filter_word = {"","\\.","\\?","\\/">\\~","\\!","\\@","\\#","\\$","\\%","\\^","\\&","\\*","\\(","\\)","\\_","\\+","\\=","\\|","\\\\","\\}","\\]","\\{","\\[","\\\"","\\'","\\:","\\;","\\<","\\,","\\>","\\.","\\?","\\/"};

   for(int i=0;i<filter_word.length;i++){
    //while(str.indexOf(filter_word[i]) >= 0){
       str_imsi = str.replaceAll(filter_word[i],"");
       str = str_imsi;
    //}
   }

   return str;

  }


아님 replace가 안 먹을때는 이런방법도..^^

import java.util.StringTokenizer;

 public class WebUtil
 {
            // 문자열 변환  String a= "abc" => replace(a, "c") => a : ab
            public String strReplace(String s1, String s2){
                       String res = "";
                       StringTokenizer str = new StringTokenizer(s1, s2);


                        while(str.hasMoreTokens()){
                                      res += str.nextToken();  
                                System.out.println(res);
                        }
                return res;
            }
 }

 

[출처http://mean79.tistory.com/478



오늘은 JavaScript에서 함수 사용 시 주의할 부분에 대해 알아보겠습니다.

JavaScript는 동적 타입이면서 함수로의 인자 전달이 유연하기 때문에 사용에 주의가 요구됩니다.

중복 정의

Java에서는 함수를 중복 정의하면 에러가 발생합니다.

Duplicate method in Java

하지만 JavaScript에서는 함수를 중복으로 정의해도 에러가 발생하지 않고 대신 마지막 함수만 유효하게 사용됩니다. 이에 대한 사례는 사용되지 않는 코드를 참고하세요.

호출 인자 누락

호출자(caller)가 함수에 인자를 전달하지 않았는데 함수 내에서 해당 인자를 사용하는 경우입니다.

다음의 예를 보죠.

  1. checkDateFormat 함수를 두 개의 인자 date와 datePattern으로 호출합니다.

    function setCondition(rowId) {
        try {
            ...
            var date = getCellEditingValue("input", rowId, "startDate", $tr);
    
            var result = checkDateFormat(date, datePattern);
            if (!result.success) {
                throw new Error("date is not vaild.");
            }
    
  2. 호출된 checkDateFormat 함수에서는 위에서 전달되지 않은 dateName 인자를 사용합니다.

    function checkDateFormat(dt, dateFormat, dateName) {
        var isValid = ValidatorFactory.getDateFormatValidator(dateFormat);
    
        if (!isValid(dt)) {
            return {
                success: false,
                message: dateName + ' : 일자 형식이 잘못되었습니다.'
            };
        }
    

그 결과 undefined 값과 문자열이 결합하여 유효하지 않은 문자열이 사용자에게 노출되므로 해당 인자에 대한 처리(null 체크나 기본값 설정)가 필요합니다.

호출 인자의 속성 누락

호출자가 함수에 전달한 인자에 없는 속성을 함수 내에서 사용하는 경우입니다.

다음의 예를 보죠.

  1. fn_detailPopup 함수를 호출하는 두 개의 실행 경로 1)과 2)가 있습니다. 1)의 경우 argsVo.statusCodeId가 설정되지 않은 채로 호출합니다.

    if (colName.indexOf("testSeverity") != -1) {
        argsVo.flag = "SEVERITY";
        argsVo.severityCodeId = colName.replace("testSeverity", "");
    
        fn_detailPopup(argsVo); // 1)
    }
    
    if (colName.indexOf("statusCodeId") != -1) {
        argsVo.flag = "STATUS";
        argsVo.statusCodeId = colName.replace("statusCodeId", "");
    
        fn_detailPopup(argsVo); // 2)
    }
    
  2. 호출된 fn_detailPopup 함수에서는 argvVo 인자의 설정되지 않은 statusCodeId 속성을 사용합니다.

    function fn_detailPopup(argsVo) {
        ...
        url += '&severityCode=' + argsVo.severityCodeId;
        url += '&statusCodeId=' + argsVo.statusCodeId;
    

그 결과 statusCodeId 파라미터가 “undefined”라는 문자열로 서버에 전달되므로 서버에서 이에 대한 처리가 필요할 수 있습니다. 따라서 클라이언트 측에서 해당 속성 존재 여부를 서버 전달 전에 명확하게 체크하는 것이 좋습니다.

API 호출 시 인자 타입 오류

JavaScript built-in 함수나 DOM API 함수는 정해진 타입의 인자가 있어서 잘못된 타입의 인자로 호출하는 경우 TypeError가 발생합니다.

가령 아래 코드 실행 시 TypeError: Argument 1 of Node.appendChild is not an object. 에러가 발생합니다.

document.body.appendChild('foo');

제가 개발 중인 솔루션에서는 built-in 함수와 DOM API 함수 모델링을 통해 인자 타입 정보를 내장하여 실행 전에 소스 레벨에서 아래와 같이 검출할 수 있습니다.first argument type of Node.prototype.appendChild() API must be Node DOM instance object.

API 호출 시 인자 개수 오류

JavaScript built-in 함수나 DOM API 함수는 잘못된 개수의 인자로 호출하는 경우 TypeError가 발생할 수 있습니다.

가령 아래 코드 실행 시 TypeError: Not enough arguments to Document.getElementById. 에러가 발생합니다.

var elem = document.getElementById();

개발 중인 솔루션에서는 built-in 함수와 DOM API 함수 모델링을 통해 아래와 같이 검출됩니다.number of arguments of Document.prototype.getElementById() API must be 1

Wrap-Up

이상 JavaScript 함수 사용에 대해 알아보았습니다.

다른 언어와 다른 JavaScript 특성을 이해하고 함수 사용에 주의하세요.

  • JavaScript는 함수 오버로딩을 지원하지 않으므로 함수 정의를 중복하지 않도록 한다.
  • 다양한 실행 경로에서 인자 및 인자 속성 정의가 잘 전달되는지 점검한다. 필요한 경우 함수 내에서 인자 및 속성에 대한 유효성 검사를 하는 것이 좋다.



출처 : https://cimfalab.github.io/deepscan/2016/10/function-misuse

반응형
반응형

파일 다운로드 창을 하나 만들어서 그 창에 있는 파일 여러개를 버튼 하나로 동시에 다운로드할 수 있는 기능을

만들려고 했다.


하지만 실패.. 구글링에 이것저것 찾아봤는데 http 뭐...response 이런거 통신할때는 파일 하나밖에 전송 안된다고  얼핏 본것같다. (아님말고..)

만약에 그렇게 구현하려면 아마 setTime으로 시간을 조정해서 해야할듯?


아무튼..  잘안되서 포기하고 파일들을 zip파일로 묶어 바로 전송하도록 했다.


참고로 ZipOutputStream은 한글지원이 안된다고 한다..



 

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
53
54
import java.util.zip.ZipOutputStream;
 
int bufferSize = 1024 * 2;
String ouputName = "test";
            
ZipOutputStream zos = null;
            
try {
                
    if (request.getHeader("User-Agent").indexOf("MSIE 5.5"> -1) {
        response.setHeader("Content-Disposition""filename=" ouputName + ".zip" + ";");
    } else {
        response.setHeader("Content-Disposition""attachment; filename=" + ouputName + ".zip" + ";");
    }
    response.setHeader("Content-Transfer-Encoding""binary");
    
                
    OutputStream os = response.getOutputStream();
    zos = new ZipOutputStream(os); // ZipOutputStream
    zos.setLevel(8); // 압축 레벨 - 최대 압축률은 9, 디폴트 8
    BufferedInputStream bis = null;
                
    
    String[] filePaths = {"filePath1","filePath2","filePath3"};
    String[] fileNames = {"fileName1","fileName2","fileName3"};
    int    i = 0;
    for(String filePath : filePaths){
        File sourceFile = new File(filePath);
                        
        bis = new BufferedInputStream(new FileInputStream(sourceFile));
        ZipEntry zentry = new ZipEntry(fileNames[i]);
        zentry.setTime(sourceFile.lastModified());
        zos.putNextEntry(zentry);
        
        byte[] buffer = new byte[bufferSize];
        int cnt = 0;
        while ((cnt = bis.read(buffer, 0, bufferSize)) != -1) {
            zos.write(buffer, 0, cnt);
        }
        zos.closeEntry();
 
        i++;
    }
               
    zos.close();
    bis.close();
                
                
catch(Exception e){
    e.printStackTrace();
}
 
 
cs



출처 : https://m.blog.naver.com/PostView.nhn?blogId=92211hyeon&logNo=220337059932&proxyReferer=https%3A%2F%2Fwww.google.co.kr%2F

반응형
반응형

출처:http://homoefficio.github.io/

Spring에서 JSON에 XSS 방지 처리 하기

고마운 lucy-xss-servlet-filter의 한계

XSS(Cross Site Scripting) 방지를 위해 널리 쓰이는 훌륭한 lucy-xss-servlet-filter는 Servlet Filter 단에서 < 등의 특수 문자를 &lt; 등으로 변환해주며, 여러 가지 관련 설정을 편리하게 지정할 수 있어 정말 좋다.

lucy-xss-servlet 는 naver에서 발표하고 Git 에서 배포된다 

https://github.com/naver/lucy-xss-servlet-filter 이곳에서도 참고 할 수 있다

그런데 그 처리가 form-data에 대해서만 적용되고 Request Raw Body로 넘어가는 JSON에 대해서는 처리해주지 않는다는 단점이 있다. 그래서 JSON을 주고 받는 API 서버의 경우에는 직접 처리를 해줘야 한다.

lucy-xss-servlet-filter를 수정해서 JSON도 처리하도록 만드는 방법도 있겠지만, 여기에서는 Response를 클라이언트로 내보내는 단계에서 처리하는 방법을 알아본다.

HandlerInterceptor

Response 쪽에서 공통적으로 처리해줘야할 일이 있다면 금방 떠오르는 것이 HanderInterceptor의 postHandle()이다. 이 메서드의 파라미터는 HttpServletRequest requestHttpServletResponse responseObject handlerModelAndView modelAndView이고, response에서 Response Body를 꺼내서, < => &lt; 등의 변환 처리를 하고 다시 response에 넣어주면 될 것 같다.

하지만 response에서 Response Body를 끄집어 내는 것도 쉽지 않고, 그 내용을 바꿔서 다시 집어넣는 것도 여의치 않다. 다른 방법이 필요하다.

MessageConverter

다음으로 생각나는 것은 MessageConverter다. 어차피 결국에는 Jackson 같은 Mapper를 통해 JSON 문자열로 Response에 담겨지므로, Mapper가 JSON 문자열을 생성할 때 XSS 방지 처리를 해주면 될 것 같다.

찾아보니 역시나 http://stackoverflow.com/questions/25403676/initbinder-with-requestbody-escaping-xss-in-spring-3-2-4 이런 자료가 있다. 좀 오래된 버전이고 군더더기도 있어서 Jackson 2.#, SpringBoot 1.# 버전 기준으로 깔끔하게, 그리고 커스터마이징 할 수 있는 부분을 추가해서 정리해봤다.

큰 흐름은 다음과 같다.

  1. 처리할 특수 문자 지정
  2. 특수 문자 인코딩 값 지정
  3. ObjectMapper에 특수 문자 처리 기능 적용
  4. MessageConverter에 ObjectMapper 설정
  5. WebMvcConfigurerAdapter에 MessageConverter 추가

처리할 특수 문자 지정

XSS 방지 처리할 특수 문자를 다음과 같이 CharacterEscapes를 상속한 클래스를 직접 만들어서 지정해준다.

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
53
54
55
56
57
import com.fasterxml.jackson.core.SerializableString;
import com.fasterxml.jackson.core.io.CharacterEscapes;
import com.fasterxml.jackson.core.io.SerializedString;
import org.apache.commons.lang3.text.translate.AggregateTranslator;
import org.apache.commons.lang3.text.translate.CharSequenceTranslator;
import org.apache.commons.lang3.text.translate.EntityArrays;
import org.apache.commons.lang3.text.translate.LookupTranslator;
 
public class HTMLCharacterEscapes extends CharacterEscapes {
 
    private final int[] asciiEscapes;
 
    private final CharSequenceTranslator translator;
 
    public HTMLCharacterEscapes() {
 
        // 1. XSS 방지 처리할 특수 문자 지정
        asciiEscapes = CharacterEscapes.standardAsciiEscapesForJSON();
        asciiEscapes['<'= CharacterEscapes.ESCAPE_CUSTOM;
        asciiEscapes['>'= CharacterEscapes.ESCAPE_CUSTOM;
        asciiEscapes['&'= CharacterEscapes.ESCAPE_CUSTOM;
        asciiEscapes['\"'= CharacterEscapes.ESCAPE_CUSTOM;
        asciiEscapes['('= CharacterEscapes.ESCAPE_CUSTOM;
        asciiEscapes[')'= CharacterEscapes.ESCAPE_CUSTOM;
        asciiEscapes['#'= CharacterEscapes.ESCAPE_CUSTOM;
        asciiEscapes['\''= CharacterEscapes.ESCAPE_CUSTOM;
 
        // 2. XSS 방지 처리 특수 문자 인코딩 값 지정
        translator = new AggregateTranslator(
            new LookupTranslator(EntityArrays.BASIC_ESCAPE()),  // <, >, &, " 는 여기에 포함됨
            new LookupTranslator(EntityArrays.ISO8859_1_ESCAPE()),
            new LookupTranslator(EntityArrays.HTML40_EXTENDED_ESCAPE()),
            // 여기에서 커스터마이징 가능
            new LookupTranslator(
                new String[][]{
                    {"(",  "&#40;"},
                    {")",  "&#41;"},
                    {"#",  "&#35;"},
                    {"\'""&#39;"}
                }
            )
        );
    }
 
    @Override
    public int[] getEscapeCodesForAscii() {
        return asciiEscapes;
    }
 
    @Override
    public SerializableString getEscapeSequence(int ch) {
        return new SerializedString(translator.translate(Character.toString((char) ch)));
 
        // 참고 - 커스터마이징이 필요없다면 아래와 같이 Apache Commons Lang3에서 제공하는 메서드를 써도 된다.
        // return new SerializedString(StringEscapeUtils.escapeHtml4(Character.toString((char) ch)));
    }
}
cs


ObjectMapper에 특수 문자 처리 기능 적용 후 MessageConverter 등록

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
@Bean
public WebMvcConfigurerAdapter controlTowerWebConfigurerAdapter() {
    return new WebMvcConfigurerAdapter() {
 
        @Override
        public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
            super.configureMessageConverters(converters);
 
            // 5. WebMvcConfigurerAdapter에 MessageConverter 추가
            converters.add(htmlEscapingConveter());
        }
 
        private HttpMessageConverter<?> htmlEscapingConveter() {
            ObjectMapper objectMapper = new ObjectMapper();
            // 3. ObjectMapper에 특수 문자 처리 기능 적용
            objectMapper.getFactory().setCharacterEscapes(new HTMLCharacterEscapes());
 
            // 4. MessageConverter에 ObjectMapper 설정
            MappingJackson2HttpMessageConverter htmlEscapingConverter =
                    new MappingJackson2HttpMessageConverter();
            htmlEscapingConverter.setObjectMapper(objectMapper);
 
            return htmlEscapingConverter;
        }
    };
}
cs

정리

lucy-xss-servlet-filter는 JSON에 대한 XSS는 처리해주지 않는다.

  • 따라서, JSON에 대한 XSS가 필요하다면
  • Jackson의 com.fasterxml.jackson.core.io.CharacterEscapes를 상속하는 클래스 A를 직접 만들어서 처리해야 할 특수문자를 지정하고,
  • ObjectMapper에 A를 설정하고,
  • ObjectMapper를 MessageConverter에 등록해서 Response가 클라이언트에 나가기 전에 XSS 방지 처리 해준다.



언제 개인 프로젝트에 적용해 볼까 하고 가져왔다

반응형
반응형


-XSS 필터



웹 페이지를 만들보면 사용자의 악의적인 공격을 많이 받게되는데



이런 것들중 가장 대표적인것이 XSS 공격이다


크로스 사이트 스크립트 라는것인데 서버로 보내는 입력값에 자바스크립트를 보내서


다른 사용자에게 자신이 만든 스크립트를 실행시켜서 사용자의 정보를 빼내는것이다




지금 당장 자신의 사이트가 XSS 를 방어하고 있는지 확인하는 방법은 간단하다


입력창 아무대서나 <script> alert("script ok"); </script> 라고 입력하고


저장한 후 상세화면으로 들어갔을때 해당 코드가 실행되는지 확인하면 간단하다



이런 문제를 해결하는데에는 많은 방법이 있지만 간단하게 Filter 추가 만으로 해결할 수 있는 방법이 있다


1. CrossScriptingFilter 필터 파일

2. RequestWrapper  필터링을 실행할 파일

3. web.xml 에서 세팅


1. 기본 컨트롤 클래스

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
 
package com.greatwebguy.filter;
 
import java.io.IOException;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
 
 
public class CrossScriptingFilter implements Filter {
 
    public void init(FilterConfig filterConfig) throws ServletException {
        this.filterConfig = filterConfig;
    }
 
    public void destroy() {
        this.filterConfig = null;
    }
 
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
        throws IOException, ServletException {
 
        chain.doFilter(new RequestWrapper((HttpServletRequest) request), response);
 
    }
 
}
cs




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
53
package com.greatwebguy.filter;
 
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
 
public final class RequestWrapper extends HttpServletRequestWrapper {
 
    public RequestWrapper(HttpServletRequest servletRequest) {
        super(servletRequest);
    }
 
    public String[] getParameterValues(String parameter) {
 
      String[] values = super.getParameterValues(parameter);
      if (values==null)  {
                  return null;
          }
      int count = values.length;
      String[] encodedValues = new String[count];
      for (int i = 0; i < count; i++) {
                 encodedValues[i] = cleanXSS(values[i]);
       }
      return encodedValues;
    }
 
    public String getParameter(String parameter) {
          String value = super.getParameter(parameter);
          if (value == null) {
                 return null;
                  }
          return cleanXSS(value);
    }
 
    public String getHeader(String name) {
        String value = super.getHeader(name);
        if (value == null)
            return null;
        return cleanXSS(value);
 
    }
 
    private String cleanXSS(String value) {
                //You'll need to remove the spaces from the html entities below
        value = value.replaceAll("<""& lt;").replaceAll(">""& gt;");
        value = value.replaceAll("\\(""& #40;").replaceAll("\\)""& #41;");
        value = value.replaceAll("'""& #39;");
        value = value.replaceAll("eval\\((.*)\\)""");
        value = value.replaceAll("[\\\"\\\'][\\s]*javascript:(.*)[\\\"\\\']", "\"\"");
        value = value.replaceAll("script", "");
        return value;
    }
}
cs



3.(<filter-class> 에는 해당 클래스 파일 경로를 넣어야한다)

1
2
3
4
5
6
7
8
9
 
<filter>
    <filter-name>XSS</filter-name>
    <filter-class>com.greatwebguy.filter.CrossScriptingFilter</filter-class>
</filter>
<filter-mapping>
    <filter-name>XSS</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>
cs




-URIEncodin 필터


Tomcat에서 한글 encoding을 설정하는 방법은 요청 메써드 (GET or POST)에 따라 다르다.

get 방식

Tomcat의 sever.xml 을 열고 

1
2
3
4
<Connector port="9090" protocol="HTTP/1.1" 
                 connectionTimeout="20000" 
                redirectPort="8443"
                URIEncoding="utf-8" />
cs


위 URIEncoding 부분을 추가했다.. 그러니 한글이 깨지는 것을 막을 수 있었다.
기본적으로 톰캣은 ISO-8859-1 인코딩 한다.
그래서 한글이 깨졌던거 같다.

post 방식

web.xml 아래와 같이 filter class 를 등록한다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
 <filter>
  <filter-name>Set Character Encoding</filter-name>
  <filter-class>filters.SetCharacterEncodingFilter</filter-class>
  <init-param>
   <param-name>encoding</param-name>
   <param-value>utf-8</param-value>
  </init-param>
 </filter>
 
 <filter-mapping>
  <filter-name>Set Character Encoding</filter-name>
  <url-pattern>/*</url-pattern>
 </filter-mapping>
 
 <filter-mapping>
   <filter-name>encodingFilter</filter-name>
   <url-pattern>/*</url-pattern>
 </filter-mapping>
 
 
cs





출처 사이트:

http://18281818.tistory.com/76 [반이라도 이해하자]

http://kcmuni.tistory.com/entry/한글-깨짐-처리URIEncodingUTF-8 [내일을 항해~]


반응형
반응형

오늘은 간단한 팁을 드리려고합니다

보통 submit 방식으로 데이터를 넘긴후 

알림창을띄워줘야할떄가 있습니다.

페이지로 이동해서 해도되지만 ajax 방식이 아니라서 애매하게되죠


검색하면 PrintWriter 라는 클래스를 이용하여 자바단에서 스크립트 조작이 가능합니다

그런데 잘못사용하는 경우가 있습니다


-잘못된 사용의 예


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
@RequestMapping(value = "/goregist", method = RequestMethod.POST)
    @ResponseBody
    public ModelAndView OrganRegist(HttpServletRequest request, HttpServletResponse response) throws Exception {
        Map<String, Object> result = new HashMap<String,Object>();
        C_OrganVO vo = new C_OrganVO();
        vo.setT_num(Integer.parseInt(request.getParameter("t_num")));
        vo.setType(request.getParameter("type"));
        vo.setName(request.getParameter("name"));
        vo.setContent(request.getParameter("content"));
        vo.setHomepage(request.getParameter("homepage"));
        vo.setPhone_number(request.getParameter("phone_number"));
        int cnt = c_organService.registC_Organ(vo);
        if(cnt==1){
            result.put("state""success");
            PrintWriter writer = response.getWriter();
            writer.println("<script>alert('Success'); location.href='/helpInfo/update';</script>");
            return new ModelAndView("redirect:/helpInfo/update");
        } else{
            result.put("state""fail");
            result.put("error", egovMessageSource.getMessage("fail.update.information"));
        }
        return new ModelAndView("redirect:/helpInfo/02");
    }
cs


실제로 잘못 사용된 예제를 가져와봤습니다

여기서 보면 

1
2
3
result.put("state""success");
PrintWriter writer = response.getWriter();
writer.println("<script>alert('Success'); location.href='/helpInfo/update';</script>");
cs



이렇게 된 부분이있을건데 잘못사용된 부분입니다

response는 예민한 객체이기 때문에


1
2
3
4
5
6
7
response.setContentType("text/html; charset=UTF-8");
 
PrintWriter out = response.getWriter();
 
out.println("<script>alert('계정이 등록 되었습니다'); location.href='이동주소';</script>");
 
out.flush();
cs


이렇게 사용해주시는것이 올바를 표현방식입니다

이상 사용법설명을 마치겠습니다

반응형
반응형
1

+ Recent posts