天天看點

bboss mvc檔案上傳下載下傳實戰進階

在上一篇文章《bboss mvc檔案上傳下載下傳實戰演練》 http://yin-bp.iteye.com/blog/1130035

中介紹了采用bboss mvc、aop/ioc、persistent組合完成檔案上傳、存儲到資料庫、從資料庫中下載下傳檔案的基本功能,我們看到了如何通過MultipartHttpServletRequest擷取上傳檔案,如何通過SQLExecutor/ConfigSQLExecutor中操作blob字段的api存儲和讀取檔案的基本功能:

FieldRowHandler(擷取blob為檔案的字段行處理器)

NullRowHandler

   本文作為上篇的進階補充,介紹直接綁定MultipartFile對象或者MultipartFile數組到控制其方法參數或者po對象屬性的案例。

   對應的eclipse工程和運作demo可在本文的附件中下載下傳:

http://dl.iteye.com/topics/download/c7393bc6-b8ee-3dd5-b4b3-e969ea63dbc0

   demo工程中包含了derby資料庫檔案目錄database,部署到tomcat中運作之前需要修改/src/poolman.xml檔案中dburl路徑為相應實體路徑的下的database/cimdb,編譯後即可。

  啟動tomcat, 通路的位址還是:

http://localhost:8080/bbossupload/upload/main.page

   第一部分 本文的技術要點:

1. 控制器方法參數綁定機制增加MultipartFile、MultipartFile[]類型綁定支援,可以和RequestParam注解一起使用,也可以直接使用(預設擷取第一個input[file]域對應的附件),使用方法如下:

public String uploadFileWithMultipartFile(@RequestParam(name="upload1")  MultipartFile file,

ModelMap model)

