Класс 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
. Определим в ней следующий код:
User Java Bean Page
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. И,
таким образом, страница получит данные из сервлета.
Когда я начинал работать в Java EE, серверная инфраструктура казалась мне загадочным капризным монстром. И это при том, что в программирование я пришёл из админов. Залил ear в Resin, проверь, поднялся ли? Успешно ли распаковался? Однажды мы с админами потратили полночи чтобы понять, почему после успешного вроде бы деплоя на запросы отвечает по-прежнему старая копия приложения. При таких танцах с бубном переход на GlassFish казался хорошим решением, а отказ от ejb - ещё лучшим. Кто-то из моих коллег радовался могуществу Spring, кто-то искал что-то попроще... Я писал сервлеты под tomcat, а когда делал что-то совсем маленькое - просто встраивал jetty.
Чем проще, тем лучше. Понятно, что есть нетривиальные требования, есть сложные задачи. Но признаемся себе, сколько простых ненагруженных сервисов вы реализовали используя слишком мощные и сложные инструменты? "Я привык к этому фреймфорку и не хочу терять скилл" - слышу я обычно. "Ты уйдёшь и тот, кто будет поддерживать этот монстрокод, проклянёт тебя" - думаю я в ответ.
Может я и не убедил вас писать простые вещи простыми средствами, но посмотрите все-таки как можно сделать серверное 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(" "
+
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(" "
+
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. Почему бы и нет? Но если проект не пойдёт в продакшн мы скажем себе спасибо за то, что не привлекали админов, не тратили дни на развертывание и настройку окружения, а просто взяли и сделали то что было нужно. И не более того.
Как вы наверное уже знаете - L2jServer сменил политику обновлений своих кодов и теперь обновления выходят примерно один раз в месяц, но тем не менее, код остается открытым и доступным для всех желающих изучить и установить Freya.
→
L2Teon проделал почти 150 корректировок кода с момента выхода прошлой ревизии java сервера Lineage 2 Interlude. Благодаря этому была повышена безопасность и отказоустойчивость сервера. Обновлена защита заточки предметов, исправлен спавн-лист. Исправлен баг с питомцами. Отключена загрузка AI с ядра, теперь только с «\data\scripts\ai\». Исправлены умения: Curse of Doom, Anchor, Mirage. Исправлен баг со складом (не верно указаны данные FloodProtector). Исправлен баг с исчезновением питомца после смерти. Исправлены умения Spell Force и Batle Force. Закрыта возможность чрезмерной заточки предметов. Исправление записей таблицы NPC благодаря которому нет ошибок в консоли.
→
Разработка Java сервера Lineage 2 Gracia Epilogue или просто Plus продолжается, и сегодня для владельцев серверов на базе L2Open-Team доступно следующее обновление. Добавлена опция отвечающая за шанс поднятия уровня Soul Crystal. Исправлен третий этаж в Steel Citadel, точнее возможность на него перейти. Добавлено восстановление маны Шаманом Орков при ударах. Исправлено получение магической поддержки новичкам. Исправление невидимости персонажей. Были добавлены семена манора по Lineage 2 Gracia Epilogue. Добавлен новый квест Pailaka Injured Dragon (необходим тест). В движке реализовано умение "Семь Стрел (Seven Arrow)". Добавлены Эвенты: Последний Герой и Захват Базы. Администратору доступен телепорт ко всем Рейд Боссам Gracia.
→
В очередной раз вышло обновление сборки сервера Lineage 2 Epilogue от команды L2jServer с ревизией 4309 у ядра и 7529 у датапака. Исправлено отображение окна действий при совершении трансформации. Возможность активации кэширования всех имен существующих персонажей. Исправление проблемы с отключением авто-сосок на одетом оружии. Добавлена настройка дальности вещания событий с кораблями. Доступна новая опция включения Чемпионов для спавна на карту. Реализация клановых дирижаблей, исправление пути полета в квестах. Добавлена поддержка более точного поиска двойных окон. Был исправлена ошибка Геодвига из-за которой выводилось "Can"t see target". В транспортных средствах теперь невозможно производить торговлю. Дроплист проверяется при загрузке сервера на предмет "левых" предметов.
Есть ли способ создать очень простой 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