JavaWeb基礎(chǔ)(五)-Servlet詳解

這篇文章, 我主要分享JavaWeb動(dòng)態(tài)網(wǎng)頁開發(fā).要談JavaWeb動(dòng)態(tài)網(wǎng)頁開發(fā).我們就要來了解Servlet, 所以我會按如下進(jìn)行分享

  • Servlet的規(guī)范
  • Servlet的請求流程
  • Servlet初始化參數(shù)
  • Servlet繼承體系的設(shè)計(jì)原因
  • Servlet請求和響應(yīng)
    主要圍繞Servlet的原理Servlet的應(yīng)用兩條主線來分享.
    Servlet的原理: 包含Servlet的規(guī)范Servlet的基本請求流程Servlet繼承體系的設(shè)計(jì)原因
    Servlet的應(yīng)用: 包含Servlet初始化參數(shù)迫靖、Servlet請求和響應(yīng)

1.什么是Servlet規(guī)范

Servlet是一套規(guī)范, 所謂的規(guī)范就是做了約束.

  • 是一個(gè)規(guī)范.Servlet是一個(gè)規(guī)范,所謂的規(guī)范就是Servlet約束了一些東西, 主要約束了容器、約束了項(xiàng)目目錄結(jié)構(gòu)钉嘹,約束了我們的代碼.
  • 是一個(gè)組件. Servlet也可以看成是一個(gè)組件, 因?yàn)橐粋€(gè)遵循Servlet規(guī)范的程序可以跑在實(shí)現(xiàn)Servlet規(guī)范的容器中求冷。
Servlet的規(guī)范

2.如何編寫一個(gè)最簡單的Servlet的步驟

  • 創(chuàng)建一個(gè)HelloServlet類繼承自HttpServlet.竟稳。
  • 復(fù)寫其service方法, 在其中編寫業(yè)務(wù)邏輯處理請求健蕊。
  • 配置web.xml. 增加xml中的servlet對象和servlet-mapping對象.其中servlet對象用來關(guān)聯(lián)我們的類,并給這個(gè)類一個(gè)別名。servlet-mapping對象用來映射servlet和和訪問的資源名罩缴。這樣才來告訴tomcat容器, 一旦請求來了, 該根據(jù)資源名去找哪個(gè)servlet做處理蚊逢。

3.如何研究Servlet對象的生命周期

Servlet對象生命周期依賴于容器, 因?yàn)镾ervlet規(guī)范已經(jīng)約定了Servlet對象必須放在實(shí)現(xiàn)Servlet規(guī)范的容器中運(yùn)行, 換區(qū)話說Servlet對象從出生到死亡都由容器調(diào)度。所以容器負(fù)責(zé)Servlet的創(chuàng)建箫章、初始化烙荷、運(yùn)行、釋放.

要了解Servlet具體的生命周期, 我們先介紹以下上個(gè)方法.這三個(gè)方法是Servlet的生命周期方法.

生命周期方法

  • init(ServletConfig); 負(fù)責(zé)初始化Servlet.
  • service(ServletRequest, ServletResponse); 負(fù)責(zé)處理請求.
  • destory(); 負(fù)責(zé)釋放Servlet.

觀察Servlet的生命周期

我們可以創(chuàng)建一個(gè)HelloServlet如下, 并且給它提供一個(gè)無參構(gòu)造方法, 分別在上面上個(gè)生命周期方法中做打印, 來研究其調(diào)用順序.

創(chuàng)建HelloServlet, 繼承自HttpServlet.復(fù)寫生命周期方法

package com.sweetcs.web.servlet;

import java.io.IOException;

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 HelloServlet extends HttpServlet{
    
    public HelloServlet() {
        // TODO Auto-generated constructor stub
        System.out.println("Servlet構(gòu)造方法");
    }
    
    @Override
    public void init(ServletConfig config) throws ServletException {
        // TODO Auto-generated method stub
        super.init(config);
        
        System.out.println("Servlet init");
    }
    
    
    @Override
    protected void service(HttpServletRequest arg0, HttpServletResponse arg1) throws ServletException, IOException {
        System.out.println("Servlet service");
    }
    
    @Override
    public void destroy() {
        // TODO Auto-generated method stub
        super.destroy();
        System.out.println("Servlet destroy");
    }   
}

