Tutoriel sur la création d'une application CRUD avec JSF2 (partie 2) : mise en œuvre de PrettyFaces et PrimeFaces

| Oumar Cisse (PaloIT) | PaloIT |

Dans la première partie du tutoriel, j'avais déjà mis en place le cœur de l'application. Dans cette partie, nous allons aborder son aspect graphique avec la mise en place de JSF2 et PrimeFaces. Nous étudierons par la même occasion la réécriture des URL avec PrettyFaces.

Pour réagir au contenu de cet article, un espace de dialogue vous est proposé sur le forum Commentez .

- Titre : Tutoriel sur la création d'une application CRUD avec JSF2 (partie 2) : mise en œuvre de PrettyFaces et PrimeFaces

- Auteurs : Oumar Cisse (PaloIT), PaloIT

- Parution : 11 juillet 2013

- Licence : Copyright ® 2013 PaloIT. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.

Sommaire

- I. Justification de Spring comme injecteur de dépendances

- II. Configuration de web.xml

- III. Configuration de faces-config.xml

- IV. Mise en place de PrimeFaces

- V. Réécriture des URL

- VI. Mise en place de PrettyFaces

- VII. Remerciements

I - Justification de Spring comme injecteur de dépendances

Cette question mérite d'être posée dans la mesure où, comme Spring, JSF permet de faire l'injection de dépendances. Il existe de multiples raisons et parmi elles on peut citer :

- mieux vaut avoir un seul framework d'IOC que deux ;

- Spring est plus mature et plus complète que JSF en matière d'injection de dépendances ;

- possibilité d'utiliser les beans de services comme des backing beans (beans JSF) ;

- possibilité d'utiliser les mêmes composants (beans) pour plusieurs applications.

II - Configuration de web.xml

Voici notre fichier web.xml

web.xml

1. <?xml version="1.0" encoding="UTF-8"?>

2. <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

3. xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"

4. xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"

5. version="2.5">

6. <!-- JSF -->

7. <context-param>

8. <param-name>javax.faces.PROJECT_STAGE</param-name>

9. <param-value>Development</param-value>

10. </context-param>

11. <servlet>

12. <servlet-name>facesServlet</servlet-name>

13. <servlet-class>javax.faces.webapp.FacesServlet</servlet-class>

14. </servlet>

15. <servlet-mapping>

16. <servlet-name>facesServlet</servlet-name>

17. <url-pattern>*.jsf</url-pattern>

18. </servlet-mapping>

20. <!-- Pretty FACES -->

22. <filter>

23. <filter-name>Pretty Filter</filter-name>

24. <filter-class>com.ocpsoft.pretty.PrettyFilter</filter-class>

25. </filter>

26. <filter-mapping>

27. <filter-name>Pretty Filter</filter-name>

28. <url-pattern>/*</url-pattern>

29. <dispatcher>FORWARD</dispatcher>

30. <dispatcher>REQUEST</dispatcher>

31. <dispatcher>ERROR</dispatcher>

32. </filter-mapping>

34. <!-- SPRING -->

36. <listener>

37. <listener-class>

38. org.springframework.web.context.ContextLoaderListener

39. </listener-class>

40. </listener>

41. <!-- Lets the bean definition file specify scopes of request and session. -->

42. <listener>

43. <listener-class>

44. org.springframework.web.context.request.RequestContextListener

45. </listener-class>

46. </listener>

48. <welcome-file-list>

49. <welcome-file>index.html</welcome-file>

50. </welcome-file-list>

51. </web-app>

Nous allons nous attarder un peu sur ce fichier afin que vous puissiez comprendre la configuration. De la ligne 11 à la ligne 19, nous avons défini une Servlet, celle de JSF qui intercepte toutes les URL terminant par .jsf. Des lignes 20 à 29, nous avons déclaré le filtre de PrettyFaces qui intercepte toutes les URL afin de les réécrire (nous y reviendrons plus tard). Des lignes 34 à 39, nous avons défini deux listeners de Spring. Nous allons expliquer le rôle de chaque listener :

- ContextLoaderListener : il est lancé lors du démarrage de l'application. C'est lui qui instancie l'applicationContext en se basant sur le fichier WEB-INF/applicationContext.xml. Une fois instanciée, la référence de l'applicationContext est placée dans ServletContext. On peut ainsi y accéder grâce à la méthode getRequiredWebApplicationContext de WebApplicationContextUtils.

- RequestContextListener : en plus des scopes classiques de Spring, ce listener nous permet d'avoir les scopes Request et Sessions.

III - Configuration de faces-config.xml

D'habitude c'est JSF qui se charge de la gestion des beans. Nous allons maintenant déléguer cette gestion à Spring. Pour cela, nous allons configurer notre fichier faces-config.xml comme suit :

faces-config.xml

1. <?xml version='1.0' encoding='UTF-8'?>

2. <faces-config xmlns="http://java.sun.com/xml/ns/javaee"

3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

4. xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-facesconfig_2_0.xsd"

5. version="2.0">

6. <application>

7. <el-resolver>org.springframework.web.jsf.el.SpringBeanFacesELResolver</el-resolver>

8. </application>

9. </faces-config>

Nous allons maintenant mettre en place notre classe PersonBean qui sera un composant Spring.

PersonBean

1. package com.paloit.bean;

3. import java.util.List;

5. import javax.faces.event.ActionEvent;

7. import org.springframework.beans.factory.annotation.Autowired;

8. import org.springframework.context.annotation.Scope;

9. import org.springframework.stereotype.Component;

11. import com.paloit.entities.Person;

12. import com.paloit.manager.PersonManager;

14. /**

15. * PersonBean

16. *

17. * @author Palo-IT

18. * @since 22 févr. 2013

19. */

