GWT中默认一个service对应一个servlet,这样会使web.xml要配置很多servlet, 不是很方便。我这里通过一个Dispatch servlet来分配service, 这样每个service都成了pojo,使得配置更加方便,也容易测试。
1. Server code
Configure web.xml like
<servlet>
<servlet-name>gwt-dispatch</servlet-name>
<servlet-class>
com.xxxxx.gwt.GwtRpcServiceDispatch
</servlet-class>
<init-param>
<param-name>prefix</param-name>
<param-value>/gsvc</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>gwt-dispatch</servlet-name>
<url-pattern>/gsvc/*</url-pattern>
</servlet-mapping>
prefix参数表示service访问url的根路径
Why it works: Let's see the code of GwtRpcServiceDispatch.java
1 /**
2 * @author xwang
3 * Dispatch the gwt services
4 */
5 public class GwtRpcServiceDispatch extends RemoteServiceServlet {
6 private static final long serialVersionUID = -2797202947611240618L;
7
8 private Injector injector;
9
10 private int beginIndexOfClassName;
11
12 @Override
13 public void init(ServletConfig config) throws ServletException {
14 super.init(config);
15 // get guice injector, it init by ServletContextListener
16 injector = InjectorHolder.getInjector();
17 if (injector == null) {
18 throw new UnavailableException("Guice Injector not found (did you forget to register a "
19 + this.getClass().getSimpleName() + "?)");
20 }
21
22 // set prefix of service url
23 String prefix = config.getInitParameter("prefix");
24 if (prefix == null || prefix.length() == 0) {
25 beginIndexOfClassName = 1;
26 } else if (prefix.startsWith("/")) {
27 beginIndexOfClassName = prefix.length() + 1;
28 } else {
29 beginIndexOfClassName = prefix.length() + 2;
30 }
31 }
这里先要设置Guice Injector, 应为我们的service中用到了guice. 其次设置prefix的长度.
接着就可以根据URL来实例化RomteService,如下:
1 /**
2 * get service implement class's instance
3 * @return service implement class's instance
4 */
5 protected Object getCurrentHandler() {
6 String classPath = getThreadLocalRequest().getRequestURI();
7 // /gsvc/com/xxxxx/bus/domain/service/LandmarkService => com.xxxxx.bus.domain.service.LandmarkService
8 String className = classPath.substring(beginIndexOfClassName);
9 if (className.endsWith("/")) {
10 className = className.substring(0, className.length() - 1);
11 }
12 className = className.replaceAll("/", ".");
13
14 Class<?> clazz = null;
15 try {
16 clazz = Class.forName(className);
17 } catch (ClassNotFoundException e) {
18 e.printStackTrace();
19 throw new IllegalStateException(e.getMessage());
20 }
21
22 return injector.getInstance(clazz);
23 }
当然我们需要重新定义RemoteServiceServlet的主处理方法:
1 // this is the main method of RemoteServiceServlet to process request
2 @Override
3 public String processCall(String payload) throws SerializationException {
4 Object serviceHandler = getCurrentHandler(); //get instance of RemoteService
5
6 try {
7 RPCRequest rpcRequest = RPC.decodeRequest(payload, serviceHandler.getClass(), this);
8 return RPC.invokeAndEncodeResponse(serviceHandler, rpcRequest.getMethod(), rpcRequest.getParameters(), rpcRequest
9 .getSerializationPolicy());
10 } catch (IncompatibleRemoteServiceException ex) {
11 getServletContext().log("An IncompatibleRemoteServiceException was thrown while processing this call.", ex);
12 return RPC.encodeResponseForFailure(null, ex);
13 }
14 }
还要重新定义support方法:
1 // RemoteServiceServlet use this judge the instance
2 public boolean supports(Object handler) {
3 return handler instanceof RemoteService;
4 }
现在我们的RemoteService就成为了一个pojo如:
1 public interface LandmarkService extends RemoteService {
2 ...........
3 }
4
5 public class LandmarkServiceImpl implements LandmarkService {
6 ...........
7 }
2. Client code
gwt client这边需要用
1 ServiceHelper.registerServiceEntryPoint(instance);
获取访问URL.
why it works:
1 /**
2 * register service url
3 * @param svcObj service object
4 * com.xxxxx.bus.domain.service.LandmarkService => /gsvc/com/xxxxx/bus/domain/service/LandmarkService
5 */
6 public static void registerServiceEntryPoint(Object svcObj) {
7 ServiceDefTarget endpoint = (ServiceDefTarget) svcObj;
8 String endpointText = GWT.getTypeName(svcObj);
9 endpointText = endpointText.substring(0, endpointText.indexOf("_Proxy"));
10 endpointText = endpointText.replace('.', '/');
11 endpoint.setServiceEntryPoint("/gsvc/" + endpointText);
12 }
GWT.getTypeName can get the class name of service object
你可以使用如下代码的方式构造你的service
1 public interface LandmarkService extends RemoteService {
2 public static class Initer {
3 private static LandmarkServiceAsync instance;
4 public static LandmarkServiceAsync getInstance(){
5 if (instance == null) {
6 instance = (LandmarkServiceAsync) GWT.create(LandmarkService.class);
7 ServiceHelper.registerServiceEntryPoint(instance);
8 }
9
10 return instance;
11 }
12 }
13 ........
1. Server code
Configure web.xml like
<servlet>
<servlet-name>gwt-dispatch</servlet-name>
<servlet-class>
com.xxxxx.gwt.GwtRpcServiceDispatch
</servlet-class>
<init-param>
<param-name>prefix</param-name>
<param-value>/gsvc</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>gwt-dispatch</servlet-name>
<url-pattern>/gsvc/*</url-pattern>
</servlet-mapping>
prefix参数表示service访问url的根路径
Why it works: Let's see the code of GwtRpcServiceDispatch.java
1 /**
2 * @author xwang
3 * Dispatch the gwt services
4 */
5 public class GwtRpcServiceDispatch extends RemoteServiceServlet {
6 private static final long serialVersionUID = -2797202947611240618L;
7
8 private Injector injector;
9
10 private int beginIndexOfClassName;
11
12 @Override
13 public void init(ServletConfig config) throws ServletException {
14 super.init(config);
15 // get guice injector, it init by ServletContextListener
16 injector = InjectorHolder.getInjector();
17 if (injector == null) {
18 throw new UnavailableException("Guice Injector not found (did you forget to register a "
19 + this.getClass().getSimpleName() + "?)");
20 }
21
22 // set prefix of service url
23 String prefix = config.getInitParameter("prefix");
24 if (prefix == null || prefix.length() == 0) {
25 beginIndexOfClassName = 1;
26 } else if (prefix.startsWith("/")) {
27 beginIndexOfClassName = prefix.length() + 1;
28 } else {
29 beginIndexOfClassName = prefix.length() + 2;
30 }
31 }
这里先要设置Guice Injector, 应为我们的service中用到了guice. 其次设置prefix的长度.
接着就可以根据URL来实例化RomteService,如下:
1 /**
2 * get service implement class's instance
3 * @return service implement class's instance
4 */
5 protected Object getCurrentHandler() {
6 String classPath = getThreadLocalRequest().getRequestURI();
7 // /gsvc/com/xxxxx/bus/domain/service/LandmarkService => com.xxxxx.bus.domain.service.LandmarkService
8 String className = classPath.substring(beginIndexOfClassName);
9 if (className.endsWith("/")) {
10 className = className.substring(0, className.length() - 1);
11 }
12 className = className.replaceAll("/", ".");
13
14 Class<?> clazz = null;
15 try {
16 clazz = Class.forName(className);
17 } catch (ClassNotFoundException e) {
18 e.printStackTrace();
19 throw new IllegalStateException(e.getMessage());
20 }
21
22 return injector.getInstance(clazz);
23 }
当然我们需要重新定义RemoteServiceServlet的主处理方法:
1 // this is the main method of RemoteServiceServlet to process request
2 @Override
3 public String processCall(String payload) throws SerializationException {
4 Object serviceHandler = getCurrentHandler(); //get instance of RemoteService
5
6 try {
7 RPCRequest rpcRequest = RPC.decodeRequest(payload, serviceHandler.getClass(), this);
8 return RPC.invokeAndEncodeResponse(serviceHandler, rpcRequest.getMethod(), rpcRequest.getParameters(), rpcRequest
9 .getSerializationPolicy());
10 } catch (IncompatibleRemoteServiceException ex) {
11 getServletContext().log("An IncompatibleRemoteServiceException was thrown while processing this call.", ex);
12 return RPC.encodeResponseForFailure(null, ex);
13 }
14 }
还要重新定义support方法:
1 // RemoteServiceServlet use this judge the instance
2 public boolean supports(Object handler) {
3 return handler instanceof RemoteService;
4 }
现在我们的RemoteService就成为了一个pojo如:
1 public interface LandmarkService extends RemoteService {
2 ...........
3 }
4
5 public class LandmarkServiceImpl implements LandmarkService {
6 ...........
7 }
2. Client code
gwt client这边需要用
1 ServiceHelper.registerServiceEntryPoint(instance);
获取访问URL.
why it works:
1 /**
2 * register service url
3 * @param svcObj service object
4 * com.xxxxx.bus.domain.service.LandmarkService => /gsvc/com/xxxxx/bus/domain/service/LandmarkService
5 */
6 public static void registerServiceEntryPoint(Object svcObj) {
7 ServiceDefTarget endpoint = (ServiceDefTarget) svcObj;
8 String endpointText = GWT.getTypeName(svcObj);
9 endpointText = endpointText.substring(0, endpointText.indexOf("_Proxy"));
10 endpointText = endpointText.replace('.', '/');
11 endpoint.setServiceEntryPoint("/gsvc/" + endpointText);
12 }
GWT.getTypeName can get the class name of service object
你可以使用如下代码的方式构造你的service
1 public interface LandmarkService extends RemoteService {
2 public static class Initer {
3 private static LandmarkServiceAsync instance;
4 public static LandmarkServiceAsync getInstance(){
5 if (instance == null) {
6 instance = (LandmarkServiceAsync) GWT.create(LandmarkService.class);
7 ServiceHelper.registerServiceEntryPoint(instance);
8 }
9
10 return instance;
11 }
12 }
13 ........