web.xml中配置資源名的要交個(gè)哪個(gè)servlet處理

<?xml version="1.0" encoding="UTF-8"?>

<web-app xmlns="http://java.sun.com/xml/ns/javaee"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
                      http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
  version="3.0"
  metadata-complete="true">
  <display-name>Welcome to Tomcat</display-name>
  <description>
     Welcome to Tomcat
  </description>


    <servlet>
        <servlet-name>HelloServlet</servlet-name>
        <servlet-class>com.sweetcs.web.servlet.HelloServlet</servlet-class>
    </servlet>
    
    <servlet-mapping>
        <servlet-name>HelloServlet</servlet-name>
        <url-pattern>/hello</url-pattern>
    </servlet-mapping>
  
</web-app>

第一次訪問http://127.0.0.1:8080/hello打印輸出

第一次訪問

第二檬寂、三次訪問http://127.0.0.1:8080/hello打印輸出

第二终抽、三次訪問

通過上述觀察可以發(fā)現(xiàn),第一次訪問是依次調(diào)用了構(gòu)造方法桶至、init方法昼伴、service方法.但是什么時(shí)候Servlet對象的destory方法才會調(diào)用呢?我們進(jìn)行以下兩種方式驗(yàn)證镣屹。

  • 第一種停止tomcat的運(yùn)行, 點(diǎn)擊帶有叉號的貓
點(diǎn)擊帶有叉號的貓

輸出如下,說明調(diào)用了destory方法, Servlet被正確的釋放掉.

打印出destory
  • 第二種直接終止程序.
點(diǎn)擊小紅點(diǎn)終止程序

輸出如下, 說明Servlet對象的destory方法沒有被容器調(diào)用, 也就是說Servlet沒有被正確的釋放掉.

根據(jù)上述實(shí)驗(yàn)驗(yàn)證,我們可以得出以下結(jié)論

總結(jié)

  • Servlet的生命周期是先由容器創(chuàng)建Servlet對象, 所以會調(diào)用其構(gòu)造方法.然后再調(diào)用init方法進(jìn)行初始化, 最后調(diào)用service方法處理請求.
  • 由次可以見Servlet只在第一次訪問時(shí)候創(chuàng)建.創(chuàng)建完后容器就調(diào)用了servlet的init方法.
  • Servlet對象在整個(gè)容器中只有一份,屬于單例.因?yàn)槎啻蔚南嗤瑄rl的請求過來, 都沒有再調(diào)用構(gòu)造方法, 顯然沒有在創(chuàng)建新的Sevlet對象.
  • Servlet必須提供無參數(shù)構(gòu)造器.由于Sevlet對象不是我們手動(dòng)創(chuàng)建的, 而是交給容器負(fù)責(zé)圃郊。在這里我們使用的是tomcat容器.而tomcat容器是使用反射技術(shù)Class clazz = Class.forName();clazz.newInstance()創(chuàng)建Servlet對象.所以我們必須提供無參構(gòu)造器.當(dāng)然Java中如果你不提供構(gòu)造器, 默認(rèn)就會存在一個(gè)無參構(gòu)造器。
  • 要正確的讓Servlet得到釋放, 必須得停止tomcat容器.如果是程序異常中斷, Servlet并不能得到釋放.

4.Servlet請求流程

