Простой HTTP-сервер в Java с использованием только Java SE API
Последнее обновление: 20.09.2018
Класс Java Bean должен соответствовать ряду ограничений:
иметь конструктор, который не принимает никаких параметров
определять для всех свойств, которые используются в jsp, методы геттеры и сеттеры
названия геттеров и сеттеров должны соответствовать условностям: перед именем переменной добавляется get (для геттера) и set (для сеттера), а название переменной включается с большой буквы. Например, если переменная называется firstName, то функции геттера и сеттера должны называться соответственно getFirstName и setFirstName.
Однако для переменных типа boolean для функции геттера используется вместо get приставка is. Например, переменная enabled и геттер isEnabled.
реализовать интерфейс Serializable или Externalizable
Рассмотрим, как использовать классы JavaBean. Допустим, у нас есть следующая структура:
В папке Java Resources/src расположен класс User со следующим кодом:
Import java.io.Serializable; public class User implements Serializable { private static final long serialVersionUID = 2041275512219239990L; private String name; private int age; public User() { this.name = ""; this.age = 0; } public User(String name, int age) { this.name = name; this.age = age; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } }
Данный класс представляет пользователя и является классом Java Bean: он реализует интерфейс Serializable, имеет конструктор без параметров, а его методы - геттеры и сеттеры, которые предоставляют доступ к переменным name и age, соответствуют условностям.
В папке WebContent определена страница user.jsp . Определим в ней следующий код:
Name: ${user.name}
Age: ${user.age}
Данная страница jsp получает извне объект user и с помощью синтаксиса EL выводит значения его свойств. Стоит обратить внимание, что здесь идет обращение к переменным name и age, хотя они являются приватными.
В папке Java Resources/src в файле HelloServlet.java определен сервлет HelloServlet:
Import java.io.IOException; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; @WebServlet("/hello") public class HelloServlet extends HttpServlet { protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { User tom = new User("Tom", 25); request.setAttribute("user", tom); getServletContext() .getRequestDispatcher("/user.jsp") .forward(request, response); } }
Сервлет создает объект User. Для передачи его на страницу user.jsp устанавливается атрибут "user" через вызов request.setAttribute("user", tom) . Далее происходит перенаправление на страницу user.jsp. И, таким образом, страница получит данные из сервлета.
Есть ли способ создать очень простой HTTP-сервер (поддерживающий только GET/POST) в Java, используя только API Java SE, без написания кода для ручного анализа HTTP-запросов и отформатирования HTTP-ответов вручную? Java SE API прекрасно инкапсулирует функциональность HTTP-клиента в HttpURLConnection, но существует ли аналоговый для HTTP-сервер функционал?
Просто, чтобы быть ясным, проблема, с которой я сталкиваюсь с множеством примеров ServerSocket, которые я видел в Интернете, заключается в том, что они выполняют собственный алгоритм синтаксического анализа/отклика запросов и обработку ошибок, что является утомительным, подверженным ошибкам и вряд ли быть всеобъемлющим, и я стараюсь избегать этого по этим причинам.
В качестве примера ручной HTTP-манипуляции, которую я пытаюсь избежать:
18 ответов
Начиная с Java SE 6 в Sun Oracle JRE имеется встроенный HTTP-сервер. В сводке пакета com.sun.net.httpserver описаны участвующие классы и приведены примеры.
Вот начальный пример, скопированный из их документов (тем не менее, всем, кто пытается его редактировать, потому что это ужасный кусок кода, пожалуйста, не копируйте, а не мой, более того, вы никогда не должны редактировать цитаты, если они не изменились. в первоисточнике). Вы можете просто скопировать и запустить его на Java 6+.
package com.stackoverflow.q3732109; import java.io.IOException; import java.io.OutputStream; import java.net.InetSocketAddress; import com.sun.net.httpserver.HttpExchange; import com.sun.net.httpserver.HttpHandler; import com.sun.net.httpserver.HttpServer; public class Test { public static void main(String args) throws Exception { HttpServer server = HttpServer.create(new InetSocketAddress(8000), 0); server.createContext("/test", new MyHandler()); server.setExecutor(null); // creates a default executor server.start(); } static class MyHandler implements HttpHandler { @Override public void handle(HttpExchange t) throws IOException { String response = "This is the response"; t.sendResponseHeaders(200, response.length()); OutputStream os = t.getResponseBody(); os.write(response.getBytes()); os.close(); } } }
Следует отметить, что часть response.length() в их примере плохая, это должна была быть response.getBytes().length . Даже в этом getBytes() метод getBytes() должен явно указывать кодировку, которую вы затем указываете в заголовке ответа. Увы, хотя и вводящий в заблуждение начинающих, в конце концов, это всего лишь базовый пример.
Выполните его и перейдите по адресу http://localhost: 8000/test, и вы увидите следующий ответ:
Что касается использования com.sun.* , Обратите внимание, что это, в отличие от того, что думают некоторые разработчики, абсолютно не запрещено общеизвестными часто задаваемыми вопросами. Почему разработчики не должны писать программы, называющие "солнечные" пакеты . Этот sun.misc.BASE64Encoder часто задаваемых вопросов касается пакета sun.* (Такого как sun.misc.BASE64Encoder) для внутреннего использования Oracle JRE (который, таким образом, уничтожит ваше приложение при запуске его на другом JRE), а не пакет com.sun.* . Sun/Oracle также просто разрабатывает программное обеспечение поверх API Java SE, как и любая другая компания, такая как Apache и так далее. Использование com.sun.* рекомендуется (но не запрещено), когда это касается реализации определенного Java API, такого как GlassFish (Java EE impl), Mojarra (JSF impl), Джерси (JAX-RS impl) и т.д.,
Решение com.sun.net.httpserver не переносится через JRE. Лучше использовать официальный API веб-сервисов в javax.xml.ws для загрузки минимального HTTP-сервера...
Import java.io._ import javax.xml.ws._ import javax.xml.ws.http._ import javax.xml.transform._ import javax.xml.transform.stream._ @WebServiceProvider @ServiceMode(value=Service.Mode.PAYLOAD) class P extends Provider { def invoke(source: Source) = new StreamSource(new StringReader("
Hello There!
")); } val address = "http://127.0.0.1:8080/" Endpoint.create(HTTPBinding.HTTP_BINDING, new P()).publish(address) println("Service running at "+address) println("Type +[C] to quit!") Thread.sleep(Long.MaxValue)EDIT: это действительно работает! Вышеприведенный код выглядит как Groovy или что-то в этом роде. Вот перевод на Java, который я тестировал:
Import java.io.*; import javax.xml.ws.*; import javax.xml.ws.http.*; import javax.xml.transform.*; import javax.xml.transform.stream.*; @WebServiceProvider @ServiceMode(value = Service.Mode.PAYLOAD) public class Server implements Provider