Это то, как мы в настоящее время управляем нашей клиент-серверной связью. Мы используем архитектуру JavaEE без сохранения состояния и предоставляем все как службы REST. Это позволяет нам масштабировать горизонтально, добавляя больше серверов и просто добавляя их к записи кластера в конфигурации Glassfish.
Однако из-за отсутствия отражения или работающей JSON-библиотеки это заставляет нас внедрять метод toJson () в каждый объект передачи данных BY HAND (будьте внимательны с учетом регистра). Мы добавили наш серверный проект в качестве модуля в метапроект PlayN и добавили ядро в качестве зависимости от сервера. Таким образом, вы можете поместить каждый DTO в основной проект (что довольно здорово). Размещение их на сервере приводит к тому, что люди пытаются аннотировать классы как сущности, что приводит к сбою во время сборки html. В настоящее время я думаю о добавлении общего проекта в сборку, как в проектах GWT.
Вот как мы отправляем данные на сервер (для этого примера без какой-либо абстракции сделайте себе одолжение и используйте его):
private void loadMapFromServer() {
SessionDto session = this.main.getSessionCtrl().getSessionMdl();
PlayN.net().post("http://localhost:8080/server/rest/map/mapMdl",
session.toJson(),
new Callback<String>() {
@Override
public void onSuccess(String result) {
mapMdl = new MapDto();
}
@Override
public void onFailure(Throwable cause) {
PlayN.log().error("fail " + cause.getMessage());
}
});
}
Обратите внимание, как мы убираем аргумент POST с помощью session.toJson (). Это связано с отсутствующей функцией MIME-типа, и передача строк JSON через GWT не удастся.
А вот как это выглядит на сервере:
package com.fact.server;
//I also posted the imports, for clarity.
import com.fact.core.map.MapDto;
import com.fact.core.user.SessionDto;
import com.fact.server.game.map.MapCtrl;
import com.google.gson.Gson;
import javax.ejb.Stateless;
import javax.inject.Inject;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import org.apache.log4j.Logger;
@Stateless
@Path("/map")
public class MapSrvs {
@Inject
Logger logger;
@Inject
MapCtrl mapCtrl;
Gson gson = new Gson();
@POST
@Path("/mapMdl/")
@Produces( MediaType.APPLICATION_JSON )
public MapDto getMapMdl(String sessionDtoStr) {
//logger.info("map was requested: " + sessionDtoStr);
// Use gson to deserialize the class. Jersey would do this, if PlayN
// would allow to set a correct MIME type (and @Consumes was set).
// We could simply write: getMapMdl(SessionDto sessionDto)
SessionDto sessionDto = gson.fromJson(sessionDtoStr, SessionDto.class);
if(sessionDto == null) {
return null;
}
// [...] check for a valid session
MapDto mapMdl = new MapDto();
mapMdl.foo = "message from server";
return mapMdl;
}
}
Это было бы немного лучше, если бы PlayN позволял вам устанавливать тип MIME, чтобы вам не приходилось разыгрывать String с помощью Gson. Однако это работает довольно хорошо. Мы используем Джерси на стороне сервера для обработки всего остального. Чтобы запустить его, мне нужно было поместить в файл web.xml следующее:
<servlet>
<!-- We need jersey for the REST stuff -->
<servlet-name>jersey-serlvet</servlet-name>
<servlet-class>
com.sun.jersey.spi.container.servlet.ServletContainer
</servlet-class>
<init-param>
<param-name>com.sun.jersey.config.property.packages</param-name>
<param-value>com.fact.server</param-value>
</init-param>
<init-param>
<!-- This took me hours to find :(. It is needed to automatically
map POJOs to JSON code. -->
<param-name>com.sun.jersey.api.json.POJOMappingFeature</param-name>
<param-value>true</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>jersey-serlvet</servlet-name>
<url-pattern>/rest/*</url-pattern>
</servlet-mapping>
Также Джерси уже включен в Java-EE-Api, так что он работает "из коробки". Надеюсь, это поможет. Если кто-нибудь знает, как выполнить анализ JSON на стороне клиента, посмотрите на этот вопрос: Как преобразовать POJO в JSON в PlayN?