浅尝Java验证码制作(下)

方法三:

用开源组件Jcaptcha实现,与Spring组合使用可产生多种形式的验证码,JCaptcha 即为 Java 版本的 CAPTCHA 项目,其是一个开源项目,支持生成图形和声音版的验证码,在生成声音版的验证码时,需要使用到 FreeTTS。而CAPTCHA 全称 Completely Automated Public Turing Test to Tell Computers and Humans Apart,最早作为卡内基梅隆大学的一个科研项目,用于生成一个人类容易通过而计算机难以通过的测试,目前广泛应用于网络应用,用于阻止机器人发布垃圾信息。目前,JCaptcha 官方网站显示有 2.0 版本,但二进制版只有 1.0 版可供下载。

首先我们需准备相应的jar包

JCaptcha 项目在实现中,还引用了 commons-collections 和 commons-logging 两个开源项目,再加上 JCaptcha 本身的实现,我们共需要三个包,具体信息如下:

  • jcaptcha-2.0-all.jar
  • commons-logging-1.1.1.jar
  • commons-collections-3.2.jar

其次我们看下面web.xml中的关键配置信息:除配置了Jcaptcha组件的具体class路径外,还配置了SubmitActionServlet这个用于比对验证码的servlet,并且都为二者做了映射,可理解为换了名字,分别为/jcaptcha.jpg和/submit.action调用组件或servlet时直接用这个映射名即可。

 1 <servlet>
 2             <servlet-name>jcaptcha</servlet-name>
 3             <servlet-class>com.octo.captcha.module.servlet.image.SimpleImageCaptchaServlet</servlet-class>
 4     </servlet>
 5
 6     <servlet>
 7             <servlet-name>submit</servlet-name>
 8             <servlet-class>com.octo.captcha.module.servlet.image.sample.SubmitActionServlet</servlet-class>
 9     </servlet>
10
11     <servlet-mapping>
12             <servlet-name>jcaptcha</servlet-name>
13             <url-pattern>/jcaptcha.jpg</url-pattern>
14     </servlet-mapping>
15
16     <servlet-mapping>
17             <servlet-name>submit</servlet-name>
18             <url-pattern>/submit.action</url-pattern>
19     </servlet-mapping>

web.xml

然后来看SubmitActionServlet怎么实现:由于导入了jcaptcha的组件包,所以直接调用其中封装好的方法SimpleImageCaptchaServlet.validateResponse(request, userCaptchaResponse)来判断验证码中的信息是否与提交的匹配,而不需要去考虑具体的实现过程。

 1 public class SubmitActionServlet extends HttpServlet
 2 {
 3   protected void doPost(HttpServletRequest request, HttpServletResponse response)
 4     throws ServletException, IOException
 5   {
 6     String userCaptchaResponse = request.getParameter("japtcha");
 7     boolean captchaPassed = SimpleImageCaptchaServlet.validateResponse(request, userCaptchaResponse);
 8     if (captchaPassed)
 9       response.getWriter().write("captcha passed");
10     else {
11       response.getWriter().write("captcha failed");
12     }
13     response.getWriter().write("<br/><a href=‘index.jsp‘>Try again</a>");
14   }
15 }

SubmitActionServlet

最后我们看一下简单的前台调用:

1 <html>
2 <body>
3 <h2>Simple Captcha Servlet sample</h2>
4 <form action="submit.action" method="post">
5      <img src="jcaptcha.jpg" /> <input type="text" name="japtcha" value="" />
6      <input type="submit"/>
7 </form>
8 </body>
9 </html>

index.jsp

实现图例:

方法四:

用开源组件kaptcha实现,同样使用kaptcha需要下载其jar组件包,kaptcha 是一个非常实用的验证码生成工具。有了它,你可以生成各种样式的验证码,因为它是可配置的。kaptcha工作的原理是调用 com.google.code.kaptcha.servlet.KaptchaServlet(可以看出他是谷歌的一个开源项目),生成一个图片。同时将生成的验证码字符串放到 HttpSession中。

