Skip to content

Instantly share code, notes, and snippets.

@lavesan
Last active August 24, 2019 17:13
Show Gist options
  • Save lavesan/1ab10e21f43294662fae620100303fa0 to your computer and use it in GitHub Desktop.
Save lavesan/1ab10e21f43294662fae620100303fa0 to your computer and use it in GitHub Desktop.
Playframework

Recebendo dados query string:

No controller:

// 1 forma
Map<String, String[]> queryString = request().queryString();
Map<String, String> map = new HashMap<>();
queryString.forEach((s, strings) -> map.put(s, strings[0]));

Form<DataTableForm> form = this.mFormFactory.form(DataTableForm.class).bind(map);

DataTableForm model = form.get();

// 2 forma
Form<DataTableForm> form = this.mFormFactory.form(DataTableForm.class).bindFromRequest();

DataTableForm model = form.get();

// Validando
if(isNullOrInvalid(form)) {
  ObjectNode json = Json.newObject();
  formErrorAsJson(json, form);
  return badRequest(json);
}

Na classe modelo, que passo o que vai vir como request de query-string

public class DataTableForm {
  // Usando o Ebean para validar
  @Constraints.required("Sem idade")
  Integer idade;
  
  @Constraints.min({ value= 1, message="No mínimo o valor 1"})
  @Constraints.required("Sem nome")
  String nome;
  
  List lista;
}

Retornando um objeto dentro um parâmetro:

Controller

// Essa tupla faz a SQL
F.Tuple<List<TransactionSQL>, Long> tuple = TransactionSQL.findByAdvancedFilter(filter, user.getEstablishmentIds().size() > 1);
List<DexTransactionViewModel> object = tuple._1.stream()
  .map(DexTransactionViewModel::new)
   .collect(Collectors.toList());

ObjectNode json = Json.newObject();
json.set("data", Json.toJson(object));
json.put("code", 0);

No model, que vai ser o objeto

public String id;
public int idade;
public String nome;
public String algumaCoisa;
public Integer oqueEuquiser;

Rodando SQL para pegar os dados

import io.ebean.annotation.Sql;
import javax.persistence.Entity;
import java.util.List;

@Sql
@Entity
public class ClasseSql {
  public String id;
  public int idade;
  public String nome;
  public String algumaCoisa;
  public Integer oqueEuquiser;
  
  // Exemplos de como coletar os dados
  public static ClasseSql findById(Long id) {
    return getData().where().eq("uma_coluna", id).findOne();
  }
  
  // Escrevendo SQL na mão
  public static Query<ClasseSql> getData() {
    RawSql rawSql = getRawSql();
    return Ebean.find(ClasseSql.class)
      .setRawSql(rawSql);
  }
  private static RawSql getRawSql() {
    // Fazendo uma query e alterando o valor das variáveis
    return RawsqlBuilder.parse("select * from alguma_tabela")
      .columnMapping("coluna_idade", "idade")
      .columnMapping("coluna_nome", "nome")
      .columnMapping("coluna_alguma_coisa", "algumaCoisa")
      .columnMapping("coluna_oque_eu_quiser", "oqueEuQuiser")
  }
}

SQL

Com Ebean

Na classe de query .java

@Entity
@Table(name = "nome_da_tabela")
public class User extends Model {
  // Marca como coluna de id
  // Linka a variável ao valor da coluna
  @Id
  @Column(name = "coluna_id")
  public Long id;
  
  // Não deixa ser nula
  @Column(name = "coluna_nome", nullabel = false)
  public String nome;
  
  @Column(name = "coluna_password")
  public String password;
  
  // Não deixa alterar seu valor
  @Column(name = "alguma_coluna", updatable = false)
  public string algumaCoisa;
  
  // Rodando alguma query com o ebean
  public static User authenticate(String login, String clearPassword) {
        return FINDER.query().where()
                .and(Expr.ieq("coluna_nome", nome),
                        Expr.eq("coluna_password", DigestUtils.md5Hex(clearPassword)))
                .findOne();
    }
}

No controller

User user = new User();
user.nome = "Ronaldo";
user.password = "123456";
user.algumaCoisa = "algo";
// Com isso salvo os dados
user.save();

Serve para fazer consultas num banco de dados e linkar entidades e colunas em variáveis de uma classe

Documentação:
https://ebean.io/docs/mapping/

Usando play framework

Aplicação MVC

