Création d’un projet Spring + hibernate + web service REST + Spring security. 3 – Création des Services
Les deux premiers billets de cette série étaient consacrés à la création du projet et des objets métiers puis à la création des DAO.
On va maintenant pouvoir passer à la création des services.
Comme pour les DAO, on va commencer par créer une interface qui définit les signatures des méthodes CRUD :
public interface ServiceBase<T extends IOM> { DaoBase<T> getDao(); T load(Class<T> entityClass, Serializable identifiant); T get(Class<T> entityClass, Serializable id); T load(Serializable id); List<T> list(); void delete(T entity); void delete(Integer identifier); T save(final T entity); }
Elle est quasiment identique à DaoBase. Sauf que la première méthode permet de récupérer le DAO associé au service (et non la classe de l’objet métier, dans le cas de DaoBase).
On définit ensuite l’implémentation de cette classe :
public abstract class ServiceBaseImpl<T extends OMBase> implements ServiceBase<T> { public abstract DaoBase<T> getDao(); @Override public void delete(Integer identifier) { getDao().delete(identifier); } @Override public void delete(T entity) { getDao().delete(entity); } @Override public T get(Class<T> entityClass, Serializable id) { return getDao().get(entityClass, id); } @Override public List<T> list() { return getDao().list(); } @Override public T load(Class<T> entityClass, Serializable identifiant) { return getDao().load(entityClass, identifiant); } @Override public T load(Serializable id) { return getDao().load(id); } @Override public T save(T entity) { return getDao().save(entity); } }
Qui fait seulement des appels aux méthodes du DAO.
On crée maintenant nos interfaces de services :
public interface UserService extends ServiceBase<User> { }
public interface NoteService extends ServiceBase<Note> { }
public interface FileTypeService extends ServiceBase<FileType> { }
public interface FileService extends ServiceBase<File> { }
Elles sont toutes vides, donc je ne ferai pas de commentaire.
On définit maintenant les implémentations de ces interfaces
public class FileServiceImpl extends ServiceBaseImpl<File> implements FileService { /** * dao */ private FileDao dao; /** * * @return the dao */ public FileDao getDao() { return dao; } /** * * @param dao * the dao to set */ public void setDao(FileDao dao) { this.dao = dao; } }
public class FileTypeServiceImpl extends ServiceBaseImpl<FileType> implements FileTypeService { /** * dao */ private FileTypeDao dao; /** * * @return the dao */ public FileTypeDao getDao() { return dao; } /** * * @param dao * the dao to set */ public void setDao(FileTypeDao dao) { this.dao = dao; } }
public class NoteServiceImpl extends ServiceBaseImpl<Note> implements NoteService { /** * dao */ private NoteDao dao; /** * * @return the dao */ public NoteDao getDao() { return dao; } /** * * @param dao * the dao to set */ public void setDao(NoteDao dao) { this.dao = dao; } }
public class UserServiceImpl extends ServiceBaseImpl<User> implements UserService, UserDetailsService { /** * dao */ private UserDao dao; /** * l'encodeur de mot de passe injecte par spring */ private PasswordEncoder passEncoder; /** * Objet qui permet de faire un "salt" sur le mot de passe avant de <br/> * le hasher. Cela ajout un niveau de sécurité en rendant plus difficiles * les attaque<br/> * par dictionnaire. */ private SaltSource saltSource; /** * * @return the dao */ public UserDao getDao() { return dao; } /** * * @param dao * the dao to set */ public void setDao(UserDao dao) { this.dao = dao; } @Override public UserDetails loadUserByUsername(String arg0) throws UsernameNotFoundException, DataAccessException { return dao.loadByUserName(arg0); } public void setPassEncoder(PasswordEncoder passEncoder) { this.passEncoder = passEncoder; } public void setSaltSource(SaltSource saltSource) { this.saltSource = saltSource; } }
Les trois premières implémentations n’ont pas grand-chose de spécial. Si ce n’est qu’elles contiennent un objet DAO, et un setter sur cet objet, permettant l’injection par Spring.
La dernière implémentation, « UserServiceImpl » implémente UserDetailsService, une classe de Spring Security. La seule méthode à définir est loadUserByUsername(String). Enfin, cette classe contient deux références à des objets, des classes PasswordEncoder et SaltSource. Le PasswordEncoder permet d’encoder les mots de passe (hashage par MD5, par exemple). Le SaltSource permet d’ajouter un « salt » au mot de passe avant de l’encoder, afin d’améliorer la sécurité en rendant plus difficile les attaques par dictionnaire. Les deux objets seront injectés via spring.
On peut maintenant déclarer les beans spring correspondant aux services, dans applicationContext-service.xml :
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd"> <bean id="noteService" class="fr.mael.jfreenote.service.impl.NoteServiceImpl"> <property name="dao" ref="noteDao" /> </bean> <bean id="userService" class="fr.mael.jfreenote.service.impl.UserServiceImpl"> <property name="dao" ref="userDao" /> </bean> <bean id="fileService" class="fr.mael.jfreenote.service.impl.FileServiceImpl"> <property name="dao" ref="fileDao" /> </bean> <bean id="fileTypeService" class="fr.mael.jfreenote.service.impl.FileTypeServiceImpl"> <property name="dao" ref="fileTypeDao" /> </bean> </beans>
Le fichier est très simple, on injecte juste à chaque service son dao correspondant. Je n’ai pas encore fait l’injection du PasswordEncoder et du SaltSource dans userService, parce que je n’ai pas encore montré comment les déclarer.
Voilà, c’est tout pour la gestion de services.
Dans le prochain billet, nous verrons comment implémenter un service REST.