jQuery 와 Servlet을 이용한 간단한 Captcha 샘플~

Captcha 란 간단히 아래쪽 그림과 같은 기능을 하는것을 말한다.


 

제작해본 샘플은 

서버측에서 이미지를 생성해 주고, 생성된 문자열을 세션에 저장시켜주는 기능을 수행하는 Servlet 하나와

고 서블릿을 사용하는 클라이언트 쪽 html 파일로 구성된다. 

사용한 라이브러리는 랜덤 스트링 생성을 편하게 하기 위해 apache commons lang 의 RandomStringUtils 를 사용했다.


CaptchaGenServlet.java
package servlet;

import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics2D;
import java.awt.GraphicsEnvironment;
import java.awt.RenderingHints;
import java.awt.font.FontRenderContext;
import java.awt.geom.Rectangle2D;
import java.awt.image.BufferedImage;
import java.io.IOException;

import javax.imageio.ImageIO;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.lang.RandomStringUtils;

public class CaptchaGenServlet extends HttpServlet {
	private static final long serialVersionUID = 1L;

	@Override
	public void init() throws ServletException {
		super.init();
		
		// 폰트 등록
		try {
			Font font = Font.createFont(Font.TRUETYPE_FONT,
                                    this.getClass().getResourceAsStream("/servlet/HelveticaMedCd.ttf"));
			GraphicsEnvironment.getLocalGraphicsEnvironment().registerFont(font);
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	
    public CaptchaGenServlet() {
        super();
    }

	protected void doGet(HttpServletRequest request, HttpServletResponse response) 
                      throws ServletException, IOException {
		generateCaptcha(request, response);
	}

	protected void doPost(HttpServletRequest request, HttpServletResponse response) 
                       throws ServletException, IOException {
		generateCaptcha(request, response);
	}
	
	private void generateCaptcha(HttpServletRequest request, HttpServletResponse response){
		try {
			// 알파벳 숫자섞인 5자리 문자열 생성
			String randomString = RandomStringUtils.randomAlphanumeric(5).toUpperCase();
			
			// 세션에 저장
			request.getSession().setAttribute("CAPTCHA", randomString);
			
			Font font = new Font("Helvetica 67 Medium Condensed", Font.PLAIN, 50);
			FontRenderContext frc = new FontRenderContext(null, true, true);
			Rectangle2D bounds = font.getStringBounds(randomString, frc);
			int w = (int) bounds.getWidth();
			int h = (int) bounds.getHeight();
			
			// 이미지 생성
			BufferedImage image = new BufferedImage(w, h, BufferedImage.TYPE_INT_RGB);
			Graphics2D g = image.createGraphics();
			g.setColor(Color.WHITE);
			g.fillRect(0, 0, w, h);
			g.setColor(new Color(113, 193, 217));
			g.setFont(font);
			g.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, 
                               RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
			g.setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS, 
                               RenderingHints.VALUE_FRACTIONALMETRICS_ON);
			g.drawString(randomString, (float) bounds.getX(), (float) -bounds.getY());
			g.dispose();

			ImageIO.write(image, "png",  response.getOutputStream());
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
}


이미지 생성시 문자열에 쓸 폰트를 클래스패스에 위치시킨 다음에 30번째 라인처럼 불러와서 폰트를 등록시킬 수 있다.
폰트 등록후 57번째 라인처럼 등록된 폰트를 불러와 쓸 수 있는데 시스템에 등록된 폰트들 이름을 확인하기 위해서는 다음과 같은 코드로 확인하면 된다.
Font[] fontList = GraphicsEnvironment.getLocalGraphicsEnvironment().getAllFonts();
			
for( Font f : fontList){
	System.out.println(f.getName());
}



web.xml 서블릿 설정

<servlet>
	<display-name>CaptchaGenServlet</display-name>
	<servlet-name>CaptchaGenServlet</servlet-name>
	<servlet-class>servlet.CaptchaGenServlet</servlet-class>
</servlet>
<servlet-mapping>
	<servlet-name>CaptchaGenServlet</servlet-name>
	<url-pattern>/captcha</url-pattern>
</servlet-mapping>



Captcha UI
<html>
<head>
	<title>Captcha Test</title>
	
	<script type="text/javascript" src="/jquery-1.6.1.min.js"></script>
	
	<script>
		$(document).ready(function(){
			create();
			
			$("#refreshBtn").click(function(e){
				e.preventDefault();
				create();
			});
			
			$("#confirmBtn").click(function(e){
				e.preventDefault();
				$("#frm").submit();
			});
			
			function create(){
				$("#captcha img").attr("src", "/captcha?"+Math.random());
			}
		});
	</script>
	
	<style>
		#captcha {
			width : 230px;
			height : 70px;
			border: 3px dotted #A3C552;
			text-align: center;
			padding: 5px;
		}
	</style>
</head>

<body>
	Catpcha Test!!!
	<form id="frm" action="result.jsp" method="post">
		<div id="captcha"><img/></div>
		<br/>
		<input type="text" name="captchaInput"/>
		<button id="confirmBtn">확인</button>
		<button id="refreshBtn">리푸레쉬</button>
	</form>
</body>
</html>



쪽바로 입력했는지 체크하기(result.jsp)
SESSION : ${sessionScope['CAPTCHA']}
PARAM : ${param.captchaInput}

통과 : ${ sessionScope['CAPTCHA'] eq param.captchaInput ? 'O' : 'X'}

CaptchaSample.war