출처 : http://blog.naver.com/innerlog?Redirect=Log&logNo=40184670892

참고 : https://www.lesstif.com/pages/viewpage.action?pageId=12451848

javax.net.ssl.SSLHandshakeException의 경우 통상적으로 유효한 SSL인증서가 없을때 발생한다.

내 경우에는 Spring 3.0에서 SimpleEmail을 이용한 메일발송시에 발생했는데

smtp.naver.com:465 를 사용하였는데 아무리 검색을 해봐도 인증서를 만들어야 된다던가 하는 답 뿐이었다.

방화벽 문제일 수 있다고 해서 확인해봤더니 방화벽은 꺼놓은 상태이고...

 

알고보니 바이러스 백신이 구동되고 있어서였다. 

 

아래 첨부파일은 jre에 유효하지 않은 인증서 등록하는 Class

InstallCert.java

 InstallcertJava.java

 

XStream : http://xstream.codehaus.org/download.html


XStream Maven

<dependency>
      <groupId>com.thoughtworks.xstream</groupId>
      <artifactId>xstream</artifactId>
      <version>1.4.4</version>
</dependency> 



Source

 package iwa.xml;

import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.util.AbstractMap;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;

import org.junit.Test;

import com.thoughtworks.xstream.XStream;
import com.thoughtworks.xstream.converters.Converter;
import com.thoughtworks.xstream.converters.MarshallingContext;
import com.thoughtworks.xstream.converters.UnmarshallingContext;
import com.thoughtworks.xstream.io.HierarchicalStreamReader;
import com.thoughtworks.xstream.io.HierarchicalStreamWriter;

public class MapConverterTest {

 @Test
 public void marshal() throws Exception {
  Map<String,Object> map = new HashMap<String,Object>();
        map.put("name","chris");
        map.put("island","faranga");
        Map<String,Object> map2 = new HashMap<String,Object>();
        map2.put("test", "테스트");
        map2.put("code", "1");
        map.put("tests", map2);
        Map<String,Object> map3 = new HashMap<String,Object>();
        map3.put("national", "korea");
        map3.put("dev", "kkk");
        map2.put("devList", map3);

        XStream x = new XStream();
        x.alias("root", Map.class);
        x.registerConverter(new MapEntryConverter());
       
        String xml = x.toXML(map);
        System.out.println(xml);
 }
 
 @Test
 public void unmarshal() throws Exception {
  String xml = "<root><tests><test>테스트</test><code>1</code><devList><dev>kkk</dev><national>korea</national></devList></tests><name>chris</name><island>faranga</island></root>";
  XStream x = new XStream();
  x.autodetectAnnotations(true);
  x.alias("root", HashMap.class);
  x.registerConverter(new MapEntryConverter());
  InputStream is = new ByteArrayInputStream(xml.getBytes("UTF-8"));
  HashMap<String, Object> o = (HashMap<String, Object>)(x.fromXML(is));
  System.out.println(o);
 }
 
 public static class MapEntryConverter implements Converter {
      
  public boolean canConvert(Class clazz) {
            return AbstractMap.class.isAssignableFrom(clazz);
        }

        public void marshal(Object value, HierarchicalStreamWriter writer, MarshallingContext context) {
            AbstractMap map = (AbstractMap) value;
            for (Object obj : map.entrySet()) {
                Entry entry = (Entry) obj;
                Object entryValue = entry.getValue();
               
                if(entryValue instanceof Map) {
                 writer.startNode(entry.getKey().toString());
                 marshal(entry.getValue(), writer, context);
                 writer.endNode();
                 continue;
                }
               
                writer.startNode(entry.getKey().toString());
                writer.setValue(entryValue.toString());
                writer.endNode();
            }
        }
        public Object unmarshal(HierarchicalStreamReader reader, UnmarshallingContext context) {
         Map<String, Object> map = new HashMap<String, Object>();

            while(reader.hasMoreChildren()) {
                reader.moveDown();
                if(reader.hasMoreChildren()) {
                 Map<String, Object> childMap = new HashMap<String, Object>();
                 map.put(reader.getNodeName(), childMap);
                 unmarshalHierarchical(reader, context, childMap);
                 reader.moveUp();
                 continue;
                }
                map.put(reader.getNodeName(), reader.getValue());
                reader.moveUp();
            }
            return map;
        }
       
        private void unmarshalHierarchical(HierarchicalStreamReader reader, UnmarshallingContext context, Map<String, Object> map) {
            while(reader.hasMoreChildren()) {
                reader.moveDown();
                if(reader.hasMoreChildren()) {
                 Map<String, Object> childMap = new HashMap<String, Object>();
                 map.put(reader.getNodeName(), childMap);
                 unmarshalHierarchical(reader, context, childMap);
                 reader.moveUp();
                 continue;
                }
                map.put(reader.getNodeName(), reader.getValue());
                reader.moveUp();
            }
        }
 }
 
}


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

package test;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.xml.bind.JAXBContext;
import javax.xml.bind.Marshaller;

import org.junit.Test;

import test.model.AppModel;

//@RunWith(SpringJUnit4ClassRunner.class)
//@ContextConfiguration(locations = { "classpath:../config/spring/egov/context-*.xml", "classpath:../config/spring/iwa/*.xml"})
public class TestXml {
 
 
 
 @Test
 public void test1() throws Exception {
  JAXBContext context = null;
  List<AppModel> list = null;
  Marshaller marshaller = null;
  
  context = JAXBContext.newInstance(AppModel.class);
  list = new ArrayList<AppModel>();
  AppModel app = new AppModel();
  app.setAppId("1");
  app.setAppNm("앱1");
  list.add(app);
  
  AppModel app2 = new AppModel();
  app2.setAppId("2");
  app2.setAppNm("앱2");
  list.add(app2);
  
  marshaller = context.createMarshaller();
  marshaller.setProperty(Marshaller.JAXB_ENCODING, "UTF-8");
  marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
  marshaller.marshal(app2, System.out);
 }
 
 
 @Test
 public void test2() throws Exception {
  Map<String,Object> userData = new HashMap<String,Object>();
  Map<String,String> nameStruct = new HashMap<String,String>();
  nameStruct.put("first", "Joe");
  nameStruct.put("last", "Sixpack");
  userData.put("name", nameStruct);
  userData.put("gender", "MALE");
  userData.put("verified", Boolean.FALSE);
  userData.put("userImage", "Rm9vYmFyIQ==");
  
  JAXBContext jc = JAXBContext.newInstance(Map.class);
  Marshaller marshaller = jc.createMarshaller();
  marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
  marshaller.marshal(userData, System.out);
 }
 
 
 
 
 
 /*
 private String rootNodeName = "itemList";
 
 @SuppressWarnings("unchecked")
 public List<Map<String, Object>> fromXML(String xmlData) throws Exception {
  XStream xStream = new XStream(new DomDriver("UTF-8"));
  Mapper mapper = xStream.getMapper();
  xStream.alias(rootNodeName, List.class);
  xStream.registerConverter(new MapConverter(mapper));
  return (List<Map<String, Object>>) xStream .fromXML(xmlData);
 }
 
 public String toXML(List<Map<String, Object>> mapList) {
  XStream xStream = new XStream(new DomDriver("UTF-8"));
  Mapper mapper = xStream.getMapper();
  xStream.alias(rootNodeName, List.class);
  xStream.registerConverter(new MapConverter(mapper));
  return xStream.toXML(mapList);
 }
 
 public String toXML(Map<String, Object> map) {
  XStream xStream = new XStream(new DomDriver("UTF-8"));
  Mapper mapper = xStream.getMapper();
  xStream.alias(rootNodeName, Map.class);
  xStream.registerConverter(new MapConverter(mapper));
  return xStream.toXML(map);
 }
 
 public static class MapConverter extends AbstractCollectionConverter implements Converter {
  *//**
   * Map 객체가 될 Node 명
   *//*
  private String nodeName = "itemInfo";

  public MapConverter(Mapper mapper) {
   super(mapper);
  }

  *//**
   * Converting 가능한 샘플인지 판단
   *//*
  @Override
  public boolean canConvert(Class type) {
   boolean flag = type.equals(java.util.ArrayList.class);
   return flag;
  }

  *//** Map을 XML로 변환하는 규칙 *//*
  @Override
  public void marshal(Object source, HierarchicalStreamWriter writer, MarshallingContext context) {
   List<Map<String, Object>> list = (List<Map<String, Object>>) source;
   for(int inx=0; inx<list.size(); inx++) {
    Map<String, Object> data = list.get(inx);
    writer.startNode(nodeName);
    for (Object obj : data.entrySet()) {
     Entry<String, Object> ety = (Entry<String, Object>)obj;
     writer.startNode(ety.getKey().toString());
     writer.setValue(ety.getValue().toString());
     writer.endNode();
    }
    writer.endNode();
   }
  }

  *//** XML을 List<Map>으로 변환하는 규칙 *//*
  @Override
  public Object unmarshal(HierarchicalStreamReader reader, UnmarshallingContext context) {
   List<Map<String, Object>> resultList = new ArrayList<Map<String, Object>>();
   Map<String, Object> element = null;
   for (; reader.hasMoreChildren(); reader.moveUp()) {
    reader.moveDown();
    element = new HashMap<String, Object>();
    for (; reader.hasMoreChildren(); reader.moveUp()) {
     reader.moveDown();
     String tempValue = reader.getValue();
     String tempKey = reader.getNodeName();
     
     if (tempValue != null) {
      tempValue = tempValue.trim().replaceAll("\n", "");
     }
     element.put(tempKey, tempValue);
    }
    resultList.add(element);
   } 
   return resultList;
  }
  
 }
 */
}




 