我們了解了Servlet的規(guī)范女蜈、Servlet的生命周期描沟、接著我們研究下我們從瀏覽器通過http協(xié)議請求相應(yīng)的資源的時(shí)候飒泻。服務(wù)器端的Servlet從接受到請求的到響應(yīng)的流程.

  • 1.當(dāng)tomcat服務(wù)器接受到瀏覽器的請求時(shí), 會進(jìn)行URL的解析.將URL分解出ContextPathResourceName.即上下文路徑資源名稱.
  • 2.解析完成后, tomcat會去讀取其conf/server.xml中的所有Context對象.(我把Context元素叫對象)
  • 3.然后根據(jù)ContextPath的值和Context對象path屬性進(jìn)行比較, 找到對應(yīng)的Context對象。
    如果沒有找到對應(yīng)的Context對象就報(bào)404 Not Found.
    如果有找到對應(yīng)的Context對象則進(jìn)入第4步.(如下是一個(gè)Context元素<Context docBase='xxx' path='contextPath' />)
  • 4.讀取Context對象的docBase屬性值,即為項(xiàng)目的部署路徑所在地址.tomcat會根據(jù)該地址取讀取其下的WEB-INF/web.xml配置文件.
  • 5.解析web.xml中的所有Servlet-Mapping對象, 并用ResouceName和Servlet-Mapping對象的url-pattern比較.如果知道到匹配的進(jìn)入第6步, 否者也是報(bào)404 Not Found.
  • 6.根據(jù)找到的Servlet-Mapping對象的servlet-name繼續(xù)找到Servlet對象對應(yīng)的全限定類名.
  • 7.嘗試去 Servlet緩存池獲取對應(yīng)的Servlet對象.根據(jù)全限定類名取對應(yīng)的Servlet對象.如果取到, 則直接調(diào)用其service方法(傳入已經(jīng)創(chuàng)建好的request和reponse對象)
  • 8.如果Servlet緩存池中沒有對應(yīng)的對象, 則使用反射技術(shù), 加載解析出來的全限定類名.并調(diào)用其newInstance()方法創(chuàng)建Servlet對象.
  • 9.創(chuàng)建ServletConfig對象, 該對象即代表web.xml.調(diào)用Servlet對象的init方法.servlet.init(config)
    1. 調(diào)用Servlet對象的service方法處理請求, 相應(yīng)數(shù)據(jù). servlet.service(request, response)
    1. 如果有重復(fù)的請求進(jìn)來, 則進(jìn)入第7步.

注意

  • server.xml文件配置了contextPath.web.xml配置了資源名稱.
  • server.xml文件讓tomcat根據(jù)contextPath去找到對應(yīng)的根目錄地址.web.xml文件根據(jù)tomcat根據(jù)資源名稱知道對應(yīng)的Servlet類,再通過反射技術(shù)創(chuàng)建Sevlet對象.

5.Servlet初始化參數(shù)

了解完Servlet的請求流程, 我們也就明白了底層是如何創(chuàng)建Servlet對象, 同時(shí)知道了配置文件的作用吏廉。接著我們就順著該流程的第一個(gè)步驟, 創(chuàng)建并初始化Servlet對象, 想來了解下Servlet的初始化參數(shù).

5.1 init(config)

什么是初始化參數(shù), 即Servlet在創(chuàng)建后, 我們可能會需要它附帶一些屬性, 并且我們用配置好的參數(shù)來初始化這些Servlet.這些參數(shù)都是配置在web.xml<Servlet元素>中.
如下我們給HelloServlet配置初始化參數(shù), 并讀取出來查看.

web.xml配置, 在servlet元素中添加init-param元素

    <servlet>
        <servlet-name>HelloServlet</servlet-name>
        <servlet-class>com.sweetcs.web.servlet.HelloServlet</servlet-class>
        <init-param>
            <param-name>encoding</param-name>
            <param-value>UTF-8</param-value>
        </init-param>
    </servlet>

Java代碼

public class HelloServlet extends HttpServlet{
    
    private ServletConfig config;
    
    public HelloServlet() {
        // TODO Auto-generated constructor stub
        System.out.println("Servlet構(gòu)造方法");
    }
    
    @Override
    public void init(ServletConfig config) throws ServletException {
        // TODO Auto-generated method stub
        super.init(config);
        this.config = config;
        System.out.println("Servlet init");
    }
    
    
    @Override
    protected void service(HttpServletRequest arg0, HttpServletResponse arg1) throws ServletException, IOException {
        System.out.println("Servlet service");
        
        String encoding = config.getInitParameter("encoding");
        System.out.println(encoding);
        
    }
    
