1、订单系统
2、提交订单
3、MyCAT
1、在购物车页面点击“去结算”按钮跳转到订单确认页面。
a) 展示商品列表
b) 配送地址列表
c) 选择支付方式
2、展示订单确认页面之前,应该确认用户身份。
a) 使用拦截器实现。
b) Cookie中取token
c) 取不到token跳转到登录页面
d) 取到token,根据token查询用户信息。
e) 如果没有用户信息,登录过期跳转到登录页面
f) 取到用户信息,放行。
3、提交订单
a) 生成订单
b) 展示订单提交成功页面。
订单系统系统:订单确认页面、订单提交成功页面。
订单服务系统
创建一个订单服务系统:
e3-order
|--e3-order-interface(jar)
|--e3-order-Service(war)
e3-order-web(war)
导入静态页面
1、在购物车页面点击“去结算”按钮跳转到订单确认页面。
2、请求的url:
/order/order-cart
3、参数:没有参数。
4、购物车商品数据从cookie中取出来的。可以在订单系统中取到cookie中的购物车数据。
5、配送地址列表,需要用户登录。需要根据用户id查询收货地址列表。静态数据。
6、支付方式。静态数据。
7、返回值:逻辑视图String,展示订单确认页面。
引入其他工程接口即可。
引入服务
<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"; } }
在展示订单确认页面之前,需要对用户身份进行认证,要求用户必须登录。
1、使用springmvc的拦截器实现。需要实现一个接口HandlerInterceptor接口。
2、业务逻辑
a) 从cookie中取token。
b) 没有token,需要跳转到登录页面。
c) 有token。调用sso系统的服务,根据token查询用户信息。
d) 如果查不到用户信息。用户登录已经过期。需要跳转到登录页面。
e) 查询到用户信息。放行。
3、在springmvc.xml中配置拦截器。
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 } }
1、在订单确认页面点击“提交订单”按钮生成订单。
2、请求的url:/order/create
3、参数:提交的是表单的数据。保存的数据:订单、订单明细、配送地址。
a) 向tb_order中插入记录。
要求订单号不能重复。
订单号可读性号。
可以使用redis的incr命令生成订单号。订单号需要一个初始值。
b) 向tb_order_item订单明细表插入数据。
c) tb_order_shipping,订单配送信息
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。
可以使用逆向工程。
参数: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"/>
引用服务
<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(); }
简单的说,MyCAT就是:
?一个彻底开源的,面向企业应用开发的“大数据库集群”
?支持事务、ACID、可以替代Mysql的加强版数据库
?一个可以视为“Mysql”集群的企业级数据库,用来替代昂贵的Oracle集群
?一个融合内存缓存技术、Nosql技术、HDFS大数据的新型SQL Server
?结合传统数据库和新型分布式数据仓库的新一代企业级数据库产品
?一个新颖的数据库中间件产品
MyCAT的目标是:低成本的将现有的单机数据库和应用平滑迁移到“云”端,解决数据存储和业务规模迅速增长情况下的数据瓶颈问题。
?支持 SQL 92标准
?支持Mysql集群,可以作为Proxy使用
?支持JDBC连接ORACLE、DB2、SQL Server,将其模拟为MySQL Server使用
?支持galera for mysql集群,percona-cluster或者mariadb cluster,提供高可用性数据分片集群
?自动故障切换,高可用性
?支持读写分离,支持Mysql双主多从,以及一主多从的模式
?支持全局表,数据自动分片到多个节点,用于高效表关联查询
?支持独有的基于E-R 关系的分片策略,实现了高效的表关联查询
?多平台支持,部署和实施简单
如图所示:MyCAT使用Mysql的通讯协议模拟成了一个Mysql服务器,并建立了完整的Schema(数据库)、Table (数据表)、User(用户)的逻辑模型,并将这套逻辑模型映射到后端的存储节点DataNode(MySQL Instance)上的真实物理库中,这样一来,所有能使用Mysql的客户端以及编程语言都能将MyCAT当成是Mysql Server来使用,不必开发新的客户端协议。
l 性能问题
l 数据库连接过多
l E-R分片难处理
l 可用性问题
l 成本和伸缩性问题
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上
原文:https://www.cnblogs.com/huozhonghun/p/10201599.html