zoukankan      html  css  js  c++  java
  • 第三章 深入Servlet技术

    3.1 配置Servlet

    1. <servlet-name>,<servlet-class>是必须配置的,以便于web容器知道浏览器具体访问的是哪个servlet
    2. <init-param>用于初始化参数,在servlet中可使用getServletContext().getInitParam(String paramName)来获取初始化参数值。
    3. <load-on-startup>配置该servlet加载方式,置1Tomcat将在启动时便加载该servlet,否在会在第一次请求时加载。

    3.2 配置<servlet-mapping>

        

    3.3 response生成图片验证码

      

      

    //创建BufferedImage对象,设置图片的长度宽度和色彩。   
    BufferedImage image = new BufferedImage(width,height,BufferedImage.TYPE_INT_RGB);   
    
    OutputStream os = response.getOutputStream();  
    
    //取得Graphics对象,用来绘制图片   
    Graphics g = image.getGraphics();  
    ……
    ……
    ……
    //释放此图形的上下文以及它使用的所有系统资源,类似于关闭流   
    g.dispose();   
                 
    //通过ImageIO对象的write静态方法将图片输出。   
     ImageIO.write(image, "JPEG", os);   
    os.close();  

    3.4 读取web.xml参数

      上一节中创建一个servlet用来输出图片,当需要输出其它格式时,需要修改源代码。因此这种常量可以写在配置文件中,servlet读取参数即可。

    例如:

      

      

      

    3.5 上下文参数context-param

      上一节中在web.xml中配置的初始化参数都是在特定的servlet中配置的,因此只能被此servlet读取。使用<context-param>可配置全局参数。例如:

    3.6 资源注射(@Resource

      

    3.7 注射数据源

      

    3.8 上传客户端

    代码如下:  

     1 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
     2 <html>
     3 <head>
     4 <title>上传文件</title>
     5 <meta http-equiv="keywords" content="keyword1,keyword2,keyword3">
     6 <meta http-equiv="description" content="this is my page">
     7 <meta http-equiv="content-type" content="text/html; charset=UTF-8">
     8 <link rel="stylesheet" type="text/css" href="css/style.css">
     9 </head>
    10 
    11 <body>
    12 <form action="servlet/UploadServlet" method="post" enctype="multipart/form-data">
    13 <div align="center"><br/>
    14     <fieldset style="90%">
    15         <legend>上传文件</legend><br/>
    16         <div class='line'>
    17             <div align='left' class="leftDiv">上传文件一</div>
    18             <div align='left' class="rightDiv">
    19                 <input type="file" name="file1" class="text">
    20             </div>
    21         </div>
    22         <div class='line'>
    23             <div align='left' class="leftDiv">上传文件二</div>
    24             <div align='left' class="rightDiv">
    25                 <input type="file" name="file2" class="text">
    26             </div>
    27         </div>
    28         <div class='line'>
    29             <div align='left' class="leftDiv">上传文件说明一</div>
    30             <div align='left' class="rightDiv"><input type="text" name="description1" class="text"></div>
    31         </div>
    32         <div class='line'>
    33             <div align='left' class="leftDiv">上传文件说明二</div>
    34             <div align='left' class="rightDiv"><input type="text" name="description2" class="text"></div>
    35         </div>
    36         <div class='line'>
    37             <div align='left' class="leftDiv"></div>
    38             <div align='left' class="rightDiv"><br/>
    39                 <input type="submit" value="  上传文件  " class="button">
    40             </div>
    41         </div>
    42     </fieldset>
    43 </div>
    44 </form>
    45 </body>
    46 </html>
    47 
    48 
    49 注意:上传文件必须设置method="post" enctype="multipart/form-data"
    View Code

    3.9 上传服务器

      上一节中,通过html界面向服务器传送两个文件,和两个文件说明。这一节,将会对收到的请求进行解析,获取文件和文件说明。这里需要使用org.apache.commons.fileupload包。

      代码如下:

      

     1     File file1 = null, file2 = null;//声明文件流
     2     String description1 = null, description2 = null;
     3     
     4     // 使用 DiskFileUpload 对象解析 request
     5     DiskFileUpload diskFileUpload = new DiskFileUpload();
     6     List<FileItem> list = diskFileUpload.parseRequest(request);
     7     
     8     for(FileItem fileItem : list){ //对list中的所有FileItem进行遍历,并判断其类型
     9                     if(fileItem.isFormField()){ //判断一个参数域是普通的表单输入域,还是文件上传域,如果该方法返回真的话,则是前者,如果为假,则是后者。
    10                         // 如果是 文本域
    11                         if("description1".equals(fileItem.getFieldName())){
    12                             // 如果该 FileItem 名称为 description1
    13                             out.println("遍历到 description1 ... <br/>");
    14                             description1 = new String(fileItem.getString().getBytes(), "UTF-8");
    15                         }
    16                         if("description2".equals(fileItem.getFieldName())){
    17                             // 如果该 FileItem 名称为 description2
    18                             out.println("遍历到 description2 ... <br/>");
    19                             description2 = new String(fileItem.getString().getBytes(), "UTF-8");
    20                         }
    21                     }
    22                     else{
    23                         // 否则,为文件域
    24                         if("file1".equals(fileItem.getFieldName())){
    25                             // 服务器端文件,放在 attachment文件夹下
    26                             file1 = new File(this.getServletContext().getRealPath("attachment"), remoteFile.getName());//第二个参数为子目录名
    27                             file1.getParentFile().mkdirs();
    28                             file1.createNewFile();
    29                             
    30                             // 写文件,将 FileItem 的文件内容写到文件中
    31                             InputStream ins = fileItem.getInputStream();
    32                             OutputStream ous = new FileOutputStream(file1);
    33                             
    34                             try{
    35                                 byte[] buffer = new byte[1024]; 
    36                                 int len = 0;
    37                                 while((len=ins.read(buffer)) > -1)
    38                                     ous.write(buffer, 0, len);
    39                                 out.println("已保存文件" + file1.getAbsolutePath() + "<br/>");
    40                             }finally{
    41                                 ous.close();
    42                                 ins.close();
    43                             }
    44                         }
    View Code

       思路:

    1. DiskFileUpload 对象通过parseRequest解析request并存入list集合,存放类型为FileItem
    2. 遍历list,通过对list中每个元素调用fileItem.isFormField(),返回false则说明该元素是文件
    3. 通过fileItem.getFieldName()获取该元素的文件名,通过InputStream ins = fileItem.getInputStream();创建输入流,

    OutputStream ous = new FileOutputStream(File file1);创建输出流。

    将输入流写入到输入流。

     

    3.10 上传进度条

    前端:Ajax查询上传进度

    后端:写一个监听器(继承ProgressListener,是org.apache.commons.fileupload的一个接口),文件上传过程中,会不断调用这个监听器。

    写一个状态类,用于保存上传状态相关数据(比如文件大小,上传时间,上传速度,百分百)

      后端代码: 

      1 public class ProgressUploadServlet extends HttpServlet {
      2 
      3     private static final long serialVersionUID = -4935921396709035718L;
      4 
      5     public void doPost(HttpServletRequest request, HttpServletResponse response)
      6             throws ServletException, IOException {
      7 
      8         // 上传状态
      9         UploadStatus status = new UploadStatus();
     10 
     11         // 监听器
     12         UploadListener listener = new UploadListener(status);
     13 
     14         // 把 UploadStatus 放到 session 里
     15         request.getSession(true).setAttribute("uploadStatus", status);
     16 
     17         // Apache 上传工具
     18         ServletFileUpload upload = new ServletFileUpload(
     19                 new DiskFileItemFactory());
     20 
     21         // 设置 listener
     22         upload.setProgressListener(listener);
     23 
     24         try {
     25             List itemList = upload.parseRequest(request);
     26 
     27             for (Iterator it = itemList.iterator(); it.hasNext();) {
     28                 FileItem item = (FileItem) it.next();
     29                 if (item.isFormField()) {
     30                     System.out.println("FormField: " + item.getFieldName()
     31                             + " = " + item.getString());
     32                 } else {
     33                     System.out.println("File: " + item.getName());
     34 
     35                     // 统一 Linux 与 windows 的路径分隔符
     36                     String fileName = item.getName().replace("/", "\");
     37                     fileName = fileName.substring(fileName.lastIndexOf("\"));
     38 
     39                     File saved = new File("C:\upload_test", fileName);
     40                     saved.getParentFile().mkdirs();
     41 
     42                     InputStream ins = item.getInputStream();
     43                     OutputStream ous = new FileOutputStream(saved);
     44 
     45                     byte[] tmp = new byte[1024];
     46                     int len = -1;
     47 
     48                     while ((len = ins.read(tmp)) != -1) {
     49                         ous.write(tmp, 0, len);
     50                     }
     51 
     52                     ous.close();
     53                     ins.close();
     54 
     55                     response.getWriter().println("已保存文件:" + saved);
     56                 }
     57             }
     58         } catch (Exception e) {
     59             e.printStackTrace();
     60             response.getWriter().println("上传发生错误:" + e.getMessage());
     61         }
     62     }
     63 
     64     public void doGet(HttpServletRequest request, HttpServletResponse response)
     65             throws ServletException, IOException {//Ajax访问该servlet时会调用此函数
     66 
     67         response.setHeader("Cache-Control", "no-store");
     68         response.setHeader("Pragrma", "no-cache");
     69         response.setDateHeader("Expires", 0);
     70 
     71         UploadStatus status = (UploadStatus) request.getSession(true)
     72                 .getAttribute("uploadStatus");
     73 
     74         if (status == null) {
     75             response.getWriter().println("没有上传信息");
     76             return;
     77         }
     78 
     79         long startTime = status.getStartTime();
     80         long currentTime = System.currentTimeMillis();
     81 
     82         // 已传输的时间 单位:s
     83         long time = (currentTime - startTime) / 1000 + 1;
     84 
     85         // 传输速度 单位:byte/s
     86         double velocity = ((double) status.getBytesRead()) / (double) time;
     87 
     88         // 估计总时间 单位:s
     89         double totalTime = status.getContentLength() / velocity;
     90 
     91         // 估计剩余时间 单位:s
     92         double timeLeft = totalTime - time;
     93 
     94         // 已完成的百分比
     95         int percent = (int) (100 * (double) status.getBytesRead() / (double) status
     96                 .getContentLength());
     97 
     98         // 已完成数 单位:M
     99         double length = ((double) status.getBytesRead()) / 1024 / 1024;
    100 
    101         // 总长度 单位:M
    102         double totalLength = ((double) status.getContentLength()) / 1024 / 1024;
    103 
    104         // 格式:百分比||已完成数(M)||文件总长度(M)||传输速率(K)||已用时间(s)||估计总时间(s)||估计剩余时间(s)||正在上传第几个文件
    105         String value = percent + "||" + length + "||" + totalLength + "||"
    106                 + velocity + "||" + time + "||" + totalTime + "||" + timeLeft
    107                 + "||" + status.getItems();
    108 
    109         response.getWriter().println(value);
    110     }
    111 
    112 }
    View Code

      前端代码:

      1 <%@ page language="java" contentType="text/html; charset=UTF-8"%>
      2 <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
      3 <html>
      4 <head>
      5 <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
      6 <title>Insert title here</title>
      7 <style type="text/css">
      8 body, td, div {font-size: 12px; font-familly: 宋体; }
      9 #progressBar {width: 400px; height: 12px; background: #FFFFFF; border: 1px solid #000000; padding: 1px; }
     10 #progressBarItem {width: 30%; height: 100%; background: #FF0000; }
     11 </style>
     12 </head>
     13 
     14 <body>
     15 
     16 <iframe name=upload_iframe width=0 height=0></iframe>
     17 
     18 <form action="servlet/ProgressUploadServlet" method="post" enctype="multipart/form-data" target="upload_iframe" onsubmit="showStatus(); ">
     19 
     20 <input type="file" name="file1" style=" 350px; "> <br />
     21 <input type="file" name="file2" style=" 350px; "> <br />
     22 <input type="file" name="file3" style=" 350px; "> <br />
     23 <input type="file" name="file4" style=" 350px; "> <input type="submit"
     24     value=" 开始上传 " id="btnSubmit"></form>
     25 
     26 <div id="status" style="display: none; ">
     27     上传进度条:
     28     <div id="progressBar"><div id="progressBarItem"></div></div>
     29     <div id="statusInfo"></div>
     30 </div>
     31 
     32 <br/>
     33 <br/>
     34 <br/>
     35 <br/>
     36 <br/>
     37 
     38 <script type="text/javascript">
     39 
     40 var _finished = true;
     41 
     42 function $(obj){
     43     return document.getElementById(obj);
     44 }
     45 
     46 function showStatus(){ //主函数
     47     _finished = false;
     48     $('status').style.display = 'block'; 
     49     $('progressBarItem').style.width = '1%'; 
     50     $('btnSubmit').disabled = true;
     51     
     52     setTimeout("requestStatus()", 1000); //每隔1000ms执行一次requestStatus()函数
     53 }
     54 
     55 function requestStatus(){
     56 
     57     if(_finished)    return;
     58     
     59     var req = createRequest(); //建立请求
     60     
     61     req.open("GET", "servlet/ProgressUploadServlet");
     62     req.onreadystatechange=function(){callback(req);}// Ajax得到响应进入callback(req)函数
     63     req.send(null);
     64     
     65     setTimeout("requestStatus()", 1000); 
     66 }
     67 
     68 function createRequest()
     69 {
     70     if(window.XMLHttpRequest)//ns
     71     {
     72         return new XMLHttpRequest();
     73     }else//IE
     74     {
     75         try{
     76             return new ActiveXObject("Msxml2.XMLHTTP");
     77         }catch(e){
     78             return new ActiveXObject("Microsoft.XMLHTTP");
     79         }
     80     }
     81     return null;
     82 }
     83 function callback(req){
     84 
     85     if(req.readyState == 4) {
     86         if(req.status != 200){
     87             _debug("发生错误。 req.status: " + req.status + "");
     88             return;
     89         }
     90         
     91         _debug("status.jsp 返回值:" + req.responseText);
     92         
     93         var ss = req.responseText.split("||");
     94             
     95         // 格式:百分比||已完成数(M)||文件总长度(M)||传输速率(K)||已用时间(s)||估计总时间(s)||估计剩余时间(s)||正在上传第几个文件
     96         $('progressBarItem').style.width = '' + ss[0] + '%'; 
     97         $('statusInfo').innerHTML = '已完成百分比: ' + ss[0] + '% <br />已完成数(M): ' + ss[1] + '<br/>文件总长度(M): ' + ss[2] + '<br/>传输速率(K): ' + ss[3] + '<br/>已用时间(s): ' + ss[4] + '<br/>估计总时间(s): ' + ss[5] + '<br/>估计剩余时间(s): ' + ss[6] + '<br/>正在上传第几个文件: ' + ss[7];
     98         
     99         if(ss[1] == ss[2]){
    100             _finished = true;
    101             $('statusInfo').innerHTML += "<br/><br/><br/>上传已完成。";     
    102             $('btnSubmit').disabled = false;
    103         }
    104     }
    105 }
    106 function _debug(obj){
    107     var div = document.createElement("DIV");
    108     div.innerHTML = "[debug]: " + obj;
    109     document.body.appendChild(div); 
    110 }
    111 
    112 </script>
    113 
    114 </body>
    115 </html
    View Code

      监听器代码:

     1 import org.apache.commons.fileupload.ProgressListener;
     2 
     3 public class UploadListener implements ProgressListener {
     4 
     5     private UploadStatus status;
     6 
     7     public UploadListener(UploadStatus status) {
     8         this.status = status;
     9     }
    10 
    11     public void update(long bytesRead, long contentLength, int items) {
    12         status.setBytesRead(bytesRead);
    13         status.setContentLength(contentLength);
    14         status.setItems(items);
    15     }
    16 }
    View Code

      状态类代码:

     1 public class UploadStatus {
     2 
     3     private long bytesRead;
     4 
     5     private long contentLength;
     6 
     7     private int items;
     8 
     9     private long startTime = System.currentTimeMillis();
    10 
    11     public long getBytesRead() {
    12         return bytesRead;
    13     }
    14 
    15     public void setBytesRead(long bytesRead) {
    16         this.bytesRead = bytesRead;
    17     }
    18 
    19     public long getContentLength() {
    20         return contentLength;
    21     }
    22 
    23     public void setContentLength(long contentLength) {
    24         this.contentLength = contentLength;
    25     }
    26 
    27     public int getItems() {
    28         return items;
    29     }
    30 
    31     public void setItems(int items) {
    32         this.items = items;
    33     }
    34 
    35     public long getStartTime() {
    36         return startTime;
    37     }
    38 
    39     public void setStartTime(long startTime) {
    40         this.startTime = startTime;
    41     }
    42 
    43 }
    View Code

    3.11 Servlet生命周期

     

     

    之前在web.xml中配置的参数需要每次都在doGet()doPost()中获取,效率较低。因此可以在servlet中写入init()函数,在函数中获取web.xml参数。这样,当用户第一次访问该servlet时,会获取初始化参数,而下一次访问servlet时便不再初始化参数,因此提高效率。

     

     

    3.12 Servlet直接的跳转(Forward)

      

    3.13 Servlet之间的跳转(重定向Redirect)

      

    3.14 Servlet之间的跳转(自动刷新Refresh)

      

    3.15 线程安全

      servlet不是线程安全的,因此谨慎使用类的变量,应尽量将变量定义在函数doGet()内部。

    联系方式:wuchaodzxx@126.com
  • 相关阅读:
    mac安装protobuf2.4.1时报错./include/gtest/internal/gtest-port.h:428:10: fatal error: 'tr1/tuple' file not found和google/protobuf/message.cc:175:16: error: implicit instantiation of undefined template
    java基础六 [异常处理](阅读Head First Java记录)
    安装和使用iOS的包管理工具CocoaPods
    Node.js的知识点框架整理
    java基础五 [数字与静态](阅读Head First Java记录)
    java基础四 [构造器和垃圾回收](阅读Head First Java记录)
    Appium学习路-安装篇
    Dell笔记本Ubuntu无线网卡驱动安装
    Ubuntu系统使用命令禁用触摸板等输入设备
    linux(ubuntu) 查看系统设备信息
  • 原文地址:https://www.cnblogs.com/wuchaodzxx/p/5515708.html
Copyright © 2011-2022 走看看