使用kaptcha可以方便的配置:

  • 验证码的字体
  • 验证码字体的大小
  • 验证码字体的字体颜色
  • 验证码内容的范围(数字,字母,中文汉字!)
  • 验证码图片的大小,边框,边框粗细,边框颜色
  • 验证码的干扰线(可以自己继承com.google.code.kaptcha.NoiseProducer写一个自定义的干扰线)
  • 验证码的样式(鱼眼样式、3D、普通模糊……当然也可以继承com.google.code.kaptcha.GimpyEngine自定义样式)

……

对kaptcha的配置信息同样的是放在了web.xml中:<init-param>标签中即初始化的配置信息

  1 <servlet>
  2         <servlet-name>Kaptcha</servlet-name>
  3         <servlet-class>
  4             com.google.code.kaptcha.servlet.KaptchaServlet
  5         </servlet-class>
  6         <init-param>
  7             <description>图片边框,合法值:yes , no</description>
  8             <param-name>kaptcha.border</param-name>
  9             <param-value>yes</param-value>
 10         </init-param>
 11         <init-param>
 12             <description>
 13                 边框颜色,合法值: r,g,b (and optional alpha) 或者
 14                 white,black,blue.
 15             </description>
 16             <param-name>kaptcha.border.color</param-name>
 17             <param-value>black</param-value>
 18         </init-param>
 19         <init-param>
 20             <description>边框厚度,合法值:>0</description>
 21             <param-name>kaptcha.border.thickness</param-name>
 22             <param-value>1</param-value>
 23         </init-param>
 24         <init-param>
 25             <description>图片宽 200</description>
 26             <param-name>kaptcha.image.width</param-name>
 27             <param-value>200</param-value>
 28         </init-param>
 29         <init-param>
 30             <description>图片高 50</description>
 31             <param-name>kaptcha.image.height</param-name>
 32             <param-value>50</param-value>
 33         </init-param>
 34         <init-param>
 35             <description>图片实现类</description>
 36             <param-name>kaptcha.producer.impl</param-name>
 37             <param-value>
 38                 com.google.code.kaptcha.impl.DefaultKaptcha
 39             </param-value>
 40         </init-param>
 41         <init-param>
 42             <description>文本实现类</description>
 43             <param-name>kaptcha.textproducer.impl</param-name>
 44             <param-value>
 45                 com.google.code.kaptcha.text.impl.DefaultTextCreator
 46             </param-value>
 47         </init-param>
 48         <init-param>
 49             <description>文本集合,验证码值从此集合中获取</description>
 50             <param-name>kaptcha.textproducer.char.string</param-name>
 51             <param-value>1234567890</param-value>
 52               <!--<param-value>abcde2345678gfynmnpwx</param-value>-->
 53             <!--<param-value>慕课网教程验证码实例</param-value> -->
 54         </init-param>
 55         <init-param>
 56             <description>验证码长度 5</description>
 57             <param-name>kaptcha.textproducer.char.length</param-name>
 58             <param-value>4</param-value>
 59         </init-param>
 60         <init-param>
 61             <description>字体 Arial, Courier</description>
 62             <param-name>kaptcha.textproducer.font.names</param-name>
 63             <param-value>Arial, Courier</param-value>
 64         </init-param>
 65         <init-param>
 66             <description>字体大小 40px.</description>
 67             <param-name>kaptcha.textproducer.font.size</param-name>
 68             <param-value>40</param-value>
 69         </init-param>
 70         <init-param>
 71             <description>
 72                 字体颜色,合法值: r,g,b 或者 white,black,blue.
 73             </description>
 74             <param-name>kaptcha.textproducer.font.color</param-name>
 75             <param-value>black</param-value>
 76         </init-param>
 77         <init-param>
 78             <description>文字间隔 2</description>
 79             <param-name>kaptcha.textproducer.char.space</param-name>
 80             <param-value>2</param-value>
 81         </init-param>
 82         <init-param>
 83             <description>干扰实现类</description>
 84             <param-name>kaptcha.noise.impl</param-name>
 85             <param-value>
 86                 <!-- com.google.code.kaptcha.impl.NoNoise -->
 87                 com.google.code.kaptcha.impl.DefaultNoise
 88             </param-value>
 89         </init-param>
 90         <init-param>
 91             <description>
 92                 干扰颜色,合法值: r,g,b 或者 white,black,blue.
 93             </description>
 94             <param-name>kaptcha.noise.color</param-name>
 95             <param-value>black</param-value>
 96         </init-param>
 97         <init-param>
 98             <description>
 99                 图片样式: 水纹com.google.code.kaptcha.impl.WaterRipple
