Portfolio de proyectos

Proyecto: Construir una aplicación Back-End en Spring con posibilidad de consumir métodos mediante SOAP.

La idea de construir sobre el protocolo SOAP (Simple Object Access Protocol) y una conexión a la base de datos H2 mediante Spring Boot era aprender los principios para una comunicación efectiva mediante una API para así acceder desde diferentes arquitecturas y lenguajes a métodos backend que nos permiten integrar un esquema MVC (Modelo Vista Controlador) consumiendo métodos del Backend y mostrándolos desde una vista en el FrontEnd construidas con otra tecnología.

La forma de implementar esto, es la siguiente:

La clase main


@SpringBootApplication
public class SoapModelsApplication implements CommandLineRunner {
  @Autowired
  JdbcTemplate jdbcTemplate;

  @Autowired
  JdbcOper jdbcOper = new JdbcOper(jdbcTemplate);

  public static void main(String[] args) {
    SpringApplication.run(SoapModelsApplication.class, args);
  }

  @Override
  public void run(String... strings) throws Exception {
    Endpoint.publish("http://localhost:1516/WS/modelos",new SoapUser(jdbcOper));
    Endpoint.publish("http://localhost:1516/WS/departamentos",new SoapDepartaments(jdbcOper));
  }
}

El método publish de la clase Endpoint lo que hace es crear y publicar un Endpoint en la dirección dada mediante el protocolo HTTP, HTTPS, TCP, SMTP o JMS para la publicación de un objeto que contiene las implementaciones de los métodos que se van a consumir.
En el siguiente caso, creamos un Endpoint basandonos en el objeto SoapUser correspondiente a los métodos de llamada del modelo correspondiente a User y otro Endpoint basándonos en el objeto SoapDepartaments que contiene la implementación del modelo Departaments.

    Endpoint.publish("http://localhost:1516/WS/modelos",new SoapUser(jdbcOper));
    Endpoint.publish("http://localhost:1516/WS/departamentos",new SoapDepartaments(jdbcOper));

Los modelos:

User
  public class User implements DynamicQuerys, RowMapper, Serializable {
    private static final long serialVersionUID = 1L;
    public long id;
    public String firstname, lastname;

    public User(long id, String firstname, String lastname) {
        super();
        this.id = id;
        this.firstname = firstname;
        this.lastname = lastname;
    }

    public User() {
        super();
    }

    public String getFirstName(){
        return firstname;
    }
    public String getLastName(){
        return lastname;
    }

    @Override
    public String toString() {
        return String.format(
                "Customer[id=%d, firstname='%s', lastname='%s']",
                id, firstname, lastname);
    }

    @Override
    public DynamicQuerys mapRow(ResultSet rs, int rowNum) throws SQLException {
        User Mapper = new User(rs.getLong("id"), rs.getString("firstname"), rs.getString("lastname"));
        return Mapper;
    }
}
Departaments
public class Departaments implements DynamicQuerys, RowMapper, Serializable {
    private static final long serialVersionUID = 1L;
    public long id;
    public String name, type;

    public Departaments(long id, String name, String type) {
        super();
        this.id = id;
        this.name = name;
        this.type = type;
    }

    public Departaments() {
        super();
    }

    public String getname(){
        return name;
    }
    public String gettype(){
        return type;
    }

    @Override
    public String toString() {
        return String.format(
                "Customer[id=%d, name='%s', type='%s']",
                id, name, type);
    }

    @Override
    public DynamicQuerys mapRow(ResultSet rs, int rowNum) throws SQLException {
        Departaments Mapper = new Departaments(rs.getLong("id"),
                                               rs.getString("name"),
                                               rs.getString("type"));
        return Mapper;
    }
}

En los modelos implementamos las interfaces DynamicQuerys para poder realizar casting (conversiones) entre objetos de diferentes modelos en sus correspondientes llamadas y aprovechar así los métodos de uno con diferentes creaciones de objetos, RowMapper es la que nos permite obtener resultados de la BD y extraerlos en un objeto y Serializable, ya que la información de dichos objetos va a ser transmitidas en forma de bytes por el protocolo HTTP

