반응형

이번 포스팅에서 소개하는  JDK1.6 기반의 SimpleCaptcha 라이브러리를 이용한 CAPTCHA 샘플 프로그램은 이전 샘플과는 달리 Servlet

을 사용하지 않고 단순 Java객체로 구현했으며, 이전 포스팅에서 소개한 바와 같이 음성서비스도 지원한다.


다음은 CaptCha Image를 생성하는 'CaptCha' 클래스의 소스 코드이다.

package captcha;


import static nl.captcha.Captcha.NAME;
import java.awt.Color;
import java.awt.Font;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import nl.captcha.Captcha;
import nl.captcha.backgrounds.GradiatedBackgroundProducer;
import nl.captcha.gimpy.DropShadowGimpyRenderer;
import nl.captcha.servlet.CaptchaServletUtil;
import nl.captcha.text.producer.NumbersAnswerProducer;
import nl.captcha.text.renderer.DefaultWordRenderer;


public class CaptCha{

    private static final long serialVersionUID = 1L;
    private static int width = 150; //이미지 가로크기
    private static int height = 50; //이미지 높이


    public void getCaptCha(HttpServletRequest req, HttpServletResponse res) throws IOException {

     // 폰트 설정 부분 =============================================
        List<Font> fontList = new ArrayList<Font>();
        fontList.add(new Font("", Font.HANGING_BASELINE, 40));
        fontList.add(new Font("Courier", Font.ITALIC, 40));
        fontList.add(new Font("", Font.PLAIN, 40));

        List<Color> colorList = new ArrayList<Color>();
        colorList.add(Color.black); //또는  colorList.add(Color.green), colorList.add(Color.blue) 등으로 설정
        //=========================================================


        Captcha captcha = new Captcha.Builder( width, height)
               //.addText() 또는 아래와 같이 정의    
               //6자리 숫자와 폰트를 설정한다.
               .addText(new NumbersAnswerProducer(6), new DefaultWordRenderer(colorList, fontList))
               .gimp(new DropShadowGimpyRenderer()).gimp()
               // BlockGimpyRenderer,FishEyeGimpyRenderer,RippleGimpyRenderer,ShearGimpyRenderer,StretchGimpyRenderer
               .addNoise().addBorder()
               .addBackground(new GradiatedBackgroundProducer())
                // FlatColorBackgroundProducer,SquigglesBackgroundProducer,TransparentBackgroundProducer
                .build();

        

         //JSP에서 Captcha 객체에 접근할 수 있도록 Session에 저장한다.

         req.getSession().setAttribute(NAME, captcha); //NAME = Captcha.NAME = 'simpleCaptcha'
         CaptchaServletUtil.writeImage(res, captcha.getImage());
    }
}



다음은 CaptCha Audio를 생성하는 'AudioCaptCha' 클래스의 소스 코드이다.

package captcha;


import java.io.IOException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import nl.captcha.Captcha;
import nl.captcha.audio.AudioCaptcha;
import nl.captcha.servlet.CaptchaServletUtil;


public class AudioCaptCha {

    public void getAudioCaptCha(HttpServletRequest req, HttpServletResponse res, String answer)

      throws IOException{


        HttpSession session = req.getSession();
       
        //Captcha.NAME = 'simpleCaptcha'
        Captcha captcha = (Captcha) session.getAttribute(Captcha.NAME);
        String getAnswer = answer; 

        if ( getAnswer == null || getAnswer.equals("") ) getAnswer = captcha.getAnswer();

 

        AudioCaptcha audiocaptcha = new AudioCaptcha.Builder()
                           //.addAnswer(new DefaultTextProducer(6, getAnswer.toCharArray())) 또는 다음과 같이...
                           .addAnswer(new SetTextProducer(getAnswer))
                           .addNoise() //잡음추가
                           .build();


        CaptchaServletUtil.writeAudio(res, audiocaptcha.getChallenge());

    }
}

 


다음은 User Defined TextProducer 인 'SetTextProducer' 클래스이다. 여기서 'SetTextProducer' 클래스는 전달받은 문자열을 그대로

