Web期末课程设计v1.0(五) | 闲优购系统 | 模拟网站埋点实现用户浏览记录的统计与显示
作者:互联网
文章目录
以往课设记录
-
Web期末课程设计v1.0(一) | 大学生闲置物品交易系统 | 选择页面模板(附资源),使用 JQuery AJAX实现注册、登陆
-
Web期末课程设计v1.0(二) | 闲优购 | 使用Bootstrap5各组件优化页面,使用AJAX请求实现用户修改信息功能
-
Web期末课程设计v1.0(三) | 闲优购系统 | 基于Bootstrap设计商品页面、使用JQuery实现上传文件并显示到图片组件、使用JSTL标签显示数据库的内容到无序列表
-
Web期末课程设计v1.0(四) | 闲优购系统 | 实现JQuery图片上传 | 使用JQ插件提交AJAX请求实现发布商品并保存到数据库 | 商品分类分页显示
运行环境
- windows10
- IDEA专业版
- JDK8
- HTML5、CSS3、JavaScript
- JQuery
- Bootstrap5
1. 页面效果展示
1.1 显示当前位置
1.2 购买商品时候的询问窗口
确认购买后
1.3 显示浏览记录
2. 功能实现
2.1 使用Boostrap5框架的Modal实现确认购买后的弹出的窗口
Bootstrap5 modal 官方文档
关于modal组件的使用:
- 一个button按钮组件负责启动一个modal模态框
在按钮中需要设置这几个参数
参数名称 | 描述 |
---|---|
data-bs-toggle=modal | 用于指定按钮的目标为一个modal模态框 |
data-bs-target = #… | 用于指定当前按钮绑定的模态框组件的ID |
- 一个div负责显示modal模态框的内容,模态框所需的参数参考官方代码,除了id外,笔者未作修改
jsp
<!-- Button trigger modal -->
<button id="bt-buy" type="button" class="btn btn-primary" data-bs-toggle="modal" data-bs-target="#staticBackdrop" hidden>
modal组件
</button>
<!-- Modal -->
<div class="modal fade" id="staticBackdrop" data-bs-backdrop="static" data-bs-keyboard="false" tabindex="-1" aria-labelledby="staticBackdropLabel" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title text-danger" id="staticBackdropLabel">
<i class="bi bi-exclamation-triangle-fill"></i>
温馨提示
</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body">
是否确认购买?
</div>
<div class="modal-footer">
<button id="btn-buy-cancel" type="button" class="btn btn-danger" data-bs-dismiss="modal">我再想想</button>
<button id="btn-buy-ok" type="button" class="btn btn-success" data-bs-toggle="modal" data-bs-target="#modal-buy-ok">确认购买</button>
</div>
</div>
</div>
</div>
<!-- Modal -->
<div class="modal fade" id="modal-buy-ok" tabindex="-1" aria-labelledby="modal-h-buy-ok" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title text-danger" id="modal-h-buy-ok">
<i class="bi bi-exclamation-triangle-fill"></i>
温馨提示
</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body">
<h5 class="display-5 text-success text-center">
购买成功!
<i class="bi bi-check-circle"></i>
</h5>
</div>
</div>
</div>
</div>
2.2 实现记录浏览记录
2.2.1 存储浏览记录的表、对象
关于数据表的问题,首先用户uid、商品cid必须有外键约束,即需要是用户表和商品表里真实存在的数据,其次是需关联uid、cid这两个属性,为实现浏览记录的覆盖,这两个字段不能重复出现,具体实现可以看之后的SQL语句与dao层代码。
Mysql数据表
create table user_action(
id int primary key auto_increment,
uid int not null,
cid int not null,
time timestamp(0) null default current_timestamp,
CONSTRAINT a_cid
FOREIGN KEY (cid) REFERENCES commodity(id),
CONSTRAINT a_uid
FOREIGN KEY (uid) REFERENCES user(id)
) default charset=utf8;
CREATE UNIQUE INDEX index_user_action ON user_action (uid, cid);
实体类 CommodityRecord.java
package com.uni.entity;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.sql.Timestamp;
@NoArgsConstructor
@AllArgsConstructor
@Data
public class CommodityRecord {
private int id;
private User user;
private Commodity commodity;
private Timestamp time;
}
2.2.2 浏览记录存储理念——埋点
当用户点击一个商品卡片时,会产生一个浏览记录,于是可以通过JS代码给每个商品卡片绑定一个函数。
当卡片被单击时,JS提交AJAX请求到后端,后端对操作的用户、浏览的商品存储到数据库。
那么怎么获取到请求的用户以及商品呢?
笔者采取的措施是:
-
在JSP页面显示商品卡片时候,通过设置data-…属性,来指定当前商品的用户id和商品id。
-
JS代码获取用户id和商品id ,提交到Servlet,后端根据这两个ID查询到对应的数据,从而插入新的浏览记录到数据库。
不过在保存记录时,会遇到一个问题:
如果用户访问的商品记录是已经存在的,那么该如何处理?
为防止出现重复记录,即用户点击同一商品的记录都出现在数据表,这样就可能会产生许多冗余数据,其实可以给浏览记录数据表添加一个字段,用于表示浏览的次数,默认为1,不过为简化课程设计,笔者就直接采用覆盖式,将其访问时间覆盖,实现的SQL语句:
insert into user_action (uid, cid) values (?, ?) on duplicate key update time=?"
2.2.3 JS埋点
$(document).ready(function (){
var cid = 0
var uid = 0
$(".card-commodity").click(function (){
cid = $(this).data("cid")
uid = $(this).data("uid")
// 埋点记录
$.ajax({
url: '/visted?cid=' + cid + "&uid=" + uid,
type: "GET",
success: function (data){
}
});
$("#bt-buy").click();
});
$(".btn-commodity-type").click(function (){
window.location.href=$(this).attr("href");
});
$("#btn-buy-ok").click(function (){
// 确认购买后,添加商品订单....
});
});
2.2.4 Servlet 处理埋点请求
Action层
package com.uni.action;
import com.uni.entity.User;
import com.uni.service.Service;
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 java.io.IOException;
@WebServlet(name = "UserVistedAction", urlPatterns = "/visted")
public class UserVistedAction extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
int cid = Integer.parseInt(req.getParameter("cid"));
int uid = Integer.parseInt(req.getParameter("uid"));
User user = (User) req.getSession().getAttribute("userInfo");
// 当用户访问非自己发布商品时,进行埋点记录
if(user.getId() != uid)
Service.commodity.insertAction(user.getId(), cid);
resp.getWriter().write("埋点完毕!");
}
}
Dao层
public boolean insertAction(int uid, int cid) {
Connection connection = DruidUtil.getConnection();
String sql = "insert into user_action (uid, cid) values (?, ?) on duplicate key update time=?";
boolean ok = false;
try{
PreparedStatement pstmt = connection.prepareStatement(sql);
pstmt.setInt(1, uid);
pstmt.setInt(2, cid);
pstmt.setTimestamp(3, new Timestamp(System.currentTimeMillis()));
ok = pstmt.execute();
DruidUtil.release(connection, pstmt, null);
} catch (SQLException throwables) {
throwables.printStackTrace();
}
return ok;
}
2.3.5 JSP页面
<c:forEach items="${sessionScope.commodityInfo}" var="cd">
<div class="col-3 mb-5">
<div class="card-commodity" data-uid="${cd.uid}" data-cid="${cd.id}">
<img src="${cd.img}" class="card-img-top">
<div class="card-body">
<h5 class="card-title text-center">¥${cd.price}</h5>
<h6>商品名称: <span>${cd.name}</span></h6>
<h6 class="card-text" href="#">商品类型: ${cd.typeName}</h6>
<a class="card-text" href="#">商品描述: ${cd.info}</a>
<p>商家: <a href="#">${cd.userName}</a></p>
</div>
</div>
</div>
</c:forEach>
2.3 显示浏览记录
在记录用户浏览记录后,用户在个人信息页面可以查询到自己的浏览记录,和记录类似,同样是操作数据表。
2.3.1 Servlet层
package com.uni.action;
import com.uni.entity.CommodityRecord;
import com.uni.entity.User;
import com.uni.service.Service;
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.io.IOException;
import java.util.List;
@WebServlet(name ="UserHistoryAction", urlPatterns = "/history")
public class UserHistoryAction extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
HttpSession session = req.getSession();
User user =(User) session.getAttribute("userInfo");
List<CommodityRecord> commodityRecords = Service.user.queryHistory(user);
session.setAttribute("commodityRecords", commodityRecords);
resp.sendRedirect("card_user_info.jsp");
}
}
2.3.2 JSP页面 JSTL应用
<h3 class="h-title-black">
<i class="bi bi-clock-history"></i>
浏览记录 共${sessionScope.commodityRecords.size()}条
<c:if test="${not empty sessionScope.historyPageNow && sessionScope.commodityRecords.size() > 0}">
[${sessionScope.historyPageNow},${sessionScope.historyPageNow+1}] 条
</c:if>
</h3>
<div class="row row-cols-1 row-cols-md-2 g-4">
<c:set var="pageNow" scope="page" value="${sessionScope.historyPageNow}"></c:set>
<c:forEach items="${sessionScope.commodityRecords}" begin="${pageNow}" end="${pageNow + 1}" var="cr" varStatus="index">
<c:if test="${index.index <= sessionScope.commodityRecords.size()}">
<div class="card-commodity-row">
<div class="card-commodity" data-uid="${cr.user.id}" data-cid="${cr.commodity.id}">
<img src="${cr.commodity.img}" class="card-img-top">
<div class="card-body">
<h5 class="card-title text-center">¥${cr.commodity.price}</h5>
<h6>商品名称: <span>${cr.commodity.name}</span></h6>
<h6 class="card-text" href="#">商品类型: ${cr.commodity.typeName}</h6>
<a class="card-text" href="#">商品描述: ${cr.commodity.info}</a>
<p>商家: <a href="#">${cr.user.name}</a></p>
</div>
<div class="card-footer">
<small class="text-muted">上次浏览日期: ${fn:replace(cr.time, ".0", "")}</small>
</div>
</div>
</div>
</c:if>
</c:forEach>
</div>
3. 总结
至此,已完成了浏览信息的记录与显示,接下来的阶段就是商品订单信息的添加,其实在整个过程中,笔者做了许多简化工作,目前发现的最大问题就是dao层冗余代码过多,比如要查询一个商品记录,就需要在dao层接口定义一个新的方法,然后impl类实现,接着service层又要声明一个方法,Impl类调用dao层接口实现类的方法。总的来说比较繁琐…
标签:Web,课程设计,闲优购,uid,cid,浏览,user,import,记录 来源: https://blog.csdn.net/Unirithe/article/details/122121845