spring+ jcaptcha(spring框架下的彩色验证码)

1、从jcaptcha官方网站下载jcaptcha的发行包,并将其发行包中的jar文件考贝到本地项目WEB-INF目录下的lib目录中。

官方网址http://jcaptcha.sourceforge.net/

2、在web.xml文件中配置

Java代码 spring+ jcaptcha(spring框架下的彩色验证码)
  1. <servlet>   
  2.      <servlet-name>jcaptcha</servlet-name>   
  3.      <servlet-class>cn.hxex.order.core.jcaptcha.ImageCaptchaServlet</servlet-class>   
  4.      <load-on-startup>3</load-on-startup>   
  5.  </servlet>   
  6.   
  7.  <servlet-mapping>   
  8.      <servlet-name>jcaptcha</servlet-name>   
  9.      <url-pattern>/captcha.jpg</url-pattern>   
  10.  </servlet-mapping>  
 <servlet>
      <servlet-name>jcaptcha</servlet-name>
      <servlet-class>cn.hxex.order.core.jcaptcha.ImageCaptchaServlet</servlet-class>
      <load-on-startup>3</load-on-startup>
  </servlet>

  <servlet-mapping>
      <servlet-name>jcaptcha</servlet-name>
      <url-pattern>/captcha.jpg</url-pattern>
  </servlet-mapping>



3、jcaptcha在spring中的配置

