BacGyber's Tricks

Apache 세팅 및 PHP 7.2 설치 on MacOS

□ Tech (Software)

apache 와 php (7.2버젼) 세팅을 최근에 했는데 해당 내용 정리해봅니다.


구글링으로 여러 페이지를 참고해서 진행했습니다.


제가 진행한 방법은.... 약간의 시행착오로 인한 꼼수가 담긴 방법이라

Best Practice 는 아니나 또 나름 편한 장점이 있습니다.


바로 그대로 따라하시지 말고 진행된 Step 을 간단히 훑으신후 

저와 똑같이 하셔도 좋고

아님 제가 언급한 조금 다른 방향으로 진행하시는것이 좋을것 같습니다.


◈ brew install php72 --with-httpd


php72 와 httpd 를 이렇게 설치했습니다.


그런데 어느 순간부터 아파치의 httpd config 위치가 꼬이기 시작했습니다.


apachectl -V 로 확인하면 brew로 세팅된 /usr/local 쪽으로 나오는데

실제 참고한 httpd.conf 는 /private/etc 쪽을 보더군요.



그 이유는 아파치 데몬에서 강제 시작시키는 아파치 설정은 원래대로였기 때문에 그랬던거 같은데

해당 부분만 바로 잡아 진행하시는 것이 가장 좋은 방법 같습니다.


즉 자동실행되지 않게 하고... 데몬 등의 부분에서 모두 brew 에서 설치한 쪽으로 바라보게 해야겠죠.


이 글들이 좋으니 참고가 되실겁니다.


http://lukearmstrong.co.uk/2016/12/setup-apache-mysql-php-homebrew-macos-sierra/


https://gist.github.com/DragonBe/0faebe58deced34744953e3bf6afbec7




그런데... 저는 그렇게 진행하지 않았습니다. 

제 방법은 베스트안이 아닐수도 있지만... 저처럼 진행하시는 것도 나쁘지는 않은거 같습니다.


왜냐면...

저는 리눅스 init demon 설정같은것은 해본적은 있으나 익숙하진 않은데요. 

저와 비슷하신 분이라면 오히려 제 방법이 더 편한 장점이 있습니다. 



제가 진행한 방법 (현재 단계 포함해서 적습니다)



1) brew를 이용한 php7 및 httpd 설치


2) brew --with-httpd 로 생성되었던 아파치 모듈 libphp7.so 를 별도 위치에 백업


3) brew uninstall


brew uninstall httpd

brew uninstall php72


4) 아파치는 맥의 기본 경로쪽으로 세팅


5) php7 설치 


6) Apache - PHP7 연동



자 그럼 다음 내용을 계속 보시죠.

주요 내용 위주로 언급했습니다. (글을 날려먹어서;;)

저처럼 진행하지 않더라도 참고가 되실수 있는 내용들이 포함은 되어 있습니다.


◈ Apache 세팅

원래 MacOs 기본 아파치 쪽에 세팅했습니다.


Apache config 위치 : /private/etc/apache2/httpd.conf


* 아파치 설정파일 위치는 httpd -V 커맨드로 확인 가능합니다.



* 사용자별 세팅


Document Root 를 직접 수정해서 써도 되겠지만...

권장 가이드대로... 사용자별 세팅을 진행해보았습니다.


급하게 하다보면 실수가 있으니 꼼꼼히 하나씩 하시는게 좋을거 같습니다.

실수를 바로 잡는데 이 글이 도움이 되었습니다. 아주 잘 정리해주셨더라구요.


https://xho95.github.io/macos/apache/webserver/mod_wsgi/2016/10/02/Apache-WebServer.html



◈ PHP 설치, 연동

* 주요 커맨드




* PHP 연동 세팅 - /etc/apache2/httpd.conf


php5모듈은 계속 주석처리해두고

php7모듈 라인을 하나 추가했습니다.  


모듈은 위에서 언급한대로... 앞단계에서 생성된 so 파일을  복사를 하여

별도 경로를 만들어 넣어두었습니다.



* OS 보안 (SIP) 때문에 /usr/libexec 에 복사할수 없어서 /usr/local/libexec 경로 생성하여 하위에 복사했음



* PHP 연동 세팅 - /etc/apache2/other/php7.conf


기존에 있던 php5.conf 를 카피해 php7.conf 를 생성후 약간 수정했습니다.

파일 내용 전체를 담아둡니다. 



이렇게 진행하시는게 귀찮으면 그냥 httpd.conf 파일의 해당 부분을 편집하셔도 됩니다...




* php 연동 참고




◈ 그 외 메모

* source ~/.profile 이후 echo $PATH 를 하니 변경한 패쓰가 인식되지 않는것이 좀 이상했습니다.

