Solucionado (ver solução)
Solucionado
(ver solução)
24
respostas

Integrar Upload de arquivo no projeto Mudi

Salve, pessoal!! Sou neófito neste universo e peço ajuda. Concluí o excelente curso Spring MVC autenticação com Spring Security, API Rest e AJAX. Eu gostaria de fazer uma alteração no cadastramento de novo pedido, imaginando um novo cenário, descrito abaixo:

A interface de cadastramento de pedido passa a ter a alteração em destaque abaixo, na descrição do produto, quando será permitido a escolha de um arquivo (em formato txt ou csv), contendo a descrição detalhada do produto. Este arquivo deverá ser carregado e lido na aplicação:

Novo pedido

Ao clicar em Carregar arquivo, o conteúdo do campo Descrição deverá ser preenchido, em quatro linhas, com:

1. o nome do arquivo selecionado
2. o tamanho em bytes do arquivo
3. a primeira linha
4. a última linha

Ao clicar em Cadastrar Pedido, o mesmo deverá ser persistido, como já acontecia, porém, com o valor do campo descrição composto conforme acima.

Tenho como base para o contexto de upload de arquivo, uma aplicação modelo, que contém a estrutura apresentada abaixo, da qual, eu imagino terei que incorporar módulos na aplicação Mudi;

Aplicação de uplodad de arquivo

Eu tenho dúvidas básicas, por exemplo, quais módulos da aplicação de upload eu deverei 'clonar' na aplicação Mudi, e dúvida mais básica ainda, de como associar o click no novo botão Carregar arquivo à execução do upload do arquivo identificado.

Agradeceria por alguma 'luz'! :)

Aceitaria, também, de bom grado, sugestão de modelos de aplicações web que contemplem persistência em banco de dados, a exemplo da aplicação Mudi, e que, também, faça upload e manuseio de arquivos em formatos txt e csv.

Obrigado,

Hideraldo Lima Fernandes

24 respostas

É uma pena que, após duas semanas, não houve nenhuma resposta. Eu imaginava que houvesse até uma IA, para auxiliar nisto, e não deixar perguntas, de alunos ativos, sem respostas, até mesmo, por mais idiota que possa ter sido o questionamento. Foi deum aluno, com dúvidas.

Meu plano vence este mês e eu estava decidido a renovar, mas, diante desta inércia neste fórum, entendo não me atenderá mais. Agradeço pelos cursos que fiz. Ótimos cursos, com ótimos professores. Mas vejo, que nesta questão de respostas aos alunos, há muito o que que avançar. De minha parte, foi uma decepção.

Saudações,

Hideraldo Lima Fernandes

Oi Hideraldo!

Você chegou a começar a implementação dessa mudança no projeto mudi? Manda aqui o código que fez até o momento para irmos te ajudando no que estiver com problemas ou dificuldades.

Salve, Rodrigo, Grato pelo retorno. Eu comecei, sim. Eu tenho um projeto em mente que envolve o upload e manuseio de arquivos em formato txt e csv. Eu gostaria, neste momento, sem alterar a estrutura do pedido, ou qualquer estrutura presente no projeto Mudi, de fazer as seguintes implementações: O formulário de pedido passará a receber o nome do arquivo para upload, definido no clique em Escolher arquivo. Apenas isto. Este nome de arquivo deverá ser persistido na coluna nomeProduto do modelo Mudi. Depois do clique em Cadastrar Pedido, antes da persistência, o upload deve ser efetuado, e as seguintes informações obtidas: Caminho do arquivo, persistido na coluna descricao. Tipo do arquivo, txt ou csv, peristido na coluna urlProduto. Tamanho em bytes do arquivo, persistido na coluna urlImagem. Estou entendendo que o clique em Cadastrar Pedido, fará a execução do controller PedidoController.java, e que lá deveremos inserir os códigos para uplodad e obtenção dos dados descritos acima, antes da execução de pedidoRepository.save(pedido).

O formulário de pedido fica com a seguinte estrutura, então:

Novo formulário de PedidoO projeto, após as inserções que fiz, de módulos do projeto piloto de upload de arquivos, pacotes br.com.alura.mvc.mudi.uploadingfiles*, ficou com a estrutura exibida abaixo:

Projeto Mudi, estrutura com upload de arquivo Gostaria de saber se há alguma forma de lhe enviar o código do projeto em arquivo compactado, ou devo enviar por aqui mesmo, o que me parece ficará bastante extenso e trabalhoso. Gostaria de saber também, se tens algum projeto modelo, que contemple persistência em banco de dados, como o Mudi, mas que tenha também rotinas de upload e manuseio de arquivos externos. Que pena, vi agora a mensagem para arrastar e soltar arquivos aqui, mas não aceita .zip :(

No aguardo, Muito obrigado por ora,

Abraços, Hideraldo Lima Fernandes

Para fazer o upload do arquivo não precisa mudar muita coisa no projeto, pois é algo relativamente simples.

Vai precisar alterar a página HTML do formulário, adicionando o seguinte atributo na tag <form>:

enctype="multipart/form-data"

E para receber o arquivo no controller basta declarar um novo parâmetro do tipo MultipartFile do Spring:

@PostMapping("novo")
public String novo(MultipartFile arquivo) {
    String nome = arquivo.getOriginalFilename();
    long tamanho = arquivo.getSize();
    String conteudo = new String(file.getBytes());

    //resto do codigo...
}

Bom dia, Rodrigo, tudo bem? Muito obrigado pelo valioso retorno.

Eu acho que entendi, mas continua uma dúvida (que deve ser bem banal...): No controller, já temos:

    @PostMapping("novo")
    public String novo(@Valid RequisicaoNovoPedido requisicao, BindingResult result) {
        if(result.hasErrors()) {
            return "pedido/formulario";
        }
        String username = SecurityContextHolder.getContext().getAuthentication().getName();
        User usuario = userRepository.findByUsername(username);
        Pedido pedido = requisicao.toPedido();
        pedido.setUser(usuario);
        pedidoRepository.save(pedido);

        return "redirect:/home";
    }

Como deve ficar este controller, com esta sugestão? Haverá dois @PostMapping("novo")??

Me desculpe pela ignorância. Eu venho de décadas de atuação no mundo mainframe, e estou apanhando bastante nesta mudança de paradigma. Eu tenho um projeto em mente, que tenho certeza que não é nada complicado...

Mas, eu vencendo esta etapa, de conseguir gravar em Pedido, desta nova forma, fazendo upload de um arquivo e obtendo os atributos, acho que deslancharei e não ficarei incomodando com dúvidas básicas.

Muito obrigado,

Abraços

Hideraldo Lima Fernandes

Sem problemas. Aos poucos você vai pegando as manhas e ficando fluente :)

A sugestão que tinha dado era para substituir o método no controller, para que o cadastro seja feito via upload de arquivo.

@PostMapping("novo")
public String novo(MultipartFile arquivo, BindingResult result) {
    if(result.hasErrors()) {
        return "pedido/formulario";
    }

    String username = SecurityContextHolder.getContext().getAuthentication().getName();
    User usuario = userRepository.findByUsername(username);

    Pedido pedido = new Pedido();
    pedido.setUser(usuario);

    pedido.setDescricao(arquivo.getOriginalFilename());
    pedido.setUrlImagem(arquivo.getSize());

    pedidoRepository.save(pedido);

    return "redirect:/home";
}

Rodrigo, Maravilha, muito obrigado mesmo!

Eu implementei exatamente como você sugeriu, tive que comentar a linha do setUrlImagem, para compilar, pois dá erro de formato, mas ao executar está ocorrendo o erro abaixo:

An Errors/BindingResult argument is expected to be declared immediately after the model attribute, the @RequestBody or the @RequestPart arguments to which they apply: public java.lang.String br.com.alura.mvc.mudi.controller.PedidoController.novo(org.springframework.web.multipart.MultipartFile,org.springframework.validation.BindingResult)

O controller está deste jeito:

    package br.com.alura.mvc.mudi.controller;

    import javax.validation.Valid;

    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.security.core.context.SecurityContextHolder;
    import org.springframework.stereotype.Controller;
    import org.springframework.validation.BindingResult;
    import org.springframework.web.bind.annotation.GetMapping;
    import org.springframework.web.bind.annotation.PostMapping;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.multipart.MultipartFile;

    import br.com.alura.mvc.mudi.dto.RequisicaoNovoPedido;
    import br.com.alura.mvc.mudi.model.Pedido;
    import br.com.alura.mvc.mudi.model.User;
    import br.com.alura.mvc.mudi.repository.PedidoRepository;
    import br.com.alura.mvc.mudi.repository.UserRepository;

    @Controller
    @RequestMapping("pedido")
    public class PedidoController {

    @Autowired
    private PedidoRepository pedidoRepository;

    @Autowired
    private UserRepository userRepository;

    @GetMapping("formulario")
    public String formulario(RequisicaoNovoPedido requisicao) {
        return "pedido/formulario";
    }

    @PostMapping("novo")
    public String novo(MultipartFile arquivo, BindingResult result) {
        if(result.hasErrors()) {
            return "pedido/formulario";
        }

        String username = SecurityContextHolder.getContext().getAuthentication().getName();
        User usuario = userRepository.findByUsername(username);

        Pedido pedido = new Pedido();
        pedido.setUser(usuario);

        pedido.setDescricao(arquivo.getOriginalFilename());
//        pedido.setUrlImagem(arquivo.getSize());

        pedidoRepository.save(pedido);

        return "redirect:/home";
    }
}

Você poderia me dar mais esta dica, de como resolver este erro?

Obrigado,

Abraço,

Hideraldo Lima Fernandes

Ah sim, vai precisar alterar esse método então, por conta do jeito que foi feito ao longo desse curso:

@PostMapping("novo")
public String novo(MultipartFile arquivo) {
    if(arquivo == null) {
        return "pedido/formulario";
    }

    String username = SecurityContextHolder.getContext().getAuthentication().getName();
    User usuario = userRepository.findByUsername(username);

    Pedido pedido = new Pedido();
    pedido.setUser(usuario);

    pedido.setDescricao(arquivo.getOriginalFilename());
    pedido.setUrlImagem("" + arquivo.getSize());

    pedidoRepository.save(pedido);

    return "redirect:/home";
}

Salve, Rodrigo, Muito obrigado pelo retorno.

Fiz a alteração, mas continua dando o mesmo erro:

An Errors/BindingResult argument is expected to be declared immediately after the model attribute, the @RequestBody or the @RequestPart arguments to which they apply: public java.lang.String br.com.alura.mvc.mudi.controller.PedidoController.novo(org.springframework.web.multipart.MultipartFile,org.springframework.validation.BindingResult) java.lang.IllegalStateException: An Errors/BindingResult argument is expected to be declared immediately after the model attribute, the @RequestBody or the @RequestPart arguments to which they apply: public java.lang.String br.com.alura.mvc.mudi.controller.PedidoController.novo(org.springframework.web.multipart.MultipartFile,org.springframework.validation.BindingResult)

