Статьи

Смешивание ExtJs, JSON-P и Java Web в NetBeans

В предыдущей статье   я продемонстрировал, как создавать приложения ExtJs. В следующих строках я покажу содержимое небольшого приложения для управления пациентами, использующего ExtJs в качестве клиентской среды и Java Web со средой Spring на стороне сервера.

I- таблица схемы базы данных

Ниже сценария DDL таблицы Patient

CREATE TABLE Patient(
Id INT NOT NULL AUTO_INCREMENT,
FirstName VARCHAR(100) NOT NULL,
LastName  VARCHAR(100) NOT NULL, 
Address   VARCHAR(100) NOT NULL,
City      VARCHAR(100) NOT NULL,
Country   VARCHAR(100) NOT NULL,
PRIMARY KEY (ID)
);

II — Клиентская сторона: архитектура ExtJs + MVC

Сначала нам нужно создать новый веб-проект Java (пожалуйста, следуйте этому руководству ) с Spring Web MVC в IDE NetBeans. Мой был назван PatientManagement .

Во второй раз мы создаем клиентскую часть, используя среду ExtJs и соблюдая архитектуру MVC (Controller и View). Ниже картинка, подытоживающая проект: 

Index.html файл исходного кода:

<!--
To change this license header, choose License Headers in Project Properties.
To change this template file, choose Tools | Templates
and open the template in the editor.
-->
<!DOCTYPE html>
<html>
    <head>
        <title>PATIENT MANAGEMENT</title>
        <link rel="stylesheet" type="text/css" href="ext/resources/css/ext-all.css">
        <script type="text/javascript" src="ext/ext-all.js"></script>
        <script type="text/javascript" src="app.js"></script>
    </head>
    <body></body>
</html>

App.js   содержимое файла:

Ext.Loader.setConfig({
    enabled: true
});

Ext.application({
    name: 'PM',
    appFolder: 'front/app',
    controllers: ['PatientController'],
    autoCreateViewport: true,
    launch: function() {

    }
});

Взгляды :

AppToolbar.js содержимое файла:

/* 
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */

Ext.define('PM.view.patient.AppToolbar', {
    extend: 'Ext.panel.Panel',
    alias: 'widget.apptoolbar',    
    initComponent: function() {
        this.dockedItems = [
            {xtype: 'toolbar',
                dock: 'top',
                items: [
                    {
                        xtype: 'cycle',
                        showText: 'true',
                        text: '<html><b>Patient</b></html>',
                        width: '300',
                        menu: {
                            xtype: 'menu',
                            width: '150',
                            items: [
                                {
                                    xtype: 'menucheckitem',
                                    text: 'New patient',
                                    action: 'create'
                                },
                                {
                                    xtype: 'menucheckitem',
                                    text: 'Patients list',
                                    action: 'listing'
                                }

                            ]
                        }
                    }
                ]
            }

        ];

        this.callParent(arguments);
    }
});

AddPatient.js исходный файл кода:

/* 
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */


Ext.define('PM.view.patient.AddPatient', {
    extend: 'Ext.window.Window',
    alias: 'widget.addpatient',
    title: 'Create a patient',
    layout: 'fit',
    autoShow: true,
    initComponent: function() {
        this.items = [
            {
                xtype: 'form',
                bodyStyle: {
                    background: 'none',
                    padding: '10px',
                    border: '0'
                },
                items: [
                    {
                        xtype: 'textfield',
                        name: 'firstname',
                        allowBlank: false,
                        fieldLabel: '<html><b>Firts Name</b></html>'
                    },
                    {
                        xtype: 'textfield',
                        name: 'lastname',
                        allowBlank: false,
                        fieldLabel: '<html><b>Last Name</b></html>'
                    },
                    {
                        xtype: 'textfield',
                        name: 'address',
                        fieldLabel: '<html><b>Address</b></html>',
                        allowBlank: false
                    },
                    {
                        xtype: 'textfield',
                        name: 'city',
                        fieldLabel: '<html><b>City</b></html>',
                        allowBlank: false
                    },
                    {
                        xtype: 'textfield',
                        name: 'country',
                        fieldLabel: '<html><b>Country</b></html>',
                        allowBlank: false

                    }
                ]
            }
        ];
        this.buttons = [
            {
                text: 'Save',
                action: 'save'
            },
            {
                text: 'Cancel',
                scope: this,
                handler: this.close
            }
        ];

        this.callParent(arguments);
    }
});

