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

  Mongo DB存储样例结构如下图所示:
这里写图片描述

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

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

  1、 服务架构
  
  整体架构为服务架构,其中Web服务由Apache HttpServer提供,使用HTML5、Javascript、CSS;业务服务由SUN Httpserver技术开发为Restful服务;人工智能由Python开发并提供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文件中。
这里写图片描述
  (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应用程序,执行结果如下图所示:
这里写图片描述

  使用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月

Logo

权威|前沿|技术|干货|国内首个API全生命周期开发者社区

更多推荐