面试:----电商项目中比较难得问题

来源:互联网 发布:pp助手无法安装软件 编辑:程序博客网 时间:2024/05/17 21:57

SSO单点登录:

SSO系统:这里涉及到拦截器。

       这里是利用了sso的接口文档,即校验接口、注册、登录接口、根据token查询用户接口、安全退出接口。

   这个的调用服务层是利用jsonp的形式访问的服务接口,实现跨域访问。客户端全部在jsp页面实现的。

具体流程:

     当用户点击注册的时候,跳转到注册页面,即用户信息的保存功能。检验用户名是否存在、手机号和邮箱不能为空。

       当用户点击登录按钮的时候,用户输入用户名和密码,检验用户名是否在数据库中存在,然后用户名密码是否正确。这里的密码是用了spring的MD5加密技术。当全部成功后,给用户颁发一个token令牌(利用uuid实现),然后将token存入到redis中(token的key是它生成的号,值是用户的名字),然后设置在redis的过期时间。这相当于用户的session。

   然后将token写入cookie中,前台页面利用jsonp调用,根据cookie中的token的值,调用sso的根据token查询用户的服务,查看用户是否有效,如果有效则将用户返回前台页面,前台页面获取用户的用户名显示在首页,表示***已登陆。

   这里的cookie是设置了共享域,即全部子系统都可以访问到cookie。

当用户登录其他子系统时,先从从cookie中获取token信息,根据token信息获取用户信息,判断用户信息是否有效,如果有效则放行,如果无效,则利用拦截器拦截跳转到登录页面。用户再次登录的时候刷新redis的时间,重新设置有效期。

拦截器的拦截,在springMVC.xml中设置拦截的名称。




订单模块需要用到的表:

1、数据库的设计:订单相关表设计、订单关联的诸如商品列表、会员信息、折扣、积分、打包销售等;账单相关表,包括内部账单和渠道支付账单(如微信支付、支付宝支付等),还有就是操作日志类。建议网上去找一些资料或者开源电商产品参考一下,这块第一次做考虑完整比较难的,当然是根据实际需求裁剪,但如果大面上设计有问题后面功能扩展的时候会非常难受;

2、第三方支付:主要是支付过程中一些正常和异常的流程,微信支付你可以参考它帮助文档中推荐的测试用例,挺完整的;另外就是后台需要轧账和平账,就是你要每天和第三方平台去对一次账,看看两边数据库里的支付情况是否正确。

3、你在上面提到了及时到账,那就证明可能有个人账户体系,这里的充值、提现要想好怎么搞?一般第三方支付针对个人是没有提现接口的,只有退款


购物车与商城以及订单的关系:

从一般的商城来看,可以分为B2C与C2C,也就是单商城系统和多商城系统。单商城的系统,基本上就是全部商品生成一个订单,而多商城系统里面的购物车则是可以根据店铺来分别支付生成订单(如微店)或者全部统一支付然后根据店铺拆分订单(如有赞,淘宝等)。

      总结如下:

          

      如上图所示:

     (1)根据每个店铺生成订单去支付,很好理解,例如我在店铺A,买了1,2,3这几个商品,我只需要生成一个订单号,然后去支付就可以了,后续的退款等各种处理,只需要根据该订单号进行处理即可。

     (2) 那么,最后一个,购物车里面有多个店铺的商品,又需要一起支付的时候怎么办呢?假定我们使用微信支付,微信支付每次下单只能使用唯一一个单号,那么我们只能把不同的店铺,例如店铺A和店铺B的所有商品,都统一放到一个订单号去微信下单支付。但是,这样子又违反了订单规则:不同的店铺存在着不同的订单业务,店铺和订单是一对多的关系,而且每个订单号必须是唯一的。怎么办?这个时候,我们可以把内部订单号和微信下单号做一个映射(也就是图所说的拆单),后续做各种处理例如退款等,就可以通过映射关系去进行处理,如下图:

      

      总结一下他们之间的关系:

      (1)购物车可以存在多个店铺多个商品,可以一次性给钱购买购物车所有商品

      (2)一个订单只能对应一个店铺,一个店铺可以拥有多个订单

      (3)微信下单号只有一个,一个微信下单号可以对应多个内部订单号,一个内部订单号只能对应一个微信下单号



C2C商城购物车数据库设计与技术实现

 由于B2C商城和C2C大同小异,这里暂且不讨论B2C的设计和实现,相信会C2C实现而不会B2C的同学是不存在的。且纵观目前的商城,大部分慢慢倾向于增加商家入住功能,所以建议预留多商铺功能,即先把商铺表加进去,与商品相关的带上商铺id,只不过目前商铺只有一个就是自己,就这样可以减少业务需求改动带来的大量数据库结构和代码的改动。