Será que falta mais algum ajuste? Será porque nomeProduto como consta como Not Null no modelo e deveríamos de alguma forma tratar isto, como era tratado na diretiva anterior ( if(result.hasErrors() )?

Grato pela atenção,

Abraço,

Hideraldo Lima Fernandes

Confere se o método está do jeito que mandei na mensagem anterior, contendo apenas o MultipartFile como parâmetro. Reinicia o projeto também, para garantir que as mudanças tiveram efeito.

Salve, Rodrigo, Grato pelo retorno.

O controller está como você mandou:

@Controller
@RequestMapping("pedido")
public class PedidoController {

@Autowired
private PedidoRepository pedidoRepository;

@Autowired
private UserRepository userRepository;

@GetMapping("formulario")
public String formulario(RequisicaoNovoPedido requisicao) {
    return "pedido/formulario";
}

@PostMapping("novo")
public String novo(MultipartFile arquivo, BindingResult result) {
    if(arquivo == null) {
        return "pedido/formulario";
    }

    String username = SecurityContextHolder.getContext().getAuthentication().getName();
    User usuario = userRepository.findByUsername(username);

    Pedido pedido = new Pedido();
    pedido.setUser(usuario);

    pedido.setDescricao(arquivo.getOriginalFilename());

// pedido.setUrlImagem(arquivo.getSize());

    pedidoRepository.save(pedido);

    return "redirect:/home";
}

}

E eu já havia reiniciado, pensando que poderia ser isto, mas continua ocorrendo o erro.

Obrigado,

Hideraldo Lima Fernandes

O método chamado novo está diferente do que eu mandei:

public String novo(MultipartFile arquivo, BindingResult result) {

É para ficar assim:

public String novo(MultipartFile arquivo) {

Salve, Rodrigo, Grato pelo retorno. Agradeço pela paciência, a qual admiro muito. Realmente, aquele BindingResult.. não deveria estar lá.

Agora, ocorreu um outro erro, apontando para o formulário. Este erro não ocorria antes desta implementação de hoje.

O erro é o seguinte:

An error happened during template parsing (template: "class path resource [templates/pedido/formulario.html]") org.thymeleaf.exceptions.TemplateInputException: An error happened during template parsing (template: "class path resource [templates/pedido/formulario.html]") . . Caused by: org.attoparser.ParseException: Error during execution of processor 'org.thymeleaf.spring5.processor.SpringInputFileFieldTagProcessor' (template: "pedido/formulario" - line 17, col 56) at org.attoparser.MarkupParser.parseDocument(MarkupParser.java:393) at org.attoparser.MarkupParser.parse(MarkupParser.java:257) at org.thymeleaf.templateparser.markup.AbstractMarkupTemplateParser.parse(AbstractMarkupTemplateParser.java:230) ... 73 more Caused by: org.thymeleaf.exceptions.TemplateProcessingException: Error during execution of processor 'org.thymeleaf.spring5.processor.SpringInputFileFieldTagProcessor' (template: "pedido/formulario" - line 17, col 56) at org.thymeleaf.processor.element.AbstractAttributeTagProcessor.doProcess(AbstractAttributeTagProcessor.java:117) at org.thymeleaf.processor.element.AbstractElementTagProcessor.process(AbstractElementTagProcessor.java:95) at org.thymeleaf.util.ProcessorConfigurationUtils$ElementTagProcessorWrapper.process(ProcessorConfigurationUtils.java:633) at org.thymeleaf.engine.ProcessorTemplateHandler.handleStandaloneElement(ProcessorTemplateHandler.java:918) at org.thymeleaf.engine.TemplateHandlerAdapterMarkupHandler.handleStandaloneElementEnd(TemplateHandlerAdapterMarkupHandler.java:260) at org.thymeleaf.templateparser.markup.InlinedOutputExpressionMarkupHandler$InlineMarkupAdapterPreProcessorHandler.handleStandaloneElementEnd(InlinedOutputExpressionMarkupHandler.java:256) at org.thymeleaf.standard.inline.OutputExpressionInlinePreProcessorHandler.handleStandaloneElementEnd(OutputExpressionInlinePreProcessorHandler.java:169) at org.thymeleaf.templateparser.markup.InlinedOutputExpressionMarkupHandler.handleStandaloneElementEnd(InlinedOutputExpressionMarkupHandler.java:104) at org.attoparser.HtmlVoidElement.handleOpenElementEnd(HtmlVoidElement.java:92) at org.attoparser.HtmlMarkupHandler.handleOpenElementEnd(HtmlMarkupHandler.java:297) at org.attoparser.MarkupEventProcessorHandler.handleOpenElementEnd(MarkupEventProcessorHandler.java:402) at org.attoparser.ParsingElementMarkupUtil.parseOpenElement(ParsingElementMarkupUtil.java:159) at org.attoparser.MarkupParser.parseBuffer(MarkupParser.java:710) at org.attoparser.MarkupParser.parseDocument(MarkupParser.java:301) ... 75 more Caused by: java.lang.IllegalStateException: Neither BindingResult nor plain target object for bean name 'requisicaoNovoPedido' available as request attribute . . . O formulário, depois da adaptações que fiz, ficou da seguinte, maneira:

    <div class="container">
        <div th:replace="~{base :: titulo('Novo Pedido')}"></div>

        <div class="card ">
            <form th:action="@{/pedido/novo}" th:object="${requisicaoNovoPedido}" class="card-body" method="post" enctype="multipart/form-data">

                <div class="form-group">
                    <label>Escolha do arquivo</label>

                    <div  enctype="multipart/form-data" >
                        <label>Arquivo de entrada:</label>
                        <input type="file" name="file" id="nomeArquivo" th:field="*{nomeProduto}" th:errorclass="is-invalid" for="nomeProduto"></input>
                        <div class="invalid-feedback" th:errors="*{nomeProduto}">
                            Erros do nome do arquivo
                        </div>
                    </div>
                </div>

                <div class="form-group">
                    <label for="descricao">Caminho do arquivo</label>
                    <input class="form-control"  th:field="*{descricao}" placeholder="aqui conterá o Caminho do arquivo">
                </div>

                <div class="form-group">
                    <label for="urlProduto">Tipo do arquivo</label>
                    <input th:field="*{urlProduto}" class="form-control" placeholder="aqui conterá o Tipo do arquivo"/>
                </div>

                <div class="form-group">
                    <label for="urlImagem">Tamanho do arquivo</label>
                    <input th:field="*{urlImagem}" class="form-control" placeholder="aqui conterá o Tamanho do arquivo"/>
                </div>

                <button class="btn btn-primary" type="submit">Cadastrar Pedido</button>
            </form>
        </div>
    </div>
</body>

É bem possível que as adaptações que fiz contenham inconsistências. Você poderia apontar a possível causa do erro, por gentileza? A linha 17 é a que contém o primeiro input.

Obrigado,

Hideraldo Lima Fernandes

Vai precisar fazer alterações no código dessa página html também.

Altere a tag form para ficar assim (sem o atributo th:object):

<form th:action="@{/pedido/novo}" class="card-body" method="post" enctype="multipart/form-data">

No input do arquivo, troque o atributo name="file" para: name="arquivo"

Talvez precise remover o atributo th:field dos outros inputs, mas precisa testar para ver se acontece algum erro com esse atributo.

Rodrigo, Grato pela atenção. Fiz as alterações solicitadas, na tag form e atributo name. E tive, realmente, que remover th:field de todos os inputs.

Agora está ocorrendo erro no formulário home.html, conforme abaixo:

Caused by: org.attoparser.ParseException: Exception evaluating SpringEL expression: "pedido.status.name()" (template: "usuario/home" - line 21, col 11)

Segue, abaixo, código de home.html:

    <div class="container">
        <div th:replace="~{base :: titulo('Meus Pedidos')}"></div>

        <nav class="navbar navbar-expand navbar-light bg-light d-flex justify-content-between mb-3">
            <div class="navbar-nav">
                <a th:classappend="${status} == null ? 'active'" class="nav-item nav-link" th:href="@{/usuario/pedido}">Todos</a>
                <a th:classappend="${status} == 'aguardando' ? 'active'" class="nav-item nav-link" th:href="@{/usuario/pedido/aguardando}">Aguardando</a>
                <a th:classappend="${status} == 'aprovado' ? 'active'" class="nav-item nav-link" th:href="@{/usuario/pedido/aprovado}">Aprovado</a>
                <a th:classappend="${status} == 'entregue' ? 'active'" class="nav-item nav-link" th:href="@{/usuario/pedido/entregue}">Entregue</a>
            </div>
            <a href="/pedido/formulario"><button class="btn btn-outline-secondary my-2 my-sm-0">Novo</button></a>
        </nav>

        <div class="card mb-3" th:each="pedido : ${pedidos}">
            <th:block th:switch="${pedido.status.name()}">
                <div th:case="'AGUARDANDO'" class="card-header alert-warning" th:text="${pedido.nomeProduto}">Nome do produto</div>
                <div th:case="'APROVADO'" class="card-header alert-success" th:text="${pedido.nomeProduto}">Nome do produto</div>
                <div th:case="'ENTREGUE'" class="card-header alert-dark" th:text="${pedido.nomeProduto}">Nome do produto</div>
            </th:block>

            <div class="card-body">
                <div class="row">
                    <div class="col-12 col-sm-8  mb-3">
                        <div class="row">
                            <div class="col-md-5">Valor: <span th:if="${pedido.valorNegociado} != null" th:text="${'R$ ' + #numbers.formatDecimal(pedido.valorNegociado,3,'POINT',2,'COMMA')}">200,99</span></div>
                            <div class="col-md-7">Data da entrega: <span th:text="${#temporals.format(pedido.dataDaEntrega, 'dd/MM/yyyy')}">10/02/2020</span></div>
                        </div>

                        <div>Produto</div>
                        <div> <input class="form-control" th:value="${pedido.urlProduto}" value="url do produto"/></div>

                        <div>Descrição</div>
                        <div>
                            <textarea class="form-control" th:text="${pedido.descricao}">descrição do pedido</textarea>
                        </div>
                    </div>
                    <div class="col-12 col-sm-4">
                        <div>
                            <img class="img-thumbnail" th:src="${pedido.urlImagem}" src=""/>
                        </div>
                    </div>
                </div>
            </div>
        </div>
    </div>
</body>

Abaixo, formulario.html:

    <div class="container">
        <div th:replace="~{base :: titulo('Novo Pedido')}"></div>

        <div class="card ">
            <form th:action="@{/pedido/novo}" class="card-body" method="post" enctype="multipart/form-data">

                <div class="form-group">
                    <label>Escolha do arquivo</label>

                    <div  enctype="multipart/form-data" >
                        <label>Arquivo de entrada:</label>
                        <input type="file" name="arquivo" for="nomeProduto"></input>
                        <div class="invalid-feedback" >
                            Erros do nome do arquivo
                        </div>
                    </div>
                </div>

                <div class="form-group">
                    <label for="descricao">Caminho do arquivo</label>
                    <input class="form-control"  placeholder="aqui conterá o Caminho do arquivo">
                </div>

                <div class="form-group">
                    <label for="urlProduto">Tipo do arquivo</label>
                    <input class="form-control" placeholder="aqui conterá o Tipo do arquivo"/>
                </div>

                <div class="form-group">
                    <label for="urlImagem">Tamanho do arquivo</label>
                    <input  class="form-control" placeholder="aqui conterá o Tamanho do arquivo"/>
                </div>

                <button class="btn btn-primary" type="submit">Cadastrar Pedido</button>
            </form>
        </div>
    </div>
</body>

Abaixo, código do controller:

Poderia, por gentileza, me orientar neste novo erro?

Obrigado,

Hideraldo Lima Fernandes

Código do controller, que não coube no outro post:

package br.com.alura.mvc.mudi.controller;

import javax.validation.Valid;

import org.springframework.beans.factory.annotation.Autowired; import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.stereotype.Controller; import org.springframework.validation.BindingResult; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.multipart.MultipartFile;

import br.com.alura.mvc.mudi.dto.RequisicaoNovoPedido; import br.com.alura.mvc.mudi.model.Pedido; import br.com.alura.mvc.mudi.model.User; import br.com.alura.mvc.mudi.repository.PedidoRepository; import br.com.alura.mvc.mudi.repository.UserRepository;

@Controller @RequestMapping("pedido") public class PedidoController {

@Autowired
private PedidoRepository pedidoRepository;

@Autowired
private UserRepository userRepository;

@GetMapping("formulario")
public String formulario(RequisicaoNovoPedido requisicao) {
    return "pedido/formulario";
}

@PostMapping("novo")
public String novo(MultipartFile arquivo) {
    if(arquivo == null) {
        return "pedido/formulario";
    }

    String username = SecurityContextHolder.getContext().getAuthentication().getName();
    User usuario = userRepository.findByUsername(username);

    Pedido pedido = new Pedido();
    pedido.setUser(usuario);

    pedido.setNomeProduto(arquivo.getName());
    pedido.setDescricao(arquivo.getOriginalFilename());
    pedido.setUrlImagem(arquivo.toString());

// pedido.setUrlProduto(valueOf(arquivo.getSize()));

    pedidoRepository.save(pedido);

    return "redirect:/home";
}

}

Obrigado,

Faltou setar o status do pedido. O método novo no controller deve ficar assim então:

@PostMapping("novo")
public String novo(MultipartFile arquivo) {
    if(arquivo == null) {
        return "pedido/formulario";
    }

    String username = SecurityContextHolder.getContext().getAuthentication().getName();
    User usuario = userRepository.findByUsername(username);

    Pedido pedido = new Pedido();
    pedido.setUser(usuario);

    pedido.setDescricao(arquivo.getOriginalFilename());
    pedido.setUrlImagem("" + arquivo.getSize());

    pedido.setStatus(StatusPedido.AGUARDANDO);

    pedidoRepository.save(pedido);

    return "redirect:/home";
}

Rodrigo, Grato pela atenção. Me desculpe, mas fiz a alteração e o erro continua exatamente o mesmo:

Caused by: org.attoparser.ParseException: Exception evaluating SpringEL expression: "pedido.status.name()" (template: "usuario/home" - line 21, col 11)

Segue, abaixo, código do controller:

package br.com.alura.mvc.mudi.controller;

import javax.validation.Valid;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Controller;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.multipart.MultipartFile;

import br.com.alura.mvc.mudi.dto.RequisicaoNovoPedido;
import br.com.alura.mvc.mudi.model.Pedido;
import br.com.alura.mvc.mudi.model.StatusPedido;
import br.com.alura.mvc.mudi.model.User;
import br.com.alura.mvc.mudi.repository.PedidoRepository;
import br.com.alura.mvc.mudi.repository.UserRepository;

@Controller
@RequestMapping("pedido")
public class PedidoController {

@Autowired
private PedidoRepository pedidoRepository;

@Autowired
private UserRepository userRepository;

@GetMapping("formulario")
public String formulario(RequisicaoNovoPedido requisicao) {
    return "pedido/formulario";
}

@PostMapping("novo")
public String novo(MultipartFile arquivo) {
    if(arquivo == null) {
        return "pedido/formulario";
    }

    String username = SecurityContextHolder.getContext().getAuthentication().getName();
    User usuario = userRepository.findByUsername(username);

    Pedido pedido = new Pedido();
    pedido.setUser(usuario);

    pedido.setDescricao(arquivo.getOriginalFilename());
    pedido.setUrlImagem("" + arquivo.getSize());

    pedido.setStatus(StatusPedido.AGUARDANDO);

    pedidoRepository.save(pedido);

    return "redirect:/home";
}

}

Não estou reenviando o código de home.html porque não o alterei em nada.

Reiniciei o projeto e ocorre o erro, mesmo assim.

Poderia reavaliar a ocorrência, por gentileza?

Obrigado,

Hideraldo Lima Fernandes

Deve ter algum pedido no banco de dados que foi salvo sem o status. Acesse o banco e apague da tabela de pedidos os registros sem status ou coloque como status o valor AGUARDANDO.

Rodrigo, Maravilha!!! Deixou de ocorrer o erro.

Agora, só uma dúvida, eu prometo ser a última do dia:

Na implementação que eu havia feito, antes de falar com você, quando inclui no projeto os dois pacotes br.com.alura.mvc.mudi.uploadingfiles*, em um deles existe o módulo StorageProperties.java, exibido abaixo, onde aponta para qual diretório deve ser gravado o arquivo.

package br.com.alura.mvc.mudi.uploadingfiles.storage;

import org.springframework.boot.context.properties.ConfigurationProperties;

@ConfigurationProperties("storage")
public class StorageProperties {

/**
 * Folder location for storing files
 */
private String location = "upload-dir";

public String getLocation() {
    return location;
}

public void setLocation(String location) {
    this.location = location;
}

}

Acontece que, me parece, que este módulo sequer está sendo executado! Na verdade, estou entendendo que os dois pacotes que inseri são desnecessários. Estes pacotes, bem como os diretórios que incorporei, estão em destaques abaixo:

estrutura projeto A minha pergunta é : Após clicar em Cadastra Pedido, em formulário.html, está ocorrendo corretamente a persistência no banco de dados, mas, quanto ao upload, ele é efetuado? Para onde vai o arquivo?

Te prometo que, sanada a dúvida acima eu tentarei evoluir por aqui e não lhe incomodarei mais!!

Muito obrigado por todo apoio ao longo do dia!! Evolui muito e não tenho dúvidas que já me ajudou muito mesmo para começar a deslanchar melhor sozinho.

Abraços,

Hideraldo Lima Fernandes

solução!

Oi Hideraldo!

Na verdade esses pacotes e classes de exemplo de upload de fato não foram usados e podem ser apagados do projeto. Sobre o arquivo, no código que te mandei de exemplo ele apenas pega as informações do arquivo para salvar na tabela de pedidos. Em nenhum momento o arquivo em si está sendo salvo.

Se além de salvar as informações na tabela você também quiser salvar o arquivo, então terá que alterar o código do método novo no controller, para também salvar o arquivo:

@PostMapping("novo")
public String novo(MultipartFile arquivo) {
    if(arquivo == null) {
        return "pedido/formulario";
    }

    String username = SecurityContextHolder.getContext().getAuthentication().getName();
    User usuario = userRepository.findByUsername(username);

    Pedido pedido = new Pedido();
    pedido.setUser(usuario);
    pedido.setDescricao(arquivo.getOriginalFilename());
    pedido.setUrlImagem("" + arquivo.getSize());
    pedido.setStatus(StatusPedido.AGUARDANDO);

    pedidoRepository.save(pedido);

    //salva o arquivo numa pasta chamada uploads:
    try {
        byte[] bytes = arquivo.getBytes();
        Path path = Paths.get("uploads/" + arquivo.getOriginalFilename());
        Files.write(path, bytes);
    } catch (IOException e) {
        e.printStackTrace();
    }

    return "redirect:/home";
}

Bom dia, Rodrigo, tudo bem? Show!! Show de bola meu amigo. Agora está exatamente como preciso, para poder avançar. Na verdade pretendo ler e manusear os arquivos.

Quero lhe agradecer, muito, muito mesmo. Não tem preço que pague tal apoio. Lhe desejo tudo de bom, sempre em sua vida.

Podemos considerar este tópico como muito bem resolvido!!

Abraços,

Hideraldo Lima Fernandes

Perfeito. Bons estudos! :)

Muito obrigado, Abraços. :)