- 浏览: 56235 次
- 性别:
- 来自: 上海
最新评论
-
冲锋陷阵:
这一个办法还是不行。。。
文件编码格式转换 -
jxd1976:
下面没了?
Hessian2序列化 -
ccj:
使用Gwt-SL整合效果很好.
GWT和AOP -
gwbasic:
有新版本了,请参照论坛中的<<gw ...
GWT和AOP -
li_tieyang:
ServerSerializationStreamReader ...
GWT和AOP
上文http://gwbasic.iteye.com/admin/show/39079提到的GWTSpringController.java,继承的是GWT中的RemoteServiceServlet类,在使用过程中发现这个类不支持AOP,原因
于是参照RemoteServiceServlet重新写了一个在Spring中使用的Controller
GWTServiceController
// delegate 用法参照 org.springframework.web.servlet.mvc.multiaction.MultiActionController
开源真好:D
public String processCall(String payload) throws SerializationException { // ............. // ............ // Actually get the service interface, so that we can query its methods. // Class serviceIntf; try { // 此处的serviceIntf,是用getClassForName获取的,没有经过proxy代理 serviceIntf = getClassFromName(serviceIntfName); } catch (ClassNotFoundException e) { throw new SerializationException("Unknown service interface class '" + serviceIntfName + "'", e); } // Read the method name. // String methodName = streamReader.readString(); // Read the number and names of the parameter classes from the stream. // We have to do this so that we can find the correct overload of the // method. // int paramCount = streamReader.readInt(); Class[] paramTypes = new Class[paramCount]; for (int i = 0; i < paramTypes.length; i++) { String paramClassName = streamReader.readString(); try { paramTypes[i] = getClassOrPrimitiveFromName(paramClassName); } catch (ClassNotFoundException e) { throw new SerializationException("Unknown parameter " + i + " type '" + paramClassName + "'", e); } } // For security, make sure the method is found in the service interface // and not just one that happens to be defined on this class. // Method serviceIntfMethod = findInterfaceMethod(serviceIntf, methodName, paramTypes, true); }
于是参照RemoteServiceServlet重新写了一个在Spring中使用的Controller
GWTServiceController
import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.UnsupportedEncodingException; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.HashMap; import java.util.Map; import java.util.zip.GZIPOutputStream; import javax.servlet.ServletContext; import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.springframework.web.context.ServletContextAware; import org.springframework.web.servlet.ModelAndView; import org.springframework.web.servlet.mvc.Controller; import com.google.gwt.user.client.rpc.RemoteService; import com.google.gwt.user.client.rpc.SerializationException; import com.google.gwt.user.server.rpc.impl.ServerSerializableTypeOracle; import com.google.gwt.user.server.rpc.impl.ServerSerializableTypeOracleImpl; import com.google.gwt.user.server.rpc.impl.ServerSerializationStreamReader; import com.google.gwt.user.server.rpc.impl.ServerSerializationStreamWriter; public class GWTServiceController implements ServletContextAware, Controller { private ServletContext servletContext; /** Object we'll invoke methods on. Defaults to this. */ private Object delegate; public void setServletContext(ServletContext servletContext) { this.servletContext = servletContext; } public ServletContext getServletContext() { return servletContext; } public Object getDelegate() { return delegate; } public void setDelegate(Object delegate) { this.delegate = delegate; registerImplementedRemoteServiceInterface(this.delegate); } public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception { doPost(request, response); return null; } /* * These members are used to get and set the different HttpServletResponse and * HttpServletRequest headers. */ private static final String ACCEPT_ENCODING = "Accept-Encoding"; private static final String CHARSET_UTF8 = "UTF-8"; private static final String CONTENT_ENCODING = "Content-Encoding"; private static final String CONTENT_ENCODING_GZIP = "gzip"; private static final String CONTENT_TYPE_TEXT_PLAIN_UTF8 = "text/plain; charset=utf-8"; private static final String GENERIC_FAILURE_MSG = "The call failed on the server; see server log for details"; private static final HashMap TYPE_NAMES; /** * Controls the compression threshold at and below which no compression will * take place. */ private static final int UNCOMPRESSED_BYTE_SIZE_LIMIT = 256; static { TYPE_NAMES = new HashMap(); TYPE_NAMES.put("Z", boolean.class); TYPE_NAMES.put("B", byte.class); TYPE_NAMES.put("C", char.class); TYPE_NAMES.put("D", double.class); TYPE_NAMES.put("F", float.class); TYPE_NAMES.put("I", int.class); TYPE_NAMES.put("J", long.class); TYPE_NAMES.put("S", short.class); } /** * Return true if the response object accepts Gzip encoding. This is done by * checking that the accept-encoding header specifies gzip as a supported * encoding. */ private static boolean acceptsGzipEncoding(HttpServletRequest request) { assert (request != null); String acceptEncoding = request.getHeader(ACCEPT_ENCODING); if (null == acceptEncoding) { return false; } return (acceptEncoding.indexOf(CONTENT_ENCODING_GZIP) != -1); } /** * This method attempts to estimate the number of bytes that a string will * consume when it is sent out as part of an HttpServletResponse. This really * a hack since we are assuming that every character will consume two bytes * upon transmission. This is definitely not true since some characters * actually consume more than two bytes and some consume less. This is even * less accurate if the string is converted to UTF8. However, it does save us * from converting every string that we plan on sending back to UTF8 just to * determine that we should not compress it. */ private static int estimateByteSize(final String buffer) { return (buffer.length() * 2); } /** * Find the invoked method on either the specified interface or any super. */ private static Method findInterfaceMethod(Class intf, String methodName, Class[] paramTypes, boolean includeInherited) { try { return intf.getDeclaredMethod(methodName, paramTypes); } catch (NoSuchMethodException e) { if (includeInherited) { Class[] superintfs = intf.getInterfaces(); for (int i = 0; i < superintfs.length; i++) { Method method = findInterfaceMethod(superintfs[i], methodName, paramTypes, true); if (method != null) { return method; } } } return null; } } private final ServerSerializableTypeOracle serializableTypeOracle; /** * The default constructor. */ public GWTServiceController() { serializableTypeOracle = new ServerSerializableTypeOracleImpl(getPackagePaths()); this.delegate = this; registerImplementedRemoteServiceInterface(this.delegate); } /** * This is called internally. */ public final void doPost(HttpServletRequest request, HttpServletResponse response) { Throwable caught; try { // Read the request fully. // String requestPayload = readPayloadAsUtf8(request); // Invoke the core dispatching logic, which returns the serialized // result. // String responsePayload = processCall(requestPayload); // Write the response. // writeResponse(request, response, responsePayload); return; } catch (IOException e) { caught = e; } catch (ServletException e) { caught = e; } catch (SerializationException e) { caught = e; } catch (Throwable e) { caught = e; } respondWithFailure(response, caught); } /** * This is public so that it can be unit tested easily without HTTP. */ public String processCall(String payload) throws SerializationException { // Let subclasses see the serialized request. // onBeforeRequestDeserialized(payload); // Create a stream to deserialize the request. // ServerSerializationStreamReader streamReader = new ServerSerializationStreamReader(serializableTypeOracle); streamReader.prepareToRead(payload); // Read the service interface // String serviceIntfName = streamReader.readString(); // TODO(mmendez): need a way to check the type signature of the service intf // Verify that this very servlet implements the specified interface name. // 从delegate中获取serviceIntf Class serviceIntf = getImplementedRemoteServiceInterface(serviceIntfName); if (serviceIntf == null) { // Bad payload, possible hack attempt. // throw new SecurityException( "Blocked attempt to access interface '" + serviceIntfName + "', which is either not implemented by this servlet or which doesn't extend RemoteService; this is either misconfiguration or a hack attempt"); } // Read the method name. // String methodName = streamReader.readString(); // Read the number and names of the parameter classes from the stream. // We have to do this so that we can find the correct overload of the // method. // int paramCount = streamReader.readInt(); Class[] paramTypes = new Class[paramCount]; for (int i = 0; i < paramTypes.length; i++) { String paramClassName = streamReader.readString(); try { paramTypes[i] = getClassOrPrimitiveFromName(paramClassName); } catch (ClassNotFoundException e) { throw new SerializationException("Unknown parameter " + i + " type '" + paramClassName + "'", e); } } // For security, make sure the method is found in the service interface // and not just one that happens to be defined on this class. // Method serviceIntfMethod = findInterfaceMethod(serviceIntf, methodName, paramTypes, true); // If it wasn't found, don't continue. // if (serviceIntfMethod == null) { // Bad payload, possible hack attempt. // throw new SecurityException("Method '" + methodName + "' (or a particular overload) on interface '" + serviceIntfName + "' was not found, this is either misconfiguration or a hack attempt"); } // Deserialize the parameters. // Object[] args = new Object[paramCount]; for (int i = 0; i < args.length; i++) { args[i] = streamReader.deserializeValue(paramTypes[i]); } // Make the call via reflection. // String responsePayload = GENERIC_FAILURE_MSG; ServerSerializationStreamWriter streamWriter = new ServerSerializationStreamWriter(serializableTypeOracle); Throwable caught = null; try { Class returnType = serviceIntfMethod.getReturnType(); Object returnVal = serviceIntfMethod.invoke(this.delegate, args); responsePayload = createResponse(streamWriter, returnType, returnVal, false); } catch (IllegalArgumentException e) { caught = e; } catch (IllegalAccessException e) { caught = e; } catch (InvocationTargetException e) { // Try to serialize the caught exception if the client is expecting it, // otherwise log the exception server-side. caught = e; Throwable cause = e.getCause(); if (cause != null) { // Update the caught exception to the underlying cause caught = cause; // Serialize the exception back to the client if it's a declared // exception if (isExpectedException(serviceIntfMethod, cause)) { Class thrownClass = cause.getClass(); responsePayload = createResponse(streamWriter, thrownClass, cause, true); // Don't log the exception on the server caught = null; } } } if (caught != null) { responsePayload = GENERIC_FAILURE_MSG; ServletContext servletContext = getServletContext(); // servletContext may be null (for example, when unit testing) if (servletContext != null) { // Log the exception server side servletContext.log("Exception while dispatching incoming RPC call", caught); } } // Let subclasses see the serialized response. // onAfterResponseSerialized(responsePayload); return responsePayload; } /** * Override this method to examine the serialized response that will be * returned to the client. The default implementation does nothing and need * not be called by subclasses. */ protected void onAfterResponseSerialized(String serializedResponse) { } /** * Override this method to examine the serialized version of the request * payload before it is deserialized into objects. The default implementation * does nothing and need not be called by subclasses. */ protected void onBeforeRequestDeserialized(String serializedRequest) { } /** * Determines whether the response to a given servlet request should or should * not be GZIP compressed. This method is only called in cases where the * requestor accepts GZIP encoding. * <p> * This implementation currently returns <code>true</code> if the response * string's estimated byte length is longer than 256 bytes. Subclasses can * override this logic. * </p> * * @param request the request being served * @param response the response that will be written into * @param responsePayload the payload that is about to be sent to the client * @return <code>true</code> if responsePayload should be GZIP compressed, * otherwise <code>false</code>. */ protected boolean shouldCompressResponse(HttpServletRequest request, HttpServletResponse response, String responsePayload) { return estimateByteSize(responsePayload) > UNCOMPRESSED_BYTE_SIZE_LIMIT; } /** * @param stream * @param responseType * @param responseObj * @param isException * @return response */ private String createResponse(ServerSerializationStreamWriter stream, Class responseType, Object responseObj, boolean isException) { stream.prepareToWrite(); if (responseType != void.class) { try { stream.serializeValue(responseObj, responseType); } catch (SerializationException e) { responseObj = e; isException = true; } } String bufferStr = (isException ? "{EX}" : "{OK}") + stream.toString(); return bufferStr; } /** * Returns the {@link Class} instance for the named class. * * @param name the name of a class or primitive type * @return Class instance for the given type name * @throws ClassNotFoundException if the named type was not found */ private Class getClassFromName(String name) throws ClassNotFoundException { return Class.forName(name, false, this.getClass().getClassLoader()); } /** * Returns the {@link Class} instance for the named class or primitive type. * * @param name the name of a class or primitive type * @return Class instance for the given type name * @throws ClassNotFoundException if the named type was not found */ private Class getClassOrPrimitiveFromName(String name) throws ClassNotFoundException { Object value = TYPE_NAMES.get(name); if (value != null) { return (Class) value; } return getClassFromName(name); } /** * Obtain the special package-prefixes we use to check for custom serializers * that would like to live in a package that they cannot. For example, * "java.util.ArrayList" is in a sealed package, so instead we use this prefix * to check for a custom serializer in * "com.google.gwt.user.client.rpc.core.java.util.ArrayList". Right now, it's * hard-coded because we don't have a pressing need for this mechanism to be * extensible, but it is imaginable, which is why it's implemented this way. */ private String[] getPackagePaths() { return new String[] { "com.google.gwt.user.client.rpc.core" }; } /** * Returns true if the {@link java.lang.reflect.Method Method} definition on * the service is specified to throw the exception contained in the * InvocationTargetException or false otherwise. NOTE we do not check that the * type is serializable here. We assume that it must be otherwise the * application would never have been allowed to run. * * @param serviceIntfMethod * @param e * @return is expected exception */ private boolean isExpectedException(Method serviceIntfMethod, Throwable cause) { assert (serviceIntfMethod != null); assert (cause != null); Class[] exceptionsThrown = serviceIntfMethod.getExceptionTypes(); if (exceptionsThrown.length <= 0) { // The method is not specified to throw any exceptions // return false; } Class causeType = cause.getClass(); for (int index = 0; index < exceptionsThrown.length; ++index) { Class exceptionThrown = exceptionsThrown[index]; assert (exceptionThrown != null); if (exceptionThrown.isAssignableFrom(causeType)) { return true; } } return false; } private final Map<String, Class> knownImplementedInterfacesMap = new HashMap<String, Class>(); private void registerImplementedRemoteServiceInterface(Object delegate) { this.knownImplementedInterfacesMap.clear(); if (delegate != null) { Class cls = delegate.getClass(); if (cls.isInterface()) { addImplementedRemoteServiceInterfaceRecursive(cls); } else { while (cls != null) { Class[] intfs = cls.getInterfaces(); for (int i = 0; i < intfs.length; i++) { addImplementedRemoteServiceInterfaceRecursive(intfs[i]); } // we look in the superclass cls = cls.getSuperclass(); } } } } private void addImplementedRemoteServiceInterfaceRecursive(Class intfToCheck) { assert (intfToCheck.isInterface()); if (RemoteService.class.equals(intfToCheck)) return; if (RemoteService.class.isAssignableFrom(intfToCheck)) { this.knownImplementedInterfacesMap.put(intfToCheck.getName(), intfToCheck); } Class[] intfs = intfToCheck.getInterfaces(); for (int i = 0; i < intfs.length; i++) { addImplementedRemoteServiceInterfaceRecursive(intfs[i]); } } private Class getImplementedRemoteServiceInterface(String intfName) { return this.knownImplementedInterfacesMap.get(intfName); } private String readPayloadAsUtf8(HttpServletRequest request) throws IOException, ServletException { int contentLength = request.getContentLength(); if (contentLength == -1) { // Content length must be known. throw new ServletException("Content-Length must be specified"); } String contentType = request.getContentType(); boolean contentTypeIsOkay = false; // Content-Type must be specified. if (contentType != null) { // The type must be plain text. if (contentType.startsWith("text/plain")) { // And it must be UTF-8 encoded (or unspecified, in which case we assume // that it's either UTF-8 or ASCII). if (contentType.indexOf("charset=") == -1) { contentTypeIsOkay = true; } else if (contentType.indexOf("charset=utf-8") != -1) { contentTypeIsOkay = true; } } } if (!contentTypeIsOkay) { throw new ServletException( "Content-Type must be 'text/plain' with 'charset=utf-8' (or unspecified charset)"); } InputStream in = request.getInputStream(); try { byte[] payload = new byte[contentLength]; int offset = 0; int len = contentLength; int byteCount; while (offset < contentLength) { byteCount = in.read(payload, offset, len); if (byteCount == -1) { throw new ServletException("Client did not send " + contentLength + " bytes as expected"); } offset += byteCount; len -= byteCount; } return new String(payload, "UTF-8"); } finally { if (in != null) { in.close(); } } } /** * Called when the machinery of this class itself has a problem, rather than * the invoked third-party method. It writes a simple 500 message back to the * client. */ private void respondWithFailure(HttpServletResponse response, Throwable caught) { ServletContext servletContext = getServletContext(); servletContext.log("Exception while dispatching incoming RPC call", caught); try { response.setContentType("text/plain"); response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR); response.getWriter().write(GENERIC_FAILURE_MSG); } catch (IOException e) { servletContext.log("sendError() failed while sending the previous failure to the client", caught); } } private void writeResponse(HttpServletRequest request, HttpServletResponse response, String responsePayload) throws IOException { byte[] reply = responsePayload.getBytes(CHARSET_UTF8); String contentType = CONTENT_TYPE_TEXT_PLAIN_UTF8; if (acceptsGzipEncoding(request) && shouldCompressResponse(request, response, responsePayload)) { // Compress the reply and adjust headers. // ByteArrayOutputStream output = null; GZIPOutputStream gzipOutputStream = null; Throwable caught = null; try { output = new ByteArrayOutputStream(reply.length); gzipOutputStream = new GZIPOutputStream(output); gzipOutputStream.write(reply); gzipOutputStream.finish(); gzipOutputStream.flush(); response.setHeader(CONTENT_ENCODING, CONTENT_ENCODING_GZIP); reply = output.toByteArray(); } catch (UnsupportedEncodingException e) { caught = e; } catch (IOException e) { caught = e; } finally { if (null != gzipOutputStream) { gzipOutputStream.close(); } if (null != output) { output.close(); } } if (caught != null) { getServletContext().log("Unable to compress response", caught); response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR); return; } } // Send the reply. // response.setContentLength(reply.length); response.setContentType(contentType); response.setStatus(HttpServletResponse.SC_OK); response.getOutputStream().write(reply); } }
// delegate 用法参照 org.springframework.web.servlet.mvc.multiaction.MultiActionController
/* For GWT 1.4.60 */ public class GwtRemoteServiceController extends RemoteServiceServlet implements Controller, ServletContextAware { private static final long serialVersionUID = 8175888785480720736L; private Object delegate; private ServletContext servletContext; @Override public void setServletContext(ServletContext servletContext) { this.servletContext = servletContext; } @Override public ServletContext getServletContext() { return servletContext; } @Override public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception { super.doPost(request, response); return null; } @Override public String processCall(String payload) throws SerializationException { Object delegateToUse = this.delegate; if (delegateToUse == null) { return super.processCall(payload); } else { try { RPCRequest rpcRequest = RPC.decodeRequest(payload, delegateToUse.getClass(), this); return RPC.invokeAndEncodeResponse(delegateToUse, rpcRequest .getMethod(), rpcRequest.getParameters(), rpcRequest .getSerializationPolicy()); } catch (IncompatibleRemoteServiceException ex) { getServletContext() .log( "An IncompatibleRemoteServiceException was thrown while processing this call.", ex); return RPC.encodeResponseForFailure(null, ex); } } } public Object getDelegate() { return delegate; } public void setDelegate(Object delegate) { this.delegate = delegate; } }
开源真好:D
评论
3 楼
ccj
2008-04-25
使用Gwt-SL整合效果很好.
2 楼
gwbasic
2008-03-25
有新版本了,请参照论坛中的<<gwt spring 完美整合>>
http://www.iteye.com/topic/143455
delegate 用法参照 org.springframework.web.servlet.mvc.multiaction.MultiActionController
http://www.iteye.com/topic/143455
delegate 用法参照 org.springframework.web.servlet.mvc.multiaction.MultiActionController
public class GwtRemoteServiceController extends RemoteServiceServlet implements Controller, ServletContextAware { private static final long serialVersionUID = 8175888785480720736L; private Object delegate; private ServletContext servletContext; @Override public void setServletContext(ServletContext servletContext) { this.servletContext = servletContext; } @Override public ServletContext getServletContext() { return servletContext; } @Override public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception { super.doPost(request, response); return null; } @Override public String processCall(String payload) throws SerializationException { Object delegateToUse = this.delegate; if (delegateToUse == null) { return super.processCall(payload); } else { try { RPCRequest rpcRequest = RPC.decodeRequest(payload, delegateToUse.getClass(), this); return RPC.invokeAndEncodeResponse(delegateToUse, rpcRequest .getMethod(), rpcRequest.getParameters(), rpcRequest .getSerializationPolicy()); } catch (IncompatibleRemoteServiceException ex) { getServletContext() .log( "An IncompatibleRemoteServiceException was thrown while processing this call.", ex); return RPC.encodeResponseForFailure(null, ex); } } } public Object getDelegate() { return delegate; } public void setDelegate(Object delegate) { this.delegate = delegate; } }
1 楼
li_tieyang
2008-03-19
ServerSerializationStreamReader streamReader = new ServerSerializationStreamReader(
serializableTypeOracle);
你用的GWT是什么版本,我用1.4.6的这句代码过不去.
serializableTypeOracle);
你用的GWT是什么版本,我用1.4.6的这句代码过不去.
相关推荐
此外,GWT还支持代码分割、模块化以及AOP(面向切面编程)等高级特性,极大地提升了开发效率和代码质量。 **GWT的主要特性:** 1. **Java编程**:GWT允许开发者使用Java编写前端代码,借助强大的Java生态系统,...
标题 "gwt+spring+hibernate" 涉及的是一个使用Google Web Toolkit (GWT)、Spring框架和Hibernate ORM技术的集成示例。这是一个常见的Web应用开发组合,用于构建高效、可扩展且功能丰富的Java web应用程序。下面将...
- 基于GWT的AOP(面向切面编程)特性,允许在运行时进行优化。 8. **社区支持和文档** - SmartGWT有一个活跃的社区,提供讨论、示例和解决方案。 - 官方文档详尽,包括API参考、教程和示例代码,帮助开发者快速...
3. 使用Spring的AOP和DI来管理服务实现类,包括依赖注入和服务的生命周期管理。 4. 在客户端,通过GWT的RPC机制调用服务器端服务,实现数据交换。 5. 使用Hibernate配置数据库连接和实体映射,处理数据持久化。 6. ...
2. **编译过程**:GWT 2.1.0引入了先进的编译技术,通过AOP(面向切面编程)和JIT(即时编译)优化,将Java源代码转换为高性能的JavaScript代码。这一过程包括源码到字节码、字节码到JSIR(JavaScript Intermediate ...
Spring 是一个全面的Java企业级应用开发框架,提供了依赖注入(DI)、面向切面编程(AOP)和声明式事务管理等核心功能。在本实例中,Spring 可能用于管理应用程序的bean,提供服务层的实现,以及负责与数据库的交互...
9. **AOP(面向切面编程)**:GWT还引入了切面编程的概念,例如,你可以使用GWT的 Gin 框架进行依赖注入,或者使用 Errai 框架实现更复杂的AOP功能。 10. **兼容性和版本更新**:随着Web技术的发展,GWT也不断更新...
在IT行业中,Spring框架是Java企业级应用开发的首选,而Google Web Toolkit (GWT) 则是一个用于构建和优化复杂Web应用程序的开源工具。本文将深入探讨如何将这两个强大的技术进行集成,以便利用Spring的强大功能来...
它可以通过ApplicationContext来管理SmartGwt的视图和服务,同时通过Bean配置管理Mybatis的SqlSessionFactory和Mapper实例。Spring的AOP可以方便地实现日志记录、权限控制等功能。 整合步骤通常包括以下几个部分: ...
SmartGWT是基于GWT(Google Web Toolkit)的一个强大的UI库,提供丰富的用户界面组件和高性能的JavaScript客户端应用。Spring是一个开源的Java应用框架,它提供了依赖注入、AOP(面向切面编程)以及各种企业服务。...
4. **更好的AOP支持**:GWT 2.7增强了对Aspect-Oriented Programming (AOP)的支持,方便开发者进行代码组织和模块化。 5. **模块化改进**:模块化的改进让开发者能更好地管理大型项目,提高代码的可维护性和重用性。...
它通过提供依赖注入(DI)和面向切面编程(AOP)等功能来实现这一目标。依赖注入允许更灵活地管理对象之间的关系,从而提高了代码的可测试性和可重用性。Spring还支持事务管理和安全控制,这对于企业级应用来说是必...
Spring4GWT是将Spring框架与Google Web Toolkit (GWT) 结合的一种技术,它旨在帮助开发者在GWT应用中更好地实现服务层管理和依赖注入,从而提升开发效率和代码的可维护性。以下是对Spring4GWT技术的详细说明: 1. *...
Spring是一个全面的企业级应用开发框架,核心特性包括依赖注入(DI)和面向切面编程(AOP)。Spring还提供了对数据库访问的支持,如JDBC抽象层和ORM(对象关系映射)集成,包括Mybatis。在本项目中,Spring负责管理...
4. **AOP支持**:GWT 使用AOP(面向切面编程)实现事件处理、国际化和代码分离等功能。 5. **RPC通信**:GWT 提供了内置的远程过程调用(RPC)机制,使得客户端与服务器之间的数据交换简单易行。 ### Mocha GWT的...
- **Spring-GWT-RPC**:GWT的Remote Procedure Call (RPC)机制可以与Spring的AOP和DI集成,实现服务端的Spring Bean作为GWT RPC的服务端点。这样,客户端可以直接调用服务端的业务逻辑,而无需关心服务的实现细节。...
而Spring框架则常用于后端服务,提供依赖注入、AOP(面向切面编程)等功能,便于构建可维护和可扩展的系统。将两者结合,可以构建出前后端分离、结构清晰的GWT应用。 总的来说,GWT的通信机制是通过RPC服务,利用...
接下来,Spring框架是Java企业级应用中的核心组件,它提供依赖注入(DI)和面向切面编程(AOP)等特性,帮助开发者管理对象的生命周期和依赖关系。整合EXT-GWT与Spring,可以实现组件的灵活配置,使UI组件能够轻松...
1. GWT-RPC与Spring:GWT-RPC是GWT内部的通信机制,Spring4可以通过AOP进行拦截,实现服务端的事务管理和权限控制。同时,Spring4的Service层可以作为GWT-RPC的服务端,提供远程调用的接口。 2. Spring Security与...
而Spring框架则是Java后端开发的核心框架,提供了依赖注入、AOP(面向切面编程)、事务管理等功能,极大地提高了开发效率和应用的可维护性。 在"gwt_spring-nolib.zip"这个压缩包中,我们可以看到一个实际的GWT和...