100                 鱼眼com.google.code.kaptcha.impl.FishEyeGimpy
101                 阴影com.google.code.kaptcha.impl.ShadowGimpy
102             </description>
103             <param-name>kaptcha.obscurificator.impl</param-name>
104             <param-value>
105                 com.google.code.kaptcha.impl.WaterRipple
106             </param-value>
107         </init-param>
108         <init-param>
109             <description>背景实现类</description>
110             <param-name>kaptcha.background.impl</param-name>
111             <param-value>
112                 com.google.code.kaptcha.impl.DefaultBackground
113             </param-value>
114         </init-param>
115         <init-param>
116             <description>背景颜色渐变,开始颜色</description>
117             <param-name>kaptcha.background.clear.from</param-name>
118             <param-value>green</param-value>
119         </init-param>
120         <init-param>
121             <description>背景颜色渐变,结束颜色</description>
122             <param-name>kaptcha.background.clear.to</param-name>
123             <param-value>white</param-value>
124         </init-param>
125         <init-param>
126             <description>文字渲染器</description>
127             <param-name>kaptcha.word.impl</param-name>
128             <param-value>
129                 com.google.code.kaptcha.text.impl.DefaultWordRenderer
130             </param-value>
131         </init-param>
132         <init-param>
133             <description>
134                 session中存放验证码的key键
135             </description>
136             <param-name>kaptcha.session.key</param-name>
137             <param-value>KAPTCHA_SESSION_KEY</param-value>
138         </init-param>
139         <init-param>
140             <description>
141                 The date the kaptcha is generated is put into the
142                 HttpSession. This is the key value for that item in the
143                 session.
144             </description>
145             <param-name>kaptcha.session.date</param-name>
146             <param-value>KAPTCHA_SESSION_DATE</param-value>
147         </init-param>
148     </servlet>
149     <servlet-mapping>
150         <servlet-name>Kaptcha</servlet-name>
151         <url-pattern>/randomcode.jpg</url-pattern>
152     </servlet-mapping>

web.xml

前台调用:验证码图片的路径用了映射名randomcode.jpg,点击事件onclick()调用了js函数,js函数中同样的用当前时间使浏览器缓存失效来刷新验证码图片。

 1 <html>
 2 <head>
 3 <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
 4 <title>randomcode</title>
 5 <script type="text/javascript">
 6     function changeR(node){
 7         // 用于点击时产生不同的验证码
 8         node.src = "randomcode.jpg?time="+new Date().getTime() ;
 9     }
10 </script>
11 </head>
12 <body>
13 <img alt="random" src="randomcode.jpg" onclick="changeR(this)" style="cursor: pointer;">
14     <form action="check.jsp">
15         <input type="text" name="r">
16         <input type="submit" value="s">
17     </form>
18 </body>
19 </html>

index.jsp

验证码的比对check.jsp:通过(String) session.getAttribute(com.google.code.kaptcha.Constants.KAPTCHA_SESSION_KEY);得到验证码图片中字符串信息。

 1 <html>
 2 <head>
 3 <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
 4 <title>check</title>
 5 </head>
 6 <body>
 7     <%
 8         // 检查是否是正确的验证码
 9         String k = (String) session
10                 .getAttribute(com.google.code.kaptcha.Constants.KAPTCHA_SESSION_KEY);
11         String str = request.getParameter("r");
12         if (k.equals(str))
13             out.print("true");
14         out.print(k + "---" + str);
15     %>
16 </body>
17 </html>

check.jsp

实现图例:

