Avant la version 2.1, il n'y avait que les RPC pour communiquer avec le serveur en Gwt.
Depuis cette version, un nouveau api est disponible, Request Factory.
Cet api permet de n'envoyer que les informations nécessaires au client et au serveur. Il y a économie de bande passante.
Au niveau du code, beaucoup de changement sont à prévoir. J'ai passé beaucoup de temps à essayer d'utiliser cet api avec Spring.
La base de donnée h2, spring 3.1 ainsi que gwt 2.4 ont été utilisé pour cet exemple.
L'interface graphique comporte deux boutons, un pour charger toutes les données de la base de donnée et l'autre pour y ajouter un élément.
Le fichier web.xml
<web -app="-app" version="3.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xsi:schemalocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd">
<context -param="-param">
<param -name="-name" />contextConfigLocation
<param -value="-value" />/WEB-INF/applicationContext.xml
</context>
<listener>
<listener -class="-class">org.springframework.web.context.ContextLoaderListener</listener>
</listener>
<servlet>
<servlet -name="-name">requestFactoryServlet</servlet>
<servlet -class="-class">com.google.web.bindery.requestfactory.server.RequestFactoryServlet</servlet>
</servlet>
<servlet -mapping="-mapping">
<servlet -name="-name">requestFactoryServlet</servlet>
<url -pattern="-pattern">/gwtRequest</url>
</servlet>
<welcome -file-list="-file-list">
<welcome -file="-file">welcomeGWT.html</welcome>
</welcome>
</web>
Dans le fichier applicationContext.xml, je n'ai que
<context:annotation -config="-config">
<context:component -scan="-scan" base-package="org.calibra">
<bean id="propertyConfigurer"
class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"
p:location="/WEB-INF/jdbc.properties" />
<bean id="dataSource"
class="org.springframework.jdbc.datasource.DriverManagerDataSource"
p:driverClassName="${jdbc.driverClassName}"
p:url="${jdbc.url}"
p:username="${jdbc.username}"
p:password="${jdbc.password}" />
Dans le fichier Main.gwt.xml, il faut ajouter
<inherits name="javax.validation.Validation"/>
<inherits name='com.google.web.bindery.requestfactory.RequestFactory'/>
Dans le package Domain
public class Account {
private Long id;
private String username;
private Integer version;
....
}
Dans le package server
La classe AccountLocator est nécessaire afin de ne pas mettre ces opérations directement dans la classe Account.
public class AccountLocator extends Locator<Account, Long> {
@Autowired
private AccountDAO accountDAO;
@Override
public Account create(Class<? extends Account> clazz) {
return new Account();
}
@Override
public Account find(Class<? extends Account> clazz, Long id) {
if (accountDAO == null) {
HttpServletRequest request = RequestFactoryServlet.getThreadLocalRequest();
ApplicationContext context = WebApplicationContextUtils.getWebApplicationContext(request.getSession().getServletContext());
accountDAO =context.getBean(AccountDAO.class);
}
return accountDAO.findAccount(id);
}
@Override
public Class<Account> getDomainType() {
throw new UnsupportedOperationException("Not supported yet.");
}
@Override
public Long getId(Account domainObject) {
return domainObject.getId();
}
@Override
public Class<Long> getIdType() {
return Long.class;
}
@Override
public Object getVersion(Account domainObject) {
return domainObject.getVersion();
}
La classe SpringServiceLocator est nécessaire afin d'avoir accès au bean.
public class SpringServiceLocator implements ServiceLocator {
@Override
public Object getInstance(Class<?> clazz) {
HttpServletRequest request = RequestFactoryServlet.getThreadLocalRequest();
ServletContext servletContext = request.getSession().getServletContext();
ApplicationContext context = WebApplicationContextUtils.getWebApplicationContext(servletContext);
return context.getBean(clazz);
}
}
Dans le package server.service
public interface AccountService {
public Account findAccount(Long id);
public List<Account> loadAllAccounts();
public void save(Account account);
public void delete(Account account);
}
@Service
public class AccountServiceImpl implements AccountService{
@Autowired
private AccountDAO accountDAO;
@Override
public void save(Account account){
accountDAO.save(account);
}
@Override
public List<Account> loadAllAccounts() {
return accountDAO.loadAllAccounts();
}
@Override
public Account findAccount(Long id) {
return accountDAO.findAccount(id);
}
@Override
public void delete(Account account) {
accountDAO.delete(account);
}
}
Dans le package server.dao
@Repository
public class AccountDAOImpl implements AccountDAO {
protected JdbcTemplate jdbcTemplate;
@Override
public Account findAccount(Long id) {
StringBuffer sb = new StringBuffer();
sb.append("select id, username, version from account where id = ?");
List<Account> accountList = jdbcTemplate.query(sb.toString(),
new Object[]{id}, mapper);
if (accountList != null && accountList.size() > 0) {
return accountList.get(0);
}
return null;
}
@Override
public List<Account> loadAllAccounts() {
StringBuffer sb = new StringBuffer();
sb.append("select id, username, version from account");
List<Account> accountList = jdbcTemplate.query(sb.toString(), mapper);
return accountList;
}
@Override
public void save(Account account) {
if (account.getVersion() == null) {
account.setVersion(0);
jdbcTemplate.update("insert into account(username, version) values(?, ?)",
account.getUsername(), account.getVersion());
} else {
account.setVersion(account.getVersion() + 1);
jdbcTemplate.update("update account(username, version) set username=?, version=? where id=?",
account.getUsername(), account.getVersion(), account.getId());
}
}
@Override
public void delete(Account account) {
jdbcTemplate.update("delete from account where id = ?", account.getId());
}
@Autowired
public void setDataSource(DataSource datasource) {
this.jdbcTemplate = new JdbcTemplate(datasource);
}
private static ParameterizedRowMapper<Account> mapper = new ParameterizedRowMapper<Account>() {
@Override
public Account mapRow(ResultSet rs, int rowNum) throws SQLException {
Account account = new Account();
account.setId(rs.getLong("id"));
account.setUsername(rs.getString("username"));
account.setVersion(rs.getInt("version"));
return account;
}
};
}
public interface AccountDAO {
public Account findAccount(Long id);
public List<Account> loadAllAccounts();
public void save(Account account);
public void delete(Account account);
}
Dans le package shared
public interface AccountRequestFactory extends RequestFactory {
AccountRequest accountRequest();
}
@Service(locator = SpringServiceLocator.class, value =AccountService.class)
public interface AccountRequest extends RequestContext {
Request<AccountProxy> findAccount(Long id);
Request<List<AccountProxy>> loadAllAccounts();
Request<Void> save(AccountProxy accountProxy);
Request<Void> delete(AccountProxy accountProxy);
}
@ProxyFor(value=Account.class, locator = AccountLocator.class)
public interface AccountProxy extends EntityProxy{
public Long getId();
public String getUsername();
public Integer getVersion();
public void setUsername(String userName);
public void setId(Long id);
public void setVersion(Integer version);
}
Dans le package client
public class MainEntryPoint implements IsWidget, EntryPoint {
private final AccountRequestFactory requestFactory = GWT.create(AccountRequestFactory.class);
AccountRequest request;
AccountProxy newAccount;
@Override
public Widget asWidget() {
Button loadAllButton = new Button("Load all Account");
final ValueListBox<AccountProxy> accountListBox = new ValueListBox<AccountProxy>(new Renderer<AccountProxy>() {
@Override
public String render(AccountProxy object) {
return object.getUsername();
}
@Override
public void render(AccountProxy object, Appendable appendable) throws IOException {
appendable.append(object.getUsername());
}
});
loadAllButton.addClickHandler(new ClickHandler() {
@Override
public void onClick(ClickEvent event) {
request = requestFactory.accountRequest();
Request<List<AccountProxy>> loadAllAccounts = request.loadAllAccounts();
loadAllAccounts.fire(new Receiver<List<AccountProxy>>() {
@Override
public void onSuccess(List<AccountProxy> response) {
accountListBox.setAcceptableValues(response);
Window.alert("account ajouté");
}
});
}
});
Button addButton = new Button("Add account");
addButton.addClickHandler(new ClickHandler() {
@Override
public void onClick(ClickEvent event) {
request = requestFactory.accountRequest();
AccountProxy accountProxy = request.create(AccountProxy.class);
accountProxy.setUsername("joe");
request.save(accountProxy).fire(new Receiver<Void>() {
@Override
public void onSuccess(Void response) {
Window.alert("account ajouté");
}
});
}
});
VerticalPanel vp = new VerticalPanel();
vp.setSpacing(10);
vp.add(loadAllButton);
vp.add(accountListBox);
vp.add(addButton);
return vp;
}
@Override
public void onModuleLoad() {
requestFactory.initialize(new SimpleEventBus());
RootPanel.get().add(asWidget());
}
}
Liste de jar présent dans WEB-INF/lib/
Les sources de cet exemples est disponible ici.
Ces jar ne sont pas inclus dans les sources.
Aucun commentaire:
Enregistrer un commentaire