이번 포스팅에서 소개하는 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