可以发现我们的验证码变得越来越来丰富多彩了,但是还停留在一个只验证英文字母和数字的阶段,那么还能不能玩点高端的呢,答案是肯定的。接下来我们来看一下中文验证码和算术运算验证码怎么实现。都只需基于以上kaptcha的使用进行修改即可。

中文验证码的实现:

首先我们找到kaptcha.jar包下有个DefaultTextCreator.class字节码文件,顾名思义,他是来产生验证码中文本的一个类,我们可以通过自己实现一个继承于他的类,并通过配置来使用自己的实现类来使验证码中的文本变为中文。经过如下反编译后得到的类我们可以看到其是那样实现的,其中的getText()函数用于产生getConfig()配置器将要渲染的验证码文本,所以我们只需继承配置类并实现文本产生接口后重写getText()方法即可。

 1 public class DefaultTextCreator
 2   extends Configurable
 3   implements TextProducer
 4 {
 5   public String getText()
 6   {
 7     int length = getConfig().getTextProducerCharLength();
 8     char[] chars = getConfig().getTextProducerCharString();
 9     int randomContext = chars.length - 1;
10     Random rand = new Random();
11     StringBuffer text = new StringBuffer();
12     for (int i = 0; i < length; i++) {
13       text.append(chars[(rand.nextInt(randomContext) + 1)]);
14     }
15     return text.toString();
16   }
17 }

DefaultTextCreator.class反编译结果

如下为ChineseText.java的具体实现:其中程序只执行getText()中的代码,原来代码写到了getText1()中,不执行,大家可以做一个比较。

 1 public class ChineseText extends Configurable implements TextProducer {
 2
 3     public String getText() {
 4         int length = getConfig().getTextProducerCharLength();
 5         //char[] charS = getConfig().getTextProducerCharString();
 6
 7         String[] s = new String[]{"我","爱","扎","瓦","和","卖","塞","扣"};
 8
 9         Random rand = new Random();
10         StringBuffer sb = new StringBuffer();
11         for(int i = 0; i < length; i++){
12             int ind = rand.nextInt(s.length);
13             sb.append(s[ind]);
14         }
15         return sb.toString();
16     }
17     /**
18      * 中午实例
19      * @return
20      */
21     public String getText1() {
22         int length = getConfig().getTextProducerCharLength();
23         String finalWord = "", firstWord = "";
24         int tempInt = 0;
25         String[] array = { "0", "1", "2", "3", "4", "5", "6", "7", "8", "9",
26                 "a", "b", "c", "d", "e", "f" };
27
28         Random rand = new Random();
29
30         for (int i = 0; i < length; i++) {
31             switch (rand.nextInt(array.length)) {
32             case 1:
33                 tempInt = rand.nextInt(26) + 65;
34                 firstWord = String.valueOf((char) tempInt);
35                 break;
36             case 2:
37                 int r1,
38                 r2,
39                 r3,
40                 r4;
41                 String strH,
42                 strL;// high&low
43                 r1 = rand.nextInt(3) + 11; // 前闭后开[11,14)
44                 if (r1 == 13) {
45                     r2 = rand.nextInt(7);
46                 } else {
47                     r2 = rand.nextInt(16);
48                 }
49
50                 r3 = rand.nextInt(6) + 10;
51                 if (r3 == 10) {
52                     r4 = rand.nextInt(15) + 1;
53                 } else if (r3 == 15) {
54                     r4 = rand.nextInt(15);
55                 } else {
56                     r4 = rand.nextInt(16);
57                 }
58
59                 strH = array[r1] + array[r2];
60                 strL = array[r3] + array[r4];
61
62                 byte[] bytes = new byte[2];
63                 bytes[0] = (byte) (Integer.parseInt(strH, 16));
64                 bytes[1] = (byte) (Integer.parseInt(strL, 16));
65
66                 firstWord = new String(bytes);
67                 break;
68             default:
69                 tempInt = rand.nextInt(10) + 48;
70                 firstWord = String.valueOf((char) tempInt);
71                 break;
72             }
73             finalWord += firstWord;
74         }
75         return finalWord;
76     }
77 }

ChineseText.java

最后一步就是去web.xml中改文本实现类的值,使组件调用自己写的那个类产生中文验证码。

