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


 


 


 



 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值