2015-02-17 18 views
7

Tôi muốn tạo một ứng dụng máy chủ HTTP rất đơn giản trong Java.Java: Ứng dụng Máy chủ HTTP đơn giản phản hồi trong JSON

Ví dụ, nếu tôi chạy các máy chủ trên localhost tại cảng , và tôi làm cho đến sau cuộc gọi từ trình duyệt của tôi, tôi muốn có được một mảng với chuỗi Json 'hello world!':

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

tôi muốn có một cái gì đó trong máy chủ đó trông như thế này (mã rất trừu tượng):

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

    return jsonFormattedResponse; 
} 

tôi đoán rằng chức năng này không nên thực sự "trở lại" các json , nhưng để gửi nó bằng cách sử dụng một số trình xử lý phản hồi HTTP hoặc một cái gì đó tương tự ...

Cách đơn giản nhất để làm điều đó là gì, không cần làm quen với nhiều loại thư viện của bên thứ ba có các tính năng và phương pháp đặc biệt?

+3

Hãy thử tìm ra một hướng dẫn về servlets. Ví dụ: http://www.tutorialspoint.com/servlets/ – Mike

+1

Khởi động mùa xuân làm cho loại điều này rất dễ dàng, nhưng khi bạn ngụ ý có một số lượng * lớn * phức tạp dưới mui xe. Nó sẽ dễ dàng như một vài phụ thuộc POM và khoảng 5 dòng mã mặc dù. Có những HOWTO tốt trên trang web Spring Boot. –

Trả lời

9

Bạn có thể sử dụng các lớp học từ gói 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); 
     } 
    } 
} 
+2

Lưu ý: Gói 'httpserver' có vẻ là" API bị hạn chế "trong Eclipse. Để tránh né, hãy xem [tại đây] (http://stackoverflow.com/a/29329228/1639625) –

1

Nếu bạn đã quen thuộc với servlet bạn không cần nhiều để tạo ra một máy chủ đơn giản để đạt được những gì bạn muốn. Nhưng tôi muốn nhấn mạnh rằng nhu cầu của bạn có thể sẽ tăng lên nhanh chóng và do đó bạn có thể cần phải chuyển sang một khung làm việc RESTful (ví dụ: Spring WS, Apache CXF) trên đường.

Bạn cần đăng ký URI và nhận thông số bằng công nghệ servlet chuẩn. Có thể bạn có thể bắt đầu tại đây: http://docs.oracle.com/cd/E13222_01/wls/docs92/webapp/configureservlet.html

Tiếp theo, bạn cần một nhà cung cấp JSON và sắp đặt hàng tuần (còn gọi là marshall) ở định dạng JSON. Tôi khuyên bạn nên JACKSON. Hãy xem hướng dẫn này: http://www.sivalabs.in/2011/03/json-processing-using-jackson-java-json.html

Cuối cùng, mã của bạn sẽ trông giống như thế này:

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 URL trong web.xml của bạn:

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

Hãy nhớ đây là một mã giả. Có rất nhiều việc bạn có thể làm để tăng cường, thêm một số lớp tiện ích, v.v.

Tuy nhiên, khi dự án của bạn phát triển nhu cầu cho một khuôn khổ toàn diện hơn trở nên rõ ràng hơn.

+0

Cảm ơn câu trả lời của bạn. Làm thế nào trong mã của bạn tôi có thể xác định rằng nó sẽ được gọi là chỉ cho 'func1'? Nếu tôi nhận được một cuộc gọi với 'func2', tôi muốn trả lời khác nhau – SomethingSomething

+1

Một cách để làm điều đó, ánh xạ func1 đến một lớp và func2 đến một lớp khác ... có nhiều cách khác để thực hiện, nhưng đây là cách đơn giản nhất . – Rafa

1

Bạn có thể:

Cài đặt Apache Tomcat và chỉ thả JSP vào dự án ROOT triển khai thực hiện điều này.

Tôi thứ hai @xehpuk. Nó không thực sự là khó để viết máy chủ HTTP lớp duy nhất của bạn bằng cách sử dụng Java tiêu chuẩn. Nếu bạn muốn thực hiện nó trong các phiên bản trước, bạn có thể sử dụng NanoHTTPD, đây là một triển khai máy chủ HTTP đơn lớp khá nổi tiếng.

Cá nhân tôi khuyên bạn nên xem xét Apache Sling (thực hiện khá nhiều tham chiếu của api REST Java). Bạn có thể có thể thực hiện yêu cầu của bạn ở đây bằng cách sử dụng Sling mà không có bất kỳ lập trình nào cả.

Nhưng như những người khác đã gợi ý, cách tiêu chuẩn để làm điều này là để tạo ra một java WAR và triển khai nó thành một 'servlet container' như Tomcat hoặc Jetty, vv

0

Run main để khởi động server trên cổng 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 phụ thuộc:

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' 
} 
Các vấn đề liên quan