AudioCaptcha가 사용할 수 있도록 하는 역할을 한다.

package captcha;


import nl.captcha.text.producer.TextProducer;


public class SetTextProducer implements TextProducer {

    private final String srcStr;

    public SetTextProducer(String answer) {   
        srcStr = answer; 
   }

   

    //@Override
   public String getText() {        
        return srcStr;
   }

}

 


다음은 본 예제의 메인 페이지에 해당하는 'index.jsp'의 소스 코드이다.

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%
  String ctx = request.getContextPath(); //콘텍스트명 얻어오기.
  response.setHeader("Pragma-directive", "no-cache");
  response.setHeader("Cache-directive", "no-cache");
  response.setHeader("Pragma", "no-cache");
  response.setHeader("Cache-Control", "no-cache");
  response.setDateHeader("Expires",0);
%>
<!DOCTYPE  html>
<html>
<head>
<title>CaptCha Exam None Servlet</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0, user-scalable=no, target-densitydpi=medium-dpi" />
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta http-equiv="Cache-Control" content="no-cache" />
<meta http-equiv="Pragma" content="no-cache" />
<meta http-equiv="Imagetoolbar" content="no" />
<script type="text/javascript" src="//ajax.googleapis.com/ajax/libs/jquery/1.9.0/jquery.min.js"></script>


<script type="text/javascript">

 /*
  * Captcha Image 요청
  * [주의] IE의 경우 CaptChaImg.jsp 호출시 매번 변하는 임의의 값(의미없는 값)을 파라미터로 전달하지 않으면
  * '새로고침'버튼을 클릭해도 CaptChaImg.jsp가 호출되지 않는다. 즉, 이미지가 변경되지 않는 문제가 발생한다.
  *  그러나 크롭의 경우에는 파라미터 전달 없이도 정상 호출된다.
  */
 function changeCaptcha() {
  //IE에서 '새로고침'버튼을 클릭시 CaptChaImg.jsp가 호출되지 않는 문제를 해결하기 위해 "?rand='+ Math.random()" 추가
  $('#catpcha').html('<img src="<%=ctx%>/captcha_mod/CaptChaImg.jsp?rand='+ Math.random() + '"/>');
 }


 function winPlayer(objUrl) {
  $('#audiocatpch').html(' <bgsound src="' + objUrl + '">');
 }

 
 /*
  * Captcha Audio 요청
  * [주의] IE의 경우 CaptChaAudio.jsp 호출시 매번 매번 변하는 임의의 값(의미없는 값)을 파라미터로 전달하지 않으면
  * '새로고침'된 이미지의 문자열을 읽지 못하고 최초 화면 로드시 로딩된 이미지의 문자열만 읽는 문제가 발생한다.
  * 이 문제의 원인도 결국 매번 변하는 파라미터 없이는 CaptChaAudio.jsp가 호출되지 않기 때문이다.
  * 그러나 크롭의 경우에는 파라미터 전달 없이도 정상 호출된다. 
  */
 function audioCaptcha() {

   var uAgent = navigator.userAgent;
   var soundUrl = 'CaptChaAudio.jsp';
   if (uAgent.indexOf('Trident') > -1 || uAgent.indexOf('MSIE') > -1) {
       //IE일 경우 호출
       winPlayer(soundUrl+'?agent=msie&rand='+ Math.random());
   } else if (!!document.createElement('audio').canPlayType) {
       //Chrome일 경우 호출
       try { new Audio(soundUrl).play(); } catch(e) { winPlayer(soundUrl); }
   } else window.open(soundUrl, '', 'width=1,height=1');
 }

 
 //화면 호출시 가장 먼저 호출되는 부분
 $(document).ready(function() {

  
  changeCaptcha(); //Captcha Image 요청
  
  $('#reLoad').click(function(){ changeCaptcha(); }); //'새로고침'버튼의 Click 이벤트 발생시 'changeCaptcha()'호출
  $('#soundOn').click(function(){ audioCaptcha(); }); //'음성듣기'버튼의 Click 이벤트 발생시 'audioCaptcha()'호출
  
  //'확인' 버튼 클릭시
  $('#frmSubmit').click(function(){
      if ( !$('#answer').val() ) {
           alert('이미지에 보이는 숫자 또는 스피커를 통해 들리는 숫자를 입력해 주세요.');
      } else {
           $.ajax({
               url: 'CaptchaSubmit.jsp',
               type: 'POST',
               dataType: 'text',
               data: 'answer=' + $('#answer').val(),
               async: false,  
               success: function(resp) {
                    alert(resp);
                    $('#reLoad').click();
                    $('#answer').val('');
              }
         });
      }
  });

 });
