一,数据库表的设计
-- 购物车表
-- 每个用户都有一个购物车
drop table if exists t_shopcar;
create table t_shopcar(
uid int,
bid int,
num int,-- 同种商品的数量
`status` tinyint(4) default 1,-- 1:正常,0:禁用,-1:删除
create_time timestamp default current_timestamp,-- 记录创建时间,时间戳,在创建新纪录时吧这个字段值设置为当前时间,但以后修改时不再更新它
update_time timestamp on update current_timestamp,-- 记录更新时间,时间戳,在创建新纪录时吧这个字段值设为0,但以后修改的时候更新为当前的时间戳
-- foreign key(uid) references t_user(id),
foreign key (uid) references t_user(id) on update cascade on delete cascade,
foreign key(bid) references t_book(id)
);
mysql> desc t_shopcar;
+-------------+------------+------+-----+---------------------+-----------------------------+
| Field | Type | Null | Key | Default | Extra |
+-------------+------------+------+-----+---------------------+-----------------------------+
| uid | int(11) | YES | MUL | NULL | |
| bid | int(11) | YES | MUL | NULL | |
| num | int(11) | YES | | NULL | |
| status | tinyint(4) | YES | | 1 | |
| create_time | timestamp | NO | | CURRENT_TIMESTAMP | |
| update_time | timestamp | NO | | 0000-00-00 00:00:00 | on update CURRENT_TIMESTAMP |
+-------------+------------+------+-----+---------------------+-----------------------------+
这里的create_time和update_time不用插入,会自动将当前时间插入
select * from t_shopcar order by update_time desc;
+------+------+------+--------+---------------------+---------------------+
| uid | bid | num | status | create_time | update_time |
+------+------+------+--------+---------------------+---------------------+
| 9 | 8 | 9 | NULL | 2019-02-13 15:21:42 | 2019-02-13 22:45:50 |
| 9 | 16 | 13 | NULL | 2019-02-12 19:07:50 | 2019-02-13 22:30:33 |
| 9 | 18 | 5 | NULL | 2019-02-13 17:07:11 | 2019-02-13 22:14:16 |
| 9 | 15 | 2 | NULL | 2019-02-13 14:46:33 | 2019-02-13 14:49:31 |
| 9 | 3 | 1 | 1 | 2019-02-12 13:56:06 | 2019-02-12 13:56:06 |
+------+------+------+--------+---------------------+---------------------+
二,加入购物车
1. sql查询的问题
在加入购物车时需要先查询购物车之前是否已存在这种商品。如果以存在就在之前的基础上更新它的num值。
不存在的话就直接插入。
在查询购物车中的商品时,需要根据uid进行查询,再根据bid(商品id)进行分组,统计同种商品的件数,也就是统计组内的数量,最后再根据update_time进行降序排列。
(其实这点是之前没有想好,如果在加入购物车之前已经查询是否存在这种商品那么uid和bid就是唯一的了,就不存在重复的情况了,也就不用再根据bid进行分组统计同种商品的件数了。算是又练习了一下sql。)
mysql> select T.uid,T.bid,sum(T.num) as bid_count,T.status,T.update_time,T.create_time from (select uid,bid,num,status,update_time,create_time from t_shopcar where uid=9) as T group by bid order by update_time desc;
+------+------+-----------+--------+---------------------+---------------------+
| uid | bid | bid_count | status | update_time | create_time |
+------+------+-----------+--------+---------------------+---------------------+
| 9 | 8 | 9 | NULL | 2019-02-13 22:45:50 | 2019-02-13 15:21:42 |
| 9 | 16 | 13 | NULL | 2019-02-13 22:30:33 | 2019-02-12 19:07:50 |
| 9 | 18 | 5 | NULL | 2019-02-13 22:14:16 | 2019-02-13 17:07:11 |
| 9 | 15 | 3 | NULL | 2019-02-13 14:49:31 | 2019-02-13 14:46:33 |
| 9 | 3 | 1 | 1 | 2019-02-12 13:56:06 | 2019-02-12 13:56:06 |
| 9 | 2 | 2 | 1 | 0000-00-00 00:00:00 | 2019-02-12 15:00:34 |
+------+------+-----------+--------+---------------------+---------------------+
MyBatis插入时间为0000-00-00 00:00:00这种情况时会出现异常需要在jdbc.url上加入zeroDateTimeBehavior=convertToNull
jdbc.url=jdbc:mysql://localhost:3306/book_ssm_db?characterEncoding=UTF8&useSSL=false&serverTimezone=UTC&zeroDateTimeBehavior=convertToNull
2. 点击加入购物车时的页面跳转问题。
<br/>数量:<input type="button" value="-" onclick="subShop()"/>
<input type="text" id="shopCount" size="2" value="1"/>
<input type="button" value="+" onclick="addShop()"/>
................................................................
<input type="hidden" value="${book.id}" id="bid"/>
<input type="hidden" value="${user.id}" id="uid">
在点击加入购物车时需要将bid和text框中的商品数量shopCount添加到购物车中,
shopCount的值需要在text框中获取,所以需要通过js的方式在点击添加到购物车这个按钮时时触发js函数得到shopCount的值,然后在js函数中通过ajax将shopCount的值作为num,还要把bid(图书id)传给后台的action。
addLabel.js
function addShop(){
var count=$("#shopCount").val();
$("#shopCount").html($("#shopCount").val(++count));
}
function subShop(){
var count=$("#shopCount").val();
if (count>1){
$("#shopCount").html($("#shopCount").val(--count));
}
}
但是如果用户在未登录的情况下将商品(图书)加入到购物车时addToCar就会被未登录的拦截器拦截,ajax请求无法完成,拦截器拦截了请求却跳不过去,无法跳转到登录页面,被僵在这里了。
(如果不用ajax请求,拦截器的跳转是正常的)
所以暂时想到的就是将跳转到登录页面这个请求放到js里面去做。
addLabel.js
function addToCar(){
var count=$("#shopCount").val();
var bid=$("#bid").val();
var uid=$("#uid").val();
if (uid==null||uid==""){
//在原有窗口打开
window.location.href = "toLogin";
// window.open("toLogin");在新窗口中打开
}
else {
$.ajax({
type : "post",
url : "addToCar",// 后台的action
data : {
num : count,
bid : bid,
uid : uid
},
dataType : "json",
success : success_function
});
}
}
function success_function(data){
//这里的data是服务器从后端返回的结果
alert(typeof(data.res));
alert("data"+data.res);
// var sta=data.res.substring(0,data.res.lastIndexOf("="));
// var end=data.res.substring(data.res.indexOf("="),data.res.length);
// alert("sta"+sta.toString()+"end"+end.toString());
window.location.href=data.res+data.bid;
// alert(${pageContext.request.contextPath}+"/WEB-INF/content/"+data.toString()+".jsp");
// var localObj = window.location; //这个的意思是获取当前页面的地址
// var protocol = location.protocol ;//获取http或https
// var host = localObj.host;// 获取JSP地址栏IP和端口号 //localhost:8080
// var contextPath = localObj.pathname.split("/")[1]; //获取项目名
// var basePath = protocol +"//"+host+"/"+contextPath;
//http://localhost:8081/bookDetail/WEB-INF/content/car/addSuccess.jsp
// window.location.href=basePath.toString()+"/WEB-INF/content/"+data.toString()+".jsp";
return true;
}
但是添加到购物车之后,由于是ajax请求所以后台的action返回的逻辑地址无法正常跳转。本来想在js中的ajax回调函数中用
window.location.href=${pageContext.request.contextPath}+"/WEB-INF/content/"+data.toString()+".jsp";
但是报错,{用不了,js中没法用${}
又改成
// var localObj = window.location; //这个的意思是获取当前页面的地址
// var protocol = location.protocol ;//获取http或https
// var host = localObj.host;// 获取JSP地址栏IP和端口号 //localhost:8080
// var contextPath = localObj.pathname.split("/")[1]; //获取项目名
// var basePath = protocol +"//"+host+"/"+contextPath;
//http://localhost:8081/bookDetail/WEB-INF/content/car/addSuccess.jsp
// window.location.href=basePath.toString()+"/WEB-INF/content/"+data.toString()+".jsp";
地址试了好多遍还是不对。
想在后台的action中直接用请求转发跳转的,这样还是同一个request要传递的数据也不会丢,但是地址还是不对。。。
这种方式放弃了。
然后又改,将要跳转的地址和参数都放到map中在回调函数中取出来。
map.put("res","addSuccess?bid="+tShopCar.getBid());
window.location.href=data.res
之前res写的是result,结果在Js中data.result的时候type还有值都是undefined,和js中的函数冲突了。
但是改了之后浏览器里面控制台还是500
百度,再百度
结果是 window.location.href传参的问题
不能写成
window.location.href=“addSuccess?bid=5” 这种
一定要把地址和参数分开写
window.location.href=“addSuccess?bid=”+“5”
然后又改
把data.res的地址和参数分割开。
// var sta=data.res.substring(0,data.res.lastIndexOf("="));
// var end=data.res.substring(data.res.indexOf("="),data.res.length);
// alert("sta"+sta.toString()+"end"+end.toString());
window.location.href=sta+end;
但是sta和end的值莫名其妙,是数字。
算了,还是改后台的action吧。
map.put("bid",tShopcar.getBid().toString());
map.put("res","carbookDetail?bid=");
map.put("res","addSuccess?bid="+tShopCar.getBid());
这下终于成功了,改了一天再不成功我怕是真的要被气晕过去了。
@Controller
public class CarController {
@Autowired
private ICarService carService;
@Autowired
private IBookService bookService;
//Ajax方式请求后台时,未登录访问购物车被拦截,ajax请求失败,但是一直在请求?所以被拦截之后拦截器无法跳转到登录页面
@ResponseBody//将函数返回值作为请求返回值,没有这个注解的话,请求的响应应该是一个页面,不需要页面的话应该加上这个注解。
@RequestMapping(value = "addToCar",method = RequestMethod.POST)
public Map<String,String> addToCar(TShopcar tShopcar, Model model, HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
System.out.println("-----addToCar-----"+tShopcar);
Map<String,String> map=new HashMap<String,String>();
map.put("bid",tShopcar.getBid().toString());
if(carService.addBook(tShopcar.getUid(),tShopcar.getBid(),tShopcar.getNum())){
//网站端跳转到添加成功的页面,如果是手机端不用跳转
// request.getRequestDispatcher(request.getContextPath()+"/WEB-INF/content/car/addSuccess.jsp").forward(request, response);
map.put("res","addSuccess?bid=");
// return "addSuccess";
}
else {
//添加失败,购物车已满!
// request.getRequestDispatcher(request.getContextPath()+"/WEB-INF/content/book/bookDetail.jsp").forward(request, response);
// return "bookDetail";
map.put("res","carbookDetail?bid=");
}
System.out.println("carController addToCar map===>"+map.get("res"));
return map;
}
@RequestMapping(value = "addSuccess",method=RequestMethod.GET)
public String addSuccess(int bid,Model model){
TBook book=bookService.selectBookById(bid);
model.addAttribute("book",book);
// List<TShopcar> bookList=carService.QueryCar(tShopcar.getUid());
// model.addAttribute("shopCount",bookList.size());
return "car/addSuccess";
}
@RequestMapping(value = "carbookDetail",method=RequestMethod.GET)
public String addFail(int bid,Model model){
TBook book=bookService.selectBookById(bid);
model.addAttribute("book",book);
return "book/bookDetail";
}
@RequestMapping(value = "queryCar",method = RequestMethod.GET)
public String queryCar(int uid,Model model){
List<TShopcar> bookInCar=carService.QueryCar(uid);
//查出TShopcar需要用到的属性有num即商品的件数,还有bid,需要根据bid去查找出对应的book
//<书,书的件数>
Map shopCarList=new HashMap<TBook,Integer>();
for (TShopcar shopcar:bookInCar){
shopCarList.put(bookService.selectBookById(shopcar.getBid()),shopcar.getNum());
}
model.addAttribute("shopcarList",shopCarList);
return "car/shopcarList";
}
}