    @Override
    public void destroy() {
        // TODO Auto-generated method stub
        super.destroy();
        System.out.println("Servlet destroy");
    }   
}

啟動(dòng)tomcat, 并瀏覽器輸入http://127.0.0.1:8080/hello.打印如下,可以正確的將配置參數(shù)讀取出來.

Servlet構(gòu)造方法
Servlet init
Servlet service
UTF-8

5.2

根據(jù)5.1我們知道一個(gè)ServletConfig對象 對應(yīng)的就是其WEB-INF下的web.xml配置文件.其主要作用就是用來讀取配置文件中的Servlet元素的初始化信息泞遗。

其有以下兩個(gè)常用接口

  • public String getInitParameter(String name); 根據(jù)配置的參數(shù)的key讀取對應(yīng)的value值
  • public Enumeration<String> getInitParameterNames(); 可以讀取到所有的配置參數(shù)的key值.

6 Servlet繼承體系的設(shè)計(jì)原因

上面我們分享了如何編寫一個(gè)Servlet程序、以及Servlet的生命周期過程席覆、Servlet的請求流程和Servlet的初始化參數(shù)史辙。接著我們就來研究下Servlet的繼承體系。我主要借助eclipse和源碼來和大家分享下Servlet的繼承體系的結(jié)構(gòu)和設(shè)計(jì)原因.

1.Servlet的是一個(gè)規(guī)范, 我們?nèi)绾巫裱湟?guī)范來編寫程序呢?

我們通過查看Servlet接口可以看到其對應(yīng)的接口代碼.如果讓我們自己來實(shí)現(xiàn)一個(gè)Servlet程序,那么我們首先得實(shí)現(xiàn)其Servlet接口.
并且我們得實(shí)現(xiàn)其生命周期方法, 來讓tomcat能管理Servlet對象佩伤、并且我們得實(shí)現(xiàn)ServletConfig接口.讓Servlet能得到正確的初始化.依照這個(gè)思路我們可以寫出第一個(gè)版本實(shí)現(xiàn)Servlet接口.

package com.sweetcs.web.servlet;

import java.io.IOException;

import javax.security.auth.login.Configuration;
import javax.servlet.Servlet;
import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;

public class MyServlet implements Servlet{

    private ServletConfig config;
    
    @Override
    public void init(ServletConfig config) throws ServletException {
        // TODO Auto-generated method stub
        System.out.println("初始化參數(shù)");
        this.config = config;
    }

    @Override
    public ServletConfig getServletConfig() {
        // TODO Auto-generated method stub
        return this.config;
    }

    @Override
    public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException {
        // TODO Auto-generated method stub
        
        System.out.println("處理請求");
    }

    @Override
    public String getServletInfo() {
        // TODO Auto-generated method stub
        return null;
    }

    @Override
    public void destroy() {
        // TODO Auto-generated method stub
        System.out.println("desotry servlet");
    
    }
    
}

為了讓tomcat能正確找到對應(yīng)的Servlet我們還需要配置web.xml

<?xml version="1.0" encoding="UTF-8"?>

<web-app xmlns="http://java.sun.com/xml/ns/javaee"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
                      http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
  version="3.0"
  metadata-complete="true">
  <display-name>Welcome to Tomcat</display-name>
  <description>
     Welcome to Tomcat
  </description>

    <servlet>
        <servlet-name>MyServlet</servlet-name>
        <servlet-class>com.sweetcs.web.servlet.MyServlet</servlet-class>
    </servlet>
    
    <servlet-mapping>
        <servlet-name>MyServlet</servlet-name>
        <url-pattern>/test</url-pattern>
    </servlet-mapping>
  
</web-app>

啟動(dòng)tomcat.并在瀏覽器中輸入http://127.0.0.1:8080/test進(jìn)行測試.

初始化參數(shù)
處理請求

