一、背景
前段时间公司要求我做一个上传和下载固件的页面,以备硬件产品在线升级,现在我把这部分功能抽取出来作为一个Demo Project给大家分享。
话不多说,先看项目演示 --> 演示 源码
二、源码
前端
js库:jquery-3.2.1.min.js,jquery.form.js(异步表单提交),jsviews.min.js(模板渲染)
jsviews科普:jsviews是实现MVVM的js库,分为JsRender(渲染),JsViews(数据视图双向绑定),JsObservable (数据监听),有兴趣的同学可以去官网了解,这里只用到了渲染的功能。
1、下载页面 index.html
<!DOCTYPE html> <html> <head><meta charset="UTF-8"><title>ajaxSubmit上传</title><link rel="shortcut icon" href="images/favicon.ico"><link rel="Bookmark" href="images/favicon.ico"><link rel="stylesheet" href="css/index.css" /><script type="text/javascript" src="js/jquery-3.2.1.min.js"></script><script type="text/javascript" src="js/jquery.form.js"></script><script type="text/javascript" src="js/jsviews.min.js"></script><script type="text/javascript" src="js/common.js"></script></head> <body> <h1>上传下载Demo</h1> <h2>1、上传文件</h2> <form id="addForm"><div><span>选择类型:</span><select name="code" id="code"><option value="0">普通开关</option><option value="1">插座</option></select></div><div><span>选择文件(小于5k):</span><input type="file" id="file" name="file"></div><div><button type="button" id="addConfirm" name="addConfirm">确定</button></div> </form> <h2>2、测试上传结果</h2> <table id="tbBody"> <thead> <tr><td>类型</td><td>文件名</td><td>通过Servlet下载</td></tr> </thead> </table> </body> <script type="text/javascript" src="js/index.js"></script> <!-- jsviews模板 --> <script id="listTmpl" type="text/x-jsrender"><tr><td>{^{if code=='0'}}普通开关{{else code=='1'}}插座{{else}}数据错误{{/if}}</td><td>{{:fileName}}</td><td><a href="fileDownload?fileName={{:fileName}}">urlServlet</a></td></tr> </script> </html>
2、公共js js/common.js
//获取链接参数 function getQueryString(name) {var reg = new RegExp("(^|&)"+ name +"=([^&]*)(&|$)");var r = window.location.search.substr(1).match(reg);if(r!=null)return unescape(r[2]); return null; }
3、 js/index.js
//提交表单 function addSubmit(){var options={url: "fileUpload",type:'post', datatype:'json',success: function (data) {var result = JSON.parse(data);if(result.code == "0000"){var pageBarTmpl = $.templates("#listTmpl");var html = pageBarTmpl.render(result.content);$("#tbBody").append(html);}else{alert(result.desc);} }}$("#addForm").ajaxSubmit(options); } //提交前检查 function submitCheck(){var code = $("#code").val();if (!code) {alert("请选择类型");return false;}var file = $("#file").val();if (!file) {alert("请选择需要上传的固件");return false;}return true;} //按钮触发 $("#addConfirm").click(function(){if(submitCheck())addSubmit(); });
4、css/index.css
table th,table td{ border:1px solid black;
}
form div{margin:5px;
}
后端
使用到了commons-fileupload-1.3.1.jar,commons-io-2.4.jar以及gson-2.6.2.jar
1、返回结果类 RspResult.java
/*** 返回结果类* @author zhang**/ public class RspResult{private String code; //返回码private String desc; //返回描述private Map<String,Object> content; //返回内容public String getCode() {return code;}public void setCode(String code) {this.code = code;}public String getDesc() {return desc;}public void setDesc(String desc) {this.desc = desc;}public Map<String, Object> getContent() {return content;}public void setContent(Map<String, Object> content) {this.content = content;}}
2、自定义异常类 MyException.java
/*** 自定义异常* @author zhang**/ public class MyException extends Exception{private static final long serialVersionUID = 3075956744530570774L;private String code; //错误码private String desc; //描述public MyException(String code, String desc) {super();this.code = code;this.desc = desc;}public String getCode() {return code;}public void setCode(String code) {this.code = code;}public String getDesc() {return desc;}public void setDesc(String desc) {this.desc = desc;} }
3、文件上传Servlet FileUpload.java
/*** 文件上传类* 使用commons-fileupload工具包解析表单内容,捕获自定义异常* @author zhang**/ public class FileUpload extends HttpServlet{private static final long serialVersionUID = -4700695646596658600L;private static final String SAVE_LOCATION = "/home/www/download/blog/ajaxUpload/"; //保存地址 @Overrideprotected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException {resp.setCharacterEncoding("UTF-8");RspResult result = new RspResult();result.setCode("0000");result.setDesc("success");try {DiskFileItemFactory factory = new DiskFileItemFactory();ServletFileUpload upload = new ServletFileUpload(factory);upload.setFileSizeMax( 5*1024 ); //单个文件最大上传大小为5kupload.setSizeMax( 5*1024 ); //设置全部文件最大上传总大小为5kupload.setHeaderEncoding("utf-8"); //设置编码 List<FileItem> fileItems = upload.parseRequest(req);Iterator<FileItem> iterator = fileItems.iterator();Map<String, Object> rspConent = new HashMap<>();DiskFileItem fileItem = null;//循环读取表单数据while (iterator.hasNext()) {FileItem item = iterator.next();if (!item.isFormField()) { //是否为文件类型,因为只有一个文件,所以单个引用就行fileItem = (DiskFileItem) item;}else {rspConent.put(item.getFieldName(), item.getString());}}if(fileItem == null)throw new MyException("0001","无选择文件");String fileName = fileItem.getName();fileItem.write(new File(SAVE_LOCATION + fileName));rspConent.put("fileName", fileName);result.setContent(rspConent);} catch (FileUploadException e ) {result.setCode("0001");result.setDesc("文件上传大小为5k");e.printStackTrace();} catch (MyException e ) { //取得自定义异常结果 result.setCode(e.getCode());result.setDesc(e.getDesc());} catch (Exception e) {result.setCode("0001");result.setDesc("未知错误");e.printStackTrace();}finally {PrintWriter out = null;try {out = resp.getWriter();} catch (IOException e) {e.printStackTrace();}out.write(new Gson().toJson(result));}} }
4、文件下载Servlet FileDownload.java
/*** 文件下载类,读取文件,以字节流形式写到response* @author admin**/ public class FileDownload extends HttpServlet { private static final long serialVersionUID = -9135576688701595777L;private final String SAVE_LOCATION = "/home/www/download/blog/ajaxUpload/"; @Overrideprotected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException {InputStream in = null;try {String fileName = req.getParameter("fileName");in = new FileInputStream(SAVE_LOCATION+fileName);// 设置输出格式resp.setCharacterEncoding("utf-8");resp.addHeader("Content-Disposition", "attachment; filename=\"" + URLEncoder.encode(fileName, "UTF-8") + "\"");// 读取数据byte[] b = new byte[100];int len = 0;while ((len = in.read(b)) > 0)resp.getOutputStream().write(b, 0, len);} catch (UnsupportedEncodingException e2) {e2.printStackTrace();} catch (FileNotFoundException e1) {e1.printStackTrace();} catch (IOException e) {e.printStackTrace();}finally {try {if(in != null)in.close();} catch (IOException e) {e.printStackTrace();}}}@Overrideprotected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {doPost(req, resp);}}
配置
1、项目配置 web.xml
<?xml version="1.0" encoding="UTF-8"?> <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:jsp="http://java.sun.com/xml/ns/javaee/jsp" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" id="WebApp_ID" version="2.5"><display-name>upload-download-demo</display-name><welcome-file-list><welcome-file>index.html</welcome-file></welcome-file-list><servlet><servlet-name>fileUpload</servlet-name><servlet-class>com.yuejia.servlet.FileUpload</servlet-class></servlet><servlet-mapping><servlet-name>fileUpload</servlet-name><url-pattern>/fileUpload</url-pattern></servlet-mapping><servlet><servlet-name>fileDownload</servlet-name><servlet-class>com.yuejia.servlet.FileDownload</servlet-class></servlet><servlet-mapping><servlet-name>fileDownload</servlet-name><url-pattern>/fileDownload</url-pattern></servlet-mapping> </web-app>
2、tomcat配置url支持utf-8 server.xml
<Connector port="8080" protocol="HTTP/1.1" connectionTimeout="20000" redirectPort="8443" URIEncoding="UTF-8" />
三、总结
本Demo适合一次性上传小文件,多数情况下需要先上传文件再进行表单提交,视需求而定。
在保存文件建议在文件名后面加上时间戳,保证同名文件不会被覆盖。
以上!