Чем проще, тем лучше. Понятно, что есть нетривиальные требования, есть сложные задачи. Но признаемся себе, сколько простых ненагруженных сервисов вы реализовали используя слишком мощные и сложные инструменты? "Я привык к этому фреймфорку и не хочу терять скилл" - слышу я обычно. "Ты уйдёшь и тот, кто будет поддерживать этот монстрокод, проклянёт тебя" - думаю я в ответ.
Может я и не убедил вас писать простые вещи простыми средствами, но посмотрите все-таки как можно сделать серверное java-приложение вообще без сервера. Это, в конце концов, интересно.
Как, вообще без сервера? Писать обработку запросов самому?
Ну, нет, что вы. Я за простые решения, но не за велосипеды. Все уже написано и, более того, уже установлено. Java-сервер уже есть в вашем jdk. Просто используйте его )
import com.sun.net.httpserver.HttpServer; import java.io.IOException; import java.net.InetSocketAddress; import java.util.concurrent.Executors; public class Main { private static final int PORT = 9090; public static void main(String[] args) throws IOException { int port = PORT; if (args.length > 0) { try { port = Integer.parseInt(args[0]); } catch (Exception e) { e.printStackTrace(); } } HttpServer server = HttpServer.create(new InetSocketAddress(port), 0); server.createContext("/publish", new PublishHandler()); server.createContext("/subscribe", new SubscribeHandler()); server.setExecutor(Executors.newCachedThreadPool()); server.start(); System.out.println("Server is listening on port " + port); } }
com.sun.net.HttpServer - вот все что нам нужно. Наше приложение будет слушать запросы на порту 9090 или том, что будет указан java -jar наш.jar тут. Наши обработчики мы навешиваем на контексты перед стартом сервера. Все предельно просто. Чтобы в обработчиках сосредоточиться на бизнес-логике, сделаем им абстрактный предок, где порешаем все мелочи вроде вычитывания параметров зарпроса и логирования пары запрос-ответ:
import com.sun.net.httpserver.HttpExchange; import com.sun.net.httpserver.HttpHandler; import java.io.IOException; import java.io.OutputStream; import java.text.SimpleDateFormat; import java.util.Date; import java.util.HashMap; import java.util.Map; import java.util.UUID; public abstract class HttpHandlerBased implements HttpHandler { protected abstract String doGet(HttpExchange exchange, Map<String, String> params); @Override public void handle(HttpExchange exchange) throws IOException { String requestMethod = exchange.getRequestMethod(); if (requestMethod.equalsIgnoreCase("GET")) { String uriStr = exchange.getRequestURI().getQuery(); String id = UUID.randomUUID().toString().replace("-", ""); log("[req " + id + "] " + uriStr); Map<String, String> pars = new HashMap<String, String>(); String[] pairs; if (uriStr != null && uriStr.contains("=")) { if (uriStr.contains("&")) pairs = uriStr.split("&"); else pairs = new String[]{uriStr}; for (String pair : pairs) { String[] p = pair.split("="); if (p.length == 2) { pars.put(p[0], p[1]); } } } String resp = doGet(exchange, pars); log("[rsp " + id + "] " + resp); exchange.sendResponseHeaders(200, resp.length()); OutputStream body = exchange.getResponseBody(); body.write(resp.getBytes("UTF-8")); body.close(); } } public static void log(String msg) { System.out.println(new SimpleDateFormat("HH:mm:ss:SSS dd.MM.yy").format(new Date())+" - "+msg); } }
Имея "за плечами" такого предка, нам останется реализовать метод doGet, в каждом конкретном "сервлете". Метод POST я тут не обрабатываю потому что он мне не нужен. Но обработать его не сложнее, можете попробовать сами.
Итак, что же мы получаем?
Для "секретного web-сервера", по сути внутреннего API java, мы имеем очень приятные инструменты для работы с данными запроса, заголовками ответа и т.п. Все это не требует никакой установки, настройки, есть прямо "в коробке" и готово к работе. Чем не инструмент для простого web-сервиса? Конечно, когда мы проверим свою идею и задумаемся о продакшене, можно перенести свою бизнес-логику в "честные" сервлеты и использовать тот же tomcat или resin. Почему бы и нет? Но если проект не пойдёт в продакшн мы скажем себе спасибо за то, что не привлекали админов, не тратили дни на развертывание и настройку окружения, а просто взяли и сделали то что было нужно. И не более того.
http://sparkjava.com/ тут как по мне намного проще
ОтветитьУдалитьесли нужно что то поумнее - есть springboot
ещё пару интересных java-серверов. Я не против. Но фишка описанного выше способа - в отсутствии вообще чего-либо кроме стандартной jdk.
УдалитьИнтересное решение, но не очень понятно - как управлять заголовками?
ОтветитьУдалитьне проще ли сервлет создать
ОтветитьУдалитьКак Вы сервлет запустите без контейнера?
ОтветитьУдалитьПро заголовки
ОтветитьУдалитьexchange.getResponseHeaders().put("Content-Type", Arrays.asList("text/plain; charset=UTF-8"));
и размер задать
byte[] bytes = builder.toString().getBytes();
exchange.sendResponseHeaders(200, bytes.length);
Nice Blog Post !
ОтветитьУдалить