说明:当用户点击购物车按钮时,应该跳转到购物车列表页面.
页面名称: cart.jsp
页面数据: ${cartList}html
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; }
<?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>
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"; } }
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); } }
1.页面URL分析
2.商品的参数 在url地址中 RESTFul风格.
3.页面JS分析java
/** * 业务描述: * 完成购物车数量的修改操做 * 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); }
/** * 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); }
业务逻辑: 当删除购物车时,应该删除数据库记录,以后将页面重定向到购物车列表页面.web
/** * 实现购物车删除操做 * 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"; }
@Override public void deleteCart(Cart cart) { //userId/itemId cartMapper.delete(new QueryWrapper<>(cart)); //根据对象中不为null的属性当作where条件. }
业务说明: 当购物车点击新增时,须要重定向到购物车列表页面. 完成购物车"新增""
注意事项: 若是用户重复添加购物车.则只作购物车数量的更新,若是购物车没有记录,则新增数据.
2).参数接收ajax
/** * 业务描述: * 实现购物车的新增 * 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"; }
/** * 若是购物车已存在,则更新数量,不然新增. * 如何判断购物车数据是否存在 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); } }
需求: 若是用户不登陆,则不容许访问购物车列表页面,若是没有登陆则应该重定向到用户登陆页面.redis
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/**"); } }
说明:经过拦截器动态获取userIdspring
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(); } }
名称: 本地线程变量
做用: 能够在同一个线程内,实现数据的共享.
![Image \[2\].png](/img/bVcHRC0)数据库
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(); } }
![Image \[3\].png](/img/bVcHRDp)apache
![Image \[4\].png](/img/bVcHRDu)服务器
![Image \[5\].png](/img/bVcHRDv)cookie
![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>
![Image \[7\].png](/img/bVcHREf)
删除orderItem的主键标识
![Image \[8\].png](/img/bVcHREx)
订单项目代码结构以下
![Image \[9\].png](/img/bVcHREC)
![Image \[10\].png](/img/bVcHREG)
![Image \[11\].png](/img/bVcHREV)
![Image \[12\].png](/img/bVcHRFJ)
![Image \[13\].png](/img/bVcHRFL)
![Image \[14\].png](/img/bVcHRF6)
![Image \[15\].png](/img/bVcHRGd)
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"; } }
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)