서버를 구동할때 class를 실행시키는 방법이다.


주로 소켓통신을 위해 동시에 켜주거나 여러모로 자주 사용 하게 된다.


1. web.xml 


<web-app> </web-app> 사이에 추가해 준다. 전자정부 프레임워크 라면 ContextLoaderListener 가 이미

추가 되어 있을텐데 그 밑에 고대로 복사해준다.


1
2
3
     <listener>
        <listener-class>패키지경로.클래스명</listener-class>
    </listener>
cs



끝.



주의사항: 대충 다른거 긁어와서


1
2
3
4
5
 public static void main(String[] args) {
          // 5개의 쓰레드를 생성하는 서버를 생성한다.
          PlatformServer server = new PlatformServer(5);
          server.start();
      }

cs


저런 코드 그대로 놔두고 실행시키면 안된다.

생성자를 만들어 주지 않으면 아래와 같은 에러가 발생한다.


심각: Error configuring application listener of class 패키지 경로

java.lang.InstantiationException: egovframework.패키지경로

at java.lang.Class.newInstance(Unknown Source)

at org.apache.catalina.core.DefaultInstanceManager.newInstance(DefaultInstanceManager.java:114)

at org.apache.catalina.core.StandardContext.listenerStart(StandardContext.java:4984)

at org.apache.catalina.core.StandardContext.startInternal(StandardContext.java:5584)

at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:147)

at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1572)

at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1562)

at java.util.concurrent.FutureTask.run(Unknown Source)

at java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)

at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)

at java.lang.Thread.run(Unknown Source)

Caused by: java.lang.NoSuchMethodException: 패키지경로.<init>()

at java.lang.Class.getConstructor0(Unknown Source)

... 11 mor


하나의 was에 여러개의 프로젝트(컨텍스트)가 존재할 경우 일반적으론


서로간 세션의 공유가 되지 않는다. 


이때 각 컨텍스트간의 세션이 공유될 수 있는 방법을 알아보자.



1. 서버의 context.xml의 변경


1
2
3
4
5
6
7
8
9
10
<!-- The contents of this file will be loaded for each web application -->
<Context>
 
    <!-- Default set of monitored resources -->
    <WatchedResource>WEB-INF/web.xml</WatchedResource>
 
    <!-- Uncomment this to disable session persistence across Tomcat restarts -->
    <!--
    <Manager pathname="" />
    -->
cs


저 위의 컨텍스트를 아래와 같이 바꿔준다.


1
2
3
4
5
6
7
8
9
10
<!-- The contents of this file will be loaded for each web application -->
<Context crossContext="true">
 
    <!-- Default set of monitored resources -->
    <WatchedResource>WEB-INF/web.xml</WatchedResource>
 
    <!-- Uncomment this to disable session persistence across Tomcat restarts -->
    <!--
    <Manager pathname="" />
    -->
cs



2. server.xml 변경


1
 <Connector connectionTimeout="20000" port="8080" protocol="HTTP/1.1" redirectPort="8443"/>

cs


1
 <Connector connectionTimeout="20000" port="8080" protocol="HTTP/1.1" redirectPort="8443" emptySessionPath="true"/>
cs


emptySessionPath="true" 를 추가 한다.



3. 세션 세팅


1
request.getSession().getServletContext().setAttribute("ssUserId", userId);

cs


기존의 방법에서 가운데 getServletContext()를 추가 하여 준다.


root로 지정되어 있지 않는 컨텍스트에선 

getServletContext("/sample") 와 같이 컨텍스트명을 지정하여 준다.



4. 세션 겟


1
String ssUserId =  (String) request.getSession().getServletContext().getContext("/").getAttribute("ssUserId");
cs


가지고 올땐 위와 같이 가져오며 루트가 아닌 컨텍스트에서 set 한 경우엔 getContext("/sample") 와 같이 컨텍스트 명을 넣어 사용 하면 된다.



오브젝트를 생성하고 특정 데이터의 개수에 따라


속성을 추가적으로 생성해야 하는 경우가 있으나 


속성의 이름을 지정하지 못해 곤란해 했던 경우가 있다.


일반적인 오브젝트의 속성 추가는

1
2
3
4
5
6
7
8
var _gridObj = {};
 
 
_gridObj.time1 = 1;
_gridObj.time2 = 2;
_gridObj.time3 = 3;
_gridObj.time4 = 4;
 
cs


위와 같이 이루어 지지지만 데이터의 개수만큼 time뒤에 들어가는 숫자가 바뀌어야 한다면


아래와 같이 작성을 해주면 된다.


1
2
3
4
5
var _gridObj = {};
for(var dataCount = 0; dataCount < dataSize; dataCount++){
    _gridObj[ 'time'+dataCount] = result;
}
 
cs





DWGViewX 를 사용해 웹에서 cad 파일을 볼 수 있도록 해주는 도중 파일을 불러오지 못하는 오류가 발생 하였다.


일단 


