jsp-servlet图像验证码

本文涉及的产品
函数计算FC,每月15万CU 3个月
简介: 实现图像验证码类ImageValidateCode: package com.myhome;import java.awt.Color;import java.awt.Font;import java.awt.Graphics;import java.awt.image.BufferedImage;import java.io.IOException;import jav

实现图像验证码类ImageValidateCode:

package com.myhome;


import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.util.Random;


import javax.imageio.ImageIO;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
/**
 * 防止暴力破解,使用的图像验证码
 * */
public class ImageValidateCode extends HttpServlet 
{


/**
* 实现java.io.Serializable这个接口是为序列化,
* serialVersionUID 用来表明实现序列化类的不同版本间的兼容性。
* 如果你修改了此类, 要修改此值。否则以前用老版本的类序列化的类恢复时会出错。
* 为了在反序列化时,确保类版本的兼容性。序列化时为了保持版本的兼容性,

* 即在版本升级时反序列化仍保持对象的唯一性。
*/
private static final long serialVersionUID = 5403703649596352260L;
//产生随机数
private Random random =new Random();
//定义图形验证码中绘制字符的字体,字体名称,字体样式,字体大小l;如:"Arial Black"或"Fixedsys", Font.CENTER_BASELINE, 18
private final Font mFont=new Font("Arial Black", Font.PLAIN, 24);
//定义验证码的大小,即高度和宽度
private final int IMG_WIDTH=90;
private final int IMG_HEIGHT=25;
//干扰线的数量
private final int LineSize=50;
//产生的随机字符数量
private int stringNum = 4;  
/**
* 获取随机颜色的方法
* */
private Color getRandColor(int fc,int bc)
{
if(fc>255)
{
fc=255;
}
if(bc>255)
{
bc=255;
}
//产生随机的RGB三原色
int r=fc+random.nextInt(bc-fc-16);
int g=fc+random.nextInt(bc-fc-14);
int b=fc+random.nextInt(bc-fc-18);
return new Color(r, g, b);
}
/**
* 获取大、小写字母和数字随机字符串方法
* */
private String getRandString()
{
//Math.random()---random()方法,是返回一个[0,1)的浮点数。

//一般我们是这样运用的,比如我要取一个1~9的随机数int a=(int)(Math.random()*10)注意是是乘上10再转。
//Math.round()方法,round 就是四舍五入,

//math.round(-8.9) -9;math.round(-8.1) -8;math.round(8.9) 9;math.round(8.1) 8
//生成0、1、2的随机数字
int randi=(int) Math.round(Math.random()*2);
//用来存储数据的ASC码
long itmp=0;
//用于存储字符
char ctmp='\u0000';

//以“\u”开头的是一个Unicode码的字符,每一个'\u0000'都代表了一个空格。

//Unicode可同时包含65536个字符,ASCII/ANSI只包含255个字符,实际上是Unicode的一个子集。

//Unicode字符通常用十六进制编码方案表示,范围在'\u0000'到'\uFFFF'之间。

//\u0000到\u00FF表示ASCII/ANSI字符。

//“\u”表示这是一个Unicode值.\u0000代表的应该是NULL,输出控制台是一个空格...
switch(randi)
{
//生成大写字母
case 1:
itmp=Math.round(Math.random()*25+65);//long类型
ctmp=(char) itmp;//char类型
return String.valueOf(ctmp);//String类型
//生成小写字母
case 2:
itmp=Math.round(Math.random()*25+97);
ctmp=(char) itmp;
return String.valueOf(ctmp);
//生成数字
default :
itmp=Math.round(Math.random()*9);
return itmp+"";//将整型数字连接成字符串
}
}
/**
* 绘制随机字符串
* */
private String drawString(Graphics g,String randomString,int i)
{
g.setFont(mFont);//设置字符串字体
g.setColor(new Color(random.nextInt(255), random.nextInt(255), random.nextInt(255)));//设置字符串颜色
String rands=getRandString();
randomString+=rands;
g.translate(random.nextInt(3), random.nextInt(2));//设置画在图片上的文字的x,y坐标,随即偏移值
g.drawString(rands, 18*i+5, 18);//字符间距设置为15px
,使用此图形上下文的当前字体和颜色绘制由指定 string 给定的文本。最左侧字符的基线位于此图形上下文坐标系统的 (x, y) 位置处。即:str - 要绘制的 string。x - x 坐标。y - y 坐标。//从图像左面10个像素个像素(后15*i+10),距上面16个像素的位置开始从左到右的方向输出rands的值。
return randomString;
}
/**
* 绘制干扰线
* */
private void drawLine1(Graphics g)
{
//参数:x1 - 第一个点的 x 坐标。y1 - 第一个点的 y 坐标。x2 - 第二个点的 x 坐标。y2 - 第二个点的 y 坐标。x1和x2是起点坐标,x2和y2是终点坐标
int x=random.nextInt(IMG_WIDTH);
int y=random.nextInt(IMG_HEIGHT);
int x1=random.nextInt(13);
int y1=random.nextInt(15);
g.drawLine(x, y, x+x1, y+y1);
}
private void drawLine2(Graphics g)
{
//参数:x1 - 第一个点的 x 坐标。y1 - 第一个点的 y 坐标。x2 - 第二个点的 x 坐标。y2 - 第二个点的 y 坐标。x1和x2是起点坐标,x2和y2是终点坐标
int x=random.nextInt(IMG_WIDTH);
int y=random.nextInt(IMG_HEIGHT);
int x1=random.nextInt(13);
int y1=random.nextInt(15);
g.drawLine(x, y, x-x1, y-y1);
}
/**
* 图像验证码的生成
* */
@Override
protected void service(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException 
{
System.out.println("验证码开始生成了");
//设置禁止缓存
response.setHeader("Pragma","No-cache");
response.setHeader("Cache-Control","no-cache");
response.setDateHeader("Expires", 0);
response.setContentType("image/jpeg");//设置输出流内容格式为图片格式
/*禁用IE缓存
* HTTP消息报头包括普通报头、请求报头、响应报头、实体报头。
* 普通报头中的Cache-Control用于指定缓存指令,缓存指令是单向的(响应中出现的缓存指令在请求中未必会出现),且是独立的(一个消息的缓存指令不会影响另一个消息处理的缓存机制),HTTP1.0使用的类似的报头域为Pragma。
* 请求时的缓存指令包括:no-cache(用于指示请示或响应消息不能缓存)、no-store、max-age、max-stale、min-fresh、only-if-cached;
* 响应时的缓存指令包括:public、private、no-cache、no-store、no-transform、must-revalidate、proxy-revalidate、max-age、s-maxage。
* 例:为了指示IE浏览器(客户端)不要缓存页面,服务器端的jsp程序可以编写如下:response.setHeader(“Cache-Control”, “no-cache”);//response.setHeader(“Pragma”, “no-cache”);
* 作用相当于上行代码,通常两者合用Expires实体报头域给出响应过期的日期和时间。为了让代理服务器或浏览器在一段时间以后更新缓存中(再次访问曾访问过的页面时,直接从缓存中加载,缩短响应时间和降低服务器负载)的页面,我们可以使用Expires实体报头域指定页面过期时间。
* 例:Expires:Thu,15 Sep 2006 16:23:12 GMTHTTP1.1的客户端和缓存必须将其他非法的日期格式(包括0)看作已经过期。
* 如:为了让浏览器不要缓存页面,也可以利用Expires实体报关域,设置为0,jsp程序如下:response.setDateHeader(“Expires”, “0”);
* */
//在内存中创建一副图像,宽90像素,高25像素,rgb模式的色彩
BufferedImage image=new BufferedImage(IMG_WIDTH, IMG_HEIGHT, BufferedImage.TYPE_INT_RGB);
//在内存中创建一个画笔
Graphics g=image.getGraphics();
//设置画笔颜色
g.setColor(getRandColor(200, 250));
//填充背景色,使用当前的画笔颜色修改图片背景色 
g.fillRect(1, 1, IMG_WIDTH-1, IMG_HEIGHT-1);//4个参数的意思分别为,起始X坐标,起始Y坐标,宽度,高度。
//为图形验证码绘制边框
g.setColor(new Color(155,155,155));
g.drawRect(0, 0, IMG_WIDTH,IMG_HEIGHT);
//生成随机干扰线
g.setColor(getRandColor(110, 133));
for(int i=0;i<=LineSize;i++){
drawLine1(g);
drawLine2(g);
}
//用于保存系统生成的随机字符串
String randomString = "";
//绘制随机字符串
for(int j=0;j<stringNum;j++){
randomString=drawString(g, randomString, j);
}
//获取HttpSesssion对象
HttpSession session=request.getSession(true);
//getSession(true):true: 如果session存在,则返回该session,否则创建一个新的session;false: 如果session存在,则返回该session,否则返回null.
//将随机字符串放入到HttpSession对象中,验证码中的随机数不区分大小写
session.setAttribute("rand", randomString.toLowerCase());
String rands=(String) session.getAttribute("rand");
System.out.println("验证码生成成功"+rands);
System.out.println("验证码生成成功"+randomString.toLowerCase().toString());
//释放画笔对象
g.dispose();
//向输出流中输出图像
ImageIO.write(image, "JPEG", response.getOutputStream());
}
}

jsp界面实现index.jsp和validat.jsp:

 validat.jsp:

<body>
    <img src="checkServlet" /> <a href="validat.jsp" >看不清楚,换张图片</a>
 </body>


index.jsp:

<head>

<script type="text/javascript">

//看不清图片,重新加载一张图像验证码
function reloadVercode(){
document.getElementById("authImg").src="auth.jpg?now="+new Date();
}
</script>
</head>


<body>
    <img src="auth.jpg" id="authImg" /><a href="javascript:void(null)" onclick="reloadVercode()">看不清,换一张</a>

 </body>

web.xml配置:

<!-- 定义图像验证码的servlet  index.jsp配置-->
  <servlet>
  <servlet-name>img</servlet-name>
  <servlet-class>com.myhome.ImageValidateCode</servlet-class>
  </servlet>
  <servlet-mapping>
  <servlet-name>img</servlet-name>
  <url-pattern>/auth.jpg</url-pattern>
  </servlet-mapping>
  
  <!-- 定义图像验证码的servlet  validat.jsp配置-->
    <servlet>
    <servlet-name>CheckServlet</servlet-name>
    <servlet-class>com.myhome.ImageValidateCode</servlet-class>
  </servlet>
   <servlet-mapping>
    <servlet-name>CheckServlet</servlet-name>
    <url-pattern>/checkServlet</url-pattern>
  </servlet-mapping>


效果图:

 

其他:

package com.myhome;


public class Test {
/**
* 产生随机字符串
* */
private String getRandomChar()
{
int rand = (int)Math.round(Math.random() * 2);
System.out.println("随机数:"+rand);
long itmp = 0;
char ctmp = '\u0000';
System.out.println("字符:"+ctmp);
switch (rand)
{
case 1:
itmp = Math.round(Math.random() * 25 + 65);
String s1=getType(itmp);
System.out.println(s1+itmp);
ctmp = (char)itmp;
String s2=getType(ctmp);
System.out.println(s2+itmp);
System.out.println(getType(String.valueOf(ctmp))+String.valueOf(ctmp));
return String.valueOf(ctmp);

case 2:
itmp = Math.round(Math.random() * 25 + 97);
System.out.println(itmp);
ctmp = (char)itmp;
System.out.println(ctmp);
System.out.println(String.valueOf(ctmp));
return String.valueOf(ctmp);
default :
itmp = Math.round(Math.random() * 9);
String.valueOf(itmp);
return  itmp + "";
}
}
/**
* 判断对象的类型
* */
private <T> String getType(T t)
{
if(t instanceof String)
{
return "String";
}else if(t instanceof Integer)
{
return "int";
}else if(t instanceof Character)
{
return "char";
}else if(t instanceof Long)
{
return "long";
}else {
return "don't know Type of" +t;
}
}
public static void main(String[] args) 
{
Test t=new Test();
t.getRandomChar();
}
}


 


 


 

相关实践学习
【文生图】一键部署Stable Diffusion基于函数计算
本实验教你如何在函数计算FC上从零开始部署Stable Diffusion来进行AI绘画创作,开启AIGC盲盒。函数计算提供一定的免费额度供用户使用。本实验答疑钉钉群:29290019867
建立 Serverless 思维
本课程包括: Serverless 应用引擎的概念, 为开发者带来的实际价值, 以及让您了解常见的 Serverless 架构模式
目录
相关文章
|
Java
Servlet实现登录带有验证码验证案例
Servlet实现登录带有验证码验证案例
171 0
|
缓存 JavaScript 前端开发
Servlet验证码的创建应用
1. 打开javaEE,新建一个Dynamic Web Project,然后在工程下的Java Resources—src新建一个Servlet
114 0
|
Web App开发 JavaScript 前端开发
|
JavaScript 前端开发 Java
|
4月前
|
缓存 安全 Java
Java服务器端技术:Servlet与JSP的集成与扩展
Java服务器端技术:Servlet与JSP的集成与扩展
38 3
|
4月前
|
存储 缓存 前端开发
Servlet与JSP在Java Web应用中的性能调优策略
Servlet与JSP在Java Web应用中的性能调优策略
35 1
|
4月前
|
存储 Java 关系型数据库
基于Servlet和JSP的Java Web应用开发指南
基于Servlet和JSP的Java Web应用开发指南
62 0
|
4月前
|
前端开发 安全 Java
在Java服务器端开发的浩瀚宇宙中,Servlet与JSP犹如两颗璀璨的明星,它们联袂登场,共同编织出动态网站的绚丽篇章。
在Java服务器端开发的浩瀚宇宙中,Servlet与JSP犹如两颗璀璨的明星,它们联袂登场,共同编织出动态网站的绚丽篇章。
30 0