Содержимое файла viewport 
Viewport.js :

Ext.define('PM.view.Viewport', {
    extend: 'Ext.container.Viewport',
    alias: 'widget.viewport',    
    items: [
        {
            xtype: 'apptoolbar'
        }],
    initComponent: function() {
       this.callParent(arguments);
    }
}); 

Контроллер:

Содержание PatientController.js ниже:

/* 
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */


Ext.define('PM.controller.PatientController', {
    extend: 'Ext.app.Controller',
    views: ['patient.AddPatient', 'patient.AppToolbar'],
    init: function() {
        this.control({
            'addpatient button[action=save]': {
                click: this.doCreatePatient
            },
            'apptoolbar > toolbar > cycle > menu > menucheckitem[action=create]': {
                click: this.onCreatePatient
            }

        });
    },
    onCreatePatient: function() {
        //The panel to create a patient appears on the screen
        var view = Ext.widget('addpatient');
    },
    //Function to create a new patient
    doCreatePatient: function(button) {
        var win = button.up('window'),
                form = win.down('form'),
                values = form.getValues()
        if (form.getForm().isValid()) {
            Ext.Ajax.request({
                url: 'PatientController',
                method: 'POST',
                params: {
                    patientcreateData: Ext.encode(values)
                },
                scope: this,
                stateful: true
            });

            win.close();
        }
    },
});

В этом контроллере мы используем синглтон Ext.Ajax для отправки HTTP-запроса на удаленный сервер. В нашем примере мы будем использовать метод POST для отправки данных, и мы будем использовать серверный сервлет  PatientController.java (см. Ниже код источника). Объект JSON — это PatientCreateData .

Web.xml файл был изменен в соответствии с проектом , чтобы файл index.html в качестве страницы приветствия.

<welcome-file-list>
        <welcome-file>index.html</welcome-file>
    </welcome-file-list>

III — Серверная реализация

Ниже приведен пример файлов Java, определяющих серверную часть приложения:

Код модели  Patient.java   находится здесь:

/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package com.model.patientmanagement;

/**
 *
 * @author constantin
 */
public class Patient {

    private int id;
    private String firstname;
    private String lastname;
    private String address;
    private String city;
    private String country;

    public Patient() {
    }

    public Patient(String firstname, String lastname, String address, String city, String country) {
        this.firstname = firstname;
        this.lastname = lastname;
        this.address = address;
        this.city = city;
        this.country = country;
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getFirstname() {
        return firstname;
    }

    public void setFirstname(String firstname) {
        this.firstname = firstname;
    }

    public String getLastname() {
        return lastname;
    }

    public void setLastname(String lastname) {
        this.lastname = lastname;
    }

    public String getAddress() {
        return address;
    }

    public void setAddress(String address) {
        this.address = address;
    }

    public String getCity() {
        return city;
    }

    public void setCity(String city) {
        this.city = city;
    }

    public String getCountry() {
        return country;
    }

    public void setCountry(String country) {
        this.country = country;
    }

}

Содержимое файла DAO P atientDao.java находится здесь:

/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package com.dao.patientmanagement;

import com.model.patientmanagement.Patient;
import java.util.List;
import javax.sql.DataSource;

/**
 *
 * @author constantin
 */
public interface PatientDao {

    public void setDataSource(DataSource dataSource);

    public void createPatient(String firstname, String lastname, String address, String city, String country);

    public Patient getPatientById(Integer id);

    public void deletePatient(Integer id);

    public List<Patient> listPatients();

    public void updateFirstName(Integer id, String firstname);

}

Источник PatientTemplate.java :

/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package com.impl.patientmanagement;

import com.dao.patientmanagement.PatientDao;
import com.model.patientmanagement.Patient;
import java.util.List;
import javax.sql.DataSource;
import org.springframework.dao.DataAccessException;
import org.springframework.jdbc.core.JdbcTemplate;

/**
 *
 * @author constantin
 */
public class PatientTemplate implements PatientDao {

