tomcat8, eclipse+maven,dojo1.9javascript
首先須要生成一個webapp的maven項目。本次開發用到了tomcat的servlet api, jsp api以及jstl,所以須要在pom.xml中聲明所需的依賴。爲了避免超過字數上限,我只列出依賴的ID。html
tomcat-servlet-api tomcat-jsp-api jstl
index.jsp, 負責界面展現。對應的URL爲http://localhost:8080/images 前端
UploaderServlet, 負責處理dojo發送的AJAX圖片上傳請求,並返回JSON格式的消息。對應的URL爲http://localhost:8080/images/ajaxUploader java
ImagesServlet, 負責處理對上傳後的圖片訪問請求。對應的URL爲http://localhost:8080/images/*.png|jpg|gif?download=true|falsenode
Servlet3可使用annotation config,也可使用傳統的web.xml。咱們仍是用web.xml.web
<?xml version="1.0" encoding="UTF-8"?> <web-app version="3.0" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"> <display-name>Archetype Created Web Application</display-name> <context-param> <!-- 定義上傳圖片最終存放的文件夾。 --> <param-name>shareFolder</param-name> <param-value>d:/share/data</param-value> </context-param> <servlet> <servlet-name>imageUploader</servlet-name> <servlet-class>servlets.UploaderServlet</servlet-class> <multipart-config> <!--臨時存放上傳文件的地方--> <location>d:/share/tmp</location> <!--容許上傳的文件最大值,約10MB。默認值爲 -1,表示沒有限制。--> <max-file-size>10240000</max-file-size> <!--針對該 multipart/form-data 請求的最大數量,默認值爲 -1,表示沒有限制。--> <max-request-size>20480000</max-request-size> <!--當數據量大於約10MB時,內容將被寫入tmp目錄下的文件。--> <file-size-threshold>10240000</file-size-threshold> </multipart-config> </servlet> <servlet-mapping> <servlet-name>imageUploader</servlet-name> <url-pattern>/ajaxUploader</url-pattern> </servlet-mapping> <servlet> <servlet-name>imageAccess</servlet-name> <servlet-class>servlets.ImagesServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>imageAccess</servlet-name> <url-pattern>*.png</url-pattern> <url-pattern>*.jpg</url-pattern> <url-pattern>*.gif</url-pattern> </servlet-mapping> </web-app>
從上可見,全部的圖片訪問均由ImagesServlet處理,文件上傳由UploaderServlet處理。UploaderServlet下面配置了文件上傳的限制,請看註釋。另外我還聲明瞭一個context-param,做用請看註釋。ajax
使用request.getPart()方法,能夠獲得文件上傳part的對象。將上傳的流保存在指定的目錄文件中。json
特別注意的是,此servlet響應的將是dojo.io.iframe發送來的AJAX請求,所以,返回JSON格式的響應,將是最好的選擇。後端
響應dojo.io.iframe的JSON格式,必須包含在下面的結構中。這是dojo.io.iframe所能解析的結構,也是必須遵循的規則, 響應的,response header必須設置爲text/html。api
<html> <body> JSON_DATA </body> </html>
UploadServlet的部分代碼以下:
public class UploaderServlet extends HttpServlet { @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { try { Part image = req.getPart("image"); //servlet3.0.1新加入的方法,在3中,咱們只能經過header來本身解析filename. String imageName = image.getSubmittedFileName(); String shareFolder = req.getServletContext().getInitParameter("shareFolder"); File imageFile = new File(shareFolder, imageName); FileOutputStream fos=null; InputStream is =null; try { fos = new FileOutputStream(imageFile); is = image.getInputStream(); byte[] bytes = new byte[4096]; int bytesReaded = -1; while ((bytesReaded=is.read(bytes))!=-1) { fos.write(bytes, 0, bytesReaded); } fos.flush(); } finally { //關閉全部的流。 } sendCreated(resp, imageName); } catch (Exception e) { e.printStackTrace(); sendError(resp); return; } } private void sendError(HttpServletResponse resp) { resp.setStatus(200); resp.setContentType("text/html;charset=UTF-8"); StringBuilder body = new StringBuilder() .append("<html> ") .append(" <boby> ") .append(" <textarea> ") .append(" {status:500, message:'Can't load your image.'} ") .append(" </textarea> ") .append(" </body> ") .append("</html> "); resp.setContentLength(body.length()); PrintWriter out; try { out = resp.getWriter(); out.print(body.toString()); out.flush(); out.close(); } catch (IOException e) { e.printStackTrace(); } } private void sendCreated(HttpServletResponse resp, String image) { resp.setStatus(200); resp.setContentType("text/html;charset=UTF-8"); StringBuilder body = new StringBuilder() .append("<html> ") .append(" <boby> ") .append(" <textarea> ") .append(String.format("{status:201, image:'%s', message:'File created.'}", image)) .append(" </textarea> ") .append(" </body> ") .append("</html> "); resp.setContentLength(body.length()); PrintWriter out; try { out = resp.getWriter(); out.print(body.toString()); out.flush(); out.close(); } catch (IOException e) { e.printStackTrace(); } } }
處理圖片訪問請求的servlet。只須要將存放的文件以字節流的形式輸出到response中便可。在輸出流以前,咱們還要檢查If-Modified-Since和If-None-Match兩個header。若是圖片沒有修改過,則返回304. 若是修改過,則輸出流,並設置新的Last-Modified和ETag兩個header。
public class ImagesServlet extends HttpServlet { @Override public void doGet(HttpServletRequest request, HttpServletResponse response) { String path = request.getRequestURI(); String imageName = path.substring(path.lastIndexOf('/')+1); File image = new File(request.getServletContext().getInitParameter("shareFolder"), imageName); if (!image.exists()) { response.setStatus(404); return; } long lastModified = image.lastModified(); long ifModifiedSince = request.getDateHeader("If-Modified-Since"); if ((lastModified / 1000 * 1000) <= ifModifiedSince) { response.setStatus(304); return; } response.setStatus(200); String mimeType = request.getServletContext().getMimeType(imageName); if(mimeType==null) {mimeType = "application/octet-stream";} response.addHeader("content-type", mimeType); response.setContentLength((int)image.length()); response.addDateHeader("Last-Modified", lastModified); String isDownload = request.getParameter("download"); if (isDownload!=null&&"true".equals(isDownload)) { //force download String headerKey = "Content-Disposition"; String headerValue = String.format("attachment; filename=\"%s\"", imageName); response.setHeader(headerKey, headerValue); } FileInputStream in=null; ServletOutputStream out=null; try { in = new FileInputStream(image); out = response.getOutputStream(); byte[] bytes = new byte[4096]; int bytesReaded = -1; while ((bytesReaded = in.read(bytes))!=-1) { out.write(bytes, 0, bytesReaded); } out.flush(); } catch (Exception e) { e.printStackTrace(); response.setStatus(500); } finally { //關閉全部的流。 } } }
前端開發重要是對index.jsp的內容展現方面進行開發。做爲網站的welcome頁面,也是惟一的頁面,它將承載全部的用戶交互。在此頁面上只包含兩個功能:
圖片上傳Form。
已經上傳的圖片的展示。
使用dojo.io.iframe進行無刷新的圖片上傳。圖片上傳成功之後,會接受服務器返回的JSON對象,其中含有圖片的信息。而後使用JS將圖片插入到全部圖片的前面。
當刷新本頁面時,JSP會掃面圖片文件夾。列出全部的圖片,並將preview顯示在頁面上。咱們能夠點擊download如下載圖片,也能夠點擊view,使得瀏覽器直接打開圖片。
如下是部分代碼。
<script src="//ajax.googleapis.com/ajax/libs/dojo/1.9.2/dojo/dojo.js"></script> <script type="text/javascript"> require(["dojo/io/iframe", "dojo/dom-construct","dojo/on","dojo/dom","dojo/query","dojo/string", "dojo/domReady!"], function(ioIframe,domConst,on,dom,query,string){ var upload=function() { ioIframe.send({ url:'${pageContext.request.contextPath }/ajaxUploader', form:'uploader', handleAs:'json', load: function(response, ioArgs){ if (response.status == 201) { var nodeHtml = <!--建立新image的preview的html--> var node = domConst.toDom(nodeHtml); domConst.place(node, 'icons', 'first'); } else { alert(response.message); } return response; }, // Callback on errors: error: function(response, ioArgs){ alert(response); return response; } }); }; on(dom.byId("uploadButton"), "click", upload); }); </script> <div> <form enctype="multipart/form-data" id="uploader" method="post"> <div><label>Please select a image:</label><input type="file" name="image"/></div> <div><input type="button" value="Upload" id="uploadButton"></div> </form> <div id="icons"> <% String shareFolder = request.getServletContext().getInitParameter("shareFolder"); File dir = new File(shareFolder); String[] list = dir.list(); pageContext.setAttribute("list", list); %> <c:forEach var="image" items="${list }"> <!--建立每一個image的preview--> </c:forEach> </div> </div>