참고 : http://blog.naver.com/PostView.nhn?blogId=ugigi&logNo=70058661623
         http://blog.naver.com/xxrcn11/20135603375
         http://blog.daum.net/wetet/1813

CryptTest.java

 package iwa.crypt;

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.PrivateKey;
import java.security.PublicKey;

import javax.crypto.Cipher;
import javax.crypto.CipherOutputStream;

public class CryptTest {

 public static final int bufSize = 1024;

 // 파일 암호화

 public void encryptFile(String in, String out) throws Exception {
  Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
  ObjectInputStream ois = new ObjectInputStream(new FileInputStream("PublicKey.ser"));
  PublicKey publicKey = (PublicKey) ois.readObject();
  ois.close();
  cipher.init(Cipher.ENCRYPT_MODE, publicKey);
  FileInputStream fis = new FileInputStream(in);
  FileOutputStream fos = new FileOutputStream(out);
  CipherOutputStream cos = new CipherOutputStream(fos, cipher);
  byte[] buffer = new byte[bufSize];
  int length;
  while ((length = fis.read(buffer)) != -1)
   cos.write(buffer, 0, length);
  fis.close();
  fos.close();
 }

 // 파일 복호화
 public void decryptFile(String in, String out) throws Exception {
  Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
  ObjectInputStream ois = new ObjectInputStream(new FileInputStream("PrivateKey.ser"));
  PrivateKey privateKey = (PrivateKey) ois.readObject();
  ois.close();
  cipher.init(Cipher.DECRYPT_MODE, privateKey);
  FileInputStream fis = new FileInputStream(in);
  FileOutputStream fos = new FileOutputStream(out);
  CipherOutputStream cos = new CipherOutputStream(fos, cipher);
  byte[] buffer = new byte[bufSize];
  int length;
  while ((length = fis.read(buffer)) != -1)
   cos.write(buffer, 0, length);
  fis.close();
  fos.close();
 }

 // 키 생성
 public void genKey() throws Exception {
  KeyPairGenerator key = KeyPairGenerator.getInstance("RSA");
  key.initialize(1024);
  KeyPair kp = key.genKeyPair();
  PrivateKey privateKey = kp.getPrivate();
  PublicKey publicKey = kp.getPublic();
  ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("PrivateKey.ser"));
  out.writeObject(privateKey);
  out.close();
  out = new ObjectOutputStream(new FileOutputStream("PublicKey.ser"));
  out.writeObject(publicKey);
  out.close();
 }

 public static void main(String[] args) {
  CryptTest c = new CryptTest();
  try {
   // 키 생성
   c.genKey();
   // 파일 암호화
   c.encryptFile("a.txt", "b.txt");
   // 파일 복호화
   c.decryptFile("b.txt", "c.txt");
  } catch (Exception e) {
   e.printStackTrace();
  }
 }

}


출처 : http://likebnb.tistory.com/97
참고 : http://helloworld.naver.com/helloworld/197937

최근에 자바 애플릿을 만들 일이 있었다.
프로그램을 열심히 작성하고 에러 없이 컴파일까지 완료하였다.
그런데 JAR로 압축하여 웹서버로 배포하여 테스트를 하는데 다음과 같이 에러를 내뿜고 동작하질 않았다.

원인은 아래 그림의 Caused by로 시작되는 줄에 나타난 것 처럼 인증되지 않는 JAR의 실행이 인증예외를 발생시킨 탓이다.
그도 그럴 것이 Java Applet은 로컬 PC로 다운로드 되어 실행되는 것으로 로컬 PC의 자원에 대한 접근이 가능하기 때문에
이를 아무런 제약 없이 실행하게 둘 수 없다는 보안 규칙 때문이다.

java.security.cert.CertificateException: Certificate has been denied at...





 

그렇다면 결론은? 그렇다. 개발된 JAR를 보안 인증서로 서명하여 배포하면 된다.

그래서 오늘 함께 알아 볼 내용은 개발 및 테스트를 위한 과정에서 임시 인증서를 이용하여 테스트를 위한 서명된 JAR를 만들어 보는 
것이다. 이를 위해 JAVA 개발킷에 함께 딸려 온 keytool과 jarsigner라는 유틸리티가 필요하다.



1. 제일 먼저 키저장소를 새로 생성한다.

keytool -genkey -keystore likebnb.keystore -alias likebnb







2. 생성된 키저장소를 자가인증(self certificate)한다.

keytool -selfcert -alias likebnb -keystore likebnb.keystore






3. 인증된 키저장소를 확인한다.

 keytool -list -keystore likebnb.keystore







4. 키저장소를 이용하여 JAR에 서명을 한다.

 jarsigner -keystore likebnb.keystore test.jar likebnb






5. 서명된 JAR와 그렇지 않은 원본 JAR는 다음과 같이 파일의 크기가 다름을 알 수 있다.





이상과 같이 JAR를 인증서로 서명하여 웹에서 사용할 수 있도록 하는 방법을 알아 보았다. 추가로 ant 등을 이용하여 컴파일을 하기
위해서는 아래 구문과 같이 build.xml 파일을 수정해 주어야 한다.

  <target name="signjar">
    <signjar alias="likebnb" jar="build/jars/test.jar"
     keystore="../likebnb.keystore" storepass="my.password" />
    <delete dir="build/classes"/>
  </target>



이상의 방법은 어디까지나 테스트를 목적으로 하는 임시 인증서 및 서명이므로 실제로 배포할 때에는 공인인증기관에서 발급 받은
인증서를 가지고 서명해야 하는 것은 두말할 것 없는 일이다. 어쨌든 개발하고 있는 애플릿을 테스트 해보기 위해선 알아두면 좋겠다.


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


출처 : http://kdarkdev.tistory.com/238

// http://docs.oracle.com/cd/E19900-01/820-0849/ablra/index.html
// key 생성, 확인, jar파일에 사인하기 예제
// 옵션설명 ->
/*
 - genkey : 키를 생성한다
 - alias : 키저장소 별칭
 - keyalg : 암호화 알고리즘 방식 (아래는 RSA암호화 방식의 공개키쌍 생성)
 - keystore : 키의 저장파일 (해당경로로 key가 생성된다)
 - storetype : 키저장소 방식, 기본으로 제공되는 JKS가 있고 JCEKS라는 저장소도 있다 JCEKS는 3DES방식을 적용하기때문에 좀더 안전하다고 한다.
 - validity : 유효기간. 아래는 100년으로 설정
 - dname : 추가정보 입력
 -
*/
// KEY 생성
keytool -genkey -alias testkeyname -keyalg RSA -keystore d:/signkeystore.ks -storetype JCEKS -validity 36500  -dname "cn=test, ou=test, o=test, c=KR" -keypass 123456 -storepass 123456

//KEY 삭제
keytool -delete  -alias testkeyname -storetype JCEKS -keystore d:/signkeystore.ks -storepass 123456

//KEY List확인
keytool -list -v -keystore d:/signkeystore.ks -storepass 123456 -storetype JCEKS

//JAR sign
jarsigner -keystore d:/signkeystore.ks -storetype JCEKS -storepass 123456 -keypass 123456 d:/applet.jar testkeyname 


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


출처 : http://mesque.tistory.com/16

http://blog.ejbca.org/2008/02/converting-keystores-between-jks-and.html 

JKS 타입은 안드로이드 마켓등록에 사용 되는 인증서 타입

keytool 의 경로는 일반적으로 C:\Program Files\Java\jdk\bin 이다. 

JKSP12
keytool -importkeystore -srckeystore JKS인증서 -srcstoretype JKS -deststoretype PKCS12
 -destkeystore P12인증서 

P12JKS
keytool -importkeystore -srckeystore P12인증서 -srcstoretype PKCS12 -deststoretype JKS -destkeystore JKS인증서  

JKS인증서 ( ex> D:\keystore, D:\keystore.jks ) 
P12인증서 ( ex> D:\keystore.p12 ) 

p.s : 프로그램 파일에서 destkeystore를 생성할 경우 오류가 발생 할 수 있으므로,

D:\keystore.p12 등으로 출력 경로를 한다


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

출처 : http://www.sysnet.pe.kr/Default.aspx?mode=2&sub=0&detail=1&pageno=0&wid=1262&rssMode=1&wtype=0


.keystore 파일에 저장된 개인키 추출방법과 인증기관으로부터 온 공개키를 합친 pfx 파일 만드는 방법

(제목 참 길군요. ^^)

2년 전에 아래와 같은 일이 있었습니다.

JKS(Java Key Store)에 저장된 인증서를 ActiveX 코드 서명에 사용하는 방법
; http://www.sysnet.pe.kr/2/0/882


그런데, 이제 그 인증서가 만료가 되었고 마침 Verisign 측에서의 키관리 정책 변경(2048bit)으로 인해 기존 .key 파일을 사용할 수 없어 사내에서 인증서 담당하시는 분이 새롭게 키를 생성해서 발급을 받았습니다.

문제는, 지난 번과 같이 협업을 하려고 했는데, 해당 방법을 설명한 웹 문서가 없어져 버린 것입니다.

Convert the Java JKS key-store to Microsoft PFX format
; http://www.crionics.com/products/opensource/faq/signFree.htm


그래서, 일단 자바의 ".keystore" 파일을 다음과 같은 이야기와 함께 통째로 저한테 보내주었습니다.

  1. 회사정보를 바탕으로 keystore 파일 생성
  2. keystore 파일로부터 제가 보내드린 csr 생성
  3. verisign으로부터 받은 cer을 keystore 파일에 반영


