Construyendo una Aplicación con JavaFX y Java EE 7

Introducción

    Propósito

    Este tutorial abarca el construir una aplicación de escritorio con JavaFX 2.0 y Scene Builder. Además de cómo construir un servicio web RESTful que provea la información a la aplicación de escritorio.

    Tiempo para completarlo

    Aproximadamente 90 minutos

    Introducción

    JavaFX es una herramienta que permite a los desarrolladores crear aplicaciones de las llamadas rich internet applications (RIAs). JavaFX está diseñada para proveer una plataforma ligera y acelerada de gráficos para aplicaciones de negocio empresariales, al mismo tiempo que permite a los desarrolladores crear sus aplicaciones completamente en el lenguaje de programación Java.

    En este tutorial harás y aprenderás lo siguiente:

    Del lado del servidor:

    1. Crear un servicio web RESTful que se conecta a una BD para extraer la información que publicará como servicio web. Para esto crearás además del servicio web una entidad Customer y un EJB CustomerFacade para obtener los datos de la base de datos.
    2. Correr el servicio web localmente

            Del lado del cliente:

    1. Crear la UI usando Scene Builder de la aplicación
    2. Crear la lógica de la aplicación al crear varias clases de ayuda como la clase Customer, la clase CustomerMessageBodyReader que hará el parsing de la información JSON (utilizando la nueva API en Java EE7) recibida del servicio web. Además de la clase SampleController , clase que concentra la lógica de la aplicación y que utiliza el nuevo cliente de REST de Java EE7 para comunicarse con el servicio web.

    Requerimientos de Software y Hardware

    La siguiente es la lista de requerimientos de hardware y software:

    • JDK 7 (lo puedes obtener aquí)
    • JavaFX Scene Builder (lo puedes obtener aquí)
    • NetBeans 7.3, con Java EE 7 y GlassFish 4.0 (lo puedes obtener aquí. Asegúrate de seleccionar la casilla de GlassFish durante la instalación)

    Prerrequisitos

    Antes de iniciar este tutorial, tu deberías:

    • Tener JDK 7 instalado.
    • Tener JavaFX Scene Builder instalado.
    • Haber instalado NetBeans 7.3 con Java EE 7 incluyendo GlassFish 4.0 y asegurarse que está abierto y corriendo.

