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;
}
2、服务层异步接口,就是服务接口后加Async,和服务层接口在同一个包下面
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);
}
}
也可以将继承的RemoteServiceServlet换成HttpServlet,那么普通的servlet环境中,servlet也可以注入spring bean了。