<object id="DWGViewX" codebase="http://www.autodwg.com/dwgviewx/dwgviewx.cab" height="520" width="700" classid="clsid:AC53EFE4-94A7-47E6-BBFC-E9B9CF322299">

                        <param name="_Version" value="65536">

                        <param name="_ExtentX" value="18521">

                        <param name="_ExtentY" value="13758">

                        <param name="_StockProps" value="0">

                       <param name="DrawingFile" value="불러올 파일이 있는 경로">

                        <param name="ShowToobar" value="-1">

                        <param name="ShowLayoutBar" value="1">

                        <embed name="DWGViewX" width="700" height="520" type="DWGVIEWXLib.DwgViewX" showtoolbar="-1" showlayoutbar="1" pluginspage="http://www.autodwg.com/dwgviewx/dwgviewx.cab" title="undefined">

                    </object>



사용방법은 html안에 이렇게 사용해 넣으면 된다.


DrawingFile 파라메터의 밸류값에 불러올 파일이 있는 경로를 지정해 주면 된다.


절대경로를 사용한다면 클라이언 PC의 경로를 뒤진다 (ex) C/programs/..........기타등등)


서버에 있는 파일을 보여주고 싶다면


경로값이 해당 dwg파일을 다운로드 받는 url을 넣으면 해당 파일을 보여준다.



문제는 자꾸 no mapping uri가 나타나면서 에러가 나고 하얀색 화면만 나타난다는 점이다.


해당 경로를 브라우저의 URL창에 넣으면 파일은 정상적으로 다운로드가 되지만 dwg뷰어에서는 해당 url를 찾지 못한다고 나올 뿐이다.


어노테이션 설정에 문제가 있는 건지 한참을 뒤져보다가 원인을 찾게 되었다.


원인은 DrawingFile의 value값이 중간에 인코딩이 되어 요청된다는 것이다.


한글은 깨지고 영문은 전부 소문자로 변환된 후 요청을 한다.


해결방법은 그냥 호출받는 주소를 전부 소문자로 바꿔줘 버렸다...

파일이름은 파일이 업로드 될때 실제 저장된 파일이름은 UUID로 바꾼후에 영문소문자로 바꿔서 저장을 하도록 했다.


이제 도면파일 잘나온다.


액티브X 사라져버렸으면 좋겠다.

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

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


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

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 + ";");




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





버그 예.


1. 클라이언트(브라우저)에서 jquery ajax 를 수행하여 GET request를 한다.

2. 서버가 GET request를 받고 routing을 수행하여 해당하는 데이터를 response한다.


Chrome, FF, Safari 의 경우 - 서버가 보낸 response를 받고 데이터를 확인한다.

IE 의 경우 - 서버가 보낸 response는 받으나 데이터가 없다.




서버쪽 로그를 확인해보니 특정한 GET 요청을 서버가 받지 못하고 있었다.


헌데 alert(‍), console.log() 등을 이용해서 확인해본 결과


ajax 수행은 error가 나지 않고 제대로 success 를 띄움



재밌는건 익스플로러의 개발자도구를 띄워놓은 상태에선 값을 잘 받아 온다는 점이다.




원인 및 해결 방법



URL이 같으면 IE의 ajax 연결은 cache를 사용하고 갱신하지 않는다는 것이다.


그래서 ajax 연결 시 URL을 매번 바꾸어주어야 한다는 것


간단한 해결 방법은 시간과 같이 매번 변하는 파라메터를 같이 날려 주는 것


http://localhost:8080/session

=> http://localhost:8080/session?1260790889296



제이쿼리에서는 

jQuery.ajaxSetup({cache:false});

와 같이 캐쉬사용을 끄는 옵션도 있지만 간혹 적용이 안되는 경우도 있는 것 같다.


전자정부 프레임워크를 사용하다 보면 미친듯한 메모리 점유율에 이클립스가 뻗어버릴때가 종종 있다.


이경우 이클립스에 힙메모리 할당만 어느정도 조절해 준다면 보다 원활한 작업을 진행 할 수가 있다.


먼저 eclipse.ini 파일을 열어 본다



-vmargs << 요 아랫부분을 수정해 준다.



---- 이 아래 부분을 복사해 넣는다 --------

-Dfile.encoding=UTF-8

-Dosgi.requiredJavaVersion=1.7

-Xverify:none

-XX:+UseParallelGC

-XX:-UseConcMarkSweepGC

-XX:PermSize=128M

-XX:MaxPermSize=128M

-XX:MaxNewSize=128M

-XX:NewSize=128M

-Xms512m

-Xmx512m

-----------요기까지--------------


-Xverify:none => 클래스의 유효성을 검사 생략. (시작 시간이 줄어 빨라진다.)
-XX:+UseParallelGC => 병렬 가비지 컬렉션 사용. (병렬 처리로 속도 향상)
-XX:+AggressiveOpts => 컴파일러의 소수점 최적화 기능을 작동시켜 빨라진다.
-XX:-UseConcMarkSweepGC => 병행 mark-sweep GC 수행하여 이클립스 GUI의 응답을 빠르게한다.
-XX:+CMSIncrementalMode=true => 점진적인 GC

