Java操作Excel文件之使用JXL 学习笔记
百科上对于JXL的说明:
通过java操作excel表格的工具类库
支持Excel 95-2000的所有版本
生成Excel 2000标准格式
支持字体、数字、日期操作
能够修饰单元格属性
支持图像和图表 应该说以上功能已经能够大致满足我们的需要。最关键的是这套API是纯Java的,并不依赖Windows系统,即使运行在Linux下,它同样能够正确的处理Excel文件。另外需要说明的是,这套API对图形和图表的支持很有限,而且仅仅识别PNG格式。 |
前几天学习了下,总结备忘下:贴个关于Excel操作类的代码:(需要加入jxl.jar包)
/** * * <pre> * MS Office Excel 文件操作对象 * 注:利用第三方包jxl.jar进行操作 * 注:暂不支持excel2007版本新格式xlsx后缀名 * 提供操作内容: * 1.创建Excel文件 * 2.读取Excel文件 * 3.导出(写入)Excel文件 * 4.判断是否为Excel文件 * </pre> * * @author 陈书挺 * @create 2010-6-12 * @version v1.0 * * <pre> * 修改时间 修改人 修改原因 * 2010-6-12 陈书挺 新建类 * 2010-6-13 陈书挺 修改createExcel(String)方法 | 增加createExcel(String, String...)方法 * </pre> * */ public class ExcelOperator { /* * Excel文件后缀名 */ private static final String EXCEL_POSTFIX = ".xls"; /** * 创建指定的文件路径的一个Excel文件<br> * 默认创建3个工作表分别为:Sheet1|Sheet2|Sheet3<br> * 注:只支持xls格式的文件 * @param filePath 文件路径 * @throws Exception */ public void createExcel(String filePath) throws Exception{ this.createExcel(filePath, "Sheet1" , "Sheet2" , "Sheet3"); } /** * 创建指定的文件路径的一个Excel文件,并指定工作表名<br> * 注:只支持xls格式的文件 * @param filePath 文件路径 * @param sheetNames 工作表名数组 * @throws Exception */ public void createExcel(String filePath , String...sheetNames) throws Exception{ if(!this.isExcel(filePath)){ throw new Exception("对不起,文件必须是Excel文件,必须是xls格式的文件"); } File file = new File(filePath); //工厂方法创建一个可写入的工作薄(WorkBook) WritableWorkbook workBook = Workbook.createWorkbook(file); //创建一个可写入的工作表(Sheet) 得到的对象为WritableSheet对象 //工作表名 工作表在工作簿中的位置 for (int i = 0; i < sheetNames.length; i++) { workBook.createSheet(sheetNames[i], i); } workBook.write(); workBook.close(); } /** * 读取指定文件路径的Excel文件,以集合方式返回<br> * 说明:读取所有工作表的内容 * @param filePath 文件路径 * @return List集合,List集合中的元素表示一个工作表 * List中存储String[][]数组,一个数组表示存储工作表的内容 * 返回文件中的所有内容 * @throws Exception */ public List<String [][]> readExcel(String filePath) throws Exception{ if(!this.isExcel(filePath)){ throw new Exception("对不起,文件必须是Excel文件,必须是xls格式的文件"); } List<String [][]> contents = new ArrayList<String[][]>(); File file = new File(filePath); //创建工作薄 Workbook workBook = Workbook.getWorkbook(file); //获取工作表 Sheet [] sheets = workBook.getSheets(); if(sheets!=null && sheets.length>0){ for (int i = 0; i < sheets.length; i++) { String[][] content = this.readExcel(filePath, i); contents.add(content); } } workBook.close(); return contents; } /** * 将指定内容写入指定的Excel文件,并指定相应的工作表名 * @param filePath 文件路径 * @param contents 数据内容 * @param sheetName 工作表名 * @throws Exception */ public void writeExcel(String filePath , String [][] contents ,String sheetName) throws Exception{ if(!this.isExcel(filePath)){ throw new Exception("对不起,文件必须是Excel文件,必须是xls格式的文件"); } File file = new File(filePath); //工厂方法创建一个可写入的工作薄(WorkBook) WritableWorkbook workBook = Workbook.createWorkbook(file); WritableSheet sheet = workBook.createSheet(sheetName, 0); for (int i = 0; i < contents.length; i++) { for (int j = 0; j < contents[i].length; j++) { sheet.addCell(new Label(j,i,contents[i][j])); } } workBook.write(); workBook.close(); } /** * 将指定内容写入指定的Excel文件,并指定相应的工作表名 * @param filePath 文件路径 * @param contents 数据内容 * @param sheetName 工作表名 * @throws Exception */ public void writeExcel(String filePath , Vector<Vector<String>> contents , String sheetName) throws Exception{ this.writeExcel(filePath, StringUtils.toStringArray(contents), sheetName); } /** * 读取指定文件路径、指定工作表索引的Excel文件 * * @param filePath Excel文件路径 * @param sheetIndex 工作表索引 从0开始 * @return 与Excel结构相似的二维数组,二维数组中存储的是表格中的内容 * @throws Exception */ public String [][] readExcel(String filePath , int sheetIndex) throws Exception{ if(!this.isExcel(filePath)){ throw new Exception("文件必须是Excel文件,必须是xls格式的文件"); } File file = new File(filePath); //创建工作薄 Workbook workBook = Workbook.getWorkbook(file); //获取工作表 Sheet [] sheets = workBook.getSheets(); if(sheetIndex>sheets.length-1){ throw new Exception("工作表索引["+sheetIndex+"]超出范围"); } //获取指定工作表 Sheet sheet = sheets[sheetIndex]; //获取当前工作薄的行数 int rows = sheet.getRows(); //获取当前工作薄的列数 int columns = sheet.getColumns(); //存储Excel中的数据 String [][] content = new String[rows][columns]; this.initArrays(content); for (int i = 0; i < rows; i++) { //得到当前行的所有单元格 Cell [] cells = sheet.getRow(i); if(cells!=null && cells.length>0){ for (int j= 0; j < cells.length; j++) { String cellContent = cells[j].getContents(); content[i][j]=cellContent; } } } workBook.close(); return content; } /** * 判断指定文件的路径是否是Excel文件 * @param filePath 文件的路径 * @return 是否是Excel文件 * true:是Excel文件 * false:不是Excel文件 */ public boolean isExcel(String filePath){ //获取文件后缀名 String postfix = FileUtils.getPostfix(filePath); if(!postfix.equals(ExcelOperator.EXCEL_POSTFIX)){ return false; } return true; } /* * 初始化二维数组内容为"" * @param arrays 要初始化二维数组 */ private void initArrays(String [][] arrays){ for (int i = 0; i < arrays.length; i++) { for (int j = 0; j < arrays[i].length; j++) { arrays[i][j]=""; } } } }
使用iText5.x创建PDF中文处理问题
今天无意中在网上看到iText这个东东,iText 是利用Java 来操作PDF 操作的一种开源API
简单说明下使用该API创建PDF文件的过程
PS:使用的是iText5.x版本
/** * 创建PDF文件 * @param filePath 文件路径 * @param content 需要写入的内容 * @throws DocumentException * @throws IOException */ public void createPdf(String filePath ,String content) throws DocumentException, IOException{ //1.创建Document对象 Document document = new Document(); FileOutputStream fos = new FileOutputStream(filePath); //2.创建一个PdfWriter实例 PdfWriter.getInstance(document, fos); //3.打开文档 document.open(); Paragraph graph = new Paragraph(content); //4.加入段落 document.add(graph); //5.关闭文档 document.close(); }
利用上述程序,运行结果。发现,只有英文部分被写入,中文部分无法被写入。百度得到结论:
需要加入itextasian.jar包,itextasian.jar包有实现了对中文字体的支持。因此加载itextasian.jar到classpath下。
在上述代码中加入如下代码:
BaseFont baseFontChinese = BaseFont.createFont("STSong-Light", "UniGB-UCS2-H", BaseFont.NOT_EMBEDDED); Font fontChinese = new Font(baseFontChinese , 12 , Font.NORMAL); Paragraph graph = new Paragraph(content , fontChinese);
运行,得到如下异常:
Font 'STSong-Light' with 'UniGB-UCS2-H' is not recognized
还是不行,继续研究,在网上前辈们说如下原因:
iText5.x版本以上中的font和encoding文件都是从String RESOURCE_PATH = "com/itextpdf/text/pdf/fonts/"加载的,而老itextasian.jar的包名是com.lowagie.text.pdf.fonts, 包名不一致导致路径错误,。 |
具体解决方法就是修改包的路径了,详细方法如下:
1.解压iTextAsian.jar 得到如下目录: iTextAsian --com --lowagie --text --fonts --...(字体属性文件) 2.将解压后的com目录下的包名lowagie更改为itextpdf 3.在命令行转至iTextAsian目录,重新打包为iTextAsian.jar文件 4.打包命令如下: jar cvf iTextAsian.jar com/itextpdf/text/pdf/fonts/* 5.执行后,将新的iTextAsian.jar加入classpath路径 |
运行结果,OK,解决问题。
最终代码如下:
/** * 创建PDF文件 * @param filePath 文件路径 * @param content 需要写入的内容 * @throws DocumentException * @throws IOException */ public void createPdf(String filePath ,String content) throws DocumentException, IOException{ //1.创建Document对象 Document document = new Document(); FileOutputStream fos = new FileOutputStream(filePath); //2.创建一个PdfWriter实例 PdfWriter.getInstance(document, fos); //3.打开文档 document.open(); BaseFont baseFontChinese = BaseFont.createFont("STSong-Light", "UniGB-UCS2-H", BaseFont.NOT_EMBEDDED); Font fontChinese = new Font(baseFontChinese , 12 , Font.NORMAL); Paragraph graph = new Paragraph(content , fontChinese); document.add(graph); document.close(); }
继续研究ing~~
Spring中抽象类不能注入属性
昨天做项目的时候,因为注入用的很爽,自然而然的在什么类下都用注入,结果出问题,注入的属性都是为null,查了一下,会不会是抽象类的问题呢,百度之,得下面的答案:
抽象类不能生成实例对象,spring无法注入 。 因为spring的原理是启动服务器时读取配置文件,取得类名后利用反射机制在spring上下文中生成一个单例的对象,由spring注入属性并维护此对象的状态,抽象类在反射生成对象时就已经失败了,后面的不会进行。 |
初学Hibernate一对多关联
今天,花了些时间去了解了Hibernate的一对多关联,做的例子是
描述一个用户拥有多个角色。实现一个添加用户,从而在数据库中添加用户和角色记录
角色记录由Hibernate完成。
贴个代码:(只贴出主要部分)
1.SQL脚本
--用户表 create table users ( userID number primary key, --用户ID name varchar(20) -- not null--真实姓名 ); --角色表 create table roles ( roleID number primary key, --角色ID roleName varchar2(20), --角色名称 userID number ); alter table roles add constraint fk_role_re_user foreign key(userID) references users(userID);
1.POJO-用户对象
/** * 用户对象 * @author ChenST */ public class Users implements java.io.Serializable { //用户ID private Long userid; //姓名 private String name; //角色列表 private Set roleses = new HashSet(0); // Constructors /** default constructor */ public Users() { } ////setter和getter方法略 }
2.POJO-角色对象
/** * 角色对象 * @author ChenST */ public class Roles implements java.io.Serializable { //角色ID private Long roleid; //所属于用户 private Users users; //角色名 private String rolename; //所属于用户ID private Long userid; // Constructors /** default constructor */ public Roles() { } ///setter和getter方法略 }
3.HBM-用户映射文件
<hibernate-mapping> <class name="com.shine.pojo.Users" table="USERS" schema="CST"> <id name="userid" type="java.lang.Long"> <column name="USERID" precision="22" scale="0" /> <!-- 如果非自动增长列,可以设置成assigned 不能设置成sequence --> <generator class="assigned"/> </id> <property name="name" type="java.lang.String"> <column name="NAME" length="20" /> </property> <!-- 此处的cascade要设置成save-update, 否则无法级联更新(插入) cascade的值 sava-update:级联保存、更新 delete:级联删除 none:不级联,默认值 all:级联保存、更新、删除 inverse属性表示是否把对Set的改动反应到数据库中去 inverse=true不反应 inverse=false反应(默认) =false表示会去维护中间表 =true表示不会去维护中间表 --> <set name="roleses" inverse="false" cascade="save-update"> <key> <column name="ROLEID" precision="22" scale="0" not-null="true" unique="true" /> </key> <one-to-many class="com.shine.pojo.Roles" /> </set> </class> </hibernate-mapping>
4.HBM-角色映射文件
<hibernate-mapping> <class name="com.shine.pojo.Roles" table="ROLES" schema="CST"> <id name="roleid" type="java.lang.Long"> <column name="ROLEID" precision="22" scale="0" /> <!-- 如果非自动增长列,可以设置成assigned 不能设置成sequence --> <generator class="assigned" /> </id> <many-to-one name="users" class="com.shine.pojo.Users" update="false" insert="false" fetch="select"> <column name="ROLEID" precision="22" scale="0" not-null="true" unique="true" /> </many-to-one> <property name="rolename" type="java.lang.String"> <column name="ROLENAME" length="20" /> </property> <property name="userid" type="java.lang.Long"> <column name="USERID" precision="22" scale="0" /> </property> </class> </hibernate-mapping>
5.DAO-用户DAO实现类
/** * 用户Dao的实现类 * @author ChenST * */ public class UserDaoImpl implements IUserDao { /** * 保存对象 */ public void save(Users user) { //Session对象负责执行被持久化对象的CURD操作 Session session=null; //Transaction对象负责事务上的 Transaction trans=null; try{ //获取session对象 session=HibernateSessionFactory.getSession(); //获取事务 trans=session.beginTransaction(); session.saveOrUpdate(user); trans.commit(); }catch (Exception e) { e.printStackTrace(); trans.rollback(); }finally{ //关闭Session HibernateSessionFactory.closeSession(); } } }
6.JUNIT-用户Dao测试
/** * 测试UserDao * @author ChenST */ public class UserDaoTest extends TestCase { /** * 测试保存方法 */ public void testSave(){ IUserDao userDao=new UserDaoImpl(); Users user=new Users(3L,"cst",new HashSet()); Roles role1=new Roles(3L,user,"a",3L); user.getRoleses().add(role1); userDao.save(user); } }
完毕。。。
Ant学习笔记
看Hibernate的时候发现Ant这个东东,花了3个小时查了些资料,并总结如下:
Ant是用来编译/运行/测试java程序
Ant可用于项目管理。
Ant还提供了打包,生成API文档等多功能。
总之,Ant可提高程序员的开发效率。
使用MyEcipse创建build.xml文件(如果自己写比较麻烦的话,可以用工具帮你生成,不过感觉有挺多垃圾信息)
具体方法如下:
【项目右键】>>【Export】>>【General】>>【 Ant Buildfiles】>>【 next】>>【 finish】即可
贴个下午写的一个 build.xml 文件:
<?xml version="1.0" encoding="UTF-8"?> <!-- <project>构建文件对应的一个项目 属性介绍: basedir表示项目的基准目录 basedir="."表示基准目录为src目录 default表示默认的运行目标(必须) name表示项目名 --> <project basedir="." default="build" name="Ant"> <property environment="env"/> <!-- <property>定义属性以及于其对应的值 通常:src存放java源代码文件 classes存放java编译后的文件 lib存放要用到的第三方jar包 dist存放打包后的jar包 doc存放API文档 --> <property name="src.dir" value="src/com/shine/ant"/> <property name="classes.dir" value="bin/com/shine/ant"/> <property name="lib.dir" value="lib"/> <property name="dist.dir" value="dist"/> <property name="doc.dir" value="doc"/> <!-- <path>定义类路径,其中值指向classes.dir --> <path id="Ant.classpath"> <pathelement location="${classes.dir}"/> </path> <!-- 初始化操作 --> <target name="init"> <!-- <delete>标签表示删除一个或一组文件 属性介绍: dir表示要删除的目录 --> <delete dir="${classes.dir}" /> <!-- <mkdir>标签表示创建目录 属性介绍: dir表示要创建的目录 --> <mkdir dir="${classes.dir}"/> <!-- <copy>标签用于文件或文件集的拷贝 属性介绍: includeemptydirs表示制定是否拷贝空目录 默认值为拷贝,此处不拷贝 todir表示目标目录 --> <copy includeemptydirs="false" todir="${classes.dir}"> <!-- <fileset>表示了一组文件信息 属性介绍: dir表示基目录 excludes表示需要派出的文件模式的文件列表 --> <fileset dir="${src.dir}" excludes="**/*.launch,**/*.java"/> </copy> </target> <!-- 清除操作 --> <target name="clean"> <delete dir="${classes.dir}"/> </target> <!-- <target>标签表示你要做的操作 属性name表示目标的名字,起到识别作用 depends表示依赖,就是要先执行clean才可以执行 --> <!-- 清除所有 --> <target depends="clean" name="cleanall"/> <target depends="build-project" name="build"/> <!-- 建立工程 --> <target depends="init" name="build-project"> <!-- <javac>标签用于编译一个或一组java文件 属性介绍: debug表示包含的调试信息 srcdir表示源文件 destdir表示class文件的输出目录 --> <javac debug="true" srcdir="${src.dir}" destdir="bin" > </javac> </target> <!-- 打包成jar包 --> <target name="pack"> <mkdir dir="${dist.dir}"/> <!-- <jar>文件用来生成一个jar文件 属性介绍: destfile表示生成的jar文件名 basedir表示被打包的文件名 --> <jar destfile="${dist.dir}/ant.jar" basedir="${classes.dir}"> <!-- <exclude>表示被排除的文件 --> <exclude name="**/*.java"/> </jar> </target> <!-- 生成API文档 --> <target name="doc"> <delete dir="${doc.dir}"/> <mkdir dir="${doc.dir}"/> <!-- <javadoc>标签用于生成javadoc-API文档 属性介绍: destdir表示要输出的目录 --> <javadoc destdir="${doc.dir}"> <!-- 指定要被包含的文件 为src/com/shine/ant下的所有类 --> <packageset dir="src" defaultexcludes="yes"> <include name="com/shine/ant/**"/> </packageset> </javadoc> </target> </project>
完毕~~~
Spring2.5常用注解
公司代码很多Spring注解,下午花了点时间学习了下。贴个小案例来使用这些注解:
学习的注解列表
@Component |
@Service |
@Repository |
@Controller |
@Autowired |
@Qualifier |
@Resource |
@PostConstruct |
@PreDestroy |
1.水果接口
/** * 水果接口 * * @author ChenST * */ public interface Fruit { /** * 获取水果的名字 * @return */ public String getName(); }
2.苹果类
/** * 苹果 * @author ChenST * */ @Service public class Apple implements Fruit { /* * (non-Javadoc) * @see com.spring.annotation.Fruit#getName() */ public String getName() { return "苹果"; } }
3.梨类
/** * 梨 * @author ChenST * */ @Service public class Pear implements Fruit { public String getName() { return "梨"; } }
4.人类
/** * 人,拥有水果 * @author ChenST * */ /* * @Service表示定义个Bean对象默认Bean的名字为 * 类的第一个字母小写名字,例如Human为human * @Service("name")也可以自己指定名字name * ----------以下四种注解是等效的,只是意义不同 * @Component 比较中立的类进行注释 * @Service 表示服务层 * @Repository表示持久层 * @Controller表示控制层 */ @Service public class Human { /** 表示拥有水果 */ /*@Autowired(required = false)表示不确定 *Spring容器中拥有某个类的Bean时候,这样Spring *找不到这个Bean时也不报错 * *@Autowired注解表示自动注入对象。在配置文件中需要配置 *<context:annotation-config /> *<context:component-scan base-package="*"/> * *@Qualifier("apple")表示当这个fruit有两个实现类时 *指定其中一个。负责会报错 * *@Resource注释与Autowired差不多,Resource可以通过 *name和type来指明要注入的类 */ //@Autowired //@Qualifier("apple") //@Resource(name="apple") @Resource(type=Apple.class) private Fruit fruit; public void setFruit(Fruit fruit) { this.fruit = fruit; } /** * 吃水果 */ public void eat(){ System.out.println("我在吃"+this.fruit.getName()); } /* * @PostConstruct表示Spring容器初始化后调用 */ @PostConstruct public void eatBegin(){ System.out.println("我要开始吃了"); } /* * @PreDestroy表示Spring容器销毁之前调用 */ @PreDestroy public void eatFinish(){ System.out.println("吃完了"); } }
5.测试类
/** * 测试类 * * @author ChenST * */ public class Test { public static void main(String[] args) { ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml"); Human human=(Human) ctx.getBean("human"); human.eat(); } }
5.applicationContext.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-2.5.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd"> <!-- 自动注解配置 --> <context:annotation-config /> <context:component-scan base-package="*" /> </beans>
6.运行结果
我要开始吃了 我在吃苹果 吃完了
Spring中进行测试-Junit框架的扩展
利用Spring来进行测试。首先看看下面几个类。【参照网上的资料】
1.AbstractSpringContextTests 类是针对所有测试情景的类,一般不使用,而是使用他们的之类。
2.AbstractDependencyInjectionSpringContextTests 类继承了AbstractSpringContextTests类是一个针对所有测试的超类,具体依赖于Spring上下文。可支持依赖注入。
3.AbstractTransactionalSpringContextTests 类继承了AbstractDependencyInjectionSpringContextTests类,继承该类的测试用例在spring管理的事务中进行,测试完后对数据库的记录不会造成任何影响。你对数据库进行一些操作后,它会自动把数据库回滚,这样就保证了你的测试对于环境没有任何影响。
测试用例需实现protected abstract String[] getConfigLocations()方法来获取上下文。
1.创建一个测试类的基类
/** * Spring测试的基类 * * @author ChenST * */ public abstract class BaseSpringTest extends AbstractDependencyInjectionSpringContextTests { /** * 获取上下文spring context,该路径是在classpath下的路径 */ public String[] getConfigLocations() { String[] configLocations = { "applicationContext.xml" }; return configLocations; } }
2.测试用例
/** * 测试用例,测试Dao的方法getUserInfo(String userCode) * * @author ChenST * */ public class UsersDaoTest extends BaseSpringTest { /** 用户Dao,注入实现 */ private UsersDAO userDao; public void setUserDao(UsersDAO userDao) { this.userDao = userDao; } /** * 测试getUserInfo()方法,需要以test开头 */ public void testGetUserInfo(){ Users user=userDao.getUserInfo("004"); System.out.println(user.getDepartment().getDepName()); } }
可通过MyEclipse中的Outline透视图中进行单个方法的测试或者整个类的测试。
Bean属性拷贝出现java.lang.ExceptionInInitializerError可能原因
前些天,进行使用PropertyUtils工具进行Bean的属性拷贝,总出现:java.lang.ExceptionInInitializerError错误,明明字段啥的都一样啊。。许久才发现。原来我包引错了~~闷~
我引用的是 com.sun.org.apache.commons.beanutils.PropertyUtils 类。
正确的是引用 org.apache.commons.beanutils.PropertyUtils 类
备注并引以为戒。
Cannot find ActionMappings or ActionFormBeans collection错误
今天,将一个工程改成EJB时候,使用Struts的Action访问,出现Cannot find ActionMappings or ActionFormBeans collection错误。
百度之~~得:可能少了Struts的包,于是将Struts的包再重新导入一次,解决问题。
网上说,这类问题可能还可能有如下问题所导致:备忘下~~
①Web.xml未初始化问题 |
Strust异常:JasperException①NestedWriteNestingTei
昨日,基于公司的框架,并使用了Struts进行了开发和配置信息,结果访问时出现如下异常:
Failed to load or instantiate TagExtraInfo class: org.apache.struts.taglib.nested.NestedWriteNestingTei
网上说是因为包冲突问题,于是乎得到解决方案如下:
只要删除掉部署后的 /WEB-INF/lib 下的 jsp-api.jar 和 servlet-api.jar 包即可~~