2015-02-17 11 views
7

Chcę utworzyć bardzo prostą aplikację serwera HTTP w Javie.Java: Prosta aplikacja serwera HTTP, która odpowiada w JSON

Na przykład, jeśli mogę uruchomić serwer na localhost w porcie , i robię się następujące połączenia z mojej przeglądarce, chcę otrzymać tablicę JSON z ciągu znaków „Hello World!”:

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

chciałbym mieć w czymś serwera, który wygląda następująco (kod bardzo abstrakcyjnego):

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

    return jsonFormattedResponse; 
} 

myślę, że ta funkcja nie powinna właściwie „powrót” JSON , ale aby wysłać go za pomocą instrukcji obsługi HTTP lub czegoś podobnego ...

Co to jest najprostszy sposób to zrobić, bez konieczności zapoznania się z wieloma rodzajami bibliotek stron trzecich, które mają specjalne funkcje i metodologię?

+3

Spróbuj poszukać tutorial serwletów. Przykład: http://www.tutorialspoint.com/servlets/ – Mike

+1

Spring Boot sprawia, że ​​tego typu rzeczy są bardzo łatwe, ale jak sugerujesz, ma * ogromną * złożoność pod maską. Byłoby to tak proste, jak kilka zależności POM i około 5 linii kodu. Na stronie Spring Boot znajdują się dobre HOWTO. –

Odpowiedz

9

Można użyć klas z pakietu 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

Uwaga: Pakiet 'httpserver' wydaje się być" ograniczonym API "w Eclipse. Aby obejść, zobacz [tutaj] (http://stackoverflow.com/a/29329228/1639625) –

1

Jeśli jesteś już zaznajomiony z serwletu nie trzeba wiele, aby stworzyć prosty serwer, aby osiągnąć to, co chcesz. Ale chciałbym podkreślić, że twoje potrzeby prawdopodobnie szybko wzrosną i dlatego możesz potrzebować przejścia do RESTful framework (np .: Spring WS, Apache CXF).

Należy zarejestrować identyfikatory URI i pobrać parametry przy użyciu standardowej technologii serwletu. Może zaczniesz tutaj: http://docs.oracle.com/cd/E13222_01/wls/docs92/webapp/configureservlet.html

Następnie potrzebujesz dostawcy JSON i serializacji (aka marshall) w formacie JSON. Polecam JACKSON. Spójrz w tym tutorialu: http://www.sivalabs.in/2011/03/json-processing-using-jackson-java-json.html

Wreszcie, Twój kod będzie wyglądał podobnie do tego:

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

Mapa adresy URL w 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> 

Pamiętaj, to jest pseudokod. Jest wiele rzeczy, które możesz zrobić, aby ją ulepszyć, dodając kilka klas użytkowych itp.

Niemniej jednak, wraz z rozwojem twojego projektu, twoja potrzeba stworzenia bardziej wszechstronnych ram staje się bardziej oczywista.

+0

Dziękuję za odpowiedź. Jak w twoim kodzie mogę zdefiniować, że będzie on wywoływany tylko dla 'func1'? Jeśli otrzymam połączenie z 'func2', chciałbym odpowiedzieć inaczej – SomethingSomething

+1

Jednym ze sposobów, aby to zrobić, mapować func1 na klasę i func2 na inną klasę ... istnieje wiele innych sposobów, aby to zrobić, ale to jest najprostsze . – Rafa

1

Mogłeś:

Instalacja Apache Tomcat, i po prostu upuścić JSP do projektu głównego, który implementuje ten.

I sekunda @xehpuk. W rzeczywistości nie jest trudno napisać własny serwer HTTP z jedną klasą przy użyciu standardowej Java. Jeśli chcesz to zrobić we wcześniejszych wersjach, możesz użyć NanoHTTPD, która jest dość dobrze znaną implementacją serwera HTTP jednej klasy.

Osobiście polecam zapoznanie się z procesem Apache Sling (w zasadzie implementacja referencyjna apletu REST Java). Możesz prawdopodobnie zaimplementować swoje wymagania tutaj, używając Sling bez jakiegokolwiek programowania.

Ale jak inni sugerowali, standardowy sposób to zrobić jest stworzenie java WAR i wdrożyć go w „kontenerze serwletów” takich jak Tomcat lub Jetty itp

0

Run main aby uruchomić serwer na porcie 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 zależności:

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' 
} 
Powiązane problemy