使用 jcaptcha 产生图片校验码

使用 jcaptcha 产生图片校验码

具体使用的例子: www.tongriben.com

第一步:下载 jcaptcha-all-1.0-RC2.0.1.jar
第二步:代码实现
CaptchaServiceSingleton.java
Java代码 复制代码
  1.     
  2. package com.yh.web.jcaptcha;   
  3.   
  4. import java.awt.Color;   
  5. import java.awt.image.BufferedImage;   
  6. import java.io.IOException;   
  7. import java.io.OutputStream;   
  8. import java.util.ArrayList;   
  9. import java.util.Iterator;   
  10.   
  11. import javax.servlet.http.HttpServletRequest;   
  12. import javax.servlet.http.HttpServletResponse;   
  13. import javax.servlet.http.HttpSession;   
  14.   
  15. import org.apache.log4j.Logger;   
  16.   
  17. import com.octo.captcha.component.image.backgroundgenerator.BackgroundGenerator;   
  18. import com.octo.captcha.component.image.backgroundgenerator.GradientBackgroundGenerator;   
  19. import com.octo.captcha.component.image.fontgenerator.FontGenerator;   
  20. import com.octo.captcha.component.image.fontgenerator.RandomFontGenerator;   
  21. import com.octo.captcha.component.image.textpaster.RandomTextPaster;   
  22. import com.octo.captcha.component.image.textpaster.SimpleTextPaster;   
  23. import com.octo.captcha.component.image.textpaster.TextPaster;   
  24. import com.octo.captcha.component.image.wordtoimage.ComposedWordToImage;   
  25. import com.octo.captcha.component.image.wordtoimage.WordToImage;   
  26. import com.octo.captcha.component.wordgenerator.RandomWordGenerator;   
  27. import com.octo.captcha.component.wordgenerator.WordGenerator;   
  28. import com.octo.captcha.engine.image.ListImageCaptchaEngine;   
  29. import com.octo.captcha.image.ImageCaptcha;   
  30. import com.octo.captcha.image.ImageCaptchaFactory;   
  31. import com.octo.captcha.image.gimpy.GimpyFactory;   
  32. import com.sun.image.codec.jpeg.JPEGCodec;   
  33. import com.sun.image.codec.jpeg.JPEGImageEncoder;   
  34.   
  35. public class CaptchaServiceSingleton extends ListImageCaptchaEngine {   
  36.     private static Logger log = Logger.getLogger(CaptchaServiceSingleton.class);   
  37.   
  38.     private static final Integer MIN_WORD_LENGTH = new Integer(4);   
  39.   
  40.     private static final Integer MAX_WORD_LENGTH = new Integer(6);   
  41.   
  42.     private static final Integer IMAGE_WIDTH = new Integer(70);   
  43.   
  44.     private static final Integer IMAGE_HEIGHT = new Integer(20);   
  45.   
  46.     private static final Integer MIN_FONT_SIZE = new Integer(12);   
  47.   
  48.     private static final Integer MAX_FONT_SIZE = new Integer(14);   
  49.   
  50.     private static final String NUMERIC_CHARS = "23456789";// No numeric 0   
  51.   
  52.     private static final String UPPER_ASCII_CHARS = "ABCDEFGHJKLMNPQRSTXYZ";// No   
  53.   
  54.     // upper   
  55.     // O I   
  56.   
  57.     // we dont use the lower characters because it cause dificult in some case,   
  58.     // so that   
  59.     // we must always UPPERCASE the input from user (currently in   
  60.     // OnlineUserImpl)   
  61.     private static final String LOWER_ASCII_CHARS = "abcdefghjkmnpqrstxyz";// No   
  62.   
  63.     // lower   
  64.     // o i   
  65.   
  66.     /**  
  67.      * Singleton instance of this class  
  68.      */  
  69.     private static CaptchaServiceSingleton instance = new CaptchaServiceSingleton();   
  70.   
  71.     private ArrayList textPasterList;   
  72.   
  73.     private ArrayList backgroundGeneratorList;   
  74.   
  75.     private ArrayList fontGeneratorList;   
  76.   
  77.     ImageCaptcha imageCaptcha = null;   
  78.   
  79.     /**  
  80.      * Private constructor to prevent instantiation  
  81.      */  
  82.     private CaptchaServiceSingleton() {   
  83.     }   
  84.   
  85.     public static CaptchaServiceSingleton getInstance() {   
  86.         return instance;   
  87.     }   
  88.   
  89.     protected void buildInitialFactories() {   
  90.         try {   
  91.             textPasterList = new ArrayList();   
  92.             backgroundGeneratorList = new ArrayList();   
  93.             fontGeneratorList = new ArrayList();   
  94.   
  95.             textPasterList.add(new SimpleTextPaster(MIN_WORD_LENGTH,   
  96.                     MAX_WORD_LENGTH, Color.black));   
  97.             textPasterList.add(new RandomTextPaster(MIN_WORD_LENGTH,   
  98.                     MAX_WORD_LENGTH, Color.black));   
  99.             textPasterList.add(new SimpleTextPaster(MIN_WORD_LENGTH,   
  100.                     MAX_WORD_LENGTH, Color.black));   
  101.             textPasterList.add(new RandomTextPaster(MIN_WORD_LENGTH,   
  102.                     MAX_WORD_LENGTH, Color.black));   
  103.             textPasterList.add(new SimpleTextPaster(MIN_WORD_LENGTH,   
  104.                     MAX_WORD_LENGTH, Color.blue));   
  105.             textPasterList.add(new RandomTextPaster(MIN_WORD_LENGTH,   
  106.                     MAX_WORD_LENGTH, Color.blue));   
  107.   
  108.             backgroundGeneratorList.add(new GradientBackgroundGenerator(   
  109.                     IMAGE_WIDTH, IMAGE_HEIGHT, Color.orange, Color.white));   
  110.             backgroundGeneratorList.add(new GradientBackgroundGenerator(   
  111.                     IMAGE_WIDTH, IMAGE_HEIGHT, Color.white, Color.green));   
  112.             backgroundGeneratorList.add(new GradientBackgroundGenerator(   
  113.                     IMAGE_WIDTH, IMAGE_HEIGHT, Color.gray, Color.white));   
  114.             backgroundGeneratorList.add(new GradientBackgroundGenerator(   
  115.                     IMAGE_WIDTH, IMAGE_HEIGHT, Color.white, Color.orange));   
  116.             backgroundGeneratorList.add(new GradientBackgroundGenerator(   
  117.                     IMAGE_WIDTH, IMAGE_HEIGHT, Color.green, Color.white));   
  118.             backgroundGeneratorList.add(new GradientBackgroundGenerator(   
  119.                     IMAGE_WIDTH, IMAGE_HEIGHT, Color.yellow, Color.white));   
  120.             backgroundGeneratorList.add(new GradientBackgroundGenerator(   
  121.                     IMAGE_WIDTH, IMAGE_HEIGHT, Color.white, Color.magenta));   
  122.   
  123.                
  124.   
  125.             // fontGeneratorList.add(new   
  126.             // TwistedAndShearedRandomFontGenerator(MIN_FONT_SIZE,   
  127.             // MAX_FONT_SIZE));   
  128.             // fontGeneratorList.add(new   
  129.             // TwistedRandomFontGenerator(MIN_FONT_SIZE, MAX_FONT_SIZE));// link   
  130.             // character too much   
  131.             fontGeneratorList.add(new RandomFontGenerator(MIN_FONT_SIZE,   
  132.                     MAX_FONT_SIZE));// to easy to read   
  133.             // fontGeneratorList.add(new   
  134.             // DeformedRandomFontGenerator(MIN_FONT_SIZE, MAX_FONT_SIZE));// to   
  135.             // small font   
  136.   
  137.             // no char upper O, char lower o and numerric 0 because user cannot   
  138.             // answer   
  139.             WordGenerator words = new RandomWordGenerator(NUMERIC_CHARS   
  140.                     + UPPER_ASCII_CHARS);   
  141.   
  142.             for (Iterator fontIter = fontGeneratorList.iterator(); fontIter   
  143.                     .hasNext();) {   
  144.                 FontGenerator font = (FontGenerator) fontIter.next();   
  145.                 for (Iterator backIter = backgroundGeneratorList.iterator(); backIter   
  146.                         .hasNext();) {   
  147.                     BackgroundGenerator back = (BackgroundGenerator) backIter   
  148.                             .next();   
  149.                     for (Iterator textIter = textPasterList.iterator(); textIter   
  150.                             .hasNext();) {   
  151.                         TextPaster parser = (TextPaster) textIter.next();   
  152.   
  153.                         WordToImage word2image = new ComposedWordToImage(font,   
  154.                                 back, parser);   
  155.                         ImageCaptchaFactory factory = new GimpyFactory(words,   
  156.                                 word2image);   
  157.                         addFactory(factory);   
  158.                     }   
  159.                 }   
  160.             }   
  161.         } catch (Exception ex) {   
  162.             log.error("产生校验码初始化异常 == " + ex);   
  163.             // throw ex;   
  164.         }   
  165.     }   
  166.   
  167.     /**  
  168.      * Write the captcha image of current user to the servlet response  
  169.      *   
  170.      * @param request  
  171.      *            HttpServletRequest  
  172.      * @param response  
  173.      *            HttpServletResponse  
  174.      * @throws IOException  
  175.      */  
  176.     public void writeCaptchaImage(HttpServletRequest request,   
  177.             HttpServletResponse response) throws IOException {   
  178.   
  179.         imageCaptcha = getNextImageCaptcha();   
  180.         HttpSession session = request.getSession();   
  181.         session.setAttribute("imageCaptcha", imageCaptcha);   
  182.         BufferedImage image = (BufferedImage) imageCaptcha.getChallenge();   
  183.   
  184.         OutputStream outputStream = null;   
  185.         try {   
  186.             outputStream = response.getOutputStream();   
  187.             // render the captcha challenge as a JPEG image in the response   
  188.             response.setHeader("Cache-Control""no-store");   
  189.             response.setHeader("Pragma""no-cache");   
  190.             response.setDateHeader("Expires"0);   
  191.   
  192.             response.setContentType("image/jpeg");   
  193.   
  194.             JPEGImageEncoder encoder = JPEGCodec   
  195.                     .createJPEGEncoder(outputStream);   
  196.             encoder.encode(image);   
  197.   
  198.             outputStream.flush();   
  199.             outputStream.close();   
  200.             outputStream = null;// no close twice   
  201.         } catch (IOException ex) {   
  202.             log.error("产生图片异常 == " + ex);   
  203.             throw ex;   
  204.         } finally {   
  205.             if (outputStream != null) {   
  206.                 try {   
  207.                     outputStream.close();   
  208.                 } catch (IOException ex) {   
  209.                 }   
  210.             }   
  211.             imageCaptcha.disposeChallenge();   
  212.         }   
  213.     }   
  214.   
  215.     public boolean validateCaptchaResponse(String validateCode,   
  216.             HttpSession session) {   
  217.         boolean flag = true;   
  218.         try {   
  219.             imageCaptcha = (ImageCaptcha) session.getAttribute("imageCaptcha");   
  220.             if (imageCaptcha == null) {   
  221.                 // log.info("validateCaptchaResponse returned false due to   
  222.                 // imageCaptcha is null");   
  223.                 flag = false;   
  224.             }   
  225.             //validateCode = validateCode.toLowerCase();// use upper case for   
  226.             validateCode = validateCode.toUpperCase();// use upper case for   
  227.             // easier usage   
  228. flag = (imageCaptcha.validateResponse(validateCode)).booleanValue();   
  229.             session.removeAttribute("imageCaptcha");   
  230.             return flag;   
  231.         } catch (Exception ex) {   
  232.             ex.printStackTrace();   
  233.             log.error("校验码校验异常 == " + ex);   
  234.             return false;   
  235.         }   
  236.     }   
  237.        
  238. }  
 
