Java实现验证码步骤详解

在生活中,我们登陆一个网站的时候经常会碰到需要登陆的界面,而这种界面的通常会有一个输入框,后面跟着一个图片,叫你在输入框中输入图片中的数字和字母,完成登录校验。

页面如下图所示:
在这里插入图片描述
而这种验证码是怎么实现的呢?

下面就来写一个小项目,来试一下这个登录界面上加上一个验证码:(本项目使用spring+mybatis+servlet实现)
系统的基本流程就是:用户通过前台表单提交信息给servlet,servlet将前台传过来的信息和后台传过来的信息进行比较并跳转页面,而验证码的信息时存在session中的。

首先,我们建一个表:(实现登录的校验)
在这里插入图片描述
然后在eclipse中建立一个动态web工程(包结构如下)
在这里插入图片描述
在这里插入图片描述](https://img-blog.csdnimg.cn/20191027164436209.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzM3NzQ1NjM2,size_16,color_FFFFFF,t_70)
按照如图所示建好包结构:
导包:
在这里插入图片描述
我们先建好实体类:Users.java (和数据库中的字段对应好)

package com.zmx.pojo;

public class Users {
	
	private Integer id;
	private String username;
	private String password;
	
	public Integer getId() {
		return id;
	}
	public void setId(Integer id) {
		this.id = id;
	}
	public String getUsername() {
		return username;
	}
	public void setUsername(String username) {
		this.username = username;
	}
	public String getPassword() {
		return password;
	}
	public void setPassword(String password) {
		this.password = password;
	}
	
}

第二步,编写UsersMapper.java接口 (用来查询用户名和密码是否和数据库中匹配,这里采用的是注解方式)

package com.zmx.mapper;

import org.apache.ibatis.annotations.Select;

import com.zmx.pojo.Users;

public interface UsersMapper {
	
	@Select("select * from users where username=#{username} and password=#{password}")
	Users selByUsersPwd(Users users);
}

第三步:编写UsersService接口(用来执行业务逻辑)

package com.zmx.service;

import com.zmx.pojo.Users;

public interface UsersService {
	
	Users login(Users users);
}

第四步:编写UsersService接口的实现类UsersServiceImpl(业务逻辑实现类)

package com.zmx.service.impl;

import com.zmx.mapper.UsersMapper;
import com.zmx.pojo.Users;
import com.zmx.service.UsersService;

public class UsersServiceImpl implements UsersService {
	
	private UsersMapper usersMapper;
	
	public UsersMapper getUsersMapper() {
		return usersMapper;
	}

	public void setUsersMapper(UsersMapper usersMapper) {
		this.usersMapper = usersMapper;
	}


	public Users login(Users users) {
		return usersMapper.selByUsersPwd(users);
	}

}

这里引入了UsersMapper,并实现了get/set方法,目的就是将UsersMapper注入UsersServiceImpl中,从而可以调用UsersMapper中的方法。

第五步:编写Servlet(LoginServlet和ValidCodeServlet)
其中UsersServlet是用来进行数据校验的,而ValidCodeServlet是用来创建一个验证码
首先,我们先来创建ValidCodeServlet:

package com.zmx.servlet;

import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;

import javax.imageio.ImageIO;
import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

@WebServlet("/validcode")
public class ValidCodeServlet extends HttpServlet {
	
	@Override
	protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
		//创建一张图片
		BufferedImage image = new BufferedImage(200, 100, BufferedImage.TYPE_INT_RGB);
		
		//透明玻璃
		Graphics2D gra = image.createGraphics();
		//设置画笔颜色
		gra.setColor(Color.white);
		//从哪个座标开始填充,后两个参数,矩阵区域
		gra.fillRect(0, 0, 200, 100);
		
		//产生4个一位数的随机数
		List<Integer> randList = new ArrayList<Integer>();
		Random rand = new Random();
		for(int i=0; i < 4; i++) {
			randList.add(rand.nextInt(10));
		}
		
		//设置画笔的颜色及样式
		gra.setColor(Color.BLACK);
		gra.setFont(new Font("宋体",Font.BOLD|Font.ITALIC,40));
		Color[] colors = new Color[] {Color.RED,Color.YELLOW,Color.BLUE,Color.GREEN,Color.PINK,Color.GRAY};
		
		//将rand产生的4个随机数画在透明玻璃上
		for(int i=0; i < randList.size(); i++) {
			gra.setColor(colors[rand.nextInt(colors.length)]);
			gra.drawString(randList.get(i)+"", i*40, 70+(rand.nextInt(21)-10));
		}
		
		//在验证码图片上随机画上2条线
		for(int i = 0; i < 2; i++) {
			gra.setColor(colors[rand.nextInt(colors.length)]);
			//画横线
			gra.drawLine(0, rand.nextInt(101), 200, rand.nextInt(101));
		}
		
		//设置图片的格式,并输出到页面上
		ServletOutputStream outputStream = resp.getOutputStream();
		ImageIO.write(image, "jpg", outputStream);
		
		//将验证码中的4位数字转换成字符保存在session中
		HttpSession session = req.getSession();
		session.setAttribute("code", ""+randList.get(0)+randList.get(1)+randList.get(2)+randList.get(3));
	}
}

