QCon 2015 - AngularJS Java EE

Propaganda
Combinando AngularJS com Java EE
Rodrigo Cândido da Silva
@rcandidosilva
About Me
• Software Architect
• http://integritastech.com
• JUG Leader do GUJavaSC
• http://gujavasc.org
• Twitter
• @rcandidosilva
• Contatos
• http://rodrigocandido.me
Agenda
• Arquitetura Rich Client
• RESTful Web Services
• Java EE 7
• JAX-RS
• WebSocket
• JSON-P
• AngularJS
• Demo
Client-side vs. Server-side
• Server-side
• Tudo é processado no
servidor
• Mais stateful
• Fraca escalabilidade
• Client-side
• Complexo e dinâmico
• Mais stateless
• Maior escalabilidade
Ascenção do Javascript
• O debate cliente ‘leve' vs cliente ‘pesado' é antigo…
• Frameworks web server-side mandaram por um tempo
(Struts, Spring, MVC, JSF)
• Ajax foi uma mudança suave para o client-side (GWT,
Vaadin)
• Rich clients estão voltando voltaram, graças ao
JavaScript/HTML5
• Motores Javascript melhoraram muito
• Melhores ferramentas desenvolvimento
• Melhores padrões (CSS3, HTML5, Websocket)
Arquitetura Rich Client
Arquitetura Rich Client
• Similar a arquiteturas cliente/servidor
• Client responsável pela UI, input, validação, lógica e
estado
• Server responsável pela lógica de negócio, modelo de
domínio, persistência
• Web/HTTP é a cola que conecta client e server
• Protocolos de comunicação comuns
• REST na maioria dos casos
• WebSocket quando precisa de comunicação full-duplex
• Ferramentas Javascript suportam REST muito bem, mas
ainda não WebSocket
• O formato comum (talvez ideal?) de troca de dados é JSON
Arquitetura REST
Arquitetura REST
• Características:
• ︎Protocolo cliente/servidor sem estado (HTTP)
• ︎Operações bem definidas (GET, POST, PUT)
• ︎Sintaxe universal para identificação de recursos
(URL)
• ︎Transferência de informações em formato padrão
(XML, HTML, JSON)
• Web Services que seguem a arquitetura REST são
denominados RESTful
RESTful Web Services
HATEOAS
• Hypermedia As The Engine of Application State
• Clientes somente precisam saber a URI root da aplicação e os media
types utilizados
• Descrevem o estado atual da aplicação e como navegar para o
próximo estado
Java EE é uma ótima plataforma
server-side para esta arquitetura
Java EE History
Java EE 7
!
Java EE 6
Java EE 5
J2EE 1.4
J2EE 1.3
CMP,
Connector
Architecture
Web
Services
Mgmt,
Deployment,
Async
Connector
Ease of
Development,
EJB 3, JPA,
JSF, JAXB,
JAX-WS,
StAX, SAAJ
Pruning,
Extensibility
Ease of Dev,
CDI, JAX-RS
JMS 2,
Batch, TX,
Concurrency,
Interceptor,
WebSocket,
JSON!
JAX-RPC, CMP/
BMP, JSR 88
Web$Profile$
$
Servlet 3,
EJB 3.1 Lite
!
Web$Profile$
$
JAX-RS 2
!
Java EE 7
Java EE + JavaScript
JavaScript/HTML5
Java API for
WebSocket
JAX-RS
Java API for
JSON
JAXB
Bean Validation
Servlet
EJB 3
JPA
CDI
JMS
JTA
JCA
JAX-RS
• Suporte a RESTful em Java
• API padronizada
• Programação declarativa
• Abstrações para implementação no server e client
• Serviços implementados via POJO
• Configuração via anotações
• @Path, @GET, @POST, @PUT, @DELETE, @PathParam,
@QueryParam, @Produces, @Consumes, etc
• Plugável e extensível
• Providers, filters, interceptors, validators
• Suporte a processamento assíncrono
• Integrado com as tecnologias do Java EE
JAX-RS
@Path
Define a URI para ser utilizada pelo endpoint
@GET
Determina acesso ao serviço via HTTP GET
@POST
Determina acesso ao serviço via HTTP POST
@PUT
Determina acesso ao serviço via HTTP PUT
@DELETE
Determina acesso ao serviço via HTTP DELETE
@HEAD
Determina acesso ao serviço via HTTP HEAD
@PathParam
Define o mapeamento do valor informado na URI para um
determinado parâmetro de método
@QueryParam
Define o mapeamento do valor informado na query string
para um determinado parâmetro de método
@Consumes
Define um determinado MIME type para recebimento de
dados pelo serviço
@Produces
Define um determinado MIME type para envio de dados
pelo serviço
@Provider
Define um determinado componente para auxiliar no JAXRS runtime.
@ApplicationPath
Determina o root path de uma aplicação JAX-RS
Manipulação de Parâmetros
• Além do @PathParam há outras cinco anotações que
permitem extrair informação de um request
• @QueryParam e @DefaultValue
• Extraem dados de um query string (?nome=valor&nome=valor)
• @FormParam
• Extrai dados de um formulário (applicaton/x-www-form-urlencoded)
• @CookieParam
• Extrai dados de cookies (pares nome=valor)
• @HeaderParam
• Extrai dados de cabeçalhos HTTP
• @MatrixParam
• Extrai dados de segmentos de URL
Validação de Dados
• Os dados enviados para métodos em classes de resource
podem ser validados através da API Bean Validation, que
é configurada via anotações
@POST
@Path("/criar")
@Consumes(MediaType.APPLICATION_FORM_URLENCODED)
public void criarFilme(
@NotNull
@FormParam("titulo") String titulo,
@NotNull
@FormParam("diretor") String diretor,
@Min(1900) @FormParam("ano")
int ano) { ... }
@Pattern(regexp="tt[0-9]{5-7}")
private String imdbCode;
Conversão de Dados
• ParamConverterProvider pode ser utilizado para gerenciar a
conversão de objetos customizados Object para String e vice-versa
• Por exemplo, pode ser utilizado para produzir um objeto java.util.Date a
partir de uma String formatada.
@Provider
public class MyBeanConverterProvider implements ParamConverterProvider {
@Override
public <T> ParamConverter<T> getConverter(
Class<T> clazz, Type type, Annotation[] annotations) {
if (clazz.getName().equals(MyBean.class.getName())) {
return new ParamConverter<T>() {
@Override
public T fromString(String value) {...}
@Override
public String toString(T bean) {...}
};
}
return null;
}
}
Tratamento de Exceções
• Geração e lançamento da exceção customizada
@Path("items/{itemid}/")
public Item getItem(@PathParam("itemid") String itemid) {
Item i = getItems().get(itemid);
if (i == null) {
throw new CustomNotFoundException("Item, " +
itemid + ", is not found");
}
return i;
}
• Exemplo de definição de exceção customizada
public class CustomNotFoundException extends WebApplicationException {
public CustomNotFoundException() {
super(Responses.notFound().build());
}
}
Filtros e Interceptadores
Filtros
• Filtros podem ser server side e/ou client side
• ContainerRequestFilter, ContainerResponseFilter
• ClientRequestFilter, ClientResponseFilter
public class AuthorizationRequestFilter implements ContainerRequestFilter {
@Override
public void filter(ContainerRequestContext requestContext)
throws IOException {
final SecurityContext securityContext =
requestContext.getSecurityContext();
if (securityContext == null ||
!securityContext.isUserInRole("privileged")) {
requestContext.abortWith(Response.status(
Response.Status.UNAUTHORIZED)
.entity("User cannot access the resource.").build());
}
}
}
Interceptadores
• Existem dois tipos de interceptors (Reader e Writer)
// @Compress annotation is the name binding annotation
@NameBinding
@Retention(RetentionPolicy.RUNTIME)
public @interface Compress {}
@Path("helloworld")
public class HelloWorldResource {
@GET @Path("too-much-data")
@Compress
public String getVeryLongString() {...}
}
@Compress
public class GZIPWriterInterceptor implements WriterInterceptor {
@Override
public void aroundWriteTo(WriterInterceptorContext context)
throws IOException, WebApplicationException
{...}
}
@Context
• @Context pode ser utilizado para injetar diversos objetos
contextuais disponíveis em uma requisição ou resposta HTTP
• Objetos da Servlet API
• ServletConfig
• ServletContext
• HttpServletRequest
• HttpServletResponse
• Objetos da JAX-RS API
• Application
• UriInfo
• Request
• HttpHeaders
• SecurityContext
• Providers
@Context
Request request;
@Context
UriInfo uriInfo;
@PUT
public metodo(@Context HttpHeaders headers) {
String m = request.getMethod();
URI ap
= uriInfo.getAbsolutePath();
Map<String, Cookie> c = headers.getCookies();
}
@GET @Path("auth")
public login(@Context SecurityContext sc) {
String userid =
sc.getUserPrincipal().getName();
if (sc.isUserInRole("admin")) { ... }
}
Hypermedia Support
• JAX-RS oferece um modelo para suportar HATEOAS por
meio de suporte à hypermedia
• Em cada mensagem de resposta, deve ser incluído os links
para a próxima mensagem
• Utilizando este suporte, a aplicação consegue definir todo o
modelo de navegação via HTTP
@POST
@Consumes({"application/json", "application/xml"})
@Produces({"application/json", "application/xml"})
public Response create(Article article) {
Article created = articleDao.create(article);
return Response.ok(created)
.link("link-URI", "link-rel")
.links(produceLinks(created))
.build();
}
private Link[] produceLinks(Article article) {...}
Integração com CDI
• JAX-RS integra-se muito bem com as tecnologias da
plataforma Java Enterprise, especialmente com os
componentes EJBs e CDI.
• CDI beans podem ser injetados diretamente nos
resources. Providers e Application terão comportamento
singleton ou @ApplicationScoped
@Path("/cdibean")
public class CdiBeanResource {
@Inject MyOtherCdiBean bean;
@GET
@Produces("text/plain")
public String getIt() {
return bean.getIt();
}
}
// CDI injected bean
Integração com EJB
• Exemplo de integração com EJB
@Local
public interface LocalEjb {
@GET
@Produces("text/plain")
public String getIt();
}
@Stateless
@Path("/stateless")
public class StatelessEjbResource implements LocalEjb {
@Override
public String getIt() {
return "Hi Stateless!";
}
}
Cache Control
• JAX-RS suporta configurações para controle de caching de
responses HTTP por meio da classe CacheControl
@GET
@Path("{id}")
public Response read(@PathParam("id") int id) {
Article article = articleDao.findById(id);
CacheControl cacheControl = new CacheControl();
cacheControl.setMaxAge(60);
return Response.ok(article)
.cacheControl(cacheControl)
.build();
}
Chamadas Assíncronas
• Possibilita o processamento multithread no servidor,
aumentando o seu throughput
• Libera a thread do servidor para executar outras tarefas
• @Suspended indica que o método será executado de
maneira assíncrona
• Possível configurar timeout
@Path(“Async") @RequestScope
public class AsyncResource {
@GET
public void asyncGet(@Suspended final AsyncResponse asyncResponse) {
new Thread(new Runnable() {...}).start();
}
}
WebSocket
• Oferece comunicação bi-direcional (full-duplex) através
•
•
•
•
de uma simples conexão TCP
Inicia através de um hand-shake através do protocolo
HTTP, mas as conversações utilizam o protocolo
WebSockets.
Suporte requisições assíncronas
Perfeito para aplicações como chat e jogos
Utiliza as tecnologias web existentes
WebSocket
Connected !
open
open
message
Client
message
error
message
Server
message
close
Disconnected
WebSocket
Client
Remote
Endpoint
Session
Message
Handler
Remote
Endpoint
Internet
Session
Message
Handler
Client
Remote
Endpoint
Session
WebSocket
Endpoint
Client
Message
Handler
REST vs. WebSocket
Java API for WebSocket
• Programação declarativa com anotações
• Client and server-side
• Powerful API
• @ServerEndpoint, @OnOpen, @OnClose, @OnMessage,
@OnError, Session, Remote
• Plugável e extensível
• Encoders, decoders, sub-protocols
• Lifecycle callback handlers
• Permite empacotá-los em aplicações Java EE
Java API for WebSocket
• Define o endpoint do servidor WebSocket para
conexão pelos clientes
@ServerEndpoint(”/chat”)
public class ChatServer {
@OnOpen
public void onOpen(Session peer) {...}
@OnClose
public void onClose(Session peer) { ... }
@OnMessage
public void message(String message, Session client)
throws IOException {...}
@OnError
public void error(Session session, Throwable t) { ... }
}
Java API for WebSocket
• Exemplo de cliente em JavaScript
var wsUri = "ws://" + document.location.hostname + ":" +
document.location.port +
document.location.pathname + "chat";
var websocket = new WebSocket(wsUri);
websocket.onopen = function(evt) { onOpen(evt) };
websocket.onmessage = function(evt) { onMessage(evt) };
websocket.onerror = function(evt) { onError(evt) };
JSON
• JavaScript Object Notation
{id:123, cidade:”Paris”, voos:[“M344”,”J919”]}
• Pode ser codificado diretamente em String e processado com
métodos como split(), substring(), indexOf() dentre outros
• Java EE 7 disponibiliza um API para construir objetos JSON e
para converter strings JSON em mapas
• É um par de APIs de baixo nível (não é mapeamento objeto-
JSON)
• Existem várias implementações que fazem mapeamento (binding)
objeto-JSON automático (não são parte do Java EE)
• MOXy, Jettison, Jersey, Jackson, etc.
Java API for JSON
• API para parser e geração de objetos JSON definida
pelo Java EE
• Object Model API - javax.json
• Análogo a DOM: estrutura em árvore; I/O streaming via
decorators
• JsonObject: representa um objeto JSON
• JsonArray: representa um array JSON
• Leitura e gravação usando JsonReader e JsonWriter
• JSON Streaming API - javax.json.stream
• Análogo a SAX: leitura sequencial (baixo nível)
• JsonParser: permite ler um stream JSON e capturar eventos
• JsonGenerator: métodos para criar uma estrutura JSON
Java API for JSON
• JSON Object Model API
JsonArray value =
Json.createArrayBuilder()
[
{
.add(Json.createObjectBuilder()
.add("type", "home")
"type": "home ,
.add("number", "212 555-1234")
"number": "212 555-1234"
)
},
.add(Json.createObjectBuilder()
{
.add("type", "fax")
"type": "fax ,
.add("number", "646 555-4567")
"number": "646 555-4567"
}
)
.build();
]
Java API for JSON
• JSON Streaming
{
"firstName": "John", "lastName": "Smith", "age": 25,
"phoneNumber": [
{ "type": "home", "number": "212 555-1234" },
{ "type": "fax", "number": "646 555-4567" }
]
}
Event event = parser.next();
// START_OBJECT
event = parser.next();
// KEY_NAME
event = parser.next();
// VALUE_STRING
String name = parser.getString();
// "John
JAXB
• JAXB beans permitem reutilizar o mesmo JavaBean
para gerar representações JSON e XML no response
@XmlRootElement
public class MyJaxbBean {
public String name;
public int age;
...
}
@GET
@Produces("application/json")
public MyJaxbBean getMyBean() {
return new MyJaxbBean("Agamemnon", 32);
}
{"name":"Agamemnon", "age":"32"}
AngularJS é uma ótima alternativa para
implementação Web rich client
AngularJS
• Framework JavaScript MVW* client-side para
desenvolver aplicações web modernas e dinâmicas
• A primeira versão open-source foi liberada em 2010 e
desde então ele é mantido pela Google e pela
comunidade
• Aproximadamente 2 releases mensais, projeto
altamente ativo
• O que faz o AngularJS ser especial?
AngularJS
• Google Trends
AngularJS
• Jobs Trends
indeed.com
dice.com
AngularJS
• Diferenciais
• Organização da bagunça no client-side
• Views, modules, controllers, services, providers, etc
• Reutilização de código e modularidade (DRY)
• Killer Features
• Two-way data binding
• Dependency Injection
• Controllers, Services
• Directives, Filters, Templates, etc
• Integração natural com REST, SOA, SOFEA
• Ótima testabilidade
AngularJS
• Two-way data binding
AngularJS
• Dependency Injection
.controller('LoginController', function($scope, $rootScope, $location,
$http, $cookieStore, LoginService) {
$scope.login = function () {
LoginService.authenticate($.param({username: $scope.username,
password: $scope.password}),
function (user) {
$rootScope.user = user;
$http.defaults.headers.common[xauth] = user.token;
$cookieStore.put('user', user);
$location.path("/");
});
};
})
AngularJS
• Controllers
var myApp = angular.module('myApp',[]);
myApp.controller('GreetingController', ['$scope',
function($scope) {
$scope.greeting = "Hola!";
}]);
<div ng-controller="GreetingController">
{{ greeting }}
</div>
AngularJS
• Services
var services = angular.module(
"myApp.services", ["ngResource"]);
services.factory("LoginService",
function($resource) {
return $resource(":action", {},
{
authenticate: {
method: "POST",
params: {"action":
"authenticate"},
headers: {“Content-Type":
"application/json"}}
}
);
});
JavaScript Tools
Demo
• Java EE + AngularJS
• https://github.com/rcandidosilva/javaee-javascript
Conclusões…
• Clientes Javascript/HTML5 estão conquistando
desenvolvedores
• Comunicação entre cliente e servidor em JSON via REST
ou WebSocket
• Java EE funciona muito bem como backend para clientes
ricos em Javascript, especialmente JAX-RS, Java API
para WebSockets, e JSON-P
• Enjoy it ;)
Perguntas
?
Muito obrigado!
@rcandidosilva
rodrigocandido.me
Download