项目第4天-课堂笔记
一、我的收藏
实现的步骤:
1. header.html代码,头部页面登录信息位置“我的收藏”跳转到myfavorite.html页面
2. myfavorite.html代码,我的收藏页面,页面加载时提交异步获取当前登录用户收藏分页数据列表请求到
FavoriteServlet,并获取返回的PageBean数据更新到页面上。
<!-- 排行榜 end-->
<!--引入尾部-->
<div id="footer"></div>
<!--导入布局js,共享header和footer-->
<script type="text/javascript" src="js/include.js"></script>
<script type="text/javascript" src="js/getParameter.js"></script>
<script>
//接收参数:pageNumber
var pageNumber = getParameter("pageNumber");
//发Ajax请求到Servlet,分页查询我的收藏,显示出来。默认查询第1页
$.post("favorite","action=myFavorite&pageNumber=" + pageNumber,function(result){
if (result.ok) {
var v = result.data;
if (v === -1) {
//未登录,跳转到登录页面
location.href = "login.html";
}else{
//已登录状态,v的值就是pageBean的数据
var pageBean = v;
//1. 显示路线的信息
var routes = pageBean.data;
var routeHtml = "";
for (var route of routes){
routeHtml += "<div class=\"col-md-3\">\n" +
" <a href=\"route_detail.html?rid="+route.rid+"\">\n" +
" <img src=\""+route.rimage+"\" alt=\"\">\n" +
" <div class=\"has_border\">\n" +
" <h3>"+route.rname+"</h3>\n" +
" <div class=\"price\">网付价<em>¥</em><strong>"+route.price+"</strong><em>起</em></div>\n" +
" </div>\n" +
" </a>\n" +
" </div>";
}
$("#home>.row").html(routeHtml);
//2. 显示分页条
var pageHtml = "";
//2.1 拼接 首页和上一页
if (pageBean.pageNumber > 1) {
pageHtml += "<li><a href=\"myfavorite.html?pageNumber=1\">首页</a></li>";
pageHtml += "<li class=\"threeword\"><a href=\"myfavorite.html?pageNumber="+(pageBean.pageNumber-1)+"\">上一页</a></li>";
}
//2.2 拼接 页码
for (var i = pageBean.start; i <= pageBean.end; i++) {
var curClass = i===pageBean.pageNumber?"curPage":"";
pageHtml += "<li class='"+curClass+"'><a href=\"myfavorite.html?pageNumber="+i+"\">"+i+"</a></li>";
}
//2.3 拼接 下一页和末页
if (pageBean.pageNumber < pageBean.pageCount) {
pageHtml += "<li class=\"threeword\"><a href=\"myfavorite.html?pageNumber="+(pageBean.pageNumber + 1)+"\">下一页</a></li>";
pageHtml += "<li class=\"threeword\"><a href=\"myfavorite.html?pageNumber="+pageBean.pageCount+"\">末页</a></li>";
}
$(".pageNum>ul").html(pageHtml);
}
}else{
alert(result.msg);
}
},"json");
</script>
3. FavoriteServlet.java代码,收藏Servlet处理前端请求,调用IFavoriteService业务接口获取PageBean数据分
页对象业务方法。
public void myFavorite(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
ResultInfo info = null;
try {
//从session里得到当前用户的User对象
User user = (User) request.getSession().getAttribute("loginUser");
if (user != null) {
//1. 接收参数
String pageNumberStr = request.getParameter("pageNumber");
int pageNumber = 1;
int pageSize = 12;
if (pageNumberStr != null && !"".equals(pageNumberStr)) {
pageNumber = Integer.parseInt(pageNumberStr);
}
//2. 完成功能
PageBean<Route> pageBean = favoriteService.myFavorite(user, pageNumber,pageSize);
//3. 处理结果
info = new ResultInfo(true, pageBean);
}else{
//未登录状态,给客户端返回一个状态值
info = new ResultInfo(true, -1);
}
} catch (Exception e) {
e.printStackTrace();
info = new ResultInfo(false, "系统忙,请稍候");
}
ObjectMapper mapper = new ObjectMapper();
String json = mapper.writeValueAsString(info);
response.getWriter().print(json);
}
4. IFavoriteService.java代码,收藏业务接口定义获取PageBean数据分页对象业务方法。
@Override
public PageBean<Route> myFavorite(User user, int pageNumber, int pageSize) {
PageBean<Route> pageBean = new PageBean<Route>();
/*当前页码 */
pageBean.setPageNumber(pageNumber);
/*每页多少条*/
pageBean.setPageSize(pageSize);
/*总共多少数据*/
int totalCount = favoriteDao.getMyFavoriteCount(user.getUid());
pageBean.setTotalCount(totalCount);
/*分了多少页*/
int pageCount = PageUtils.calcPageCount(totalCount, pageSize);
pageBean.setPageCount(pageCount);
/*页码条从几开始显示*/
int[] pagination = PageUtils.pagination(pageNumber, pageCount);
pageBean.setStart(pagination[0]);
/*页码条显示到几结束*/
pageBean.setEnd(pagination[1]);
/*当前页的数据集合*/
int index = PageUtils.calcSqlLimitIndex(pageNumber, pageSize);
List<Route> routeList = favoriteDao.myFavorite(user.getUid(), index, pageSize);
pageBean.setData(routeList);
return pageBean;
}
5. FavoriteServiceImpl.java代码,收藏业务接口实现类实现获取PageBean数据分页对象业务方法。调用
IFavoriteDao数据访问接口获取当前登录用户收藏数据列表总记录数和当前页收藏数据列表。
6. IFavoriteDao.java代码,收藏数据访问接口定义获取当前登录用户收藏数据列表总记录数和当前页收藏数据
列表方法。
7. FavoriteDaoImpl.java代码,收藏数据访问接口实现类实现获取当前登录用户收藏数据列表总记录数和当前页
收藏数据列表方法
@Override
public int getMyFavoriteCount(Integer uid) {
return jdbcTemplate.queryForObject("SELECT COUNT(*) FROM tab_favorite WHERE uid = ?", Integer.class, uid);
}
@Override
public List<Route> myFavorite(Integer uid, int index, int pageSize) {
return jdbcTemplate.query("SELECT r.* FROM tab_favorite f, tab_route r WHERE f.rid = r.rid AND uid = ? LIMIT ?,?", new BeanPropertyRowMapper<>(Route.class), uid, index, pageSize);
}
要求:
-
当用户在登录之后,点击“我的收藏”,跳转到我的收藏页面myfavorite.html。
-
在myfavorite.html页面里,发Ajax请求,得到当前用户收藏的所有路线,分页显示
分析:
-
如何查询“我的收藏”?
SELECT r.* FROM tab_favorite f, tab_route r WHERE f.rid = r.rid AND uid = ? LIMIT ?,?
步骤:
1. 在myFavorite.html页面里发Ajax请求到Servlet
-
接收参数:pageNumber
-
发Ajax请求到Servlet,传参:分页条件pageNumber(搜索条件uid不需要客户端传递,是在服务端自己获取的)
2. 在Servlet里处理请求,准备页面需要的数据,返回给页面
-
先从session获取当前登录的User对象。如果获取不到,说明是未登录,返回值:-1
-
如果是已登录状态,调用Service,准备页面需要的数据
-
在Service里面
-
- 创建PageBean对象
-
准备pageNumber
-
准备pageSize
-
准备总数量(我的收藏总数量),调用dao,执行SQL语句
-
计算pageCount
-
计算分页条的start和end
-
准备我的收藏的数据集合,调用dao,执行SQL语句
-
/*查看收藏*/
/*我的收藏的数量*/
@Override
public int getMyFavoriteCount(Integer uid) {
String sql="SELECT COUNT(*) FROM tab_favorite WHERE uid = ?";
return jdbcTemplate.queryForObject(sql,Integer.class,uid);
}
@Override
public List<Route> myFavorite(Integer uid, int index, int pageSize) {
String sql="SELECT r.* FROM tab_favorite f, tab_route r WHERE f.rid = r.rid AND uid = ? LIMIT ?,?";
return jdbcTemplate.query(sql,new BeanPropertyRowMapper<>(Route.class),uid,index,pageSize);
}
-
返回pageBean对象
-
得到结果PageBean
-
把PageBean放到resultInfo里,把resultInfo转换成json,返回客户端页面
ObjectMapper mapper = new ObjectMapper();
String json = mapper.writeValueAsString(info);
response.getWriter().print(json);
3. 在myfavorite.html页面里处理结果
-
得到结果值,如果是-1:是未登录状态,跳转到登录页面
-
如果不是-1:值就是pageBean的数据
-
把pageBean里的路线列表,循环显示到页面上
-
拼接分页条的HTML代码,显示到页面上
-
分页条里的按钮,要有跳转链接:myfavorite.html?pageNumber=页码
-
favoriterank.html代码
<!--导入底部-->
<div id="footer"></div>
<!--导入布局js,共享header和footer-->
<script type="text/javascript" src="js/include.js"></script>
<script type="text/javascript" src="js/getParameter.js"></script>
<script>
//接收参数
var rname = getParameter("rname");
var minprice = getParameter("minprice");
var maxprice = getParameter("maxprice");
var pageNumber = getParameter("pageNumber");
//发Ajax请求,得到搜索的结果,分页显示
var params = "action=rankRoutes&rname="+rname+"&minprice="+minprice+"&maxprice="+maxprice+"&pageNumber="+pageNumber;
$.post("route",params,function(result){
if (result.ok) {
var pageBean = result.data;
//1. 显示路线列表数据
var routes = pageBean.data;
var routeHtml = "";
for(var i=0; i<routes.length; i++){
var route = routes[i];
//1. 第1名,序号样式类名:num one; 第2名,序号样式类名:num two; 其它,序号样式类名:num
//2. 显示的序号是 总序号(所有搜索结果里的排序序号)
var number = i + 1 + (pageBean.pageNumber - 1)* pageBean.pageSize;
var className = "";
if (number === 1) {
className = "one";
}else if (number === 2) {
className = "two";
}
routeHtml += "<li>\n" +
" <span class=\"num "+className+"\">"+number+"</span>\n" +
" <a href=\"route_detail.html\"><img src=\""+route.rimage+"\" alt=\"\"></a>\n" +
" <h4><a href=\"route_detail.html\">"+route.rname+"</a></h4>\n" +
" <p>\n" +
" <b class=\"price\">¥<span>"+route.price+"</span>起</b>\n" +
" <span class=\"shouchang\">已收藏"+route.count+"次</span>\n" +
" </p>\n" +
" </li>";
}
$(".list>ul").html(routeHtml);
//2. 显示分页条
var pageHtml = "";
//2.1 拼接 首页和上一页
if (pageBean.pageNumber > 1) {
pageHtml += "<li><a href=\"favoriterank.html?rname="+rname+"&minprice="+minprice+"&maxprice="+maxprice+"&pageNumber=1\">首页</a></li>";
pageHtml += "<li class=\"threeword\"><a href=\"favoriterank.html?rname="+rname+"&minprice="+minprice+"&maxprice="+maxprice+"&pageNumber="+(pageBean.pageNumber - 1)+"\">上一页</a></li>";
}
//2.2 拼接 页码
for (var i = pageBean.start; i <= pageBean.end; i++) {
var curClass = i===pageBean.pageNumber?"curPage":"";
pageHtml += "<li class='"+curClass+"'><a href=\"favoriterank.html?rname="+rname+"&minprice="+minprice+"&maxprice="+maxprice+"&pageNumber="+i+"\">"+i+"</a></li>";
}
//2.3 拼接 下一页和末页
if (pageBean.pageNumber < pageBean.pageCount) {
pageHtml += "<li class=\"threeword\"><a href=\"favoriterank.html?rname="+rname+"&minprice="+minprice+"&maxprice="+maxprice+"&pageNumber="+(pageBean.pageNumber + 1)+"\">下一页</a></li>";
pageHtml += "<li class=\"threeword\"><a href=\"favoriterank.html?rname="+rname+"&minprice="+minprice+"&maxprice="+maxprice+"&pageNumber="+pageBean.pageCount+"\">末页</a></li>";
}
$(".pageNum>ul").html(pageHtml);
}else {
alert(result.msg);
}
},"json");
//“搜索”按钮被点击时,要把搜索条件传递给favoriterank.html
$("#searchBtn").click(function () {
location.href = "favoriterank.html?rname=" + $("#searchRname").val()+"&minprice="+$("#searchMin").val()+"&maxprice="+$("#searchMax").val()+"&pageNumber=1";
});
//回显搜索条件
/*var rname = getParameter("rname");
var minprice = getParameter("minprice");
var maxprice = getParameter("maxprice");*/
$("#searchRname").val(rname);
$("#searchMin").val(minprice);
$("#searchMax").val(maxprice);
</script>
二、收藏排行榜
要求
-
用户点击了“收藏排行榜”,跳转到favoriterank.html,在页面发Ajax得到并显示 收藏排行榜的数据
-
用户在favoriterank.html页面上,输入搜索条件,点击“搜索”按钮,得到搜索结果,并分页显示
分析
-
收藏排行榜:按照旅游路线的收藏数量降序排列,得到的就是收藏的排行榜
步骤
1. 跳转到收藏排行榜页面
-
从导航条上,点击“收藏排行榜”链接,跳转到favoriterank.html。传参:pageNumber=1
-
从收藏排行榜页面上,点击“搜索”按钮,跳转到favoriterank.html。传参:
-
搜索条件:路线名称rname, 最小金额minprice,最大金额maxprice
-
分页条件:页码pageNumber
-
2. 在favoriterank.html页面上发Ajax请求到Servlet
-
接收参数:
-
搜索条件:路线名称rname, 最小金额minprice,最大金额maxprice
-
分页条件:页码pageNumber
-
-
向Servlet发Ajax请求,把搜索条件和分页条件传递给Servlet
3. 在Servlet里处理请求,准备页面需要的数据,返回给页面
-
接收参数:分页条件和搜索条件
-
封装实体:把搜索条件封装成了一个QueryVO
-
完成功能:调用service,准备页面需要的数据,得到PageBean对象
-
在Service里:
-
创建pageBean对象
-
准备pageNumber页码
-
准备pageSize每页几条
-
准备totalCount总数量:根据搜索条件查询,符合条件的总数量
-
因为条件不固定,所以在dao层,需要动态拼接SQL语句
-
-
准备pageCount总页数:计算
-
准备start和end:分页时起始页码和结束页码, 计算出来
-
准备data:当前页码的数据集合List<Route>,根据搜索条件进行查询,根据分页条件进行分页
-
因为条件不固定,所以在dao层,需要动态拼接SQL语句
-
-
把pageBean对象返回给Servlet
-
-
-
处理结果:
-
得到结果PageBean
-
把PageBean放到resultInfo里,把resultInfo转换成json,返回客户端页面
-
4. 在favoriterank.html页面上处理结果
-
得到pageBean里的路线列表,循环显示
-
每个路线前边,显示的是排名序号。计算方法:
序号= 索引i + 1 + (当前页码 - 1)* 每页几条;
-
每个路线前边,显示的样式,是根据排名序号判断得到的:
-
第1名:样式 num one
-
第2名:样式 num two
-
其它: 样式 num
-
-
-
得到PageBean里的分页信息,拼接显示分页条
-
分页条里每个按钮上的链接,都要跳转到favoriterank.html,并且传递所有参数:搜索条件和分页条件
favoriterank.html?rname=路线名称&minprice=最小金额&maxprice=最大金额&pageNumber=页码
-
三、拓展:IoC和AOP了解
1. IoC
1.1 依赖问题
-
在实际开发中,代码之间是有依赖性的,叫耦合性。比如:
-
Service依赖于Dao的实现类对象
-
-
编译期依赖:
-
在代码编译期间,就有依赖的关系。比如:
-
在Service里直接使用new的方式,创建依赖的dao层对象
private UserDao userDao = new UserDaoImpl();
-
-
如何解决编译期依赖?
-
使用反射生成对象,代替掉new生成对象
private UserDao userDao = BeanFactory.getBean();
public class BeanFactory { public static Object getBean(){ Object object = null; try { Class clazz = Class.forName("com.itheima.dao.impl.UserDaoImpl"); object = clazz.newInstance(); } catch (Exception e) { e.printStackTrace(); } return object; } }
-
-
-
运行期依赖:
-
在上边的代码运行过程中,所需要的类
"com.itheima.dao.impl.UserDaoImpl"
就必须存在。在运行时的依赖叫运行期依赖 -
问题:如果要修改换了其它实现类,就必须要修改源码。重新编译,重新打包,重新部署
-
解决方案:把类名放到配置文件中,程序里读取配置文件,得到全限定类名,然后再创建实现对象
-
在Service里要创建dao对象:调用工具类使用反射生成的对象
private UserDao userDao = BeanFactory.getBean("userDao"); private RouteDao routeDao = BeanFactory.getBean("routeDao");
-
在工具类里:读取了配置文件,得到全限定类名,然后生成实例对象
public class BeanFactory { public static Object getBean(String id){ Object object = null; try { //读取配置文件,得到userDao的实现类的全限定类名 ResourceBundle bundle = ResourceBundle.getBundle("beans"); String className = bundle.getString(id); Class clazz = Class.forName(className); object = clazz.newInstance(); } catch (Exception e) { e.printStackTrace(); } return object; } }
-
配置文件如下:
userDao=com.itheima.dao.impl.UserDaoImpl routeDao=com.itheima.dao.impl.RouteDaoImpl
-
1.2 IoC思想
什么是IoC
-
IoC:Inversion of Controller,控制反转,是一种程序开发的思想
-
正常过程:如果程序依赖于一个对象,原本是自己主动创建依赖的对象
-
控制返转:如果程序依赖于一个对象,把创建依赖对象的控制权交出去。程序调用其它工具BeanFacotry,被动接收得到一个对象
-
IoC的作用:
-
用于解耦。(降低层与层之间的耦合性)
2. aop思想
aop思想:
-
AOP:Aspect Oriented Programming,面向切面编程
-
作用:在不影响原本功能代码逻辑的情况下,对功能代码进行增强/控制
-
AOP是在IoC的基础上提供的功能
Spring里的AOP使用
-
事务控制。通过配置文件/注解配置,在不影响dao层代码的情况下,对dao层进行事务控制
内容回顾
1. HTML+Ajax功能实现的流程
1.1 页面发Ajax请求,传参到Servlet
-
Ajax请求到Servlet时,传参:
-
如果是分页查询,需要传参有:
-
搜索条件
-
分页条件
-
-
如果是普通查询,需要传参:
-
查询的条件
-
-
如果是增、删、改功能,需要传参:
-
增加:表单提交的内容,向数据库里保存里需要的数据
-
删除:传参删除的条件
-
修改:表单提交的内容,向数据库里修改的数据,要注意修改的条件(必须有参数)
-
-
1.2 在Servlet里处理功能,返回处理的结果给页面
-
接收参数:
-
页面提交的参数
-
如果有些参数不是从页面里得到的,就从服务端写代码得到。比如:当前登录的用户User对象
-
-
封装实体:
-
如果页面传参较多,可以封装成实体对象
-
增、改:表单提交的数据,封装成对象的JavaBean对象
-
搜索条件:封装成一个QueryVO对象
-
-
调用Service,准备页面需要的数据
-
在Service里:
-
如果是查询功能,就准备页面需要显示的结果数据
-
如果是增、删、改功能,就准备操作的结果数据:boolean是否成功
-
返回操作结果
-
-
-
得到结果:是Service准备的数据
-
处理结果:
-
如果给客户端返回的数据过多,通常封装到一个结果ResultInfo里。把ResultInfo转换成json,返回客户端
-
把结果转换成json,返回到客户端
-
-
1.3 在页面上接收并处理结果
-
如果是查询的结果:把结果数据获取到,使用jQuery的dom操作方法把这些结果显示到页面上
-
用的最多的是:
html("html代码")
-
如果是简单结果,根据不同结果做不同处理
-
-
如果是其它(增、删、改)的结果:
-
根据不同的结果,做不同的处理。成功了跳转到什么地方;失败了显示错误信息
-
2. JSP+Servlet功能实现的流程
2.1 页面发请求到Servlet
-
表单提交
-
点击按钮,触发js发请求:location.href = "Servlet的地址"
2.2 在Servlet里处理请求,返回处理的结果给JSP
-
接收参数
-
封装实体
-
完成功能:调用Service完成功能
-
页面需要什么数据,Service就准备什么数据
-
如果是增、删、改操作,结果通常是boolean值(是否操作成功)
-
把结果返回给Servlet
-
-
处理结果
-
如果是增、删、改操作,通常是重定向跳转到jsp页面/Servlet上(比如:删除之后,跳转到结果列表页面)
-
如果是查询,通常是把查询结果放到request域里,请求转发到JSP页面上
-
2.3 在JSP页面里处理显示结果
-
使用EL表达式从域里得到结果
-
使用JSTL的if、forEach标签,把结果显示到页面上