package com.yh.web.jcaptcha;

import java.awt.Color;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Iterator;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import org.apache.log4j.Logger;

import com.octo.captcha.component.image.backgroundgenerator.BackgroundGenerator;
import com.octo.captcha.component.image.backgroundgenerator.GradientBackgroundGenerator;
import com.octo.captcha.component.image.fontgenerator.FontGenerator;
import com.octo.captcha.component.image.fontgenerator.RandomFontGenerator;
import com.octo.captcha.component.image.textpaster.RandomTextPaster;
import com.octo.captcha.component.image.textpaster.SimpleTextPaster;
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.wordgenerator.RandomWordGenerator;
import com.octo.captcha.component.wordgenerator.WordGenerator;
import com.octo.captcha.engine.image.ListImageCaptchaEngine;
import com.octo.captcha.image.ImageCaptcha;
import com.octo.captcha.image.ImageCaptchaFactory;
import com.octo.captcha.image.gimpy.GimpyFactory;
import com.sun.image.codec.jpeg.JPEGCodec;
import com.sun.image.codec.jpeg.JPEGImageEncoder;

public class CaptchaServiceSingleton extends ListImageCaptchaEngine {
	private static Logger log = Logger.getLogger(CaptchaServiceSingleton.class);

	private static final Integer MIN_WORD_LENGTH = new Integer(4);