자... 그럼 위의 이야기를 길게 풀어써보겠습니다.

1번 단계에서 생성된 keystore 안에는 개인키/공개키가 함께 담겨 있습니다. 단지 그 누구도 알아주지 않는 키 정보라는 것만 차이가 있을 뿐 PKI 암호화에는 장애없이 사용할 수 있습니다. 문제는, 제가 배포하는 공개키가 실제로 저한테서 왔다는 것을 다른 사람들이 어떻게 신뢰할 수 있을까 하는 점입니다. 누구나 인증서를 만들때 "회사정보"는 임의로 만들 수 있기 때문에 그 부분은 아무런 의미가 없습니다.

이런 문제를 해결하기 위해 "인증기관"이 있는 것입니다. 우리는 그 인증기관에게 위의 2번 단계를 거쳐서 우리가 가진 "공개키"를 보내게 됩니다. 참고로, 이 과정에서 '개인키'를 보내는 것이 아닙니다. 인증 기관조차도 우리의 개인키가 어떤 건지는 알아선/유출되어선 안됩니다.

마지막으로 3번 단계를 거쳐서 "인증기관"은 자신들의 개인키로 우리의 공개키를 '서명'하고 그 서명된 '공개키 파일' (보통은 Base64 인코딩된 텍스트)을 보내줍니다. Verisign 의 경우 이 파일은 다음과 같은 형식으로 된 텍스트 내용을 메일로 전달해 줍니다.

-----BEGIN CERTIFICATE-----
MIIE4zCCA8ugAwIBAgIQEJ8dqq+4MxWmtkpu7YLYFjANBgkqhkiG9w0BAQUFADCB
...[생략]...
lZ5gwQ3kd61SRXy6I9uXU79fteLDHxNhmqynIKLCh9vg2Rwp9diGLiA0dtEmpJIv
/cX9tj7/6mEVgkha9/KCCcS7Ez7QygYxbepftABY+UtSJF3q+N1Rc8wYlVhw9jiM
c+yBNWmdiQ==
-----END CERTIFICATE-----


즉, 3번 단계의 "받은 cer" 파일이 의미하는 것이 바로 위의 "BEGIN/END CERTIFICATE" 입니다. 이렇게 받은 공개키 인증서 정보를 .keystore 파일에 반영하면 이제서야 제대로 된 개인키/공개키를 가지게 되는 것입니다.

엄밀히, ActiveX 나 Applet 의 경우 '응용 프로그램 서명'작업을 거치는 것은 '공개키'와는 무관합니다. 왜냐하면, '서명'작업은 개인키로 하기 때문입니다. 즉, 굳이 Verisign과 같은 인증기관의 개입없이도 1번 단계에 생성한 개인키만으로도 ActiveX 나 Applet 의 서명이 가능합니다.

"서명되어 생성된 Signature" 는 '공개키'로만 유일하게 검증(Verification)을 거칠 수 있습니다. 그래서 편의상 ActiveX/Applet DLL 파일내에 '공개키'를 'signature'와 함께 포함시켜서 배포를 하는데 이렇게 해서 최종 생성된 파일이야 말로 "서명된 파일"이 되는 것입니다. 인증기관이 필요한 유일한 이유는, 포함된 공개키가 실제 그 '회사 정보로 생성된 공개키'인지를 확인하는 데 필요한 것 뿐입니다.




여기까지 이해를 하셨으면, .keystore 파일에 우리가 원하는 '개인키'가 있음을 알 수 있습니다. 그리고 저한테는 지금 동료 개발자가 보내준 ".keystore" 파일이 있으니 keytool.exe 를 잘 사용하면 문제를 해결할 수 있을 것 같습니다. 검색해 보니 다행히 아래와 같이 답이 나옵니다.

How do I list / export private keys from a keystore?
; http://stackoverflow.com/questions/150167/how-do-i-list-export-private-keys-from-a-keystore


명령어 실행 형식은 다음과 같습니다.

keytool.exe -importkeystore -srcstoretype [Keystore 형식] -srckeystore [Keystore 경로] -deststoretype [개인키 파일 인코딩 형식] -destkeystore [개인키 담을 파일 경로]


인자중에 하나로 쓰이는 "Source Keystore 형식(-srcstoretype)"을 어떻게 알 수 있을까요?

지난 번 글에서 설명한 데로 직접 .keystore 파일에 대고 다음과 같이 -list 명령어를 내려보면 알 수 있습니다.

* .keystore 파일이 D:\settings 폴더에 있는 상황.
* [keystore암호]는 해당 ".keystore" 파일을 생성한 담당자에게 물어보면 알 수 있습니다.

C:\temp>keytool -list -storepass [keystore암호] -keystore d:\settings\.keystore
Keystore 유형: JKS
Keystore 공급자: SUN

Keystore에는 1 항목이 포함되어 있습니다.

jennifersoft, 2012. 3. 7, PrivateKeyEntry,
인증서 지문(MD5): 0F:8D:26:B3:DE:47:63:D2:89:74:63:45:B2:1F:55:54


그럼, 제 경우에 이런 식으로 명령어를 내리면 되겠군요. ^^

C:\temp>keytool.exe -importkeystore -srcstoretype JKS -srckeystore d:\settings\.keystore -deststoretype PKCS12 -destkeystore d:\settings\keys.pk12.der
대상 키 저장소 암호 입력:      <-- 새로 생성되는 keys.pk12.der 파일에 대한 암호 입력
새 암호를 다시 입력하십시오:   <-- 확인
소스 키 저장소 암호 입력:      <-- 이전 .keystore 에 접근하는 암호 입력
별칭 jennifersoft에 대한 항목을 성공적으로 가져왔습니다.
가져오기 명령 완료:  1개 항목을 성공적으로 가져왔습니다. 0개 항목은 실패했거나
취소되었습니다.


이렇게 생성된 der 파일을 openssl.exe 도구를 사용해서 pem 파일로 변경해 줄 수 있습니다. openssl 은 다음의 사이트에서 소스 코드를 구할 수 있지만,

openssl
; http://www.openssl.org/source/


바이너리 배포는 하지 않으므로 빌드된 exe 파일은 다음의 사이트에서 구할 수 있습니다.

Win32 OpenSSL
; http://www.slproweb.com/products/Win32OpenSSL.html

Win32 OpenSSL v1.0.0g Light
; http://www.slproweb.com/download/Win32OpenSSL_Light-1_0_0g.exe


그래서, 이렇게 명령어를 내려주면 pem 파일을 얻을 수 있습니다.

C:\temp>openssl.exe pkcs12 -in c:\temp\keys.pk12.der -nodes -out c:\temp\private.rsa.pem
WARNING: can't open config file: C::\temp\openssl.cfg
Enter Import Password:  <-- keytool.exe 에서 입력했던 "대상 키 저장소 암호"를 입력
MAC verified OK


생성된 private.rsa.pem 파일을 보면 "---BEGIN PRIVATE KEY--- / ---END PRIVATE KEY---" 쌍의 텍스트를 확인할 수 있습니다. 바로 우리가 그토록 원했던 '개인키'가 있다는 것입니다. ^^ 또한 원본이었던 ".keystore" 파일에 자바 개발자가 Verisign 의 서명을 받은 인증서를 반영해 두었기 때문에 pem 파일내에 보면 우리의 공개키 뿐만 아니라 verisign 측의 공개키도 함께 있는 "BEGIN/END CERTIFICATE" 쌍을 볼 수 있습니다.

그런데, 이제부터의 단계가 좀 애매합니다. private/public key를 모두 가지고 있기 때문에 pfx 파일로 바로 변환할 수 있을 것 같은데, 이 방법을 잘 모르겠습니다. 또한 pem 파일은 윈도우 인증서 관리자에서 직접 import 를 지원하지 않습니다. 어떻게 해서든지 pfx 로 변환해야 하는데요. 음... 잘 모르겠습니다. 예전 방법을 써야지. ^^




이전에 해본 대로 pem 파일에서 private 키만을 담은 pvk 파일을 가져올 수 있습니다.

pem-key-file 을 pvk-file 로 변환하는 것은 다음의 pvk.exe 를 사용하시면 됩니다.

PVK file information.
; http://www.drh-consultancy.demon.co.uk/pvk.html

Win32 binary
; http://www.drh-consultancy.demon.co.uk/pvktool.zip

소스 코드
; http://www.drh-consultancy.demon.co.uk/pvksrc.tgz.bin


위의 pvk.exe 를 이용해서 다음과 같이 pem 파일을 pvk 파일로 변환할 수 있습니다.

C:\temp>d:\tools\cert\pvk.exe -in c:\temp\private.rsa.pem -topvk -strong -out c:\temp\private.key
Enter Password:             <-- private.key 파일을 보호할 암호 입력
Verifying - Enter Password: <-- 암호 입력 확인


이렇게 개인키만 소지한 파일을 만들었으니, 이제 verisign의 서명을 받은 우리의 공개키 파일이 필요한데요. 이것 역시 .keystore 에서 구할 수 있습니다. (아니면 아마도 private.rsa.pem 파일에서 얻는 방법도 있을 것입니다.)

하지만 그럴 필요없이, Verisign 측에서 보낸 메일에 보면 "BEGIN CERTIFICATE / END CERTIFICATE" 로 둘러쌓인 텍스트를 그냥 cer 파일로 저장해도 됩니다.

