Java 內(nèi)置Http Server構(gòu)建web應(yīng)用案例詳解
一、概述
使用Java技術(shù)構(gòu)建Web應(yīng)用時, 我們通常離不開tomcat和jetty之類的servlet容器,這些Web服務(wù)器功能強(qiáng)大,性能強(qiáng)勁,深受歡迎,是運(yùn)行大型Web應(yīng)用的必備神器。
雖然Java的設(shè)計(jì)初衷就是用來開發(fā)大型應(yīng)用的,然而有時候我們開發(fā)的程序只是簡單的小型應(yīng)用,對于功能的需求和性能的要求并不高, 可能僅僅就幾百行甚至幾十行代碼,這個時候使用tomcat之類的Web服務(wù)器去運(yùn)行就顯得有點(diǎn)大材小用了。 比如說只是將數(shù)據(jù)庫中的數(shù)據(jù)讀出來轉(zhuǎn)換成JSON,以Web服務(wù)的形式吐給調(diào)用方這樣的閹割型Web應(yīng)用。 如下圖所示

二、最簡單的Java Http服務(wù)器
其實(shí)在jdk中已經(jīng)內(nèi)置了用于此類簡單Web應(yīng)用構(gòu)建需求的類庫了,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();
}
}
}
如上代碼清單所示, 僅僅幾行代碼就可以構(gòu)建一個五臟俱全的Web應(yīng)用了。執(zhí)行代碼,在瀏覽器地址欄里代開鏈接
http://localhost:8001/test
就能運(yùn)行這個段程序,輸入的結(jié)果為helloworld
三、獲得外部數(shù)據(jù)
那在這個程序中如何獲取到外部傳遞過來的數(shù)據(jù)呢?比如說URL上的查詢字符串,POST提交的數(shù)據(jù)等,其實(shí)也很簡單
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);
//獲得表單提交數(shù)據(jù)(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;
}
}
上面的代碼清單標(biāo)識了實(shí)現(xiàn)的方法。
注意,要保證上面代碼編譯通過, 需要引入commons-io.jar,此包中提供將InputStream轉(zhuǎn)換成String的方法。
四、并發(fā)處理
com.sun.net.httpserver似乎默認(rèn)不支持同時處理多個請求,一旦有并行的請求涌入,需要排隊(duì)等待程序處理,導(dǎo)致Web程序響應(yīng)卡頓。自定義實(shí)現(xiàn)的方法也很簡單,為每個請求開一個新的線程處理即可, 如下代碼清單所示
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);
//獲得表單提交數(shù)據(jù)(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;
}
}
五、優(yōu)點(diǎn)
Java內(nèi)置Web服務(wù)器在功能、性能、穩(wěn)定等方面是無法和tomcat和jetty之類的專業(yè)Web服務(wù)器相比的, 它的優(yōu)點(diǎn)主要是開發(fā)和部署方便簡單, 把程序代碼編譯成jar包后,丟到裝有jvm的服務(wù)器上, 直接運(yùn)行就可以了,省去了安裝相關(guān)的軟件、依賴, 配置復(fù)雜的環(huán)境等工作量。
但是, 在一些各方面要求都比較高的生產(chǎn)環(huán)境下,還是建議使用專門的Web服務(wù)器,畢竟它們久經(jīng)考驗(yàn),能滿足所有功能需求,并且出問題的幾率低。
到此這篇關(guān)于Java 內(nèi)置Http Server構(gòu)建web應(yīng)用案例詳解的文章就介紹到這了,更多相關(guān)Java 內(nèi)置Http Server構(gòu)建web應(yīng)用內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
使用Java如何將圖片轉(zhuǎn)成Base64編碼,并壓縮至40k
這篇文章主要介紹了使用Java如何將圖片轉(zhuǎn)成Base64編碼,并壓縮至40k問題,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2023-06-06
Java實(shí)現(xiàn)LeetCode(報(bào)數(shù))
這篇文章主要介紹了Java實(shí)現(xiàn)LeetCode(報(bào)數(shù)),本文通過使用java實(shí)現(xiàn)leetcode的報(bào)數(shù)題目和實(shí)現(xiàn)思路分析,需要的朋友可以參考下2021-06-06
IDEA的Mybatis Log Plugin插件配置和使用詳解
這篇文章主要介紹了IDEA的Mybatis Log Plugin插件配置和使用,本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下2020-09-09
Springboot應(yīng)用中過濾器如何修改response的header和body內(nèi)容
這篇文章主要介紹了Springboot應(yīng)用中過濾器如何修改response的header和body內(nèi)容問題,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2023-07-07
SpringBoot圖文并茂詳解如何引入mybatis與連接Mysql數(shù)據(jù)庫
這篇文章主要介紹了SpringBoot如何引入mybatis與連接Mysql數(shù)據(jù)庫,本文通過圖文并茂的形式給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下2022-07-07
Spring Boot打開URL出現(xiàn)signin問題的解決
這篇文章主要介紹了Spring Boot打開URL出現(xiàn)signin問題的解決,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2021-12-12
Java高并發(fā)編程之CAS實(shí)現(xiàn)無鎖隊(duì)列代碼實(shí)例
這篇文章主要介紹了Java高并發(fā)編程之CAS實(shí)現(xiàn)無鎖隊(duì)列代碼實(shí)例,在多線程操作中,我們通常會添加鎖來保證線程的安全,那么這樣勢必會影響程序的性能,那么為了解決這一問題,于是就有了在無鎖操作的情況下依然能夠保證線程的安全,需要的朋友可以參考下2023-12-12

