SSM商城项目(十三)
1. 学习计划
1、订单系统
2、提交订单
3、MyCAT
2. 订单系统
2.1. 功能分析
1、在购物车页面点击“去结算”按钮跳转到订单确认页面。
a) 展示商品列表
b) 配送地址列表
c) 选择支付方式
2、展示订单确认页面之前,应该确认用户身份。
a) 使用拦截器实现。
b) Cookie中取token
c) 取不到token跳转到登录页面
d) 取到token,根据token查询用户信息。
e) 如果没有用户信息,登录过期跳转到登录页面
f) 取到用户信息,放行。
3、提交订单
a) 生成订单
b) 展示订单提交成功页面。
订单系统系统:订单确认页面、订单提交成功页面。
订单服务系统
2.2. 工程搭建
创建一个订单服务系统:
e3-order
|--e3-order-interface(jar)
|--e3-order-Service(war)
e3-order-web(war)
导入静态页面
2.3. 展示订单确认页面
2.3.1. 功能分析
1、在购物车页面点击“去结算”按钮跳转到订单确认页面。
2、请求的url:
/order/order-cart
3、参数:没有参数。
4、购物车商品数据从cookie中取出来的。可以在订单系统中取到cookie中的购物车数据。
5、配送地址列表,需要用户登录。需要根据用户id查询收货地址列表。静态数据。
6、支付方式。静态数据。
7、返回值:逻辑视图String,展示订单确认页面。
2.3.2. Dao层、Service层(没有)
引入其他工程接口即可。
2.3.3. 表现层
引入服务
<dubbo:reference interface="cn.e3mall.car.service.CartService" id="cartService" />
@Controller
public class OrderController { @Autowired
private CartService cartService; @RequestMapping("/order/order-cart")
public String showOrderCart(HttpServletRequest request){
//取用户id
TbUser user= (TbUser) request.getAttribute("user");
//根据用户id取收货地址列表
//使用静态数据。。。
//取支付方式列表
//静态数据
//根据用户id取购物车列表
List<TbItem> cartList = cartService.getCartList(user.getId());
//把购物车列表传递给jsp
request.setAttribute("cartList", cartList);
return "order-cart";
}
}
2.4. 用户身份认证
在展示订单确认页面之前,需要对用户身份进行认证,要求用户必须登录。
2.4.1. 功能分析
1、使用springmvc的拦截器实现。需要实现一个接口HandlerInterceptor接口。
2、业务逻辑
a) 从cookie中取token。
b) 没有token,需要跳转到登录页面。
c) 有token。调用sso系统的服务,根据token查询用户信息。
d) 如果查不到用户信息。用户登录已经过期。需要跳转到登录页面。
e) 查询到用户信息。放行。
3、在springmvc.xml中配置拦截器。
2.4.2. 拦截器实现
springmvc.xml
<mvc:interceptors>
<mvc:interceptor>
<mvc:mapping path="/**"/>
<bean class="cn.e3mall.order.interceptor.LoginInterceptor"></bean>
</mvc:interceptor>
</mvc:interceptors>
LoginInterceptor.java
public class LoginInterceptor implements HandlerInterceptor{
@Autowired
private TokenService tokenService;
@Autowired
private CartService cartService; @Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
//从cookie中取token
String token=CookieUtils.getCookieValue(request, "token");
//判断token是否存在
if(StringUtils.isBlank(token)){
//如果token不存在,跳转到登录页面
response.sendRedirect("http://localhost:8089/page/login?redirect="+request.getRequestURL());
//拦截
return false;
}
//如果token存在,根据token取用户信息
E3Result e3Result = tokenService.getUserByToken(token);
//如果取不到,表示已经过期,需要重新登录
if(e3Result.getStatus()!=200){
//如果token不存在,跳转到登录页面
response.sendRedirect("http://localhost:8089/page/login?redirect="+request.getRequestURL());
//拦截
return false;
}
//如果取到,已经登录,把用户信息写入request
TbUser user = (TbUser) e3Result.getData();
request.setAttribute("user", user);
//判断cookie中是否有购物车数据,如果有就合并
String string = CookieUtils.getCookieValue(request, "car",true);
if(StringUtils.isNoneBlank(string)){
cartService.mergeCart(user.getId(), JsonUtils.jsonToList(string, TbItem.class));
}
//放行
return true;
} @Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
ModelAndView modelAndView) throws Exception {
// TODO Auto-generated method stub } @Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
throws Exception {
// TODO Auto-generated method stub }
}
2.4.3. 实现sso系统的回调
3. 提交订单
3.1. 功能分析
1、在订单确认页面点击“提交订单”按钮生成订单。
2、请求的url:/order/create
3、参数:提交的是表单的数据。保存的数据:订单、订单明细、配送地址。
a) 向tb_order中插入记录。
- 订单号需要手动生成。
要求订单号不能重复。
订单号可读性号。
可以使用redis的incr命令生成订单号。订单号需要一个初始值。
- Payment:表单数据
- payment_type:表单数据
- user_id:用户信息
- buyer_nick:用户名
- 其他字段null
b) 向tb_order_item订单明细表插入数据。
- Id:使用incr生成
- order_id:生成的订单号
- 其他的都是表单中的数据。
c) tb_order_shipping,订单配送信息
- order_id:生成的订单号
- 其他字段都是表单中的数据。
d) 使用pojo接收表单的数据。
可以扩展TbOrder,在子类中添加两个属性一个是商品明细列表,一个是配送信息。
把pojo放到e3-order-interface工程中。
public class OrderInfo extends TbOrder implements Serializable{
private List<TbOrderItem> orderItems;
private TbOrderShipping orderShipping; public List<TbOrderItem> getOrderItems() {
return orderItems;
}
public void setOrderItems(List<TbOrderItem> orderItems) {
this.orderItems = orderItems;
}
public TbOrderShipping getOrderShipping() {
return orderShipping;
}
public void setOrderShipping(TbOrderShipping orderShipping) {
this.orderShipping = orderShipping;
} }
业务逻辑:
1、接收表单的数据
2、生成订单id
3、向订单表插入数据。
4、向订单明细表插入数据
5、向订单物流表插入数据。
6、返回e3Result。
3.2. Dao层
可以使用逆向工程。
3.3. Service层
参数:OrderInfo
返回值:e3Result
@Service
public class OrderServiceImpl implements OrderService{ @Autowired
private TbOrderMapper orderMapper;
@Autowired
private TbOrderItemMapper orderItemMapper;
@Autowired
private TbOrderShippingMapper orderShippingMapper;
@Autowired
private JedisClient jedisClient; @Override
public E3Result createOrder(OrderInfo orderInfo) {
// 生成订单号
if(!jedisClient.exists("ORDER_ID_GEN")){
jedisClient.set("ORDER_ID_GEN","11500");
}
String orderId = jedisClient.incr("ORDER_ID_GEN").toString();
//补全orderInfo属性
orderInfo.setOrderId(orderId);
//1、未付款,2、已付款,3、未发货,4、已发货,5、交易成功,6、交易关闭
orderInfo.setStatus(1);
Date date = new Date();
orderInfo.setCreateTime(date);
orderInfo.setUpdateTime(date);
//插入订单表
orderMapper.insert(orderInfo);
//向订单明细表插入数据
List<TbOrderItem> orderItems = orderInfo.getOrderItems();
for (TbOrderItem tbOrderItem : orderItems) {
//生成明细id
Long orderItemId = jedisClient.incr("ORDER_ITEM_ID_GEN");
tbOrderItem.setId(orderItemId.toString());
tbOrderItem.setOrderId(orderId);
//插入数据
orderItemMapper.insert(tbOrderItem);
}
//向订单物流表插入数据
TbOrderShipping orderShipping = orderInfo.getOrderShipping();
orderShipping.setOrderId(orderId);
orderShipping.setCreated(date);
orderShipping.setUpdated(date);
orderShippingMapper.insert(orderShipping);
//返回
return E3Result.ok(orderId);
} }
发布服务
<dubbo:service interface="cn.e3mall.order.service.OrderService" ref="orderServiceImpl" timeout="600000"/>
3.4. Controller
引用服务
<dubbo:reference interface="cn.e3mall.order.service.OrderService" id="orderService" />
请求的url:/order/create
参数:使用OrderInfo接收
返回值:逻辑视图。
@RequestMapping(value="/order/create", method=RequestMethod.POST)
public String createOrder(OrderInfo orderInfo, HttpServletRequest request) {
// 取用户信息
TbUser user = (TbUser) request.getAttribute("user");
// 把用户信息添加到orderInfo中
orderInfo.setUserId(user.getId());
orderInfo.setBuyerNick(user.getUsername());
// 调用Service创建订单。
E3Result result = orderService.createOrder(orderInfo);
//如果订单生成成功,需要删除购物车
if(result.getStatus()==200){
cartService.clearCartItem(user.getId());
}
//把订单号传递给页面
request.setAttribute("orderId", result.getData());
request.setAttribute("payment", orderInfo.getPayment());
// 返回逻辑视图展示成功页面
return "success";
}
调用CartServiceImpl.java
//清空购物车
@Override
public E3Result clearCartItem(long userId) {
jedisClient.del("Cart:" + userId);
return E3Result.ok();
}
4. MyCAT介绍
4.1. 什么是MyCAT?
简单的说,MyCAT就是:
一个彻底开源的,面向企业应用开发的“大数据库集群”
支持事务、ACID、可以替代Mysql的加强版数据库
一个可以视为“Mysql”集群的企业级数据库,用来替代昂贵的Oracle集群
一个融合内存缓存技术、Nosql技术、HDFS大数据的新型SQL Server
结合传统数据库和新型分布式数据仓库的新一代企业级数据库产品
一个新颖的数据库中间件产品
MyCAT的目标是:低成本的将现有的单机数据库和应用平滑迁移到“云”端,解决数据存储和业务规模迅速增长情况下的数据瓶颈问题。
4.2. MyCAT的关键特性
支持 SQL 92标准
支持Mysql集群,可以作为Proxy使用
支持JDBC连接ORACLE、DB2、SQL Server,将其模拟为MySQL Server使用
支持galera for mysql集群,percona-cluster或者mariadb cluster,提供高可用性数据分片集群
自动故障切换,高可用性
支持读写分离,支持Mysql双主多从,以及一主多从的模式
支持全局表,数据自动分片到多个节点,用于高效表关联查询
支持独有的基于E-R 关系的分片策略,实现了高效的表关联查询
多平台支持,部署和实施简单
4.3. MyCAT架构
如图所示:MyCAT使用Mysql的通讯协议模拟成了一个Mysql服务器,并建立了完整的Schema(数据库)、Table (数据表)、User(用户)的逻辑模型,并将这套逻辑模型映射到后端的存储节点DataNode(MySQL Instance)上的真实物理库中,这样一来,所有能使用Mysql的客户端以及编程语言都能将MyCAT当成是Mysql Server来使用,不必开发新的客户端协议。
5. Mycat解决的问题
l 性能问题
l 数据库连接过多
l E-R分片难处理
l 可用性问题
l 成本和伸缩性问题
5.1. Mycat对多数据库的支持
6. 分片策略
MyCAT支持水平分片与垂直分片:
水平分片:一个表格的数据分割到多个节点上,按照行分隔。
垂直分片:一个数据库中多个表格A,B,C,A存储到节点1上,B存储到节点2上,C存储到节点3上。
MyCAT通过定义表的分片规则来实现分片,每个表格可以捆绑一个分片规则,每个分片规则指定一个分片字段并绑定一个函数,来实现动态分片算法。
1、Schema:逻辑库,与MySQL中的Database(数据库)对应,一个逻辑库中定义了所包括的Table。
2、Table:表,即物理数据库中存储的某一张表,与传统数据库不同,这里的表格需要声明其所存储的逻辑数据节点DataNode。在此可以指定表的分片规则。
3、DataNode:MyCAT的逻辑数据节点,是存放table的具体物理节点,也称之为分片节点,通过DataSource来关联到后端某个具体数据库上
4、DataSource:定义某个物理库的访问地址,用于捆绑到Datanode上
SSM商城项目(十三)的更多相关文章
- SSM商城项目(一)
1. 学习计划 1.电商行业的背景. 2.宜立方商城介绍 3.宜立方商城的系统架构 a) 功能介绍 b) 架构讲解 4.工程搭建-后台工程 a) 使用maven搭建工程 b) 使用maven的tomc ...
- SSM商城项目(四)
1. 学习计划 1.图片服务器 2.图片服务器安装 3.图片服务器的使用 4.图片上传功能 5.富文本编辑器的使用方法 6.商品添加功能实现 2. 图片服务器 1.存储空间可扩展. 2.提供一个统一的 ...
- SSM商城项目(二)
1. 学习计划 1.将工程改造为基于SOA架构 2.商品列表查询功能实现. 2. 将工程改造为SOA架构 2.1. 分析 由于商城是基于soa的架构,表现层和服务层是不同的工程.所以要实现商品列表查询 ...
- SSM商城项目(五)
1. 学习计划 1.前台系统搭建 2.商城首页展示 3.Cms系统的实现 a) 内容分类管理 b) 内容管理 4.前台内容动态展示 2. 商城首页展示 2.1. ...
- SSM商城项目(十二)
1. 学习计划 1.购物车实现 2.未登录状态下使用购物车 3.登录状态下使用购物车 2. 购物车的实现 2.1. 功能分析 1.购物车是一个独立的表现层工程. 2.添加购物车不要求登录.可以 ...
- SSM商城项目(十一)
1. 学习计划 1.sso注册功能实现 2.sso登录功能实现 3.通过token获得用户信息 Ajax跨域请求(jsonp) 2. Sso系统工程搭建 需要创建一个sso服务工程,可以参考e ...
- SSM商城项目(十)
1. 学习计划 1.使用freemarker实现网页静态化 a)Freemarker的使用方法 b)Freemarker模板的语法 c)Freemarker整合springmvc 2.Active ...
- SSM商城项目(九)
1. 学习计划 1.Activemq整合springMQ的应用场景 2.添加商品同步索引库 3.商品详情页面动态展示 4.展示详情页面使用缓存 2. Activemq整合spring 2.1. ...
- SSM商城项目(八)
1. 学习计划 1.solr集群搭建 2.使用solrj管理solr集群 3.把搜索功能切换到集群版 4.添加商品同步到索引库 2. 什么是SolrCloud SolrCloud(solr 云 ...
随机推荐
- Git从库中移除已删除大文件
写在前面大家一定遇到过在使用Git时,不小心将一个很大的文件添加到库中,即使删除,记录中还是保存了这个文件.以后不管是拷贝,还是push/pull都比较麻烦.今天在上传工程到github上,发现最大只 ...
- C#中Dispose,finalize,GC,析构函数区别
释放类所使用的未托管资源的两种方式: 1.利用运行库强制执行的析构函数,但析构函数的执行是不确定的,而且,由于垃圾收集器的工作方式,它会给运行库增加不可接受的系统开销. 2.IDisposable接 ...
- Thread.Abort 方法
[SecurityPermissionAttribute(SecurityAction.Demand, ControlThread = true)] public void Abort() 在调用此方 ...
- linux远程windows桌面
rdesktop,例子如下,-f为全屏,-a为颜色设置 rdesktop -f -a 32 192.168.88.235
- git 本地修改、撤消操作
// 撤消本地文件的修改,还原到最近版本 git checkout -- * 是撤销从上次提交之后所做的所有修改 git checkout -- <filaname> 是撤销从上次提交之后 ...
- Struts2国际化学习笔记
今天在家里学习了Struts2中的国际化技术,国际化技术其实我的理解就是同一个网站项目或者同一个网页能够自由切换或者自适应本地语言,并根据本地语言进行网页展示. 实现Struts2中的国际化的方法是: ...
- python3学习笔记九(if语句)
# !/usr/bin/python3 斐波那数列,两个元素的总和确定下一个数a,b = 0,1while b < 1000: print(b,end=',') a, b = b, a+bpri ...
- note 8 字符串
字符串String 一个字符的序列 使用成对的单引号或双引号括起来 或者三引号""" 和 ''' 表示块注释 字符串运算 长度 len()函数 first_name = ...
- CentOS 7下Samba服务安装与配置详解
1. Samba简介 Samba是在Linux和UNIX系统上实现SMB协议的一个免费软件,由服务器及客户端程序构成.SMB(Server Messages Block,信息服务块)是一种在局域网上共 ...
- WinForm控件--DotNetBar--SuperGridControl
//SuperGridControl控件初始化 private void ResetLayout(SuperGridControl SGC) { GridPanel panel = SGC.Prima ...