반응형

spring-boot-1.4.2.RELEASE.jar 의 org/springframework/boot/logging/logback/base.xml 에 위치한 파일 내용입니다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<?xml version="1.0" encoding="UTF-8"?>
 
<!--
Base logback configuration provided for compatibility with Spring Boot 1.1
-->
 
<included>
    <include resource="org/springframework/boot/logging/logback/defaults.xml" />
    <property name="LOG_FILE" value="${LOG_FILE:-${LOG_PATH:-${LOG_TEMP:-${java.io.tmpdir:-/tmp}}}/spring.log}"/>
    <include resource="org/springframework/boot/logging/logback/console-appender.xml" />
    <include resource="org/springframework/boot/logging/logback/file-appender.xml" />
    <root level="INFO">
        <appender-ref ref="CONSOLE" />
        <appender-ref ref="FILE" />
    </root>
</included>
 
cs


반응형
반응형

java에서 대소문자 구분없이 치환하는 코드 입니다.


앞에 (?i) 를 넣어 주면 됩니다.


1
2
3
  public static void main(String[] args) {
    System.out.println("ONCLICK".replaceAll("(?i)onclick""noclick"));
  }
cs


결과 입니다.



noclick
 
cs


반응형
반응형


개발하다보면 랜덤 한글이름이 필요한 경우가 있습니다.

뭐 유니코드니 아스키코드니 복잡하게 하지 않고 단순무식하게 한글이름 랜덤하게 생성해주는 함수를 만들어 보았습니다.


성은 우리나라 많이쓰는 성 순위 100위 이고, 이름은 대충 이름에 많이 들어가는 글자들 정리해 봤습니다.