https://assist-software.net/blog/how-play-work-play-framework-tutorial

Model: dados usados na aplicação
View: front-end
Controller: mexem com as requests e decidem que lógica usar

Ele usa o REST

“GET, POST, DELETE...”

https://www.youtube.com/watch?v=gpaIwB18XL0

https://www.playframework.com/documentation/1.3.0-RC1/firstapp

COMANDOS

ajuda:

help run

criar novo projeto:

play new projeto

File -> New -> Project -> Java EE -> [só-adicionar-o-play2.x]

compilar:

compile || sbt compile

rodar:

run || sbt run localhost:9000

rodar testes:

test || testOnly com.coloco-o-diretório

abro console para digitar e rodar o que digitei:

console

excluir arquivos gerados:

clean

adicionar bibliotecas:

vou no arquivo build.sbt e adiciono em libraryDependencies

baixar bibliotecas:

update

rodar em uma porta específica:

run -Dhttp.port=9998 -Dpidfile.path=/path/to/app1/pidfile

arquitetura:

  • app ->
    • views (Front-end)
    • controllers (Mexem na lógica das requests)
    • !opcionalmente posso adicionar:
    • models (Dados pego na base de dados)
    • utils (Funções e variáveis muito chamadas na aplicação em geral)
    • service (Requisições na base de dados)
  • conf ->
    • routes (tem as rotas)
    • application.conf (é o que linka ao banco de dados)
    • internacionalização..
  • project ->
    • build do projeto
  • public ->
    • javascripts (códigos em javascript para carregarem na página)
    • stylesheets (css, scss, sass, less...)
    • images (assets usados na página)

Seu index é o app/views/index.scala.html

routes: método HTTP -> Caminho da Request -> ação GET /usuários controllers.usuários.index() POST /request DELETE

passando 2 parâmetros para página:

import views.html.pasta.outraPagina
import views.html.pagina
...

public static Result helloWorld() { return ok(pagina.render("Hello World!", 1)); }

recebendo 2 parâmetros na página:

@(message1: String, message2: Integer) <h1>@message1</h1> <h1>@message2</h1>

transpilação concluída que será o html:

<h1>Hello World!</h1>
<h1>1</h1>

.scala.html

Criando e setando uma variável

@var variavel: String = "Declarei"

@defining() { variavel =>
<h2>@variavel</h2>
}

chamando um ‘componente’:

@componenteCriado(“Passando parâmetro se necessário”)

passando HTML como parâmetro de um .scala.html que recebe HTML:

@paginaScalaHtml {<div class=”alguma”>Passei esse HTML</div>}

ir para página clicando em um link:

<a href="”@routes.controllerDosComponentes.funcaoQueChamaComponente()”"></a>

Criando função javascript dentro do scala.html:

@funcao(parametro:Int, parametro2:Int) = @{
	// Posso alterar um parâmetro da página
	var filter = parametroDaPagina

	// Chamando uma função de um controller
	routes.controllerDeAlgo.list(parametro, parametro2, filter)
}

para chamar é só:

@funcao(1, 6)

Usando condicionais

@if(variavel != 0){}
@for(int i = 0; variavel.length > i; i++){}
@while(variavel != null){}
@do{}while(variavel != null);
@switch(variavel){case 0: {break;}case 1: {break;}}

Chamando tipos para fazer algo

@Integer.toparse()

Query String:

forma habitual do play:

Forma habitual

Traduzindo:

  1. Se não existir valor, o valor é 1
  2. Recebe 3 parâmetros, se não existir o valor padrão de cada um é “0”
  3. Recebe 3 parâmetros, se não existir o valor padrão de cada um é 0

forma improvisada:

No .java:

play.mvc.Controller

Com ele, posso usar o .render()

Se eu não avisar nenhum render, é o index.html que vai ser

No index.html tenho:

#{extends 'main.html' /}
#{set title:'Home' /}

#{welcome /}
{extends ‘página.html’ /}
chamo assim para usar como um componente
{}

No main.html:

#{doLayout /}
Aqui é onde o index.html vai ser colocado

Atalhos:

Alt+insert

Cria automaticamente Get, Set, Constructor, toString…

Criando comunicação JDBC

import java.sql.Connection;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CompletionStage;
import javax.inject.Inject;

import play.mvc.Controller;
import play.db.NamedDatabase;
import play.db.Database;

class JavaJdbcConnection {
    private Database db;
    private DatabaseExecutionContext executionContext;