2.如何讀取初始化參數(shù)

我們現(xiàn)在遵循Servlet接口開發(fā)的Servlet程序能正常運(yùn)行了,但是我們?nèi)绾巫x取配置呢?我們可以這樣做,用一個(gè)ServletConfig屬性存儲該ServletConfig對象, 在service方法需要的時(shí)候進(jìn)行讀取.我們在service方法中讀取
如下代碼

    @Override
    public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException {
        // TODO Auto-generated method stub
        
        System.out.println("處理請求");
        String encoding = config.getInitParameter("encoding");
    }

為什么上述實(shí)現(xiàn)需要重構(gòu)
上述代碼并不存在問題, 但是如果我們現(xiàn)在有10個(gè)Servlet要編寫, 我們就得重復(fù)的在每個(gè)Servlet中存儲一個(gè)ServletConfig屬性用來存儲ServletConfig.而且我們還得為每個(gè)Servlet實(shí)現(xiàn)上述代碼中的所有接口聊倔。這時(shí)候代碼就重復(fù)了, 一旦代碼重復(fù), 我們就要考慮進(jìn)行重構(gòu),如何進(jìn)行重構(gòu)呢?對于重復(fù)代碼我們可以采用繼承方式或者組合方法.一般我們都使用組合方式進(jìn)行重構(gòu), 但是在這里由于我們編寫的Servlet都是必須實(shí)現(xiàn)該規(guī)范的, 所以我們并沒必要去用組合的方式.
由此思路我們可以將這些代碼抽取到一個(gè)類中, 我們把它叫MyGenericServlet

3.消除Servlet接口重復(fù)代碼,實(shí)現(xiàn)MyGenericServlet

package com.sweetcs.web.servlet;

import java.io.IOException;

import javax.servlet.Servlet;
import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;

public abstract class MyGenericServlet implements Servlet{
    private ServletConfig config;
    
    @Override
    public void init(ServletConfig config) throws ServletException {
        // TODO Auto-generated method stub
        System.out.println("初始化參數(shù)");
        this.config = config;
    }

    @Override
    public ServletConfig getServletConfig() {
        // TODO Auto-generated method stub
        return this.config;
    }

    @Override
    public abstract void service(ServletRequest req, ServletResponse res) throws ServletException, IOException;
    

    @Override
    public String getServletInfo() {
        // TODO Auto-generated method stub
        return null;
    }

    @Override
    public void destroy() {
        // TODO Auto-generated method stub
        System.out.println("desotry servlet");
    
    }
}
  • 之所以將service聲明為抽象方法,是因?yàn)槿绻贿@樣做.這很容易忘記要復(fù)寫該service方法,該方法主要負(fù)責(zé)請求的處理, 不同的servlet對請求的處理邏輯是不盡相同的, 所以將其聲明為抽象方法是比較合適的.
  • 根據(jù)抽象方法約定, MyGenericServlet也必須為抽象類

4.現(xiàn)在考慮子類如何讀取初始化參數(shù)?

  • 首先子類并沒有辦法直接訪問父類的config屬性,因?yàn)樵搶傩允莗rivate的, 比較好的方法是父類提供進(jìn)一步的封裝讓我們能根據(jù)key來讀取初始化參數(shù)值.
  • 考慮到ServletConfig對象中擁有兩個(gè)常用方法,我們可以在父類中實(shí)現(xiàn)這兩個(gè)常用方法, 而Servlet規(guī)范中,恰好也提供了ServletConfig接口生巡,所以我們可以讓MyGenericServlet實(shí)現(xiàn)該接口.
public abstract class MyGenericServlet implements Servlet, ServletConfig{
    private ServletConfig config;
    
    @Override
    public String getInitParameter(String name) {
        // TODO Auto-generated method stub
        return config.getInitParameter(name);
    }
    
    @Override
    public Enumeration<String> getInitParameterNames() {
        // TODO Auto-generated method stub
        return config.getInitParameterNames();
    }
.......// 省略后面代碼
}

5.需要定制專門處理Http的Servlet

