Java:在 JSON 中响应的简单 HTTP 服务器应用程序
Java: Simple HTTP Server application that responds in JSON
我想在 Java 中创建一个非常简单的 HTTP 服务器应用程序。
例如,如果我 运行 localhost 上的服务器,端口 8080,我从我的浏览器,我想得到一个 Json 数组,其中包含字符串 'hello world!':
http://localhost:8080/func1?param1=123¶m2=456
我想在服务器中有这样的东西(非常抽象的代码):
// Retunrs JSON String
String func1(String param1, String param2) {
// Do Something with the params
String jsonFormattedResponse = "['hello world!']";
return jsonFormattedResponse;
}
我想这个函数实际上不应该 "return" json,而是使用一些 HTTP 响应处理程序或类似的东西发送它...
最简单的方法是什么,无需熟悉多种具有特殊功能和方法的第 3 方库?
您可以使用包 com.sun.net.httpserver
中的 类:
import com.sun.net.httpserver.Headers;
import com.sun.net.httpserver.HttpServer;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.InetSocketAddress;
import java.net.URI;
import java.net.URLDecoder;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
public class JsonServer {
private static final String HOSTNAME = "localhost";
private static final int PORT = 8080;
private static final int BACKLOG = 1;
private static final String HEADER_ALLOW = "Allow";
private static final String HEADER_CONTENT_TYPE = "Content-Type";
private static final Charset CHARSET = StandardCharsets.UTF_8;
private static final int STATUS_OK = 200;
private static final int STATUS_METHOD_NOT_ALLOWED = 405;
private static final int NO_RESPONSE_LENGTH = -1;
private static final String METHOD_GET = "GET";
private static final String METHOD_OPTIONS = "OPTIONS";
private static final String ALLOWED_METHODS = METHOD_GET + "," + METHOD_OPTIONS;
public static void main(final String... args) throws IOException {
final HttpServer server = HttpServer.create(new InetSocketAddress(HOSTNAME, PORT), BACKLOG);
server.createContext("/func1", he -> {
try {
final Headers headers = he.getResponseHeaders();
final String requestMethod = he.getRequestMethod().toUpperCase();
switch (requestMethod) {
case METHOD_GET:
final Map<String, List<String>> requestParameters = getRequestParameters(he.getRequestURI());
// do something with the request parameters
final String responseBody = "['hello world!']";
headers.set(HEADER_CONTENT_TYPE, String.format("application/json; charset=%s", CHARSET));
final byte[] rawResponseBody = responseBody.getBytes(CHARSET);
he.sendResponseHeaders(STATUS_OK, rawResponseBody.length);
he.getResponseBody().write(rawResponseBody);
break;
case METHOD_OPTIONS:
headers.set(HEADER_ALLOW, ALLOWED_METHODS);
he.sendResponseHeaders(STATUS_OK, NO_RESPONSE_LENGTH);
break;
default:
headers.set(HEADER_ALLOW, ALLOWED_METHODS);
he.sendResponseHeaders(STATUS_METHOD_NOT_ALLOWED, NO_RESPONSE_LENGTH);
break;
}
} finally {
he.close();
}
});
server.start();
}
private static Map<String, List<String>> getRequestParameters(final URI requestUri) {
final Map<String, List<String>> requestParameters = new LinkedHashMap<>();
final String requestQuery = requestUri.getRawQuery();
if (requestQuery != null) {
final String[] rawRequestParameters = requestQuery.split("[&;]", -1);
for (final String rawRequestParameter : rawRequestParameters) {
final String[] requestParameter = rawRequestParameter.split("=", 2);
final String requestParameterName = decodeUrlComponent(requestParameter[0]);
requestParameters.putIfAbsent(requestParameterName, new ArrayList<>());
final String requestParameterValue = requestParameter.length > 1 ? decodeUrlComponent(requestParameter[1]) : null;
requestParameters.get(requestParameterName).add(requestParameterValue);
}
}
return requestParameters;
}
private static String decodeUrlComponent(final String urlComponent) {
try {
return URLDecoder.decode(urlComponent, CHARSET.name());
} catch (final UnsupportedEncodingException ex) {
throw new InternalError(ex);
}
}
}
附带说明,['hello world!']
无效 JSON。字符串必须用双引号括起来。
如果您已经熟悉 servlet,则不需要太多创建简单的服务器来实现您想要的。但我想强调的是,您的需求可能会迅速增加,因此您可能需要转向 RESTful 框架(例如:Spring WS、Apache CXF)。
您需要使用标准的 servlet 技术注册 URI 和获取参数。也许你可以从这里开始:http://docs.oracle.com/cd/E13222_01/wls/docs92/webapp/configureservlet.html
接下来,您需要一个 JSON 提供程序并以 JSON 格式对其进行序列化(也称为编组)。我推荐杰克逊。看看这个教程:
http://www.sivalabs.in/2011/03/json-processing-using-jackson-java-json.html
最后,您的代码将类似于:
public class Func1Servlet extends HttpServlet {
public void doGet(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
String p1 = req.getParameter("param1");
String p2 = req.getParameter("param2");
// Do Something with the params
ResponseJSON resultJSON = new ResponseJSON();
resultJSON.setProperty1(yourPropert1);
resultJSON.setProperty2(yourPropert2);
// Convert your JSON object into JSON string
Writer strWriter = new StringWriter();
mapper.writeValue(strWriter, resultJSON);
String resultString = strWriter.toString();
resp.setContentType("application/json");
out.println(resultString );
}
}
在您的 web.xml 中映射网址:
<servlet>
<servlet-name>func1Servlet</servlet-name>
<servlet-class>myservlets.func1servlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>func1Servlet</servlet-name>
<url-pattern>/func1/*</url-pattern>
</servlet-mapping>
请记住这是一个伪代码。您可以做很多事情来增强它,添加一些实用程序 类,等等...
然而,随着项目的增长,您对更全面的框架的需求变得更加明显。
你可以:
安装 Apache Tomcat,然后将 JSP 拖放到实现它的 ROOT 项目中。
我支持@xehpuk。使用标准 Java 编写自己的单个 class HTTP 服务器实际上并不难。如果你想在早期版本中这样做,你可以使用 NanoHTTPD,这是一个非常著名的单一 class HTTP 服务器实现。
我个人建议您查看 Apache Sling(几乎是 Java REST api 的参考实现)。您或许可以在此处使用 Sling 实现您的要求,而无需任何编程。
但正如其他人所建议的那样,执行此操作的标准方法是创建一个 java WAR 并将其部署到 'servlet container' 中,例如 Tomcat 或 Jetty 等
运行 main
在端口 8080
上启动服务器
public class Main {
public static void main(String[] args) throws LifecycleException {
Tomcat tomcat = new Tomcat();
Context context = tomcat.addContext("", null);
Tomcat.addServlet(context, "func1", new HttpServlet() {
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException {
Object response = func1(req.getParameter("param1"), req.getParameter("param2"));
ObjectMapper mapper = new ObjectMapper();
mapper.writeValue(resp.getWriter(), response);
}
});
context.addServletMappingDecoded("/func1", "func1");
tomcat.start();
tomcat.getServer().await();
}
private static String[] func1(String p1, String p2) {
return new String[] { "hello world", p1, p2 };
}
}
Gradle 依赖关系:
dependencies {
compile group: 'org.apache.tomcat.embed', name: 'tomcat-embed-core', version: '8.5.28' // doesn't work with tomcat 9
compile group: 'com.fasterxml.jackson.core', name: 'jackson-databind', version: '2.9.4'
}
我想在 Java 中创建一个非常简单的 HTTP 服务器应用程序。
例如,如果我 运行 localhost 上的服务器,端口 8080,我从我的浏览器,我想得到一个 Json 数组,其中包含字符串 'hello world!':
http://localhost:8080/func1?param1=123¶m2=456
我想在服务器中有这样的东西(非常抽象的代码):
// Retunrs JSON String
String func1(String param1, String param2) {
// Do Something with the params
String jsonFormattedResponse = "['hello world!']";
return jsonFormattedResponse;
}
我想这个函数实际上不应该 "return" json,而是使用一些 HTTP 响应处理程序或类似的东西发送它...
最简单的方法是什么,无需熟悉多种具有特殊功能和方法的第 3 方库?
您可以使用包 com.sun.net.httpserver
中的 类:
import com.sun.net.httpserver.Headers;
import com.sun.net.httpserver.HttpServer;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.InetSocketAddress;
import java.net.URI;
import java.net.URLDecoder;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
public class JsonServer {
private static final String HOSTNAME = "localhost";
private static final int PORT = 8080;
private static final int BACKLOG = 1;
private static final String HEADER_ALLOW = "Allow";
private static final String HEADER_CONTENT_TYPE = "Content-Type";
private static final Charset CHARSET = StandardCharsets.UTF_8;
private static final int STATUS_OK = 200;
private static final int STATUS_METHOD_NOT_ALLOWED = 405;
private static final int NO_RESPONSE_LENGTH = -1;
private static final String METHOD_GET = "GET";
private static final String METHOD_OPTIONS = "OPTIONS";
private static final String ALLOWED_METHODS = METHOD_GET + "," + METHOD_OPTIONS;
public static void main(final String... args) throws IOException {
final HttpServer server = HttpServer.create(new InetSocketAddress(HOSTNAME, PORT), BACKLOG);
server.createContext("/func1", he -> {
try {
final Headers headers = he.getResponseHeaders();
final String requestMethod = he.getRequestMethod().toUpperCase();
switch (requestMethod) {
case METHOD_GET:
final Map<String, List<String>> requestParameters = getRequestParameters(he.getRequestURI());
// do something with the request parameters
final String responseBody = "['hello world!']";
headers.set(HEADER_CONTENT_TYPE, String.format("application/json; charset=%s", CHARSET));
final byte[] rawResponseBody = responseBody.getBytes(CHARSET);
he.sendResponseHeaders(STATUS_OK, rawResponseBody.length);
he.getResponseBody().write(rawResponseBody);
break;
case METHOD_OPTIONS:
headers.set(HEADER_ALLOW, ALLOWED_METHODS);
he.sendResponseHeaders(STATUS_OK, NO_RESPONSE_LENGTH);
break;
default:
headers.set(HEADER_ALLOW, ALLOWED_METHODS);
he.sendResponseHeaders(STATUS_METHOD_NOT_ALLOWED, NO_RESPONSE_LENGTH);
break;
}
} finally {
he.close();
}
});
server.start();
}
private static Map<String, List<String>> getRequestParameters(final URI requestUri) {
final Map<String, List<String>> requestParameters = new LinkedHashMap<>();
final String requestQuery = requestUri.getRawQuery();
if (requestQuery != null) {
final String[] rawRequestParameters = requestQuery.split("[&;]", -1);
for (final String rawRequestParameter : rawRequestParameters) {
final String[] requestParameter = rawRequestParameter.split("=", 2);
final String requestParameterName = decodeUrlComponent(requestParameter[0]);
requestParameters.putIfAbsent(requestParameterName, new ArrayList<>());
final String requestParameterValue = requestParameter.length > 1 ? decodeUrlComponent(requestParameter[1]) : null;
requestParameters.get(requestParameterName).add(requestParameterValue);
}
}
return requestParameters;
}
private static String decodeUrlComponent(final String urlComponent) {
try {
return URLDecoder.decode(urlComponent, CHARSET.name());
} catch (final UnsupportedEncodingException ex) {
throw new InternalError(ex);
}
}
}
附带说明,['hello world!']
无效 JSON。字符串必须用双引号括起来。
如果您已经熟悉 servlet,则不需要太多创建简单的服务器来实现您想要的。但我想强调的是,您的需求可能会迅速增加,因此您可能需要转向 RESTful 框架(例如:Spring WS、Apache CXF)。
您需要使用标准的 servlet 技术注册 URI 和获取参数。也许你可以从这里开始:http://docs.oracle.com/cd/E13222_01/wls/docs92/webapp/configureservlet.html
接下来,您需要一个 JSON 提供程序并以 JSON 格式对其进行序列化(也称为编组)。我推荐杰克逊。看看这个教程: http://www.sivalabs.in/2011/03/json-processing-using-jackson-java-json.html
最后,您的代码将类似于:
public class Func1Servlet extends HttpServlet {
public void doGet(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
String p1 = req.getParameter("param1");
String p2 = req.getParameter("param2");
// Do Something with the params
ResponseJSON resultJSON = new ResponseJSON();
resultJSON.setProperty1(yourPropert1);
resultJSON.setProperty2(yourPropert2);
// Convert your JSON object into JSON string
Writer strWriter = new StringWriter();
mapper.writeValue(strWriter, resultJSON);
String resultString = strWriter.toString();
resp.setContentType("application/json");
out.println(resultString );
}
}
在您的 web.xml 中映射网址:
<servlet>
<servlet-name>func1Servlet</servlet-name>
<servlet-class>myservlets.func1servlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>func1Servlet</servlet-name>
<url-pattern>/func1/*</url-pattern>
</servlet-mapping>
请记住这是一个伪代码。您可以做很多事情来增强它,添加一些实用程序 类,等等...
然而,随着项目的增长,您对更全面的框架的需求变得更加明显。
你可以:
安装 Apache Tomcat,然后将 JSP 拖放到实现它的 ROOT 项目中。
我支持@xehpuk。使用标准 Java 编写自己的单个 class HTTP 服务器实际上并不难。如果你想在早期版本中这样做,你可以使用 NanoHTTPD,这是一个非常著名的单一 class HTTP 服务器实现。
我个人建议您查看 Apache Sling(几乎是 Java REST api 的参考实现)。您或许可以在此处使用 Sling 实现您的要求,而无需任何编程。
但正如其他人所建议的那样,执行此操作的标准方法是创建一个 java WAR 并将其部署到 'servlet container' 中,例如 Tomcat 或 Jetty 等
运行 main
在端口 8080
public class Main {
public static void main(String[] args) throws LifecycleException {
Tomcat tomcat = new Tomcat();
Context context = tomcat.addContext("", null);
Tomcat.addServlet(context, "func1", new HttpServlet() {
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException {
Object response = func1(req.getParameter("param1"), req.getParameter("param2"));
ObjectMapper mapper = new ObjectMapper();
mapper.writeValue(resp.getWriter(), response);
}
});
context.addServletMappingDecoded("/func1", "func1");
tomcat.start();
tomcat.getServer().await();
}
private static String[] func1(String p1, String p2) {
return new String[] { "hello world", p1, p2 };
}
}
Gradle 依赖关系:
dependencies {
compile group: 'org.apache.tomcat.embed', name: 'tomcat-embed-core', version: '8.5.28' // doesn't work with tomcat 9
compile group: 'com.fasterxml.jackson.core', name: 'jackson-databind', version: '2.9.4'
}