Prosty przykład wykorzystania Java Servlets, JPA, Oracle 10XE i Glassfish v3
Celem tego wpisu jest pokazanie w jaki sposób stworzyć dynamiczną prostą aplikację WWW wykorzystującą technologię Java Servlets pobierającą dane z lokalnie dostępnej bazy danych Oracle 10g XE z wykorzystaniem JPA. Całość ma obsługiwać Glassfish v3.
Struktura relacyjna w bazie danych jest bardzo prosta, ale wystarczająca do zapoznania z JPA – składa się z tabeli zawierającej dane studentów takie jak imię, nazwisko i z z tabeli opisującej grupy dziekańskie. Obie tabele powiązane są relacją wiele-do-jednego, także grupa może składać się z wielu studentów, natomiast każdy student przynależy do dokładnie 1 grupy.
Na wstępie zaznaczam, że jestem początkujący w tej dziedzinie. Jeśli ktoś bardziej doświadczony, znajdzie jakieś nieścisłości lub błędy to proszę o pozostawienie komentarza. Chętnie poprawię i przy okazji czegoś się nauczę.
Opisana wyżej struktura bazy danych jest reprezentowana przez dwie encje połączone relacją i wygląda to następująco:

Java Persistence Api (JPA) jest wykorzystywane do mapowania encji zapisanych w bazie danych (wiersze tabeli) na ich obiektową reprezentację również nazywaną encją. Zbieżność terminów może powodować konsternację dlatego w dalszej części wpisu przez pojęcie encja należy rozumieć tylko odpowiednio opisaną klasę w języku Java.
W ogólnym wypadku każda klasa spełniająca wymogi JavaBean tj. posiadająca bezparametrowy konstruktor oraz metody get i set dla pól może zostać przekształcona w encję. Dla przykładu, Grupa może zostać opisana przez taki komponent:
package eu.doniec.piotr.bean
public class Grupa {
private Long id;
private String nazwa;
private String opis;
public Long getId() { return id; }
public void setId(Long id) { this.id = id; }
public String getNazwa() { return nazwa; }
public void setNazwa(String nazwa) { this.nazwa = nazwa; }
public String getOpis() { return opis; }
public void setOpis(String opis) { this.opis = opis; }
}
Modyfikacja do postaci encji, możliwej do wykorzystania przez JPA do obsługi danych zawartych w tabeli Grupy polega na opisaniu klasy metainformacjami – adnotacjami z pakietu javax.persistence. Gotowa klasa przedstawia się następująco:
package eu.doniec.piotr.persistence;
import java.io.Serializable;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.NamedQuery;
import javax.persistence.Table;
@Entity
@NamedQuery(
name="findAllGroups",
query="SELECT g FROM Grupa g"
)
@Table(name="GRUPY")
public class Grupa implements Serializable {
@Id @GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
private String nazwa;
private String opis;
public Long getId() { return id; }
public void setId(Long id) { this.id = id; }
public String getNazwa() { return nazwa; }
public void setNazwa(String nazwa) { this.nazwa = nazwa; }
public String getOpis() { return opis; }
public void setOpis(String opis) { this.opis = opis; }
}
Podobnie sytuacja wygląda z klasą Studenta, choć tu sytuacja jest trochę inna. Struktura bazy danych wymaga aby tabela STUDENCI posiadała ograniczenie FOREIGN_KEY na dodatkowe pole GRUPA_ID. W takiej sytuacji w ramach encji Student umieszczamy odwołanie do encji Grupa. Właściwość ta jest dodatkowo oznaczona adnotacją @ManyToOne oznaczającą właśnie że wielu studentów może przynależeć do jednej grupy.
package eu.doniec.piotr.persistence;
import java.io.Serializable;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.NamedQuery;
import javax.persistence.Table;
import javax.persistence.ManyToOne;
import javax.persistence.JoinColumn;
@Entity
@NamedQuery(
name="findAllStudents",
query="SELECT s FROM Student s"
)
@Table(name="STUDENCI")
public class Student implements Serializable {
@Id @GeneratedValue(strategy = GenerationType.AUTO)
private Long nr_indeksu;
private String imie;
private String nazwisko;
@ManyToOne
private Grupa grupa;
public Long getNr_indeksu() { return nr_indeksu; }
public void setNr_indeksu(Long nr_indeksu) { this.nr_indeksu=nr_indeksu; }
public String getImie() { return imie; }
public void setImie(String imie) { this.imie = imie; }
public String getNazwisko() { return nazwisko; }
public void setNazwisko(String nazwisko) { this.nazwisko = nazwisko; }
public Grupa getGrupa() { return grupa; }
public void setGrupa(Grupa grupa) { this.grupa = grupa; }
}
Encje są zdefiniowane, pozostało jeszcze je wykorzystać. W tym celu powstanie servlet, który wyświetli nr indeksu, nazwisk i przydział studenta do grupy. W celu wykorzystania stworzonych obiektów trzeba utworzyć obiekt EntityManager’a, a raczej „wstrzyknąć” go do aplikacji – uzyskuje się to annotacją @PersistenceContext. Utworzony w ten sposób EntityManager jest zarządzany przez kontener aplikacji tzw. container-managed. Sensowne wydaje się wstrzyknięcie go w klasie implementującej ServletContextListener i zapisanie w kontekście servletu, w ten sposób łatwo będzie się do niego dostać:
package eu.doniec.piotr.listeners;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import javax.servlet.annotation.WebListener;
import javax.servlet.ServletContext;
import javax.persistence.PersistenceContext;
import javax.persistence.EntityManager;
@WebListener()
public class ContextListener implements ServletContextListener {
@PersistenceContext
private EntityManager em;
private ServletContext context;
public void contextInitialized(ServletContextEvent sce) {
context = sce.getServletContext();
context.setAttribute("EntityManager", em);
}
public void contextDestroyed(ServletContextEvent sce) {
context.removeAttribute("EntityManager");
}
}
Na tym etapie, pozostało już tylko stworzenie serwletu i konfiguracja połączenia z bazą danych. Ostatni, prymitywny fragment kodu wypisuje na ekran nr indeksu, nazwisko i nazwę grupy do której zapisany jest student.
package eu.doniec.piotr.servlets;
import eu.doniec.piotr.persistence.Student;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Iterator;
import java.util.List;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.persistence.EntityManager;
import javax.persistence.Query;
@WebServlet(name="studenci", urlPatterns={"/studenci"})
public class Studenci extends HttpServlet {
protected void processRequest(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
response.setContentType("text/html;charset=UTF-8");
PrintWriter out = response.getWriter();
try {
EntityManager em = (EntityManager)getServletContext().getAttribute("EntityManager");
Query q = em.createNamedQuery("findAllStudents");
out.println("<html>");
out.println("<head>");
out.println("<title>Servlet studenci</title>");
out.println("</head>");
out.println("<body>");
out.println("<h1>Servlet studenci at " + request.getContextPath () + "</h1>");
out.println("<table>");
out.println("<tr><th>Numer indeksu</th><th>Nazwisko</th><th>Grupa</th></tr>");
List studenci = q.getResultList();
for (Iterator iter = studenci.iterator(); iter.hasNext();) {
Student s = (Student) iter.next();
out.println("<tr>");
out.println("<td>" + s.getNr_indeksu() +"</td>");
out.println("<td>" + s.getNazwisko() + "</td>");
out.println("<td>" + s.getGrupa().getNazwa() +"</td>");
out.println("</tr>");
}
out.println("</body>");
out.println("</html>");
} finally {
out.close();
}
}
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
processRequest(request, response);
}
}
Plik persistence.xml:
<?xml version="1.0" encoding="UTF-8"?>
<persistence version="1.0" xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd">
<persistence-unit name="baza-danych-nauczyciela-pu" transaction-type="JTA">
<provider>oracle.toplink.essentials.PersistenceProvider</provider>
<jta-data-source>jdbc/bazanauczyciela</jta-data-source>
</persistence-unit>
</persistence>
Sposób stworzenie źródła danych dla Oracle pod Glassfish wystarczająco dobrze opisany jest tu: http://technology.amis.nl/blog/1276/configuring-a-oracle-datasource-on-glassfish.
| Drukuj artykuł | Ten wpis został napisany przez pejotr na 03-02-2010 o 21:03, i jest w kategorii J2EE, Java, Programowanie. Podążaj za odpowiedziami do tego wpisu przez RSS 2.0. Możesz napisać komentarz, lub trackbacka z Twojej własnej strony. |