經(jīng)過1--4 我們已經(jīng)抽取了MyGenericServlet, 進(jìn)一步讓代碼重用性得到提高.現(xiàn)在的問題是, MyGenericServlet是處理一般的資源的Servlet耙蔑。其service方法中的request和response對象并不是HttpRequest和HttpResponse對象.也就是說MyGenericServlet并不適合處理Http類型的請求,它是一個(gè)處理通用的請求,子類還需要繼承MyGenericServlet做進(jìn)一步訂制.

  • 我們需要實(shí)現(xiàn)MyHttpServlet,讓其繼承MyGenericServlet.并復(fù)寫其service方法.在該方法中我們對ServletRequest和ServletResponse進(jìn)行強(qiáng)制類型轉(zhuǎn)換.并提供一個(gè)重載的service方法孤荣。在該重載service方法中我們進(jìn)行方法的分發(fā)甸陌。具體代碼如下
package com.sweetcs.web.servlet;

import java.io.IOException;

import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class MyHttpServlet extends MyGenericServlet{

    
    @Override
    public void service(ServletRequest req, ServletResponse res)
        throws ServletException, IOException {

        HttpServletRequest  request;
        HttpServletResponse response;

        try {
            request = (HttpServletRequest) req;
            response = (HttpServletResponse) res;
        } catch (ClassCastException e) {
            throw new ServletException("non-HTTP request or response");
        }
        service(request, response);
    }
    
    protected void service(HttpServletRequest req, HttpServletResponse resp) {
        
        String method = req.getMethod();
        
        if ("GET".equalsIgnoreCase(method)) {
            doGet();
        }else if ("POST".equalsIgnoreCase(method)) {
            doPost();
        }else {
            
        }
        
    }

    private void doPost() {
        // TODO Auto-generated method stub
        
    }

    private void doGet() {
        // TODO Auto-generated method stub
        doPost();
    }
}

繼承體系圖

通過上述代碼,我們可以可以對比下我們實(shí)現(xiàn)的繼承體系HttpServlet的繼承體系盐股。(按command + t查看類的繼承結(jié)構(gòu))
其之所以這樣設(shè)計(jì),就是為了消除代碼重復(fù),為了提供專門處理Http請求的Servlet

MyHttpServlet的繼承結(jié)構(gòu)
HttpServlet繼承結(jié)構(gòu)
總結(jié)Servlet繼承結(jié)構(gòu)
  • GenericServlet是一個(gè)抽象類, 實(shí)現(xiàn)了Sevlet接口, 并實(shí)現(xiàn)了大多數(shù)的Servlet接口方法, 并實(shí)現(xiàn)了ServletConfig接口用來讀取初始化參數(shù).(還實(shí)現(xiàn)了java.io.Serializable接口支持網(wǎng)絡(luò)序列化傳輸)
  • HttpServlet繼承自GeneircServlet是對其進(jìn)一步的擴(kuò)展,專門用來處理Http類型的請求.

7. Servlet請求和相應(yīng)

我們了解了整個(gè)Servlet的請求流程和其體系結(jié)構(gòu),其實(shí)現(xiàn)在我們就可以進(jìn)行更多復(fù)雜的業(yè)務(wù)邏輯開發(fā)钱豁。在這之前我們需要了了解下HttpServletRequest和HttpServletResponse的常用API.
由于是API的使用, 我們將簡要的介紹完API功能后, 使用代碼演示一個(gè)注冊用戶的功能.

HttpServletRequest

是什么:HttpServletRequest是ServletRequest的子類, 主要用于處理Http請求, 其表示一個(gè)Http請求對象.

常用API
  • getMethod(). 獲取請求對象的方式,是GET還是POST等等
  • getRequestURI(). 獲取請求的資源路徑(contextPath+resouceName)
  • getRequestURL(). 獲取整個(gè)URL地址
  • getHeader(String name) 根據(jù)name獲取請求頭中的字段信息.
獲取請求參數(shù)的方法
  • getParameter(String name);
  • getParameterValues(String name);
  • getParameterNames();
  • getParameterMap();
