书城项目-显示登录的用户信息、书城项目-注销登录、书城项目-表单重复提交的三种常见情况、书城项目-验证码底层原理、书城项目-谷歌验证码的使用、书城项目-把谷歌验证码加入到书城中使用、书城项目-验证码的切换
3、项目第六阶段
3.1、登陆—显示用户名
UserServlet 程序中保存用户登录的信息
package top.qaqaq.web;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import top.qaqaq.pojo.User;
import top.qaqaq.service.UserService;
import top.qaqaq.service.impl.UserServiceImpl;
import top.qaqaq.utils.WebUtils;
import java.io.IOException;
import static com.google.code.kaptcha.Constants.KAPTCHA_SESSION_KEY;
/**
* @author RichieZhang
* @create 2022-12-10 上午 11:26
*/
public class UserServlet extends BaseServlet {
private UserService userService = new UserServiceImpl();
/**
* 注销
* @param req
* @param resp
* @throws ServletException
* @throws IOException
*/
protected void logout(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// 1. 销毁Session中用户登录的信息(或者销毁Session)
req.getSession().invalidate();
// 2. 重定向到首页(或登陆页面)。
resp.sendRedirect(req.getContextPath());
}
/**
* 处理登录的功能
* @param req
* @param resp
* @throws ServletException
* @throws IOException
*/
protected void login(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//1. 获取请求参数
String username = req.getParameter("username");
String password = req.getParameter("password");
// 调用 userService.login() 登录处理业务
User loginUser = userService.login(new User(null, username, password, null));
// 如果等于null,说明登录 失败!
if (loginUser == null){
// 把错误信息,和回显的表单项信息,保存在Request域中
req.setAttribute("msg","用户名或密码错误!");
req.setAttribute("username", username);
// 跳回登录页面
req.getRequestDispatcher("/pages/user/login.jsp").forward(req,resp);
} else {
// 登录 成功
// 保存用户登录的信息到session域中
req.getSession().setAttribute("user",loginUser);
// 跳到成功页面Login_success.html
req.getRequestDispatcher("/pages/user/login_success.jsp").forward(req,resp);
}
}
/**
* 处理注册的功能
* @param req
* @param resp
* @throws ServletException
* @throws IOException
*/
protected void regist(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// 获取Session中的验证码
String token = (String) req.getSession().getAttribute(KAPTCHA_SESSION_KEY);
// 删除 Session中的验证码
req.getSession().removeAttribute(KAPTCHA_SESSION_KEY);
// 1、获取请求的参数
String username = req.getParameter("username");
String password = req.getParameter("password");
String email = req.getParameter("email");
String code = req.getParameter("code");
// User user = new User();
//测试代码
// Map<String, String[]> parameterMap = req.getParameterMap();
// for (Map.Entry<String, String[]> entry : parameterMap.entrySet()) {
// System.out.println(entry.getKey() + "=" + Arrays.asList(entry.getValue()));
// }
// WebUtils.copyParamToBean(req.getParameterMap(),user);
User user = WebUtils.copyParamToBean(req.getParameterMap(), new User());
// 2、检查 验证码是否正确 === 写死,要求验证码为:abcde
if (token != null && token.equalsIgnoreCase(code)) {
// 3、检查 用户名是否可用
if (userService.existsUsername(username)) {
System.out.println("用户名[" + username + "]已存在");
// 把回显信息,保存到Request域中
req.setAttribute("msg","用户名已存在!!");
req.setAttribute("username", username);
req.setAttribute("email", email);
// 跳回注册页面
req.getRequestDispatcher("/pages/user/regist.jsp").forward(req, resp);
} else {
// 可用
// 调用 Sservice 保存到数据库
userService.registUser(new User(null,username,password,email));
// 跳到注册成功页面 regist_success.jsp
req.getRequestDispatcher("/pages/user/regist_success.jsp").forward(req, resp);
}
} else {
// 把回显信息,保存到Request域中
req.setAttribute("msg","验证码错误!!");
req.setAttribute("username", username);
req.setAttribute("email", email);
System.out.println("验证码[" + code + "]错误");
req.getRequestDispatcher("/pages/user/regist.jsp").forward(req, resp);
}
}
}
修改 login_succuess_menu.jsp
<%--
Created by IntelliJ IDEA.
User: ZRich
Date: 2022/12/9
Time: 下午 5:11
To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<div>
<span>欢迎<span class="um_span">${sessionScope.user.username}</span>光临尚硅谷书城</span>
<a href="pages/order/order.jsp">我的订单</a>
<a href="userServlet?action=logout">注销</a>
<a href="index.jsp">返回</a>
</div>
还要修改首页 index.jsp 页面的菜单 :
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>书城首页</title>
<%-- 静态包含 base标签,css样式,jQuery文件 --%>
<%@ include file="/pages/common/head.jsp"%>
</head>
<body>
<div id="header">
<img class="logo_img" alt="" src="static/img/logo.gif" >
<span class="wel_word">网上书城</span>
<div>
<%-- 如果用户还没有登录,显示 【登录 和注册的菜单】 --%>
<c:if test="${empty sessionScope.user}">
<a href="pages/user/login.jsp">登录</a> |
<a href="pages/user/regist.jsp">注册</a>
</c:if>
<%-- 如果已经登录,则显示 登录 成功之后的用户信息。 --%>
<c:if test="${not empty sessionScope.user}">
<span>欢迎<span class="um_span">${sessionScope.user.username}</span>光临尚硅谷书城</span>
<a href="pages/order/order.jsp">我的订单</a>
<a href="userServlet?action=logout">注销</a>
</c:if>
<a href="pages/cart/cart.jsp">购物车</a>
<a href="pages/manager/manager.jsp">后台管理</a>
</div>
</div>
<div id="main">
<div id="book">
<div class="book_cond">
<form action="client/bookServlet" method="get">
<input type="hidden" name="action" value="pageByPrice">
价格:<input id="min" type="text" name="min" value="${param.min}"> 元 -
<input id="max" type="text" name="max" value="${param.max}"> 元
<input type="submit" value="查询" />
</form>
</div>
<div style="text-align: center">
<span>您的购物车中有3件商品</span>
<div>
您刚刚将<span style="color: red">时间简史</span>加入到了购物车中
</div>
</div>
<c:forEach items="${requestScope.page.itmes}" var="book">
<div class="b_list">
<div class="img_div">
<img class="book_img" alt="" src="${book.imgpath}" />
</div>
<div class="book_info">
<div class="book_name">
<span class="sp1">书名:</span>
<span class="sp2">${book.name}</span>
</div>
<div class="book_author">
<span class="sp1">作者:</span>
<span class="sp2">${book.author}</span>
</div>
<div class="book_price">
<span class="sp1">价格:</span>
<span class="sp2">${book.price}</span>
</div>
<div class="book_sales">
<span class="sp1">销量:</span>
<span class="sp2">${book.sales}</span>
</div>
<div class="book_amount">
<span class="sp1">库存:</span>
<span class="sp2">${book.stock}</span>
</div>
<div class="book_add">
<button>加入购物车</button>
</div>
</div>
</div>
</c:forEach>
</div>
<%-- 静态包含分页条 --%>
<%@include file="/pages/common/page_nav.jsp"%>
</div>
<%-- 静态包含页脚内容 --%>
<%@include file="/pages/common/footer.jsp"%>
</body>
</html>
3.2、登出—注销用户
1、销毁 Session 中用户登录的信息(或者销毁 Session)
2、重定向到首页(或登录页面)。
UserServlet 程序中添加 logout 方法
/**
* 注销
* @param req
* @param resp
* @throws ServletException
* @throws IOException
*/
protected void logout(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// 1. 销毁Session中用户登录的信息(或者销毁Session)
req.getSession().invalidate();
// 2. 重定向到首页(或登陆页面)。
resp.sendRedirect(req.getContextPath());
}
修改【注销】的菜单地址
<a href="userServlet?action=logout">注销</a>
index.jsp
login_success_menu.jsp
3.3、表单重复提交之—–验证码
表单重复提交有三种常见的情况:
一:提交完表单。服务器使用请求转来进行页面跳转。这个时候,用户按下功能键 F5,就会发起最后一次的请求。造成表单重复提交问题。解决方法:使用重定向来进行跳转
二:用户正常提交服务器,但是由于网络延迟等原因,迟迟未收到服务器的响应,这个时候,用户以为提交失败,就会着急,然后多点了几次提交操作,也会造成表单重复提交。
三:用户正常提交服务器。服务器也没有延迟,但是提交完成后,用户回退浏览器。重新提交。也会造成表单重复提交。
3.4、谷歌 kaptcha 图片验证码的使用
谷歌验证码 kaptcha 使用步骤如下:
1、导入谷歌验证码的 jar 包
kaptcha-2.3.2.jar
2、在 web.xml 中去配置用于生成验证码的 Servlet 程序
<servlet>
<servlet-name>KaptchaServlet</servlet-name>
<servlet-class>com.google.code.kaptcha.servlet.KaptchaServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>KaptchaServlet</servlet-name>
<url-pattern>/kaptcha.jpg</url-pattern>
</servlet-mapping>
3、在表单中使用 img 标签去显示验证码图片并使用它
<form action="http://localhost:8080/JavaWeb_Code_Demo/registServlet" method="get">
用户名:<input type="text" name="username"> <br/>
验证码:<input type="text" style="width: 60px" name="code">
<img src="http://localhost:8080/JavaWeb_Code_Demo/kaptcha.jpg" alt="" style="width: 100px; height: 28px;"> <br/>
<input type="submit" value="注册">
</fo
4、在服务器获取谷歌生成的验证码和客户端发送过来的验证码比较使用。
package top.qaqaq.servlet;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import java.io.IOException;
import static com.google.code.kaptcha.Constants.KAPTCHA_SESSION_KEY;
/**
* @author RichieZhang
* @create 2022-12-13 下午 2:26
*/
public class RegistServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// super.doGet(req, resp);
// 获取Session中的验证码
String token = (String) req.getSession().getAttribute(KAPTCHA_SESSION_KEY);
// 删除 Session中的验证码
req.getSession().removeAttribute(KAPTCHA_SESSION_KEY);
// 获取表单项输入的验证码
String code = req.getParameter("code");
// 获取用户名
String username = req.getParameter("username");
if (token != null && token.equalsIgnoreCase(code)) {
System.out.println("保存到数据库:" + username);
//req.getRequestDispatcher("/ok.jsp").forward(req,resp);
// try {
// Thread.sleep(5000);
// } catch (InterruptedException e) {
// e.printStackTrace();
// }
resp.sendRedirect(req.getContextPath() + "/ok.jsp");
} else {
System.out.println("请不要重复提交表单");
}
}
}
切换验证码:
// 给验证码的图片,绑定单击事件
$("#code_img").click(function () {
// 在事件响应的function函数中有一个this对象。这个this对象,是当前正在响应事件的dom对象。
// src属性表示验证码img标签的 图片路径。它可读,可写
// alert(this.src);
this.src = "${basePath}kaptcha.jpg?d=" + new Date().getTime();
})