	private static final Integer MAX_WORD_LENGTH = new Integer(6);

	private static final Integer IMAGE_WIDTH = new Integer(70);

	private static final Integer IMAGE_HEIGHT = new Integer(20);

	private static final Integer MIN_FONT_SIZE = new Integer(12);

	private static final Integer MAX_FONT_SIZE = new Integer(14);

	private static final String NUMERIC_CHARS = "23456789";// No numeric 0

	private static final String UPPER_ASCII_CHARS = "ABCDEFGHJKLMNPQRSTXYZ";// No

	// upper
	// O I

	// we dont use the lower characters because it cause dificult in some case,
	// so that
	// we must always UPPERCASE the input from user (currently in
	// OnlineUserImpl)
	private static final String LOWER_ASCII_CHARS = "abcdefghjkmnpqrstxyz";// No

	// lower
	// o i

	/**
	 * Singleton instance of this class
	 */
	private static CaptchaServiceSingleton instance = new CaptchaServiceSingleton();

	private ArrayList textPasterList;

	private ArrayList backgroundGeneratorList;

	private ArrayList fontGeneratorList;

	ImageCaptcha imageCaptcha = null;

	/**
	 * Private constructor to prevent instantiation
	 */
	private CaptchaServiceSingleton() {
	}

	public static CaptchaServiceSingleton getInstance() {
		return instance;
	}

