欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

基于Java内置的HttpServer实现轻量级Restful

程序员文章站 2022-07-12 20:30:56
...

  在服务架构体系里,例如传统的SOA,以及微服务架构,有各种各样的解决方案和产品。以前后端分离的服务架构为例,服务接口采用Restful技术,一些解决方案是采用Node.js或者Spring boot等产品,特别是采用强大Spring体系的框架,在遇到以非结构化数据(以MongoDB为例)为主的情况下,原来处理关系型数据库的架构将成为鸡肋,为什么呢?
  
  在前后端分离的情况下,前端将更多的基于HTML DOM开发(或者被VUE等框架封装),而DOM本身是树状结构,同样,Mongo DB的数据存储也是树状结构,如此这样,对于增删改查数据操作,中间还需要分层处理吗?我看是没有必要。
  
  JavaScript HTML DOM结构如下图所示:
基于Java内置的HttpServer实现轻量级Restful

  Mongo DB存储样例结构如下图所示:
基于Java内置的HttpServer实现轻量级Restful

  由于Mongo DB数据库Schema没有严格的限制,换句话说可以任意更改,这样,在与前端界面对接过程中,夸张的说,前端只写一次“保存”代码,遍历所有数据项,保存到后台Mongo DB中,也可以只写一次代码[10] ,简化开发并快速迭代。

  基于物联网大数据(对应使用MongoDB),人工智能大数据(Python + Spark),以及云服务技术需求,根据去中心化、物联网服务嵌入化等思路,构建自己的服务架构,初步设计思路和技术验证如下:

  1、 服务架构
  
  整体架构为服务架构,其中Web服务由Apache HttpServer提供,使用HTML5、Javascript、CSS;业务服务由SUN Httpserver技术开发为Restful服务;人工智能由Python开发并提供Restful服务,等等,如下图所示。
基于Java内置的HttpServer实现轻量级Restful

  2、基于Java内置的HttpServer实现轻量级Restful

  JDK1.6以上版本提供了一个简单的HttpServer类,据此我们可以构建自己的嵌入式Http Server,提供Restful服务,它支持Http和Https协议,提供了HTTP1.1的部分实现,没有被实现的那部分可以通过扩展已有的Http Server API来实现,我们必须自己实现HttpHandler接口,HttpServer会调用HttpHandler实现类的回调方法来处理客户端请求,在这里,我们把一个Http请求和它的响应称为一个交换,包装成HttpExchange类,HttpServer负责将HttpExchange传给 HttpHandler实现类的回调方法。
  
  Sun Httpserver类库包是在rt.jar文件中。
基于Java内置的HttpServer实现轻量级Restful
  (1)Http服务线程代码:

import java.io.IOException;  
import java.net.InetSocketAddress;  
import com.sun.net.httpserver.HttpServer;  
import com.sun.net.httpserver.spi.HttpServerProvider;
/**
 * @author XiaoYW
 *
 */
public class RestServerSample {

    public static void serverStart() throws IOException {  
        HttpServerProvider provider = HttpServerProvider.provider();  
        HttpServer httpserver =provider.createHttpServer(new InetSocketAddress(8080), 100);
        //监听端口8080,  

        httpserver.createContext("/RestSample", new RestGetHandler());
        httpserver.setExecutor(null);  
        httpserver.start();  
        System.out.println("server started");  
    }  

    public static void main(String[] args) throws IOException {
        serverStart();
    }
}

  (2)实现Restful GET样例:
  
  如果抛开JavaEE容器及相关架构,那么,可以直接采用开发应用程序的方式,通过调用自行开发的类和方法,再借助Headers、 HttpExchange ,返回符合Rest规范的JSON格式数据。前端是通过Javascript代码中的Ajax方法调用,Restful GET实现样例如下(由于是Demo代码,代码不是很完整,如感兴趣,请反馈多交流):

import java.io.IOException;
import java.io.OutputStream;
import java.net.URI;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;

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