    @Inject
    public JavaJdbcConnection(Database db, DatabaseExecutionContext executionContext) {
        this.db = db;
        this.executionContext = executionContext;
    }

    public CompletionStage<Void> updateSomething() {
        return CompletableFuture.runAsync(() -> {
            // get jdbc connection
            Connection connection = db.getConnection();

            // do whatever you need with the db connection
            return;
        }, executionContext);
    }

}

Comunicação com banco de dados (base de dados):

Coloco no application.conf.

só acrescentar isso para criar um banco default:

db.default.driver=org.h2.Driver
db.default.url=”jdbc:h2:mem:play” #banco de teste dentro da memória
db.default.user=sa
db.default.password=""

# linkando para bancos de dados diferentes
#db.default.url="jdbc:h2:/path/to/db-file" banco padrão do play
# postgreSQL
#db.default.driver=org.postgresql.Driver  no caso do postgres
#db.default.url="jdbc:postgresql:/path/to/db-file"  no caso do postgres
# mySQL
#db.default.driver=com.mysql.jdbc.Driver  no caso do postgres
#db.default.url="jdbc:mysql:/path/to/db-file"  no caso do postgres
# NÃO ESQUECER DE COLOCAR PASSWORD E USUÁRIO


#posso setar mais quantos bancos eu quiser
db.myCustom.driver=org.h2.Driver
db.myCustom.url=”jdbc:h2:mem:play”

ebean.default="models.*"

Isso indica ao Play! qual o banco que ele deve usar e também que ele pode criar automaticamente os comandos de banco de dados que geram as tabelas do modelo. Configuramos também o Ebean, implementação ORM que vem por padrão com o Play!, para procurar os modelos no pacote models. Acessando o banco de dados default

import javax.inject.*;
import play.db.*;

import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CompletionStage;

@Singleton
class AcessoDatabase {
	private Database db;
	private DatabaseExecutionContext execCtx;

	@Inject
	public AcessoDatabase(Database db, DatabaseExecutionContext ctx) {
		this.db = db;
		this.execCtx = ctx;
}

public CompletionStage<Integer> comunicando() {
	return CompletableFuture.supplyAsync(() -> {
		return db.widthConnection(connection -> {
			// Fazer algo com esta comunicação
			return 1;
});
}, execCtx);
}
}

Acessando banco de dados que não é o default

package javaguide.sql;
import javax.inject.Inject;
import javax.inject.Singleton;

import play.mvc.Controller;
import play.db.NamedDatabase;
import play.db.Database;

// inject "orders" database instead of "default"
@javax.inject.Singleton
class JavaNamedDatabase {
private Database db;
private DatabaseExecutionContext executionContext;

    @Inject
    public JavaNamedDatabase(@NamedDatabase("orders") Database db, DatabaseExecutionContext executionContext) {
        this.db = db;
        this.executionContext = executionContext;
    }

    // do whatever you need with the db using supplyAsync(() -> { ... }, executionContext);

}

Respondendo uma requisição:

Uso a classe CompletableFuture, que retorna o sucesso ou falha da requisição

String sqlCommand = “select \* from test”;

// play.db é a API para acessar o banco de dados jdbc
Connection connect = play.db.DB.createConnection();
try{
Statement stmt = connect.createStatement();
try{
stmt.execute(sql);
} finally {
stmt.close();
}
} finally {
connect.close();
}

Atribuindo valores em variáveis apartir de um comando SQL

String sql = “select \* from tableRawSql rawsql = RawSqlBuilder.parse(sql)
.coulumnMapping(column_1_no_banco, variavel1)
.columnMapping(column_2_no_banco, varavel2)
.create();

ExpressionList<ClasseVariaveis> expression = Ebean.find(ClasseVariaveis.class)
.setRawSql(rawSql).setDistinct(true).where();

https://www.playframework.com/documentation/1.3.0-RC1/firstapp

Equipamentos do playframework

=> Setar um tempo para algo de modo assíncrono:
(No caso estou executando uma função)

private final ActorSystem actorSystem;
private final ExecutionContextExecutor exec;

@Inject
public AsyncController(ActorSystem actorSystem, ExecutionContextExecutor exec) {
this.actorSystem = actorSystem;
this.exec = exec;
}

private CompletionStage<String> funcao(){
actorSystem.scheduler().scheduleOnce(
Duration.create(time, timeUnit),
() -> future.complete("Hi!"),
exec
)
return future;;
}

