WEB后端_Day06(Cookie练习、Session会话、登录-显示用户名、验证码、EasyCaptcha、Servlet3.0新增功能、购物车)
Cookie
由服务端产生,保存在客户端的这样一种会话保持技术
创建cookie Cookie cookie = new Cookie(key ,value);
设置cookie的生命周期 cookie.setMaxAge(N秒);
设置cookie的路径:cookie.setPath(req.getContextPath()+"/");//工程路径名
将cookie传递个客户端:resp.addCookie(cookie对象);
设置路径:
public class CookieServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doPost(req,resp);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//创建Cookie
Cookie cookie = new Cookie("key", "Cookie_value");
cookie.setMaxAge( 60 * 60);
cookie.setPath(req.getContextPath()+"/abc");
//将cookie添加到相应头中
resp.addCookie(cookie);
}
}
public class GetCookieServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doPost(req,resp);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
Cookie newCookie = new Cookie("key1", "lanqiao");
newCookie.setPath(req.getContextPath()+"/def");
resp.addCookie(newCookie);
}
}
<servlet>
<servlet-name>cook</servlet-name>
<servlet-class>cn.lanqiao.CookieServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>cook</servlet-name>
<url-pattern>/abc/cook</url-pattern>
</servlet-mapping>
<servlet>
<servlet-name>get</servlet-name>
<servlet-class>cn.lanqiao.GetCookieServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>get</servlet-name>
<url-pattern>/def/get</url-pattern>
</servlet-mapping>
Cookie 练习—免输入用户名登录
当用户第一次登陆的时候 是需要输入用户名和密码
当用户第一次登录成功之后 则后续将不再需要输入用户名 用户实现一个自动填充。
<form action="/login">
用户名:<input type="text" placeholder="请输入用户名" name="username" value="${cookie.username.value}"/><br/><br/>
密码:<input type="text" placeholder="请输入密码" name="password" value=""/><br/><br/>
<input type="submit" value="登陆">
</form>
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String username = req.getParameter("username");
String password= req.getParameter("password");
if("admin".equals(username)&&"123456".equals(password)){
//此时就登陆成功
resp.getWriter().write("登陆成功");
//登陆成功之后 将用户名存入到cookie 并回传给客户端
Cookie cookie = new Cookie("username", username);
cookie.setMaxAge(24*60*60);
resp.addCookie(cookie);
}else{
resp.sendRedirect("/index.jsp");
}
}
Cookie的失效
1 设置的maxAge到期
2 手动清除浏览器的cookie
Session 会话
什么是Session 会话
-
Session 就一个接口(HttpSession)。
-
Session 就是会话。它是用来维护一个客户端和服务器之间关联的一种技术。
-
每个客户端都有自己的一个Session 会话。
-
Session 会话中,我们经常用来保存用户登录之后的信息。
如何创建Session 和获取(id 号,是否为新
如何创建和获取Session。它们的API 是一样的。
-
request.getSession()
-
- 第一次调用是:创建Session 会话
- 之后调用都是:获取前面创建好的Session 会话对象。
- 第一次调用是:创建Session 会话
-
isNew(); 判断到底是不是刚创建出来的(新的)
-
true 表示刚创建
-
false 表示获取之前创建
每个会话都有一个身份证号。也就是ID 值。而且这个ID 是唯一的。getId() 得到Session 的会话id 值。
HttpSession session = req.getSession();
//判断session是否是新建的
System.out.println(session.isNew());
//获取session的id
System.out.println(session.getId());
当我们在请求一个应用的使用,如果第一访问应用请求的是一个jsp页面 那么此时就会立即创建一个session对象
什么时候新建session?
-
当第一次请求的是jsp的时候 且页面没有设置session指令或者设置为true 则在访问jsp的时候 就会创建session
-
如果第一次直接请求一个servlet 则servlet新建
-
如果第一一次请求的jsp的页面的session设置为false 在会在第一个请求的servelt中创建一个新的session
使用session来存取数据
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.setContentType("text/html");
resp.setCharacterEncoding("utf-8");
String username = req.getParameter("username");
String password= req.getParameter("password");
if("admin".equals(username)&&"123456".equals(password)){
//此时就登陆成功
resp.getWriter().write("登陆成功");
//登陆成功之后 将用户名存入到cookie 并回传给客户端
Cookie cookie = new Cookie("username", username);
cookie.setMaxAge(24*60*60);
resp.addCookie(cookie);
//将用户信息保存到session中
HttpSession session = req.getSession();
session.setAttribute("username",username);
req.getRequestDispatcher("/success.jsp").forward(req,resp);
}else{
resp.sendRedirect("/index.jsp");
}
}
获取session中的数据
欢迎:${sessionScope.username}
Session 生命周期控制
public void setMaxInactiveInterval(int interval) 设置Session 的超时时间(以秒为单位),超过指定的时长,Session就会被销毁。
- 值为正数的时候,设定Session 的超时时长。
- 负数表示永不超时(极少使用)
public int getMaxInactiveInterval()获取Session 的超时时间
public void invalidate() 让当前Session 会话马上超时无效。
Session 默认的超时时长是多少! Session 默认的超时时间长为30 分钟。
tomcat的conf/web.xml中 单位为分钟
<session-config>
<session-timeout>30</session-timeout>
</session-config>
我们也可以在自己的web.xml中来配置session的默认时间
安全退出
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
HttpSession session = req.getSession();
//无论session是否到达失效时间 都会立即失效
session.invalidate();
resp.sendRedirect("/index.jsp");
}
session失效的方式:
-
关闭浏览器
-
session的超时时限到达
-
调用了session.invalidate();
Session和Cookie的区别:
-
Session他是由服务端自动创建,并保存在服务器端
-
Cookie 他是由服务端创建 而且是由我们自己手动创建 ,并保存在客户端的
-
对同一个session的判断 是通过客户端携带的sessionID来判定的
JSESSIONID=F147FA96640D80F4A9F33F54549F0254
cookie中保存的key是固定的 JSESSIONID
登陆—显示用户名
注销
public void logout(HttpServletRequest req, HttpServletResponse resp){
HttpSession session = req.getSession();
session.invalidate();
resp.sendRedirect("/pages/user/login.jsp");
}
表单重复提交之-----验证码
表单重复提交有三种常见的情况:
一:提交完表单。服务器使用请求转发进行页面跳转。这个时候,用户按下功能键F5,就会发起最后一次的请求。造成表单重复提交问题。解决方法:使用重定向来进行跳转
二:用户正常提交服务器,但是由于网络延迟等原因,迟迟未收到服务器的响应,这个时候,用户以为提交失败,就会着急,然后多点了几次提交操作,也会造成表单重复提交–可以在前端,当用户点击了提交按钮之后 ,就将提交按钮置为不可用。
三:用户正常提交服务器。服务器也没有延迟,但是提交完成后,用户回退浏览器。重新提交。也会造成表单重复提交。
服务器端避免重复提交的思路:
-
在进入每一个jsp页面的时候 都是需要经过servelt
-
在进入表单页时,此时可以在servlet中产生一个token 将token保存在session中,然后在页面从session中获取token
-
当提交表单的时候 连同token一起提交到处理表达的servlet中
-
此时用提交的token和session中保存的token进行比较 如果一致,则不是重复提交 正常处理表单数据 ,同时将session中token重新生成或者直接将token给移除
-
如果重复提交 页面存在token 而此时的session中的token 已经发生了变化
-
如果此时客户重复提交 那么当我们接受到之后 通过token的判断 因为token不一致 则可以认定为重复提交
EasyCaptcha
简介
Java图形验证码,支持gif、中文、算术等类型,可用于Java Web、JavaSE等项目
使用
下载并添加jar
在web.xml中进行配置
<!-- 图形验证码servlet -->
<servlet>
<servlet-name>CaptchaServlet</servlet-name>
<servlet-class>com.wf.captcha.servlet.CaptchaServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>CaptchaServlet</servlet-name>
<url-pattern>/captcha</url-pattern>
</servlet-mapping>
前端
<label>验证码:</label>
<input class="itxt" type="text" style="width: 150px;" name = "code" id="code"/>
<img src="captcha" width="130px" height="48px" />
后端
看不清 换一张
<label>验证码:</label>
<input class="itxt" type="text" style="width: 150px;" name = "code" id="code"/>
<a href="javascript:void(0)" id="captcha">
<img src="captcha" id="captchaImg" width="130px" height="48px" />
</a>
$("#captcha").click(function (){
//请求后边的参数 必须要有 如果没有 因为每一次的请求路径都是一样的 此时浏览器会认为是重复请求 所以就不会发送这个请求到服务器
$("#captchaImg").attr("src","${basePath}captcha?d="+new Date())
})
Servlet3.0新增的注解功能
@WebServlet注解
1. 说明:该注解用来配置Servlet,其将会在服务器启动时被tomcat容器处理,容器将根据具体的属性配置将相应的类部署为 Servlet。
- 参数的说明:
@WebServlet(name = "user",urlPatterns = {"/user","/bookUser"},
initParams = {@WebInitParam(name = "username",value = "admin"),@WebInitParam(name = "password",value = "123456")},
loadOnStartup = 100)
监听器@WebListener 不需要参数
购物车模型分析
购物车模型的实现
public class CartItem {
private Integer id;
private String name;
private Integer number;
private BigDecimal price;
private BigDecimal totalPrice;
public CartItem() {
}
public CartItem(String name, Integer number, BigDecimal price, BigDecimal totalPrice) {
this.name = name;
this.number = number;
this.price = price;
this.totalPrice = totalPrice;
}
public CartItem(Integer id, String name, Integer number, BigDecimal price, BigDecimal totalPrice) {
this.id = id;
this.name = name;
this.number = number;
this.price = price;
this.totalPrice = totalPrice;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getNumber() {
return number;
}
public void setNumber(Integer number) {
this.number = number;
}
public BigDecimal getPrice() {
return price;
}
public void setPrice(BigDecimal price) {
this.price = price;
}
public BigDecimal getTotalPrice() {
return totalPrice;
}
public void setTotalPrice(BigDecimal totalPrice) {
this.totalPrice = totalPrice;
}
}
public class Cart {
private Integer totalNumber;
private BigDecimal priceAll;
//表示购物车
private Map<Integer,CartItem> cart = new HashMap<>();
public Map<Integer, CartItem> getCart() {
return cart;
}
//添加商品到购物车
public void addItem(CartItem item){
Integer id = item.getId();
//购物车中已经有了该商品
if(cart.containsKey(id)){
Integer number = cart.get(id).getNumber()+1;
item.setNumber(number);
BigDecimal totalPrice = item.getPrice().multiply(BigDecimal.valueOf(number));
item.setTotalPrice(totalPrice);
}
cart.put(id,item);
}
//删除商品
public void deleteItem(Integer id){
cart.remove(id);
}
//清空购物城
public void emptyCar(){
cart.clear();
}
//修改商品的数量
public void updateItem(Integer id,Integer number){
CartItem item = cart.get(id);
item.setNumber(number);
item.setTotalPrice(item.getPrice().multiply(BigDecimal.valueOf(number)));
cart.put(id,item);
}
public Integer getTotalNumber() {
int totalNumber = 0 ;
for(Map.Entry<Integer,CartItem> entry :cart.entrySet()){
CartItem item = entry.getValue();
totalNumber += item.getNumber();
}
return totalNumber;
}
public BigDecimal getPriceAll() {
BigDecimal priceAll = new BigDecimal(0);
for(Map.Entry<Integer,CartItem> entry :cart.entrySet()){
CartItem item = entry.getValue();
priceAll.add(item.getTotalPrice());
}
return priceAll;
}
}
加入购物车功能的实现
实现首页经过servlet的跳转 从数据库获取数据
在index.jsp实现转发
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<meta charset="UTF-8">
<title>零点读书</title>
</head>
<body>
<jsp:forward page="/index?_method=list"></jsp:forward>
</body>
</html>
@WebServlet("/index")
public class IndexServlet extends BaseServlet{
private IBookService bookService = new BookServiceImpl();
public void list(HttpServletRequest req , HttpServletResponse resp) throws ServletException, IOException {
String pageNoStr = req.getParameter("pageNo");
Integer pageNo = 1;
if(!"".equals(pageNoStr)&&pageNoStr!=null){
pageNo = Integer.parseInt(pageNoStr);
}
Page<Book> page = bookService.pageList(pageNo,Page.PAGESIZE);
req.setAttribute("page",page);
req.getRequestDispatcher("/pages/home.jsp").forward(req,resp);
}
}
添加商品到购物车
home.jsp
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<meta charset="UTF-8">
<title>零点读书</title>
<%@include file="public/top.jsp"%>
</head>
<body>
<div id="header">
<img class="logo_img" alt="" src="static/img/logo.jpg" >
<div>
<a href="pages/user/login.jsp">登录</a> |
<a href="pages/user/regist.jsp">注册</a>
<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="" method="get">
价格:<input id="min" type="text" name="min" value=""> 元 -
<input id="max" type="text" name="max" value=""> 元
<input type="submit" value="查询" />
</form>
</div>
<div style="text-align: center">
<span>您的购物车中有${cart.totalNumber}件商品</span>
<div>
您刚刚将<span style="color: red">${item.name}</span>加入到了购物车中
</div>
</div>
<c:forEach items="${page.pageList}" var="book">
<div class="b_list">
<div class="img_div">
<img class="book_img" alt="" src="static/img/hxjs.jpg" />
</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">
<form action="cart" method="post">
<input type="hidden" name="_method" value="addCart"/>
<input type="hidden" name="id" value="${book.id}">
<input type="submit" value="加入购物车"/>
</form>
</div>
</div>
</div>
</c:forEach>
</div>
<div id="page_nav">
<c:if test="${page.pageNo > 1}">
<a href="book?_method=list&pageNo=1">首页</a>
<a href="book?_method=list&pageNo=${page.pageNo-1}">上一页</a>
</c:if>
<c:forEach begin="1" end="${page.pageTotal}" step="1" var="i">
<c:if test="${i == page.pageNo}">
【${i}】
</c:if>
<c:if test="${i != page.pageNo}">
<a href="book?_method=list&pageNo=${i}">${i}</a>
</c:if>
</c:forEach>
<c:if test="${page.pageNo < page.pageTotal}">
<a href="book?_method=list&pageNo=${page.pageNo+1}">下一页</a>
<a href="book?_method=list&pageNo=${page.pageTotal}">末页</a>
</c:if>
共${page.pageTotal}页,共${page.totalCount}条记录 到第<input value="${page.pageNo}" name="pn" id="pn_input"/>页
<input type="button" id="subBtn" value="确定">
</div>
<jsp:include page="/pages/public/foot.jsp"/>
</div>
</body>
</html>
@WebServlet("/cart")//可以不写name 直接给一个字符串就是url
public class CartServlet extends BaseServlet{
private IBookService bookService = new BookServiceImpl();
public void addCart(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
Integer id = Integer.parseInt(req.getParameter("id"));
Book book = bookService.queryBookById(id);
CartItem item = new CartItem(book.getId(),book.getName(),1,book.getPrice(),book.getPrice());
//购物车保存在session中
HttpSession session = req.getSession();
Cart cart = (Cart) session.getAttribute("cart");
if(cart == null){
Cart newCart = new Cart();
newCart.addItem(item);
session.setAttribute("cart",newCart);
}else{
cart.addItem(item);
}
String pageNoStr = req.getParameter("pageNo");
Integer pageNo = 1;
if(!"".equals(pageNoStr)&&pageNoStr!=null){
pageNo = Integer.parseInt(pageNoStr);
}
Page<Book> page = bookService.pageList(pageNo,Page.PAGESIZE);
req.setAttribute("page",page);
req.setAttribute("item",item);
req.getRequestDispatcher("/pages/home.jsp").forward(req,resp);
}
}
购物车信息的展示
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<html>
<head>
<meta charset="UTF-8">
<title>购物车</title>
<jsp:include page="/pages/public/top.jsp"/>
<link type="text/css" rel="stylesheet" href="static/css/style.css" >
<script type="text/javascript">
$(function (){
$(".del").click(function (){
return confirm("您确定要删除该商品吗?");
})
$(".empty").click(function (){
return confirm("您确定要清空购物车吗?");
})
})
</script>
</head>
<body>
<div id="header">
<img class="logo_img" alt="" src="static/img/logo.jpg" >
<div>
<span>欢迎<span class="um_span">${user.username}</span>光临零点读书</span>
<a href="pages/order/order.html">我的订单</a>
<a href="logout">注销</a>
<a href="index.jsp">返回</a>
</div>
</div>
<div id="main">
<c:if test="${empty sessionScope.cart}">
<h1 style="color: red">您当前的购物车为空,请前往商品页选购商品</h1>
</c:if>
<c:if test="${not empty sessionScope.cart}">
<table>
<tr>
<td colspan="5" style="font-size:28px;font-weight:800">购物车</td>
</tr>
<tr>
<td>商品名称</td>
<td>数量</td>
<td>单价</td>
<td>金额</td>
<td>操作</td>
</tr>
<c:forEach items="${sessionScope.cart.cart.values()}" var="item">
<tr>
<td>${item.name}</td>
<td>${item.number}</td>
<td>${item.price}</td>
<td>${item.totalPrice}</td>
<td><a href="cart?_method=deleteCartItem&id=${item.id}" class="del">删除</a></td>
</tr>
</c:forEach>
</table>
</c:if>
<c:if test="${not empty sessionScope.cart}">
<div class="cart_info">
<span class="cart_span">购物车中共有<span class="b_count">${sessionScope.cart.totalNumber}</span>件商品</span>
<span class="cart_span">总金额<span class="b_price">${sessionScope.cart.priceAll}</span>元</span>
<span class="cart_span"><a href="cart?_method=emptyCart" class="empty">清空购物车</a></span>
<span class="cart_span"><a href="pages/cart/checkout.html">去结账</a></span>
</div>
</c:if>
</div>
<div id="bottom">
<span>
零点读书.Copyright ©2020
</span>
</div>
</body>
</html>