文章目录
- 1.实现最简单的登录
- 2.过滤器处理中文乱码
- 3.编写最简单前端页面
- 4.编写验证码servlet
- 5.修改前端页面,添加验证码和自动登录按钮
- 6.实现自动登录
- 7.前端脚本编写:读取cookie并实现验证的点击切换
- 8.小结
1.实现最简单的登录
首先,要想实现验证码和自动登录就要弄清楚登录这个过程中有多少步骤,那么接下来我来说说我的登录逻辑。
首先,要实现登录,必须要servlet去验证输入的用户名和密码是否正确,
那么简单的servlet就出炉了:
package com.ps.Servlet;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.*;
import java.io.IOException;
//这里配置的就是以后表单要提交的地址
@WebServlet(urlPatterns = "/Login")
public class LoginServlet 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 {
//获取数据
String username = request.getParameter("username");
String password = request.getParameter("password");
//在这里应该是把参数传给数据库来判断的,为了简便演示,我就先这么写了
if ("admin".equals(username) && "123456".equals(password)) {
//把登录后的信息存储在会话域中,方面访问别的页面使用
session.setAttribute("username", username);
//跳转到index页面
response.sendRedirect("index.jsp");
} else {
//输入的信息错误,跳回到原页面,需要重新输入
request.getRequestDispatcher("login.html").forward(request, response);
}
}
2.过滤器处理中文乱码
写到这里实现并运行过的小伙伴就会发现一个问题,那就有些时候传入的参数会乱码,尤其是在传入中文的时候会乱码。
原因是我没有处理请求的编码格式,这是为什么呢?
因为在比较大的项目中,这种问题经常会出现,如果每个servlet里面都加入的话,就比较麻烦,为了不麻烦,那我们编写一个处理请求参数乱码问题的过滤器(filter)就好了。
不会没有关系,代码在下面:
package com.ps.Filter;
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
/**
* 目标:
* 拦截请求,把涉及到登录和注册的请求拦截下来,修改请求编码避免获取参数的时候乱码
*/
//这里配置的就是servlet1的路径配置成完全一样的就好了
@WebFilter(urlPatterns = "/Login")
public class RequestFilter implements Filter {
public void destroy() {
}
public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws ServletException, IOException {
//1.强性把类型转换,便于操作
HttpServletRequest request = (HttpServletRequest) req;
HttpServletResponse response = (HttpServletResponse) resp;
//2.修改编码,防止乱码
request.setCharacterEncoding("utf-8");
//3.放行
chain.doFilter(request, response);
}
public void init(FilterConfig config) throws ServletException {
}
}
3.编写最简单前端页面
写完上面两个步骤的话,我们就可以先写一个前端页面来测试一下了。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>login</title>
</head>
<body>
<h2>用户登录</h2>
<!--form的id是为了以后自动登录的时候获取,method就是请求的方法,action就是请求的servlet地址,就是前面配置的那个-->
<form action="Login" method="post" id="loginForm">
<!--name属性是给servlet获取值的-->
用户名: <input name="username" type="text">
<br>
<br>
密码: <input name="password" type="password">
<br>
<br>
<input value="登录" type="submit">
</form>
</body>
</html>
以上,就是最简单的一个登录功能的实现了,我相信都已经跟的上了,那么接下来我们就稍稍微微的加快点速度
4.编写验证码servlet
这里其实没有太多好说的,都是比较固定的东西,所以看看就好。
package com.ps.Servlet;
import javax.imageio.ImageIO;
import javax.servlet.ServletContext;
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 java.awt.*;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.util.Random;
/**
* 生成验证码,并把验证码存储在会话域中
*/
@WebServlet(urlPatterns = "/Encode")
public class EncodeServlet extends HttpServlet {
// 写一个方法随机获取颜色
public Color randomColor() {
// r g b 取值范围 0到255
Random random = new Random();
return new Color(
random.nextInt(256),
random.nextInt(256),
random.nextInt(256));
}
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.doGet(request, response);
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 创建缓存图片:指定宽width=90,高 height=30
int width = 90;
int height = 30;
BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
// 获取画笔对象
Graphics g = image.getGraphics();
// 设置画笔颜色,并且填充矩形区域
g.setColor(Color.white);
g.fillRect(0, 0, width, height);
// 创建可变字符串
StringBuilder sb = new StringBuilder();
// 从字符数组中随机得到字符,根据需求添加你需要的字符
char[] arr = {'1', '2', '3', '4', '5', '6', '7', '8', '9', '0',
'A', 'B', 'C', 'D', 'N', 'E', 'W', 'b', 'o', 'y'};
// 创建随机对象
Random r = new Random();
for (int i = 0; i < 4; i++) {
// 随机产生一个索引值
int index = r.nextInt(arr.length);
// 根据索引获得随机字符
char ch = arr[index];
// 拼接字符
sb.append(ch);
// 设置字体,大小为 18
g.setFont(new Font(Font.DIALOG, Font.BOLD + Font.ITALIC, 18));
// 设置字的颜色随机
g.setColor(randomColor());
// 绘制字符串
// 7. 将每个字符画到图片上,位置:
int x = 5 + (i * 20);
int y = 20;
g.drawString(String.valueOf(ch), x, y);
}
// 将验证码字符串存储会话域中
HttpSession session = request.getSession();
session.setAttribute("verCode", sb.toString());
// 8. 画10条干扰线,线的位置是随机的,x 范围在 width 之中,y 的范围在 height 之中。
for (int i = 0; i < 10; i++) {
// 设置颜色随机
g.setColor(randomColor());
int x1 = r.nextInt(width + 1);
int x2 = r.nextInt(height + 1);
int y1 = r.nextInt(width + 1);
int y2 = r.nextInt(height + 1);
g.drawLine(x1, y1, x2, y2);
}
// 9. 将缓存的图片输出到响应输出流中
ImageIO.write(image, "png", response.getOutputStream());
}
}
这样写完之后,我们前端页面只需要把img标签的src地址写成我们servlet的地址就可以实现验证码了。而之前的servlet也只需要根据相应的标签获取页面的验证码,再去获取会话域中的存放的正确验证码即可,由于还要实现自动登录,一会儿一起放最终结果好了。
5.修改前端页面,添加验证码和自动登录按钮
前面已经把主要功能实现了,那么接下来就是随便修改一下页面就好了,如下:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>login</title>
<style>
body {
margin-top: 20px;
margin: 0 auto;
}
.carousel-inner .item img {
width: 100%;
height: 300px;
}
.container .row div {
/* position:relative;
float:left; */
}
font {
color: #666;
font-size: 22px;
font-weight: normal;
padding-right: 17px;
}
</style>
</head>
<body>
<div class="container" style="width:100%;height:460px;">
<div class="row">
<div class="col-md-5">
<div style="width:440px;border:1px solid #E7E7E7;padding:20px 0 20px 30px;border-radius:5px;margin-top:60px;background:#fff;">
<form id="loginForm" class="form-horizontal" action="Login" method="post">
<div class="form-group">
<label for="username" class="col-sm-2 control-label">用户名</label>
<div class="col-sm-6">
<!--表单要加上name属性,否则服务器得到不值-->
<input type="text" class="form-control" name="username" id="username" placeholder="请输入用户名">
</div>
</div>
<div class="form-group">
<label for="password" class="col-sm-2 control-label">密码</label>
<div class="col-sm-6">
<input type="password" class="form-control" name="password" id="password"
placeholder="请输入密码">
</div>
</div>
<div class="form-group">
<label for="verCode" class="col-sm-2 control-label">验证码</label>
<div class="col-sm-3">
<input type="text" class="form-control" name="verCode" id="verCode" placeholder="请输入验证码">
</div>
<div class="col-sm-3">
<img src="Encode" style="width: 90px; height: 30px; cursor: pointer;"
onclick="changeImage(this)"
title="看不清,点击刷新">
</div>
</div>
<div class="form-group">
<div class="col-sm-offset-2 col-sm-10">
<div class="checkbox">
<label>
<input name="remember" type="checkbox"> 自动登录
</label>
</div>
</div>
</div>
<div class="form-group">
<div class="col-sm-offset-2 col-sm-10">
<input id="click" type="submit" width="100" value="登录" name="submit" border="0"
style=" eight:35px;width:100px;">
</div>
</div>
</form>
</div>
</div>
</div>
</div>
</body>
</html>
这样一个比较有代表性的框就有了,只需要实现功能就可以了。
6.实现自动登录
要想实现自动登录,那么就要明白自动登录是用什么实现的。
cookie这是唯一一个存在用户浏览器的一组数据,所以想要实现自动登录,就只能通过cookie来实现,完成这一步的时候,如果浏览器禁用了cookie,记得解除。
那么如何实现登录,其实就是在用户请求数据,服务器返回响应的时候,把用户名和密码以cookie的形式返回给客户端,这样下次登陆的时候,就只需要在前端页面编写js脚本实现读取cookie和自动发起请求即可实现。
但是我们现在多了一个验证码呀,这可怎么办呢?
其实也很简单,思路就是:
在cookie中多添加一个验证码的cookie,内容输入为不可能出现的验证码,这样用户在自己输入的时候就不会那样输入,而你又可以实现自动登陆了。
这样实现就可以了吗?
一般情况下是可以了,但是架不住有些小伙伴神通广大呀,想要更强力的杜绝,最好是把验证码框的内容长度也给定死了,在我们脚本读取cookie的时候,在手动修改长度,这样验证码可以任意长度任意字符串,就可以杜绝大部分小伙伴了,毕竟它不知道你的真实验证码是什么。
那么接下来,我们来实现自动登陆中servlet的编写,也顺便把验证码的判断加入进去:
package com.ps.Servlet;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.*;
import java.io.IOException;
@WebServlet(urlPatterns = "/Login")
public class LoginServlet 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 {
//1.获取数据
String username = request.getParameter("username");
String password = request.getParameter("password");
String remember = request.getParameter("remember");
String code = request.getParameter("verCode");
//2.获取会话域中的验证码
HttpSession session = request.getSession();
String encode = (String) session.getAttribute("verCode");
//3.判断验证码是否通过,记住密码的,或者是输入验证码正确的
if (code.equals(encode) || code.equals("remember")) {
//4.验证码输入正确,判断输入的信息是否正确
if ("admin".equals(username) && "123456".equals(password)) {
//6.输入的信息正确,查看是否需要记住账号和密码
if (remember != null) {
//8.需要记住账号和密码实现自动登录,创建cookie
Cookie uCookie = new Cookie("username", username);
uCookie.setMaxAge(6000);
response.addCookie(uCookie);
Cookie pCookie = new Cookie("password", password);
pCookie.setMaxAge(6000);
response.addCookie(pCookie);
Cookie codeCookie = new Cookie("verCode", "remember");
codeCookie.setMaxAge(600);
response.addCookie(codeCookie);
}
//9.把登录后的信息存储在会话域中,方面访问别的页面使用
session.setAttribute("username", username);
//10.跳转到index页面
response.sendRedirect("index.jsp");
} else {
//7.输入的信息错误,跳回到原页面,需要重新输入
request.getRequestDispatcher("login.html").forward(request, response);
}
} else {
//5.验证码输入不正确,需要重新输入
request.getRequestDispatcher("login.html").forward(request, response);
}
}
}
写到这里大部分小伙伴就发现了,哎好像后台该实现的都实现了,前端页面的按钮啥的也都有了,那是不是可以用了?其实还不可以,还有一些脚本没有编写,那么最后一步就是脚本的编写了
7.前端脚本编写:读取cookie并实现验证的点击切换
你看就这么简单就到最后一步了,前端页面脚本的编写其实没那么难,那么我们就先来实现一下验证码的点击切换功能。
看过之前页面的小伙伴一定还记得,我在img标签上加入了onclick属性,并写了一个函数名,那么我们就以那个函数名来编写一下,切换函数:
<script>
function changeImage(img) {
//给对应的servlet发送请求,并添加输入值
//如果不添加输入值,会让服务器认为你在重复请求
//认为你请求的时间太短了,不需要响应,进而使用本地数据缓存
//导致验证码点击切换失败
img.src = "Encode?t=" + Math.random();
}
</script>
看了上面的脚本,非常的简单是吧,确实是,那么我们在一鼓作气把读取cookie的也写了吧。
<script>
//如果你的脚本放在页面的最开始就一定要加入这个函数
//不然你写的脚本就无法运行了
window.onload = function () {
// 读取Cookie信息
var cookies = document.cookie;
// 如果cookie不为空
if (cookies) {
// 得到用户名、密码和验证码
// 其实就是一组键值对,根据你设置好的来就可以了
var username = getCookie("username");
var password = getCookie("password");
var code = getCookie("verCode");
// 填写相应的数值
document.getElementById("username").value = username;
document.getElementById("password").value = password;
document.getElementById("verCode").value = code;
// 提交表单
document.getElementById("click").click();
}
};
//获取cookie的值
function getCookie(cname) {
//由于读取的cookie是通过;来分割的,所以需要根据;来获取对应的参数
var ca = document.cookie.split(';');
for (var i = 0; i < ca.length; i++) {
var c = ca[i];
var arr = c.split("=");
//这里一定要加入trim,这个很重要
//为什么呢?因为cookie会在其中加入一些空格
//去掉空格之后才能获取到正确的数值
if (arr[0].trim() == cname) {
return arr[1];
}
}
return "";
}
</script>
写到这里,内容基本就写完了,接下来就该测试一下代码了:
反复进入登录页面,哎,验证码登录和自动登录都实现了。
你学会了吗?
8.小结
那么我们象征性的小结一下吧。
如何实现自动登录:
1.在前端页面设置自动登录按钮
2.servlet获取是否要自动登录
3.自动登录则返回cookie给浏览器,让浏览器保存
4.编写脚本来帮助我们自动填写cookie中的数据
如何实现验证码:
1.编写能生成验证的servlet(不会写没关系,直接复制就好)
2.在前端页面加入img标签,并把src路径写成生成验证码的servlet的路径
3.设置name属性,便于后台servlet获取数据
4.编写脚本函数实现点击刷新验证码
如何同时实现验证和自动登录:
1.设定一个字符串为自动登录时的验证码
2.把这个字符串设置成cookie,并返回给浏览器
3.脚本实现自动登录的时候,把设置的字符串输入进去
4.当servlet判断到验证码是设置好的验证码时,放行,直接去判断用户名和密码是否正确