Upload de imagem com Spring e UIKit

Prezados implementando upload no meu projeto, me orientei pelo projeto da Algaworks Brewer ( faz o upload da foto da cerveja), utilizando um framework front-end UIkit
O upload esta sendo feito, pelo que pude perceber que em uma pasta com o nome “null” esta servindo como local onde esta sendo armazenado os arquivos, mais tem algo bem estranho ocorrendo e eu não sei dizer o motivo.

Bem primeiro a imagem do arquivo que foi feito upload não esta aparecendo e percebo o erro 404 esta ocorrendo em um GET, segundo observei que é criado uma pasta dentro da pasta do projeto só que com o nome null, quando deveria ser a pasta foto

Entendo que não seja muito elucidativo o que descrevi mais se alguém que faz uso destas tecnologias puder comentar

O projeto faz uso do SpingBoot, Thymeleaf e Bootstrap

Cadê o código, jovem?! Seu print só nos permite opinar o que vc já falou na descrição, o path da imagem não existe.
Como é sua rotina de criação da pasta, do arquivo, etc? Nos ajude a te ajudar :slight_smile:

Olá Raphael! bom dia meu caro.

Então sobre o código como disse ele é extraído do projeto da Algaworks que ta no Git onde eu estudei até o 25.2 pois tudo é uma sequencia,
Algaworks

eu fiz dois cursos desta empresa porém este que abordou sobre o caso infelizmente não pude fazer, venho com o java já há algum tempo mais longe de ser um profissional, olha eu também fiz umas alterações de forma que o erro é outro observei o seguinte:
O erro agora é de servidor 500, ou seja o upload da imagem é feita e ao tentar ler para mostrar a imagem ocorre o erro 500 conforme as três imagens abaixo o Header da requisição o Response e a pasta onde esta sendo feito o upload.

Então como o código não é meu e sim do projeto do curso eu fiz utilização do mesmo por entender que utilizando a lib UIkit uma lib Frot-End tem suas vantagens e o código para fazer ela funcionar um javascript com poucas linhas e o upload esta sendo feito então o problema é no servidor, onde esta sendo salvo ( o local ) e por não estar encontrando este caminho vem o erro, o erro do response vem de uma exceção vem então o código fonte extraído do git

FotoStorageLocal.jar ( comentei dentro do código nos metodos de criar pasta e de recuperar a foto )

class FotoStorageLocal implements FotoStorage {

    private static final Logger logger = LoggerFactory.getLogger(FotoStorageLocal.class);
    private static final String THUMBNAIL_PREFIX = "thumbnail.";

    private Path local;
    private Path localTemporario;

    public FotoStorageLocal() {
	    this(getDefault().getPath(System.getenv("HOME"), ".ecommercefotos"));
    }

    public FotoStorageLocal(Path path) {
	    this.local = path;
	    criarPastas();
    }

    @Override
    public String salvarTemporariamente(MultipartFile[] files) {
	    String novoNome = null;
	    if (files != null && files.length > 0) {
		    MultipartFile arquivo = files[0];
		    novoNome = renomearArquivo(arquivo.getOriginalFilename());
		    try {
			    arquivo.transferTo(new File(this.localTemporario.toAbsolutePath().toString() + getDefault().getSeparator() + novoNome));
		    } catch (IOException e) {
			    throw new RuntimeException("Erro salvando a foto na pasta temporária", e);
		    }
	    }		
	    return novoNome;
    }

    @Override
    public byte[] recuperarFotoTemporaria(String nome) {
	    try {
		    return Files.readAllBytes(this.localTemporario.resolve(nome));
	    } catch (IOException e) {
		    throw new RuntimeException("Erro lendo a foto temporária", e);
	    }
    }

    @Override
    public void salvar(String foto) {
	    try {
		    Files.move(this.localTemporario.resolve(foto), this.local.resolve(foto));
	    } catch (IOException e) {
		    throw new RuntimeException("Erro movendo a foto para destino final", e);
	    }
	
	    try {
		    Thumbnails.of(this.local.resolve(foto).toString()).size(40, 68).toFiles(Rename.PREFIX_DOT_THUMBNAIL);
	    } catch (IOException e) {
		    throw new RuntimeException("Erro gerando thumbnail", e);
	    }
    }