	protected void buildInitialFactories() {
		try {
			textPasterList = new ArrayList();
			backgroundGeneratorList = new ArrayList();
			fontGeneratorList = new ArrayList();

			textPasterList.add(new SimpleTextPaster(MIN_WORD_LENGTH,
					MAX_WORD_LENGTH, Color.black));
			textPasterList.add(new RandomTextPaster(MIN_WORD_LENGTH,
					MAX_WORD_LENGTH, Color.black));
			textPasterList.add(new SimpleTextPaster(MIN_WORD_LENGTH,
					MAX_WORD_LENGTH, Color.black));
			textPasterList.add(new RandomTextPaster(MIN_WORD_LENGTH,
					MAX_WORD_LENGTH, Color.black));
			textPasterList.add(new SimpleTextPaster(MIN_WORD_LENGTH,
					MAX_WORD_LENGTH, Color.blue));
			textPasterList.add(new RandomTextPaster(MIN_WORD_LENGTH,
					MAX_WORD_LENGTH, Color.blue));

			backgroundGeneratorList.add(new GradientBackgroundGenerator(
					IMAGE_WIDTH, IMAGE_HEIGHT, Color.orange, Color.white));
			backgroundGeneratorList.add(new GradientBackgroundGenerator(
					IMAGE_WIDTH, IMAGE_HEIGHT, Color.white, Color.green));
			backgroundGeneratorList.add(new GradientBackgroundGenerator(
					IMAGE_WIDTH, IMAGE_HEIGHT, Color.gray, Color.white));
			backgroundGeneratorList.add(new GradientBackgroundGenerator(
					IMAGE_WIDTH, IMAGE_HEIGHT, Color.white, Color.orange));
			backgroundGeneratorList.add(new GradientBackgroundGenerator(
					IMAGE_WIDTH, IMAGE_HEIGHT, Color.green, Color.white));
			backgroundGeneratorList.add(new GradientBackgroundGenerator(
					IMAGE_WIDTH, IMAGE_HEIGHT, Color.yellow, Color.white));
			backgroundGeneratorList.add(new GradientBackgroundGenerator(
					IMAGE_WIDTH, IMAGE_HEIGHT, Color.white, Color.magenta));

			

			// fontGeneratorList.add(new
			// TwistedAndShearedRandomFontGenerator(MIN_FONT_SIZE,
			// MAX_FONT_SIZE));
			// fontGeneratorList.add(new
			// TwistedRandomFontGenerator(MIN_FONT_SIZE, MAX_FONT_SIZE));// link
			// character too much
			fontGeneratorList.add(new RandomFontGenerator(MIN_FONT_SIZE,
					MAX_FONT_SIZE));// to easy to read
			// fontGeneratorList.add(new
			// DeformedRandomFontGenerator(MIN_FONT_SIZE, MAX_FONT_SIZE));// to
			// small font

			// no char upper O, char lower o and numerric 0 because user cannot
			// answer
			WordGenerator words = new RandomWordGenerator(NUMERIC_CHARS
					+ UPPER_ASCII_CHARS);

			for (Iterator fontIter = fontGeneratorList.iterator(); fontIter
					.hasNext();) {
				FontGenerator font = (FontGenerator) fontIter.next();
				for (Iterator backIter = backgroundGeneratorList.iterator(); backIter
						.hasNext();) {
					BackgroundGenerator back = (BackgroundGenerator) backIter
							.next();
					for (Iterator textIter = textPasterList.iterator(); textIter
							.hasNext();) {
						TextPaster parser = (TextPaster) textIter.next();

						WordToImage word2image = new ComposedWordToImage(font,
								back, parser);
						ImageCaptchaFactory factory = new GimpyFactory(words,
								word2image);
						addFactory(factory);
					}
				}
			}
		} catch (Exception ex) {
			log.error("产生校验码初始化异常 == " + ex);
			// throw ex;
		}
	}

