web-dev-qa-db-fra.com

Stocker des images dans la botte de printemps H2 thymeleaf

Bonne journée. Je veux stocker une image dans une base de données h2, puis récupérer et afficher la même image dans une page html. J'utilise la méthode de démarrage de printemps et de téléchargement de fichier, mais des erreurs se produisent dans les résultats de la liaison.

Voici les pages/classes:

Catégorie.Java

package com.vishal.project.entities;

@Entity
@Table(name="category")
public class Category implements Serializable {
private static final long serialVersionUID = 1L;

@Id
@GeneratedValue(strategy= GenerationType.IDENTITY)
@Column(name="ID")
private Long id;

@Size(min=1, max=90)
@Column(name="CATEGORY_NAME")
private String CategoryName;


@Lob
@Column(name="CATEGORY_PHOTO")
private byte[] CategoryPhoto;


public Category(Long id, @Size(min = 1, max = 90) String categoryName, byte[] categoryPhoto) {
    super();
    this.id = id;
    CategoryName = categoryName;
    CategoryPhoto = categoryPhoto;
}

public byte[] getCategoryPhoto() {
    return CategoryPhoto;
}

public void setCategoryPhoto(byte[] categoryPhoto) {
    CategoryPhoto = categoryPhoto;
}

public Category() {}

@OneToMany(mappedBy = "category", cascade=CascadeType.ALL, orphanRemoval=true)
private Set<Book> Books = new HashSet<>();

public Set<Book> getBooks() {
    return Books;
}

public void setBooks(Set<Book> books) {
    Books = books;
}

public Long getId() {
    return id;
}
public void setCategoryID(Long id) {
    this.id = id;
}
public String getCategoryName() {
    return CategoryName;
}
public void setCategoryName(String categoryName) {
    CategoryName = categoryName;
}

@Override
public String toString() {

    return "Category ID:" + id + 
           "Category Name:"+ CategoryName;
}


}

Categorycontroller.Java

package com.vishal.project.web;


import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.servlet.mvc.support.RedirectAttributes;
import com.vishal.project.entities.Category;
import com.vishal.project.services.CategoryService;
import com.vishal.project.util.Message;


@Controller
@RequestMapping(value="/categories")
public class CategoryController {


private final Logger logger = LoggerFactory.getLogger(BookController.class);

@Autowired
private MessageSource  messageSource;

@Autowired 
private CategoryService categoryService;

@GetMapping
public String list(Model uiModel) {
    logger.info("Listing categories:");
    List<Category> categories = categoryService.findALL();
    uiModel.addAttribute("categories", categories);
    logger.info("No. of categories: " + categories.size());
    return "categories";
}

@GetMapping(value = "/{id}" , consumes="Multipart/formdata")
public String show(@PathVariable Long id, Model model) {
    Category category = categoryService.findbyID(id);


    model.addAttribute("category", category);
    return "showCategory";
}

@GetMapping(value = "/edit/{id}")
public String updateForm(@PathVariable Long id, Model model) {
    model.addAttribute("category", categoryService.findbyID(id));
    return "updateCategory";
}

@GetMapping(value = "/new")
public String create(Model uiModel) {
    logger.info("creating Category ...");
    Category category = new Category();     

    uiModel.addAttribute("category", category);
    return "updateCategory";
}


@PostMapping(value = "/upload")
public String saveCategory(@Valid @ModelAttribute("category") Category category, BindingResult bindingResult,
        Model uiModel, HttpServletRequest httpServletRequest, RedirectAttributes redirectAttributes,
        Locale locale, @RequestParam(value="file", required=true) MultipartFile file) {
    logger.info("Creating Category....");
    logger.info("Category ID" + category.getId());
    logger.info("Category ID" + category.getCategoryName());
    logger.info("Category ID" + category.getCategoryPhoto());
    if(bindingResult.hasErrors())
    {
        logger.info("Error:", bindingResult.getAllErrors());
        logger.debug("field Error:", bindingResult.getFieldError());
        uiModel.addAttribute("message", new Message("error", messageSource.getMessage("category_save_fail", new Object[] {}, locale)));
        uiModel.addAttribute("category", category);
        return "updateCategory";
    }
    uiModel.asMap().clear();
    redirectAttributes.addFlashAttribute("message", 
            new Message("success", messageSource.getMessage("Category_save_success", new Object[] {}, locale)));
    //process upload file 
    logger.info("File Name :", file.getName() );
    logger.info("File Size :", file.getSize() );
    logger.info("File content type :", file.getContentType() );
    if(file != null) {
    byte[] filecontent = null;
    try
    {
        InputStream inputStream = file.getInputStream();
        if(inputStream == null) 
            logger.debug("file InputStream is null");
        filecontent = IOUtils.toByteArray(inputStream);     
        category.setCategoryPhoto(filecontent);
    }catch(IOException ex) {
        logger.error("Error Saving uploaded file");
    }
    category.setCategoryPhoto(filecontent);
    }

    categoryService.save(category);
    return "redirect:/categories/" + category.getId().toString();
}

}

 category Image

