系统构建的若干通用方面

这几年做项目的过程中,杂七杂八的记录在wiki中的东东,没啥条理,罗列整理一下。


ORM Entity对象与业务对象的互相转换, 可以考虑采用成熟的。框架,如Dozer(http://dozer.sourceforge.net/), 当业务情况比较复杂,应用领域对象设计系统时, 由于领域对象与DB Entity的矛盾, 存在大量的对象复制操作,所以使用此类框架能节省很多功夫。

- MySQL:

SELECT * FROM TABLE1 
WHERE [......] 
ORDER BY [......] LIMIT [low-index], [up-index]

- Oracle: 

SELECT * FROM (
    SELECT A.*, ROWNUM RN 
    FROM (
            SELECT * 
            FROM TABLE1 
            WHERE [.....] 
            ORDER BY GMT_CREATE DESC
        ) A
    ) 
WHERE RN BETWEEN [low-index] AND [up-index];

- MSServer:

SELECT * 
FROM (
        SELECT ROW_NUMBER() OVER (ORDER BY [....]) rownum, * 
        FROM TABLE1
     ) a 
WHERE rownum > [low-index] AND rownum < [up-index]
    

对于从查询页面A跳转到其他页面B。时, 如果B页面有返回按钮, 则需要考虑如果实现返回后, 恢复A页面之前的查询条件中的已填入值。该问题引出另外一个问题: 页面的查询参数如何在页面之间传输,最好的方式是直接采用URL + 参数, google, 百度等均采用。

必须确定系统中不同数据采用的删除方式(物理删除和逻辑删除)。 通常,对于财务, 账单, 用户, 操作记录, 已经系统的核心数据等等采用逻辑删除。 通常一个系统的核心数据, 在程序层面体现在其核心领域对象上, 比如: 电子商务系统核心对象是商品订单, 航空订票系统核心对象是机票订单, 财务系统核心对象是账单, 企业公文流转系统核心对象是公文等等, 如上的核心对象数据在各自的系统中都应该采用逻辑删除, 而非物理删除。

数据库主键生成策略的选择。主键生成函数如果存在重复概率,那么必须在相关资源插入的时候,将主键生成和数据保存做同步处理, 保证两者在一个同步块中,否则在多并发多线程时会产生数据库主键插入冲突;如果主键生成随机无重复, 则不必要。

无论对于Formt提交还是Ajax提交而言, 都存在重复提交的问题。 form提交可以采用struts等框架自带的token机制。 而对于ajax提交有两种主要的方式: 一种是发送请求前,设置button为disabled, 要求必须是button触发; 另外一种是采用ajax同步提交, 具体有jquery的async设置等等。

对于一个系统而言, 一些核心业务数据的“来源”在通常需要区分, 这样便于记录查询数据问题。 比如:对于平台型电商系统(比如淘宝。),订单的来源有可能是(1)本平台预定 。(2)订单开放API预定。再比如:对于契约系统而言,契约数据可能来源于:(1)从外部通过Excel/CSV导入 (2)通过系统页面创建提交

对于系统中的核心操作数据的增删改操作, 必须。记录所有的输入输出, 尤其删除时, 需要记录整个信息实体,而非通常的主键值, 比如: 电子商务系统中订单的操作, 物流系统中订单的操作, 航空系统中航程单的操作, 。金融系统中账户操作, 账单系统中账单的操作。

系统主键生成策略主要分两种形式: a. 无序组合(完全随机数生成,如GUID); b. 完全有序组合(如自增键, 毫秒数等); C. 无序组合 + 有序组合(如主键=单位I。D+自增字段值)。三种情况各有长短处, 。通常对于业务型数据(如订单, 公文),采用 c的方式比较普遍, 原因是希望通过主键(订单号, 公文号)能尽可能的确立较多的信息(如 所属单位, 发布时间等等)

  1. 允许输入 ,直接按原文(输入)存储进数据库,展示的时候,进行转义,如<script> 转义为 &#60script&#62, 那么浏览器展现时直接以文本方式展示为<script>,而不进行“解释”。具体显示时,JSP可以使用fn:escapeXml,js可以采用对应的Js库(如:mhandbook项目的xss-filter)。

  2. 不允许输入,在JS和后端进行字符判定,如添加Filter对所有的Request参数(form和Get)进行判定,出现敏感字符(可定义黑名单)即可抛出异常。此处不可以转义存储,因为,转义后可能超出数据库相应字段的最大长度限制,导致SQL异常。

方式一更加可取,对用户也更加友好。

一些成熟Server端解决方案:

一些成熟前端解决方案:

  • CSRF防御,必须先保证先防御XSS(相对而言,XSS更难防御),数据改变操作必须用POST,防御三种方式:
    1. Referer判断:可以伪造,所以并不安全。

    2. 验证码:用户体验差。

    3. Token:最可靠。但大型服务时,需要一台token生成及校验服务器;需要更改所有表单添加字段。中小型服务还是足够了。原理:无法通过ajax等方式获得外域页面中的 token值,xmlhttprequest需要遵守浏览器同源策略。

    一些成熟解决方案:

  • 禁止网站被恶意反向代理(Ifram嵌入):

    1. 客户端脚本: if (top.location != self.location) { top.location=self.location; } 缺点:对搜索引擎不友好。

    2. 服务端设置: Apache和Ngix有对应的设置。

  • Referer是可以被客户单伪造的(如某些浏览器插件),因此,不能够将Referer用在一些非常关键的检查上。Referer两个最常用的用途:

    1. 防盗链 :在WEB服务器(Apache/Ngix)可以设置某些资源(图片)只能被本域名访问

    2. 访问统计:统计每一个页面都是从哪些入口页面过来的