1          <init-param>
2             <description>文本实现类</description>
3             <param-name>kaptcha.textproducer.impl</param-name>
4             <param-value>
5                 ChineseText
6             </param-value>
7         </init-param>            

web.xml修改处

实现图例:

算数运算验证码的实现:

和上述中文验证码相同,我们需要通过继承类和接口来实现自己的类,并改写其中的函数,然后通过改配置信息来使组件调用自己实现的类从而实现验证码形式的多样化。

KaptchaServlet字节码文件经过反编译后的代码如下:

 1 public class KaptchaServlet
 2   extends HttpServlet
 3   implements Servlet
 4 {
 5   private Properties props = new Properties();
 6   private Producer kaptchaProducer = null;
 7   private String sessionKeyValue = null;
 8
 9   public void init(ServletConfig conf)
10     throws ServletException
11   {
12     super.init(conf);
13
14     ImageIO.setUseCache(false);
15
16     Enumeration<?> initParams = conf.getInitParameterNames();
17     while (initParams.hasMoreElements())
18     {
19       String key = (String)initParams.nextElement();
20       String value = conf.getInitParameter(key);
21       this.props.put(key, value);
22     }
23     Config config = new Config(this.props);
24     this.kaptchaProducer = config.getProducerImpl();
25     this.sessionKeyValue = config.getSessionKey();
26   }
27
28   public void doGet(HttpServletRequest req, HttpServletResponse resp)
29     throws ServletException, IOException
30   {
31     resp.setDateHeader("Expires", 0L);
32
33     resp.setHeader("Cache-Control", "no-store, no-cache, must-revalidate");
34
35     resp.addHeader("Cache-Control", "post-check=0, pre-check=0");
36
37     resp.setHeader("Pragma", "no-cache");
38
39     resp.setContentType("image/jpeg");
40
41     String capText = this.kaptchaProducer.createText();
42
43     req.getSession().setAttribute(this.sessionKeyValue, capText);
44
45     BufferedImage bi = this.kaptchaProducer.createImage(capText);
46
47     ServletOutputStream out = resp.getOutputStream();
48
49     ImageIO.write(bi, "jpg", out);
50     try
51     {
52       out.flush();
53     }
54     finally
55     {
56       out.close();
57     }
58   }
59 }

KaptchaServlet.class反编译结果

然后自己实现的KaptchaServlet.java代码如下:在原来的字节码文件上增加了实现加法验证码的逻辑,通过比对即可发现。

 1 public class KaptchaServlet extends HttpServlet implements Servlet {
 2     private Properties props;
 3     private Producer kaptchaProducer;
 4     private String sessionKeyValue;
 5
 6     public KaptchaServlet() {
 7         this.props = new Properties();
 8
 9         this.kaptchaProducer = null;
10
11         this.sessionKeyValue = null;
12     }
13
14     public void init(ServletConfig conf) throws ServletException {
15         super.init(conf);
16
17         ImageIO.setUseCache(false);
18
19         Enumeration initParams = conf.getInitParameterNames();
20         while (initParams.hasMoreElements()) {
21             String key = (String) initParams.nextElement();
22             String value = conf.getInitParameter(key);
23             this.props.put(key, value);
24         }
25
26         Config config = new Config(this.props);
27         this.kaptchaProducer = config.getProducerImpl();
28         this.sessionKeyValue = config.getSessionKey();
29     }
30
31     public void doGet(HttpServletRequest req, HttpServletResponse resp)
32             throws ServletException, IOException {
33         resp.setDateHeader("Expires", 0L);
34
35         resp.setHeader("Cache-Control", "no-store, no-cache, must-revalidate");
36
37         resp.addHeader("Cache-Control", "post-check=0, pre-check=0");
38
39         resp.setHeader("Pragma", "no-cache");
40
41         resp.setContentType("image/jpeg");
42
43         String capText = this.kaptchaProducer.createText();
44         String s1 = capText.substring(0, 1);
45         String s2 = capText.substring(1, 2);
46         int r = Integer.valueOf(s1).intValue() + Integer.valueOf(s2).intValue();
47
48         req.getSession().setAttribute(this.sessionKeyValue, String.valueOf(r));
49
50         BufferedImage bi = this.kaptchaProducer.createImage(s1+"+"+s2+"=?");
51
52         ServletOutputStream out = resp.getOutputStream();
53
54         ImageIO.write(bi, "jpg", out);
55         try {
56             out.flush();
57         } finally {
58             out.close();
59         }
60     }
61 }

