JavaWeb - 黑马旅游网(番外2):用户收藏分页展示

it2024-03-10  80

黑马旅游网(番外2):用户收藏分页展示

1 功能描述2 功能分析2.1 业务逻辑2.2 实现细节2.2.1 用户身份获取2.2.2 特殊情况处理2.2.3 代码编写位置 3 代码实现3.1 后端3.1.1 Servlet3.1.2 Service3.1.3 Dao 3.2 前端 4 相关链接

1 功能描述

接上篇黑马旅游网(番外1):“自动登录”,本篇博客介绍我对黑马旅游网项目的第 2 个扩展功能:用户收藏界面展示。在用户已经登录网站且收藏了一些旅游线路的情况下。点击页面 header 区域中的 我的收藏 即可跳转至收藏界面。

这里需要处理两种特殊情况:1. 用户尚未登陆;2. 用户没有收藏任何旅游线路。在前端都要给与相应的提示信息。

2 功能分析

2.1 业务逻辑

收藏列表中的很多功能细节和之前实现的功能具备较大的重复度,但是整个业务逻辑和之前比还是存在区别,对数据库的查询要比之前稍微复杂一些。先不考虑未登录/无收藏等特殊情况,一般情况下,首先要查询当前登录用户的收藏内容,这一步需要查询 tab_favorite 表,这张表关联了 uid 和 rid:

将当前登录用户的 uid 作为查询条件,查找满足约束的所有记录的 rid 。再将 rid 作为查询条件去 tab_route 表中做分页查询相应的旅游线路信息。参考黑马旅游网(5):旅游线路分页展示,后端的查询结果是将 PageBean<Route> 转换为 json 形式响应给客户端浏览器,前端再做处理和展示,功能完成。

2.2 实现细节

2.2.1 用户身份获取

用户身份的获取方式我总结为两种:

后端:从 Session 中直接获取 User bean 对象,进而获取 uid;前端:利用后端之前返回的登录用户 json 数据,抓取 uid 并以 GET 请求方式提交给后端,后端采用 getParameter() 方法获取到 uid。

在我的代码中使用后端方式获取,实现起来也相对容易。

2.2.2 特殊情况处理

用户未登录 Session 中没有 User Bean 对象,无法执行查询,那么后端会向前端传递一个 null 对象。前端可以将此作为判断条件做相应处理。用户无收藏 正确执行查询,但是没有查询到收藏线路,则 PageBean 中的 totalCount 属性取默认值 0。前端可以将此作为判断条件做相应处理。

2.2.3 代码编写位置

查询收藏线路的执行实体是登录用户,因此在后端的 Servlet 层,将该查询业务定义在 UserServlet 和 UserService 中。用户收藏内容保存在 tab_favorite 中,因此具体的查询逻辑应当定义在 FavoriteDao 中。旅游线路信息保存在 tab_route 中,因此对旅游线路的分页查询应当定义在 RouteDao 中。

可以通过一张简图理解 另外,查询用户收藏内容时,在 Dao 层需要定专门在 domain 包中义一个 Bean 对象接收收藏数据。

public class MyFavorite { private int uid; private String date; private int rid; /* setter & getter */ }

3 代码实现

3.1 后端

3.1.1 Servlet

UserServlet.java