[예제 test.cer]

-----BEGIN CERTIFICATE-----
MIIE4zCCA8ugAwIBAgIQEJ8dqq+4MxWmtkpu7YLYFjANBgkqhkiG9w0BAQUFADCB
...[생략]...
lZ5gwQ3kd61SRXy6I9uXU79fteLDHxNhmqynIKLCh9vg2Rwp9diGLiA0dtEmpJIv
/cX9tj7/6mEVgkha9/KCCcS7Ez7QygYxbepftABY+UtSJF3q+N1Rc8wYlVhw9jiM
c+yBNWmdiQ==
-----END CERTIFICATE-----


이렇게 개인키/공개키를 구했으니 모든 준비작업은 끝났습니다. "인증서 관련(CER, PVK, SPC, PFX) 파일 만드는 방법"에서 설명한 데로 따르면 됩니다. 그리하여 cert2spc 를 이용해서 spc 파일을 만들고,

c:\temp>cert2spc.exe c:\temp\test.cer c:\temp\test.spc
Succeeded


마지막으로 pvkimprt.exe 도구를 이용해서 spc 파일과 key 정보로부터 pfx 파일로 만들 수 있습니다. 그래서, 다음과 같이 명령을 내리면,

c:\temp>pvkimprt.exe -pfx c:\temp\test.spc c:\temp\private.key


암호를 묻는 창이 나옵니다.

jks_to_pfx_1.png

pvk.exe 를 이용하여 private.key 를 만들 때 입력했던 암호를 넣고 계속하면 이어서 본격적인 '인증서 가져오기' 마법사 단계로 넘어갑니다.

jks_to_pfx_2.png

확인을 누르면, 아래 화면 처럼 개인키를 내보낼 수 있는 유형으로 보관할 지 결정합니다. (이것은 회사 정책에 따라 달라질 수 있지만, 여기서는 편의상 "yes"를 선택하겠습니다.) 이에 대한 차이는 "인증서 관리 - 내보내기/가져오기" 글을 참고하세요.

jks_to_pfx_3.png

그 다음은 기본값으로 두고 진행합니다.

jks_to_pfx_4.png

이제 새롭게 생성될 pfx 파일에 '개인키'를 가지게 되므로 이를 보호하기 위해 암호를 다시 입력합니다. (이전과 다른 새로운 암호를 입력해도 됩니다.)

jks_to_pfx_5.png

확인을 누르면 pfx 파일을 저장할 파일명을 지정할 수 있고,

jks_to_pfx_6.png

마지막으로 정보를 확인하고 "Finish" 버튼을 누르면 정상적으로 pfx 파일이 생성됩니다.

휴~~~ 끝입니다. 친근한 pfx 파일이 생성되었으니, 이제 뭐든 ^^ 원하는 데로 작업을 하시면 됩니다.

* apache httpclient 4.4 이상 버전

import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.impl.client.HttpClients;
import javax.net.ssl.SSLContext;
import org.apache.http.ssl.SSLContexts;
import org.apache.http.ssl.TrustStrategy;
import java.security.cert.X509Certificate;
import java.security.cert.CertificateException;
import org.apache.http.conn.ssl.NoopHostnameVerifier;
import org.apache.http.impl.client.CloseableHttpClient;

HttpClientBuilder httpClientBuilder = HttpClients.custom();

SSLContext sslcontext = SSLContexts.custom()
    .useProtocol("SSL")
// .loadTrustMaterial(null, new TrustSelfSignedStrategy())
    .loadTrustMaterial(null, new TrustStrategy() {
        @Override
        public boolean isTrusted(X509Certificate[] paramArrayOfX509Certificate, String paramString) throws CertificateException {
            return true;
        }
    }).build();

httpClientBuilder.setSSLHostnameVerifier(new NoopHostnameVerifier()).setSSLContext(sslcontext);

CloseableHttpClient httpClient = httpClientBuilder.build();
httpClient.execute();



* apache httpclient 4.3 이하 버전

import javax.net.ssl.SSLContext;
import org.apache.http.conn.ssl.SSLContexts;
import org.apache.http.conn.ssl.TrustSelfSignedStrategy;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;

SSLContext sslcontext = SSLContexts.custom()
    .useSSL()
    .loadTrustMaterial(null, new TrustSelfSignedStrategy())
/*
    .loadTrustMaterial(null, new TrustStrategy() {
        @Override
        public boolean isTrusted(java.security.cert.X509Certificate[] paramArrayOfX509Certificate, String paramString) throws java.security.cert.CertificateException {
            return true;
        }
    })
*/
    .build();

SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(sslcontext, SSLConnectionSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);

CloseableHttpClient httpClient = HttpClients.custom()
    .setSSLSocketFactory(sslsf)
    .build();

httpClient.execute();




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


출처 : http://comphy.iptime.org/user/wordpress/?p=81


Apache Commons HttpClient는 JDK 1.4부터 등장한 Java Secure Socket Extension (JSSE)를 기반으로 SSL (또는 TLS) 상의 HTTP (HTTP/S) 통신에 대한 지원을 제공한다. Commons HttpClient를 이용한 HTTP/S 통신 방법을 살펴보자.

1. Commons HttpClient 사용하기
일반적으로 Commons HttpClient의 HTTP 통신은 아래와 같다.

import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.HttpStatus;
import org.apache.commons.httpclient.methods.GetMethod;
// import org.apache.commons.httpclient.methods.PostMethod;

public class HttpClientSample {

