2016年5月月 发布的文章

A/B测试:基本概念

网站设计中,我们经常会面临多个设计方案的选择,比如某个按钮是用红色还是用蓝色,是放左边还是放右边。传统的解决方法通常是集体讨论表决,或者由某位专家或领导来拍板,实在决定不了时也有随机选一个上线的。虽然传统解决办法多数情况下也是有效的,但A/B 测试(A/B Testing)可能是解决这类问题的一个更好的方法。
所谓 A/B 测试,简单来说,就是为同一个目标制定两个方案(比如两个页面),让一部分用户使用 A 方案,另一部分用户使用 B 方案,记录下用户的使用情况,看哪个方案更符合设计目标。当然,在实际操作过程之中还有许多需要注意的细节。
A/B 测试并不是互联网测试新发明的方法,事实上,自然界也存在着类似 A/B 测试的事件,比如下图中的达尔文雀。

ab测试

ab测试


达尔文雀主要生活在太平洋东部加拉帕戈斯(Galapagos)的一个名为伊莎贝拉(Isabela)的岛上,一部分生活在岛的西部,另一部分生活在岛的东部,由于生活环境的细微不同它们进化出了不同的喙。这被认为是自然选择学说上的一个重要例证。
同样一种鸟,究竟哪一种喙更适合生存呢?自然界给出了她的解决方案,让鸟儿自己变异(多个设计方案),然后优胜劣汰。具体到达尔文雀这个例子上,不同的环境中喙也有不同的解决方案。
上面的例子虽然和网站设计无关,但包含了 A/B 测试最核心的思想,即:
1、多个方案并行测试;
2、每个方案只有一个变量(比如鸟喙)不同;
3、以某种规则优胜劣汰。
需要特别留意的是第 2 点,它暗示了 A/B 测试的应用范围,——必须是单变量。有时我们的多个设计稿可能会有非常大的差异,这样的情况一般不太适合做 A/B 测试,因为它们的变量太多了,变量之间会有较多的干扰,我们很难通过 A/B 测试的方法来找出各个变量对结果的影响程度。比如,土豆烧肉和豆腐鲫鱼汤都挺美味,但我们很难比较土豆和豆腐哪一个对菜的美味影响更大,而土豆烧肉和豆腐烧肉则是不错的比较。另外,虽然 A/B 测试名字中只包含 A、B ,但并不是说它只能用于比较两个方案的好坏,事实上,你完全可以设计多个方案进行测试,“A/B 测试”这个名字只是一个习惯的叫法。
回到网站设计,一般来说,每个设计方案应该大体上是相同的,只是某一个地方有所不同,比如某处排版、文案、图片、颜色等。然后对不同的用户展示不同的方案。
要注意,不同的用户在他的一次浏览过程中,看到的应该一直是同一个方案。比如他一开始看到的是 A 方案,则在此次会话中应该一直向他展示 A 方案,而不能一会儿让他看 A 方案,一会儿让他看 B 方案。同时,还需要注意控制访问各个版本的人数,大多数情况下我们会希望将访问者平均分配到各个不同的版本上。要做到这些很简单,根据 cookie (比如 cookie 会话ID的最后一位数字)决定展示哪个版本就是一个不错的方法。
下面是 A/B 测试示意图:
ab测试流程

ab测试流程


可以看到,要实现 A/B 测试,我们需要做以下几个工作:
1、开发两个(或多个)不同的版本并部署;
2、收集数据;
3、分析数据,得出结果。
关于 A/B 测试的基本概念就介绍到这里,其余部分我会在后续文章中继续介绍。
http://oldj.net/article/ab-testing-basic-concept/

估算文件大小预测业务量

在开发新系统或者预测未来的业务量,经常需要评估下容量、文件大小。
redis容量的预估:
http://www.searchdatabase.com.cn/showcontent_55189.htm
文件大小的评估:
package java_code;
import java.io.File;
public class FileSize {
	 public static long getFileSize(String filename) {
	      File file = new File(filename);
	      if (!file.exists() || !file.isFile()) {
	         System.out.println("文件不存在");
	         return -1;
	      }
	      return file.length();
	   }
	   public static void main(String[] args) {
	      long size = getFileSize("d:/u");
	      System.out.println("文件大小为: " + size+" Byte");
	   }
}

jeestie-java web脚手架使用教程(四)

相关技术资源和难点
网站:http://jeesite.com/
github:https://github.com/thinkgem/jeesite
一些特殊需求
为了实现报表嵌入,然后再登录前和登录后都去刷了一个空白页面,页面里有一个隐藏的iframe,里边有登录另外一个网址的程序,因此实现了跨域登录。
spring mvc+mybatis多数据源的实现:
http://ctrlc.iteye.com/blog/2248428
还有就是代码包里的文件:

doc

doc


前端轮播的实现:
lunbo

lunbo

<!DOCTYPE html>
<html>
<head>
<script  src="jquery-1.12.3.min.js" type="text/javascript"></script>
<script src="jquery.jcarousellite.min.js" type="text/javascript"></script>
<script>
$(function() {
    $(".anyClass").jCarouselLite({
        btnNext: ".next",
        btnPrev: ".prev"
    });
});
</script>
<title>biee</title>
</head>
<body>
<button class="prev"><<</button>
<button class="next">>></button>
<div class="anyClass">
    <ul>
        <li><img src="biee.jpg" alt="" width="100" height="100" ></li>
        <li><img src="biee2.jpg" alt="" width="100" height="100" ></li>
        <li><img src="biee3.jpg" alt="" width="100" height="100" ></li>
        <li><img src="biee.jpg" alt="" width="100" height="100" ></li>
    </ul>
</div>
</body>
</html>

jeesite脚手架的缺点:界面可以改造为更“现代一点”
用谷歌能让程序员多活十年!

jeestie-java web脚手架使用教程(三)

看代码:
代码结构清晰合理,四层。代码分为三块:java代码、页面和数据库mapping的。照猫画虎很简单就可以写出一个hello world。

code

code


jsp

jsp


mybatis

mybatis


src/main/java
com.thinkgem.jeesite Jeesite平台目录
├ common 公共模块存放目录
│ ├ beanvalidator 实体Bean验证相关类
│ ├ log 日志工具相关类
│ ├ mapper 各种Object到Xml、Object到Json的映射转换类
│ ├ persistence 持久层相关类
│ ├ security 安全相关类
│ ├ service 业务层相关类
│ ├ servlet 公共servlet相关类
│ ├ utils 各种操作小工具类
│ └ web 模型控制器层相关类
└ modules JeeSite内置功能模块存放目录
├ act Activiti工作流引擎目录
├ cms 内容管理、新闻发布模块目录
├ gen Web版本代码生成器目录
├ oa 在线办公模块演示用例存放目录
└ sys 系统核心模块存放目录
├ dao 数据访问层相关类
├ entity 实体相关类
├ interceptor 系统模块拦截器相关类
├ service 业务处相关类
├ web 模型控制器层相关类
└ utils 系统模块的工具类
src/main/resource
act Activiti工作流引擎相关文件(部署文件、bpmn)
cache Ehcache缓存配置存放目录
mappings Mybatis Sql映射文件存放目录
jeesite.properties 系统配置属性文件
spring-*.xml Spring相关文件
log4j.properties Log4j日志配置属性文件
src/main/webapp
static 静态文件存放目录(JS、CSS、前端插件类库等)
└ compressor.bat JavaScrpt和CSS文件压缩脚本
userfiles 用户上传文件目录
WEB-INF WEB应用安全目录,通过映射访问相关文件。
├ lib 依赖jar包目录
├ tags Tags标签存放目录
├ views 视图文件目录
│ ├ reportlets 帆软报表文件存放路径
│ ├ resources 帆软报表配置文件存放目录
│ ├ error 系统异常映射相关页面
│ ├ include 视图相关包含文件
│ ├ layouts 视图布局相关文件
│ └ modules 内置核心功能模块视图相关文件
│ ├ act Activiti模块视图相关文件
│ ├ cms 内容管理模块视图相关文件
│ ├ gen 代码生成模块视图相关文件
│ ├ oa 在线办公模块视图相关文件
│ └ sys 系统管理模块视图相关文件
├ ckfinder.xml CKfinder配置文件
├ decorators.xml Decorator配置文件
└ web.xml Web配置文件
db
db 数据库相关脚本、模型及执行文件
├ act 各模块数据初始化, Oracle建表脚本,数据初始数据脚本文件。
├ cms
├ gen
├ oa
├ sys
└ init-db.bat 初始化数据库执行脚本(需要Maven支持)
bin
clean.bat 清理项目生成的文件脚本
eclipase.bat 生成eclipse项目执行脚本
package.bat 生成编译项目文件(war包)
run-jetty.bat Jetty服务器运行脚本
run-tomcat6.bat Tomcat6服务器运行脚本
run-tomcat7.bat Tomcat7服务器运行脚本

jeestie-java web脚手架使用教程(二)

接上回,先看jeestie的网站和文档。
网站:http://jeesite.com/
github:https://github.com/thinkgem/jeesite
谷歌一下jeesite看下是否有很多资料。
需要注意的点如下:

相关技术框架:(你熟悉的是最好的)
1、后端
核心框架:Spring Framework 4.0
安全框架:Apache Shiro 1.2
视图框架:Spring MVC 4.0
服务端验证:Hibernate Validator 5.1
布局框架:SiteMesh 2.4
工作流引擎:Activiti 5.15、FoxBPM 6
任务调度:Spring Task 4.0
持久层框架:MyBatis 3.2
数据库连接池:Alibaba Druid 1.0
缓存框架:Ehcache 2.6、Redis
日志管理:SLF4J 1.7、Log4j
工具类:Apache Commons、Jackson 2.2、Xstream 1.4、Dozer 5.3、POI 3.9
2、前端
JS框架:jQuery 1.9。
CSS框架:Twitter Bootstrap 2.3.1。
客户端验证:JQuery Validation Plugin 1.11。
富文本:CKEcitor
文件管理:CKFinder
动态页签:Jerichotab
手机端框架:Jingle
数据表格:jqGrid
对话框:jQuery jBox
下拉选择框:jQuery Select2
树结构控件:jQuery zTree
日期控件: My97DatePicker
4、平台
服务器中间件:在Java EE 5规范(Servlet 2.5、JSP 2.1)下开发,支持应用服务器中间件 有Tomcat 6、Jboss 7、WebLogic 10、WebSphere 8。
数据库支持:目前仅提供MySql和Oracle数据库的支持,但不限于数据库,平台留有其它数据库支持接口, 可方便更改为其它数据库,如:SqlServer 2008、MySql 5.5、H2等
开发环境:Java EE、Eclipse、Maven、Git
界面:



界面

界面




功能:
用户管理、角色和权限

用户管理、角色和权限


支持多种数据源:mysql/oracle/redis
运行环境搭建:
eclipse/jdk/tomcat/maven
jeeste是基于spring mvc的,所以要先看配置文件。
jeesite.properties  系统配置属性文件,这里主要配置的是数据库,工程信息,和mybatis配合可以配置多个数据源。

