Portfolio de proyectos

Proyecto: Interconectar sistemas AS400 y BD en JavaServer mediante sockets. Server en Java.

La clase application

Implementaremos la clase principal de nuestra aplicación, ella contendra el metodo main(), el metodo run() de la interfaz CommandLineRunner y los metodos static de acceso y peticiones a la base de datos.

	
@SpringBootApplication
public class BdsocketsApplication implements CommandLineRunner{
  private static ArrayList MiFichero;

  private static List splitArrayList;
  private static String MiStringSock[] = new String[4];
  private static final Logger log = LoggerFactory.getLogger(BdsocketsApplication.class);

  // Atributos FTP
  public static String ip = "XXX.XXX.XXX.XXX"; //IP del servidor FTP
  public static String user = "fran";// Usuario FTP
  public static String pass = "xxxx";// Password FTP
  public static String localFileDownload = "./datos.txt"; //Ruta del fichero local una vez descargado del FTP
  public static String hostFile = "prueba.txt"; //Nombre del fichero del FTP

  public static FTPClient ftp = new FTPClient();
  //END - Atributos FTP

  public static void main(String args[]) throws IOException {
    System.out.println("*****Mi servidor Java*****");
    Flujos Flujo1 = new Flujos();

    /* Se inicia la arquitectura cliente-servidor en JAVA inicializando el servidor que recibira las peticiones del cliente */

    Servidor MiServidor = new Servidor();
    MiServidor.startServer();
    System.out.println("**************************");
    MiStringSock = MiServidor.getMensaje();
    System.out.println(MiStringSock[0]);

    /* Si recibimos un "OK" lanzamos la descarga del fichero subido por el mainframe en el servidor FTP y lanzamos las conexiones y querys
    pertinentes contra la BD */
    if(MiStringSock[0].equals("OK")){
       conectar();
       desrcargarArchivoFTP();

       MiFichero = Flujo1.leer_fichero("datos.txt");
       SpringApplication.run(BdsocketsApplication.class, args);
    } else {
       System.out.println("No se activa la BD");
    }
  }

  @Autowired
  JdbcTemplate jdbcTemplate;


  @Override
  public void run(String... strings) throws Exception {

    String queryIns = "INSERT INTO customers(first_name, last_name) VALUES (?,?)";

    /* Este algoritmo esta abierto a mejoras, ya que actualmente lo que realiza es:
      Separa por ; cada elemento de la lista que contendrá el fichero en su totalidad, cada linea es un elemento de la lista.
      Se crea una nueva lista con un único elemento que contendra un array de Objects con los dos String contenientes por linea.
      Se llama al metodo dinamyc_query para insertar dicha linea en la base de datos.
      Se podría mejorar pasando una lista con arrays de objetos con todas las lineas del fichero, y una vez ahí, llamar al metodo
      dinamyc_query para hacer una inserción multiple.
    */
    for(String linea : MiFichero){
      System.out.println(linea);
      splitArrayList = Arrays.asList(linea).stream()
          .map(name -> name.split(";"))
          .collect(Collectors.toList());
      dinamyc_query(queryIns,splitArrayList);
    }
    
    /* Este pequeño fragmento de código realizaría la función de vista pintando en consola todos los elementos contenidos en la BD  */
    
    ArrayList Codigos = new ArrayList();
    ArrayList Nombres = new ArrayList();

    

    String sql4 = "SELECT * FROM customers";
    Customer MiMapap4 = new Customer();
    List MiLista4 = dinamyc_query(sql4,MiMapap4);
    MiLista4.forEach(pd3 -> Nombres.add(((Customer)pd3).getFirstName()));
    MiLista4.forEach(pd3 -> Codigos.add(((Customer)pd3).getLastName()));
    System.out.printf("\nLos empleados que contiene la BD son:\n");
    FormateaString MiImpresion = new FormateaString(Nombres,Codigos);
    MiImpresion.imprimeFormato();
  }

/*
  La función dinamyc_querys usa el poliformismo del paradigma de la POO para implementar una función genérica que pueda realizar las operaciones 
  de INSERT, UPDATAE, DELETE y SELECT contra la base de datos, dependiendo del tipo y número de parametros que le pasemos a la función.

  String sql: El string que contiene La query en SQL.
  Object[] Params: será un array de Object con los parametros que le pasaremos a la query.
  RowMapper Mapa: Es un objeto RowMapper donde se devolvera el resultado de la query en caso de que sea un SELECT. Para poderla
                   usar, el modelo de datos deberá implementar la interfaz RowMapper<> y sobreescribir el metodo mapRow que devolvera
                   un objeto.
*/
/* Metodo para realizar una SELECT con filtros */
  public List dinamyc_query(String sql, Object[] Params, RowMapper Mapa){
    return jdbcTemplate.query(sql, Params, Mapa);
  }

/* Metodo para realizar una SELECT sin filtros */
  public List dinamyc_query(String sql, RowMapper Mapa){
    return jdbcTemplate.query(sql, Mapa);
  }

/* Metodo para realizar un único INSERT, UPDATE o DELETE  */
  public void dinamyc_query(String sql, Object[] Params){
    jdbcTemplate.update(sql,Params);
  }

/* Metodo para realizar varíos  INSERT, UPDATE o DELETE, en procesamiento por lotes  */
  public void dinamyc_query(String sql, List Params){
    jdbcTemplate.batchUpdate(sql,Params);
  }

/*
  El metodo enterLocalPassiveMode de la clase FTP le indicara al cliente FTP que se conecte en modo PASIVO:
  Este metodo usa el puerto 21 para el envío de comandos y un puerto abieto aleatorio en un rango para la transferencia de datos.
*/
  public static void conectar() throws SocketException, IOException {
    ftp.connect(ip);
    ftp.enterLocalPassiveMode();
    if (ftp.login(user, pass))
      System.out.println("login OK");
    else
      System.out.println("login Error");
  }

/* Metodo para descargar el fichero del FTP */

