通知
此博客运行在jpress系统上,如果你喜欢此博客模板,请加QQ群:1061691290(whimurmur模板/jpress插件),免费下载使用

Servlet学习记录3

4162人浏览 / 0人评论 | 作者:whisper  | 分类: JAVAWEB  | 标签: java web整合开发王者归来  | 

作者:whisper

链接:http://proprogrammar.com:443/article/18

声明:请尊重原作者的劳动,如需转载请注明出处


      提交表单信息

   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="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">视频       
            <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; ">
        © 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("              ");
        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;

    @Override
    public void init() throws ServletException {
        this.log("执行 init() 方法 ... ");
        ServletConfig conf = this.getServletConfig();
        startPoint = Double.parseDouble(conf.getInitParameter("startPoint"));
    }
    

    @Override
    protected void service(HttpServletRequest arg0, HttpServletResponse arg1) throws ServletException, IOException {
        this.log("执行 service() 方法 ... ");
        super.service(arg0, arg1);
    }

    @Override
    public 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' onclick='history.go(-1);' value='纳税光荣 逃税可耻 返回'  class=button>");
            
        }catch(Exception e){
            out.println("请输入数值类型数据。<input type='button' onclick='history.go(-1);' value='返回'  class=button>");
        }
        out.println("</BODY>");
        out.println("</HTML>");
        out.flush();
        out.close();
    }

    @Override
    public 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();
    }

    @Override
    public 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 对象解析 request
        DiskFileUpload diskFileUpload = new DiskFileUpload();
        try {
            // 将 解析的结果 放置在 List 中
            List<FileItem> list = diskFileUpload.parseRequest(request);
            out.println("遍历所有的 FileItem ... <br/>");
            // 遍历 list 中所有的 FileItem
            for(FileItem fileItem : list){
                if(fileItem.isFormField()){
                    // 如果是 文本域
                    if("description1".equals(fileItem.getFieldName())){
                        // 如果该 FileItem 名称为 description1
                        out.println("遍历到 description1 ... <br/>");
                        description1 = new String(fileItem.getString().getBytes(), "UTF-8");
                    }
                    if("description2".equals(fileItem.getFieldName())){
                        // 如果该 FileItem 名称为 description2
                        out.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解析二进制数据,获取上传的文本内容。


亲爱的读者:有时间可以点赞评论一下

点赞(0) 打赏

全部评论

还没有评论!