书城项目历程记录2|最后阶段记录

2024年1月31日

p270-276

1.免用户名登录和注销(知识点cookie和session)

在学习了cookie和session之后,实现了免用户名登录和注销操作。
免用户名就是在本次session登录成功之后,对session进行setAttribute操作,jsp文件通过EL语言${sessionScope.user.username}获取。

// 登录 成功
//跳到成功页面login_success.html
req.getSession().setAttribute("user", loginUser);
req.getRequestDispatcher("/pages/user/login_success.jsp").forward(req, resp);

注销操作就是设置本次session立即销毁。

req.getSession().invalidate();
resp.sendRedirect(req.getContextPath());//重定向到当前目录。

2.表单重复提交的情况及解决方法—验证码

老师花了很大力气说明什么是表单重复提交的情况(有三种情况以及其解决方法)。

表单重复提交有三种常见的情况:
一:提交完表单。服务器使用请求转来进行页面跳转。这个时候,用户按下功能键 F5,就会发起最后一次的请求。 造成表单重复提交问题。解决方法:使用重定向来进行跳转。
二:用户正常提交服务器,但是由于网络延迟等原因,迟迟未收到服务器的响应,这个时候,用户以为提交失败,就会着急,然后多点了几次提交操作,也会造成表单重复提交。
三:用户正常提交服务器。服务器也没有延迟,但是提交完成后,用户回退浏览器。重新提交。也会造成表单重复 提交。

所谓的重定向操作就是:

//原:
req.getRequestDispatcher("/ok.jsp").forward(req, resp);
//重定向
resp.sendRedirect(req.getContextPath()+"/ok.jsp");

后面两种情况的解决方法是验证码
以下是截图下来的底层逻辑:
书城项目历程记录2|最后阶段记录_第1张图片

3.如何使用谷歌验证码包(会给出图片,并自动保存在session域中)。

谷歌验证码 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/tmp/registServlet" method="get">
	用户名:<input type="text" name="username" > <br>
	验证码:<input type="text" style="width: 80px;" name="code">
	<img src="http://localhost:8080/tmp/kaptcha.jpg" alt="" style="width: 100px; height: 28px;"> <br>
	<input type="submit" value="登录">
</form>

4、在服务器获取谷歌生成的验证码和客户端发送过来的验证码比较使用。

@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
	// 获取 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);
		resp.sendRedirect(req.getContextPath() + "/ok.jsp");
	} else {
		System.out.println("请不要重复提交表单");
	}
}

4.在书城项目中增加验证码

与上述没有区别。

5.如何实现点击验证码获取更清晰的验证码图片?

第一步肯定是给img绑定单击事件。

<img id="code_img" alt="" src="kaptcha.jpg" style="float: right; margin-right: 40px; width: 110px; height: 30px;">

然后

// 页面加载完成之后
			$(function () {

				// 给验证码的图片,绑定单击事件
				$("#code_img").click(function () {
					// 在事件响应的function函数中有一个this对象。这个this对象,是当前正在响应事件的dom对象 (就是img)
					// src属性表示验证码img标签的 图片路径。它可读,可写
					// alert(this.src);
					this.src = "${basePath}kaptcha.jpg?d=" + new Date();
				});

涉及到浏览器缓冲的问题,以下是老师的讲解:
书城项目历程记录2|最后阶段记录_第2张图片

2024年2月1日

p277
进入购物车阶段。是session版本,所以只在web层操作,意思是只涉及servlet。
先是明确了购物车这个模块需要的对象(购物车和商品项)。
再明确功能(加入,删除,清空,修改商品数量)–》对应的是servlet。
书城项目历程记录2|最后阶段记录_第3张图片
p278
完成购物车和商品项类的定义。
p279
完成购物车的功能方法。这里涉及了map的使用和BigDecimal的使用。
Map

//linked有两个优势,1.有序插入顺序和取出顺序一致 2.增删效率高 因为底层是双向链表
private Map<Integer, CartItem> items = new LinkedHashMap<Integer, CartItem>();
public void addItem(CartItem cartItem){
        //不能直接添加,原先购物车上有的,在原有的基础上进行修改。所以items要用map来进行查找比较合适。
        CartItem item = items.get(cartItem.getId());
        if(item == null){
            items.put(cartItem.getId(), cartItem);
        }else {
            item.setCount(item.getCount()+1);
            item.setTotalPrice(item.getPrice().multiply(new BigDecimal(item.getCount())));
        }
    }
//遍历
public Integer getTotalCount() {
        Integer totalCount = 0;
        for(Map.Entry<Integer, CartItem> entry:items.entrySet()){
            totalCount+=entry.getValue().getCount();
        }
        return totalCount;
    }

BigDecimal

public BigDecimal getTotalPrice() {
        BigDecimal totalPrice = new BigDecimal(0);
        for(Map.Entry<Integer, CartItem> entry:items.entrySet()){
            totalPrice = totalPrice.add(entry.getValue().getPrice());
        }
        return totalPrice;
    }
//乘法
item.setTotalPrice(item.getPrice().multiply(new BigDecimal(item.getCount())));

对于类的Test文件编写,快捷键ctrl+shift+t
选择合适的目录和想要测试的方法,JUnit4。

2024年2月13日

昨天晚上开启服务器之后就一直是空白页面,最后是在配置里,fix了提醒的部分。
添加入购物车,发现没办法404,原因是herf/book/,而我重新 创建了new_book。
请求头Refere的使用,就是这个请求发出时,浏览器处于的地址。

System.out.println("请求头 Referer 的值:" + req.getHeader("Referer"));
// 重定向回原来商品所在的地址页面
resp.sendRedirect(req.getHeader("Referer"));

比较重要的还有修改购物车某一个商品的数量,这里在界面上使用了change事件。
书城项目历程记录2|最后阶段记录_第4张图片

// 给输入框绑定 onchange 内容发生改变事件
$(".updateCount").change(function () {
// 获取商品名称
var name = $(this).parent().parent().find("td:first").text();
var id = $(this).attr('bookId');
// 获取商品数量
var count = this.value;
if ( confirm("你确定要将【" + name + "】商品修改数量为:" + count + " 吗?") ) {
//发起请求。给服务器保存修改
location.href =
"http://localhost:8080/book/cartServlet?action=updateCount&count="+count+"&id="+id;
} else {
// defaultValue 属性是表单项 Dom 对象的属性。它表示默认的 value 属性值。
this.value = this.defaultValue;
}
});

最重要的记忆点就是重定向才能避免重复提交。

resp.sendRedirect(req.getContextPath()+"/pages/cart/checkout.jsp");

老师留了很大部分有关订单的功能完善,不知道到底要不要去完成。

2024年2月15日

现在第八第九部分,放在了知识点里面记录了。

你可能感兴趣的:(书城项目,java)