1.创建一个生成验证码的工具类VCCUtil
package com.example.utils;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.util.Random;
/**
* 生成验证码
*/
public class VCCUtil {
public final static String code = "QWERTYUIOPASDFGHJKLZXCVBNMqwertyuiopasdfghjklzxcvbnm1234567890";
//用于获取每次生成的验证码
private String coding ="";
//无参构造
public VCCUtil() {
}
/**
* @return 验证码
*/
public String getCoding() {
return coding;
}
/**
* @param width 元素的宽
* @param height 元素的高
* @return BufferedImage 验证码图片
*/
public BufferedImage addCode(int width, int height){
//创建图片对象
BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_3BYTE_BGR);
//美化图片
//通过图片对象下的方法获取画笔对象
Graphics gp = image.getGraphics();
//设置画笔的颜色
gp.setColor(Color.PINK);
//使用画笔填充的方法
gp.fillRect(0,0,width,height);
//使用画笔的绘画方法
gp.setColor(Color.orange);
gp.drawRect(0,0,width-1,height-1);
//使用画笔的绘画方法画字符串(写验证码)
Random ran = new Random();
//循环写四个验证码
for (int i = 1; i <=4 ; i++) {
gp.setColor(Color.BLUE);
int index = ran.nextInt(code.length());
int yAxis = ran.nextInt(5)+2;
char ch = code.charAt(index);//随机取字符
gp.drawString(Character.toString(ch),width/10*i+yAxis,height/2+yAxis);
this.coding += ch;//储存生成的验证码
}
//设置干扰线
for (int i = 1; i <3 ; i++) {
gp.setColor(Color.RED);
int x1 = ran.nextInt(20)+10;
int xmax = ran.nextInt(width-100+1)+100;
int y1 = ran.nextInt(20)+10;
int ymax = ran.nextInt(height-20+1)+10;
gp.drawLine(x1,y1,xmax,ymax);
}
return image;
}
}
2.创建servlet层VerifyCodeServlet类,用于每次访问该servlet时调用工具类生成验证码图片并将图片输出到页面,同时将获取到的验证码通过servletContext对象共享数据通过另一个servlet将验证码响应到页面中
package com.example.web.system_info;
import com.example.utils.VCCUtil;
import javax.imageio.ImageIO;
import javax.servlet.*;
import javax.servlet.http.*;
import javax.servlet.annotation.*;
import java.awt.image.BufferedImage;
import java.io.IOException;
@WebServlet(name = "VerifyCodeServlet", value = "/VerifyCode")
public class VerifyCodeServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.doPost(request, response);
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
request.setCharacterEncoding("utf-8");
response.setContentType("text/json;charset=utf-8");
int width = 200;
int heeght = 50;
//获取验证码对象
VCCUtil vccUtil = new VCCUtil();
BufferedImage image = vccUtil.addCode(width, heeght);
String coding = vccUtil.getCoding();
//共享验证码
ServletContext servletContext = this.getServletContext();
servletContext.setAttribute("code",coding);
//将图片输入到页面
ImageIO.write(image, "jpg", response.getOutputStream());
}
}
3.创建VerfyCodeShareServlet类,获取到servletContext域中共享的验证码数据,响应到页面
package com.example.web.system_info;
import com.alibaba.fastjson.JSON;
import javax.servlet.*;
import javax.servlet.http.*;
import javax.servlet.annotation.*;
import java.io.IOException;
import java.io.PrintWriter;
@WebServlet(name = "VerfyCodeShareServlet", value = "/VerfyCodeShare")
public class VerfyCodeShareServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.doPost(request, response);
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
request.setCharacterEncoding("utf-8");
response.setContentType("text/json;charset=utf-8");
PrintWriter writer = response.getWriter();
ServletContext servletContext = this.getServletContext();
String code = (String) servletContext.getAttribute("code");
String s = JSON.toJSONString(code);
writer.write(s);
writer.flush();
writer.close();
// servletContext.removeAttribute("code");
}
}
前端使用的是vue组件
设置验证码图片的格式
<template>
<div class="back">
<div class="box-add">
<el-form :model="ruleForm" :rules="rules" ref="ruleForm" label-width="100px" class="demo-ruleForm">
<el-form-item label="用户名:" prop="userId">
<el-input placeholder="请输入管理员账号" v-model="ruleForm.userId"></el-input>
</el-form-item>
<el-form-item label="密码:" prop="userPwd">
<el-input placeholder="请输入密码" type="password" v-model="ruleForm.userPwd"
autocomplete="off"></el-input>
</el-form-item>
<el-form-item label="验证码:" prop="vCode">
<el-input style="width: 130px" placeholder="请输入验证码" v-model="ruleForm.vCode"></el-input>
<p class="p11" @click="refresh"
style="display: inline-block;width: 150px;height: 40px;overflow: hidden;border-radius: 5px">
<img style="position: relative;bottom: 20px;right: 10px" width="200%" height="200%" id="change"
src="http://localhost:8081/VerifyCode" alt="">
</p>
</el-form-item>
<el-form-item class="button-login">
<el-button type="primary" @click="submitForm('ruleForm')">登录</el-button>
<el-button @click="resetForm('ruleForm')">重置</el-button>
</el-form-item>
</el-form>
</div>
</div>
</template>
2.编写script
export default {
name: "Login",
data() {
return {
code: '',
user: '',
ruleForm: {
vCode: '',
userId: null,
userPwd: null,
userName: null,
roleName: null
},
//验证表单
rules: {
userId: [
{required: true, message: '请输入用户编码', trigger: 'blur'},
{min: 2, max: 20, message: '长度在 2 到 20 个字符', trigger: 'blur'}
],
userPwd: [
{required: true, message: '请输入密码', trigger: 'blur'},
{min: 2, max: 20, message: '长度在 3 到 20 个字符', trigger: 'blur'}
],
vCode: [
{required: true, message: '请输入密码', trigger: 'blur'},
{min: 4, max: 4, message: '验证码个数不正确', trigger: 'blur'}
]
}
};
},
methods: {
//点击图片刷新验证码
refresh() {
var date = new Date();
let time = date.getSeconds();
document.getElementById("change").src = "http://localhost:8081/VerifyCode?" + time;
//获取验证码
this.getRefresh();
},
//获取验证码用于点击时获取
getRefresh(){
const _this = this;
axios.get("http://localhost:8081/VerfyCodeShare?").then((resp) => {
_this.code = resp.data;
console.log(_this.code);
})
},
//网页打开时先刷新一次后台中的验证码,不然页面中显示的验证码与真实校验的验证码不符
visitVerty(){
axios.get("http://localhost:8081/VerifyCode");
},
submitForm(formName) {
this.$refs[formName].validate((valid) => {
if (valid) {
const _this = this;
console.log(_this.ruleForm.vCode);//输出用户输入的验证码
console.log(_this.code);//在控制台输出获取到的当前验证码
if (_this.code === _this.ruleForm.vCode) {
axios.post("http://localhost:8081/Login", this.ruleForm).then((resp) => {
if (resp.data.userId == this.ruleForm.userId && resp.data.userPwd === this.ruleForm.userPwd) {
this.$message({
message: '登录成功!',
type: 'success'
});
//将用户名放入sessionStorage中
sessionStorage.setItem("user", JSON.stringify(resp.data));
sessionStorage.setItem("userToken", resp.data.userPwd)
//将用户名放入vuex中
_this.$store.dispatch("setUser", JSON.stringify(resp.data));
_this.$store.dispatch("setToken", resp.data.userPwd);
//打印login状态
console.log(_this.$store.state.isLogin);
_this.$router.push("/home");
} else {
this.$message({
showClose: true,
message: '登录失败',
type: 'error'
});
}
})
} else {
this.$message({
showClose: true,
message: '验证码不正确',
type: 'error'
});
}
} else {
console.log('error submit!!');
return false;
}
});
},
resetForm(formName) {
this.$refs[formName].resetFields();
},
},
beforeRouteEnter: (to, from, next) => {
next(vm => {
vm.$store.dispatch("setUser", null);
});
},
created() {
//钩子函数,页面加载前获取验证码
this.visitVerty();
}
}
2.编写css样式
.back {
overflow: hidden;
position: absolute;
top: 0;
left: 0;
width: 100vw;
height: 100vh;
background: url("../assets/222.jpg") no-repeat 0 0/100% 100%;
}
.p11 {
position: absolute;
top: -13px;
right: 5px;
}
.box-add {
width: 400px;
height: 300px;
border-radius: 30px;
padding-top: 100px;
padding-right: 50px;
margin: 100px auto;
background-color: rgba(100, 100, 100, 0.5);
/*box-shadow: 0 0 5px 2px rgba(28, 27, 27, 0.53);*/
}
.button-login {
margin-top: 40px;
}
.button-login .el-button {
margin: 0 25px;
}
测试一下控制台输出的验证码 与 页面显示的验证码是否一致