En kontroller, service og DAO-eksempel med Spring Boot og JSF

1. Introduksjon

JavaServer Faces er et komponentbasert brukergrensesnittrammer på serversiden. Opprinnelig ble den utviklet som en del av Jakarta EE. I denne veiledningen, vi vil undersøke hvordan vi kan integrere JSF i en Spring Boot-applikasjon.

Som et eksempel implementerer vi en enkel applikasjon for å lage en TO-DO-liste.

2. Maven-avhengigheter

Vi må utvide vårt pom.xml å bruke JSF-teknologier:

 org.apache.tomcat.embed tomcat-embed-jasper org.glassfish javax.faces 2.3.7 

De javax.faces artifact inneholder også JSF APIer og implementeringene. Detaljert informasjon finner du her.

3. Konfigurere JSF Servlet

JSF-rammeverket bruker XHTML-filer for å beskrive innholdet og strukturen til brukergrensesnittet. Serversiden genererer JSF-filene fra XHTML-beskrivelsene.

La oss starte med å lage en statisk struktur i en index.xhtml filen i src / main / webapp katalog:

    TO-DO-applikasjon 

Velkommen til TO-DO-applikasjonen!

Dette er en statisk melding gjengitt fra xhtml.

Innholdet vil være tilgjengelig på /index.jsf. Selv om vi får en feilmelding på klientsiden hvis vi prøver å nå innholdet på dette stadiet:

Det oppsto en uventet feil (type = Ikke funnet, status = 404). Ingen melding tilgjengelig

Det blir ingen feilmelding om backend. Likevel kan vi finne ut av det vi trenger en JSF-servlet for å håndtere forespørselen og servletkartleggingen for å matche forespørselen med behandleren.

Siden vi er i Spring Boot, kan vi enkelt utvide applikasjonsklassen vår til å håndtere den nødvendige konfigurasjonen:

@SpringBootApplication offentlig klasse JsfApplication utvider SpringBootServletInitializer {public static void main (String [] args) {SpringApplication.run (JsfApplication.class, args); } @Bean public ServletRegistrationBean servletRegistrationBean () {FacesServlet servlet = new FacesServlet (); ServletRegistrationBean servletRegistrationBean = ny ServletRegistrationBean (servlet, "* .jsf"); retur servletRegistrationBean; }}

Dette ser bra ut og ganske rimelig, men dessverre fortsatt ikke bra nok. Når vi prøver å åpne /index.jsf nå får vi en ny feil:

java.lang.IllegalStateException: Fant ikke sikkerhetskopi for fabrikkens javax.faces.context.FacesContextFactory.

Dessverre trenger vi en web.xml ved siden av Java-konfigurasjonen. La oss lage det i src / webapp / WEB-INF:

 Ansikter Servlet javax.faces.webapp.FacesServlet 1 Ansikter Servlet * .jsf 

Nå er konfigurasjonen vår klar til bruk. Åpen /index.jsf:

Velkommen til TO-DO-applikasjonen! Dette er en statisk melding gjengitt fra xhtml.

Før vi lager brukergrensesnittet, la oss lage backend av applikasjonen.

4. Implementering av DAO-mønsteret

DAO står for data-tilgangsobjekt. Vanligvis er DAO-klassen ansvarlig for to konsepter. Innkapsling av detaljene i utholdenhetslaget og gir et CRUD-grensesnitt for en enkelt enhet. Du finner en detaljert beskrivelse i denne opplæringen.

For å implementere DAO-mønsteret, Vi definerer først et generisk grensesnitt:

offentlig grensesnitt Dao {Valgfritt get (int id); Samling getAll (); int lagre (T t); ugyldig oppdatering (T t); ugyldig sletting (T t); }

La oss nå lage vår første og eneste domeneklasse i denne oppgaveapplikasjonen:

offentlig klasse Todo {privat int id; privat strengmelding; privat int prioritet; // standard getters og setters}

Neste klasse blir implementeringen av Dao. Det fine med dette mønsteret at vi når som helst kan tilby en ny implementering av dette grensesnittet.

Derfor kan vi endre utholdenhetslaget uten å berøre resten av koden.

For vårt eksempel, vi bruker en lagringsklasse i minnet:

@Komponent offentlig klasse TodoDao implementerer Dao {private List todoList = new ArrayList (); @Override public Valgfritt get (int id) {return Optional.ofNullable (todoList.get (id)); } @Override public Collection getAll () {return todoList.stream () .filter (Objects :: nonNull) .collect (Collectors.collectingAndThen (Collectors.toList (), Collections :: unmodifiableList)); } @ Override public int save (Todo todo) {todoList.add (todo); int-indeks = todoList.size () - 1; todo.setId (indeks); returindeks; } @Override offentlig ugyldig oppdatering (Todo todo) {todoList.set (todo.getId (), todo); } @ Overstyr offentlig ugyldig sletting (Todo todo) {todoList.set (todo.getId (), null); }}

5. Servicelaget

DAO-lagets hovedmål er å håndtere detaljene i utholdenhetsmekanismen. Mens tjenestelaget står på toppen av det for å håndtere forretningskrav.

Legg merke til at DAO-grensesnittet vil bli referert fra tjenesten:

@Scope (value = "session") @Component (value = "todoService") offentlig klasse TodoService {@Autowired privat Dao todoDao; privat Todo todo = ny Todo (); offentlig ugyldig lagre () {todoDao.save (todo); todo = ny Todo (); } offentlig samling getAllTodo () {return todoDao.getAll (); } public int saveTodo (Todo todo) {validate (todo); gå tilbake todoDao.save (todo); } privat ugyldig validering (Todo todo) {// Detaljer utelatt} offentlig Todo getTodo () {return todo; }}

Her er tjenesten en navngitt komponent. Vi vil bruke navnet til å referere til bønnen fra JSF-sammenheng.

Denne klassen har også et øktomfang som vil være tilfredsstillende for denne enkle applikasjonen.

For mer informasjon om våromfang, ta en titt på denne veiledningen. Siden Spring's innebygde omfang har en annen modell enn JSF, er det verdt å vurdere å definere et tilpasset omfang.

Mer veiledning om dette er tilgjengelig i denne veiledningen.

6. Kontrolleren

Akkurat som i et JSP-program, vil kontrolleren håndtere navigering mellom de forskjellige visningene.

Deretter implementerer vi en minimalistisk kontroller. Den navigerer fra åpningssiden til oppgavelisten:

@Scope (value = "session") @Component (value = "jsfController") offentlig klasse JsfController {public String loadTodoPage () {checkPermission (); returner "/todo.xhtml"; } privat ugyldig kontrollPermission () {// Detaljer utelatt}}

Navigasjonen er basert på det returnerte navnet. Derav loadTodoPage vil sende oss til todo.xhtml side som vi implementerer neste.

7. Koble til JSF og vårbønner

La oss se hvordan vi kan referere til komponentene våre fra JSF-sammenheng. Først utvider vi index.xthml:

  // samme kode som før // samme kode som før 

Her introduserte vi en commandButton innsiden av et skjemaelement. Dette er viktig siden hver UIC-kommando element (f.eks. commandButton)må plasseres inne i en UIForm element (f.eks. form).

På dette stadiet kan vi starte søknaden vår og undersøke /index.jsf:

Dessverre får vi en feil når vi klikker på knappen:

Det oppsto en uventet feil (type = Internal Server Error, status = 500). javax.el.PropertyNotFoundException: /index.xhtml @ 11,104 action = "# {jsfController.loadTodoPage}": Target Unreachable, identifier [jsfController] løst til null

Meldingen angir tydelig problemet: jsfController løst å null. Den tilsvarende komponenten er enten ikke opprettet, eller i det minste er den usynlig fra JSF-sammenheng.

I denne situasjonen er sistnevnte sant.

Vi må koble vårkonteksten med JSF kontekst innenfor webapp / WEB-INF / ansikter-config.xml:

   org.springframework.web.jsf.el.SpringBeanFacesELResolver 

Nå som kontrolleren vår er klar til å jobbe, trenger vi den todo.xhtml!

8. Samhandle med en tjeneste fra JSF

Våre todo.xhtml siden vil ha to formål. Først vil den vise alle oppgavelementene.

For det andre, gi muligheten til å legge til nye elementer i listen.

For det vil UI-komponenten direkte samhandle med tjenesten deklarert tidligere:

    TO-DO-applikasjon Liste over TO-DO-poster Melding nr. {Item.message} Priority # {item.priority} Legg til nytt gjøremål: 

Ovennevnte to formål er implementert i to separate div elementer.

I den første brukte vi en data bord element for å representere alle verdiene fra todoService.AllTodo.

Den andre div inneholder et skjema der vi kan endre tilstanden til Å gjøre objekt i TodoService.

Vi bruker inputText element for å godta brukerinngang, der den andre inngangen automatisk blir konvertert til en int. Med kommandoKnapp, brukeren kan vedvare (inn i minnet nå) Å gjøre objekt med todoService.save.

9. Konklusjon

JSF-rammeverket kan integreres i vårrammen. Du må velge hvilket rammeverk som skal håndtere bønnene. I denne opplæringen brukte vi Spring framework.

Imidlertid er omfangsmodellen litt annerledes enn JSF-rammeverket. Så du kan vurdere å definere egendefinerte omfang i vårkonteksten.

Som alltid er koden tilgjengelig på GitHub.


$config[zx-auto] not found$config[zx-overlay] not found