새로 터미널 창을 오픈하니 적용이 되어있더군요.



* MacOS Sierra 에서 기본 쉘은 bash 네요.

zsh 가독성이 좋다고 한거 같은데... 담에 봐서 사용해봐야겠습니다.



* 아마도 익숙하실apache 기동 관련 커맨드



* test.php. ( //Users/사용자명/Sites )



http:/localhost/~UserName/test.php


캡쳐 사진은 유저 세팅이 아닌... 아파치 루트 계정 Document Root 쪽에 만들어 테스트했을때 캡쳐했던 겁니다.

혹시나 사진에 보이는 url 보고 헷갈리실까봐 말씀드립니다. 



http:/localhost/~UserName

접속시엔 index.html 의  It Works! 가 보입니다.



[Solved] Eclipse Oxygen 에서 SVN 세팅 오류

□ Tech (Software)

최근 버젼으로 이클립스 설치후 SVN 세팅이 제대로 안되어 해결한 내용을 공유합니다.


* 설치 환경 : windows7 64bit, JDK 8 64bit


저는 이클립스를 설치시 STS로 설치합니다. ( 버젼 : 3.9.1.RELEASE )

Eclipse Oxygen 이 깔리더군요 (버젼 : Eclipse Oxygen.1a (4.7.1a) )


SVN 환경 세팅은 두 단계죠.


1. Subversive SVN Team Provider 를 설치


2. Subversive SVN Connectors 설치


구체적인 내용은 여기를 참고해주시구요 : http://www.eclipse.org/subversive/installation-instructions.php



그런데... 과거경험으로는...


Team Provider 설치후 Restart가 되면

자동으로 SVN Connectors 설치 창이 뜨거나...


아니면 Windows > Preference > Team 쪽으로 이동하면...

Connectors 설치 창이 떴었는데....


이번에는 SVN 커넥터 설치창이 자동으로 뜨지 않더군요.


그래서 SVN 커넥터 설치 주소를 파악후

Install New Software 기능으로 진행을 하니 설치가 완료되지 않고 실패가 되었습니다.


그래서 이클립스 Error view 쪽을 보니 에러 항목이 있는게 보였습니다.


몇주 지나서 정확한 에러 내용은 기억이 안나지만...

SVN 세팅과 관련된.... 느낌이었던거 같습니다.


해당 에러항목을 Delete 하고 나서 이클립스를 재기동후


Windows > Preference > Team > Connectors 쪽으로 이동하니

Connectors 설치창이 떠서 정상 설치되었습니다.



기억이 정확히 안나고... 당시 따로 저장해두었던 것이 아니라... 구체적으로 적진 못했네요.


이 부분은 제가 설치한 이후 패치가 되었길 바라지만... 혹시나 그렇지 않아서 이러한 문제에 막힌 분이 계시다면...

도움이 되면 좋을거 같네요.



[solved] Oracle 접속 WAS 로그에서 SQLRecoverableException 발생

□ Tech (Software)

최근 오픈한 시스템에서 겪은 내용 간단히 정리합니다.


일부 사용자들이 웹페이지가 안열린다는 얘기가 있었습니다.


WAS 로그를 확인해봤는데 

두대중 한대의 WAS 로그에서 이러한 내용이 있었습니다. 



java.sql.SQLRecoverableException: I/O Exception: Connection reset



구글링했더니 도움이 될만한 검색결과가 여러개 나왔던거 같습니다.

그 중 오라클 커뮤니티 게시물 내용이 깔끔한거 같아 복사해둡니다.


I was recently struggling with this exact same problem. I opened a ticket with Oracle and this is what they told me.


java.security.SecureRandom is a standard API provided by sun. Among various methods offered by this class void

nextBytes(byte[])

is one. This method is used for generating random bytes. Oracle 11g JDBC drivers use this API to generate random number during

login. Users using Linux have been encountering SQLException("Io exception: Connection

reset").


The problem is two fold


1. The JVM tries to list all the files in the /tmp (or alternate tmp directory set by -Djava.io.tmpdir) when

SecureRandom.nextBytes(byte[]) is invoked. If the number of files is large the

method takes a long time to respond and hence cause the server to timeout


2. The method void nextBytes(byte[]) uses /dev/random on Linux and on some machines which lack the random

number generating hardware the operation slows down to the extent of bringing the whole login process to

a halt. Ultimately the the user encounters SQLException("Io exception: Connection reset")


Users upgrading to 11g can encounter this issue if the underlying OS is Linux which is running on a faulty hardware.


Cause

The cause of this has not yet been determined exactly. It could either be a problem in

your hardware or the fact

that for some reason the software cannot read from dev/random



Solution 

Change the setup for your application, so you add the next parameter to the java command:


-Djava.security.egd=file:/dev/../dev/urandom




We made this change in our java.security file and it has gotten rid of the error.





* 내용을 보면... Linux 상에서 파라미터를 조정하여도 해결될 확률은 있는거 같군요.

  어떤 이유인건 간에... Linux 상의 부하로 인해 발생할 수 있는 상황 같기도 하구요.

  적용한 이유 문제가 없는걸 보면... 이번 경우는 위의 두가지 유형중 두번째에 해당하는 확률이 높은것 같습니다.  



* 환경 정보 요약

Linux Server상의 JEUS 에서 Oracle 12C 에 연결

 


웹 풀스택 책 PDF (국내 개인이 정리)

□ Tech (Software)

짧게 요약된 책이라서 그런것인지... 내공 있는 설명은 없는것 같습니다만...

웹 개발 입문자나 초급자 들에게 도움이 충분히 될 거 같습니다.


https://drive.google.com/file/d/0B-tD535n_rOfX1Iwa0RBRU9VWGM/view


오프라인 강의도 하는 젊은 분이 정리하신거 같은데 사업도 번창하길 바라겠습니다.


* 어떤 커뮤니티에서 직접 홍보한 글을 보고 알게 된 정보인데... 어떤 커뮤니티였는진 기억은 안나네요



[PHP,JS] 모바일 기기 여부 판단하여 모바일용 웹페이지로 이동시키기 (주소 동적처리)

□ Tech (Software)

현재는 데스크탑용 일반 웹페이지만 있는 php 웹사이트가 있습니다.

추가로 모바일 웹페이지를 고려중인 상황인데요.


관련하여 미리 Test성 개발을 진행해보았습니다.


진행 순서

1. 테스트할 출발 페이지 B를 만든다 (기존 소스 A를 카피함)

2. 모바일 페이지 C를 더미로 만든다 (구분할수 있도록 기존 소스 B 카피해서 title 만 바꾸어둠)


   * 해당 서비스를 제가 하고 있는건 아니고 지인분(개발자 아님)이 운영하고 있는건데요.  

개발 관련 내용을 물어봐서 바로 답을 얻기는 어려운 상황입니다.

현재 사용하는 서브도메인 ( www.abc.com ) 을 모바일웹에서 ( m.abc.com)  으로 이용할수는 있을텐데... 

어떤 상황인지 정확히 알지 못하고, 이 테스트를 위해 그 설정이 될때까지 기다릴수는 없어서

일단 테스트는 기존 www 서브도메인이 연결된 소스 루트에 m 폴더를 만들어서 그 아래에 페이지 C 를 두었습니다.


개발코드 - PHP / JAVASCRIPT

PHP 및 JAVASCRIP 둘 다 진행해보았습니다.


아주 잘 정리된 블로그가 있어서 참고했습니다. ( 감사합니다. http://kiss7.tistory.com/316 )


제가 +@ 한 내용은 (제 글 제목에 표현되기도 했는데)

주소 동적 처리 입니다.


즉... 

핸드폰에서 브라우저로

www.abc.com/actor/woman.php/best/leeyeonhee?year=2017&broadcastType=cable

로 접속했을경우

m.abc.com/actor/woman.php/best/leeyeonhee?year=2017&broadcastType=cable

로 돌려주는 식입니다.


요청한 url 을 활용해 일부만 변환해서 다른 주소로 가도록 하는 것이죠.


그런데 아래 실제 코드는 m.abc.com 식으로 한 건 아니고... 앞서 서브도메인 관련 언급한 대로... m 이란 디렉토리 만든 상황대로 했습니다.


즉...

www.abc.com/m/girl.php/best/leeyeonhee?year=2017&broadcastType=cable

이런 페이지로 이동되는거죠.

참고로 예로 든 페이지 uri 는 좀 이상하죠? ㅎㅎ REST 형식과 get parameter 를 다 커버함을 알 수 있도록... uri 예를 든겁니다.


그럼 설명은 잠시 뒤로 미루고 소스 먼저^^

  

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
<? session_start(); ?>
 
<?
    // 모바일 브라우저의 경우 모바일 전용 페이지로 이동
    // reference : http://kiss7.tistory.com/316
    $mobileKeyWords = array ('iPhone''iPod''BlackBerry''Android''Windows CE''Windows CE;''LG''MOT''SAMSUNG''SonyEricsson''Mobile''Symbian''Opera Mobi''Opera Mini''IEmobile');
 
    $isMobile = 0;
 
    for($i = 0 ; $i < count($mobileKeyWords) ; $i++)
    {
        if(strpos($_SERVER['HTTP_USER_AGENT'],$mobileKeyWords[$i]) == true)
        {
            $isMobile = 1;
            break;
        }
    }
 
    if$isMobile == 1 )
    {
        $mbU = "/m" . $_SERVER['REQUEST_URI'];
        echo("<script>location.href = '".$mbU."';</script>");
    }
?>
 
<script type="text/javascript" language="JavaScript">
 
    var mbU = "<?=$mbU?>";
 
    var mobileKeyWords = new Array('iPhone''iPod''BlackBerry''Android''Windows CE''Windows CE;''LG''MOT''SAMSUNG''SonyEricsson''Mobile''Symbian''Opera Mobi''Opera Mini''IEmobile');
    for (var word in mobileKeyWords)
    {
        if (navigator.userAgent.match(mobileKeyWords[word]) != null)
        {
            window.location.href = mbU;
            break;
        }
    }
 
</script>
 
cs


* 가독성을 위해 자바스크립트로 이동시키는 부분 28 ~ 38 라인은 주석처리 되어 있던걸 해제 하였습니다. 

  자바스크립트 이동시키는 기능을 쓰려면 위에 php 부분에서 일부분을 주석처리하면 됩니다.


* PHP 부분에서 페이지 이동은 javascript 기능을 이용하였습니다.

원래 Sample 대로  

header("Location: http://이동할주소");

exit;

을 이용하면 잘 될수도 있을텐데 저는 약간 변형해서 for 문 바깥에서 이동시키도록 구현해보았었는데요.


그 상황에서 이런 오류가 발생하더군요  "Warning: Cannot modify header information"

그런데... 제가 아래 코드에는 빼두었지만 원래 인클루드하는  소스들이 있습니다.

즉 제가 변형해서 쓰는 것이 이유가 아니라 인클루드한 페이지와 관련이 있을거 같기도 한데 그 내용은 검토해보지 않았습니다. 


그래서 최종 이동기능을 php 에서 담당하지 않고, javascript 가 담당하도록 처리하였습니다.

echo("<script>location.href = '".$mbU."';</script>");


* 동적 처리를 위해 사용한 코드가 $_SERVER['REQUEST_URI'] 입니다.


도메인과 파라미터 부분도 필요하실수 있을텐데요. url 각 부분을 잡아내는 것은 아래와 같이 받아내서 필요한 부분을 사용하시면 될 거 같습니다.


$svHost = $_SERVER['HTTP_HOST'];

$svRqUri = $_SERVER['REQUEST_URI'];

$svQueryStr = $_SERVER['QUERY_STRING'];



저처럼 php에 경험이 많지 않은분들에게는 도움이 될 거 같아서 기초적인 내용이긴 하지만 공유해봅니다


목업 / 프로토타이핑 - 웹사이트 / 프로그램 비교

□ Tech (Software)

wireframe, mockup, prototype 의 용어가 혼재해서 쓰이는거 같습니다.


먼저 용어 정리를 좀 해보자면...


용어정리 - 목업? 와이어프레임? 프로토타이핑?


Sketch - Wireframe - Mockup - Prototype 의 흐름으로 보면 좋을거 같습니다.

하지만 꼭 위의 흐름으로 갈 필요는 없겠죠.


그럼 하나씩 볼까요?


Sketch : 대강의 밑그림

Wireframe : 화면 Flow, 네비게이션, 정보 설계도 좀 된 느낌

Mockup : 실제 느낌의 디자인 (즉 가능하다면 색감까지, 사이즈까지)

   헝거게임 Mockingjay 할때 Mock 입니다.

   * 모방, 모사 할때의 모와... 뭔가 맞닿은 듯한 느낌도 들죠. 먼 과거의 어근이 같았을지도 모르죠.

Prototype : 실제 동작시에 어떻게 된다는 느낌까지 받을수 있도록 구현


그런데 예전에 앱 개발하는거 보면 말은 Mockup 이라고 하는데.... Sketch 수준에서 머문 경우도 많더군요.

아무튼 용어로 꼬투리 잡을 필요는 없을거 같구요... 당시엔 그냥 무조건 용어를 목업이라고 하던데

요새 분위기는 좀 구체적으로 하지 않을까 추측이 되네요. 요새도 그대로이려나? ^^;;


Mock 관련 서비스 / 프로그램 비교


예전 경험으로 제 주변에서 제일 많이 쓰는건 절대적으로... 발사믹 이었습니다.


발사믹


제가 직접 발사믹을 써서 뭘 만들어본일은 없습니다. 결과물을 본 기억으로... 프로토타입 기능은 없거나 약했던 거 같네요.

손 글씨 느낌은... 사용자에 따라 좋다고 느낄수도 있고, 오히려 좋지 않다고 느낄수도 있을거 같습니다.



Mockup Plus


https://www.mockplus.com/


구글링해보면 이 툴에 대한 호평도 많이 보이네요

기능 검토를 해보려면 사이트가서 보는거보다는 유투브에서 영상 찾아보시는게 가장 빠르게 캐치하는 방법입니다.



Axure RP


이건 검토를 위해 직접 살짝 만져봤습니다. 그리고 기획자에게 사용하도록 시켰죠 ㅎㅎ

적당히 쓰는데 학습시간이 많이 걸리지 않습니다. 하지만 상대적으로 난이도가 높아서 그런지 어렵다는 얘기가 많더군요. 하지만 그리 어렵지 않으니 사용 목적이 있다면 익혀서 쓰면 됩니다.


이 제품의 강점은 Wireframe 과 Prototype 부분입니다.

버튼 링크를 통해 화면간 Flow 정의가 가능합니다. 그리고 그 결과물을 Export 해서 브라우저상에서 프로토타입으로 보여줄수가 있습니다.


대한민국 대부분의 외부고객 내부고객들이 PPT로 작업한 화면설계를 다 보여줘도 나중에 딴 소리하는 경우가 많습니다.


프로젝트 진행땐 관심이 없고 나중에 오픈할때쯤 체감되는 시점이 되면 신경쓰는것이죠.

각자 본인이 하는일도 계획성 없이 하다가 마지막에 닥치면 그때서야 뒤늦게 이거저거 챙기는 경우도 많고....

그만큼 업무부하가 많아서 그런거 같기도 한데요... 아무튼 바람직하지 않은 안타까운 현실입니다.


Axure를 사용하면 브라우저상에서 프로토타이핑이 되므로 실제 결과물에 가까운 느낌을 주어 

기획 - 개발 당사자 입장에서도 그리고 고객 입장에서도 체감도가 높아서 UX 설계를 설계단계에서 거의 확정하는데에 도움이 됩니다.


또한 익숙해지면 PPT 에 비해 시간이 더 많이 걸릴것도 없구요. 일부 관점에서는 훨씬 더 빨리 할수 있는 부분도 있죠.



Oven - http://ovenapp.io


카카오에서 만든거로 압니다.

직접 살짝 써봤는데... 


v


사용법은 쉽습니다만 아직 완성도가 애매하고 아쉬운점이 있습니다.



프로토나우 - http://protonow.navercorp.com


Axure 를 많이 참고했는데 아직 기능은 기본적인것만 갖춘 수준인거 같네요.

무료라는 장점이 있으니... 담에 필요할때 한 번 설치해봐야겠습니다.


쉿~ 뒷담화

카카오나 네이버나... 네이밍이 그닥 맘에 들진 않네요

특히 프로토나우... 나름 프로토타입 기능을 강조해 그렇게 만든거 같긴 한데... 꼭 뭐 사행성 복권 이름 갖지 않나요?

저 같음 그냥 참본 (CharmBon) 정도로 할거 같습니다.

* 우리말 "참" 과 "Charm"도 닮아있죠?^^


조만간 목업 툴이 필요할수 있어서 이번엔 살짝만 검토해봤고... 그 내용을 정리해보았습니다.

How to rotate tomcat catalina.out (with logrotate)

□ Tech (Software)

How to rotate tomcat catalina.out (with logrotate)

(Tomcat catalina.out 로그 Rotation)


여러 방법이 있는데 logrotate 가 제일 낫다. 다른 방법으로 하지 말고 무조건 logrotate 로 하도록 한다.

- 명시적임

- 좋은 기능이 많음

- 백업시 압축 가능, 오래된 백업 파일을 삭제 등

*  root 권한이 있어야 작업이 가능함


설치 확인


서버(리눅스)에서 logrotate 타이핑해서 엔터치니 설명이 나옴. 이미 설치되어 있네.



설정


# logrotate -f /etc/logrotate.d/tomcat

# vi tomcat

  

/usr/local/tomcat/apache-tomcat-7.0.68/server1/logs/catalina.out {

copytruncate

daily

rotate 30

missingok

notifempty

dateext

}


/usr/local/tomcat/apache-tomcat-7.0.68/server2/logs/catalina.out {

copytruncate

daily

rotate 30

missingok

notifempty

dateext

}

상기 설정 내용 : 일단위 rotation, 백업파일 30일치 유지 등......


* 옵션의 의미는 man logrotate 등으로 확인 가능

* 해당 경로의 기존 파일들을 참고하면 도움이 된다.

  

Test


logrotate -f /etc/logrotate.d/tomcat

=> 실제 rotation 시점처럼 강제로 rotation이 실행됨.  설정이 제대로 되었는지 확인시 이용



Reference - logrotate 외의 내용도 포함

http://blog.net2free.net/260

http://egloos.zum.com/yoontaesub/v/2093136

http://blog.naver.com/kazami20/172050936

http://siho.tistory.com/52



Reference - logrotate

http://linuxism.tistory.com/298

http://imhotk.tistory.com/824

http://www.mimul.com/pebble/default/2009/12/27/1261911840000.html

http://blueskai.tistory.com/101


How to trace log Axis on client side with log4j

□ Tech (Software)

How to trace log Axis on client side with log4j

log4j로 Axis client 로그 남기기



environment

axis (not axis2)

Axis client codes are generated by Eclipse plugin



how to

* append configurations to existing log4j.xml


1. Appender


       <!-- Tracing Axis Client Log ( This could also trace Axis Server log -->

       <appender name="WSCLOG" class="org.apache.log4j.DailyRollingFileAppender">

            <param name="File" value="${vc.root}/log/wsc.log"/>

               <param name="Append" value="true"/>

               <param name="Threshold" value="DEBUG"/>


               <!-- Rollover at midnight each day -->

               <param name="DatePattern" value="yyyy-MM-dd'.log'"/>


               <layout class="org.apache.log4j.PatternLayout">

                       <!-- The default pattern: Date Priority [Category] Message\n -->

                       <param name="ConversionPattern" value="%d %-5p [%c] %m%n"/>

               </layout>

       </appender>

       

2. Category


         <!-- Tracing Axis Client Log ( This could also trace Axis Server log  -->

       <category name="org.apache.axis">

               <priority value="DEBUG" />

               <appender-ref ref="CONSOLE"/>

               <appender-ref ref="WSCLOG"/>

       </category>

       

       <category name="org.apache.axis.encoding">

               <priority value="DEBUG" />

               <appender-ref ref="CONSOLE"/>

               <appender-ref ref="WSCLOG"/>

       </category>

       

       <category name="org.apache.axis.utils">

               <priority value="DEBUG" />

               <appender-ref ref="CONSOLE"/>

               <appender-ref ref="WSCLOG"/>

       </category>

       

       <category name="org.apache.axis.message">

               <priority value="DEBUG" />

               <appender-ref ref="CONSOLE"/>

               <appender-ref ref="WSCLOG"/>

       </category>

       <!-- Tracing Axis Client Log ( This could also trace Axis Server log << -->




refernce

http://axis.apache.org/axis/java/developers-guide.html#Configuring_the_Logger


[issue solved] Loading Excel Data on ExtJs Grid using SheetJs

□ Tech (Software)



[solved] Loading Excel Data on ExtJs Grid using SheetJs


이런 저런 이슈처리를 많이 하는데 기록은 오랜만에 합니다.

기술적으로 참고도 가능할것이나.. 그보다는

현상을 분석하고 처리하는 사고 방식에 대해서도 참고가 되면 좋겠습니다.

사고방식 역시 특별한건 없습니다. 기본적인 것인데... 의외로 이것이 제대로 안되는 분들이 많습니다. 뭐 각자 잘하는 부분이 서로 다르니 그런것이겠죠...

# 현상 분석, 직접 정확히 하기


이번건의 경우 전달받은 현상은 제대로 파악이 된 경우였습니다.

아무튼 항상 현상을 직접 파악하는 것이 이슈 해결의 첫번째 단추 입니다.


시간상 직접하지 못한다면 질의를 통해 최대한 검증하고

의심이 갈 경우 직접 검증하는게 좋겠죠.


그렇게 할 시간조차 내기 애매한 경우엔 일단 전달받은 현상으로 접근하여 빠른 임시 조치후 다시 현상을 파악하던가 해야할 것입니다.


"일반적인 세상살이 현실"에서도 "전산"에서도 많은 사람들이 현상 자체를 제대로 분석하지 못하는 경우가 많으므로 문제해결 능력을 키우려는 분들은 정말 문제가 뭔지 파악하는게 가장 중요합니다.

아무도 믿지 마십시오. 현상을 전달해주는 기술자 말도 부정확합니다. 경험상 60~80%는 부정확하거나 오히려 잘못 짚고 있습니다. 

수사를 하듯, 데이터 모델링을 하듯 근본적인 것에 부터 확인을 하여 스스로 현상을 재정의 하십시오.

기존에 이 부분에 대해 알고 있지는 않았고 이슈 해결을 위해 단발성 지원을 하였습니다.

소스 변경하여 처리하는데는 2시간이 소요되었습니다. 컨디션 난조로 현상 분석을 좀 천천히 진행했습니다.

급하게 현상 분석시엔 문제 처리방향을 잘못 짚게 되어 결국 시간을 허비하게 되죠.

소스 변경 이후.... 해당 소스수정을 통해 확실히 이슈해결이 보장되는 것인지에 대한 검토, 

반복 테스트를 위해 추가적인 시간이 더 투입되었습니다.


* 환경

오픈소스 sheetjs 를 이용해 엑셀 (.xls, .xlsx) 을 읽는다.

이후 extjs 그리드상에 로딩.

* 이슈

엑셀 업로드가 되지 않는다.

* 현상

처음 업로드는 됨. 

안되는 경우는 프레임 새로고침 또는 해당 기능 화면을 닫았다 열어서 진행할 경우임.

테스트서버에서만 발생하며, 개발자 서버에선 발생하지 않음.

기존 타 프로젝트 환경에선 발생하지 않았다고 함

* Error Log in Client Javascript

Uncaught ReferenceError: XLS is not defined

=> XLS 는 sheet js 쪽의 오브젝트임

* 분석 1

클라이언트단에서 발생하는 것인데 왜 서버에 따라 다른가?

런타임상에서 분석결과 엑셀업로드시 스크립트를 서버를 통해 다운로드 하고 있다. ( 속도가 그리 느리진 않음. http 200 성공됨)

해당 XLS 인스턴스가 없어서 참조를 못하거나 있는데도 찾아가질 못하거나 그런것이겠지

* 분석 2- 원인

해당 화면 리로드나 닫아서 다시 열었을때 해당 인스턴스가 destroy 되는것 같다.

그런데 로딩 타이밍에서 

1) Extjs 또는 WebWorker 에서 있다고 판단하여 다시 생성되지 않거나

2) 로딩이 되더라도 어디에선가는 최초 로딩과 조금 다른 로직으로 인해 로딩이 늦게 되거나 하는 시간차

3) 최종 이용부분이 빨리 호출되던가 하는 시간차

결국 SheetJs 에서 로딩시에는 XLS 가 없거나 있더라도 참조할수 있는 구조가 뒤틀려 에러가 나는거 같다.

* 처리

* 기존 로딩 순서 파악

* 어떤 순서로 로딩이 되어야 하는것이 맞는지 소스 분석 및 재정리

* 그 순서에 맞게 될 수 있는 방법 검토 및 소스 변경

** 관련 과정에서 ExtJs, SheetJs, WebWorker (SheetJs 에서 이용) 쪽을 살펴보았습니다.

초반 개발한 분이 잘했으나 아마 급하게 진행하다보니 이런 구멍이 있었을거 같네요.

전체적인 메카니즘에 대해 핵심적인 파악을 했다면 더 좋은 버젼이 되었겠죠

* 처리 - 변경전후 소스

몇개의 소스를 수정하였습니다.

분산되어 js 로딩하면서 생기는 구멍을 깔끔히 정리하였습니다.

아래는 초기에 순차적으로 nested callback 으로 js 들을 로딩하고 마지막 callback 에서 동작해야할 method 를 호출하도록 한 소스 입니다.

그 method 가 호출되면  sheetjs 를 통해 읽은 data 가 자체적으로 구현한 method 에 전달되어 해당 data 가 그리드에 로딩이 됩니다. 


        if(fileExt == ".XLS")

       {

               // OLD - "XLS undefined"

//                Ext.Loader.loadScript({url : '/view/common/js/sheetjs/xls/xls-read.js', onLoad : function(){xlsLoad(e);}});

               

               // NEW

               Ext.Loader.loadScript(

                               {

                                       url : '/view/common/js/sheetjs/xls/shim.js', 

                                       onLoad : function(){

                                               //xlsLoad(e);

                                               Ext.Loader.loadScript(

                                                               {

                                                                       url : '/view/common/js/sheetjs/xls/xls.js', 

                                                                       onLoad : function(){

                                                                               //xlsLoad(e);

                                                                               Ext.Loader.loadScript(

                                                                                               {

                                                                                                       url : '/view/common/js/sheetjs/xls/xls-read.js', 

                                                                                                       onLoad : function(){

                                                                                                               xlsLoad(e);

                                                                                                       }

                                                                                               }

                                                                               );

                                                                       }

                                                               }

                                               );

                                       }

                               }

               );

       }

       else if(fileExt == ".XLSX")

       {

               // OLD - "XLS undefined"

//                Ext.Loader.loadScript({url : '/view/common/js/sheetjs/xlsx/xlsx-read.js', onLoad : function(){xlsxLoad(e);}});

               

               // NEW

               Ext.Loader.loadScript(

                               {

                                       url : '/view/common/js/sheetjs/xlsx/shim.js', 

                                       onLoad : function(){

                                               //xlsLoad(e);

                                               Ext.Loader.loadScript(

                                                               {

                                                                       url : '/view/common/js/sheetjs/xlsx/jszip.js', 

                                                                       onLoad : function(){

                                                                               //xlsLoad(e);

                                                                               Ext.Loader.loadScript(

                                                                                               {

                                                                                                       url : '/view/common/js/sheetjs/xlsx/xlsx.js', 

                                                                                                       onLoad : function(){

                                                                                                               //xlsLoad(e);

                                                                                                               Ext.Loader.loadScript(

                                                                                                                               {

                                                                                                                                       url : '/view/common/js/sheetjs/xlsx/xlsx-read.js', 

                                                                                                                                       onLoad : function(){

                                                                                                                                               xlsxLoad(e);

                                                                                                                                       }

                                                                                                                               }

                                                                                                               );

                                                                                                       }

                                                                                               }

                                                                               );

                                                                       }

                                                               }

                                               );

                                       }

                               }

               );

       }

       else

       {

               Ext.MessageBox.show({

            msg: Lang.get('EXCEL_FILE_ONLY'),

            buttons: Ext.MessageBox.OK,

            icon: Ext.MessageBox.ERROR,

            fn : function(){

                    ExcelLoader.formCmp.up("[xtype=window]").close();

            }

        });

       } 



* 부연1

이 app는 Single Page Application 구조로 개발되지 않았습니다.

만약 SPA 라면... 이와 같은 현상은 발생하지 않았을것 같습니다.

SheetJs 쪽을 분석해봐야 알겠으나... 지금과 같이 ExtJs 를 이용한 동적로딩이 아닌...

현재 MPA 구조에서는... Excel 업로드 이용하는 화면마다 

정적으로 관련 js 를 로딩하여도 문제는 해결될 것 같습니다.

단 그 경우 ap 전반적인 수정이 필요하므로

진행하기 좀 애매한 점이 있습니다.

* 부연2 - 기존에는 발생하지 않았다? 

로딩 부분 개선 이후 여러차례 테스트 결과 전혀 기존 현상이 발생하지 않았습니다.


기존 타 서버에서 발생치 않았다고 하는데.... 그것이 정말 사실이라면... 조금 설명이 애매해진다고 볼 수도 있습니다.

하지만... "기존 타 환경에서의 서버 처리및 서버 클라이언트 사이의 속도가 늘 빨랐다" 라는 가정을 한다면 그리 이상할것도 없습니다.


클라이언트에서 관련 처리 속도가 아주 빠르므로...
클라이언트 - 서버간의 로딩 시간이 타 환경 서버들보다 아주 조금 더 늦다해도 이런 현상은 있을수 있습니다.

XLS 인스턴스를 로딩하는 xls.js 의 경우 0.2 초라는 적지 않은 시간이 소요되고 있습니다.



Reference

ExtJs

http://docs.sencha.com/extjs/4.2.2/#!/api/Ext.Loader-method-loadScript


SheetJs

https://github.com/SheetJS/js-xlsx

webworker

https://developer.mozilla.org/en-US/docs/Web/API/Worker

https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API 

[Spring] How to exclude html in Spring MVC

□ Tech (Software)

[Spring] How to exclude html in Spring MVC

[스프링] Spring MVC 에서 html 예외처리


IntelliJ 써볼까 해서... 집에서 다운로드 받아서 스프링으로 간단 프로젝트 만들다가 메모를 남겨본다.


프레임웍 처음부터 새로 구성할때마다 이걸 찾아서 했던거 같다.


뭐... 기존 소스가 있으면 찾아봐도 될텐데 집이라서....


Spring MVC xml 에 한 줄 넣어주면 된다.



<?xml version="1.0" encoding="UTF-8"?>

<beans:beans xmlns="http://www.springframework.org/schema/mvc"

             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

             xmlns:beans="http://www.springframework.org/schema/beans"

             xmlns:context="http://www.springframework.org/schema/context"

             xmlns:mvc="http://www.springframework.org/schema/mvc"

             xsi:schemaLocation="http://www.springframework.org/schema/beans

http://www.springframework.org/schema/beans/spring-beans.xsd

http://www.springframework.org/schema/context

http://www.springframework.org/schema/context/spring-context-3.0.xsd

http://www.springframework.org/schema/mvc

http://www.springframework.org/schema/mvc/spring-mvc.xsd">


    <context:component-scan base-package="com.bacgyber.helloworld"/>


    <mvc:default-servlet-handler/>


    <beans:bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">

        <beans:property name="prefix" value="/WEB-INF/views/" />

        <beans:property name="suffix" value=".jsp" />

    </beans:bean>


</beans:beans>


ref) http://docs.spring.io/spring/docs/3.1.x/spring-framework-reference/html/mvc.html#mvc-default-servlet-handler


딱 0.5초~ 아래 공감버튼 누르는데 사용해주시면

제 기분은 5배 Up 이 될거 같아요 :)