如果用户购物车内的商品都是一个店铺的,那么就不存在拆单、映射表这种说法,直接生成唯一订单号作为微信订单号支付就可以,但是谁都不知道需求是如何变化的,既然淘宝都是可以统一支付不同店铺的商品,那么设计的时候最好是支持购物车所有商品统一支付的,这样子就通杀了,不管你是B2C的购物车,还是微店的购物车,还是淘宝的购物车,都能满足需求。如果只能支持不同店铺做分别支付,类似微店这样,那么万一产品要改成支付宝这样子,就又得重新设计映射表,进行拆单了。本人所在公司的产品经理刚开始比较倾向于微店这种产品设计,而我设计系统时,也仅仅往产品的需求思考,而没考虑到淘宝的设计,现在换一个产品又要改为淘宝这种购物车,就感觉深深地掉进了坑里面。这里学到了一个道理,那就是永远不要相信产品经理(哭),当然也不要过度设计,这里其实不是过度设计,只是用多一点时间,就能减少以后的巨大时间,而且产品人员也很喜欢参考大公司的产品功能,毕竟一些基础功能都是经过大量的用户反馈的。

那么我们就以有赞这种做法来设计我们的购物车和订单吧。

      1、订单表

          

     2、购物车表

          

      最主要的是:商铺订单号in_trade_no和第三方支付下单号out_trade_no


- 下单核心实现(非完整代码)

       

一》购物车提交过来的下单最终是以不同店铺组成的数组
  如:             

 $data = arrray(           '店铺A' => array('商品1''商品2'),           '店铺B' => array('商品1''商品2'),);
二》只有一个数组时,让商铺订单号in_trade_no和第三方支付下单号out_trade_no一致,这样子的好处是,我们可以认为订单号和下单号一致时就是在一个店铺支付的,而不是多个,这样就可以复用微信下单接口返回的数据,从而对该待付款订单进行付款,而不是再调下单接口生成新的订单号去支付(既可以减少接口调用,也可以减少费单)
        如:            
