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

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