20. @Component

21. @Scope

22. public class PersonBean {

24. // =========================================================================

25. // ATTRIBUTES

26. // =========================================================================

27. private Person person;

29. private PersonManager manager;

31. // =========================================================================

32. // CONSTRUCTORS

33. // =========================================================================

35. public PersonBean() {

36. }

38. // =========================================================================

39. // METHODS

40. // =========================================================================

41. public String savePerson() {

42. manager.savePerson(person);

43. return "home";

44. }

46. public void deletePerson(ActionEvent event) {

47. manager.deletePerson(person);

48. }

50. public String editPerson(){

51. return "new_person";

52. }

54. public String newPerson(){

55. reinit();

56. return "new_personr";

57. }

58. person = new Person();

59. }

61. // =========================================================================

62. // OVERRIDES

63. // =========================================================================

65. // =========================================================================

66. // GETTERS & SETTERS

67. // =========================================================================

68. public List<Person> getAllPersons() {

69. return manager.getAllPersons();

70. }

72. public Person getPerson() {

73. return person;

74. }

76. public void setPerson(Person person) {

77. this.person = person;

78. }

80. @Autowired

81. public void setManager(PersonManager manager) {

82. this.manager = manager;

83. }

85. }

IV - Mise en place de PrimeFaces

JSF est un framework puissant et simple permettant de mettre en place des applications Web en se basant sur le Model MVC2. Cependant, JSF ne dispose que de peu de composants de base, laissant ainsi le soin au développeur d'utiliser des librairies ou d'implémenter ses propres composants. Parmi les librairies, PrimeFaces a particulièrement retenu mon attention. En effet, son intérêt principal réside dans sa simplicité, la richesse et la qualité de ses composants. À cela s'ajoute la quantité de composants mis à la disposition du développeur (plus de 100 composants). Contrairement aux autres librairies de composants comme RicheFaces, ICEfaces, Trinidad, l'intégration de PrimeFaces se fait sans configuration. En effet, il suffit d'ajouter ses dépendances dans le projet. Pour ce faire, il faut télécharger primefaces-x-y-z.jar et le placer dans le dossier lib ou à travers Maven en ajoutant la dépendance dans le fichier pom.xml.

pom.xml

1. <repository>

2. <id>prime-repo</id>

3. <name>PrimeFaces Maven Repository</name>

4. <url>http://repository.primefaces.org</url>

5. </repository>

7. <dependency>

8. <groupId>org.primefaces</groupId>

9. <artifactId>primefaces</artifactId>

10. <version>3.5</version>

11. </dependency>

Nous allons mettre en place notre page xhtml. Pour cela, nous aurons deux pages. La première (home.xhtml) permettra d'afficher la liste des personnes présentes en base alors que la deuxième (user.xhtml) servira à créer ou mettre à jour une personne.

home.xhtml

1. <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"

2. "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

3. <html xmlns="http://www.w3.org/1999/xhtml"

4. xmlns:h="http://java.sun.com/jsf/html"

5. xmlns:f="http://java.sun.com/jsf/core"

6. xmlns:p="http://primefaces.org/ui">

7. <h:head>

8. <title></title>

9. <link href="./css/styles.css" rel="stylesheet" type="text/css" />

10. </h:head>

11. <h:body>

12. <h:form id="form">

13. <p:outputPanel id="users">

14. <p:dataTable id="usersTable" value="#{personBean.allPersons}"

15. var="person">

16. <p:column>

17. <f:facet name="header">

18. <h:outputText value="Name" />

19. </f:facet>

20. <p:commandLink action="#{personBean.editPerson}">

21. <h:outputText value="#{person.name}" />

22. <f:setPropertyActionListener target="#{personBean.person}"

23. value="#{person}" />

24. </p:commandLink>

25. </p:column>

27. <p:column>

28. <f:facet name="header">

29. <h:outputText value="Age" />

30. </f:facet>

31. <p:commandLink action="#{personBean.editPerson}">

32. <h:outputText value="#{person.age}" />

33. <f:setPropertyActionListener target="#{personBean.person}"

34. value="#{person}" />

35. </p:commandLink>

36. </p:column>

37. </p:dataTable>

38. </p:outputPanel>

39. <p:commandButton value="Create New User"

40. action="#{personBean.newPerson}" />

41. </h:form>

42. </h:body>

43. </html>

new_person.xhtml

1. <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"

2. "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

3. <html xmlns="http://www.w3.org/1999/xhtml"