#============================#
#===== Database sttings =====#
#============================#
#oracle database settings
#jdbc.type=oracle
#jdbc.driver=oracle.jdbc.driver.OracleDriver
#jdbc.url=jdbc:oracle:thin:@127.0.0.1:1521:orcl
#jdbc.username=jeesite
#jdbc.password=123456
#mysql database setting
jdbc.type=mysql
jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/jeesite?useUnicode=true&characterEncoding=utf-8
jdbc.username=root
jdbc.password=root
#mssql database settings
#jdbc.type=mssql
#jdbc.driver=net.sourceforge.jtds.jdbc.Driver
#jdbc.url=jdbc:jtds:sqlserver://localhost:1433/jeesite
#jdbc.username=sa
#jdbc.password=sa
#pool settings
jdbc.pool.init=1
jdbc.pool.minIdle=3
jdbc.pool.maxActive=20
#jdbc.testSql=SELECT 'x'
jdbc.testSql=SELECT 'x' FROM DUAL
#redis settings
redis.keyPrefix=jeesite
redis.host=127.0.0.1
redis.port=6379
#============================#
#===== System settings ======#
#============================#
#\u4ea7\u54c1\u4fe1\u606f\u8bbe\u7f6e
productName=JeeSite \u5feb\u901f\u5f00\u53d1\u5e73\u53f0
copyrightYear=2014
version=V1.2.6
#\u6f14\u793a\u6a21\u5f0f: \u4e0d\u80fd\u64cd\u4f5c\u548c\u4fdd\u5b58\u7684\u6a21\u5757\uff1a sys: area/office/user/role/menu/dict, cms: site/category
demoMode=false
#\u7ba1\u7406\u57fa\u7840\u8def\u5f84, \u9700\u540c\u6b65\u4fee\u6539\uff1aweb.xml
adminPath=/a
#\u524d\u7aef\u57fa\u7840\u8def\u5f84
frontPath=/f
#\u7f51\u7ad9URL\u540e\u7f00
urlSuffix=.html
#\u662f\u5426\u4e0d\u5141\u8bb8\u5237\u65b0\u4e3b\u9875\uff0c\u4e0d\u5141\u8bb8\u60c5\u51b5\u4e0b\uff0c\u5237\u65b0\u4e3b\u9875\u4f1a\u5bfc\u81f4\u91cd\u65b0\u767b\u5f55
notAllowRefreshIndex=false
#\u662f\u5426\u5141\u8bb8\u591a\u8d26\u53f7\u540c\u65f6\u767b\u5f55
user.multiAccountLogin=true
#\u5206\u9875\u914d\u7f6e
page.pageSize=30
#\u7855\u6b63\u7ec4\u4ef6\u662f\u5426\u4f7f\u7528\u7f13\u5b58
supcan.useCache=false
#\u901a\u77e5\u95f4\u9694\u65f6\u95f4\u8bbe\u7f6e, \u5355\u4f4d\uff1a\u6beb\u79d2, 30s=30000ms, 60s=60000ms
oa.notify.remind.interval=60000
#============================#
#==== Framework settings ====#
#============================#
#\u4f1a\u8bdd\u8d85\u65f6\uff0c \u5355\u4f4d\uff1a\u6beb\u79d2\uff0c 20m=1200000ms, 30m=1800000ms, 60m=3600000ms
session.sessionTimeout=1800000
#\u4f1a\u8bdd\u6e05\u7406\u95f4\u9694\u65f6\u95f4\uff0c \u5355\u4f4d\uff1a\u6beb\u79d2\uff0c2m=120000ms\u3002
session.sessionTimeoutClean=120000
#\u7f13\u5b58\u8bbe\u7f6e
ehcache.configFile=cache/ehcache-local.xml
#ehcache.configFile=cache/ehcache-rmi.xml
#\u7d22\u5f15\u9875\u8def\u5f84
web.view.index=/a
#\u89c6\u56fe\u6587\u4ef6\u5b58\u653e\u8def\u5f84
web.view.prefix=/WEB-INF/views/
web.view.suffix=.jsp
#\u6700\u5927\u6587\u4ef6\u4e0a\u4f20\u9650\u5236\uff0c\u5355\u4f4d\u5b57\u8282. 10M=10*1024*1024(B)=10485760 bytes\uff0c\u9700\u540c\u6b65\u4fee\u6539\uff1ackfinder.xml
web.maxUploadSize=10485760
#\u65e5\u5fd7\u62e6\u622a\u8bbe\u7f6e\uff0c\u6392\u9664\u7684URI\uff1b\u5305\u542b @RequestMapping\u6ce8\u89e3\u7684value\u3002\uff08\u5df2\u4f5c\u5e9f\uff09
#web.logInterceptExcludeUri=/, /login, /sys/menu/tree, /sys/menu/treeData, /oa/oaNotify/self/count
#web.logInterceptIncludeRequestMapping=save, delete, import, updateSort
#\u9759\u6001\u6587\u4ef6\u540e\u7f00
web.staticFile=.css,.js,.png,.jpg,.gif,.jpeg,.bmp,.ico,.swf,.psd,.htc,.htm,.html,.crx,.xpi,.exe,.ipa,.apk
#\u5355\u70b9\u767b\u5f55CAS\u8bbe\u7f6e
cas.server.url=http://127.0.0.1:8180/cas
cas.project.url=http://127.0.0.1:8080/jeesite
#\u5de5\u4f5c\u6d41\u8bbe\u7f6e
activiti.isSynActivitiIndetity=false
activiti.export.diagram.path=c:/activiti_diagram
#activiti font (windows font: \u5b8b\u4f53  linux font: simsun)
activiti.diagram.activityFontName=\u5b8b\u4f53
activiti.diagram.labelFontName=\u5b8b\u4f53
#activiti\u5916\u90e8\u8868\u5355\u6839\u5730\u5740\u914d\u7f6e
activiti.form.server.url=
#\u4e0a\u4f20\u6587\u4ef6\u7edd\u5bf9\u8def\u5f84, \u8def\u5f84\u4e2d\u4e0d\u5141\u8bb8\u5305\u542b\u201cuserfiles\u201d
#userfiles.basedir=D:/jeesite
#\u5de5\u7a0b\u8def\u5f84\uff0c\u5728\u4ee3\u7801\u751f\u6210\u65f6\u83b7\u53d6\u4e0d\u5230\u5de5\u7a0b\u8def\u5f84\u65f6\uff0c\u53ef\u518d\u6b64\u6307\u5b9a\u7edd\u5bf9\u8def\u5f84\u3002
#projectPath=D\:\\workspace\\jeesite

spring-*.xml   Spring相关文件
spring-mvc.xml,加载配置文件,配置扫描的controller的包路径,可以全扫描。定义视图的后缀和路径。配置错误页面。

<!--?xml version="1.0" encoding="UTF-8"?-->
    Spring MVC Configuration
    <!-- 加载配置属性文件 -->
	<!-- 使用Annotation自动注册Bean,只扫描@Controller -->
	<!-- base-package 如果多个,用“,”分隔 -->
	<!-- 默认的注解映射的支持,org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping -->
			<!-- 将StringHttpMessageConverter的默认编码设为UTF-8 -->
			<!-- 将Jackson2HttpMessageConverter的默认格式化输出为false -->
                	application/json;charset=UTF-8
            <!-- 使用XML格式输出数据 -->
				                com.thinkgem.jeesite.common.persistence.BaseEntity
				                com.thinkgem.jeesite.common.supcan.treelist.TreeList
				                com.thinkgem.jeesite.common.supcan.treelist.cols.Col
				                com.thinkgem.jeesite.common.supcan.treelist.cols.Group
    <!-- REST中根据URL后缀自动判定Content-Type及相应的View -->
	        <map>
            </map>
	<!-- 定义视图文件解析 -->
	<!-- 对静态资源文件的访问, 将无法mapping到Controller的path交给default servlet handler处理 -->
	<!-- 静态资源映射 -->
	<!-- 定义无Controller的path<->view直接映射 -->
	<!-- 拦截器配置,拦截顺序:先执行后定义的,排在第一位的最后执行。-->
		<!-- 手机视图拦截器 -->
	<!-- 支持Shiro对Controller的方法级AOP安全控制 begin-->
				error/403
				error/500
	<!-- 支持Shiro对Controller的方法级AOP安全控制 end -->
	<!-- 上传文件拦截,设置最大上传文件大小   10M=10*1024*1024(B)=10485760 bytes -->