public String uploadFileWithMultipartFiles(@RequestParam(name="upload1")  MultipartFile[] files,

public String uploadFileWithMultipartFile( MultipartFile file,

public String uploadFileWithMultipartFiles(MultipartFile[] files,

2. PO對象屬性資料綁定機制增加MultipartFile、MultipartFile[]類型綁定支援,可以和RequestParam注解一起使用,也可以直接與屬性名稱直接綁定,使用方法如下:

public String uploadFileWithFileBean(FileBean files)

FileBean是一個自定義的java bean,結構如下:

public class FileBean
{
	private MultipartFile upload1;
	@RequestParam(name="upload1")
	private MultipartFile[] uploads;
	@RequestParam(name="upload1")
	private MultipartFile anupload;
	//省略屬性的get/set方法
}	      

3. 改進的SQLParams api,可以直接對MultipartFile對象存入clob或者blob列。

sqlparams.addSQLParam("FILECONTENT", multipartfile,SQLParams.BLOBFILE);

對于大字段的處理建議采用以下方法:

sqlparams.addSQLParam("FILECONTENT", multipartfile,SQLParams.BLOBFILE);//直接傳遞MultipartFile對象進行插入

sqlparams.addSQLParam("FILECONTENT", inputStream, size,SQLParams.BLOBFILE);//直接傳遞InputStream對象以及流大小Size屬性進行插入

一個完整的插入大字段的執行個體:

String sql = "";
		try {
			sql = "INSERT INTO filetable (FILENAME,FILECONTENT,fileid,FILESIZE) VALUES(#[filename],#[FILECONTENT],#[FILEID],#[FILESIZE])";
			SQLParams sqlparams = new SQLParams();
			sqlparams.addSQLParam("filename", filename, SQLParams.STRING);
			sqlparams.addSQLParam("FILECONTENT", inputStream, size,SQLParams.BLOBFILE);
			sqlparams.addSQLParam("FILEID", UUID.randomUUID().toString(),SQLParams.STRING);
			sqlparams.addSQLParam("FILESIZE", size,SQLParams.LONG);
			SQLExecutor.insertBean(sql, sqlparams);			
			
		} catch (Exception ex) {
			ex.printStackTrace();
			result = false;
			throw new Exception("上傳附件關聯臨控指令布控資訊附件失敗:" + ex);
		} finally {
			if(inputStream != null){
				inputStream.close();
			}
		}      

或者

public void uploadClobFile(MultipartFile file) throws Exception
	{

		
		String sql = "";
		try {
			sql = "INSERT INTO CLOBFILE (FILENAME,FILECONTENT,fileid,FILESIZE) VALUES(#[filename],#[FILECONTENT],#[FILEID],#[FILESIZE])";
			SQLParams sqlparams = new SQLParams();
			sqlparams.addSQLParam("filename", file.getOriginalFilename(), SQLParams.STRING);
			sqlparams.addSQLParam("FILECONTENT", file,SQLParams.CLOBFILE);
			sqlparams.addSQLParam("FILEID", UUID.randomUUID().toString(),SQLParams.STRING);
			sqlparams.addSQLParam("FILESIZE", file.getSize(),SQLParams.LONG);
			SQLExecutor.insertBean(sql, sqlparams);			
			
		} catch (Exception ex) {
		
			
			throw new Exception("上傳附件關聯臨控指令布控資訊附件失敗:" + ex);
		} 
		
		
	}      

4. FieldRowHandler處理器,實作從blob/clob中擷取單個字段檔案對象的處理,其他類似類型資料也可以使用FieldRowHandler,使用示例如下:

public File getDownloadClobFile(String fileid) throws Exception
	{
		try
		{
			return SQLExecutor.queryTField(
											File.class,
											new FieldRowHandler<File>() {

												@Override
												public File handleField(
														Record record)
														throws Exception
												{

													// 定義檔案對象
													File f = new File("d:/",record.getString("filename"));
													// 如果檔案已經存在則直接傳回f
													if (f.exists())
														return f;
													// 将blob中的檔案内容存儲到檔案中
													record.getFile("filecontent",f);
													return f;
												}
											},
											"select * from CLOBFILE where fileid=?",
											fileid);
		}
		catch (Exception e)
		{
			throw e;
		}
	}      

第二部分 相關的實作細節

由于上篇文章已經詳細介紹了上傳下載下傳的代碼詳細情況,本文中隻介紹MultipartFile控制器方法綁定和存儲到資料庫中部分實作以及下載下傳方法執行個體,完整的代碼請下載下傳附件中的eclipse工程直接運作demo就可以了。

1.控制器方法

public class UploadController
{

	...............

	/**
         * 直接使用MultipartHttpServletRequest 擷取附件資訊的方法
	 * @param request
	 * @param model
	 * @param idNum
	 * @param type
	 * @param des
	 * @param byid
	 * @return
	 */
	public String uploadFile(MultipartHttpServletRequest request,
			ModelMap model)
	{

		Iterator<String> fileNames = request.getFileNames();
		// 根據伺服器的檔案儲存位址和原檔案名建立目錄檔案全路徑
		
		try
		{
			while (fileNames.hasNext())
			{
				String name = fileNames.next();
				MultipartFile[] files = request.getFiles(name);				 
//				file.transferTo(dest)
				for(MultipartFile file:files)
				{
					String filename = file.getOriginalFilename();
					if (filename != null && filename.trim().length() > 0)
					{
						uploadService.uploadFile(file.getInputStream(), file
								.getSize(), filename);

					}
				}
			}
			
		}
		catch (Exception ex)
		{
			ex.printStackTrace();
		}
		return "path:ok";
	}
	
	
	/**
         * RequestParam注解和MultipartFile結合綁定參數方法,将參數upload1對應的附件直接以MultipartFile對象傳入控制方法,簡單又便捷,附件将被存儲到derby資料庫的blob字段中。
	 * @param request
	 * @param model
	 * @param idNum
	 * @param type
	 * @param des
	 * @param byid
	 * @return
	 */
	public String uploadFileWithMultipartFile(@RequestParam(name="upload1")  MultipartFile file,
			ModelMap model)
	{

		
		// 根據伺服器的檔案儲存位址和原檔案名建立目錄檔案全路徑
		
		try
		{
			String filename = file.getOriginalFilename();
			if (filename != null && filename.trim().length() > 0)
			{
				uploadService.uploadFile(file.getInputStream(), file
						.getSize(), filename);

			}			
			
		}
		catch (Exception ex)
		{
			ex.printStackTrace();
		}
		return "path:ok";
	}
	
	/**
         * RequestParam注解和MultipartFile結合綁定參數方法,将參數upload1對應的附件直接以MultipartFile對象傳入控制方法,簡單又便捷,附件将被存儲到derby資料庫的clob字段中。
	 * @param request
	 * @param model
	 * @param idNum
	 * @param type
	 * @param des
	 * @param byid
	 * @return
	 */
	public String uploadFileClobWithMultipartFile(@RequestParam(name="upload1")  MultipartFile file,
			ModelMap model)
	{

		
		// 根據伺服器的檔案儲存位址和原檔案名建立目錄檔案全路徑
		
		try
		{
		
			uploadService.uploadClobFile(file);
		}
		catch (Exception ex)
		{
			ex.printStackTrace();
		}
		return "path:ok";
	}
	
	/**
         * RequestParam注解和MultipartFile[]結合綁定參數方法,将參數upload1(頁面上有多個upload1 file input元素)對應的附件直接以MultipartFile[]對象傳入控制方法,簡單又便捷,附件将被存儲到derby資料庫的blob字段中。
	 * @param request
	 * @param model
	 * @param idNum
	 * @param type
	 * @param des
	 * @param byid
	 * @return
	 */
	public String uploadFileWithMultipartFiles(@RequestParam(name="upload1")  MultipartFile[] files,
			ModelMap model)
	{

		
		// 根據伺服器的檔案儲存位址和原檔案名建立目錄檔案全路徑
		
		try
		{
			
			{
				 
//				file.transferTo(dest)
				for(MultipartFile file:files)
				{
					String filename = file.getOriginalFilename();
					if (filename != null && filename.trim().length() > 0)
					{
						uploadService.uploadFile(file.getInputStream(), file
								.getSize(), filename);

					}
				}
			}
			
		}
		catch (Exception ex)
		{
			ex.printStackTrace();
		}
		return "path:ok";
	}
	
	/**
         * 本方法示範了po對象中綁定MultipartFile屬性的功能。FileBean的結構如下:
         private MultipartFile upload1;
	@RequestParam(name="upload1")
	private MultipartFile[] uploads;
	@RequestParam(name="upload1")
	private MultipartFile anupload;
        上面的結構展示了不同屬性綁定方式。
	 * @param request
	 * @param model
	 * @param idNum
	 * @param type
	 * @param des
	 * @param byid
	 * @return
	 */
	public String uploadFileWithFileBean(FileBean files,
			ModelMap model)
	{

		
		
		
		try
		{
			
			//進行相應的處理
			
		}
		catch (Exception ex)
		{
			ex.printStackTrace();
		}
		return "path:ok";
	}

	

	/**
	 * 查詢資料庫的操作也隻好放在控制器中處理
	 * @param fileid
	 * @param request
	 * @param response
	 * @throws Exception
	 */
	public void downloadFileFromBlob(
			@RequestParam(name = "fileid") String fileid,
			 HttpServletRequest request, HttpServletResponse response)
			throws Exception
	{

		uploadService.downloadFileFromBlob(fileid, request, response);

	}
	
	/**
	 * 直接将blob對應的檔案内容以相應的檔案名響應到用戶端,需要提供request和response對象
	 * 這個方法比較特殊,因為derby資料庫的blob字段必須在statement有效範圍内才能使用,是以采用了空行處理器,來進行處理
	 * 查詢資料庫的操作也隻好放在控制器中處理
	 * @param fileid
	 * @param request
	 * @param response
	 * @throws Exception
	 */
	public void downloadFileFromClob(
			@RequestParam(name = "fileid") String fileid,
			 HttpServletRequest request, HttpServletResponse response)
			throws Exception
	{

		uploadService.downloadFileFromClob(fileid, request, response);

	}

	/**
	 * 将資料庫中存儲的檔案内容轉儲到應用伺服器檔案目錄中,然後将轉儲的檔案下載下傳,無需提供response和request對象
	 * 
	 * @param fileid
	 * @return
	 * @throws Exception
	 */
	public @ResponseBody File downloadFileFromFile(@RequestParam(name = "fileid") String fileid)
			throws Exception
	{

		return uploadService.getDownloadFile(fileid);
	}
	public @ResponseBody File downloadFileFromClobFile(@RequestParam(name = "fileid") String fileid)
	throws Exception
	{
	
		return uploadService.getDownloadClobFile(fileid);
	}
	

	......
      

2.持久層dao實作部分:

public class UpLoadDaoImpl implements UpLoadDao {
	
	@Override
	/**
	 * CREATE
    TABLE CLOBFILE
    (
        FILEID VARCHAR(100),
        FILENAME VARCHAR(100),
        FILESIZE BIGINT,
        FILECONTENT CLOB(2147483647)
    )
	 */
	public void uploadClobFile(MultipartFile file) throws Exception
	{

		
		String sql = "";
		try {
			sql = "INSERT INTO CLOBFILE (FILENAME,FILECONTENT,fileid,FILESIZE) VALUES(#[filename],#[FILECONTENT],#[FILEID],#[FILESIZE])";
			SQLParams sqlparams = new SQLParams();
			sqlparams.addSQLParam("filename", file.getOriginalFilename(), SQLParams.STRING);
			sqlparams.addSQLParam("FILECONTENT", file,SQLParams.CLOBFILE);
			sqlparams.addSQLParam("FILEID", UUID.randomUUID().toString(),SQLParams.STRING);
			sqlparams.addSQLParam("FILESIZE", file.getSize(),SQLParams.LONG);
			SQLExecutor.insertBean(sql, sqlparams);			
			
		} catch (Exception ex) {
		
			
			throw new Exception("上傳附件關聯臨控指令布控資訊附件失敗:" + ex);
		} 
		
		
	}
	
	/**
	 * 上傳附件
	 * @param inputStream
	 * @param filename
	 * @return
	 * @throws Exception
	 */
	public boolean uploadFile(InputStream inputStream,long size, String filename) throws Exception {
		boolean result = true;
		String sql = "";
		try {
			sql = "INSERT INTO filetable (FILENAME,FILECONTENT,fileid,FILESIZE) VALUES(#[filename],#[FILECONTENT],#[FILEID],#[FILESIZE])";
			SQLParams sqlparams = new SQLParams();
			sqlparams.addSQLParam("filename", filename, SQLParams.STRING);
			sqlparams.addSQLParam("FILECONTENT", inputStream, size,SQLParams.BLOBFILE);
			sqlparams.addSQLParam("FILEID", UUID.randomUUID().toString(),SQLParams.STRING);
			sqlparams.addSQLParam("FILESIZE", size,SQLParams.LONG);
			SQLExecutor.insertBean(sql, sqlparams);			
			
		} catch (Exception ex) {
			ex.printStackTrace();
			result = false;
			throw new Exception("上傳附件關聯臨控指令布控資訊附件失敗:" + ex);
		} finally {
			if(inputStream != null){
				inputStream.close();
			}
		}
		return result;
	}
	
	public File getDownloadFile(String fileid) throws Exception
	{
		try
		{
			return SQLExecutor.queryTField(
											File.class,
											new FieldRowHandler<File>() {

												@Override
												public File handleField(
														Record record)
														throws Exception
												{

													// 定義檔案對象
													File f = new File("d:/",record.getString("filename"));
													// 如果檔案已經存在則直接傳回f
													if (f.exists())
														return f;
													// 将blob中的檔案内容存儲到檔案中
													record.getFile("filecontent",f);
													return f;
												}
											},
											"select * from filetable where fileid=?",
											fileid);
		}
		catch (Exception e)
		{
			throw e;
		}
	}
	
	public File getDownloadClobFile(String fileid) throws Exception
	{
		try
		{
			return SQLExecutor.queryTField(
											File.class,
											new FieldRowHandler<File>() {

												@Override
												public File handleField(
														Record record)
														throws Exception
												{

													// 定義檔案對象
													File f = new File("d:/",record.getString("filename"));
													// 如果檔案已經存在則直接傳回f
													if (f.exists())
														return f;
													// 将blob中的檔案内容存儲到檔案中
													record.getFile("filecontent",f);
													return f;
												}
											},
											"select * from CLOBFILE where fileid=?",
											fileid);
		}
		catch (Exception e)
		{
			throw e;
		}
	}

	@Override
	public void deletefiles() throws Exception
	{

		SQLExecutor.delete("delete from filetable ");	
		SQLExecutor.delete("delete from CLOBFILE ");	
	}

	@Override
	public List<HashMap> queryfiles() throws Exception
	{

		return SQLExecutor.queryList(HashMap.class, "select FILENAME,fileid,FILESIZE from filetable");
		
	}
	@Override
	public List<HashMap> queryclobfiles()throws Exception
	{

		return SQLExecutor.queryList(HashMap.class, "select FILENAME,fileid,FILESIZE from CLOBFILE");
		
	}

	@Override
	public void downloadFileFromBlob(String fileid, final HttpServletRequest request,
			final HttpServletResponse response) throws Exception
	{

		try
		{
			SQLExecutor.queryByNullRowHandler(new NullRowHandler() {
				@Override
				public void handleRow(Record record) throws Exception
				{

					StringUtil.sendFile(request, response, record
							.getString("filename"), record
							.getBlob("filecontent"));
				}
			}, "select * from filetable where fileid=?", fileid);
		}
		catch (Exception e)
		{
			throw e;
		}
		
	}
	
	@Override
	public void downloadFileFromClob(String fileid, final HttpServletRequest request,
			final HttpServletResponse response) throws Exception
	{

		try
		{
			SQLExecutor.queryByNullRowHandler(new NullRowHandler() {
				@Override
				public void handleRow(Record record) throws Exception
				{

					StringUtil.sendFile(request, response, record
							.getString("filename"), record
							.getClob("filecontent"));
				}
			}, "select * from CLOBFILE where fileid=?", fileid);
		}
		catch (Exception e)
		{
			throw e;
		}
		
	}

	
}      

代碼都很簡單,也非常容易了解,這裡不做過多的解釋。有問題可以留言讨論,也可以加入群組:

21220580

3625720

154752521

官方網站:

http://www.bbossgroups.com/