Search buenodc

Nesta página
  1. Configurando o Spring Session
  2. Utilizando a sessão
  3. Para saber mais

Trabalhando com sessões no Spring

Para entender o que é uma sessão e qual problema ela resolve é necessário compreender o funcionamento do protocolo HTTP e o modelo cliente-servidor. O HTTP é um protocolo sem estado, ou seja, ele não guarda nenhuma informação sobre as requisições anteriores. Isso significa que as mensagens entre o cliente e o servidor são independentes uma da outra, ou seja, não existe uma noção de sequência entre as mensagens.

Por exemplo, imagine que Lenny (uma pessoa fictícia) abriu o navegador em seu computador e acessou o site http://www.kabum.com.br. Conforme já visto sobre o modelo cliente/servidor, nesse momento o navegador está fazendo uma requisição para o servidor do site kabum.com.br e o servidor está respondendo com o conteúdo (HTML) da página inicial. Após isso, você clicou em um link que o levou para a página de produtos. Nesse momento, o navegador fez uma nova requisição na qual o servidor prontamente respondeu, porém o servidor não sabe que essa nova solicitação também é uma requisição do mesmo Lenny que acabará de acessar a página inicial. É primordial ter esse entendimento para compreender qual problema essa tecnologia vem resolver.

Imagine agora outro cenário, você acessou o mesmo site de compras porém agora adicionou um produto ao carrinho e logo em seguida acessou a página de um novo produto. Dado que as requisições são independentes, como a página do novo produto recentemente acessada vai saber que existe um produto adicionado ao carrinho? como o servidor saberá que o produto adicionado ao carrinho pertence ao Lenny e não ao Moe (outra pessoa fictícia)?. Essa informação, o produto adicionado, precisa de alguma maneira ser armazenada em algum local e compartilhada entre as requisições. É aí que as sessões atuam.

Existem diversos casos de uso para as sessões, além do exemplo anterior do carrinho de compras poderíamos citar o status do login dos usuários, as preferências do usuário, o histórico de navegação, uma lista de produtos favoritos, etc. Agora que você tem uma compreensão básica sobre o que é uma sessão e qual problema ela resolve, vamos ver como o Spring trabalha com sessões.

Como falado anteriormente, a sessão deve permitir o armazenamento e o compartilhamento de informações entre as requisições. A princípio esse armazenamento pode ser feito na memória do computador servidor. Porém, essa abordagem apresenta problemas, por exemplo, se existir mais de um servidor provendo a aplicação - situação comum para escalar a aplicação - cada servidor terá sua própria memória e as informações armazenadas não serão compartilhadas entre eles. Portanto, essa abordagem não é muito atrativa.O Spring vai oferecer alternativas de abordagens para esse problema, como por exemplo armazenar as informações em um banco de dados.

Ai você pode pensar, mas se já vai armazenar no banco de dados, porque não armazenar diretamente no banco de dados? É um ponto importante e vai ter alternativas a isso como um banco de dados em memória como o Redis, por exemplo. Além do mais, é esperado que as informações armazenadas na sessão sejam temporárias e não precisam ser armazenadas para sempre no banco de dados. Por isso é importante considerar quais informações serão armazenadas na sessão. Para saber mais consulte a documentação oficial linkada no final do artigo.

Configurando o Spring Session

Como o intuito desse artigo é apenas apresentar o conceito de sessão e não entrar em detalhes sobre as diferentes abordagens, vamos utilizar do Spring Session com o armazenamento no banco de dados MySQL. Para isso, basta adicionar a dependência spring-session-jdbc ao arquivo pom.xml:

	<dependency>
			<groupId>org.springframework.session</groupId>
			<artifactId>spring-session-jdbc</artifactId>
		</dependency>

Além disso, adicione a linha abaixo no arquivo de configuração application.properties. Essa linha é responsável por criar as tabelas necessárias para armazenar as informações da sessão no banco de dados.

spring.session.jdbc.initialize-schema=always

