Servlet3.0.1與dojo實現圖片AJAX上傳與下載,附lastmodified實現

開發環境

tomcat8, eclipse+maven,dojo1.9javascript

Maven項目

首先須要生成一個webapp的maven項目。本次開發用到了tomcat的servlet api, jsp api以及jstl,所以須要在pom.xml中聲明所需的依賴。爲了避免超過字數上限,我只列出依賴的ID。html

    tomcat-servlet-api
    tomcat-jsp-api
    jstl

咱們將有兩個servlet和一個JSP

  1. index.jsp, 負責界面展現。對應的URL爲http://localhost:8080/images 前端

  2. UploaderServlet, 負責處理dojo發送的AJAX圖片上傳請求,並返回JSON格式的消息。對應的URL爲http://localhost:8080/images/ajaxUploader java

  3. ImagesServlet, 負責處理對上傳後的圖片訪問請求。對應的URL爲http://localhost:8080/images/*.png|jpg|gif?download=true|falsenode

後端開發

web.xml

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

UploaderServlet

使用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();
        }
    }
}

ImagesServlet

處理圖片訪問請求的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頁面,也是惟一的頁面,它將承載全部的用戶交互。在此頁面上只包含兩個功能:

  1. 圖片上傳Form。

  2. 已經上傳的圖片的展示。

index.jsp

使用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>

最終的UI效果

源代碼下載地址

http://pan.baidu.com/s/1dDpDNhR 

相關文章
相關標籤/搜索