catégorieShow.page

<body>
<div th:replace="fragments/header_admin :: header_admin">Header</div>
<div class="container">

<h1>Category Details</h1>

<div>
    <form class="form-horizontal" th:object="${category}" >
    <input type="hidden" th:field="*{id}"/>
        <div class="form-group">
            <label class="col-sm-2 control-label">Category Name:</label>
            <div class="col-sm-10">
                <p class="form-control-static" th:text="${CategoryName}"> 
</p></div>
        </div>

        <div class="form-group">
            <label class="col-sm-2 control-label" >Category Photo</label>
            <div class="col-sm-10">
                <p class="form-control-static" ><img alt="CatName" 
  th:src="@{CategoryPhoto}" /> </p></div>
        </div>
    </form>
</div>

page categoryUpdate (créer ou mettre à jour une catégorie avec des détails et une image)

<div class="container">

<h1>Category Details</h1>

<div>
    <form  class="form-horizontal" th:object="${category}" th:action="@{/categories/upload}" method="post" enctype="multipart/form-data">
        <input type="hidden" th:field="*{id}"/>
        <div class="form-group">
            <label class="col-sm-2 control-label">Category Name</label>
            <div class="col-sm-10">
                <input class="form-control" th:field="*{CategoryName}"/>
            </div>
        </div>
          <div class="form-group">
            <label class="col-sm-2 control-label">Category Photo</label>
            <div class="col-sm-10">
                <input name="file" type="file" class="form-control" th:field="*{CategoryPhoto}"/>
            </div>
        </div>
        <div class="row">
            <button class="btn btn-default">Save</button>
        </div>
    </form>
</div>
<div th:insert="~{fragments/footer :: footer}">&copy; 2017 Iuliana Cosmina & Apress</div>

L'erreur: j'obtiens dans bindingResult de la méthode CategoryController.saveCategory ().

Lorsque je débogue le code, j'obtiens l'erreur. Voici une photo pour démontrer:

 enter image description here

J'ai de la difficulté à afficher des images sur la page CategoryShow à l'aide de thymleaf. Toute aide serait la bienvenue.

Mise à jour: Quelqu'un peut-il me dire ce que cette erreur signifie, s'il vous plaît:

Failed to convert property value of    type 'org.springframework.web.multipart.support.StandardMultipartHttpServletRequest$StandardMultipartFile' to required type 'byte[]' for property 'CategoryPhoto'; nested exception is 
Java.lang.IllegalArgumentException: Cannot convert value of type 'org.springframework.web.multipart.support.
StandardMultipartHttpServletRequest$StandardMultipartFile' to required type 'byte' for property
'CategoryPhoto[0]': PropertyEditor [org.springframework.beans.propertyeditors.CustomNumberEditor] returned 
inappropriate value of type 'org.springframework.web.multipart.support.StandardMultipartHttpServletRequest$StandardMultipartFile' 

** Mise à jour finale: le message d'erreur suivant s'affiche: ** La partie de la requête requise 'fichier' n'est pas présente 

9
Vishal Torne

Ce que vous pouvez toujours faire est de comparer un téléchargement de fichier de travail exemple avec le vôtre.

