一,概述
使用 Java 技术构建 web 应用时, 我们通常离不开 tomcat 和 jetty 之类的 servlet 容器,这些 Web 服务器功能强大,性能强劲,深受欢迎,是运行大型 Web 应用的必备神器.
虽然 Java 的设计初衷就是用来开发大型应用的,然而有时候我们开发的程序只是简单的小型应用,对于功能的需求和性能的要求并不高, 可能仅仅就几百行甚至几十行代码,这个时候使用 tomcat 之类的 Web 服务器去运行就显得有点大材小用了. 比如说只是将数据库中的数据读出来转换成 JSON,以 Web 服务的形式吐给调用方这样的阉割型 Web 应用. 如下图所示
二,最简单的 Java Http 服务器
其实在 jdk 中已经内置了用于此类简单 Web 应用构建需求的类库了,sun 公司提供的 com.sun.net.httpserver 包就是用来帮助我们解决这类问题的
如上代码清单所示, 仅仅几行代码就可以构建一个五脏俱全的 Web 应用了.执行代码,在浏览器地址栏里代开链接
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();
}
}
}
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 服务器,毕竟它们久经考验,能满足所有功能需求,并且出问题的几率低.
来源: https://www.cnblogs.com/aspwebchh/p/8300945.html