SSH学习笔记(三)

三、项目拓展

下面在前面的小项目中添加一个小功能,动态生成execl文件及下载,要用到apache的POI组件,这个包默认已经被spring加载

1、在UserService.java中添加方法

public InputStream getInputStream();

在它的实现类中实现

package com.test.service.impl; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.InputStream; import java.io.OutputStream; import java.util.List; import org.apache.poi.hssf.usermodel.HSSFCell; import org.apache.poi.hssf.usermodel.HSSFRow; import org.apache.poi.hssf.usermodel.HSSFSheet; import org.apache.poi.hssf.usermodel.HSSFWorkbook; import com.test.bean.User; import com.test.dao.UserDAO; import com.test.service.UserService; public class UserServiceImpl implements UserService { private UserDAO userDao; public void delete(User user) { // TODO Auto-generated method stub this.userDao.removeUser(user); } public List<User> findAll() { // TODO Auto-generated method stub return this.userDao.findAllUsers(); } public User findById(Integer id) { // TODO Auto-generated method stub return this.userDao.findUserById(id); } public void save(User user) { // TODO Auto-generated method stub this.userDao.saveUser(user); } public void update(User user) { // TODO Auto-generated method stub this.userDao.updateUser(user); } public UserDAO getUserDao() { return userDao; } public void setUserDao(UserDAO userDao) { this.userDao = userDao; } public InputStream getInputStream() { HSSFWorkbook wb = new HSSFWorkbook(); //生成ececl HSSFSheet sheet = wb.createSheet("sheet1"); //创建sheet1 HSSFRow row = sheet.createRow(0); //创建一行 HSSFCell cell = row.createCell((short) 0); //一个单元格 cell.setEncoding(HSSFCell.ENCODING_UTF_16); //设置字符集 cell.setCellValue("序号"); cell = row.createCell((short) 1); cell.setEncoding(HSSFCell.ENCODING_UTF_16); cell.setCellValue("姓"); cell = row.createCell((short) 2); cell.setEncoding(HSSFCell.ENCODING_UTF_16); cell.setCellValue("名"); cell = row.createCell((short) 3); cell.setEncoding(HSSFCell.ENCODING_UTF_16); cell.setCellValue("年龄"); List<User> list = this.findAll(); for (int i = 0; i < list.size(); ++i) { User user = list.get(i); row = sheet.createRow(i + 1); cell = row.createCell((short) 0); cell.setEncoding(HSSFCell.ENCODING_UTF_16); cell.setCellValue(i + 1); cell = row.createCell((short) 1); cell.setEncoding(HSSFCell.ENCODING_UTF_16); cell.setCellValue(user.getFirstname()); cell = row.createCell((short) 2); cell.setEncoding(HSSFCell.ENCODING_UTF_16); cell.setCellValue(user.getLastname()); cell = row.createCell((short) 3); cell.setEncoding(HSSFCell.ENCODING_UTF_16); cell.setCellValue(user.getAge()); } File file = new File("test.xls"); try { OutputStream os = new FileOutputStream(file); wb.write(os); os.close(); } catch (Exception e) { e.printStackTrace(); } InputStream is = null; try { is = new FileInputStream(file); } catch (FileNotFoundException e) { e.printStackTrace(); } return is; } }

生产的临时文件test.xls在apache的bin目录中

2、在com.test.user.action中新建GenerateExcelAction.java

package com.test.action.user; import java.io.InputStream; import com.opensymphony.xwork2.ActionSupport; import com.test.service.UserService; public class GenerateExcelAction extends ActionSupport { private UserService service; public UserService getService() { return service; } public void setService(UserService service) { this.service = service; } public InputStream getDownloadFile() { return this.service.getInputStream(); } @Override public String execute() throws Exception { return SUCCESS; } }

在structs.xml中添加action的声明

<action name="generateExcel" class="generateExcelAction"> <result name="success" type="stream"> <!-- 注意类型为stream --> <param name="contentType">application/vnd.ms-excel</param> <!-- 文件类型 --> <param name="contentDisposition">filename="AllUsers.xls"</param> <!-- 浏览器呈现的文件名 --> <param name="inputName">downloadFile</param> <!-- 文件下载的方法为getDownloadFile --> </result> </action>

在applicationContext.xml中添加action的声明

<bean id="generateExcelAction" class="com.test.action.user.GenerateExcelAction" scope="singleton"> <!-- 类没有状态,所以可以配置成singleton --> <property name="service" ref="userService"></property> </bean>

在list.jsp中添加链接

<s:a href="index.jsp">Homepage</s:a><br><br> <s:a href="generateExcel.action">生成excel</s:a>

好了这个功能已经完成了。


3、但是出现了一个问题:程序生成了一个中间文件,如果有一个连接在写这个文件,刚好又有另外一个连接在下载这个文件,这样就会产生冲突。解决方案有两个:1)、对于每一个连接都生成一个名字随机的中间文件,当连接结束及时删除这个中间文件。2)、直接把流输出到内存里,直接生成Inputstream传送客户端,这样就不会生成临时文件了,这种方法在第4点中介绍。