spring-context.xml 这个配置文件是对数据库做配置,数据源已经是多数据源了,可以同事读取很多个不同的数据库

<?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:context="http://www.springframework.org/schema/context" xmlns:jdbc="http://www.springframework.org/schema/jdbc"
	xmlns:jee="http://www.springframework.org/schema/jee" xmlns:tx="http://www.springframework.org/schema/tx"
    xmlns:util="http://www.springframework.org/schema/util" xmlns:task="http://www.springframework.org/schema/task" xsi:schemaLocation="
		http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
		http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd
		http://www.springframework.org/schema/jdbc http://www.springframework.org/schema/jdbc/spring-jdbc-4.0.xsd
		http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-4.0.xsd
		http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.0.xsd
		http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-4.0.xsd
		http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task-4.0.xsd" default-lazy-init="true">
	<description>Spring Configuration</description>
    <!-- 加载配置属性文件 -->
	<context:property-placeholder ignore-unresolvable="true" location="classpath:jeesite.properties" />
	<!-- 加载应用属性实例,可通过  @Value("#{APP_PROP['jdbc.driver']}") String jdbcDriver 方式引用 -->
    <util:properties id="APP_PROP" location="classpath:jeesite.properties" local-override="true"/>
	<!-- 使用Annotation自动注册Bean,解决事物失效问题:在主容器中不扫描@Controller注解,在SpringMvc中只扫描@Controller注解。  -->
	<context:component-scan base-package="com.thinkgem.jeesite,com.rong360.data.portal"><!-- base-package 如果多个,用“,”分隔 -->
		<context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
	</context:component-scan>
 	<!-- MyBatis begin -->
    <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
        <property name="dataSource" ref="dynamicDataSource"/>
        <property name="typeAliasesPackage" value="com"/>
        <property name="typeAliasesSuperType" value="com.thinkgem.jeesite.common.persistence.BaseEntity"/>
        <property name="mapperLocations" value="classpath:/mappings/**/*.xml"/>
		<property name="configLocation" value="classpath:/mybatis-config.xml"></property>
    </bean>
    <!-- 扫描basePackage下所有以@MyBatisDao注解的接口 -->
    <bean id="mapperScannerConfigurer" class="org.mybatis.spring.mapper.MapperScannerConfigurer">
        <property name="sqlSessionFactoryBeanName" value="sqlSessionFactory" />
        <property name="basePackage" value="com"/>
        <property name="annotationClass" value="com.thinkgem.jeesite.common.persistence.annotation.MyBatisDao"/>
    </bean>
    <!-- 定义事务 -->
	<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
		<property name="dataSource" ref="dynamicDataSource" />
	</bean>
	<!-- 配置 Annotation 驱动,扫描@Transactional注解的类定义事务  -->
	<tx:annotation-driven transaction-manager="transactionManager" proxy-target-class="true"/>
    <!-- MyBatis end -->
	<!-- 配置 JSR303 Bean Validator 定义 -->
	<bean id="validator" class="org.springframework.validation.beanvalidation.LocalValidatorFactoryBean" />
	<!-- 缓存配置 -->
	<bean id="cacheManager" class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean">
		<property name="configLocation" value="classpath:${ehcache.configFile}" />
	</bean>
	<!-- 计划任务配置,用 @Service @Lazy(false)标注类,用@Scheduled(cron = "0 0 2 * * ?")标注方法 -->
    <task:executor id="executor" pool-size="10"/> <task:scheduler id="scheduler" pool-size="10"/>
    <task:annotation-driven scheduler="scheduler" executor="executor" proxy-target-class="true"/>
	<!-- 第一个mysql数据源配置, 使用 BoneCP 数据库连接池 -->
	<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource" init-method="init" destroy-method="close">
	    <!-- 数据源驱动类可不写,Druid默认会自动根据URL识别DriverClass -->
	    <property name="driverClassName" value="${jdbc.driver}" />
		<!-- 基本属性 url、user、password -->
		<property name="url" value="${jdbc.url}" />
		<property name="username" value="${jdbc.username}" />
		<property name="password" value="${jdbc.password}" />
		<!-- 配置初始化大小、最小、最大 -->
		<property name="initialSize" value="${jdbc.pool.init}" />
		<property name="minIdle" value="${jdbc.pool.minIdle}" />
		<property name="maxActive" value="${jdbc.pool.maxActive}" />
		<!-- 配置获取连接等待超时的时间 -->
		<property name="maxWait" value="60000" />
		<!-- 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒 -->
		<property name="timeBetweenEvictionRunsMillis" value="60000" />
		<!-- 配置一个连接在池中最小生存的时间,单位是毫秒 -->
		<property name="minEvictableIdleTimeMillis" value="300000" />
		<property name="validationQuery" value="${jdbc.testSql}" />
		<property name="testWhileIdle" value="true" />
		<property name="testOnBorrow" value="false" />
		<property name="testOnReturn" value="false" />
		<!-- 打开PSCache,并且指定每个连接上PSCache的大小(Oracle使用)
		<property name="poolPreparedStatements" value="true" />
		<property name="maxPoolPreparedStatementPerConnectionSize" value="20" /> -->
		<!-- 配置监控统计拦截的filters -->
	    <property name="filters" value="stat" />
	</bean>
	<!-- 第二个mysql数据源配置, 使用 BoneCP 数据库连接池 -->
    <bean id="dataSource2" class="com.alibaba.druid.pool.DruidDataSource" init-method="init" destroy-method="close">
        <!-- 数据源驱动类可不写,Druid默认会自动根据URL识别DriverClass -->
        <property name="driverClassName" value="${jdbc.driver}" />
        <!-- 基本属性 url、user、password -->
        <property name="url" value="${jdbc.url2}" />
        <property name="username" value="${jdbc.username2}" />
        <property name="password" value="${jdbc.password2}" />
        <!-- 配置初始化大小、最小、最大 -->
        <property name="initialSize" value="${jdbc.pool.init}" />
        <property name="minIdle" value="${jdbc.pool.minIdle}" />
        <property name="maxActive" value="${jdbc.pool.maxActive}" />
        <!-- 配置获取连接等待超时的时间 -->
        <property name="maxWait" value="60000" />
        <!-- 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒 -->
        <property name="timeBetweenEvictionRunsMillis" value="60000" />
        <!-- 配置一个连接在池中最小生存的时间,单位是毫秒 -->
        <property name="minEvictableIdleTimeMillis" value="300000" />
        <property name="validationQuery" value="${jdbc.testSql}" />
        <property name="testWhileIdle" value="true" />
        <property name="testOnBorrow" value="false" />
        <property name="testOnReturn" value="false" />
        <!-- 打开PSCache,并且指定每个连接上PSCache的大小(Oracle使用)
        <property name="poolPreparedStatements" value="true" />
        <property name="maxPoolPreparedStatementPerConnectionSize" value="20" /> -->
        <!-- 配置监控统计拦截的filters -->
        <property name="filters" value="stat" />
    </bean>
    <!-- 第三个mysql数据源配置, 使用 BoneCP 数据库连接池 -->
    <bean id="dataSource4" class="com.alibaba.druid.pool.DruidDataSource" init-method="init" destroy-method="close">
        <!-- 数据源驱动类可不写,Druid默认会自动根据URL识别DriverClass -->
        <property name="driverClassName" value="${jdbc.driver}" />
        <!-- 基本属性 url、user、password -->
        <property name="url" value="${jdbc.url3}" />
        <property name="username" value="${jdbc.username3}" />
        <property name="password" value="${jdbc.password3}" />
        <!-- 配置初始化大小、最小、最大 -->
        <property name="initialSize" value="${jdbc.pool.init}" />
        <property name="minIdle" value="${jdbc.pool.minIdle}" />
        <property name="maxActive" value="${jdbc.pool.maxActive}" />
        <!-- 配置获取连接等待超时的时间 -->
        <property name="maxWait" value="60000" />
        <!-- 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒 -->
        <property name="timeBetweenEvictionRunsMillis" value="60000" />
        <!-- 配置一个连接在池中最小生存的时间,单位是毫秒 -->
        <property name="minEvictableIdleTimeMillis" value="300000" />
        <property name="validationQuery" value="${jdbc.testSql}" />
        <property name="testWhileIdle" value="true" />
        <property name="testOnBorrow" value="false" />
        <property name="testOnReturn" value="false" />
        <!-- 打开PSCache,并且指定每个连接上PSCache的大小(Oracle使用)
        <property name="poolPreparedStatements" value="true" />
        <property name="maxPoolPreparedStatementPerConnectionSize" value="20" /> -->
        <!-- 配置监控统计拦截的filters -->
        <property name="filters" value="stat" />
    </bean>
    <!-- 第三个数据源配置, 使用 BoneCP 数据库连接池 -->
    <bean id="dataSource3" class="com.alibaba.druid.pool.DruidDataSource" init-method="init" destroy-method="close">
        <!-- 数据源驱动类可不写,Druid默认会自动根据URL识别DriverClass -->
        <property name="driverClassName" value="${o.jdbc.driver}" />
        <!-- 基本属性 url、user、password -->
        <property name="url" value="${o.jdbc.url}" />
        <property name="username" value="${o.jdbc.username}" />
        <property name="password" value="${o.jdbc.password}" />
        <!-- 配置初始化大小、最小、最大 -->
        <property name="initialSize" value="${jdbc.pool.init}" />
        <property name="minIdle" value="${jdbc.pool.minIdle}" />
        <property name="maxActive" value="${jdbc.pool.maxActive}" />
        <!-- 配置获取连接等待超时的时间 -->
        <property name="maxWait" value="60000" />
        <!-- 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒 -->
        <property name="timeBetweenEvictionRunsMillis" value="60000" />
        <!-- 配置一个连接在池中最小生存的时间,单位是毫秒 -->
        <property name="minEvictableIdleTimeMillis" value="300000" />
        <property name="validationQuery" value="${jdbc.testSql}" />
        <property name="testWhileIdle" value="true" />
        <property name="testOnBorrow" value="false" />
        <property name="testOnReturn" value="false" />
        <!-- 打开PSCache,并且指定每个连接上PSCache的大小(Oracle使用)  -->
        <property name="poolPreparedStatements" value="true" />
        <property name="maxPoolPreparedStatementPerConnectionSize" value="20" />
        <!-- 配置监控统计拦截的filters -->
        <property name="filters" value="stat" />
    </bean>
    <!-- 动态数据源 -->
    <bean id="dynamicDataSource" class="com.thinkgem.jeesite.common.db.DynamicDataSource">
        <property name="defaultTargetDataSource" ref="dataSource"/>
        <property name="targetDataSources">
            <map>
                <entry key="dataSource" value-ref="dataSource"/>
                <entry key="dataSource2" value-ref="dataSource2"/>
                <entry key="dataSource3" value-ref="dataSource3"/>
                <entry key="dataSource4" value-ref="dataSource4"/>
            </map>
        </property>
    </bean>
	<!-- 数据源配置, 使用应用服务器的数据库连接池
	<jee:jndi-lookup id="dataSource" jndi-name="java:comp/env/jdbc/jeesite" />-->
	<!-- 数据源配置, 不使用连接池
	<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
		<property name="driverClassName" value="${jdbc.driver}" />
		<property name="url" value="${jdbc.url}" />
		<property name="username" value="${jdbc.username}"/>
		<property name="password" value="${jdbc.password}"/>
	</bean>-->
