Série AngularJS: Aplicação JEE com AngularJS

Olá Pessoal,

No post de hoje vamos ver como persistir os dados que estão no nosso front-end com AngularJS em uma base de dados, mas o nosso back-end é Java usando Spring, Hibernate e Jersey.

Lets go…

Starting…

Vou considerar que você já conhece Spring e Hibernate, portanto o post irá direto ao assunto. Veremos apenas como fazer com que os dados do front-end chegue ao back-end. É necessário que você tenha o Jersey no Controller do lado do Server-side. Fiz um post sobre o AngularJS e Jersey.

Antes de começar

  1. Crie um projeto webapp, de preferência com o maven;
  2. Adicione as dependências do Spring, hibernate, banco de dados, Jersey;
  3. Tenha a lib do angular no projeto ou use a versão online.

O nosso projeto

É muito simples, apenas um formulário que cadastra um customer. Veja o projeto:

angularjcustomerproject

Vou considerar que você já tem a camada de serviço DAO e application-context do Spring devidamente criados e funcionando.

Adicionando Dependência no pom.xm Jersey-Spring

<dependency>

<groupId>com.sun.jersey.contribs</groupId>

<artifactId>jersey-spring</artifactId>

<version>1.8</version>

<exclusions>

<exclusion>

<groupId>org.springframework</groupId>

<artifactId>spring</artifactId>

</exclusion>

<exclusion>

<groupId>org.springframework</groupId>

<artifactId>spring-core</artifactId>

</exclusion>

<exclusion>

<groupId>org.springframework</groupId>

<artifactId>spring-web</artifactId>

</exclusion>

<exclusion>

<groupId>org.springframework</groupId>

<artifactId>spring-beans</artifactId>

</exclusion>

<exclusion>

<groupId>org.springframework</groupId>

<artifactId>spring-context</artifactId>

</exclusion>

</exclusions>

</dependency>

Configurando o Jersey-Spring

No arquivo web.xml deixe assim:

<servlet>

<servlet-name>jersey-servlet</servlet-name>

<servlet-class>com.sun.jersey.spi.spring.container.servlet.SpringServlet</servlet-class>

<init-param>

<param-name>com.sun.jersey.config.property.packages</param-name>

<!– Aqui é o package onde vai ficar o controller –>

<param-value>com.camilolopes.jersey.services</param-value>

</init-param>

<init-param>

<param-name>com.sun.jersey.api.json.POJOMappingFeature</param-name>

<param-value>true</param-value>

</init-param>

</servlet>

Crie a classe CustomerController.java conforme a seguir:

@Controller

@Path(“/service”)

public class CustomerController {

@Autowired

@Qualifier(“customerService”)

private CustomerService customerService; //substituir pela sua classe de Service gerenciada pelo Spring

@GET

@Produces(MediaType.APPLICATION_JSON)

public List<Customer> getCustomer() {

List<Customer> list = customerService.getListCustomers();

return list;

}

@POST

@Consumes(MediaType.APPLICATION_JSON)

public void saveCustomer(Customer customer){

customerService.save(customer);

}

public CustomerService getCustomerService() {

return customerService;

}

public void setCustomerService(CustomerService customerService) {

this.customerService = customerService;

}

}

 

Se você viu o nosso post com Jersey e conhece WebService já sabe o que significa essa classe.  Em poucas palavras, é através dessa classe que o front-end e o back-end se comunicam através de um objeto JSON. Então quando o angular precisa enviar algo para o back-end ele vai precisar chamar algum serviço disponível nessa classe, e temos apenas dois: um GET e outro POST.

Criando o app.js

 

       $app = angular.module(‘app’,[‘ngResource’]);

$app.config(function($routeProvider,$httpProvider,$locationProvider){

//routes

$routeProvider.

when(‘/’,{templateUrl:’view/customers.html’,controller:customerController}).

when(‘/create’,{templateUrl:’view/form.html’,controller:customerController}).

when(‘/list’,{templateUrl:’view/customers.html’,controller:customerController}).

otherwise(

{

redirectTo:’/’

});

$httpProvider.responseInterceptors.push(function($q,$rootScope){

return function(promise){

return promise.then(function(response){

return (response);

},function(response){

$data = response.data;

$error = $data.error;

if($error && $error.text){

console.log(“ERROR: ” + $error.text);

}

else{

if(response.status=404)

console.log(“page not found”);

}

return $q.reject(response);

});

};

});

});