    @Override
    public byte[] recuperar(String nome) {
                // Não esta sendo possivel recuperar a foto na pasta mais no Response em anexo vemos que o nome da imagem esta errado e também vemos o nome da pasta  
	    try {
		    return Files.readAllBytes(this.local.resolve(nome));
	    } catch (IOException e) {
		    throw new RuntimeException("Erro lendo a foto " + nome + " na pasta " + this.local.toString(), e);
	    }
    }

    @Override
    public byte[] recuperarThumbnail(String fotoCerveja) {
	    return recuperar(THUMBNAIL_PREFIX + fotoCerveja);
    }

    @Override
    public void excluir(String foto) {
	    try {
		    Files.deleteIfExists(this.local.resolve(foto));
		    Files.deleteIfExists(this.local.resolve(THUMBNAIL_PREFIX + foto));
	    } catch (IOException e) {
		    logger.warn(String.format("Erro apagando foto '%s'. Mensagem: %s", foto, e.getMessage()));
	    }
	
    }

    private void criarPastas() {
                // Aqui onde é criado as pastas que e onde ficara os arquivos apos upload
                // Este código esta criando a pasta com o nome null e sei que o motivo é o atributo
                // this.local não conter valor contudo em nenhum fonte encontrei uma passagem de parametros para a chamada desta classe e ao meu entender a pasta a ser criada deve ser fotos, ou deveria
	    try {
		    Files.createDirectories(this.local);
		    this.localTemporario = getDefault().getPath(this.local.toString(), "temp");
		    Files.createDirectories(this.localTemporario);
		
		    if (logger.isDebugEnabled()) {
			    logger.debug("Pastas criadas para salvar fotos.");
			    logger.debug("Pasta default: " + this.local.toAbsolutePath());
			    logger.debug("Pasta temporária: " + this.localTemporario.toAbsolutePath());
		    }
	    } catch (IOException e) {
		    throw new RuntimeException("Erro criando pasta para salvar foto", e);
	    }
    }

    private String renomearArquivo(String nomeOriginal) {
	    String novoNome = UUID.randomUUID().toString() + "_" + nomeOriginal;
	
	    if (logger.isDebugEnabled()) {
		    logger.debug(String.format("Nome original: %s, novo nome: %s", nomeOriginal, novoNome));
	    }
	
	    return novoNome;		
    }

}

Aqui abaixo temos a classe de controller da foto

@RestController
@RequestMapping("/fotos")
public class FotosController {

private static final Logger logger = LoggerFactory.getLogger(FotosController.class);
	
@Autowired
private FotoStorage fotoStorage;

@PostMapping
public DeferredResult<FotoDTO> upload(@RequestParam("files[]") MultipartFile[] files) {
	DeferredResult<FotoDTO> resultado = new DeferredResult<>();

	Thread thread = new Thread(new FotoStorageRunnable(files, resultado, fotoStorage));
	thread.start();
	
	return resultado;
}

@GetMapping("/temp/{nome:.*}")
public byte[] recuperarFotoTemporaria(@PathVariable String nome) {
	return fotoStorage.recuperarFotoTemporaria(nome);
}

@GetMapping("/{nome:.*}")
public byte[] recuperar(@PathVariable String nome) {
	return fotoStorage.recuperar(nome);
}	

}

e pelo que pude perceber uma classe de configuracao do serviço do spring

@Configuration
@ComponentScan(basePackageClasses = {
              CategoryService.class})
public class ServiceConfig {

    @Bean
    public FotoStorage fotoStorage() {
	    return new FotoStorageLocal();
    }		

}

Não entendi ainda o motivo da pasta a ser criada esta sendo criada com o nome “null” mais também em nenhum local do código eu vejo a passagem de parâmetro com o nome da pasta se pensar bem nome é e pode ser qualquer um correto? mais estou hoje novamente olhando este código pra ver se desenrolo isto.

pode ser a maneira que esta buscando o local o “HOME” dependendo do sistema operacional pode mudar, testa com “user.home”

Olá, alguma solução para este tópico ?? Estou com o mesmo problema.