    public static void main(String[] args) {

        HttpClient httpclient = new HttpClient();
        GetMethod httpget = new GetMethod("http://www.java2go.net/");
        // PostMethod httppost = new 
        // PostMethod("https://www.java2go.net/nopage.html");

        try {
            int statusCode = httpclient.executeMethod(httpget);

            System.out.println("Response Status Code: " + statusCode);
            System.out.println("Response Status Line: " + httpget.getStatusLine());
            System.out.println("Response Body: \n" 
                    + httpget.getResponseBodyAsString());

            if (statusCode == HttpStatus.SC_OK) {
                // if (statusCode >= 200 && statusCode < 300) {
                System.out.println("Success!");
            } else {
                System.out.println("Fail!");
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            httpget.releaseConnection();
        }
    }
}


정상적인 경우 결과는 아래와 같다.

Response Status Code: 200
Response Status Line: HTTP/1.1 200 OK
Response Body: 
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" 
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>Java2go.net</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />

... 생략 ...

</body>
</html>
Success!


실패한 경우 결과는 아래와 같다.

Response Status Code: 404
Response Status Line: HTTP/1.1 404 Not Found
Response Body: 
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">
<HTML><HEAD>
<TITLE>404 Not Found</TITLE>
</HEAD><BODY>
<H1>Not Found</H1>
The requested URL /nopage.html was not found on this server.<P>
<HR>
<ADDRESS>Apache/1.3.37p3 Server at java2go.net Port 80</ADDRESS>
</BODY></HTML>

Fail!


2. SSL 통신과 Trusted CA 인증서 등록하기
JSSE가 올바르게 설치되었다면, 기본적으로 HTTP/S 통신도 일반 HTTP 통신과 같이 위와 같은  코드를 그대로 사용할 수 있다. 단, 이 경우에 서버 싸이트 인증서가 클라이언트쪽에 신뢰하는 인증서로서 인식될 수 있어야 한다. 그렇지 않으면 아래와 같은 SSL handshake 오류가 발생한다.

javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: 
No trusted certificate found
at com.sun.net.ssl.internal.ssl.BaseSSLSocketImpl.a(DashoA12275)
at com.sun.net.ssl.internal.ssl.SSLSocketImpl.a(DashoA12275)
at com.sun.net.ssl.internal.ssl.SSLSocketImpl.a(DashoA12275)
at com.sun.net.ssl.internal.ssl.SunJSSE_az.a(DashoA12275)
at com.sun.net.ssl.internal.ssl.SunJSSE_az.a(DashoA12275)
at com.sun.net.ssl.internal.ssl.SunJSSE_ax.a(DashoA12275)
at com.sun.net.ssl.internal.ssl.SSLSocketImpl.a(DashoA12275)
at com.sun.net.ssl.internal.ssl.SSLSocketImpl.j(DashoA12275)
at com.sun.net.ssl.internal.ssl.SSLSocketImpl.a(DashoA12275)
at com.sun.net.ssl.internal.ssl.AppOutputStream.write(DashoA12275)
... 생략 ...
Caused by: sun.security.validator.ValidatorException: No trusted certificate found
at sun.security.validator.SimpleValidator.buildTrustedChain(SimpleValidator.java:304)
at sun.security.validator.SimpleValidator.engineValidate(SimpleValidator.java:107)
at sun.security.validator.Validator.validate(Validator.java:202)
at com.sun.net.ssl.internal.ssl.X509TrustManagerImpl.checkServerTrusted(DashoA12275)
at com.sun.net.ssl.internal.ssl.JsseX509TrustManager.checkServerTrusted(DashoA12275)
... 17 more


JDK에 의해 제공되어지는 Java Standard Trust Keystore는 ${JAVA_HOME}/jre/lib/security/cacerts에 위치한다. 이 cacerts 키스토어 파일에 대상 서버의 SSL 싸이트 인증서를 발행한 기관의 CA 인증서가 신뢰하는 인증서로 등록되어 있어야 한다. 다음과 같이 keytool.exe를 사용하여 키스토어에 등록된 신뢰하는 인증서 목록을 조회할 수 있다.

C:\jdk1.4.2\jre\lib\security>keytool -list -v -keystore cacerts
Enter keystore password: changeit

Keystore type: jks
Keystore provider: SUN

Your keystore contains 52 entries

Alias name: verisignclass3g2ca
Creation date: Jun 16, 2004
Entry type: trustedCertEntry

Owner: OU=VeriSign Trust Network, OU="(c) 1998 VeriSign, Inc. - For authorized
use only", OU=Class 3 Public Primary Certification Authority - G2, O="VeriSign,
Inc.", C=US
Issuer: OU=VeriSign Trust Network, OU="(c) 1998 VeriSign, Inc. - For authorized
use only", OU=Class 3 Public Primary Certification Authority - G2, O="VeriSign,
Inc.", C=US
Serial number: 7dd9fe07cfa81eb7107967fba78934c6
Valid from: Mon May 18 09:00:00 KST 1998 until: Wed Aug 02 08:59:59 KST 2028
Certificate fingerprints:
MD5: A2:33:9B:4C:74:78:73:D4:6C:E7:C1:F3:8D:CB:5C:E9
SHA1: 85:37:1C:A6:E5:50:14:3D:CE:28:03:47:1B:DE:3A:09:E8:F8:77:0F


*******************************************
*******************************************


Alias name: entrustclientca
Creation date: Jan 10, 2003
Entry type: trustedCertEntry

Owner: CN=Entrust.net Client Certification Authority, OU=(c) 1999 Entrust.net
Limited, OU=www.entrust.net/Client_CA_Info/CPS incorp. by ref. limits liab.,
O=Entrust.net, C=US
Issuer: CN=Entrust.net Client Certification Authority, OU=(c) 1999 Entrust.net
Limited, OU=www.entrust.net/Client_CA_Info/CPS incorp. by ref. limits liab.,
O=Entrust.net, C=US
Serial number: 380391ee
Valid from: Wed Oct 13 04:24:30 KST 1999 until: Sun Oct 13 04:54:30 KST 2019
Certificate fingerprints:
MD5: 0C:41:2F:13:5B:A0:54:F5:96:66:2D:7E:CD:0E:03:F4
SHA1: DA:79:C1:71:11:50:C2:34:39:AA:2B:0B:0C:62:FD:55:B2:F9:F5:80

... 생략 ...


다음과 같은 방법으로 키스토어 파일에 Trusted CA 인증서를 추가로 등록할 수 있다. CA 인증서는 웹브라우저에서 열쇠모양의 아이콘을 누르면 해당 싸이트 인증서를 볼 수 있고, 거기에서 인증서를 복사할 수 있다. 아래 예시는 Trusted CA 인증서를 ${JAVA_HOME}\jre\lib\secutiry\cacerts에 등록을 하는 방법이다.

C:\j2sdk1.4.2\jre\lib\security>keytool -import -keystore cacerts -file 
c:\certs\TradeSignCA.cer -alias tradesignca
Enter keystore password:  changeit
Owner: CN=TradeSignCA, OU=AccreditedCA, O=TradeSign, C=KR
Issuer: CN=KISA RootCA 1, OU=Korea Certification Authority Central, O=KISA, C=KR
Serial number: 2764
Valid from: Tue Nov 15 11:14:59 KST 2005 until: Sun Nov 15 11:14:59 KST 2015
Certificate fingerprints:
         MD5:  C2:E0:27:3D:36:4B:86:29:74:4D:6B:9F:5A:B5:01:26
         SHA1: A0:CD:6A:6D:A4:7B:73:15:F5:8A:CB:1F:C6:FD:C2:14:C9:3B:5D:BE
Trust this certificate? [no]:  y
Certificate was added to keystore


이렇게 서버 CA 인증서가 신뢰하는 인증서로 등록이 되면, 일반 HTTP 통신과 같이 URL이 https://인 주소로 SSL 통신을 정상적으로 할 수 있다. 키스토어 파일에서 인증서를 제거하는 방법은 아래와 같다.

C:\jdk1.4.2\jre\lib\security>keytool -delete -keystore cacerts -alias tradesignca
Enter keystore password:  changeit


아래처럼 서버 싸이트 인증서를 바로 등록할 수도 있다. 그러나 싸이트 인증서는 보통 Trusted CA 인증서보다 유효기간이 짧아 매번 갱신을 해줘야 할 것이다.

C:\jdk1.4.2\jre\lib\security>keytool -import -keystore cacerts -file
c:\certs\www.java2go.net.cer -alias mykey
Enter keystore password:  changeit
Owner: CN=www.java2go.net, OU=KTNET, OU=AccreditedCA, O=TradeSign, C=KR
Issuer: CN=TradeSignCA, OU=AccreditedCA, O=TradeSign, C=KR
Serial number: 596e9cf0
Valid from: Tue May 12 13:37:20 KST 2009 until: Wed May 12 14:07:20 KST 2010
Certificate fingerprints:
         MD5:  EF:EB:11:66:BD:CC:B1:D4:88:35:AB:25:9F:2F:79:8B
         SHA1: DC:C4:31:20:46:25:72:68:8B:96:AC:92:EE:F3:8D:15:EF:A7:46:2D
Trust this certificate? [no]:  y
Certificate was added to keystore


3. Commons HttpClient의 SSL 커스터마이징
기본적인 사용법 이외에 자기서명(self-signed)되었거나 또는 신뢰되지 않은(untrusted) SSL 인증서를 사용하는 경우처럼 SSL 통신을 커스터마이징할 필요가 있을 수 있다.

기본 커스터마이징 방법은 org.apache.commons.httpclient.protocol.SecureProtocolSocketFactory을 구현해서 org.apache.commons.httpclient.protocol.Protocol를 생성하여 등록해주면 된다. 다음과 같은 코드 한 줄을 추가해 주면 된다. 자세한 내용은 이곳을 참조한다.

Protocol.registerProtocol("https", 
new Protocol("https", new MySSLSocketFactory(), 443));


Commons HttpClient의 contribution 패키지에서 사용할 수 있는 EasySSLProtocolSocketFactory를 사용하면 신뢰되지 않은 자기서명(self-signed)된 인증서를 가진 서버와도 바로 SSL 통신을 할 수 있다. 즉, cacerts 키스토어에 서버 인증서를 별도로 등록할 필요가 없다. 다음과 같이 사용할 수 있다.

import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.HttpStatus;
import org.apache.commons.httpclient.contrib.ssl.EasySSLProtocolSocketFactory;
import org.apache.commons.httpclient.methods.GetMethod;
import org.apache.commons.httpclient.protocol.Protocol;

public class HttpClientSample2 {

    public static void main(String[] args) {

        HttpClient httpclient = new HttpClient();
        GetMethod httpget = new GetMethod("https://www.java2go.net/");

        try {
            Protocol.registerProtocol("https", new Protocol("https",
                    new EasySSLProtocolSocketFactory(), 443));

            int statusCode = httpclient.executeMethod(httpget);

            System.out.println("Response Status Code: " + statusCode);
            System.out.println("Response Status Line: " + httpget.getStatusLine());
            System.out.println("Response Body: \n"
                    + httpget.getResponseBodyAsString());

            if (statusCode == HttpStatus.SC_OK) {
                System.out.println("Success!");
            } else {
                System.out.println("Fail!");
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            httpget.releaseConnection();
        }
    }
}


호출 로그

{DEBUG} [2009-06-18 23:29:31,062] <org.apache.commons.httpclient.HttpConnection> ()
 : Open connection to www.java2go.net:443


참조: http://hc.apache.org/httpclient-3.x/sslguide.html


JCaptcha

다운로드 : http://sourceforge.net/projects/jcaptcha/

참고 : http://blog.kgom.kr/52
         http://blog.naver.com/tyboss?Redirect=Log&logNo=70021305170&from=postView
         https://jcaptcha.atlassian.net/wiki/display/general/JCaptcha+and+the+SpringFramework


다운로드 한 jcaptcha-1.0-all.jar 를 프로젝트에 포함시킨다.

CaptchaController.java

CaptchaService.java

CaptchaServiceSingleton.java

ImageCaptchaEngine.java

ImageCaptchaServlet.java

index.jsp




1. Servlet 으로 설정


ImageCaptchaEngine.java (커스터마이징 CaptchaEngine)

package com.web.common.captcha;

import java.awt.Font;

import com.octo.captcha.component.image.backgroundgenerator.BackgroundGenerator;
import com.octo.captcha.component.image.backgroundgenerator.FunkyBackgroundGenerator;
import com.octo.captcha.component.image.color.RandomRangeColorGenerator;
import com.octo.captcha.component.image.fontgenerator.FontGenerator;
import com.octo.captcha.component.image.fontgenerator.RandomFontGenerator;
import com.octo.captcha.component.image.textpaster.RandomTextPaster;
import com.octo.captcha.component.image.textpaster.TextPaster;
import com.octo.captcha.component.image.wordtoimage.ComposedWordToImage;
import com.octo.captcha.component.image.wordtoimage.WordToImage;
import com.octo.captcha.component.word.wordgenerator.RandomWordGenerator;
import com.octo.captcha.component.word.wordgenerator.WordGenerator;
import com.octo.captcha.engine.image.ListImageCaptchaEngine;
import com.octo.captcha.image.gimpy.GimpyFactory;

public class ImageCaptchaEngine extends ListImageCaptchaEngine {
    protected void buildInitialFactories() {
        // 랜덤 문자 설정
        WordGenerator wgen = new RandomWordGenerator("ABCDEFGHIJKLMNOPQRSTUVWXYZ123456789");
       
        // Text 색 설정
        RandomRangeColorGenerator cgen = new RandomRangeColorGenerator(
                new int[] { 0, 100 },
                new int[] { 0, 100 },
                new int[] { 0, 100 });
       
        // Text 설정 (랜덤 시작 Text Size, 랜덤 종료 Text Size, 색)
        TextPaster textPaster = new RandomTextPaster(new Integer(4), new Integer(7), cgen, true);
       
        // 백그라운드 색 설정
        RandomRangeColorGenerator bcgen = new RandomRangeColorGenerator(
                new int[] { 150, 255 },
                new int[] { 150, 255 },
                new int[] { 150, 255 });
       
        // 백그라운드 설정 (가로 크기, 세로 크기, 색)
        BackgroundGenerator backgroundGenerator = new FunkyBackgroundGenerator(new Integer(150), new Integer(50), bcgen);
       
        // 백그라운드 기본 설정
        // BackgroundGenerator backgroundGenerator = new FunkyBackgroundGenerator(new Integer(150), new Integer(50));
       
        // 글꼴 설정
        Font[] fontsList = new Font[] {
                new Font("Arial", 0, 10),
                new Font("Tahoma", 0, 10),
                new Font("Verdana", 0, 10)
        };
       
        // 폰트 설정 (랜덤 시작 폰트 Size, 랜덤 종료 폰트 Size)
        FontGenerator fontGenerator = new RandomFontGenerator(new Integer(20), new Integer(35), fontsList);
       
        WordToImage wordToImage = new ComposedWordToImage(fontGenerator, backgroundGenerator, textPaster);
        this.addFactory(new GimpyFactory(wgen, wordToImage));
    }
}



CaptchaServiceSingleton.java

package com.web.common.captcha;

import com.octo.captcha.service.captchastore.FastHashMapCaptchaStore;
import com.octo.captcha.service.image.DefaultManageableImageCaptchaService;
import com.octo.captcha.service.image.ImageCaptchaService;

public class CaptchaServiceSingleton {
    private final static ImageCaptchaService instance;
    static {
        instance = new DefaultManageableImageCaptchaService(new FastHashMapCaptchaStore(), new ImageCaptchaEngine(), 180, 100000, 75000);
    }