KaptchaServlet.java

我们还需在web.xml开头进行更改配置使组件来调用自己实现的servlet:

1 <servlet-name>Kaptcha</servlet-name>
2         <servlet-class>
3             KaptchaServlet
4         </servlet-class>

web.xml部分更改

实现图例:

总结:

这里只是简单实现了验证码,但要用到商业项目上还是远远不够的,验证码想要不被破解还要加上各种加密算法,即使这样,也可以随处搜索到某某验证码被破解的情况。在网络上有一个地下数据库,里面存储的是我们的个人信息,那些信息都是一条条整理好的,这十分可怕,但这样一个数据库是客观存在的,验证码作为保护账户密码的重要一环,已变得越来越不安全,因为个人信息的泄露,别人掌握了你足够的信息就可以对你实行诈骗,其中验证码是重要一环,近日就有一毕业生被骗取验证码后,几个小时内所有财富都被转走的事件发生。所以请保护好你的验证码,不要轻易泄露给他人。

当然我们也不会坐以待毙,目前的验证码种类繁多也越来越难以破解,像语音识别、面部识别这些都是耳熟能详的就不多说了。

这里我们引入一个验证码“新”概念:双因素认证。

双因素认证是一种采用时间同步技术的系统,采用了基于时间、事件和密钥三变量而产生的一次性密码来代替传统的静态密码。每个动态密码卡都有一个唯一的密钥,该密钥同时存放在服务器端,每次认证时动态密码卡与服务器分别根据同样的密钥,同样的随机参数(时间、事件)和同样的算法计算了认证的动态密码,从而确保密码的一致性,从而实现了用户的认证。因每次认证时的随机参数不同,所以每次产生的动态密码也不同。由于每次计算时参数的随机性保证了每次密码的不可预测性,从而在最基本的密码认证这一环节保证了系统的安全性。解决因口令欺诈而导致的重大损失,防止恶意入侵者或人为破坏,解决由口令泄密导致的入侵问题。

简单来说,双因素身份认证就是通过你所知道再加上你所能拥有的这二个要素组合到一起才能发挥作用的身份认证系统。例如,在ATM上取款的银行卡就是一个双因素认证机制的例子,需要知道取款密码和银行卡这二个要素结合才能使用。

目前主流的双因素认证系统是基于时间同步型,市场占有率高的有DKEY双因素认证系统RSA双因素认证系统等,由于DKEY增加对短信密码认证及短信+令牌混合认证支持,相比RSA,DKEY双因素认证系统更具竞争力。

时间: 2024-10-17 07:16:21

浅尝Java验证码制作(下)的相关文章

浅尝Java验证码制作(上)

相信大家对验证码这玩意不会陌生,无论是申请账号还是某些情况下登录时都会要求输入验证码.经过统计,验证码一次验证就成功通过的概率是90%,并不高,那么很多人对于这种降低用户体验度的设计肯定会怀疑他的必要性,但黑格尔说过:凡是合乎理性的东西都是现实的:凡是现实的东西都是合乎理性的.接下来我们来了解一下验证码. 验证码是一种区别用户是计算机还是人的公共全自动程序,他被用于防止恶意破解密码.刷票.论坛灌水,防止黑客通过暴力破解方式不断地登录,应用于银行.社区.论坛.投票系统等等. 废话不多说我们来看看我

浅谈JAVA验证码~

这两天在帮同学做个项目,项目中需要做个验证码,说实话那么多年竟然没注意过这东西,原理很简单,贴出来给大家做个参考. 1.简单介绍 一般稍微有些经验的程序员都不会再自己写原生验证码生成了,因为各种强大的开源组件,足以解决我们大部分的需求.但是,毕竟也是刚接触这东西,还需要从原理入手的. 项目效果图: 下面我就简单介绍下原生和使用开源项目kaptcha生成验证码的两种形式. 2.jdk原生生成验证码 效果: 2.1 验证码生成的流程 1.定义BufferedImage(图像数据缓冲区)对象 2.获得