Java代码 spring+ jcaptcha(spring框架下的彩色验证码)
  1.     <bean id="channelProcessingFilter"  
  2.           class="org.acegisecurity.securechannel.ChannelProcessingFilter">   
  3.         <property name="channelDecisionManager">   
  4.             <ref local="channelDecisionManager"/>    
  5.         </property>   
  6.         <property name="filterInvocationDefinitionSource">   
  7.             <value>   
  8.                 CONVERT_URL_TO_LOWERCASE_BEFORE_COMPARISON   
  9.                 PATTERN_TYPE_APACHE_ANT   
  10.                 /j_security_check=REQUIRES_CAPTCHA_ONCE_ABOVE_THRESOLD_REQUESTS   
  11.             </value>   
  12.         </property>   
  13.     </bean>   
  14.   
  15.     <bean id="channelDecisionManager"  
  16.           class="org.acegisecurity.securechannel.ChannelDecisionManagerImpl">   
  17.         <property name="channelProcessors">    
  18.             <list>   
  19.                 <ref local="testOnceAfterMaxRequestsCaptchaChannelProcessor"/>   
  20.                 <ref local="alwaysTestAfterTimeInMillisCaptchaChannelProcessor"/>   
  21.                 <ref local="alwaysTestAfterMaxRequestsCaptchaChannelProcessor"/>   
  22.                 <ref local="alwaysTestBelowAverageTimeInMillisBetweenRequestsChannelProcessor"/>   
  23.             </list>   
  24.         </property>   
  25.     </bean>   
  26.   
  27.     <!-- REQUIRES_CAPTCHA_ONCE_ABOVE_THRESOLD_REQUESTS -->   
  28.     <bean id="testOnceAfterMaxRequestsCaptchaChannelProcessor"  
  29.           class="org.acegisecurity.captcha.TestOnceAfterMaxRequestsCaptchaChannelProcessor">   
  30.         <property name="thresold">   
  31.             <value>0</value>   
  32.         </property>   
  33.         <property name="entryPoint">   
  34.             <ref bean="captchaEntryPoint"/>   
  35.         </property>   
  36.     </bean>   
  37.   
  38.     <!-- REQUIRES_CAPTCHA_ABOVE_THRESOLD_REQUESTS -->   
  39.     <bean id="alwaysTestAfterMaxRequestsCaptchaChannelProcessor"  
  40.           class="org.acegisecurity.captcha.AlwaysTestAfterMaxRequestsCaptchaChannelProcessor">   
  41.         <property name="thresold">   
  42.             <value>5</value>   
  43.         </property>   
  44.         <property name="entryPoint">   
  45.             <ref bean="captchaEntryPoint"/>   
  46.         </property>   
  47.     </bean>   
  48.   
  49.     <!-- REQUIRES_CAPTCHA_AFTER_THRESOLD_IN_MILLIS -->   
  50.     <bean id="alwaysTestAfterTimeInMillisCaptchaChannelProcessor"  
  51.           class="org.acegisecurity.captcha.AlwaysTestAfterTimeInMillisCaptchaChannelProcessor">   
  52.         <property name="thresold">   
  53.             <value>5000</value>   
  54.         </property>   
  55.         <property name="entryPoint">   
  56.             <ref bean="captchaEntryPoint"/>   
  57.         </property>   
  58.     </bean>   
  59.   
  60.     <!-- REQUIRES_CAPTCHA_BELOW_AVERAGE_TIME_IN_MILLIS_REQUESTS -->   
  61.         
  62.     <bean   
  63.             id="alwaysTestBelowAverageTimeInMillisBetweenRequestsChannelProcessor"  
  64.             class="org.acegisecurity.captcha.AlwaysTestBelowAverageTimeInMillisBetweenRequestsChannelProcessor">   
  65.         <property name="thresold">   
  66.             <value>20000</value>   
  67.         </property>   
  68.         <property name="entryPoint">   
  69.             <ref bean="captchaEntryPoint"/>   
  70.         </property>   
  71.     </bean>   
  72.   
  73.     <bean id="captchaEntryPoint"  
  74.           class="org.acegisecurity.captcha.CaptchaEntryPoint">   
  75.         <!--验证码验证失败后转向的页面!-->   
  76.         <property name="captchaFormUrl">   
  77.             <value>/admin/login.jsp?login_error=code_error</value>   
  78.         </property>   
  79.         <property name="includeOriginalRequest">   
  80.             <value>false</value>   
  81.         </property>   
  82.         <property name="includeOriginalParameters">   
  83.             <value>false</value>   
  84.         </property>   
  85.     </bean>   
  86.   
  87.     <bean id="captchaValidationProcessingFilter"  
  88.           class="org.acegisecurity.captcha.CaptchaValidationProcessingFilter">   
  89.         <property name="captchaService">   
  90.             <ref bean="captchaService"/>   
  91.         </property>   
  92.         <property name="captchaValidationParameter" value="j_captcha_response"/>   
  93.     </bean>   
  94.        
  95.     <!-- imageCaptchaService is injected into captchaImageCreateController as well as to captchaService beans -->   
  96.    <!--自己定义的实体类(注意路径!!)-->   
  97.     <bean id="captchaService" class="cn.hxex.order.core.jcaptcha.JCaptchaServiceProxyImpl">   
  98.         <property name="jcaptchaService" ref="imageCaptchaService"/>   
  99.     </bean>   
  100.        
  101.     <bean id="imageCaptchaService" class="com.octo.captcha.service.image.DefaultManageableImageCaptchaService">   
  102.         <constructor-arg type="com.octo.captcha.service.captchastore.CaptchaStore" index="0">   
  103.             <ref bean="fastHashMapCaptchaStore"/>   
  104.         </constructor-arg>   
  105.         <!-- (1) which captcha Engine you use -->   
  106.         <constructor-arg type="com.octo.captcha.engine.CaptchaEngine" index="1">   
  107.             <ref bean="captchaEngineEx"/>   
  108.         </constructor-arg>   
  109.         <constructor-arg index="2">   
  110.             <value>180</value>   
  111.         </constructor-arg>   
  112.         <constructor-arg index="3">   
  113.             <value>100000</value>   
  114.         </constructor-arg>   
  115.         <constructor-arg index="4">   
  116.             <value>75000</value>   
  117.         </constructor-arg>   
  118.     </bean>   
  119.   
  120.     <bean id="fastHashMapCaptchaStore" class="com.octo.captcha.service.captchastore.FastHashMapCaptchaStore"/>   
  121.   
  122.     <!-- (2) you can define more than one captcha engine here -->   
  123.     <bean id="captchaEngineEx"  
  124.           class="cn.hxex.order.core.jcaptcha.engine.CaptchaEngineEx">         
  125.     </bean>   
  126.   
  127.          <bean id="filterChainProxy"  
  128.         class="org.acegisecurity.util.FilterChainProxy">   
  129.         <property name="filterInvocationDefinitionSource">    
  130.             <value>   
  131.                 CONVERT_URL_TO_LOWERCASE_BEFORE_COMPARISON   
  132.                 PATTERN_TYPE_APACHE_ANT   
  133.                 /**=httpSessionContextIntegrationFilter,captchaValidationProcessingFilter,channelProcessingFilter,authenticationProcessingFilter,exceptionTranslationFilter,filterInvocationInterceptor   
  134.             </value>   
  135.         </property>   
  136.     </bean>   
  137.   
  138.          <bean id="httpSessionContextIntegrationFilter"  
  139.         class="org.acegisecurity.context.HttpSessionContextIntegrationFilter">   
  140.         <!-- 将下面的property注释掉,验证码将无效!!! -->   
  141.         <property name="context">   
  142.             <value>   
  143.                 org.acegisecurity.captcha.CaptchaSecurityContextImpl   
  144.             </value>   
  145.         </property>   
  146.     </bean>   
  147. ·············省略了一些spring安全框架的bean,自己加去吧  
    <bean id="channelProcessingFilter"
          class="org.acegisecurity.securechannel.ChannelProcessingFilter">
        <property name="channelDecisionManager">
            <ref local="channelDecisionManager"/> 
        </property>
        <property name="filterInvocationDefinitionSource">
            <value>
                CONVERT_URL_TO_LOWERCASE_BEFORE_COMPARISON
                PATTERN_TYPE_APACHE_ANT
                /j_security_check=REQUIRES_CAPTCHA_ONCE_ABOVE_THRESOLD_REQUESTS
            </value>
        </property>
    </bean>

    <bean id="channelDecisionManager"
          class="org.acegisecurity.securechannel.ChannelDecisionManagerImpl">
        <property name="channelProcessors"> 
            <list>
                <ref local="testOnceAfterMaxRequestsCaptchaChannelProcessor"/>
                <ref local="alwaysTestAfterTimeInMillisCaptchaChannelProcessor"/>
                <ref local="alwaysTestAfterMaxRequestsCaptchaChannelProcessor"/>
                <ref local="alwaysTestBelowAverageTimeInMillisBetweenRequestsChannelProcessor"/>
            </list>
        </property>
    </bean>

    <!-- REQUIRES_CAPTCHA_ONCE_ABOVE_THRESOLD_REQUESTS -->
    <bean id="testOnceAfterMaxRequestsCaptchaChannelProcessor"
          class="org.acegisecurity.captcha.TestOnceAfterMaxRequestsCaptchaChannelProcessor">
        <property name="thresold">
            <value>0</value>
        </property>
        <property name="entryPoint">
            <ref bean="captchaEntryPoint"/>
        </property>
    </bean>

    <!-- REQUIRES_CAPTCHA_ABOVE_THRESOLD_REQUESTS -->
    <bean id="alwaysTestAfterMaxRequestsCaptchaChannelProcessor"
          class="org.acegisecurity.captcha.AlwaysTestAfterMaxRequestsCaptchaChannelProcessor">
        <property name="thresold">
            <value>5</value>
        </property>
        <property name="entryPoint">
            <ref bean="captchaEntryPoint"/>
        </property>
    </bean>

    <!-- REQUIRES_CAPTCHA_AFTER_THRESOLD_IN_MILLIS -->
    <bean id="alwaysTestAfterTimeInMillisCaptchaChannelProcessor"
          class="org.acegisecurity.captcha.AlwaysTestAfterTimeInMillisCaptchaChannelProcessor">
        <property name="thresold">
            <value>5000</value>
        </property>
        <property name="entryPoint">
            <ref bean="captchaEntryPoint"/>
        </property>
    </bean>

    <!-- REQUIRES_CAPTCHA_BELOW_AVERAGE_TIME_IN_MILLIS_REQUESTS -->
     
    <bean
            id="alwaysTestBelowAverageTimeInMillisBetweenRequestsChannelProcessor"
            class="org.acegisecurity.captcha.AlwaysTestBelowAverageTimeInMillisBetweenRequestsChannelProcessor">
        <property name="thresold">
            <value>20000</value>
        </property>
        <property name="entryPoint">
            <ref bean="captchaEntryPoint"/>
        </property>
    </bean>

    <bean id="captchaEntryPoint"
          class="org.acegisecurity.captcha.CaptchaEntryPoint">
        <!--验证码验证失败后转向的页面!-->
        <property name="captchaFormUrl">
            <value>/admin/login.jsp?login_error=code_error</value>
        </property>
        <property name="includeOriginalRequest">
            <value>false</value>
        </property>
        <property name="includeOriginalParameters">
            <value>false</value>
        </property>
    </bean>

    <bean id="captchaValidationProcessingFilter"
          class="org.acegisecurity.captcha.CaptchaValidationProcessingFilter">
        <property name="captchaService">
            <ref bean="captchaService"/>
        </property>
        <property name="captchaValidationParameter" value="j_captcha_response"/>
    </bean>
    
    <!-- imageCaptchaService is injected into captchaImageCreateController as well as to captchaService beans -->
   <!--自己定义的实体类(注意路径!!)-->
    <bean id="captchaService" class="cn.hxex.order.core.jcaptcha.JCaptchaServiceProxyImpl">
        <property name="jcaptchaService" ref="imageCaptchaService"/>
    </bean>
    
    <bean id="imageCaptchaService" class="com.octo.captcha.service.image.DefaultManageableImageCaptchaService">
        <constructor-arg type="com.octo.captcha.service.captchastore.CaptchaStore" index="0">
            <ref bean="fastHashMapCaptchaStore"/>
        </constructor-arg>
        <!-- (1) which captcha Engine you use -->
        <constructor-arg type="com.octo.captcha.engine.CaptchaEngine" index="1">
            <ref bean="captchaEngineEx"/>
        </constructor-arg>
        <constructor-arg index="2">
            <value>180</value>
        </constructor-arg>
        <constructor-arg index="3">
            <value>100000</value>
        </constructor-arg>
        <constructor-arg index="4">
            <value>75000</value>
        </constructor-arg>
    </bean>

    <bean id="fastHashMapCaptchaStore" class="com.octo.captcha.service.captchastore.FastHashMapCaptchaStore"/>

    <!-- (2) you can define more than one captcha engine here -->
    <bean id="captchaEngineEx"
          class="cn.hxex.order.core.jcaptcha.engine.CaptchaEngineEx">      
    </bean>

         <bean id="filterChainProxy"
		class="org.acegisecurity.util.FilterChainProxy">
		<property name="filterInvocationDefinitionSource"> 
			<value>
				CONVERT_URL_TO_LOWERCASE_BEFORE_COMPARISON
				PATTERN_TYPE_APACHE_ANT
				/**=httpSessionContextIntegrationFilter,captchaValidationProcessingFilter,channelProcessingFilter,authenticationProcessingFilter,exceptionTranslationFilter,filterInvocationInterceptor
			</value>
		</property>
	</bean>

         <bean id="httpSessionContextIntegrationFilter"
		class="org.acegisecurity.context.HttpSessionContextIntegrationFilter">
		<!-- 将下面的property注释掉,验证码将无效!!! -->
		<property name="context">
			<value>
				org.acegisecurity.captcha.CaptchaSecurityContextImpl
			</value>
		</property>
	</bean>
·············省略了一些spring安全框架的bean,自己加去吧



4、编写jcaptcha的实体类

实体类包的路径一定要和spring配置文件里的路径一样

(1)CaptchaEngine 类

Java代码 spring+ jcaptcha(spring框架下的彩色验证码)
  1. package cn.hxex.order.core.jcaptcha.engine;   
  2.   
  3. import java.awt.Color;   
  4.   
  5. import com.octo.captcha.component.image.backgroundgenerator.BackgroundGenerator;   
  6. import com.octo.captcha.component.image.backgroundgenerator   
  7.   .FunkyBackgroundGenerator;   
  8. import com.octo.captcha.component.image.fontgenerator.FontGenerator;   
  9. import com.octo.captcha.component.image.fontgenerator   
  10.   .TwistedAndShearedRandomFontGenerator;   
  11. import com.octo.captcha.component.image.textpaster.RandomTextPaster;   
  12. import com.octo.captcha.component.image.textpaster.TextPaster;   
  13. import com.octo.captcha.component.image.wordtoimage.ComposedWordToImage;   
  14. import com.octo.captcha.component.image.wordtoimage.WordToImage;   
  15. import com.octo.captcha.component.word.wordgenerator.RandomWordGenerator;   
  16. import com.octo.captcha.component.word.wordgenerator.WordGenerator;   
  17. import com.octo.captcha.engine.image.ListImageCaptchaEngine;   
  18. import com.octo.captcha.image.gimpy.GimpyFactory;   
  19.   
  20. /**  
  21.  * SpringSide Custom的认证图片  
  22.  *   
  23.  * @author cac  
  24.  */  
  25. public class CaptchaEngine extends ListImageCaptchaEngine {   
  26.   /**  
  27.    * @see ListImageCaptchaEngine  
  28.    */  
  29.   protected void buildInitialFactories() {   
  30.     WordGenerator wordGenerator    
  31.       = new RandomWordGenerator("023456789");   
  32.     // nteger minAcceptedWordLength, Integer maxAcceptedWordLength,Color[]   
  33.     // textColors   
  34.     TextPaster textPaster = new RandomTextPaster(4,5, Color.WHITE);   
  35.     // Integer width, Integer height   
  36.     BackgroundGenerator backgroundGenerator    
  37.       = new FunkyBackgroundGenerator(100,40);   
  38.     // Integer minFontSize, Integer maxFontSize   
  39.     FontGenerator fontGenerator = new TwistedAndShearedRandomFontGenerator(2022);   
  40.     WordToImage wordToImage = new ComposedWordToImage(fontGenerator,   
  41.         backgroundGenerator, textPaster);   
  42.     addFactory(new GimpyFactory(wordGenerator, wordToImage));   
  43.   }   
  44. }  
