共计 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)