Creando el Servicio Web RESTful

    En esta sección crearás un servicio RESTful que provea la información a la aplicación de escritorio.

    Creando el Proyecto

      En NetBeans, selecciona File > New Project.

      En la ventana New Project, realiza los siguientes pasos:

      a. Selecciona Java Web en Categories.
      b. Selecciona Web Application en Projects.
      c. Haz click en Next.
       

      En la ventana New Web Application, introduce ServerSide como el nombre del proyecto y haz click en Next.

      En la ventana New Web Application, haz click en Finish.

      Después de este paso, el proyecto se crea en NetBeans.

    Creando la Clase Entity

      En esta sección crearás una clase Entity de la tabla Customers, que se encuentra en la base de datos de ejemplo que ya se encuentra en NetBeans.

      Haz clic derecho en la carpeta Sources Packages y selecciona New > Other...

      En la ventana New File, realiza los siguientes pasos:

      a. Selecciona Persistence en Categories.
      b. Selecciona Entity Classes from Database en File Types.
      c. Haz click en Next.
       

      En la ventana New Entity Classes from Database, realiza los siguientes pasos:

      a. Selecciona jdbc/sample en Data Source.
          Esta es la BD de ejemplo que ya viene en NetBeans por default.
      b. Selecciona la tabla CUSTOMER en Selected Tables.
          Esta es la única tabla de la BD que se usará.
      c. Asegúrate que la casilla Include Related Tables no esté seleccionada.
          CUSTOMER inicialmente está ligada con otras dos tablas: DISCOUNT_CODE y MICRO_MARKET, pero no las usaremos en este caso.
      d. Haz click en Next.

      En la ventana New Entity Classes from Database, realiza los siguientes pasos:

      a. Introduce com.samples.entity en Package.
      b. Asegúrate que las primeras dos casillas no esten seleccionadas.
         No se usarán ni Named Queries ni JAXB en este caso.
      d. Haz click en Finish.
       

      Después de este paso NetBeans crea la clase entity Customer.java dentro de la carpeta com.samples.entity:

    Creando el Servicio RESTful

      En esta sección crearás el servicio web RESTful, que expone la infomación de la tabla CUSTOMER en formato JSON.

      Haz clic derecho en el proyecto y selecciona New > Other...

      En la ventana New File, realiza los siguientes pasos:

      a. Selecciona Web Services en Categories.
      b. Selecciona RESTful Web Services from Patterns en File Types.
      c. Haz click en Next.
       

      En la ventana New RESTful Web Services from Patterns, haz click en Next.Vamos a utilizar la opción por default: Simple Root Resource.

      En la ventana New RESTful Web Services from Patterns, realiza los siguientes pasos:

      a. Introduce com.samples.rest en el campo Resource Package.
      b. Introduce customer en el campo Path.
      c. Introduce CustomerREST en el campo Class Name.
      d. Selecciona application/json en MIME Type.
      e. Haz click en Finish.
       

      Después de este paso NetBeans crea la clase CustomerREST.java dentro de la carpeta com.samples.rest. Además crea la clase ApplicationConfig.java, dentro de la misma carpeta.

      En la clase CustomerREST introduce el siguiente código:

      @Inject
      private CustomerFacade customerFacade;

      Presiona Ctrl+Shift+I para resolver los imports que se necesitan. Sin embargo en este punto la clase CustomerFacade aún no se puede resolver, ya que se creará en un paso mas adelante.

      En la misma clase CustomerREST, realiza lo siguientes cambios al método getJson, además de agregar un nuevo método llamado findByName:

      @GET
      @Produces({"application/json"})
      public List<Customer> getJson() {
          return customerFacade.findAll();
      }

      @GET
      @Path("/search/{name}")
      @Produces({"application/json"})
      public List<Customer> findByName(@PathParam("name") String name) {
         return customerFacade.findByName(name);
      }

      Presiona Ctrl+Shift+I para resolver los imports que se necesitan.

      Haz clic derecho en la carpeta com.samples.rest y selecciona New > Other...

      En la ventana New File, realiza los siguientes pasos:

      a. Selecciona
      Enterprise JavaBeans en Categories.
      b. Selecciona Session Bean en File Types.
      c. Haz click en Next.

      En la ventana New Session Bean, introduce CustomerFacade en el campo EJB Name y haz click en Finish.

      NetBeans crea un bean Stateless en el proyecto, es decir, un bean que no mantiene un estado. Este bean será la interfaz con la base de datos y sus operaciones.

      Agrega el siguiente código a CustomerFacade:

      @PersistenceContext(unitName = "ServerSidePU")
      private EntityManager em;
       
      public List<Customer> findAll() {
        return em.createQuery("select c from Customer c").getResultList();
      }
       
      public List<Customer> findByName(String name) {
        return em.createQuery("select c from Customer c where UPPER(c.name) LIKE :custName").
                               setParameter("custName", "%" + name.toUpperCase() + "%").getResultList();
      }

      En este archivo, se crea un EntityManager que se asocia con un Persistence Context y un Persistence Unit (PU) denominado ServerSidePU. El PU está definido en el archivo persistence.xml.
      Se crean además dos métodos: findAll y findByName. El primer método regresa todos los datos de la tabla Customer y el segundo regresa solo los nombres que coincidan con el parámetro enviado.

      Es momento de ejecutar el servicio web. Haz clic derecho en el proyecto y selecciona Run.

      GlassFish empieza a correr y el proyecto es instalado en GlassFish. Una ventana del explorador se abre. con la dirección http://localhost:8080/ServerSide.

      Escribe la siguiente dirección en el explorador que se abrió al correr en proyecto en el paso anterior:

      http://localhost:8080/ServerSide/webresources/customer.

      Al introducir esta URL en el explorador se invoca el método getJson() de CustomerREST.

      Escribe la siguiente dirección en el explorador:

      http://localhost:8080/ServerSide/webresources/customer/search/John.

      Al introducir esta URL en el explorador se invoca el método findByName() de CustomerREST, enviándole como parámetro el nombre de John para su búsqueda.

