提交表单信息

  Web程序的任务是实现服务器与客户端浏览器之间的信息交互。客户端提交的信息可能来自表单里的文本框,密码框,选择框,单选按钮,复选框以及文件域。这些表单信息被以参数形式提交到了服务器。Servlet的任务就是正确地获取这些信息,并根据信息做出不同的响应。

  提交信息的方式包括GET与POST,分别触发Servlet的doGet方法与doPost方法,一般而言,就像当初HHTP协议所设计的那样,GET用于从服务器获取信息(通过提交的参数指定要获取什么样的信息),而POST用于向服务器提交信息。POST方式提交数据又包括两种形式,即普通POST提交方式与可以上传文件的POST提交方式。

  GET实现搜索引擎

  HTML中使用FORM提交数据,当FORM的method属性设为GET时浏览器就以GET的方式提交表单数据。FORM的action属性设置数据将提交到哪个URL。

  以GET方式提交数据时,浏览器把表单内容组织成一个查询字符串(Query String),各变量之间以“&"链接,然后以Servlet路径加问号"?"加查询字符串的形式获取服务器内容。

  例如,要向某个Servlet(网址为http://servername/someServlet)提交两个参数a与b,a参数的值为aValue,b参数的值为bValue,则组织后的URL为http://servername/someServlet?a=aValue&b=bValue,Servlet中HttpServletRequest对象通过方法getParameter("a")可以获取到aValue,getParameter("b")获取到bValue,getQueryString()获取到字符串"a=aValue&b=bValue"(必要的时候要先使用setCharacterEncoding(encoding)设置实际编码方式)。GET方式提交表单内容时所有被提交的内容都将显示在浏览器地址栏中。

  不经过FORM提交数据而直接以输入网址,或者单击链接的方式访问Servlet也被看做是GET方式提交数据。

  GET方式提交表单的典型应用是搜索引擎。GET方式就是被设计为查询用的。下面使用GET方式制作一个搜索引擎。先新建一个简单的主界面search.html。

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>search.html</title>
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
<style>div, body, span {font-size:14px; }</style>
</head><body>
<div align="center"><img src="data:images/yahoo.gif" style='margin:25px; '><div><form action='/servlet/servlet/SearchServlet' method='get'><input type="radio" name="type" value="web" checked>网页 <input type="radio" name="type" value="news">新闻 <input type="radio" name="type" value="image">图片 <input type="radio" name="type" value="video">视频 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<input type="checkbox" name="allowedAdult" value="true">允许成人内容 <br/><br/><input type="text" name="word" value="" style="width:300px; "> <input type="submit" value="用雅虎搜索" style="width:100px; "></form></div><div style="margin-top:50px; ">&copy; Helloween 2007-2010</div>
</div></body>
</html>

  这是一个静态的HTML文本文件,它的内容不会随Request的不同而发生改变。该HTML文件的布局使用了标签<div>而没有使用<table>等。这是因为<div>要比<table>灵活的多。当<div>连同css样式表与JavaScript脚本语言或者Ajax一块儿使用时,<div>具有非常丰富的表现性。现在的Web 2.0站点都采用<div>标签来展示网页内容。

  该HTML页面效果如图3.9所示。页面内包含一个<form>表单,单击查询后,将以GET方式访问<form>的action属性指定的Servlet。

  然后写一个SearchServlet类来实现关键的业务逻辑部分:搜索引擎程序。这里使用Yahoo Search API来调用Yahoo搜索引擎数据库里的数据,读者需要到Yahoo下载API包,网址为http://developer.yahoo.com/search。也可以从随书光盘中找到yahoo_search-2.0.1.jar,将jar包加入到项目的libraries中,即/WEB-INF/lib/下(没有请新建)。使用向导新建SearchServlet,部分代码如下:

package com.helloweenvsfei.servlet;import java.io.IOException;
import java.io.PrintWriter;
import java.math.BigInteger;
import java.net.URLEncoder;import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;import com.yahoo.search.ImageSearchRequest;
import com.yahoo.search.ImageSearchResult;
import com.yahoo.search.ImageSearchResults;
import com.yahoo.search.NewsSearchRequest;
import com.yahoo.search.NewsSearchResult;
import com.yahoo.search.NewsSearchResults;
import com.yahoo.search.SearchClient;
import com.yahoo.search.VideoSearchRequest;
import com.yahoo.search.VideoSearchResult;
import com.yahoo.search.VideoSearchResults;
import com.yahoo.search.WebSearchRequest;
import com.yahoo.search.WebSearchResult;
import com.yahoo.search.WebSearchResults;public class SearchServlet extends HttpServlet {private static final long serialVersionUID = -1249623428210967632L;public void doGet(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {response.setCharacterEncoding("UTF-8");request.setCharacterEncoding("UTF-8");// 搜索关键字String word = request.getParameter("word");// 搜索类型String type = request.getParameter("type");// 是否允许成人内容。如果选中,则为 "true",否则为 null.String allowedAdult = request.getParameter("allowedAdult");boolean adultOk = "true".equals(allowedAdult);response.setContentType("text/html");PrintWriter out = response.getWriter();out.println("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\">");out.println("<HTML>");out.println("  <HEAD><TITLE>" + word + " 搜索结果</TITLE></HEAD>");out.println("<style>");out.println("    body, div {font-size:12px; padding:2px; margin:0px; }");out.println("    .imgDiv{float:left; width: 172px; height:250px;  margin:2px; padding:2px; border:1px pink solid; overflow:hidden; }");out.println("</style>");out.println("  <BODY>");out.println("<div style='float:left; height:40px; '><img src='../images/yahoo.gif'></div>");out.println("<form action='" + request.getRequestURI() + "' method='get'>");out.println("    <div style='height:40px; '>");out.println("        <input type='radio' name='type' value='web' " + (type.equals("web")?"checked":"") + ">网页");out.println("        <input type='radio' name='type' value='news' " + (type.equals("news")?"checked":"") + ">新闻");out.println("        <input type='radio' name='type' value='image' " + (type.equals("image")?"checked":"") + ">图像");out.println("        <input type='radio' name='type' value='video' " + (type.equals("video")?"checked":"") + ">视频");out.println("        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;");out.println("        <input type='checkbox' name='allowedAdult' value='true' " + (adultOk?"checked":"") + ">允许成人内容 <br/>");out.println("        <input type='text' name='word' value='" + word + "' style='width:300px; '> <input type='submit' value='用雅虎搜索' style='width:100px; '>");out.println("    </div>");out.println("</form>");SearchClient client = new SearchClient("javasdktest");try{if("image".equals(type)){ImageSearchRequest searchRequest = new ImageSearchRequest(URLEncoder.encode(word, "UTF-8"));// 是否显示成人内容
                searchRequest.setAdultOk(adultOk);// 查询记录数searchRequest.setResults(20);// 从第 0 条记录开始显示searchRequest.setStart(BigInteger.valueOf(0));double startTime = System.currentTimeMillis();ImageSearchResults results = client.imageSearch(searchRequest);double endTime = System.currentTimeMillis();out.println("<div align=right style='width:100%; background: #FFDDDD; height:25px; padding:2px; border-top:1px solid #FF9999; margin-bottom:5px; '>");out.println("    总共 " + results.getTotalResultsAvailable() + " 条数据,总用时 " + ( endTime - startTime )/1000 + " 秒。");out.println("</div>");for(ImageSearchResult result : results.listResults()){out.println("<div class='imgDiv'>");out.println("    <div align='center'><a href=\"" + result.getClickUrl() + "\" target=_blank><img width=160 height=120 src=\"" + result.getThumbnail().getUrl() + "\" border='0'></a></div>");out.println("    <div align='center'><a href=\"" + result.getRefererUrl() + "\" target=_blank>" + result.getTitle() + "</a></div>");out.println("    <div align='center'>" + result.getWidth() + "x" + result.getHeight() + " " + result.getFileFormat() + "</div>");out.println("    <div>" + (result.getSummary()==null ? "" : result.getSummary()) + "</div>");out.println("</div>");}}else if("web".equals(type)){WebSearchRequest searchRequest = new WebSearchRequest(URLEncoder.encode(word, "UTF-8"));// 是否显示成人内容
                searchRequest.setAdultOk(adultOk);// 查询记录数searchRequest.setResults(20);// 从第 0 条记录开始显示searchRequest.setStart(BigInteger.valueOf(0));double startTime = System.currentTimeMillis();WebSearchResults results = client.webSearch(searchRequest);double endTime = System.currentTimeMillis();out.println("<div align=right style='width:100%; background: #FFDDDD; height:25px; padding:2px; border-top:1px solid #FF9999; margin-bottom:5px; '>");out.println("    总共 " + results.getTotalResultsAvailable() + " 条数据,总用时 " + ( endTime - startTime )/1000 + " 秒。");out.println("</div>");for(WebSearchResult result : results.listResults()){out.println("<div style='margin:8px; width:500px; '>");out.println("    <div><a href=\"" + result.getClickUrl() + "\" target=_blank><b>" + result.getTitle() + "</b></a> 文件格式:" + result.getMimeType() + "</div>");out.println("    <div>网址:<a href=\"" + result.getUrl() + "\" target=_blank>" + result.getUrl() + "</a></div>");out.println("    <div>" + result.getSummary() + (result.getCache()==null ? "" : " [<a href=\"" + result.getCache().getUrl() + "\" target=_blank>网页快照</a>]") +"</div>");out.println("</div>");}}else if("news".equals(type)){NewsSearchRequest searchRequest = new NewsSearchRequest(URLEncoder.encode(word, "UTF-8"));// 是否显示成人内容
//                searchRequest.setAdultOk(adultOk);// 查询记录数searchRequest.setResults(20);// 从第 0 条记录开始显示searchRequest.setStart(BigInteger.valueOf(0));double startTime = System.currentTimeMillis();NewsSearchResults results = client.newsSearch(searchRequest);double endTime = System.currentTimeMillis();out.println("<div align=right style='width:100%; background: #FFDDDD; height:25px; padding:2px; border-top:1px solid #FF9999; margin-bottom:5px; '>");out.println("    总共 " + results.getTotalResultsAvailable() + " 条数据,总用时 " + ( endTime - startTime )/1000 + " 秒。");out.println("</div>");for(NewsSearchResult result : results.listResults()){out.println("<div style='margin:8px; width:500px; '>");out.println("    <div><a href=\"" + result.getClickUrl() + "\" target=_blank><b>" + result.getTitle() + "</b></a></div>");out.println("    <div>网址:<a href=\"" + result.getUrl() + "\" target=_blank>" + result.getUrl() + "</a></div>");out.println("    <div>" + result.getSummary() + "</div>");out.println("</div>");}}else if("video".equals(type)){VideoSearchRequest searchRequest = new VideoSearchRequest(URLEncoder.encode(word, "UTF-8"));// 是否显示成人内容
                searchRequest.setAdultOk(adultOk);// 查询记录数searchRequest.setResults(20);// 从第 0 条记录开始显示searchRequest.setStart(BigInteger.valueOf(0));double startTime = System.currentTimeMillis();VideoSearchResults results = client.videoSearch(searchRequest);double endTime = System.currentTimeMillis();out.println("<div align=right style='width:100%; background: #FFDDDD; height:25px; padding:2px; border-top:1px solid #FF9999; margin-bottom:5px; '>");out.println("    总共 " + results.getTotalResultsAvailable() + " 条数据,总用时 " + ( endTime - startTime )/1000 + " 秒。");out.println("</div>");for(VideoSearchResult result : results.listResults()){out.println("<div class='imgDiv'>");out.println("    <div align='center'><a href=\"" + result.getClickUrl() + "\" target=_blank><img width=160 height=120 src=\"" + result.getThumbnail().getUrl() + "\" border='0'></a></div>");out.println("    <div align='center'><a href=\"" + result.getRefererUrl() + "\" target=_blank>" + result.getTitle() + "</a></div>");out.println("    <div align='center'>" + result.getWidth() + "x" + result.getHeight() + " " + result.getFileFormat() + "</div>");out.println("    <div>" + (result.getSummary()==null ? "" : result.getSummary()) + "</div>");out.println("</div>");}}}catch(Exception e){e.printStackTrace();out.println("<font color=red>Exception: " + e.getMessage() + "</font>");}out.println("  </BODY>");out.println("</HTML>");out.flush();out.close();}}

  为节省篇幅,代码中只列出了图片搜索的相关代码,完整代码请参看随书光盘。用该搜索引擎搜索图像时会显示图像的缩略图、文件名称、原始图像大小、图像格式,以及图像文字描述等内容。使用该搜索引擎程序搜索图片titanic,效果如下:

  留意一下地址栏,使用GET方式提交数据时所有被提交的信息都显示在了地址栏中。由于没有自己的数据库,因此SearchServlet使用了Yahoo的API。Yahoo Search API提供了搜索网页、新闻、图片、视频的程序接口,只需要寥寥几句话就可以完成搜索过程。Yahoo Search API的工作原理通过访问Yahoo的Web Service来获取搜索数据。本书后面的章节中还会讲到怎么构建自己的Web Service。读者可以自行验证一下,该搜索引擎的搜索结果与Yahoo搜索引擎(http://www.yahoo.com)的搜索结果完全一致。

  另外,要想在该搜索引擎中搜索中文,需要修改TOMCAT目录下的/conf/server.xml里设定的默认的GET编设方式,否则会出现乱码。下面为server.xml中需要修改的部分。粗体部分为添加的代码。如果不指定UTF-8方式编码,TOMCAT将使用ISO-8859-1编码。

<Connector port="8080" protocol="HTTP/1.1"connectionTimeout="20000"redirectPort="8443" URIEncoding="UTF-8" />

  GET方式提交表单时,所有被提交的内容都会被显示在浏览器地址栏中,并可能会被浏览器记录在缓存里,因此提交敏感信息(如密码、银行账号等)时不能使用GET方式。GET提交时URL总长度不同浏览器有不同的限制,因此提交过长的内容时也不能使用GET方式。

  POST提交个人信息

  由于GET方式提交表单具有上述的限制,因此需要使用POST提交表单。把HTML中FORM的method属性设置为POST,浏览器即以POST方式提交表单内容。

  POST方式提交表单时,表单的内容不会显示在浏览器中,浏览器中只显示接受该表单数据的Servlet路径,因此POST可以提交一些敏感信息(如密码等)。POST方式提交表单时也不受内容长度的限制,理论上可以接受非常大的数据量。

  同GET方式一样,Servlet可以通过HttpServletRequest对象的getParameter(String param)方法获取param对应的参数值。不同的是,由于POST方式不会使用"?"以及"&“符号来组织一个QueryString,因此POST时使用getQueryString()将返回null。

  下面使用POST方式来提交一个用户信息表单。使用向导在项目servlet的WebRoot文件夹下新建HTML文件,取名postPersonInformation.html。

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>提交用户信息</title>
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
<style>
body, div, td, input {font-size:12px; margin:0px; }
select {height:20px; width:300px; }
.title {font-size: 16px; padding: 10px; margin:10px; width:80%; }
.text {height:20px; width:300px; border:1px solid #AAAAAA; }
.line {margin:2px; }
.leftDiv {width:110px; float:left; height:22px; line-height:22px; font-weight:bold; }
.rightDiv {height:22px; }
.button {color:#fff;font-weight:bold;font-size: 11px; text-align:center;padding:.17em 0 .2em .17em;border-style:solid;border-width:1px;border-color:#9cf #159 #159 #9cf;background:#69c url(images/bg-btn-blue.gif) repeat-x;
}
</style>
</head>
<body>
<form action="/servlet/servlet/PostServlet" method="POST">
<div align="center"><br/><fieldset style='width:90%'><legend>填写用户信息</legend><br/><div class='line'><div align="left" class='leftDiv'>请填写您的姓名:</div><div align="left" class='rightDiv'><input type="text" name="name" class="text" /></div></div><div class='line'><div align="left" class='leftDiv'>请填写您的密码:</div><div align="left" class='rightDiv'><input type="password" name="password" class="text" /></div></div><div class='line'><div align="left" class='leftDiv'>请再次输入密码:</div><div align="left" class='rightDiv'><input type="password" name="passwordConfirm" class="text" /></div></div><div class='line'><div align="left" class='leftDiv'>请选择性别:</div><div align="left" class='rightDiv'><input type="radio" name="sex" value="男" id="sexMale"><label for="sexMale">男</label><input type="radio" name="sex" value="女" id="sexFemale"><label for="sexFemale">女</label></div></div><div class='line'><div align="left" class='leftDiv'>请输入年龄:</div><div align="left" class='rightDiv'><input type="text" name="age" class="text"></div></div><div class='line'><div align="left" class='leftDiv'>请输入生日:</div><div align="left" class='rightDiv'><input type="text" name="birthday" class="text"> <br/>格式:"yyyy-mm-dd"</div></div><div class='line'><div align="left" class='leftDiv'>请选择您的爱好</div><div align="left" class='rightDiv'><input type="checkbox" name="interesting" value="音乐影视" id="i1"><label for="i1">音乐影视</label> <input type="checkbox" name="interesting" value="外出旅游" id="i2"><label for="i2">外出旅游</label> <input type="checkbox" name="interesting" value="社交活动" id="i3"><label for="i3">社交活动</label> </div></div><div class='line'><div align="left" class='leftDiv'>请选择省市:</div><div align="left" class='rightDiv'><select name="area"><option>---请选择省份---</option><optgroup label="北京市"><option value="北京市海淀区">海淀区</option><option value="北京市朝阳区">朝阳区</option><option value="北京市东城区">东城区</option><option value="北京市西城区">西城区</option></optgroup><optgroup label="山东省"><option value="山东省济南市">济南市</option><option value="山东省青岛市">青岛市</option><option value="山东省潍坊市">潍坊市</option></optgroup></select></div></div><div class='line'><div align="left" class='leftDiv'>自我描述:</div><div align="left" class='rightDiv'><textarea name="description" rows="8" style="width:300px; ">请填写其他资料... </textarea></div></div><div class='line'><div align="left" class='leftDiv'></div><div align="left" class='rightDiv'><br/><input type="submit" name="btn" value=" 提交信息 " class="button"><br/></div></div></fieldset>
</div>
</form>
</body>
</html>

  该页面内使用了文本框text,密码框password,单选按钮radio,复选框checkbox,选择框select,文本域textarea等。这些HTML组件的值都可以提交给Servlet。如果同一个名称的参数有多个值(例如页面内兴趣爱好最多可以有三个值),则以字符串数组的形式提交给Servlet,Servlet可以通过HttpServletRequest的getPrarameters(String param)取得这个字符串数组。

  下面编写一个Servlet来接收HTML页面提交的信息。使用向导新建PostServlet

package com.helloweenvsfei.servlet;import java.io.IOException;
import java.io.PrintWriter;import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;public class LifeCycleServlet extends HttpServlet {private static final long serialVersionUID = -7197419401412129310L;private static double startPoint = 0;@Overridepublic void init() throws ServletException {this.log("执行 init() 方法 ... ");ServletConfig conf = this.getServletConfig();startPoint = Double.parseDouble(conf.getInitParameter("startPoint"));}@Overrideprotected void service(HttpServletRequest arg0, HttpServletResponse arg1) throws ServletException, IOException {this.log("执行 service() 方法 ... ");super.service(arg0, arg1);}@Overridepublic void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {this.log("执行 doPost() 方法 ... ");response.setCharacterEncoding("UTF-8");response.setContentType("text/html");PrintWriter out = response.getWriter();out.println("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\">");out.println("<HTML><HEAD><TITLE>个人所得税计算</TITLE></HEAD>");out.println("<link rel='stylesheet' type='text/css' href='../css/style.css'>");out.println("<BODY>");out.println("<div align='center'><br/><fieldset style=width:90%><legend>个税计算器</legend><br/>");try{// 从参数中获取的工资数目double income = new Double(request.getParameter("income"));// 应纳税部分double charge = income - startPoint;// 缴税double tax = 0;if (charge<=0) {tax=0;}if (charge>0&&charge<=500) {tax=charge*0.05;}if (charge>500&&charge<=2000) {tax=charge*0.1-25;}if (charge>2000&&charge<=5000) {tax=charge*0.15-125;}if (charge>5000&&charge<=20000) {tax=charge*0.2-375;}if (charge>20000&&charge<=40000) {tax=charge*0.25-1375;}if (charge>40000&&charge<=60000) {tax=charge*0.30-3375;}if (charge>60000&&charge<=80000) {tax=charge*0.35-6375;}if (charge>80000&&charge<=100000) {tax=charge*0.4-10375;}if (charge>100000) {tax=charge*0.45-15375;}out.println("<div style='line'>");out.println("    <div class='leftDiv'>您的工资为</div><div class='rightDiv'>" + income + " 元</div>");out.println("</div>");out.println("<div style='line'>");out.println("    <div class='leftDiv'>您应纳税</div><div class='rightDiv'>" + tax + " 元</div>");out.println("</div><br/>");out.println("<input type='button' οnclick='history.go(-1);' value='纳税光荣 逃税可耻 返回'  class=button>");}catch(Exception e){out.println("请输入数值类型数据。<input type='button' οnclick='history.go(-1);' value='返回'  class=button>");}out.println("</BODY>");out.println("</HTML>");out.flush();out.close();}@Overridepublic void doGet(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {this.log("执行 doGet() 方法 ... ");response.setCharacterEncoding("UTF-8");response.setContentType("text/html");PrintWriter out = response.getWriter();out.println("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\">");out.println("<link rel='stylesheet' type='text/css' href='../css/style.css'>");out.println("<HTML><HEAD><TITLE>个人所得税计算</TITLE></HEAD>");out.println("<div align='center'><br/><fieldset style=width:90%><legend>个税计算器</legend><br/>");out.println("<form method='post' action='LifeCycleServlet'>");out.println("<div style='line'>");out.println("    <div class='leftDiv'>您的工资为</div><div align='left' class='rightDiv'><input type='text' name='income'> 单位:元</div>");out.println("</div><br/>");out.println("<div style='line'>");out.println("    <div class='leftDiv'></div><div align='left' class='rightDiv'><input type='submit' value='  计算个税  ' class=button></div>");out.println("</div>");out.println("</form>");out.println("<BODY>");out.println("</BODY>");out.println("</HTML>");out.flush();out.close();}@Overridepublic void destroy() {this.log("执行 destroy() 方法 ... ");startPoint = 0;}}

  程序运行效果如下:

  可以看到以POST方式提交数据的时候,浏览器地址栏中不显示被提交的内容,提交的数据量也要大于GET。POST就是设计为提交数据的。

  当提交的数据长度大于256个字符,或者要提交文件时,只能选择POST方式。

  上传文件客户端

  除了提交表单,上传文件也是很常见的客户端与Web程序交互的操作。电子相册,网络硬盘,邮件附件,视频网站等都是采用Web文件上传的形式。相对于FTP文件上传,Web文件上传速度要慢一些,但是使用方便,不需要客户端,仅有一个浏览器就可以,而且权限也比FTP容易控制。

  Web文件上传也是采用POST的方式。与前面讲的POST提交表单不同的是,上传文件需要设置FORM的enctype属性为multipart/form-data。由于上传的文件会比较大,因此需要设置该参数指定浏览器使用二进制上传。如果不设置,enctype属性默认为application/x-www-form-urlencoded,浏览器将使用ASCII向服务器发送数据,导致发送文件失败。

  上传文件要使用文件域(<input type="file"/>),并把FORM的Enctype设置为multipart/form-data,例如:

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>上传文件</title>
<meta http-equiv="keywords" content="keyword1,keyword2,keyword3">
<meta http-equiv="description" content="this is my page">
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
<link rel="stylesheet" type="text/css" href="css/style.css">
</head><body>
<form action="servlet/UploadServlet" method="post" enctype="multipart/form-data">
<div align="center"><br/><fieldset style="width:90%"><legend>上传文件</legend><br/><div class='line'><div align='left' class="leftDiv">上传文件一</div><div align='left' class="rightDiv"><input type="file" name="file1" class="text"></div></div><div class='line'><div align='left' class="leftDiv">上传文件二</div><div align='left' class="rightDiv"><input type="file" name="file2" class="text"></div></div><div class='line'><div align='left' class="leftDiv">上传文件说明一</div><div align='left' class="rightDiv"><input type="text" name="description1" class="text"></div></div><div class='line'><div align='left' class="leftDiv">上传文件说明二</div><div align='left' class="rightDiv"><input type="text" name="description2" class="text"></div></div><div class='line'><div align='left' class="leftDiv"></div><div align='left' class="rightDiv"><br/><input type="submit" value="  上传文件  " class="button"></div></div></fieldset>
</div>
</form>
</body>
</html>

  上传文件服务器端

  客户端运行的代码很简单,服务器要复杂一些。由于上传文件时浏览器是以二进制的方式发送数据,因此Servlet里不能简单地通过HttpServletRequest的getParameter()方法来获取文件域以及文本域的内容。要想获取其中的内容,必须根据HTTP协议所规定的格式解析浏览器提交的Request。

  解析二进制数据流比较麻烦。已经有许多类库已经完成了这项工作,例如SmartUpload与Apache Commons Fileupload。SmartUpload是一个商业类库,解析Request过程中数据存放在内存里,因此速度较快,但上传大文件时会发生内存溢出。Apache Commons Fileupload是一个免费的开源类库。一些框架比如Struts里集成 Apache Commons Fileupload类库来实现文件上传。

  Commons Fileupload是Apache commons众多开源组件中的一员。从Apache网站(http://www.apache.org)或者随书光盘中找到Apache Commons Upload类库,并将commons-fileupload.jar加入到项目的libraries中即/WEB-INF/lib/下,新建UploadServlet,代码如下:

package com.helloweenvsfei.servlet;import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.URLEncoder;
import java.util.List;import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;import org.apache.commons.fileupload.DiskFileUpload;
import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.FileUploadException;public class UploadServlet extends HttpServlet {private static final long serialVersionUID = 7523024737218332088L;public void doGet(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {response.setCharacterEncoding("UTF-8");response.getWriter().println("请以 POST 方式上传文件");}@SuppressWarnings("unchecked")public void doPost(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {File file1 = null, file2 = null;String description1 = null, description2 = null;response.setCharacterEncoding("UTF-8");response.setContentType("text/html");PrintWriter out = response.getWriter();out.println("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\">");out.println("<HTML>");out.println("  <HEAD><TITLE>A Servlet</TITLE></HEAD>");out.println("  <link rel='stylesheet' type='text/css' href='../css/style.css'>");out.println("  <BODY>");out.println("<div align=center><br/>");out.println("<fieldset style='width:90%'><legend>上传文件</legend><br/>");out.println("        <div class='line'>");out.println("            <div align='left' class='leftDiv'>上传日志:</div>");out.println("            <div align='left' class='rightDiv'>");// 使用 DiskFileUpload 对象解析 requestDiskFileUpload diskFileUpload = new DiskFileUpload();try {// 将 解析的结果 放置在 List 中List<FileItem> list = diskFileUpload.parseRequest(request);out.println("遍历所有的 FileItem ... <br/>");// 遍历 list 中所有的 FileItemfor(FileItem fileItem : list){if(fileItem.isFormField()){// 如果是 文本域if("description1".equals(fileItem.getFieldName())){// 如果该 FileItem 名称为 description1out.println("遍历到 description1 ... <br/>");description1 = new String(fileItem.getString().getBytes(), "UTF-8");}if("description2".equals(fileItem.getFieldName())){// 如果该 FileItem 名称为 description2out.println("遍历到 description2 ... <br/>");description2 = new String(fileItem.getString().getBytes(), "UTF-8");}}else{// 否则,为文件域if("file1".equals(fileItem.getFieldName())){// 客户端文件路径构建的 File 对象File remoteFile = new File(new String(fileItem.getName().getBytes(), "UTF-8"));out.println("遍历到 file1 ... <br/>");out.println("客户端文件位置: " + remoteFile.getAbsolutePath() + "<br/>");// 服务器端文件,放在 upload 文件夹下file1 = new File(this.getServletContext().getRealPath("attachment"), remoteFile.getName());file1.getParentFile().mkdirs();file1.createNewFile();// 写文件,将 FileItem 的文件内容写到文件中InputStream ins = fileItem.getInputStream();OutputStream ous = new FileOutputStream(file1);try{byte[] buffer = new byte[1024]; int len = 0;while((len=ins.read(buffer)) > -1)ous.write(buffer, 0, len);out.println("已保存文件" + file1.getAbsolutePath() + "<br/>");}finally{ous.close();ins.close();}}if("file2".equals(fileItem.getFieldName())){// 客户端文件路径构建的 File 对象File remoteFile = new File(new String(fileItem.getName().getBytes(), "UTF-8"));out.println("遍历到 file2 ... <br/>");out.println("客户端文件位置: " + remoteFile.getAbsolutePath() + "<br/>");// 服务器端文件,放在 upload 文件夹下file2 = new File(this.getServletContext().getRealPath("attachment"), remoteFile.getName());file2.getParentFile().mkdirs();file2.createNewFile();// 写文件,将 FileItem 的文件内容写到文件中InputStream ins = fileItem.getInputStream();OutputStream ous = new FileOutputStream(file2);try{byte[] buffer = new byte[1024]; int len = 0;while((len=ins.read(buffer)) > -1)ous.write(buffer, 0, len);out.println("已保存文件" + file2.getAbsolutePath() + "<br/>");}finally{ous.close();ins.close();}}}}out.println("Request 解析完毕");} catch (FileUploadException e) {// TODO Auto-generated catch block
            e.printStackTrace();}out.println("            </div>");out.println("        </div>");if(file1 != null){out.println("        <div class='line'>");out.println("            <div align='left' class='leftDiv'>file1:</div>");out.println("            <div align='left' class='rightDiv'>");out.println("                <a href='" + request.getContextPath() + "/attachment/" + file1.getName() + "' target=_blank>" + file1.getName() +  "</a>"    );out.println("            </div>");out.println("        </div>");}if(file2 != null){out.println("        <div class='line'>");out.println("            <div align='left' class='leftDiv'>file2:</div>");out.println("            <div align='left' class='rightDiv'>");out.println("                <a href='" + request.getContextPath() + "/attachment/" + URLEncoder.encode(file2.getName(), "UTF-8") + "' target=_blank>" + file2.getName() +  "</a>"    );out.println("            </div>");out.println("        </div>");}out.println("        <div class='line'>");out.println("            <div align='left' class='leftDiv'>description1:</div>");out.println("            <div align='left' class='rightDiv'>");out.println(description1);out.println("            </div>");out.println("        </div>");out.println("        <div class='line'>");out.println("            <div align='left' class='leftDiv'>description2:</div>");out.println("            <div align='left' class='rightDiv'>");out.println(description2);out.println("            </div>");out.println("        </div>");out.println("</fieldset></div>");out.println("  </BODY>");out.println("</HTML>");out.flush();out.close();}}

  UploadServlet中将上传过程日志打印在页面上。上传成功后显示上传文件的链接地址,可以直接在浏览器中打开查看上传后的文件效果。程序运行效果如下:

  上传文件时数据将以二进制形式提交,而非ASCII方式提交,因此Servlet不能用request.getParameter()等方式获取提交的文本内容。本例使用Commons-upload解析二进制数据,获取上传的文本内容。

转载于:https://www.cnblogs.com/liunianfeiyu/p/10657612.html

Servlet学习记录3相关推荐

  1. Servlet学习记录

    目录 目录 前言 什么是Servlet Servlet生命周期 Servlet工作原理 Servlet的类层次结构 实现Servlet的三种方式 1) 实现Servlet接口 2) 继承Generic ...

  2. Android 学习记录(持续更新)

    Android 学习记录(持续更新) 1.AndroidManifest.xml 详解: http://www.jb51.net/article/73731.htm (AndroidManifest. ...

  3. Android 开发学习记录(4)---- httpclient使用(三)

    之前在Android 开发学习记录(3)---- httpclient使用(二)中介绍了如何使用httpclient访问需要账户登录的网址,当然首先是要有一个合法的登录账户. 但是现在好多网站在登录时 ...

  4. 基于Android的学生学习记录与提醒管理系统

    末尾获取源码 开发语言:Java Java开发工具:JDK1.8 后端框架:SSM 前端:采用Vue技术开发 数据库:MySQL5.7和Navicat管理工具结合 服务器:Tomcat8.5 开发软件 ...

  5. Pytorch学习记录-torchtext和Pytorch的实例( 使用神经网络训练Seq2Seq代码)

    Pytorch学习记录-torchtext和Pytorch的实例1 0. PyTorch Seq2Seq项目介绍 1. 使用神经网络训练Seq2Seq 1.1 简介,对论文中公式的解读 1.2 数据预 ...

  6. HTML5与CSS3权威指南之CSS3学习记录

    title: HTML5与CSS3权威指南之CSS3学习记录 toc: true date: 2018-10-14 00:06:09 学习资料--<HTML5与CSS3权威指南>(第3版) ...

  7. springboot @cacheable不起作用_Springboot学习记录13 使用缓存:整合redis

    本学习记录的代码,部分参考自gitee码云的如下工程.这个工程有详尽的Spingboot1.x教程.鸣谢! https://gitee.com/didispace/SpringBoot-Learnin ...

  8. 【Cmake】Cmake学习记录

    Cmake学习记录 1.1 常例 add_library(gen_reference_infogen_reference_info/gen_reference_info.hgen_reference_ ...

  9. ASP.NETCore学习记录(一)

    ASP.NETCore学习记录(一) asp.net core介绍  Startup.cs  ConfigureServices  Configure  0. ASP.NETCore 介绍 ASP.N ...

最新文章

  1. 新款iPhone,比绿更绿
  2. .bat脚本自动yes_第四章: Python脚本获取聚宽(JQData)免费行情数据
  3. [LeetCode] 402. Remove K Digits Java
  4. 2021中考高考成绩查询,2021中考
  5. python label background设置成透明_纯Python绘制满满艺术感的山脊地图
  6. C#LeetCode刷题之#746-使用最小花费爬楼梯( Min Cost Climbing Stairs)
  7. Docker pull镜像报错问题
  8. c语言程序员算法题库,100个超级经典地C语言算法,程序员必须练习.doc
  9. 字节跳动面试官:千峰java培训多少钱
  10. 强化学习读书笔记 - 06~07 - 时序差分学习(Temporal-Difference Learning)
  11. war包启动命令_【漏洞预警】Oracle WebLogic远程命令执行0day漏洞(CVE20192725补丁绕过)...
  12. python按钮代码_Python QPalette.Button方法代码示例
  13. 动态规划之子串和(续。升级版)nyoj745
  14. wireshark显示过滤器和捕获过滤器
  15. EGM2008大地水准面模型在工程中的应用综述
  16. A The Miracle and the Sleeper
  17. 计算机维修情况说明书,电脑坏了(电脑坏了情况说明)
  18. dlna 交互步骤-转发
  19. js中的颜色对应的常量代码code
  20. P1873 砍树(二分答案)

热门文章

  1. spring配置bean
  2. 多线程操作数据库时为了防止数据的增删改的混乱该在数据库层还是程序层面上进行同步?
  3. 安装ATOM并使用apm
  4. 机器学习常用算法的优缺点总结
  5. web开发---为什么要安装web服务器
  6. 使用Vmware workstation出现权限不足
  7. 单刀双掷的模拟开关MAX4544
  8. wifi理论数据速率计算
  9. 网络文件共享服务之NFS
  10. python中PIL的安装参考教程