SSM商城项目(十三)

1.   学习计划

1、订单系统

2、提交订单

3、MyCAT

2.   订单系统

2.1. 功能分析

1、在购物车页面点击“去结算”按钮跳转到订单确认页面。

a)         展示商品列表

b)        配送地址列表

c)         选择支付方式

2、展示订单确认页面之前,应该确认用户身份。

a)         使用拦截器实现。

b)        Cookie中取token

c)         取不到token跳转到登录页面

扫描二维码关注公众号,回复: 4725014 查看本文章

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中插入记录。

  1. 订单号需要手动生成。

要求订单号不能重复。

订单号可读性号。

可以使用redis的incr命令生成订单号。订单号需要一个初始值。

  1. Payment:表单数据
  2. payment_type:表单数据
  3. user_id:用户信息
  4. buyer_nick:用户名
  5. 其他字段null

b)        向tb_order_item订单明细表插入数据。

  1. Id:使用incr生成
  2. order_id:生成的订单号
  3. 其他的都是表单中的数据。

c)         tb_order_shipping,订单配送信息

  1. order_id:生成的订单号
  2. 其他字段都是表单中的数据。

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上

猜你喜欢

转载自www.cnblogs.com/huozhonghun/p/10201599.html