Creando la Aplicación con JavaFX

    En esta sección crearás una aplicación de escritorio de búsqueda de la información que provee el servicio web creado en la sección anterior.

    Creando el Proyecto de JavaFX

      En NetBeans, selecciona File > New Project.

      En la ventana New Project, realiza los siguientes pasos:

      a. Selecciona JavaFX en Categories.
      b. Selecciona JavaFX FXML Application en Projects.
      c. Haz click en Next.
       

      En la ventana New JavaFX Application, realiza los siguientes pasos:

      a. Introduce JavaFXApplicationCustomerSearch en el campo Project Name.
      b. Introduce CustomerSearch en el campo FXML name.
      c. Haz click en Finish.
       

      Haz click derecho en el proyecto recién creado y selecciona Run.

      Después de este paso, el proyecto se compila y ejecuta mostrando una ventana con un botón. Esta interfaz es la que se crea por default al crear el proyecto:

      NetBeans ha creado tres archivos: CustomerSearch.fxml, que es la interfaz de usuario en lenguaje FXML, que está basado en XML; CustomerSearchController.java, que está asociado con los elementos gráficos del documento FXML y que coordina el comportamiento de estos elementos. Por último, la clase JavaFXApplicationCustomerSearch.java, que es el punto de entrada para la aplicación:

      Abre el archivo JavaFXApplicationCustomerSearch.java y agrega el siguiente código:

      stage.setTitle("Java Day Demo");
      stage.setWidth(650);
      stage.setHeight(650);

    Creando la Interfaz Gráfica de la Aplicación

      En esta sección crearás la interfaz gráfica de la aplicación utlizando Scene Builder.

      Haz clic derecho en el archivo FXML CustomerSearch.fxml y selecciona Open

      Al abrir un archivo FXML y al haber instalado Scene Builder previamente, NetBeans abre el archivo en Scene Builder:

      En Scene Builder, y tomando de una esquina el panel principal (AnchorPane), agranda el panel hasta un tamaño de 620 pixeles de ancho por 600 pixeles de alto:

      Desplaza el botón a la esquina superior derecha del panel. Dale las dimensiones que sean de tu agrado haciendo click en él y arrastrando una esquina.
      Tip: Presionando Ctrl + 7 ocultas y muestras el panel derecho.

      Haz click en el botón y presiona Ctrl + 7 para mostrar el panel derecho y realiza los siguientes pasos:

      a. Introduce buttonSearch en el campo fx:id.
      b. Introduce Buscar en el campo Text.
      c. Presiona Enter.

       

      En el mismo panel derecho, ve a la sección Code e introduce #handleSearchAction en el campo On Action.

       

      Presiona Ctrl + 6 para mostrar el panel izquierdo si no estuviera visible. Selecciona y arrastra un elemento Text Field del panel hacia la esquina superior izquierda.
      Dale las dimensiones que sean de tu agrado haciendo click y arrastrando una esquina.

       

      Haz click en el Text Field y presiona Ctrl + 7 para mostrar el panel derecho. En la sección Properties introduce textFieldSearch en el campo fx:id y presiona Enter.

       

      En el mismo panel derecho, ve a la sección Code e introduce #handleSearchAction en el campo On Action.

       

      Selecciona y arrastra hacia al panel principal un elemento Table View del panel izquierdo.

      Selecciona el Table View en el panel y arrastra una de sus esquinas para ajustar su tamaño de tal manera que cubra la superficie sobrante del panel:

      Presiona Ctrl + 6 para mostrar el panel izquierdo si no estuviera visible. Selecciona y haz click derecho sobre una columna TableColumn. Selecciona Duplicate del menú.

      Con esto se crea una columna extra en la tabla.

      Para dar el tamaño adecuado a las columnas realiza los siguientes pasos:

      a. Selecciona la primer columna TableColumn del panel de la izquierda y presiona Ctrl + 7 para mostrar el panel izquierdo.
      b. Introduce 170 en el campo Pref Width.
      c. Presiona Enter.
      d. Repite los pasos anteriores para la segunda y tercer columna, con un ancho de 190 y 210 respectivamente.

      Haz click sobre la tabla e introduce tableView en el campo fx:id.


      Para dar el nombre adecuado a las columnas ve al panel de la izquierda y edita los nombres de cada TableColumn de la siguiente manera:


      Presiona Ctrl+S para guardar el archivo o en el menú selecciona File > Save.

      Por último, agregarás manualmente la etiqueta XML <cellValueFactory> a cada etiqueta <TableColumn> en el archivo CustomerSearch.fxml.
      Selecciona el archivo CustomerSearch.fxml y haz click derecho sobre él. Selecciona Edit.

      Introduce el siguiente código dentro del archivo.

      <?import javafx.scene.control.cell.*?>

      <cellValueFactory>  
          <PropertyValueFactory property="name" />
      </cellValueFactory>

      <cellValueFactory>           
          <PropertyValueFactory property="addressline1" />         
      </cellValueFactory>

      <cellValueFactory>           
          <PropertyValueFactory property="email" />
      </cellValueFactory>

      Recuerda remover el fin de la marca (/) en los elementos <TableColumn> y agregar </TableColumn>, dado que agregarás <cellValueFactory> como hijo de <TableColumn>.
      Además asegúrate que el import vaya debajo del tag <xml>.

      El elemento <cellValueFactory> dentro de <TableColumn> nos permite "ligar" las columnas en la UI con las columnas de la tabla Customer, en la BD.

    Desarrollando el Controlador

      En esta sección crearas la lógica de la clase CustomerSearchController.java, que entre otras cosas, instanciará la clase javax.ws.rs.client.Client para hacer llamadas al servicio web RESTful .

      De la siguiente liga, obtén el archivo zip, descomprímelo y guarda la carpeta en tu disco duro. La carpeta contiene las librerias necesarias para el cliente de JAX-RS 2.0.

      Haz click derecho sobre Libraries en el proyecto. Selecciona Add JAR/Folder:

      Selecciona todos los JARs de la carpeta que descomprimiste en el paso anterior. Haz click en Open.

      Abre el archivo CustomerSearchController.java y cambia el nombre del método handleButtonAction por handleSearchAction. Borra el parámetro de entrada del método.

      Reemplaza el código existente en el método handleSearchAction() por el siguiente:

      WebTarget clientTarget;
      ObservableList<Customer> data = tableView.getItems();
      data.clear();
      Client client = ClientBuilder.newClient();
      client.register(CustomerMessageBodyReader.class);
      if (textFieldSearch.getText().length() > 0) {
          clientTarget = client.target("http://localhost:8080/ServerSide/webresources/customer/search/{beginBy}");
          clientTarget = clientTarget.resolveTemplate("beginBy", textFieldSearch.getText());
      } else {
          clientTarget = client.target("http://localhost:8080/ServerSide/webresources/customer");
      }  
      GenericType<List<Customer>> listc = new GenericType<List<Customer>>() {
          };
      List<Customer> customers = clientTarget.request("application/json").get(listc);

      for (Customer c : customers) {
          data.add(c);
          System.out.println(c.toString());
      }

      Presiona Ctrl+Shift+I para resolver los imports faltantes.No todas las clases serán resueltas hasta completar los siguientes pasos.

      En el mismo archivo, agrega las siguientes lineas de código:

      @FXML
      private TextField textFieldSearch;
      @FXML
      private Button buttonSearch;
      @FXML
      private TableView<Customer> tableView;

      Presiona Ctrl+Shift+I para resolver los imports faltantes. La clase Customer no será resuelta hasta completar los siguientes pasos.

      En la misma clase CustomerSearchController.java, agrega la siguiente linea de código dentro del método initialize:

        handleSearchAction();

      La clase CustomerSearchController que se ha ido modificando en esta sección aún contiene dos clases desconocidas hasta ahora: Customer y CustomerMessageBodyReader. Estas dos clases se construirán en la siguiente sección.

    Creando el Parser con JSON-P

      En esta sección crearás la clase Customer y el JSON parser utlizando la nueva API de Java para JSON en Java EE 7.

      Haz clic derecho en la carpeta javafxapplicationcustomersearch y selecciona New > Java Class...

      En la ventana New Java Class, introduce Customer en el campo Class Name y haz click en Finish.

       

      En el archivo Customer.java introduce el siguiente código:

      import java.io.Serializable;

      private String name;
      private String addressline1;
      private String email;

       

      Coloca el cursor al final de la última declaración de variable y presiona Alt + Insert. Selecciona Getter and Setter...

      Selecciona las tres casillas y haz click en Generate.

      Guarda el archivo. Con esto la clase Customer se habrá creado.

      Haz clic derecho en la carpeta javafxapplicationcustomersearch y selecciona New > Java Class...

      En la ventana New Java Class, introduce CustomerMessageBodyReader en el campo Class Name y haz click en Finish.

      Introduce el siguiente código en la clase CustomerMessageBodyReader:

      @Provider
      @Consumes({"application/json"})

      implements MessageBodyReader<List<Customer>>

      @Override
      public boolean isReadable(Class<?> type, Type type1, Annotation[] antns,
                                                 MediaType mt) {
          return true;
      }

      Después de introducir el código presiona Ctrl+Shift+I para arreglar los imports.
      Asegúrate de seleccionar la clase java.lang.reflect.Type al momento de seleccionar los imports.

      Introduce el siguiente código en la misma clase CustomerMessageBodyReader:

      @Override
      public List<Customer> readFrom(Class<List<Customer>> type, Type type1, Annotation[] antns, MediaType mt, MultivaluedMap<String, String> mm, InputStream in) throws IOException,  WebApplicationException {
          if (mt.getType().equals("application") && mt.getSubtype().equals("json")) {
            Customer customer = new Customer();
            List<Customer> customers = new ArrayList();
            JsonParser parser = Json.createParser(in);
            while (parser.hasNext()) {
              JsonParser.Event event = parser.next();
              switch (event) {
                case START_OBJECT:
                  customer = new Customer();
                  break;
                case END_OBJECT:
                  customers.add(customer);
                  break;
                case KEY_NAME:
                  String key = parser.getString();
                  parser.next();
                  switch (key) {
                    case "name":
                      customer.setName(parser.getString());
                      break;
                    case "addressline1":
                      customer.setAddressline1(parser.getString());
                      break;
                    case "email":
                      customer.setEmail(parser.getString());
                      break;
                    default:
                      break;
                  }
                  break;
                default:
                  break;
              }
            }
            return customers;
          }
          throw new UnsupportedOperationException("Not supported MediaType: " + mt);
        }

      Después de introducir el código presiona Ctrl+Shift+I para arreglar los imports.

      Haz terminado con la codificación de la aplicación. Haz click derecho sobre el proyecto y selecciona Build.

