使用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服务器,毕竟它们久经考验,能满足所有功能需求,并且出问题的几率低。
使用Java内置的Http Server构建Web应用的更多相关文章
- Java 性能分析工具 , 第 2 部分:Java 内置监控工具
引言 本文为 Java 性能分析工具系列文章第二篇,第一篇:操作系统工具.在本文中将介绍如何使用 Java 内置监控工具更加深入的了解 Java 应用程序和 JVM 本身.在 JDK 中有许多内置的工 ...
- 【子非鱼】冒泡排序过程呈现之java内置GUI表示
自己玩玩写写,排序的过程多么有趣,特别是把看着电脑吧一堆乱七八糟的数据排成有序组合的时候,看起来贼舒服,特别是强迫症患者.好了,话不多说上代码,也算是自己记录一下吧,没有什么技术含量但个人感觉比较有趣 ...
- 深入理解Java内置锁和显式锁
synchronized and Reentrantlock 多线程编程中,当代码需要同步时我们会用到锁.Java为我们提供了内置锁(synchronized)和显式锁(ReentrantLock)两 ...
- java内置线程池ThreadPoolExecutor源码学习记录
背景 公司业务性能优化,使用java自带的Executors.newFixedThreadPool()方法生成线程池.但是其内部定义的LinkedBlockingQueue容量是Integer.MAX ...
- Java内置包装类
Java内置包装类有Object.Integer.Float.Double.Number.Charcter.Boolean.Byte.System. Number,是抽象类,也是超类(父类).Numb ...
- java注解学习(1)注解的作用和三个常用java内置注解
今天,记录一下自己学习的关于注解方面的知识. Annotation是从JDK5.0开始引入的新技术 Annotation的作用: -不是程序本身,可以对程序做出解释(这一点和注释没什么区别) -可以被 ...
- 不使用java内置函数,将String字符串转换为int类型
package com.test; public class AtoiTest { public static void main(String[] args) throws Exception { ...
- 设计模式 - 观察者模式(Observer Pattern) Java内置 用法
观察者模式(Observer Pattern) Java内置 用法 本文地址: http://blog.csdn.net/caroline_wendy/article/details/26601659 ...
- 【开发者笔记】冒泡排序过程呈现之java内置GUI表示
自己玩玩写写,排序的过程多么有趣,特别是把看着电脑吧一堆乱七八糟的数据排成有序组合的时候,看起来贼舒服,特别是强迫症患者.好了,话不多说上代码,也算是自己记录一下吧,没有什么技术含量但个人感觉比较有趣 ...
随机推荐
- Java二维数组的概念和使用方法
二维数组 数组的数组---二维数组的每一个元素是一个一维数组 定义格式 数据类型[][] 数组名 = new 数据类型[二维数组的长度/包含的一维数组的个数][每个一维数组的长度]; int[][] ...
- 转:java单例设计模式
本文转自:http://www.cnblogs.com/yinxiaoqiexuxing/p/5605338.html 单例设计模式 Singleton是一种创建型模式,指某个类采用Singleton ...
- 自学WPF之XAML(二)控件
摘自<深入浅出WPF>. 在WPF中是数据驱动UI,数据是核心,是主动的,UI从属于数据,并表达数据,是被动的.UI是展示给用户操作的.响应UI操作的元素是控件(control).下面是我 ...
- 《Java并发编程实战》/童云兰译【PDF】下载
<Java并发编程实战>/童云兰译[PDF]下载链接: https://u253469.pipipan.com/fs/253469-230062521 内容简介 本书深入浅出地介绍了Jav ...
- Solr集群搭建详细教程(二)
注:欢迎大家转载,非商业用途请在醒目位置注明本文链接和作者名dijia478,商业用途请联系本人dijia478@163.com. 之前步骤:Solr集群搭建详细教程(一) 三.solr集群搭建 注意 ...
- jQuery对表单元素的取值和赋值操作代码(转)
使用常规的思路:$("#keyword").value 取值是取不到的,因为此时$('#keydord')已经不是个element,而是个jquery对象,所以应该使用:$(&qu ...
- iOS 面试题、知识点 之一
最近面试,发现这些题个人遇到的几率大一些,与大家分享一下,分三文给大家: 当然Xcode新版本与之前一版本的区别,以及iOS新特性是必要了解的吧. Xcode8 和iOS 10 在之前文章有发过,感兴 ...
- JAVA 解析、编辑nginx.conf
最近工程开发遇到一个需求:用Java去解析并编辑nginx.conf 在github上找到nginx-java-parser工具,项目地址:https://github.com/odiszapc/ng ...
- 关于spring mybateis 定义resultType="java.util.HashMap"
关于spring mybateis 定义resultType="java.util.HashMap" List<HashMap<String, Object>& ...
- Python数据分析工具
1.Numpy 安装:pip install numpy [root@kvm work]# cat numpy_test.py #!/usr/bin/env python #coding:utf-8 ...