Java验证码的jar制作

Java验证码代码: package cn.itcast.image; import java.awt.BasicStroke;import java.awt.Color;import java.awt.Font;import java.awt.Graphics2D;import java.awt.image.BufferedImage;import java.io.IOException;import java.io.OutputStream;import java.util.Random;

动态验证码制作(RandomCodeImage )

在很多的网页中,他们的登录,注册等等地方都有验证码的存在,这下验证码都是动态生成的,有些验证码模糊不堪,有些干扰很多, 而验证码是用来干什么的呢?防止人为输入的不安全?错,验证码真正的用途在于,防止机器的识别,所以,验证码往往都是图片格式的, 人可以识别出来,而机器就识别不出来,这样就可以防止机器识别,就可以保证正在操作的是人,而并不是机器的操作,安全性更高: 下面就分享一下我自己写得一个简单的验证码制作的代码!希望可以一起学习,有什么不足,敬请指正: 这是我封装的一个验证码制作的java类:

Python图形界面开发编程:wxPython(浅尝篇)

Python 提供了多个图形开发界面的库,几个常用 Python GUI 库如下: Tkinter: Tkinter 模块(Tk 接口)是 Python 的标准 Tk GUI 工具包的接口 .Tk 和 Tkinter 可以在大多数的 Unix 平台下使用,同样可以应用在 Windows 和 Macintosh 系统里.Tk8.0 的后续版本可以实现本地窗口风格,并良好地运行在绝大多数平台中. wxPython:wxPython 是一款开源软件,是 Python 语言的一套优秀的 GUI 图形库,

来自后端的突袭? --开包即食的教程带你浅尝最新开源的C# Web引擎 Blazor

来自后端的突袭? --开包即食的教程带你浅尝最新开源的C# Web引擎 Blazor 在今年年初, 恰逢新春佳节临近的时候. 微软给全球的C#开发者们, 着实的送上了一分惊喜. 微软正式开源Blazor ,将.NET带回到浏览器. 这个小惊喜, 迅速的在dotnet开发者中间传开了. 而就在昨天(2018年3月22日) Blazor发布了它的第一次Release. Blazor到底是个什么样的东西呢?我们是否真的可以携着C#语言进入前端的市场中? 不如现在就跟我一起体验dotnet blazor

【转】浅谈Java中的equals和==

浅谈Java中的equals和== 在初学Java时,可能会经常碰到下面的代码: 1 String str1 = new String("hello"); 2 String str2 = new String("hello"); 3 4 System.out.println(str1==str2); 5 System.out.println(str1.equals(str2)); 为什么第4行和第5行的输出结果不一样?==和equals方法之间的区别是什么?如果在初

浅谈java异常[Exception]

本文转自:focusJ 一. 异常的定义 在<java编程思想>中这样定义 异常:阻止当前方法或作用域继续执行的问题.虽然java中有异常处理机制,但是要明确一点,决不应该用"正常"的态度来看待异常.绝对一点说异常就是某种意义上的错误,就是问题,它可能会导致程序失败.之所以java要提出异常处理机制,就是要告诉开发人员,你的程序出现了不正常的情况,请注意. 记得当初学习java的时候,异常总是搞不太清楚,不知道这个异常是什么意思,为什么会有这个机制?但是随着知识的积累逐渐也

浅尝key-value数据库(二)——MongoDB的优与劣

浅尝key-value数据库(二)——MongoDB的优与劣 MongoDB的名字取自英文单词"humongous"的中间五个字母,是一个C++开发的基于分布式文件存储的数据库开源项目.他的文件存储格式是BSON(Binary JSON),因此可以高效存储二进制数据,例如图像.视频等大对象. 由于我是CentOS x86_64的系统,于是安装MongoDB非常简单: vi /etc/yum.repos.d/mongo.repo [10gen] name=10gen Repository