miércoles, 30 de noviembre de 2016

Resumen videos Spring Boot 101 Parte 2/4. Fichero de configuración, JPA

Continuamos con un resumen de lo mas destacado de  nuestro querido amigo Dan Geabunea y su inestimable recurso de Romanian Coder.


1. Fichero de configuración application.properties

En este fichero podemos guardar las siguientes propiedades:

1. Las que afectan a las de documentación JSONDoc que hemos visto en una entrada anterior.

2. Para inidicar donde se guardan los archivos de BD. Por ejemplo para h2 se puede hacer

   spring.datasource.url=jdbc:h2:file:./bookings.db

3. El puerto donde correrá nuestra aplicación

  server.port = 8080


4. Variables que vamos a utilizar para configurar nuestra aplicación

  app-mode = development  (para distinguir entre development o production)

Para el caso de las variables a utilizar en la aplicación se puede hacer referencia a ella mediante 2 métodos que hablaremos mas tarde.

2. Recuperar variables de aplication.properties

Para ello podemos actuar de 2 maneres distintas

MÉTODO 1: Inyección de propiedad


@Value("${app-mode}")
private String appMode;


MÉTODO 2: Inyección de constructor


private String appMode2;
public DemoController (Environment env) {
  appMode2=env.getProperty("app-mode");
}

Siendo DemoController el nombre de la clase sobre la que creamos el constructor.

3. El Model de Spring

Spring proporciona un lugar donde guardar ciertas variables que nos serán útiles para dar un comportamiento concreto al programa. Estas variables se guardan en el "Model".
Para guardar las variables en el Model hay un método que se llama addAttribute. Podemos por ejemplo, añadir al modelo, entre otras, las variables recuperadas de application.properties. Veamos un pequeño ejemplo

package com.ximodante;

import java.util.Date;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.ui.Model;

@Controller
public class ViewController {
 
 @Value("${app-mode}")
 private String appMode;
 
 @RequestMapping("/")
 public String index(Model model){
  model.addAttribute("datetime", new Date());
  model.addAttribute("username", "Informatica Dantesca");
  model.addAttribute("mode", appMode);
  return "index";
 }

}
Aquí estamos adelantando lo que veremos mas adelante, que es mostrar una plantilla Thymeleaf llamada "index.html" cuando llamamos a nuestra aplicación con la ruta "http://localhost:8080"


4. JPA muy simple


PASO 1:
Cuando creamos el proyecto en la entrada anterior le hemos dicho utilizar JPA y h2

PASO 2:
Crearemos una entidad (POJO) y le indicaremos entre otras las siguientes anotaciones:

@Entity:
Anotación a nivel de clase para que JPA sepa que es una entidad a persistir

@Id:
Anotación sobre un atributo numérico para que sea clave única

@GeneratedValue(strategy = GenerationType.SEQUENCE)
Para que sea autogerado e incremental

Veamos la clase en concreto a la cual hemos quitado verbosidad con Lombok


package com.ximodante;

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

import lombok.Getter;
import lombok.Setter;

@Entity
public class HotelBooking {
 @Id
 @GeneratedValue(strategy = GenerationType.SEQUENCE)
 @Getter private long id;
 @Getter @Setter private String hotelName;
 @Getter @Setter private double pricePerNight;
 @Getter @Setter private int nbOfNights;
        

 public HotelBooking() {
  super();
 }

 public HotelBooking(String hotelName, double pricePerNight, int nbOfNights){
        this.hotelName = hotelName;
        this.pricePerNight = pricePerNight;
        this.nbOfNights = nbOfNights;
 }
    
    
 public double getTotalPrice(){
        return pricePerNight * nbOfNights;
 }

    
}


5. JpaRepository

En Spring podemos heredar de la interfaz JpaRepository y adapatarla a nuestra clase. pero con la "ventaja" que Spring nos da de tener métodos por "convención". Notar el uso de la anotación @Repository  Veamos interfaz adaptada:

package com.ximodante;

import java.util.List;

import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
@Repository
public interface BookingRepository extends JpaRepository < HotelBooking,Long >{
 List < HotelBooking > findByPricePerNightLessThan(double price);
}

Mirar el método findByPricePerNightLessThan, el cual no hemos creado en ningún sitio!!! Pero que si que podemos ver en la documentación de Spring.

6. Generador de datos en la BD con CommandLineRunner

Spring proporciona generadores de datos en las BD de prueba. Hay que tener cuidado ya que tal como tenenos nuestro proyecto, está pensado en el desarrollo y no en la producción ya que se borran todos los datos de la BD y se crean solo los que se indican en el generador.

En cualquier caso Spring te permite esta alimentación de la BD mediante la implementación de la intefaz CommandLineRunner y haciendo uso del JpaRepository. Notar las notaciones @Component y @Autowired.
Veamos como guardamos llenamos la BD con información de la entidad mostrada arriba


package com.ximodante;

import java.util.ArrayList;
import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.stereotype.Component;

@Component
public class DatabaseSeeder implements CommandLineRunner {

 private BookingRepository bookingRepository;
 
 @Autowired
 public DatabaseSeeder(BookingRepository bookingRepository){
  this.bookingRepository = bookingRepository;
 }
 
 @Override
 public void run(String... arg0) throws Exception {
        List <HotelBooking > bookings=new ArrayList<>();
        
     bookings.add(new HotelBooking("Palas",14.5,3));
     bookings.add(new HotelBooking("Ibis",24.5,2));
     bookings.add(new HotelBooking("Atenea",20,5));
     bookings.add(new HotelBooking("Palasiet",200,1));
  
     this.bookingRepository.save(bookings);
 }

}


7. REST con JPA


Nuestro querido amigo, en su tutorial, nos enseña a como integrar todas estas tecnologías. Aquí listo la clase que ofrece las funciones de persistencia a traves de servicios REST. Como los hemos documentado don JSONDoc, podemos verlos tal como lo hicimos en le punto anterior


package com.ximodante;


import java.util.List;

import org.jsondoc.core.annotation.Api;
import org.jsondoc.core.annotation.ApiMethod;
import org.jsondoc.core.annotation.ApiPathParam;
import org.jsondoc.core.pojo.ApiStage;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping(value = "/bookings")
@Api(
 name = "Hotel Booking API",
 description = "Provides a list of methods that manage hotel bookings",
 stage = ApiStage.RC)

public class BookingController {

 private BookingRepository bookingRepository;
 
 @Autowired
 public BookingController(BookingRepository bookingRepository){
     this.bookingRepository=bookingRepository;
    }

    @RequestMapping(value="/all" ,method = RequestMethod.GET)
    @ApiMethod(description = "Get all hotel bookings from database")
    public List getAll(){
     return this.bookingRepository.findAll();
    }
    
    
    @RequestMapping(value = "/affordable/{price}", method = RequestMethod.GET)
    @ApiMethod(description = "Get all hotel bookings from database whose price is under the provided value")
    public List getAffordable(@ApiPathParam(name = "price") @PathVariable double price){
     return this.bookingRepository.findByPricePerNightLessThan(price);
    }

    @RequestMapping(value = "/create", method = RequestMethod.POST)
    @ApiMethod(description = "Create a hotel booking and save it to the database")
    public List create(@RequestBody HotelBooking hotelBooking){
     this.bookingRepository.save(hotelBooking);
     return this.bookingRepository.findAll();
     
    }
    @RequestMapping(value = "/delete/{id}", method = RequestMethod.POST)
    @ApiMethod(description = "Deleta a hotel booking whose id is the provided value")
    public List remove(@ApiPathParam(name = "id") @PathVariable long id) {
     bookingRepository.delete(id);
     return this.bookingRepository.findAll();
    }
}








No hay comentarios :

Publicar un comentario