1、对用户信息的描述
首先用户有一些基本信息:
最简单的:
用户名称 + 用户密码
然后是用户状态,例如封号,注销,停用,等等
用户名称 + 用户密码 + 账号状态
接着为了防止脚本攻击,又产生了图形码验证,为了区分人和机器
用户名称 + 用户密码 + 用户状态 + 图形验证码
2、过程设计:
所以按照最后的这种形式,我们设计一个登陆业务的过程
首先用户在界面上看到三个东西:
- 名称框
- 密码框
- 验证码框
由于账号状态由后台控制,所以这里不会出现,也不会给用户查看
用户名是否会产生重复?
这个问题可以在注册的时候进行业务控制,
也就是说,我们是在一个用户名不会重复的前提下设计的
第一点:
三个框框都是必须填入信息的,这是第一限制
第二点:
基于上面用户名不重复的前提上,如果用户输入不存在的用户名就应该限制,并作出提示,用户不存在
第三点:
根据用户提供的名称获取到对应的密码,就开始对密码进行匹配,如果错误,则限制,并作出提示,密码错误
第四点:
检查验证码是否匹配,如果错误则限制,并作出提示
而限制是在页面上实现,服务器则负责信息校验的问题:
所以我们的页面和服务器职责是明确的。
对用户的输入信息进行控制,符合第一道工序之后传输信息给服务器,
服务器根据提供的信息进行校验,然后反馈给页面,
页面对反馈信息进行对应的处理,实现页面的限制
所以数据库的用户表设计根据这个业务的需要
至少提供:
用户名|用户密码|账号状态|
验证码是随机生成的,不应该存储在数据库,且浪费存储资源
前置的总结:
但是我没有想到的是可以使用JS来处理页面之间的跳转
因为之前的案例都是通过表单完成,这个步骤完全没有JS来参与逻辑控制
然后后端的事情显得非常的明确,我要做的业务其实也只是查询需要的结果打包给前端
信息校验在业务中处理,然后返回
具体实现描述
JS在发送Ajax之前进行控制,给服务后由程序对数据库访问,查询的结果和用户输入比较
再来是验证码校验,然后返回信息给前端,只有对的JS页面跳转,其他弹窗警告
3、具体实现的代码:
验证码图片生成和保存验证码:
应该简称ImageIDServlet
package cn.dzz.servlet;
import javax.imageio.ImageIO;
import javax.servlet.ServletOutputStream;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Random;/**
* @author ArkD42
* @file OA
* @create 2020 - 06 - 18 - 10:01*/@WebServlet("/verify")
public class VerificationCodeServlet extends BaseServlet{/**
* /verify?act=genImage
* @param request
* @param response
* @throws IOException*/public void genImage(HttpServletRequest request, HttpServletResponse response) throws IOException {//设置图片的宽高
int width = 60, height = 20;//创建具有可访问图像数据缓冲区的Image
BufferedImage bufferedImage =new BufferedImage(width, height,BufferedImage.TYPE_INT_RGB);
Graphics2D graphics2D=bufferedImage.createGraphics();//创建一个随机数生成对象
Random random =new Random();
graphics2D.setColor(Color.WHITE);
graphics2D.fillRect(0, 0, width, height);//创建字体,字体的大小应该根据图片的高度来定
Font font = new Font("微软雅黑", Font.PLAIN, 18);//设置字体
graphics2D.setFont(font);//画边框
graphics2D.setColor(Color.BLACK);
graphics2D.drawRect(0, 0, width - 1, height - 1);//随机产生160条干扰线
graphics2D.setColor(Color.LIGHT_GRAY);for (int i = 0; i < 160; i++) {int x =random.nextInt(width);int y =random.nextInt(height);int x1 = random.nextInt(12);int y1 = random.nextInt(12);
graphics2D.drawLine(x, y, x+ x1, y +y1);
}//randomCode 用于保存随机产生的验证码
StringBuffer randomCode =new StringBuffer();int red = 0, green = 0, blue = 0;//随机产生4位数字的验证码
for (int i = 0; i < 4; i++) {//得到随机产生的验证码数字
String strRand = String.valueOf(random.nextInt(10));//产生随机的颜色分量来构造颜色值
red = random.nextInt(110);
green= random.nextInt(50);
blue= random.nextInt(50);//用随机产生的颜色将验证码绘制到图像中
graphics2D.setColor(new Color(red, green, blue));
graphics2D.drawString(strRand,13 * i + 6, 16);
randomCode.append(strRand);
}//将四位数字的验证码保存到session中
request.getSession().setAttribute("randomCode", randomCode.toString());
System.out.println(this.getClass().getName()+ "生成的验证码:" +randomCode.toString());//禁止图像缓存
response.setHeader("Pragma", "no-cache");
response.setHeader("Cache-Control", "no-cache");
response.setDateHeader("Expires", 0);
response.setContentType("image/jpeg");//将图像输出到servlet输出流中
ServletOutputStream sos =response.getOutputStream();
ImageIO.write(bufferedImage, "jpeg", sos);
sos.close();
}
}
然后在登录页的事件绑定:
/>
functionloadImage(){
document.getElementById("verify_img").src="verify?act=genImage&time=" + newDate().getTime();
}
在Dao层中需要的实现:
@OverridepublicUser queryUserByName(String username) {final String SQL = "SELECT * FROM t_user WHERE user_name = ?";returnJdbcForTxUtil.queryOne(
TransactionManager.getCurrentThreadConnection(),
User.class,
SQL,newObject[]{username}
);
}
然后是登陆业务实现:
@OverridepublicJsonResult login(HttpServletRequest request) {//验证码的验证
HttpSession session =request.getSession();
String randomCode= session.getAttribute("randomCode").toString();
String imgID= request.getParameter("imgID");
System.out.println(request.getRemoteAddr()+ "用户输入的是:" + imgID + " 从Session得到的是:" +randomCode);if (!(randomCode.equals(imgID))) return new JsonResult(500,"验证码错误",null);//用户信息验证
String username = request.getParameter("username");
String password= request.getParameter("password");
User user=userDao.queryUserByName(username);
System.out.println(user);if (user == null) return new JsonResult(200,"没有此用户",null);else{if (!(password.equals(user.getUser_password()))) return new JsonResult(300,"密码错误",null);else if (user.getUser_status() != 1) return new JsonResult(400,"账号状态异常",null);
}
session.setAttribute("userInfo",user);return new JsonResult(100,"验证通过",null);
}
登陆Servlet反馈给登录页
/*** /login?act=loginCheck
* 处理从/WEB-INF/jsp/login.jsp页的表单发送的请求,进行信息校验
*@paramrequest
*@paramresponse
*@return
*/
publicJsonResult loginCheck(HttpServletRequest request, HttpServletResponse response) {
JsonResult result=loginService.login(request);returnresult;
}
最后是由登录页的JS处理
/*登陆验证*/$(function() {
$("#loginBtn").click(function() {
let username= $("#username").val();
let password= $("#password").val();
let imgID= $("#imgID").val();if(username === "" || password === "" || imgID === "") {
alert("请输入用户或密码或验证码!!!");
}else{//ajax 登录
let url = "/login?act=loginCheck";
let obj={
username:username,
password:password,
imgID:imgID
}
$.ajax({
url: url,
type:"post",
data: obj,
success:function(data) {/*不要使用全等,JS会把对象和字符串比较类型,对不上就不走了*/
if (data.feedbackStatus == "100") location.href="/home"; //状态100 验证通过
else if (data.feedbackStatus == "200") alert(data.messageses); //状态200 用户不存在
else if (data.feedbackStatus == "300") alert(data.messageses); //状态200 密码错误
else if (data.feedbackStatus == "400") alert(data.messageses); //状态400 账号状态异常
else if (data.feedbackStatus == "500") alert(data.messageses); //状态500 验证码错误
},
dataType:"json"});
}
});
});