</beans>

spring-context-shiro.xml 这个配置的是安全认证,需要修改地方不多。

<?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:context="http://www.springframework.org/schema/context" xsi:schemaLocation="
		http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
		http://www.springframework.org/schema/context  http://www.springframework.org/schema/context/spring-context-4.0.xsd" default-lazy-init="true">
	<description>Shiro Configuration</description>
    <!-- 加载配置属性文件 -->
	<context:property-placeholder ignore-unresolvable="true" location="classpath:jeesite.properties" />
	<!-- Shiro权限过滤过滤器定义 -->
	<bean name="shiroFilterChainDefinitions" class="java.lang.String">
		<constructor-arg>
			<value>
				/static/** = anon
				/userfiles/** = anon
				${adminPath}/cas = cas
				${adminPath}/login = authc
				${adminPath}/logout = logout
				${adminPath}/** = user
				/act/rest/service/editor/** = perms[act:model:edit]
				/act/rest/service/model/** = perms[act:model:edit]
				/act/rest/service/** = user
				/ReportServer/** = user
			</value>
		</constructor-arg>
	</bean>
	<!-- 安全认证过滤器 -->
	<bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
		<property name="securityManager" ref="securityManager" /><!--
		<property name="loginUrl" value="${cas.server.url}?service=${cas.project.url}${adminPath}/cas" /> -->
		<property name="loginUrl" value="${adminPath}/login" />
		<!--<property name="successUrl" value="${adminPath}?login" />-->
		<property name="successUrl" value="/black" />
		<property name="filters">
            <map>
                <entry key="cas" value-ref="casFilter"/>
                <entry key="authc" value-ref="formAuthenticationFilter"/>
            </map>
        </property>
		<property name="filterChainDefinitions">
			<ref bean="shiroFilterChainDefinitions"/>
		</property>
	</bean>
	<!-- CAS认证过滤器 -->
	<bean id="casFilter" class="org.apache.shiro.cas.CasFilter">
		<property name="failureUrl" value="${adminPath}/login"/>
	</bean>
	<!-- 定义Shiro安全管理配置 -->
	<bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
		<property name="realm" ref="systemAuthorizingRealm" />
		<property name="sessionManager" ref="sessionManager" />
		<property name="cacheManager" ref="shiroCacheManager" />
	</bean>
	<!-- 自定义会话管理配置 -->
	<bean id="sessionManager" class="com.thinkgem.jeesite.common.security.shiro.session.SessionManager">
		<property name="sessionDAO" ref="sessionDAO"/>
		<!-- 会话超时时间,单位:毫秒  -->
		<property name="globalSessionTimeout" value="${session.sessionTimeout}"/>
		<!-- 定时清理失效会话, 清理用户直接关闭浏览器造成的孤立会话   -->
		<property name="sessionValidationInterval" value="${session.sessionTimeoutClean}"/>
<!--  		<property name="sessionValidationSchedulerEnabled" value="false"/> -->
 		<property name="sessionValidationSchedulerEnabled" value="true"/>
		<property name="sessionIdCookie" ref="sessionIdCookie"/>
		<property name="sessionIdCookieEnabled" value="true"/>
	</bean>
	<!-- 指定本系统SESSIONID, 默认为: JSESSIONID 问题: 与SERVLET容器名冲突, 如JETTY, TOMCAT 等默认JSESSIONID,
		当跳出SHIRO SERVLET时如ERROR-PAGE容器会为JSESSIONID重新分配值导致登录会话丢失! -->
	<bean id="sessionIdCookie" class="org.apache.shiro.web.servlet.SimpleCookie">
	    <constructor-arg name="name" value="jeesite.session.id"/>
	</bean>
	<!-- 自定义Session存储容器 -->
<!-- 	<bean id="sessionDAO" class="com.thinkgem.jeesite.common.security.shiro.session.JedisSessionDAO"> -->
<!-- 		<property name="sessionIdGenerator" ref="idGen" /> -->
<!-- 		<property name="sessionKeyPrefix" value="${redis.keyPrefix}_session_" /> -->
<!-- 	</bean> -->
	<bean id="sessionDAO" class="com.thinkgem.jeesite.common.security.shiro.session.CacheSessionDAO">
		<property name="sessionIdGenerator" ref="idGen" />
		<property name="activeSessionsCacheName" value="activeSessionsCache" />
		<property name="cacheManager" ref="shiroCacheManager" />
	</bean>
	<!-- 定义授权缓存管理器 -->
<!-- 	<bean id="shiroCacheManager" class="com.thinkgem.jeesite.common.security.shiro.cache.SessionCacheManager" /> -->
	<bean id="shiroCacheManager" class="org.apache.shiro.cache.ehcache.EhCacheManager">
		<property name="cacheManager" ref="cacheManager"/>
	</bean>
	<!-- 保证实现了Shiro内部lifecycle函数的bean执行 -->
	<bean id="lifecycleBeanPostProcessor" class="org.apache.shiro.spring.LifecycleBeanPostProcessor"/>
	<!-- AOP式方法级权限检查  -->
	<bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator" depends-on="lifecycleBeanPostProcessor">
		<property name="proxyTargetClass" value="true" />
	</bean>
	<bean class="org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor">
    	<property name="securityManager" ref="securityManager"/>
	</bean>
</beans>

jeestie-java web脚手架使用教程(一)

最近需要新开一个项目,需要完成一个数据门户的portal,java web是几年前使用的东西,说简单呢挺简单的,但自己搭建一套还是比较耗时的,想要快速完成,把时间花在门户建设上,还是找开源的吧。比较了portal里的Liferay和一般的java web脚手架,如jeestie,觉得还是脚手架好一些。
说一下选择的标准:
1、可控性:对源代码的掌握是不是很复杂。开发框架是不是很常见,架构简单,代码易读。
2、功能性:基本功能是否都满足。用户管理、角色管理、权限控制和一般的内容发布都是必须的。
3、好界面:界面是不是很复杂,有无控件支持。对于后端人员来说,写一段div+css可能确实有点困难。
4、数据源:是否对多种数据库有支持。mysql、oracle和redis等等。
5、支持多:看下这个脚手架是否有很多人用,网上资料多否,项目本身的文档是否完备。
最重要的一点是:你得亲自去跑一个hello world去体验一下
拿到一个开源项目该怎么入手?
步骤:
1、看项目主页,看项目文档,看别人评价。
2、搭运行环境,jdk、maven、IDE和数据库
3、写hello world,运行项目工程。
4、改配置,改代码,再运行。
下一篇进入正题,这篇文章作为一个引子,其实过程都是通用的。