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.