    private DataSource dataSource;
    private JdbcTemplate jdbcTemplateObject;

    @Override
    public void setDataSource(DataSource dataSource) {
        this.dataSource = dataSource;
        this.jdbcTemplateObject = new JdbcTemplate(dataSource);
    }

    @Override
    public void createPatient(String firstname, String lastname, String address, String city, String country) {
        try {
            String Sql = "insert into Patient(firstname, lastname, address, city,country) values (?,?,?,?,?)";
            jdbcTemplateObject.update(Sql, firstname, lastname, address, city, country);

        } catch (DataAccessException ex) {
            System.out.println("Error" + ex.getMessage());
        }
    }

    @Override
    public Patient getPatientById(Integer id) {
        throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
    }

    @Override
    public void deletePatient(Integer id) {
        throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
    }

    @Override
    public List<Patient> listPatients() {
        throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
    }

    @Override
    public void updateFirstName(Integer id, String firstname) {
        throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
    }

}

PatientMapper.java содержимое файла:

/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package com.impl.patientmanagement;

import com.model.patientmanagement.Patient;
import java.sql.ResultSet;
import java.sql.SQLException;
import org.springframework.jdbc.core.RowMapper;

/**
 *
 * @author constantin
 */
public class PatientMapper implements RowMapper<Patient> {

    @Override
    public Patient mapRow(ResultSet rs, int i) throws SQLException {
        //throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
        Patient patient = new Patient(); 
        patient.setId(rs.getInt("id"));
        patient.setFirstname(rs.getString("firstname"));
        patient.setLastname(rs.getString("lastname"));
        patient.setAddress(rs.getString("address"));
        patient.setCity(rs.getString("city"));
        patient.setCountry(rs.getString("country"));  
        return patient ;  
    }
}

Вот источник кода метода doPost сервлета PatientController.java :

 @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
      
        //Get the context of the application
        ServletContext servletContext = this.getServletContext();

        WebApplicationContext wac = WebApplicationContextUtils.getRequiredWebApplicationContext(servletContext);

        String patientcreateData = request.getParameter("patientcreateData");

        //I parse here the json object
        GenericJsonParser jsonPatient = new GenericJsonParser();
        HashMap<String, String> patientMap = jsonPatient.getJsonMap(patientcreateData);

        String firstname = patientMap.get("firstname");
        String lastname = patientMap.get("lastname");
        String address = patientMap.get("address");
        String city = patientMap.get("city");
        String country = patientMap.get("country");

        PatientTemplate patient = (PatientTemplate) wac.getBean("patienttemplate");
        
        patient.createPatient(firstname, lastname, address, city, country);               

    }

Класс для анализа объекта Json реализован, как показано ниже ( GenericJsonParser.java ):

Этот класс очень важен, поскольку в API JSON-P нет метода для привязки объекта Java и объекта JSON. Он анализирует объект Json и возвращает карту, которую легче использовать в коде Java.

/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package com.controller.patientmanagement;

import java.io.StringReader;
import java.util.HashMap;
import javax.json.Json;
import javax.json.stream.JsonParser;
import static javax.json.stream.JsonParser.Event.END_OBJECT;
import static javax.json.stream.JsonParser.Event.KEY_NAME;

/**
 *
 * @author constantin Drabo
 * This class allow you to parse a  Json object coming from client side
 */
public class GenericJsonParser {

    public GenericJsonParser() {
    }

    public HashMap<String, String> getJsonMap(String jsonflux) {

        String keyvalue;
        JsonParser parser = Json.createParser(new StringReader(jsonflux));
        JsonParser.Event event = parser.next();

        HashMap<String, String> jsonElements;
        jsonElements = new HashMap<String, String>();

        while (event != END_OBJECT) {
            event = parser.next();
            if (event == KEY_NAME) {
                keyvalue = parser.getString();
                System.out.println("KeyValue === " + keyvalue);
                parser.next();
                jsonElements.put(keyvalue, parser.getString());
            }
        }

        return jsonElements;
    }

}

IV- Запустить приложение

Приложение будет выглядеть так, когда оно запущено:

Вот пример данных, которые мы сохраним:

Когда они нажимают кнопку Сохранить, они получают этот объект Json (здесь захваченный Firebug):