request的編碼問題
  • 如果是post請求, 記得設(shè)置為UTF-8編碼 req.setCharacterEncoding("UTF-8");
  • 如果是GET請求, 可以先進(jìn)行轉(zhuǎn)碼, 先轉(zhuǎn)成字節(jié)數(shù)組,再轉(zhuǎn)換成UTF-8格式的字符編碼(tomcat中請求對象,默認(rèn)是ISO-8859-1編碼疯汁,不兼容中文.)
byte[] data = username.getBytes("ISO-8859-1");
username = new String(data, "UTF-8"); // 這時(shí)候就可以正確的輸出

HttpServletResponse

常用API
  • getOuputStream(); 獲取字節(jié)輸出流.常用在文件的下載
  • getWriter(); 獲取字符輸出流.用在像網(wǎng)頁輸出字符
注意
  • 記得設(shè)置MIME類型和charset.
    resp.setContentType("text/html; charset=UTF-8")

需求,寫代碼

我們需要完成這樣一個(gè)需求, 通過servlet完成一個(gè)網(wǎng)頁版的計(jì)算器牲尺。具體頁面如下, 因?yàn)槲覀冞€沒介紹jsp, 所以需要在servlet中完成網(wǎng)頁頁面的繪制.

頁面

計(jì)算器頁面

代碼

package com.sweetcs.calc.servlet;

import java.io.IOException;
import java.io.PrintWriter;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

@WebServlet("/calc")
public class CalcServlet extends HttpServlet{

    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        
        req.setCharacterEncoding("UTF-8"); // 只針對post請求有效
        resp.setContentType("text/html; charset=UTF-8"); // 設(shè)置輸出的類型和編碼
        String op = req.getParameter("op");
        String leftNum =  req.getParameter("leftNum");
        String rightNum = req.getParameter("rightNum");
        
        if (leftNum == null || "".equals(leftNum)) leftNum = "0";
        if (rightNum == null || "".equals(rightNum)) rightNum = "0";
        
        String result = "0";
        System.out.println(op);
        System.out.println(leftNum + "," + rightNum);
        
        
        
        if (op != null) {
            switch (op) {
            case "+":
                result = (Double.parseDouble(leftNum) + Double.parseDouble(rightNum))+"";
                break;
            case "-":
                result =  (Double.parseDouble(leftNum) - Double.parseDouble(rightNum))+"";
                break;
            case "*":
                result =  (Double.parseDouble(leftNum) * Double.parseDouble(rightNum))+"";
                break;
            case "/":
                result =  (Double.parseDouble(leftNum) / Double.parseDouble(rightNum))+"";
                break;
            default:
                break;
            }
        }
        
        PrintWriter pw = resp.getWriter();
        pw.write("<!DOCTYPE html> <html>"
                + " <head> "
                + "<meta charset='UTF-8'> "
                        + "<title>Insert title here</title> "
                        + "</head> "
                        + "<body> " + "<form action='/calc' method='GET'>"
                        + "<input type='text' name='leftNum' /> "
                        + "<select name = 'op'> "
                        + "<option value='+'>+</option> "
                        + "<option value='-'>-</option> "
                        + "<option value='*'>*</option> "
                        + "<option value='/'>/</option> "
                        + "</select> "
                        + "<input type='text' name='rightNum' /> "
                        + "<input type='submit' value='=' /> "
                                + "<input type='text' name='result' value="+ result +" /> "
                                + "</form> "
                                + "</body> "
                                + "</html>");
        pw.close();
        
    }
    
}

后續(xù)

