• 网上商城后台架构设计


    一、视图层选型

    关于视图层技术的选择,很多年来,也是争议颇多的一个话题。对于选择.NET技术的公司来说,这个问题还是很好选择的,跟着微软就可以了。微软阵营的问题是选择太少,出了问题不知道怎么办,只能网上找控件,碰到收费的控件,又爱又恨,最后还是放弃,不了了之。痛恨微软和别人的不开源,自己的代码却从不给人看,这是微软阵营的特点。

    如果说微软阵营抱怨封闭不开源,选择太少的话,那么J2EE阵营最大的问题则是选择太多了,不仅普通程序员无法从纷繁复杂的各类开源框架中做出正确的选择,即使对于系统架构师这类老手,从数十种开源框架中,找到符合自己公司和项目特点的那个,也是相当挠头的。比如说现在最流行的Ajax开源框架JQuery,仅最基本最常用的DataGrid控件,解决方案就有十几个。如何从这十几个DataGrid控件中选择最合适的一个,也就是所谓的“银弹”,是相当的痛苦啊。当然,开源的源代码也多得是,可惜的是绝大部分程序员从来不看别人的源代码,虽然张口闭口大家都在谈着StrutsSpringHibernate,有几个人把他们的源代码读过一遍?甚至开发文档阅读过一遍?

    我教给大家一个框架的秘诀,如果自己实在不知道如何选择,那就遵循两个原则:一是是否得到IBMOracle、微软这类大型软件公司的支持;二是别问为什么,就选择大家最常用的,随大流就可以了。

    对于UI这一层的选择,J2EE阵营有3类选择。

    1Ajax:包括JQueryExtJs以及ZKAjax框架。国内的用友、金蝶、阿里软件等和其他一些传统管理软件转过来的公司,一般会采用ExtJs作为自己视图层解决方案。

    2FlexFlex最终生成的还是FlashFlex的出现,是真正的富客户端解决方案(Rich Internet Application)。界面基于标准的XML标签,非常华丽,再加上功能强大的ActionScript,不仅适用于传统MIS开发,而且还可以开发网络游戏,像著名的网络游戏开心农场,就是基于Flash开发的。不过,Flash也面临巨大的挑战。首先是没有得到风头正猛的苹果公司的支持,Flash在移动开发领域,也遇到了强大的阻力。如果说苹果公司只是给了Adobe背后一刀,尚未伤其筋骨的话,那么微软在最新的技术路线图中,则明确表示IE9也将不再支持Flash,那么微软会不会给Adobe致命的一击?微软和苹果的理由是它们都将只支持HTML5.0

    3JSFJSF一般在大公司使用,比如Oracle经典的J2EE开发框架。不过,在国内由JSP转向JSF的公司并不多见。

    我这里给个建议,对于进销存MIS系统的开发,如果考虑跟以前的兼容,首选是ExtJS,其次是Flex,最后是ZKJBoss的企业级开发框架Seam,而对于网站类开发,则只选择JQuery就可以了。

    为什么我们还选择Flex作为自己的UI层技术解决方案呢?首先我们可以排除的是JSFJSF仅有少数公司在用,JSF是用Swing的解决思路去解决Web难题,Swing首先就在桌面领域败给了SWT,在Web领域,这个失败的技术架构,同样也没有得到大家的认可。那么在ExtJsFlex之间如何选择呢?我之所以选择Flex,是因为Flex支持Restful风格的技术架构。Flex跟后台的通信机制,事实上有3种:Remote ObjectWeb ServiceHttpService组件。第三种HttpService组件,就是Restful风格的。采用Restful后,后台接收数据的代码跟前台技术无关,这套代码同样可适用于ASPJSPPHP,只要它们支持Restful就可以了,真正可以做到mushup(混合语言)编程,这就是我所说的自己的“银弹”。当然,选择ExtJS你可以选择JSON格式的数据进行前后台通信。

    如果IE以后真的不支持Flash了,这个还真的是一个问题,好在我们的架构,跟视图层无关,视图层是随时可以替换掉的,目前来看,只有FlexRestful支持得最好,所以我们选择Flex作为自己的技术解决方案,而且不存在浏览器不兼容的问题。IEChrome以及Firefox等主流浏览器都是支持Flash的,而且Adobe也做了一个Flash转化为HTML格式的工具,Flash一样可以在iPAD上运行。

    二、构建自己的Struts

    本节我们将模仿Struts解决问题的思路,设计出自己的一套MVC框架。

    首先,我们先提出自己的需求,在满足这个特定需求前提下,再设计自己的“山寨轮子”。在提出自己的需求之前,我们要先明白使用我们这个框架的用户是谁。明确了自己的用户,才能更好地满足他们的需求,为他们服务。在这里,我们假设框架的用户就是自己公司或者对这个框架感兴趣的程序员。在明确了这个框架的使用者之后,我们再来看看它要满足的功能上的需求。

    Struts是一个MVC框架,视图层没有疑问了,指的是JSPASPPHP这类可以动态生成HTMLXML或其他格式文档的Web网页的语言。上面我们提到,Struts的伟大之处,在于它用SetGet这类面向对象的技术来存取网页数据,而不是以前的统统都是黑盒式的request.getParameter()方法。我们采用的是Restful技术架构,所以,对于View层,我们是没有自己特定选择的,JSPASPPHPFlex,理论上都可以满足,前提是这类脚本语言必须得有Restful风格的框架支持。Flex内置实现了Restful,所以我们这里采用Flex作为自己视图层的解决方案。对于Model层,我曾经面试过上百位程序员,问StrutsModel层指的是什么,回答正确的不到30%StrutsModel层,其实就是ActionFormStrutsMVC仅仅是经典J2EE框架Web层的MVC框架,所以它的Model层并不是指的J2EE的多层框架中的Model层。

    我们要重点介绍的是控制(Control)层,控制层是我们这个框架的核心。Struts的控制层其实是一个过渡层,它把网页数据自动转化为ActionForm,拿到了数据,我们再写自己的商业逻辑,通过多种运算,把结果保存到数据库当中。

    由于我们要做的是多租户的SaaS架构的MVC框架,所以与Struts要满足的用户需求还是非常不一样的。多租户意味着用户业务逻辑和界面有可能是不一样的。标准的进销存和网店系统,往往屏蔽掉了最终客户的特性需求和行业特点,试图一套软件走遍天下,这是不符合国情的,也是目前SaaS软件难以普及的一个重要原因。软件公司试图引导客户标准化作业,我认为是行不通的。我们将从另外一个角度,从技术架构上解决SaaS架构下客户个性化定制的问题。

    对于视图层,我们并不限制客户个性化定制自己的页面,所以,我们的Model层,一定不是有确认属性的ActionForm,我们必须支持动态的属性添加。这里我们选择HashMap。读者看到这里,可能会有疑惑,StrutsActionForm把我们从黑盒中解放出来,我们这次为啥又进入了一个黑盒HashMap当中?这句话问得好,这叫有破有立,为了要满足个性化的需求,所以我们要屏蔽确认的属性方法,只能用HashMap。否则,我们就不能满足这个特性。

    基于以上需求和原则,我们设计出自己的MVC架构。先看增加、修改、删除功能的实现,代码如下所示。

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

    <mappings>

    <url-mapping action="simplecreate.do" class="com.softbnd.jetblue.saas. webframework.action.SimpleCreateAction"/>  

    <url-mapping action="simpleupdate.do" class="com.softbnd.jetblue.saas. webframework.action.SimpleUpdateAction"/>

    <url-mapping action="create.do" class="com.softbnd.jetblue.saas.webframework. action.CreateAction"/>

    <url-mapping action="update.do" class="com.softbnd.jetblue.saas.webframework.action.UpdateAction"/>

    <url-mapping action="suspend.do" class="com.softbnd.jetblue.saas.webframework.action.SuspendAction"/>

    <url-mapping action="simplesuspend.do" class="com.softbnd.jetblue.saas. webframework.action.SimpleSuspendAction"/>

    <url-mapping action="remove.do" class="com.softbnd.jetblue.saas.webframework.action.RemoveAction"/>

    <url-mapping action="querycountry.do" class="com.softbnd.jetblue.saas. webframework.action.LogonQueryAction">

          <query SQL="select * from country "/>

    </url-mapping>

    <url-mapping action="queryprovince.do" class="com.softbnd.jetblue.saas. webframework.action.LogonQueryAction">

          <query SQL="select * from province order by seq "/>

    </url-mapping>

    <url-mapping action="querycity.do" class="com.softbnd.jetblue.saas. webframework.action.LogonQueryAction">

          <query SQL="select * from city where provinceno='?' order by seq" />

    </url-mapping>

    </mappings>

    其中,url-mapping标签表示我们把httpURL转换为Action。我们也要满足增加、删除、查询和修改动作的自动化。对于单表的增删和修改,我们定义几个缺省的类。

    1CreateAction类:满足单表的数据新增功能。

    2UpdateAction类:满足所有的修改功能,包括主子表连带的修改。

    3RemoveAction类:满足所有的删除功能,包括主子表连带的删除。

    再看查询功能的实现,代码如下。

    <url-mapping description="查询入库单"action="queryfeedin.do" class="com. softbnd.jetblue.saas.webframework.action.LogonQueryAction">

    <query SQL="select feedin.*,DATE_FORMAT(entrydate,'%Y-%m-%d') entrydate2, warehousename from feedin,warehouse where feedin.warehouseno= warehouse. warehouseno and feedin.tenantno in ('#tenantno#') and warehouse. tenantno in ('#tenantno#','0000000000')">

          <subquery SQL="select feedinlineitem.*,goodsname,gtname ,puname

          from feedinlineitem,goods,packageunit,goodstype

          where feedinlineitem.goodsno=goods.goodsno and goods.goodsunitno= packageunit.puno and goods.goodstypeno=goodstype.gtno

          and feedinlineitem.feedinno='?' and feedinlineitem.tenantno in ('#tenantno#') and goods.tenantno in ('#tenantno#') and packageunit.tenantno in ('#tenantno#') and goodstype.tenantno in ('#tenantno#','0000000000')"/>

          <parameter requestname="date1" name="entrydate" type="Date" op=" &gt;=" or=" feedin.status='0' "/>

          <parameter requestname="date2" name="entrydate" type="Date" op= "&lt;=" or=" feedin.status='0' "/>  

          <parameter requestname="feedinno" name="feedinno" type="String"/>

          <parameter requestname="status" name="feedin.status" type="String" op="="/>

        </query>

    </url-mapping>

    这是一个满足单表查询功能的标签。其中parameter是跟UI层查询参数密切相关的。UI层有多少个查询条件,这里就有多少个查询标签一一对应。Class则代表这个查询action的实现是默认的LogonQueryAction类,LogonQueryAction类能满足80%的查询需求。

    Query标签定义的是查询SQL语句,查询条件能跟parameter自动匹配上,从而动态生成SQL语句传给后台,并把结果放在一个HashTable表里。其类图如图1所示。

    1 查询类图

    以上这些类只是标签的具体实现,我们还需要一个runtime引擎把这些标签串起来,其类图如图2所示。

    其中,ControlServlet类负责截获所有后缀是abc.do或者abc.action的请求,并通过URLMappingsXmlDAO类,把XML文件解析为SubQueryLinkParameterQuery等标签,跟具体的SQL对应起来,并把请求转换到LogonQueryAction类,LogonQueryAction类负责动态解析SQL,把Parameter标签里面的参数动态转换为具体的查询语句,并交给后台的DAO处理,还包括分页查询等功能,从而自动实现一次完整的查询动作。

    由于我们是SaaS架构的,面向的是多租户,所以还有一个数据隔离的问题。对于数据隔离的实现,也有好几种架构可供选择。比如独立Schema,或者每个业务表增加一个租户ID等。如果你使用的是Oracle数据库,你的应用程序可能不需要做什么改变,只需要利用Oracle数据库的特性,就可以实现多租户下数据隔离的策略,前提必须是Oracle9i以后的版本,并且绑定到Oracle数据库之上。在这里,我们用最简单的方法实现数据隔离,就是每个业务表增加一个租户IDtenantid)。所以,我们每个SQL语句里面,每个表都会多出一个tenantid。也许有的读者会问,这么做个性化是满足了,但是性能上会不会有影响?是的,我们又回到了上面所述的“银弹”原则,当我们满足某个特定需求的时候,必然是以牺牲另外的特性为代价的,解析XML文件,动态调用Java类,肯定没有直接的Java静态编译和调用速度快。

    本文摘自电子工业出版社出版的《B2B2C网上商城开发指南——基于SaaS和淘宝API开放平台》一书。本书由邢波涛、郭娟著。

    相关文章:

    新一代电子商务发展趋势

    软件架构经验总结

    购买链接:当当网 卓越网

  • 相关阅读:
    洛谷 P1226 【模板】快速幂||取余运算 题解
    洛谷 P2678 跳石头 题解
    洛谷 P2615 神奇的幻方 题解
    洛谷 P1083 借教室 题解
    洛谷 P1076 寻宝 题解
    洛谷 UVA10298 Power Strings 题解
    洛谷 P3375 【模板】KMP字符串匹配 题解
    Kafka Shell基本命令
    Mybatis与Hibernate的详细对比
    MyBatis简介
  • 原文地址:https://www.cnblogs.com/broadview/p/2045471.html
Copyright © 2020-2023  润新知