경우에 맞춰서 조금 수정해서 쓰시면 쓸만한 랜덤 한글 이름을 뽑아 쓰실 수 있을 겁니다.


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
public static String randomHangulName() {
    List<String> 성 = Arrays.asList("김""이""박""최""정""강""조""윤""장""임""한""오""서""신""권""황""안",
        "송""류""전""홍""고""문""양""손""배""조""백""허""유""남""심""노""정""하""곽""성""차""주",
        "우""구""신""임""나""전""민""유""진""지""엄""채""원""천""방""공""강""현""함""변""염""양",
        "변""여""추""노""도""소""신""석""선""설""마""길""주""연""방""위""표""명""기""반""왕""금",
        "옥""육""인""맹""제""모""장""남""탁""국""여""진""어""은""편""구""용");
    List<String> 이름 = Arrays.asList("가""강""건""경""고""관""광""구""규""근""기""길""나""남""노""누""다",
        "단""달""담""대""덕""도""동""두""라""래""로""루""리""마""만""명""무""문""미""민""바""박",
        "백""범""별""병""보""빛""사""산""상""새""서""석""선""설""섭""성""세""소""솔""수""숙""순",
        "숭""슬""승""시""신""아""안""애""엄""여""연""영""예""오""옥""완""요""용""우""원""월""위",
        "유""윤""율""으""은""의""이""익""인""일""잎""자""잔""장""재""전""정""제""조""종""주""준",
        "중""지""진""찬""창""채""천""철""초""춘""충""치""탐""태""택""판""하""한""해""혁""현""형",
        "혜""호""홍""화""환""회""효""훈""휘""희""운""모""배""부""림""봉""혼""황""량""린""을""비",
        "솜""공""면""탁""온""디""항""후""려""균""묵""송""욱""휴""언""령""섬""들""견""추""걸""삼",
        "열""웅""분""변""양""출""타""흥""겸""곤""번""식""란""더""손""술""훔""반""빈""실""직""흠",
        "흔""악""람""뜸""권""복""심""헌""엽""학""개""롱""평""늘""늬""랑""얀""향""울""련");
    Collections.shuffle(성);
    Collections.shuffle(이름);
    return 성.get(0+ 이름.get(0+ 이름.get(1);
  }
 
  public static void main(String[] args) {
    for (int i = 0; i < 100; i++) {
      if (i % 10 == 0) {
        System.out.println();
      }
      System.out.print(randomHangulName() + ", ");
    }
  }
cs



아래는 100개 돌려본 결과 입니다.


1
2
3
4
5
6
7
8
9
10
11
 
권래다, 전량운, 강덕봉, 채원조, 모여잎, 오서찬, 채려열, 유비철, 정한새, 용배란, 
오걸두, 구항탁, 엄숭강, 백월해, 진혜들, 임출석, 길더얀, 설손무, 연문희, 최탁더, 
위빈상, 편운신, 조진빈, 곽옥석, 용담현, 백혜의, 임권조, 이천비, 길요흥, 박회휴, 
남심가, 인솜길, 기리용, 하선송, 여열울, 황시송, 한의혜, 맹묵보, 주디변, 용양번, 
염지묵, 성덕동, 탁조옥, 주더형, 허휘주, 송다회, 옥상평, 성도울, 우희덕, 주추형, 
옥래삼, 옥린재, 추바후, 남모율, 방향용, 황엽번, 조병바, 박순자, 주하소, 나동길, 
신웅직, 신강뜸, 남은길, 어산묵, 왕직만, 길항훈, 강미헌, 황견채, 탁엽설, 모영판, 
함백자, 최고덕, 백일시, 배고문, 설리미, 홍만엄, 탁하달, 임영애, 양으자, 전훔늘, 
허을율, 이별솜, 문설타, 길술잎, 어길도, 심언자, 주섭중, 차더익, 박술늬, 선인정, 
표흥바, 강학경, 길손애, 노훈단, 표건새, 곽회라, 방향석, 남묵현, 임헌춘, 신고봉, 
cs


반응형
반응형

개발하다 보면 알파벳 포함한 문자열을 KEY로 잡으면서 시퀀셜하게 증가 시켜야하는 경우가 있습니다.


이럴 때 사용할 수 있는 알파벳 증가 시키키 함수 입니다.


아래 함수를 쓰시면 됩니다.


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
  public static String nextAlphabet(String source) {
    int length = source.length();
    char lastChar = source.charAt(length - 1);
    if (lastChar == 'Z') {
      if (length == 1) {
        return source = "AA";
      }
      source = nextAlphabet(source.substring(0length - 1));
      source += "A";
      return source;
    }
    return source.substring(0length - 1+ String.valueOf((char) (lastChar + 1));
  }
 
  public static void main(String[] args) {
    String source = "A";
    for (int i = 1; i < 1000; i++) {
      if (i % 26 == 0) {
        System.out.println();
      }
      source = nextAlphabet(source);
      System.out.print(source + ",");
 
    }
  }
cs



결과 화면은 아래와 같습니다.

Z까지 되면 자릿수가 늘어 납니다.


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
B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z,
AA,AB,AC,AD,AE,AF,AG,AH,AI,AJ,AK,AL,AM,AN,AO,AP,AQ,AR,AS,AT,AU,AV,AW,AX,AY,AZ,
BA,BB,BC,BD,BE,BF,BG,BH,BI,BJ,BK,BL,BM,BN,BO,BP,BQ,BR,BS,BT,BU,BV,BW,BX,BY,BZ,
CA,CB,CC,CD,CE,CF,CG,CH,CI,CJ,CK,CL,CM,CN,CO,CP,CQ,CR,CS,CT,CU,CV,CW,CX,CY,CZ,
DA,DB,DC,DD,DE,DF,DG,DH,DI,DJ,DK,DL,DM,DN,DO,DP,DQ,DR,DS,DT,DU,DV,DW,DX,DY,DZ,
EA,EB,EC,ED,EE,EF,EG,EH,EI,EJ,EK,EL,EM,EN,EO,EP,EQ,ER,ES,ET,EU,EV,EW,EX,EY,EZ,
FA,FB,FC,FD,FE,FF,FG,FH,FI,FJ,FK,FL,FM,FN,FO,FP,FQ,FR,FS,FT,FU,FV,FW,FX,FY,FZ,
GA,GB,GC,GD,GE,GF,GG,GH,GI,GJ,GK,GL,GM,GN,GO,GP,GQ,GR,GS,GT,GU,GV,GW,GX,GY,GZ,
HA,HB,HC,HD,HE,HF,HG,HH,HI,HJ,HK,HL,HM,HN,HO,HP,HQ,HR,HS,HT,HU,HV,HW,HX,HY,HZ,
IA,IB,IC,ID,IE,IF,IG,IH,II,IJ,IK,IL,IM,IN,IO,IP,IQ,IR,IS,IT,IU,IV,IW,IX,IY,IZ,
JA,JB,JC,JD,JE,JF,JG,JH,JI,JJ,JK,JL,JM,JN,JO,JP,JQ,JR,JS,JT,JU,JV,JW,JX,JY,JZ,
KA,KB,KC,KD,KE,KF,KG,KH,KI,KJ,KK,KL,KM,KN,KO,KP,KQ,KR,KS,KT,KU,KV,KW,KX,KY,KZ,
LA,LB,LC,LD,LE,LF,LG,LH,LI,LJ,LK,LL,LM,LN,LO,LP,LQ,LR,LS,LT,LU,LV,LW,LX,LY,LZ,
MA,MB,MC,MD,ME,MF,MG,MH,MI,MJ,MK,ML,MM,MN,MO,MP,MQ,MR,MS,MT,MU,MV,MW,MX,MY,MZ,
NA,NB,NC,ND,NE,NF,NG,NH,NI,NJ,NK,NL,NM,NN,NO,NP,NQ,NR,NS,NT,NU,NV,NW,NX,NY,NZ,
OA,OB,OC,OD,OE,OF,OG,OH,OI,OJ,OK,OL,OM,ON,OO,OP,OQ,OR,OS,OT,OU,OV,OW,OX,OY,OZ,
PA,PB,PC,PD,PE,PF,PG,PH,PI,PJ,PK,PL,PM,PN,PO,PP,PQ,PR,PS,PT,PU,PV,PW,PX,PY,PZ,
QA,QB,QC,QD,QE,QF,QG,QH,QI,QJ,QK,QL,QM,QN,QO,QP,QQ,QR,QS,QT,QU,QV,QW,QX,QY,QZ,
RA,RB,RC,RD,RE,RF,RG,RH,RI,RJ,RK,RL,RM,RN,RO,RP,RQ,RR,RS,RT,RU,RV,RW,RX,RY,RZ,
SA,SB,SC,SD,SE,SF,SG,SH,SI,SJ,SK,SL,SM,SN,SO,SP,SQ,SR,SS,ST,SU,SV,SW,SX,SY,SZ,
TA,TB,TC,TD,TE,TF,TG,TH,TI,TJ,TK,TL,TM,TN,TO,TP,TQ,TR,TS,TT,TU,TV,TW,TX,TY,TZ,
UA,UB,UC,UD,UE,UF,UG,UH,UI,UJ,UK,UL,UM,UN,UO,UP,UQ,UR,US,UT,UU,UV,UW,UX,UY,UZ,
VA,VB,VC,VD,VE,VF,VG,VH,VI,VJ,VK,VL,VM,VN,VO,VP,VQ,VR,VS,VT,VU,VV,VW,VX,VY,VZ,
WA,WB,WC,WD,WE,WF,WG,WH,WI,WJ,WK,WL,WM,WN,WO,WP,WQ,WR,WS,WT,WU,WV,WW,WX,WY,WZ,
XA,XB,XC,XD,XE,XF,XG,XH,XI,XJ,XK,XL,XM,XN,XO,XP,XQ,XR,XS,XT,XU,XV,XW,XX,XY,XZ,
YA,YB,YC,YD,YE,YF,YG,YH,YI,YJ,YK,YL,YM,YN,YO,YP,YQ,YR,YS,YT,YU,YV,YW,YX,YY,YZ,
ZA,ZB,ZC,ZD,ZE,ZF,ZG,ZH,ZI,ZJ,ZK,ZL,ZM,ZN,ZO,ZP,ZQ,ZR,ZS,ZT,ZU,ZV,ZW,ZX,ZY,ZZ,
AAA,AAB,AAC,AAD,AAE,AAF,AAG,AAH,AAI,AAJ,AAK,AAL,AAM,AAN,AAO,AAP,AAQ,AAR,AAS,AAT,AAU,AAV,AAW,AAX,AAY,AAZ,
ABA,ABB,ABC,ABD,ABE,ABF,ABG,ABH,ABI,ABJ,ABK,ABL,ABM,ABN,ABO,ABP,ABQ,ABR,ABS,ABT,ABU,ABV,ABW,ABX,ABY,ABZ,
ACA,ACB,ACC,ACD,ACE,ACF,ACG,ACH,ACI,ACJ,ACK,ACL,ACM,ACN,ACO,ACP,ACQ,ACR,ACS,ACT,ACU,ACV,ACW,ACX,ACY,ACZ,
ADA,ADB,ADC,ADD,ADE,ADF,ADG,ADH,ADI,ADJ,ADK,ADL,ADM,ADN,ADO,ADP,ADQ,ADR,ADS,ADT,ADU,ADV,ADW,ADX,ADY,ADZ,
AEA,AEB,AEC,AED,AEE,AEF,AEG,AEH,AEI,AEJ,AEK,AEL,AEM,AEN,AEO,AEP,AEQ,AER,AES,AET,AEU,AEV,AEW,AEX,AEY,AEZ,
AFA,AFB,AFC,AFD,AFE,AFF,AFG,AFH,AFI,AFJ,AFK,AFL,AFM,AFN,AFO,AFP,AFQ,AFR,AFS,AFT,AFU,AFV,AFW,AFX,AFY,AFZ,
AGA,AGB,AGC,AGD,AGE,AGF,AGG,AGH,AGI,AGJ,AGK,AGL,AGM,AGN,AGO,AGP,AGQ,AGR,AGS,AGT,AGU,AGV,AGW,AGX,AGY,AGZ,
AHA,AHB,AHC,AHD,AHE,AHF,AHG,AHH,AHI,AHJ,AHK,AHL,AHM,AHN,AHO,AHP,AHQ,AHR,AHS,AHT,AHU,AHV,AHW,AHX,AHY,AHZ,
AIA,AIB,AIC,AID,AIE,AIF,AIG,AIH,AII,AIJ,AIK,AIL,AIM,AIN,AIO,AIP,AIQ,AIR,AIS,AIT,AIU,AIV,AIW,AIX,AIY,AIZ,
AJA,AJB,AJC,AJD,AJE,AJF,AJG,AJH,AJI,AJJ,AJK,AJL,AJM,AJN,AJO,AJP,AJQ,AJR,AJS,AJT,AJU,AJV,AJW,AJX,AJY,AJZ,
AKA,AKB,AKC,AKD,AKE,AKF,AKG,AKH,AKI,AKJ,AKK,AKL,AKM,AKN,AKO,AKP,AKQ,AKR,AKS,AKT,AKU,AKV,AKW,AKX,AKY,AKZ,
ALA,ALB,ALC,ALD,ALE,ALF,ALG,ALH,ALI,ALJ,ALK,ALL,
cs


반응형
반응형

SpringSecurity 에서 자동로그인 RememberMe 를 사용하면 해당 쿠키를 찾지 못하는 경우 CookieTheftException 예외가 발생합니다.

이 예외를 잡아서 처리하고 싶을 때 아래처럼 필터를 이용하신면 됩니다.


1
2
3
4
5
6
7
8
9
10
11
 
@Configuration
@EnableWebSecurity
public class MultiHttpSecurityConfig extends WebSecurityConfigurerAdapter {
  @Override
  protected void configure(HttpSecurity http) throws Exception {
        ...
        http.addFilterAfter(new ExceptionHandlerFilter(), SecurityContextHolderAwareRequestFilter.class);
        ...
  }
}
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
 
import java.io.IOException;
 
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
 
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.security.web.authentication.rememberme.CookieTheftException;
import org.springframework.web.filter.GenericFilterBean;
 
import kr.go.seoul.scc.mobile.web.config.Url.HOME;
 
public class ExceptionHandlerFilter extends GenericFilterBean {
 
  private static Logger logger = LoggerFactory.getLogger(ExceptionHandlerFilter.class);
  /**
   * Default AJAX request Header
   */
  private String ajaxHaeder = "AJAX";
 
  public void destroy() {
  }
 
  public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
      throws IOException, ServletException {
    HttpServletRequest req = (HttpServletRequest) request;
    HttpServletResponse res = (HttpServletResponse) response;
 
    if (isAjaxRequest(req)) {
      try {
        chain.doFilter(req, res);
      } catch (CookieTheftException e) {
        logger.error("쿠키바뀜1", e);
        res.sendError(HttpServletResponse.SC_FORBIDDEN);
      }
    } else
      try {
        chain.doFilter(req, res);
      } catch (CookieTheftException e) {
        logger.error("쿠키바뀜2", e);
        res.sendRedirect(HOME.INTRO_EXPIRED);
      }
  }
 
  private boolean isAjaxRequest(HttpServletRequest req) {
    return req.getHeader(ajaxHaeder) != null && req.getHeader(ajaxHaeder).equals(Boolean.TRUE.toString());
  }
 
  /**
   * Set AJAX Request Header (Default is AJAX)
   * 
   * @param ajaxHeader
   */
  public void setAjaxHaeder(String ajaxHeader) {
    this.ajaxHaeder = ajaxHeader;
  }
}
cs


반응형
반응형

현재 작업중인 네트워크의 outbound port 방화벽을 확인해야하는 경우가 있습니다.

이 때, 해당 포트가 열려있는 서버가 있으면 telnet 명령어나 'java-telnet-대신-포트-방화벽-확인하기' 를 이용해서 해당 IP PORT를 찔러보면 바로 알 수 있습니다.

하지만, 해당 포트를 리슨하고 있는 서버가 없을 경우 확인해 볼 방법이 없습니다.

이런 경우 아래 간단한 java 소스를 통해서 서버에서 원하는 포트를 Listen하고 있도록 만들 수 있습니다.


컴파일 : javac PortListen.java

실행 : java PortListen [포트번호] 

1
2
3
4
5
6
7
8
9
10
11
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
 
public class PortListen {
  public static void main(String[] args) throws IOException {
    ServerSocket serverSocket = new ServerSocket(Integer.parseInt(args[0]));
    Socket socket = serverSocket.accept();
  }
}
 



실행 후 해당 포트가 Listen 중인지 확인하는 방법 입니다.

리눅스 : netstat -an|grep 포트번호

윈도우 : netstat -an|findstr 포트번호


더 이상 방화벽이 열린 건지 아닌 건지 헤매지 맙시다.

반응형
반응형

Spring boot 이용해서 Scheduler 를 작업할 때, 부분적인 단위 테스트를 하기가 어렵습니다.


내가 원하는 Job만 선택적으로 실행할 수 있는 테스트 코드입니다.


도움이 되시길 바랍니다.


-- SearchScheduler --

1
2
3
4
5
6
7
8
@Component
public class SearchScheduler {
 
  @Scheduled(fixedDelay = 3000)
  public void searchTest() {
 
  }
}


-- StatScheduler --

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
@Component
public class StatScheduler {
  private static Logger prettyLogger = LoggerFactory.getLogger(Constants.PRETTY_LOGGER_NAME);
 
  // cron 문법 참조
  // http://www.quartz-scheduler.org/documentation/quartz-1.x/tutorials/crontrigger
  @Scheduled(cron = "*/3 * * * * *")
  public void test3() {
    PrettyLog prettyLog = new PrettyLogImpl("StatScheduler.test3-클래스명.메서드명");
    // TODO
    prettyLog.stop();
    prettyLogger.info(prettyLog.prettyPrint());
  }
 
  @Scheduled(cron = "* * * * * *")
  public void test1() {
    PrettyLog prettyLog = new PrettyLogImpl("StatScheduler.test1");
    prettyLog.append("When""1초마다 돌지요");
    prettyLog.stop();
    prettyLogger.info(prettyLog.prettyPrint());
  }
}



-- 테스트 코드 --

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
 
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;
 
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.context.TestConfiguration;
import org.springframework.scheduling.annotation.SchedulingConfigurer;
import org.springframework.scheduling.config.CronTask;
import org.springframework.scheduling.config.IntervalTask;
import org.springframework.scheduling.config.ScheduledTaskRegistrar;
import org.springframework.scheduling.support.ScheduledMethodRunnable;
import org.springframework.test.context.ActiveProfiles;
import org.springframework.test.context.junit4.SpringRunner;
 
 
@RunWith(SpringRunner.class)
@SpringBootTest
public class StatSchedulerTest {
 
  @Test
  public void test() {
    PrettyLog prettyLog = new PrettyLogImpl("test");
    try {
      TimeUnit.SECONDS.sleep(10);
    } catch (Exception e) {
      if (e != null) {
        prettyLog.append("ERROR", e.toString());
      }
      e.printStackTrace();
    } finally {
      prettyLog.stop();
      System.out.println(prettyLog.prettyPrint());
    }
  }
 
  @TestConfiguration
  static class SchedulingTestConfig implements SchedulingConfigurer {
    @Override
    public void configureTasks(ScheduledTaskRegistrar taskRegistrar) {
      PrettyLog prettyLog = new PrettyLogImpl("SchedulingTestConfig");
      List<IntervalTask> taskList = taskRegistrar.getFixedDelayTaskList();
      List<CronTask> cronTaskList = taskRegistrar.getCronTaskList();
      List<IntervalTask> newTaskList = new ArrayList<>();
      List<CronTask> newCronTaskList = new ArrayList<>();
 
      prettyLog.start("IntervalTask");
      for (IntervalTask task : taskList) {
        ScheduledMethodRunnable runnable = (ScheduledMethodRunnable) task.getRunnable();
        String methodName = runnable.getMethod().getName();
        Object target = runnable.getTarget();
 
        if (target instanceof SearchScheduler) {
          if (methodName.equals("searchTest")) {
            prettyLog.append("method",
                target.getClass().getSimpleName() + "." + methodName + "(" + task.getInterval() + "ms)");
            newTaskList.add(new IntervalTask(runnable, task.getInterval(), task.getInitialDelay()));
          }
        }
      }
      prettyLog.stop();
 
      prettyLog.start("CronTask");
      for (CronTask task : cronTaskList) {
        ScheduledMethodRunnable runnable = (ScheduledMethodRunnable) task.getRunnable();
        Method method = runnable.getMethod();
        String methodName = method.getName();
        Object target = runnable.getTarget();
        if (target instanceof StatScheduler) {
          if (methodName.equals("test1")) {
            prettyLog.append("method",
                target.getClass().getSimpleName() + "." + methodName + "(" + task.getExpression() + ")");
            newCronTaskList.add(new CronTask(runnable, task.getExpression()));
          }
        }
      }
      prettyLog.stop();
 
      taskRegistrar.setFixedDelayTasksList(newTaskList);
      taskRegistrar.setCronTasksList(newCronTaskList);
      prettyLog.stop();
      System.out.println(prettyLog.prettyPrint());
    }
  }
}




-- 설정 부분 로그 --


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
+---------------------------------------------------
|START                : 2037-09-19 04:54:33,195
|ID                   : SchedulingTestConfig
| +---------------------------------------------------
| |START                : 2037-09-19 04:54:33,196
| |ID                   : IntervalTask
| |method               : SearchScheduler.searchTest(3000ms)
| |ELAPSED              : 0 ms
| +---------------------------------------------------
| +---------------------------------------------------
| |START                : 2037-09-19 04:54:33,201
| |ID                   : CronTask
| |method               : StatScheduler.test1(* * * * * *)
| |ELAPSED              : 0 ms
| +---------------------------------------------------
|ELAPSED              : 13 ms
+---------------------------------------------------
cs


반응형
반응형

Netty 4.0 이전 버전과 이후 버전의 가장 큰 차이점 입니다.

참고하세요.


IoBuffervsChannelBuffer
get()readByte()
get(byte[])readBytes(byte[])
remaining()readableBytes()
put(byte[])writeBytes(byte[])
put(byte)writeByte(byte)
flip()resetReaderIndex() 
allocate(int)ChannelBuffers.buffer(int)
setAutoExpanddynamicBuffer
skip(int)skipBytes(int)
position()readerIndex()


반응형
반응형
새로운 리눅스 서버에서 서비스를 하기 위해 시스템을 구성하다보면 오라클11g jdbc 라이브러리를 통해 DB접근 시 아래와 같이 Connection Reset 오류가 발생할 수 있습니다.

1
java.sql.SQLRecoverableException: IO Error: Connection reset



원인으로는 Connection 생성시에 암호화에 사용할 40BYTE 키를 랜덤하게 생성하는데 이 랜덤키를 생성하지 못해서 발생하는 문제입니다.


Java는 리눅스에서 기본적으로 /dev/random 을 통해서 난수를 생성합니다.

이 파일이 난수를 생성하는 기반이 "서버의 장치 드라이버와 기타 소스로부터 모은 환경적 노이즈"를 가지고 난수를 생성하게 됩니다.

그래서 새 서버에서는 OS의 환경적 노이즈가 적어서 난수 생성에 문제가 생기는 겁니다.


해결방법으로는 /dev/urandom 을 대신 사용해서 난수를 생성시키는 겁니다.


방법은 2가지가 있습니다.


1. java vm 옵션을 통해 해당 java 데몬의 난수 생성 파일을 변경하는 겁니다. 

1
2
3
4
5
-Djava.security.egd=file:///dev/urandom switch
 
or
 
-Djava.security.egd=file:/dev/./urandom



2. java 자체 옵션을 변경합니다.

1
2
$JAVA_HOME/jre/lib/security/java.security


위 파일 에서 아래 라인을 추가하거나 수정해 줍니다.

1
securerandom.source=file:/dev/./urandom



/dev/random vs /dev/urandom 바로가기

반응형
반응형

스프링웹mvc에서 자주 쓰는 기능 중 하나인 MultipartFile 의 transferTo 을 사용할 때 주의사항을 하나 공유하고자 합니다.


이 기능은 파일을 업로드 할 때 사용됩니다.


파일을 업로드하면 transferTo 를 통해서 실제 파일시스템에 쓰게(write) 됩니다.


그런데 Servlet 3.0 에서는 절대경로에 파일을 쓸수 없게 제한하고 있습니다. WAS의 지정된 임시 dir에서 상대 경로로만 업로드할 수 있습니다.


하지만 Tomcat에서는 이 부분을 절대경로도 허용해 주고 있습니다. 덕분에 혼란이 가중 된 건 누구 잘못일까요 ㅜㅜ.


Local 은 Tomcat에서 개발하고 테스트 후 Jeus에 배포를 했더니 파일이 계속 Jeus의 임시 디렉토리 하위에 들어갑니다.


한참을 삽질 후에 기술지원을 받고 나서야 이 사실을 알 수 있었습니다. Jeus는 스펙에 따른거라고 하니 Tomcat을 욕합니다.


아래는 transferTo 의 주석에 달린 Note 입니다. Tomcat에서 잘되어서 대충 본 제 잘못이 사실 제일 큽니다. ㅜㅜ


1
Note: when using Servlet 3.0 multipart support you need to configure the location relative to which files will be copied as explained in javax.servlet.http.Part.write.
cs


반응형

+ Recent posts