Esse código acima apenas cria rotas com base no que for chamado no browser. Por exemplo, se chamarmos /create vai ser carregado a página form.html e o controller  customerController que ainda vamos criar.

A outra função é, em caso de erro no response, podermos exibir um conteúdo customizado. A novidade que temos nesse arquivo é:

$app = angular.module(‘app’,[‘ngResource’]);

Lembra que nos posts anteriores passávamos [] para o segundo parâmetro do module? Agora estamos dizendo que vamos usar ng-resource para conectar a um WebService.  Adicione ao seu projeto angular-resource.js  ou use a versão online:

<script src=“http://code.angularjs.org/1.0.6/angular-resource.min.js”></script>

Criando customerController.js

Vamos agora criar o controller do angular, portanto crie um arquivo JavaScript chamado customerController.js. Não vamos organizar o projeto, pode colocar dentro de webapp mesmo:

function customerController($scope,$resource,$location){

//estamos criando um objeto e linkando com o webservice CustomerController.java

Customer = $resource(“rest/service/”);

//estamos criando uma função que carrega todos os customers.

$scope.loadAll = function(){

Customer.query(

function(data){

$scope.rows = data;

});

};

//quando chamado cria um novo customer e salva.

       $scope.newOne = function() {

var c = new Customer();

//estou atribuindo o nome digitado ao atributo do domain Customer.

c.name = $scope.nameCustomer;

c.$save();

};

}

No inicio parece estranho, mas é porque é diferente do que estamos acostumados. Coloquei a explicação em modo de comentário inline para facilitar o entendimento. Não se preocupe se no inicio se sentir desconfortável com a estrutura, também me senti, mas com o tempo fui aprendendo melhor e vendo que faz sentindo a forma que o angular trata o binding.

Criando o arquivo index.html

Vamos carregar as libs, então esse arquivo terá libs e a ng-view:

 

<html ng-app=“app”>

<head>

<meta charset=“UTF-8”>

<script src=“http://code.angularjs.org/1.0.6/angular.min.js”></script>

<script src=“app.js”></script>

<script src=“customerController.js”></script>

</head>

<body>

<a href=“#/create”>Create</a>

<a href=“#/list”>List</a>

<script src=“http://code.angularjs.org/1.0.6/angular-resource.min.js”></script>

<div ng-view></div>

</body>

</html>

Criando o form.html

<body ng-controller=“customerController”>

<h2>Register Customer</h2>

<form  name=“customerform”>

<div>

<label>Name</label>

<input name=“name” ng-model=“nameCustomer” require/> {{nameCustomer}}

</div>

<div>

<label>Phone</label>

<input name=“phone” ng-model=“phoneCustomer” /> {{phoneCustomer}}

</div>

<div>

<label>E-mail</label>

<input name=“email” ng-model=“emailCustomer” type=“email” required /> {{emailCustomer}}

</div>

<div>

<input type=“button” value=“Save” ng-click=“newOne()” ng-disabled=“customerform.$invalid”/>

</div>

</form>

</body>

 

 Criando customers.html

Aqui vamos listar os customers cadastrados

<div ng-init=“loadAll()”>

<table id=“tableData”>

<thead>

<tr>

<th>ID</th>

<td>Nome</td>

</tr>

</thead>

<tbody>

<tr ng-repeat=“row in rows”>

<td>{{row.id}}</td>

<td>{{row.name}}</td>

</tr>

</tbody>

</table>

</div>

 

Observe que temos ng-init. Essa diretiva invoca o método que carrega todos os customers.

Em seguida temos a diretiva ng-repeat que funciona como um forEach do Java rows; é a variável que criamos no customerController.js

Testando

Assumindo que seu BD está up, suba a aplicação (caso tenha criado um maven Project, apenas digite mvn tomcat:run via linha de comando):

angularjscustomerrunning

Clique no link Create

angularjscustomercreate

Observe a url e o botão save. A url tem alguma relação com as rotas que criamos? E o botão save, por que está desabilitado?