/** * 获取`我的收藏`方法 */ public void findMyFavorite(HttpServletRequest request, HttpServletResponse response) throws IOException { // 获取session,取得用户对象 HttpSession session = request.getSession(); User user = (User) session.getAttribute("user"); if (user == null) { // 用户未登录 writeValue(null, response); return; } // 获取并处理浏览器请求属性 String currentPageStr = request.getParameter("currentPage"); // 当前页数 String pageSizeStr = request.getParameter("pageSize"); // 每页显示条数 int currentPage = this.parseInt(currentPageStr, 1); int pageSize = this.parseInt(pageSizeStr, 8); // 2.获取service,根据uid查rid,再根据rid查详情数据 PageBean<Route> routePageBean = service.favorPageQuery(user.getUid(), currentPage, pageSize); // 3.将数据回写至浏览器 writeValue(routePageBean, response); }

3.1.2 Service

UserServiceImpl.java

/** * 查询`我的收藏` * @param uid 用户uid * @return 泛型为Route类的PageBean对象, * 收藏结果的分页展示 */ @Override public PageBean<Route> favorPageQuery(int uid, int currentPage, int pageSize) { // 创建PageBean<Route>对象 PageBean<Route> routePageBean = new PageBean<>(); // 查询总记录数totalCount int totalCount = favoriteDao.findCountByUid(uid); if (totalCount == 0) {// 没有查到收藏记录 return routePageBean; } // 计算起始记录数start,计算总页数totalPage int start = (currentPage - 1) * pageSize; int totalPage = (totalCount % pageSize == 0) ? (totalCount / pageSize) : (totalCount / pageSize + 1); // 分页查询rid列表(封装在MyFavorite类中) List<MyFavorite> pageFavoriteList = favoriteDao.findByUidAndPage(uid, start, pageSize); // 创新一个空的List<Route>集合 List<Route> routeList = new ArrayList<>(); // 遍历pageFavoriteList组装routeList for (MyFavorite myFavorite : pageFavoriteList) { // 根据其rid属性利用routeDao查route对象 Route route = routeDao.findOne(myFavorite.getRid()); // 向routeList中追加route属性 routeList.add(route); } // 并组装PageBean<Route>对象 routePageBean.setCurrentPage(currentPage); // 设置当前页码 routePageBean.setPageSize(pageSize); // 设置每页显示条数 routePageBean.setTotalPage(totalPage); // 设置总页数 routePageBean.setTotalCount(totalCount); // 查询并设置总记录数 routePageBean.setList(routeList); return routePageBean; }

3.1.3 Dao

FavoriteDaoImpl.java

/** * 查询用户uid的收藏总数 * @param uid 用户uid * @return 收藏路线总数 */ @Override public int findCountByUid(int uid) { String sql = "SELECT COUNT(*) FROM tab_favorite WHERE uid = ?"; return template.queryForObject(sql, Integer.class, uid); } /** * 分页查询用户uid的收藏记录 * @param uid 用户uid * @param start 起始条目 * @param pageSize 每页显示条数 * @return MyFavorite Bean 对象构成的 List 集合 */ @Override public List<MyFavorite> findByUidAndPage(int uid, int start, int pageSize) { String sql = "SELECT * FROM tab_favorite WHERE uid = ? LIMIT ? , ?"; return template.query(sql, new BeanPropertyRowMapper<>(MyFavorite.class), uid, start, pageSize); }

RouteDaoImpl.java (复用之前的线路信息查询代码)

/** * 根据线路id查询详细信息 * @param rid 线路id * @return Route Bean 对象 */ @Override public Route findOne(int rid) { String sql = "SELECT * FROM tab_route WHERE rid = ?"; return template.queryForObject(sql, new BeanPropertyRowMapper<>(Route.class), rid); }

3.2 前端

前端这里我基本参考之前的旅游线路分页展示的代码实现的。主体逻辑就是页面跳转来后,执行一个 AJAX 请求向后端要数据,提交请求时需要传递 currentPage,后端默认处理为 1。接收 json 形式的 PageBean 对象:

PageBean 为空:说明用户没有登录,给与相应的提示信息PageBean 中的 totalCount 属性为 0,说明用户没有收藏任何线路,给与相应的提示信息正常情况,参考分页线路展示实现即可,这里对这种情况不再做具体展示,可以参考黑马旅游网(5):旅游线路分页展示,或者访问我的 GitHub 仓库 阅读。

myfavorite.html

/** * 我的收藏分页展示 */ $(function () { let currentPage = getParameter("currentPage"); load(currentPage); }); function load(currentPage) { $.get("user/findMyFavorite", {currentPage: currentPage}, function (pageBean) { // 解析pageBean数据,展示到页面上 if (pageBean == null) { // 可以添加一些渲染,由于我主学后端,这里就不展开了 $("#favorite_routes").html('<span id="notlogin">您尚未登录,请<a href="login.html"> 【【登录】 </a></span>'); } if (pageBean["totalCount"] === 0) { // 可以添加一些渲染,由于我主学后端,这里就不展开了 $("#favorite_routes").html('<span id="nofavorite">您还没有任何收藏哦,去看一看线路列表吧</span>'); } /*分页栏展示*/ /*旅游线路展示*/ }); }

4 相关链接

项目课程链接:https://www.bilibili.com/video/BV1CE411E7h4 完整课程连接:https://www.bilibili.com/video/BV1uJ411k7wy 《黑马旅游网》系列博客及笔者源码传送门:https://blog.csdn.net/xing123456jl/article/details/109173068

最新回复(0)