java驗(yàn)證碼生成的基本流程
1.驗(yàn)證碼的生成,我們能夠看到是用Graphics對象畫出來的。對象我們必須要獲得Graphics對象
1-1、Graphics對象的獲取,要通過BufferedImage獲得
<span style="font-size:18px;">int width=100;//確定框框的大小 int height=40; BufferedImage bfi =new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB); Graphics g=bfi.getGraphics();//獲得Graphics對象就可以畫圖</span>
1-2、一般的驗(yàn)證碼背景框都是白色的
<span style="font-size:18px;"> //1,設(shè)置背景(白框框) g.setColor(Color.WHITE);//白色的畫筆 g.fillRect(0, 0, width, height);//畫矩形矩形框框</span>
1-3、保存數(shù)據(jù)(后臺驗(yàn)證使用)和設(shè)置字體樣式(美觀)
String str="";//保存數(shù)據(jù)
Random rom=new Random();
//設(shè)置字體的大寫與粗
g.setFont(new Font("a", Font.BOLD,20));
1-4、生成具體的數(shù)值,以及隨機(jī)生成的顏色
for(int i=0;i<4;i++){
int num=rom.nextInt(10);//生成的隨機(jī)數(shù)
g.setColor(new Color(rom.nextInt(256),rom.nextInt(256), rom.nextInt(256)));//設(shè)置畫筆的顏色(隨機(jī))
g.drawString(""+num, 20*i, 20+rom.nextInt(10));//畫出線,x的位置每一之間增加20,y的坐標(biāo)以20一條線,在線上或者是線下
//PS:位置需要明確些,
}
1-5、一般的數(shù)字容易被其他軟件直接識別出來,為了防黑。稍微加一點(diǎn)干擾線
//畫出一些干擾線
for (int i = 0; i < 10; i++) {
g.setColor(new Color(rom.nextInt(256),rom.nextInt(256), rom.nextInt(256)));//設(shè)置畫筆的顏色(隨機(jī))
g.drawLine(rom.nextInt(100),rom.nextInt(40), rom.nextInt(100), rom.nextInt(40));//位置也是隨機(jī),x,y的值不要超過矩形框框
}
1-6、銷毀Graphics對象和存儲圖片
<span style="white-space:pre"> </span>g.dispose();//銷毀對象 ImageIO.write(bfi, "JPEG", res.getOutputStream());//圖片用字節(jié)流 直接得到 PS::: res是Servlet里面的。
這樣驗(yàn)證碼就生成了,那我們?nèi)绾螌?dǎo)入到前臺去呢
2、具體實(shí)現(xiàn)
前臺代碼呈現(xiàn)():
<body> <h1>用戶登錄</h1><br/> 用戶名:<input type="text" name="nametext"/><br/> 密 碼:<input type="text" name="psd"/><br/> 請輸入驗(yàn)證碼:<input type="text"/> <img <span style="color:#ff0000;">src="/IMG/immg" </span>id="aid"/><a href="javascript:flush()" >看不清</a> </body>
src的地址來源就是從后臺發(fā)過來的。路徑是很有意思的。
2-1步驟
項(xiàng)目里面
myeclipse --> src -->new Servlet 出現(xiàn)如下:

點(diǎn)擊----》next 出現(xiàn)如下頁面:

這個配置會自動到項(xiàng)目里面的web-INF文件夾里面web.xml。這個框框里面的值就是前臺 src里面寫的需要訪問的路徑,----> 點(diǎn)擊完成就行了。
自動了。生成如下界面:

在這里就可寫之前的代碼。但是需要注意,我們必須通過覆蓋這個方法才能有效:
protected void service(HttpServletRequest req, HttpServletResponse resp)//自動生成 輸入 <span style="font-family: Arial, Helvetica, sans-serif;">service 補(bǔ)全,自動生成</span>
throws ServletException, IOException {
// TODO Auto-generated method stub
super.service(req, resp);
}
具體的代碼如下:
package cn.hncu.com.servlet;
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.image.BufferedImage;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Random;
import javax.imageio.ImageIO;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class Imgdemo extends HttpServlet {
@Override
public void service(ServletRequest req, ServletResponse res)
throws ServletException, IOException {
int width=100;//確定框框的大小
int height=40;
BufferedImage bfi =new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
Graphics g=bfi.getGraphics();//獲得Graphics對象就可以畫圖
//1,設(shè)置背景(白框框)
g.setColor(Color.WHITE);//白色的畫筆
g.fillRect(0, 0, width, height);//畫矩形矩形框框
//2,具體生成隨機(jī)數(shù)
String str="";//保存數(shù)據(jù)
Random rom=new Random();
//設(shè)置字體的大寫與粗
g.setFont(new Font("a", Font.BOLD,20));
//畫出具體的圖片
for(int i=0;i<4;i++){
int num=rom.nextInt(10);//生成的隨機(jī)數(shù)
g.setColor(new Color(rom.nextInt(256),rom.nextInt(256), rom.nextInt(256)));//設(shè)置畫筆的顏色(隨機(jī))
g.drawString(""+num, 20*i, 20+rom.nextInt(10));//畫出線,x的位置每一之間增加20,y的坐標(biāo)以20一條線,在線上或者是線下
//PS:位置需要明確些,
}
//畫出一些干擾線
for (int i = 0; i < 10; i++) {
g.setColor(new Color(rom.nextInt(256),rom.nextInt(256), rom.nextInt(256)));//設(shè)置畫筆的顏色(隨機(jī))
g.drawLine(rom.nextInt(100),rom.nextInt(40), rom.nextInt(100), rom.nextInt(40));//位置也是隨機(jī),x,y的值不要超過矩形框框
}
g.dispose();
ImageIO.write(bfi, "JPEG", res.getOutputStream());//圖片用字節(jié)流 直接得到
}
}<span style="font-family: Arial, Helvetica, sans-serif; background-color: rgb(255, 255, 255);"> </span>
前臺代碼:
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%
String path = request.getContextPath();
String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<base href="<%=basePath%>">
<title>My JSP 'img.jsp' starting page</title>
<meta http-equiv="pragma" content="no-cache">
<meta http-equiv="cache-control" content="no-cache">
<meta http-equiv="expires" content="0">
<meta http-equiv="keywords" content="keyword1,keyword2,keyword3">
<meta http-equiv="description" content="This is my page">
<!--
<link rel="stylesheet" type="text/css" href="styles.css">
-->
<script type="text/javascript">
function flush(){
var text=document.getElementById("aid");
var date =new Date();
var tt=date.getTime();
text.src="/IMG/immg?"+tt;
}
</script>
</head>
<body>
<h1>用戶登錄</h1><br/>
用戶名:<input type="text" name="nametext"/><br/>
密 碼:<input type="text" name="psd"/><br/>
請輸入驗(yàn)證碼:<input type="text"/>
<img src="/IMG/immg" id="aid"/><a href="javascript:flush()" >看不清</a>
</body>
</html>
對于前臺代碼需要解釋一下:
當(dāng)我們的的驗(yàn)證碼傳過來看不清的時(shí)候需要刷新,而瀏覽器有自動記憶的功能,當(dāng)沒有新的參數(shù)傳進(jìn)來的時(shí)候,瀏覽器是不會刷新的,所以我們需要手動的去寫一個js控制參數(shù)傳,我們知道,只有時(shí)間是不會變化的,所有我們采用時(shí)間來作為參數(shù)傳遞。
PS:自己坑了一段時(shí)間的問題:驗(yàn)證碼的路徑問題。前端的“/”表示 tomcat目錄,在項(xiàng)目內(nèi)部,如web.xml中“/”表示該項(xiàng)目下。也就是說,他們兩個的目錄差了一層。
最后附上自己在測試的時(shí)候的代碼以及修改數(shù)字形狀的問題,如改成2D的效果更不錯。都有很明顯的記錄。
package cn.hncu.com;
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.geom.AffineTransform;
import java.awt.image.BufferedImage;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Random;
import javax.imageio.ImageIO;
import org.junit.Test;
public class Demoimg {
@Test
public void Test() throws Exception{
String str="9988";
int width=60;
int height=30;
//通過bufferedImage對象獲得Graphics對象
BufferedImage bfi=new BufferedImage(width, height, BufferedImage.TYPE_INT_BGR);
Graphics g=bfi.getGraphics();
g.drawString(str, 10,10);
g.dispose();//類似于IO中的關(guān)流
ImageIO.write(bfi , "JPEG", new FileOutputStream("F:\\ex\\a.jpg"));
//bfi為畫布,將畫布寫到文件中JPEG為指定文件格式
}
@Test
public void Test2() throws Exception{
int width=100;
int height=40;
BufferedImage bfi =new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
Graphics g=bfi.getGraphics();//獲得Graphics對象就可以畫圖
//1,設(shè)置背景(白框框)
g.setColor(Color.WHITE);//白色的畫筆
g.fillRect(0, 0, width, height);
//2,具體生成隨機(jī)數(shù)
String str="";//保存數(shù)據(jù)
Random rom=new Random();
//設(shè)置字體的大寫與粗
g.setFont(new Font("a", Font.BOLD,20));
//畫出具體的圖片
for(int i=0;i<4;i++){
int num=rom.nextInt(10);//生成的隨機(jī)數(shù)
g.setColor(new Color(rom.nextInt(256),rom.nextInt(256), rom.nextInt(256)));//設(shè)置畫筆的顏色(隨機(jī))
g.drawString(""+num, 20*i, 20+rom.nextInt(10));//畫出線,x的位置每一之間增加20,y的坐標(biāo)以20一條線,在線上或者是線下
//PS:位置需要明確些,
}
//畫出一些干擾線
for (int i = 0; i < 10; i++) {
g.setColor(new Color(rom.nextInt(256),rom.nextInt(256), rom.nextInt(256)));//設(shè)置畫筆的顏色(隨機(jī))
g.drawLine(rom.nextInt(100),rom.nextInt(40), rom.nextInt(100), rom.nextInt(40));//位置也是隨機(jī),x,y的值不要超過矩形框框
}
g.dispose();
ImageIO.write(bfi, "JPEG", new FileOutputStream("F:\\ex\\b.jpg"));
}
//畫出可以變化的情況
//字體能夠旋轉(zhuǎn)的驗(yàn)證碼
@Test
public void Test3() throws IOException{
int width=100;
int height=40;
BufferedImage bfi =new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
Graphics g=bfi.getGraphics();
Graphics2D g2d=(Graphics2D) g;
Random rom =new Random();
g2d.setColor(Color.WHITE);//設(shè)置畫筆的顏色
g2d.fillRect(0, 0, width, height);//畫出一個白色的矩形
g2d.setFont(new Font("a", Font.BOLD, 20));
for(int i=0;i<4;i++){
int num=rom.nextInt(10);
//旋轉(zhuǎn),放縮
AffineTransform aff=new AffineTransform();
//aff.rotate(Math.random(), i*18, height-20);//旋轉(zhuǎn)
aff.scale(0.6+Math.random(), 0.6+Math.random());//縮放
g2d.setColor(new Color(rom.nextInt(256),rom.nextInt(256),rom.nextInt(256)));
g2d.setTransform(aff);
g2d.drawString(""+num, i*18, height-25);
}
g2d.dispose();
ImageIO.write(bfi, "JPEG", new FileOutputStream("F:\\ex\\c.jpg"));
}
}
以上就是關(guān)于java生成驗(yàn)證碼的基本流程,還附帶了自己親自的測試的代碼,希望這些都能幫到大家。
相關(guān)文章
java構(gòu)建Stream流的多種方式總結(jié)
Java?8引入了Stream流作為一項(xiàng)新的特性,它是用來處理集合數(shù)據(jù)的一種函數(shù)式編程方式,本文為大家整理了多種java構(gòu)建Stream流的方式,希望對大家有所幫助2023-11-11
解讀Java中打印輸出對象內(nèi)容為什么可以不寫.toString()
這篇文章主要介紹了解讀Java中打印輸出對象內(nèi)容為什么可以不寫.toString()問題,具有很的參考價(jià)值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教2023-09-09
詳解spring+springmvc+mybatis整合注解
本篇文章主要介紹了詳解spring+springmvc+mybatis整合注解,詳細(xì)的介紹了ssm框架的使用,具有一定的參考價(jià)值,有興趣的可以了解一下2017-04-04
RabbitMQ實(shí)現(xiàn)Work Queue工作隊(duì)列的示例詳解
工作隊(duì)列(又稱任務(wù)隊(duì)列)的主要思想是避免立即執(zhí)行資源密集型任務(wù),而不得不等待它完成。本篇文章將記錄和分享RabbitMQ工作隊(duì)列相關(guān)的知識點(diǎn),希望對大家有所幫助2023-01-01
Java使用Apache Commons高效處理CSV文件的操作指南
在 Java 開發(fā)中,CSV(Comma-Separated Values,逗號分隔值)是一種常見的數(shù)據(jù)存儲格式,廣泛用于數(shù)據(jù)交換和簡單的存儲任務(wù),本文將介紹Java使用Apache Commons高效處理CSV文件的操作指南,需要的朋友可以參考下2025-03-03
java利用udp實(shí)現(xiàn)發(fā)送數(shù)據(jù)
這篇文章主要為大家詳細(xì)介紹了java利用udp實(shí)現(xiàn)發(fā)送數(shù)據(jù),文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2020-07-07

