我在PlayN中编写了一个游戏,它必须与带有Seam的JavaEE-Server进行通信。 首先,我只需要在HTML5中运行游戏。
当前的问题是PlayN客户端和JavaEE-Server之间的通信
1)首先,我尝试通过PlayN.net()接口进行通信,使用JSON交换信息。由于PlayN在端口8888上运行而服务器在8080上运行,因此我正确地遇到了同源策略的问题。
2)现在我正在寻找一个有效的解决方案。你会推荐哪一个?你有其他想法吗?
a)我正在尝试使用RPC,如How to handle RPCs in client-server PlayN game?中所述 ,使用GWT-syncproxy。
b)我尝试playN在与服务器相同的端口上运行,即8080 - 所以我不再遇到同源策略的问题。问题:HTML5 playN app可以在同一个端口上运行吗? 因此,当我使用Eclipse启动JavaEE-Server时,它还应该在端口8080上启动PlayN Web应用程序,对吗?
这可能吗?
c)最苛刻的解决方案(目前正在运行):服务器将JSON-String写入文件,playN客户端读取该文件。
你推荐什么?我想实施解决方案2,因为它是最干净的解决方案,但我不知道它有多难以及它是如何工作的。
感谢您的帮助!
答案 0 :(得分:3)
我认为问题在于您正在“运行”与您的Seam服务器分开的PlayN。
如果我理解正确,你执行Maven任务以HTML格式运行你的游戏,另一方面你运行Jboss(或任何Java EE服务器),你应该做的是运行
mvn package
将创建游戏之战,然后在您的Java EE服务器上发布该战争,然后您可以使用 PlayN.net 包,没有任何问题,在单个服务器中运行< / p>
答案 1 :(得分:2)
这就是我们目前处理客户/服务器通信的方式。我们使用无状态JavaEE体系结构,并提供REST服务。这允许我们通过添加更多服务器来水平扩展,只需将它们添加到Glassfish配置中的集群条目即可。
然而,由于缺少反射或工作JSON lib,它迫使我们在每个数据传输对象BY HAND中实现toJson()方法(具有区分大小写的carfull)。我们将我们的服务器项目作为模块添加到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());
}
});
}
注意我们如何使用session.toJson()将POST参数混为一谈。这是因为缺少MIME类型功能,并且通过GWT传递JSON字符串将失败。 这就是它在服务器上的外观:
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类型,这将会更好一点,这样您就不必使用Gson强制转换String。然而,这非常有效。我们在服务器端使用Jersey来处理所有REST的东西。为了让它运行,我必须将以下内容放入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>
此外,Jersey已经包含在Java-EE-Api中,所以它开箱即用。我希望这有帮助。如果有人知道如何进行客户端JSON解析,请查看这个问题:How do I convert a POJO to JSON in PlayN?