El siguiente método, mapRow lo que hace es mapear una tabla de la base de datos según el modelo que convenga, devuelve un objeto DynamicQuerys, de esta forma luego lo podremos convertir a un objeto del modelo User o del modelo Departaments, y acepta como argumentos, un objeto ResultSet y un entero indicando el número de filas que se quiere mapear.
El mapeo se realiza de la siguiente forma, creando un objeto del tipo del modelo en el que implementamos la llamada, en este caso, Departaments y pasándole como argumentos los métodos correspondientes al tipo de dato que se quiere mapear del objeto ResultSet.

      public DynamicQuerys mapRow(ResultSet rs, int rowNum) throws SQLException {
        Departaments Mapper = new Departaments(rs.getLong("id"),
                                               rs.getString("name"),
                                               rs.getString("type"));
        return Mapper;
    }


La interfaz DinamycQuerys

  public interface DynamicQuerys {
}

Es una interfaz vacía para poder realizar operaciones de casting entre los diferentes objetos de los modelos pertenecientes a las tablas de la BD.

Las interfaces para implementar el WS

Esta arquitectura permite separar la interfaz del objeto en la creación de un WS para consumir métodos por SOAP

ISoap
  @WebService(serviceName = "BDforSoap")
public interface ISoap {
    @WebMethod(operationName = "getUsers")
    public List getUsers();

    @WebMethod(operationName = "addUsers")
    public void addUser(@WebParam(name = "Usuario") List user);
    /*
    @WebMethod(operationName = "createDB")
    public void createDB();
    */
    /* Nueva implementación */
    @WebMethod(operationName = "getSelUser")
    public List getSelUser(@WebParam(name = "userName") String userName);

}
ISoapDept
@WebService(serviceName = "SoapDept")
public interface ISoapDept {
    @WebMethod(operationName = "getDept")
    public List getDeptps();

    @WebMethod(operationName = "addDept")
    public void addDept(@WebParam(name = "Departamentos") List Departaments);
    /*
    @WebMethod(operationName = "createDB")
    public void createDB();
    */
}

La implementación del WS la hacemos mediante anotaciones, de forma que la anotación @WebService índica que la clase es un servicio, así como el nombre del servicio que vendrá dado en el WSDL (Web Service Description Languaje) y la anotación @WebMethod indica que el método asociado a esta anotación, es un método que podra consumirse por la API Soap, así como podremos darle el nombre dle método que tendrá en el contrato (WSDL). Con la anotación @WebParam(name = "Departamentos") le damos el nombre al parámetro que tendrá en el contrato.

En esta forma de implementar el WS lo hacemos desde Java hacía el WSDL, pero la forma correcta sería generar el WSDL y a partir de ahí generar los objetos Java y sus métodos.

Las implementaciones de los métodos del WS
@Repository
@WebService(endpointInterface = "com.example.SoapModels.ISoapDept")
public class SoapDepartaments implements ISoapDept{

    @Autowired
    private JdbcOper jdbcOperations;

    public SoapDepartaments(JdbcOper jdbcOper) {
        this.jdbcOperations = jdbcOper;
    }

    @Override
    public List getDeptps() {
        String sqlSel = "SELECT * FROM Departaments";
        Departaments MiMapap4 = new Departaments();
        List MiLista4 = jdbcOperations.dinamyc_query(sqlSel,MiMapap4);
        List SelectUser = new ArrayList<>();

        for(DynamicQuerys usuarios : MiLista4){
            SelectUser.add((Departaments)usuarios);
        }
        return SelectUser;
    }

    @Override
    public void addDept(List Departaments) {
        String queryIns = "INSERT INTO Departaments(name, type) VALUES (?,?)";

        List splitArrayList = new ArrayList<>();

        for(Departaments departamentos : Departaments){
            Object[] ArrayObject = new Object[2];

            ArrayObject[0] = departamentos.getname();
            ArrayObject[1] = departamentos.gettype();

            splitArrayList.add(ArrayObject);
        }

        jdbcOperations.dinamyc_query(queryIns, splitArrayList);
    }
}

Con la anotación @WebService(endpointInterface = "com.example.SoapModels.ISoapDept") vinculamos el paquete donde se encuentra la interfaz y susodicha a la clase.
Implementaremos así los métodos especificados en la interfaz, estos serán, el método de recuperar de la BD los departamentos, y el método de añadir un nuevo departamento en la BD. Ambos podrán ser consumidos desde una aplicación externa mediante el protocolo SOAP.