	/**
	 * Write the captcha image of current user to the servlet response
	 * 
	 * @param request
	 *            HttpServletRequest
	 * @param response
	 *            HttpServletResponse
	 * @throws IOException
	 */
	public void writeCaptchaImage(HttpServletRequest request,
			HttpServletResponse response) throws IOException {

		imageCaptcha = getNextImageCaptcha();
		HttpSession session = request.getSession();
		session.setAttribute("imageCaptcha", imageCaptcha);
		BufferedImage image = (BufferedImage) imageCaptcha.getChallenge();

		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();
			outputStream = null;// no close twice
		} catch (IOException ex) {
			log.error("产生图片异常 == " + ex);
			throw ex;
		} finally {
			if (outputStream != null) {
				try {
					outputStream.close();
				} catch (IOException ex) {
				}
			}
			imageCaptcha.disposeChallenge();
		}
	}

	public boolean validateCaptchaResponse(String validateCode,
			HttpSession session) {
		boolean flag = true;
		try {
			imageCaptcha = (ImageCaptcha) session.getAttribute("imageCaptcha");
			if (imageCaptcha == null) {
				// log.info("validateCaptchaResponse returned false due to
				// imageCaptcha is null");
				flag = false;
			}
			//validateCode = validateCode.toLowerCase();// use upper case for
			validateCode = validateCode.toUpperCase();// use upper case for
			// easier usage
flag = (imageCaptcha.validateResponse(validateCode)).booleanValue();
			session.removeAttribute("imageCaptcha");
			return flag;
		} catch (Exception ex) {
			ex.printStackTrace();
			log.error("校验码校验异常 == " + ex);
			return false;
		}
	}
	
}

