@TableName("tb_cart")
@Data
@Accessors(chain = true)
public class Cart extends BasePojo{
@TableId(type = IdType.AUTO)
private Long id;
private Long userId;
private Long itemId;
private String itemTitle;
private String itemImage;
private Long itemPrice;
private Integer num;
}
<dependencies>
<dependency>
<groupId>com.jt</groupId>
<artifactId>jt-common</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
</dependencies>
<!--添加插件 有main方法时 需要添加插件-->
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<excludes>
<exclude>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</exclude>
</excludes>
</configuration>
</plugin>
</plugins>
</build>
说明: 当用户点击购物车按钮时,应该跳转到购物车展现页面cart.jsp
url如下: http://www.jt.com/cart/show.html
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;
/**
* 展现购物车列表信息 根据userId查询购物车记录
* url: http://www.jt.com/cart/show.html
* 参数: 根据userId查询购物车数据信息
* 返回值: 购物车展现页面
* 页面取值方式: ${cartList}
*/
@RequestMapping("/show")
public String show(Model model){
long userId = 7L; //暂时写死 后期维护
List<Cart> cartList = cartService.findCartListByUserId(userId);
//利用model对象将数据保存到request对象中
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 queryWrapper = new QueryWrapper();
queryWrapper.eq("user_id", userId);
return cartMapper.selectList(queryWrapper);
}
}
用户如果重复加购? 只做数量的更新
1.页面结构分析
2.加入购物车按钮
<a class="btn-append " id="InitCartUrl" onclick="addCart();" clstag="shangpin|keycount|product|initcarturl">加入购物车<b></b></a>
3.点击事件
//利用post传值
function addCart(){
var url = "http://www.jt.com/cart/add/${item.id}.html";
document.forms[0].action = url; //js设置提交链接
document.forms[0].submit(); //js表单提交
}
4.form表单分析
<form id="cartForm" method="post">
<input class="text" id="buy-num" name="num" value="1" onkeyup="setAmount.modify('#buy-num');"/>
<input type="hidden" class="text" name="itemTitle" value="${item.title }"/>
<input type="hidden" class="text" name="itemImage" value="${item.images[0]}"/>
<input type="hidden" class="text" name="itemPrice" value="${item.price}"/>
</form>
2.4.2 编辑CartController
/**
* 业务说明: 实现用户购物车数据新增
* url: http://www.jt.com/cart/add/1474391990.html
* 参数: 购物车表单提交 Cart对象
* 返回值: 重定向到跳转到购物车展现页面
*
* 扩展内容: 如果restFul的参数,与对象的属性名称一致,则可以直接赋值
*/
@RequestMapping("/add/{itemId}")
public String addCart(Cart cart){
long userId = 7;
cart.setUserId(userId);
cartService.addCart(cart);
return "redirect:/cart/show.html";
}
2.4.3 编辑CartService
/**
* 难点: 用户如果重复加购? 只做数量的更新
* 业务操作:
* 1.根据userId/itemId查询数据库检查是否加购.
* 有值: 已经加购 则只更新数量
* 没有值: 第一次加购 则直接入库即可.
* @param cart
*/
@Override
public void addCart(Cart cart) {
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 = cart.getNum() + cartDB.getNum();
Cart temp = new Cart();
temp.setNum(num).setId(cartDB.getId());
//根据id 更新对象中不为null的数据...
cartMapper.updateById(temp);
}
}
3.1页面分析
1).页面URL分析
2).页面html分析
<div class="quantity-form" data-bind="">
<a href="javascript:void(0);" class="decrement" clstag="clickcart|keycount|xincart|diminish1" id="decrement">-</a>
<input type="text" class="quantity-text" itemPrice="${cart.itemPrice}" itemId="${cart.itemId}" value="${cart.num }" id="changeQuantity-11345721-1-1-0">
<a href="javascript:void(0);" class="increment" clstag="clickcart|keycount|xincart|add1" id="increment">+</a>
</div>
3).页面JS
$(".increment").click(function(){
//+
var _thisInput = $(this).siblings("input");
_thisInput.val(eval(_thisInput.val()) + 1);
$.post("/cart/update/num/"+_thisInput.attr("itemId")+"/"+_thisInput.val(),function(data){
TTCart.refreshTotalPrice();
});
});
/**
* 购物车数量更新操作
* URL地址: http://www.jt.com/cart/update/num/1474391990/16
* 参数: itemId,num
* 返回值: 没有 void
*/
@RequestMapping("/update/num/{itemId}/{num}")
@ResponseBody //将返回值转化为json 代表ajax程序结束
public void updateNum(Cart cart){
long userId = 7;
cart.setUserId(userId);
cartService.updateNum(cart);
}
//sql: update tb_cart set num=#{num},updated=#{updated} where user_id=#{userId} and
// item_id = #{itemId}
@Override
public void updateNum(Cart cart) {
Cart temp = new Cart();
temp.setNum(cart.getNum());
QueryWrapper queryWrapper = new QueryWrapper();
queryWrapper.eq("user_id", cart.getUserId());
queryWrapper.eq("item_id", cart.getItemId());
cartMapper.update(temp,queryWrapper);
}
业务说明: 当用户点击删除按钮时,应该重定向到购物车展现页面.
/**
* URL地址:http://www.jt.com/cart/delete/1474391990.html
* 返回值: String类型
*/
@RequestMapping("/delete/{itemId}")
public String deleteCart(Cart cart){
long userId = 7;
cart.setUserId(userId);
cartService.deleteCart(cart);
return "redirect:/cart/show.html";
}
@Override
public void deleteCart(Cart cart) {
//根据对象中不为null的属性充当where条件
cartMapper.delete(new QueryWrapper<>(cart));
}
当用户在没有登录的条件下,不允许访问敏感业务数据例如购物车/订单业务等…
难点:
1.如何判断用户是否登录? 1.检查cookie 2.检查redis
2.如何控制权限? 拦截器!
配置拦截器
编辑拦截器接口
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 org.springframework.web.servlet.ModelAndView;
import redis.clients.jedis.JedisCluster;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.function.Predicate;
@Component //将对象交给Spring容器管理
public class UserInterceptor implements HandlerInterceptor {
@Autowired
private JedisCluster jedisCluster;
/**
* 通过拦截器实现拦截,重定向系统登录页面
* @param request
* @param response
* @param handler
* @return
* @throws Exception
*
* 返回值说明:
* boolean false 表示拦截 一般配合重定向方式使用
*
* 业务调用:
* 1.获取cookie中的数据
* 2.检查redis中是否有数据
* 3.校验用户是否登录.
*/
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
//1.获取cookie中的数据,检查是否登录
String ticket = CookieUtil.getCookieValue(request, "JT_TICKET");
if(StringUtils.hasLength(ticket) && jedisCluster.exists(ticket)){
//判断数据是否有值
//2.动态获取user信息
String json = jedisCluster.get(ticket);
//3.将json转化为用户对象
User user = ObjectMapperUtil.toObj(json, User.class);
request.setAttribute("JT_USER", user);
return true; //表示程序放行
}
//实现用户重定向
response.sendRedirect("/user/login.html");
return false;
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
request.removeAttribute("JT_USER");
}
}
名称: 本地线程变量
作用: 在同一个线程内,实现数据共享.
package com.jt.util;
import com.jt.pojo.User;
public class UserThreadLocal {
//线程的一个属性 ThreadLocal是线程安全的
private static ThreadLocal<User> threadLocal = new ThreadLocal<>();
public static void set(User user){
threadLocal.set(user);
}
public static User get(){
return threadLocal.get();
}
public static void remove(){
threadLocal.remove(); //删除数据
}
}
1.拦截器赋值
2.用户取值
3.数据销毁
1 -建一个购物车POJO对象
2-使用Dubbo+zk进行jt-web(消费者)和jt-cart(提供者)
3-点击购物车按钮时候,跳转到购物车界面: 根据userId查询购物车数据信息,并把数据渲染到购物车页面
4-添加到购物车:
1) 商品未加购,执行新增操作入库
2) 商品已加购,获取该商品的购物信息,只需要更新数量
控制层CartController代码的实现:
(扩展内容: 如果restFul的参数,与对象的属性名称一致,则可以直接赋值)
@RequestMapping("/add/{itemId}")
public String addCart(Cart cart){
long userId = 7;//后期用localThread维护
cart.setUserId(userId);
cartService.addCart(cart);
return "redirect:/cart/show.html";
}
业务层CartServiceImpl代码的实现:
难点: 用户如果重复加购? 只做数量的更新
业务操作:
1.根据userId/itemId查询数据库检查是否加购.
有值: 已经加购 则只更新数量
没有值: 第一次加购 则直接入库即可.
把前端传过来的cart参数用构造器QueryWrapper进行eq字段比较如下
QueryWrapper<Cart> queryWrapper = new QueryWrapper<>();
queryWrapper.eq("user_id", cart.getUserId());
queryWrapper.eq("item_id", cart.getItemId());
Cart cartDB = cartMapper.selectOne(queryWrapper);//要么是null,说明购物车内未加购过,要么是有数据,说明加购过.
然后进行判断:
if(cartDB == null){ //说明用户第一次加购
cartMapper.insert(cart);
}else{
//说明用户之间添加过该商品 数量的更新
int num = cart.getNum() + cartDB.getNum();
Cart temp = new Cart();
temp.setNum(num).setId(cartDB.getId());
//根据id 更新对象中不为null的数据...
cartMapper.updateById(temp);
}
实现思路:先从本地线程获取到对应的购物车,然后再更新数量就可以
控制层CartController
利用本地线程localThead 获取共享数据即可以获得用户的id,根据userId查询对应的用户购物车,然后直接更新数量
/**
* 购物车数量更新操作
* URL地址: http://www.jt.com/cart/update/num/1474391990/16
* 参数: itemId,num
* 返回值: 没有 void
*/
@RequestMapping("/update/num/{itemId}/{num}")
@ResponseBody //将返回值转化为json 代表ajax程序结束
public void updateNum(Cart cart){
long userId = 7;
cart.setUserId(userId);
cartService.updateNum(cart);
}
编辑CartService
1-重新new一个购物车,获取到数量,
根据控制层的购物车进行数量的更新即可.
//sql: update tb_cart set num=#{num},updated=#{updated} where user_id=#{userId} and
// item_id = #{itemId}
@Override
public void updateNum(Cart cart) {
Cart temp = new Cart();
temp.setNum(cart.getNum());
QueryWrapper queryWrapper = new QueryWrapper();
queryWrapper.eq("user_id", cart.getUserId());
queryWrapper.eq("item_id", cart.getItemId());
cartMapper.update(temp,queryWrapper);
}
当用户在没有登录的条件下,不允许访问敏感业务数据例如购物车/订单业务等…
难点:
1.如何判断用户是否登录? 1.检查cookie 2.检查redis
2.如何控制权限? MVC拦截器!
1、串口、COM口是指的物理接口形式(硬件)。而TTL、RS-232、RS-485是指的电平标准(电信号)。 2、接设备的时候,一般只接GND RX TX。不会接Vcc或者+3.3v的电源线,避免与目标设备上的供电冲突。 3、PL2303、CP2102芯片是 USB 转 TTL串口 的芯片,用USB来扩展串口(TTL电平)。 4、MAX232芯片是 TTL电平与RS2
python difflib模块讲解示例
《Unity3D网络游戏实战》第2章异步代码异步客户端异步代码Async.csusing System;using System.Threading;namespace Async { class MainClass { public static void Main (string[] args) { Timer timer = new Timer(Timeout, null, 2000, 0); Thread.Sleep(2000*2); Console.WriteL
第一步、准备工作 安装系统前要做一些准备工作,首先是制作你要安装的系统的系统镜像。制作系统镜像要先下载一个UltraISO软件。然后右键点击选择“以管理员的身份运行”(注意:必须这样做)。打开后点击左上角的“文件”-—“打开”,找到存放系统镜像的目录,选中系统镜像,然后点击“打开”。然后点击 “启动”—“开始硬盘录入”,然后选择一个U盘作为系统启动盘(注意:这个U盘必须足够大,一般16G的就...
http://www.sandy1219.com/3d/test2/testflabcamera.html package{ import flab3d.FlabCamera3D; import flash.display.Sprite; import flash.display.StageAlign; import flash.display.Stage
virtual int Send( const void* lpBuf, int nBufLen, int nFlags = 0);Dialog中Socket设置AsyncSelect(FD_WRITE),触发虚函数OnSend(),之后调用Send()发送消息。参数lpBuf包含要传输的数据的缓冲区。nBufLen中的数据的长度lpBuf以字节为单位。nFlags...
有没有空(busy)([Ynoi2018]天降之物)给你一个长为 n 的序列 a你需要实现 m 个操作,操作有两种:1.把序列中所有值为 x 的数的值变成 y2.找出一个位置 i 满足 ai==x,找出一个位置 j 满足 aj==y,使得|i-j|最小,并输出|i-j|部分分:二分考虑把整个区间分成两部分,那么这两个数要么都在左边,要么都在右边,要么一左一右。前两种情况可以递归解决,同...
PAT配置 问题 在R1通过PAT配置实现企业内网192.168.0.0/24复用f0/1端口 方案网络拓扑如图-3所示:图-3 步骤实现此案例需要按照如下步骤进行。步骤一:基于端口的PAT配置限制1)删除动态NAT配置tarena-R1(config)#no ip nat inside source list 1tarena-R1(config)#no ip n...
特点:有joinable和detached两种类型的线程。joinable(默认)可以被其他线程回收和杀死,但其存储器、资源不会在显式和隐式退出后被回收。detached不可以被回收和杀死,但其资源会在结束后自动回收。 线程属性可以存在pthread_attr_t类型的变量中,它包含着一个线程可以设置的所有属性,并需要初始化才能使用。同理,互斥锁和条件变量属性使用类pthread_mutexa...
风尚学Webpack-面试篇(4)
一.解决中文不能导入:先说以下没安装之前,正常的解决方法:设置数据库 :vim /etc/my.cnf在[mysqld]下添加:character_set_server=utf8并且在创建zabbix库的时候,设置utf8:create database zabbix character set utf8;以上。然后再说以下已经安装完了出现如下错误的解决方法:导出数据库:...