Bibliotecas:

time<long>
future<CompletableFuture<String>>
ActorSystem
ExecutionContextExecutor
Duration
TimeUnit

=> Ação que roda sempre que página é aberta:
(no caso, estou incrementando um valor com 1)

private final Counter counter;

@Inject
public CountController(Counter counter) {
this.counter = counter;
}

public Result count() {
return ok(Integer.toString(counter.nextCount()));
}

Bibliotecas:

Counter
Result (resultado)

Comentário a pensar sobre USAR ou NÃO USAR playframework

An interesting article with some very good points, although a bit too pro Play for my liking. Play Framework is a mess, the documentation is inconsistent or just missing for some versions and it's overly complicated for what it actually does, I would not recommend using it from Java or Scala. A few additions to the Bad bullet points for Scala...

  • Breaking changes across versions
  • Tooling (IDE plugins are a million miles away from compared with those for Java)
  • Compilation - it's slow, very slow
  • Syntax - too complicated and inconsistent
  • Static typing (especially when rendering HTML and building frontend apps)
  • SBT - possibly the worst build tool I've ever used For REST APIs or backend services I think Clojure/Java/JaxRs/DropWizard/Scala/Play are a good fit but I think they should be avoided when rendering HTML and building frontend apps.

POST

Routes

POST api/diretorio @controllers.funcaoControlador(dado1: String, dado2:String ?= "")

Controller do POST

Rodando assincronamente

import controllers.api.SQLController;
...
public CompletionStage<Result> funcao(String dado1, String dado2) {
  @Inject
  HttpExecutionContext context;
    
  return CompletableFuture.supplyAsync(() -> {
    ObjectNode json = Json.newObject();
    // Controlando os dados da requisição
    // json.put("nome da variável", "dados da variável")
    
    // Assim posso colocar um erro e já retornar um erro
    if(condicionalDeErro){
      // Retorno em Array
      json.put("code", "dados de erro");
      return badRequest(json);
    }
    if(algumOutroErro){
      DebugUtil.w(String.format("Enviando dados dinamicamente para debug (%d - %s) \"%s\".", dado1, dado2, dado3));
      errorAsJson(json, 20, String.format("Enviando dados dinamicamente como resposta \"%s\".", dado1));
      return badRequest(json);
    }
    
    // Retorno em Objeto
    json.put("code", 0);
    json.put("dado1", this.dado1);
    json.put("dado2", this.dado2);
    
    return ok(json);
  }, this.context.current());
}

Setando o json

json.set(ListDeNomes, ListDeValores);

Controller para retornar os dados de algo

JPA + Ebean
import io.ebean.Finder;
import io.ebean.Model;
import io.ebean.annotation.WhenCreated;

// Esses @ são chamados de anotations
// Os anotations servem para referenciar à colunas e tabelas do banco.
@Entity
@Table(name="nome_da_tabela")
public class ClasseCriada extends Model {
  // isso linka o FINDER à classe, logo posso chamar ele para chamar as coisas
  private static final Finder<Long, ClasseCriada> FINDER = new Finder<Long, ClasseCriada>(ClasseCriada.class){};
  
  @Id
  @Column(name="nome_da_coluna_id")
  public Long id;
  
  @Columns(name="outro_dado")
  public String outroDado;
  
  // Graças à extender Model, posso usar o byId para procurar os dados pelo id
  public ClasseCriada findById(Long id) {
    ClasseCriada dados = FINDER.byId(id);
    // Assim uso os dados:
    // dados.outroDado
    return dados;
  }
  // Existem várias funções no Model, como:
  public List<ClasseCriada> listaDeAlgo(Long id) {
    return FINDER.query().where().eq(propertyName: "algum_valor_unico", id).findList();
  }
  // Pegando todos os dados
  public List<ClasseCriada> listaComTudo() {
    return FINDER.query().where().eq(propertyName: "coluna_da_tabela", true).findList();
  }
  
  // Chamando para receber esta lista:
  // listaDealgo(3).stream.map(elemento -> elemento.outroDado).collect(Collectors.toList());
}

Posso retornar em um ARRAY com:

ArrayNode array = Json.newArray();
ObjectNode json = Json.newObject();
...
array.add(json)
...
return ok(array)

GET

Controller

Routes

GET api/diretorio:id @controllers.funcaoControlador()

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment