SpringBoot part4 day19
1 购物车订单删除
1.1页面分析

1.2 jt-web CartController

@Reference(check=false)private DubboCatService cartService;/*** 删除页面 cart/delete/${cart.itemId}.html* 请求参数:itemId/userId* 返回值结果:重定向到系统首页* */@RequestMapping("/delete/{itemId}")public String doDeleteCard(Cart cart){Long userId = 7L;cart.setUserId(userId);cartService.deleteCart(cart);return "redirect:/cart/show.html";}
1.3 jt-cart DubboCartService
//删除购物车商品信息@Overridepublic void deleteCart(Cart cart) {cartMapper.delete(new QueryWrapper<>(cart));}
1.4购物车权限控制
1.4.1 需求说明
当用户在没有登陆的条件下不允许访问敏感业务,购物车操作/订单操作等 使用拦截器机制
过滤器:过滤url请求,一般不做业务处理
拦截器:在服务器工作前进行拦截,或者服务器返回数据后进行拦截进行数据处理
一共三个拦截:服务器执行之前,服务器返回数据之后,用户拿到数据之前
早期在Xml进行配置,springBoot都是用配置类

1.4.2创建包结构

添加拦截器
package com.jt.interceptor;import com.jt.util.CookieUtil;
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//将拦截器交给spring容器管理
public class UserInterceptor implements HandlerInterceptor {private static final String JT_TICKET="JT_TICKET";@Autowiredprivate JedisCluster jedisCluster;/*** 返回值说明:* 1.false 表示拦截 一般都要配合重定向使用* 2.true 表示放行* 如何实现业务:* 判断用户是否登陆???Cookie数据 检查redis中的数据* 重定向到系统登陆页面* @param request* @param response* @param handler* throws Exception* */@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {//1.检验Cookie中是否有结果Cookie cookie= CookieUtil.getCookie(request, JT_TICKET);//2.校验Cookie是否有效if(cookie!=null){String ticket=cookie.getValue();if(StringUtils.hasLength(ticket)){//校验redis中是否有结果if(jedisCluster.exists(ticket)){//用户存在,直接返回truereturn true;}}//没有结果,cookie中数据有误,需要删除cookieCookieUtil.addCookie(response, JT_TICKET, "", "*", "jt.com", 0);}//3.如果数据为空,重定向到系统首页response.sendRedirect("/user/login.html");return false; //表示拦截}
}
添加拦截器配置

//添加拦截器配置@Autowiredprivate UserInterceptor userInterceptor;@Overridepublic void addInterceptors(InterceptorRegistry registry) {registry.addInterceptor(userInterceptor).addPathPatterns("/cart/**","/order/**");}
1.5 动态获取userId
在拦截其中获取用户信息



package com.jt.interceptor;import com.jt.pojo.User;
import com.jt.util.CookieUtil;
import com.jt.util.ObjectMapperUtil;
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//将拦截器交给spring容器管理
public class UserInterceptor implements HandlerInterceptor {private static final String JT_TICKET="JT_TICKET";@Autowiredprivate JedisCluster jedisCluster;/*** 返回值说明:* 1.false 表示拦截 一般都要配合重定向使用* 2.true 表示放行* 如何实现业务:* 判断用户是否登陆???Cookie数据 检查redis中的数据* 重定向到系统登陆页面* @param request* @param response* @param handler* throws Exception* */@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {//1.检验Cookie中是否有结果Cookie cookie= CookieUtil.getCookie(request, JT_TICKET);//2.校验Cookie是否有效if(cookie!=null){String ticket=cookie.getValue();if(StringUtils.hasLength(ticket)){//校验redis中是否有结果if(jedisCluster.exists(ticket)){//获取user信息String json=jedisCluster.get(ticket);User user= ObjectMapperUtil.toObject(json,User.class);//获取到的对象如何传输?????requestrequest.setAttribute("JT_USER", user);//用户存在,直接返回truereturn true;}}//没有结果,cookie中数据有误,需要删除cookieCookieUtil.addCookie(response, JT_TICKET, "", "*", "jt.com", 0);}//3.如果数据为空,重定向到系统首页response.sendRedirect("/user/login.html");return false; //表示拦截}//为了防止内存泄漏,将多余数据删除@Overridepublic void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {request.removeAttribute("JT_USER");}
}
2 ThreadLocal介绍
本地线程变量
2.1工作原理
作用: 在线程内部(一个线程)实现数据的共享
request 对象只有在@controller表示的类中才能获取
threadLocal没有线程安全问题 作用 : 在线程内部实现数据共享

2.2工具API编辑
jt-web中

package com.jt.util;import com.jt.pojo.User;public class UserThreadLocal {private static ThreadLocal<User> threadLocal=new ThreadLocal<User>();public static void setUser(User user){threadLocal.set(user);}public static User getUser(){return threadLocal.get();}public static void remove(){threadLocal.remove();}}
微服务中Dubbo开启另一个线程执行任务
思考题: JT-WEB中ThreadLocal.set(xxx),问 在jt-cart中的service能否执行ThreadLocal.get()???
A. 不能


由于内存的泄漏,所以对加入ThreadLocal中数据要进行删除
重构拦截器工具API
package com.jt.interceptor;import com.jt.pojo.User;
import com.jt.util.CookieUtil;
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//将拦截器交给spring容器管理
public class UserInterceptor implements HandlerInterceptor {private static final String JT_TICKET="JT_TICKET";@Autowiredprivate JedisCluster jedisCluster;/*** 返回值说明:* 1.false 表示拦截 一般都要配合重定向使用* 2.true 表示放行* 如何实现业务:* 判断用户是否登陆???Cookie数据 检查redis中的数据* 重定向到系统登陆页面* @param request* @param response* @param handler* throws Exception* */@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {//1.检验Cookie中是否有结果Cookie cookie= CookieUtil.getCookie(request, JT_TICKET);//2.校验Cookie是否有效if(cookie!=null){String ticket=cookie.getValue();if(StringUtils.hasLength(ticket)){//校验redis中是否有结果if(jedisCluster.exists(ticket)){//获取user信息String json=jedisCluster.get(ticket);User user= ObjectMapperUtil.toObject(json,User.class);//获取到的对象如何传输?????requestrequest.setAttribute("JT_USER", user);UserThreadLocal.setUser(user);//用户存在,直接返回truereturn true;}}//没有结果,cookie中数据有误,需要删除cookieCookieUtil.addCookie(response, JT_TICKET, "", "*", "jt.com", 0);}//3.如果数据为空,重定向到系统首页response.sendRedirect("/user/login.html");return false; //表示拦截}//为了防止内存泄漏,将多余数据删除@Overridepublic void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {//移除request对象request.removeAttribute("JT_USER");//移除threadLocal数据UserThreadLocal.remove();}
}
对购物车所有功能中的user进行动态获取
package com.jt.controller;import com.alibaba.dubbo.config.annotation.Reference;
import com.jt.pojo.Cart;
import com.jt.pojo.User;
import com.jt.service.DubboCatService;
import com.jt.util.UserThreadLocal;
import com.jt.vo.SysResult;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;import javax.servlet.http.HttpServletRequest;
import java.util.List;@Controller
@RequestMapping("/cart")
public class CartController {@Reference(check=false)private DubboCatService cartService;/*** 删除页面 cart/delete/${cart.itemId}.html* 请求参数:itemId/userId* 返回值结果:重定向到系统首页* */@RequestMapping("/delete/{itemId}")public String doDeleteCard(Cart cart){Long userId= UserThreadLocal.getUser().getId();cart.setUserId(userId);cartService.deleteCart(cart);return "redirect:/cart/show.html";}/**** */@RequestMapping("/add/{itemId}")public String saveCart(Cart cart){Long userId= UserThreadLocal.getUser().getId();cart.setUserId(userId);cartService.saveCart(cart);return "redirect:/cart/show.html";}/*** 购物车商品数量更新操作* 业务需求: 实现商品数量的更新操作* url:http://www.jt.com/cart/update/num/1474391990/10* 参数: userId=7/itemId/num* 返回值: void** 用法: 如果restFul参数名称与对象的属性名称一致,则可以使用对象的方式接收* */@RequestMapping("/update/num/{itemId}/{num}")@ResponseBody//1.将数据用json返回 2.表示ajax请求结束public void doupdateCartNum(Cart cart){Long userId= UserThreadLocal.getUser().getId();cart.setUserId(userId);cartService.updateCartNum(cart);}/*** 展现购物车列表信息* http://www.jt.com/cart/show.html* 参数: 必须获取userId=7L* 返回值:cart.jsp* 页面取值参数${cartList}* */@RequestMapping("/show")public String doFindCart(Model model, HttpServletRequest request){// User user=(User)request.getAttribute("JT_USER");Long userId= UserThreadLocal.getUser().getId(); //暂时写死,后期维护List<Cart> cartList=cartService.findCartList(userId);model.addAttribute("cartList", cartList);return "cart";}}
3 商品订单的实现
3.1订单确认页面的跳转
3.1.1 需求的分析:
页面跳转: order-cart.jsp页面,需要展现商品数据信息,同时有收件人地址信息.
3.1.2jt-web新建OrderController
package com.jt.controller;import com.alibaba.dubbo.config.annotation.Reference;
import com.jt.pojo.Cart;
import com.jt.service.DubboCatService;
import com.jt.util.UserThreadLocal;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;import java.util.List;@Controller
@RequestMapping("/order")
public class OrderController {@Reference(check = false)private DubboCatService cartsrvice;/*** 1.实现订单确认页面跳转* url地址: http://www.jt.com/order/create.html* 参数说明: 获取userId* 返回值结果: 订单确认页面 order-cart.jsp* 页面取值方式: ${carts}*/@RequestMapping("/create")public String doFindOrderCart(Model model){long userId= UserThreadLocal.getUser().getId();;List<Cart> cartList=cartsrvice.findCartList(userId);model.addAttribute("carts", cartList);return "order-cart";}}
测试结果

3.2 创建订单项目
3.2.1订单模块表设计

3.2.2在jt-common中导入pojo对象

package com.jt.pojo;import java.util.Date;
import java.util.List;import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;import lombok.Data;
import lombok.experimental.Accessors;@TableName("tb_order")
@Data
@Accessors(chain=true)
public class Order extends BasePojo{@TableField(exist=false) //入库操作忽略该字段private OrderShipping orderShipping;//封装订单商品信息 一对多@TableField(exist=false) //入库操作忽略该字段private List<OrderItem> orderItems;@TableIdprivate String orderId;private String payment;private Integer paymentType;private String postFee;private Integer status;private Date paymentTime;private Date consignTime;private Date endTime;private Date closeTime;private String shippingName;private String shippingCode;private Long userId;private String buyerMessage;private String buyerNick;private Integer buyerRate;}
package com.jt.pojo;import java.util.Date;
import java.util.List;import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;import lombok.Data;
import lombok.experimental.Accessors;
@TableName("tb_order_item")
@Data
@Accessors(chain=true)
public class OrderItem extends BasePojo{private String itemId;private String orderId;private Integer num;private String title;private Long price;private Long totalFee;private String picPath;
}
package com.jt.pojo;import java.util.Date;
import java.util.List;import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;import lombok.Data;
import lombok.experimental.Accessors;
@TableName("tb_order_shipping")
@Data
@Accessors(chain=true)
public class OrderShipping extends BasePojo{@TableIdprivate String orderId;private String receiverName;private String receiverPhone;private String receiverMobile;private String receiverState;private String receiverCity;private String receiverDistrict;private String receiverAddress;private String receiverZip;}

3.3定义服务提供者jt-order

server:port: 8095servlet:context-path: /
spring:datasource:#引入druid数据源#type: com.alibaba.druid.pool.DruidDataSourcedriver-class-name: com.mysql.jdbc.Driverurl: jdbc:mysql://127.0.0.1:3307/jtdb?serverTimezone=GMT%2B8&useUnicode=true&characterEncoding=utf8&autoReconnect=true&allowMultiQueries=true#url: jdbc:mysql://192.168.126.129:8066/jtdb?serverTimezone=GMT%2B8&useUnicode=true&characterEncoding=utf8&autoReconnect=true&allowMultiQueries=trueusername: rootpassword: rootmvc:view:prefix: /WEB-INF/views/suffix: .jsp
#mybatis-plush配置
mybatis-plus:type-aliases-package: com.jt.pojomapper-locations: classpath:/mybatis/mappers/*.xmlconfiguration:map-underscore-to-camel-case: true#关于Dubbo配置
dubbo:scan:basePackages: com.jt #指定dubbo的包路径application: #应用名称name: provider-order #一个接口对应一个服务名称registry:address: zookeeper://192.168.126.129:2181?backup=192.168.126.129:2182,192.168.126.129:2183protocol: #指定协议name: dubbo #使用dubbo协议(tcp-ip) web-controller直接调用sso-Serviceport: 20883 #每一个服务都有自己特定的端口 不能重复.logging:level: com.jt.mapper: debug
<!--添加依赖--><dependencies><dependency><groupId>com.jt</groupId><artifactId>jt-common</artifactId><version>1.0-SNAPSHOT</version></dependency></dependencies><build><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId></plugin></plugins></build>

3.4SpringMVC参数传递说明
3.4.1简单参数赋值
<input type="text" name="name" value="二郎神">
<input type="text" name="age" value="18">
public void doFindUser(String name,Integer age){}
3.4.2对象赋值
<input type="text" name="name" value="二郎神">
<input type="text" name="age" value="18">
<input type="text" name="sex" value="男">
public void doFindUser(User user){}
3.4.3对象引用赋值
<input type="text" name="name" value="二郎神">
<input type="text" name="age" value="18">
<input type="text" name="name" value="哮天犬">
<input type="text" name="age" value="15">
问题:如果页面中有重名属性
解决方案:利用对象的引用封装
class Dog{private String name;private Integer age;
}
class User{private String name;private Integer age;private Dog dog;
}
<input type="text" name="name" value="二郎神">
<input type="text" name="age" value="18">
<input type="text" name="dog.name" value="哮天犬">
<input type="text" name="dog.age" value="15">
public void doGetUser(User user){}
给list集合传递参数:
class Dog{private String name;private Integer age;
}
class User{private String name;private Integer age;private Dog dog;private List<String> hobbys;
}
<input type="text" name="name" value="二郎神">
<input type="text" name="age" value="18">
<input type="text" name="dog.name" value="哮天犬">
<input type="text" name="dog.age" value="15">
<input type="text" name="hobbys[0]" value="敲代码">
<input type="text" name="hobbys[1]" value="学java">
3.5订单入库的实现
3.5.1 业务分析
1)url

2).页面参数分析

3).页面结构分析


4).POJO对象赋值

5).页面JS分析

表单数据序列化:

OrderController
@Reference(check = false)private DubboOrderService orderService;@RequestMapping("/submit")@ResponseBodypublic SysResult doSubmit(Order order){long userId=UserThreadLocal.getUser().getId();order.setUserId(userId);String orderId=orderService.saveOrder(order);if(StringUtils.hasLength(orderId))return SysResult.success(orderId);return SysResult.fail();}
DubboOrderServiceImpl
package com.jt.service;import com.alibaba.dubbo.config.annotation.Service;
import com.jt.mapper.OrderItemMapper;
import com.jt.mapper.OrderMapper;
import com.jt.mapper.OrderShippingMapper;
import com.jt.pojo.Order;
import com.jt.pojo.OrderItem;
import com.jt.pojo.OrderShipping;
import org.springframework.beans.factory.annotation.Autowired;import java.util.List;@Service(timeout=3000)
public class DubboOrderServiceImpl implements DubboOrderService{@Autowiredprivate OrderMapper orderMapper;@Autowiredprivate OrderItemMapper orderItemMapper;@Autowiredprivate OrderShippingMapper orderShippingMapper;@Override@Transactionalpublic String saveOrder(Order order) {//字符串拼接String orderId=order.getUserId()+""+System.currentTimeMillis();//1.完成订单入库操作order.setOrderId(orderId).setStatus(1);//未付款状态orderMapper.insert(order);//2.订单物流入库OrderShipping orderShipping=order.getOrderShipping();orderShipping.setOrderId(orderId);orderShippingMapper.insert(orderShipping);//3.订单商品的入库List<OrderItem> lists=order.getOrderItems();for (OrderItem orderItem : lists) {orderItem.setOrderId(orderId);orderItemMapper.insert(orderItem);}return orderId;}
}
3.6订单的查询
3.6.1页面分析

编辑OrderController
/*** 实现订单页面的查询* http://www.jt.com/order/success.html?id=71608193982133*页面取值:order对象及封装的两个属性* */@RequestMapping("/success")public String doSuccess(@RequestParam("id") String orderId,Model model){//将id赋值给orderIdOrder order=orderService.findOrderById(orderId);model.addAttribute("order",order);return "success";}
编辑OrderService
@Overridepublic Order findOrderById(String orderId) {//查询订单商品信息QueryWrapper<OrderItem> queryWrapper=new QueryWrapper<>();queryWrapper.eq("order_id", orderId);List<OrderItem> orderItemLists=orderItemMapper.selectList(queryWrapper);//查询物流信息OrderShipping orderShipping=orderShippingMapper.selectById(orderId);//查询订单信息Order order=orderMapper.selectById(orderId);//数据包装order.setOrderItems(orderItemLists).setOrderShipping(orderShipping);return order;}
测试效果:

项目的梳理:

本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!