对于第一种方法,又有两种方式:自己写代码随机生成字符串或者借助第三方的库。自己写代码的话如下:

在项目中新建包com.test.util,在该包中新建CharacterUtils.java

package com.test.util; //一般项目中都有util的包,这个包起辅助作用,方法一般是static,这样直接调用就行 import java.util.Random; public class CharacterUtils { public static String getRandomString(int length) //生产长度为length的随机随机字符串,方法一 { String str = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; Random random = new Random(); StringBuffer sb = new StringBuffer(); for (int i = 0; i < length; ++i) { int number = random.nextInt(62); sb.append(str.charAt(number)); } return sb.toString(); } // public static String getRandomString2(int length) //生产长度为length的随机随机字符串,方法二 // { // Random random = new Random(); // StringBuffer sb = new StringBuffer(); // // for (int i = 0; i < length; ++i) // { // int number = random.nextInt(3); // long result = 0; // // switch (number) // { // case 0: // result = Math.round(Math.random() * 25 + 65); // sb.append(String.valueOf((char)result)); // break; // case 1: // result = Math.round(Math.random() * 25 + 97); // sb.append(String.valueOf((char)result)); // break; // case 2: // sb.append(String.valueOf(new Random().nextInt(10))); // break; // } // } // // return sb.toString(); // } // public static void main(String[] args) // { // System.out.println(getRandomString2(10)); // } }

将UserServiceImpl.java中test.xml生成的地方改为

String fileName = CharacterUtils.getRandomString(10); fileName = new StringBuffer(fileName).append(".xls").toString(); File file = new File(fileName);

要达到生成随机字符串的效果,也可用apache提供的包,实施如下:
将UserServiceImpl.java中test.xml生成的地方改为

String fileName = RandomStringUtils.randomAlphanumeric(10); //apache 提供的方法 fileName = new StringBuffer(fileName).append(".xls").toString(); File file = new File(fileName);

下面删除这个临时文件,我们采用的方法是在文件生成好之后20分钟线程删除这个文件,并且每次服务器启动的时候在init()方法里检查apache的bin目录下是否有临时文件,如果有的话就删除掉。
在UserServiceImpl.java中加入

new Thread(new Runnable() { public void run() { try { Thread.sleep(20000 * 60); //睡眠20分钟 } catch (InterruptedException e) { e.printStackTrace(); } file.delete();//删除临时文件 } }).start();

新建包com.test.servlet,在包中新建DeleteFileServlet.java,这个servlet用来在tomcat启动的时候删除apache的bin目录下的xls临时文件,所以用户不访问这个servlet,这个servlet只需要实现init()方法,而不需要doGet(),doPost(),也不需要servlet-mapping。

package com.test.servlet; import java.io.File; import java.io.FileFilter; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; public class DeleteFilesServlet extends HttpServlet { public void destroy() { } public void init() throws ServletException { // 方法一比较简单 // File file = new File("."); //获取当前目录文件 // // File[] subFiles = file.listFiles(); // // for(File f : subFiles) // { // if(f.getName().endsWith("xls")) // { // f.delete(); // } // } // 方法二,使用FileFilter File file = new File("."); File[] subFiles = file.listFiles(new FileFilter() { public boolean accept(File pathname) { if(pathname.getName().endsWith("xls")) { return true; } return false; } } ); for(File f : subFiles) { f.delete(); } } }

在web.xml中加入

<servlet> <servlet-name>DeleteFilesServlet</servlet-name> <servlet-class>com.test.servlet.DeleteFilesServlet</servlet-class> <load-on-startup>8</load-on-startup> </servlet>

 

4、好了现在来看第二种方式,不生成临时文件,直接使用流来输出。这样的话第3步全部不用做,直接在UserServiceImpl.java中

ByteArrayOutputStream os = new ByteArrayOutputStream(); //不生成临时文件 try { wb.write(os); } catch (IOException e) { e.printStackTrace(); } byte[] content = os.toByteArray(); InputStream is = new ByteArrayInputStream(content); return is;

 

到此为止,系统已经全部完成。

附录:

整个笔记参照了[浪曦原创]Struts2.Hibernate3.2.Spring2.0整合(风中叶),这是一个很好的视频教程,适合快速了解SSH

项目源码http://www.kuaipan.cn/file/id_3287587011724175.html


 


 


 



 

转载于:https://www.cnblogs.com/moiyer/archive/2011/08/24/2316165.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值