Revisão 2.1

Esta é uma revisão para a segunda prova.

  1. Na aplicação de MiniBlog, o que você faria para que a lista de posts fosse exibido na ordem, sendo que os mais recentes apareçam primeiro e os mais antigos no final?

    Desenvolva a solução que você optou.

  2. Essa é uma questão para discussão em sala.
  3. Desenvolva a funcionalidade de modificar os posts do MiniBlog, que atenda aos seguintes requisitos:

    1. O horário de publicação não poderá ser alterado.
    2. Na visualização do texto do post, se ele foi modificado, deverá ser exibida a informação de que o post foi modificado em tal data/hora.
    3. A modificação do post deve ocorrer de forma automática, quando o usuário solicitar a modificação, então essa será a hora em que o post foi modificado.

    Nessa questão, você deverá alterar o esquema da tabela Posts, adicionando uma segunda coluna DATETIME para saber o momento da modificação. Use a instrução abaixo na tabela já criada:

    ALTER TABLE Posts ADD modificado DATETIME NULL

    Assim, em resumo, para atingir os objetivos da questão, você precisará:

    1. Adicionar a nova coluna ao banco de dados.
    2. Adicionar o novo campo à classe de dados Post.
    3. Modificar o PostDao para utilizar o novo campo.
    4. Adicionar um novo subcomando para exibir o formulário de modificação e executar a ação de modificar o post no banco de dados.

    OBS: lembre-se que a coluna modificado é NULL, portanto, para saber se o post foi modificado no Java, basta fazer a comparação modificado != null.

  4. Esse é um tipo de problema que é melhor se resolvido em partes. Como a aplicação já está estruturada em MVC, vou descrever a solução usando cada uma das camadas.


    Model

    As mudanças necessárias na camada model são bem simples, basta considerar o campo modificado nas classes modelo e de acesso a dados.

    Post.java (classe modelo)
    PostDao.java (apenas os métodos alterados)

    View

    Nas interfaces de usuário, precisamos criar um formulário para modificar um post e adicionar à tela de visualização a informação do campo modificado se necessário.

    /posts/visualizar.jsp (visualização de post com aviso de modificado)
    /posts/modificar.jsp (nova tela com formulário de modificação)

    O mais importante são essas duas telas acima, mas também é necessário links para o usuário acessar o formulário de de modificação do post, eu fiz isso na lista de posts.

    Mas note que há uma variável booleana isAdmin para exibir o link, como simulação de acesso como administrador. Essa variável é definida no comando Posts:index que usa essa tela.

    /posts/lista.jsp (lista de posts com link para edição)

    Controller

    Eu adicionei o comando Posts:atualizar que é bem parecido com o de adicionar posts, mas utiliza o campo modificado.

    Note que eu não precisei mexer no comando Posts:visualizar, pense no porque 🤔

    Posts:atualizar (novo comando)

    A simulação de acesso como administrador é feito no comando Posts:index.

    Posts:index (comando com alteração)
  5. Adicione à aplicação MiniBlog o recurso de marcar um post com uma tag.

    A funcionalidade de tags deverá funcionar da seguinte forma:

    1. Cada post poderá ser marcado com apenas uma tag.
    2. Poderá haver posts sem marcação.
    3. A criação de tags deverá ser automática, se ao criar ou modificar um post, for escrito o nome de uma tag inexistente, então esta deverá ser criada.
    4. Na visualização do texto do post, deverá aparecer a tag marcada. Se o post não tiver marcação, então deverá ser exibido essa informação.
    5. Não será necessário criar telas de CRUD para as tags.

    As tags serão mantidas na tabela Tags:

    CREATE TABLE Tags (
      id   INT PRIMARY KEY IDENTITY,
      nome VARCHAR(30) UNIQUE NOT NULL
    )

    E é preciso criar a chave estrangeira na tabela Posts:

    ALTER TABLE Posts ADD tag_id INT NULL REFERENCES Tags (id)

    Estou fornecendo também as classes de acesso a dados Tag e TagDao, com os métodos necessários para a questão.

    Tag.java
    package model;
    
    public class Tag {
        private int id;
        private String nome;
    
        public int getId() {
            return id;
        }
    
        public void setId(int id) {
            this.id = id;
        }
    
        public String getNome() {
            return nome;
        }
    
        public void setNome(String nome) {
            this.nome = nome;
        }
    }
    TagDao.java
    package dao;
    
    import model.Tag;
    import org.sql2o.Connection;
    
    import java.util.List;
    
    public class TagDao {
        /**
         * Referência da fábrica de conexões
         */
        private static final Database db = Database.getInstance();
    
        public Tag obter(int id) {
            String query =
                "SELECT id, nome " +
                "FROM Tags " +
                "WHERE id=:id";
    
            try (Connection con = db.open()) {
                return con.createQuery(query)
                    .addParameter("id", id)
                    .executeAndFetchFirst(Tag.class);
            }
        }
    
        public List<Tag> obterTodos() {
            String query =
                "SELECT id, nome " +
                "FROM Tags";
    
            try (Connection con = db.open()) {
                return con.createQuery(query)
                    .executeAndFetch(Tag.class);
            }
        }
    
        public boolean adicionar(Tag tag) {
            String query =
                "INSERT INTO Tags (nome) " +
                "VALUES (:nome)";
    
            try (Connection con = db.open()) {
                con.createQuery(query)
                    .addParameter("nome", tag.getNome())
                    .executeUpdate();
    
                // Obtém id gerado automaticamente pelo SGBD
                Integer id = con.getKey(Integer.class);
                tag.setId(id);
    
                return con.getResult() > 0;
            }
        }
    }
  6. Esse também é um tipo de problema melhor resolvido em partes. Mas dessa vez vou apresentar as camadas em ordem contrária.


    View

    Primeiramente, na criação/modificação de um post, é preciso que o usuário possa indicar a tag usada. Para isso, devemos modificar as telas de formulário para ter esse novo campo.

    /posts/adicionar.jsp (formulário com novo campo tag)
    /posts/modificar.jsp (formulário com novo campo tag)

    E, para completar, ao visualizar um post, o usuário quer saber qual a tag marcada. Nesse caso, modificamos a tela de visualização de post.

    /posts/visualizar.jsp (visualização de post com a tag)

    Controller

    Basicamente, precisamos alterar o código dos comandos para a nova situação.

    Posts:visualizar (alterado para obter tag)
    Posts:publicar (alterado para publicar post com uma tag)
    Posts:atualizar (alterado para atualizar post com uma tag)
    obterOuCriarTag() (método interno da classe do comando)

    Model

    Primeiramente, eu atualizei o DAO de tags para ter um método de obter uma tag pelo nome.

    obterPorNome() (novo método de TagDao)

    Depois, eu atualizei a classe Post para adicionar o novo campo.

    Post.java (classe modelo com novo campo)

    E, por último, atualizei o DAO de posts para utilizar o novo campo.

    Note nas linhas 9, 22 e 45 a chamada addColumnMapping("tag_id", "tagId"). Isso é um mapeamento da coluna tag_id da tabela para o atributo tagId da classe modelo usado pela biblioteca sql2o

    PostDao.java (apenas os métodos alterados)