-XX:PermSize=128M        => Permanent Generation(영구 영역) 크기(Out Of Memory 에러시 크기 조절)

-XX:MaxPermSize=128M  => 최대 Permanent Generation 크기

-XX:NewSize=128M         => New Generation(새 영역) 크기

-XX:MaxNewSize=128M   => New Generation(새 영역) 의 최대 크기


-Xms512m : 이클립스가 사용하는 최소 Heap 메모리
-Xmx512m : 이클립스가 사용하는 최대 Heap 메모리
                     최소와 최대를 같은 값으로 설정하면 오르락 내리락 하지않아 빨라진다.
[메모리 정의 예]
1 기가 이하 메모리인 컴퓨터인 경우 => -Xms256m -Xmx256m
2 기가 ~ 3 기가 메모리인 컴퓨터    => -Xms512m -Xmx512m
4기가 이상 메모리인 컴퓨터            => -Xms1024m -Xmx1024m




켄도 UI에서 제공하는 차트는 매우 유용합니다.


간단하고 예쁜 차트를 그릴수 있기 때문이죠


제 주변에선 유료 라이센스인 켄도UI를 사용하는 사람이 없기 때문에


혼자서 레퍼런스 뒤지고 삽질 하면서 배우고 있습니다 ㅎㅎ


켄도 UI에서 제공하는 차트의 배경색을 없애는 방법 입니다.


자바 스크립트에서의 코딩은 아래와 같이 작성 합니다.


 $("#kendoChart").kendoChart({

 chartArea: {

   height: 250,

   background: ""

 },

 });


위와 같이 background에 공백문자를 넣으면 배경이 사라집니다.


이것저것 막 해보다가 얻어걸렸는데 저게 정확한 사용법인지는 잘 모르겠습니다만


방법을 정말 모르겠으면 일단 되도록 만들어야겠죠? ㅎㅎ



동적쿼리를 생성해야 하는 경우는 상당히 많다.


이번에 ibatis를 처음 사용하면서 편하긴 하지만 알아야 할것도 참 많다고 생각이 드는데


아무튼 ibatis에서 리스트를 받아와 쿼리문에 foreach문 같은 반복문을 생성하도록 하려면


iterate를 사용해야 한다.


사용법은


<iterate property="measureTypeList" open="(" close=")" conjunction="or">

<![CDATA[ TYPE_ID =#measureTypeList[]#]]>

</iterate>


이런식으로 사용이 가능 하다.


property는 받아오는 리스트의 이름


open는 반복문이 시작할때 들어가는 텍스트


close는 그 반대


즉 저렇게 돌리면


(TYPE_ID  =#measureTypeList[]# or TYPE_ID  =#measureTypeList[]# or TYPE_ID  =#measureTypeList[]#)



이런식으로 돌아간다 conjunction은 반복할때마다 들어갈 텍스트이다



그런데 저렇게 사용을 할때 


outOfBoundsException 에러가 나는 경우가 있다!!!


컨트롤러에서 보내는 parameterClass를 리스트로 만들어서 보냈는데! 왜!!! 왜 안돼는걸까!



ArrayList<String> measureTypeList = new ArrayList<String>();

measureTypeList.add("MEASURE_TYP_117");

measureTypeList.add("MEASURE_TYP_118");


컨트롤러에서 저런식으로 만들어서 바로 파라메터로 보내버렸을때 발생하는 에러 이다



위의 에러를 해결하기 위해서는


만들어 놓은 리스트를 hash맵에 담아서 보내야 한다


HashMap measureTypeListMap = new HashMap();

measureTypeListMap.put("measureTypeList", measureTypeList);



이런식으로 해쉬맵에 담아서 보내면 에러가 해결이 된다.



<select id="WidgetTagDAO.measureTypeList" parameterClass="HashMap" resultMap="widgetTag">

<![CDATA[

SELECT*

   

 FROM

 where

]]>

<iterate property="measureTypeList" open="(" close=")" conjunction="or">

<![CDATA[ TYPE_ID   =#measureTypeList[]#]]>

</iterate>

</select>

XML에서 작성하면 위와 같이 작성을 하면 된다.




자바스크립트로 화면을 구현하다 보면 같은 행동을 반복하게 하는 애니매이션이나 로직을 구현해야 하는 경우가 종종 생긴다.


간단한 예로 디지털 시계 같은걸 구현한다던가 


매시간마다 데이터를 계속해서 요청을 한다던가


이럴때 setInterval 함수를 사용한다.


방법은 간단하다.


setInterval(실행할 function이름,반복할시간단위);


ex) setInterval(getChartData,1000);


getChartData라는 펑션을 1초마다 반복한다는 것이다.


getChartData 대신에 펑션을 직접 입력해도 된다


setInterval(function(){

alert('1초가 지났어요');

},1000);


위처럼 해도 무방하다



추가로 반복을 멈추고 싶을땐


var interval = setInterval(getChartData

,1000);


위와같이 선언후 실행하다


멈추고 싶을떄


clearInterval(interval);


해주면 된다.

+ Recent posts