Ele está desabilitado porque fizemos isso no form.html:

<input type=“button” value=“Save” ng-click=“newOne()” ng-disabled=“customerform.$invalid”/>

Olhe para a diretiva ng-disabled. Ali estamos dizendo que se o formulário for invalid desabilite o botão. E o que é um formulário inválido? Nesse caso, se os campos que marcamos como required não estiverem preenchidos, é um form inválido. Observe que quando preencher os campos requeridos, automaticamente o botão fica habilitado:

angularjscustomerformvalid

Clique em save. Se clicar mais de uma vez acontece isso:

angularjscustomerlist

Click no link List

Poderiamos redirencionar usando $location.path(“nomeDaRota”);

Apesar de termos vários outros atributos no form, salvamos apenas o name. Mas sinta-se a vontade em praticar e salvar os demais.  Conferindo no banco:

angularjscustomerbd

Pronto. Salvando dados no BD com AngularJS, Spring, Jersey, Hibernate. Simples, não?

O projeto completo está no meu GitHub no repositório dedicado às minhas brincadeiras com angularJS: https://github.com/camilolopes/workspaceAngularJs

Sempre estarei subindo projetos novos, brincando com o framework… Se quiser acompanhar basta me seguir no github.

Enfim, espero que tenham gostado do post.

Abraços, see ya!! 

Série AngularJS: AngularJS com Jersey

 

Olá Pessoal,

No post de hoje veremos como mandar os dados do front-end para o back-end usando o Jersey, mas há outras opções como Spring MVC.

Lets go..

Introdução

A ideia aqui é como mandar o que está na tela para o back-end. O AngularJS não depende do seu back-end, mas de alguma forma vamos precisar que ele converse com o server-side. Como fazer isso? Simples, via objeto JSON usando RESTful. Essa é a forma que podemos mandar os dados que estão na tela para o nosso back-end. Não vou entrar em detalhes do que é um objeto JSON e toda teoria. Basta dar uma “googlada” que há vários posts e artigos sobre o assunto.

Jersey

Vamos usar o Jersey no nosso Controller, que terá como responsabilidade receber um objeto JSON e retornar um objeto JSON para camada de view. Ou seja, é por aqui que o AngularJS vai conversar com nosso back-end e deixar transparente qual linguagem estamos usando (poderia ser Java, PHP, Ruby etc).

Poderíamos usar o Spring MVC retornando um objeto JSON. Pouco importa para o Angular o que teríamos aqui, desde que o objeto retornado fosse JSON.

Na Prática

Vamos deixar de teoria e colocar a mão na massa. Para o Jersey, você precisa ter lido este post. Não vou focar no código do Jersey, pois esse já foi abordado em outro post, portanto considero que você entenda ou já tenha as chamadas dos paths correto no seu controller e o método retornando JSON. A seguir, o método que vamos usar nesse exemplo:

@GET

       @Path(“/client”)

       @Produces(MediaType.APPLICATION_JSON)

       public List<Client> getCliente() {

             Client client = new Client();

             client.setId(1);

             client.setName(“Hello World Camilo”);

             ArrayList<Client> list = new ArrayList<Client>();

             list.add(client);

             return list;

                     }

Caso não tenha no Controller, adicione. Se você fez o exemplo do post sobre Jersey aqui no blog, basta alterar o método existente conforme acima.

  1. Crie o arquivo app.js que terá a configuração da nossa aplicação. Esse arquivo deve ficar na raiz, ou seja, em webapp. Claro que você poderia colocar em qualquer outro local, mas vamos manter tudo simples aqui. Veja como ele se parece:

/*

 * Nesse arquivo estamos configurando variáveis e métodos GLOBAIS

 */

SERVER_URL=”http://localhost:8080/hellojersey/rest”; 

//criando o module para toda app 

       $app = angular.module(‘app’,[]);      

