(十)文件上传与下载
-
文件上传的几种方式:
- 上传到服务器的文件夹中。(不重要的文件),一般在数据库中只存文件的路径和文件名。
- 上传到数据库的字段中。(重要的文件),在字段中以二进制的形式存储。
一、上传到服务器的文件夹中。
- 前提:
- index.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <%@ taglib prefix="s" uri="/struts-tags" %> <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <% String path=request.getContextPath(); %> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>Insert title here</title> </head> <body> <h2>上传到文件夹</h2> <form action="uploadAction/upload!upload_toFolder" enctype="multipart/form-data" method="post"> <table border="1" width="50%" height="50%"> <tr> <td>ID:</td> <td><s:textfield name="id"></s:textfield></td> </tr> <tr> <td>文件:</td> <td><s:file name="file" ></s:file></td> </tr> <tr> <td><s:submit value="提交"></s:submit></td> </tr> </table> </form> <h2>上传到服务器</h2> <form action="uploadAction/upload!upload_to_table" enctype="multipart/form-data" method="post"> <table border="1" width="50%" height="50%"> <tr> <td>ID:</td> <td><s:textfield name="id"></s:textfield></td> </tr> <tr> <td>文件:</td> <td><s:file name="file" ></s:file></td> </tr> <tr> <td><s:submit value="提交"></s:submit></td> </tr> </table> </form> </body> </html>
- struts.xml
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE struts PUBLIC "-//Apache Software Foundation//DTD Struts Configuration 2.3//EN" "http://struts.apache.org/dtds/struts-2.3.dtd"> <struts> <constant name="struts.i18n.encoding" value="UTF-8"></constant> <constant name="struts.multipart.maxSize" value="209715200"></constant> <constant name="struts.action.extension" value="action,,"></constant> <constant name="struts.enable.DynamicMethodInvocation" value="true" /> <constant name="struts.devMode" value="true" /> <constant name="struts.i18n.reload" value="true"></constant> <constant name="struts.ui.theme" value="simple" /> <constant name="struts.configuration.xml.reload" value="true"></constant> <constant name="struts.ognl.allowStaticMethodAccess" value="true"></constant> <constant name="struts.handle.exception" value="true"></constant> <package name="default" namespace="/uploadAction" extends="struts-default"> <action name="upload" class="action.FileUpload"> <result name="list">/list.jsp</result> </action> </package> <package name="download" namespace="/download" extends="struts-default" > <action name="downloadAction" class="action.DownLoadAction"> <result name="down_for_struts" type="stream"> <param name="bufferSize">10240</param> <param name="contentType"> application/octet-stream </param> <param name="contentDisposition"> attachment;filename=${encode_filename} <!-- ${} OGNL表达式,只用于xml文件中获取广义值栈的值 --> </param> <param name="contentCharSet">ISO-8859-1</param> <param name="inputName">fileInput</param> </result> </action> </package> </struts>
-
FileUpload 。java
package action; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.InputStream; import java.sql.Connection; import org.apache.commons.dbutils.QueryRunner; import org.apache.commons.dbutils.ResultSetHandler; import org.apache.commons.dbutils.handlers.MapHandler; import org.apache.commons.dbutils.handlers.MapListHandler; import org.apache.commons.io.FileUtils; import com.opensymphony.xwork2.ActionContext; import com.opensymphony.xwork2.util.ValueStack; import java.sql.PreparedStatement; import java.sql.SQLException; import java.util.List; import java.util.Map; import DBUtils.DButil; import Global.Global; import actionUtil.BaseAction; public class FileUpload extends BaseAction { private static final long serialVersionUID = 1L; /* ============================================== */ private int id; // 用于接收表单中的id private File file; // 用于接收表单的文件 private String fileFileName; // 控件名称+FileName 用于获取上传文件的名。 private String fileContentType; // 控件名称+ContentType 用于获取文件的类型,比如txt、word等 private String fileName=""; private String filePath=""; public String getFileContentType() { return fileContentType; } public void setFileContentType(String fileContentType) { this.fileContentType = fileContentType; } public String getFileFileName() { return fileFileName; } public void setFileFileName(String fileFileName) { this.fileFileName = fileFileName; } public int getId() { return id; } public void setId(int id) { this.id = id; } public File getFile() { return file; } public void setFile(File file) { this.file = file; } /* ============================================== */ @Override public String execute() { return "success"; } /** * 文件上传到服务器中的文件夹里。 * 1. 当用户成功上传文件或者上传失败的时候会有javaScript的alert提示,那么这个方法的返回值只能是null,否则脚本将无法运行。 * @return */ public String upload_toFolder() { if(fileFileName!=null && !fileFileName.equals("")){ //如果文件名不为null或者不为空,说明用户有上传文件,需要处理文件上传 fileName=this.getFileFileName(); boolean isuploaderror=true; String errorMsg=""; //错误消息 try { String uploadpath=this.context.getRealPath("/upload"); //获取存放用户文件的文件夹路径 File destFile=new File(uploadpath+"/"+this.fileFileName); //存放到文件夹里的用户上传文件 FileUtils.copyFile(file, destFile); //FileUtils文件工具类的copyFile可以一个文件的拷贝到另一个文件。 filePath=fileName; isuploaderror=false; } catch (Exception e) { e.printStackTrace(); errorMsg=e.getMessage(); } if(isuploaderror == true){ //说明上传错误,数据库不能记录 Global.WebErrorMsg(response, errorMsg); }else{ //上传正确,记录到数据库 String sql="insert into file(id,filename,filepath) values('"+this.id+"','"+this.fileFileName+"','"+filePath+"')"; boolean flag=false; try { flag = DButil.uptData(sql); } catch (Exception e) { errorMsg=e.getMessage(); //如果上传错误,就把错误消息赋给errorMsg,前提是try里面的uptData方法定义里把异常抛出且uptData方法里的catch块里有把throw e即把异常对象抛出,否则这里的e.getMessage()就没有异常消息内容。 e.printStackTrace(); } if(flag==true){ //文件数据成功存入数据库 String ListURL=request.getContextPath()+"/uploadAction/upload!list"; //跳转到显示全部文件记录的页面 out.print("<script lang='javascript'>"); out.println("alert('文件数据存入成功')"); out.println("window.location.href='"+ListURL+"'"); out.print("</script>"); }else{ //文件数据存入数据库失败,返回上一页。 Global.WebErrorMsg(response, errorMsg); } } } return null; } /** * 以二进制形式上传到数据库的字段中。 * 前提: * 1. jdk 1.6 以上版本。 * 2. 必须要用prepare的Statement语句,否则操作不成功。 * 3. 当用户成功上传文件或者上传失败的时候会有javaScript的alert提示,那么这个方法的返回值只能是null,否则脚本将无法运行。 * @return */ public String upload_to_table() { InputStream inputStream=null; if(fileFileName!=null && !fileFileName.equals("")){ //如果文件名不为null或者不为空,说明用户有上传文件,需要处理文件上传 fileName=this.getFileFileName(); String errorMsg=""; //错误消息 try { inputStream=new FileInputStream(this.file); } catch (FileNotFoundException e1) { e1.printStackTrace(); } //上传正确,记录到数据库 String sql="insert into file(id,filename,filedata) values(?,?,?)"; boolean flag=false; Connection conn=null; PreparedStatement pstat=null; try { conn=DButil.getConn(); conn.setAutoCommit(false); //当用户上传数据的时候禁止事务的自动提交 pstat= conn.prepareStatement(sql); pstat.setInt(1, this.id); pstat.setString(2, this.fileFileName); pstat.setBinaryStream(3, inputStream); pstat.executeUpdate(); flag=true; conn.commit(); //提交事务 } catch (Exception e) { try { conn.rollback();//有异常就回滚事务。 } catch (SQLException e1) { e1.printStackTrace(); } flag=false; errorMsg=e.getMessage(); //如果上传错误,就把错误消息赋给errorMsg,前提是try里面的uptData方法定义里把异常抛出且uptData方法里的catch块里有把throw e即把异常对象抛出,否则这里的e.getMessage()就没有异常消息内容。 e.printStackTrace(); } if(flag==true){ //文件数据成功存入数据库 String ListURL=request.getContextPath()+"/uploadAction/upload!list"; //跳转到显示全部文件记录的页面 out.print("<script lang='javascript'>"); out.println("alert('文件数据存入成功')"); out.println("window.location.href='"+ListURL+"'"); out.print("</script>"); }else{ //文件数据存入数据库失败,返回上一页。 Global.WebErrorMsg(response, errorMsg); } } return null; } /** *生成文件数据库中所有文件的列表,以提供用户下载 * @return */ public String list() throws Exception { //导入commons-dbutils-1.3.jar 使用里面的查询类实现快速查询 QueryRunner run=new QueryRunner(); String sql="select id,filename,filepath from file "; Connection conn=DButil.getConn(); List<Map<String, Object>> fileList =run.query(conn, sql, new MapListHandler()); ActionContext actionContext=ActionContext.getContext(); ValueStack valueStack=actionContext.getValueStack(); valueStack.set("map", fileList); return "list"; } }
- list.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <%@ taglib prefix="s" uri="/struts-tags"%> <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <%String path=request.getContextPath(); %> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>Insert title here</title> </head> <body> <s:debug></s:debug> <table border="1" width="100%"> <tr> <th>id</th> <th>文件名</th> <th>文件路径</th> <th colspan="3">操作</th> </tr> <s:iterator value="map" var="file" > <tr> <td><s:property value="#file.id" /></td> <td><s:property value="#file.filename" /></td> <td><s:property value="#file.filepath" /></td> <td><s:if test="#file.filepath!=null && #file.filename!='' "> <a href="<%=path%>/download/downloadAction!from_folder?id=<s:property value="#file.id" />">从文件夹下载</a> </s:if> </td> <td> <s:if test="#file.filename!='' &&(#file.filepath==null || #file.filepath=='' )"> <a href="<%=path%>/download/downloadAction!from_table?id=<s:property value="#file.id" />">从数据库下载</a> </s:if> </td> <td><s:if test="#file.filepath!=null && #file.filename!='' "> <a href="<%=path%>/download/downloadAction!from_struts?id=<s:property value="#file.id" />">从struts下载</a> </s:if> </td> </tr> </s:iterator> </table> </body> </html>
-
DownLoadAction 。java
package action; import java.io.File; import java.io.FileInputStream; import java.io.InputStream; import java.io.OutputStream; import java.sql.Connection; import java.sql.ResultSet; import java.sql.Statement; import java.util.Map; import org.apache.commons.dbutils.QueryRunner; import org.apache.commons.dbutils.handlers.MapHandler; import org.apache.commons.io.IOUtils; import DBUtils.DButil; import actionUtil.BaseAction; public class DownLoadAction extends BaseAction { @Override public String execute() throws Exception { return null; } /** * 从文件夹中下载文件 步骤: 1. 从数据库中根据客户端传来的id用找到这个文件 2. 定义response对象为二进制输出流 3. * 把文件的输入流拷贝到response输出流中。 注意: * * @return */ public String from_folder() throws Exception { int id = Integer.parseInt(request.getParameter("id")); String sql = "select filename,filepath from file where id='" + id + "'"; Connection conn = null; String upload = context.getRealPath("/upload"); // 拿到存放文件的上传文件夹的路径 String filepath = ""; String filename = ""; try { conn = DButil.getConn(); QueryRunner run = new QueryRunner(); Map<String, Object> map = run.query(conn, sql, new MapHandler()); if (map != null) { filename = (String) map.get("filename"); filepath = (String) map.get("filepath"); File file = new File(upload + "/" + filepath); // 拿到用户想要下载的文件 if (file.exists() == true) { // 文件夹中有这个文件 InputStream fileinput = new FileInputStream(file); // 拿到用户想下载文件的输入流 /* * 本类的response对象是BaseAction类中的response对象。这个对象定义了this. * response.setContentType("text/html"); * 如果我们要想response返回的是文件流那么必修对这个对象进行重新定义。 */ response.reset(); response.setContentType("application/octet-stream"); // 表示输出的类型是流的数据类型。会弹出下载的窗口 String enco_filename = new String(filename.getBytes("GBK"), "ISO-8859-1"); // 设定下载窗口中显示文件名 response.setHeader("Content-Disposition", "attachment; filename=\"" + enco_filename + "\""); OutputStream fileout = response.getOutputStream(); // 拿到response的输出流 // 文件输入流与response输出流的拷贝 int i = 0; byte[] byteArray = new byte[10240]; while ((i = fileinput.read(byteArray)) != -1) { fileout.write(byteArray, 0, i); out.flush(); } fileout.close(); // 输入输出流的关闭 fileinput.close(); } else { // 文件夹中没有这个文件 throw new RuntimeException("下载的文件不存在。"); } } } catch (Exception e) { e.printStackTrace(); } finally { DButil.close(conn, null, null); } return null; } /** * 从数据库中下载文件 * * @return */ public String from_table() { int id = Integer.parseInt(request.getParameter("id")); String sql = "select filename,filedata from file where id='" + id + "'"; Connection conn = null; Statement stat = null; ResultSet rs = null; String filename = ""; try { conn = DButil.getConn(); stat = conn.createStatement(); rs = stat.executeQuery(sql); if (rs.next()) { filename = rs.getString("filename"); String enco_filename = new String(filename.getBytes("GBK"), "ISO-8859-1"); // 设定下载窗口中显示文件名 InputStream input = rs.getBinaryStream("filedata"); if (input != null) { /* * 本类的response对象是BaseAction类中的response对象。这个对象定义了this. * response.setContentType("text/html"); * 如果我们要想response返回的是文件流那么必修对这个对象进行重新定义。 */ response.reset(); response.setContentType("application/octet-stream"); // 表示输出的类型是流的数据类型。会弹出下载的窗口 response.setHeader("Content-Disposition", "attachment; filename=\"" + enco_filename + "\""); OutputStream fileout = response.getOutputStream(); // 拿到response的输出流 // 文件输入流与response输出流的拷贝 int i = 0; byte[] byteArray = new byte[10240]; while ((i = input.read(byteArray)) != -1) { fileout.write(byteArray, 0, i); out.flush(); } fileout.close(); // 输入输出流的关闭 input.close(); } } } catch (Exception e) { e.printStackTrace(); } finally { DButil.close(conn, null, null); } return null; } /** * 1.以struts方式下载文件,与从文件夹下载类似, * 2.用户需要的文件不是以response方式返回而是以return到struts.xml中的result这个result以stream的方法返回结果<result name="down_for_struts" type="stream"> * 3.在result中配置参数,即下载文件的相关信息。 * 4.在开发中一般用从文件夹或者从服务器字段下载,而不用struts下载,因为如果文件名中含有空格那么这种方法无法显示空格以后的内容。 * 5.如果在result中需要使用到action中的变量比如文件名、文件输入流等,需要把这些变量设为成员变量且定义getset方法 * @return */ private InputStream fileInput; private String encode_filename; public InputStream getFileInput() { return fileInput; } public void setFileInput(InputStream fileInput) { this.fileInput = fileInput; } public String getEncode_filename() { return encode_filename; } public void setEncode_filename(String encode_filename) { this.encode_filename = encode_filename; } public String from_struts() { int id = Integer.parseInt(request.getParameter("id")); String sql = "select filename,filepath from file where id='" + id + "'"; Connection conn = null; String upload = context.getRealPath("/upload"); // 拿到存放文件的上传文件夹的路径 String filepath = ""; String filename = ""; try { conn = DButil.getConn(); QueryRunner run = new QueryRunner(); Map<String, Object> map = run.query(conn, sql, new MapHandler()); if (map != null) { filename = (String) map.get("filename"); filepath = (String) map.get("filepath"); File file = new File(upload + "/" + filepath); // 拿到用户想要下载的文件 if (file.exists() == true) { // 文件夹中有这个文件 encode_filename = new String(filename.getBytes("GBK"), "ISO-8859-1"); // 设定下载窗口中显示文件名 response.reset(); this.fileInput=new FileInputStream(file); } } else { // 文件夹中没有这个文件 throw new RuntimeException("下载的文件不存在。"); } } catch (Exception e) { e.printStackTrace(); } return "down_for_struts"; } }
- BaseAction.java
package actionUtil; import java.io.IOException; import java.io.PrintWriter; import javax.servlet.ServletContext; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; import org.apache.struts2.interceptor.ServletRequestAware; import org.apache.struts2.interceptor.ServletResponseAware; import org.apache.struts2.util.ServletContextAware; import com.opensymphony.xwork2.ActionSupport; public abstract class BaseAction extends ActionSupport implements ServletRequestAware, ServletResponseAware, ServletContextAware { protected HttpServletRequest request; protected HttpServletResponse response; protected ServletContext context; protected HttpSession session; protected PrintWriter out; public void setServletRequest(HttpServletRequest request) { this.request = request; if (this.request != null) { this.session = this.request.getSession(); } } public void setServletResponse(HttpServletResponse response) { this.response = response; if (this.response != null) { try { this.response.setContentType("text/html"); this.out = this.response.getWriter(); } catch (IOException e) { e.printStackTrace(); } } } public void setServletContext(ServletContext context) { this.context = context; } public abstract String execute() throws Exception; }
- DButil.java
package DBUtils; import java.sql.Connection; import java.sql.DriverManager; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; public class DButil { private static final String DRIVER="com.mysql.jdbc.Driver"; private static final String USER="root"; private static final String PASSWD=""; private static final String URL="jdbc:mysql://127.0.0.1:3306/user?useUnicode=true&characterEncoding=UTF-8"; static{ try{ Class.forName(DRIVER); }catch(Exception e){ throw new RuntimeException("无法加载驱动包"); } } public static Connection getConn() { Connection conn=null; try { conn=DriverManager.getConnection(URL,USER,PASSWD); } catch (SQLException e) { e.printStackTrace(); } return conn; } public static boolean uptData(String sql) throws Exception { Connection conn = null; Statement stmt = null; boolean flag = false; try { conn = DButil.getConn(); stmt = conn.createStatement(); stmt.executeUpdate(sql.toString()); flag = true; } catch (Exception e) { flag = false; e.printStackTrace(); throw e; } finally { DButil.close(conn, stmt, null); } return flag; } public static void close(Connection conn,Statement stat,ResultSet rs){ if(conn!=null){ try { conn.close(); } catch (SQLException e) { e.printStackTrace(); } } if(stat!=null){ try { stat.close(); } catch (SQLException e) { e.printStackTrace(); } } if(rs!=null){ try { rs.close(); } catch (SQLException e) { e.printStackTrace(); } } } }
- Global.java
package Global; import java.io.IOException; import java.io.PrintWriter; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; public class Global { public static void WebErrorMsg(HttpServletResponse resonse,String errorMsg) { PrintWriter out; try { out = resonse.getWriter(); out.print("<head>"); out.print("<meta http-equiv='content-type' content='text/html;charset=UTF-8'/>"); out.print("</head>"); out.print("<script lang='javascript'>"); out.println("window.alert(\"数据操作出现错误!原因 = " + errorMsg + "\");"); out.print("window.history.back();"); out.print("</script>"); } catch (IOException e) { e.printStackTrace(); } } }
结果: