Hola, muy
buenas tardes a todos.
Debido al éxito del vídeo de la primera parte sobre
la creación del modelo y de su configuración en el "application.properties";
ahora nos concentraremos en la parte de la constitución de su respectivo
repositorio y servicio que son partes esenciales de una API Rest con Spring
Boot y JPA, conectando a MySQL.
En todo caso, hoy voy a tratar sobre ¿Qué es un
repositorio, y que es un servicio en un API Rest?
En resumidas cuentas, un repositorio visto desde un
archivo en Java no es más que una interfaz que hereda de una serie de
"Repositories" y una de ellas en la que vamos a trabajar en este
vídeo (artículo) es la de JPA Repository, aunque también podríamos mencionar el
CRUDRepository.
Para darle un significado más concreto, un repositorio
es una lista de instrucciones por el cual está previamente configurado para que
el administrador de sistema, y también, el usuario final, pueda ejecutar las
operaciones determinadas, algunas como, buscar por ID, guardar la información
en su respectiva bases de datos, o darle al usuario en sí, la facultad de
eliminar un dato en la DB.
Generalmente un archivo como el JPARepository es un
archivo .class en Java, lo que efectua realmente son las tareas que hace en el
CRUD que estamos realizando, y por consiguiente, dichas tareas son agrupadas
como métodos con y sin parámetros, la estructura del JPARepository viene a
asemejarse a una interfaz, que no es más que, un conjunto de métodos o firmas
que llevan o no parámentros.
La sintáxis de nuestro UserRepository, queda
expreso de la siguiente forma, aunque también podemos incluir en dicho
repositorio, los métodos o firmas definidos por el usuario:
@Repository
public interface UserRepository extends JpaRepository<UserModel,Long>
{
Como puede saber, el archivo UserRepository
(repositorio), reune todos los métodos que HEREDAN de la clase
JPARepository, llevando consigo dos parámetros encerrados en dos símbolos menor
y mayor que, dichos parámetros son determinados como: 1. El tipo de Model (que
aparece como UserModel), y 2. El tipo de dato al cuál está asociado la llave
primaria ID del archivo UserModel que en este caso es Long.
Como regla general, todo archivo que esté
relacionado con el repositorio, se emplea la anotación @Repository.
En resumen, un repositorio no es más que, una
colección de métodos heredados de una clase en específico (en este segundo
vídeo empleamos el JPARepository) que llevan dos parámetros dados, uno para el
tipo de Modelo, y el otro para el tipo de dato que es la llave primaria
perteneciente al Modelo perse.
Ahora pasemos de una vez a lo que es un Servicio
en una APIRest con Spring Boot, podría deducir que, un servicio no es más que
la inyección de los métodos dados en la interfaz UserRepository (más
exactamente del repositorio de nuestra APIRest), salvo que, para que se pueda
implementar nuestro Servicio a partir de lo anterior, se emplea
la anotación @Autowired.
La anotación @Autowired es súper
importante utilizarla ya que es una de las partes más indispensables a la hora
de crear nuestra APIRest, palabras más, palabras menos; dicha anotación hace
las veces de una llave que nos permite "conectar", en este caso,
nuestro Repository con el servicio. En nuestro artículo (vídeo), se empleará
todo el conjunto de métodos que parte de nuestro repositorio, y como de ahorrar
código se trata, vamos a crear nuestro servicio por medio de las interfaces, no
obstante, y partiendo de lo anterior, esta porción de código es por el cuál nos
permite "inyectar" nuestro repositorio, al servicio:
@Autowired
UserRepository userRepository;
Todo
archivo que esté asociado a un Servicio en SpringBoot, es indispensable el uso
de la anotación @Service, para indicar que dicho elemento es un servicio
como tal. Antes de proceder con la implementación del repositorio y del
servicio en sí, para nuestra API Rest, se debe crear los siguientes paquetes,
uno para el Repositorio y otro para el servicio:
.png) |
Fig 1. - Procedimiento para agregar un paquete en Java (ampliar imágen - Parte 1)
|
Sólamente haciendo clic derecho del ratón en dónde
está el paquete principal de nuestro proyecto, luego le damos en New
->Package, para luego desplegar un cuadro en dónde seleccionaremos Interface
bajo los nombres de UserRepository y UserServiceInterface (este último nos
ayuda cuándo vayamos a implementar los métodos de la interfaz
UserServiceInterface, nos ayuda un montón a la hora de escribir código), Un submenú nos aparecerá después de haber realizado el procedimiento previo:
.png) |
Fig 2. - Submenú para definir al usuario qué se va a crear
|
La
apariencia en la barra del explorador quedará así:
.png) |
Fig 3. - Vista de la barra del explorador de IntelliJIDEA (Nótese que están las interfaces para el repositorio y el servicio)
|
Después de los pasos anteriormente descritos, vayamos al archivo UserRepository que está en el paquete del mismo nombre, y vamos a heredar todos los atributos de la clase JPARepository, además de implementar nuestras propias firmas (o clases en sí, porqué una interfaz es una plantilla para definir unas clases por el cuál el usuario debe definir que se va a hacer con ellas), antes de iniciar con la escritura o bien, la implementación en código, se debe colocar la anotación @Repository, encima de "public interface" para definir de que en sí, es un repositorio:
package com.toadsdewin.basicCrud.UserRepository;
import com.toadsdewin.basicCrud.UserModel.UserModel;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
import java.util.List;
@Repository
public interface UserRepository extends JpaRepository<UserModel,Long>
{
public List<UserModel> findByCountry(String country);
public List<UserModel> findByOccupation(String occupation);
public List<UserModel> findByProfession(String profession);
public List<UserModel> findByAge (Integer age);
}
Nuestro repositorio contiene todos los métodos heredados de la clase JPARepository, más otros tres que son definidos por nosotros como son:
- findByCountry: lleva por parámetro un objeto de tipo String cuya palabra es country, nos indica el país por el que debemos buscar.
- findByOccupation: el mismo significado que findByCountry, sólo que éste nos permite indexar la ocupación otorgada a la persona que se agregó en nuestra DB.
- findByProfession: la misma función que findByCountry, sólo que ésta nos permite indexar la profesión de la persona que está en nuestra DB.
- findByAge: lleva por parámetro un objeto de tipo Integer cuya palabra es age, nos indica que podemos buscar un listado de usuarios que tenga una determinada edad.
No obstante, nuestro repositorio llevan dos parámetros en un diamanta como se ve después de la palabra JPARepository, cada elemento pertenece a dos objetos, uno que es el nombre de la clase asociada al Modelo, y su segundo parámetro lleva consigo el tipo de dato u objeto al cuál está asociada nuestra llave primaria. Ahora bien, ¿Y cómo vamos a trasladar todos esos métodos a su respectivo servico?, no tienen que preocuparse, se los explicaré.
Vamos directamente a nuestro archivo UserServiceInterface, y escribiremos nuestro código tal como aparece a continuación:
package com.toadsdewin.basicCrud.UserService;
import com.toadsdewin.basicCrud.UserModel.UserModel;
import java.util.List;
public interface UserServiceInterface
{
public boolean deleteUser(Long id);
public List<UserModel> getUsers();
public List<UserModel> getByCountry(String country);
public List<UserModel> getByOccupation(String occupation);
public List<UserModel> getByProfession(String profession);
public List<UserModel> getByAge(Integer age);
public UserModel saveUser(UserModel user);
public UserModel upgradeUser(UserModel user,Long id);
public UserModel getById(Long id);
}
En esta interfaz de UserServiceInterface (valga la redundancia), tenemos nueve métodos compuestos de cuatro elementos de tipo List (de java.util.*), tres del tipo UserModel (viene del modelo), y un primitivo de tipo lógico o boolean. Al implementar nuestra interfaz, previa creación del código UserService y también de la implementación de nuestras anotaciones @Service y @Autowired, nos quedará de la siguiente forma, eso sí siguiendo los pasos dados a partir de la Figura 1:
package com.toadsdewin.basicCrud.UserService;
import com.toadsdewin.basicCrud.UserModel.UserModel;
import com.toadsdewin.basicCrud.UserRepository.UserRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
import java.util.Objects;
@Service
public class UserService implements UserServiceInterface
{
@Autowired
UserRepository userRepository;
@Override
public boolean deleteUser(Long id) {
try {
userRepository.deleteById(id);
return true;
}
catch (Exception error)
{
error.getMessage();
}
return false;
}
@Override
public List<UserModel> getUsers() {
return (List<UserModel>)userRepository.findAll();
}
@Override
public List<UserModel> getByCountry(String country) {
return userRepository.findByCountry(country);
}
@Override
public List<UserModel> getByOccupation(String occupation) {
return userRepository.findByOccupation(occupation);
}
@Override
public List<UserModel>getByProfession(String profession)
{
return userRepository.findByProfession(profession);
}
@Override
public List<UserModel> getByAge(Integer age) {
return userRepository.findByAge(age);
}
@Override
public UserModel saveUser(UserModel user) {
return userRepository.save(user);
}
@Override
public UserModel upgradeUser(UserModel user, Long id) {
try {
UserModel upgrade = userRepository.findById(id).get();
if (Objects.nonNull(user.getName()) && !"".equalsIgnoreCase(user.getName()))
{
upgrade.setName(user.getName());
}
if (Objects.nonNull(user.getSurname()) && !"".equalsIgnoreCase(user.getSurname()))
{
upgrade.setSurname(user.getSurname());
}
if (Objects.nonNull(user.getCountry()) && !"".equalsIgnoreCase(user.getCountry()))
{
upgrade.setCountry(user.getCountry());
}
if(Objects.nonNull(user.getOccupation()) && !"".equalsIgnoreCase(user.getOccupation()))
{
upgrade.setOccupation(user.getOccupation());
}
if(Objects.nonNull(user.getProfession())&& !"".equalsIgnoreCase(user.getProfession()))
{
upgrade.setProfession(user.getProfession());
}
if(Objects.nonNull((user.getAge()))&&! "".equals(user.getAge()))
{
upgrade.setAge(user.getAge());
}
return userRepository.save(upgrade);
}catch(Exception error)
{
error.getMessage();
}
return null;
}
@Override
public UserModel getById(Long id) {
return userRepository.findById(id).orElse(null);
}
}
Hasta el momento, esta es la parte de la implementación de nuestro repositorio y servicio, respectivamente; para que se vea realmente la ejecución de nuestros dos elementos, nos hace falta un elemento bien indispensable, se podría decir que es el santo grial del desarrollo de una API Rest con Spring Boot, y no es más que su @Controller, o controlador en sí, para esta última parte de nuestra implementación, les explicaré no solamente qué es y como funciona un controlador, sino que también voy a tocar el tema de los estados HTTP que aparecen en sus respectivas anotaciones aparte del @Controller. Eso sí, nos vemos en el siguiente post (vídeo).