收集采集:调查.
http://www.surveymonkey.com
搭建项目:
struts1:
servlet--ActionServlet
struts2: (struts1 + webwork)
开发web程序的框架,基于filter--StrutsPrepareAndExecuteFilter.
耦合度低:
1.原生servlet API
2.我们自己的类和struts2的api.
3.拦截器
分离关注:拦截器.
action:原型,有状态.独占,线程安全.
synchorized:锁
threadlocal:线程本地化.数据安全.
m:model,模型,携带数据.
v:view,显示层
c:controller.
单例:
多例:pool,池化技术.
原型:原始模型.
scope:singleton|prototype|request|session|globalsession
hibernate:
持久化技术,封装数据的访问细节(sql+ ??),体现oop.
轻量级jdbc
spring:
业务层框架,管理bean的容器.
ioc:inverseof controller,获得依赖对象方式.
aop:面向切面编程,aspectoriented program
通知:前置 后置 环绕 异常 引入,
使用代理:1-jdk动态代理(接口代理) 2-cglib代理(final)
搭建项目:
1.创建web项目
2.引入类库
[struts2]
asm-3.3.jar
asm-commons-3.3.jar
asm-tree-3.3.jar
commons-fileupload-1.2.2.jar
commons-io-2.0.1.jar
commons-lang-2.5.jar
freemarker-2.3.18.jar
javassist-3.11.0.GA.jar
ognl-3.0.4.jar
struts2-core-2.3.1.2.jar
xwork-core-2.3.1.2.jar
[hibernate]
antlr-2.7.6.jar
commons-collections-3.1.jar
hibernate3.jar
javassist-3.11.0.GA.jar
jta-1.1.jar
log4j.jar
slf4j-api-1.5.8.jar
slf4j-log4j12.jar
[spring]
org.springframework.aop-3.1.0.RELEASE.jar
org.springframework.asm-3.1.0.RELEASE.jar
org.springframework.aspects-3.1.0.RELEASE.jar
org.springframework.beans-3.1.0.RELEASE.jar
org.springframework.context-3.1.0.RELEASE.jar
org.springframework.context.support-3.1.0.RELEASE.jar
org.springframework.core-3.1.0.RELEASE.jar
org.springframework.expression-3.1.0.RELEASE.jar
org.springframework.jdbc-3.1.0.RELEASE.jar
org.springframework.orm-3.1.0.RELEASE.jar
org.springframework.transaction-3.1.0.RELEASE.jar
org.springframework.web-3.1.0.RELEASE.jar
com.springsource.net.sf.cglib-2.2.0.jar
com.springsource.org.aopalliance-1.0.0.jar
com.springsource.org.aspectj.tools-1.6.6.RELEASE.jar
com.springsource.org.aspectj.weaver-1.6.8.RELEASE.jar
com.springsource.org.apache.commons.logging-1.1.1.jar
[struts-spring-plugin]
struts2-spring-plugin-2.3.1.2.jar
[driver]
mysql-connector-java-5.0.8-bin.jar
[datasource]
com.springsource.com.mchange.v2.c3p0-0.9.1.2.jar
3.创建包结构
cn.itcast.surveypark.dao
cn.itcast.surveypark.dao.impl
cn.itcast.surveypark.domain
cn.itcast.surveypark.service
cn.itcast.surveypark.service.impl
cn.itcast.surveypark.struts2.action
cn.itcast.surveypark.util
4.配置文件
[struts2]
1.web.xml
<!--配置struts2 filter -->
<filter>
<filter-name>action</filter-name>
<filter-class>org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>action</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
2.struts.xml:conf/struts.xml
<?xmlversion="1.0"?>
<!DOCTYPEstruts PUBLIC
"-//ApacheSoftware Foundation//DTD Struts Configuration 2.1.7//EN"
"http://struts.apache.org/dtds/struts-2.1.7.dtd">
<struts>
<packagename="surveyParkPkg" namespace="/"extends="struts-default">
</package>
</struts>
[spring]
<?xmlversion="1.0"?>
<beansxmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-3.0.xsd">
<!--组件扫描 -->
<context:component-scanbase-package="cn.itcast.surveypark.dao.impl,cn.itcast.surveypark.service.impl,cn.itcast.surveypark.struts2.action"/>
<!--分散配置 -->
<context:property-placeholderlocation="classpath:jdbc.properties"/>
<!--数据源 -->
<beanid="dataSource"class="com.mchange.v2.c3p0.ComboPooledDataSource">
<propertyname="driverClass" value="${jdbc.driverclass}" />
<propertyname="jdbcUrl" value="${jdbc.url}" />
<propertyname="user" value="${jdbc.username}" />
<propertyname="password" value="${jdbc.password}" />
<propertyname="maxPoolSize" value="${c3p0.pool.size.max}" />
<propertyname="minPoolSize" value="${c3p0.pool.size.min}" />
<propertyname="initialPoolSize" value="${c3p0.pool.size.ini}" />
<propertyname="acquireIncrement" value="${c3p0.pool.size.increment}"/>
</bean>
<!--本地会话工厂bean,spring整合hibernate的核心入口 -->
<beanid="sessionFactory"class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
<!--注入数据源 -->
<propertyname="dataSource" ref="dataSource" />
<!--指定hibernate配置文件 -->
<propertyname="configLocation" value="classpath:hibernate.cfg.xml"/>
<!--指定映射文件目录 -->
<propertyname="mappingDirectoryLocations">
<list>
<value>classpath:cn/itcast/surveypark/domain</value>
</list>
</property>
</bean>
<!--事务管理器,在service层面上实现事务管理,而且达到平台无关性 -->
<beanid="txManager"class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<propertyname="sessionFactory" ref="sessionFactory" />
</bean>
<!--配置事务通知 -->
<tx:adviceid="txAdvice" transaction-manager="txManager">
<tx:attributes>
<tx:methodname="save*" propagation="REQUIRED"isolation="DEFAULT" />
<tx:methodname="update*" propagation="REQUIRED"isolation="DEFAULT" />
<tx:methodname="delete*" propagation="REQUIRED"isolation="DEFAULT" />
<tx:methodname="batch*" propagation="REQUIRED"isolation="DEFAULT" />
<tx:methodname="new*" propagation="REQUIRED"isolation="DEFAULT" />
<tx:methodname="get*" propagation="REQUIRED"isolation="DEFAULT" read-only="true"/>
<tx:methodname="load*" propagation="REQUIRED"isolation="DEFAULT" read-only="true"/>
<tx:methodname="find*" propagation="REQUIRED"isolation="DEFAULT" read-only="true"/>
<tx:methodname="*" propagation="REQUIRED"isolation="DEFAULT" />
</tx:attributes>
</tx:advice>
<!--aop事务配置 -->
<aop:config>
<aop:advisoradvice-ref="txAdvice" pointcut="execution(**..*Service.*(..))"/>
</aop:config>
</beans>
Struts2 Action的方法跳过校验:
在方法上增加注解:@SkipValidation
Struts2 Action只在指定的方法前校验:
//只在doLogin()方法前校验:
Public void validateDoLogin(){}
或:
Public void validateDoDaoLogin(){}
可以加validate前缀或validateDo前缀
eclipse查看类继承关系,快捷键:Ctrl+T
struts2流程图(数据采集第2天):
Strust2迭代时会把当前对象压入栈顶,<s:iterator>输出栈顶的的内容(输出栈顶对象的toString()方法):<s:property/>
Struts2解决action中为模型赋值问题(第2天上午)
不能直接为model赋值,没有改变栈顶的引用.
--------------------------------------
1.使用属性赋值(apache).
2.把新model压入栈顶.
ActionContext.getContext().getValueStack().push(s);
3.通过prepare拦截器 +paramsPrepareParamsStack组合,解决action的模型赋值问题
1.classSurveyAction ...{
publicString designSurvey(){
...
}
publicvoid prepareDesignSurvey(){
this.model= xxx ;
}
}
2.struts.xml配置文件中使用paramsPrepareParamsStack.
<interceptor-stackname="surveyparkStack">
<interceptor-refname="loginInterceptor" />
<interceptor-refname="paramsPrepareParamsStack" />
</interceptor-stack>
4.打开modelDriven的刷新模型属性.
struts.xml
<!--自定义拦截器栈 -->
<interceptor-stackname="surveyparkStack">
<interceptor-refname="loginInterceptor" />
<interceptor-refname="defaultStack">
<paramname="modelDriven.refreshModelBeforeResult">true</param>
</interceptor-ref>
</interceptor-stack>
懒加载问题
-----------------------------------
1.OpenSessionInView 过滤器
1.优点点:一劳永逸.
2.缺点:性能差.
2.在service层强行初始化代理对象
Struts显示页面前刷新模型的拦截器配置,struts.xml:
<!-- 注册自定义登录拦截器 -->
<interceptors>
<interceptorname="loginInterceptor" class="cn.itcast.surveypark.struts2.interceptor.LoginInterceptor"></interceptor>
<!--自定义拦截器栈 -->
<interceptor-stackname="surveyParkStack">
<interceptor-refname="loginInterceptor"/>
<interceptor-refname="defaultStack">
<paramname="modelDriven.refreshModelBeforeResult">true</param>
</interceptor-ref>
</interceptor-stack>
</interceptors>
hibernate不支持两级以上的写操作.不能使用 deletexxx .. from Question q where q.page.survey.id = ?
<!-- update=false,阻止s.update()/s.saveOrUpdate(),不能阻止hql更新 -->
<property name="closed"column="closed" type="boolean"update="false"/>
限制上传的文件
-----------------------
struts.xml
<actionname="SurveyAction_*" class="surveyAction"method="{1}">
...
<resultname="input">/addLogo.jsp</result>
<interceptor-refname="surveyparkStack">
<!--文件大小 -->
<paramname="fileUpload.maximumSize">60000</param>
<paramname="fileUpload.allowedExtensions">.jpg,.jpeg,.png,.gif,.bmp</param>
<paramname="fileUpload.allowedTypes">image/jpg,image/jpeg,image/pjpeg,image/bmp,image/gif,image/png</param>
</interceptor-ref>
</action>
对错误信息国际化
------------------------
0.strust错误信息在struts包的第一个目录下:struts2-core-2.3.1.2.jar!\org\apache\struts2\struts-messages.properties
1.创建SurveyAction.properties
struts.messages.error.file.too.large=Filetoo large: {0} "{1}" "{2}" {3}
struts.messages.error.content.type.not.allowed=Content-Typenot allowed: {0} "{1}" "{2}" {3}
struts.messages.error.file.extension.not.allowed=Fileextension not allowed: {0} "{1}" "{2}" {3}
2.创建临时文件1.txt,翻译成中文,最好使用windows记事本编写(字符集问题)
struts.messages.error.file.too.large=文件太大!
struts.messages.error.content.type.not.allowed=类型不对!
struts.messages.error.file.extension.not.allowed=扩展名不符!
3.对1.txt转码,转成ascii码.
cmd
cdD:\eclipse\workspace-jee\lsn_surveypark0909\src\cn\itcast\surveypark\struts2\action
native2ascii-encoding gb2312 1.txt 2.txt
4.生成2.txt是文件
struts.messages.error.file.too.large=\u6587\u4ef6\u592a\u5927!
struts.messages.error.content.type.not.allowed=\u7c7b\u578b\u4e0d\u5bf9!
struts.messages.error.file.extension.not.allowed=\u6269\u5c55\u540d\u4e0d\u7b26!
5.刷新项目
6.重命名2.txt文件成SurveyAction_zh_CN.properties
7.删除1.txt临时文件
8.配置fielupload上传拦截器使用action相关的消息束文件.
<interceptor-refname="surveyparkStack">
<!--文件大小 -->
<paramname="fileUpload.maximumSize">60000</param>
<paramname="fileUpload.allowedExtensions">.jpg,.jpeg,.png,.gif,.bmp</param>
<paramname="fileUpload.allowedTypes">image/jpg,image/jpeg,image/pjpeg,image/bmp,image/gif,image/png</param>
<paramname="fileUpload.useActionMessageBundle">true</param>
</interceptor-ref>
动态指定错误页面
---------------------------------
1.在SurveyAction增加属性
classSurveyAction ..{
...
privateString inputPage ;
//get/set
publicString doAddLogo(){
...
}
//由prepare拦截器在文件上传拦截器之前调用
publicvoid prepareDoAddLogo(){
this.inputPage= "/addLogo.jsp" ;
}
}
2.struts.xml
<resultname="input">${inputPage}</result>
深度复制(通过序列化)
Surveys1 = new Survey();
s1.setTitle("ss");
Pagep1 = new Page();
p1.setTitle("pp");
Questionq1 = new Question();
q1.setTitle("q1");
Questionq2 = new Question();
q2.setTitle("q2");
//
p1.setSurvey(s1);
p1.getQuestions().add(q1);
p1.getQuestions().add(q2);
//深度复制
ByteArrayOutputStreambaos = new ByteArrayOutputStream();
ObjectOutputStreamoos = new ObjectOutputStream(baos);
oos.writeObject(p1);
oos.close();
baos.close();
byte[]data = baos.toByteArray();
ByteArrayInputStreambais = new ByteArrayInputStream(data);
ObjectInputStreamois = new ObjectInputStream(bais);
Pagecopy = (Page) ois.readObject();
ois.close();
bais.close();
System.out.println(copy.getTitle());
深度复制,不需要复制的属性可以加transient关键字:
private transient Survey survey;
这样在序列化时就不会复制survey属性
Hibernate公式
<!-- 通过公式查询最大最小页序 -->
<property name="maxOrderno"formula="(select max(p.orderno) from pages p where p.surveyid = id)"/>
<property name="minOrderno"formula="(select min(p.orderno) from pages p where p.surveyid = id)"/>
Sql字符串联接函数concat:
select count(*) from Answer a wherea.questionId = ? and concat(',',a.answerIds,',') like ?
JFreeChart饼图示例:
public class App {
publicstatic void main(String[] args) throws Exception {
//
Stringtitle = "各大公司JEE AS市场占有率统计" ;
DefaultPieDatasetds = new DefaultPieDataset();
ds.setValue("IBM",2000);
ds.setValue("ORACLE",3500);
ds.setValue("JBOSS",1570);
ds.setValue("用友",4400);
JFreeChartchart = ChartFactory.createPieChart3D(title, ds, true, false, false);
//中文
chart.getTitle().setFont(newFont("宋体", Font.BOLD, 25));//标题字体
chart.getLegend().setItemFont(newFont("宋体", Font.PLAIN, 18));
//绘图区
PiePlotplot = (PiePlot) chart.getPlot();
plot.setLabelFont(newFont("宋体", Font.PLAIN, 15));
//背景
//chart.setBackgroundImage(ImageIO.read(newFile("f:/sunset.jpg")));//图表区背景
//plot.setBackgroundImage(ImageIO.read(newFile("f:/water.jpg")));
//设置分裂效果
plot.setExplodePercent("IBM",0.1f);
plot.setExplodePercent("JBOSS",0.2f);
//设置前景色透明度
plot.setForegroundAlpha(0.7f);
//设置标签生成器
//{0}:公司名称
//{1}:销量
//{2}:百分比
//{3}:总量
//{4}:
plot.setLabelGenerator(newStandardPieSectionLabelGenerator("{0}({1}/{3}-{2})"));
ChartUtilities.saveChartAsJPEG(newFile("f:\\pie.jpg"), chart, 800, 500);
}
}
JFreeChart条形图示例:
public class AppBar {
publicstatic void main(String[] args) throws Exception {
DefaultCategoryDatasetds = new DefaultCategoryDataset();
ds.addValue(2000,"IBM", "一季度");
ds.addValue(2300,"ORACLE", "一季度");
ds.addValue(2800,"JBOSS", "一季度");
ds.addValue(3300,"用友", "一季度");
ds.addValue(4800,"IBM", "二季度");
ds.addValue(4300,"ORACLE", "二季度");
ds.addValue(3200,"JBOSS", "二季度");
ds.addValue(1800,"用友", "二季度");
ds.addValue(1500,"IBM", "三季度");
ds.addValue(2600,"ORACLE", "三季度");
ds.addValue(3900,"JBOSS", "三季度");
ds.addValue(2100,"用友", "三季度");
Stringtitle = "前三季度各大公司JEE AS销量统计" ;
JFreeChartchart = ChartFactory.createBarChart3D(title, "季度","销量(单位:万台)", ds, PlotOrientation.VERTICAL, true, false, false);
//中文
chart.getTitle().setFont(newFont("宋体", Font.BOLD, 25));//大标题
//提示条
chart.getLegend().setItemFont(newFont("宋体", Font.BOLD, 15));
CategoryPlotplot = (CategoryPlot) chart.getPlot();
//域轴字体
plot.getDomainAxis().setLabelFont(newFont("宋体", Font.BOLD, 18));
plot.getDomainAxis().setTickLabelFont(newFont("宋体", Font.PLAIN, 15));//小标签字体
//range
plot.getRangeAxis().setLabelFont(newFont("宋体", Font.BOLD, 15));
plot.setForegroundAlpha(0.6f);
ChartUtilities.saveChartAsJPEG(newFile("f:\\bar.jpg"), chart, 800, 500);
}
}
JFreeChart线图示例:
public class AppLine {
publicstatic void main(String[] args) throws Exception {
DefaultCategoryDatasetds = new DefaultCategoryDataset();
ds.addValue(2000,"IBM", "一季度");
ds.addValue(2300,"ORACLE", "一季度");
ds.addValue(2800,"JBOSS", "一季度");
ds.addValue(3300,"用友", "一季度");
ds.addValue(4800,"IBM", "二季度");
ds.addValue(4300,"ORACLE", "二季度");
ds.addValue(3200,"JBOSS", "二季度");
ds.addValue(1800,"用友", "二季度");
ds.addValue(1500,"IBM", "三季度");
ds.addValue(2600,"ORACLE", "三季度");
ds.addValue(3900,"JBOSS", "三季度");
ds.addValue(2100,"用友", "三季度");
Stringtitle = "前三季度各大公司JEE AS销量统计" ;
JFreeChartchart = ChartFactory.createLineChart(title, "季度","销量(单位:万台)", ds, PlotOrientation.VERTICAL, true, false, false);
//中文
chart.getTitle().setFont(newFont("宋体", Font.BOLD, 25));//大标题
//提示条
chart.getLegend().setItemFont(newFont("宋体", Font.BOLD, 15));
CategoryPlotplot = (CategoryPlot) chart.getPlot();
//域轴字体
plot.getDomainAxis().setLabelFont(newFont("宋体", Font.BOLD, 18));
plot.getDomainAxis().setTickLabelFont(newFont("宋体", Font.PLAIN, 15));//小标签字体
//range
plot.getRangeAxis().setLabelFont(newFont("宋体", Font.BOLD, 15));
plot.setForegroundAlpha(0.6f);
ChartUtilities.saveChartAsJPEG(newFile("f:\\line.jpg"), chart, 800, 500);
}
}
Poi示例:
public class App {
publicstatic void main(String[] args) throws Exception {
//内存中
HSSFWorkbookwb = new HSSFWorkbook();
HSSFSheetsheet = wb.createSheet("first sheet");
wb.createSheet("secondsheet");
//创建行
HSSFRowrow = sheet.createRow(0);
HSSFCellcell = row.createCell(0);
cell.setCellValue(false);
row.createCell(1).setCellValue(Calendar.getInstance());
row.createCell(2).setCellValue(newDate());
row.createCell(3).setCellValue(1234567890.9870654f);
Stringdesc = "dddddddddddddddddddddddddddddddddddddddddddddddddddddddd";
row.createCell(4).setCellValue(newHSSFRichTextString(desc));
//格式化数据
HSSFDataFormatformat = wb.createDataFormat();//创建格式对象
HSSFCellStylestyle = wb.createCellStyle();//创建样式对象
//设置格式
style.setDataFormat(format.getFormat("yyyy-MM-ddhh:mm:ss"));
cell= row.getCell(1);
cell.setCellStyle(style);//对cell应用样式
row.getCell(2).setCellStyle(style);
//设置列宽
sheet.setColumnWidth(1,5000);//单位:1/20
sheet.autoSizeColumn(2);
//数字格式化???
style= wb.createCellStyle();
style.setDataFormat(format.getFormat("#,###.0000"));
row.getCell(3).setCellStyle(style);
//文本自动换行
sheet.setColumnWidth(4,5000);
style= wb.createCellStyle();
style.setWrapText(true);//回绕文本
row.getCell(4).setCellStyle(style);
//设置文本对齐方式
sheet.setColumnWidth(0,5000);
row= sheet.createRow(1);
row.createCell(0).setCellValue("左上");
row.createCell(1).setCellValue("中中");
row.createCell(2).setCellValue("右下");
//对齐方式--左上
style= wb.createCellStyle();
style.setAlignment(HSSFCellStyle.ALIGN_LEFT);//左对齐
style.setVerticalAlignment(HSSFCellStyle.VERTICAL_TOP);//上对齐
row.getCell(0).setCellStyle(style);
//对齐方式--中中
style= wb.createCellStyle();
style.setAlignment(HSSFCellStyle.ALIGN_CENTER);//左对齐
style.setVerticalAlignment(HSSFCellStyle.VERTICAL_CENTER);//上对齐
row.getCell(1).setCellStyle(style);
//对齐方式--右下
style= wb.createCellStyle();
style.setAlignment(HSSFCellStyle.ALIGN_RIGHT);//左对齐
style.setVerticalAlignment(HSSFCellStyle.VERTICAL_BOTTOM);//上对齐
row.getCell(2).setCellStyle(style);
//设置行高
row.setHeightInPoints(50);
//设置字体
style= row.getCell(1).getCellStyle();
HSSFFontfont = wb.createFont();
font.setFontName("宋体");
font.setFontHeightInPoints((short)18);
font.setColor(HSSFColor.RED.index);
style.setFont(font);
//文本旋转
style.setRotation((short)-30);
//设置边框
row= sheet.createRow(2);
cell= row.createCell(0);
style= wb.createCellStyle();
style.setBorderTop(HSSFCellStyle.BORDER_DASH_DOT_DOT);
style.setTopBorderColor(HSSFColor.BLUE.index);
cell.setCellStyle(style);
//计算列
row= sheet.createRow(3);
row.createCell(0).setCellValue(20);
row.createCell(1).setCellValue(34.78);
row.createCell(2).setCellValue(45.98);
row.createCell(3).setCellFormula("sum(A4:C4)");
//整体移动行
sheet.shiftRows(1,3, 2);
//拆分窗格
//1000:左侧窗格的宽度
//2000:上侧窗格的高度
//3:右侧窗格开始显示的列的索引
//4:下侧窗格开始显示的行的索引
//1:激活的哪个面板区
sheet.createSplitPane(1000,2000, 3, 4, 1);
//冻结窗口
sheet.createFreezePane(1,2, 3, 4);
wb.write(newFileOutputStream("f:/poi.xls"));
}
}
Html标签中readonly和disabled的区别:
两种都不可以修改,但是disabled不会提交到服务器,readonly会提交
<!-- logger -->
<bean id="logger"class="cn.itcast.surveypark.advice.Logger">
<propertyname="logService" ref="logService" />
</bean>
<!-- aop事务配置 -->
<aop:config>
<!--事务切入点 -->
<aop:pointcutexpression="execution(* *..*Service.*(..))"id="txPointcut"/>
<!--日志切入点 -->
<aop:pointcutexpression="(execution(* *..*Service.save*(..))
orexecution(* *..*Service.update*(..))
orexecution(* *..*Service.delete*(..))
orexecution(* *..*Service.batch*(..))
orexecution(* *..*Service.new*(..))) and !bean(logService)"
id="loggerPointcut"/>
<aop:advisoradvice-ref="txAdvice" pointcut-ref="txPointcut"/>
<!--配置日志切面 -->
<aop:aspectid="loggerAspect" ref="logger">
<aop:aroundmethod="record" pointcut-ref="loggerPointcut"/>
</aop:aspect>
</aop:config>
日志类:
public class Logger {
private LogService logService;
//注入logService
public void setLogService(LogService logService) {
this.logService = logService;
}
public Object record(ProceedingJoinPoint pjp){
Log log = new Log();
try {
ActionContext ac = ActionContext.getContext();
if(ac != null){
HttpServletRequest request =(HttpServletRequest) ac.get(ServletActionContext.HTTP_REQUEST);
if(request != null){
User user = (User)request.getSession().getAttribute("user");
if(user != null){
log.setOperator("" +user.getId() + ":" + user.getEmail());
}
}
}
//方法名
String methodName = pjp.getSignature().getName();
log.setOperName(methodName);
//方法参数列表
Object[] args = pjp.getArgs();
log.setOperParams(StringUtil.arr2Str(args));
//调用目标对象的方法
Object ret = pjp.proceed();
//成功
log.setOperResult("success");
//结果消息
if(ret != null){
log.setOperResult(ret.toString());
}
return ret;
} catch (Throwable throwable) {
log.setOperResult("failure");
log.setResultMsg(throwable.getMessage());
} finally {
logService.saveEntity(log);
}
return null;
}
}
Struts2允许静态方法调用:
Strust.xml
在default.properties中搜索static:struts.ognl.allowStaticMethodAccess=true
<!-- 允许静态方法调用 -->
<constantname="struts.ognl.allowStaticMethodAccess" value="true"/>
大数据量处理:
数据量大:
1.分表(动态表).
2.分库.
使用spring的调度器动态生成日志表
1.引入quartz类库
com.springsource.org.quartz-1.6.2.jar
2.创建石英任务
Mysql创建表(如果不存在就创建):
Create tatble if not exists logs_2013_2like logs;//表结构和logs一样
使用调度器动态生成日志表
------------------------------
0.dao和service增加执行原生sql语句的功能.
dao
-----------------
publicinterface BaseDao<T> {
...
publicvoid executeSQL(String sql,Object...objects);
}
publicclass BaseDaImpl<T> ...{
...
//执行原生的sql语句
publicvoid executeSQL(String sql,Object...objects){
SQLQueryq = sf.getCurrentSession().createSQLQuery(sql);
for(inti = 0 ; i < objects.length ; i ++){
q.setParameter(i,objects[i]);
}
q.executeUpdate();
}
}
service
-----------------------
publicinterface BaseService<T> {
...
publicvoid executeSQL(String sql,Object...objects);
}
publicabstract class BaseServiceImpl<T> implements BaseService<T> {
...
//执行原生的sql语句
publicvoid executeSQL(String sql,Object...objects){
dao.executeSQL(sql,objects);
}
}
1.引入quartz类库
com.springsource.org.quartz-1.6.2.jar
2.创建石英任务
/**
* 使用spring集成的石英调度,动态生成日志表
*/
publicclass GenerateLogsTableTask extends QuartzJobBean {
//
privateLogService logService ;
publicvoid setLogService(LogService logService) {
this.logService= logService;
}
/**
* 执行任务
*/
protectedvoid executeInternal(JobExecutionContext arg0) throws JobExecutionException {
StringtableName = LogUtil.generateLogTableName(1);
Stringsql = "create table if not exists " + tableName + " likelogs";
logService.executeSQL(sql);
System.out.println(tableName+ " 生成了! " );
tableName= LogUtil.generateLogTableName(2);
sql= "create table if not exists " + tableName + " like logs";
logService.executeSQL(sql);
System.out.println(tableName+ " 生成了! " );
}
}
3.配置调度任务
[conf/schedules.xml]
<?xmlversion="1.0"?>
<beansxmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-3.0.xsd">
<!--任务明细bean,对石英任务包装 -->
<beanid="jobDetailBean"class="org.springframework.scheduling.quartz.JobDetailBean">
<propertyname="jobClass"value="cn.itcast.surveypark.schedule.GenerateLogsTableTask" />
<propertyname="jobDataAsMap">
<map>
<entrykey="logService" value-ref="logService" />
</map>
</property>
</bean>
<!--cron触发器bean,设置任务的调度策略的 -->
<beanid="cronTriggerBean"class="org.springframework.scheduling.quartz.CronTriggerBean">
<propertyname="jobDetail" ref="jobDetailBean" />
<!--cron表达式 -->
<propertyname="cronExpression">
<value>00 0 15 * ?</value>
</property>
</bean>
<!--调度器工厂bean,激活触发器,启动石英任务的 -->
<beanclass="org.springframework.scheduling.quartz.SchedulerFactoryBean">
<propertyname="triggers">
<refbean="cronTriggerBean"/>
</property>
</bean>
</beans>
4.配置web.xml文件,一同加载spring的所有配置文件
<!--通过上下文参数指定spring配置文件的位置 -->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:beans.xml,classpath:schedules.xml</param-value>
</context-param>
5.修改时间,为触发任务接近的时间,比如2013-1-1423:59:00秒
6.启动观察效果
mySql联合查询(合并两次查询的结果):
Select * from logs_2013_1 union select *from logs_2013_2;
Spring石英任务包装:
<?xml version="1.0"?>
<beansxmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-3.0.xsd">
<!--任务明细bean,对石英任务包装 -->
<beanid="jobDetailBean" class="org.springframework.scheduling.quartz.JobDetailBean">
<propertyname="jobClass"value="cn.itcast.surveypark.schedule.GenerateLogsTableTask" />
<propertyname="jobDataAsMap">
<map>
<entrykey="logService" value-ref="logService" />
</map>
</property>
</bean>
<!--cron触发器bean,设置任务的调度策略的 -->
<beanid="cronTriggerBean"class="org.springframework.scheduling.quartz.CronTriggerBean">
<propertyname="jobDetail" ref="jobDetailBean" />
<!--cron表达式 -->
<propertyname="cronExpression">
<value>00 0 15 * ?</value>
</property>
</bean>
<!--调度器工厂bean,激活触发器,启动石英任务的 -->
<beanclass="org.springframework.scheduling.quartz.SchedulerFactoryBean">
<propertyname="triggers">
<refbean="cronTriggerBean"/>
</property>
</bean>
</beans>
对于数据库数据量不大,库里面某个表的数据量大的时候,可以采用分表存储。
对于数据库数据量大的时候,可以分库存储。分库分为竖直分库和水平分库。
可扩展性:伸缩性.scalable
降低数据库存储压力:
分表:整个库的数据量不是很大,但是某个(些)表的数据量较大.
分库:
竖直:数据库之间是异构的.
水平:数据库之间是同构的.(数据存储范围不同)
竖直分库(竖直分库的库结构不同,数据库异构,适用于每个模块独立性比较强,量又比较大):
水平分库(模块之间结构比较紧密,经常跨模块访问)
模块划分:
设计调查
参与调查
调查维护
统计分析
权限控制
系统模块
日志
事务
安全
采用分库处理,存放答案.
-------------------------
1.创建从库
lsn_surveypark0909(主库)
lsn_surveypark0909_1(从库)
2.配置多个数据源
3.创建数据源路由器
4.配置数据源路由器
Spring,Struts,Hibernate框架集成流程:
路由数据源:
1,
2,更改loger和tx的顺序,通过oder
<!-- 数据源(主库) -->
<bean id="dataSource_main"class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="driverClass"value="${jdbc.driverclass}" />
<property name="jdbcUrl" value="${jdbc.url}"/>
<property name="user" value="${jdbc.username}"/>
<property name="password"value="${jdbc.password}" />
<property name="maxPoolSize"value="${c3p0.pool.size.max}" />
<property name="minPoolSize"value="${c3p0.pool.size.min}" />
<property name="initialPoolSize"value="${c3p0.pool.size.ini}" />
<property name="acquireIncrement"value="${c3p0.pool.size.increment}" />
</bean>
<!-- 数据源(从库) -->
<bean id="dataSource_1"parent="dataSource_main">
<property name="jdbcUrl"value="jdbc:mysql://localhost:3306/lsn_surveypark0909_1" />
</bean>
<!-- 数据源路由器 -->
<bean id="dataSource_router"class="cn.itcast.surveypark.datasource.SurveyparkDataSourceRouter">
<property name="targetDataSources">
<map>
<entry key="odd"value-ref="dataSource_main" />
<entry key="even"value-ref="dataSource_1" />
</map>
</property>
<property name="defaultTargetDataSource"ref="dataSource_main" />
</bean>
/**
* 自定义数据源路由器
*/
importorg.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;
public classSurveyparkDataSourceRouter extends AbstractRoutingDataSource {
protected ObjectdetermineCurrentLookupKey() {
SurveyToken token =SurveyToken.getCurrentToken();
if(token != null){
int id =token.getCurrentSurvey().getId();
//解除绑定
SurveyToken.unbindToken();
return (id % 2) ==0?"even":"odd" ;
}
return null;
}
}
/**
* 调查令牌,绑定到当前的线程,传播到数据源路由器.进行分库判断
*/
public classSurveyToken {
private Survey currentSurvey ;
private staticThreadLocal<SurveyToken> t = new ThreadLocal<SurveyToken>();
public Survey getCurrentSurvey() {
return currentSurvey;
}
public void setCurrentSurvey(SurveycurrentSurvey) {
this.currentSurvey = currentSurvey;
}
/**
* 将令牌对象绑定到当前线程
*/
public static void bindingToken(SurveyTokentoken){
t.set(token);
}
/**
* 从当前线程取得绑定的令牌对象
*/
public static SurveyTokengetCurrentToken(){
return t.get() ;
}