Com essas alterações, o Spring Session criou as tabelas necessárias para armazenar as informações da sessão no banco de dados. Você pode conferir acessando seu banco de dados e verificando a existência das tabelas SPRING_SESSION e SPRING_SESSION_ATTRIBUTES.

Caso queira controlar a criação das tabelas, é importante saber que os scripts de criação estão no repositório do Spring Session no GitHub.

Utilizando a sessão

Para exemplificar a utilização da sessão vamos implementar uma funcionalidade de armazenar notas. Para isso vamos precisar de um novo controlador e uma nova visão. Crie o controlador NoteControllerj.java na pasta de controladores e nele adicione o seguinte código:

@Controller
public class NoteController {
    
    private final String SESSION_NOTE = "SESSION_NOTE";
    
    @GetMapping("/notes")
    public String notes(Model model, HttpSession session) {

        List<String> notes=(List<String>) session.getAttribute(SESSION_NOTE);
        model.addAttribute("notes", notes);
        return "notes/index";
    }

    @PostMapping("/notes/save")
    public String saveNote(@RequestParam String note, HttpSession session) {
        
        List<String> notes=(List<String>) session.getAttribute(SESSION_NOTE);
        if(notes==null){
            notes=new ArrayList<>();
        }
        notes.add(note);
        session.setAttribute(SESSION_NOTE,notes);
        
        return "redirect:/notes";
    }

}

Analisando o código anterior, a novidade existente é o parâmetro HttpSession. Esse objeto é responsável por armazenar as informações da sessão. Lembre-se que a sessão serve para guardar informações, e no caso do esse é o objeto que nos provê essa funcionalidade.

Para armazenar uma informação na sessão, basta utilizar o método setAttribute passando como parâmetro um nome de atributo que será usado para identificar essa informação e o valor que deseja armazenar. Já para recuperar uma informação, basta utilizar o método getAttribute passando como parâmetro o nome do mesmo atributo utilizado para guardar. Para evitar erros de digitação, é comum criar constantes para armazenar o nome dos atributos.

No método notes, é recuperado o valor do atributo SESSION_NOTE através do método session.getAttribute() e adicionado ao modelo para que possa ser exibido na visão. Já no método saveNote, é recuperado o valor do atributo SESSION_NOTE e adicionado a uma lista. Caso a lista não exista, é criada uma nova lista. O parâmetro note passado via formulário é então adicionado na lista e após isso, a lista é adicionada novamente a sessão com o método setAtributte.

Veja que apenas estamos manipulando dados, adicionado e lendo de um armazenamento. O Spring estará encarregado de compartilhar essa informação entre as requisições. Veja que acessamos o conteúdo da sessão em dois métodos diferentes.

Por fim crie a visão notes/index.html com apenas um formulário para adicionar uma nota e uma lista com as notas adicionadas. O intuito aqui é deixar o mais simples possível para facilitar o entendimento.

<h1>Notes</h1>
<form th:action="@{/notes/save}" th:method="POST">
    <input type="text" name="note" id="note">
    <button type="submit">Save</button>
</form>

<div th:unless="${#lists.isEmpty(notes)}">
    <ul>
        <li th:each="note : ${notes}" th:text="${note}"></li>
    </ul>
</div>

Agora acesse no navegador e tente adicionar alguma nota. Veja que mesmo que você navegue em diferentes páginas, a nota adicionada estará sempre disponível. Isso acontece porque o Spring Session está armazenando as informações da sessão no banco de dados e compartilhando entre as requisições. Faça um segundo teste, abra a mesma rota /notes em um novo navegador ou mesmo em modo privativo no mesmo navegador CTRL + SHIFT + N e adicione uma nova nota. Veja que as notas adicionadas em uma aba não estão disponíveis na outra. Isso acontece porque a sessão é atrelada ao cliente (nesse caso, o navegador em questão). Veja o banco de dados, o Spring vai fazer a inserção de um registro para cada cliente (navegador) que acesse a aplicação.

Para saber mais