Java: Simple HTTP Server application that responds in JSON

后端 未结 4 1793
天命终不由人
天命终不由人 2021-02-15 19:56

I want to create a very simple HTTP server application in Java.

For example, if I run the server on localhost in port 8080, and I make

相关标签:
4条回答
  • 2021-02-15 20:43

    You could use classes from the package 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);
            }
        }
    }
    
    0 讨论(0)
  • 2021-02-15 20:44

    You could :

    Install Apache Tomcat, and just drop a JSP into the ROOT project that implements this.

    I second @xehpuk. It's not actually that hard to write your own single class HTTP server using just standard Java. If you want to do it in earlier versions you can use NanoHTTPD, which is a pretty well known single class HTTP server implementation.

    I would personally recommend that you look into Apache Sling (pretty much THE Reference implementation of a Java REST api). You could probably implement your requirements here using Sling without ANY programming at all.

    But as others have suggested, the standard way to do this is to create a java WAR and deploy it into a 'servlet container' such as Tomcat or Jetty etc.

    0 讨论(0)
  • 2021-02-15 20:57

    If you are already familiar with servlet you do not need much to create a simple server to achieve what you want. But I would like to emphasize that your needs will likely to increase rapidly and therefore you may need to move to a RESTful framework (e.g.: Spring WS, Apache CXF) down the road.

    You need to register URIs and get parameters using the standard servlet technology. Maybe you can start here: http://docs.oracle.com/cd/E13222_01/wls/docs92/webapp/configureservlet.html

    Next, you need a JSON provider and serialize (aka marshall) it in JSON format. I recommend JACKSON. Take a look at this tutorial: http://www.sivalabs.in/2011/03/json-processing-using-jackson-java-json.html

    Finally, your code will look similar to this:

    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 );
      }
    }
    

    Map URLs in your 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>
    

    Keep in mind this is a pseudo-code. There are lots you can do to enhance it, adding some utility classes, etc...

    Nevertheless, as your project grows your need for a more comprehensive framework becomes more evident.

    0 讨论(0)
  • 2021-02-15 20:59

    Run main to start the server on port 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:

    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'
    }
    
    0 讨论(0)
提交回复
热议问题