//criando a routes

       $app.config(function($routeProvider,$httpProvider,$locationProvider){

                           //definindo as rotas

             $routeProvider.

             when(‘/’,{templateUrl:’view/customers.html’,controller:customerController}).

             when(‘/clientes’,{templateUrl:’view/hello.html’,controller:customerController}).

              otherwise({redirectTo:’/’});    

       $httpProvider.responseInterceptors.push(function($q,$rootScope){

             return function(promise){

                    return promise.then(function(response){

                           return (response);

                    },function(response){

                           $data = response.data;

                           $error = $data.error;

//                  coloquei os alerts para me certificar que a função foi chamada

                           if($error && $error.text)

                                  alert(“ERROR: ” + $error.text);

                           else{

                                  if(response.status=404)

                                  alert(“Page not found”);

                           }

                           return $q.reject(response);

                    });

             };

       });

});

        $app.run(function($rootScope){

                $rootScope.server=function(url){

                        alert(SERVER_URL + url);

                        return SERVER_URL + url;                      

                };

        }       

);

                   

SERVER_URL é uma variável global que criamos e que tem o caminho do nosso serviço REST. Observe que criamos uma variável Server que vai concatenar com o valor passado, por exemplo. Para chamar um serviço GET disponível diretamente, a url é assim:

http://localhost:8080/hellojersey/rest/hello/client

Mas, a ideia é fazer que isso aconteça via AngularJS de maneira transparente.  No código anterior, quando criamos as routers, falamos que quando chamar raiz “/”, o conteúdo do arquivo view/customers.html deve ser exibido na mesma página. E quando chamar /clientes deve ser o conteúdo do arquivo hello.html. 

Criando o customerController.js

Vamos criar o nosso controller

function customerController($scope,$http,$routeParams,$location){

       $scope.rows=null;

       $scope.row=null; 

$scope.loadAll = function(){

/*     esse é o cara que chama o service rest

 * Observe que ele concatena o valor com o que foi definido na variável SERVER

 */

       $http.get($scope.server(“/hello/client”)).success(function(data){

             $scope.rows=data;

             alert(“loadALL”);

       }).error(function(data){

             alert(“Error…”);

             console.log(data);

       });

}; 

}

É aqui que acontece a magia. Observe que passo o caminho do meu serviço,