Recuperar el listado de Departamentos de la BD

Lo primero que haremos, es preparar la query que va a recuperar todos los departamentos de la BD, esta será un SELECT sin filtros. Luego crearemos un objeto Departaments para pasarle el método de mapeo a los métodos de consulta a la BD que estarán contenidos en el objeto jdbcOperations, como este devolvera una lista de objetos relativos a la interfaz DynamicQuerys, tendrémos que crear nosotros una nueva Lista de objetos Departaments y añadir todo lo devuelto por el mapeo en forma de DynamicQuerys a la lista de Departaments, para esto realizaremos un for, recorriendo toda la lista primera e insertándola en la segunda.
Retornaremos la lista de Departaments.

Añadir Departamentos a la BD

Preparamos la query que lanzaremos contra la BD, esta será un INSERT con dos parámetros pertenecientes al nombre del departamento y al tipo de departamento, dos de los atributos contenidos en el objeto Departaments.
A continuación creamos una lista de arrays de objetos, que serán los que contendrán los parámetros a insertar, realizamos un bucle for y como tenemos dos atributos como parámetros, vamos insertando un Array de Object[] por cada departamento que queramos insertar en la BD.
Por último llamamos al método dinamic_query del objeto jdbcOperations e insertamos en la BD de una vez todos los departamentos pasados por parámetros de Objetc[].

La clase implementadora de los métodos de acceso a la BD

@Repository
public class JdbcOper {

    @Autowired
    JdbcTemplate jdbcTemplate;

    public JdbcOper(JdbcTemplate jdbcTemplate) {
        this.jdbcTemplate = jdbcTemplate;
    }

    public List dinamyc_query(String sql, Object[] Params, RowMapper Mapa){
        return jdbcTemplate.query(sql, Params, Mapa);
    }

    public List dinamyc_query(String sql, RowMapper Mapa){
        return jdbcTemplate.query(sql, Mapa);
    }

    public void dinamyc_query(String sql, Object[] Params){
        jdbcTemplate.update(sql,Params);
    }

    public void dinamyc_query(String sql, List Params){
        jdbcTemplate.batchUpdate(sql,Params);
    }
}

Esta clase usa el polimorfismo de la POO para dependiendo del número y el tipo de parámetros que le pasemos, realice una acción u otra mediante el método dinamyc_query, un parámetro que es común a todas las formas del método, es el de String sql cuya entrada es un string con la query correspondiente en SQL que realizaremos contra la BD, los siguientes parámetros, pueden ser, un Array de Object[] para pasar parámetros por ejemplo en un filtro de un WHERE o datos a insertar o a actualizar en un INSERT.
Otro parámetro posible es el de un RowMapper, para mapear los datos que nos devolverá la query. O también tenemos la posibilidad de pasar una lista de Arrays de Object, de esta forma podemos integrar varios INSERT en una misma consulta a la BD.

Los @Autowired

El @autowired es una de las anotaciones más famosas dentro del framework de Spring bott y se utiliza para hacer inyección de dependencias, un proceso que permite que un objeto reciba sus dependencias de fuentes externas, en vez de crearlas por sí mismo.
De esta forma, por ejemplo al crear un objeto jdbcOper ya le pasamos la dependencia de jdbcTemplate creado en el main, es una forma de hacer que esto funcione, por ejemplo, inyectamos la dependencia JdbcTemplate en el main, que es la clase que se encargara de acceder a los datos de la BD, también inyectamos en el main, la dependencia de JdbcOper creando una instancia de este objeto que sera inyectado en las clases de los controladores de los modelos.
A mi modo de entender, la inyección de dependencias lo que hace es inyectar un objeto ya instanciado en una clase, de esta forma ya lo tenemos inicializado y listo para usarse, sin tener que crear una instancia de ese mismo objeto dentro de la clase, así también usamos la información de la instancia de un objeto a otro, no creándolo desde cero.



Contacto

Para más información, proponer o trabajar en algún proyecto conjunto:

Email: arxivelogic@proton.me