4. xmlns:h="http://java.sun.com/jsf/html"

5. xmlns:f="http://java.sun.com/jsf/core"

6. xmlns:p="http://primefaces.org/ui">

7. <h:head>

8. <title></title>

9. <link href="./css/styles.css" rel="stylesheet" type="text/css" />

10. </h:head>

11. <h:body>

12. <h:form id="form">

13. <p:growl id="msgs" />

14. <p:panel header="Create a new User">

15. <h:panelGrid columns="2" id="grid">

16. <h:outputLabel value="Name : *" for="txt_name" />

17. <p:inputText id="txt_name" value="#{personBean.person.name}"

18. required="true" />

20. <h:outputLabel value="age : *" for="txt_age" />

21. <p:inputText id="txt_age" required="true"

22. value="#{personBean.person.age}" />

24. <p:commandButton value="Reset" type="reset" />

25. <p:commandButton id="btn_add" value="Add"

26. action="#{personBean.savePerson}" />

27. </h:panelGrid>

28. </p:panel>

29. </h:form>

30. </h:body>

31. </html>

V - Réécriture des URL

On peut remarquer qu'on a la même URL pour créer et pour éditer une personne. Ceci est normal, car nous utilisons la même page pour les deux actions. Nous allons utiliser deux URL pour différencier les deux actions. Pour ce faire, nous utiliserons PrettyFaces.

VI - Mise en place de PrettyFaces

Pour mettre en place PrettyFaces, nous allons déclarer le filtre de PrettyFaces dans le fichier web.xml afin d'intercepter toutes les requêtes HTTP et de les traiter. Une fois notre filtre déclaré, nous créons un fichier pretty-config.xml. C'est dans ce fichier que nous allons mettre en place les règles de réécriture des URL.

pretty-config.xml

1. <?xml version="1.0" encoding="UTF-8"?>

2. <pretty-config xmlns="http://ocpsoft.com/prettyfaces/3.3.2"

3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

4. xsi:schemaLocation="http://ocpsoft.com/prettyfaces/3.3.2

6. http://ocpsoft.com/xml/ns/prettyfaces/ocpsoft-pretty-faces-3.3.2.xsd">

8. <url-mapping id="home">

9. <pattern value="/" />

10. <view-id value="home.jsf" />

11. </url-mapping>

12. <url-mapping id="new_user">

13. <pattern value="/new_user" />

14. <view-id value="/new_person.jsf" />

15. </url-mapping>

16. <url-mapping id="edit">

17. <pattern value="/edit/#{personBean.person.name}" />

18. <view-id value="/new_person.jsf" />

19. </url-mapping>

20. </pretty-config>

L'URL pour éditer une personne est maintenant : /edit/nom de la personne et pour créer une nouvelle personne /new_user

Nous allons maintenant modifier notre classe PersonBean afin de l'adapter avec notre configuration PrettyFaces.

PersonBean

1. package com.paloit.bean;

3. import java.util.List;

5. import javax.faces.event.ActionEvent;

7. import org.springframework.beans.factory.annotation.Autowired;

8. import org.springframework.context.annotation.Scope;

9. import org.springframework.stereotype.Component;

11. import com.paloit.entities.Person;

12. import com.paloit.manager.PersonManager;

14. /**

15. * PersonBean

16. *

17. * @author Palo-IT

18. * @since 22 févr. 2013

19. */

20. @Component

21. @Scope

22. public class PersonBean {

24. // =========================================================================

25. // ATTRIBUTES

26. // =========================================================================

27. private Person person;

29. private PersonManager manager;

31. // =========================================================================

32. // CONSTRUCTORS

33. // =========================================================================

35. public PersonBean() {

36. }

38. // =========================================================================

39. // METHODS

40. // =========================================================================

41. public String savePerson() {

42. manager.savePerson(person);

43. return "pretty:home";

44. }

46. public void deletePerson(ActionEvent event) {

47. manager.deletePerson(person);

48. }

50. public String editPerson(){

51. return "pretty:edit";

52. }

54. public String newPerson(){

55. reinit();

56. return "pretty:new_user";

57. }

59. public void reinit() {

60. person = new Person();

61. }

63. // =========================================================================

64. // OVERRIDES

65. // =========================================================================

67. // =========================================================================

68. // GETTERS & SETTERS

69. // =========================================================================

70. public List<Person> getAllPersons() {

71. return manager.getAllPersons();

72. }

74. public Person getPerson() {

75. return person;

76. }

78. public void setPerson(Person person) {

79. this.person = person;

80. }

82. @Autowired

83. public void setManager(PersonManager manager) {

84. this.manager = manager;

85. }

87. }

Comme vous le voyez, les méthodes ne renvoient plus le nom de la page mais plutôt l'ID défini dans le fichier de mapping des URL de PrettyFaces précédé de « pretty: ». Et maintenant, voici le résultat final :

VII - Remerciements

Cet article a été publié avec l'aimable autorisation de la société PaloIT.

Nous tenons à remercier f-leb pour sa relecture orthographique attentive de cet article et Mickael Baron pour la mise au gabarit.