第三章 深入Servlet技术

3.1 配置Servlet

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

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                         }

  思路:

  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 }

  前端代码:

  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

  监听器代码:

 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 }

  状态类代码:

 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 }

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()内部。

时间: 2024-10-11 01:19:57

第三章 深入Servlet技术的相关文章

第三章 传统加密技术

1 对称加密模型 对称加密防范的五个基本成分: 明文:原始的消息或是数据,是算法的输入 加密算法:加密算法对明文进行各种代替和变化 密钥:加密算法的输入,密钥独立于明文和算法,算法根据所用的特定密钥产生不同的输出 密文:算法的输入 解密算法:是加密算法的逆运算.输入密文和密钥,输出原始明文. 传统密码的安全使用满足如下两个要求: 机密算法必须足够强:即使对方拥有一定数量的密文和产生这些秘文的明文,他也不能破译密文或是发现密钥 发送者和接受者必须在某种安全模式下获得密钥并且必须保护密钥的安全. 对

阅读《大型网站技术架构》 第三章心得

今天阅读了<大型网站技术架构> 的第三章,这一章主要讲解了大型网站核心架构要素,并且概括的讲解了相应的实现方法. 软件架构除了系统功能需求外,还需要关注性能.可用性.伸缩性.扩展性.安全性. 其中性能是网站的重要指标.优化网站性能的手段有很多种其中包括: 1.使用CD和反响代理加快反应速度. 2.在应用服务器端实现本地缓存和分布式缓存. 3.通过异步操作将用户的请求发送至消息队列等待后续任务处理,而当前请求直接返回响应给用户. 4.多台应用服务器组成集群. 5.代码层面使用多线程.改善内存管理

编译技术图式(第三章 词法分析)

编译技术图式(第三章 词法分析) 1.词法分析概述 2.词法分析器和语法分析器的关系 (1)词法分析作为单独的一遍 (2)词法分析作为子程序 3.词法分析器的输出 二元式 (单词类别<整数编码>,单词属性) 依赖于所对应的程序设计语言 关键字“一字一码” 标点符号“一字一码” 对标识符.常数.字符串等“一类一码” 丢弃其它不相关字符 (注释.空白符等) 4.词法分析器的实现 1)正则表达式:一种用来描述字符串集合的工具 2)字母表:一个有限的符号集合 集合{0, 1}是二进制字母表 3)字母表

构建之法前三章读后感

一. 软件作为一个产品,在提供用户使用前经历了许多工序,我们用工程的方式将开发软件的工序,过程加以工程化,系统化.成立了一套完整的体系后,有利于帮助我们开发软件,乃至于大型的系统. 软件具有一定的特殊性,使得软件工程师们做开发提升了一定的难度,但软件工程有助于软件系统的开发,帮助工程师们设计,构建,测试和维护软件.所以,软件工程的最终目的是帮助工程师们创造“足够好”的软件,提高软件的质量,用户满意度,可靠性,可维护性等. 第一章问题:怎么才算是一个真正的软件工程师? 二.   一个优秀的软件,通

0320 《构建之法》前三章观后感

第一章.为我们解释什么是软件,什么是软件工程,读完这章对这些概念有一定的认识这章让我明白,代码不能盲目的敲,好的软件并非两三天,并非一两个人就能赶出来的,需要大家的精诚合作.同时,在编写程序之前,还需要做一系列的分析.设计,要满足客户的需求,后续还要对软件进行测试.维护等.在这之前,我一直觉得能把程序运行,能有正确的结果,那就完成任务了,可这只是整个软件流程的一部分而已.看了邹老师的书,才知道其实创新有很多的方面,除了技术,还有商业思路,差异化等等,这些都给了我很大的感触,作为一名程序员,我们不

2017.06.29数据挖掘基础概念第二.三章

第二章21.研究的属性类型标称属性:值是一些符号或事物的名称,代表某种类型.编码或状态二元属性:是一种标称属性,只有两个类别或状态,又称布尔属性序数属性:是一种属性,其可能的值之间具有有意义的序或秩评定,但是相续值之间的差是未知的数值属性:是定量的,即他是可度量的量,可用整数或实数值表示(区间和比率标度)22.数据散布常见的度量量(数据如何分散的方法/识别离群点)极差 四分位数.四分位数极差.五数概括图.方差和标准差23.审视数据的图形条形.饼图.线图.分位数图.分位数-分位数图.直方图和散点图

操作系统思考 第三章 虚拟内存

第三章 虚拟内存 作者:Allen B. Downey 原文:Chapter 3 Virtual memory 译者:飞龙 协议:CC BY-NC-SA 4.0 3.1 简明信息理论 比特是二进制的数字,也是信息的单位.一个比特有两种可能的情况,写为0或者1.如果是两个比特,那就有四种可能的组合,00.01.10和11.通常,如果你有b个比特,你就可以表示2 ** b个值之一.一个字节是8个比特,所以它可以储存256个值之一. 从其它方面来讲,假设你想要储存字母表中的字母.字母共有26个,所以你

linux及安全《Linux内核设计与实现》第三章——20135227黄晓妍

第三章 (由于linux不区分进程和线程,所以它们在linux中被称为task,也叫任务) 总结:本章主要包括进程以及线程的概念和定义,Linux内核如何管理每个进程,他们在内核中如何被列举,如何创建,最终如何消亡.操作系统存在的意义在于运行用户程序,进程管理是所有操作系统的心脏所在. 3.1进程 进程是处于执行期的程序,是正在执行的程序代码的实时结果.但不仅局限于一段可执行的代码,还包括其他资源(打开的文件,挂起的信号,内核内部数据,处理器的状态,一个或者多个内存映射的内存地址空间,一个或者多

《构建之法》第一、二、三章读后感

第一章系统地告诉了我们什么是软件,也就是软件=程序+软件工程,软件工程是怎样的一个存在,包括软件的种类和性质,都系统地分析给我们,更是强调了一个工程团队对软件工程的重要性,同时也给我们指出了某些软件会出现的问题,比如说会有BUG,给我们介绍了当遇到这些问题的时候需要怎样去解决问题和修正BUG,完成客户给我们的要求.总的来说,第一章就是带我们走进了软件工程的线索. 第二章叫做个人技术和流程,在这一章中我看到了程序执行过程中耗时最多的三个函数,三个函数加起来占用了整个程序的84%的时间,并给我们分析