从@蔡学镛看到的数据库的一些设计原则,可以考虑考虑.梳理数据库时,你会很惊讶地发现,各种数据都被塞进数据库,所以做数据库梳理的第一步是把它们区分出来,我的区分方式是:核心数据、业务数据、核心缓存数据、业务缓存数据、Session 数据。核心数据及其缓存都要再根据领域(domain)来区分,业务数据及其缓存都要再根据业务(business)来区分。梳理数据库或设计数据存储时,可以考虑数据的属性:1. 访问频率 (高/中/低)2. 读写比 (只读/读多/读少)3. 重要性 (重要/普通/不重要)4. 保密性 (保密/普通/不需保密)5. 数据笔数 (多/一般/少)6. 数据体积 (大/中/小)7. 一致性要求 (强/中/弱)8. 热点现象 (强/中/弱)9. 索引方式 ( ____ )
from: http://www.75team.com/archives/729什么是double cookie验证double cookie验证是利用cookie来验证请求合法性的一种方法。一个double cookie验证的url形如http://a.com?c=cookie向服务器请求的url带上cookie,服务器收到请求后,解析出url中的cookie和http请求带过来的cookie进行对比。如果一样就说明请求合法,不一样就可以判定请求非法。因为是用url中的cookie和http请求中的cookie进行验证,所以叫double cookie验证。验证原理url是客户端javascript生成的,javascript可以读取cookie。url可以从任意客户端访问,但是只有一个客户端的http请求带给服务器的cookie和url中的cookie是一致的。注意事项用来验证的cookie在每个客户端必须唯一用来验证的cookie不能是敏感信息。比如登录用户的token不能作为验证的cookie应用场景double cookie验证不能判断用户修改本地cookie然后再进行的访问。但是没有关系。举个应用场景。比如一个网站的 评分功能的请求是这样的http://a.com?score=100&id=10000如果有人把这个url发到网上,引诱其它用户来点击,那么就会生成大量的评分请求。这时就可以用double cookie验证了。因为很难让点击这个链接的人先修改本地cookie然后再点击链接使用建议有的同学喜欢把cookie做个变换,防止别人一眼看出来是用哪个cookie做的验证。没必要这样做,也不应该这样做。变换的方法一定会暴露在客户端验证的目的不是为了防止有意伪造对cooie做变换的方法如果不得当,可能会对cookie的结构造成依赖。如果哪天cookie的结构改变了,就会使验证代码失效,甚至报错。
from: http://www.plhwin.com/2014/06/13/web-security-sql/Web安全简史在Web1.0时代,人们更多是关注服务器端动态脚本语言的安全问题,比如将一个可执行脚本(俗称Webshell)通过脚本语言的漏洞上传到服务器上,从而获得服务器权限。在Web发展初期,随着动态脚本语言的发展和普及,以及早期工程师对安全问题认知不足导致很多”安全血案”的发生,至今仍然遗留下许多历史问题,比如PHP语言至今仍然无法从语言本身杜绝「文件包含漏洞」(参见这里),只能依靠工程师良好的代码规范和安全意识。伴随着Web2.0、社交网络、微博等一系列新型互联网产品的兴起,基于Web环境的互联网应用越来越广泛,Web攻击的手段也越来越多样,Web安全史上的一个重要里程碑是大约1999年发现的SQL注入攻击,之后的XSS,CSRF等攻击手段愈发强大,Web攻击的思路也从服务端转向了客户端,转向了浏览器和用户。在安全领域,一般用帽子的颜色来比喻黑客的善与恶,白帽子是指那些工作在反黑客领域的技术专家,这个群体是”善”的的象征;而黑帽子则是指那些利用黑客技术造成破坏甚至谋取私利造成犯罪的群体,他们是”恶”的代表。“白帽子”和”黑帽子”是两个完全对立的群体。对于黑帽子而言,他们只要找到系统的一个切入点就可以达到入侵破坏的目的,而白帽子必须将自己系统所有可能被突破的地方都设防,以保证系统的安全运行。这看起来好像是不公平的,但是安全世界里的规则就是这样,可能我们的网站1000处都布防的很好,考虑的很周到,但是只要有一个地方疏忽了,攻击者就会利用这个点进行突破,让我们另外的1000处努力白费。常见攻击方式一般说来,在Web安全领域,常见的攻击方式大概有以下几种:1、SQL注入攻击2、跨站脚本攻击 - XSS3、跨站伪造请求攻击 - CSRF4、文件上传漏洞攻击5、分布式拒绝服务攻击 - DDOS说个题外话,本来这篇文章一开始的标题叫做 「Web安全之常见攻击方法与防范」,我原本想把上面的这5种方法都全部写在一篇文章里,可是刚写完第一个SQL注入攻击的时候,就发现文章篇幅已经不短了,又很难再进行大幅度的精简,所以索性把Web安全分成一个系列,分多篇文章来呈现给大家,下面你看到的就是第一篇「Web安全之SQL注入攻击的技巧与防范」。SQL注入常见攻击技巧SQL注入攻击是Web安全史上的一个重要里程碑,它从1999年首次进入人们的视线,至今已经有十几年的历史了,虽然我们现在已经有了很全面的防范对策,但是它的威力仍然不容小觑,SQL注入攻击至今仍然是Web安全领域中的一个重要组成部分。以PHP+MySQL为例,让我们以一个Web网站中最基本的用户系统来做实例演示,看看SQL注入究竟是怎么发生的。1、创建一个名为demo的数据库:CREATE DATABASE `demo` DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci;2、创建一个名为user的数据表,并插入1条演示数据:CREATE TABLE `demo`.`user` (`uid` INT( 11 ) NOT NULL AUTO_INCREMENT PRIMARY KEY COMMENT '用户uid',`username` VARCHAR( 20 ) NOT NULL COMMENT '用户名',`password` VARCHAR( 32 ) NOT NULL COMMENT '用户密码') ENGINE = INNODB;INSERT INTO `demo`.`user` (`uid`, `username`, `password`) VALUES ('1', 'plhwin', MD5('123456'));实例一通过传入username参数,在页面打印出这个会员的详细信息,编写 userinfo.php 程序代码:<?phpheader('Content-type:text/html; charset=UTF-8');$username = isset($_GET['username']) ? $_GET['username'] : '';$userinfo = array();if($username){ //使用mysqli驱动连接demo数据库 $mysqli = new mysqli("localhost", "root", "root", 'demo'); $sql = "SELECT uid,username FROM user WHERE username='{$username}'"; //mysqli multi_query 支持执行多条MySQL语句 $query = $mysqli->multi_query($sql); if($query){ do { $result = $mysqli->store_result(); while($row = $result->fetch_assoc()){ $userinfo[] = $row; } if(!$mysqli->more_results()){ break; } } while ($mysqli->next_result()); }}echo '<pre>',print_r($userinfo, 1),'</pre>';上面这个程序要实现的功能是根据浏览器传入的用户名参数,在页面上打印出这个用户的详细信息,程序写的这么复杂是因为我采用了mysqli的驱动,以便能使用到 `multi_query` 方法来支持同时执行多条SQL语句,这样能更好的说明SQL注入攻击的危害性。假设我们可以通过 http://localhost/test/userinfo.php?username=plhwin 这个URL来访问到具体某个会员的详情,正常情况下,如果浏览器里传入的username是合法的,那么SQL语句会执行:SELECT uid,username FROM user WHERE username='plhwin'但是,如果用户在浏览器里把传入的username参数变为 `plhwin';SHOW TABLES-- hack`,也就是当URL变为 `http://localhost/test/userinfo.php?username=plhwin';SHOW TABLES-- hack` 的时候,此时我们程序实际执行的SQL语句变成了:SELECT uid,username FROM user WHERE username='plhwin';SHOW TABLES-- hack'_注意:在MySQL中,最后连续的两个减号表示忽略此SQL减号后面的语句,我本机的MySQL版本号为5.6.12,目前几乎所有SQL注入实例都是直接采用两个减号结尾,但是实际测试,这个版本号的MySQL要求两个减号后面必须要有空格才能正常注入,而浏览器是会自动删除掉URL尾部空格的,所以我们的注入会在两个减号后面统一添加任意一个字符或单词,本篇文章的SQL注入实例统一以 `-- hack` 结尾。_经过上面的SQL注入后,原本想要执行查询会员详情的SQL语句,此时还额外执行了 SHOW TABLES; 语句,这显然不是开发者的本意,此时可以在浏览器里看到页面的输出:Array( [0] => Array ( [uid] => 1 [username] => plhwin )[1] => Array ( [Tables_in_demo] => user ))你能清晰的看到,除了会员的信息,数据库表的名字`user`也被打印在了页面上,如果作恶的黑客此时将参数换成 `plhwin';DROP TABLE user-- hack`,那将产生灾难性的严重结果,当你在浏览器中执行`http://localhost/test/userinfo.php?username=plhwin';DROP TABLE user-- hack` 这个URL后,你会发现整个 `user` 数据表都消失不见了。通过上面的例子,大家已经认识到SQL注入攻击的危害性,但是仍然会有人心存疑问,MySQL默认驱动的mysql_query方法现在已经不支持多条语句同时执行了,大部分开发者怎么可能像上面的演示程序那样又麻烦又不安全。是的,在PHP程序中,MySQL是不允许在一个mysql_query中使用分号执行多SQL语句的,这使得很多开发者都认为MySQL本身就不允许多语句执行了,但实际上MySQL早在4.1版本就允许多语句执行,通过PHP的源代码,我们发现其实只是PHP语言自身限制了这种用法,具体情况大家可以看看这篇文章「PHP+MySQL多语句执行」。实例二如果系统不允许同时执行多条SQL语句,那么SQL注入攻击是不是就不再这么可怕呢?答案是否定的,我们仍然以上面的user数据表,用Web网站中常用的会员登录系统来做另外一个场景实例,编写程序login.php,代码如下:<?phpif($_POST){…
from: http://robbinfan.com/blog/38/orm-cache-sumupORM缓存引言从10年前的2003年开始,在Web应用领域,ORM(对象-关系映射)框架就开始逐渐普及,并且流行开来,其中最广为人知的就是Java的开源ORM框架Hibernate,后来Hibernate也成为了EJB3的实现框架;2005年以后,ORM开始普及到其他编程语言领域,其中最有名气的是Ruby on rails框架的ORM - ActiveRecord。如今各种开源框架的ORM,乃至ODM(对象-文档关系映射,用在访问NoSQLDB)层出不穷,功能都十分强大,也很普及。然而围绕ORM的性能问题,也一直有很多批评的声音。其实ORM的架构对插入缓存技术是非常容易的,我做的很多项目和产品,但凡使用ORM,缓存都是标配,性能都非常好。而且我发现业界使用ORM的案例都忽视了缓存的运用,或者说没有意识到ORM缓存可以带来巨大的性能提升。ORM缓存应用案例我们去年有一个老产品重写的项目,这个产品有超过10年历史了,数据库的数据量很大,多个表都是上千万条记录,最大的表记录达到了9000万条,Web访问的请求数每天有300万左右。老产品采用了传统的解决性能问题的方案:Web层采用了动态页面静态化技术,超过一定时间的文章生成静态HTML文件;对数据库进行分库分表,按年拆表。动态页面静态化和分库分表是应对大访问量和大数据量的常规手段,本身也有效。但它的缺点也很多,比方说增加了代码复杂度和维护难度,跨库运算的困难等等,这个产品的代码维护历来非常困难,导致bug很多。进行产品重写的时候,我们放弃了动态页面静态化,采用了纯动态网页;放弃了分库分表,直接操作千万级,乃至近亿条记录的大表进行SQL查询;也没有采取读写分离技术,全部查询都是在单台主数据库上进行;数据库访问全部使用ActiveRecord,进行了大量的ORM缓存。上线以后的效果非常好:单台MySQL数据库服务器CPU的IO Wait低于5%;用单台1U服务器2颗4核至强CPU已经可以轻松支持每天350万动态请求量;最重要的是,插入缓存并不需要代码增加多少复杂度,可维护性非常好。总之,采用ORM缓存是Web应用提升性能一种有效的思路,这种思路和传统的提升性能的解决方案有很大的不同,但它在很多应用场景(包括高度动态化的SNS类型应用)非常有效,而且不会显著增加代码复杂度,所以这也是我自己一直偏爱的方式。因此我一直很想写篇文章,结合示例代码介绍ORM缓存的编程技巧。今年春节前后,我开发自己的个人网站项目,有意识的大量使用了ORM缓存技巧。对一个没多少访问量的个人站点来说,有些过度设计了,但我也想借这个机会把常用的ORM缓存设计模式写成示例代码,提供给大家参考。我的个人网站源代码是开源的,托管在github上:robbin_siteORM缓存的基本理念我在2007年的时候写过一篇文章,分析ORM缓存的理念:ORM对象缓存探讨 ,所以这篇文章不展开详谈了,总结来说,ORM缓存的基本理念是:以减少数据库服务器磁盘IO为最终目的,而不是减少发送到数据库的SQL条数。实际上使用ORM,会显著增加SQL条数,有时候会成倍增加SQL。数据库schema设计的取向是尽量设计 细颗粒度 的表,表和表之间用外键关联,颗粒度越细,缓存对象的单位越小,缓存的应用场景越广泛尽量避免多表关联查询,尽量拆成多个表单独的主键查询,尽量多制造 n + 1 条查询,不要害怕“臭名昭著”的 n + 1 问题,实际上 n + 1 才能有效利用ORM缓存利用表关联实现透明的对象缓存在设计数据库的schema的时候,设计多个细颗粒度的表,用外键关联起来。当通过ORM访问关联对象的时候,ORM框架会将关联对象的访问转化成用主键查询关联表,发送 n + 1条SQL。而基于主键的查询可以直接利用对象缓存。我们自己开发了一个基于ActiveRecord封装的对象缓存框架:second_level_cache ,从这个ruby插件的名称就可以看出,实现借鉴了Hibernate的二级缓存实现。这个对象缓存的配置和使用,可以看我写的ActiveRecord对象缓存配置 。下面用一个实际例子来演示一下对象缓存起到的作用:访问我个人站点的首页。 这个页面的数据需要读取三张表:blogs表获取文章信息,blog_contents表获取文章内容,accounts表获取作者信息。三张表的model定义片段如下,完整代码请看models :class Account < ActiveRecord::Base acts_as_cached has_many :blogsendclass Blog < ActiveRecord::Base acts_as_cached belongs_to :blog_content, :dependent => :destroy belongs_to :account, :counter_cache => trueendclass BlogContent < ActiveRecord::Base acts_as_cachedend传统的做法是发送一条三表关联的查询语句,类似这样的:SELECT blogs.*, blog_contents.content, account.name FROM blogs LEFT JOIN blog_contents ON blogs.blog_content_id = blog_contents.id LEFT JOIN accounts ON blogs.account_id = account.id往往单条SQL语句就搞定了,但是复杂SQL的带来的表扫描范围可能比较大,造成的数据库服务器磁盘IO会高很多,数据库实际IO负载往往无法得到有效缓解。我的做法如下,完整代码请看home.rb :@blogs = Blog.order('id DESC').page(params[:page])这是一条分页查询,实际发送的SQL如下:SELECT * FROM blogs ORDER BY id DESC LIMIT 20转成了单表查询,磁盘IO会小很多。至于文章内容,则是通过blog.content的对象访问获得的,由于首页抓取20篇文章,所以实际上会多出来20条主键查询SQL访问blog_contents表。就像下面这样:DEBUG - BlogContent Load (0.3ms) SELECT `blog_contents`.* FROM `blog_contents` WHERE `blog_contents`.`id` = 29 LIMIT 1DEBUG - BlogContent Load (0.2ms) SELECT `blog_contents`.*…
一篇很不错的进行加密的文章!from: http://www.oschina.net/news/52976/hashing-or-encrypt对于网站来说, 再没有什么比用户信息泄露更让人尴尬的了。 尤其是当存有用户密码的文件如果被黑客获取, 对网站的安全和用户的信心来说都是巨大的打击。 如最近的Ebay泄密事件和小米的用户数据泄露事件。 保证用户信息安全首先需要正确理解对于用户密码的安全控制和保护。 这里OWASP的主席Michael Coates最近的一篇关于一些基本概念的介绍能够帮助开发人员更好的理解现代Hashing算法和加密对于用户密码保护的作用。 安全牛编译如下:在过去几个月, 我们看到了一些严重的数据泄露事件, Ebay和Adobe的数据泄露事件影响了几百万用户。 Snapchat也遭受到了数据泄露事件的影响。 每一次密码泄露事件后, 人们都会问同一个问题, 这些密码的存储是不是安全? 不幸的是, 这个看上去简单的问题其实并不好回答。尽管在很多情况下, Hashing和加密都能够满足安全存储的需要, 对于在线应用而言, 很多情况下, 对于用户密码的安全存储往往只有一种正确的方案。 Hashing.是通过一个不可逆的杂凑函数计算出一个Hash值, 而通过这个值无法逆向计算出输入值(比如用户密码)。 对称加密则是采用密钥进行加密计算, 这是一种可逆的运算。 任何人如果有了密钥, 就能够解密出原始明文。下表是Hashing和对称加密的对比Hashing对称加密不可逆函数可逆运算能够逆向算出初始值不能可以对于现代杂凑算法而言, 从Hash值逆向算出输入值非常困难。 参见下面关于彩虹表,盐化等的讨论对称加密就是设计来是的任何拥有密钥的人能够解密出原始明文其他需要考虑的方面杂凑算法的选择加密算法的选择对每个用户进行盐化保护密钥显示第 1 至 6 项结果,共 6 项当在线应用收到一个用户名和一个密码后, 就以密码为输入到杂凑函数中去得出一个Hash值, 然后用这个Hash值与数据库中存储的该用户的密码Hash值做比较, 如果两个Hash值相同, 就可以认为用户提供了有效的用户名和密码。 采用Hashing的好处是, 应用不需要存储用户的明文密码, 只需要存储Hash值。在线应用如何利用密码的Hash值来认证用户下图就是关于采用Hashing方式的简单描述:那么, 所有杂凑算法都能用吗? 不是的, 事实上, 杂凑算法中不同的算法的差别很大, 并不是所有的杂凑算法都适合存储密码。说起来可能有点出人预料, 早期的杂凑算法速度过快, 黑客们尽管不能通过Hash值逆向计算出原输入值, 但是黑客们可以通过暴力破解的方式遍历所有可能的密码组合来尝试能够能够“碰撞”到用户密码的Hash值。 为了避免这种威胁, 现代的杂凑算法能够通过多重迭代, 使得在每次Hash计算时产生一些延时, 对单次Hash计算, 这样的延时基本没有任何影响, 而对于黑客的暴力破解来说, 几百万次计算的延时能够被放大几百年, 这样到使得暴力破解基本不现实的地步。在Hashing中, 最好采用针对每个用户的盐化方式, 通过对用户密码添加一个随机字符串(随机字符串可以是显式存储), 这样可以相同的密码产生相同的Hash值, 这样, 攻击者可以下载一个巨大的存有事先计算好Hash值的查找表, 也叫做彩虹表。 通过Hash值, 反向查找对应的输入值。而通过下面两个表格可以看出, 通过对不同用户进行不同的盐化, 同样的密码就会出现不同的Hash值, 这样使得攻击者利用彩虹表进行攻击变得困难。没有盐化用户名密码Hash值Joepassword123xyfkdl323...Suepassword123xyfkdl323...**盐化后**用户名密码盐化字符串Hash值Joepassword12348a023jl2…ied390fl2...Suepassword1239fh3ls321…40akdl23…**类似于账户锁定的机制对于密码存储的模式有什么影响吗?**简单的回答, 就是, 没有影响。 对密码的安全存储是为了提供在密码文件被盗取后的防护。 黑客对于密码Hash的攻击是一种离线攻击。 也就是说, 密码文件已经被盗取, 黑客可以利用自己的计算机通过尝试不同的密码来找出密码。 由于是离线攻击, 账号锁定或者验证码之类的安全机制已经没有作用了。 这些机制只有在针对网站服务器的在线登录页面攻击时才会起作用。对于密码存储, 采用对称加密而不是Hashing的风险在哪里?对称加密的设计就是一个可逆的运算, 这意味着在线应用必须能够访问到密钥, 并且在每次密码验证时都要使用。 如果加密后的密码被窃取的话, 黑客需要获取对称加密的密钥, 而一旦密钥被破解出来, 不管是通过某种方式泄露出来, 或者一些弱的密钥被暴力方式破解出来, 所有的密码都会被黑客获得。总结对于密码的安全存储来说, 理解对称加密与Hashing的区别非常重要。 一些如PBKDF2, bcrypt以及scrypt等算法都采用的每用户盐化以及多重迭代的Hashing方式以安全存储密码。互联网已经日益成为重要的用户信息存储的场所。 网站开发人员及网站老板们需要尽其所能地保证用户信息的安全。 了解如何利用现代的Hashing算法对用户密码进行基本的安全控制保护非常重要。
GistBox 提供一种漂亮的方式来组织代码片段。将你的库保存到云端进行备份,再也不用担心丢失。GistBox采用标准的HTML5技术构建。GistBox使用GitHub的后端,但增加了自己的标签和搜索功能层。使用Github账号登陆Gistbox可以将你的代码直接同步进来,反过来,你在GB上的所有改动也都会同步到Github上;GistBox的结构设 计清晰,从左至右分别是主导航(新建Gist,Gists入口,收藏入口-Labels)、Gists列表(Public/Private)、具体代码 区,亲们可以用Label给代码加上各种分辨标签,方便分类整理,在检索代码时可以用顶部的搜索栏,输入关键词或Label可以更快的搜索到目标代码。网址: http://www.gistboxapp.com/
from: http://it.deepinmind.com/java/2014/05/21/better-java.htmlJava是最流行的编程语言之一,但似乎并没有人喜欢使用它。好吧,实际上Java是一门还不错的编程语言,由于最近Java 8发布了,我决定来编辑一个如何能更好地使用Java的列表,这里面包括一些库,实践技巧以及工具。这篇文章在GitHub上也有。你可以随时在上面贡献或者添加你自己的Java使用技巧或者最佳实践。编码风格结构体* builder模式依赖注入避免null值不可变避免过多的工具类格式* 文档Stream部署框架Maven* 依赖收敛持续集成Maven仓储配置管理库遗失的特性* Apache CommonsGuavaGsonJava TuplesJoda-TimeLombokPlay frameworkSLF4JjOOQ测试jUnit 4jMockAssertJ工具IntelliJ IDEA* ChrononJRebel校验框架Eclipse Memory Analyzer资源书籍播客编码风格传统的Java编码方式是非常啰嗦的企业级JavaBean的风格。新的风格更简洁准确,对眼睛也更好。结构体我们这些码农干的最简单的事情就是传递数据了。传统的方式就是定义一个JavaBean:public class DataHolder { private String data;public DataHolder() {}public void setData(String data) { this.data = data;}public String getData() { return this.data;}}这不仅拖沓而且浪费。尽管你的IDE可以自动地生成这个,但这还是浪费。因此,[不要这么写](http://www.javapractices.com/topic/TopicAction.do?Id=84)。相反的,我更喜欢C的结构体的风格,写出来的类只是包装数据:public class DataHolder { public final String data;public DataHolder(String data) { this.data = data;}}这样写减少了一半的代码。不仅如此,除非你继承它,不然这个类是不可变的,由于它是不可变的,因此推断它的值就简单多了。如果你存储的是Map或者List这些可以容易被修改的数据,你可以使用ImmutableMap或者ImmutableList,这个在不可变性这节中会有讨论。Builder模式如果你有一个相对复杂的对象,可以考虑下Builder模式。你在对象里边创建一个子类,用来构造你的这个对象。它使用的是可修改的状态,但一旦你调用了build方法,它会生成一个不可变对象。想象一下我们有一个非常复杂的对象DataHolder。它的构造器看起来应该是这样的:public class ComplicatedDataHolder { public final String data; public final int num; // lots more fields and a constructorpublic class Builder { private String data; private int num; public Builder data(String data) { this.data = data; return this; } public Builder num(int num) { this.num = num; return this; } public ComplicatedDataHolder build() { return new ComplicatedDataHolder(data, num); // etc }}}现在你可以使用它了:final ComplicatedDataHolder cdh = new ComplicatedDataHolder.Builder() .data("set this") .num(523) .build();关于Builder的使用[这里](http://en.deepinmind.com/blog/2014/05/21/the-builder-pattern-in-practice.html)还有些更好的例子,我这里举的例子只是想让你大概感受一下。当然这会产生许多我们希望避免的样板代码,不过好处就是你有了一个不可变对象以及一个连贯接口。依赖注入这更像是一个软件工程的章节而不是Java的,写出可测的软件的一个最佳方式就是使用依赖注入(Dependency injection,DI)。由于Java强烈鼓励使用面向对象设计 ,因此想写出可测性强的软件,你需要使用DI。在Java中,这个通常都是用Spring框架来完成的。它有一个基于XML配置的绑定方式,并且仍然相当流行。重要的一点是你不要因为它的基于XML的配置格式而过度使用它了。在XML中应该没有任何的逻辑和控制结构。它只应该是依赖注入。还有一个不错的方式是使用Dagger库以及Google的Guice。它们并没有使用Spring的XML配置文件的格式,而是将注入的逻辑放到了注解和代码里。避免null值如果有可能的话尽量避免使用null值。你可以返回一个空的集合,但不要返回null集合。如果你准备使用null的话,考虑一下@Nullable注解。IntelliJ IDEA对于@Nullable注解有内建的支持。如果你使用的是Java 8的话,可以考虑下新的Optional类型。如果一个值可能存在也可能不存在,把它封装到Optional类里面,就像这样:public class FooWidget { private final String data; private final Optional<Bar> bar;public FooWidget(String data) { this(data, Optional.empty());}public FooWidget(String data, Optional<Bar> bar) { this.data = data; this.bar = bar;}public Optional<Bar> getBar() {…
from: http://zhuanlan.zhihu.com/wooyun/19747591作者:园长 (@mm yz)攻击JavaWeb应用[1]-JavaEE 基础攻击JavaWeb应用[2]-CS交互安全攻击JavaWeb应用[3]-SQL注入[1]攻击JavaWeb应用[4]-SQL注入[2]攻击JavaWeb应用[5]-MVC安全攻击JavaWeb应用[6]-程序架构与代码审计攻击JavaWeb应用[7]-Server篇[1]攻击JavaWeb应用[8]-后门篇攻击JavaWeb应用[9]-Server篇[2]
Simditor是团队协作工具 Tower 使用的富文本编辑器。相比传统的编辑器它的特点是:功能精简,加载快速输出格式化的标准HTML每一个功能都有非常优秀的使用体验兼容的浏览器:IE10+、Chrome、Firefox、Safari。Demo和文档:http://simditor.tower.im/[repo owner=”mycolorway” name=”simditor”]