    public static ImageCaptchaService getInstance() {
        return instance;
    }
    
    /*
    // 기본 설정 그대로 사용
    private static ImageCaptchaService instance = new DefaultManageableImageCaptchaService();
    public static ImageCaptchaService getInstance(){
        return instance;
    }
    
    // 기본 설정 옵션만 변경하여 사용
    private static ImageCaptchaService instance = initializeService();
    private static ImageCaptchaService initializeService(){
        SimpleListImageCaptchaEngine engine = new SimpleListImageCaptchaEngine();
        return new DefaultManageableImageCaptchaService(new FastHashMapCaptchaStore(), engine, 180, 100000, 75000);
    }
    
    public static ImageCaptchaService getInstance(){
        return instance;
    }
    */
}



ImageCaptchaServlet.java

package com.web.common.captcha;

import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.io.IOException;

import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import com.octo.captcha.service.CaptchaServiceException;
import com.sun.image.codec.jpeg.JPEGCodec;
import com.sun.image.codec.jpeg.JPEGImageEncoder;

public class ImageCaptchaServlet extends HttpServlet {

    @Override
    public void init(ServletConfig servletConfig) throws ServletException {
        super.init(servletConfig);
    }
   
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        byte[] captchaChallengeAsJpeg = null;
        ByteArrayOutputStream jpegOutputStream = new ByteArrayOutputStream();
        try {
            String captchaId = request.getSession().getId();
            BufferedImage challenge = CaptchaServiceSingleton.getInstance().getImageChallengeForID(captchaId, request.getLocale());
            JPEGImageEncoder jpegEncoder = JPEGCodec.createJPEGEncoder(jpegOutputStream);
            jpegEncoder.encode(challenge);
        } catch (IllegalArgumentException e) {
            response.sendError(HttpServletResponse.SC_NOT_FOUND);
            return;
        } catch (CaptchaServiceException e) {
            response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
            return;
        }
       
        captchaChallengeAsJpeg = jpegOutputStream.toByteArray();
        response.setHeader("Cache-Control", "no-store");
        response.setHeader("Pragma", "no-cache");
        response.setDateHeader("Expires", 0);
        response.setContentType("image/jpeg");
        ServletOutputStream responseOutputStream = response.getOutputStream();
        responseOutputStream.write(captchaChallengeAsJpeg);
        responseOutputStream.flush();
        responseOutputStream.close();
    }
   



web.xml

<servlet>
        <servlet-name>jcaptcha</servlet-name>
        <servlet-class>com.web.common.captcha.ImageCaptchaServlet</servlet-class>
        <load-on-startup>0</load-on-startup>
 </servlet>
 <servlet-mapping>
        <servlet-name>jcaptcha</servlet-name>
        <url-pattern>/jcaptcha</url-pattern>
 </servlet-mapping>




JSP (HTML)

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ taglib prefix="c"  uri="http://java.sun.com/jsp/jstl/core" %>

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<title>Insert title here</title>

<script type="text/javascript" src="<c:url value="/resources/js/jquery-1.7.1.min.js" />"></script>
<script>
jQuery(function($) {
    $('#j_captcha_response').on('keyup', function() {
        var _self = $(this);
        var val = _self.val();
        if(val) {
            _self.val(val.toUpperCase());
        }
    });
});
</script>

</head>
<body>

<form action="<c:url value="/captcha/insert" />" method="post">
    <div>
        <img src="<c:url value="/jcaptcha" />" style="border:1px solid #999;" />
    </div>
    <div>
        <input type="text" name="j_captcha_response" id="j_captcha_response" style="ime-mode:disabled;" />
    </div>
    <div>
        <input type="submit" value="전송" />    
    </div>
</form>

</body>
</html>



CaptchaController.java (Contoller)

package com.web.captcha.controllers;

import java.util.Map;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.support.MessageSourceAccessor;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;

import com.octo.captcha.service.CaptchaServiceException;
import com.web.common.captcha.CaptchaServiceSingleton;


@Controller("captcha.CaptchaController")
@RequestMapping("captcha")
public class CaptchaController {

    public static final Logger log = LoggerFactory.getLogger(CaptchaController.class);
    
    @Autowired
    private MessageSourceAccessor messageSourceAccessor;
    
    
    @RequestMapping(value="index", method=RequestMethod.GET)
    public void index(@RequestParam Map<String, Object> paramMap, ModelMap modelMap) throws Exception {
        log.debug("=========================================================================================");
        log.debug("== paramMap : {}", paramMap);
        log.debug("=========================================================================================");
       
        modelMap.put("paramMap", paramMap);
    }
    
    
    @RequestMapping(value="insert", method=RequestMethod.POST)
    public String insert(@RequestParam Map<String, Object> paramMap, ModelMap modelMap, HttpServletRequest request, HttpSession session) throws Exception {
        log.debug("=========================================================================================");
        log.debug("== paramMap : {}", paramMap);
        log.debug("=========================================================================================");
       
        modelMap.put("paramMap", paramMap);
       
       
        Boolean isResponseCorrect = Boolean.FALSE;
        String captchaId = session.getId();
        String jCaptchaResponse = (String)paramMap.get("j_captcha_response");

        try {
            isResponseCorrect = CaptchaServiceSingleton.getInstance().validateResponseForID(captchaId, jCaptchaResponse);
            log.debug("isResponseCorrect : {}", isResponseCorrect);

           
        } catch (CaptchaServiceException e) {
        }
       
        return "captcha/index";
    }
       
}



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

2. Spring 으로 설정

1. CaptchaServiceSingleton 를 CaptchaService 로 대체

CaptchaService.java

package com.web.common.captcha;

import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Service;

import com.octo.captcha.service.captchastore.FastHashMapCaptchaStore;
import com.octo.captcha.service.image.DefaultManageableImageCaptchaService;
import com.octo.captcha.service.image.ImageCaptchaService;

@Service
@Scope(value="singleton")
public class CaptchaService {
   
    private final static ImageCaptchaService instance;
   
    static {
        instance = new DefaultManageableImageCaptchaService(new FastHashMapCaptchaStore(), new ImageCaptchaEngine(), 180, 100000, 75000);
    }
   
    public ImageCaptchaService getInstance() {
        return instance;
    }
   
    /*
    @PostConstruct
    public void init() {
    }
   
    @PreDestroy
    public void close() {
    }
    */
   



2. ImageCaptchaServlet 을 Contoller로 대체

CaptchaContoller.java

package com.web.captcha.controllers;

import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.util.Map;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.support.MessageSourceAccessor;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;

import com.octo.captcha.service.CaptchaServiceException;
import com.sun.image.codec.jpeg.JPEGCodec;
import com.sun.image.codec.jpeg.JPEGImageEncoder;
import com.web.common.captcha.CaptchaService;


@Controller("captcha.CaptchaController")
@RequestMapping("captcha")
public class CaptchaController {

    public static final Logger log = LoggerFactory.getLogger(CaptchaController.class);
    
    @Autowired
    private MessageSourceAccessor messageSourceAccessor;
    
