有个需求
1.要把用户从数据库查询到的明细,可以支持一xls方式的导出。
2.用户可以讲xls格式的数据导入到数据库
一开始就想到了使用jxl,先热热身,看看jxl.jar的基本使用方法
package cn.com.xinli.util; import java.io.File; import java.io.FileOutputStream; import java.io.OutputStream; import java.sql.Connection; import java.sql.DriverManager; import java.sql.PreparedStatement; import java.text.SimpleDateFormat; import java.util.Date; import jxl.Sheet; import jxl.Workbook; import jxl.format.Alignment; import jxl.format.Border; import jxl.format.BorderLineStyle; import jxl.format.CellFormat; import jxl.write.Label; import jxl.write.WritableCellFormat; import jxl.write.WritableFont; import jxl.write.WritableSheet; import jxl.write.WritableWorkbook; public class TestJXL { public static void main(String[] args) throws Exception { TestJXL.saveToEXcle(); } public static void saveToEXcle() { // 准备设置excel工作表的标题 String[] title = {"编号","产品名称","产品价格","产品数量","生产日期","产地","是否出口"}; try { // 获得开始时间 long start = System.currentTimeMillis(); // 输出的excel的路径 String filePath = "c:\\test.xls"; // 创建Excel工作薄 WritableWorkbook wwb; // 新建立一个jxl文件,即在C盘下生成test.xls OutputStream os = new FileOutputStream(filePath); wwb=Workbook.createWorkbook(os); // 添加第一个工作表并设置第一个Sheet的名字 WritableSheet sheet = wwb.createSheet("产品清单", 0); Label label; for(int i=0;i<title.length;i++){ // Label(x,y,z)其中x代表单元格的第x+1列,第y+1行, 单元格的内容是y // 在Label对象的子对象中指明单元格的位置和内容 label = new Label(i,0,title[i]); // 将定义好的单元格添加到工作表中 sheet.addCell(label); } // 下面是填充数据 /* * 保存数字到单元格,需要使用jxl.write.Number * 必须使用其完整路径,否则会出现错误 * */ // 填充产品编号 jxl.write.Number number = new jxl.write.Number(0,1,20071001); sheet.addCell(number); // 填充产品名称 label = new Label(1,1,"金鸽瓜子"); sheet.addCell(label); /* * 定义对于显示金额的公共格式 * jxl会自动实现四舍五入 * 例如 2.456会被格式化为2.46,2.454会被格式化为2.45 * */ jxl.write.NumberFormat nf = new jxl.write.NumberFormat("0.00"); //#.## jxl.write.WritableCellFormat wcf = new jxl.write.WritableCellFormat(nf); // 填充产品价格 jxl.write.Number nb = new jxl.write.Number(2,1,0.1,wcf); sheet.addCell(nb); // 填充产品数量 jxl.write.Number numb = new jxl.write.Number(3,1,200); sheet.addCell(numb); /* * 定义显示日期的公共格式 * 如:yyyy-MM-dd hh:mm * */ SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd"); String newdate = sdf.format(new Date()); // 填充出产日期 label = new Label(4,1,newdate); sheet.addCell(label); // 填充产地 label = new Label(5,1,"陕西西安"); sheet.addCell(label); /* * 显示布尔值 * */ jxl.write.Boolean bool = new jxl.write.Boolean(6,1,true); sheet.addCell(bool); /* * 合并单元格 * 通过writablesheet.mergeCells(int x,int y,int m,int n);来实现的 * 表示将从第x+1列,y+1行到m+1列,n+1行合并 * * */ sheet.mergeCells(0,3,2,3); label = new Label(0,3,"合并了三个单元格"); sheet.addCell(label); /* * * 定义公共字体格式 * 通过获取一个字体的样式来作为模板 * 首先通过web.getSheet(0)获得第一个sheet * 然后取得第一个sheet的第二列,第一行也就是"产品名称"的字体 * */ CellFormat cf = wwb.getSheet(0).getCell(1, 0).getCellFormat(); WritableCellFormat wc = new WritableCellFormat(); // 设置居中 wc.setAlignment(Alignment.CENTRE); // 设置边框线 wc.setBorder(Border.ALL, BorderLineStyle.THIN); // 设置单元格的背景颜色 wc.setBackground(jxl.format.Colour.RED); label = new Label(1,5,"字体",wc); sheet.addCell(label); // 设置字体 jxl.write.WritableFont wfont = new jxl.write.WritableFont(WritableFont.createFont("隶书"),20); WritableCellFormat font = new WritableCellFormat(wfont); label = new Label(2,6,"隶书",font); sheet.addCell(label); /*设置列宽*/ sheet.setColumnView(0,12); sheet.setColumnView(1,10); sheet.setColumnView(2,8); sheet.setColumnView(3,20); sheet.setColumnView(4,8); sheet.setColumnView(5,15); sheet.setColumnView(6,12); sheet.setColumnView(7,15); // 写入数据 wwb.write(); // 关闭文件 wwb.close(); long end = System.currentTimeMillis(); System.out.println("----完成该操作共用的时间是:"+(end-start)/1000); } catch (Exception e) { System.out.println("---出现异常---"); e.printStackTrace(); } } }
下面完成需求1,导出
先决条件:
a.mysql环境+struts
b.建立测试使用的person表
CREATE TABLE `person` ( `id` int(11) NOT NULL AUTO_INCREMENT, `name` varchar(10) NOT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=34 DEFAULT CHARSET=gbk
分析:当用户点击了导出按钮,会弹出一个对话框,打开或者保存,这个是使用
response.setContentType("application/vnd.ms-excel;charset=GBK");//设置输出类型 response.addHeader("Content-Disposition","attachment;filename="+fileName);
然后使用输出流构造 WritableWorkbook 工作薄对象,吧从数据库查到的结果集,一行一行的写到xls中
需求2
要将xls中的数据读取出来,然后插到数据库中,关键是 拿到输入流,根据输入流构造WritableWorkbook 工作薄对象,然后使用
Sheet sheet = book.getSheet( 0 ); // 得到第一列第一行的单元格 int columnum = sheet.getColumns(); // 得到列数 int rownum = sheet.getRows(); // 得到行数
得到行数和列数,写个双循环,拿到单元格里面的内容,构造sql语句,然后将它们插入到数据库中,关于根据单元格的内容批量执行sql,这里有一个效率问题,网上看到一个blog,受益很大(MYSQL)
对于大数据量的插入,建议使用insert into tableName (x,xx,xxx) values(x,xx,xxx),(xx,xxx,xxxx)…,的方式
这样只执行一个sql 就将数据插入到数据库中了,使用循环 来insert,或者使用 pstmt.addBatch()的放似乎都没有这样效率高,效率在这样写sql效率比 循环 来insert,或者使用 pstmt.addBatch() 能提高10倍左右的时间,不过sql的长度是有限制的,我们可以自己设置每1000条记录提交一次来解决
下面贴一下Action中的关键代码
package cn.com.xinli.action.user; import java.io.DataInputStream; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.List; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import jxl.Sheet; import jxl.Workbook; import jxl.format.Alignment; import jxl.write.Label; import jxl.write.WritableCellFormat; import jxl.write.WritableSheet; import jxl.write.WritableWorkbook; import org.apache.log4j.Logger; import org.apache.struts.action.ActionForm; import org.apache.struts.action.ActionForward; import org.apache.struts.action.ActionMapping; import cn.com.xinli.action.BaseAction; import cn.com.xinli.bean.User; import cn.com.xinli.util.DBUtil; public class ExcleOperateAction extends BaseAction { Logger log=Logger.getLogger(ExcleOperateAction.class); @Override public ActionForward doIt(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception { String operType = request.getParameter("operType"); log.info("operType:"+operType); if (operType != null) { if (operType.equals("upload")) { return upload(mapping, form, request, response); } else if(operType.equals("download")) { return download(mapping, form, request, response); } } return null; } private ActionForward download(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception { log.info("开始执行导出文件操作"); String fileName = new String("记录明细".getBytes("GB2312"), "ISO_8859_1"); response.setContentType("application/vnd.ms-excel;charset=GBK");//设置输出类型 response.addHeader("Content-Disposition","attachment;filename="+fileName); try { // 创建Excel工作薄 WritableWorkbook wwb; wwb = Workbook.createWorkbook(response.getOutputStream()); WritableCellFormat wc = new WritableCellFormat(); /*居中*/ wc.setAlignment(Alignment.CENTRE); // 添加第一个工作表并设置第一个Sheet的名字 WritableSheet sheet = wwb.createSheet("网银明细", 0); String[] title = { "ID", "Name"}; Label label; for (int i = 0; i < title.length; i++) { // Label(x,y,z)其中x代表单元格的第x+1列,第y+1行, 单元格的内容是z // 在Label对象的子对象中指明单元格的位置和内容 label = new Label(i, 0, title[i],wc); // 将定义好的单元格添加到工作表中 sheet.addCell(label); } List<User> list=new ArrayList<User>(); Connection conn=null; ResultSet rs=null; PreparedStatement pstmt; conn=DBUtil.getConnection(); String sql="select * from person"; pstmt=conn.prepareStatement(sql.toString()); rs =pstmt.executeQuery(); while(rs.next()) { User user=new User(); user.setId(rs.getString("id")); user.setName(rs.getString("name")); list.add(user); } if(list.size()>0) { int cols=0; int rows=1; for(User user : list) { Label label1=new Label(cols++,rows,user.getId(),wc); Label label2=new Label(cols++,rows,user.getName(),wc); sheet.addCell(label1); sheet.addCell(label2); rows++; cols=0; } /*设置列宽*/ sheet.setColumnView(0,12); sheet.setColumnView(1,10); } wwb.write(); // 关闭文件 wwb.close(); } catch(Exception e) { e.printStackTrace(); } return null; } private ActionForward upload(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception { log.info("开始执行导入文件操作"); try { /*读取文件流*/ DataInputStream in = new DataInputStream(request.getInputStream()); /*过滤HTTPHeader,否则jxl会报无法识别文件结尾的错误*/ for(int i = 0; i < 4; i++) { in.readLine(); } Workbook book = Workbook.getWorkbook(in); Sheet sheet = book.getSheet( 0 ); // 得到第一列第一行的单元格 int columnum = sheet.getColumns(); // 得到列数 int rownum = sheet.getRows(); // 得到行数 System.out.println("列数:"+columnum); System.out.println("行数 :"+rownum); Connection conn=null; PreparedStatement pstmt; conn=DBUtil.getConnection(); StringBuffer sql = new StringBuffer("INSERT INTO person (id,name) values "); for ( int i =0; i < rownum; i ++) // 循环进行读写,这里从1开始是不读取第一行 { if(i!=0) { sql.append(","); } sql.append("("); for ( int j = 0 ; j < columnum; j ++ ) { String c=sheet.getCell(j, i).getContents(); // 得到第j列第i行的单元格的内容 System.out.println("("+j+","+i+"):"+c); sql.append("'"+c+"'"); if(j<columnum-1) { sql.append(","); } } sql.append(")"); } pstmt=conn.prepareStatement(sql.toString()); pstmt.execute(); request.setAttribute("message", "上传文件成功.."); return mapping.findForward("result"); } catch(Exception e) { request.setAttribute("message", "上传文件失败.."+e.getMessage()); return mapping.findForward("result"); } } }
关于附件:
1.下载附件直接可以导入到eclipse
2.mysql+person 表 可以直接 使这个web项目跑起来
参考资料:
http://www.blogjava.net/hankchen/archive/2009/09/01/293430.html
http://www.pcstu.com/databases/MSsql/jq/20080929/63477.html
http://fuhao9611.iteye.com/blog/72485