Une autre chose qui sera utile pour comparer vos noms d’entrée avec le nom de la méthode de votre contrôleur s’attend de votre fichier.

Si votre code posté est toujours pertinent, vous pouvez trouver le nom "Fileimport" sur votre entrée de fichier dans le modèle, mais dans votre contrôleur, vous attendez un fichier (@RequestParam (value = "fichier", required = false)).

Autres choses qui vous aident dans le débogage:

  • en utilisant les outils de développement du navigateur et voyez ce que vous envoyez via le réseau
  • log requêtes entrantes côté serveur (soit de cette façon, soit trop compliqué pour vous, vous pouvez simplement parcourir les noms de paramètres et les enregistrer (et si possible, leurs valeurs également)

Si cela ne vous aide pas, alors mettez à jour le message: mettez à jour votre code (modèle + contrôleur, si modifié) et utilisez un meilleur stacktrace: en mieux, cela signifie que vous devez afficher non seulement la dernière ligne N du stacktrace, mais au moins jusqu'à la première ligne où l'exécution passe par votre code (en d'autres termes, le nom de la classe commence par votre paquet), et encore mieux si la première est causée par ou la seconde si elle est significative) est présente.

3
m4gic

Spring traduit les fichiers téléchargés en MultipartFile objects; vous ne pouvez donc pas les mapper directement sur un tableau d'octets.

Vous pouvez obtenir un tableau d'octets à partir d'un fichier multipart à l'aide de MultipartFile # getBytes () .

Dans votre cas, vous pourriez utiliser un objet intermédiaire (comme un CategoryForm) où le champ CategoryPhoto serait de type MultipartFile. Ensuite, dans votre contrôleur, vous le mappez à l'objet Category que vous avez déjà en utilisant la méthode I montré ci-dessus.

3
Gustavo Passini

Bonjour, votre forme Thymeleaf est résolue comme suit: l’attribut name est supprimé si l’attribut th: field est présent.

<form class="form-horizontal" action="/categories/upload" method="post" enctype="multipart/form-data">
    <input id="id" name="id" value="" type="hidden">
    <div class="form-group">
        <label class="col-sm-2 control-label">Category Name</label>
        <div class="col-sm-10">
            <input class="form-control" id="CategoryName" name="CategoryName" value="">
        </div>
    </div>
      <div class="form-group">
        <label class="col-sm-2 control-label">Category Photo</label>
        <div class="col-sm-10">
            <input name="CategoryPhoto" class="form-control" id="CategoryPhoto" type="file">
        </div>
    </div>
    <div class="row">
        <button class="btn btn-default">Save</button>
    </div>
</form>

Ce qui indique clairement l’erreur que vous obtenez même si vous mentionnez comme nom = "fichier" dans l’entrée de fichier, il est résolu en nom = catégoriePhoto à cause de th: field = "* {CategoryPhoto}" mentionné après la balise name.

utiliser th: valeur = "$ {product.name}" "th: name =" nom "th: id =" nom "au lieu du th: champ, il sera plus flexible

3
Manoj Ramanan

Les problèmes sont résolus Il suffit de vous dire ce que j'ai fait dans mon cas:

1) Si vous téléchargez un fichier dans la page, utilisez le fichier de pièce comme argument pour votre publication. Mappage dans la méthode du contrôleur

2) En ce qui concerne mon deuxième problème, l'image ne s'affiche pas dans une page HTML à l'aide de thymeleaf, car j'utilise byte [] pour persister dans ma base de données. Donc, il n'a pas été résolu par thymeleaf. J'ai donc utilisé le codec binaire Commune Apache comm (Base64) (qui peut être ajouté en tant que dépendance Gradle ou Maven) pour convertir mon image d'octet [] en chaîne Base64 afin qu'elle puisse être résolue par thymleaf. Ainsi:

    Category category = categoryService.findbyID(id);
    byte[] image = category.getCategoryPhoto();
    String CatImage =  Base64.encodeBase64String(image);

puis en HTML

<img  th:src="@{'data:image/jpeg;base64,'+${Cimage}}" />

espérons que cela aide quelqu'un !! Merci.

0
Vishal Torne