精华内容
下载资源
问答
  • 大家,我是 Rocky0429,一个最近老在 GitHub 上闲逛的蒟蒻… 特别惭愧的是,虽然我很早就知道 GitHub,但是学会逛 GitHub 的时间特别晚。当时一方面是因为菜,看着这种全是英文的东西难受,不知道该怎么去玩,另...

    在这里插入图片描述



    大家好,我是 Rocky0429,一个最近老在 GitHub 上闲逛的蒟蒻…


    特别惭愧的是,虽然我很早就知道 GitHub,但是学会逛 GitHub 的时间特别晚。当时一方面是因为菜,看着这种全是英文的东西难受,不知道该怎么去玩,另一方面是一直在搞 ACM,没有做一些工程类的项目,所以想当然的以为和 GitHub 也没什么关系(当然这种想法是错误的)。


    后来自己花了一个星期看完了 Python 的基础知识,就想着找点项目看一看,学一学,练一练,这个时候我才真正的去了解 GitHub,开始了在 GitHub 的瞎逛之旅,在开始之初,随之而来的问题是我不知道哪些项目当时还是新手的我,哪些项目是好项目,哪些项目好玩有价值。


    虽然现在我已经在 GitHub 上逛的相当流畅,但我还是想如果有一个东西可以收集这些对新手友好的东西,那么我当时可以少走更多的弯路,节省更多的时间吧。


    那么有这么一个东西么?


    有的,而且已经做了三年多,这就是

    展开全文
  • 面试()项目介绍

    万次阅读 多人点赞 2019-09-07 19:49:29
    前言 因为我这里写的是乐优商城项目,所以面试我会按照乐优商城项目来回答 关于具体的架构另篇blog上有写 乐优商城项目架构:...您,我叫杨椰,我是名大四应届毕业生,毕业于一所普通二本学校.目前暂无工作...

    前言

    因为我这里写的是乐优商城项目,所以面试我会按照乐优商城项目来回答
    关于具体的架构另一篇blog上有写
    乐优商城项目架构:(https://blog.csdn.net/Makasa/article/details/100590048)

    问题一:请简单的介绍一下你自己吧!

    1.自我介绍:个人信息+教育经历+项目经验

    您好,我叫杨椰,我是一名大四应届毕业生,毕业于一所普通二本学校.目前暂无工作经验来找实习工作,有做过一个乐优商城的项目经验(为时一个月):它是一个全品类的电商购物网站(B2C)主线功能就是:用户可以在线购买商品,加入购物车,下单等,管理员可以在后台管理商品的上下架,监控商品销售状况。而我所主要做的就是将这些提供好的Rest风格的业务接口一一实现。

    2.如果问到专业:你不是本专业学生为什么选择这个行业

    类似作文的技巧:先抑后扬:肯定自己的不足,但是突出自己的优点(所以语气重词突出在但是)

    • 因为喜欢,没错,我不是本专业的学生,这虽然看起来是我简历的缺点:不是本专业学生未具备良好的一个硬件实力基础:教本知识,类似目前的一些公司招聘门槛可能会是必须是与计算机相关专业的学生。
    • 但是呢,我觉得这同时也凸显了我的优点:我不是本专业的学生,现在却依旧能站在面试官您的面前,想必,我也是付出了一些精力和时间的。我觉得我有很强的学习能力和自觉能力。我有很大的自信,我并不比计算机相关专业的学生差。即使现在可能还是一个小菜鸟,但日后我绝对会更加优秀与日变强,我相信我会做到。

    3.如果问到你是女生你为什么选择这份工作

    突出女性的优点:细心

    • 原因还是因为自己真实喜欢,我知道这个社会大多对女性带有偏见,大学期间,有老师曾说过:性别有时候是一个公司招聘的隐性条件,而如果我不喜欢,我大可不必选择这样一份技术能力要求很高的工作。很多人可能会说:女性在这方面逻辑思考能力相对对男性较弱。但是女性也有更强的地方:细心。这对于一些bug的寻找等等,也有很大的帮助。在我所知:程序媛占比很少,当然我也希望我能成为这占比很少中的优秀程序媛的一份子。

    问题二:谈谈你的项目吧!

    1.分析:

    考官通过看你的简历或者你的介绍来了解你所做的项目,那么考官肯定想更详细的了解你的项目,看是不是与你的简历写的项目经验一致。也就是考核你是否具有真实的项目经验。一般来说,在你的简历至少有一个重点项目,放在简历项目经验栏的第一位。把项目的业务功能描述清楚。在这里你就是重点谈一个项目就可以了。 从下面几个方面来进行陈 述

    • 1. 用一句话简述项目
    • 2. 详细的列出项目实现的功能
    • 3. 说出项目实现的技术和架构,能说出项目的不寻常之处,比如采用了某项新技术,采用 了良好的架框等
    • 4. 能让别人感觉出项目的规模
    • 5. 说出你在项目中的责任 通过这些来证明你是的确开发过了这个项目, 并且这个项目是一个真实的。
      还有就是你是真正具有项目经验的。合乎企业的用人需要。 特别注意要把项目所实现的功能描述得越详细越好。当然用词要简洁,表达要流利。其次要尽可能采用专业术语,显得你的专业。不要犯低级错误。 请记住, 你要描述的是整个项目而不仅仅是你做的那一个模块。 有些项目你只参与了其中一个模块,但是你要把整个项目描述出来,不要仅仅描述你参与的那一个模块。 说出你项目采用的技术及架构,还要能说明你在项目中的责任。

    2.回答

    乐优商城这个项目采用了目前流行的微服务架构方案。我们选择的是以SpringCloud为核心的,基于Rest风格的微服务架构。我们整个项目是采用了前后端分离的开发模式。

    前端分为两部分:

    • 后台管理:主要面向的是数据管理人员,是基于Vue单页应用开发的
    • 门户系统:面向的是客户,门户采用的Vue结合Nuxt实现服务端渲染方式

    后端

    • 采用基于SpringCloud的微服务架构,统一对外提供Rest风格接口,无论是后台管理还是门户系统都共享这些微服务接口,而微服务中通过JWT方式来识别用户身份,开放不同接口。

    注意:
    到这里先不说了,如果继续追问微服务拆分粒度或者SpringCloud细节,再接着回答微服务拆分

    (这里大概介绍一下即可,我写的比较详细)
    整个项目分为十二个部分:网关,eureka注册中心,公用工具类以及9个微服务
    无论是前台还是后台系统,都共享相同的微服务集群,包括

    1. Eureka注册中心
    2. zuul网关服务
    3. 公用工具类:vo,dto,工具类,自定义异常类及枚举等等…

    且基于nginx实现初步的请求 负载均衡和请求限流

    (九微服务)

    • 1.商品微服务: 主要是进行商品分类管理、品牌管理、商品规格参数管理

      在这里,我记得有一个难点就是商品规格参数的管理:你需要设计Spu(standard product unit标准产品单位)和Sku(standard product unit库存量单位),设计这个你需要去寻找规律,我是看那个京东和淘宝商品详情页下面的规格参数:发现同一分类的规格参数名称是一样的,规格参数名称和分类id绑定到一起,规格参数值和商品id绑定到一起,这里就要设计两个表,采用竖表设计,一个规格组和一个规格参数表。

      额…库存管理设计有一个很大的问题:分布式事务的问题,另说。

    • 2.文件上传微服务: 因为品牌的新增那里需要添加品牌的图片,我就把他给独立出来作为一个文件上传微服务,以后不管是文件还是图片都可以远程调用该微服务。

      这里用到了一个技术就是FastDFS,即分布式文件存储(基于FastDFS解决大数据量的分布式文件存储问题),因为文件上传保存在本地即服务器机器肯定是有问题的,因为单机器存储能力是有限的。

      然后FastDFS它本身是一个轻量级、高性能的开源分布式文件系统,可以做文件存储、同步、访问上传、下载等功能。

      比如上传的大概流程就是:客户端发送文件上传请求给跟踪者TrackerCluster(本身保存组的信息,组有哪些机器),跟踪者跟踪每一次文件上传的路径向去存储集群(storage cluster)查找,并返回可用的存储服务器的ip地址和端口号给客户端,客户端再通过ip和端口号与其中一台存储服务器简历连接,并进行文件上传。最后存储集群返回一个文件ID。【根据上传流程图即非常好理解,所以我决定给他画个图

    • 3.搜索微服务: 主要就是门户系统页面进行商品查找等等. 这里主要采用的技术就是elasticsearch,用来完成商品的全文检索功能

      用它的原因是:

      1.它本身就是基于json的分布式搜索和分析引擎,不需要人工搭建集群,比solar快,因为它能实时搜索。

      2.Restful风格,一切API都遵循Rest原则,易上手(GET/POST/PUT/DELETE)

      3.近实时搜索,数据更新在ElasticSearch中几乎是完全同步的。

      我是把elasticsearch装在了虚拟机里面,然后又在其里面安了一个ik分词器的插件,方便用来查询。

      然后,这里有个难点就是搜索的过滤条件生成,例如:高级聚合功能,说难其实也不难,你首先需要了解并学习全文检索的一些语法:聚合,查询什么的…然后把他们变为java代码。只是java代码实现时候的逻辑可能会比较复杂。

    • 4.页面静态化微服务: 主要是把动态生成的html页面变为静态内容保存,以后用户的请求到来,直接访问静态页面,不再经过服务的渲染。可以大大提高页面响应速度和并发能力

      在项目里:是用在商品详情页的静态化
      这里用到的技术就是ThyMeleaf实现页面模板和静态化,提高页面响应速度和并发能力。并且SpringBoot里已经自动配置了模板引擎,只需要引ThyMeleaf依赖即可。

    • 5.短信微服务: 完成短信的发送,对接阿里云平台,通过RabbitMQ(消息队列) 实现异步的短信发送

      这个里面得注意:需要进行限流,对同一个手机号发送消息限制一分钟之后才可以再发送验证
      这里是在阿里云里面注册了账号开通了短信业务。

    • 6.用户微服务: 主要是实现用户的登录注册、用户信息管理等业务 用户注册、注册数据校验、查询用户信息、

    • 7.认证微服务(即授权中心): 对用户权限(及服务权限(未实现))进行认证 这里有几个点:需要注意

      1.登录授权功能:(判断用户是否存在,存在生成token,把token写入Cookie中保存)

      2.校验用户登录功能:(无token:未登录,有token:解析token,并刷新token(即重新生成token)再写入Cookie,因为Cookie是默认30分钟就消失的,如果用户仍旧在页面操作,那你需要重新设置token并写入Cookie)

      3.网关需要进行登录拦截:(有些路径应该放行,登录之后仍可访问)
      这里使用了JWT和RSA非对称加密,让token更具有安全性

      刁钻问题:
      cookie被禁用怎么办:给个提示,你的cookie被禁用了,请打开
      cookie被盗用怎么办:把用户ip加到PayLoad中,即进行身份识别,如果不对,返回不安全信息让你修改密码。

    • 8.购物车微服务: 实现购物车相关功能

      离线购物车:主要使用localstorage保存到客户端,几乎不与服务端交互

      在线购物车:使用Redis实现。利用redis实现可靠缓存服务即热点数据保存
      设计双层Map:Map<String,<String,Object>>把这个放到redis里面
      第一个key是用户id,第二个key是购物车id,值是购物车信息 购物车CURD

    • 9.订单微服务: 实现订单相关业务(创建订单,查询订单信息)

      创建订单需要

       同时减库存,跨服务业务,需要注意事务处理,流程 	
       查询订单提交的商品信息 	
       计算订单总价(计算商品总价+邮费-优惠券) 	
       写入订单、订单详情、订单状态
       减库存,远程同步调用商品微服务,实现减库存(这种方法只是取巧)
      

      对于减库存问题:我们需要解决分布式事务问题(2PC,TCC,MQ异步确保)

    展开全文
  • 电商项目介绍

    万次阅读 多人点赞 2018-10-22 14:47:39
    电商项目介绍 2.电商行业技术特点 ①技术新:(NoSql推广首在社区网站和电商项目),发展快,需求推动技术的革新。 ②技术范围广:除了java,像淘宝前端还使用了PHP,数据库MySQL或者oracle,nosql,服务器端使用...

    电商项目介绍

    2.电商行业技术特点

    技术新(NoSql推广首在社区网站和电商项目),发展快,需求推动技术的革新。

    技术范围广:除了java,像淘宝前端还使用了PHP,数据库MySQL或者oraclenosql,服务器端使用Linux,服务器安全、系统安全

    分布式:以前是在一台机器上做运算,现在是分散到很多机器上,最后汇总起来。(集中式向分布式进行考虑)由需求来推动

    高并发、集群、负载均衡、高可用:由并发问题采用集群进行处理,其中,集群会涉及服务器的主从以及分布问题,使用负载均衡。(权重高低)高可用是对用户而言,用户的服务不中断(系统升级,服务不中断,淘宝每周更新2)

    海量数据:双11,570亿的背后,订单有多少?浏览次数有多少?商品会有多少?活动相关数据?

    业务复杂:不要简单的认为是:商品展示出来后,加入购物车后购买就完成了。后台特别复杂,比如优惠(包邮、满减)

    系统安全:系统上线必须通过系统安全部门审核通过。前年CSDN数据泄露。快捷酒店数据泄露(通过身份证就可以查看你的开房记录)。近几年,安全意识逐步在提高。

    电商行业的一些概念

        1、 B2C商家对客户京东当当发展B2C平台,天猫(B2C平台 淘宝商城由马云提出,率先发展为平台),1号店也是(在上海)

              2、 B2B商家对商家阿里巴巴(不零售,只批发,淘宝很多商家都会去阿里巴巴进货);

              3、 C2C个人对个人淘宝市场,淘宝QQ商城;

    系统功能

       本商城系统是一个综合性的B2C平台,类似京东商城、天猫商城。

    会员可以在商城浏览商品、下订单,以及参加各种活动。

    商家可以在入住淘淘商城,在该平台上开店出售自己的商品,并且得到淘淘商城提供的可靠的服务。

    管理员、运营可以在平台后台管理系统中管理商品、订单、会员等。

    客服可以在后台管理系统中处理用户的询问以及投诉。

      

     

        首先我们要有商品,管理员可以在系统中管理商品,用户可以查看商品。
        商品多了之后要有类目模块,管理员可以管理类目信息,用户可以根据类目检索商品。
        有了商品之后,要有人(会员)买东西,普通用户注册为会员,会员可以登录到系统管理自己的信息(密码)
        买了之后会生成订单会员可以购买商品并且可以下单,管理员可以管理订单。
        有了订单之后需要支付(在线支付/货到付款)
        ……

    这样,我们就可以把整个电商项目的功能记清楚了!

    分布式系统架构

    左图为分布式系统架构,右图为传统架构!

       

    各个系统说明:

    后台管理系统:管理商品、订单、类目、商品规格属性、用户管理以及内容发布等功能。

    前台系统:用户可以在前台系统中进行注册、登录、浏览商品、首页、下单等操作。

    会员系统:用户可以在该系统中查询已下的订单、收藏的商品、我的优惠券、团购等信息。

    订单系统:提供下单、查询订单、修改订单状态、定时处理订单。

    搜索系统:提供商品的搜索功能。

    单点登录系统:为多个系统之间提供用户登录凭证以及查询登录用户的信息。

    谈到分布式架构,我们必须对比传统架构才能彰显其优势。

        最为明显的一点,在传统的架构中,如果某个功能需要进行维护,那么我们必须停掉整个服务,这对于公司的运营会造成损失。分布式系统在核心功能模块使用单独服务器,维护部分模块不影响用户的其他操作。

        在海量数据处理方面,传统架构显得比较乏力;分布式系统架构采用服务器集群,使用负载均衡,海量数据处理游刃有余!

        在性能(检索)以及维护方面,分布式系统架构也有较为明显的优势。

    6.本系统人员配置情况

    产品经理:3人,确定需求以及给出产品原型图。

    项目经理:1人,项目管理。

    前端团队:3人,根据产品经理给出的原型制作静态页面。

    后端团队:20人,实现产品功能。

    测试团队:3人,测试所有的功能。

    运维团队:2人,项目的发布以及维护。

     

    7.开发流程

        

     

    此图不做详细解释(就业指导课已进行详细说明,注意整个流程中容易被问到的问题)

     

    8.后台开发环境

        

    需要注意,在几个环境中,预发布环境和生产环境几乎一样,开发环境和测试环境是独立存在的,每一个阶段的活是由对应的工作人员来负责的。
    此外,我们还需要熟悉 SVN主干、分支、标签开发过程流程

        

        整个开发沿着主线进行,在一个版本定型后,前一个版本出现bug,那么此时会对bug进行修复,投入使用的依旧是之前定型的那个版本,待前一个版本的bug修复好了之后,会定义一个新的版本,主线不会改变,如果改动不大,那么只需修订问题,继续沿用此版本(1.0.x),只有出现较大改动时,才会升级一个新的版本号(1.1.x)。所有动作,交替进行,沿主线向前推进!

    9.涉及技术

    SpringSpringMVCMybatis

    JSPJSTLjQueryjQuery pluginEasyUIKindEditor(富文本编辑器)CSS+DIV

    Redis(缓存服务器)

    LuceneSolr(搜索)

    httpclient(调用系统服务)

    Mysql

    Nginxweb服务器)

    Quartz(定时任务)

    RabbitMQ(消息队列)

     

    技术详解见其它章节,未接触技术点(标背景色技术点)将在本项目后续内容中进行介绍。

    10.开发工具和环境

    Eclipse 4.4.1 

    Maven 3.2.3

    Tomcat 7.0.47Maven Tomcat Plugin

    JDK 1.7

    Mysql 5.6

    Nginx 1.5.1

    Redis 2.8.9

    Win7 操作系统

    SVN(版本管理) 

     

    此章节,需要注意所有开发工具的版本号要对应(一致),否则会出现冲突问题,面试大忌!(常识:电商项目火起来的时间不是很久,在开发的时候,很多开发工具和环境不像之前那些传统系统那么老旧,这点一定要引起注意!)

     

    电商项目面试问题

     

    项目介绍

    属于B2C平台----商家对客户

    系统的用途,主要是提供B2C的平台,其中自营商品也有商家入住,类似天猫。

    系统架构,采用分布式的系统架构,其中前台系统和单点登录系统采用了集群的方式部署,在后台管理系统中采用了Maven的多模块化的管理,其中采用了水平切分的方式,将pojo、dao、service、web分层开发,这样做的好处就是可以重用性更高。

    系统内部接口调用采用Httpclient,并且使用Httpclient的连接池技术,接口提供端采用RESTful方式的接口定义;

    系统之间的通知机制采用MQ的方式,使用RabbitMQ的实现,使用了RabbitMQ的消息订阅模式的消息机制;

    系统的接口还对JS的跨域做了支持,采用了jsonp的解决方法,在后台接口中扩展了spirng提供的jackson数据转化器实现;

        ④部署方面,采用了Nginx+tomcat的模式,其中nginx的作用一方面是做反向代理、负载均衡、另一方面是做图片等静态资源的服务器。

    项目介绍应该从这个项目的模式、功能、架构、解决了什么问题、部署以及投入使用情况来说。

    2.整个项目的架构如何?

    一般情况这个问题要从两个方面去回答,从技术架构和功能架构去谈。

    技术架构:本项目使用主流框架spring+springmvc+mybatis进行开发,采用分布式的系统架构,前台系统和单点登录系统采用了集群的方式部署,后台管理系统中采用了Maven的多模块化的管理,其中采用了水平切分的方式,将pojo、dao、service、web分层开发,这样做的好处就是可以重用性更高。系统内部接口调用采用Httpclient,并且使用Httpclient的连接池技术,接口提供端采用RESTful方式的接口定义;系统之间的通知机制采用MQ的方式,使用RabbitMQ的实现,使用了RabbitMQ的消息订阅模式的消息机制;系统的接口还对JS的跨域做了支持,采用了jsonp的解决方法,在后台接口中扩展了spirng提供的jackson数据转化器实现;搜索系统使用了solr实现,在保证系统高性能的前提下,尽可能为公司节约成本,我们使用MySQL数据库进行集群(oracle收费)。在部署方面,采用了Nginx+tomcat的模式,其中nginx的作用一方面是做反向代理、负载均衡、另一方面是做图片等静态资源的服务器。

    功能架构:分布式系统架构

    各个系统说明:

    后台管理系统:管理商品、订单、类目、商品规格属性、用户管理以及内容发布等功能。

    前台系统:用户可以在前台系统中进行注册、登录、浏览商品、首页、下单等操作。

    会员系统:用户可以在该系统中查询已下的订单、收藏的商品、我的优惠券、团购等信息。

    订单系统:提供下单、查询订单、修改订单状态、定时处理订单。

    搜索系统:提供商品的搜索功能。

    单点登录系统:为多个系统之间提供用户登录凭证以及查询登录用户的信息。

    谈到分布式架构,我们必须对比传统架构才能彰显其优势。

        ①最为明显的一点,在传统的架构中,如果某个功能需要进行维护,那么我们必须停掉整个服务,这对于公司的运营会造成损失。分布式系统在核心功能模块使用单独服务器,维护部分模块不影响用户的其他操作。

        ②在海量数据处理方面,传统架构显得比较乏力;分布式系统架构采用服务器集群,使用负载均衡,海量数据处理游刃有余!

        ③在性能(检索)以及维护方面,分布式系统架构也有较为明显的优势。

    传统架构

    3.这个项目为用户提供了哪些服务?包括哪些功能?

    u 商品管理模块:其中包括品牌管理,属性管理商品录入/上下架管理,商品添加审核,静态页面发布
    u 订单模块:其中包括使用activiti工作流订单的查询和订单的流转,定时作废
    u 商品前台首页:其中主要负责首页商品列表筛选,首页上动态展示筛选条件,点击每一个筛选条件下面的商品列表要做联动
    u 单品页面:采用freemarker来实现页面静态化,展示商品详情信息和商品购买,该页面采用静态化以减轻系统压力,使用了cxf框架发布服务
    u 提交订单页面:提交用户的订单信息, 处理并发问题。
    u 个人中心,包括用户的登录,个人信息的管理,收货地址的管理,用户所下的订单的管理
    u 购物车:把购物车的信息存在cookie里面管理

    4.你承担这个项目的哪些核心模块?

    在项目中主要负责相关系统的开发,主要有:

        1) 后台管理系统,主要实现商品管理、商品规格参数管理、订单管理、会员管理等、CMS(内容管理系统)等,并且提供了跨域支持;

        2) 前台系统,主要是面向用户访问,使用Httpclient和后台系统接口做交互,并且该系统在部署上采用集群的方式;

        3) 单点登录系统,主要是提供集中用户登录凭证的集中解决方案,提供和用户信息相关的接口,比如说用户注册、查询等接口。

        4) 订单系统,主要是提供和订单相关的业务接口,在订单系统了做了严格的数据校验以及高并发写的支持(这里可以说使用队列实现),并且使用了Quartz定时任务实现对订单的定时扫描,比如说关闭超时未付款的订单;

        5) 搜索系统,主要是提供商品的搜索,采用开源企业级系统Solr实现,采用了MQ机制保证了商品数据可以及时同步到solr中;

        6) 会员系统,主要是维护用户的信息,已购买订单、优惠券、系统消息、修改密码、绑定手机等功能;

        7) 缓存,主要是用Redis实现,并且对Redis做了集群来保证Redis服务的高可用。8) 支付系统,主要是负责订单的支付、对账等功能,主要是对接了支付宝的接口;

    5.这些模块的实现思路说一下?

    ①商品管理模块

    品牌管理:
    主要掌握的核心是品牌的添加
    l 图片服务器的搭建,
    l 上传图片到图片服务器
    l 表单的验证,离开焦点的验证,点击完成时的验证,后台服务器的ajax验证,表单规范
    l 防止表单的二次提交
    l 编辑时不需要修改品牌名,区别readOnly和disabled

    l 删除时的二次确认
    注意:
    自定义属性必须掌握:html中自定义的属性可以帮助索引元素
    图片服务器的搭建
    1. 创建一个maven的web工程,在工程中创建一个存放资源的目录
    2. 把tomcat的web.xml中DefaultServlet的只读属性改成false
     
    3. 编写上传到图片服务器的代码
    由于应用服务器与图片服务器出于不同的两台机器之中,所以可以提高系统的性能,能起到负载均衡的作用。上传图片时使用Jersey客户端API调用REST风格的Web服务,Jersey1是一个开源的、可以用于生产环境的JAX-RS(RESTful Web Services 的Java API 规范,JSR-311)实现。通Jersey 可以很方便的使用Java来创建一个RESTful Web Services。

    byte[] fileByte = commFile.getBytes();

    //创建客服端,基于webservice

    Client client = Client.create();

     

    //指定资源路径

    WebResource webResource = client.resource(Constants.picPath+fileName);

     

    //使用put的请求方式把资源文件放到资源服务器上

    webResource.put(String.class, fileByte);

    前台使用ajax提交表单,需要使用jquery的jquery.form.js插件

    $("#form").ajaxSubmit({

    url:url,

    type:"post",

    dataType:"text",

    data:{

    ...

    },

    //beforeSubmit:validate,

    success:function(responseText){

    var obj = $.parseJSON(responseText);

    },

    error:function(){

    }

    });

     

    4. 图片服务器中Upload文件夹中随便建立一个文件,防止空文件夹的情况下发布后upload消失

    表单验证

    1. 提交时做验证
        做好约定,每个文本中设置reg属性和tip自定义的属性,reg存放正则表达式,tip中存放不合法时的提示信息,还有品牌名称重复的验证。
    reg2,tip属于自定义的属性,这种定义方式方便使用jquery的属性选择器

    <p>

        <label><samp>*</samp>品牌名称:</label>

        <input type="text" id="brandName" name="brandName" class="text state" reg2="^[a-zA-Z0-9\u4e00-\u9fa5]{1,20}$" tip="必须是中英文或数字字符,长度1-20"/>

        <span></span>

    </p>

    2. 在表单提交时做验证使用$(“form”).submit(function(){ return false });,必填字段和非必填的字段需要区别对待

    $("#form111").submit(function(){

        var isSubmit = true;

        $(this).find("[reg2]").each(function(){

            var regStr = $(this).attr("reg2");

            //剪掉值中的两侧的字符串

            var value = $.trim($(this).val());

            var tip = $(this).attr("tip");

            //创建正则表达式的对象

            var reg = new RegExp(regStr);

            if(!reg.test(value)){

                $(this).next("span").html(tip);

                isSubmit = false;

                //跳出循环,在jquery的each语句之中跳出循环使用return false; 如果在原生js里面可使用break;, return;:代表终止执行程序

                return false;

            }

        });

        $(this).find("[reg1]").each(function(){

            var regStr = $(this).attr("reg1");

            var value = $.trim($(this).val());

            var tip = $(this).attr("tip");

            var reg = new RegExp(regStr);

            if(value != null && value != ""){

                if(!reg.test(value)){

                    $(this).next("span").html(tip);

                    isSubmit = false;

                    return false;

                }

            }

        }); 

        return isSubmit;

    });

     

    3. 使用离焦事件做友好的提示

    $("input[reg2]").blur(function(){

        var regStr = $(this).attr("reg2");

        var value = $.trim($(this).val());

        var tip = $(this).attr("tip");

        var reg = new RegExp(regStr);

        if(!reg.test(value)){

            $(this).next("span").html(tip);

        }else{

            $(this).next("span").html("");

        }

    });

    4. 表单的二次提交处理

    l 锁屏
    l 锁按钮

    ②商品的查询

    商品查询需要组合条件加分页查询
    l 组合条件:品牌,审核状态,商品名称,需要动态sql

    <select id="queryItemByCondtion" resultMap="BaseResultMap" parameterType="map">

        select *

        from (select a.*, rownum rm

            from (

                select *

                    from eb_item ei

                        <where>

                            <if test="brandId != null">

                              ei.brand_id = #{brandId}  

                           </if>

                           <if test="auditStatus != null">

                              and ei.audit_status = #{auditStatus}  

                           </if>

                           <if test="showStatus != null">

                               and ei.show_status = #{showStatus}  

                            </if>

                           <if test="itemName != null">

                               and ei.item_name like '%${itemName}%'

                           </if>

                        </where>

                    order by ei.item_id desc) a

                 <![CDATA[

                 where rownum < #{endNum}) b

            where b.rm > #{startNum}

                 ]]>

    </select>

    --查询大于当前页首行号,主要解决oraclerownum不支持大于号的问题

    select *

    from (

        --查询小于当前最大行号的数据

        select rownum rm,a.*

        from (

            --第一个select查询所有的业务数据

           select * from eb_item

           ) a

        where rownum < 21) b

    where b.rm > 10

     

    l 分页查询
    1. 查询结果集的sql,传入开始行数和结束的行数

    select *

    from (select a.*, rownum rm

          from (

              ...

             内部sql

             ...

          ) a where rownum < #{endNum}) b

    where b.rm > #{startNum}

    2. 使用内部sql查询结果集的总条数

    3. 使用分页工具类,创建page对象更换每次的数据总条数和当前页数和每页的条数,查询出结果集后把结果集注入到page对象之中

    public class Page {

        int totalCount = 0;

        int pageSize = 10;

        int currentPageNo = 1;

        int startNum = 0;

        int endNum = 11;

        public Page(int totalCount, int pageSize, int currentPageNo) {

            super();

            this.totalCount = totalCount;

            this.pageSize = pageSize;

            this.currentPageNo = currentPageNo;

        }

        public int getStartNum(){

            return (currentPageNo - 1) * pageSize;

        }

     

        public int getEndNum(){

            return currentPageNo * pageSize + 1;

        }

        public int getTotalPage(){

            int totalPage = totalCount/pageSize;

            if(totalPage == 0 || totalCount%pageSize != 0){

                totalPage ++;

            }

            return totalPage;

        }

        public int getNextPage(){

            if(currentPageNo >= getTotalPage()){

                return currentPageNo;

            }else{

                return currentPageNo + 1;

            }

        }

        public int getPrePage(){

            if(currentPageNo <= 1){

                return currentPageNo;

            }else{

                return currentPageNo - 1;

            }

        }

        List<?> list;

     

        public List<?> getList() {

            return list;

        }

     

        public void setList(List<?> list) {

            this.list = list;

        }

     

        public int getTotalCount() {

            return totalCount;

        }

     

        public void setTotalCount(int totalCount) {

            this.totalCount = totalCount;

        }

     

        public int getPageSize() {

            return pageSize;

        }

     

        public void setPageSize(int pageSize) {

            this.pageSize = pageSize;

        }

     

        public int getCurrentPageNo() {

            return currentPageNo;

        }

     

        public void setCurrentPageNo(int currentPageNo) {

            this.currentPageNo = currentPageNo;

        }

     

        public void setStartNum(int startNum) {

            this.startNum = startNum;

        }

     

        public void setEndNum(int endNum) {

            this.endNum = endNum;

        }

    }

    4. 制作前端样式

    var currentPageNo = parseInt($("#currentPageNo").val());

    var totalCount = parseInt($("#totalCount").val());

    var totalPage = parseInt($("#totalPage").val());

    $("#pagePiece").html(totalCount);

    $("#pageTotal").html(currentPageNo+"/"+totalPage);

    if(currentPageNo <= 1){

        $("#previous").hide();

    }else{

        $("#previous").show();

    }

    if(currentPageNo >= totalPage){

        $("#next").hide();

    }else{

        $("#next").show();

    } 

    $("#next").click(function(){

        $("#pageNo").val(parseInt(currentPageNo)+1);

        $("#form1").submit();

    });

    $("#previous").click(function(){

        $("#pageNo").val(parseInt(currentPageNo)-1);

        $("#form1").submit();

    });

     

    Oracle  分页sql的描述:
      1.最内层的写查询当前表的全量即可
      2.对于oracle数据库分页需要依赖于rownum,但是rownum不支持大于号,但是支持小于号,可以rownum小于结束行号查询出来一个结果集(在全量的外层套一个select,它的结果集需要把rownum作为结果返回)
      3.在第二步的结果集基础上再做一次查询,查询条件以第二步查询出来的rownum的值作为条件大于开始行号即可

    ③商品发布

    Console和portal是分开部署在两台服务器上,发布需要在console端去控制,但是生成的静态化的文件要发布到portal的工程之中,所以发布的服务要在portal上,但是要在console中来调用,异构之间的调用要使用webservice。
    1. 采用cxf的webservice框架来整合spring
    2. 在web.xml中来配置cxf的核心servlet

    <servlet>

        <servlet-name>cxfServlet</servlet-name>

        <servlet-class>org.apache.cxf.transport.servlet.CXFServlet</servlet-class>

    </servlet>

    <servlet-mapping>

        <servlet-name>cxfServlet</servlet-name>

        <url-pattern>/services/*</url-pattern>

    </servlet-mapping>

    3. 创建服务的接口和接口的实现类,注意接口上加上@WebService注解

    4. 创建cxf的核心配置文件cxf-servlet.xml,配置带有接口的webservice服务使用<jaxws:server>标签

    <?xml version="1.0" encoding="UTF-8"?>

    <beans xmlns="http://www.springframework.org/schema/beans"

    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:jaxws="http://cxf.apache.org/jaxws"

    xmlns:jaxrs="http://cxf.apache.org/jaxrs" xmlns:cxf="http://cxf.apache.org/core"

    xsi:schemaLocation="http://www.springframework.org/schema/beans 

              http://www.springframework.org/schema/beans/spring-beans.xsd

                http://cxf.apache.org/jaxrs http://cxf.apache.org/schemas/jaxrs.xsd

                http://cxf.apache.org/jaxws http://cxf.apache.org/schemas/jaxws.xsd

                http://cxf.apache.org/core http://cxf.apache.org/schemas/core.xsd">

        <!-- 引入CXF Bean定义如下,早期的版本中使用 -->

        <import resource="classpath:META-INF/cxf/cxf.xml" />

        <import resource="classpath:META-INF/cxf/cxf-extension-soap.xml" />

        <import resource="classpath:META-INF/cxf/cxf-servlet.xml" />

     

        <jaxws:server id="publish" address="/publish" serviceClass="cn.itcast.ecps.ws.service.EbItemWSService">

            <jaxws:serviceBean>

                <bean class="cn.itcast.ecps.ws.service.impl.EbItemWSServiceImpl"></bean>

            </jaxws:serviceBean>

        <!-- 输入输出的拦截器 -->

     

            <jaxws:inInterceptors>

                <bean class="org.apache.cxf.interceptor.LoggingInInterceptor"></bean>

            </jaxws:inInterceptors>

     

            <jaxws:outInterceptors>

                <bean class="org.apache.cxf.interceptor.LoggingOutInterceptor"></bean>

            </jaxws:outInterceptors>

        </jaxws:server>

    </beans>

    5. 修改cxf-servlet.xml的位置,在spring的listener中加载

    <listener>

        <listener-class>

            org.springframework.web.context.ContextLoaderListener

        </listener-class>

    </listener>

    <context-param>

        <param-name>contextConfigLocation</param-name>

        <param-value>

            classpath*:beans.xml,classpath*:cxf-servlet.xml

        </param-value>

    </context-param> 

    6. 启动服务器发布webservice的服务,使用wsdl2java生成客户端的代码

    Wsdl2java –d . –p cn.itcast.ecps.ws.stub http://.........wsdl?
    7. 在客户端调用。

    ④订单管理模块

    1) 流程设计

     

    2) 订单整合activiti工作流

    1.activiti流程和spring整合
    创建activiti-context.xml文件

    <beans xmlns="http://www.springframework.org/schema/beans"

    xmlns:context="http://www.springframework.org/schema/context" xmlns:tx="http://www.springframework.org/schema/tx"

    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd

    http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd

    http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd"> 

        

        <bean id="processEngineConfiguration" class="org.activiti.spring.SpringProcessEngineConfiguration">

            <!-- 数据源 -->

            <property name="dataSource" ref="dataSource" />

            <!-- 配置事务管理器,统一事务 -->

            <property name="transactionManager" ref="txManager" />

            <!-- 设置建表策略 -->

            <property name="databaseSchemaUpdate" value="true" />

        </bean>

     

        <bean id="processEngine" class="org.activiti.spring.ProcessEngineFactoryBean">

            <property name="processEngineConfiguration" ref="processEngineConfiguration" />

        </bean>

        <bean id="repositoryService" factory-bean="processEngine" factory-method="getRepositoryService" />

        <bean id="runtimeService" factory-bean="processEngine" factory-method="getRuntimeService" />

        <bean id="taskService" factory-bean="processEngine" factory-method="getTaskService" />

        <bean id="historyService" factory-bean="processEngine" factory-method="getHistoryService" />

    </beans>

     

    1. 画流程图
    2. 创建流程服务类

    package cn.itcast.service.impl;

    import java.io.File;

    import org.activiti.engine.RepositoryService;

    import org.activiti.engine.repository.DeploymentBuilder;

    import org.springframework.beans.factory.annotation.Autowired;

    import org.springframework.stereotype.Service;

    import cn.itcast.service.IWorkFlowService;

     

    //@Service

    public class WorkflowServiceImpl implements IWorkFlowService {

     

        @Autowired

        RepositoryService repositoryService;

     

        /*public RepositoryService getRepositoryService() {

            return repositoryService;

        }

     

        public void setRepositoryService(RepositoryService repositoryService) {

            this.repositoryService = repositoryService;

        }*/

     

        public void deployFlow() {

            //创建发布流程配置对象

            DeploymentBuilder builder = repositoryService.createDeployment();

            //指定流程资源路径

            builder.addClasspathResource("activit-orderflow.bpmn").addClasspathResource("activit-orderflow.png");

            builder.deploy();

        }

    }

    1. 部署流程

    2. 查询业务任务
    3. 办理任务

    6.项目中哪些功能模块涉及了大数据量访问?你是如何解决的?

    系统前台是互联网上的用户访问的,会有大量用户来访问。
    假定有1w个人打开你的网站来订商品,问你如何解决并发问题(可扩展到任何高并发网站要考虑的并发读写问题)
    问题,1w个人来访问,商品没出去前要保证大家都能看到有商品,不可能一个人在看到商品的时候别人就不能看了。到底谁能抢到,那得看这个人的运气(网络快慢等)
    其次考虑的问题,并发,1w个人同时点击购买,到底谁能成交?总共只有一张商品。

    Update eb_sku t sett.stock = t.stock  1 where t.sku_id = #{skuId} and t.stock > 0

    Update eb_sku t set t.sale = t.sale +1 where t.sku_id = #{skuId} 

    首先我们容易想到和并发相关的几个方案 : 锁同步

        同步更多指的是应用程序的层面,多个线程进来,只能一个一个的访问,java中指的是syncrinized关键字。锁也有2个层面,一个是java中谈到的对象锁,用于线程同步;另外一个层面是数据库的锁;如果是分布式的系统,显然只能利用数据库端的锁来实现。

        假定我们采用了同步机制或者数据库物理锁机制,如何保证1w个人还能同时看到有商品,显然会牺牲性能,在高并发网站中是不可取的。使用hibernate后我们提出了另外一个概念:乐观锁(一定要用)悲观锁(即传统的物理锁);采用乐观锁即可解决此问题。乐观锁意思是不锁定表的情况下,利用业务的控制来解决并发问题,这样即保证数据的并发可读性又保证保存数据的排他性,保证性能的同时解决了并发带来的脏数据问题。
    hibernate中如何实现乐观锁:

    前提:在现有表当中增加一个冗余字段,version版本号, long类型

    原理:

    1)只有当前版本号》=数据库表版本号,才能提交

    2)提交成功后,版本号version ++

    实现很简单:在ormapping增加一属性-lock="version"即可,以下是样例片段optimistic

    <hibernate-mapping>

        <class name="com.insigma.stock.ABC" optimistic-lock="version" table="T_Stock" schema="STOCK">

    </hibernate-mapping>

    更新的时候给版本号字段加上 1,然后 UPDATE 会返回一个更新结果的行数,通过这个行数去判断。

    Sku_id

    sale

    Version(乐观锁的标志字段)

    1

    100

    1

    UPDATE 必须这样写:

    Sale = 100

    UPDATE EB_SKU u

       SET u.SALES = #SALES#,

           u.version = u.version + 1

     WHERE u.SKU_ID = #SKUID#

       AND u.version = #version#

    Update user t set t.address = #{address} where t.user_id = #{userId}

    如果更新执行返回的数量是 0 表示产生并发修改了,需要重新获得最新的数据后再进行更新操作。

    HibernateJPA  ORM 框架或者实现,是使用版本号,再判断 UPDATE 后返回的数值,如果这个值小于 1 时则抛出乐观锁并发修改异常。

     

    解决大量用户访问量问题方案是集群部署,防止宕机,负载均衡

    1.我们采用4台portal服务器来集群,使用2台nginx代理服务器,

        1)反向代理,把4台portal的服务(host)集中起来,访问动态链接代理地址(代理IP:192.168.1.100)时候会把请求转发到4太portal上,如果访问静态页面直接访问nginx上的资源文件就可以了,静态html中有ajax的请求由nginx的反向代理功能来转发。

        2)部署静态资源(html和图片)

    2.Rsync用作资源同步

        当console上传的图片,由于rsync的部署,会指定一个具体的同步目录(上传图片的目录),一旦发现目录中有文件就立刻同步到nginx上

    3.Redis负责管理session和缓存搜索的数据

        管理session的原因:用于多台服务器之间需要有相同的session,同享策略耗费资源,所以采用redis来存储session。缓存频繁被搜索的数据。

    7.在做这个项目的时候你碰到了哪些问题?你是怎么解决的?

    ①.开发webservice接口出现客户端和服务端不同步,导致接口无法测试,产生的原因沟通不畅。

    ②.订单提交时由于本地bug或者意外故障导致用户钱支付了但是订单不成功,采用对账方式来解决。

    ③.上线的时候一定要把支付的假接口换成真接口。

    ④.项目中用到了曾经没有用过的技术,解决方式:用自己的私人时间主动学习

    ⑤.在开发过程中与测试人员产生一些问题,本地环境ok但是测试环境有问题,环境的问题产生的,浏览器环境差异,服务器之间的差异

    ⑥.系统运行环境问题,有些问题是在开发环境下OK,但是到了测试环境就问题,比如说系统文件路径问题、导出报表中的中文问题(报表采用highcharts),需要在系统jdk中添加相应的中文字体才能解决;

    8.你做完这个项目后有什么收获?

        首先,在数据库方面,我现在是真正地体会到数据库的设计真的是一个程序或软件设计的重要和根基。因为数据库怎么设计,直接影响到一个程序或软件的功能的实现方法、性能和维护。由于我做的模块是要对数据库的数据进行计算和操作的,所以我对数据库的设计对程序的影响是深有体会,就是因为我们的数据库设计得不好,搞得我在对数据库中的数据进行获取和计算利润、总金时,非常困难,而且运行效率低,时间和空间的复杂也高,而且维护起来很困难,过了不久,即使自己有注释,但是也要认真地看自己的代码才能明白自己当初的想法和做法。加上师兄的解说,让我对数据库的重要的认识更深一层,数据库的设计真的是重中之重。

     

        其次,就是分工的问题。虽然这次的项目我们没有在四人选出一个组长,但是,由于我跟其他人都比较熟,也有他们的号码,然后我就像一个小组长一样,也是我对他们进行了分工。俗话也说,分工合作,分好了工,才能合作。但是这次项目,我们的分工却非常糟糕,我们在分工之前分好了模块,每个模块实现什么功能,每个人负责哪些模块。本以为我们的分工是明确的,后来才发现,我们的分工是那么的一踏糊涂,一些功能上紧密相连的模块分给了两个人来完成,使两个人都感到迷惘,不知道自己要做什么,因为两个人做的东西差不多。我做的,他也在做,那我是否要继续做下去?总是有这样的疑问。从而导致了重复工作,浪费时间和精力,并打击了队员的激情,因为自己辛辛苦苦写的代码,最后可能没有派上用场。我也知道,没有一点经验的我犯这样的错是在所难免,我也不过多地怪责自己,吸取这次的教训就好。分工也是一门学问。

     

        再者,就是命名规范的问题。可能我们以前都是自己一个人在写代码,写的代码都是给自己看的,所以我们都没有注意到这个问题。就像师兄说的那样,我们的代码看上去很上难看很不舒服,也不知道我们的变量是什么类型的,也不知道是要来做什么的。但是我觉得我们这一组人的代码都写得比较好看,每个人的代码都有注释和分隔,就是没有一个统一的规范,每个人都人自己的一个命名规则和习惯,也不能见名知义。还有就是没有定义好一些公共的部分,使每个人都有一个自己的“公共部分”,从而在拼起来时,第一件事,就是改名字。而这些都应该是在项目一开始,还没开始写代码时应该做的。

     

        然后,我自己在计算时,竟然太大意算错了利润,这不能只一句我不小心就敷衍过去,也是我的责任,而且这也是我们的项目的核心部分,以后在做完一个模块后,一定要测试多次,不能过于随便地用一个数据测试一下,能成功就算了,要用可能出现的所有情况去测试程序,让所有的代码都有运行过一次,确认无误。

     

        最后,也是我比较喜欢的东西,就是大家一起为了一个问题去讨论和去交流。因为我觉得,无论是谁,他能想的东西都是有限的,别人总会想到一些自己想不到的地方。跟他人讨论和交流能知道别人的想法、了解别人是怎样想一个问题的,对于同样的问题自己又是怎样想的,是别人的想法好,还是自己的想法好,好在什么地方。因为我发现问题的能力比较欠缺,所以我也总是喜欢别人问我问题,也喜欢跟别人去讨论一个问题,因为他们帮我发现了我自己没有发现的问题。在这次项目中,我跟植荣的讨论就最多了,很多时候都是不可开交的那种,不过我觉得他总是能够想到很多我想不到的东西,他想的东西也比我深入很多,虽然很多时候我们好像闹得很僵,但是我们还是很要好的! 嘻嘻!而且在以后的学习和做项目的过程中,我们遇到的问题可能会多很多,复杂很多,我们一个人也不能解决,或者是没有想法,但是懂得与他人讨论与交流就不怕这个问题,总有人的想法会给我们带来一片新天地。相信我能做得更好。

     

        还有就是做项目时要抓准客户的要求,不要自以为是,自己觉得这样好,那样好就把客户的需求改变,项目就是项目,就要根据客户的要求来完成。

    9.你这个项目中使用什么构建的?多模块开发是如何划分的呢?为什么要这么做?

    我们这个项目使用Maven进行构建,并使用了水平划分,这样划分层次清晰,代码重用性高,易于独立维护。

    ①垂直划分

     

    ②水平划分

     

    优缺点:

        垂直:功能模块明确,层次不够清晰,代码重用性差。

        水平:层次清晰,代码重用性高,独立维护。

     

    淘淘商城后台管理系统采取水平划分。

    10.你觉得在文件上传功能上面需要注意什么?

    对上传的文件做校验!

    11.在你这个项目中,是如何设计商品规格的?

    实现思路很重要!

    12.在这个项目中你是如何实现跨系统调用的?

     

    有两种调用方式:
    1、 Ajax,走前台js,通过jsonp来跨域,关于jsonp请参考:http://www.cnblogs.com/yuzhongwusan/archive/2012/12/11/2812849.html

    a) 效率

    b) 带宽

    document.domain="taotao.com"
    jsonp,部署子域名的情况 
    需要在SpringMVC中扩展MappingJackson2HttpMessageConverter,支持jsonp。跨域问题,因为我们是子域名访问子系统接口的,采用jsonp解决;

    2、 后台转发请求,走后台,通过httpclient来调。

    a) 可以加逻辑(加缓存只能这条路走)

    b) 安全,接口不在公网公开

    重点学习httpclient中的示例
    掌握spring和Httpclient的集成

    我们这个项目2种方式都使用到了。

    13.你这个项目中CMS系统是如何设计的,简单的说一下其设计思想?

    隐藏在内容管理系统(CMS)之后的基本思想是分离内容的管理和设计。页面设计存储在模板里,而内容存储在数据库或独立的文件中。 当一个用户请求页面时,各部分联合生成一个标准的HTML(标准通用标记语言下的一个应用)页面。

    内容管理系统被分离成以下几个层面:各个层面优先考虑的需求不同

        1,后台业务子系统管理(管理优先:内容管理):新闻录入系统,BBS论坛子系统,全文检索子系统等,针对不同系统的方便管理者的内容录入:所见即所得的编辑管理界面等,清晰的业务逻辑:各种子系统的权限控制机制等;

        2,Portal系统(表现优先:模板管理):大部分最终的输出页面:网站首页,子频道/专题页,新闻详情页一般就是各种后台子系统模块的各种组合,这种发布组合逻辑是非常丰富的,Portal系统就是负责以上这些后台子系统的组合表现管理;

        3,前台发布(效率优先:发布管理):面向最终用户的缓存发布,和搜索引擎spider的URL设计等……

        内容管理和表现的分离:很多成套的CMS系统没有把后台各种子系统和Portal分离开设计,以至于在Portal层的模板表现管理和新闻子系统的内容管理逻辑混合在一起,甚至和BBS等子系统的管理都耦合的非常高,整个系统会显得非常庞杂。而且这样的系统各个子系统捆绑的比较死,如果后台的模块很难改变。但是如果把后台各种子系统内容管理逻辑和前台的表现/发布分离后,Portal和后台各个子系统之间只是数据传递的关系:Portal只决定后台各个子系统数据的取舍和表现,而后台的各个子系统也都非常容易插拔。

        内容管理和数据分发的分离:需要要Portal系统设计的时候注意可缓存性(Cache Friendly)性设计:CMS后台管理和发布机制,本身不要过多考虑"效率"问题,只要最终页面输出设计的比较Cacheable,效率问题可通过更前端专门的缓存服务器解决。

        此外,就是除了面向最终浏览器用户外,还要注意面向搜索引擎友好(Search engine Friendly)的URL设计:通过 URL REWRITE转向或基于PATH_INFO的参数解析使得动态网页在链接(URI)形式上更像静态的目录结构,方便网站内容被搜索引擎收录;

    14.在这个项目中,你们主要使用什么样的数据格式来进行数据的传输的?你对JSON了解么?能说说JSON对象如何转换成Java对象的?

     

    15.单点系统的设计思想你了解吗?他在系统架构中的作用是什么?位置如何?

    单点登录SSO(Single Sign On)说得简单点就是在一个多系统共存的环境下,用户在一处登录后,就不用在其他系统中登录,也就是用户的一次登录能得到其他所有系统的信任。单点登录在大型网站里使用得非常频繁,例如像阿里巴巴这样的网站,在网站的背后是成百上千的子系统,用户一次操作或交易可能涉及到几十个子系统的协作,如果每个子系统都需要用户认证,不仅用户会疯掉,各子系统也会为这种重复认证授权的逻辑搞疯掉。实现单点登录说到底就是要解决如何产生和存储那个信任,再就是其他系统如何验证这个信任的有效性,因此要点也就以下几个:

    存储信任

    验证信任

    只要解决了以上的问题,达到了开头讲得效果就可以说是SSO。最简单实现SSO的方法就是用Cookie,实现流程如下所示:

    不难发现以上的方案是把信任存储在客户端的Cookie里,这种方法虽然实现方便但立马会让人质疑两个问题:

    Cookie不安全

    不能跨域免登

    对于第一个问题一般都是通过加密Cookie来处理,第二个问题是硬伤,其实这种方案的思路的就是要把这个信任关系存储在客户端,要实现这个也不一定只能用Cookie,用flash也能解决,flash的Shared Object API就提供了存储能力。

    一般说来,大型系统会采取在服务端存储信任关系的做法,实现流程如下所示:

    以上方案就是要把信任关系存储在单独的SSO系统(暂且这么称呼它)里,说起来只是简单地从客户端移到了服务端,但其中几个问题需要重点解决:

    如何高效存储大量临时性的信任数据

    如何防止信息传递过程被篡改

    如何让SSO系统信任登录系统和免登系统

    对于第一个问题,一般可以采用类似与memcached的分布式缓存的方案,既能提供可扩展数据量的机制,也能提供高效访问。对于第二个问题,一般采取数字签名的方法,要么通过数字证书签名,要么通过像md5的方式,这就需要SSO系统返回免登URL的时候对需验证的参数进行md5加密,并带上token一起返回,最后需免登的系统进行验证信任关系的时候,需把这个token传给SSO系统,SSO系统通过对token的验证就可以辨别信息是否被改过。对于最后一个问题,可以通过白名单来处理,说简单点只有在白名单上的系统才能请求生产信任关系,同理只有在白名单上的系统才能被免登录。

    16.你们这个项目中订单ID是怎么生成的?我们公司最近打算做一个电商项目,如果让你设计这块,你会考虑哪些问题?

    生成订单ID的目的是为了使订单不重复,本系统订单ID生成规则:

        用户ID+当前系统的时间戳

    String orderId = order.getUserId() + "" + System.currentTimeMillis();

    设计的时候我会考虑:

    订单ID不能重复

    订单ID尽可能的短(占用存储空间少,实际使用方便,客服相关)

    订单ID要求是全数字(客服)

    17.各个服务器的时间不统一怎么办?

    在各个服务器上做时间的统一;(运维)

    18.在问题17的基础上,可能存在毫秒级的偏差情况,怎么办?

    修改订单生成规则:
        用户ID+当前系统的时间戳+随机数(3~4位) 问题:太长? 把时间戳中的2014中的20拿掉;

    19.你们线上部署时什么样的,能画一下吗?

    20.多台tomcat之间的session是怎么同步的?

    不用session,我们使用单点登陆,使用redis,存在redis,生成,A同步到B,B同步到C。

    21.如何解决并发问题的?

    集群,负载均衡,nginx(主备,一般主在工作,备闲置;资源浪费),lvs(在2个Nginx前做一个拦截,接收后进行分工)。有问题,如果nginx挂掉,整个系统就挂了。可以主备解决,可以前面搭一个lvs。这块不是你做的,但是你知道怎么解决(非常复杂,但是必须了解。针对具体的情况去具体对待,CPU,内存,不要一刀切。)

    22.你们生产环境的服务器有多少台?

    面试前要数好,一般是十几到二十台。(用在哪里?这是重点)

    Nginx至少2台

    Tomcat至少3台以上

    数据库至少2台

    Redis至少一台

    可参考17问图

    23.数据备份是怎么做的?有没有做读写分离?

    主从(一主多从,主要是备份主),每天备份,备份的文件不要放到数据库服务器上,可以FTP。要检查有效否。读写分离自己查一下,分库分表做过。

    24.你们服务器不止一台吧,那么你们的session是怎么同步的?

    此问题与18相同,如果购物车使用session做的话,此问题极易被问到。

    Session放到redis里面,使用单点登录系统。购物车设计思路:未登录(先写到cookie中,登录后写到数据库表中);已登录(直接写到数据库,而不会写到cookie)实际项目是不使用session的,使用redis集中处理处理数据,取代session的作用,应用在单点登录、购物车等。

    25.你们使用什么做支付的?如果使用易宝做支付,请求超时了怎么处理?

    ①重试,一般三次,每次重试都要停顿一会,比如,以第一次停顿1秒,第二次停顿2秒,第三次停顿3秒;
    ②给订单标识付款异常状态,并且发出警告(邮件、短信)给相关人员。

    ③写个定时任务,定时处理异常状态的订单。

    26.你刚才不是说付款成功后易宝会有数据返回吗?如果付款后易宝没有返回,或者返回超时了,但是钱又已经扣了,你怎么办?

    ①我们请求了易宝,但是没有接受到响应,我们就认为该订单没有支付成功,并且将订单标识为异常状态;
    ②使用定时任务处理;

    ③做一个对账的任务,实时处理异常状态的订单。

    27.你们怎么做退款功能的,要多长时间才能把钱退回给用户?

    用户申请退款后,经过客服审核通过会将退款请求提交到易宝,具体到账时间要看易宝的处理。

    28.你前台portal采用4台服务器集群部署 那你数据库有几台服务器?如果前台高并发访问性能提上去了,那数据库会不会造成一个瓶颈,这一块你是怎么处理的?

     

    29.你购物车存cookie里边可以实现不登录就可以使用购物车,那么我现在没有登录把商品存购物车了,然后登录了, 然后我换台电脑并且登录了还能不能看见我购物车的信息?如果看不到怎么做到cookie同步,就是在另外一台电脑上可以看到购物车信息

    更换电脑,必须登录才能看到之前购物车的商品。

    跨域cookie同步方案:

    场景:有时一个公司可能有多个不同域名的网站,比如sina.com和weibo.cn,比如taobao.com和tmall.com。

    这些网站背后很多是同一套会员体系。由于http协议规定cookie是跟着域名走的,这时就需要在不同的域名下同步登陆状态,避免出现用户体验上出现需要二次登陆验证的情况。

    假设下面这样一个场景:

        用户在 bbb.com上已经登陆,现在要去aaa.com上玩,在aaa.com域名下暂未登录。需要访问的aaa.com/resource.html资源需 要登录才能访问。两个网站是同一套会员体系,同一个公司的。这是要让用户体验上做到用户在aaa.com上玩也能识别出登录状态。

    以上面场景为例,下面画了个实现跨域同步简单流程图:

    解释如下:

    第一步 :用户向aaa.com发起get请求,获取resource.html资源,aaa.com发现用户未登录,返回302状态和外部重定向url:

    Java代码  收藏代码

    j.bbb.com?target=www.aaa.com/resource.html  

    注意j.bbb.com子域名上部署的应用可以认为是专门用了跨域同步。

     

    第二步 :用户根据重定向url,访问j.bbb.com?target=www.aaa.com/resource.html,由于在bbb.com上已经登 录,所以bbb.com上能拿到从client端传递过来cookie信息。子域j.bbb.com上的应用负责将cookie读取出来,并作为参数再次 重定向到

    Java代码  收藏代码 

    p.aaa.com?tartet=www.aaa.com/resource.html&sessionid=xxx&loginId=xxx&……  

    第三步 :用户根据第二步重定向url,访问p.aaa.com。p.aaa.com子域名上的应用专门负责根据请求参数里的参数对,往aaa.com域写入cookie,并重定向到用户第一步请求的url。

    第四步 :经过前三步,已经完成了再aaa.com域名下同步bbb.com的登录状态,用户再次请求aaa.com/resource.html,这是就能成功访问了。

    30.点一个链接访问到一个页面,这个页面上既有静态数据,又有动态数据(需要查数据库的),打开这个页面的时候就是很慢但是也能打开。怎么解决这个问题,怎么优化?

    如果要静态页面的话 那就得用freemarker或者通过ajax异步,通过js操作异步刷新表单,通过js对返回结果组装成html。

    缓存、动态页面静态化:

    所谓缓存, 是指将那些经常重复的操作结果暂时存放起来, 在以后的执行过程中, 只要使用前面的暂存结果即可.

    那么在我们开发Web网站的过程中, 到底有多少工作可以采用用缓存呢? 或者说, 我们可以在哪些地方使用缓存呢? 见下图: 下图是客户端浏览器和Web服务器之间的一次完整的通信过程, 红色圆圈标示了可以采用缓存的地方.

    首先, 最好的情况是客户端不发送任何请求直接就能获得数据, 这种情况下, 用于缓存的数据保存在客户端浏览器的缓存中.

    其次, 在具有代理服务器的网络环境中, 代理服务器可以针对那些经常访问的网页制作缓存, 当局域网中第一台主机请求了某个网页并返回结果后, 局域网中的第二台主机再请求同一个网页, 这时代理服务器会直接返回上一次缓存的结果, 并不会向网络中的IIS服务器发送请求, 例如: 现在的连接电信和网通线路的加速器等. 但是代理服务器通常有自己专门的管理软件和管理系统, 作为网站开发人员对代理服务器的控制能力有限.

    再次, 前面也说过, 当用户将请求地址发送到IIS服务器时, IIS服务器会根据请求地址选择不同的行为, 如: 对于*.aspx页面会走应用程序管道, 而对*.html、*.jpg等资源会直接返回资源, 那么我们可以把那些频繁访问的页面做成*.html文件, 这样用户请求*.html, 将不用再走应用程序管道, 因此会提升效率. 例如: 网站首页、或某些突发新闻或突发事件等, 可以考虑做成静态网页. 就拿”天气预报的发布页面”打比方: 天气预报的发布页面的访问用户非常多, 我们可以考虑将发布页做成静态的*.html网页, 之后在整个网站程序启动时, 在Gboabl.asax的Application_Start事件处理器中, 创建子线程以实现每3个小时重新获取数据生成新的天气发布页面内容.

    之后的asp.net的处理流程, 作为程序员我们是无法干涉的. 直到启动HttpApplication管道后, 我们才可以通过Global.asax或IHttpModule来控制请求处理过程, 在应用程序管道中适合做整页或用户控件的缓存. 如: 缓存热门页面, 我们可以自动缓存整个网站中访问量超过一定数值(阀值)的页面, 其中为了减小IO操作, 将缓存的页面放在内容中.

    31.如果用户一直向购物车添加商品怎么办?并且他添加一次你查询一次数据库?互联网上用户那么多,这样会对数据库造成很大压力你怎么办?

    在回答这个问题前,请想好自己的项目是否真的需要使用购物车?(SKU数少,商品结构单一等就不需要使用购物车了)

    购物车的设计方案:

    购物车的实现不存在哪种方式更好,完全是根据公司和项目架构相关的,类似苏宁使用的是数据库存储,但是国美使用的就是Session,不同的软件架构和不同的业务需求对应的购物车存储也是不一样的

    用数据库存你得给数据库造成多大的负担啊, 而且对于购物车, 这种需要实时操作的东西, 数据库的访问量一大了, 就容易出现并发错误, 或者直接崩溃.

    用Session确实效率很高, 而且会话是针对各个连接的, 所以便于管理, 但是用Session也不是完美的, 因为Session是有有效期的, 根据服务器的设置不同而不一样长, 如果你在购物的过程中Session超时了, 那么购物车中的东西就会全没了.不知道你看过当当网的购物车没有, 当你下线之后, 再次上线, 购物车中的东西还是存在的, 这对于用户来说非常方便.所以如果你的服务器够强的话, 你完全可以用一个静态变量来保存所有用户的购物车, 比如用一个静态的Map, 以IP作为Key,区分不同用户的购物车, 这样就可以使用户在下线的情况下也可以保存购物车中的内容.这种方法实现过, 只是没有用大量的并发访问测试其稳定性, 但是一定是可行的。 

    采用存储过程将购物车存储于数据库相应表的方式,优点:数据稳定,不易丢失。缺点:效率低,增加数据库服务器负担。变量 + Datatable保存于客户端,优点:效率高,减轻数据库服务器负担。缺点:Session保存的变量容易丢失,但是一般情况下不会造成影响。变量 + 购物车对象保存于客户端,这种方式以面向对象为指导思想,逻辑上具有一定的复杂性。优点:效率高,减轻数据库服务器负担,使用便捷。缺点:Session保存的变量容易丢失,但是一般情况下不会造成影响

    购物车的核心功能

    购物车数据存数据库好处有很多,可以分析购买行为,可以为客户保存购买信息(不会因为浏览器关闭而丢失)等,我的这个项目的购物车使用的就是将购物车数据存数据库中,未登录时可以加20个商品,登录后可以加50个。

    32.做促销时,商品详情页面的静态页面如何处理价格问题。

    京东商品详情页虽然仅是单个页面,但是其数据聚合源是非常多的,除了一些实时性要求比较高的如价格、库存、服务支持等通过AJAX异步加载加载之外,其他的数据都是在后端做数据聚合然后拼装网页模板的。整个京东有数亿商品,如果每次动态获取如上内容进行模板拼装,数据来源之多足以造成性能无法满足要求;最初的解决方案是生成静态页,但是静态页的最大的问题:

    1、无法迅速响应页面需求变更;

    2、很难做多版本线上对比测试。如上两个因素足以制约商品页的多样化发展,因此静态化技术不是很好的方案。

     

    数据主要分为四种:商品页基本信息、商品介绍(异步加载)、其他信息(分类、品牌、店铺等)、其他需要实时展示的数据(价格、库存等)。而其他信息如分类、品牌、店铺是非常少的,完全可以放到一个占用内存很小的Redis中存储;而商品基本信息我们可以借鉴静态化技术将数据做聚合存储,这样的好处是数据是原子的,而模板是随时可变的,吸收了静态页聚合的优点,弥补了静态页的多版本缺点;另外一个非常严重的问题就是严重依赖这些相关系统,如果它们挂了或响应慢则商品页就挂了或响应慢;商品介绍我们也通过AJAX技术惰性加载(因为是第二屏,只有当用户滚动鼠标到该屏时才显示);而实时展示数据通过AJAX技术做异步加载

     

    1、接收商品变更消息,做商品基本信息的聚合,即从多个数据源获取商品相关信息如图片列表、颜色尺码、规格参数、扩展属性等等,聚合为一个大的JSON数据做成数据闭环,以key-value存储;因为是闭环,即使依赖的系统挂了我们商品页还是能继续服务的,对商品页不会造成任何影响;

    2、接收商品介绍变更消息,存储商品介绍信息;

    3、介绍其他信息变更消息,存储其他信息

    技术选型

    MQ可以使用如Apache ActiveMQ;

    Worker/动态服务可以通过如Java技术实现;

    RPC可以选择如alibaba Dubbo;

    KV持久化存储可以选择SSDB(如果使用SSD盘则可以选择SSDB+RocksDB引擎)或者ARDB(LMDB引擎版);

    缓存使用Redis;

    SSDB/Redis分片使用如Twemproxy,这样不管使用Java还是Nginx+Lua,它们都不关心分片逻辑;

    前端模板拼装使用Nginx+Lua;

    数据集群数据存储的机器可以采用RAID技术或者主从模式防止单点故障;

    因为数据变更不频繁,可以考虑SSD替代机械硬盘。

     

    核心流程

    1、首先我们监听商品数据变更消息;

    2、接收到消息后,数据聚合Worker通过RPC调用相关系统获取所有要展示的数据,此处获取数据的来源可能非常多而且响应速度完全受制于这些系统,可能耗时几百毫秒甚至上秒的时间;

    3、将数据聚合为JSON串存储到相关数据集群;

    4、前端Nginx通过Lua获取相关集群的数据进行展示;商品页需要获取基本信息+其他信息进行模板拼装,即拼装模板仅需要两次调用(另外因为其他信息数据量少且对一致性要求不高,因此我们完全可以缓存到Nginx本地全局内存,这样可以减少远程调用提高性能);当页面滚动到商品介绍页面时异步调用商品介绍服务获取数据;

    5、如果从聚合的SSDB集群/Redis中获取不到相关数据;则回源到动态服务通过RPC调用相关系统获取所有要展示的数据返回(此处可以做限流处理,因为如果大量请求过来的话可能导致服务雪崩,需要采取保护措施),此处的逻辑和数据聚合Worker完全一样;然后发送MQ通知数据变更,这样下次访问时就可以从聚合的SSDB集群/Redis中获取数据了。

     

    基本流程如上所述,主要分为Worker、动态服务、数据存储和前端展示;因为系统非常复杂,只介绍动态服务和前端展示、数据存储架构;Worker部分不做实现。

    33.商品搜索框的搜索联想如何实现?比如输入“羽绒” ,然后输入框下会列出很多关于羽绒服的搜索条件 “羽绒服男正品折扣 ”等等。

     

    34.一个电商项目,在tomcat里面部署要打几个war包?

     

    35.你说你用了redis缓存,你redis存的是什么格式的数据,是怎么存的?

     

     36.购物车知识补充(在设计购物车时需要注意哪些细节)

    为什么购物车的设计很重要?

    ①购物车是消费的最后一环

    购物车在用户整体消费过程中一般是在最后一环,用户完整的消费体验应该是:打开APP或网站->浏览商品->加入购物车->确认订单并支付,在这个过程中,购物车和支付环节可以合并成一环,基本上用户点开购物车并开始填写地址的时候,就有很大的几率要完成购买,做好商品展现以及推送的环节,如果在最后的购物一环没有好的用户体验,岂不呜呼哀哉。

    ②购物车隐含的对比收藏功能

    与现实购物车不同的是,网络消费者也比较喜欢把看中但不计划买的商品先放入购物车,或者把商品统一放到购物车直接进行比较,以备日后购买,因此从购物车保存的信息,就能够知道用户的大致偏好。

    ③购物车的重交易属性

    用户在浏览商品涉及的只是前端展示,但购物车这一环涉及到最终的交易,对于用户来说,需要了解本次交易的基本物品信息、价格信息;而对于商户来说,确认收款、订单生成、物流环节都需要在这里获取到信息,才能完成本次的交易。

    购物车设计需要展示的基本信息

    购物车主要作用就是告诉用户买了什么,价格多少,不同类型的物品可能会有不同展示方式,但最基本的包括商品名称、价格、数量(若是服务,可能是次数)、其他附属信息。

    哪些细节要让用户买得舒服?

    亲,记得前面说的用户是如何看待购物车的功能吗?还记得你的用户会多次使用购物车,如果你只是完整做好信息展示不做好其他事情真的好吗?

    ①登录环节不要放在加入购物车前

    请让用户先加入购物车,并在进行结算的时候在提醒用户需要登录。为什么?过早提醒用户需要登录才能购买,会打断用户浏览的流程(用户可能还要购买其他物品好吗?)这样的设置会让部分用户避而远之。

    这里涉及到的一个点是在APP端需要记忆用户加入购物车的信息,与登录后的购物车信息合并(如果一开始没有这样考虑好,技术那可能会有难度)

    ②自动勾选用户本次挑选的商品

    用户使用购物车有一个大的作用就是收藏,所以你要知道很多用户在购物车中积累了很多物品,当每次挑选加入购物车的商品,用户每次来到购物车要重新把本次的购买商品选上是很不好的体验。

    所以这里一般是自动勾选本次挑选的商品,同样这里也要储存用户的勾选信息。

    ③陈列展示,注意沉底商品

    让用户看见当前想买的商品就好了,把一些时间久远的,已经卖完的沉底显示。这样做的好处是能让用户看见之前的选择但没购买的商品,提醒一下说不定就又勾上买了哦!

    ④归类展示,可能增加购买

    考虑如何进行归类展示,C2C可以按照商家分类,B2C可以按照品牌分类。

    ⑤价格和优惠的提醒

    消费用户会关系自己每一次的消费价格,为避免商品列表过长隐藏价格信息,APP端一般会把总价固定底部提示。同时在合计信息中,展示优惠价格,能够促进消费者购买。

     

    哪些细节要推动用户继续购买?

    ①还差一点就可以有优惠啦!

    凑单,常用的手段包括运费见面或是满减促销,一般在网站底部会展示一些适合凑单的商品;在APP端可以给链接(不过需要权衡用户跳转会不会再跳回来哦!)

    ②提醒用户有些商品你真的可以买了

    有关调查显示,加入购物车而没有购买的,在4小时以内提醒用户,会有27%的唤醒率哦!

    所以需要提醒的几个点有:

    生成订单但是还没支付的

    商品有优惠信息

    商品库存不足的

    这些信息可以促进消费者购买,注意提醒的时间段,早上9点至晚上8点为宜,其他时间段就可能打扰用户咯(当然也要视产品类型而定啦,只不过大半夜提醒用户买东西确实不好,不是?)

    展开全文
  • 面试中,面试官让你介绍一个电商项目

    千次阅读 多人点赞 2018-10-06 18:19:15
    原 java电商面试介绍 2016年10月28日 19:27:29 x_minde 阅读数:26511更多 个人分类: 面试 ...在青岛做了两年开发,大大小小参与过三个项目的开发,一个是某公司内部的人员管理系统,一个是物流项目,...

    java电商面试介绍

    2016年10月28日 19:27:29 x_minde 阅读数:26511更多

    个人分类: 面试

    版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/xue_mind/article/details/52959107

    在青岛做了两年开发,大大小小参与过三个项目的开发,一个是某公司内部的人员管理系统,一个是物流项目,最近做的是一个电商项目。

    前两个项目采用的是ssh框架搭建的,最近的项目采用的是ssm框架搭建的。在实际开发中,我觉得这两个框架,他们最大的区别在于hibernate与mybatis的区别。

    Hibernate与mybatis相比较,mybatis更为轻便、灵活,容易掌握。mybatis可以把sql语句从java代码中分离了出来,放在了配置文件中书写,大大降低里java代码与SQL语句的耦合度,更容易对sql语句操作,重要的是mybatis还可以书写动态的sql语句,但mybatis也存在一些缺陷,比如mybatis本身的缓存机制没有hibernate那么完善,hibernate除了本身有良好的缓存机制,还可以使用第三方缓存。Hibernate较完整的封装了JDBC,但学起来要比mybatis更困难一些。Hibernate的DAO层开发比MyBatis简单,对对象的维护和缓存要比MyBatis好。

    (springmvc与Struts的区别:springmvc是方法级别的拦截,一个方法对应一个request上下文,而方法同时又跟一个url对应,参数的传递是直接注入到方法中的,是该方法独有的。

    struts2是类级别的拦截, 一个类对应一个request上下文, struts是在接受参数的时候,可以用属性来接受参数, 这就说明参数是让多个方法共享的,这也就无法用注解或其他方式标识其所属方法了)。

     

    该商城是一个综合性的B2C平台,主要针对女性消费者,主要销售女性化妆品,首饰,服装等女性用品。商家入驻商城销售自家的产品,并且可以得到商城提供的各种服务。

     

    在整个项目中,我们采用的是nginx+tomcat来部署的(面试官会可能问nginx是谁来部署的?如何部署的?Nginx的执行流程,优点),nginx一方面做加载静态资源的服务器,另一方面来做反向代理和负载均衡。因为该项目需要在多个环境中运行,我们利用了nginx的反向代理解决了不同环境同系统访问地址不统一带来的问题。

     

    因为整个项目实现的功能较多, 所以采用分布式的架构设计,整个项目包括后台管理系统、前台系统、订单系统、登录系统、搜索系统、购物车系统等,这样做的好处是使每个功能模块独立出来,降低了各系统之间的耦合度,增删一个功能不会影响其他功能模块。

     

    因为项目是采用分布式架构设计的,各模块之间是相互独立的,而各模块的访问路径又是不同的,所以当跨域请求数据的时候会遇到跨域受限的问题。比如当用户首次访问该网站首页时,首页页面会异步请求后台管理系统加载商品的类目,这是就会出现跨域受限的问题,以前开发时,如果在本模块内,我们是通过ajax异步请求数据的,但Ajax不支持跨域,所以用ajax无法解决跨域请求数据的问题。最后我们使用的是jsonp来解决这个问题的。jsonp通过script标签的src可以跨域请求的特性,加载资源,将加载的资源(通过一个方法名将数据进行包裹)当做是js脚本解析,定义一个回调函数(是怎么实现的?),获取传入的数据。我们使用jsonp是因为Jsonp的兼容性比较好,并且在请求完毕后可以通过callback的方式回传结果。但jsonp有一个缺点是只支持get请求而不支持post等其他类型的http请求。

     

    这样我们解决了浏览器访问当前页面去加载后台系统数据出现的跨域问题,但是另一个问题又来了,其他系统该如何得到调用后台系统的数据呐?我们想可以发送http请求来访问后台数据,我们想到的是使用httpclient来解决此问题,因为httpclient可以使用java代码模拟浏览器发送http请求(get方法如何传递参数?定义uribuilder对象,在uribuilder里设置参数,以key和value,都是string类型的,然后将uribuilder放到uri中,在后将uri讲给httpget请求。Post方法如果传输数据?模拟表单提交,将数据封装到list集合中,然后将集合数据放入构造的表单实体中,在将表单实体请求放到httppost对象中)。向外抛出一个接口,执行过程是:1、创建httpclient对象2、构建请求对象post ,get请求3、如果有参数,就去构造请求参数 

           3.1 get

           使用uribuilder去构造请求参数

           3.2 post

            构建表单实体,把表单实体放入到 post请求对象中。

    4、执行请求 ,并且接受响应

    5、处理响应结果

    6. 释放连接。无论执行方法是否成功,都必须释放连接。

    HttpClient实现认为是线程安全的。

    每次连接发起Http请求的时候都会重新建立连接(经历3次握手),用完就会关闭连接(4次挥手),这样会消耗很多时间,所有我们采用了连接池。如果不采用连接池,每次连接都会打开一个端口,在大并发的情况下系统的端口资源很快就会被用完,导致无法建立新的连接。

     

    像项目中首页的大广告和商品类目这些不需要经常修改的数据,如果用户每次刷新页面的时候都要去数据库中查询,这样会浪费资源和增加数据库的压力。所以我们想当把这些数据添加到一个缓冲中,用户去访问的时候,先去缓存中命中,如果命中失败,再去数据库中查询,然后把查询到的数据添加到缓存中。目前比较主流的缓存技术有Redis和Memcached,单纯从缓存命中的角度来说,Memcached要高一些,可Redis和Memcache的差距其实并不大,但Redis提供的功能更加强大一些,读写速度也很快。所以我们选用了redis来缓存数据。Redis把数据以key—value的形式缓存到内存中,并提供了多种数据存储类型(string,set,list,hash等),还自身提供了持久化功能(2种),还可以把数据备份到磁盘中(Redis的SAVE命令用于创建当前 Redis 数据库的备份),防止redis宕机时的数据丢失。(会周期性的把更新的数据写入磁盘或者把修改操作写入追加的记录文件,并且在此基础上实现了master-slave(主从)同步)。我们使用的是spring与jedis整合的客户端,可以利用jedis做分片式集群,解决了redis内存受限的问题。

     

    之前实现的登录和注册是在同一个tomcat内部完成,而现在系统架构是每一个系统都是由一个团队进行维护,每个系统都是单独部署运行一个单独的tomcat,所以,不能将用户的登录信息保存到session中(多个tomcat的session是不能共享的)(session共享?),所以我们需要一个单独的系统来维护用户的登录信息。我们是这样做的,用户去登录页面登录,去数据库查询是否有该用户,如果没有提示用户,如果有就把用户信息保存到redis中,并生成一个token保存到cookie中,

     

     

    在后台管理系统中采用了Maven的多模块化的管理,其中采用了水平切分的方式(垂直与水平划分的区别:垂直:功能模块明确,层次不够清晰,代码重用性差。水平:层次清晰,代码重用性高,独立维护。),将各层分层开发,这样做的好处是代码重用性高,层次清晰,易于独立维护。系统内部接口调用采用Httpclient,接口提供端采用RESTful方式的接口定义(一种软件架构风格,设计风格而不是标准,只是提供了一组设计原则和约束条件),系统之间的通知机制采用MQ的方式,使用RabbitMQ的实现,使用了RabbitMQ的消息订阅模式的消息机制;部署方面,采用了Nginx+tomcat的模式,其中nginx的作用一方面是做反向代理、负载均衡、另一方面是做图片等静态资源的服务器;

    在此项目中我主要负责后台管理模块,主要实现商品管理和商品规格参数管理,对商品和商品规格进行CRUD操作。;在实现前台调用后台数据时,为了实现系统间的调用,便使用了httpclient技术来实现此功能,在后台提供了需要调用的接口。(httpclient介绍,工作原理,优缺点)。如果在后台对商品进行操作,为了使前台数据与后台数据实现同步,我们使用了RabbitMQ消息队列机制实现商品同步功能(RabbitMQ介绍,工作原理,优缺点);

    在此项目中,我还参与了购物车模块的开发。在开发这个模块时候,我们考虑了会员在未登录和登录两种情况下把商品加入购物车,后台如何该保存商品信息。

    在用户商品详情页点击加入购物车的时候,我们用了登录拦截器来判断用户是否登录;购物车首先标识要唯一,因为每个账号要对应一个购物车,在登录状态下,我们可以直接将数据保存到数据库中,使用用户的id表示自己购买的商品,但是如果在未登录状态下呢,或者对购车访问量大的时候,这个就存在弊端,因为这样高速的读写数据库,会对数据库的压力比较大,在这里我们就看看如何用Redis和RabbitMQ解决这个问题。

    一:登录状态下添加商品到购物车

     此时购物车是对应一个用户,很简单,就是将商品的数据插入数据库中即可,但是如果读写频繁的时候,就存在压力问题,此时我们可以使用Redis担任读的部分功能。

    在向数据库中插入数据的时候,使用RabbitMQ发送消息,然后有一个消息系统监听消息,将RabbitMQ中消息内容(插入数据库中的商品数据)保存到Redis中,但是此时Redis中我们该用什么存储结构,在Redis中存储结构有很多种,这里我们使用hash结构(介绍一下是如何利用hash结构保存商品数据的),在用户查询自己的购物车数据的时候,就不要到数据库中查询,而是直接从redis中将数据拿出来即可,这样数据库的读压力就被Redis分担出去了。

    二:未登录下加入购物车,登录下合并购物车

    在未登录状态下,没有指定的用户,此时购物车应该怎么分配,数据把偶才能在什么位置,这个其实也不难,我们可以将数据临时保存到Redis中,并不插入数据库中,因为此时没有对应的用户,Redis生成一个唯一的outerKey,保存到cookie中,每次添加商品,带上这个cookie,这样就保证每次加入同一个购物车,这个数据会被保存一段时间,当用户登录的时候,我们该如何将未登录状态下的购车和登录状态下的购车数据合并呢。这个就需要使用到消息了,我们可以发送一个消息给后台系统,将未登录状态下的outerKey传递给后台系统,后台系统到Redis中查询到未登录状态下的购物车,将购物车中的数据插入到数据库中,和之前登录状态下的购车数据合并,重新缓存到Redis中,此时缓存到Redis中的购物车是和未登录状态不同的,因为这个缓存的购物车是有主人的,未登录状态下缓存的临时购物车就保存到了登录用户的购物车。

    (自己设两个自问自答的问题) 

    数据库也可以做读写分离,为什么要使用Redis担任读呢,直接使用读写分离不就可以了吗?

    数据库的读写分离的确可以解决问题,但是像Redis这种非关系型数据库比较明显的优点就是数据处理效率高,读写分离和Redis的效率相比较来说,个人感觉还是使用Redis可靠。

    Redis担任读的问题,当像双11这种大量访问的情况下,Redis会不会崩溃?

    这个问题我也想过,这个我们可以考虑使用Redis的集群,这样就可以解决大部分的问题。

    展开全文
  • 电商项目介绍---说的很

    千次阅读 2017-11-13 20:28:39
    在杭州做了两年开发,大大小小参与过三个项目的开发,一个是某公司内部的人员管理系统,一个是物流项目,最近做的是一个电商项目。 前两个项目采用的是ssh框架搭建的,最近的项目采用的是ssm框架搭建的。在实际...
  • 【vue】使用vue-cli4.0快速搭建一个项目

    万次阅读 多人点赞 2019-10-25 10:38:43
    最近公司的项目终于到了空闲期,而闲不住的我终于目标放到了项目的迁移上面 因为公司的项目比较早的原因(虽然当时vue-cli也出来了段时间,但是不敢轻易尝试啊!) 所以使用的环境还是 vue2.x版本的,而又因为...
  • 已经写的Vue项目转成uni-app项目

    万次阅读 多人点赞 2019-01-10 15:45:25
    介绍一下我写的vue项目 ...(具体原因:相信了uni-app吹的牛b,一个套代码可以适用,安卓,IOS,微信小程序 经过了解,发现uni-app项目不支持vue-router。所以我的工作量就比较大了。 由于我的项目是采...
  • 如何看一个Java项目

    万次阅读 2017-06-07 10:21:57
    1项目介绍,wiki,源码包的readme等。 2明确项目的目标,应用场景,甚至是用到的技术方案。 3根据源码包的架构,以及了解到的用到的技术方案,大概猜测一下各个模块的功能。 4同样浏览所有的源码文件,通过文件...
  • JAVA面试技巧之项目介绍

    万次阅读 多人点赞 2019-01-08 11:11:35
    项目介绍是有套路的,面试时,要将简历中的项目准备!   如何介绍简历中的项目呢?看下面何妙计—— 我们在跟面试官讲解的时候,讲解项目一定要围绕着以下几方面: 1、项目名称 2、开发时间(这...
  • 系列自动化测试的开源项目介绍

    万次阅读 多人点赞 2018-11-21 14:14:22
    在如今开源的时代,我们就不要再闭门造车了,热烈的拥抱开源吧!...、性能自动化测试 1、项目名称:基于Jmeter实现的在线压测平台和在线管理Jmeter脚本系统 项目简介: 本项目基于renren-f...
  • JavaWeb项目介绍

    万次阅读 2018-03-29 22:19:54
    web项目:通俗的说就是在服务器上跑的项目,页面是通过服务器上的程序运算所得到的结果。常见的web项目按计算机语言分,有:Java Web(Java EE)、ASP.Net、PHP项目。JavaWeb项目:顾名思义就是后台用java代码写的web...
  • TFS源代码控制系统的基本场景如何把一个项目添加到源代码管理中如何与服务器同步如何做Check-In如何做分支与合并什么是上架与下架 我们知道工作项是项目管理的基本元素,但是一个项目的成功,光有工作项还是不够...
  • Maven(一)如何用Eclipse创建一个Maven项目

    万次阅读 多人点赞 2017-09-30 00:05:13
    Apache Maven 是一个项目管理和整合工具。基于工程对象模型(POM)的概念,通过一个中央信息管理模块,Maven 能够管理项目的构建、报告和文档。 Maven工程结构和内容被定义在一个 xml 文件中——pom.xml,是 ...
  • 分享一个我开发的MVVM架构的开源小项目

    万次阅读 多人点赞 2019-03-01 07:56:31
    大家,今天跟大家分享一个我编写的MVVM架构的开源小项目。话说这个小项目已经提前跟大家预热很久了,也是被不少朋友催了很多次。我之前在公众号里透漏过这个项目能够帮助大家更地理解MVVM架构,当然我也希望确实...
  • Qt5.7+Opencv2.4.9人脸识别()项目介绍

    万次阅读 热门讨论 2017-05-04 09:58:57
    Qt5.7+Opencv2.4.9人脸识别()项目介绍
  • 电影售票系统项目介绍

    万次阅读 2017-06-13 15:22:22
    电影售票系统项目介绍 电影售票系统是基于web的电影购票网站,注册登录用户可在线浏览热映电影信息,电影排行榜,查看附近影院,支持在线购票,实时支付等。该系统UI界面简洁大方,操作简单,实时更新电影影院数据...
  • blogs博客系统项目介绍

    万次阅读 2019-03-18 12:44:15
    blogs博客系统项目介绍blogs项目简介项目展示项目详述 blogs 一个简易的博客系统 GitHub地址:点击查看项目源码 Gitee地址:点击查看项目源码 项目简介 该项目是我之前学习的一个项目,一个较为完整的博客系统,具备...
  • 作者|鲁佳出品|阿里巴巴新零售淘系技术部导读:甘特图是一个非常实用的项目管理工具。在阿里的日常项目工作中,不管是 PD 还是开发同学,大家普遍都会遇到需要规划项目工作安排...
  • 项目管理工具WBS CHART PRO介绍

    万次阅读 2014-12-04 10:52:36
    工作结构分解(WBS)是对项目范围的一种逐级分解的层次化结构编码。依据美国项目管理协会的PMBOK,分解指主要可交付成果分成...给大家推荐一个的工具,这就是美国CRITICAL TOOLS公司开发的WBS CHART PRO软件。WBS
  • 一个项目Web工程看Eclipse如何导入Gradle项目

    万次阅读 热门讨论 2016-02-21 17:07:40
    概述上一节,我们说了...部分的github上的示例代码也在用Gradle构建,如果还是只能用maven,那么很多项目都只能用肉眼看,不能真正的调试起来,更精细的去看运行时的状态,对于理解代码的思想还是有不小障碍的。
  • Java程序员:整个项目的具体开发流程介绍

    万次阅读 多人点赞 2019-06-19 15:57:36
    对于程序员这个“质朴”的职位来说,说的再多,也没有做的多来的实在。 就以程序员找工作为例,哪怕...你可以在网上搜索一个中等大小的项目整个流程摸透,代码搞清楚,逻辑理清楚,然后再写在简历上。这样做,至...
  • 如何用Eclipse创建一个Maven项目

    万次阅读 2018-12-08 10:10:31
     Apache Maven 是一个项目管理和整合工具。基于工程对象模型(POM)的概念,通过一个中央信息管理模块,Maven 能够管理项目的构建、报告和文档。  Maven工程结构和内容被定义在一个 xml 文件中——pom.xml,是 ...
  • 如何在面试中介绍自己的项目

    千次阅读 2019-04-24 15:20:58
    常见的问法是,说下你最近的(或最拿得出手的)一个项目。 根据我们的面试经验,发现有不少候选人对此没准备,说起来磕磕巴巴,甚至有人说出项目经验从时间段或技术等方面和简历上的不匹配,这样就会造成如下的后果...
  • Java面试之项目介绍

    千次阅读 2020-03-04 17:04:46
    1.请描述下你做的项目: XXX系统是什么什么,主要目的是XXX...mvc是种设计模式,他强制性的应用程序的输入、处理和输出分开。mvc中的模型、视图、控制器分别担任着不同的任务。 视图:视图是用户看到并与之交互...
  • 赞,看看,习惯!本文 GitHub https://github.com/OUYANGSIHAI/JavaInterview 已收录,这是我花了3月总结的一线大厂Java面试总结,本人已拿腾讯等大厂offer。 上面文章写完已经0点过后了,就没有精力写完...
  • 大屏监控系统实战(1)-项目介绍

    千次阅读 多人点赞 2020-01-21 15:32:27
    个项目的起源非常的偶然,源于今年我有幸入选2019年CSDN博客之星年度总评选,并且排名一直还不错,在前20的行列中,而排名第的天元浪子大大,用python分析了波投票情况,我本人对自己也非常感兴趣,但因为我...
  • IntelliJ IDEA 项目相关的几重要概念介绍 发布于 2015-09-23 23:02:48 | 11 次阅读 | 评论: 0 | 来源: 网络整理 本篇内容为大家提供的是IntelliJ IDEA 使用教程中的IntelliJ IDEA 项目相关的几重要...
  • 如何在面试中介绍自己的项目经验

    千次阅读 2018-12-17 13:35:27
    常见的问法是,说下你最近的(或最拿得出手的)一个项目。 根据我们的面试经验,发现有不少候选人对此没准备,说起来磕磕巴巴,甚至有人说出项目经验从时间段或技术等方面和简历上的不匹配,这样就会造成如下的后果...
  • Otter-入门篇1(阿里开源项目Otter介绍)

    万次阅读 2016-07-27 16:38:32
    今天笔者又来开坑了,这次开坑的对象呢是阿里的一个开源项目Otter,Otter它是一个数据同步解决方案,可以解决本地跨网络跨机房跨地域的数据同步问题,并且拥有可观的效率,web管理工具等特点,而且背景也很优秀,据说阿里...
  • 手把手带你撸一个校园APP(一):项目简介

    万次阅读 多人点赞 2018-06-23 23:22:02
    这个项目很早之前就在做,是为我大学母校(河北科技师范学院)做的一个项目,所以还是有很深的感情的。整体项目基于 Bmob 后端云来实现,其实功能和技术都并不算复杂,自己记录一下,也给需要的朋友们提供一些参考和...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 680,380
精华内容 272,152
关键字:

怎么把一个项目介绍好