ImageCaptchaServlet.java
Java代码 复制代码
  1.     
  2. package com.yh.web.servlet;   
  3.   
  4. import java.io.IOException;   
  5.   
  6. import javax.servlet.ServletConfig;   
  7. import javax.servlet.ServletException;   
  8. import javax.servlet.http.HttpServlet;   
  9. import javax.servlet.http.HttpServletRequest;   
  10. import javax.servlet.http.HttpServletResponse;   
  11.   
  12. import com.yh.web.jcaptcha.CaptchaServiceSingleton;   
  13. import com.octo.captcha.service.CaptchaServiceException;   
  14.   
  15. public class ImageCaptchaServlet extends HttpServlet {   
  16.   
  17.     private static final long serialVersionUID = -5382766069139170499L;   
  18.     public void init(ServletConfig servletConfig) throws ServletException {   
  19.   
  20.         super.init(servletConfig);   
  21.   
  22.     }   
  23.   
  24.     protected void doGet(HttpServletRequest httpServletRequest,   
  25.             HttpServletResponse httpServletResponse) throws ServletException,   
  26.             IOException {   
  27.         System.out.println("---------- ImageCaptchaServlet pass here -------------");   
  28.         try {   
  29.             CaptchaServiceSingleton.getInstance().writeCaptchaImage(   
  30.                     httpServletRequest, httpServletResponse);   
  31.   
  32.         } catch (IllegalArgumentException e) {   
  33.             httpServletResponse.sendError(HttpServletResponse.SC_NOT_FOUND);   
  34.             return;   
  35.         } catch (CaptchaServiceException e) {   
  36.             httpServletResponse   
  37.                     .sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);   
  38.             return;   
  39.         }   
  40.     }   
  41. }  
 
package com.yh.web.servlet;

import java.io.IOException;

import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import com.yh.web.jcaptcha.CaptchaServiceSingleton;
import com.octo.captcha.service.CaptchaServiceException;

public class ImageCaptchaServlet extends HttpServlet {

	private static final long serialVersionUID = -5382766069139170499L;
	public void init(ServletConfig servletConfig) throws ServletException {

		super.init(servletConfig);

	}

	protected void doGet(HttpServletRequest httpServletRequest,
			HttpServletResponse httpServletResponse) throws ServletException,
			IOException {
		System.out.println("---------- ImageCaptchaServlet pass here -------------");
		try {
			CaptchaServiceSingleton.getInstance().writeCaptchaImage(
					httpServletRequest, httpServletResponse);

		} catch (IllegalArgumentException e) {
			httpServletResponse.sendError(HttpServletResponse.SC_NOT_FOUND);
			return;
		} catch (CaptchaServiceException e) {
			httpServletResponse
					.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
			return;
		}
	}
}

jsp页面增加校验码内容:
<tr><td>
校验码:<input type="text" size="8" name="checkCode" id="checkCode" class="normal_input"/><img src="/jcaptcha" id="checkCodeImg" οnclick="this.src='/jcaptcha?now=' + new Date().getTime()" alt="看不清,点击换一张" >请输入校验码,大小写不区分<br> 如看不清,请点击图片换一张
</td></tr>
判断校验码是否正确的java代码:
Java代码 复制代码
  1. HttpSession session = request.getSession();      
  2. boolean isResponseCorrect = false;      
  3. // retrieve the response      
  4. String validateCode = checkCode.trim();      
  5. System.out.println("checkCode == "     
  6.         + checkCode);      
  7. try {      
  8.     isResponseCorrect = CaptchaServiceSingleton.getInstance()      
  9.             .validateCaptchaResponse(validateCode, session);      
  10.      
  11.     return isResponseCorrect;      
  12. catch (Exception e) {      
  13.     // should not happen, may be thrown if the id is not valid      
  14.      
  15.     return false;      
  16. }    
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值