'Java'에 해당되는 글 18건

  1. 2016.04.07 자바에서 jpeg 이미지(사진) 사이즈 조절하기
  2. 2015.11.25 대용량 엑셀다운로드 참고
  3. 2015.11.03 JAVA에서 10만건 엑셀을 읽어서 DB에 넣어주고 싶습니다.
  4. 2013.08.20 한글깨질때!!!
  5. 2012.11.08 모바일 참고
  6. 2011.10.12 jad로 역컴파일..
  7. 2010.08.30 Design Pattern 정리 (헤드퍼스트 디자인 패턴)
  8. 2010.08.30 javascript singleton (자바스크립트 싱글턴)
  9. 2010.08.30 네이버 OpenAPI 를 AJAX 방식으로 쓰기위한 JSP 프록시 만들기
  10. 2010.06.22 [JAVA] iBATIS + OSCACHE 사용 시 Cache Model에 대한 이해
  11. 2010.05.17 java velocity 참조..
  12. 2010.01.19 자바 원하는 오라클 함수를..(Java Stored Procedures or Functions)
  13. 2009.12.15 ResourceBundle 사용하기
  14. 2009.03.30 ROME을 활용해서 Feed 생성하기
  15. 2009.03.29 Struts2 에서 확장자 제거하기

자바에서 jpeg 이미지(사진) 사이즈 조절하기

|

출처 : http://sexy.pe.kr/tc/642

[JAVA] 자바에서 jpeg 이미지(사진) 사이즈 조절하기


스윙을 공부하다가 이미지 다루는 일이 자주 생겨 공부할 겸 포스팅 하게 되네요~


1. 파일에서 이미지 불러오기
Image orginalImage = ImageIO.read(new File("사진파일명.jpg"));

2. 이미지 사이즈 수정
Image resizeImage = originalImage.getScaledInstance( 넓이, 높이, Image.SCALE_SMOOTH); //속도보다 이미지 부드러움 우선
(SCALE_AREA_AVERAGING, SCALE_DEFAULT, SCALE_FAST, SCALE_REPLICATE, SCALE_SMOOTH 중에 선택)

3. 결과물을 옮길 이미지 생성
BufferedImage newImage = new BufferedImage( 넓이, 높이, BufferedImage.TYPE_INT_RGB );

4. 생성한 이미지에 크기 수정된 이미지 그리기
Graphics g = newImage.getGraphics();
g.drawImage(resizeImage, 0, 0, this);
g.dispose();

5. 새로 생성한 이미지를 파일로 저장하기
ImageIO.write(newImage, "jpg", new File("새 사진파일명.jpg"));


#사용된 패키지
java.awt.Image, java.awt.image.BufferedImage, javax.imageio.ImageIO, java.io.File, java.awt.Graphics

 

And

대용량 엑셀다운로드 참고

|
http://mycup.tistory.com/171

 

http://blog.naver.com/anabaral/130190317041

And

JAVA에서 10만건 엑셀을 읽어서 DB에 넣어주고 싶습니다.

|

제목: JAVA에서 10만건 엑셀을 읽어서 DB에 넣어주고 싶습니다. - 초보 - 20
분류: 질문
이름: 시그시끄 ( 포인트:7535, 가입일:2012-03-30 )


등록일: 2014-11-19 10:58
조회수: 3579 / 추천수: 1




이 글(사진)을 추천 하신분들(1명)
익명할래요

    현재 구현하고 싶은것은 엑셀의 내용을 DB에 저장하는 것입니다.

    POI 를 이용해서 몇천건 정도의 엑셀은 1~2분내에서 읽고 DB에 저장까지 됩니다.


    그런데 문제는 엑셀에 10만건 가량의 row가 있을때는 heap memory error 가 뜨네요 ㅠㅠ

    이클립스 메모리도 늘려줘봤는데 읽을 수가 없네요.


    XML로 파싱을 하든가. 객체에 바인딩해서 처리하려고 해도 먼저 엑셀을 읽어야 파싱을 하든 뭘 할텐데, 메모리 에러만 뜰 뿐 진행을 할 수가 없네요. 아직 CSV는 알아보지는 않았지만 만약 CSV로 읽을 수 있다면 그 방법이 최선일까요?

    개발자분들의 조언 부탁드립니다.

    읽어주셔서 감사합니다!!
    [ 주소복사 http://www.ppomppu.co.kr/zboard/view.php?id=developer&no=14020 ]

    추천 1

    다른 의견 0

    추천 elf2lf
    데이터가 어떤지 잘 모르겠지만
    힙 에러라
    데이터가 안되면 가상 메모리 사용하면 될텐데
    직접 컨트롤이 안되는 자바의 문제인것 같네요
    C로 하면 메모리 지정해서 확인할 수 있을텐데
    C를 이용해서 해보시고 가능하면 C로 DLL을 만들어서 사용하면 어떨까요
    2014-11-19
    11:04:24

    [덧글]

    추천 시그시끄
    답변 감사드립니다.
    C로 DLL 만드는것 까지는 아직 제가 부족하네요.
    시간 날 때 한번 찾아보겠습니다.
    2014-11-19
    12:06:21

    [덧글]

    추천 추억만이
    아래쪽에 내려가다보면 해당 내용이 있는 것 같네요
    http://www.coderanch.com/t/424181/open-source/Read-xls-xlsx-file-format
    2014-11-19
    11:20:43

    [덧글]

    추천 시그시끄
    읽어보겠습니다. 감사합니다.
    2014-11-19
    12:06:47

    [덧글]

    추천  메뉴
    액셀 임포트 작업이 빈번하게 있나요?
    2014-11-19
    11:19:55

    [덧글]

    추천 시그시끄
    임포트 작업이라는게 INSERT 하는 부분 말씀하시는건가요?
    2014-11-19
    12:09:43

    [덧글]

    추천 LECHUCK
    아마도 POI에서 엑셀의 모든 데이터를 메모리에 올린 다음 작업을 하기 때문에 그런거 같은데요.
    먼저 이클립스 메모리가 아니라 애플리케이션 실행시 JVM에 넘겨줘야하는 -Xmx 옵션을 사용해서 메모리를 늘려줘 보시구요.
    그래도 메모리 부족이 뜬다면 모두 메모리에 올리기에는 전체 데이터가 너무 크기 때문에
    csv 파일로 해서 블럭단위로 읽으면서 DB에 추가하면 될 거 같습니다.
    아니면 xml로 한다면 DOM 대신 SaxParser를 사용해야겠죠.
    2014-11-19
    11:25:17

    [덧글]

    추천 시그시끄
    SaxParser로 파싱하려면 먼저 엑셀을 읽어야 되지 않나요?
    2014-11-19
    12:06:26

    [덧글]

    추천 귀린.
    원하시는 답변이 아니긴 한데 엑셀 몇천건을 임포트 하는데 1~2분이나 걸리나요? 1,2초면 끝나는데..
    뭔가 소스도 다시 한번 봐야 될듯 한데요..설마 쿼리문을 계속해서 돌리면서 추가하는건 아니죠?
    2014-11-19
    11:28:55

    [덧글]

    추천 시그시끄
    흠 지금 1000건씩 나눠서 ibatis 배치로 쿼리 돌리고 있는데 문제가 있는건가요?
    2014-11-19
    12:05:20

    [덧글]

    추천 토루토루
    윗분 말씀대로 이클립스 메모리 말고 run 실행 설정에서 -Xmx 옵션으로 메모리 설정하시면 될 듯 합니다.
    그리고 단순 DB Insert 라면 건별로 업데이트 하지 마시고 addBatch 이용해서 최소 천건단위로 insert 하세요.
    10만건을 정해진 시간(예 : 5초 이내) 안에 처리해야 되는게 아니라면 위 내용만으로도 작업에는 큰 문제 없어 보입니다.
    2014-11-19
    11:54:40

    [덧글]

    추천 시그시끄
    만약 10만건을 5초 이내에 올려야 되는 상황이 되면 다른 방법을 써야 하나요?
    댓글 읽고 갑자기 궁금해지네요
    2014-11-19
    12:09:08

    [덧글]

    추천 1 귀린.
    대용량 업데이트를 이용해야죠.. 검색해보니 나오네요.참고해보세요.
    http://fruitdev.tistory.com/111
    2014-11-19
    14:35:59


    추천 토루토루
    사실 addBatch를 이용하여 대용량 처리를 하더라도 특정 시간안에 모든 작업을 처리해야 되는경우에는
    싱글 스레드로 실행시 어느정도 한계가 있습니다. (제 생각)

    저의 경우 대용량 처리를 할때에는 멀티스레드로 데이터의 각 범위를 정해서 addBatch를 이용하였습니다.
    2014-11-19
    18:19:01


    추천 봄-봄
    DB에 맞는 loader 프로그램을 내부에서 호출해서 쓰세요.
    2014-11-19
    12:33:43

    [덧글]

    추천 추억만이
    이게 가장 현실적이고 가장 빠르고 가장 최고의 정답..
    2014-11-20
    12:35:16

    [덧글]

    추천 현자
    트랜잭션은 어떻게 되나요?
    트랜잭션을 개별 단위로 처리 하면 메모리 문제가 수월하긴 합니다만
    트러블 슈팅이 좀 난감해지죠.
    2014-11-19
    13:22:23

    [덧글]

    추천 익명할래요
    2년전인가.. 신입때

    파일로된 190만 라인, 100~150MB 짜리의 텍스트 파일을 DB 인서트 한적있었는데.

    저도 같은 증상 있었습니다.

    파싱 완료 -> 인서트 하는 과정에서

    파싱하다보니 변수에 데이터를 담아야 하는데 점점 많아 지면서

    힙스페이스 오류가 나는 상황이었는데요.

    1000건씩 파싱 -> 인서트 반복해서 해결했네요.

    saxparser도 찾아보니

    라인별 파싱이라고 하는데요.

    같은 방식으로 진행하면 되지 않을까 합니다.
    2014-11-19
    13:34:17

    [덧글]

    추천 푸우날쎄
    이전 프로젝트 중에 하루 교통카드데이터(서울기준, 일 하루 약 이천만건)를
    일주일 치 정도 한번에 올린적이 있었는데,
    그 때는 CSV 파싱 오픈 소스 이용해서, 읽어 들이고, 만건씩 AddBatch 사용해서
    커밋 했었습니다. 2천 만건 기준으로 약 6분 정도 소요되었던 것으로
    기억합니다.
    2014-11-19
    15:02:29

    [덧글]

    추천  달팽달팽
    java nio 써서 버퍼사이로 끊어서 리드하세요

     

     

    http://www.ppomppu.co.kr/zboard/view.php?id=developer&no=14020

    And

    한글깨질때!!!

    |

    String pram = new String(request.getParameter("param").getBytes("8859_1"),"euc-kr");

     

    request.setCharacterEncoding("UTF-8");

     

     

    response.setContentType("text/html;charset=UTF-8");

     

    java.net.URLDecoder.decode(request.getParameter("param"), "EUC-KR");

    And

    모바일 참고

    |
    http://m.egovframe.go.kr/mguide/guide/guide.do
    And

    jad로 역컴파일..

    |
    출처 :
    1.
    http://mamoru15.egloos.com/1815962
    2. http://cafe.naver.com/javababy.cafe?iframe_url=/ArticleRead.nhn%3Farticleid=68&

    < 역컴파일러 사용법 >
    1. 역컴파일하려는 class파일이 있는 폴더에 jad.exe를 옮긴다.
    2. DOS 창을 열고 그 폴더를 찾아간다.
    3. jad -sjava '클래스명' 을 타이핑한다. 
          (예) 경로가 c:javafiles, 역컴파일하려는 파일이 A.class인 경우 DOS창에서 
                        C:javafiles> jad -sjava A.class
    4. 확인해 보면 그 폴더에 A.java 파일이 생성되어 있을 것이다.
    jad.exe

    5. 여러 파일을 한번에 컴파일
    jad -sjava ./경로폴더명/*.class
    (예) jad -sjava ./temp/*.class

    And

    Design Pattern 정리 (헤드퍼스트 디자인 패턴)

    |
    출처 : http://ohgyun.com/279


    문서를 정리하다가 예전에 헤드퍼스트 디자인 패턴 책을 읽고 정리해 놓은 파일이 있어 옮겨봅니다.

    ==============================================================

    디자인 원칙
        - 애플리케이션에서 달라지는 부분을 찾아내고, 달라지지 않는 부분으로부터 분리한다.
        - 구현이 아닌 인터페이스에 맞춰서 프로그래밍한다.
        - 상속보다는 구성을 활용한다.
        - 서로 상호작용을 하는 객체 사이에서는 가능하면 느슨하게 결한하는 디자인을 사용해야 한다.
        - 클래스는 확장에 대해서는 열려 있어야 하지만 코드 변경에 대해서는 닫혀 있어야 한다.
           (OCP : Open-Closed Principle)
        - 추상화된 것에 의존하도록 만들어라. 구상클래스에 의존하도록 만들지 않도록 한다.
        - 최소 지식 원칙 - 정말 친한 친구하고만 얘기하라.
           (다음 네 종류의 객체의 메서드만 호출한다.
             1. 객체 자체 / 2. 메서드에 매개변수로 전달된 객체 / 3. 그 메서드에서 생성하거나 인스턴스를 만든 객체 / 4. 그 객체에 속하는 구성 요소)
        - 헐리우드 원칙 - 먼저 연락하지 마세요. 저희가 연락 드리겠습니다.
        - 클래스를 바꾸는 이유는 한 가지 뿐이어야 한다.
        + ... 나중에 어떻게 바뀔 것인가?


    스트래티지 패턴(Strategy Pattern)
        - 알고리즘군을 정의하고 각각을 캐슐화하여 교환해서 사용할 수 있도록 만든다.
        - 알고리즘을 사용하는 클라이언트와는 독립적으로 알고리즘을 변경할 수 있다.
        - 구성을 사용한다.
        - 일반적으로 서브클래스를 만드는 방법을 대신하여 유연성을 극대화하기 위한 용도로 쓰인다.
        - 예: QuarkBehavior & FlyBehavior
        

    옵저버 패턴(Observer Pattern)
        - 한 객체의 상태가 바뀌면 그 객체에 의존하는 다른 객체들한테 연락이 가고
           자동으로 내용이 갱신되는 방식으로 일대다(one-to-many) 의존성을 정의한다.
        - 주제(Subject) & 옵저버(Observer)
        - Observable & Observer:
             Observable 에 register, remove, notify 가 있고, 
             Observer 에 update 가 있다. (notify 에서 update 를 호출)
        - 예: 신문 구독 서비스, 기상관측 시스템
        

    데코레이터 패턴(Decorator Pattern)
        - 객체에 추가적인 요건을 동적으로 첨가한다.
        - 데코레이터는 서브클래스를 만드는 것을 통해서 기능을 유연하게 확장할 수 있는 방법을 제공한다.    
        - 예: 스타버즈 커피
        
        
    팩토리 패턴(Factory Pattern)    
        - 팩토리 메서드 패턴 :
           객체를 생성하기 위한 인터페이스를 정의하는데, 어떤 클래스의 인스턴스를 만들지는 서브클래스에서 결정하게 만든다.
           클래스의 인스턴스를 만드는 일을 서브클래스에 맡긴다.
        - 제품을 생산하는 부분과 사용하는 부분을 분리시킬 수 있다.
        - 추상 팩토리 패턴 :
           인터페이스를 이용하여 서로 연관된, 또는 의존하는 객체를 구상 클래스를 지정하지 않고 생성한다.
           구상 클래스는 서브 클래스에 의해 만들어진다.


    싱글턴 패턴(Singleton Pattern)
        - 해당 클래스의 인스턴스가 하나만 만들어지고,
           어디서든지 그 인스턴스에 접근할 수 있도록(전역 접근) 하기 위한 패턴
           
           
    커맨드 패턴(Command Pattern)
        - 요구 사항을 객체로 캡슐화 할 수 잇으며, 매개변수를 써서 여러 가지 다른 요구 사항을 집어넣을 수 있다.
           또한 요청 내역을 큐에 저장하거나 로그로 기록할 수도 잇으며, 작업취소 기능도 지원 가능하다.
        - 예: 리모콘
        - 서블릿의 doGet(), doPost() 또는 스트럿츠의 Action() 메서드도 커맨드 패턴이지 않을까?
        

    어댑터 패턴(Adapter Pattern)
        - 한 클래스의 인터페이스를 클라이언트에서 사용하고자 하는 다른 인터페이스로 변환한다.
           어댑터를 이용하면 인터페이스 호환성 문제 때문에 같이 쓸 수 없는 클래스들을 연결해서 쓸 수 있다.  
           

    퍼사드 패턴(Facade Pattern)
        - 어떤 서브시스템의 일련의 인터페이스에 대한 통합된 인터페이스를 제공한다.
           퍼사드에서 고수준 인터페이스를 정의하기 때문에 서브시스템을 더 쉽게 사용할 수 있다.
        - 서브시스템의 호출을 퍼사드에서 처리해준다. (기본 명령 호출 정도랄까...)
        - 일련의 클래스들에 대한 인터페이스를 단순화 시킨다.
        
        - 각 패턴별 차이점:
           데코레이터 패턴 : 인터페이스는 바꾸지 않고 책임(기능)만 추가
           어댑터 패턴 : 한 인터페이스를 다른 인터페이스로 변환
           퍼사드 패턴 : 인터페이스를 간단하게 바꿈


    템플릿 메서드 패턴(Template Method Pattern)
        - 메서드에서 알고리즘의 골격을 정의한다.
           알고리즘의 여러 단계 중 일부는 서브클래스에서 구현할 수 있다.
           템플릿 메서드를 이용하면 알고리즘의 구조는 그대로 유지하면서 서브클래스에서 특정 단계를 재정의할 수 있다.
        - 스트래티지 패턴과 다른 점:
           템플릿 메서드 패턴은 알고리즘의 개요를 정의한다. 실제 작업 중 일부는 서브클래스에서 처리.
           스트래티지 패턴은 객체 구성을 통해서 알고리즘을 캡슐화 및 구현
        - 예) Arrays.sort(배열); --- compareTo() 를 구현하도록 되어 있다.
                Applet , init(), start(), stop(), destory()
                그렇다면 서블릿에도 템플릿 메서드가 쓰이는 거구나. init() - service() - destory()

                
    이터레이터 패턴(Iterator Pattern)
        - 컬렉션 구현 방법을 노출시키지 않으면서도
           그 잡합체 안에 들어있는 모든 항목에 접근할 수 있게 해주는 방법을 제공한다.
        - 컬렉션의 구현을 드러내지 않으면서 컬렉셔네 있는 모든 객체들에 대해 반복작업할 수 있다.
        

    컴포지트 패턴(Composite Pattern)
        - 객체들을 트리 구조로 구성하여 부분과 전체를 나타내는 계층구조로 만들 수 있다.
           이 패턴을 이용하면 클라이언트에서 개별 객체와 다른 객체들로 구성된
           복합 객체(composite)를 똑같은 방법으로 다룰 수 있다.
        - 클라이언트에서 객체 컬렉션과 개별 객체를 똑같은 식으로 처리할 수 있다.
        - 예) 트리 구조의 패턴, 디렉토리 구조
        - 예) XMLObject 객체가 컴포지트 패턴을 구현한 게 아닐까
        

    스테이트 패턴(State Pattern)
        - 객체의 내부 상태가 바뀜에 따라서 객체의 행동을 바꿀 수 있다.
           마치 객체의 클래스가 바뀌는 것과 같은 결과를 얻을 수 있다.
        - 상태 전환의 흐름을 결정하는 코드를 어느 쪽에 집어넣는지 잘 고려해야 한다.
           (상태 객체인지, Context 객체인지)
        - 각 상태를 클래스로 캡슐화함으로써 나중에 변경시켜야 하는 내용을 국지화시킬 수 있다.
        - 스트래티지 패턴:
              어떤 클래스의 인스턴스를 만들고 그 인스턴스에게 어떤 행동을 구현하는 전략 객체를 건내준다.
           스테이트 패턴:
              컨텍스트 객체를 생성할 때 초기 상태를 지정해주는 경우 이후로는 컨텍스트 객체가 알아서 상태를 변경.
              
              
    프록시 패턴(Proxy Pattern)
        - 어떤 객체에 대한 접근을 제어하기 위한 용도로 대리인이나 대변인에 해당하는 객체를 제공하는 패턴
        - 다른 객체를 대변한느 객체를 만들어서 주 객체에 대한 접근을 제어할 수 있다.
        - 원격프록시(remote proxy): 원격 객체에 대한 접근 제어
                                                    클라이언트와 원격 객체 사이에서 데이터 전달을 관리
           가상프록시(virtual proxy): 생성하기 힘든(인스턴스를 만드는 데 많은 비용이 드는) 자원에 대한 접근 제어
           보호프록시(protection proxy): 접근 권한이 필요한 자원에 대한 접근 제어
                                                         호출하는 쪽의 권한에 따라서 객체에 있는 메소드에 대한 접근 제어
           방화벽 프록시: 일련의 네트워크 자원에 대한 접근 제어
           스마트 레퍼런스 프록시: 주 객체가 참조될 때마나 추가 행동을 제공. 객체에 대한 레퍼런스 개수를 세는 등
           캐싱 프록시: 비용이 많이 드는 작업의 결과를 임시로 저장
                              웹 서버 프록시 또는 컨텐츠 관리 및 퍼블리싱 시스템 등에서 사용
           동기화 프록시: 여러 스레드에서 주 객체에 접근하는 경우 안전하게 작업을 처리할 목적(분산 환경 등에서 사용)
           복잡도 숨김 프록시: 복잡한 클래스들의 집합에 대한 접근을 제어하고 복잡도를 숨겨줌
                                         퍼사드 프록시라고도 함.
                                         프록시에서는 접근을 제어하지만 퍼사드 패턴에서는 대체 인터페이스만 제공
           지연 복사 프록시: 클라이언트에서 필요로 할 때까지 객체가 복사되는 것을 지연시킴으로써 객체의 복사 제어
           
        - 아래 객체들은 모두 클라이언트와 객체 사이에 끼여들어서 요청을 전달한다.
             데코레이터 패턴: 클래스에 새로운 행동을 추가하기 위한 용도
             어댑터 패턴: 다른 객체의 인터페이스를 바꿔주기 위한 용도
             프록시 패턴: 어떤 클래스에 대한 접근을 제어하기 위한 용도
        - java.reflect.Proxy 에 기능이 내장되어 있다.
        
        
    디자인 패턴 정의
        - 패턴이란 특정 컨텍스트 내에서 주어진 문제에 대한 해결책이다.
        - 어떤 컨텍스트 내에서 일련의 제약조건에 의해 영향을 받을 수 있는 문제에 봉착했다면,
           그 제약조건 내에서 목적을 달성하기 위한 해결책을 찾아낼 수 있는 디자인을 적용하면 된다.    
          

    주의점 및 추가 사항      
        - 디자인 패턴의 과다한 사용은 불필요하게 복잡한 코드를 초래할 수 있다.
           항상 가장 간단한 해결책으로 목적을 달성할 수 있도록 하고, 반드시 필요할 때만 디자인 패턴을 적용하자.      
        - 코딩할 때 어떤 패턴을 사용하고 있는지 주석으로 적어주자.
           클래스와 메서드 이름을 만들 때도 사용 중인 패턴이 분명하게 드러날 수 있도록 해보자.
           다른 개발자들이 그 코드를 볼 때 무엇을 어떻게 구현했는지 훨씬 빠르게 이해할 수 있다.


    그 외 잘 정리된 참고 사이트 : http://vincehuston.org/dp/
    And

    javascript singleton (자바스크립트 싱글턴)

    |
    출처 : http://ohgyun.com/248

    좋은 정보 감사합니다.. ^^

    --------------------------------------------------------------------------------------------------------------
    발생일: 2009.12.24

    문제:
    독립적인 기능을 하는 자바스크립트 클래스를 하나 만들었다.
    이 클래스를 싱글턴으로 사용하고 싶다.

    또한, 일반적인 getInstance() 라는 스태틱 메서드를 사용하는 대신,
    바로 생성자를 호출해서 객체를 만들도록(내부적으로 싱글턴 인스턴스를 리턴) 하려고 한다.

    어떻게 하면 자바스크립트에서 생성자만으로 싱글턴을 구현할 수 있을까?


    해결책:
    한참을 고민해봤다.
    이런 방법으로 구현해보면 어떨까?

    클래스의 생성자에 대한 유효범위를 제한해두고,
    그 유효범위 안에서 window 속성의 클래스 생성자(래퍼)를 다시 정의한다.
    (일종의 프록시 패턴이라고 할 수도 있겠다)
    window 속성의 클래스 생성자에서는 클래스의 유일한 인스턴스를 만들어 리턴하도록 싱글턴을 구현한다.
    즉, 외부에서 클래스 생성자를 호출해서 객체를 만들 때에는,
    window 속성의 생성자를 호출하게 되므로 생성자만으로 싱글턴을 구현할 수 있다.


    아래 실제 구현 예제를 이해하기 위해 몇 가지 자바스크립트 언어에 대한 선수 지식이 필요하다.

    javascript 언어 특징 보기




    간단한 실제 구현 모습은 아래와 같다.

        (function() { // (a) 익명함수로 유효범위를 제한한다.
       
            // (b) window 속성의 생성자를 정의한다.
            // 외부에서 생성자를 호출할 때에는 이 생성자가 호출된다.
            window.Singleton = function(name) {
                // (d) 객체가 생성되어 있지 않을 경우, 새 객체를 _instance 에 담는다.
                if (_instance == null) {
                    _instance = new Singleton(name);
                }
                return _instance;
            }
       
            // (c) 유일한 싱글턴 인스턴스
            var _instance = null;
           
            // (e) 실제 객체 생성자
            // 외부에서 이 생성자에 접근할 수 없다.
            var Singleton = function(name) {
                this.name = name;
            }
           
        })();


    실제 객체의 생성자는 (e) 부분이다.

    외부에서 이 객체의 생성자에 접근하지 못하도록 익명함수(anonymous function)로 생성자를 감싸준다.
    이 부분이 (a) 부분이 되겠다.

    (c) 와 같이 유일한 싱글턴 인스턴스를 담을 변수를 선언해준다. 전역변수와 같이 선언되어 있지만,
    이 변수 역시 생성자와 같은 유효범위에 있기 때문에 외부에서는 접근하지 못한다.

    이제 외부에서 이 객체를 생성할 수 있도록 (b)와 같이 window 속성에 같은 이름으로 생성자를 구현해준다.
    window.Singleton 은 window 속성이기 때문에 외부에서도 호출이 가능하며,
    window prefix 없이 바로 new Singleton() 과 같이 호출이 가능하다.
    (외부에서 new Singleton(); 을 호출했을 때 (e) 부분의 실제 함수가 호출되는 게 아니다.)
    또한, window.Singleton 객체가 유효범위 밖에서 _instance 를 참조할 수 있는 건, 클로저(closure) 때문이다.

    window 속성의 객체 생성자(b)에서는 (d)에서와 같이 싱글턴 부분을 구현한다.
    _instance 가 존재하지 않을 경우, 새 객체를 생성해 할당하고, 그렇지 않을 경우 이미 존재하는 객체를 리턴한다.

    이와 같이 구현하면 외부에서 new Singleton() 을 호출했을 때,
    (실제 객체의 wrapper 격인) window.Singleton() 생성자가 호출되며,
    window.Singleton 생성자 내에서 싱글턴 객체를 리턴하게 된다.

    아래와 같이 호출해보면, new Singleton() 을 통해 싱글턴 객체가 생성되는 것을 확인할 수 있다.

        // 여기서 호출되는 Singleton 생성자는 window.Singleton 이다.
        var s1 = new Singleton('aaa');
        alert(s1.name); // aaa 출력
       
        var s2 = new Singleton('bbb'); // 이미 생성된 객체가 리턴된다.
        alert(s2.name); // aaa 출력



    다소 번거롭긴 하지만, 이 방법을 통해 실제 생성자에 대한 접근을 제한할 수 있고,
    new 키워드를 통해 싱글턴 객체를 리턴하도록 구현할 수 있다.
    (굳이 패턴으로 나누어 생각하려고 한다면, 싱글턴 + 프록시 패턴 정도겠다. )

    일반적인 패턴처럼, getInstance() 를 통해 싱글턴 객체를 생성하고 싶을 경우,
    같은 방법으로 익명함수 내에서 window.Singleton 안에 getInstance() 를 정의해주면 되겠다.

    기타 다른 방법들도 있지만,
    기존 생성된 객체를 유지하는 한도 내에서 유용하게 사용할 수 있을 것이라 생각한다.



    * 참고:
    검색해보니 싱글턴을 구현하는 다른 방법들에 대한 좋은 자료들이 많다.

        1. How to make a singleton in javascript
    이 포스트에서는 static getInstance() 메서드를 통해 싱글턴 객체를 생성하는 방법에 대해 설명되어 있다.
    가장 알아보기 쉽고 기본적인 방법이니 참고해보도록 하자.
    이 포스트에서는 자바스크립트 모듈 패턴을 통해 싱글턴 객체 생성자를 구현했다.
    constructor 이름을 통해 이미 만들어진 객체를 싱글턴으로 만드는 전역 메서드 구현에 대한 방법도 있다.
    좋은 내용이 많으니 꼭 읽어보자.
    약간 다른 방법. 이 포스트도 참고해보자.


    그 외,자바스크립트의 유효범위와 클로저에 대해 잘 이해가 안될 경우, 아래 포스트를 참고하자.
    And

    네이버 OpenAPI 를 AJAX 방식으로 쓰기위한 JSP 프록시 만들기

    |
    출처 : http://cyzest.tistory.com/8

    우선 글을 쓰기에 앞서 해당 구현방법은 철저히 개인적인 방법임을 밟히는 바이다.
    (이방법이 최적의 방법 혹은 정석이 될수 없음을 미리 알리는 바이다.)

    요즘 네이버나 다음과 같은 여러 포탈 사이트에서 오픈API를 제공하고 있다.
    거의 모든 오픈API의 방식이 개인키를 부여하여 특정주소를 요청하면 XML로 결과를 리턴해주는 방식이다.

    AJAX 에서의 자바스크립트는 기본적으로 XMLHttpRequest 객체의 open()메소드와 send()메소드를 이용해서 해당 uri의 xml을 요청할 수 있다.

    하지만 자바스크립트의 보안제약사항에 따라 XMLHttpRequest 객체는 해당 페이지를 로딩한 서버 외에는 연결할 수 없게 되어있다.
    그래서 오픈API요청을 자바스크립트에서 바로 사용할수가 없다.

    이것을 해결하기 위해선 여러방법이 있겠지만 그중에서 나는 서버에서 해당 오픈API요청을 대신하고 결과를 보여주는 프록시페이지를 만들어 보기로 했다.

    해당 구현방법을 알아보기위해 인터넷의 넓은 바다를 항해한 결과,
    아파치 자카르타 프로젝트의 commons HttpClient API를 이용하여 구현하는 방법을 찾게 되었다.

    모든 구현을 완료하고 페이지를 실행해보았지만 문제가 생겼다.
    좀더 삽질을 하고난후 commons logging APIcommons codec API도 필요하다는것을 알게되었다.
    (logging, codec 이 왜 필요한지는 아직 알수없었다. 디버깅과정에서 ClassNotFound 가 뜨는 것들을 추가해주다가 알게되었다.)
    (초보의 무식함이다 =..= 만약 아직도 안되고있었다면 계속 삽질을? ;;;)

    proxy.jsp

    <%@ page language="java" pageEncoding="utf-8"%>
    <%@ page import="org.apache.commons.httpclient.HttpClient" %>
    <%@ page import="org.apache.commons.httpclient.methods.GetMethod" %>
    <%@ page import="org.apache.commons.httpclient.HttpStatus" %>

    <%
     request.setCharacterEncoding("utf-8");

     String url = "오픈API요청URI";
     HttpClient client = new HttpClient();
     GetMethod method = new GetMethod(url);
     
     try{
      int statusCode = client.executeMethod(method);
      out.clearBuffer();
      response.reset();
      response.setStatus(statusCode);
      if(statusCode == HttpStatus.SC_OK){
       String result = method.getResponseBodyAsString();
       response.setContentType("text/xml; charset=utf-8");
       out.println(result);

      }
     }finally{
      if(method != null) method.releaseConnection();
     }
    %>


    나는 네이버 실시간 음악 순위를 리턴받아 보았다.
    (get방식으로 파라미터값을 받을수있도록 jsp를 구현한 상태이다.)

    http://cyzest.cafe24.com/open/rank/proxy_rank.jsp?query=music


    이제 자바스크립트의 XMLHttpRequest 객체에서의 open() 메소드에서는 오픈API주소가 아닌 proxy.jsp 의 주소를 요청하면 되는 것이다.

    http://cyzest.cafe24.com/open/rank


    이제 해당 오픈API의 결과를 유용하게 이용하도록 구현하는 것은 사용자의 몫이 될것이다. :)

    And

    [JAVA] iBATIS + OSCACHE 사용 시 Cache Model에 대한 이해

    |
    출처 : http://theeye.pe.kr/379

    iBATIS는 공식적으로 캐시를 할때에 OSCache를 사용할 수 있도록 되어있습니다. 하지만 그 기능이 매우 자동적이며 제한적이고 세세한 설정을 개발자가 할수가 없습니다. 그래서 다음을 한번 알아 보기로 할까요. 다음의 예시는 [이곳]에 언급된 내용을 살짝 수정하였습니다.

    <cacheModel type="OSCACHE" id="cacheModel" readOnly="true">  
      <flushInterval hours="24"/>  
      <flushOnExecute statement="flushCache"/>  
    </cacheModel>  
    <resultMap class="kr.pe.theeye.Cache" id="CacheResult">  
      ...  
    </resultMap>  
       
    <insert id="flushCache" resultClass="string">  
      INSERT ...  
    </insert> 
     
    <select id="makeCache1" resultMap="CacheResult" cacheModel="cacheModel">  
      SELECT ...  
    </select> 
     
    <select id="makeCache2" resultMap="CacheResult" cacheModel="cacheModel">  
      SELECT ...  
    </select> 
     
    <select id="makeCache3" resultMap="CacheResult" parameterClass="int"  
      cacheModel="cacheModel">  
      SELECT ... WHERE PAGE = #value# 
    </select>

    위의 SQL맵 예제에서는 INSERT문 한개와 SELECT문 3개가 존재합니다. 모두 cacheModel이라는 id의 캐시모델과 연관되어집니다. 이것을 간단하게 그림으로 그려보면 다음과 같은 모양을 가지고 있습니다.

    사용자 삽입 이미지

    그려놓고 보니깐 좀 말이 안되는 그림 같아 보이네요;; 아무튼 하나의 캐시 모델에 3가지의 캐시를 생성할 수 있는 조건이 있고 2가지 캐시를 삭제할 수 있는 조건이 있다고 봐주시면 되겠습니다. 둥근 사각형은 개발자가 임의로 호출을 해야만 하는 기능들이고 위의 동그라미는 캐시 유지 시간 설정으로 봐주시면 되겠습니다.

    이제 다음의 몇가지 예시 상황들에 대한 캐시의 처리 과정에 대해 알아보겠습니다.

    1. 한개의 캐시 처리 (makeCache1 → flushCache)
    makeCache1이 수행되면 cacheModel에 하나의 캐시가 생성됩니다.  앞으로 makeCache1이 호출될때마다 캐시가 존재하는한 DB에 접근없이 캐시결과값을 제공하게 됩니다. flushCache를 수행하면 캐시가 삭제됩니다. 다시 makeCache1을 호출하면 DB에서 결과를 가져와서 반환함과 동시에 캐시를 생성하게 됩니다. 캐시가 생성된 시점에서 flushInterval에 설정된 시간이 경과하도록 flushCache가 호출되지 않는다면 시간 만료로 자동 삭제됩니다.

    2. 두개의 캐시 처리 (makeCache1 → makeCache2 → flushCache)
    makeCache1이 호출되면 cacheModel에 하나의 캐시가 생성됩니다. makeCache2가 호출되면 마찬가지로 cacheModel에 또다른 하나의 캐시가 생성됩니다. 이 두개의 캐시는 엄연히 다르며 각각의 makeCacheX가 호출될때 해당하는 만들어진 캐시값을 반환하게 됩니다. 하지만 둘다 모두 동일하게 cacheModel안에 소속됩니다. 이어서 flushCache를 호출하게 되면 두 캐시가 모두 삭제됩니다. 정확히는 flush에 대한 설정을 해두면 해당 캐시모델의 모든 캐시를 소거한다고 보시면 됩니다. 그러므로 이런 부분에 주의하여 캐시모델을 함께 사용할지 따로 다른 캐시모델을 만들지를 결정하셔야 합니다.

    3. 인자값의 차이에 따른 처리 (makeCache3[1] -> makeCache3[2] -> flushCache)
    makeCache3에는 parameterClass를 사용하여 동적인 쿼리를 수행하도록 되어있습니다. 예시로 간단하게 int값을 받도록 하였는데요. 캐시를 생성할때의 키값에는 이 인자값들이 모두 포함되어 키를 이룹니다. 그러므로 paramterClass로 넘어오는 값이 1일때와 2일때는 다른 쿼리(키)가 됩니다. 그러므로 1이라는 값의 인자를 받아 실행되는 makeCache3의 캐시와 2라는 값을 받아 실행되는 makeCache3는 각각 별개의 캐시가 생성됩니다. 마찬가지로 하나의 cacheModel안에서 호출되지만요. flushCache를 호출하면 이 두캐시가 모두 삭제됩니다.


    결론을 내보자면 위와 같은 iBATIS에서 제공하는 기본적인 캐시모델로는 같은 쿼리지만 다른 결과가 나올 수 있는 부분에는 사용할 수 없습니다. SNS 서비스에서 볼 수 있을 다음을 생각해 봅시다.

    1. 친구들의 최근근황을 모아서 볼 수 있는 기능이 있다고 가정한다.
    2. 사용자가 접속하여 친구들의 최근근황을 확인하였다. [캐시 생성됨]
    3. 친구중 한명이 최근 근황을 업데이트 하였다.
    4. 사용자가 다시한번 친구들의 최근근황을 확인하였다. [캐시값 반환됨]

    위를 수행하였을 때 친구들의 정보가 바뀌어도 사용자는 계속 캐시된 값을 받게됨을 알 수 있습니다. 그러므로 친구들의 업데이트 된 정보를 적시에 얻기가 힘듭니다. 하지만 그렇다고 친구의 정보가 업데이트 될때 다른 사용자의 캐시를 삭제하는데도 무리가 있습니다. 왜냐하면 캐시 키 값을 모르기 때문이죠. 이부분을 해결하려면 iBATIS의 SQL맵 캐시 기능을 사용하지 말고 자체적인 알고리즘으로 구현을 해야 할 것 같습니다.
    And

    java velocity 참조..

    |
    http://www.jopenbusiness.com/tc/oss/179
    And

    자바 원하는 오라클 함수를..(Java Stored Procedures or Functions)

    |

    승용이가 오라클 프로시저, 함수 공부하면서 오라클의 substr()함수와 같은 기능을 하는 함수를 기존 함수를 사용하지 않고 만드는 방법을 물어본건데...다른 방법으로는 죽어도 모르겠고(혹시 아시는 분 여기에 좀 올려주세요)...오라클에서 자바로 구현이 가능(자바말고. pro c등 기타언어로도 가능하지만..우리가 자바개발자인고로..)하기에 이렇게 만드는 방법을 올립니다. 개발시 참고바랍니다.

     

    Java Stored Procedures or Functions

     

    오라클에서 사용자 정의 함수나 프로시저를 만드는 것은 우리같은 자바 개발자에겐 조금 짜증나는 작업이다. 만약, 자바로 함수를 간단하게 만들 수 있다면...당근 가능하다...^^...

    비즈니스단이나 뷰어단에서 해야할 일을 DB단이 처리함으로써 응용프로그램이나 미들웨어에 작업하는 것보다 빠른 속도를 얻으면서 간단하고 쉽게 제작 사용할 수 있을 것이다.

     

    자바를 이용한 오라클 함수를 만드는 방법을 예제와 함께 정리했으니 따라하며 이해하시길...

     

    예제) 오라클의 substr()함수과 같은 자바클래스를 이용한 사용자 정의 함수 작성 방법

     

    1. Java 클래스 제작(Writing the Java Classes)

    데이터베이스의 테이블들을 생성한 후, 어떠한 기능(메서드)들이 구현되어져야 하는지
    생각하고 기능들을 메서드로서 구현한다. 

    import java.sql.*;
    import java.io.*;

    public class SubStr_ex
    {
      public static String cutString(String str_in, int start_no, int cut_no)
      {
          cut_no = start_no + cut_no - 1;
          char[] tmp = str_in.toCharArray();
          String out_str = "";
          if(cut_no>str_in.length()) cut_no = str_in.length();
          for(int i=1;i<=str_in.length();i++){
             if(i>= start_no && i <= cut_no){
               out_str = out_str+tmp[i-1];
             }
          }
          return out_str;
       }
    }

     

    2. 자바클래스 오라클에 올리기(Loading the Java Classes)
    자바클래스를 작성한 후 loadjava라는 오라클의 유틸리티를 이용하여 cmd창에서 다음과 같이
    올려준다

      D:\>loadjava -u scott/tiger@127.0.0.1:1521:ora -v -r -t SubStr_ex.java
      arguments: '-u' 'scott/tiger@127.0.0.1:1521:ora' '-v' '-r' '-t' 'SubStr_ex.java'

      creating : source SubStr_ex
      loading  : source SubStr_ex
      resolving: source SubStr_ex

     

    <옵션>
    -v : verbose모드 옵션
    -r : 컴파일하고 클래스안에 외부참조를 포함한다는 옵션
    -t : 클라이언트 측 JDBC Thin 드라이버를 이용해서 데이터베이스에 연결한다는 옵션


    3. load된 자바클래스를 이용한 오라클 함수 만들기(Publishing the Java Classes)
    자바클래스를 올렸으면 이제 오라클 함수를 만들어 사용하자
    sqlplus창에서 아래와 같이 실행하자


    CREATE OR REPLACE FUNCTION SubStr_ex(str_in VARCHAR2, sn NUMBER, en NUMBER)
       RETURN VARCHAR2
    AS
       LANGUAGE JAVA
       NAME 'SubStr_ex.cutString(java.lang.String, int, int) return java.lang.String';
    /


    그러면 substr_ex()라는 사용자 함수가 생성되어져 있을 것이다.

     

    4. 이제부터는 맘대로 사용....(Calling the Java Stored Procedures or Functions)

    SQL> select substr_ex('asdfghhj',3,2) from dual;

    SUBSTR_EX('ASDFGHHJ',3,2)
    -------------------------------------------------------------------------------

    df

     

    더 많은 정보는

    http://download-west.oracle.com/docs/cd/B19306_01/java.102/b14187/cheight.htm#CHDCCHID

    이곳을 참고 바랍니다.

     

    그리고..오라클과 자바...타입 매핑

    Table 6-1 Legal Data Type Mappings

    SQL Type Java Class
    CHAR, LONG, VARCHAR2 oracle.sql.CHAR

    java.lang.String

    java.sql.Date

    java.sql.Time

    java.sql.Timestamp

    java.lang.Byte

    java.lang.Short

    java.lang.Integer

    java.lang.Long

    java.lang.Float

    java.lang.Double

    java.math.BigDecimal

    byte, short, int, long, float, double

    DATE oracle.sql.DATE

    java.sql.Date

    java.sql.Time

    java.sql.Timestamp

    java.lang.String

    NUMBER oracle.sql.NUMBER

    java.lang.Byte

    java.lang.Short

    java.lang.Integer

    java.lang.Long

    java.lang.Float

    java.lang.Double

    java.math.BigDecimal

    byte, short, int, long, float, double

    OPAQUE oracle.sql.OPAQUE
    RAW, LONG RAW oracle.sql.RAW

    byte[]

    ROWID oracle.sql.CHAR

    oracle.sql.ROWID

    java.lang.String

    BFILE oracle.sql.BFILE
    BLOB oracle.sql.BLOB

    oracle.jdbc2.Blob

    CLOB, NCLOB oracle.sql.CLOB

    oracle.jdbc2.Clob

    OBJECT

    Object types

    oracle.sql.STRUCT

    java.sql.Struct

    java.sql.SqlData

    oracle.sql.ORAData

    REF

    Reference types

    oracle.sql.REF

    java.sql.Ref

    oracle.sql.ORAData

    TABLE, VARRAY

    Nested table types and VARRAY types

    oracle.sql.ARRAY

    java.sql.Array

    oracle.sql.ORAData

    any of the preceding SQL types oracle.sql.CustomDatum

    oracle.sql.Datum

     

    2006.4.27 / 무찬아빠(naeodud@nate.com)

    And

    ResourceBundle 사용하기

    |
    출처 : http://jeongsam.net/138

    ResourceBundle 사용하기

    클래스 상속관계 java.lang.Object - java.util.ResourceBundle

    ResourceBundle은 다음과 같은 특징을 같습니다.

    • 다른 국가의 언어에 맞추어 로컬라이징을 할 수 있습니다.
    • 복수의 로케일을 동시에 처리할 수 있습니다.
    • 새로운 로케일의 추가가 쉽습니다.

    ResourceBundle을 사용하기 위해서는 다음과 같이 getBundle() 메서드를 사용하여 ResourceBundle 클래스를 로드합니다.

    ResourceBundle myResource = ResourceBundle("MyResource", 로케일);

    로케일의 생략시 현재 사용하는 로케일이 지정됩니다. 한글은 'ko_KR'로 로케일이 지정됩니다. 'MyResource'의 이름은 베이스 네임으로 로케일에 따라 자동으로 베이스 네임과 함께 로케일 이름이 붙은 이름을 먼저 찾게 됩니다. 예를 들면 로케일이 'ko_KR'인 경우 'MyResource_ko_KR'로 확장되며, 이 파일이 존재하지 않는 경우, 'MyResource_ko.properties'를 찾고 이 파일 존재하지 않으면 최종적으로 'MyResource_ko_KR.properties'이라는 리소스 파일을 현재 클래스가 위치한 패키지 내에서 찾게 됩니다. 만일 이런 이름의 파일이 없을 경우는 'MyResource.properties' 파일을 찾게 됩니다.

    package net.jeongsam.extra;
    
    import java.util.Iterator;
    import java.util.ResourceBundle;
    import java.util.Set;
    
    public class ResourceLocaleEx01 {
    	public static void main(String[] args) {
    		// net.jeongsam.extra 패키지에서 MyResource_ko_KR.properties 파일을 탐색한다.
    		ResourceBundle myResource = ResourceBundle.getBundle("net.jeongsam.extra.MyResource");
    
    		Set keys = myResource.keySet();
    		Iterator itKeys = keys.iterator();
    		
    		while (itKeys.hasNext()) {
    			String key = itKeys.next();
    			System.out.println(key + "=" + myResource.getString(key));
    		}
    	}
    
    }
    
    And

    ROME을 활용해서 Feed 생성하기

    |
    ROME과 Spring을 활용해서 Feed를 생성하는 소스입니다. 블로그 시스템을 개발하거나 기존 게시판 서비스에서 Feed를 만들어서 외부에 공유해 주기위해서 아래 소스들을 활용하면 원하시는 Feed를 생성할 수 있을 것입니다.
    ROME이 여러모로 좋은 오픈소스로 활용되는 것 같네요. 좀더 분석해서 필요한 기능들을 공유할께요.
    필요한 라이브러리는 ROME 1.0, JDOM 1.0이 필요합니다.

    1. Feed 생성 소스

    package client;

    import java.util.ArrayList;
    import java.util.List;

    import org.apache.commons.lang.StringUtils;
    import org.apache.commons.logging.Log;
    import org.apache.commons.logging.LogFactory;

    import com.mimul.DataFacade;
    import com.mimul.domain.Category;
    import com.mimul.domain.Entry;
    import com.mimul.domain.SiteConfig;
    import com.sun.syndication.feed.synd.SyndCategory;
    import com.sun.syndication.feed.synd.SyndCategoryImpl;
    import com.sun.syndication.feed.synd.SyndContent;
    import com.sun.syndication.feed.synd.SyndContentImpl;
    import com.sun.syndication.feed.synd.SyndEntry;
    import com.sun.syndication.feed.synd.SyndEntryImpl;
    import com.sun.syndication.feed.synd.SyndFeed;
    import com.sun.syndication.feed.synd.SyndFeedImpl;

    public class CreateFeed
    {
    private final Log log = LogFactory.getLog(this.getClass());
    private DataFacade dataFacade;

    public void setDataFacade(DataFacade dataFacade) {
    this.dataFacade = dataFacade;
    }

    public SyndFeed getFeed(String type)
    {
    SyndFeed feed = null;
    Entry post = null;
    List<Entry> recentEntries = null;
    List<SyndEntry> entries = null;
    List<SyndCategory> categories = null;
    StringBuilder sb = null;

    try {
    feed = new SyndFeedImpl();
    feed.setFeedType(type); //rss_2.0
    feed.setTitle("Mimul's Developer World");
    feed.setLink("http://www.mimul.com/");
    feed.setDescription("Java Ecxamples Code");
    entries = new ArrayList<SyndEntry>();

    post = new Entry();
    post.setType("post");
    post.setEntryStatus("publish");
    // 데이터 베이스에 저장된 엔트리를 가져온다
    recentEntries = dataFacade.getEntryPage(post,
    10, 0, null, null).getItems();

    for (Entry entry:recentEntries) {
    SyndEntry syndEntry = new SyndEntryImpl();
    syndEntry.setTitle(entry.getTitle());
    String link = null;
    if(StringUtils.isNotBlank(entry.getName())) {
    link = "http://www.mimul.com" + "/post/" +
    entry.getName() + ".html";
    }else{
    link = "http://www.mimul.com" + "/post/id/" +
    entry.getId() + ".html";
    }
    syndEntry.setLink(link);
    syndEntry.setAuthor(entry.getAuthor().getNickname());
    syndEntry.setPublishedDate(entry.getPostTime());
    categories = new ArrayList<SyndCategory>();
    // 카테고리 정보를 가져온다
    for(Category category:entry.getCategories()) {
    SyndCategory syndCategory = new SyndCategoryImpl();
    syndCategory.setName(category.getName());
    syndCategory.setTaxonomyUri("http://www.mimul.com" +
    "/category/" + category.getName() + "/");
    }
    syndEntry.setCategories(categories);
    SyndContent content = new SyndContentImpl();
    content.setType("text/html");
    sb = new StringBuilder();
    sb.append(entry.getSummary())
    .append("<p>").append("<a href=\"").append(link)
    .append("\">[more..]</a></p>");
    content.setValue(sb.toString());
    syndEntry.setDescription(content);
    entries.add(syndEntry);
    }
    feed.setEntries(entries);
    } catch (Exception e) {
    log.error(e);
    }
    return feed;
    }
    }
    2. Servlet 소스

    public void doPost(HttpServletRequest request, 
    HttpServletResponse response)
    throws ServletException, IOException {
    SyndFeedOutput output = null;
    try {
    SyndFeed feed = getCreateFeed().getFeed("rss_2.0");
    feed.setFeedType("rss_2.0");

    response.setContentType("application/xml; charset=UTF-8");
    response.setHeader("Pragma","No-Cache");
    response.setHeader("Cache-Control","No-Cache");
    response.setDateHeader("Expires",0);

    output = new SyndFeedOutput();
    output.output(feed, response.getWriter());
    } catch (FeedException e) {
    log.error(e);
    response.sendError(
    HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
    "FEED 생성 오류");
    }
    }
    private CreateFeed getCreateFeed() {
    return (CreateFeed) WebApplicationContextUtils.
    getWebApplicationContext(getServletConfig()
    .getServletContext()).getBean("createFeed");
    }

    And

    Struts2 에서 확장자 제거하기

    |

    Struts2에서 Action의 기본확장자는 action이다.
    REST의 관점에서 보면 URL은 Resource를 가리키고 있을 뿐이어서 action이란 접미어가 붙는 것은 restful 하지 않아 보인다.
    그래서 struts.properties의 struts.action.extension에 아무것도 할당하지 않으면 간단히 확장자를 제거 할 수 있다.

    struts.action.extension=

    struts.properties

    하지만, 이렇게 하면 welcome-file을 사용할 수 없고, *.jsp, *.gif, *.jpg등 struts action이 아닌 resource들은 접근 할 수도 없다. 그래서 다음과 같이 간단한 필터를 만들어 보았다.

    1. package filters;   
    2.   
    3. import java.io.IOException;   
    4.   
    5. import javax.servlet.Filter;   
    6. import javax.servlet.FilterChain;   
    7. import javax.servlet.FilterConfig;   
    8. import javax.servlet.ServletException;   
    9. import javax.servlet.ServletRequest;   
    10. import javax.servlet.ServletResponse;   
    11. import javax.servlet.http.HttpServletRequest;   
    12.   
    13. import org.apache.struts2.dispatcher.FilterDispatcher;   
    14.   
    15. public class StrutsRedirectFilter implements Filter {   
    16.   
    17.     FilterDispatcher dispatcher = new FilterDispatcher();   
    18.   
    19.     @Override  
    20.     public void doFilter(ServletRequest req, ServletResponse res,   
    21.             FilterChain chain) throws IOException, ServletException {   
    22.   
    23.         HttpServletRequest request = (HttpServletRequest) req;   
    24.         String uri = request.getRequestURI();   
    25.   
    26.         // 확장자가 있는 경우   
    27.         if (uri != null  
    28.                 && (uri.equals(request.getContextPath().concat("/")) || uri   
    29.                         .substring(uri.indexOf("/")).indexOf(".") > -1)) {   
    30.             chain.doFilter(req, res);   
    31.             // 아닌 경우 struts로 넘긴다.   
    32.         } else {   
    33.             dispatcher.doFilter(req, res, chain);   
    34.         }   
    35.     }   
    36.   
    37.     @Override  
    38.     public void destroy() {   
    39.         dispatcher.destroy();   
    40.     }   
    41.   
    42.     @Override  
    43.     public void init(FilterConfig config) throws ServletException {   
    44.         dispatcher.init(config);   
    45.     }   
    46. }  

    StrutsRedirectFilter.java

    이 필터를 org.apache.struts2.dispatcher.FilterDispatcher 대신 web.xml 에 넣어주면 된다.
    1. <?xml version="1.0"?>  
    2. <!DOCTYPE web-app PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"   
    3. "http://java.sun.com/dtd/web-app_2_3.dtd">  
    4.   
    5. <web-app>  
    6.   <display-name>My Application</display-name>  
    7.   <filter>  
    8.     <filter-name>struts2</filter-name>  
    9.     <filter-class>filters.StrutsRedirectFilter</filter-class>  
    10.   </filter>  
    11.   
    12.   <filter-mapping>  
    13.     <filter-name>struts2</filter-name>  
    14.     <url-pattern>/*</url-pattern>  
    15.   </filter-mapping>  
    16. </web-app>  

    And
    prev | 1 | 2 | next