sobota, 10 maja 2014

Proste połączenie spring, jpa (hibernate), spring data, postgresql

Proste zestawienie aplikacji z JPA i spring data.

1. Tworzymy projekt mavenowy w eclipsie z archetypu maven.archetype.webapp - aplikacja będzie aplikacją webową - za pomocą żądania restowego przetestujemy pobieranie danych z bazy.

2. Dodajemy potrzebne zależności do poma:
zależności mvc, rest: servlet-api, jackson-mapper-asl
mamy dodatkowe zależności do jpa: hibernate-entitymanager, jta, spring-jdbc, spring-orm, spring-data-jpa i postgresql.

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.java.ro</groupId>
    <artifactId>Invoices</artifactId>
    <packaging>war</packaging>
    <version>0.0.1-SNAPSHOT</version>
    <name>Invoices Maven Webapp</name>
    <url>http://maven.apache.org</url>
    <dependencies>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>3.8.1</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-webmvc</artifactId>
            <version>3.2.8.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>servlet-api</artifactId>
            <version>2.5</version>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>org.codehaus.jackson</groupId>
            <artifactId>jackson-mapper-asl</artifactId>
            <version>1.4.1</version>
        </dependency>

        <dependency>
            <groupId>org.hibernate</groupId>
            <artifactId>hibernate-entitymanager</artifactId>
            <version>4.3.4.Final</version>
        </dependency>
        <dependency>
            <groupId>javax.transaction</groupId>
            <artifactId>jta</artifactId>
            <version>1.1</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-jdbc</artifactId>
            <version>3.2.8.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-orm</artifactId>
            <version>3.2.8.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.postgresql</groupId>
            <artifactId>postgresql</artifactId>
            <version>9.3-1100-jdbc41</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.data</groupId>
            <artifactId>spring-data-jpa</artifactId>
            <version>1.4.3.RELEASE</version>
            <exclusions>
                <exclusion>
                    <groupId>org.springframework</groupId>
                    <artifactId>spring-aop</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
    </dependencies>
    <build>
        <finalName>Invoices</finalName>
    </build>
</project>


3. Konfigurujemy web.xml: dispacher servler oraz listener - dispacher będzie korzystać z pliku kontekstu do mvc (resta) a listener wczyta plik kontekstu do jpa:

<!DOCTYPE web-app PUBLIC
 "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
 "http://java.sun.com/dtd/web-app_2_3.dtd" >

<web-app>
    <display-name>Invoices</display-name>
   
    <!-- The definition of the Root Spring Container shared by all Servlets and Filters -->
    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>/WEB-INF/spring/root-context.xml</param-value>
    </context-param>
   
    <!-- Creates the Spring Container shared by all Servlets and Filters -->
    <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>
    <servlet>
        <servlet-name>appServlet</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>/WEB-INF/spring/servlet-context.xml</param-value>
        </init-param>
        <load-on-startup>1</load-on-startup>
    </servlet>
    <servlet-mapping>
        <servlet-name>appServlet</servlet-name>
        <url-pattern>/</url-pattern>
    </servlet-mapping>