package cn.hxex.order.core.jcaptcha.engine;

import java.awt.Color;

import com.octo.captcha.component.image.backgroundgenerator.BackgroundGenerator;
import com.octo.captcha.component.image.backgroundgenerator
  .FunkyBackgroundGenerator;
import com.octo.captcha.component.image.fontgenerator.FontGenerator;
import com.octo.captcha.component.image.fontgenerator
  .TwistedAndShearedRandomFontGenerator;
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;

/**
 * SpringSide Custom的认证图片
 * 
 * @author cac
 */
public class CaptchaEngine extends ListImageCaptchaEngine {
  /**
   * @see ListImageCaptchaEngine
   */
  protected void buildInitialFactories() {
    WordGenerator wordGenerator 
      = new RandomWordGenerator("023456789");
    // nteger minAcceptedWordLength, Integer maxAcceptedWordLength,Color[]
    // textColors
    TextPaster textPaster = new RandomTextPaster(4,5, Color.WHITE);
    // Integer width, Integer height
    BackgroundGenerator backgroundGenerator 
      = new FunkyBackgroundGenerator(100,40);
    // Integer minFontSize, Integer maxFontSize
    FontGenerator fontGenerator = new TwistedAndShearedRandomFontGenerator(20, 22);
    WordToImage wordToImage = new ComposedWordToImage(fontGenerator,
        backgroundGenerator, textPaster);
    addFactory(new GimpyFactory(wordGenerator, wordToImage));
  }
}


