功能简介
捣腾了几天,总算实现这个小小的登录功能,在此记录一下。
功能:输入框中输入用户名和密码和验证码,提交到服务器进行处理,如果验证码正确,就连接数据库查看用户名和密码是否存在,存在则进入主界面,否则重定向到登录界面。如果勾选了十天内免登录,则Cookie会记录用户名和密码,下次进入登录界面,就会自动填充上去。
所需的所有文件如下:
下面一步一步讲解如何实现的。
数据库相关准备
因为要连接mysql数据库,所以首先创建一个数据库login,再创建一张表users来保存用户名和密码。
//创建数据库
create database login;
//创建数据表
create table users
(username char(50) primary key,
pwd char(50) not null
);
//插入用户信息
insert into users values('admin','123');
接着就是下载连接mysql的驱动程序,并导入到MyEclipse中,详细步骤参考:http://blog.csdn.net/yanhui_wei/article/details/36011107
数据库的相关准备弄好之后,接下来就看看各个jsp程序。
登录界面
login.jsp
<%@ page language="java" import="java.util.*,java.net.*"
contentType="text/html; charset=utf-8"%>
<%
String path = request.getContextPath();
String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
%>
<%
request.setCharacterEncoding("utf-8");
response.setContentType("text/html;charset=utf-8");
String username = "";
String password = "";
Cookie[] arrCookie = request.getCookies();
if (arrCookie != null) {
for (Cookie ck : arrCookie) {
if (ck.getName().equals("UserName")) {
username = URLDecoder.decode(ck.getValue(), "utf-8");
}
if (ck.getName().equals("PassWord")) {
password = URLDecoder.decode(ck.getValue(), "utf-8");
break;
}
}
}
%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<base href="<%=basePath%>">
<title>登录</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 reloadCode() {
checkcode.src = "servlet/validateCode?id=" + (new Date()).getTime();
}
</script>
</head>
<body>
<div class="wrapper">
<div class="form">
<form name="loginForm" action="dologin" method="post">
<table>
<tr>
<td>用户名:</td>
<td><input type="text" name="txtUsername"
value="<%=username%>" class="input" placeholder="请输入用户名admin" />
</td>
</tr>
<tr>
<td>密码:</td>
<td><input type="password" name="txtPassword"
value="<%=password%>" class="input" placeholder="请输入密码123" />
</td>
</tr>
<tr>
<td>验证码:</td>
<td><input name="txtCheckCode" type="text" id="txtCheckCode"
placeholder="请输入验证码" class="captcha_input"> <a
href="javascript:reloadCode();"> <img
src="servlet/validateCode" id="checkcode" /> </a></td>
</tr>
<tr>
<td colspan="2"><input type="checkbox" name="isUseCookie"
checked="checked" />十天内记住我的登录状态</td>
</tr>
<tr>
<td colspan="2" align="center"><input type="submit"
value="登录" class="input login" />
</td>
</tr>
</table>
</form>
<div class="divider">
——————<span>第三方登录</span>—————
</div>
<!-- 页底开始 -->
<footer>
<p>Copyright 2017@Paranoidyang</p>
</footer>
</div>
<!-- 页底结束 -->
</div>
</body>
</html>
页面效果:
因为对这些页面进行了css设置,所以还有个
styles.css
@CHARSET "UTF-8";
* {
margin: 0;
padding: 0;
}
.wrapper {
width: 354px;
margin: 0 auto;
}
.form{
height: 300px;/*元素的高度*/
position: absolute;
top: 50%;/*元素的顶部边界离父元素的的位置是父元素高度的一半*/
margin-top: -150px;/*设置元素顶边负边距,大小为元素高度的一半*/。
}
.input {
border: 1px solid #B8B8B8;
width: 280px;
height: 45px;
padding: 0 10px;
border-radius: 5px; /*将输入框变为圆角的,5px为圆角半径*/
}
.captcha_input {
border: 1px solid #B8B8B8;
width: 184px;
height: 45px;
padding: 0 10px;
/* border-radius: 5px;将输入框变为圆角的,5px为圆角半径 */
border-top-left-radius: 5px;
border-bottom-left-radius: 5px;
}
input,
img{vertical-align:middle;}/* 让输入框和验证码图片水平局中对齐,默认情况下,图片会高出文本框一些,很难看 */
img{
height:45px;
width:90px;
}
.login {
width: 350px;
color: #fff;
background-color: #4798F6;
border: none;
margin-top: 10px;
}
/*分隔线样式*/
.divider {
letter-spacing: -1px;
color: #ddd;
text-align:center;
}
.divider span {
letter-spacing: 0;
color: #B8B8B8;
margin: 0 20px;
}
footer p {
text-align: center;
font-size: 14px;
color: #B8B8B8;
}
生成验证码
从登录页面中,可以看到有个输入验证码的功能,这是现在很多网站登录验证的一种方式。它的工作机制是这样的:当你用户名或密码输入错误时,就会弹出让输入验证码的页面,如果你一次性就输正确了,它是不会出现的,这样下来,就可以防止不法分子利用特定程序对网站进行恶意的注册和攻击。在这里,我简化这个步骤,直接就显示出让你输入验证码的界面(注意:其他网站登录中是只在输错时才会让你输入验证码的喔)。
工作原理:首先,服务端随机产生几个随机数或者随机算式,然后通过session对象将数据传输到客户端,客户端输入验证码,通过表单将数据提交到服务器,服务器提取数据之后和产生的随机数字或者算式的结果对比,以此进行验证。
下面的代码就是服务器端用于生成验证码的:
validateCode.java
package util;
import java.awt.*;
import java.awt.geom.*;
import java.awt.image.*;
import java.io.*;
import java.util.*;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import javax.imageio.ImageIO;
/*
* 生成验证码
*/
public class validateCode extends HttpServlet {
private static final long serialVersionUID = 1L;
public validateCode() {
super();
}
public void destroy() {
super.destroy();
}
public void init() throws ServletException {
super.init();
}
/*该方法主要作用是获得随机生成的颜色*/
public Color getRandColor(int s,int e){
Random random=new Random ();
if(s>255) s=255;
if(e>255) e=255;
int r,g,b;
r=s+random.nextInt(e-s); //随机生成RGB颜色中的r值
g=s+random.nextInt(e-s); //随机生成RGB颜色中的g值
b=s+random.nextInt(e-s); //随机生成RGB颜色中的b值
return new Color(r,g,b);
}
@Override
public void service(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
//设置不缓存图片
response.setHeader("Pragma", "No-cache");
response.setHeader("Cache-Control", "No-cache");
response.setDateHeader("Expires", 0);
//指定生成的响应图片,一定不能缺少这句话,否则错误.
response.setContentType("image/jpeg");
int width=85,height=25; //指定生成验证码的宽度和高度
BufferedImage image=new BufferedImage(width,height,BufferedImage.TYPE_INT_RGB); //创建BufferedImage对象,其作用相当于一图片
Graphics g=image.getGraphics(); //创建Graphics对象,其作用相当于画笔
Graphics2D g2d=(Graphics2D)g; //创建Grapchics2D对象
Random random=new Random();
Font mfont=new Font("楷体",Font.BOLD,16); //定义字体样式
g.setColor(getRandColor(200,250));
g.fillRect(0, 0, width, height); //绘制背景
g.setFont(mfont); //设置字体
g.setColor(getRandColor(180,200));
//绘制100条颜色和位置全部为随机产生的线条,该线条为2f
for(int i=0;i<100;i++){
int x=random.nextInt(width-1);
int y=random.nextInt(height-1);
int x1=random.nextInt(6)+1;
int y1=random.nextInt(12)+1;
BasicStroke bs=new BasicStroke(2f,BasicStroke.CAP_BUTT,BasicStroke.JOIN_BEVEL); //定制线条样式
Line2D line=new Line2D.Double(x,y,x+x1,y+y1);
g2d.setStroke(bs);
g2d.draw(line); //绘制直线
}
//输出由英文,数字,和中文随机组成的验证文字,具体的组合方式根据生成随机数确定。
String sRand="";
String ctmp="";
int itmp=0;
//制定输出的验证码为四位
for(int i=0;i<4;i++){
switch(random.nextInt(3)){
case 1: //生成A-Z的字母
itmp=random.nextInt(26)+65;
ctmp=String.valueOf((char)itmp);
break;
case 2: //生成汉字
String[] rBase={"0","1","2","3","4","5","6","7","8","9","a","b","c","d","e","f"};
//生成第一位区码
int r1=random.nextInt(3)+11;
String str_r1=rBase[r1];
//生成第二位区码
int r2;
if(r1==13){
r2=random.nextInt(7);
}else{
r2=random.nextInt(16);
}
String str_r2=rBase[r2];
//生成第一位位码
int r3=random.nextInt(6)+10;
String str_r3=rBase[r3];
//生成第二位位码
int r4;
if(r3==10){
r4=random.nextInt(15)+1;
}else if(r3==15){
r4=random.nextInt(15);
}else{
r4=random.nextInt(16);
}
String str_r4=rBase[r4];
//将生成的机内码转换为汉字
byte[] bytes=new byte[2];
//将生成的区码保存到字节数组的第一个元素中
String str_12=str_r1+str_r2;
int tempLow=Integer.parseInt(str_12, 16);
bytes[0]=(byte) tempLow;
//将生成的位码保存到字节数组的第二个元素中
String str_34=str_r3+str_r4;
int tempHigh=Integer.parseInt(str_34, 16);
bytes[1]=(byte)tempHigh;
ctmp=new String(bytes);
break;
default:
itmp=random.nextInt(10)+48;
ctmp=String.valueOf((char)itmp);
break;
}
sRand+=ctmp;
Color color=new Color(20+random.nextInt(110),20+random.nextInt(110),random.nextInt(110));
g.setColor(color);
//将生成的随机数进行随机缩放并旋转制定角度 PS.建议不要对文字进行缩放与旋转,因为这样图片可能不正常显示
/*将文字旋转制定角度*/
Graphics2D g2d_word=(Graphics2D)g;
AffineTransform trans=new AffineTransform();
trans.rotate((45)*3.14/180,15*i+8,7);
/*缩放文字*/
float scaleSize=random.nextFloat()+0.8f;
if(scaleSize>1f) scaleSize=1f;
trans.scale(scaleSize, scaleSize);
g2d_word.setTransform(trans);
g.drawString(ctmp, 15*i+18, 14);
}
HttpSession session=request.getSession(true);
session.setAttribute("randCheckCode", sRand);
g.dispose(); //释放g所占用的系统资源
ImageIO.write(image,"JPEG",response.getOutputStream()); //输出图片
}
}
服务器登录处理程序
用户在输入框输入完所有要求的内容后,点击登录,这些数据就会被提交到服务器的dologin.java程序,对登录操作进行处理,首先判断验证码是否正确,如果错误则重定向回login.jsp,如果正确则连接数据库,查看数据库是否存在输入的用户名和密码,如果存在则跳转到main.jsp,否则重定向到login.jsp
dologin.java
import java.io.IOException;
import java.net.URLEncoder;
import java.sql.DriverManager;
import java.sql.ResultSet;
import javax.servlet.ServletException;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.mysql.jdbc.Connection;
import com.mysql.jdbc.PreparedStatement;
public class dologin extends HttpServlet {
public dologin() {
super();
}
public void destroy() {
super.destroy();
}
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
Connection ct;
PreparedStatement ps;
ResultSet rs;
// 驱动程序名
String driver = "com.mysql.jdbc.Driver";
// URL指向要访问的数据库名library
String url = "jdbc:mysql://localhost:3306/login";
// MySQL配置时的用户名
String user = "root";
// MySQL配置时的密码
String password = "642765";
// 输入的用户名和密码
String txtUsername;
String txtPassword;
// 数据库中存储的用户名和密码
String myuserword;
String mypwd;
// 接收数据
txtUsername = request.getParameter("txtUsername");
txtPassword = request.getParameter("txtPassword");
// 验证码检测
String txtCheckCode = request.getParameter("txtCheckCode");// 获取输入框中输入的验证码
String CheckCode = request.getSession().getAttribute("randCheckCode")
.toString();// 获取验证码真实的值
boolean judgeCheckCode = txtCheckCode.equals(CheckCode);// 比对输入的验证码与真实验证码是否一致
// 如果验证码正确,就连接数据库,对比用户名和密码
if (judgeCheckCode) {
System.out.println("验证码正确");
System.out.println("正在连接数据库...");
try {
// 加载驱动程序
Class.forName(driver);
// getConnection()方法,连接MySQL数据库!!
ct = (Connection) DriverManager.getConnection(url, user,
password);
if (ct != null) {
System.out.println("数据库连接成功!");
}
ps = (PreparedStatement) ct
.prepareStatement("select * from users where username=? and pwd=? ");
ps.setString(1, txtUsername); // 将第一个?设置为参数txtUsername
ps.setString(2, txtPassword); // 将第二个?设置为参数txtPassword
// rs是一个ResultSet结果集,可以把rs理解成返回一张表行的结果集
rs = ps.executeQuery(); // 执行查找看是否存在,有的话rs.next()返回true,反之为
// false
// 如果存在此用户,则跳转到主界面
if (rs.next()) {
myuserword = rs.getString(1);// 获得表格的第一列,此处为用户名
mypwd = rs.getString(2); // 获得表格的第二列,此处为密码
System.out.println("成功从login数据库的users表中获取到用户名和密码:");
System.out.println(myuserword + "\t" + mypwd + "\t");// “\t”为“转义字符”,代表的是一个tab,也就是8个空格。
response.sendRedirect("main.jsp");
} else {
System.out.println("没有该用户,请重新输入");
response.sendRedirect("login.jsp");
}
ct.close();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
// 如果验证码错误,就跳转回登录界面
} else {
System.out.println("验证码错误");
response.sendRedirect("login.jsp");
}
// 判断是否勾选十天免登录
boolean isRememberUser = (request.getParameter("isUseCookie") != null);
if (isRememberUser) {// 要记住用户
// 把用户名和密码保存在Cookie对象里面
String username = URLEncoder.encode(txtUsername, "utf-8");
// 使用URLEncoder解决无法在Cookie当中保存中文字符串问题,
String pwd = URLEncoder.encode(txtPassword, "utf-8");
Cookie usernameCookie = new Cookie("UserName", username);
Cookie passwordCookie = new Cookie("PassWord", pwd);
usernameCookie.setMaxAge(60*60*24*10);
passwordCookie.setMaxAge(60*60*24*10);// 设置最大生存期限为10天
response.addCookie(usernameCookie);
response.addCookie(passwordCookie);
} else {
Cookie[] cookies = request.getCookies();
if (cookies != null && cookies.length > 0) {
for (Cookie c : cookies) {
if (c.getName().equals("UserName")
|| c.getName().equals("PassWord")) {
c.setMaxAge(0); // 设置Cookie失效
response.addCookie(c); // 重新保存。
}
}
}
}
}
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doGet(request, response);
}
public void init() throws ServletException {
}
}
主界面
当用户名、密码、验证码都正确时,就会跳转到main.jsp,程序如下:
main.jsp
<%@ page language="java" import="java.util.*,java.net.*" contentType="text/html; charset=utf-8"%>
<%@ page import="util.*"%>
<%
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>主界面</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">
-->
</head>
<body>
<h1>主界面</h1>
<hr>
</body>
</html>
页面显示如下:
web.xml配置
还有一步,不要漏掉了,在web.xml中还有做相关的配置,配置文件内容如下:
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" version="2.5">
<display-name></display-name>
<servlet>
<description>This is the description of my J2EE component</description>
//验证码相关配置
<servlet-name>validateCode</servlet-name>
<servlet-class>util.validateCode</servlet-class>
</servlet>
<servlet>
<servlet-mapping>
<servlet-name>validateCode</servlet-name>
<url-pattern>/servlet/validateCode</url-pattern>
</servlet-mapping>
//服务器处理程序相关配置
<servlet-name>dologin</servlet-name>
<servlet-class>dologin</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>dologin</servlet-name>
<url-pattern>/dologin</url-pattern>
</servlet-mapping>
//设置默认界面
<welcome-file-list>
<welcome-file>login.jsp</welcome-file>
</welcome-file-list>
</web-app>
总结
到此,这个简易的登录验证就实现了,还有很多需要修改完善的,接下来几天再慢慢都写下来,敬请关注。