gwt和spring整合的关键是让gwt可以访问到spring的bean,先在提供一个前端servlet分发器,配置了这个servlet后,gwt的RemoteServiceServlet就不用在web.xml中一个一个的配置了。本文使用的gwt是2.5.1版本的,spring是3.2.4版本的。
1、服务层接口:要在client包或者子包下面,@RemoteServiceRelativePath标识这个servlet的相对路径,里面的值是spring bean的id
import com.google.gwt.user.client.rpc.RemoteService; import com.google.gwt.user.client.rpc.RemoteServiceRelativePath; /** * The client side stub for the RPC service. */ @RemoteServiceRelativePath("greetingServiceImpl") public interface GreetingService extends RemoteService { String greetServer(String name) throws IllegalArgumentException; }
import com.google.gwt.user.client.rpc.AsyncCallback; /** * The async counterpart of <code>GreetingService</code>. */ public interface GreetingServiceAsync { void greetServer(String input, AsyncCallback<String> callback) throws IllegalArgumentException; }3、这个是gwt和spring整合的前端servlet总控制器,在inti方法中,设置该类可以自动装配。
import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.config.AutowireCapableBeanFactory; import org.springframework.web.context.WebApplicationContext; import org.springframework.web.context.support.WebApplicationContextUtils; import com.google.gwt.user.client.rpc.IncompatibleRemoteServiceException; import com.google.gwt.user.client.rpc.RemoteService; import com.google.gwt.user.client.rpc.SerializationException; import com.google.gwt.user.server.rpc.RPC; import com.google.gwt.user.server.rpc.RPCRequest; import com.google.gwt.user.server.rpc.RemoteServiceServlet; public class SpringGwtRemoteServiceServlet extends RemoteServiceServlet { private static final long serialVersionUID = 1L; private static final Logger LOG = LoggerFactory.getLogger(SpringGwtRemoteServiceServlet.class); public void init() throws ServletException { super.init(); if (LOG.isDebugEnabled()) { LOG.debug("Spring GWT service exporter deployed"); } WebApplicationContext context = WebApplicationContextUtils.getWebApplicationContext(getServletContext()); AutowireCapableBeanFactory factory = context.getAutowireCapableBeanFactory(); factory.autowireBean(this); } public String processCall(String payload) throws SerializationException { try { Object handler = getBean(getThreadLocalRequest()); RPCRequest rpcRequest = RPC.decodeRequest(payload, handler.getClass(), this); onAfterRequestDeserialized(rpcRequest); if (LOG.isDebugEnabled()) { LOG.debug("Invoking " + handler.getClass().getName() + "." + rpcRequest.getMethod().getName()); } return RPC.invokeAndEncodeResponse(handler, rpcRequest.getMethod(), rpcRequest.getParameters(), rpcRequest.getSerializationPolicy()); } catch (IncompatibleRemoteServiceException ex) { log("An IncompatibleRemoteServiceException was thrown while processing this call.", ex); return RPC.encodeResponseForFailure(null, ex); } } protected Object getBean(HttpServletRequest request) { String service = getService(request); Object bean = getBean(service); if (!(bean instanceof RemoteService)) { throw new IllegalArgumentException( "Spring bean is not a GWT RemoteService: " + service + " (" + bean + ")"); } if (LOG.isDebugEnabled()) { LOG.debug("Bean for service " + service + " is " + bean); } return bean; } protected String getService(HttpServletRequest request) { String url = request.getRequestURI(); String service = url.substring(url.lastIndexOf("/") + 1); if (LOG.isDebugEnabled()) { LOG.debug("Service for URL " + url + " is " + service); } return service; } protected Object getBean(String name) { WebApplicationContext applicationContext = WebApplicationContextUtils.getWebApplicationContext(getServletContext()); if (applicationContext == null) { throw new IllegalStateException("No Spring web application context found"); } if (!applicationContext.containsBean(name)) { throw new IllegalArgumentException("Spring bean not found: " + name); } return applicationContext.getBean(name); } }
4、定义spring的bean,实现服务层接口。
import java.sql.ResultSet; import java.sql.SQLException; import java.util.List; import javax.inject.Inject; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.jdbc.core.RowMapper; import org.springframework.stereotype.Service; import com.vteba.test.client.GreetingService; import com.vteba.test.model.User; import com.vteba.test.rpc.SpringGwtRemoteServiceServlet; import com.vteba.test.shared.FieldVerifier; /** * The server side implementation of the RPC service. */ @Service public class GreetingServiceImpl implements GreetingService { private static final long serialVersionUID = 1L; @Inject private JdbcTemplate jdbcTemplate; public String greetServer(String input) throws IllegalArgumentException { // Verify that the input is valid. if (!FieldVerifier.isValidName(input)) { // If the input is not valid, throw an IllegalArgumentException back // to // the client. throw new IllegalArgumentException( "Name must be at least 4 characters long"); } String sql = "select * from users"; List<User> userList = jdbcTemplate.query(sql, new RowMapper<User>() { public User mapRow(ResultSet rs, int row) { User user = new User(); try { user.setId(rs.getString("id")); user.setCompany(rs.getString("company")); user.setCreateDate(rs.getDate("create_date")); user.setMobilePhone(rs.getString("mobile_phone")); user.setState(rs.getInt("state")); } catch (SQLException e) { e.printStackTrace(); } return user; } }); System.out.println(userList); String serverInfo = "";//getServletContext().getServerInfo(); String userAgent = "";//getThreadLocalRequest().getHeader("User-Agent"); // Escape data from the client to avoid cross-site script // vulnerabilities. input = escapeHtml(input); userAgent = escapeHtml(userAgent); return "Hello, " + input + "!<br><br>I am running " + serverInfo + ".<br><br>It looks like you are using:<br>" + userAgent; } /** * Escape an html string. Escaping data received from the client helps to * prevent cross-site script vulnerabilities. * * @param html * the html string to escape * @return the escaped string */ private String escapeHtml(String html) { if (html == null) { return null; } return html.replaceAll("&", "&").replaceAll("<", "<") .replaceAll(">", ">"); } }
5、然后在web.xml中配置第三步中定义的类即可,作为前端servlet总控制器,所有请求,都经过它来分发。
这样,gwt收到请求以后就直接委托给spring bean来处理了。
<servlet> <servlet-name>springGwtRemoteServiceServlet</servlet-name> <servlet-class>com.vteba.test.rpc.SpringGwtRemoteServiceServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>springGwtRemoteServiceServlet</servlet-name> <url-pattern>/testgwt/*</url-pattern> </servlet-mapping>
6、也可以,每个RemoteServiceServlet都定义,然后配置在web.xml中,下面提供一个servlet基类,继承它后,spring bean可自动注入进来
public class AutowiredRemoteServiceServlet extends RemoteServiceServlet { private static final long serialVersionUID = 1L; public void init() throws ServletException { super.init(); WebApplicationContext context = WebApplicationContextUtils.getWebApplicationContext(getServletContext()); AutowireCapableBeanFactory factory = context.getAutowireCapableBeanFactory(); factory.autowireBean(this); } }