Ejecutando la Aplicación

    Selecciona el archivo JavaFXApplicationCustomerSearch.java y haz click derecho. Selecciona Run File.

    La aplicación al iniciar obtiene todos los datos del servicio web RESTful. Puedes introducir palabras de búsqueda por nombre en el campo de texto y presionando Enter o haciendo click el botón Buscar.

Conclusión

    En este tutorial, has aprendido a:

    • Crear un servicio web RESTful, extrayendo información de una BD a través una clase Facade con JPA.
    • Crear la interfaz de usuario de la aplicación con JavaFX y Scene Builder.
    • Crear la lógica de la aplicación utilizando el cliente de JAX-RS 2, la API de JSON 1.0 y una clase POJO.
    • Ligar la lógica de la aplicación (controlador) con la interfaz de usuario (FXML).

    Recursos

    Créditos

    • Currículum Developer: Edgar Martinez

To navigate this Oracle by Example tutorial, note the following:

Hide Header Buttons:
Click the title to hide the buttons in the header. To show the buttons again, click the title again.
Topic List:
Click a topic to navigate to that section.
Expand All Topics:
Click the button to show or hide the details for the sections. By default, all topics are collapsed.
Hide All Images:
Click the button to show or hide the screenshots. By default, all images are displayed.
Print:
Click the button to print the content. The content that is currently displayed or hidden is printed.

To navigate to a particular section in this tutorial, select the topic from the list.