(2)CaptchaEngineEx 类

Java代码 spring+ jcaptcha(spring框架下的彩色验证码)
  1. package cn.hxex.order.core.jcaptcha.engine;   
  2.   
  3. import java.awt.Color;   
  4.   
  5. import com.octo.captcha.component.image.backgroundgenerator.BackgroundGenerator;   
  6. import com.octo.captcha.component.image.backgroundgenerator   
  7.   .GradientBackgroundGenerator;   
  8. import com.octo.captcha.component.image.color.SingleColorGenerator;   
  9. import com.octo.captcha.component.image.fontgenerator.FontGenerator;   
  10. import com.octo.captcha.component.image.fontgenerator.RandomFontGenerator;   
  11. import com.octo.captcha.component.image.textpaster.DecoratedRandomTextPaster;   
  12. import com.octo.captcha.component.image.textpaster.TextPaster;   
  13. import com.octo.captcha.component.image.textpaster.textdecorator   
  14.   .BaffleTextDecorator;   
  15. import com.octo.captcha.component.image.textpaster.textdecorator   
  16.   .LineTextDecorator;   
  17. import com.octo.captcha.component.image.textpaster.textdecorator.TextDecorator;   
  18. import com.octo.captcha.component.image.wordtoimage.ComposedWordToImage;   
  19. import com.octo.captcha.component.image.wordtoimage.WordToImage;   
  20. import com.octo.captcha.component.word.wordgenerator.RandomWordGenerator;   
  21. import com.octo.captcha.component.word.wordgenerator.WordGenerator;   
  22. import com.octo.captcha.engine.image.ListImageCaptchaEngine;   
  23. import com.octo.captcha.image.gimpy.GimpyFactory;   
  24.   
  25.   
  26. /**  
  27.  * Captcha增强版本  
  28.  *   
  29.  * @author [email protected]  
  30.  * @modifyTime 21:01:52  
  31.  * @description   
  32.  * <pre>  
  33.  *  安装 Captcha Instruction <br>  
  34.  *  1.add captchaValidationProcessingFilter   
  35.  *    to applicationContext-acegi-security.xml<br>  
  36.  *  2.modify applicationContext-captcha-security.xml  
  37.  *    <ul>  
  38.  *    <li> make sure that captchaValidationProcessingFilter Call captchaService  
  39.       <li> config CaptchaEngine for captchaService (refer imageCaptchaService)   
  40.       <li> write your own CaptchaEngine  
  41.       <li> config the following, so that We use CaptchaEngineEx to generate the   
  42.           captcha image.   
  43.       </ul>  
  44.           <constructor-arg  
  45.  *              type="com.octo.captcha.engine.CaptchaEngine" index="1">   
  46.  *              <ref bean="captchaEngineEx"/gt; </constructor-arg>   
  47.  * </pre>  
  48.  */  
  49. public class CaptchaEngineEx extends ListImageCaptchaEngine {   
  50.   /**  
  51.    * ...  
  52.    */  
  53.   protected void buildInitialFactories() {   
  54.        
  55.      //Set Captcha Word Length Limitation which should not over 6        
  56.     Integer minAcceptedWordLength = new Integer(4);   
  57.     Integer maxAcceptedWordLength = new Integer(5);   
  58.     //Set up Captcha Image Size: Height and Width       
  59.     Integer imageHeight = new Integer(40);   
  60.     Integer imageWidth = new Integer(100);   
  61.        
  62.     //Set Captcha Font Size       
  63.     Integer minFontSize = new Integer(20);   
  64.     Integer maxFontSize = new Integer(22);   
  65.     //We just generate digit for captcha source char Although you can use   
  66.     //abcdefg......xyz   
  67.     WordGenerator wordGenerator    
  68.       = new RandomWordGenerator("023456789");   
  69.     
  70.      //cyt and unruledboy proved that backgroup not a factor of Security. A   
  71.      //captcha attacker won't affaid colorful backgroud, so we just use white   
  72.      //color, like google and hotmail.     
  73.     BackgroundGenerator backgroundGenerator = new GradientBackgroundGenerator(   
  74.         imageWidth, imageHeight, Color.white, Color.white);   
  75.      
  76.      //font is not helpful for security but it really increase difficultness for   
  77.      //attacker        
  78.     FontGenerator fontGenerator = new RandomFontGenerator(minFontSize,   
  79.         maxFontSize);       
  80.      // Note that our captcha color is Blue        
  81.     SingleColorGenerator scg = new SingleColorGenerator(Color.blue);   
  82.      
  83.      //decorator is very useful pretend captcha attack. we use two line text   
  84.      //decorators.   
  85.         
  86.     LineTextDecorator lineDecorator = new LineTextDecorator(1, Color.blue);   
  87.     // LineTextDecorator line_decorator2 = new LineTextDecorator(1, Color.blue);   
  88.     TextDecorator[] textdecorators = new TextDecorator[1];   
  89.   
  90.     textdecorators[0] = lineDecorator;   
  91.     // textdecorators[1] = line_decorator2;   
  92.   
  93.     TextPaster textPaster = new DecoratedRandomTextPaster(   
  94.         minAcceptedWordLength, maxAcceptedWordLength, scg,   
  95.         new TextDecorator[] { new BaffleTextDecorator(new Integer(1),   
  96.             Color.white) });   
  97.   
  98.     //ok, generate the WordTo
  99. 手机扫一扫,关注程序员技能成长

    spring+ jcaptcha(spring框架下的彩色验证码)

  100.