1234 =1234 $unified_order = WeixinPay::unifiedOrder(         $this->conf['weixin']['pay_key'],         $this->openid,1234,$order['pay']*100,$this->appid,         $this->conf['weixin']['mch_id'],         $this->conf['weixin']['pay_notify_url'],         WeixinPay::getNonceStr(),$order['title']);$data = array(                                  'appId' => $this->appid,    'nonceStr' => $unified_order['nonce_str'],    'package' => "prepay_id={$unified_order['prepay_id']}",    'signType' => 'MD5',     'timeStamp' => strval($_SERVER['time']),);$data['paySign'] = WeixinPay::MakeSign($data, $this->conf['weixin']['pay_key']);$this->vshop_orderWeixinPrepay->setPrePay(1234,$data);$this->err_msg['ok']['data'] = $data;$this->_showJsonMsg('ok');
用户支付待付款订单时直接把之前存着的下单数据拿出来:
if(商铺订单号==第三方支付下单号){           //在一个店铺内购买东西         去微信检查1234这个下单号是否已经支付过了,支付过了则退出,而且如果订单不是未付款状态,例如网络超时等直接报错退出          通过执行下面代码          $data = $this->vshop_orderWeixinPrepay->getPrePay(1234);         $this->err_msg['ok']['data'] = $data;           $this->_showJsonMsg('ok');}else{          //不一致为什么这么做?请看《三》        重新生成商铺订单号和第三方支付下单号,让其一致    调用微信下单接口,根据该订单金额等,重新下单}
《三》多个数组时,每个店铺订单对应相同的第三方支付下单号,但是商铺订单号不能与下单号出现一致的情况,否则就会导致超额付款问题。

    如
      

       1234 => 1111       4567 => 1111       8910 => 1111       而不能是       1234 => 4567       4567 => 4567       8910 => 4567
为什么商铺订单号不能与下单号出现一致的情况,否则就会导致超额付款?
场景是用户把几个店铺的商品提交过来,假如3个店铺,我们内部会生成3个内部订单号和一个微信下单号,如果成功支付问题很好解决,假如没有成功支付,前端就会像有赞那样出现3个待付款的订单。
假如这么巧,用户就对        4567 => 4567  这个单进行付款操作,按照上面《二》的逻辑,就会进到getPrePay获取到微信下单号4567的下单数据,记住,微信下单号4567的金额是内部订单号1234,4567, 8910三者金额的和,用户本来想支付第二个内部订单4567的钱,最后却变成了支付三个订单的钱,这是万万不可的,因此要确保商铺订单号不能与下单号出现一致的情况,这很简单,例如加个字母前缀等即可      
       1234 => o_4567       4567 =>o_4567       8910 =>o_4567
这样子,用户单独支付订单时,永远走的是:《 重新生成商铺订单号和第三方支付下单号,让其一致; 调用微信下单接口,根据该订单金额等,重新下单》这个逻辑,请看《二》


四》订单的退款,成功付款,只需要结合内部订单号和第三方下单号处理就可以了


SSO单点登录之跨域问题:(怎么理解的)

第一次写博客,与大家共勉.

这里用到的原理其实非常简单,将cookie存在一个公共的站点的页面上就可以了,这里我们管那个站点叫主站S.

先说说所谓的跨域

环境1:a.xxx.com需要跟b.xxx.com实现跨域,这种比较简单,只需要设置cookie的域名关联域就可以了 cookie.Domain = "xxx.com",这样两个域名间的cookie就可以互相访问,实现跨域.

环境2:a.aaa.com需要跟b.bbb.com实现跨域,这种不同域名的情况下,想要实现就必须换种方式了.

 在这里我将引入第三者,s.sss.com这个站点,就是某个浏览器同时打开了这3个站点,我们访问A站点,先判断自身是否登录,如果session为空,就重定向到S站点,判断S站点上面是否有cookie,如果S站点上面也没有cookie,则由S站点重定向到A站点的登录页.

 这样我们就实现了第一步,S站做的的就是隐藏在幕后,子站先判断自己是否存在session,如果不存在,就重定向到主站S上面去验证.

第二步,验证登录信息合法性.这里我引入token(令牌),网上有很多资料,描述token的传递,工作方式是这样,A登录成功,保存自身的session,重定向到S,S在自己站点保存一个session跟cookie,session保存token对象{tokenID,userName,startTime,endTime},cookie保存tokenID,tokenID是一个Guid,把token对象缓存在集合里面,另起一个线程,根据endTime(过期时间)来定期清理集合列表,重定向到A的时候再将tokenID传递过去,拿到tokenID后,进入验证环节,S站有提供一个接口,根据tokenID获取token对象,如果获取到对象,且没有失效,则tokenID合法,跳入index页面.情况2,A登录,直接打开B,这时候B自身没有session,会主动请求主站,主站会返回cookieID(S站存在客户端的cookie),这个时候再走验证环节,如果通过,则B根据token对象创建自身的session,再跳入index


什么是顶级域名,什么是二级域名(理解)


 一个完整的域名由二个或二个以上部分组成,各部分之间用英文的句号"."来分隔,最后一个"."的右边部分称为顶级域名(TLD,也称为一级域名),最后一个"."的左边部分称为二级域名(SLD),二级域名的左边部分称为三级域名,以此类推,每一级的域名控制它下一级域名的分配。

域名的构成
顶级域名:一个域名由两个以上的词段构成,最右边的就是顶级域名。

目前,国际上出现的顶级域名有.com,.net,.org,.gov,.edu,.mil,.cc,.to,.tv以及国家或地区的代码,其中最通用的是.com,.net,.org
.COM - -适用于商业实体,它是最流行的顶级域名,任何人都可注册一个.com域名。
.NET - -最初用于网络机构如ISP,今天,任何一个人都可注册一个.net域名。
.ORG ---设计是用于各类组织机构,包括非盈利团体,今天,任何一个人都可注册一个.org域名。 国家代码:像cn(中国),fr(法国)和au(澳大利亚)这样两个字母的域名谓之国家代码顶级域名(ccTLDs),通过ccTLDs,基本上可以辨明域名持有者的国家或地区。详细的国家代码可在 查找。

二级域名:靠左边的部分就是所谓的二级域名,在 中,cctv就是顶级域名.com下的二级域名, 还可以有 的形式,这里的mail可以谓之"主机"或"子域名"。

域名的结构
顶级域名
域名由两个或两个以上的词构成, 中间由点号分隔开。最右边的那个词称为顶级域名。下面是几个常见的顶级域名及其用法:
.COM--用于商业机构。它是最常见的顶级域名。任何人都可以注册.COM 形式的域名。
.NET--最初是用于网络组织,例如因特网服务商和维修商。现在任何人都可以注册以.NET结尾的域名。
.ORG--是为各种组织包括非盈利组织而定的。现在,任何人都可以注册以.ORG 结尾的域名。
国家代码由两个字母组成的顶级域名如.cn, .uk, .de和.jp称为国家代码顶级域名(ccTLDs), 其中.cn是中国专用的顶级域名


activeMA是怎么保证收到消息的:

消费者注册到activemq服务器时,在activemq服务器上会记录消费者的信息。并且消费者与服务器之间会保持一种类似于心跳线的机制,只要任意一方出现的异常导致程序退出,另外一方都会知道(可能是内部启动一个线程每隔几秒请求一次确定连接是否异常)。


原创粉丝点击