旅游线路收藏功能
分析
判断当前登录用户是否收藏过该线路
当页面加载完成后,发送ajax请求,获取用户是否收藏的标记
根据标记,展示不同的按钮样式
编写代码
后台代码
RouteServlet:
package cn.itcast.travel.web.servlet;
import cn.itcast.travel.domain.PageBean;
import cn.itcast.travel.domain.Route;
import cn.itcast.travel.domain.User;
import cn.itcast.travel.service.FavoriteService;
import cn.itcast.travel.service.RouteService;
import cn.itcast.travel.service.impl.FavoriteServiceImpl;
import cn.itcast.travel.service.impl.RouteServiceImpl;
import javax.servlet.*;
import javax.servlet.http.*;
import javax.servlet.annotation.*;
import java.io.IOException;
@WebServlet(name = "RouteServlet", value = "/route/*")
public class RouteServlet extends BaseServlet {
private RouteService routeService = new RouteServiceImpl();
private FavoriteService favoriteService = new FavoriteServiceImpl();
/**
* 分页查询
* @param request
* @param response
* @throws IOException
*/
public void pageQuery(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String currentPageStr = request.getParameter("currentPage");
String pageSizeStr = request.getParameter("pageSize");
String cidStr = request.getParameter("cid");
//接受rname 线路名称
String rname = request.getParameter("rname");
//解决tomcat7版本request的中文乱码问题
rname = new String(rname.getBytes("iso-8859-1"),"utf-8");
//2.处理参数
int cid = triadic(cidStr,0);//类别id
int currentPage = triadic(currentPageStr,1);//当前页码,如果不传递,则默认为第一页
int pageSize = triadic(pageSizeStr,5);//每页显示条数,如果不传递,默认每页显示5条记录
//3. 调用service查询PageBean对象
PageBean<Route> pb = routeService.pageQuery(cid, currentPage, pageSize,rname);
//4. 将pageBean对象序列化为json,返回
writeValue(pb, response);
}
public void findOne(HttpServletRequest request, HttpServletResponse response) throws IOException {
//1.接收id
String rid = request.getParameter("rid");
//2.调用service查询route对象
Route route = routeService.findOne(rid);
//3.转为json写回客户端
writeValue(route, response);
}
public void isFavorite(HttpServletRequest request, HttpServletResponse response) throws IOException {
//1. 获取线路id
String rid = request.getParameter("rid");
//2. 获取当前登录的用户 user
User user = (User) request.getSession().getAttribute("user");
//用户id //用户尚未登录 //用户已经登录
int uid = user == null ? 0 : user.getUid();
//3. 调用FavoriteService查询是否收藏
boolean flag = favoriteService.isFavorite(rid, uid);
//4. 写回客户端
writeValue(flag, response);
}
public void addFavorite(HttpServletRequest request, HttpServletResponse response){
//1. 获取线路rid
String rid = request.getParameter("rid");
//2. 获取当前登录的用户 user
User user = (User) request.getSession().getAttribute("user");
int uid ;
if(user == null){
//用户尚未登录
uid = 0;
}else{
//用户已经登录
uid = user.getUid();
}
//3.调用service添加
favoriteService.add(rid, uid);
}
}
FavoriteService
package cn.itcast.travel.service.impl;
import cn.itcast.travel.dao.FavoriteDao;
import cn.itcast.travel.domain.Favorite;
import cn.itcast.travel.service.FavoriteService;
import cn.itcast.travel.dao.impl.FavoriteDaoImpl;
import java.util.Date;
public class FavoriteServiceImpl implements FavoriteService {
private FavoriteDao favoriteDao = new FavoriteDaoImpl();
/**
* 判断是否收藏
* @param rid
* @param uid
* @return
*/
@Override
public boolean isFavorite(String rid, int uid) {
Favorite favorite = favoriteDao.findByRidAndUid(Integer.parseInt(rid), uid);
return favorite != null;//如果对象有值,则为true,反之,则为false
}
/**
* 添加收藏
* @param rid
* @param uid
*/
@Override
public void add(String rid, int uid) {
favoriteDao.add(Integer.parseInt(rid),uid);
}
}
FavoriteDao
package cn.itcast.travel.dao.impl;
import cn.itcast.travel.dao.FavoriteDao;
import cn.itcast.travel.domain.Favorite;
import cn.itcast.travel.util.JDBCUtils;
import org.springframework.dao.DataAccessException;
import org.springframework.jdbc.core.BeanPropertyRowMapper;
import org.springframework.jdbc.core.JdbcTemplate;
import java.util.Date;
public class FavoriteDaoImpl implements FavoriteDao {
private JdbcTemplate template = new JdbcTemplate(JDBCUtils.getDataSource());
@Override
public Favorite findByRidAndUid(int rid, int uid) {
Favorite favorite = null;
try {
String sql = "select * from tab_favorite where rid = ? and uid = ? ";
favorite = template.queryForObject(sql,new BeanPropertyRowMapper<Favorite>(Favorite.class),rid,uid);
} catch (DataAccessException e) {
e.printStackTrace();
}
return favorite;
}
@Override
public int findCountByRid(int rid) {
String sql = "select count(*) from tab_favorite where rid = ? ";
return template.queryForObject(sql, Integer.class, rid);
}
@Override
public void add(int rid, int uid) {
String sql = "insert into tab_favorite values(?,?,?)";
template.update(sql, rid, new Date(), uid);
}
}
前台代码
route_detail.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>路线详情</title>
<link rel="stylesheet" type="text/css" href="css/bootstrap.min.css">
<link rel="stylesheet" type="text/css" href="css/common.css">
<link rel="stylesheet" type="text/css" href="css/route-detail.css">
</head>
<body>
<!--引入头部-->
<div id="header"></div>
<!-- 详情 start -->
<div class="wrap">
<div class="bread_box">
<a href="/">首页</a>
<span> ></span>
<a href="#">国内游</a><span> ></span>
<a href="#">全国-曼谷6-7天自由行 泰国出境旅游 特价往返机票自由行二次确认</a>
</div>
<div class="prosum_box">
<dl class="prosum_left">
<dt>
<img alt="" class="big_img" src="http://www.jinmalvyou.com/Public/uploads/goods_img/img_size4/201703/m49788843d72171643297ccc033d9288ee.jpg">
</dt>
<dd id="dd">
<a class="up_img up_img_disable"></a>
<a title="" class="little_img" data-bigpic="http://www.jinmalvyou.com/Public/uploads/goods_img/img_size4/201703/m40920d0669855e745d97f9ad1df966ebb.jpg">
<img src="http://www.jinmalvyou.com/Public/uploads/goods_img/img_size2/201703/m20920d0669855e745d97f9ad1df966ebb.jpg">
</a>
<a title="" class="little_img cur_img" data-bigpic="http://www.jinmalvyou.com/Public/uploads/goods_img/img_size4/201703/m49788843d72171643297ccc033d9288ee.jpg">
<img src="http://www.jinmalvyou.com/Public/uploads/goods_img/img_size2/201703/m29788843d72171643297ccc033d9288ee.jpg">
</a>
<a title="" class="little_img" data-bigpic="http://www.jinmalvyou.com/Public/uploads/goods_img/img_size4/201703/m4531a8dbceefa2c44e6d0e35627cd2689.jpg">
<img src="http://www.jinmalvyou.com/Public/uploads/goods_img/img_size2/201703/m2531a8dbceefa2c44e6d0e35627cd2689.jpg">
</a>
<a title="" class="little_img" data-bigpic="http://www.jinmalvyou.com/Public/uploads/goods_img/img_size4/201703/m46d8cb900e9f6c0a762aca19eae40c00c.jpg">
<img src="http://www.jinmalvyou.com/Public/uploads/goods_img/img_size2/201703/m26d8cb900e9f6c0a762aca19eae40c00c.jpg">
</a>
<a title="" class="little_img" data-bigpic="http://www.jinmalvyou.com/Public/uploads/goods_img/img_size4/201703/m45ea00f6eba562a767b5095bbf8cffe07.jpg" style="display:none;">
<img src="http://www.jinmalvyou.com/Public/uploads/goods_img/img_size2/201703/m25ea00f6eba562a767b5095bbf8cffe07.jpg">
</a>
<a title="" class="little_img" data-bigpic="http://www.jinmalvyou.com/Public/uploads/goods_img/img_size4/201703/m4265ec488cd1bc7ce749bc8c9b34b87bc.jpg" style="display:none;">
<img src="http://www.jinmalvyou.com/Public/uploads/goods_img/img_size2/201703/m2265ec488cd1bc7ce749bc8c9b34b87bc.jpg">
</a>
<a title="" class="little_img" data-bigpic="http://www.jinmalvyou.com/Public/uploads/goods_img/img_size4/201703/m4e7e964909d7dd1a9f6e5494d4dc0c847.jpg" style="display:none;">
<img src="http://www.jinmalvyou.com/Public/uploads/goods_img/img_size2/201703/m2e7e964909d7dd1a9f6e5494d4dc0c847.jpg">
</a>
<a title="" class="little_img" data-bigpic="http://www.jinmalvyou.com/Public/uploads/goods_img/img_size4/201703/m467db00e1b76718fab0fe8b96e10f4d35.jpg" style="display:none;">
<img src="http://www.jinmalvyou.com/Public/uploads/goods_img/img_size2/201703/m267db00e1b76718fab0fe8b96e10f4d35.jpg">
</a>
<a title="" class="little_img" data-bigpic="http://www.jinmalvyou.com/Public/uploads/goods_img/img_size4/201703/m487bbbc6e43eba6aa6a36cc1a182f7a20.jpg" style="display:none;">
<img src="http://www.jinmalvyou.com/Public/uploads/goods_img/img_size2/201703/m287bbbc6e43eba6aa6a36cc1a182f7a20.jpg">
</a>
<a class="down_img down_img_disable" style="margin-bottom: 0;"></a>
</dd>
</dl>
<div class="prosum_right">
<p class="pros_title" id="rname">【尾单特卖】全国-曼谷6-7天自由行 泰国出境旅游 特价往返机票自由行二次确认</p>
<p class="hot" id=routeIntRoduce>1-2月出发,网付立享¥1099/2人起!爆款位置有限,抢完即止!</p>
<div class="pros_other">
<p>经营商家 :<span id="sname">国旅</span></p>
<p>咨询电话 : <span id="consphone">400-618-9090</span></p>
<p>地址 : <span id="address">程序员</span></p>
</div>
<div class="pros_price">
<p class="price"><strong id="price">¥2699.00</strong><span>起</span></p>
<p class="collect">
<a class="btn" id="favorite"><i class="glyphicon glyphicon-heart-empty"></i>点击收藏</a>
<!-- <a class="btn already" disabled="disabled"><i class="glyphicon glyphicon-heart-empty"></i>点击收藏</a>-->
<span id="favoriteCount">已收藏100次</span>
</p>
</div>
</div>
</div>
<div class="you_need_konw">
<span>旅游须知</span>
<div class="notice">
<p>1、旅行社已投保旅行社责任险。建议游客购买旅游意外保险 <br>
<p>2、旅游者参加打猎、潜水、海边游泳、漂流、滑水、滑雪、滑草、蹦极、跳伞、滑翔、乘热气球、骑马、赛车、攀岩、水疗、水上飞机等属于高风险性游乐项目的,敬请旅游者务必在参加前充分了解项目的安全须知并确保身体状况能适应此类活动;如旅游者不具备较好的身体条件及技能,可能会造成身体伤害。</p>
<p>3、参加出海活动时,请务必穿着救生设备。参加水上活动应注意自己的身体状况,有心脏病、冠心病、高血压、感冒、发烧和饮酒及餐后不可以参加水上活动及潜水。在海里活动时,严禁触摸海洋中各种鱼类,水母,海胆,珊瑚等海洋生物,避免被其蛰伤。老人和小孩必须有成年人陪同才能参加合适的水上活动。在海边游玩时,注意保管好随身携带的贵重物品。</p>
<p>4、根据中国海关总署的规定,旅客在境外购买的物品,在进入中国海关时可能需要征收关税。详细内容见《中华人民共和国海关总署公告2010年第54号文件》。</p>
<p>5、建议出发时行李托运,贵重物品、常用物品、常用药品、御寒衣物等请随身携带,尽量不要托运。行李延误属于不可抗力因素,我司将全力协助客人跟进后续工作,但我司对此不承担任何责任。</p>
<p>1、旅行社已投保旅行社责任险。建议游客购买旅游意外保险 <br>
<p>2、旅游者参加打猎、潜水、海边游泳、漂流、滑水、滑雪、滑草、蹦极、跳伞、滑翔、乘热气球、骑马、赛车、攀岩、水疗、水上飞机等属于高风险性游乐项目的,敬请旅游者务必在参加前充分了解项目的安全须知并确保身体状况能适应此类活动;如旅游者不具备较好的身体条件及技能,可能会造成身体伤害。</p>
<p>3、参加出海活动时,请务必穿着救生设备。参加水上活动应注意自己的身体状况,有心脏病、冠心病、高血压、感冒、发烧和饮酒及餐后不可以参加水上活动及潜水。在海里活动时,严禁触摸海洋中各种鱼类,水母,海胆,珊瑚等海洋生物,避免被其蛰伤。老人和小孩必须有成年人陪同才能参加合适的水上活动。在海边游玩时,注意保管好随身携带的贵重物品。</p>
<p>4、根据中国海关总署的规定,旅客在境外购买的物品,在进入中国海关时可能需要征收关税。详细内容见《中华人民共和国海关总署公告2010年第54号文件》。</p>
<p>5、建议出发时行李托运,贵重物品、常用物品、常用药品、御寒衣物等请随身携带,尽量不要托运。行李延误属于不可抗力因素,我司将全力协助客人跟进后续工作,但我司对此不承担任何责任。</p>
</div>
</div>
</div>
<!-- 详情 end -->
<!--引入头部-->
<div id="footer"></div>
<!-- jQuery (necessary for Bootstrap's JavaScript plugins) -->
<script src="js/jquery-3.3.1.js"></script>
<!-- Include all compiled plugins (below), or include individual files as needed -->
<script src="js/bootstrap.min.js"></script>
<!--导入布局js,共享header和footer-->
<script type="text/javascript" src="js/include.js"></script>
<script src="js/getParameter.js"></script>
<script>
$(document).ready(function() {
goImg();
//自动播放
// var timer = setInterval("auto_play()", 5000);
});
function goImg() {
//焦点图效果
//点击图片切换图片
$('.little_img').on('mousemove', function() {
$('.little_img').removeClass('cur_img');
var big_pic = $(this).data('bigpic');
$('.big_img').attr('src', big_pic);
$(this).addClass('cur_img');
});
//上下切换
var picindex = 0;
var nextindex = 4;
$('.down_img').on('click',function(){
var num = $('.little_img').length;
if((nextindex + 1) <= num){
$('.little_img:eq('+picindex+')').hide();
$('.little_img:eq('+nextindex+')').show();
picindex = picindex + 1;
nextindex = nextindex + 1;
}
});
$('.up_img').on('click',function(){
var num = $('.little_img').length;
if(picindex > 0){
$('.little_img:eq('+(nextindex-1)+')').hide();
$('.little_img:eq('+(picindex-1)+')').show();
picindex = picindex - 1;
nextindex = nextindex - 1;
}
});
}
//自动轮播方法
function auto_play() {
var cur_index = $('.prosum_left dd').find('a.cur_img').index();
cur_index = cur_index - 1;
var num = $('.little_img').length;
var max_index = 3;
if ((num - 1) < 3) {
max_index = num - 1;
}
if (cur_index < max_index) {
var next_index = cur_index + 1;
var big_pic = $('.little_img:eq(' + next_index + ')').data('bigpic');
$('.little_img').removeClass('cur_img');
$('.little_img:eq(' + next_index + ')').addClass('cur_img');
$('.big_img').attr('src', big_pic);
} else {
var big_pic = $('.little_img:eq(0)').data('bigpic');
$('.little_img').removeClass('cur_img');
$('.little_img:eq(0)').addClass('cur_img');
$('.big_img').attr('src', big_pic);
}
}
const rname = "#rname";
const routeIntroduce = "#routeIntroduce";
const price = "#price";
const sname= "#sname";
const consphone = "#consphone";
const address = "#address";
const dd= "#dd";
const favorite = "#favorite";
const favoriteCount = "#favoriteCount";
$(()=>{
//1.获取rid
let rid = getParameter("rid");
//2.发送请求请求 route/findOne
$.get("route/findOne",{rid:rid},function(route){
$(rname).html(route.rname);
$(routeIntroduce).html(route.routeIntroduce);
$(price).html(route.price);
$(sname).html(route.sname);
$(consphone).html(route.consphone);
$(address).html(route.address);
//设置收藏次数
$(favoriteCount).html("已收藏"+route.count+"次")
//图片展示
let ddstr = '<a class="up_img up_img_disable"></a>';
//遍历routeImgList
for(let i=0;i<route.routeImgList.length ;i++){
let imgDisplay = i >= 4 ? "display:none" : "display:block";
ddstr +=' <a title="" class="little_img" data-bigpic="'+route.routeImgList[i].bigPic+'" style="'+imgDisplay+'">\n ' +
'<img src="'+route.routeImgList[i].smallPic+'">\n </a>'
}
ddstr += '<a class="down_img down_img_disable" style="margin-bottom: 0;"></a>';
$(dd).html(ddstr);
//图片展示和切换代码调用
goImg();
});
});
$(()=>{
//发送请求,判断用户是否收藏过该线路
let rid = getParameter("rid");
$.get("route/isFavorite",{rid:rid},function (flag){
if (flag){
// 用户已经收藏过
//<a class="btn already" disabled="disabled">
//设置收藏按钮的样式
$(favorite).addClass("already");
//prop只能设置固有属性
// $(favorite).prop("disabled","disabled");
// $(favorite).removeProp("disabled");
$(favorite).attr("disabled","disabled");
// $(favorite).attr()
//删除javascript原生按钮的点击事件
// $(favorite).removeAttr("onclick");
//删除jquery点击事件
$(favorite).unbind("click");
}else {
// 用户没有收藏
};
});
//点击收藏按钮触发的方法
$(favorite).click(function(){
let rid = getParameter("rid");
//1. 判断用户是否登录
$.get("user/findOne",{},function (user){
console.log(user);
if (user){
//用户登录了
//添加功能
$.get("route/addFavorite", {rid: rid}, function () {
//代码刷新页面
//也可以通过异步获取是否被收藏了来局部更新
location.reload();
});
}else {
//用户没有登录
alert("您尚未登录,请登录")
location.href = "http://localhost/travel/login.html"
}
})
})
});
</script>
</body>
</html>
收藏次数的动态展示
前台:
后台:
RouteService
FavoriteDao
点击按钮收藏线路
分析:
编码
前台代码
后台代码
RouteServlet
FavoriteService
FavoriteDao