  public static void desrcargarArchivoFTP() throws FileNotFoundException, IOException {
    BufferedOutputStream buffOut = new BufferedOutputStream(new FileOutputStream(localFileDownload));

    if (ftp.retrieveFile(hostFile, buffOut)) {
      System.out.println("Descarga correcta");
    }
    else {
      System.out.println("Error Descarga");
    }
    buffOut.close();
  }
}                                                        		 

El modelo de datos

La siguiente clase contendrá el modelo de datos para la BD


 
/* El modelo de datos */

public class Customer implements DynamicQuerys, RowMapper {
    private long id;
    private String firstName, lastName;

    /* Creamos dos constructores para el modelo, uno para crear un objeto vacio para obtener datos, y otro para insertar datos mediante un INSERT */
    public Customer(long id, String firstName, String lastName) {
        this.id = id;
        this.firstName = firstName;
        this.lastName = lastName;
    }

    public Customer() {
    }

    /* getters */
    public String getFirstName(){
        return firstName;
    }
    public String getLastName(){
        return lastName;
    }
/* Con el metodo toString podemos visualizar los datos en forma de String almacenados en el objeto*/
    @Override
    public String toString() {
        return String.format(
                "Customer[id=%d, firstName='%s', lastName='%s']",
                id, firstName, lastName);
    }
/* Sobreescribimos el metodo mapRow que lo que hace es devolver un objeto del modelo de datos con los campos de la BD para consultas SELECT */
    @Override
    public DynamicQuerys mapRow(ResultSet rs, int rowNum) throws SQLException {
        Customer Mapper = new Customer(rs.getLong("id"), rs.getString("first_name"), rs.getString("last_name"));
        return Mapper;
    }
}                                                            

La clase flujos para leer desde el fichero

La siguiente clase contendrá todos los metodos y propiedades necesarios para leer el fichero de texto plano que hayamos descargado del Mainframe.


 
/* El objeto Flujos: Lectura del fichero de texto plano descargado del servidor FTP */
/* Lo que hacemos mediante el siguiente algoritmo  es leer el fichero descargado del FTP
   Los objetos FileInputStream típicamente representan ficheros de texto accedidos en orden secuencial, byte a byte. Con FileInputStream, se puede elegir acceder a un byte, 
   varios bytes o al fichero completo.

   Es como si con la clase FileInputStream abrieramos un flujo de datos de bytes y con la clase DataInputStream tuvieramos los metodos necesarios para leerlos o escribir en ese 
   flujo, si se trata de datos primitivos, aunque en este caso estamos usando el metodo readLine*/
public class Flujos {
    public ArrayList leer_fichero(String nameFic) {
        String linea = new String();
        ArrayList MiFichero = new ArrayList();
        try {
            FileInputStream Fichero1 = new FileInputStream(nameFic);
            DataInputStream entrada = new DataInputStream(Fichero1);

            /* usamos el metodo readline() que lee linea a linea hasta un retorno de carro de un objeto DataInputStream */
            while((linea = entrada.readLine()) != null){
            /* Añadimos a la colección cada linea del fichero*/
                    MiFichero.add(linea);
            }

            /* Cerramos el fichero */
            entrada.close();
        } catch (FileNotFoundException e) {
            System.out.println("Fichero no abierto");
        } catch (IOException e) {
            /* throw new Lo que hace es lanzar una excepción */
            throw new RuntimeException(e);
        }
        return MiFichero;
    }
}                                                             

