一、概述

使用Java技术构建Web应用时, 我们通常离不开tomcat和jetty之类的servlet容器,这些Web服务器功能强大,性能强劲,深受欢迎,是运行大型Web应用的必备神器。

虽然Java的设计初衷就是用来开发大型应用的,然而有时候我们开发的程序只是简单的小型应用,对于功能的需求和性能的要求并不高, 可能仅仅就几百行甚至几十行代码,这个时候使用tomcat之类的Web服务器去运行就显得有点大材小用了。 比如说只是将数据库中的数据读出来转换成JSON,以Web服务的形式吐给调用方这样的阉割型Web应用。 如下图所示

二、最简单的Java Http服务器

其实在jdk中已经内置了用于此类简单Web应用构建需求的类库了,sun公司提供的 com.sun.net.httpserver 包就是用来帮助我们解决这类问题的

  1. import com.sun.net.httpserver.HttpExchange;
  2. import com.sun.net.httpserver.HttpHandler;
  3. import com.sun.net.httpserver.HttpServer;
  4.  
  5. import java.io.IOException;
  6. import java.io.OutputStream;
  7. import java.net.InetSocketAddress;
  8.  
  9. public class Main {
  10.  
  11. public static void main(String[] arg) throws Exception {
  12. HttpServer server = HttpServer.create(new InetSocketAddress(8001), 0);
  13. server.createContext("/test", new TestHandler());
  14. server.start();
  15. }
  16.  
  17. static class TestHandler implements HttpHandler{
  18. @Override
  19. public void handle(HttpExchange exchange) throws IOException {
  20. String response = "hello world";
  21. exchange.sendResponseHeaders(200, 0);
  22. OutputStream os = exchange.getResponseBody();
  23. os.write(response.getBytes());
  24. os.close();
  25. }
  26. }
  27. }

如上代码清单所示, 仅仅几行代码就可以构建一个五脏俱全的Web应用了。执行代码,在浏览器地址栏里代开链接

http://localhost:8001/test

就能运行这个段程序,输入的结果为helloworld

三、获得外部数据

那在这个程序中如何获取到外部传递过来的数据呢?比如说URL上的查询字符串,POST提交的数据等,其实也很简单

  1. import com.sun.net.httpserver.HttpExchange;
  2. import com.sun.net.httpserver.HttpHandler;
  3. import com.sun.net.httpserver.HttpServer;
  4. import org.apache.commons.io.IOUtils;
  5.  
  6. import java.io.IOException;
  7. import java.io.OutputStream;
  8. import java.io.UnsupportedEncodingException;
  9. import java.net.InetSocketAddress;
  10. import java.net.URLDecoder;
  11. import java.util.Arrays;
  12. import java.util.HashMap;
  13. import java.util.Map;
  14.  
  15. public class Main {
  16.  
  17. public static void main(String[] arg) throws Exception {
  18. HttpServer server = HttpServer.create(new InetSocketAddress(8001), 0);
  19. server.createContext("/test", new TestHandler());
  20. server.start();
  21. }
  22.  
  23. static class TestHandler implements HttpHandler{
  24. @Override
  25. public void handle(HttpExchange exchange) {
  26. String response = "hello world";
  27.  
  28. try{
  29. //获得查询字符串(get)
  30. String queryString = exchange.getRequestURI().getQuery();
  31. Map<String,String> queryStringInfo = formData2Dic(queryString);
  32. //获得表单提交数据(post)
  33. String postString = IOUtils.toString(exchange.getRequestBody());
  34. Map<String,String> postInfo = formData2Dic(postString);
  35.  
  36. exchange.sendResponseHeaders(200,0);
  37. OutputStream os = exchange.getResponseBody();
  38. os.write(response.getBytes());
  39. os.close();
  40. }catch (IOException ie) {
  41.  
  42. } catch (Exception e) {
  43.  
  44. }
  45. }
  46. }
  47.  
  48. public static Map<String,String> formData2Dic(String formData ) {
  49. Map<String,String> result = new HashMap<>();
  50. if(formData== null || formData.trim().length() == 0) {
  51. return result;
  52. }
  53. final String[] items = formData.split("&");
  54. Arrays.stream(items).forEach(item ->{
  55. final String[] keyAndVal = item.split("=");
  56. if( keyAndVal.length == 2) {
  57. try{
  58. final String key = URLDecoder.decode( keyAndVal[0],"utf8");
  59. final String val = URLDecoder.decode( keyAndVal[1],"utf8");
  60. result.put(key,val);
  61. }catch (UnsupportedEncodingException e) {}
  62. }
  63. });
  64. return result;
  65. }
  66. }

