基于Java内置的HttpServer实现轻量级Restful
在服务架构体系里,例如传统的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月