Java e HTML5: Do Desktop/Web ao Mobile Loiane Groner @loiane http://loiane.com http://loiane.training
• 10+ XP TI • Java, JavaScript/HTML5, Sencha, Phonegap/Ionic, Angular • Blog: http://loiane.com • Cursos: http://loiane.training
• Meus livros:
Ferramentas de um dev Java/HTML5
• JavaEE • HTML • CSS • JavaScript • IDE favorita • NetBeans, Eclipse, IntelliJ IDEA
Desenvolvedor FrontEnd Desenvolvedor BackEnd Servidor PartevisívelnositewebParte“mágica”,nãovisívelaousuário http://www.alticreation.com/uploads/iceberg-front-end-back-end-developers.jpg
Plataforma JavaEE para HTML5: • JSON • WebSocket • Concurrency • Batch • WebServices RESTful
• JSON: JavaScript Object Notation
• JSON: JavaScript Object Notation • É uma forma de trocar dados entre frontend e backend representados por chave-valor
• JSON: JavaScript Object Notation • É uma forma de trocar dados entre frontend e backend representados por chave-valor • Exemplo: var meuObjeto = {nome : ‘Meu Nome’, idade: 21};
• JSON: JavaScript Object Notation • É uma forma de trocar dados entre frontend e backend representados por chave-valor • Exemplo: var meuObjeto = {nome : ‘Meu Nome’, idade: 21}; • API JSON Java permite pasear, transformar e consultar objectos JSON
• WebSocket: protocolo de aplicação que fornece comunicação dupla entre 2 pontos TCP • API Java fornece funcionalidade através de annotations
• Concurrency: API Java que fornece funcionalidade de comunicação assíncrona
• Concurrency: API Java que fornece funcionalidade de comunicação assíncrona • Batch: API Java que fornece funcionalidade de tarefas batch
• Webservices RESTful: JAX-RS
URL Verbo HTTP Desc api/contatos GET obtém lista de contatos api/contatos/:id GET obtém dados de contato específico api/contatos POST cria contato api/contatos/:id PUT atualiza contato api/contatos/:id DELETE deleta contato
@Entity @Table(name = "contact") @XmlRootElement @NamedQueries({ @NamedQuery(name = "Contact.findAll", query = "SELECT c FROM Contact c"), @NamedQuery(name = "Contact.findById", query = "SELECT c FROM Contact c WHERE c.id = :id"), @NamedQuery(name = "Contact.findByEmail", query = "SELECT c FROM Contact c WHERE c.email = :email"), @NamedQuery(name = "Contact.findByName", query = "SELECT c FROM Contact c WHERE c.name = :name"), @NamedQuery(name = "Contact.findByPhone", query = "SELECT c FROM Contact c WHERE c.phone = :phone")}) public class Contact implements Serializable { private static final long serialVersionUID = 1L; @Id @GeneratedValue(strategy = GenerationType.IDENTITY) @Basic(optional = false) @Column(name = "id") private Integer id; @Basic(optional = false) @NotNull @Size(min = 1, max = 255) @Column(name = "email") private String email; @Basic(optional = false) @NotNull @Size(min = 1, max = 255) @Column(name = "name") private String name; //… }
@Stateless @Path("contact") public class ContactFacadeREST extends AbstractFacade<Contact> { @POST @Override @Consumes({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON}) public void create(Contact entity) { super.create(entity); } @PUT @Path("{id}") @Consumes({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON}) public void edit(@PathParam("id") Integer id, Contact entity) { super.edit(entity); } @DELETE @Path("{id}") public void remove(@PathParam("id") Integer id) { super.remove(super.find(id)); } @GET @Path("{id}") @Produces({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON}) public Contact find(@PathParam("id") Integer id) { return super.find(id); } @GET @Override @Produces({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON}) public List<Contact> findAll() { return super.findAll(); } }
@JsonAutoDetect @Entity @Table(name="CONTACT") public class Contact { @Id @GeneratedValue @Column(name="id") private int id; @Column(name="name", nullable=false) private String name; @Column(name="phone", nullable=false) private String phone; @Column(name="email", nullable=false) private String email; }
@Repository public class ContactDAO { private HibernateTemplate hibernateTemplate; @Autowired public void setSessionFactory(SessionFactory sessionFactory) { hibernateTemplate = new HibernateTemplate(sessionFactory); } public List<Contact> getContacts(int start, int limit) { DetachedCriteria criteria = DetachedCriteria.forClass(Contact.class); return hibernateTemplate.findByCriteria(criteria, start, limit); } public void deleteContact(int id){ Object record = hibernateTemplate.load(Contact.class, id); hibernateTemplate.delete(record); } }
@Controller public class ContactController { private ContactService contactService; @RequestMapping(value="/contact/view.action") public @ResponseBody Map<String,? extends Object> view(@RequestParam int start, @RequestParam int limit) throws Exception { try{ List<Contact> contacts = contactService.getContactList(start,limit); int total = contactService.getTotalContacts(); return ExtJSReturn.mapOK(contacts, total); } catch (Exception e) { return ExtJSReturn.mapError("Error retrieving Contacts from database."); } } @RequestMapping(value="/contact/create.action") public @ResponseBody Map<String,? extends Object> create(@RequestBody ContactWrapper data) throws Exception { try{ List<Contact> contacts = contactService.create(data.getData()); return ExtJSReturn.mapOK(contacts); } catch (Exception e) { return ExtJSReturn.mapError("Error trying to create contact."); } } }
http://aprendizweb.com.br/wp-content/uploads/2015/03/frontend-e-back-end.jpg
http://www-scf.usc.edu/~chenemil/itp104/images/html5features.jpg
Plataforma HTML5 <canvas> <video> <audio>
Plataforma HTML5 <canvas> <video> <audio> CSS3 Animações Transformações
Plataforma HTML5 <canvas> <video> <audio> CSS3 Animações Transformações Sencha Ext JS Angular Backbone Knockout Ember
Plataforma HTML5 <canvas> <video> <audio> CSS3 Animações Transformações Sencha Ext JS Angular Backbone Knockout Ember Pré-processadores Sass, Less Emmet Dart
Plataforma HTML5 <canvas> <video> <audio> CSS3 Animações Transformações Sencha Ext JS Angular Backbone Knockout Ember Pré-processadores Sass, Less Emmet Dart Mobile Híbrido Phonegap/Cordova Ionic
Plataforma HTML5 <canvas> <video> <audio> CSS3 Animações Transformações Sencha Ext JS Angular Backbone Knockout Ember Pré-processadores Sass, Less Emmet Dart Mobile Híbrido Phonegap/Cordova Ionic Desktop Híbrido TideSDK AppJS Node web-kit Electron
APIs REST JSON Aplicação moderna DOM App Server Browser
+
jQuery + Backbone
http://www.the4cast.com/wp-content/uploads/2014/06/web-starterkit.jpg
APIs REST Banco de Dados JSON JSON
import {bootstrap} from '@angular/platform-browser-dynamic'; import { HTTP_PROVIDERS } from '@angular/http'; import {AppComponent} from './app.component'; bootstrap(AppComponent, [HTTP_PROVIDERS]);
import {Component} from '@angular/core'; import {ContactsComponent} from './contacts/contacts.component'; @Component({ selector: 'my-app', directives: [ContactsComponent], template: '<contacts-grid></contacts-grid>' }) export class AppComponent { }
export class Contact { id: number; name: string; phone: string; email: string; }
import { Injectable } from '@angular/core'; import { Http, Response } from '@angular/http'; import 'rxjs/add/operator/map'; @Injectable() export class ContactsService { constructor(private http: Http) { } getContacts() { return this.http.get('http://localhost:8080/contacts-spring-mvc/contact/view.action? start=0&limit=250') .map((res: Response) => res.json().data); } }
import {Component, OnInit} from '@angular/core'; import {AgGridNg2} from 'ag-grid-ng2/main'; import {Contact} from './contact.model'; import {ContactsService} from './contacts.service'; @Component({ selector: 'contacts-grid', directives: [AgGridNg2], providers: [ContactsService], template: ` <ag-grid-ng2 #agGrid style="height:100%;width:583px" class="ag-fresh" [gridOptions]="gridOptions" [rowData]="contacts"> </ag-grid-ng2 > ` }) export class ContactsComponent implements OnInit { contacts: Contact[] = []; columnDefs = [ {headerName: 'Name', field: "name", width: 200 }, {headerName: 'Phone', field: "phone" ,width:180}, {headerName: 'Email', field: "email" ,width:200} ]; gridOptions : any = []; constructor(private contactsService: ContactsService) { this.gridOptions = { rowData: this.contacts, columnDefs: this.columnDefs, enableColResize: true, enableSorting: true, enableFilter: true } } ngOnInit() { this.contactsService.getContacts() .subscribe(contacts => this.contacts = contacts);
APIs REST JSON MOBILE App Server Dispositivo Móvel WebView Nativa
import {Component} from '@angular/core'; import { HTTP_PROVIDERS } from '@angular/http'; import {Platform, ionicBootstrap} from 'ionic-angular'; import {StatusBar} from 'ionic-native'; import {TabsPage} from './pages/tabs/tabs'; @Component({ template: '<ion-nav [root]="rootPage"></ion-nav>' }) export class MyApp { private rootPage:any; constructor(private platform:Platform) { this.rootPage = TabsPage; platform.ready().then(() => { StatusBar.styleDefault(); }); } } ionicBootstrap(MyApp, [HTTP_PROVIDERS]);
import {Component} from '@angular/core' import {HomePage} from '../home/home'; import {AboutPage} from '../about/about'; import {ContactPage} from '../contact/contact'; @Component({ templateUrl: 'build/pages/tabs/tabs.html' }) export class TabsPage { private tab1Root: any; private tab2Root: any; private tab3Root: any; constructor() { // this tells the tabs component which Pages // should be each tab's root Page this.tab1Root = HomePage; this.tab2Root = AboutPage; this.tab3Root = ContactPage; } } <ion-tabs> <ion-tab [root]="tab3Root" tabTitle="Contatos" tabIcon="contacts"></ion-tab> <ion-tab [root]="tab1Root" tabTitle="Inicio" tabIcon="home"></ion-tab> <ion-tab [root]="tab2Root" tabTitle="Sobre" tabIcon="information-circle"></ion-tab> </ion-tabs>
import {Component, OnInit} from '@angular/core'; import {NavController} from 'ionic-angular'; import {Contact} from '../contact/contact.model'; import {ContactsService} from '../contact/contacts.service'; import {ContactDetailsPage} from '../contact-details/contact-details'; @Component({ templateUrl: 'build/pages/contact/contact.html', providers: [ContactsService] }) export class ContactPage implements OnInit { contacts: Contact[] = []; constructor(private nav: NavController, private contactsService: ContactsService) { } ngOnInit() { this.contactsService.getContacts() .subscribe(contacts => this.contacts = contacts); } itemSelected(contact){ this.nav.push(ContactDetailsPage, contact); } }
<ion-navbar *navbar> <ion-title> Contact </ion-title> </ion-navbar> <ion-content> <ion-list> <ion-item *ngFor="let contact of contacts" (click)="itemSelected(contact)"> {{contact.name}} </ion-item> </ion-list> </ion-content>
import {Component} from '@angular/core'; import {NavController, NavParams} from 'ionic-angular'; import {Contact} from '../contact/contact.model'; @Component({ templateUrl: 'build/pages/contact-details/contact-details.html' }) export class ContactDetailsPage { contact: Contact; constructor(private nav: NavController, private navParams: NavParams) { this.contact = this.navParams.data; } }
<ion-navbar *navbar> <ion-title>{{contact.name}}</ion-title> </ion-navbar> <ion-content padding class="speaker-detail"> <p>Id: <span>{{contact.id}}</span></p> <p>Nome: <span>{{contact.name}}</span></p> <p>Email: <span>{{contact.phone}}</span></p> <p>Telefone: <span>{{contact.email}}</span></p> </ion-content>
http://enable-cors.org/
APIs REST JSON DESKTOP App Server App Desktop Wrapper
const electron = require('electron') const app = electron.app const BrowserWindow = electron.BrowserWindow let mainWindow function createWindow () { mainWindow = new BrowserWindow({width: 800, height: 600}) mainWindow.loadURL(`file://${__dirname}/index.html`) mainWindow.webContents.openDevTools() mainWindow.on('closed', function () { mainWindow = null }) } app.on('ready', createWindow) app.on('window-all-closed', function () { if (process.platform !== 'darwin') { app.quit() } }) app.on('activate', function () { if (mainWindow === null) { createWindow() } })
electron-packager ./ --platform=darwin --arch=x64 electron-packager ./ --platform=win32 --arch=x64 electron-packager ./ --platform=linux --arch=x64
• SSL • Unauthorised access (acesso não autorizado) • Código backend sem validações • Dados sem criptografia (local e na troca de dados) • Mau uso da persistência
https://www.owasp.org
https://github.com/loiane/javaee-html5-js
http://loiane.com facebook.com/loianegroner twitter.com/loiane https://github.com/loiane youtube.com/loianegroner http://loiane.training
JavaOne Brasil 2016: JavaEE e HTML5: da web/desktop ao mobile

JavaOne Brasil 2016: JavaEE e HTML5: da web/desktop ao mobile

  • 1.
    Java e HTML5: DoDesktop/Web ao Mobile Loiane Groner @loiane http://loiane.com http://loiane.training
  • 2.
    • 10+ XPTI • Java, JavaScript/HTML5, Sencha, Phonegap/Ionic, Angular • Blog: http://loiane.com • Cursos: http://loiane.training
  • 3.
  • 4.
    Ferramentas de umdev Java/HTML5
  • 5.
    • JavaEE • HTML •CSS • JavaScript • IDE favorita • NetBeans, Eclipse, IntelliJ IDEA
  • 6.
    Desenvolvedor FrontEnd Desenvolvedor BackEndServidor PartevisívelnositewebParte“mágica”,nãovisívelaousuário http://www.alticreation.com/uploads/iceberg-front-end-back-end-developers.jpg
  • 9.
    Plataforma JavaEE paraHTML5: • JSON • WebSocket • Concurrency • Batch • WebServices RESTful
  • 10.
    • JSON: JavaScriptObject Notation
  • 11.
    • JSON: JavaScriptObject Notation • É uma forma de trocar dados entre frontend e backend representados por chave-valor
  • 12.
    • JSON: JavaScriptObject Notation • É uma forma de trocar dados entre frontend e backend representados por chave-valor • Exemplo: var meuObjeto = {nome : ‘Meu Nome’, idade: 21};
  • 13.
    • JSON: JavaScriptObject Notation • É uma forma de trocar dados entre frontend e backend representados por chave-valor • Exemplo: var meuObjeto = {nome : ‘Meu Nome’, idade: 21}; • API JSON Java permite pasear, transformar e consultar objectos JSON
  • 14.
    • WebSocket: protocolode aplicação que fornece comunicação dupla entre 2 pontos TCP • API Java fornece funcionalidade através de annotations
  • 16.
    • Concurrency: APIJava que fornece funcionalidade de comunicação assíncrona
  • 17.
    • Concurrency: APIJava que fornece funcionalidade de comunicação assíncrona • Batch: API Java que fornece funcionalidade de tarefas batch
  • 18.
  • 19.
    URL Verbo HTTPDesc api/contatos GET obtém lista de contatos api/contatos/:id GET obtém dados de contato específico api/contatos POST cria contato api/contatos/:id PUT atualiza contato api/contatos/:id DELETE deleta contato
  • 25.
    @Entity @Table(name = "contact") @XmlRootElement @NamedQueries({ @NamedQuery(name= "Contact.findAll", query = "SELECT c FROM Contact c"), @NamedQuery(name = "Contact.findById", query = "SELECT c FROM Contact c WHERE c.id = :id"), @NamedQuery(name = "Contact.findByEmail", query = "SELECT c FROM Contact c WHERE c.email = :email"), @NamedQuery(name = "Contact.findByName", query = "SELECT c FROM Contact c WHERE c.name = :name"), @NamedQuery(name = "Contact.findByPhone", query = "SELECT c FROM Contact c WHERE c.phone = :phone")}) public class Contact implements Serializable { private static final long serialVersionUID = 1L; @Id @GeneratedValue(strategy = GenerationType.IDENTITY) @Basic(optional = false) @Column(name = "id") private Integer id; @Basic(optional = false) @NotNull @Size(min = 1, max = 255) @Column(name = "email") private String email; @Basic(optional = false) @NotNull @Size(min = 1, max = 255) @Column(name = "name") private String name; //… }
  • 26.
    @Stateless @Path("contact") public class ContactFacadeRESTextends AbstractFacade<Contact> { @POST @Override @Consumes({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON}) public void create(Contact entity) { super.create(entity); } @PUT @Path("{id}") @Consumes({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON}) public void edit(@PathParam("id") Integer id, Contact entity) { super.edit(entity); } @DELETE @Path("{id}") public void remove(@PathParam("id") Integer id) { super.remove(super.find(id)); } @GET @Path("{id}") @Produces({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON}) public Contact find(@PathParam("id") Integer id) { return super.find(id); } @GET @Override @Produces({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON}) public List<Contact> findAll() { return super.findAll(); } }
  • 31.
    @JsonAutoDetect @Entity @Table(name="CONTACT") public class Contact{ @Id @GeneratedValue @Column(name="id") private int id; @Column(name="name", nullable=false) private String name; @Column(name="phone", nullable=false) private String phone; @Column(name="email", nullable=false) private String email; }
  • 32.
    @Repository public class ContactDAO{ private HibernateTemplate hibernateTemplate; @Autowired public void setSessionFactory(SessionFactory sessionFactory) { hibernateTemplate = new HibernateTemplate(sessionFactory); } public List<Contact> getContacts(int start, int limit) { DetachedCriteria criteria = DetachedCriteria.forClass(Contact.class); return hibernateTemplate.findByCriteria(criteria, start, limit); } public void deleteContact(int id){ Object record = hibernateTemplate.load(Contact.class, id); hibernateTemplate.delete(record); } }
  • 33.
    @Controller public class ContactController{ private ContactService contactService; @RequestMapping(value="/contact/view.action") public @ResponseBody Map<String,? extends Object> view(@RequestParam int start, @RequestParam int limit) throws Exception { try{ List<Contact> contacts = contactService.getContactList(start,limit); int total = contactService.getTotalContacts(); return ExtJSReturn.mapOK(contacts, total); } catch (Exception e) { return ExtJSReturn.mapError("Error retrieving Contacts from database."); } } @RequestMapping(value="/contact/create.action") public @ResponseBody Map<String,? extends Object> create(@RequestBody ContactWrapper data) throws Exception { try{ List<Contact> contacts = contactService.create(data.getData()); return ExtJSReturn.mapOK(contacts); } catch (Exception e) { return ExtJSReturn.mapError("Error trying to create contact."); } } }
  • 35.
  • 37.
  • 38.
  • 39.
  • 40.
  • 41.
    Plataforma HTML5 <canvas> <video> <audio> CSS3 Animações Transformações Sencha ExtJS Angular Backbone Knockout Ember Pré-processadores Sass, Less Emmet Dart
  • 42.
    Plataforma HTML5 <canvas> <video> <audio> CSS3 Animações Transformações Sencha ExtJS Angular Backbone Knockout Ember Pré-processadores Sass, Less Emmet Dart Mobile Híbrido Phonegap/Cordova Ionic
  • 43.
    Plataforma HTML5 <canvas> <video> <audio> CSS3 Animações Transformações Sencha ExtJS Angular Backbone Knockout Ember Pré-processadores Sass, Less Emmet Dart Mobile Híbrido Phonegap/Cordova Ionic Desktop Híbrido TideSDK AppJS Node web-kit Electron
  • 46.
  • 47.
  • 49.
  • 50.
  • 51.
    APIs REST Banco deDados JSON JSON
  • 60.
    import {bootstrap} from'@angular/platform-browser-dynamic'; import { HTTP_PROVIDERS } from '@angular/http'; import {AppComponent} from './app.component'; bootstrap(AppComponent, [HTTP_PROVIDERS]);
  • 61.
    import {Component} from'@angular/core'; import {ContactsComponent} from './contacts/contacts.component'; @Component({ selector: 'my-app', directives: [ContactsComponent], template: '<contacts-grid></contacts-grid>' }) export class AppComponent { }
  • 62.
    export class Contact{ id: number; name: string; phone: string; email: string; }
  • 63.
    import { Injectable} from '@angular/core'; import { Http, Response } from '@angular/http'; import 'rxjs/add/operator/map'; @Injectable() export class ContactsService { constructor(private http: Http) { } getContacts() { return this.http.get('http://localhost:8080/contacts-spring-mvc/contact/view.action? start=0&limit=250') .map((res: Response) => res.json().data); } }
  • 64.
    import {Component, OnInit}from '@angular/core'; import {AgGridNg2} from 'ag-grid-ng2/main'; import {Contact} from './contact.model'; import {ContactsService} from './contacts.service'; @Component({ selector: 'contacts-grid', directives: [AgGridNg2], providers: [ContactsService], template: ` <ag-grid-ng2 #agGrid style="height:100%;width:583px" class="ag-fresh" [gridOptions]="gridOptions" [rowData]="contacts"> </ag-grid-ng2 > ` }) export class ContactsComponent implements OnInit { contacts: Contact[] = []; columnDefs = [ {headerName: 'Name', field: "name", width: 200 }, {headerName: 'Phone', field: "phone" ,width:180}, {headerName: 'Email', field: "email" ,width:200} ]; gridOptions : any = []; constructor(private contactsService: ContactsService) { this.gridOptions = { rowData: this.contacts, columnDefs: this.columnDefs, enableColResize: true, enableSorting: true, enableFilter: true } } ngOnInit() { this.contactsService.getContacts() .subscribe(contacts => this.contacts = contacts);
  • 65.
  • 73.
    import {Component} from'@angular/core'; import { HTTP_PROVIDERS } from '@angular/http'; import {Platform, ionicBootstrap} from 'ionic-angular'; import {StatusBar} from 'ionic-native'; import {TabsPage} from './pages/tabs/tabs'; @Component({ template: '<ion-nav [root]="rootPage"></ion-nav>' }) export class MyApp { private rootPage:any; constructor(private platform:Platform) { this.rootPage = TabsPage; platform.ready().then(() => { StatusBar.styleDefault(); }); } } ionicBootstrap(MyApp, [HTTP_PROVIDERS]);
  • 74.
    import {Component} from'@angular/core' import {HomePage} from '../home/home'; import {AboutPage} from '../about/about'; import {ContactPage} from '../contact/contact'; @Component({ templateUrl: 'build/pages/tabs/tabs.html' }) export class TabsPage { private tab1Root: any; private tab2Root: any; private tab3Root: any; constructor() { // this tells the tabs component which Pages // should be each tab's root Page this.tab1Root = HomePage; this.tab2Root = AboutPage; this.tab3Root = ContactPage; } } <ion-tabs> <ion-tab [root]="tab3Root" tabTitle="Contatos" tabIcon="contacts"></ion-tab> <ion-tab [root]="tab1Root" tabTitle="Inicio" tabIcon="home"></ion-tab> <ion-tab [root]="tab2Root" tabTitle="Sobre" tabIcon="information-circle"></ion-tab> </ion-tabs>
  • 75.
    import {Component, OnInit}from '@angular/core'; import {NavController} from 'ionic-angular'; import {Contact} from '../contact/contact.model'; import {ContactsService} from '../contact/contacts.service'; import {ContactDetailsPage} from '../contact-details/contact-details'; @Component({ templateUrl: 'build/pages/contact/contact.html', providers: [ContactsService] }) export class ContactPage implements OnInit { contacts: Contact[] = []; constructor(private nav: NavController, private contactsService: ContactsService) { } ngOnInit() { this.contactsService.getContacts() .subscribe(contacts => this.contacts = contacts); } itemSelected(contact){ this.nav.push(ContactDetailsPage, contact); } }
  • 76.
    <ion-navbar *navbar> <ion-title> Contact </ion-title> </ion-navbar> <ion-content> <ion-list> <ion-item *ngFor="letcontact of contacts" (click)="itemSelected(contact)"> {{contact.name}} </ion-item> </ion-list> </ion-content>
  • 77.
    import {Component} from'@angular/core'; import {NavController, NavParams} from 'ionic-angular'; import {Contact} from '../contact/contact.model'; @Component({ templateUrl: 'build/pages/contact-details/contact-details.html' }) export class ContactDetailsPage { contact: Contact; constructor(private nav: NavController, private navParams: NavParams) { this.contact = this.navParams.data; } }
  • 78.
    <ion-navbar *navbar> <ion-title>{{contact.name}}</ion-title> </ion-navbar> <ion-content paddingclass="speaker-detail"> <p>Id: <span>{{contact.id}}</span></p> <p>Nome: <span>{{contact.name}}</span></p> <p>Email: <span>{{contact.phone}}</span></p> <p>Telefone: <span>{{contact.email}}</span></p> </ion-content>
  • 80.
  • 84.
  • 85.
    const electron =require('electron') const app = electron.app const BrowserWindow = electron.BrowserWindow let mainWindow function createWindow () { mainWindow = new BrowserWindow({width: 800, height: 600}) mainWindow.loadURL(`file://${__dirname}/index.html`) mainWindow.webContents.openDevTools() mainWindow.on('closed', function () { mainWindow = null }) } app.on('ready', createWindow) app.on('window-all-closed', function () { if (process.platform !== 'darwin') { app.quit() } }) app.on('activate', function () { if (mainWindow === null) { createWindow() } })
  • 86.
    electron-packager ./ --platform=darwin--arch=x64 electron-packager ./ --platform=win32 --arch=x64 electron-packager ./ --platform=linux --arch=x64
  • 91.
    • SSL • Unauthorisedaccess (acesso não autorizado) • Código backend sem validações • Dados sem criptografia (local e na troca de dados) • Mau uso da persistência
  • 92.
  • 93.
  • 95.