Java:简单的HTTP服务器应用程序,以JSON响应

relj7zay  于 2023-04-04  发布在  Java
关注(0)|答案(5)|浏览(183)

我想用Java创建一个非常简单的HTTP服务器应用程序。
例如,如果我在端口8080localhost上运行服务器,并从浏览器中调用以下调用,我希望获得字符串为'hello world!'的Json数组:

http://localhost:8080/func1?param1=123&param2=456

我想在服务器中有一些看起来像这样的东西(非常抽象的代码):

// Retunrs JSON String
String func1(String param1, String param2) {
    // Do Something with the params
    String jsonFormattedResponse = "['hello world!']";

    return jsonFormattedResponse;
}

我猜这个函数实际上不应该“返回”json,而是使用一些HTTP响应处理程序或类似的东西发送它。
最简单的方法是什么,而不需要熟悉许多具有特殊功能和方法的第三方库?

jvlzgdj9

jvlzgdj91#

你可以使用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。字符串必须用双引号括起来。

5kgi1eie

5kgi1eie2#

您可以:
安装ApacheTomcat,然后将JSP放到实现它的ROOT项目中。
我第二个@xehpuk。使用标准Java编写自己的单类HTTP服务器实际上并不难。如果你想在早期版本中这样做,你可以使用NanoHTTPD,这是一个非常知名的单类HTTP服务器实现。
我个人建议你看看Apache Sling(几乎是Java REST API的参考实现)。你可以在这里使用Sling实现你的需求,而不需要任何编程。
但正如其他人所建议的,标准的方法是创建一个java WAR并将其部署到“servlet容器”中,如Tomcat或Jetty等。

2vuwiymt

2vuwiymt3#

如果你已经熟悉servlet,你不需要太多来创建一个简单的服务器来实现你想要的。但我想强调的是,你的需求可能会迅速增加,因此你可能需要转移到一个RESTful框架(例如:Spring WS、Apache CXF)。
您需要使用标准servlet技术注册URI并获取参数。也许您可以从这里开始:http://docs.oracle.com/cd/E13222_01/wls/docs92/webapp/configureservlet.html
接下来,您需要一个JSON提供程序并将其序列化(aka马歇尔)为JSON格式。我推荐使用Jackson。看看这个教程: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 );
  }
}

Mapweb.xml中的URL:

<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>

请记住这是一个伪代码。你可以做很多事情来增强它,添加一些实用程序类,等等。
然而,随着项目的增长,您对更全面的框架的需求变得更加明显。

zlwx9yxi

zlwx9yxi4#

运行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'
}
ctrmrzij

ctrmrzij5#

有了新的SeBootStrap API,事情变得简单了:

// SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0

package jaxrs.examples.bootstrap;

import java.util.Collections;
import java.util.Set;

import jakarta.ws.rs.ApplicationPath;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.core.Application;

@ApplicationPath("helloworld")
@Path("hello")
public class HelloWorld extends Application {

    @Override
    public Set<Class<?>> getClasses() {
        return Collections.singleton(HelloWorld.class);
    }

    @GET
    public String sayHello() {
        return "Hello, World!";
    }

}

来源:https://github.com/jakartaee/rest/blob/master/examples/src/main/java/jaxrs/examples/bootstrap/HelloWorld.java
这将在helloworld/hello处提供字符串Hello, World!
你需要一些样板代码:

public static void main(final String[] args) throws InterruptedException {
    SeBootstrap.start(HelloWorld.class).thenAccept(instance -> {
        instance.stopOnShutdown(stopResult ->
                System.out.printf("Stop result: %s [Native stop result: %s].%n", stopResult,
                        stopResult.unwrap(Object.class)));
        final URI uri = instance.configuration().baseUri();
        System.out.printf("Instance %s running at %s [Native handle: %s].%n", instance, uri,
                instance.unwrap(Object.class));
        System.out.println("Send SIGKILL to shutdown.");
    });

    Thread.currentThread().join();
}

为了创建JSON,我推荐两个API:

  • GSon作为一个非常精简的API
  • Jackson。你会发现几十个教程在那里。

完整的教程可以在https://headcrashing.wordpress.com/2022/05/28/coding-microservice-from-scratch-part-1-of-7-jax-rs-done-right-head-crashing-informatics-53/找到。

相关问题