第三章 深入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="width: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="width: 350px; "> <br />
 21 <input type="file" name="file2" style="width: 350px; "> <br />
 22 <input type="file" name="file3" style="width: 350px; "> <br />
 23 <input type="file" name="file4" style="width: 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()内部。

posted @ 2016-05-21 21:58  且听风吟-wuchao  阅读(268)  评论(0编辑  收藏  举报