</script>
</head>
<body>
  <div id="catpcha">Wait...</div>
  <div id="audiocatpch" style="display: none;"></div>

  <input id="reLoad" type="button" value="새로고침" />
  <input id="soundOn" type="button" value="음성듣기" />

  <br />
  <input type="text" id="answer" name="answer" value="" />
  <input type="button" id="frmSubmit" value="확인" />
</body>
</html>

 


다음은 'CaptCha' 클래스의 호출해서 CaptCha Image를 생성하는 'CaptChaImg.jsp' 의 소스 코드이다.

 <%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8" import="captcha.CaptCha"%>
<%
    new CaptCha().getCaptCha(request, response); 
%>

 


다음은 'AudioCaptCha' 클래스를 호출하여 CaptCha Audio를 생성하는 'CaptChaAudio.jsp'의 소스 코드이다.

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8" import="captcha.AudioCaptCha, nl.captcha.Captcha"%>
<%
   //Captcha.NAME = 'simpleCaptcha'
   Captcha captcha = (Captcha) session.getAttribute(Captcha.NAME);
   String getAnswer = captcha.getAnswer();
//CaptsCha Image에 사용된 문자열을 반환한다.
   new AudioCaptCha().getAudioCaptCha(request, response, getAnswer);
%>

 


다음은 사용자가 입력한 문자열과 CaptCha 클래스가 생성한 문자열이 일치하는지 확인하는 'CaptchaSubmit.jsp'의 소스 코드이다.

<%@ page session="true" language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8" import="nl.captcha.Captcha" %>
<%
   response.setHeader("Pragma-directive", "no-cache");
   response.setHeader("Cache-directive", "no-cache");
   response.setHeader("Pragma", "no-cache");
   response.setHeader("Cache-Control", "no-cache");
   response.setDateHeader("Expires",0);
  
   //Captcha.NAME = 'simpleCaptcha'
   Captcha captcha = (Captcha) session.getAttribute(Captcha.NAME);
   String answer = request.getParameter("answer"); //사용자가 입력한 문자열
   if ( answer != null && !"".equals(answer) ) {


       if (captcha.isCorrect(answer)) { //사용자가 입력한 문자열과 CaptCha 클래스가 생성한 문자열
           session.removeAttribute(Captcha.NAME);
           out.print("입력값이 일치합니다.");
       } else {
           out.print("입력값이 일치하지 않습니다.");
       }

 

   }
%>

 


다음은 본 예제를 실행한 화면이다.


- IE11에서 실행한 화면

 


- Chrome 에서 실행한 화면


IE11, Chrome 모두 동일하게 동작한다!


[개발후기]

코드를 좀더 간결히 할 수 있었는데, 망할놈의 IE에서 제대로 동작하지 않아서 Chrome과 IE 양쪽 모두에서 정상 동작해야 한다는 요건을

충족시키려다 보니 잡코드(= 잡스런 코드)가 다소 포함됐다... IE때매 포함시킨 잡코드들은 소스 코드에 주석으로 달아놨다.

덧붙여, 본 예제와 관련된 SimpleCaptcha 라이브러들은 이전 포스팅에서 소개한 SimpleCaptcha 홈에서 다운받을 수 있다.

[원본] [JAVA] SimpleCaptcha 를 이용한 자동가입방지 문자 생성하기 - JDK1.6(JAVA6) 기반|작성자 황철연

 

[출처]http://gnujava.com/board/article_view.jsp?article_no=7121&menu_cd=16&board_no=3&table_cd=EPAR01&table_no=01

반응형



Posted by 궁극의 java개발자
,