    @Autowired
    private CaptchaService captchaService;
    
    
    @RequestMapping(value="index", method=RequestMethod.GET)
    public void index(@RequestParam Map<String, Object> paramMap, ModelMap modelMap) throws Exception {
        log.debug("=========================================================================================");
        log.debug("== paramMap : {}", paramMap);
        log.debug("=========================================================================================");
        
        modelMap.put("paramMap", paramMap);
    }
    
    
    @RequestMapping(value="jcaptcha", method=RequestMethod.GET)
    public void jcaptcha(@RequestParam Map<String, Object> paramMap, ModelMap modelMap, HttpServletRequest request, HttpServletResponse response, HttpSession session) throws Exception {
        byte[] captchaChallengeAsJpeg = null;
        ByteArrayOutputStream jpegOutputStream = new ByteArrayOutputStream();
        try {
            String captchaId = session.getId();
            BufferedImage challenge = captchaService.getInstance().getImageChallengeForID(captchaId, request.getLocale());
            JPEGImageEncoder jpegEncoder = JPEGCodec.createJPEGEncoder(jpegOutputStream);
            jpegEncoder.encode(challenge);
        } catch (IllegalArgumentException e) {
            response.sendError(HttpServletResponse.SC_NOT_FOUND);
            return;
        } catch (CaptchaServiceException e) {
            response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
            return;
        }
        
        captchaChallengeAsJpeg = jpegOutputStream.toByteArray();
        response.setHeader("Cache-Control", "no-store");
        response.setHeader("Pragma", "no-cache");
        response.setDateHeader("Expires", 0);
        response.setContentType("image/jpeg");
        ServletOutputStream responseOutputStream = response.getOutputStream();
        responseOutputStream.write(captchaChallengeAsJpeg);
        responseOutputStream.flush();
        responseOutputStream.close();
    }
    
    
    @RequestMapping(value="insert", method=RequestMethod.POST)
    public String insert(@RequestParam Map<String, Object> paramMap, ModelMap modelMap, HttpServletRequest request, HttpSession session) throws Exception {
        log.debug("=========================================================================================");
        log.debug("== paramMap : {}", paramMap);
        log.debug("=========================================================================================");
        
        modelMap.put("paramMap", paramMap);
        
        Boolean isResponseCorrect = Boolean.FALSE;
        String captchaId = session.getId();
        String jCaptchaResponse = (String)paramMap.get("j_captcha_response");
        try {
            isResponseCorrect = captchaService.getInstance().validateResponseForID(captchaId, jCaptchaResponse);
            log.debug("isResponseCorrect : {}", isResponseCorrect);
            
        } catch (CaptchaServiceException e) {
        }
        
        return "captcha/index";
    }
        
}


3. web.xml 설정 삭제

4. jsp image url 변경

JSP (HTML)

<img src="<c:url value="/captcha/jcaptcha" />" style="border:1px solid #999;" /> 



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

3. 이미지 새로고침 추가 (Ajax - Base64)


1. CaptchaContoller Ajax (json) 추가

CaptchaController.java

package com.web.captcha.controllers;

import java.awt.image.BufferedImage;
import java.io.BufferedInputStream;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.util.Map;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import org.apache.commons.codec.binary.Base64InputStream;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.support.MessageSourceAccessor;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;

import com.octo.captcha.service.CaptchaServiceException;
import com.sun.image.codec.jpeg.JPEGCodec;
import com.sun.image.codec.jpeg.JPEGImageEncoder;
import com.web.common.captcha.CaptchaService;


@Controller("captcha.CaptchaController")
@RequestMapping("captcha")
public class CaptchaController {

    public static final Logger log = LoggerFactory.getLogger(CaptchaController.class);
   
    @Autowired
    private MessageSourceAccessor messageSourceAccessor;
   