public class RestGetHandler implements HttpHandler{
    @Override
    public void handle(HttpExchange he) throws IOException {
        String requestMethod = he.getRequestMethod();
        if (requestMethod.equalsIgnoreCase("GET")) {
            Headers responseHeaders = he.getResponseHeaders();
            responseHeaders.set("Content-Type", "application/json");

            he.sendResponseHeaders(200, 0);
            // parse request
            OutputStream responseBody = he.getResponseBody();
            Headers requestHeaders = he.getRequestHeaders();
            Set<String> keySet = requestHeaders.keySet();
            Iterator<String> iter = keySet.iterator();

            while (iter.hasNext()) {
                String key = iter.next();
                List values = requestHeaders.get(key);
                String s = key + " = " + values.toString() + "\r\n";
                responseBody.write(s.getBytes());
              }
            //he.sendResponseHeaders(HttpURLConnection.HTTP_OK, response.getBytes().length);

            Map<String, Object> parameters = new HashMap<String, Object>();
            URI requestedUri = he.getRequestURI();
            String query = requestedUri.getRawQuery();
            RestParameter.parseQuery(query, parameters);
            // send response
            String response = "";
            for (String key : parameters.keySet())
                response += key + " = " + parameters.get(key) + "\r\n";
            responseBody.write(response.getBytes());

            responseBody.close();
        }
    }
}

  通过网页模拟调用,在IE浏览器上输入“http://127.0.0.1:8080/RestSample?id=001&name=xiaoyw”,效果如下:

Host = [127.0.0.1:8080]
Accept-encoding = [gzip, deflate]
Connection = [Keep-Alive]
Accept-language = [zh-CN]
User-agent = [Mozilla/5.0 (Windows NT 10.0; WOW64; Trident/7.0; rv:11.0) like Gecko]
Accept = [text/html, application/xhtml+xml, image/jxr, */*]
id = 001
name = xiaoyw

  3、使用Apache中的HttpClient,调用Web服务
  
  Apache的HttpClient可以被用于从客户端发送HTTP请求到服务器端,下面给出一个用HttpClient执行GET请求的操作方法,代码样例如下:


import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;

import org.apache.http.HttpEntity;

/**
 * @author XiaoYW
 *
 */
public class Testhttpclient {
    /** 
     * get请求 
     * @return 
     */  
    public static String doGet(String url) throws Exception{  

        CloseableHttpClient httpclient = HttpClients.createDefault();
        try {

            // 发送get请求
            HttpGet httpget = new HttpGet(url);
            CloseableHttpResponse response1 = httpclient.execute(httpget);

            try {
                System.out.println(response1.getStatusLine());
                HttpEntity entity1 = response1.getEntity();
                // do something useful with the response body
                // and ensure it is fully consumed
                ///EntityUtils.consume(entity1);
                ///System.out.println("GET Response Status:: " + response1.getStatusLine().getStatusCode());

                BufferedReader reader = new BufferedReader(new InputStreamReader(response1.getEntity().getContent()));

                String inputLine;
                StringBuffer response = new StringBuffer();

                while ((inputLine = reader.readLine()) != null) {
                    response.append(inputLine);
                }
                reader.close();

                // print result
                System.out.println(response.toString());

            } finally {
                response1.close();
            }

        } finally {
            try {
                httpclient.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

        return null;
    }  
    /**
     * @param args
     */
    public static void main(String[] args) throws Exception{
        Testhttpclient client = new Testhttpclient();
        client.doGet("http://127.0.0.1:8080/RestSample?id=001&name=xiaoyw");
    }

  运行此Java应用程序,执行结果如下图所示:
基于Java内置的HttpServer实现轻量级Restful

  使用Apache中的HttpClient自行开发服务,调用Httpserver所提供的Rest服务,可以用作服务编排(服务调用)。
  
  这种设计方案,是参考了早先使用Cordys(已经被OpenText收购)产品的架构和实践,Cordys产品虽然也是SOA、Java,但是与J2EE容器没有关系,是通过提供Soap Webservice服务(后来也提供Restful服务),结合Apache Http Server,实现了前后台分离。
  
  由于作者水平有限,欢迎同行指点!

参考:
1.《jdk自带轻量级http server例子》 CSDN博客 云守护的专栏 2014年11月
2.《Create a Simple Web Server in Java (1) - HTTP Server》 codeproject Andy Feng, Oct 2015
3.《Have a simple HTTP server》 Written and compiled by Réal Gagnon
4.《基于JDK HttpServer的RESTEasy》 CSDN博客 xiaomin_____ 2016年3月
5.《使用Apache中的HttpClient的实例CloseableHttpClient的一个例子》 CSDN博客 坤哥玩CSDN 2016年6月
6. 《HttpClient Tutorial》 The Apache Software Foundation (HttpClient 4.5.5)
7. 《JavaScript HTML DOM》 W3School
8. 《Model Tree Structures in MongoDB》 MONGODB MANUAL 3.6
9. 《HTML(JS)+SOA+MongoDB简易架构实践经验》 CSDN博客 肖永威 2016年6月
10. 《网页表单文档设计及技术实现》 CSDN博客 肖永威 2015年5月