LoginServlet:

package com.zmx.servlet;

import java.io.IOException;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import org.springframework.context.ApplicationContext;
import org.springframework.web.context.support.WebApplicationContextUtils;

import com.zmx.pojo.Users;
import com.zmx.service.UsersService;
import com.zmx.service.impl.UsersServiceImpl;

@WebServlet("/login")
public class LoginServlet extends HttpServlet {
	
	private UsersService usersService;
	
	@Override
	public void init() throws ServletException {
		ApplicationContext ac = WebApplicationContextUtils.getRequiredWebApplicationContext(getServletContext());
		usersService = ac.getBean("usersService",UsersServiceImpl.class);
	}
	
	@Override
	protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
		req.setCharacterEncoding("utf-8");
		String code = req.getParameter("code");
		HttpSession session = req.getSession();
		String codeSession = session.getAttribute("code").toString();
		if(codeSession.equals(code)) {
			String username = req.getParameter("username");
			String password = req.getParameter("password");
			Users users = new Users();
			users.setUsername(username);
			users.setPassword(password);
			Users user = usersService.login(users);
			if(user != null) {
				resp.sendRedirect("main.jsp");
			} else {
				req.setAttribute("error", "用户名或密码不正确");
				req.getRequestDispatcher("index.jsp").forward(req, resp);
			}
		} else {
			req.setAttribute("error", "验证码不正确");
			req.getRequestDispatcher("index.jsp").forward(req, resp);
			
		}
	}
}

spring的核心配置文件:applicationContext.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="
        http://www.springframework.org/schema/beans 
        http://www.springframework.org/schema/beans/spring-beans.xsd">
    
    <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
    	<property name="url" value="jdbc:mysql:///heima" />
    	<property name="username" value="root" />
    	<property name="password" value="123" />
    	<property name="driverClassName" value="com.mysql.jdbc.Driver" />
    </bean>
    
    <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
    	<property name="dataSource" ref="dataSource" />
    </bean>
    
    <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
    	<property name="basePackage" value="com.zmx.mapper" />
    	<property name="sqlSessionFactory" ref="sqlSessionFactory" />
    </bean>
    
    <bean id="usersService" class="com.zmx.service.impl.UsersServiceImpl">
    	<property name="usersMapper" ref="usersMapper"></property>
    </bean>
    
</beans>

log4j.properties

log4j.rootCategory=INFO, CONSOLE ,LOGFILE

log4j.logger.com.zmx.mapper=DEBUG

log4j.appender.CONSOLE=org.apache.log4j.ConsoleAppender
log4j.appender.CONSOLE.layout=org.apache.log4j.PatternLayout
log4j.appender.CONSOLE.layout.ConversionPattern=%C %d{YYYY-MM-dd hh:mm:ss}  %m %n

log4j.appender.LOGFILE=org.apache.log4j.FileAppender
log4j.appender.LOGFILE.File=E:/my.log
log4j.appender.LOGFILE.Append=true
log4j.appender.LOGFILE.layout=org.apache.log4j.PatternLayout
log4j.appender.LOGFILE.layout.ConversionPattern=%m %n

在web.xml中配置:在tomcat启动的时候就去加载spring核心配置文件

 <context-param>
  	<param-name>contextConfigLocation</param-name>
  	<param-value>classpath:applicationContext.xml</param-value>
  </context-param>
  
  <listener>
  	<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
  </listener>

index.jsp中使用了js代码,而点击看不清的时候向ValidCodeServlet传入一个时间戳的目的是,如果写传的话,因为浏览器的缓存机制,页面不会进行跳转。

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
<script type="text/javascript" src="js/jquery-1.7.2.js"></script>
<script type="text/javascript">
$(function(){
	$("a").click(function(){
		$("img").attr("src","validcode?date="+new Date());
		return false;
	})
})
</script>
</head>
<body>
${error }
	<form action="login" method="post">
		<table>
			<tr>
				<td>用户名:</td>
				<td><input type="text" name="username" /></td>
			</tr>
			<tr>
				<td>密码:</td>
				<td><input type="password" name="password" /></td>
			</tr>
			<tr>
				<td>验证码:</td>
				<td><input type="text" size="10" name="code" /><img src="validcode" width="80" height="40" /><a href="">看不清</a></td>
			</tr>
			<tr>
				<td><input type="submit" value="登录"></td>
				<td><input type="reset" value="重置"></td>
			</tr>
			
		</table>
	</form>
</body>
</html>

main.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
成功跳转
</body>
</html>

至此,这个小项目就算是完成了,
项目源码附下:
https://pan.baidu.com/s/1A7uxTSIy_6C0Ppq9YXf19g

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章