显示购物车列表
购物车-显示列表-持久层
规划需要执行的SQL语句
显示某用户的购物车列表数据的SQL语句大致是。
SELECT
cid,
uid,
pid,
t_cart.price,
t_cart.num,
t_product.title,
t_product.price AS realPrice,
t_product.image
FROM
t_cart
LEFT JOIN t_product ON t_cart.pid = t_product.id
WHERE
uid = #{uid}
ORDER BY
t_cart.created_time DESC
接口与抽象方法
1.由于涉及多表关联查询,必然没有哪个实体类可以封装此次的查询结果,因此需要创建VO类。创建com.cy.store.vo.CartVO类。
package com.cy.store.vo;
import java.io.Serializable;
/** 购物车数据的Value Object类 */
public class CartVO implements Serializable {
private Integer cid;
private Integer uid;
private Integer pid;
private Long price;
private Integer num;
private String title;
private Long realPrice;
private String image;
// Generate: Getter and Setter、Generate hashCode() and equals()、toString()
}
2.在CartMapper接口中添加抽象方法。
/**
* 查询某用户的购物车数据
* @param uid 用户id
* @return 该用户的购物车数据的列表
*/
List<CartVO> findVOByUid(Integer uid);
配置SQL映射
1.在CartMapper.xml文件中添加findVOByUid()方法的映射。
<!-- 查询某用户的购物车数据:List<CartVO> findVOByUid(Integer uid) -->
<select id="findVOByUid" resultType="com.cy.store.vo.CartVO">
SELECT
cid,
uid,
pid,
t_cart.price,
t_cart.num,
t_product.title,
t_product.price AS realPrice,
t_product.image
FROM
t_cart
LEFT JOIN t_product ON t_cart.pid = t_product.id
WHERE
uid = #{uid}
ORDER BY
t_cart.created_time DESC
</select>
2.在CartMapperTests测试类中添加findVOByUid()方法的测试。
@Test
public void findVOByUid() {
List<CartVO> list = cartMapper.findVOByUid(31);
System.out.println(list);
}
购物车-显示列表-业务层
规划异常
说明:无异常。
接口与抽象方法
在ICartService接口中添加findVOByUid()抽象方法。
/**
* 查询某用户的购物车数据
* @param uid 用户id
* @return 该用户的购物车数据的列表
*/
List<CartVO> getVOByUid(Integer uid);
实现抽象方法
1.在CartServiceImpl类中重写业务接口中的抽象方法。
@Override
public List<CartVO> getVOByUid(Integer uid) {
return cartMapper.findVOByUid(uid);
}
2.在CartServiceTests测试类中添加getVOByUid()测试方法。
@Test
public void getVOByUid() {
List<CartVO> list = cartService.getVOByUid(31);
System.out.println("count=" + list.size());
for (CartVO item : list) {
System.out.println(item);
}
}
购物车-显示列表-控制器
处理异常
说明:无异常。
设计请求
设计用户提交的请求,并设计响应的方式。
请求路径:/carts/
请求参数:HttpSession session
请求类型:GET
响应结果:JsonResult<List<CartVO>>
处理请求
1.在CartController类中编写处理请求的代码。
@GetMapping({"", "/"})
public JsonResult<List<CartVO>> getVOByUid(HttpSession session) {
// 从Session中获取uid
Integer uid = getUidFromSession(session);
// 调用业务对象执行查询数据
List<CartVO> data = cartService.getVOByUid(uid);
// 返回成功与数据
return new JsonResult<List<CartVO>>(OK, data);
}
2.完成后启动项目,先登录再访问http://localhost:8080/carts请求进行测试。
购物车-显示列表-前端页面
1.将cart.html页面的head头标签内引入的cart.js文件注释掉。
<!-- <script src="../js/cart.js" type="text/javascript" charset="utf-8"></script> -->
2.给form标签添加action="orderConfirm.html"属性、tbody标签添加id="cart-list"属性、结算按钮的类型改为type="button"值。如果以上属性值已经添加过无需重复添加。
3.在cart.html页面body标签内的script标签中编写展示购物车列表的代码。
$(document).ready(function() {
showCartList();
});
function showCartList() {
$("#cart-list").empty();
$.ajax({
url: "/carts",
type: "GET",
dataType: "JSON",
success: function(json) {
let list = json.data;
for (let i = 0; i < list.length; i++) {
let tr = '<tr>'
+ '<td>'
+ '<input name="cids" value="#{cid}" type="checkbox" class="ckitem" />'
+ '</td>'
+ '<td><img src="..#{image}collect.png" class="img-responsive" /></td>'
+ '<td>#{title}#{msg}</td>'
+ '<td>¥<span id="price-#{cid}">#{realPrice}</span></td>'
+ '<td>'
+ '<input type="button" value="-" class="num-btn" οnclick="reduceNum(1)" />'
+ '<input id="num-#{cid}" type="text" size="2" readonly="readonly" class="num-text" value="#{num}">'
+ '<input class="num-btn" type="button" value="+" οnclick="addNum(#{cid})" />'
+ '</td>'
+ '<td>¥<span id="total-price-#{cid}">#{totalPrice}</span></td>'
+ '<td>'
+ '<input type="button" οnclick="delCartItem(this)" class="cart-del btn btn-default btn-xs" value="删除" />'
+ '</td>'
+ '</tr>';
tr = tr.replace(/#{cid}/g, list[i].cid);
tr = tr.replace(/#{title}/g, list[i].title);
tr = tr.replace(/#{image}/g, list[i].image);
tr = tr.replace(/#{realPrice}/g, list[i].realPrice);
tr = tr.replace(/#{num}/g, list[i].num);
tr = tr.replace(/#{totalPrice}/g, list[i].realPrice * list[i].num);
if (list[i].realPrice < list[i].price) {
tr = tr.replace(/#{msg}/g, "比加入时降价" + (list[i].price - list[i].realPrice) + "元");
} else {
tr = tr.replace(/#{msg}/g, "");
}
$("#cart-list").append(tr);
}
}
});
}
4.完成后启动项目,先登录再访问http://localhost:8080/web/cart.html页面进行测试。
增加商品数量
购物车-增加商品数量-持久层
规划需要执行的SQL语句
1.首先进行查询需要操作的购物车数据信息。
SELECT * FROM t_cart WHERE cid=?
2.然后计算出新的商品数量值,如果满足更新条件则执行更新操作。此SQL语句无需重复开发。
UPDATE t_cart SET num=?, modified_user=?, modified_time=? WHERE cid=?
接口与抽象方法
在CartMapper接口中添加抽象方法。
/**
* 根据购物车数据id查询购物车数据详情
* @param cid 购物车数据id
* @return 匹配的购物车数据详情,如果没有匹配的数据则返回null
*/
Cart findByCid(Integer cid);
配置SQL映射
1.在CartMapper文件中添加findByCid(Integer cid)方法的映射。
<!-- 根据购物车数据id查询购物车数据详情:Cart findByCid(Integer cid) -->
<select id="findByCid" resultMap="CartEntityMap">
SELECT
*
FROM
t_cart
WHERE
cid = #{cid}
</select>
2.在CartMapperTests测试类中添加findByCid()测试方法。
@Test
public void findByCid() {
Integer cid = 6;
Cart result = cartMapper.findByCid(cid);
System.out.println(result);
}
购物车-增加商品数量-业务层
规划异常
1.如果尝试访问的购物车数据不存在,则抛出CartNotFoundException异常。创建com.cy.store.service.ex.CartNotFoundException类。
/** 购物车数据不存在的异常 */
public class CartNotFoundException extends ServiceException {
// Override Methods...
}
2.如果尝试访问的数据并不是当前登录用户的数据,则抛出AccessDeniedException异常。此异常类无需再次创建。
3.最终执行更新操作时,可能会抛出UpdateException异常。此异常类无需再次创建。
接口与抽象方法
在业务层ICartService接口中添加addNum()抽象方法。
/**
* 将购物车中某商品的数量加1
* @param cid 购物车数量的id
* @param uid 当前登录的用户的id
* @param username 当前登录的用户名
* @return 增加成功后新的数量
*/
Integer addNum(Integer cid, Integer uid, String username);
实现抽象方法
1.在CartServiceImpl类中,实现接口中的抽象方法并规划业务逻辑。
public Integer addNum(Integer cid, Integer uid, String username) {
// 调用findByCid(cid)根据参数cid查询购物车数据
// 判断查询结果是否为null
// 是:抛出CartNotFoundException
// 判断查询结果中的uid与参数uid是否不一致
// 是:抛出AccessDeniedException
// 可选:检查商品的数量是否大于多少(适用于增加数量)或小于多少(适用于减少数量)
// 根据查询结果中的原数量增加1得到新的数量num
// 创建当前时间对象,作为modifiedTime
// 调用updateNumByCid(cid, num, modifiedUser, modifiedTime)执行修改数量
}
2.实现addNum()方法中的业务逻辑代码。
@Override
public Integer addNum(Integer cid, Integer uid, String username) {
// 调用findByCid(cid)根据参数cid查询购物车数据
Cart result = cartMapper.findByCid(cid);
// 判断查询结果是否为null
if (result == null) {
// 是:抛出CartNotFoundException
throw new CartNotFoundException("尝试访问的购物车数据不存在");
}
// 判断查询结果中的uid与参数uid是否不一致
if (!result.getUid().equals(uid)) {
// 是:抛出AccessDeniedException
throw new AccessDeniedException("非法访问");
}
// 可选:检查商品的数量是否大于多少(适用于增加数量)或小于多少(适用于减少数量)
// 根据查询结果中的原数量增加1得到新的数量num
Integer num = result.getNum() + 1;
// 创建当前时间对象,作为modifiedTime
Date now = new Date();
// 调用updateNumByCid(cid, num, modifiedUser, modifiedTime)执行修改数量
Integer rows = cartMapper.updateNumByCid(cid, num, username, now);
if (rows != 1) {
throw new InsertException("修改商品数量时出现未知错误,请联系系统管理员");
}
// 返回新的数量
return num;
}
3.在CartServiceTests测试类中添加addNum()测试方法。
@Test
public void addNum() {
try {
Integer cid = 6;
Integer uid = 31;
String username = "管理员";
Integer num = cartService.addNum(cid, uid, username);
System.out.println("OK. New num=" + num);
} catch (ServiceException e) {
System.out.println(e.getClass().getSimpleName());
System.out.println(e.getMessage());
}
}
购物车-增加商品数量-控制器
处理异常
在BaseController类中添加CartNotFoundException异常类的统一管理。
// ...
else if (e instanceof CartNotFoundException) {
result.setState(4007);
}
// ...
设计请求
设计用户提交的请求,并设计响应的方式。
请求路径:/carts/{cid}/num/add
请求参数:@PathVariable("cid") Integer cid, HttpSession session
请求类型:POST
响应结果:JsonResult<Integer>
处理请求
1.在CartController类中添加处理请求的addNum()方法。
@RequestMapping("{cid}/num/add")
public JsonResult<Integer> addNum(@PathVariable("cid") Integer cid, HttpSession session) {
// 从Session中获取uid和username
Integer uid = getUidFromSession(session);
String username = getUsernameFromSession(session);
// 调用业务对象执行增加数量
Integer data = cartService.addNum(cid, uid, username);
// 返回成功
return new JsonResult<Integer>(OK, data);
}
2.完成后启动项目,先登录再访问http://localhost:8080/carts/6/num/add页面进行测试。
购物车-增加商品数量-前端页面
1.首先确定在showCartList()函数中动态拼接的增加购物车按钮是绑定了addNum()事件,如果已经添加无需重复添加。
<input class="num-btn" type="button" value="+" onclick="addNum(#{cid})" />
2.在script标签中定义addNum()函数并编写增加购物车数量的逻辑代码。
function addNum(cid) {
$.ajax({
url: "/carts/" + cid + "/num/add",
type: "POST",
dataType: "JSON",
success: function(json) {
if (json.state == 200) {
// showCartList();
$("#num-" + cid).val(json.data);
let price = $("#price-" + cid).html();
let totalPrice = price * json.data;
$("#total-price-" + cid).html(totalPrice);
} else {
alert("增加商品数量失败!" + json.message);
}
},
error: function(xhr) {
alert("您的登录信息已经过期,请重新登录!HTTP响应码:" + xhr.status);
location.href = "login.html";
}
});
}
3.完成后启动项目,先登录再访问http://localhost:8080/web/cart.html页面点击“+”按钮进行测试。