    @Autowired
    private CaptchaService captchaService;
   
   
    @RequestMapping(value="index", method=RequestMethod.GET)
    public void index(@RequestParam Map<String, Object> paramMap, ModelMap modelMap) throws Exception {
        log.debug("=========================================================================================");
        log.debug("== paramMap : {}", paramMap);
        log.debug("=========================================================================================");
       
        modelMap.put("paramMap", paramMap);
    }
   
   
    @RequestMapping(value="jcaptcha", method=RequestMethod.GET)
    public void jcaptcha(@RequestParam Map<String, Object> paramMap, ModelMap modelMap, HttpServletRequest request, HttpServletResponse response, HttpSession session) throws Exception {
        byte[] captchaChallengeAsJpeg = null;
        ByteArrayOutputStream jpegOutputStream = new ByteArrayOutputStream();
        try {
            String captchaId = session.getId();
            BufferedImage challenge = captchaService.getInstance().getImageChallengeForID(captchaId, request.getLocale());
            JPEGImageEncoder jpegEncoder = JPEGCodec.createJPEGEncoder(jpegOutputStream);
            jpegEncoder.encode(challenge);
        } catch (IllegalArgumentException e) {
            response.sendError(HttpServletResponse.SC_NOT_FOUND);
            return;
        } catch (CaptchaServiceException e) {
            response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
            return;
        }
       
        captchaChallengeAsJpeg = jpegOutputStream.toByteArray();
        response.setHeader("Cache-Control", "no-store");
        response.setHeader("Pragma", "no-cache");
        response.setDateHeader("Expires", 0);
        response.setContentType("image/jpeg");
        ServletOutputStream responseOutputStream = response.getOutputStream();
        responseOutputStream.write(captchaChallengeAsJpeg);
        responseOutputStream.flush();
        responseOutputStream.close();
    }
   
   
    @RequestMapping(value="jcaptchaImage.json")
    public String jcaptchaImage(@RequestParam Map<String, Object> paramMap, ModelMap modelMap, HttpServletRequest request, HttpServletResponse response, HttpSession session) throws Exception {
       
        byte[] captchaChallengeAsJpeg = null;
        ByteArrayOutputStream jpegOutputStream = new ByteArrayOutputStream();
        try {
            String captchaId = session.getId();
            BufferedImage challenge = captchaService.getInstance().getImageChallengeForID(captchaId, request.getLocale());
            JPEGImageEncoder jpegEncoder = JPEGCodec.createJPEGEncoder(jpegOutputStream);
            jpegEncoder.encode(challenge);
        } catch (IllegalArgumentException e) {
            response.sendError(HttpServletResponse.SC_NOT_FOUND);
            throw e;
        } catch (CaptchaServiceException e) {
            response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
            throw e;
        }
       
        BufferedInputStream bis = null;
        ByteArrayOutputStream baos = null;
       
        try {
            captchaChallengeAsJpeg = jpegOutputStream.toByteArray();
            BufferedInputStream captchaBis = new BufferedInputStream(new ByteArrayInputStream(captchaChallengeAsJpeg));
            Base64InputStream in = new Base64InputStream(captchaBis, true);
           
            bis = new BufferedInputStream(in);
            baos = new ByteArrayOutputStream();
            byte[] buffer = new byte[4096];
            int read = 0;
            while ((read = bis.read(buffer)) != -1) {
                baos.write(buffer, 0, read);
            }
           
            modelMap.put("captchaCode", baos.toString());
        } finally {
            if(baos != null) {
                baos.close();
            }
            if(bis != null) {
                bis.close();
            }
        }
       
        return "jsonView";
    }

   
   
   
    @RequestMapping(value="insert", method=RequestMethod.POST)
    public String insert(@RequestParam Map<String, Object> paramMap, ModelMap modelMap, HttpServletRequest request, HttpSession session) throws Exception {
        log.debug("=========================================================================================");
        log.debug("== paramMap : {}", paramMap);
        log.debug("=========================================================================================");
       
        modelMap.put("paramMap", paramMap);
       
        Boolean isResponseCorrect = Boolean.FALSE;
        String captchaId = session.getId();
        String jCaptchaResponse = (String)paramMap.get("j_captcha_response");
        try {
            isResponseCorrect = captchaService.getInstance().validateResponseForID(captchaId, jCaptchaResponse);
            log.debug("isResponseCorrect : {}", isResponseCorrect);
           
        } catch (CaptchaServiceException e) {
        }
       
        return "captcha/index";
    }
       
}
 



2. jsp 변경

JSP (HTML)

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ taglib prefix="c"  uri="http://java.sun.com/jsp/jstl/core" %>

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<title>Insert title here</title>

<script type="text/javascript" src="<c:url value="/resources/js/jquery-1.7.1.min.js" />"></script>
<script>
jQuery(function($) {
    $('#j_captcha_response').on('keyup', function() {
        var _self = $(this);
        var val = _self.val();
        if(val) {
            _self.val(val.toUpperCase());
        }
    });


    var _jcaptchaCarousel = $('#jcaptchaCarousel');
    $('#btnCaptchaReload').on('click', function() {
        $.ajax({
            url : '<c:url value="/captcha/jcaptchaImage.json" />',
            dataType : 'json',
            success : function(data, textStatus, jqXHR) {
                if(data.captchaCode) {
                    _jcaptchaCarousel
                        .empty()
                        .append($('<img />', {src:'https://t1.daumcdn.net/cfile/tistory/25572D5056E6794133"<c:url value="/captcha/insert" />" method="post">
    <div id="jcaptchaCarousel"></div>
    <div>
        <input type="button" value="이미지 새로고침" id="btnCaptchaReload" />
    </div>
    <div>
        <input type="text" name="j_captcha_response" id="j_captcha_response" style="ime-mode:disabled;" />
    </div>
    <div>
        <input type="submit" value="전송" />   
    </div>
</form>

</body>
</html> 


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

SimpleCaptcha

홈페이지 : http://simplecaptcha.sourceforge.net/index.html

한글음성 custom : http://javaking75.blog.me/220276964082


참고 : http://www.yunsobi.com/blog/406
         http://blog.naver.com/tyboss?Redirect=Log&logNo=70060667814&from=postView

package test;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.nio.channels.FileChannel;

import org.junit.Test;

public class FileTest {

   
    @Test
    public void copyStream() throws Exception {
       
        String sourceFile = "c:/grid.xls";
        String targetFile = "c:/grid_out.xls";
       
        FileInputStream fis = null;
        FileOutputStream fos = null;
       
        try {
           
            fis = new FileInputStream(sourceFile);
            fos = new FileOutputStream(targetFile);
           
            int read = 0;
            byte[] buffer = new byte[4096];
            while((read = fis.read(buffer)) != -1) {
                fos.write(buffer, 0, read);
            }
           
        } finally {
            if(fos != null) {
                fos.close();
            }
            if(fis != null) {
                fis.close();
            }
        }
    }
   
   
    @Test
    public void copyBuffer() throws Exception {
       
        String sourceFile = "c:/grid.xls";
        String targetFile = "c:/grid_out.xls";
       
        FileInputStream fis = null;
        FileOutputStream fos = null;
       
        BufferedInputStream bis = null;
        BufferedOutputStream bos = null;
       
        try {
           
            fis = new FileInputStream(sourceFile);
            fos = new FileOutputStream(targetFile);
           
            bis = new BufferedInputStream(fis);
            bos = new BufferedOutputStream(fos);
           
            int read = 0;
            byte[] buffer = new byte[4096];
            while((read = bis.read(buffer)) != -1) {
                bos.write(buffer, 0, read);
            }
           
        } finally {
            if(bos != null) {
                bos.close();
            }
            if(bis != null) {
                bis.close();
            }
        }
    }
   
   
   
    @SuppressWarnings("resource")
    @Test
    public void copyNIO() throws Exception {
       
        String sourceFile = "c:/grid.xls";
        String targetFile = "c:/grid_out.xls";
       
        FileInputStream fis = null;
        FileOutputStream fos = null;
       
        FileChannel inChannel = null;
        FileChannel outChannel = null;
       
        try {
           
            fis = new FileInputStream(sourceFile);
            fos = new FileOutputStream(targetFile);
           
            inChannel = fis.getChannel();
            outChannel = fos.getChannel();
           
            long size = inChannel.size();
            inChannel.transferTo(0, size, outChannel);
           
        } finally {
            if(outChannel != null) {
                outChannel.close();
            }
            if(inChannel != null) {
                inChannel.close();
            }
        }
       
    }
   
   
}
 


출처 : http://www.javacodegeeks.com/2012/07/anti-cross-site-scripting-xss-filter.html

XSSFilter.java

XSSInterceptor.java

XSSRequestWrapper.java


1. Filter 적용

<filter>
        <filter-name>xss</filter-name>
        <filter-class>com.jejubank.admin.util.xss.XSSFilter</filter-class>
    </filter>
   
    <filter-mapping>
        <filter-name>xss</filter-name>
        <url-pattern>*.do</url-pattern>
    </filter-mapping> 


2. Interceptor 적용

<mvc:interceptors>
        <mvc:interceptor>
            <mvc:mapping path="/**" />
            <bean class="com.jejubank.admin.util.xss.XSSInterceptor" />
        </mvc:interceptor>
    </mvc:interceptors>


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


첨부파일 있는 경우 XSS Filter
 
참고 : http://www.javapractices.com/topic/TopicAction.do?Id=221

XSSFilter.java 

XSSMultipartRequestWrapper.java 

XSSRequestWrapper.java

 

 

 

 


Homepage : http://jwebsocket.org/

Spring Long Polling Server : http://blog.springsource.org/2012/05/16/spring-mvc-3-2-preview-chat-sample/
                           https://github.com/rstoyanchev

참고 Ajax Push Engine : http://www.ape-project.org/


Push Server 구현 방식
1. Hidden IFrame
2. polling - Ajax
3. Long polling - Ajax (Comet)
4. SSE (Server-Send-Event)


WebSocket과 Async : https://www.slipp.net/wiki/pages/viewpage.action?pageId=14549157




출처 : http://blog.naver.com/tyboss/70097410517

Java SE Autodownload Files
http://www.oracle.com/technetwork/java/javase/autodownload-140472.html


Applet 을 만들 때 package를 적용하고 싶으면 java 프로젝트를 별도로 만들어 jar로 배포를 하고 class 파일 단위로 처리할 경우에는 pacakge 없이 컴파일을 해야 한다.

Applet을 refresh 하고 싶다면 새로고침 시 나오는 java 보안 경고 창에서 실행/취소 중 취소를 클릭하고 Applet 표시 부분에 마우스 우클릭 Reload Applet 클릭하면 됨. Java 콘솔도 우클릭 메뉴에 있음.



1. Applet 만들기

package com.maruara.applet;

import java.applet.Applet;
import java.awt.TextField;
import java.util.Date;

import netscape.javascript.JSObject;

public class TestApplet extends Applet implements Runnable {

  /**
  *
  */
 private static final long serialVersionUID = -176201962325630072L;
 
 JSObject window;
 Thread clockThread;
 Date date;
 boolean running = true;
 TextField tf = new TextField(30);

 public void init() {
  window = JSObject.getWindow(this);
  
  clockThread= new Thread(this);
  clockThread.start();
  add(tf);

  /*
  JSObject window = JSObject.getWindow(this);
  JSObject document = (JSObject)window.getMember("document");
  JSObject location = (JSObject)document.getMember("location");
   
  String s = (String)location.getMember("href");
  window.call("doAlert", null);
  */
 }
 
 public void doStart(String msg) {
  System.out.println(msg);
  tf.setText(msg);
  
  running = true;
  clockThread= new Thread(this);
  clockThread.start();
 }
 
 public void doStop(String msg) {
  System.out.println(msg);
  tf.setText(msg);
  
  running = false;
  clockThread = null;
 }
 
 public void run() {
  // loop until told to stop
        while (running) {
            date = new Date();
           
            window.call("view", new Object[] {date});
           
            try {
             // Wait 500milliseconds before continuing
                clockThread.sleep(1000);
            } catch (InterruptedException e) {
             System.out.println(e);
            }
            // he has wait and will now restart his actions.
         }
    }
 
 public void destroy()
    {
         // will cause thread to stop looping
         running = false;
         // destroy it.
         clockThread = null;
    }
 
}


2. Applet Jar로 묶어서 Web 서버에 올리기

jar 묶을 때 src class folder만 체크한 후 export 한다.
이미지처럼 웹에서 접근할 수 있는 경로로 이동한다.


3. HTML 적용

 <%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<title>Insert title here</title>

</head>
<body>

<%-- <object id="myApplet" name="myApplet" classid="clsid:8AD9C840-044E-11D1-B3E9-00805F499D93" archive="${pageContext.request.contextPath }/myApplet.jar" width="200" height="200" codebase="http://java.sun.com/update/1.7.0/jinstall-7u17-windows-i586.cab"> --%>
<%--  <param name="archive" value="${pageContext.request.contextPath }/myApplet.jar" /> --%>
<!--     <param name="code" value="com.maruara.applet.TestApplet.class" /> -->
<!--     <param name="codebase" value="." /> -->
<!--     <param name="type" value="application/x-java-applet;version=1.6" /> -->
<!--      No JDK 1.3 support for APPLET!! -->
<!-- </object> -->

<!-- <embed id="testapplet" -->
<!--        type="application/x-java-applet;version=1.7" -->
<!--        width="256" height="256"  -->
<%--        archive="${pageContext.request.contextPath }/myApplet.jar" --%>
<!--        code="com.maruara.applet.TestApplet.class" -->
<!--        pluginspage="http://java.com/download/" /> -->


<object id="myApplet" name="myApplet" classid="clsid:8AD9C840-044E-11D1-B3E9-00805F499D93" archive="${pageContext.request.contextPath }/myApplet.jar" width="200" height="200" codebase="http://java.sun.com/update/1.7.0/jinstall-7u17-windows-i586.cab">
 <param name="archive" value="${pageContext.request.contextPath }/myApplet.jar" />
    <param name="code" value="com.maruara.applet.TestApplet.class" />
    <param name="codebase" value="." />
    <param name="type" value="application/x-java-applet;version=1.6" />
    <comment>
     <embed id="myApplet"
         type="application/x-java-applet;version=1.7"
         width="256" height="256"
         archive="${pageContext.request.contextPath }/myApplet.jar"
         code="com.maruara.applet.TestApplet.class"
         pluginspage="http://java.com/download/" />
    </comment>
</object>

<div id="view"></div>
<button type="button" id="btnStart">시작</button>
<button type="button" id="btnStop">정지</button>

<script>
function view(time) {
 $('#view').text(time);
}

$('#btnStart').on('click', function() {
  $('#myApplet').get(0).doStart('stop');
});

$('#btnStop').on('click', function() {
 document.getElementById('myApplet').doStop('stop');
});
</script>

</body>
</html>

 

<script language="Javascript">

  var _app = navigator.appName;

  if (_app == 'Netscape') {
    document.write('<embed code="Applet1.class"',
                   'width="200"',
                   'height="200"',
                   'type="application/x-java-applet;version=1.5.0">');
    }
  else if (_app == 'Microsoft Internet Explorer') {
    document.write('<OBJECT ',
                   'classid="clsid:8AD9C840-044E-11D1-B3E9-00805F499D93"',
                   'width="200"',
                   'height="200">',
                   '<PARAM name="code" value="Applet1.class">',
                   '</OBJECT>');
    }
  else {
    document.write('<p>Sorry, unsupported browser.</p>');
    }

</script> 

+ Recent posts