Los objetos de conexión

Las siguientes clases implementan la estructura cliente-servidor por sockets para conexiones entrantes


 
/* Arquitectura Cliente-Servidor mediante soskets en JAVA, para ello implementamos dos clases, una la de Conexion y otra la de Servidor que 
heredara de esta clase Conexion */
/* La clase Conexion*/
public class Conexion
{
    public int getPUERTO() {
        return PUERTO;
    }

    private final int PUERTO = 8474; //Puerto para la conexión
    private final String HOST = "0.0.0.0"; //Host para la conexión --localhost
    protected String mensajeServidor; //Mensajes entrantes (recibidos) en el servidor
    protected ServerSocket ss;
    //Socket del servidor
    protected Socket cs; //Socket del cliente
    protected DataOutputStream salidaServidor, salidaCliente; //Flujo de datos de salida

    public Conexion(String tipo) throws IOException //Constructor
    {
        if(tipo.equalsIgnoreCase("servidor"))
        {
            ss = new ServerSocket(PUERTO);//Se crea el socket para el servidor en el puerto especificado
            cs = new Socket(); //Socket para el cliente
        }
        else
        {
            cs = new Socket(HOST, PUERTO); //Socket para el cliente en localhost en puerto
        }
    }
}

/* La clase Servidor */
public class Servidor extends Conexion //Se hereda de conexión para hacer uso de los sockets
{
    private String mensaje[] = new String[4];
    private int x = 0;
    
    public String[] getMensaje() {
        return mensaje;
    }

    public  Servidor() throws IOException{super("servidor");} //Se usa el constructor para servidor de Conexion

    public void startServer()//Método para iniciar el servidor
    {
        try
        {
            System.out.println("Esperando..."+getPUERTO()); //Esperando conexión
            /*
                Un objeto ServerSocket espera conexiones. Un objeto Socket inicia una conexión .
                Los objetos Socket se utilizan para la transferencia de datos.
                EL metodo accept() devuelve un objeto SocketChannel, que es un medio no bloqueante de comunicación que
                puede ser tratado por el objeto socket.
             */
            cs = ss.accept(); //Accept comienza el socket y espera una conexión desde un cliente

            System.out.println("Cliente en línea");

            //Se obtiene el flujo de salida del cliente para enviarle mensajes
            salidaCliente = new DataOutputStream(cs.getOutputStream());

            //Se le envía un mensaje al cliente usando su flujo de salida
            salidaCliente.writeUTF("Petición recibida y aceptada");

            //Se obtiene el flujo entrante desde el cliente
            BufferedReader entrada = new BufferedReader(new InputStreamReader(cs.getInputStream()));

            while((mensajeServidor = entrada.readLine()) != null) //Mientras haya mensajes desde el cliente
            {
                mensaje[x] = mensajeServidor;
                x = x+1;
                //Se muestra por pantalla el mensaje recibido
                System.out.println(mensajeServidor);
            }

            System.out.println("Fin de la conexión");

            ss.close();//Se finaliza la conexión con el cliente
        }
        catch (Exception e)
        {
            System.out.println(e.getMessage());
        }
    }
}                                                             

La vista propuesta por consola

El siguiente objeto permite una vista por consola de las querys lanzadas contra la BD.


 
/* La clase FormateaString propone un tipo de vista por consola para los datos de la BD */

public class FormateaString {

    private ArrayList Cadenas;
    private ArrayList Cadenas2;

    public FormateaString(ArrayList Cadenas, ArrayList Cadenas2){
        this._Cadenas = Cadenas;
        this.2Cadenas2 = Cadenas2;
    }

    public void imprimeFormato() {
        System.out.printf("*************************************\n");
        System.out.printf("*     Nombres      *     Codigos    *\n");
        System.out.printf("*************************************\n");


        for(int i=0;i<_Cadenas.size() || i<2Cadenas2.size();i++) {
            System.out.printf("*     %s",_Cadenas.get(i),2Cadenas2.get(i));
            for(int j=_Cadenas.get(i).length();j<13;j++){
                System.out.printf(" ");
            }
            System.out.printf("*    %s",2Cadenas2.get(i));
            for(int j=2Cadenas2.get(i).length();j<12;j++){
                System.out.printf(" ");
            }
            System.out.printf("*");
            System.out.printf("\n");
        }
        System.out.printf("*************************************\n");
        System.out.printf("\n");
    }
}

Contacto

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

Email: arxivelogic@proton.me