$http.get($scope.server(“/hello/client”)).success(function(data)

O resto será concatenado com a variável global SERVER_URL.

Criando as páginas HTML

Vamos criar três arquivos HTML

  • index.html: teremos um link que ao ser clicado vai exibir todos os clientes, ou seja, por baixo ele chama o nosso serviço rest que retorna todos os clientes;
  • customers.html: tem uma tabela que exibe os clientes cadastrados;
  • hello.html é apenas mais um arquivo para teste.

index.html

<html ng-app=“app”>

<head>

<meta charset=“UTF-8”>

<script src=“http://code.angularjs.org/1.0.6/angular.min.js”></script>

<script src=“app.js”></script>

<script src=“customerController.js”></script>

</head>

<body>

<li><a href=“#/clientes”>Clientes</a></li>

<div ng-view></div>

</body>

</html>

 customers.html

<h2>AngularJS Customers</h2>

<div ng-init=“loadAll()”>

<table id=“tableData”>

<thead>

<tr>

<th>ID</th>

<td>Nome</td>

</tr>

</thead>

<tbody>

<tr ng-repeat=“row in rows”>

<td>{{row.id}}</td>

<td>{{row.name}}

</tr>

</tbody>

</table>

</div>

Hello.html

<body>

hello, incluiu o conteudo de hllo.htm

</body>

Veja a estrutura do projeto:

hellojerseyangularjsproject

Testando

Execute mvn tomcat:run  via linha comando ou Eclipse

http://localhost:8080/hellojerseyangularjs/

hellojerseyangulartestraiz

Vai aparecer os alerts que inserimos

hellojerseyangularjsresult

Veja o resultado, e melhor: sem sair da página.  Click no link clientes e veja o resultado

 

hellojerseyangularjsresultclickclient

Pronto, assim terminamos de fazer AngularJS conversar com o nosso back-end de maneira simples, fácil e transparente.

GitHub

https://github.com/camilolopes/workspaceAngularJs

 Abraços, see ya!!! 

Série AngularJS Usando Locale no AngularJS

Olá Pessoal,

No post de hoje vamos ver como dar suporte à formatação suportando o locale de um país. É muito simples fazer isso como AngularJS .

Lets go…

 Starting…

No GitHub do AngularJS  temos vários locale já disponíveis . Então vamos dizer que precisamos formatar um valor para suportar a nossa moeda.  Por default o angularJS suporte o locale en_US. Para outras  formatações é preciso adicionarmos .js especifico para o país. Baixe o .js https://github.com/angular/angular.js/tree/master/src/ngLocale  referente ao país que deseja. Nesse caso vou usar o pt_br.js  (angular-locale_pt-br.js). Baixe o arquivo no github do angular. Uma forma simples é copiar o código e criar um arquivo .js .

Desenvolvimento

Considerando que você já fez um Hello World com AngularJS e brincou com os outros posts aqui no blog, vou ignorar toda parte de setup básico do angular.

Step 1

Adicione o arquivo angular-locale_pt-br.js  no  seu arquivo index.html. Assim:

<head>

<meta charset=“UTF-8”>

<title>Insert title here</title>

<script src=“js/lib/angular.js”></script>

<script src=“js/app.js”></script>

<script src=“js/angular-locale_pt-br.js”></script>

</head>

<body> 

<div ng-view> 

</div>

</body>

Step 2

Crie um arquivo locale.html

<body>

<input type=“text” ng-model=“valor”/> <p/>

Default currency {{valor | currency : “$”}} <p/>

Real {{ valor | currency}}

</body>

 

Nada demais aqui, estamos apenas usando o recurso de filter sobre qual currency usar. Se não informamos nenhum, será usado a default do angularjs, mas se encontrar algum locale e for compatível com a do browser, será usado.  Por exemplo, se tenho o browser em português e o js para o locale pt-Br,  o default será  no idioma português do Brasil.

Step 3

Usando rotas, vamos adicionar uma para locale. No meu arquivo app.js está assim:

var app = angular.module(“myapp”,[]); 

//creating route

app.config(function($routeProvider,$httpProvider,$locationProvider){

       $routeProvider.

       when(“/”,{templateUrl:”home.html”}).   

when(“/locale”,{templateUrl:”locale.html”})

            

});

 Step 4

Vamos agora testar a aplicação. 

angularjslocaleresult

Simples, não?

Vou ficando por aqui. Espero que tenham gostado dessa dica.

Abraços, see ya!!!

Série AngularJS: Aprendendo usar Deep Linking ou Rotas

Olá Pessoal,

No post de hoje vamos conhecer o recurso de deep linking do Angular, conhecido também como Rotas.

Lets go…

 

Deep Linking ou Rotas

É uma funcionalidade que temos no Angular e é muito útil durante o dia a dia. Na prática funciona assim:

O que acontece quando chamar /create? Quero que carregue o arquivo createform.html e o controller createController.js . Pronto, é isso que fazemos com as Rotas. E qual a vantagem disso?

  • Fácil Manutenção;
  • Tudo em uma página.

Na Prática

Vamos ver metendo mão na massa o que é melhor. Vou usar um projeto que está no meu GitHub chamado de recipeangularjsexample. Não há nada de Java nesse projeto. Considerando que você já sabe como configurar um projeto com AngularJS, então vou pular a parte de setup. Caso tenha dúvida, veja os posts iniciais da série.

Criando arquivo app.js

No arquivo app.js que deixei na raiz do projeto deixe assim:

var app = angular.module(“myapp”,[]); 

//creating route

app.config(function($routeProvider,$httpProvider,$locationProvider){

       $routeProvider.

       when(“/”,{templateUrl:”home.html”}).

       when(“/upper”,{templateUrl:”upperfilter.html”}).

       when(“/serviceioc”,{templateUrl:”serviceioc.html”}).

       when(“/watch”,{templateUrl:”watch.html”,controller:recipeController});      

});

É muito simples a leitura:

“quando chamar upper, carregue o conteúdo do arquivo upperfilter.html. Mas quando chamar watch, carregue o conteúdo watch.html e o controller recipeController”

Note: No exemplo acima não necessariamente os arquivos de outras rotas precise existir, meu objetivo foi mostrar como funciona e para que você entenda melhor o conceito é bem simples.

Observe que não somos obrigados a ter o controller para cada link e o que informamos é o nome do controller e não o nome do arquivo .js. Quem está começando pode se confundir e querer informar o nome do arquivo js. Ao fazer isso e chamar alguma função teremos erro no console Java script.

Crie os arquivos HTML acima e por enquanto deixe-os vazios.

Criando o recipeController.js

Crie o arquivo conforme a imagem a seguir:

angularjsrecipecontrollerjs

Criando o arquivo index.html

O arquivo index.html é que vai carregar os arquivos javascript, portanto deixe assim:

<html ng-app=“myapp”>

<head>

<meta charset=“UTF-8”>

<title>Insert title here</title>

<script src=“js/lib/angular.js”></script>

<script src=“js/app.js”></script>

<script src=“js/recipeController.js”></script>

</head>

<body> 

<div ng-view> 

</div>

</body>

</html>

 

Não se esqueça do ng-app e ng-view.  O ng-view é onde o conteúdo das páginas serão renderizados. Por isso que falei no inicio do post: uma única página para renderizar o conteúdo. É como um include.

Altere o conteúdo da página watch.html e acesse no browser:

http://localhost:8080/receipeangularexample/#/watch

Veja que vai aparecer o conteúdo que temos dentro de watch.html.

Se você tentar http://localhost:8080/receipeangularexample/watch vai receber 404? Por quê? Porque para ser um deep linking precisamos colocar # para que o response seja interceptado e tratado como rota e não um serviço da aplicação.

No meu Github há um repositorio com alguns exemplos usando AngularJS

Por hoje é isso. Simples, não?

Abraços, see ya!! 

Série AngularJS: Hello World in few minutes

Olá Pessoal,

O post de hoje é para quem está querendo começar a brincar com AngularJS e aqui vai um simples “Hello World” e vou deixar que o próprio exemplo prático fale pelo framework. 

Lets go…

Na prática

  1. Crie um simple project webapp pelo maven ou dynamic web Project (não é requerido, mas considerando que você seja um desenvolvedor Java);
  2. Em webapps crie um arquivo hello.html.

Escreva o seguinte código:

<!doctype html>

<!– estamos dizendo ‘quero usar angularjs’ –>

<html ng-app>

<head>

<!– definido a versão do angular que queremos  –>

<script

        src=“https://ajax.googleapis.com/ajax/libs/angularjs/1.0.7/angular.min.js”></script>       

        <!– aqui criamos um js que terá as function –>

<script src=“todo.js”>

</script>

<title>Insert title here</title>

</head>

<body>

<!– chamamos a funcao que está no .js –>

        <div ng-controller=“hello”>

        <!– chamamos a variavel que declaramos no .js  –>

                Hello {{name}}

                <hr />

                <label>Name</label>

<input ng-model=“typeName” placeHolder=“type your name please” /> <br />

                         Hi {{typeName}}, <br />

                        <br/>

                <br/>

                <label>Quantity of product</label>

                 <input type=“number”     ng-model=“qt” required=“required” />

                        <label>Inform Price</label>

                         <input type=“number” ng-model=“price” required=“required” />

                        Total {{qt *price | currency}}

        </div>

</body>

</html>

Vamos entender um pouco melhor, apesar dos comentários.  Quando fizermos ng-model estamos declarando uma variável, e quando dizemos {{ expresion }} estamos imprimindo o valor da variável. Se você já usou expression languague com JSF, por exemplo, é o mesmo conceito, porém com sintaxe diferente.  Mas observe que quando fizemos Hello {{ name }} ele busca a variável que está na function hello() que criamos no .js. Veja:

function hello($scope){

       $scope.name=”world AngularJS \O/”;      

}

 

O .js você pode colocar na raiz de webapps, ou dentro de um subdiretório, desde que você informe no arquivo .html onde está o seu .js.

O resultado será algo assim:

angularhelloresult

 

angularhelloresultdone

Simples? Show, né?  

Esse é o AngularJS. Esse post foi apenas uma pequena introdução prática sem entrar nos detalhes do framework. Para quem quiser estudar e se aprofundar basta passar no http://angularjs.org/ e se divertir.

No meu Github há exemplos de projetos que tenho feito com angularJS:  https://github.com/camilolopes

Abraços.