上面的代码清单标识了实现的方法。

注意,要保证上面代码编译通过, 需要引入commons-io.jar,此包中提供将InputStream转换成String的方法。

四、并发处理

com.sun.net.httpserver似乎默认不支持同时处理多个请求,一旦有并行的请求涌入,需要排队等待程序处理,导致Web程序响应卡顿。自定义实现的方法也很简单,为每个请求开一个新的线程处理即可, 如下代码清单所示

  1. import com.sun.net.httpserver.HttpExchange;
  2. import com.sun.net.httpserver.HttpHandler;
  3. import com.sun.net.httpserver.HttpServer;
  4. import org.apache.commons.io.IOUtils;
  5.  
  6. import java.io.IOException;
  7. import java.io.OutputStream;
  8. import java.io.UnsupportedEncodingException;
  9. import java.net.InetSocketAddress;
  10. import java.net.URLDecoder;
  11. import java.util.Arrays;
  12. import java.util.HashMap;
  13. import java.util.Map;
  14.  
  15. public class Main {
  16.  
  17. public static void main(String[] arg) throws Exception {
  18. HttpServer server = HttpServer.create(new InetSocketAddress(8001), 0);
  19. server.createContext("/test", new TestHandler());
  20. server.start();
  21. }
  22.  
  23. static class TestHandler implements HttpHandler{
  24. @Override
  25. public void handle(HttpExchange exchange) {
  26. new Thread(new Runnable() {
  27. @Override
  28. public void run() {
  29. try{
  30. String response = "hello world";
  31. //获得查询字符串(get)
  32. String queryString = exchange.getRequestURI().getQuery();
  33. Map<String,String> queryStringInfo = formData2Dic(queryString);
  34. //获得表单提交数据(post)
  35. String postString = IOUtils.toString(exchange.getRequestBody());
  36. Map<String,String> postInfo = formData2Dic(postString);
  37.  
  38. exchange.sendResponseHeaders(200,0);
  39. OutputStream os = exchange.getResponseBody();
  40. os.write(response.getBytes());
  41. os.close();
  42. }catch (IOException ie) {
  43. ie.printStackTrace();
  44. } catch (Exception e) {
  45. e.printStackTrace();
  46. }
  47. }
  48. }).start();
  49. }
  50. }
  51.  
  52. public static Map<String,String> formData2Dic(String formData ) {
  53. Map<String,String> result = new HashMap<>();
  54. if(formData== null || formData.trim().length() == 0) {
  55. return result;
  56. }
  57. final String[] items = formData.split("&");
  58. Arrays.stream(items).forEach(item ->{
  59. final String[] keyAndVal = item.split("=");
  60. if( keyAndVal.length == 2) {
  61. try{
  62. final String key = URLDecoder.decode( keyAndVal[0],"utf8");
  63. final String val = URLDecoder.decode( keyAndVal[1],"utf8");
  64. result.put(key,val);
  65. }catch (UnsupportedEncodingException e) {}
  66. }
  67. });
  68. return result;
  69. }
  70. }

五、优点

Java内置Web服务器在功能、性能、稳定等方面是无法和tomcat和jetty之类的专业Web服务器相比的, 它的优点主要是开发和部署方便简单, 把程序代码编译成jar包后,丢到装有jvm的服务器上, 直接运行就可以了,省去了安装相关的软件、依赖, 配置复杂的环境等工作量。

但是, 在一些各方面要求都比较高的生产环境下,还是建议使用专门的Web服务器,毕竟它们久经考验,能满足所有功能需求,并且出问题的几率低。

使用Java内置的Http Server构建Web应用的更多相关文章

  1. Java 性能分析工具 , 第 2 部分:Java 内置监控工具

    引言 本文为 Java 性能分析工具系列文章第二篇,第一篇:操作系统工具.在本文中将介绍如何使用 Java 内置监控工具更加深入的了解 Java 应用程序和 JVM 本身.在 JDK 中有许多内置的工 ...

  2. 【子非鱼】冒泡排序过程呈现之java内置GUI表示

    自己玩玩写写,排序的过程多么有趣,特别是把看着电脑吧一堆乱七八糟的数据排成有序组合的时候,看起来贼舒服,特别是强迫症患者.好了,话不多说上代码,也算是自己记录一下吧,没有什么技术含量但个人感觉比较有趣 ...

  3. 深入理解Java内置锁和显式锁

    synchronized and Reentrantlock 多线程编程中,当代码需要同步时我们会用到锁.Java为我们提供了内置锁(synchronized)和显式锁(ReentrantLock)两 ...

  4. java内置线程池ThreadPoolExecutor源码学习记录

    背景 公司业务性能优化,使用java自带的Executors.newFixedThreadPool()方法生成线程池.但是其内部定义的LinkedBlockingQueue容量是Integer.MAX ...

  5. Java内置包装类

    Java内置包装类有Object.Integer.Float.Double.Number.Charcter.Boolean.Byte.System. Number,是抽象类,也是超类(父类).Numb ...

  6. java注解学习(1)注解的作用和三个常用java内置注解

    今天,记录一下自己学习的关于注解方面的知识. Annotation是从JDK5.0开始引入的新技术 Annotation的作用: -不是程序本身,可以对程序做出解释(这一点和注释没什么区别) -可以被 ...

  7. 不使用java内置函数,将String字符串转换为int类型

    package com.test; public class AtoiTest { public static void main(String[] args) throws Exception { ...

  8. 设计模式 - 观察者模式(Observer Pattern) Java内置 用法

    观察者模式(Observer Pattern) Java内置 用法 本文地址: http://blog.csdn.net/caroline_wendy/article/details/26601659 ...

  9. 【开发者笔记】冒泡排序过程呈现之java内置GUI表示

    自己玩玩写写,排序的过程多么有趣,特别是把看着电脑吧一堆乱七八糟的数据排成有序组合的时候,看起来贼舒服,特别是强迫症患者.好了,话不多说上代码,也算是自己记录一下吧,没有什么技术含量但个人感觉比较有趣 ...

随机推荐

  1. Java二维数组的概念和使用方法

    二维数组 数组的数组---二维数组的每一个元素是一个一维数组 定义格式 数据类型[][] 数组名 = new 数据类型[二维数组的长度/包含的一维数组的个数][每个一维数组的长度]; int[][] ...

  2. 转:java单例设计模式

    本文转自:http://www.cnblogs.com/yinxiaoqiexuxing/p/5605338.html 单例设计模式 Singleton是一种创建型模式,指某个类采用Singleton ...

  3. 自学WPF之XAML(二)控件

    摘自<深入浅出WPF>. 在WPF中是数据驱动UI,数据是核心,是主动的,UI从属于数据,并表达数据,是被动的.UI是展示给用户操作的.响应UI操作的元素是控件(control).下面是我 ...

  4. 《Java并发编程实战》/童云兰译【PDF】下载

    <Java并发编程实战>/童云兰译[PDF]下载链接: https://u253469.pipipan.com/fs/253469-230062521 内容简介 本书深入浅出地介绍了Jav ...

  5. Solr集群搭建详细教程(二)

    注:欢迎大家转载,非商业用途请在醒目位置注明本文链接和作者名dijia478,商业用途请联系本人dijia478@163.com. 之前步骤:Solr集群搭建详细教程(一) 三.solr集群搭建 注意 ...

  6. jQuery对表单元素的取值和赋值操作代码(转)

    使用常规的思路:$("#keyword").value 取值是取不到的,因为此时$('#keydord')已经不是个element,而是个jquery对象,所以应该使用:$(&qu ...

  7. iOS 面试题、知识点 之一

    最近面试,发现这些题个人遇到的几率大一些,与大家分享一下,分三文给大家: 当然Xcode新版本与之前一版本的区别,以及iOS新特性是必要了解的吧. Xcode8 和iOS 10 在之前文章有发过,感兴 ...

  8. JAVA 解析、编辑nginx.conf

    最近工程开发遇到一个需求:用Java去解析并编辑nginx.conf 在github上找到nginx-java-parser工具,项目地址:https://github.com/odiszapc/ng ...

  9. 关于spring mybateis 定义resultType="java.util.HashMap"

    关于spring mybateis  定义resultType="java.util.HashMap" List<HashMap<String, Object>& ...

  10. Python数据分析工具

    1.Numpy 安装:pip install numpy [root@kvm work]# cat numpy_test.py #!/usr/bin/env python #coding:utf-8 ...