</web-app>


 4. Konfigurujemy serwis restowy (servlet-context.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:mvc="http://www.springframework.org/schema/mvc"
    xmlns:context="http://www.springframework.org/schema/context"
    xsi:schemaLocation="http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.2.xsd
        http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.2.xsd">

    <mvc:annotation-driven/>
   
    <context:component-scan base-package="com.java.ro.invoices.controler"/>
   
    <bean class="org.springframework.web.servlet.view.ContentNegotiatingViewResolver">
        <property name="order" value="1"/>
    </bean>
</beans>


5. Konfigurujemy jpa (root-context.xml): do konfiguracji potrzeba 3 podstawowych cegiełek:
  •  entityManagerFactory
  • transactionManager
  • dataSource
 oraz kilku innych beanów:
  • PersistenceAnnotationBeanPostProcessor - aby umożliwić wstrzyiwanie EntityManagera
  • jpa:repositories - określenie bazowego pakietu dla repozytorium
  • tx:annotation-driven - określenie że tranzakcyjność będzie zarządzana anotacjami
 <?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"
    xmlns:jdbc="http://www.springframework.org/schema/jdbc" xmlns:jpa="http://www.springframework.org/schema/data/jpa"
    xmlns:repository="http://www.springframework.org/schema/data/repository"
    xmlns:tx="http://www.springframework.org/schema/tx"
    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.2.xsd
        http://www.springframework.org/schema/jdbc http://www.springframework.org/schema/jdbc/spring-jdbc-3.2.xsd
        http://www.springframework.org/schema/data/jpa http://www.springframework.org/schema/data/jpa/spring-jpa-1.3.xsd
        http://www.springframework.org/schema/data/repository http://www.springframework.org/schema/data/repository/spring-repository-1.6.xsd
        http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.2.xsd">

    <!-- config with annotation -->
    <context:annotation-config />
   
    <tx:annotation-driven transaction-manager="transactionManager" />
   
    <context:component-scan base-package="com.java.ro.invoices"/>

    <!-- spring data repositories base package -->
    <jpa:repositories base-package="com.java.ro.invoices.model.repository" />

    <!-- use persistence context annotation -->
    <bean
        class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor" />

    <bean id="entityManagerFactory"
        class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
        <property name="persistenceUnitName" value="invoicesPersistenceUnit" />
        <property name="dataSource" ref="dataSource" />
        <property name="jpaVendorAdapter">
            <bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
                <property name="showSql" value="true" />
            </bean>
        </property>
        <property name="jpaPropertyMap">
            <map>
                <entry key="hibernate.dialect" value="org.hibernate.dialect.PostgreSQLDialect" />
                <entry key="hibernate.hbm2ddl.auto" value="create" />
                <entry key="hibernate.format_sql" value="true" />
            </map>
        </property>
    </bean>

    <bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
        <property name="entityManagerFactory" ref="entityManagerFactory" />
    </bean>
    <bean id="dataSource"
        class="org.springframework.jdbc.datasource.DriverManagerDataSource">
        <property name="driverClassName" value="org.postgresql.Driver" />
        <property name="url" value="jdbc:postgresql://localhost:5432/faktury" />
        <property name="username" value="invoice" />
        <property name="password" value="123" />
    </bean>

</beans>


6. W entity manager factory został podany persitence unit, należy stworzyć więc persistence.xml z tym persistent unitem - należy go umieścić w katalogu META-INF (scr/main/resources/META-INF):

<?xml version="1.0" encoding="UTF-8" ?>
<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_2_0.xsd"
  version="2.0" xmlns="http://java.sun.com/xml/ns/persistence">
  <persistence-unit name="invoicesPersistenceUnit">
  </persistence-unit>
</persistence>


7. Stworzenie przykładowej encji:

package com.java.ro.invoices.model.entity;

import java.io.Serializable;
import java.math.BigDecimal;
import java.util.Date;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;

@Entity
public class Invoice implements Serializable {
   
    private static final long serialVersionUID = 1L;

    @Id
    @GeneratedValue
    private Long id;
   
    @Column(length = 20, nullable = false)
    private String number;
   
    @Column(nullable = false)
    private Date dateOfIssue;
   
    @Column(nullable = false)
    private Date maturity;
   
    @Column(nullable = false, precision = 10, scale = 2)
    private BigDecimal totalAmount;

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getNumber() {
        return number;
    }

    public void setNumber(String number) {
        this.number = number;
    }

    public Date getDateOfIssue() {
        return dateOfIssue;
    }

    public void setDateOfIssue(Date dateOfIssue) {
        this.dateOfIssue = dateOfIssue;
    }

    public Date getMaturity() {
        return maturity;
    }

    public void setMaturity(Date maturity) {
        this.maturity = maturity;
    }

    public BigDecimal getTotalAmount() {
        return totalAmount;
    }

    public void setTotalAmount(BigDecimal totalAmount) {
        this.totalAmount = totalAmount;
    }
}


8. Tworzymy repozytorium dla encji - repozytorium będzie dziedziczyć z CRUDRepository:

package com.java.ro.invoices.model.repository;

import java.util.List;

import org.springframework.data.repository.CrudRepository;
import org.springframework.stereotype.Repository;

import com.java.ro.invoices.model.entity.Invoice;

@Repository
public interface InvoiceRepository extends CrudRepository<Invoice, Long> {

    List<Invoice> findAll();
}


9. Tworzymy prosty serwis - bardzo ważna jest adnotacja Transactional jeśli chcemy coś zapisywać:

package com.java.ro.invoices.model.service;
import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.java.ro.invoices.model.entity.Invoice;
import com.java.ro.invoices.model.repository.InvoiceRepository;

@Service
@Transactional
public class InvoiceService {
   
    @Autowired
    private InvoiceRepository repository;
   
    public List<Invoice> getInvoices() {
        return repository.findAll();
    }
}


10. Tworzymy kontroler mvc aby pobrać dane:

package com.java.ro.invoices.controler;

import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;

import com.java.ro.invoices.model.entity.Invoice;
import com.java.ro.invoices.model.service.InvoiceService;

@Controller
public class InvoiceControler {
   
   
    @Autowired
    private InvoiceService invoiceService;
   
    @RequestMapping(value="/getInvoices", method= RequestMethod.GET)
    public @ResponseBody List<Invoice> getInvoices() {
        return invoiceService.getInvoices();
    }
   
}


11. Instalujemy postgre sql i konfigurujemy bazę danych i użytkownika.
12. Testujemy aplikację startując ją na tomcacie: wchodzimy na stronę: http://localhost:8080/Invoices/getInvoices:

strona zwracja [] co jest zrozumiałe bo nie ma żadnych danych,
dodajemy dane ręcznie do bazy danych:

INSERT INTO invoice.invoice(
            id, dateofissue, maturity, "number", totalamount)
    VALUES (1, TIMESTAMP '2014-04-01 00:00:00', TIMESTAMP '2014-04-30 00:00:00', 'FV-2014-4', 122.32);

INSERT INTO invoice.invoice(
            id, dateofissue, maturity, "number", totalamount)
    VALUES (2, TIMESTAMP '2014-05-01 00:00:00', TIMESTAMP '2014-05-31 00:00:00', 'FV-2014-5', 445.76);


odświerzamy stronę i otrzymujemy rezultat:


Aplikacja zwraca rekordy z bazy danych.

Brak komentarzy:

Prześlij komentarz