JavaWeb基礎(chǔ)(六)中我將分享Web開發(fā)中的Cookie和Session.

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市幌蚊,隨后出現(xiàn)的幾起案子谤碳,更是在濱河造成了極大的恐慌,老刑警劉巖溢豆,帶你破解...
    沈念sama閱讀 217,277評論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件蜒简,死亡現(xiàn)場離奇詭異,居然都是意外死亡沫换,警方通過查閱死者的電腦和手機(jī)臭蚁,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,689評論 3 393
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來讯赏,“玉大人垮兑,你說我怎么就攤上這事∈妫” “怎么了系枪?”我有些...
    開封第一講書人閱讀 163,624評論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長磕谅。 經(jīng)常有香客問我私爷,道長雾棺,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,356評論 1 293
  • 正文 為了忘掉前任衬浑,我火速辦了婚禮捌浩,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘工秩。我一直安慰自己尸饺,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,402評論 6 392
  • 文/花漫 我一把揭開白布助币。 她就那樣靜靜地躺著浪听,像睡著了一般。 火紅的嫁衣襯著肌膚如雪眉菱。 梳的紋絲不亂的頭發(fā)上迹栓,一...
    開封第一講書人閱讀 51,292評論 1 301
  • 那天,我揣著相機(jī)與錄音俭缓,去河邊找鬼克伊。 笑死,一個(gè)胖子當(dāng)著我的面吹牛尔崔,可吹牛的內(nèi)容都是我干的答毫。 我是一名探鬼主播褥民,決...
    沈念sama閱讀 40,135評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼季春,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了消返?” 一聲冷哼從身側(cè)響起载弄,我...
    開封第一講書人閱讀 38,992評論 0 275
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎撵颊,沒想到半個(gè)月后宇攻,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,429評論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡倡勇,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,636評論 3 334
  • 正文 我和宋清朗相戀三年逞刷,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片妻熊。...
    茶點(diǎn)故事閱讀 39,785評論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡夸浅,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出扔役,到底是詐尸還是另有隱情帆喇,我是刑警寧澤,帶...
    沈念sama閱讀 35,492評論 5 345
  • 正文 年R本政府宣布亿胸,位于F島的核電站坯钦,受9級特大地震影響预皇,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜婉刀,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,092評論 3 328
  • 文/蒙蒙 一吟温、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧突颊,春花似錦溯街、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,723評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至友绝,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間迁客,已是汗流浹背郭宝。 一陣腳步聲響...
    開封第一講書人閱讀 32,858評論 1 269
  • 我被黑心中介騙來泰國打工掷漱, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人卜范。 一個(gè)月前我還...
    沈念sama閱讀 47,891評論 2 370
  • 正文 我出身青樓衔统,卻偏偏與公主長得像,于是被迫代替她去往敵國和親锦爵。 傳聞我的和親對象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,713評論 2 354

推薦閱讀更多精彩內(nèi)容

  • 從三月份找實(shí)習(xí)到現(xiàn)在险掀,面了一些公司,掛了不少湾宙,但最終還是拿到小米樟氢、百度、阿里侠鳄、京東、新浪畦攘、CVTE、樂視家的研發(fā)崗...
    時(shí)芥藍(lán)閱讀 42,246評論 11 349
  • 在學(xué)習(xí)Servlet是找到一篇不錯(cuò)的文章,轉(zhuǎn)載一下知押。學(xué)習(xí)心得,Servlet其實(shí)只是個(gè)接口,相當(dāng)于是定義了一個(gè)標(biāo)準(zhǔn)...
    君子若蓮閱讀 1,204評論 1 16
  • 0 系列目錄# WEB請求處理 WEB請求處理一:瀏覽器請求發(fā)起處理 WEB請求處理二:Nginx請求反向代理 本...
    七寸知架構(gòu)閱讀 13,957評論 22 190
  • 讀經(jīng): 《出埃及記》第30章。 經(jīng)文: 凡過去歸那些被數(shù)的人罢绽,從二十歲以外的畏线,要將這禮物奉給耶和華良价。他們?yōu)橼H生命將...
    君自爾出閱讀 3,486評論 0 2
  • 大家都知道我愛讀書,愛學(xué)習(xí)明垢,我不怕書呆子的名號,只愿意在書中沉醉痊银,書中自有顏如玉,書中自有黃金屋溯革,讀書給了我豐富的...
    妖嬈雪閱讀 490評論 0 2