共计 12611 个字符,预计需要花费 32 分钟才能阅读完成。
购物车操作
业务剖析
阐明: 当用户点击购物车按钮时, 应该跳转到购物车列表页面.
页面名称: cart.jsp
页面数据: ${cartList}
创立购物 Cart POJO
package com.jt.pojo;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import lombok.experimental.Accessors;
@TableName("tb_cart")
@Data
@Accessors(chain = true)
public class Cart extends BasePojo{@TableId(type = IdType.AUTO) // 主键自增
private Long id; // 购物车 Id 号
private Long userId; // 用户 Id 号
private Long itemId; // 商品 id 号
private String itemTitle; // 商品题目
private String itemImage; // 商品图片信息
private Long itemPrice;
private Integer num;
}
创立 JT-CART 我的项目
创立我的项目
增加继承依赖插件
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<artifactId>jt-cart</artifactId>
<parent>
<artifactId>jt2007</artifactId>
<groupId>com.jt</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<!--3. 依赖工具 API-->
<dependencies>
<dependency>
<groupId>com.jt</groupId>
<artifactId>jt-common</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
</dependencies>
<!--4. 增加 maven 插件 -->
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
购物车我的项目构造
购物车业务实现
购物车列表展示
编辑 CartController
package com.jt.controller;
import com.alibaba.dubbo.config.annotation.Reference;
import com.jt.pojo.Cart;
import com.jt.service.DubboCartService;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import java.util.List;
@Controller
@RequestMapping("/cart")
public class CartController {@Reference(check = false)
private DubboCartService cartService;
/**
* 业务形容: 展示购物车列表页面, 同时查问购物车数据
* url: http://www.jt.com/cart/show.html
* 参数: userId=7L
* 返回值: 页面逻辑名称 cart.jsp
* 页面取值: ${cartList}
*/
@RequestMapping("/show")
public String show(Model model){
Long userId = 7L; // 临时写死
List<Cart> cartList = cartService.findCartListByUserId(userId);
model.addAttribute("cartList",cartList);
return "cart";
}
}
编辑 CartService
package com.jt.service;
import com.alibaba.dubbo.config.annotation.Service;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.jt.mapper.CartMapper;
import com.jt.pojo.Cart;
import org.springframework.beans.factory.annotation.Autowired;
import java.util.List;
@Service(timeout = 3000)
public class DubboCartServiceImpl implements DubboCartService{
@Autowired
private CartMapper cartMapper;
@Override
public List<Cart> findCartListByUserId(Long userId) {QueryWrapper<Cart> queryWrapper = new QueryWrapper<>();
queryWrapper.eq("user_id", userId);
return cartMapper.selectList(queryWrapper);
}
}
页面成果展示
购物车数量的批改
页面 URL 剖析
1. 页面 URL 剖析
2. 商品的参数 在 url 地址中 RESTFul 格调.
3. 页面 JS 剖析
编辑 CartController
/**
* 业务形容:
* 实现购物车数量的批改操作
* url 地址: http://www.jt.com/cart/update/num/1474392004/4
* 参数: restFul 格调
* 返回值: void
*/
@RequestMapping("/update/num/{itemId}/{num}")
@ResponseBody // 让 ajax 程序完结
public void updateNum(Cart cart){//springmvc 针对 restFul 提供的性能 名称和属性统一
Long userId = 7L;
cart.setUserId(userId);
cartService.updateCartNum(cart);
}
编辑 CartService
/**
* Sql: update tb_cart set num=#{num},updated=#{updated}
* where user_id=#{userId} and item_id = #{itemId}
* @param cart
*/
@Override
public void updateCartNum(Cart cart) {Cart cartTemp = new Cart();
cartTemp.setNum(cart.getNum());
QueryWrapper<Cart> queryWrapper = new QueryWrapper<>();
queryWrapper.eq("user_id", cart.getUserId())
.eq("item_id", cart.getItemId());
cartMapper.update(cartTemp,queryWrapper);
}
购物车删除
页面剖析
业务逻辑: 当删除购物车时, 应该删除数据库记录, 之后将页面重定向到购物车列表页面.
编辑 CartController
/**
* 实现购物车删除操作
* 1.url 地址: http://www.jt.com/cart/delete/1474392004.html
* 2. 参数: 1474392004 itemId
* 3. 返回值: String 重定向到列表页面
*/
@RequestMapping("/delete/{itemId}")
public String deleteCart(Cart cart){
Long userId = 7L;
cart.setUserId(userId);
cartService.deleteCart(cart);
return "redirect:/cart/show.html";
}
编辑 CartService
@Override
public void deleteCart(Cart cart) { //userId/itemId
cartMapper.delete(new QueryWrapper<>(cart));
// 依据对象中不为 null 的属性当做 where 条件.
}
购物车新增
业务阐明
业务阐明: 当购物车点击新增时, 须要重定向到购物车列表页面. 实现购物车 ” 新增 ””
注意事项: 如果用户反复增加购物车. 则只做购物车数量的更新, 如果购物车没有记录, 则新增数据.
2). 参数接管
编辑 CartController
/**
* 业务形容:* 实现购物车的新增
* 1.url:http://www.jt.com/cart/add/562379.html
* 2. 参数:num: 1
* itemTitle: 三星 W999 彩色 电信 3G 手机 双卡双待双通
* itemImage: https://img14.360buyimg.com/n0/jfs/t1/125477/20/11441/43547/5f4e2293E02391add/cf8bee33b3ed4394.jpg
* itemPrice: 4299000
* 3. 返回值:String 重定向到购物车页面
*/
@RequestMapping("/add/{itemId}")
public String addCart(Cart cart){Long userId = UserThreadLocal.get().getId();
cart.setUserId(userId);
dubboCartService.addCart(cart);
return "redirect:/cart/show.html";
}
编辑 CartService
/**
* 如果购物车已存在, 则更新数量, 否则新增.
* 如何判断购物车数据是否存在 userId itemId
*
* @param cart
*/
@Override
public void addCart(Cart cart) {
//1. 查问购物车信息 userId,itemId
QueryWrapper<Cart> queryWrapper = new QueryWrapper<>();
queryWrapper.eq("user_id", cart.getUserId());
queryWrapper.eq("item_id",cart.getItemId());
Cart cartDB = cartMapper.selectOne(queryWrapper);
if(cartDB == null){
// 第一次新增购物车
cartMapper.insert(cart);
}else{
// 用户曾经加购, 更新数量
int num = cartDB.getNum() + cart.getNum();
Cart cartTemp = new Cart();
cartTemp.setNum(num).setId(cartDB.getId());
cartMapper.updateById(cartTemp);
}
}
权限管制
需要: 如果用户不登录, 则不容许拜访购物车列表页面, 如果没有登录则应该重定向到用户登录页面.
SpringMVC 调用原理图
拦截器工作原理
编辑拦截器配置
package com.jt.config;
import com.jt.interceptor.UserInterceptor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.PathMatchConfigurer;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration
public class MvcConfigurer implements WebMvcConfigurer{
// 开启匹配后缀型配置
@Override
public void configurePathMatch(PathMatchConfigurer configurer) {configurer.setUseSuffixPatternMatch(true);
}
// 配置拦截器策略
@Autowired
private UserInterceptor userInterceptor;
@Override
public void addInterceptors(InterceptorRegistry registry) {registry.addInterceptor(userInterceptor)
.addPathPatterns("/cart/**","/order/**");
}
}
编辑拦截器
阐明: 通过拦截器动静获取 userId
package com.jt.interceptor;
import com.jt.pojo.User;
import com.jt.util.ObjectMapperUtil;
import com.jt.util.UserThreadLocal;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.springframework.web.servlet.HandlerInterceptor;
import redis.clients.jedis.JedisCluster;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@Component
public class UserInterceptor implements HandlerInterceptor {
@Autowired
private JedisCluster jedisCluster;
/**
* 参数介绍:* @param request 用户申请对象
* @param response 服务器响应对象
* @param handler 以后处理器自身
* @return true:申请放行 false:申请拦挡 个别配合重定向应用
* @throws Exception
*
* 如果用户不登陆则重定向到登陆页面
*
* 判断用户是否登录了?* 根据:1. 依据 cookie 判断
* 2. 判断 redis
*/
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
String ticket = null;
//1. 判断 cookie 中是否有记录
Cookie[] cookies = request.getCookies();
if (cookies !=null && cookies.length>0){for (Cookie cookie:cookies) {if ("JT_TICKET".equals(cookie.getName())){ticket = cookie.getValue();
break;
}
}
}
//2. 判断 cookie 的数据是否无效
if (!StringUtils.isEmpty(ticket)){
//3. 判断 redis
if (jedisCluster.exists(ticket)){String userJSON = jedisCluster.get(ticket);
User user = ObjectMapperUtil.toObject(userJSON, User.class);
//4. 利用 request 对象进行数据传递 request 是最罕用的形式
request.setAttribute("JT_USER", user);
//5. 利用本地线程变量传参(两种形式都能够,第二种更便捷,然而微服务中须要审慎,只在同一线程内无效)UserThreadLocal.set(user);
return true; // 示意用户已登陆 放行
}
}
// 重定向到用户登录页面
response.sendRedirect("/user/login.html");
return false;// 示意拦挡
}
/**
* 为了满足业务须要将数据删除
*/
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {request.removeAttribute("JT_USER");
UserThreadLocal.remove();}
}
ThreadLocal 介绍
ThreadLocal 作用
名称: 本地线程变量
作用: 能够在同一个线程内, 实现数据的共享.
![Image \[2\].png](/img/bVcHRC0)
编辑 ThreadLocal 工具 API
package com.jt.util;
import com.jt.pojo.User;
public class UserThreadLocal{
// 在同一线程内无效
private static ThreadLocal<User> userThreadLocal = new ThreadLocal<>();
// 存值
public static void set(User user){userThreadLocal.set(user);
}
// 取值
public static User get(){return userThreadLocal.get();
}
// 删除
public static void remove(){userThreadLocal.remove();
}
}
重构 User 拦截器
![Image \[3\].png](/img/bVcHRDp)
动静获取 UserId
![Image \[4\].png](/img/bVcHRDu)
京淘订单模块
订单表设计
![Image \[5\].png](/img/bVcHRDv)
创立订单我的项目
创立我的项目
![Image \[6\].png](/img/bVcHRD0)
增加继承依赖
<!-- 继承父级我的项目 -->
<parent>
<artifactId>jt2007</artifactId>
<groupId>com.jt</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<!-- 依赖工具 API-->
<dependencies>
<dependency>
<groupId>com.jt</groupId>
<artifactId>jt-common</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
</dependencies>
<!-- 增加 maven 插件 -->
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
增加 POJO
![Image \[7\].png](/img/bVcHREf)
删除 orderItem 的主键标识
![Image \[8\].png](/img/bVcHREx)
构建 jt-order 我的项目
订单我的项目代码构造如下
![Image \[9\].png](/img/bVcHREC)
订单确认页面跳转
url 剖析
![Image \[10\].png](/img/bVcHREG)
页面成果展示
![Image \[11\].png](/img/bVcHREV)
对于订单提交
页面 URL 阐明
![Image \[12\].png](/img/bVcHRFJ)
申请参数
![Image \[13\].png](/img/bVcHRFL)
订单胜利跳转
页面 url 剖析
![Image \[14\].png](/img/bVcHRF6)
页面成果展示
![Image \[15\].png](/img/bVcHRGd)
编辑 OrderController
package com.jt.controller;
import com.alibaba.dubbo.config.annotation.Reference;
import com.jt.pojo.Cart;
import com.jt.pojo.Order;
import com.jt.service.DubboCartService;
import com.jt.service.DubboOrderService;
import com.jt.util.UserThreadLocal;
import com.jt.vo.SysResult;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import java.util.List;
@Controller
@RequestMapping("/order")
public class OrderController {
@Reference
private DubboCartService dubboCartService;
@Reference
private DubboOrderService dubboOrderService;
/**
* 我的订单页面跳转
* url:http://www.jt.com/order/myOrder.html
* 参数:无
* 返回值:我的订单页面
* 页面数据:*/
@RequestMapping("/myOrder")
public String myOrder(){return "my-orders";}
/**
* 实现订单查问
* url:http://www.jt.com/order/success.html?id=order.getUserId()1605862542149
* 参数:orderId
* 返回值:订单胜利页面
* 页面取值:${order.orderId}
*/
@RequestMapping("/success")
public String success(String id,Model model){Order order = dubboOrderService.findOrderId(id);
model.addAttribute("order", order);
return "success";
}
/**
* 订单提交入库操作
* url:http://www.jt.com/order/submit
* 参数:整个表单对象 order
* 返回值:SysResult 对象(orderId)*/
@RequestMapping("/submit")
@ResponseBody
public SysResult saveOrder(Order order){Long userId =UserThreadLocal.get().getId();
order.setUserId(userId);
String orderId = dubboOrderService.saveOrder(order);
if ((StringUtils.isEmpty(orderId))){return SysResult.fail();
}else {return SysResult.success(orderId);
}
}
/**
* 跳转订单确认页面
* url:http://www.jt.com/order/create.html
* 参数:临时没有
* 返回值:order-cart.jsp
*/
@RequestMapping("/create")
public String create(Model model){Long userId = UserThreadLocal.get().getId();
List<Cart> carts = dubboCartService.findCartListByUserId(userId);
model.addAttribute("carts", carts);
return "order-cart";
}
}
编辑 OrderService
package com.jt.service;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.jt.pojo.Order;
import com.jt.pojo.OrderItem;
import com.jt.pojo.OrderShipping;
import org.springframework.beans.factory.annotation.Autowired;
import com.alibaba.dubbo.config.annotation.Service;
import com.jt.mapper.OrderItemMapper;
import com.jt.mapper.OrderMapper;
import com.jt.mapper.OrderShippingMapper;
import org.springframework.transaction.annotation.Transactional;
import java.util.List;
@Service(timeout = 3000)
public class OrderServiceImpl implements DubboOrderService {
@Autowired
private OrderMapper orderMapper;
@Autowired
private OrderShippingMapper orderShippingMapper;
@Autowired
private OrderItemMapper orderItemMapper;
/**
* 实现三张表的入库
* @param order
* @return
*/
@Override
@Transactional // 管制事务
public String saveOrder(Order order) {
// 订单号:登录用户 id+ 以后工夫戳
String orderId = order.getUserId().toString() + System.currentTimeMillis();
order.setOrderId(orderId).setStatus(1);
orderMapper.insert(order);
OrderShipping orderShipping = order.getOrderShipping();
orderShipping.setOrderId(orderId);
orderShippingMapper.insert(orderShipping);
List<OrderItem> orderItems = order.getOrderItems();
for (OrderItem orderItem:orderItems){orderItem.setOrderId(orderId);
orderItemMapper.insert(orderItem);
}
return orderId;
}
// 须要通过 order 对象 返回三局部数据
@Override
public Order findOrderId(String id) {Order order = orderMapper.selectById(id);
OrderShipping orderShipping = orderShippingMapper.selectById(id);
QueryWrapper queryWrapper = new QueryWrapper();
queryWrapper.eq("order_id", id);
List<OrderItem> orderItems = orderItemMapper.selectList(queryWrapper);
order.setOrderShipping(orderShipping).setOrderItems(orderItems);
return order;
}
}
我的项目结构图
![Image \[16\].png](/img/bVcHRGp)