kaptcha生成验证码插件在html页面中使用为什么会报错求大牛指点迷津,不胜感激。

如下是代码
第一部分是web.xml的配置
<?xml version="1.0" encoding="UTF-8"?>

s2sh

index.html
index.htm
index.jsp
default.html
default.htm
default.jsp


spring
org.springframework.web.servlet.DispatcherServlet
0


spring
.do


encodingFilter
org.springframework.web.filter.CharacterEncodingFilter

encoding
UTF-8


forceEncoding
true



encodingFilter
/


org.springframework.web.context.ContextLoaderListener


contextConfigLocation
classpath:applicationContext.xml

<!-- 生成验证码配置 servlet-->

Kaptcha
com.google.code.kaptcha.servlet.KaptchaServlet


Kaptcha
/kaptcha.jpg


接下来是页面的代码,我用的是html,这块声明一下这个配置用jsp是没有问题的,只是挪到了html页面中不知怎地就报错了,不影响页面生成验证码图片,但是后台是取不到session中的字符串的,因为session并没有创建,报的错也是session不能在response相应后创建。
<!-- 验证码开始 -->
                      <div> 
                        <img src="../kaptcha.jpg" id="kaptchaImage" width="300px" height="50px" style="padding-top: 25px; "/>
                        <input type="text" class="form-control col-xs-4" id="passWord" placeholder="请输入验证码" >

                      </div>
                      <!-- 验证码结束 -->

接下来是页面点击图片生成验证码的js代码

$(function(){ $('#kaptchaImage').click(function () { $(this).attr('src', '../kaptcha.jpg?' + Math.floor(Math.random()*100) ); }); });

然后以下是报错信息

三月 24, 2017 9:28:41 上午 org.apache.catalina.core.StandardWrapperValve invoke
严重: Servlet.service() for servlet [Kaptcha] in context with path [/webapp] threw exception
java.lang.IllegalStateException: Cannot create a session after the response has been committed
at org.apache.catalina.connector.Request.doGetSession(Request.java:3016)
at org.apache.catalina.connector.Request.getSession(Request.java:2385)
at org.apache.catalina.connector.RequestFacade.getSession(RequestFacade.java:897)
at org.apache.catalina.connector.RequestFacade.getSession(RequestFacade.java:909)
at com.google.code.kaptcha.servlet.KaptchaServlet.doGet(KaptchaServlet.java:91)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:624)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:731)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:303)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208)
at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:241)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208)
at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:197)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:241)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:220)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:122)
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:505)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:170)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:103)
at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:956)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:116)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:423)
at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1079)
at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:625)
at org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:318)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
at java.lang.Thread.run(Thread.java:745)
*

报错内容有路径错误,有服务器请求错误JSP的页面直接在HTML中有很多都是会出现各种错误的,因为两者有太多不同的问题。

最终解决办法就是不在html中使用该插件,html中使用自定义的插件,因为我也没查到什么插件在这种情况下使用比较好。

遇到相同的问题,页面是 HTML 。

查看源码:KaptchaServlet

 /** */
    @Override
    public void doGet(HttpServletRequest req, HttpServletResponse resp)
            throws ServletException, IOException
    {
        // Set standard HTTP/1.1 no-cache headers.
        resp.setHeader("Cache-Control", "no-store, no-cache");

        // return a jpeg
        resp.setContentType("image/jpeg");

        // create the text for the image
        String capText = this.kaptchaProducer.createText();

        // create the image with the text
        BufferedImage bi = this.kaptchaProducer.createImage(capText);

        ServletOutputStream out = resp.getOutputStream();

        // write the data out
        ImageIO.write(bi, "jpg", out);

        // fixes issue #69: set the attributes after we write the image in case the image writing fails.

        // store the text in the session
        req.getSession().setAttribute(this.sessionKeyValue, capText);

        // store the date in the session so that it can be compared
        // against to make sure someone hasn't taken too long to enter
        // their kaptcha
        req.getSession().setAttribute(this.sessionKeyDateValue, new Date());
    }

ImageIO.write(bi, 'jpg', out) ;
执行之后,response 已经关闭了。
之后的

        // fixes issue #69: set the attributes after we write the image in case the image writing fails.

        // store the text in the session
        req.getSession().setAttribute(this.sessionKeyValue, capText);

        // store the date in the session so that it can be compared
        // against to make sure someone hasn't taken too long to enter
        // their kaptcha
        req.getSession().setAttribute(this.sessionKeyDateValue, new Date());

有通过 response 获取 Session,此时就会报错。
解决办法很简单:
创建一个自己的 Servlet

/**
 * 
 * @author TroyLiu
 *
 */
@SuppressWarnings("serial")
public class KaptchaHtmlServlet extends HttpServlet implements Servlet{

    private Properties props = new Properties();

    private Producer kaptchaProducer = null;

    private String sessionKeyValue = null;

    private String sessionKeyDateValue = null;

    /*
     * (non-Javadoc)
     *
     * @see javax.servlet.Servlet#init(javax.servlet.ServletConfig)
     */
    @Override
    public void init(ServletConfig conf) throws ServletException
    {
        super.init(conf);

        // Switch off disk based caching.
        ImageIO.setUseCache(false);

        Enumeration<?> initParams = conf.getInitParameterNames();
        while (initParams.hasMoreElements())
        {
            String key = (String) initParams.nextElement();
            String value = conf.getInitParameter(key);
            this.props.put(key, value);
        }

        Config config = new Config(this.props);
        this.kaptchaProducer = config.getProducerImpl();
        this.sessionKeyValue = config.getSessionKey();
        this.sessionKeyDateValue = config.getSessionDate();
    }


    /** */
    @Override
    public void doGet(HttpServletRequest req, HttpServletResponse resp)
            throws ServletException, IOException
    {
        // Set standard HTTP/1.1 no-cache headers.
        resp.setHeader("Cache-Control", "no-store, no-cache");

        // return a jpeg
        resp.setContentType("image/jpeg");


        // create the text for the image
        String capText = this.kaptchaProducer.createText();

        // create the image with the text
        BufferedImage bi = this.kaptchaProducer.createImage(capText);

        // store the text in the session
        req.getSession().setAttribute(this.sessionKeyValue, capText);

        // store the date in the session so that it can be compared
        // against to make sure someone hasn't taken too long to enter
        // their kaptcha
        req.getSession().setAttribute(this.sessionKeyDateValue, new Date());


        ServletOutputStream out = resp.getOutputStream();
        // write the data out
        ImageIO.write(bi, "jpg", out);

        // fixes issue #69: set the attributes after we write the image in case the image writing fails.

    }

直接先执行 req.getSession() .... 最后执行 ImageIO.write() ;

在 Web.xml 配置拦截器时指定自己的拦截器

<servlet>  
    <servlet-name>Kaptcha</servlet-name>  
    <servlet-class>com.troyliu.interceptors.KaptchaHtmlServlet</servlet-class>  
    <init-param>  
        <param-name>kaptcha.border</param-name>    <!-- 是否有边框 -->  
        <param-value>no</param-value>  
    </init-param>  
    <init-param>  
        <param-name>kaptcha.textproducer.char.space</param-name>   <!--字符之间的间距 -->  
        <param-value>8</param-value>  
    </init-param>  
    <init-param>  
        <param-name>kaptcha.textproducer.char.length</param-name>   <!-- 字符的个数 -->  
        <param-value>4</param-value>  
    </init-param>    
  </servlet>  

问题解决。
JSP 可以使用的原因,是因为 JSP 本质上也属于 servlet 的一种,当 ImageIO.write() 执行完后,response 并没有关闭。
而 HTML 不同。