使用Java內置的Http Server構建Web應用

一、概述

 

使用Java技術構建Web應用時, 我們通常離不開tomcat和jetty之類的servlet容器,這些Web服務器功能強大,性能強勁,深受歡迎,是運行大型Web應用的必備神器。

 

雖然Java的設計初衷就是用來開發大型應用的,然而有時候我們開發的程序只是簡單的小型應用,對於功能的需求和性能的要求並不高, 可能僅僅就幾百行甚至幾十行代碼,這個時候使用tomcat之類的Web服務器去運行就顯得有點大材小用了。 比如說只是將數據庫中的數據讀出來轉換成JSON,以Web服務的形式吐給調用方這樣的閹割型Web應用。 如下圖所示

 

 

 

 

二、最簡單的Java Http服務器

 

其實在jdk中已經內置了用於此類簡單Web應用構建需求的類庫了,sun公司提供的 com.sun.net.httpserver 包就是用來幫助我們解決這類問題的

 

import com.sun.net.httpserver.HttpExchange;
import com.sun.net.httpserver.HttpHandler;
import com.sun.net.httpserver.HttpServer;

import java.io.IOException;
import java.io.OutputStream;
import java.net.InetSocketAddress;

public class Main {

    public static void main(String[] arg) throws Exception {
        HttpServer server = HttpServer.create(new InetSocketAddress(8001), 0);
        server.createContext("/test", new TestHandler());
        server.start();
    }

    static  class TestHandler implements HttpHandler{
        @Override
        public void handle(HttpExchange exchange) throws IOException {
            String response = "hello world";
            exchange.sendResponseHeaders(200, 0);
            OutputStream os = exchange.getResponseBody();
            os.write(response.getBytes());
            os.close();
        }
    }
}

 

如上代碼清單所示, 僅僅幾行代碼就可以構建一個五臟俱全的Web應用了。執行代碼,在瀏覽器地址欄裏代開鏈接

http://localhost:8001/test

就能運行這個段程序,輸入的結果爲helloworld

 

 

三、獲得外部數據

 

那在這個程序中如何獲取到外部傳遞過來的數據呢?比如說URL上的查詢字符串,POST提交的數據等,其實也很簡單 

 

import com.sun.net.httpserver.HttpExchange;
import com.sun.net.httpserver.HttpHandler;
import com.sun.net.httpserver.HttpServer;
import org.apache.commons.io.IOUtils;

import java.io.IOException;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.net.InetSocketAddress;
import java.net.URLDecoder;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;

public class Main {

    public static void main(String[] arg) throws Exception {
        HttpServer server = HttpServer.create(new InetSocketAddress(8001), 0);
        server.createContext("/test", new TestHandler());
        server.start();
    }

    static class TestHandler implements HttpHandler{
        @Override
        public void handle(HttpExchange exchange) {
            String response = "hello world";

            try{
                //獲得查詢字符串(get)
                String queryString =  exchange.getRequestURI().getQuery();
                Map<String,String> queryStringInfo = formData2Dic(queryString);
                //獲得表單提交數據(post)
                String postString = IOUtils.toString(exchange.getRequestBody());
                Map<String,String> postInfo = formData2Dic(postString);

                exchange.sendResponseHeaders(200,0);
                OutputStream os = exchange.getResponseBody();
                os.write(response.getBytes());
                os.close();
            }catch (IOException ie) {

            } catch (Exception e) {

            }
        }
    }

    public static Map<String,String> formData2Dic(String formData ) {
        Map<String,String> result = new HashMap<>();
        if(formData== null || formData.trim().length() == 0) {
            return result;
        }
        final String[] items = formData.split("&");
        Arrays.stream(items).forEach(item ->{
            final String[] keyAndVal = item.split("=");
            if( keyAndVal.length == 2) {
                try{
                    final String key = URLDecoder.decode( keyAndVal[0],"utf8");
                    final String val = URLDecoder.decode( keyAndVal[1],"utf8");
                    result.put(key,val);
                }catch (UnsupportedEncodingException e) {}
            }
        });
        return result;
    }
}

 

上面的代碼清單標識了實現的方法。

 

注意,要保證上面代碼編譯通過, 需要引入commons-io.jar,此包中提供將InputStream轉換成String的方法。

 

 

四、併發處理

 

com.sun.net.httpserver似乎默認不支持同時處理多個請求,一旦有並行的請求涌入,需要排隊等待程序處理,導致Web程序響應卡頓。自定義實現的方法也很簡單,爲每個請求開一個新的線程處理即可, 如下代碼清單所示

 

import com.sun.net.httpserver.HttpExchange;
import com.sun.net.httpserver.HttpHandler;
import com.sun.net.httpserver.HttpServer;
import org.apache.commons.io.IOUtils;

import java.io.IOException;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.net.InetSocketAddress;
import java.net.URLDecoder;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;

public class Main {

    public static void main(String[] arg) throws Exception {
        HttpServer server = HttpServer.create(new InetSocketAddress(8001), 0);
        server.createContext("/test", new TestHandler());
        server.start();
    }

    static class TestHandler implements HttpHandler{
        @Override
        public void handle(HttpExchange exchange) {
            new Thread(new Runnable() {
                @Override
                public void run() {
                    try{
                        String response = "hello world";
                        //獲得查詢字符串(get)
                        String queryString =  exchange.getRequestURI().getQuery();
                        Map<String,String> queryStringInfo = formData2Dic(queryString);
                        //獲得表單提交數據(post)
                        String postString = IOUtils.toString(exchange.getRequestBody());
                        Map<String,String> postInfo = formData2Dic(postString);

                        exchange.sendResponseHeaders(200,0);
                        OutputStream os = exchange.getResponseBody();
                        os.write(response.getBytes());
                        os.close();
                    }catch (IOException ie) {
                        ie.printStackTrace();
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
            }).start();
        }
    }

    public static Map<String,String> formData2Dic(String formData ) {
        Map<String,String> result = new HashMap<>();
        if(formData== null || formData.trim().length() == 0) {
            return result;
        }
        final String[] items = formData.split("&");
        Arrays.stream(items).forEach(item ->{
            final String[] keyAndVal = item.split("=");
            if( keyAndVal.length == 2) {
                try{
                    final String key = URLDecoder.decode( keyAndVal[0],"utf8");
                    final String val = URLDecoder.decode( keyAndVal[1],"utf8");
                    result.put(key,val);
                }catch (UnsupportedEncodingException e) {}
            }
        });
        return result;
    }
}

 

五、優點

 

Java內置Web服務器在功能、性能、穩定等方面是無法和tomcat和jetty之類的專業Web服務器相比的, 它的優點主要是開發和部署方便簡單, 把程序代碼編譯成jar包後,丟到裝有jvm的服務器上, 直接運行就可以了,省去了安裝相關的軟件、依賴, 配置複雜的環境等工作量。

 

但是, 在一些各方面要求都比較高的生產環境下,還是建議使用專門的Web服務器,畢竟它們久經考驗,能滿足所有功能需求,並且出問題的機率低。 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章