|
2006年12月6日
至此,准备工作就可以了。 看看页面怎么写的 运行,就可以了。
在struts2中,获取表单元素有三种方式: 1.在action类中,为属性提供get/set方法。 2.使用javabean的引用,提供get/set方法。但是表单中名字必须是javabean引用的名字.属性名。 3.实现Modeldriven接口。
摘要: 说实话,eclipse我受够了.自从用了Intellijidea ,我的腰不酸了,腿不疼了,一口气能上一层楼.先上代码结构数据库表结构
Code highlighting produced by Actipro CodeHighlighter (freeware)http://www.CodeHighlighter.com/--> 1 CREATE DATABASE... 阅读全文
Map接口: | + -- WeakHashMap: 以弱键 实现的基于哈希表的 Map。在 WeakHashMap 中,当某个键不再正常使用时,将自动移除其条 | 目。更精确地说,对于一个给定的键,其映射的存在并不阻止垃圾回收器对该键的丢弃,这就使该键成为可终止的,被终 | 止,然后被回收。丢弃某个键时,其条目从映射中有效地移除,因此,该类的行为与其他的 Map 实现有所不同。此实现 | 不是同步的。 | + -- TreeMap:该映射根据其键的自然顺序进行排序,或者根据创建映射时提供的 Comparator 进行排序,具体取决于使用的 | 构造方法。此实现不是同步的。 | + -- HashMap:基于哈希表的 Map 接口的实现。此实现提供所有可选的映射操作,并允许使用 null 值和 null 键。(除了 | 非同步和允许使用 null 之外,HashMap 类与 Hashtable 大致相同。)此类不保证映射的顺序,特别是它不保证该顺 | 序恒久不变。此实现不是同步的。 | +-- SortedMap: 进一步提供关于键的总体排序 的 Map。该映射是根据其键的自然顺序进行排序的,或者根据通常在创建有 序映射时提供的 Comparator 进行排序。对有序映射的 collection 视图(由 entrySet、keySet 和 values 方法返回 )进行迭代时,此顺序就会反映出来。要采用此排序方式,还需要提供一些其他操作(此接口是 SortedSet 的对应映 射)。
Collection接口: | + -- Set接口:一个不包含重复元素的 collection。更正式地说,set 不包含满足 e1.equals(e2) 的元素对 e1 和 e2,并 | | 且最多包含一个 null 元素。正如其名称所暗示的,此接口模仿了数学上的 set 抽象。 | | | + -- HashSet:此类实现 Set 接口,由哈希表(实际上是一个 HashMap 实例)支持。它不保证 set 的迭代顺序; | | 特别是它不保证该顺序恒久不变。此类允许使用 null 元素。此类为基本操作提供了稳定性能,此实现不是同 | | 步的。 | | | + -- LinkedHashSet:具有可预知迭代顺序的 Set 接口的哈希表和链接列表实现。此实现与 HashSet 的不同之外在 | | 于,后者维护着一个运行于所有条目的双重链接列表。此链接列表定义了迭代顺序,即按照将元素插入到 set | | 中 的顺序(插入顺序)进行迭代。注意,插入顺序不 受在 set 中重新插入的 元素的影响。此实现不是同步 | | 的。 | | | + -- TreeSet:基于 TreeMap 的 NavigableSet 实现。使用元素的自然顺序对元素进行排序,或者根据创建 set 时 | 提供的 Comparator 进行排序,具体取决于使用的构造方法。此实现为基本操作(add、remove 和 contains) | 提供受保证的 log(n) 时间开销。此实现不是同步的。 | + -- List接口:有序的 collection(也称为序列)。此接口的用户可以对列表中每个元素的插入位置进行精确地控制。用户 | 可以根据元素的整数索引(在列表中的位置)访问元素,并搜索列表中的元素。 | + -- ArrayList:List 接口的大小可变数组的实现。实现了所有可选列表操作,并允许包括 null 在内的所有元素。 | 除了实现 List 接口外,此类还提供一些方法来操作内部用来存储列表的数组的大小。(此类大致上等同于 | Vector 类,除了此类是不同步的。)每个 ArrayList 实例都有一个容量。该容量是指用来存储列表元素的数 | 组的大小。它总是至少等于列表的大小。随着向 ArrayList 中不断添加元素,其容量也自动增长。并未指定增 | 长策略的细节,因为这不只是添加元素会带来分摊固定时间开销那样简单。此实现不是同步的。 | + -- LinkedList:List 接口的链接列表实现。实现所有可选的列表操作,并且允许所有元素(包括 null)。除了实 | 现 List 接口外,LinkedList 类还为在列表的开头及结尾 get、remove 和 insert 元素提供了统一的命名方 | 法。这些操作允许将链接列表用作堆栈、队列或双端队列。提供先进先出队列操作(FIFO)。此实现不是同步的。 | + -- Vector:Vector 类可以实现可增长的对象数组。与数组一样,它包含可以使用整数索引进行访问的组件。但是 ,Vector 的大小可以根据需要增大或缩小,以适应创建 Vector 后进行添加或移除项的操作。此实现是同步的 。 |
自从用上了tomcat5.5,发现日志信息没了,出错了也找不着有用的信息,上apache找答案,果然
Tomcat 5.5 uses Commons Logging throughout its internal code allowing the developer to choose a logging configuration that suits their needs, e.g java.util.logging or Log4J. Commons Logging provides Tomcat the ability to log hierarchially across various log levels without needing to rely on a particular logging implementation.
An important consequence for Tomcat 5.5 is that the <Logger> element found in previous versions to create a localhost_log is no longer a valid nested element of <Context>. Instead, the default Tomcat configuration will use java.util.logging. If the developer wishes to collect detailed internal Tomcat logging (i.e what is happening within the Tomcat engine), then they should configure a logging system such as java.util.logging or log4j as detailed next
习惯用log4j来配置log信息的输出。
新建log4j.properties,内容为
log4j.rootLogger=info,Console,R
log4j.appender.Console=org.apache.log4j.ConsoleAppender log4j.appender.Console.layout=org.apache.log4j.PatternLayout #log4j.appender.Console.layout.ConversionPattern=%d [%t] %-5p %c - %m%n log4j.appender.Console.layout.ConversionPattern=%d{yy-MM-dd HH:mm:ss} %5p %c{1}:%L - %m%n
log4j.appender.R=org.apache.log4j.DailyRollingFileAppender log4j.appender.R.File=${catalina.home}/logs/tomcat.log log4j.appender.R.layout=org.apache.log4j.PatternLayout log4j.appender.R.layout.ConversionPattern=%d{yyyy.MM.dd HH:mm:ss} %5p %c{1}(%L): %m%n
log4j.logger.org.apache=info, R log4j.logger.org.apache.catalina.core.ContainerBase.[Catalina].[localhost]=DEBUG, R log4j.logger.org.apache.catalina.core=info, R log4j.logger.org.apache.catalina.session=info, R
最后四行是tomcat的信息,如果改为debug日志文件将十分庞大。
将这个文件放入${catalina.home}/common/classes下,再将log4j.jar和commons-logging.jar放入${catalina.home}/common/lib下,就可以在${catalina.home}/logs/下见到日志了。
Servlet 和filter是J2EE开发中常用的技术,使用方便,配置简单,老少皆宜。估计大多数朋友都是直接配置用,也没有关心过具体的细节,今天遇到一个问题,上网查了servlet的规范才发现,servlet和filter中的url-pattern还是有一些文章在里面的,总结了一些东西,放出来供大家参考,以免遇到问题又要浪费时间。 一,servlet容器对url的匹配过程: 当一个请求发送到servlet容器的时候,容器先会将请求的url减去当前应用上下文的路径作为servlet的映射url,比如我访问的是http://localhost/test/aaa.html,我的应用上下文是test,容器会将http://localhost/test去掉,剩下的/aaa.html部分拿来做servlet的映射匹配。这个映射匹配过程是有顺序的,而且当有一个servlet匹配成功以后,就不会去理会剩下的servlet了(filter不同,后文会提到)。其匹配规则和顺序如下: 1. 精确路径匹配。例子:比如servletA 的url-pattern为 /test,servletB的url-pattern为/* ,这个时候,如果我访问的url为http://localhost/test,这个时候容器就会先进行精确路径匹配,发现/test正好被servletA精确匹配,那么就去调用servletA,也不会去理会其他的servlet了。 2. 最长路径匹配。例子:servletA的url-pattern为/test/*,而servletB的url-pattern为/test/a/*,此时访问http://localhost/test/a时,容器会选择路径最长的servlet来匹配,也就是这里的servletB。 3. 扩展匹配,如果url最后一段包含扩展,容器将会根据扩展选择合适的servlet。例子:servletA的url-pattern:*.action 4. 如果前面三条规则都没有找到一个servlet,容器会根据url选择对应的请求资源。如果应用定义了一个default servlet,则容器会将请求丢给default servlet(什么是default servlet?后面会讲)。 |
根据这个规则表,就能很清楚的知道servlet的匹配过程,所以定义servlet的时候也要考虑url-pattern的写法,以免出错。 对于filter,不会像servlet那样只匹配一个servlet,因为filter的集合是一个链,所以只会有处理的顺序不同,而不会出现只选择一个filter。Filter的处理顺序和filter-mapping在web.xml中定义的顺序相同。 二,url-pattern详解 在web.xml文件中,以下语法用于定义映射: l 以”/’开头和以”/*”结尾的是用来做路径映射的。 l 以前缀”*.”开头的是用来做扩展映射的。 l “/” 是用来定义default servlet映射的。 l 剩下的都是用来定义详细映射的。比如: /aa/bb/cc.action 所以,为什么定义”/*.action”这样一个看起来很正常的匹配会错?因为这个匹配即属于路径映射,也属于扩展映射,导致容器无法判断。
使用servlet来下载文件,其原理非常简单,只要得到文件的输入流(或相应字节),然后写输出流即可。现就其中的几个细节问题展开: 1. MIME类型的设置: Web 浏览器使用 MIME 类型来识别非 HTML 文档,并决定如何显示该文档内的数据。 例如EXCEL文件的 MIME 类型是 "application/vnd.ms-excel "。要用servlet 来打开一个 EXCEL 文档,需要将 response 对象中 header 的 contentType 设置成“application/vnd.ms-excel ”。 response.setContentType(contentType); 2. Content disposition HTTP response header中的content-disposition 允许 servlet 指定文档表示的信息。使用这种header ,你就可以将文档指定成单独打开(而不是在浏览器中打开),还可以根据用户的操作来显示。 如果用户要保存文档,你还可以为该文档建议一个文件名。这个建议名称会出现在 Save As 对话框的“文件名”栏中。如果没有指定,则对话框中就会出现 servlet 的名字。 servlet 中,将 header 设置成下面这样: response.setHeader("Content-disposition","attachment;filename="+ "Example.xls" );
response.setHeader("Content-Disposition", "inline; filename="fliename) 点击打开会在ie中打开。
需要说明的有三点: Ø 中文文件名需要进行iso8859-1转码方可正确显示: fileName = new String(fileName.getBytes("GBK"),"iso8859-1"); Ø 传递的文件名,需要包含后缀名(如果此文件有后缀名),否则丢失文件的属性,而不能自行选择相关程序打开。 Ø 有下载前询问(是打开文件还是保存到计算机)和通过IE浏览器直接选择相关应用程序插件打开两种方式,前者如上代码所示,后者如下: response.setHeader("Content-disposition","filename="+ "Example.xls" ); 3. 在研究文件的上传及下载过程中,有几点体会 程序的I/O操作往往是性能的瓶颈所在,java io定义了两个基本的抽象类:InputStream和OutputStream,对于不同的数据类型比如磁盘,网络又提供了不同的实现,java.io也提供了一些缓冲流(BufferedStream),使硬盘可以很快的读写一大块的数据, 而Java基本的I/O类一次只能读写一个字节,但缓冲流(BufferedStream)可以一次读写一批数据,,缓冲流(Buffered Stream)大大提高了I/O的性能。所以: Ø小块小块的读写数据会非常慢,因此,尽量大块的读写数据 Ø使用BufferedInputStream和BufferedOutputStream来批处理数据以提高性能 Ø对象的序列化(serialization)非常影响I/O的性能,尽量少用
希望对刚开始学Hibernate的同学有所帮助。
一、saveorUpdate与unsaved-value
到底是sava还是update Hibernate需要判断被操作的对象究竟是一个已经持久化过的持久对象还是临时对象。 1).主键Hibernate的id generator产生 <id name="id" type="java.lang.Long"> <column name="ID" precision="22" scale="0" /> <generator class="increment" /> </id>
Project project = new Project(); project.setId(XXX); this.projectDao.saveOrUpdate(project);
1、默认unsaved-value="null" 主键是对象类型,hebernate判断project的主键是否位null,来判断project是否已被持久化 是的话,对project对象发送save(project), 若自己设置了主键则直接生成update的sql,发送update(project),即便数据库里没有那条记录。 主键是基本类型如int/long/double/ 自己设置unsaved-null="0"。 所以这样的话save和update操作肯定不会报错。
2、unsaved-value="none", 由于不论主键属性为任何值,都不可能为none,因此Hibernate总是对project对象发送update(project)
3、unsaved-value="any" 由于不论主键属性为任何值,都肯定为any,因此Hibernate总是对project对象发送save(project),hibernate生成主键。
Hibernate文档中写到 saveOrUpdate()完成了如下工作: 如果对象已经在这个session中持久化过了,什么都不用做 如果对象没有标识值,调用save()来保存它 如果对象的标识值与unsaved-value中的条件匹配,调用save()来保存它 如果对象使用了版本(version或timestamp),那么除非设置unsaved-value="undefined",版本检查会发生在标识符检查之前. 如果这个session中有另外一个对象具有同样的标识符,抛出一个异常
2).主键由自己来赋值
<id name="id" type="java.lang.Long"> <column name="ID" precision="22" scale="0" /> <generator class="assigned" /> </id>
Project project = new Project(); project.setId(XXX); this.projectDao.saveOrUpdate(project);
1、默认unsaved-value="null" 这时有所不同,hibernate会根据主键产生一个select,来判断此对象是否已被持久化 已被持久化则update,未被持久化则save。 2、unsaved-value="none",update对象,同上
3、unsaved-value="any" ,save对象, 如果自己自己设置的ID在数据库中已存在,则报错。
二、save与update操作
显式的使用session.save()或者session.update()操作一个对象的时候,实际上是用不到unsaved-value的 在同一Session,save没什么可说得 update对象时, 最直接的更改一个对象的方法就是load()它,保持Session打开,然后直接修改即可: Session s =… Project p = (Project) sess.load(Project.class, id) ); p.setName(“test”); s.flush(); 不用调用s.update(p);hibernate能察觉到它的变化,会自动更新。当然显示调用的话也不会错
Hibernate文档中写到 update()方法在下列情形下使用: 程序在前面的session中装载了对象 对象被传递到UI(界面)层 对该对象进行了一些修改 对象被传递回业务层 应用程序在第二个session中调用update()保存修改
三、delete操作
删除时直接自己构造一个project即可删除 this.projectDao.delete(preojct);
以前删除我是这样写的 public void deleteProject(String id) { Project project = (Project) this.projectDao.get(Project.class, id); if (project != null) { this.projectDao.delete(project); } 即这样也是可以的 Project project = new Project(); project.setId(id); this.projectDao.delete(project).
如果有级联关系,需要把级联的子类也构造出来add进去,同样可以删除。
好了,罗嗦的够多了。
1、遍历workbook
代码
-
-
POIFSFileSystem fs =
new
POIFSFileSystem(
new
FileInputStream(filePath));
-
HSSFWorkbook wb =
new
HSSFWorkbook(fs);
-
for
(
int
i =
0
; i < wb.getNumberOfSheets(); i++) {
-
HSSFSheet sheet = wb.getSheetAt(i);
-
for
(
int
i = sheet.getFirstRowNum(); i < sheet.getLastRowNum(); i ++) {
-
HSSFRow row = sheet.getRow(i);
-
if
(row !=
null
) {
-
。。。操作}
-
}
-
}
-
-
FileOutputStream fos =
new
FileOutputStream(objectPath);
-
-
swb.write(fos);
-
fos.close();
2、得到列和单元格
代码
-
HSSFRow row = sheet.getRow(i);
-
HSSFCell cell = row.getCell((
short
) j);
3、设置sheet名称和单元格内容为中文
代码
-
wb.setSheetName(n,
"中文"
,HSSFCell.ENCODING_UTF_16);
-
cell.setEncoding((
short
)
1
);
-
cell.setCellValue(
"中文"
);
4、单元格内容未公式或数值,可以这样读写
代码
-
cell.setCellType(HSSFCell.CELL_TYPE_NUMERIC);
-
cell.getNumericCellValue()
5、设置列宽、行高
代码
-
sheet.setColumnWidth((
short
)column,(
short
)width);
-
row.setHeight((
short
)height);
6、添加区域,合并单元格
代码
-
Region region =
new
Region((
short
)rowFrom,(
short
)columnFrom,(
short
)rowTo,(
short
)columnTo);
-
sheet.addMergedRegion(region);
-
-
sheet.getNumMergedRegions()
7、常用方法
根据单元格不同属性返回字符串数值
代码
-
public
String getCellStringValue(HSSFCell cell) {
-
String cellValue =
""
;
-
switch
(cell.getCellType()) {
-
case
HSSFCell.CELL_TYPE_STRING:
-
cellValue = cell.getStringCellValue();
-
if
(cellValue.trim().equals(
""
)||cellValue.trim().length()<=
0
)
-
cellValue=
" "
;
-
break
;
-
case
HSSFCell.CELL_TYPE_NUMERIC:
-
cellValue = String.valueOf(cell.getNumericCellValue());
-
break
;
-
case
HSSFCell.CELL_TYPE_FORMULA:
-
cell.setCellType(HSSFCell.CELL_TYPE_NUMERIC);
-
cellValue = String.valueOf(cell.getNumericCellValue());
-
break
;
-
case
HSSFCell.CELL_TYPE_BLANK:
-
cellValue=
" "
;
-
break
;
-
case
HSSFCell.CELL_TYPE_BOOLEAN:
-
break
;
-
case
HSSFCell.CELL_TYPE_ERROR:
-
break
;
-
default
:
-
break
;
-
}
-
return
cellValue;
-
}
8、常用单元格边框格式
虚线HSSFCellStyle.BORDER_DOTTED 实线HSSFCellStyle.BORDER_THIN
代码
-
public
static
HSSFCellStyle getCellStyle(
short
type)
-
{
-
HSSFWorkbook wb =
new
HSSFWorkbook();
-
HSSFCellStyle style = wb.createCellStyle();
-
style.setBorderBottom(type);
-
style.setBorderLeft(type);
-
style.setBorderRight(type);
-
style.setBorderTop(type);
-
return
style;
-
}
9、设置字体和内容位置
代码
-
HSSFFont f = wb.createFont();
-
f.setFontHeightInPoints((
short
)
11
);
-
f.setBoldweight(HSSFFont.BOLDWEIGHT_NORMAL);
-
style.setFont(f);
-
style.setAlignment(HSSFCellStyle.ALIGN_CENTER);
-
style.setVerticalAlignment(HSSFCellStyle.VERTICAL_CENTER);
-
style.setRotation(
short
rotation);
-
HSSFDataFormat df = wb.createDataFormat();
-
style1.setDataFormat(df.getFormat(
"0.00%"
));
-
cell.setCellFormula(string);
-
style.setRotation(
short
rotation);
-
cell.setCellStyle(style);
10、插入图片
论坛里看到的
代码 -
- ByteArrayOutputStream byteArrayOut = new ByteArrayOutputStream();
- BufferedImage bufferImg = ImageIO.read(new File("ok.jpg"));
- ImageIO.write(bufferImg,"jpg",byteArrayOut);
-
- FileInputStream fos = new FileInputStream(filePathName+"/stencil.xlt");
- fs = new POIFSFileSystem(fos);
-
- HSSFWorkbook wb = new HSSFWorkbook(fs);
- HSSFSheet sheet = wb.getSheetAt(0);
- HSSFPatriarch patriarch = sheet.createDrawingPatriarch();
- HSSFClientAnchor anchor = new HSSFClientAnchor(0,0,1023,255,(short) 0,0,(short)10,10);
- patriarch.createPicture(anchor , wb.addPicture(byteArrayOut.toByteArray(),HSSFWorkbook.PICTURE_TYPE_JPEG));
|
最后更新:2006-10-30 20:12
一.POI简介
Jakarta POI 是apache的子项目,目标是处理ole2对象。它提供了一组操纵Windows文档的Java API
目前比较成熟的是HSSF接口,处理MS Excel(97-2002)对象。它不象我们仅仅是用csv生成的没有格式的可以由Excel转换的东西,而是真正的Excel对象,你可以控制一些属性如sheet,cell等等。
二.HSSF概况
HSSF 是Horrible SpreadSheet Format的缩写,也即“讨厌的电子表格格式”。也许HSSF的名字有点滑稽,就本质而言它是一个非常严肃、正规的API。通过HSSF,你可以用纯Java代码来读取、写入、修改Excel文件。
HSSF 为读取操作提供了两类API:usermodel和eventusermodel,即“用户模型”和“事件-用户模型”。前者很好理解,后者比较抽象,但操作效率要高得多。
三.开始编码
1 . 准备工作
要求:JDK 1.4+POI开发包
可以到
http://www.apache.org/dyn/closer.cgi/jakarta/poi/
最新的POI工具包
2 . EXCEL 结构
HSSFWorkbook excell 文档对象介绍 HSSFSheet excell的表单 HSSFRow excell的行 HSSFCell excell的格子单元 HSSFFont excell字体 HSSFName 名称 HSSFDataFormat 日期格式 在poi1.7中才有以下2项: HSSFHeader sheet头 HSSFFooter sheet尾 和这个样式 HSSFCellStyle cell样式 辅助操作包括 HSSFDateUtil 日期 HSSFPrintSetup 打印 HSSFErrorConstants 错误信息表
3 .具体用法实例 (采用 usermodel )
如何读Excel
读取Excel文件时,首先生成一个POIFSFileSystem对象,由POIFSFileSystem对象构造一个HSSFWorkbook,该HSSFWorkbook对象就代表了Excel文档。下面代码读取上面生成的Excel文件写入的消息字串: try{ POIFSFileSystem fs=new POIFSFileSystem(new FileInputStream("d:/workbook.xls")); HSSFWorkbook wb = new HSSFWorkbook(fs); HSSFSheet sheet = wb.getSheetAt(0); HSSFRow row = sheet.getRow(0); HSSFCell cell = row.getCell((short) 0); String msg = cell.getStringCellValue(); System.out.println(msg); }catch(Exception e){ e.printStackTrace(); }
如何写excel,
将excel的第一个表单第一行的第一个单元格的值写成“a test”。
POIFSFileSystem fs =new POIFSFileSystem(new FileInputStream("workbook.xls"));
HSSFWorkbook wb = new HSSFWorkbook(fs);
HSSFSheet sheet = wb.getSheetAt(0);
HSSFRow row = sheet.getRow(0);
HSSFCell cell = row.getCell((short)0);
cell.setCellValue("a test");
// Write the output to a file
FileOutputStream fileOut = new FileOutputStream("workbook.xls");
wb.write(fileOut);
fileOut.close();
4 . 可参考文档
POI 主页:
http://jakarta.apache.org/poi/
,
初学者如何快速上手使用POI HSSF
http://jakarta.apache.org/poi/hssf/quick-guide.html
。
里面有很多例子代码,可以很方便上手。
四.使用心得
POI HSSF 的usermodel包把Excel文件映射成我们熟悉的结构,诸如Workbook、Sheet、Row、Cell等,它把整个结构以一组对象的形式保存在内存之中,便于理解,操作方便,基本上能够满足我们的要求,所以说这个一个不错的选择。
------------------------------- 前面已经讲过利用POI读写Excel,下面是一个用POI向Excel中插入图片的例子。
官方文档: Images are part of the drawing support. To add an image just call createPicture() on the drawing patriarch. At the time of writing the following types are supported: PNG JPG DIB It is not currently possible to read existing images and it should be noted that any existing drawings may be erased once you add a image to a sheet.
// Create the drawing patriarch. This is the top level container for // all shapes. This will clear out any existing shapes for that sheet.
通过HSSFPatriarch类createPicture方法的在指定的wb中的sheet创建图片,它接受二个参数,第一个是HSSFClientAnchor,设定图片的大小。
1
package
com.poi.hssf.test;
2
3
import
java.io.FileOutputStream;
4
import
java.io.File;
5
import
java.io.ByteArrayOutputStream;
6
import
java.io.IOException;
7
8
import
java.awt.image.BufferedImage;
9
import
javax.imageio.
*
;
10
11
import
org.apache.poi.hssf.usermodel.HSSFWorkbook;
12
import
org.apache.poi.hssf.usermodel.HSSFSheet;
13
import
org.apache.poi.hssf.usermodel.HSSFPatriarch;
14
import
org.apache.poi.hssf.usermodel.HSSFClientAnchor;;
15
16
public
class
TestPOI
{
17
18
public
static
void
main(String[] args)
{
19
FileOutputStream fileOut
=
null
;
20
BufferedImage bufferImg
=
null
;
21
BufferedImage bufferImg1
=
null
;
22
try
{
23
24
//
先把读进来的图片放到一个ByteArrayOutputStream中,以便产生ByteArray
25
ByteArrayOutputStream byteArrayOut
=
new
ByteArrayOutputStream();
26
ByteArrayOutputStream byteArrayOut1
=
new
ByteArrayOutputStream();
27
bufferImg
=
ImageIO.read(
new
File(
"
d:/PieChart.jpg
"
));
28
bufferImg1
=
ImageIO.read(
new
File(
"
d:/fruitBarChart.jpg
"
));
29
ImageIO.write(bufferImg,
"
jpg
"
,byteArrayOut);
30
ImageIO.write(bufferImg1,
"
jpg
"
,byteArrayOut1);
31
32
//
创建一个工作薄
33
HSSFWorkbook wb
=
new
HSSFWorkbook();
34
HSSFSheet sheet1
=
wb.createSheet(
"
new sheet
"
);
35
//
HSSFRow row = sheet1.createRow(2);
36
HSSFPatriarch patriarch
=
sheet1.createDrawingPatriarch();
37
HSSFClientAnchor anchor
=
new
HSSFClientAnchor(
0
,
0
,
512
,
255
,(
short
)
1
,
1
,(
short
)
10
,
20
);
38
HSSFClientAnchor anchor1
=
new
HSSFClientAnchor(
0
,
0
,
512
,
255
,(
short
)
2
,
30
,(
short
)
10
,
60
);
39
anchor1.setAnchorType(
2
);
40
//
插入图片
41
patriarch.createPicture(anchor , wb.addPicture(byteArrayOut.toByteArray(),HSSFWorkbook.PICTURE_TYPE_JPEG));
42
patriarch.createPicture(anchor1 , wb.addPicture(byteArrayOut1.toByteArray(),HSSFWorkbook.PICTURE_TYPE_JPEG));
43
44
fileOut
=
new
FileOutputStream(
"
d:/workbook.xls
"
);
45
//
写入excel文件
46
wb.write(fileOut);
47
fileOut.close();
48
49
}
catch
(IOException io)
{
50
io.printStackTrace();
51
System.out.println(
"
io erorr :
"
+
io.getMessage());
52
}
finally
53
{
54
if
(fileOut
!=
null
)
55
{
56
57
try
{
58
fileOut.close();
59
}
60
catch
(IOException e)
61
{
62
//
TODO Auto-generated catch block
63
e.printStackTrace();
64
}
65
}
66
}
67
}
68
}
目前整个开发社区对AOP(Aspect Oriented Programing)推崇备至,也涌现出大量支持AOP的优秀Framework,--Spring, JAC, Jboss AOP 等等。AOP似乎一时之间成了潮流。Java初学者不禁要发出感慨,OOP还没有学通呢,又来AOP。本文不是要在理论上具体阐述何为AOP, 为何要进行AOP . 要详细了解学习AOP可以到它老家http://aosd.net去瞧瞧。这里只是意图通过一个简单的例子向初学者展示一下如何来进行AOP.
为了简单起见,例子没有没有使用任何第三方的AOP Framework, 而是利用Java语言本身自带的动态代理功能来实现AOP.
让我们先回到AOP本身,AOP主要应用于日志记录,性能统计,安全控制,事务处理等方面。它的主要意图就要将日志记录,性能统计,安全控制等等代码从商业逻辑代码中清楚的划分出来,我们可以把这些行为一个一个单独看作系统所要解决的问题,就是所谓的面向问题的编程(不知将AOP译作面向问题的编程是否欠妥)。通过对这些行为的分离,我们希望可以将它们独立地配置到商业方法中,而要改变这些行为也不需要影响到商业方法代码。
假设系统由一系列的BusinessObject所完成业务逻辑功能,系统要求在每一次业务逻辑处理时要做日志记录。这里我们略去具体的业务逻辑代码。
public interface BusinessInterface { public void processBusiness(); }
public class BusinessObject implements BusinessInterface { private Logger logger = Logger.getLogger(this.getClass().getName()); public void processBusiness(){ try { logger.info("start to processing..."); //business logic here. System.out.println(“here is business logic”); logger.info("end processing..."); } catch (Exception e){ logger.info("exception happends..."); //exception handling } } } 这里处理商业逻辑的代码和日志记录代码混合在一起,这给日后的维护带来一定的困难,并且也会造成大量的代码重复。完全相同的log代码将出现在系统的每一个BusinessObject中。
按照AOP的思想,我们应该把日志记录代码分离出来。要将这些代码分离就涉及到一个问题,我们必须知道商业逻辑代码何时被调用,这样我们好插入日志记录代码。一般来说要截获一个方法,我们可以采用回调方法或者动态代理。动态代理一般要更加灵活一些,目前多数的AOP Framework也大都采用了动态代理来实现。这里我们也采用动态代理作为例子。
JDK1.2以后提供了动态代理的支持,程序员通过实现java.lang.reflect.InvocationHandler接口提供一个执行处理器,然后通过java.lang.reflect.Proxy得到一个代理对象,通过这个代理对象来执行商业方法,在商业方法被调用的同时,执行处理器会被自动调用。
有了JDK的这种支持,我们所要做的仅仅是提供一个日志处理器。
public class LogHandler implements InvocationHandler {
private Logger logger = Logger.getLogger(this.getClass().getName()); private Object delegate; public LogHandler(Object delegate){ this.delegate = delegate; }
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { Object o = null; try { logger.info("method stats..." + method); o = method.invoke(delegate,args); logger.info("method ends..." + method); } catch (Exception e){ logger.info("Exception happends..."); //excetpion handling. } return o; } } 现在我们可以把BusinessObject里面的所有日志处理代码全部去掉了。
public class BusinessObject implements BusinessInterface {
private Logger logger = Logger.getLogger(this.getClass().getName()); public void processBusiness(){ //business processing System.out.println(“here is business logic”); } } 客户端调用商业方法的代码如下:
BusinessInterface businessImp = new BusinessObject();
InvocationHandler handler = new LogHandler(businessImp);
BusinessInterface proxy = (BusinessInterface) Proxy.newProxyInstance( businessImp.getClass().getClassLoader(), businessImp.getClass().getInterfaces(), handler);
proxy.processBusiness(); 程序输出如下:
INFO: method stats... here is business logic INFO: method ends... 至此我们的第一次小尝试算是完成了。可以看到,采用AOP之后,日志记录和业务逻辑代码完全分开了,以后要改变日志记录的话只需要修改日志记录处理器就行了,而业务对象本身(BusinessObject)无需做任何修改。并且这个日志记录不会造成重复代码了,所有的商业处理对象都可以重用这个日志处理器。
当然在实际应用中,这个例子就显得太粗糙了。由于JDK的动态代理并没有直接支持一次注册多个InvocationHandler,那么我们对业务处理方法既要日志记录又要性能统计时,就需要自己做一些变通了。一般我们可以自己定义一个Handler接口,然后维护一个队列存放所有Handler, 当InvocationHandler被触发的时候我们依次调用自己的Handler。所幸的是目前几乎所有的AOP Framework都对这方面提供了很好的支持.这里推荐大家使用Spring。
1 <script> 2 var start=0; 3 var n; 4 function init(){ 5 start++; 6 } 7 function process(i){ 8 n=setTimeout("init()",1000); 9 if(start>i){ 10 clearTimeout(n); 11 start=0; 12 //这里写你需要执行的代码 13 } 14 } 15 </script> 其中process(i) i为你要设置延迟的时间 秒为单位 关于timeout: 它其实就是一个循环而已,在循环里调用它的第一个参数,第2个参数是Thread.sleep的时间间隔,当然如果你不在合适的时候clearTimeout的话,它将成为一个死循环
|