关于验证码的独立模块的整合说明
验证码我们采用开源的jcaptcha(http://www.jcaptcha.net/)来实现,主要考虑到两点
1. 已经有相当成熟的成功案例。
2. 配置非常简单,整合Spring框架非常容易。
现在将配置文件和应用开发简单的说明一下
需要的包中包括
jcaptcha-all-1.0-RC6.jar
spring-2.x.x.jar
maven 配置文件只需要添加
<dependency>
<groupId>com.octo.captcha</groupId>
<artifactId>jcaptcha</artifactId>
<version>1.0-RC6</version>
</dependency>
配置文件
applicationContext-jcaptcha.xml
web.xml
ImageCaptchaServlet.java (本来只做参考也可以使用)
web.xml文件内容
<?xml version="1.0" encoding="ISO-8859-1"?>
<web-app xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd" version="2.4">
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>
/WEB-INF/applicationContext*.xml
</param-value>
</context-param>
<filter>
<filter-name>encodingFilter</filter-name> <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
<init-param>
<param-name>encoding</param-name>
<param-value>UTF-8</param-value>
</init-param>
<init-param>
<param-name>forceEncoding</param-name>
<param-value>true</param-value>
</init-param>
</filter>
<servlet>
<servlet-name>validateImage</servlet-name>
<servlet-class>com.zongheng.servlet.ImageJCaptchaServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>validateImage</servlet-name>
<url-pattern>/validateImage</url-pattern>
</servlet-mapping>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
</web-app>
类ImageJCaptchaServlet.java
package com.zongheng.servlet;
import com.octo.captcha.service.image.ImageCaptchaService;
import com.sun.image.codec.jpeg.JPEGCodec;
import com.sun.image.codec.jpeg.JPEGImageEncoder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.web.context.support.WebApplicationContextUtils;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.io.OutputStream;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class ImageJCaptchaServlet extends HttpServlet {
private static final long serialVersionUID = -5382766069139170499L;
protected final Logger logger = LoggerFactory.getLogger(getClass());
protected ImageCaptchaService captchaService;
public void init() throws ServletException {
super.init();
ApplicationContext context = WebApplicationContextUtils.getWebApplicationContext(getServletContext());
captchaService = (ImageCaptchaService) context.getBean("captchaService");
}
protected void service(HttpServletRequest request,
HttpServletResponse response) throws ServletException, IOException {
String jsessionid = request.getSession(true).getId();
BufferedImage image = captchaService.getImageChallengeForID(jsessionid,request.getLocale());
OutputStream outputStream = null;
try {
outputStream = response.getOutputStream();
// render the captcha challenge as a JPEG image in the response
response.setHeader("Cache-Control", "no-store");
response.setHeader("Pragma", "no-cache");
response.setDateHeader("Expires", 0);
response.setContentType("image/jpeg");
JPEGImageEncoder encoder = JPEGCodec.createJPEGEncoder(outputStream);
encoder.encode(image);
outputStream.flush();
outputStream.close();
} catch (IOException ex) {
logger.error("gen image error", ex);
response.sendError(HttpServletResponse.SC_NOT_FOUND);
} finally {
if (outputStream != null) {
outputStream.close();
}
}
应用程序校验验证码是否正确 非常简单
String jsessionid = request.getSession(true).getId(); //得到当前用户的SessionID
String code =request.getParameter(“code”); //获取用户输入的验证码
ApplicationContext context = … 通过注入的方式 或 通过Servlet方法得到
ImageCaptchaService captchaService = (ImageCaptchaService) context.getBean("captchaService");
Boolean flag = captchaService.validateResponseForID(sessionid,code);
If(flag){
//验证通过
}else{
//验证未通过
}
applicationContext-jcaptch.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">
<bean id="captchaService" class="com.octo.captcha.service.image.DefaultManageableImageCaptchaService">
<property name="captchaEngine" ref="imageEngine"/>
</bean>
<bean id="imageEngine" class="com.octo.captcha.engine.GenericCaptchaEngine">
<constructor-arg index="0">
<list>
<ref bean="captchaFactory"/>
</list>
</constructor-arg>
</bean>
<bean id="captchaFactory" class="com.octo.captcha.image.gimpy.GimpyFactory">
<constructor-arg ref="wordgen"/>
<constructor-arg ref="wordtoimage"/>
</bean>
<bean id="wordgen" class="com.octo.captcha.component.word.wordgenerator.RandomWordGenerator">
<constructor-arg value="23456789ABCDEFGHJKLMNPQRSTXYZ"/>
<!—建议不要使用1 因为如果通过技术手段展现图片中很难分辨1 和 I -->
</bean>
<bean id="wordtoimage" class="com.octo.captcha.component.image.wordtoimage.ComposedWordToImage">
<constructor-arg index="0" ref="fontGenRandom"/>
<constructor-arg index="1" ref="backGenUni"/>
<constructor-arg index="2" ref="simpleWhitePaster"/>
</bean>
<bean id="fontGenRandom" class="com.octo.captcha.component.image.fontgenerator.RandomFontGenerator">
<constructor-arg index="0" value="30"/>
<!—字体宽度 根据实际情况做调整-->
<constructor-arg index="1" value="40"/>
<!—字体高度 根据实际情况做调整-->
<constructor-arg index="2">
<list>
<ref bean="fontArial"/>
<ref bean="fontTahoma"/>
<ref bean="fontVerdana"/>
<ref bean="fontComic"/>
<ref bean="fontLucida"/>
</list>
</constructor-arg>
</bean>
<!--fond config -->
<bean id="fontArial" class="java.awt.Font">
<constructor-arg index="0" value="Arial"/>
<constructor-arg index="1" value="0"/>
<constructor-arg index="2" value="10"/>
</bean>
<bean id="fontTahoma" class="java.awt.Font">
<constructor-arg index="0" value="Tahoma"/>
<constructor-arg index="1" value="0"/>
<constructor-arg index="2" value="10"/>
</bean>
<bean id="fontVerdana" class="java.awt.Font">
<constructor-arg index="0" value="Verdana"/>
<constructor-arg index="1" value="0"/>
<constructor-arg index="2" value="10"/>
</bean>
<bean id="fontComic" class="java.awt.Font">
<constructor-arg index="0" value="Comic sans MS"/>
<constructor-arg index="1" value="0"/>
<constructor-arg index="2" value="10"/>
</bean>
<bean id="fontLucida" class="java.awt.Font">
<constructor-arg index="0" value="Lucida console"/>
<constructor-arg index="1" value="0"/>
<constructor-arg index="2" value="10"/>
</bean>
<!--fond end-->
<bean id="backGenUni" class="com.octo.captcha.component.image.backgroundgenerator.UniColorBackgroundGenerator">
<constructor-arg index="0" value="200"/>
<!—图片宽度 单位为pixel根据实际情况做调整-->
<constructor-arg index="1" value="100"/>
<!—图片高度 单位为pixel根据实际情况做调整-->
</bean>
<bean id="simpleWhitePaster" class="com.octo.captcha.component.image.textpaster.SimpleTextPaster">
<constructor-arg type="java.lang.Integer" index="0" value="3"/>
<!—最小的字符长度 根据实际情况做调整-->
<constructor-arg type="java.lang.Integer" index="1" value="5"/>
<!—最大的字符长度 根据实际情况做调整-->
<constructor-arg type="java.awt.Color" index="2" ref="colorGreen"/>
</bean>
<bean id="colorGreen" class="java.awt.Color">
<!—字体颜色 根据实际情况做调整-->
<constructor-arg index="0" value="10"/>
<constructor-arg index="1" value="100"/>
<constructor-arg index="2" value="200"/>
</bean>
</beans>
JSP页面程序
<script language="javascript" type="text/javascript">
function changeImage() {
document.getElementById('japtchaImage').src = '/validateImage?' + Math.random();
}
</script>
<img src="/ validateImage " width="200" id="japtchaImage" name="code" _disibledevent="changeImage();">
<a href="#" _disibledevent="changeImage();return false;" title="看不清,换一张" >看不清,换一张</a>
<!---使用Math.random()是为了确保调用Servlet,否则Servlet会缓存用户的请求-->
验证码我们采用开源的jcaptcha(http://www.jcaptcha.net/)来实现,主要考虑到两点
1. 已经有相当成熟的成功案例。
2. 配置非常简单,整合Spring框架非常容易。
现在将配置文件和应用开发简单的说明一下
需要的包中包括
jcaptcha-all-1.0-RC6.jar
spring-2.x.x.jar
maven 配置文件只需要添加
<dependency>
<groupId>com.octo.captcha</groupId>
<artifactId>jcaptcha</artifactId>
<version>1.0-RC6</version>
</dependency>
配置文件
applicationContext-jcaptcha.xml
web.xml
ImageCaptchaServlet.java (本来只做参考也可以使用)
web.xml文件内容
<?xml version="1.0" encoding="ISO-8859-1"?>
<web-app xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd" version="2.4">
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>
/WEB-INF/applicationContext*.xml
</param-value>
</context-param>
<filter>
<filter-name>encodingFilter</filter-name> <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
<init-param>
<param-name>encoding</param-name>
<param-value>UTF-8</param-value>
</init-param>
<init-param>
<param-name>forceEncoding</param-name>
<param-value>true</param-value>
</init-param>
</filter>
<servlet>
<servlet-name>validateImage</servlet-name>
<servlet-class>com.zongheng.servlet.ImageJCaptchaServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>validateImage</servlet-name>
<url-pattern>/validateImage</url-pattern>
</servlet-mapping>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
</web-app>
类ImageJCaptchaServlet.java
package com.zongheng.servlet;
import com.octo.captcha.service.image.ImageCaptchaService;
import com.sun.image.codec.jpeg.JPEGCodec;
import com.sun.image.codec.jpeg.JPEGImageEncoder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.web.context.support.WebApplicationContextUtils;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.io.OutputStream;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class ImageJCaptchaServlet extends HttpServlet {
private static final long serialVersionUID = -5382766069139170499L;
protected final Logger logger = LoggerFactory.getLogger(getClass());
protected ImageCaptchaService captchaService;
public void init() throws ServletException {
super.init();
ApplicationContext context = WebApplicationContextUtils.getWebApplicationContext(getServletContext());
captchaService = (ImageCaptchaService) context.getBean("captchaService");
}
protected void service(HttpServletRequest request,
HttpServletResponse response) throws ServletException, IOException {
String jsessionid = request.getSession(true).getId();
BufferedImage image = captchaService.getImageChallengeForID(jsessionid,request.getLocale());
OutputStream outputStream = null;
try {
outputStream = response.getOutputStream();
// render the captcha challenge as a JPEG image in the response
response.setHeader("Cache-Control", "no-store");
response.setHeader("Pragma", "no-cache");
response.setDateHeader("Expires", 0);
response.setContentType("image/jpeg");
JPEGImageEncoder encoder = JPEGCodec.createJPEGEncoder(outputStream);
encoder.encode(image);
outputStream.flush();
outputStream.close();
} catch (IOException ex) {
logger.error("gen image error", ex);
response.sendError(HttpServletResponse.SC_NOT_FOUND);
} finally {
if (outputStream != null) {
outputStream.close();
}
}
应用程序校验验证码是否正确 非常简单
String jsessionid = request.getSession(true).getId(); //得到当前用户的SessionID
String code =request.getParameter(“code”); //获取用户输入的验证码
ApplicationContext context = … 通过注入的方式 或 通过Servlet方法得到
ImageCaptchaService captchaService = (ImageCaptchaService) context.getBean("captchaService");
Boolean flag = captchaService.validateResponseForID(sessionid,code);
If(flag){
//验证通过
}else{
//验证未通过
}
applicationContext-jcaptch.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">
<bean id="captchaService" class="com.octo.captcha.service.image.DefaultManageableImageCaptchaService">
<property name="captchaEngine" ref="imageEngine"/>
</bean>
<bean id="imageEngine" class="com.octo.captcha.engine.GenericCaptchaEngine">
<constructor-arg index="0">
<list>
<ref bean="captchaFactory"/>
</list>
</constructor-arg>
</bean>
<bean id="captchaFactory" class="com.octo.captcha.image.gimpy.GimpyFactory">
<constructor-arg ref="wordgen"/>
<constructor-arg ref="wordtoimage"/>
</bean>
<bean id="wordgen" class="com.octo.captcha.component.word.wordgenerator.RandomWordGenerator">
<constructor-arg value="23456789ABCDEFGHJKLMNPQRSTXYZ"/>
<!—建议不要使用1 因为如果通过技术手段展现图片中很难分辨1 和 I -->
</bean>
<bean id="wordtoimage" class="com.octo.captcha.component.image.wordtoimage.ComposedWordToImage">
<constructor-arg index="0" ref="fontGenRandom"/>
<constructor-arg index="1" ref="backGenUni"/>
<constructor-arg index="2" ref="simpleWhitePaster"/>
</bean>
<bean id="fontGenRandom" class="com.octo.captcha.component.image.fontgenerator.RandomFontGenerator">
<constructor-arg index="0" value="30"/>
<!—字体宽度 根据实际情况做调整-->
<constructor-arg index="1" value="40"/>
<!—字体高度 根据实际情况做调整-->
<constructor-arg index="2">
<list>
<ref bean="fontArial"/>
<ref bean="fontTahoma"/>
<ref bean="fontVerdana"/>
<ref bean="fontComic"/>
<ref bean="fontLucida"/>
</list>
</constructor-arg>
</bean>
<!--fond config -->
<bean id="fontArial" class="java.awt.Font">
<constructor-arg index="0" value="Arial"/>
<constructor-arg index="1" value="0"/>
<constructor-arg index="2" value="10"/>
</bean>
<bean id="fontTahoma" class="java.awt.Font">
<constructor-arg index="0" value="Tahoma"/>
<constructor-arg index="1" value="0"/>
<constructor-arg index="2" value="10"/>
</bean>
<bean id="fontVerdana" class="java.awt.Font">
<constructor-arg index="0" value="Verdana"/>
<constructor-arg index="1" value="0"/>
<constructor-arg index="2" value="10"/>
</bean>
<bean id="fontComic" class="java.awt.Font">
<constructor-arg index="0" value="Comic sans MS"/>
<constructor-arg index="1" value="0"/>
<constructor-arg index="2" value="10"/>
</bean>
<bean id="fontLucida" class="java.awt.Font">
<constructor-arg index="0" value="Lucida console"/>
<constructor-arg index="1" value="0"/>
<constructor-arg index="2" value="10"/>
</bean>
<!--fond end-->
<bean id="backGenUni" class="com.octo.captcha.component.image.backgroundgenerator.UniColorBackgroundGenerator">
<constructor-arg index="0" value="200"/>
<!—图片宽度 单位为pixel根据实际情况做调整-->
<constructor-arg index="1" value="100"/>
<!—图片高度 单位为pixel根据实际情况做调整-->
</bean>
<bean id="simpleWhitePaster" class="com.octo.captcha.component.image.textpaster.SimpleTextPaster">
<constructor-arg type="java.lang.Integer" index="0" value="3"/>
<!—最小的字符长度 根据实际情况做调整-->
<constructor-arg type="java.lang.Integer" index="1" value="5"/>
<!—最大的字符长度 根据实际情况做调整-->
<constructor-arg type="java.awt.Color" index="2" ref="colorGreen"/>
</bean>
<bean id="colorGreen" class="java.awt.Color">
<!—字体颜色 根据实际情况做调整-->
<constructor-arg index="0" value="10"/>
<constructor-arg index="1" value="100"/>
<constructor-arg index="2" value="200"/>
</bean>
</beans>
JSP页面程序
<script language="javascript" type="text/javascript">
function changeImage() {
document.getElementById('japtchaImage').src = '/validateImage?' + Math.random();
}
</script>
<img src="/ validateImage " width="200" id="japtchaImage" name="code" _disibledevent="changeImage();">
<a href="#" _disibledevent="changeImage();return false;" title="看不清,换一张" >看不清,换一张</a>
<!---使用Math.random()是为了确保调用Servlet,否则Servlet会缓存用户的请求-->