Image Image Image Image Image
Scroll to Top

Topo

Código

SWX Labs 06 – Python

Em 17, fev 2014 | Sem Comentários | Em Blog, Código, Destaques, Open Source, Python, SWX Labs | Por Mike Lopes

capa01

No SWX Labs 06 Mike, Vinicius e Tássio conversam com Rodrigo Amaral sobre Python.

Como surgiu a linguagem, qual sua evolução, diferenciais, onde ela é aplicada e como funciona a comunidade que divulga e dá suporte a uma das linguagens de programação que mais cresce e se credencia a ser o Java do futuro.

Ouça o podcast clicando no play, se preferir faça o download

Temas abordados

  • História do Python
  • Particularidades da Sintaxe
  • Ferramentas e aplicações
  • Mercado de trabalho
  • Comunidade e eventos sobre Python

Links

2º GDG Aracaju: Aplicações web com Python e Google App Engine

gdg-aju-python

Assine o feed do nosso podcast e não perca nenhum episódio: http://feeds.feedburner.com/SWXLabs

Se preferir, também estamos no Itunes Store

Gostou? Não gostou? Erramos algo? Sua opinião é muito importante para nós, por isso deixe seu comentário ou envie email para mike@swx.com.br

Tags | , , ,

SWX Direto das trincheiras 03 – Campus Party, Podcasts e Forum de Inovação tecnológica

Em 13, fev 2014 | 28 Comentários | Em Blog, CMS, Código, Destaques, JavaScript, NodeJs, Ruby, Vídeos, Wordpress | Por Mike Lopes

Neste SWX Direto das trincheiras trazemos as novidades que rolaram na SWX, se perdeu alguma coisa confira:

  • SWX Labs 03 – Editais de Inovação: http://bit.ly/SWXLabs03
    • Bate papo com Marcelo Dósea, sobre Editais de Inovação, sua importância e como se preparar para participar.
  •  SWX Labs 04 – Planejamento: http://bit.ly/SWXLabs04
    • Neste podcast Benhun, gerente de projetos de SWX, fala sobre planejamento. São debatidos conceitos e dicas de como preparar um bom planejamento.
  • 5 formas de utilizar o google alerts para alavancar seu negócio ou carreira: http://bit.ly/GoogleAlerts5Dicas
    • No blog do CIO Market tem dicas interessantes de como aproveitar uma grande ferramenta do google, o Alerts.
  • Model em Ruby on Rails – Parte 02: http://bit.ly/NGczin
    • Segunda parte do artigo explicando um aspecto da aplicação da arquitetura MVC com Ruby on Rails.
  • Uma introdução ao gulp: http://bit.ly/1cCsR4S
    • Saiba mais sobre esse automatizador de tarefas baseado no node.js
  • Desvendando os “Custom Post Types”: http://bit.ly/1iMneoz
    • Para iniciantes e intermediários em wordpress entenderem melhor como personalizar o back end de posts no wordpress.
  • SWX na Startup and Makers da Campus Party 2014: http://bit.ly/1bPGgmy
    • Confira como foi a participação da SWX na Campus Party 2014.
  •  1º Fórum de Inovação, Propriedade Intelectual e Transferência de Tecnologia do IFS (FIPITT) – http://bit.ly/1nwdZqf
    • A SWX participa deste fórum como case de sucesso. Se vc estiver em Aracaju no dia 18/02 apareça no IFS e veja a palestra de Vinicius.

Tags | , , , , , , , , ,

SWX Labs 05 – Projeto 14 Bis

Em 10, fev 2014 | Sem Comentários | Em Blog, Cloud Computing, Código, Destaques, Rails, Ruby, Sistemas, SWX Labs | Por Mike Lopes

BisOn

No SWX Labs 05 Mike, Ighor, Tássio e principalmente Vinicius , falam sobre o principal projeto em curso na SWX, o 14 BIS.

Saiba a proposta do projeto, como ele surgiu, conseguiu financiamento e está sendo desenvolvido. Além disso, conheça uma história que fala sobre empreendedorismo e dedicação, e o saiba um pouco mais do dia a dia de uma Startup e de como executar um projeto de software.

Ouça o podcast clicando no play, se preferir faça o download

Links

Assine o feed do nosso podcast e não perca nenhum episódio: http://feeds.feedburner.com/SWXLabs

Se preferir, também estamos no Itunes Store

Gostou? Não gostou? Erramos algo? Sua opinião é muito importante para nós, por isso deixe seu comentário ou envie email para mike@swx.com.br

Temas abordados:

  • O que é o 14 BIS

    • Definição

    • CIO Market

    • Vantagens

  • Histórico

    • Surgimento da SWX

    • Insight: Problemas de instalação e manutenção de software para pequenas e médias empresas

    • Inspiração: Loja de aplicativos (Google Play e Apple Store)

    • Solução: Loja de aplicativos que automatiza a instalação de softwares

    • Histórico do desenvolvimento do 14 BIS

  • Processo de desenvolvimento do 14 BIS

    • Seleção de desenvolvedores

    • Andamento do desenvolvimento dos módulos

    • Importância da parceria com a Universidade Federal de Sergipe

  • 14 BIS na prática

    • Como funciona para comprador e fornecedor de software

    • Diferenciais competitivos

  • O futuro do 14 BIS

    • Consolidação dos grupos de projeto

    • Aumento das opções de infraestrutura de nuvem

    • Transformação do CIO Market em plataforma (plataforma como serviço)

 

 

 

Tags | , , , , , ,

31

jan
2014

Sem Comentários

Em Blog
Código
JavaScript
NodeJs

Por Mike Lopes

Uma introdução ao gulp

Em 31, jan 2014 | Sem Comentários | Em Blog, Código, JavaScript, NodeJs | Por Mike Lopes

a84cbe09a6fc383b43833c60b3f2aa29

* Por João Paulo

Introdução:

Muitas tarefas são feitas manualmente de forma repetitiva, por exemplo, ao alterar certos arquivos de um site, é necessário fazer o upload para que possam ser acessados pela web; porém, para isso, é necessário abrir o cliente ftp, preencher os dados e conectar, depois selecionar os arquivos e enviar. Além de perder tempo, essas são tarefas chatas a serem feitas, então para isso existem “automátizadores” como o grunt e o gulp.

O gulp é um automatizador de tarefas desenvolvido em cima do nodejs, seu funcionamento será estudado nesse artigo.

Instalando:

Para instalar o gulp é necessário instalar o nodejs (no ubuntu, é só executar o comando #apt-get install nodejs).

Também, obviamente, é necessário instalar o gulp. O gulp é dividido em duas partes, o “gulp CLI” que é o aplicativo para ser executado na linha de comando e o gulp, a biblioteca pro nodejs.

  • Para instalar o CLI, execute: “npm -g install gulp” (npm é o gerenciador de pacotes do nodejs).

  • Para instalar a biblioteca:  “npm install –save-dev gulp”.

Estrutura básica:

O gulp foi desenvolvido sobre o nodejs, logo é necessário ter conhecimento de javascript para poder utilizá-lo.

A primeira coisa a ser feita é criar o arquivo “package.json”, é nesse arquivo que ficam as informações sobre o projeto, como nome, versão e quais bibliotecas estão sendo utilizadas. Outro arquivo importante é o “gulpfile.js”, é esse arquivo que será lido ao executar o gulp no console para executar as automatizações, logo é nele que ficarão nossos scripts.

O “package.json” pode ser criado na mão, porém o npm pode criá-lo pra você, para isso execute “npm init” e seguir as instruções (é possível deixar tudo em branco).

O “gulpfile.js” deverá ser criado a partir de algum editor de textos.

Para instalar um plugin usa-se: “npm install –save-dev <nome-do-plugin>”, por exemplo, o uglify “npm install –save-dev gulp-ufligy”.

Como o gulp foi escrito por cima do nodejs, um plugin do gulp é uma dependência do nodejs, logo o campo com a relação dos plugins instalados no “package.json” é o “dependencies”, assim outra forma de instalar as dependências (caso o “package.json” tenha sido criado manualmente) é colocá-las no campo “dependencies” e executar no console “npm install”. Para a relação dos plugins oficiais do gulp acesse: “http://gratimax.github.io/search-gulp-plugins/”

Ao instalar um plugin, é necessário definir ele no script também, para isso usa-se “require(‘plugin’)”, por exemplo, “var gulp = require(‘gulp’);” e nesse caso, para acessar os métodos do gulp “gulp.nome_do_método();”

O gulp possui poucos métodos, abaixo segue uma DESCRIÇÃO PRÁTICA do uso deles (as informações completas sobre o uso deles são encontradas na documentação):

  • gulp.src(globs): Define o arquivo ou a pasta que terá seus arquivos lidos. O parâmetro “globs” pode ser uma string ou um array, por exemplo, “./arquivos/*.js” ou “[./arquivos/arquivo1.js, ./arquivos/arquivo2.js, …]”
  • gulp.dest(path): Define a pasta de saída do processamento.  ex.: gulp.dest(“./pasta_de_saída”)
  • gulp.task(‘Nome_da_tarefa’, function(){ /* aqui fica seu código */ }): As tarefas são blocos de códigos que serão executados. ex.: gulp.task(‘enviar_por_ftp’, function{ /* aqui ficam as instruções de como enviar */ });
  • gulp.run(‘task1’, ‘task2′, … ,’taskN’): Esse método serve pra chamar outras tarefas do mesmo projeto.
  • gulp.watch(glob, tasks): Equivalente ao “run”, ele executa outras tarefas definidas no task, porém ele executa quando há alterações nos arquivos definidos no glob, ex.: gulp.watch(‘./teste/*’, [‘enviar_por_ftp’, ‘outra_tarefa’]); nesse exemplo se qualquer arquivo na pasta “teste” for alterado, ele executará as tarefas ‘enviar_por_ftp’ e ‘outra_tarefa’.

Para executar uma tarefa basta executar: “gulp <tarefa>”, por exemplo, “gulp enviar_por_ftp”. Caso exista a tarefa “default”, ela será executada simplemente com “gulp”, mas “gulp default” também funciona.

Exemplo:

No exemplo abaixo serão juntados todos os arquivos da pasta “entrada” e será criado um arquivo chamado “concatenados.txt” na pasta “saida”. Para isso será usado o plugin “gulp-concat”.

Primeiramente, é necessário instalar o nodejs (#apt-get install nodejs) e o gulp CLI (#npm -g install gulp).

Depois é necessário criar o projeto ($npm init), observe que o “package.json” foi criado; agora vamos instalar as bibliotecas do gulp e os plugins (npm install –save-dev gulp gulp-concat), observe que o “package.json” agora possui nas dependências “gulp” e “gulp-concat”.

O próximo passo é criar o script, para isso crie o arquivo “gulpfile.js” na pasta raiz do projeto com o script abaixo.

//Criada a variável 'gulp' que é a "instância" da biblioteca 'gulp'

var gulp = require('gulp');

//Criada a variável 'concat' que é a "instância" da biblioteca 'gulp-concat'

var concat = require('gulp-concat');

//Criada a tarefa 'default'

gulp.task('default', function(){

//São lidos todos os arquivos da pasta 'entrada'

gulp.src('./entrada/*')

//Os arquivos lidos são concatenados num arquivo chamado 'concatenados.txt'

.pipe(concat('concatenados.txt'))

//A saída gerada pelo concat é salva na pasta chamada 'saída'

.pipe(gulp.dest('./saida'));

});

 Para executar o script acima basta executar “gulp” (ou “gulp default”) no terminal.

Para informações sobre o gulp acesse: https://github.com/gulpjs/gulp/blob/master/docs/README.md

* João Paulo é estudante de Computação e estagiário da SWX

Tags | , ,

28

jan
2014

Sem Comentários

Em Blog
Código
PHP
Wordpress

Por Mike Lopes

Desvendando os “Custom Post Type” – Parte 01

Em 28, jan 2014 | Sem Comentários | Em Blog, Código, PHP, Wordpress | Por Mike Lopes

Por Eloi Morais de Matos

O que é?

Os Tipos Personalizados de Posts (Custom Post Type) são tipos de post que são criados, além dos fornecidos por padrão WordPress. Quando ativamos um tema ou um plugin às vezes encontramos novos tipos de post que foi colocado para suprir as necessecidades do desenvolvedor.

Onde usar?

São usados ​​em uma grande variedade de maneiras em todo o ecossistema WordPress. Sempre que você precisar de um tipo de conteúdo que é diferente dos tipos padrão, tenha em mente que é a hora de usar os tipos personalizados de post. Alguns exemplos de como eles são usados ​​são:

  • Produtos para um site de comércio eletrônico;

  • Depoimentos em portfolio;

  • Listagem para um site imobiliário;

  • Avaliações para um site de jogos

  • Eventos para um calendário de eventos;

  • Veículos para um site automotivo;

  • Filmes para uma locadora;

  • Livros para uma biblioteca.

Você pode criar um tipo de post para cada uma delas, Cada uma com seus próprios dados e taxonomias adicionais e, em seguida, registra-las utilizando o seu tema. Isso aumenta a flexibilidade do WordPress já que você não estará limitado aos tipos de conteúdo que vem por padrão nele.

Como criar?

Se você quiser escrever novos tipos de posts personalizados, você pode registra-lo no arquivo functions.php do seu tema, ou em um plugin. Neste você pode definir as propriedades do tipo de post e como ele age dentro do WordPress. O WordPress Codex tem um guia para os tipos personalizados de post com informações sobre codificação deles, mas deixarei aqui um código simples retirado do GenerateWP onde você pode personalizar mais ainda os novos tipos de posts. Veja abaixo:

// Register Custom Post Type
function custom_post_type() {

	$labels = array(
		'name'                => _x( 'Post Types', 'Post Type General Name', 'text_domain' ),
		'singular_name'       => _x( 'Post Type', 'Post Type Singular Name', 'text_domain' ),
		'menu_name'           => __( 'Post Type', 'text_domain' ),
		'parent_item_colon'   => __( 'Parent Item:', 'text_domain' ),
		'all_items'           => __( 'All Items', 'text_domain' ),
		'view_item'           => __( 'View Item', 'text_domain' ),
		'add_new_item'        => __( 'Add New Item', 'text_domain' ),
		'add_new'             => __( 'Add New', 'text_domain' ),
		'edit_item'           => __( 'Edit Item', 'text_domain' ),
		'update_item'         => __( 'Update Item', 'text_domain' ),
		'search_items'        => __( 'Search Item', 'text_domain' ),
		'not_found'           => __( 'Not found', 'text_domain' ),
		'not_found_in_trash'  => __( 'Not found in Trash', 'text_domain' ),
	);
	$args = array(
		'label'               => __( 'post_type', 'text_domain' ),
		'description'         => __( 'Post Type Description', 'text_domain' ),
		'labels'              => $labels,
		'supports'            => array( ),
		'taxonomies'          => array( 'category', 'post_tag' ),
		'hierarchical'        => false,
		'public'              => true,
		'show_ui'             => true,
		'show_in_menu'        => true,
		'show_in_nav_menus'   => true,
		'show_in_admin_bar'   => true,
		'menu_position'       => 5,
		'menu_icon'           => '',
		'can_export'          => true,
		'has_archive'         => true,
		'exclude_from_search' => false,
		'publicly_queryable'  => true,
		'capability_type'     => 'page',
	);
	register_post_type( 'post_type', $args );

}

// Hook into the 'init' action
add_action( 'init', 'custom_post_type', 0 );

Nos próximos artigos irei fazer um passo a passo completo para criação dos tipos personalizados de post comentando para que que serve cada uma das opções. Até a próxima!

*Eloi é desenvolvedor de Software na SWX

Imagem: Christopher Ross

Tags | ,

22

jan
2014

Sem Comentários

Em Blog
Código
Rails
Ruby

Por Mike Lopes

Model em Ruby on Rails – Parte 02

Em 22, jan 2014 | Sem Comentários | Em Blog, Código, Rails, Ruby | Por Mike Lopes

* Por João Paulo

Veja a parte 01

ruby-on-rails

Um model é uma classe que herda da classe ActiveRecord::Base e está associada a uma tabela.

O arquivo do model possui o nome da tabela em minúsculo no singular (“nomedatabela.rb”) e a classe o nome em CamelCase (“class NomeDaTabela”).

É possível criar o model manualmente, porém o Rails possui um generate que cria o model, o migration e a tabela dinamicamente. Funciona no seguinte formato:

rails g model <Model> <Campo1>:tipo <Campo2>:tipo <Campon>:tipo

 ex.: A tabela “produtos”, gerada anteriormente, poderia ser gerada da seguinte forma: será gerada a tabela, o model e a migration pra ela.

rails g model Produto name:string

 Nota: Caso a tabela já tenha sido criada, é necessário adicionar o parâmetro “–force” no generate para reexecutar a migration.

 _mvc

Para acessar um campo pelo controller é necessário criar os métodos que irão ler e escrever o campo, por exemplo, para um campo “nome” ser lido, tem que ser criado o método “nome” e para gravar deverá ser criado o método “nome=”.

class table1 < ActiveRecord::Base

def nome

self[:nome]

end

def nome=(novoNome)

self[:nome] = novoNome

end

end

 

 Nota: É possível usar attr_accessor, attr_reader e attr_writer.

 Para definir um relacionamento no model é necessário chamar o método com o nome do relacionamento (belongs_to, has_one, has_many, …) e o nome na tabela. Esse relacionamento será feito a partir do id. Ex.:

class table1 < ActiveRecord::Base

belongs_to :table2

end

 

relacionará o campo “table2_id” da “table1” com o campo “id” da “table2”.

 Relacionamentos:

  • belongs_to (pertence à): Define que um registro de um model está ligado a um registro de outro model e pertence a ele numa relação “um pra um”, por exemplo, em  uma tabela com reitores e outra com universidades, “um reitor pertence a uma universidade”, assim a tabela “universidade” deverá ter um campo “reitor_id”.
  • has_one (“contém”): Define que um registro model contém outro de outro model numa relação “um pra um” (o contrário de belongs_to), no exemplo do belongs_to, temos que uma “universidade contém um reitor”.
  • has_many (“contém muitos”): Define que um registro de um model contém muitos registros de outro model. Por exemplo, um cliente pode ir a uma loja comprar vários produtos, assim à relação será “cliente contém muitos produtos”, logo a tabela “produtos_vendidos” terá um campo “cliente_id”.
  • has_and_belongs_to_many (“contém e pertence a vários”): Define que vários registros de um model está associado a vários de outro model. Por exemplo, em um sistema de vendas, existe uma tabela “pedidos” que associa vários registros da tabela “produtos” a um da tabela “cliente”, pois um cliente compra vários produtos; porém, também associa vários da tabela “clientes” a um da tabela “produtos”, pois um produto é comprado por vários clientes.

 

Validações:

 Em um model é necessário validar se os dados são válidos antes de salvar no banco de dados, para validar é necessário definir o método no formato:

“validates :<campo>, <validação>”.

 ex.: O campo “nome” da tabela “table1” será obrigatório.

class table1 < ActiveRecord::Base

validates :nome, presence: true

end

Existem vários helpers para validação, como, por exemplo, garantir que apenas números são esperados:

class table1 < ActiveRecord::Base

validates :value, numerically: true

end

Para mais helpers acesse: http://edgeguides.rubyonrails.org/active_record_validations.html#validation-helpers

É possível definir mensagens para caso ocorra um erro na validação, ou seja, para quando um valor passado não estiver de acordo com a validação:

class table1 < ActiveRecord::Base

validates :nome, presence: true, :message => “O nome é obrigatório.”

end

É possível definir a validação para uma determinada ação (create, update, …):

class table1 < ActiveRecord::Base

validates :nome, presence: true, on: :update

end

 

Validações por métodos customizados:

class table1 < ActiveRecord::Base

validate :método, on: :create

 

def metodo

if (campo1 > 10)

erros.add(:value_error, “O número tem que ser maior que 10”)

end

end

 

Informações sobre validações: http://edgeguides.rubyonrails.org/active_record_validations.html#validation-helpers

Documentação completa: http://api.rubyonrails.org/

* João Paulo é estudante de Computação e estagiário da SWX

Tags | , , , ,

15

jan
2014

Sem Comentários

Em Código
Rails
Ruby

Por Mike Lopes

Model em Ruby on Rails – Parte 01

Em 15, jan 2014 | Sem Comentários | Em Código, Rails, Ruby | Por Mike Lopes

Por João Paulo*
ruby-on-rails

O model é o componente da arquitetura de software MVC que faz a comunicação com o banco de dados (acessar e editar o banco de dados), ou seja, é no model que ficam as regras de negócio. O Rails conta com uma biblioteca para o desenvolvimento dos models de forma rápida, segura e organizada, essa biblioteca é chamada de ActiveRecord. No Rails, o model faz referências a uma tabela no banco, logo se existir um model, existe uma tabela associada a ele (essa é a ideia básica, mas não uma regra, pois é possível ter um model não associado a uma tabela).

É possível criar uma tabela manualmente, porém para alterá-la é necessário alterar manualmente em cada máquina que estiver o projeto, o que torna um processo trabalhoso, então, com o objetivo de  resolver esse problema, o Rails possui o ActiveRecord::Migrations que uma classe do ActiveRecord que define a tabela de forma que cada alteração seja facilmente enviada a todas as máquinas com o projeto. O modelo abaixo é de uma migration (nome dado a classe que herda de ActiveRecord::Migrations) em que é criada uma tabela chamada “produtos” e um campo “nome”:

ActiveRecord

class CreateProductos < ActiveRecord::Migration
	def change
		create table :produtos do |t|
			t.string :nome
		end
	end
end

O método change suporta:

  • add_column

  • add_index

  • add_reference

  • add_timestamps

  • create_table

  • create_join_table

  • drop_table (must supply a block)

  • drop_join_table (must supply a block)

  • remove_timestamps

  • rename_column

  • rename_index

  • remove_reference

  • rename_table

As migrations ficam salvas como: db/migrate/<timestamp>_<migration>.rb.

O comando “rake db:migrate” executa, no console, as migrations que ainda não foram executadas.

Para mais informações sobre migrations: http://guides.rubyonrails.org/migrations.html

É possível gerar, de forma dinâmica, uma migration a partir do console.

Abaixo estão apresentados alguns comandos:

Criar tabela:

rails g migration Create<Tabela> < campo1>:tipo <campo2>:tipo <campon>:tipo

Ex.: será criada uma migration chamada “CreateProducts” com o nome “products”:

rails g migration CreateProducts name:string

Adicionar coluna em uma tabela (depois da tabela ter sido criada):

rails g migration Add<Coluna>To<Tabela> <nome_da_coluna>:tipo

Ex.: será criada uma migration “AddRefToProducts” que acrescentará uma coluna chamada “ref” a tabela “products”:

rails g migration AddRefToProducts ref:string

Nota: é possível usar “rails generate…” ou simplesmente “rails g…”, pois eles são equivalentes.

Para mais informações sobre o rails generate acesse: http://guides.rubyonrails.org/migrations.html#creating-a-migration

* João Paulo é estudante de Computação e estagiário da SWX

Tags | , ,

10

set
2012

Sem Comentários

Em Arquitetura
Java

Por Vinicius AC

Entenda os MVCs e os frameworks Action e Component Based

Em 10, set 2012 | Sem Comentários | Em Arquitetura, Java | Por Vinicius AC

É muito comum encontrar desenvolvedores que aprendem componentes do JSF como o Primefaces e o Richfaces e gostariam de usá-las em seus projetos que utilizam frameworks web como o Spring MVC, Struts e VRaptor, porém, isso não é possível. Por que? Entenda os diferentes funcionamentos do MVC, aprenda como funcionam os frameworks e tire para sempre essa e outras dúvidas!

Um @Controller do SpringMVC

Quando trabalhamos com o SpringMVC, tratamos as requisições enviadas pelos usuários dentro de classes conhecidas como Controller. É uma classe simples, anotada com @Controller onde implementamos métodos que tratam a requisição para uma determinada URL, indicada através da anotação @RequestMapping.

@Controller
public class ProdutosController {
   @RequestMapping("adicionaProduto")
   public void adiciona(Produto p, HttpServletRequest req) {
      // pega o produto recebido no request e grava no banco de dados
   }
}

Quando a requisição é submetida para o endereço adicionaProduto e envia os parâmetros adequados para preencher o objeto Produto, ele é gravado no banco. Porém, precisamos devolver uma resposta para o usuário, que deverá conter o nome do produto adicionado, então podemos disponibilizar um atributo ao JSP através do request que recebemos no nosso método.

@RequestMapping("adicionaProduto")
public void adiciona(Produto p, HttpServletRequest req) {
   // pega o produto recebido no request e grava no banco de dados
   req.setAttribute("nome", p.getNome());
}

Então logo após a execução da ação, indicamos para o SpringMVC que o produto-adicionado.jspdeve ser mostrado. Para isso, basta fazermos nosso método retornar uma String com o nome do JSP.

@RequestMapping("adicionaProduto")
public String adiciona(Produto p) {
   // pega o produto recebido no request e grava no banco de dados
   req.setAttribute("nome", p.getNome());
   return "produto-adicionado";
}

Dessa forma, após a execução, o JSP será exibido para o usuário.

<h2>Produto ${nome} adicionado com sucesso</h2>

Onde está o MVC aí?

O mais importante nisso tudo, é notar que existe uma separação clara entre as responsabilidades no tratamento da requisição.

Quando um usuário submete uma requisição para o endereçohttp://localhost:8080/projeto/adicionaProduto, o SpringMVC a recebe e descobre, de alguma maneira, qual é o @Controller e qual método deve ser responsável por tratá-la. Nesse caso, o SpringMVC está fazendo o papel do Front Controller, que delega a responsabilidade para umController secundário, no caso a classe ProdutosController e o método adiciona. Chamamos o responsável por esse trabalho de Controlador.

Os passos do controlador

O próximo passo é a execução das regras de negócio, que podem envolver a execução da persistência das informações, validações e outras tarefas que dizem respeito aos requisitos funcionais da aplicação. Chamamos as classes que fazem esse trabalho de Modelo.

@Controller invoca o Modelo para realizar as regras de negócio

Após a execução do Modelo e de todas as as regras de negócio, o JSP contendo a resposta adequada deve ser exibido para o usuário. Nesse ponto, temos as regras de visualização implementadas, como por exemplo, exibir as informações em vermelho, dada alguma característica. Essas regras ficam todas centralizadas no JSP, que nesse caso, faz um papel que chamamos de Visão, ou seja, é o responsável pelo que o usuário irá visualizar como resultado.

@Controller indica qual visão será devolvida para o usuário

Juntando tudo o que vimos, temos o MVC – Modelo, Visão e Controlador, cujo objetivo é separar as responsabilidades da aplicação, fazendo com que tenhamos um código mais fácil de ser mantido.

Os frameworks Action Based e o MVC Push

….

Saiba mais em: http://blog.caelum.com.br/entenda-os-mvcs-e-os-frameworks-action-e-component-based/

Fonte: Adriano Almeida / Caelum

Tags | , , , , ,

18

jul
2012

Sem Comentários

Em HTML

Por Vinicius AC

Evitando erros comuns de HTML5

Em 18, jul 2012 | Sem Comentários | Em HTML | Por Vinicius AC

Fonte: DPW

Com o advento da HTML5, muitos erros comuns estão ocorrendo devido a equívocos dos desenvolvedores. Leia este artigo e saiba como evitar erros comuns de HTML5.

Este artigo é baseado no post Avoiding common HTML5 mistakes do HTML5 Doctor.

1. Não use section como contêiner para estilização

Um dos problemas mais comuns que está acontecendo em relação à implementação da HTML5 é os desenvolvedores, arbitrariamente, estarem substituindo <div> por <section> para usar na estilização. No HTML4 ou XHTML, é normal um código como:

<div id="wrapper">
    <div id="header">
        <h1>Título primário</h1>
    </div>

    <div id="main">
        <!-- conteúdo -->
    </div>

    <div id="secondary">
        <!-- conteúdo -->
    </div>

    <div id="footer">
        <!-- conteúdo -->
    </div>
</div>

Então, sem nenhum motivo plausível, alguns estão alterando seu código para:

<section id="wrapper">
    <header>
        <h1>Título primário</h1>
    </header>

    <section id="main">
        <!-- conteúdo -->
    </section>

    <section id="secondary">
        <!-- conteúdo -->
    </section>

    <footer>
        <!-- conteúdo -->
    </footer>
</section>

E isso, apesar de poder estar certo, na grande maioria dos casos, está errado… Se é preciso um elemento somente para estilização, não faz nenhum sentido deixar de usar <div>; o elemento <section> não foi criado para isso! Segundo sua documentação,

O elemento <section> representa um documento genérico ou seção de aplicação[…]. O elemento <section> não é um elemento contêiner genérico. Quando um elemento é necessário para fins de estilo ou como uma conveniência para execução de scripts, os autores são incentivados a utilizar o elemento <div>.

Ou seja, as indicações de uso do <section> para 99% dos casos são:

  • Não usá-lo apenas como “gancho” para estilos ou scripts (para isso, já existe <div>)
  • Não usá-lo se o <article><aside> ou <nav> forem mais apropriados
  • Não usá-lo a menos que exista, naturalmente, um título no início da seção

2. Só use header e hgroup quando forem necessários

Não faz sentindo escrever HTML de forma a ferir a semântica, certo? Infelizmente, não é difícil encontrar elementos <header> e <hgroup> sendo usados de forma inapropriada. Procure se informar mais a respeito da função deles, mas, resumindo:

  • <header> representa um grupo introdutório e/ou navegacional e, usualmente, contém o(s) título(s) de <section>
  • <hgroup> agrupa um conjunto de elentos <h1><h6> quando o título de uma seção tem vários níveis, tais como subtítulos, títulos alternativos, etc

2.1. Uso excessivo de header

O elemento <header> pode ser usado quantas vezes forem necessários num documento, o que está causando confusões do tipo:

<article>
    <header>
        <h1>Título primário</h1>
    </header>

    <!-- conteúdo -->
</article>

Se o <header> contém somente um elemento de título, na verdade, ele não precisa ser usado. O elemento <artcile> já garante que o título vai constar no outline do documento, e, porque <header> não contém múltiplos elementos (como consta em sua definição), por que escrever código desnecessário? A solução é simples:

<article>
    <h1>Título primário</h1>
    <!-- conteúdo -->
</article>

2.2. Uso incorreto de hgroup

Basicamente, não se deve usar <hgroup> com <header> quando:

  • Há somente 1 elemento-descendente de título
  • <hgroup> funcionaria bem por conta própria (ou seja, sem <header>)

O primeiro problema pode ser visto no código:

<header>
    <hgroup>
        <h1>Título primário</h1>
    </hgroup>

    <!-- conteúdo -->
</header>

No caso, deve-se, simplesmente, remover o elemento <hgroup>:

<header>
    <h1>Título primário</h1>
    <!-- conteúdo -->
</header>

O segundo problema é outro caso de incluir o elemento quando ele não se faz necessário:

<header>
    <hgroup>
        <h1>Título primário</h1>
        <h1>Título secundário</h1>
    </hgroup>
</header>

Se não há elementos adicionais dentro de <header> (isto é, irmãos de <hgroup>), basta remover o <header>:

<hgroup>
    <h1>Título primário</h1>
    <h1>Título secundário</h1>
</hgroup>

Com mais de 40 novos elementos (no dia da publicação deste artigo), não é incomum haver dúvidas e erros de HTML5 na hora da utilização de alguns destes. Infelizmente, ainda é o caso com o elemento <nav>Como consta em sua especificação,

Nem todos os grupos de links em uma página precisam estar contidos em um elemento <nav> – o elemento se destina, principalmente, a seções que consistem em blocos de navegação principal. (Grifo nosso)

Atenção ao grifo “blocos de navegação principal” que, apesar de ser aberto a algumas interpretações, identifica-se mais com:

  • Navegação primária
  • Navegação secundária
  • Navegação in page (dentro de um artigo longo, por exemplo)

Como diretivas gerais (e seguindo a lógica contida na especificação), não se aplica o elemento <nav> a:

  • Controles de paginação
  • Social links
  • Categorias e Tags (de um artigo de blog, por exemplo)
  • Navegação terciária
  • Rodapés muito elaborados

Nos momentos de dúvida ao usar <nav>, pergunte-se a si mesmo: “Essa é uma navegação principal?”. Para ajudar a responder, considere as seguintes “regrinhas”:

  • Não use <nav> a menos que você pense que <section> também seria apropriado com <hx>
  • Você adicionaria um link “Pular para o conteúdo” por questões de acessibilidade?

Se a resposta para essas perguntas for “não”, então, provavelmente, não se trata de um <nav>.

4. Erros comuns com o elemento figure

4.1. Nem toda imagem é figure

Os novos elementos não foram criados para que os desenvolvedores tivesse trabalho de escrever código a mais. Pensar isso é um erro comum de HTML5. Algumas pessoas, ao “atualizarem” seus sites para HTML5, colocam o elemento <figure> em todas as imagens! Fazer isso não serve pra nada e a pessoa só está aumentando o próprio trabalho…

A especificação define <figure> como

algum conteúdo de fluxo, opcionalmente com um <figcaption>, que é auto-contido e, tipicamente, referido como uma unidade única a partir do fluxo principal do documento.

E é aí que reside a beleza do elemento <figure>: ele pode ser afastado do conteúdo principal (para uma barra lateral, por exemplo) sem afetar o fluxo do documento.

Se se tratar de uma imagem puramente de apresentação, que não é referenciada em outras partes do documento, definitivamente não se trata de um <figure>. Outros casos de uso variam, mas, pra começar, pergunte-se a si mesmo: “Esta imagem é necessária para compreender o contexto atual?”. Se não, provavelmente não é um <figure> (pode ser um <aside>, talvez). Se sim, pergunte-se novamente: “Eu poderia movê-lo para um apêndice?”. Se a resposta para ambas as perguntas for “sim”, então, provavelmente, trata-se de um <figure>.

4.2. O logo não é um figure

Os mesmos princípios mostrados acima também se aplicam ao logo do site. Não é tão incomum se ver por esses dias códigos parecidos com:

<header>
    <h1>
        <figure>
            <img src="/img/logo.png" alt="Nome do site" class="hide">
        </figure>

        Nome do site
    </h1>
</header>

Isso, simplesmente, não está certo… E não estou dizendo sobre o fato de o logo estar dentro de um <h1> – isso, por si só, renderia um artigo inteiro. A real questão é o abuso do elemento <figure>! No caso, a marcação poderia, simplesmente, ser feita assim:

<header>
    <h1>Nome do site</h1>
</header>

4.3. figure pode ser mais que uma imagem

Ao contrário do que muitos pensam, <figure> pode ser áudio, vídeo, um gráfico (em SVG, por exemplo), uma citação, uma tabela, um bloco de código ou qualquer combinação destes e muito mais!

Não se limite a usar <figure> somente em imagens. Nosso trabalho como aficionados por padrões web também é de descrever com precisão nosso conteúdo através de uma correta marcação.

5. Não inclua atributos de tipo desnecessariamente

Continue lendo em: http://desenvolvimentoparaweb.com/html/evitando-erros-html5/

18

jul
2012

Sem Comentários

Em HTML
Ipad

Por Vinicius AC

projetando para o ipad

Em 18, jul 2012 | Sem Comentários | Em HTML, Ipad | Por Vinicius AC

Fonte: http://www.8164.org/designing-for-the-ipad/

por Jin, 04-12-10
I decided a while back that I wasn’t going to get an iPad. Instead, I’d wait for the second generation iPad next year. This has been my approach when it comes to new Apple products. Yes, I’m scared of the early adopter regret. As the launch date neared, my mind changed a bit. My wife is an avid book reader, and I thought it’d be a perfect device for her. But more importantly, I think the iPad will have a significant impact on how us web designers approach interaction design for this medium and the coding behind it. I need one to tinker with.

I bought one on Saturday. I love it. I won’t get into the philosophical aspects that have been debated by many recently, instead I’ll focus the rest of this post on web design/development for iPad’s Mobile Safari. Creating web sites that look and behave consistently on different browsers and versions have been the bane of us web designers’ existence since Mosaic/Netscape days. While I’m happy with the experience surfing on the iPad, I can’t help but to think, “argh another browser.” Even though Mobile Safari on the iPad is identical to iPhone’s, but the term “optimized for mobile” means differently for each device. The iPhone optimized sites are often minified version of the desktop sites, for speed and better use of screen real estate. The iPad’s browser offers the desktop experience, so it should be treated as one. I divided the rest of this post to two sections: iPad ready and iPad optimized, depending on how far you want to customize your site for iPad.

ipad ready

In my opinion, for a site to be “iPad ready” simply means that all the content and functionality are accessible via the iPad. Sites that were written according to the web standard are in a good shape already. A few things to consider:

  • Flash – It’s unlikely that Apple will allow Flash on its mobile devices anytime soon, or ever. Sites that are done entirely in Flash will have to have a HTML alternative(as they should anyways). I embed Youtube and Vimeo videos on this site sometimes. Even though they both support HTML5 <video> on their sites, unfortunately as of now they do not generate embed codes in HTML5. I recently discovered Video for Everyone by Kroc Camen. It’s a great code snippet that plays hosted or embedded videos as HTML5, with Flash/Quicktime as fallback. html5media also has a Javascript file that enables <video> and <audio> for major browsers.P.S. I can’t figure out how this embedded Youtube video is being displayed properly without any HTML5 embedding code. Please let me know if you know the answer.
  • Mouse Events – Make sure your site’s functionality does not rely purely on mouse events (mousemove, mouseover, mouseout, and CSS :hover) . Mobile Safari can trigger onMouseover, but it involves quite a bit of timing and effort on the user. You need to press down on the element that has the onMouseOver event and release fairly fast. To make it easier for the user, either remove unnecessary mouse events or have a visible link that reveals the hidden elements. A good example of inaccessible functionality is twitter’s web interface. You cannot hover therefore you lose the ability to retweet or reply.
  • Scrolling Content – The default one-finger swipe on iPhone/iPad triggers window.scroll(). Two-finger swipe has the same effect as the mouse scroll wheel. Not a lot of users may know this, therefore I think it’s best not to have content in scrolling in fixed sized block elements such as <div>s. The Safari Reference Library has good documentation on handling events.
  • Fixed Positioning – In short, don’t use it:

    Safari on iPad and Safari on iPhone do not have resizable windows. In Safari on iPhone and iPad, the window size is set to the size of the screen (minus Safari user interface controls), and cannot be changed by the user. To move around a webpage, the user changes the zoom level and position of the viewport as they double tap or pinch to zoom in or out, or by touching and dragging to pan the page. As a user changes the zoom level and position of the viewport they are doing so within a viewable content area of fixed size (that is, the window). This means that webpage elements that have their position “fixed” to the viewport can end up outside the viewable content area, offscreen.

    But if you must, Richard Herrera has a work around.

  • contenteditable – Mobile Safari currently does not support contenteditable attribute. Use a styledtextarea instead.
  • Disabling Cut/Copy/Paste Dialog – Pressing down on a text block or image brings up the Cut/Copy/Paste dialog box by default. Sometimes this behavior is not desired. For example, when pressing the top link of a navigation menu. To disable this, use -webkit-user-select: none.

ipad optimized

Fortunately, Safari is one of the leading browsers to support HTML5 and CSS3. If you want to take advantage of all iPad’s mobile Safari has to offer, here is some useful info:

  • User-agent StringMozilla/5.0(iPad; U; CPU iPhone OS 3_2 like Mac OS X; en-us) AppleWebKit/531.21.10 (KHTML, like Gecko) Version/4.0.4 Mobile/7B314 Safari/531.21.10

    David Walsh’s recent post shows how to detect iPad using Javascript, PHP and .htaccess redirection.

  • Media Query – In a way, designing for iPad is a bit easier since the screen is fixed to two sizes(portrait and landscape). We can take advantage of this by using Media Query.<link rel="stylesheet" media="all and (orientation:portrait)" href="portrait.css">
    <link rel="stylesheet" media="all and (orientation:landscape)" href="landscape.css">

    Please keep in mind, just because you can, doesn’t mean you have to. I don’t recommend making the two sets of styles drastically different from each other because it’d make the users relearn the UI. One case where I can see it’d be useful is when in portrait mode, show only the main content of the site; when in landscape, display more meta info. For example, on a blog site, show just the post body in portrait, and unhide the meta navigation, Ads blocks when in landscape.

    Jason Grigsby has a simple demo page to display different CSS styling depending on the orientation.

  • Format Detection – On iPhone, Safari automatically renders telephone numbers as a link to call. On the iPad the default action is to add the number phone to Contacts. You can disable this by:<meta name="format-detection" content="telephone=no">
  • Viewport setting – Do not use hard-coded pixel for view port dimensions. Use device-width instead.<meta name="viewport" content="width=device-width" />
  • Disable Automatic Format – Automatic Correction and Automatic Capitalization are default behaviorsfor text input. But sometimes you may not want inputs to be auto formatted. For example, inputting user name and passwords. To disable them:<input type="password" autocorrect="off" autocapitalize="off">
    <textarea rows="4" cols="50" autocapitalize="off"> </textarea">
  • Keyboard Types – You can make make it easier for the users by presenting content appropriate keyboards by using the new HTML5 attributes:Text: <input type="text" />
    Telephone: <input type="tel" /> 
    URL: <input type="url" /> 
    Email: <input type="email" /> 
    Zip Code: <input type="text" pattern="[0-9]*" />
  • Multi-Touch Event Handling – You can bind a touch event to mimic any other event. For example, make one finger swipe to mimic a two finger swipe on a DOM object. There are cases where you may want to override the defaults. For example, wouldn’t it be nice if you can swipe navigate an Image/content slider box than having to press the next/prev links? If you’re interested, you may find these JQuery plugins helpful: jQuery SwipeMultiswipe and JQTouch.

 

 

Tags | , , ,

Criando uma aplicação com o qooxdoo

Em 09, jul 2012 | Sem Comentários | Em Código, JavaScript, Open Source | Por eloi

O qooxdoo é um framework javascript universal usado para criar aplicações interativas, aplicativos para dispositivos móveis, aplicações web single-page, entre outros.

Irei repassar aqui um tutorial da própria qooxdoo para criar uma pequena aplicação web single-page contendo um cliente do twitter onde o usuário possa ler tweets públicos e poder postar tweets também.

No tutorial estarei utilizando o windows 7.

Primeiro passo é baixar o python para poder usar a poderosa ferramenta de gerar aplicações.

Link: http://www.activestate.com/activepython/downloads

Agora é só baixar a SDK do qooxdoo.

Link: http://downloads.sourceforge.net/qooxdoo/qooxdoo-2.0.1-sdk.zip

Instale o python, após a instalação extraia a sdk e coloque em uma pasta de sua preferência, aqui coloquei em C:\qooxdoo-2.0.1-sdk. Antes de começarmos a criar nossa aplicação vamos colocar o python na lista de variáveis de ambiente do windows.

Abra o cmd e digite o comando set PATH=C:\Python27; %PATH% sem aspas, onde C:\Python27 é o diretório de instalação do python.

Para criar uma aplicação é muito simples basta rodar o script create-application.py localizado em tool/bin na pasta da SDK, ainda no cmd digite: C:\qooxdoo-2.0.1-sdk\tool\bin\create-application.py –name=twitter

Isto irá criar uma aplicação chamada twitter contendo toda a estrutura de diretórios e configurações necessárias para o funcionamento da mesma, agora basta executar o comando cd twitter e entrar na pasta da aplicação agora digitando o comando generate.py para gerar os scripts de sua aplicação.

Depois de gerar os scripts, crie na pasta source/class/twitter um arquivo chamado MainWindow.js e dentro deste arquivo escreva o seguinte código.

qx.Class.define("twitter.MainWindow",
{
  extend : qx.ui.window.Window,

    construct : function()
    {
      this.base(arguments, "twitter");
    }
});

O que acabamos de fazer com esse código foi definir uma classe chamada “twitter.MainWindow” que extende da classe Window do qooxdo, o construtor da classe sobrescreve o construtor da super-classe  passando como parâmetro o título da janela, no caso “twitter”. Salve este arquivo  e abra o Application.js e abaixo do bloco de comentário coloque o seguinte código.

var main = new twitter.MainWindow();
main.open();

Nós apenas instânciamos nossa classe MainWindow e executamos o método open. Antes de testarmos nossa aplicação no navegador devemos gerar mais uma vez os scripts, já que estamos utilizando a classe Window do qooxdoo como dependência, então execute mais uma vez o comando generate.py no cmd e abra o arquivo index.html para visulaizar a aplicação no navegador. Você deve ver algo parecido com isto:

Vamos agora fazer algumas alterações na interface gráfica da nossa janela, ainda no Application.js acrescente este código:

main.moveTo(50, 30);

movemos nossa janela para uma nova localização. Voltando agora para o arquivo MainWindow.js coloque o seguinte código no construtor da janela:

//Esconder os botões da janela
this.setShowClose(false);
this.setShowMaximize(false);
this.setShowMinimize(false);

// ajustar o tamanho da janela
this.setWidth(250);
this.setHeight(300);

Atualize a página e veja as mudanças. Abaixo coloque o seguinte código:

// add o layout
var layout = new qx.ui.layout.Grid(0, 0);
this.setLayout(layout);

// toolbar
var toolbar = new qx.ui.toolbar.ToolBar();
this.add(toolbar, {row: 0, column: 0, colSpan: 2});

// lista
var list = new qx.ui.form.List();
this.add(list, {row: 1, column: 0, colSpan: 2});

this.setContentPadding(0);
layout.setRowFlex(1, 1);
layout.setColumnFlex(0, 1);

// Botão recarregar
var reloadButton = new qx.ui.toolbar.Button("Recarregar");
toolbar.add(reloadButton);

// textarea
var textarea = new qx.ui.form.TextArea();
this.add(textarea, {row: 2, column: 0});

// Botão postar
var postButton = new qx.ui.form.Button("Postar");
this.add(postButton, {row: 2, column: 1});

reloadButton.setToolTipText("Recarregar os tweets.");
textarea.setPlaceholder("Digite sua mensagem aqui...");
postButton.setToolTipText("´");

Na linha 2 criamos um layout do tipo grid e setamos ele em nossa janela, na linha 6 criamos uma toolbar e adicionamos ela a nossa janela já preparada para receber os componentes e ajusta-los em forma de grade, mesma coisa com a lista da linha 10. Na linha 13 setamos o padding da janela no valor 0, já as linhas 14 e 15 servem para deixar a lista flexível. Na linha 18 é adicionado um botão na toolbar para recarregar os tweets e nas linhas seguintes são adicionados um textarea e outro botão à janela, nas linhas finais são dados alguns toques para finalizar a nossa janela como mostrar pra que serve o botão quando o mouse fica sobre ele.

No final do construtor acrescente este código:

event : 
 {
	"reload" : "qx.event.type.Event",
	"post"   : "qx.event.type.Data"
 }

E abaixo de postButton.setToolTipText(“Poste esta mensagem no twitter.”); coloque:

reloadButton.addListener("execute", function() {
	this.fireEvent("reload");
}, this);
postButton.addListener("execute", function() {
	this.fireDataEvent("post", textarea.getValue());
}, this);

Até agora nosso arquivo MainWindow.js está assim:

qx.Class.define("twitter.MainWindow",
{
  extend : qx.ui.window.Window,

  construct : function()
  {
    this.base(arguments, "twitter", "twitter/t_small-c.png");

    // hide the window buttons
    this.setShowClose(false);
    this.setShowMaximize(false);
    this.setShowMinimize(false);

    // adjust size
    this.setWidth(250);
    this.setHeight(300);

    // add the layout
    var layout = new qx.ui.layout.Grid(0, 0);
    layout.setRowFlex(1, 1);
    layout.setColumnFlex(0, 1);
    this.setLayout(layout);
    this.setContentPadding(0);

    // toolbar
    var toolbar = new qx.ui.toolbar.ToolBar();
    this.add(toolbar, {row: 0, column: 0, colSpan: 2});

    // reload button
    var reloadButton = new qx.ui.toolbar.Button("Reload");
    toolbar.add(reloadButton);
    reloadButton.setToolTipText("Reload the tweets.");
    reloadButton.addListener("execute", function() {
      this.fireEvent("reload");
    }, this);

    // list
    var list = new qx.ui.form.List();
    this.add(list, {row: 1, column: 0, colSpan: 2});

    // textarea
    var textarea = new qx.ui.form.TextArea();
    this.add(textarea, {row: 2, column: 0});
    textarea.setPlaceholder("Enter your message here...");
    textarea.addListener("input", function(e) {
      var value = e.getData();
      postButton.setEnabled(value.length < 140 && value.length > 0);
    }, this);

    // post button
    var postButton = new qx.ui.form.Button("Post");
    this.add(postButton, {row: 2, column: 1});
    postButton.setToolTipText("Post this message on twitter.");
    postButton.addListener("execute", function() {
      this.fireDataEvent("post", textarea.getValue());
    }, this);
    postButton.setWidth(60);
    postButton.setEnabled(false);
  },

  events :
  {
    "reload" : "qx.event.type.Event",
    "post" : "qx.event.type.Data"
  }
});

Vamos agora para nosso arquivo Application.js e escrever este código:

main.addListener("reload", function() {
	this.debug("reload");
}, this);

main.addListener("post", function(e) {
	this.debug("post: " + e.getData());
}, this);

Até agora nosso arquivo Application.js está desta forma:

/* ************************************************************************

Copyright:

License:

Authors:

************************************************************************ */

/* ************************************************************************

#asset(twitter/*)

************************************************************************ */

/**
* This is the main application class of your custom application "twitter"
*/
qx.Class.define("twitter.Application",
{
  extend : qx.application.Standalone,

  /*
*****************************************************************************
MEMBERS
*****************************************************************************
*/

  members :
  {
    /**
* This method contains the initial application code and gets called
* during startup of the application
*
* @lint ignoreDeprecated(alert)
*/
    main : function()
    {
      // Call super class
      this.base(arguments);

      // Enable logging in debug variant
      if (qx.core.Environment.get("qx.debug"))
      {
        // support native logging capabilities, e.g. Firebug for Firefox
        qx.log.appender.Native;
        // support additional cross-browser console. Press F7 to toggle visibility
        qx.log.appender.Console;
      }

      /*
-------------------------------------------------------------------------
Below is your actual application code...
-------------------------------------------------------------------------
*/

      var main = new twitter.MainWindow();
      main.moveTo(50, 30);
      main.open();

      main.addListener("reload", function() {
        this.debug("reload");
      }, this);

      main.addListener("post", function(e) {
        this.debug("post: " + e.getData());
      }, this);
    }
  }
});

Gere mais uma vez os scripts e veja como está a aplicação, ela deve está parecida com esta imagem:

Agora vamos dar início a interação com o twitter, crie outro arquivo na mesma pasta que Application.js e MainWindow.js chamado de TwitterService e inicialmente escreva o seguinte código:

qx.Class.define("twitter.TwitterService",
{
  extend : qx.core.Object,
  members :
  {
  }
});

Diferente da classe MainWindow, esta não precisa extender de uma classe complexa como a Window, ela extende da classe Object que é uma classe simples. Acrescente este código antes de members:

properties : {
    tweets : {
      nullable: true,
      event: "changeTweets"
    }
  },

  events : {
    "postOk" : "qx.event.type.Event"
  },

E dentro de members o seguinte código:

__store : null,

    fetchTweets : function() {
      if (this.__store == null) {
        var url = "http://api.twitter.com/1/statuses/public_timeline.json";
        this.__store = new qx.data.store.Jsonp(url, null, "callback");
        this.__store.bind("model", this, "tweets");
      } else {
        this.__store.reload();
      }
    },

    post : function(message)
      window.open("http://twitter.com/?status=" + encodeURIComponent(message));
    }
  }

Aqui em cima criamos uma propriedade chamada tweets, que pode ser nulo e possui um evento chamado “changeTweets“. Criamos também um evento chamdo “postOk” do tipo “qx.event.type.Event” além dos membros, um atributo privado chamado “__store” (dois “__” fazem com que o atributo torne-se privado) e dois métodos o fetchTweets e o post, fetchTweets responsável pela captura de tweets públicos do twitter e post por postar o conteúdo no twitter.

Vamos voltar agora ao nosso arquivo Application.js e criar uma instância da nossa classe TwitterService e digite o seguinte código:

var service = new twitter.TwitterService();

E troque este trecho de código:

main.addListener("reload", function() {
	this.debug("reload");
}, this);

Por esse:

main.addListener("reload", function() {
  service.fetchTweets();
}, this);

E este:

main.addListener("post", function(e) {
	this.debug("post: " + e.getData());
}, this);

Por este:

main.addListener("post", function(e) {
        service.post(e.getData());
}, this);

Vamos agora para o arquivo MainWindow.js e criar um acessor para a lista, então troque onde tem var list = new qx.ui.form.List();por:

this.__list = new qx.ui.form.List();

E onde estiver list trocar por this.__list, faça o mesmo para textarea. Ainda no mesmo arquivo abaixo de events crie dois membros o __list e o __textarea ficando assim:

events :
  {
    "reload" : "qx.event.type.Event",
    "post" : "qx.event.type.Data"
  },

  members : {
    __list : null,
    __textarea : null,

Ainda dentro de members crie duas funções a getList e a clearPostMessage com o seguinte conteúdo:

getList : function() {
      return this.__list;
    },

    clearPostMessage : function() {
      this.__textarea.setValue(null);
    }

O nosso arquivo MainWindow agora está assim:

qx.Class.define("twitter.MainWindow",
{
  extend : qx.ui.window.Window,

  construct : function()
  {
    this.base(arguments, "twitter", "twitter/t_small-c.png");

    // hide the window buttons
    this.setShowClose(false);
    this.setShowMaximize(false);
    this.setShowMinimize(false);

    // adjust size
    this.setWidth(250);
    this.setHeight(300);

    // add the layout
    var layout = new qx.ui.layout.Grid(0, 0);
    layout.setRowFlex(1, 1);
    layout.setColumnFlex(0, 1);
    this.setLayout(layout);
    this.setContentPadding(0);

    // toolbar
    var toolbar = new qx.ui.toolbar.ToolBar();
    this.add(toolbar, {row: 0, column: 0, colSpan: 2});

    // reload button
    var reloadButton = new qx.ui.toolbar.Button("Reload");
    toolbar.add(reloadButton);
    reloadButton.setToolTipText("Reload the tweets.");
    reloadButton.addListener("execute", function() {
      this.fireEvent("reload");
    }, this);

    // list
    this.__list = new qx.ui.form.List();
    this.add(this.__list, {row: 1, column: 0, colSpan: 2});

    // textarea
    this.__textarea = new qx.ui.form.TextArea();
    this.add(this.__textarea, {row: 2, column: 0});
    this.__textarea.setPlaceholder("Enter your message here...");
    this.__textarea.addListener("input", function(e) {
      var value = e.getData();
      postButton.setEnabled(value.length < 140 && value.length > 0);
    }, this);

    // post button
    var postButton = new qx.ui.form.Button("Post");
    this.add(postButton, {row: 2, column: 1});
    postButton.setToolTipText("Post this message on twitter.");
    postButton.addListener("execute", function() {
      this.fireDataEvent("post", this.__textarea.getValue());
    }, this);
    postButton.setWidth(60);
    postButton.setEnabled(false);
  },

  events :
  {
    "reload" : "qx.event.type.Event",
    "post" : "qx.event.type.Data"
  },

  members : {
    __list : null,
    __textarea : null,

    getList : function() {
      return this.__list;
    },

    clearPostMessage : function() {
      this.__textarea.setValue(null);
    }
  }
});

Vamos voltar agora para o Application.js e criar um controle para nossa lista com o seguinte código:

var controller = new qx.data.controller.List(null, main.getList());
      controller.setLabelPath("text");
      controller.setIconPath("user.profile_image_url");
      controller.setDelegate({
        configureItem : function(item) {
          item.getChildControl("icon").setWidth(48);
          item.getChildControl("icon").setHeight(48);
          item.getChildControl("icon").setScale(true);
          item.setRich(true);
        }
      });

Agora vamos chamar o método bind para vincular o controle com o modelo vindo do twitter e chamar os tweets quando iniciar a aplicação:

service.bind("tweets", controller, "model");
service.fetchTweets();

Gere novamente os scripts e recarregue a página e teste nosso aplicativo funcionando.

Na hora de postar você será redirecionado para o site do twitter para autenticação, pois é muito complicado fazer a autenticação pelo aplicativo, pois o twitter só usa o OAuth para autenticar os usuários. Para baixar o projeto clique aqui.

Fonte: qooxdoo Docs

 

05

jun
2012

Sem Comentários

Em Blog
Código
Java
REST

Por Acson

Conhecendo o Play Framework

Em 05, jun 2012 | Sem Comentários | Em Blog, Código, Java, REST | Por Acson

Quem já experimentou frameworks como Django e Rails sabe bem que o desenvolvimento de aplicações web pode perfeitamente ser produtivo e até divertido. Isso estava fora da realidade do mundo Java antes do surgimento do Play Framework!.

O Play é um framework full stack, stateless, focado em produtividade, bastante parecido com Django e Rails. É construído sobre uma arquitetura assíncrona baseada em eventos, sendo muito simples de escalar. Possui suporte a módulos, gerenciamento de dependências e configuração baseada em arquivos properties. Não é necessário compilar e realizar deploy em um servidor de aplicações, o Play vem com um servidor embutido, e durante o desenvolvimento basta alterar o código, salvar e recarregar o browser. O próprio framework compila e recarrega a aplicação, como em linguagens interpretadas. E se houverem erros, eles serão exibidos no próprio browser, de forma intuitiva.

O Play vem com um conjunto de ferramentas em modo console para várias tarefas, como criar novos projetos, iniciar a aplicação com o servidor embutido, executar testes, configurar dependências, gerar um pacote WAR, etc, o que o torna bastante produtivo tanto para novos projetos quanto para dar manutenção em um projeto já existente. É possível desenvolver em Java ou Scala (sim, Scala!).

Vamos enumerar alguma das caracteristicas do framework:

  • Limpo, Rápido e Dinâmico
  • Produtivo, Poderoso e Divertido!
  • Puro Java (Permite a importação e uso de qualquer biblioteca Java)
  • Utiliza o sistema de template Groovy(Groovy trabalha de forma transparente com todos os objetos e bibliotecas Java existentes e compila diretamente para Java bytecode tanto no desenvolvimento de aplicações como no modo script.)
  • Utiliza sistemas de tradução de Rotas
  • Facilidade na resolução de erro
  • Padrão MVC
  • Assíncrono (I/O não bloqueante)
  • Stateless
  • Arquitetura RESTful ( REST (ou Representational State Transfer) é um estilo de desenvolvimento para sistemas distribuídos que privilegia a trasferência de estado sem envolver camadas de mapeamento (como o SOAP faz). Assim, os verbos GET, POST, PUT e DELETE mapeam quase que diretamente para ações READ, UPDATE, CREATE e DELETE (CRUD).
  • Persistência com JPA (JPA é uma especificação de Persistência da plataforma Java, para persistir as classes java em bancos de dados relacionais. )
  • Extensível (Através de Módulos / Bibliotecas Java)
  • TDD – Test Development Drive (Test Driven Development (TDD) ou em português Desenvolvimento dirigido por testes )

 

Como iniciar uma aplicação no Play?

É facil, basta usar o comando no consolhe (Terminal no Linux e Prompt de comando no Windows, lembrando que você terá que estar dentro da pasta do framework no windows e no linux ter adicionado o caminho da pasta ao PATH para executar o comando play):

play new nomedaaplicacao

Toda a estrutura do projeto será criada, incluindo arquivos de configuração e o roteamento inicial da aplicação. Se você deseja abrir o projeto no Eclipse ou no Netbeans, o Play! cria o projeto para você. Basta fazer assim:

play eclipsify nomedaaplicacao

Ou se preferir o Netbeans:

play netbeansify nomedaaplicacao

Dessa forma, você poderá importar o projeto de sua IDE e todas as configurações estarão realizadas. Outro comando importante é a gerador de war (deploy).

 play war nomeDoProjeto -o nomeDoProjeto.war

Pronto, feito isto basta começar a programar no projeto usando Java ou Scala 🙂 !

Slide da apresentação feita na SWX: play-framework-apresentaçao

Código de uma pequena aplicação de uma agenda feita na SWX:

No diretório /conf no arquivo application.conf , caso use mysql, basta localizar e modificar o padrão para seu usuário e senha do mysql e o nome do banco (No exemplo a seguir está sem senha).

# To connect to a local MySQL5 database, use:
db=mysql:acson@minha_agenda
// acson -> usuário do banco,  minha_agenda -> banco

No diretório /app/controllers , modifique o Application.java (ou crie se não existir)  para:

package controllers;
import play.*;
import play.mvc.*;
import play.data.validation.*;
import java.util.*;
import models.*;
public class Application extends Controller {
public static void index() {
 List<Contato> contatos = Contato.find("order by nome asc").fetch();
 render(contatos);
 }
public static void inserir() {
 render();
 }

 public static void visualizar(String email) {
 Contato contato = Contato.find("email", email).first();
 render(contato);
 }

 public static void editar(String email) {
 Contato contato = Contato.find("email", email).first();
 render(contato);
 }

 public static void excluir(String email) {
 Contato contato = Contato.find("email", email).first();
 contato.delete();
 index();
 }

 public static void cadastrar_contato(@Required String nome, @Required String email, String telefone, String twitter, String skype) {
 Contato contato = new Contato(nome, email, telefone, twitter, skype);
 if (validation.hasErrors()) {
 render("Application/inserir.html", contato);
 }

 contato.save();
 index();
 }

 public static void editar_contato(long id) {
 validation.required(request.params.get("nome"));
 validation.required(request.params.get("email"));

 Contato contato = Contato.find("id", id).first();

 if (validation.hasErrors()) {
 render("Application/editar.html", contato);
 }

 contato.nome = request.params.get("nome");
 contato.telefone = request.params.get("telefone");
 contato.email = request.params.get("email");
 contato.twitter = request.params.get("twitter");
 contato.skype = request.params.get("skype");

 contato.save();
 index();
 }
}

 

No diretório /app/models  , crie a classe Contato (Contato.java) com o seguinte código:

package models;
import play.*;
import play.db.jpa.*;
import javax.persistence.*;
import java.util.*;
@Entity
public class Contato extends Model {

 public String nome;
 public String email;

 public String telefone;
 public String twitter;
 public String skype;

 public Contato(String nome, String email, String telefone, String twitter, String skype) {
 this.nome = nome;
 this.email = email;
 this.telefone = telefone;
 this.twitter = twitter;
 this.skype = skype;
 }

}

No diretório /app/views  , crie o arquivo application.html com o seguinte código:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
 "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
 <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
<title>.: Agenda de Contatos - #{get 'title' /}</title>
 <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
 <link rel="stylesheet" type="text/css" media="screen" href="@{'/public/stylesheets/principal.css'}">
 #{get 'moreStyles' /}
 <script src="@{'/public/javascripts/jquery-1.4.2.min.js'}" type="text/javascript" charset="utf-8"></script>
 #{get 'moreScripts' /}
</head>
<body id="page1">
 <div id="geral">

 <div id="conteudo">
 <div id="logo"></div>
 <div class="linha">
 <div class="titulo">.: Agenda de Contatos</div>
 #{if request.actionMethod != "inserir" && request.actionMethod != "editar"}
 <div class="text"><a href="@{Application.inserir()}" class="button">+ Incluir Contato</a></div>
 #{/if}
 </div>
 <div class="linha"></div>
 #{doLayout /}
 </div>
 </div>
 </div>
</body>
</html>

No diretório /app/views/Application  , crie o arquivo inserir.html com o seguinte código:

#{extends 'application.html' /}
#{set title:'Inclusão' /}
#{form @Application.cadastrar_contato()}
 #{ifErrors}
 <div class="linha"><p style="color:red;"><strong>ATENÇÃO: </strong>Preencha todos os campos obrigatórios.</p></div>
 <div class="linha"></div>
 #{/ifErrors}
<div class="linha">
 <div class="duas-colunas">
 <div class="esq">
 <p><label for="nome">Nome:</label></p>
 </div>
 <div class="dir">
 <p><input type="text" name="nome" id="nome" value="${params.nome}" /></p>
 </div>
 </div>
 </div>
 <div class="linha">
 <div class="duas-colunas">
 <div class="esq">
 <p><label for="telefone">Telefone:</label></p>
 </div>
 <div class="dir">
 <p><input type="text" name="telefone" id="telefone" value="${params.telefone}" /></p>
 </div>
 </div>
 </div>
 <div class="linha">
 <div class="duas-colunas">
 <div class="esq">
 <p><label for="email">Email:</label></p>
 </div>
 <div class="dir">
 <p><input type="text" name="email" id="email" value="${params.email}" /></p>
 </div>
 </div>
 </div>
 <div class="linha">
 <div class="duas-colunas">
 <div class="esq">
 <p><label for="twitter">Twitter:</label></p>
 </div>
 <div class="dir">
 <p><input type="text" name="twitter" id="twitter" value="${params.twitter}" /></p>
 </div>
 </div>
 </div>
 <div class="linha">
 <div class="duas-colunas">
 <div class="esq">
 <p><label for="skype">Skype:</label></p>
 </div>
 <div class="dir">
 <p><input type="text" name="skype" id="skype" value="${params.skype}" /></p>
 </div>
 </div>
 </div>
 <div class="btn-submit">
 <p><input type="submit" value="Cadastrar o Contato" /></p>
 </div>

#{/form}

No diretório /app/views/Application  , crie o arquivo visualizar.html com o seguinte código:

#{extends 'application.html' /}
#{set title:'Visualiza‹o' /}
<div class="linha">
 <div class="duas-colunas">
 <div class="esq">
 <p><label for="nome">Nome:</label></p>
 </div>
 <div class="dir">
 <p>${contato.nome}</p>
 </div>
 </div>
 </div>
 <div class="linha">
 <div class="duas-colunas">
 <div class="esq">
 <p><label for="telefone">Telefone:</label></p>
 </div>
 <div class="dir">
 <p>${contato.telefone}</p>
 </div>
 </div>
 </div>
 <div class="linha">
 <div class="duas-colunas">
 <div class="esq">
 <p><label for="email">Email:</label></p>
 </div>
 <div class="dir">
 <p>${contato.email}</p>
 </div>
 </div>
 </div>
 <div class="linha">
 <div class="duas-colunas">
 <div class="esq">
 <p><label for="twitter">Twitter:</label></p>
 </div>
 <div class="dir">
 <p>${contato.twitter}</p>
 </div>
 </div>
 </div>
 <div class="linha">
 <div class="duas-colunas">
 <div class="esq">
 <p><label for="skype">Skype:</label></p>
 </div>
 <div class="dir">
 <p>${contato.skype}</p>
 </div>
 </div>
 </div>
 <div class="btn-submit">
 <p>
 <a href="@{Application.index()}">Cancelar</a>
 <a href="@{Application.editar(contato.email)}">Editar</a>
 <a href="@{Application.excluir(contato.email)}" onClick="if(!confirm('Deseja excluir este contato?')){return false;}">Excluir</a>
 </p>
 </div>

No diretório /app/views/Application  , crie o arquivo editar.html com o seguinte código:

#{extends 'application.html' /}
#{set title:'Edição' /}
#{form @Application.editar_contato(contato.id)}
 #{ifErrors}
 <div class="linha"><p style="color:red;"><strong>ATENÇÃO: </strong>Preencha todos os campos obrigatórios.</p></div>
 <div class="linha"></div>
 #{/ifErrors}
<div class="linha">
 <div class="duas-colunas">
 <div class="esq">
 <p><label for="nome">Nome:</label></p>
 </div>
 <div class="dir">
 <p><input type="text" name="nome" id="nome" value="${contato.nome}" /></p>
 </div>
 </div>
 </div>
 <div class="linha">
 <div class="duas-colunas">
 <div class="esq">
 <p><label for="telefone">Telefone:</label></p>
 </div>
 <div class="dir">
 <p><input type="text" name="telefone" id="telefone" value="${contato.telefone}" /></p>
 </div>
 </div>
 </div>
 <div class="linha">
 <div class="duas-colunas">
 <div class="esq">
 <p><label for="email">Email:</label></p>
 </div>
 <div class="dir">
 <p><input type="text" name="email" id="email" value="${contato.email}" /></p>
 </div>
 </div>
 </div>
 <div class="linha">
 <div class="duas-colunas">
 <div class="esq">
 <p><label for="twitter">Twitter:</label></p>
 </div>
 <div class="dir">
 <p><input type="text" name="twitter" id="twitter" value="${contato.twitter}"/></p>
 </div>
 </div>
 </div>
 <div class="linha">
 <div class="duas-colunas">
 <div class="esq">
 <p><label for="skype">Skype:</label></p>
 </div>
 <div class="dir">
 <p><input type="text" name="skype" id="skype" value="${contato.skype}" /></p>
 </div>
 </div>
 </div>
 <div class="btn-submit">
 <p><input type="submit" value="Editar o Contato" /></p>
 </div>

#{/form}

No diretório /app/views/Application  , crie o arquivo index.html com o seguinte código:

#{extends 'application.html' /}
#{set title:'Listagem' /}
#{if contatos.size() == 0}
 <div class="linha">
 <p>Nenhum contato cadastrado.</p>
 </div>
#{/if}
#{else}
 #{list items:contatos, as:'contato'}
 <div class="linha">
 <p><a href="@{Application.visualizar(contato.email)}">&raquo; ${contato.nome} - ${contato.email}</a></p>
 </div>
 #{/list}
#{/else}

E para ficar mais agradável e padronizado, vamos mudar o arquivo de rotas que fica em  /conf , o arquivo é o routes

# Routes
# This file defines all application routes (Higher priority routes first)
# ~~~~
# Home page
GET / Application.index
GET /cadastrar Application.inserir
GET /visualizar/{email} Application.visualizar
GET /editar/{email} Application.editar
GET /excluir/{email} Application.excluir
# Map static resources from the /app/public folder to the /public path
GET /public/ staticDir:public
# Catch all
* /{controller}/{action} {controller}.{action}

Quando o usuário chamar o método de inserir que está no Application.java, no browser aparecerá dominio/cadastrar, e assim por diante.
Terminando isso o aplicativo está pronto para uso.
Abaixo algumas telas de uma pequena aplicação que fizemos, uma agenda de contados:

Site oficial do Play Framework: http://www.playframework.org/

Github do Play Framework:  https://github.com/playframework/play

Algumas fontes consultadas: Imasters, Bragil.net