其他分享
首页 > 其他分享> > Web期末课程设计v1.0(五) | 闲优购系统 | 模拟网站埋点实现用户浏览记录的统计与显示

Web期末课程设计v1.0(五) | 闲优购系统 | 模拟网站埋点实现用户浏览记录的统计与显示

作者:互联网

文章目录

以往课设记录


运行环境


1. 页面效果展示


1.1 显示当前位置

在这里插入图片描述

1.2 购买商品时候的询问窗口

在这里插入图片描述

确认购买后

在这里插入图片描述

1.3 显示浏览记录

在这里插入图片描述

2. 功能实现

2.1 使用Boostrap5框架的Modal实现确认购买后的弹出的窗口

Bootstrap5 modal 官方文档
在这里插入图片描述
关于modal组件的使用:

参数名称描述
data-bs-toggle=modal用于指定按钮的目标为一个modal模态框
data-bs-target = #…用于指定当前按钮绑定的模态框组件的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请求到后端,后端对操作的用户、浏览的商品存储到数据库。

那么怎么获取到请求的用户以及商品呢?

笔者采取的措施是:

  1. 在JSP页面显示商品卡片时候,通过设置data-…属性,来指定当前商品的用户id和商品id。

  2. 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