简体   繁体   中英

uploading a image to the database using springboot , jpa ,thymeleaf

I am developing a simple app that use spring boot and jpa and thymeleaf, i need to upload the image to my database but when i click on submit on my page fields get inserted in database except image field. i read the different posts on the website but none of them was really close to my problem and i have no idea why it does not insert the file into the database. i have to say the image field located in recipe entity

controller

@Controller
@RequestMapping("/recipe")
public class RecipeController {
    RecipeRepository recipeRepository;
   IngredientRepository ingredientRepository;
    public RecipeController(RecipeRepository recipeRepository, IngredientRepository ingredientRepository) {
        this.recipeRepository = recipeRepository; 
        this.ingredientRepository = ingredientRepository; //// this is other repo which cause no problem
    }
    @GetMapping("/insert_recipe")
    public String insetRecipe(Model model){
        model.addAttribute("addRecipe",new Recipe());
        model.addAttribute("addingredient",new Ingredient()); // this is other entity which cause no problem
      return   "insert_recipe";
    }
    @PostMapping("/postrecipe")
    public String postRecipe(@ModelAttribute("addRecipe")@Valid Recipe recipe, BindingResult result, Model model, @ModelAttribute("addingredient") Ingredient ingredient)  {
        recipeRepository.save(recipe);
        long id=recipe.getId();
        Recipe u=recipeRepository.findById(id);
        //model.addAttribute("addingredient",recipe);
        ingredient.setRecipe(u);
        ingredientRepository.save(ingredient);
        return "redirect:/recipe/insert_recipe";
    }
}

view page

<!DOCTYPE html>
<html xmlns:th="https://www.thymeleaf.org">

<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<form th:action="@{/recipe/postrecipe}" th:object="${addRecipe}"  enctype="multipart/form-data" method="post"  >
des:    <input type="text" name="descriptiob"/>
    serving:    <input type="text" name="servings"/>
   for ingredient description <input type="text" name="description" th:object="${addingredient}">
    upload picture <input type="file" th:name="image">

    <input type="submit" value="submit">
</form>
<br/><br/>

</body>
</html>

repo

public interface RecipeRepository extends CrudRepository<Recipe,Long> {
    Recipe findById(long is);


}

entity

@Entity
public class Recipe {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private String descriptiob;
    @Lob
    private Byte[] image;
    private Integer servings;
    //setter and getter method also are in this class

error

Field error in object 'addRecipe' on field 'image': rejected value [org.springframework.web.multipart.support.StandardMultipartHttpServletRequest$StandardMultipartFile@12c96ba6]; codes [typeMismatch.addRecipe.image,typeMismatch.image,typeMismatch.[Ljava.lang.Byte;,typeMismatch]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [addRecipe.image,image]; arguments []; default message [image]]; default message [Failed to convert property value of type 'org.springframework.web.multipart.support.StandardMultipartHttpServletRequest$StandardMultipartFile' to required type 'java.lang.Byte[]' for property 'image'; nested exception is java.lang.IllegalArgumentException: Cannot convert value of type 'org.springframework.web.multipart.support.StandardMultipartHttpServletRequest$StandardMultipartFile' to required type 'java.lang.Byte' for property 'image[0]': PropertyEditor [org.springframework.beans.propertyeditors.CustomNumberEditor] returned inappropriate value of type 'org.springframework.web.multipart.support.StandardMultipartHttpServletRequest$StandardMultipartFile']]

在此处输入图像描述

GitHub link

Let's have a look at the thymeleaf fragment

upload picture <input type="file" th:name="image">

and the error message we get:

Field error in object 'addRecipe' on field 'image': (...)
Cannot convert value of type '(...) StandardMultipartHttpServletRequest$StandardMultipartFile'
(...)to required type 'java.lang.Byte' for property 'image[0]': PropertyEditor (...)
upload picture <input type="file" th:name="image">

The name image colides with the Recipe field which has a different type ( Byte[] than the MultipartFile we are trying to pass in the request).

One way to do it may be:

Step I. Change the th:name="image" to something else (that does not collide with the field names), eg th:name="imagefile"

upload picture <input type="file" th:name="imagefile">

Step II. Change the @RequestParam name to imagefile and convert the MultipartFile to the Byte[] before saving it.

    @PostMapping("/postrecipe")
    public String postRecipe(@ModelAttribute("addRecipe") Recipe recipe,
                             Model model,
                             @ModelAttribute("addingredient")@Valid Ingredient ingredient,
                             BindingResult bindingResult,
                             @RequestParam("imagefile") MultipartFile file, // changed from 'image'
                             @RequestParam("unitid") long id) throws IOException {
      long myid=id;
        recipeRepository.save(recipe);
        long ids=recipe.getId();
        Recipe u=recipeRepository.findById(ids);
        model.addAttribute("addingredient",recipe);
       UnitOfMeasure ob=unitOfMeasureRepository.findById(myid);

       Byte[] byteObjects = convertToBytes(file); // we have to convert it to Byte[] array
       u.setImage(byteObjects);
        recipeRepository.save(u); // TODO refactor - save once

        ingredient.setRecipe(u);
        ingredient.setUnitOfMeasure(ob);
        ingredientRepository.save(ingredient);
        return "redirect:/recipe/insert_recipe";
    }

    private Byte[] convertToBytes(MultipartFile file) throws IOException {
        Byte[] byteObjects = new Byte[file.getBytes().length];
        int i = 0;
        for (byte b : file.getBytes()) {
            byteObjects[i++] = b;
        }
        return byteObjects;
    }

Additional remarks:

  • Have a look at how Sfg handles the image upload and the displaying of it in the tutorial repository
  • It would be better to move the MultiPartFile to Byte[] conversion to the separate service (see the Sfg's repo / tutorial)

Edit:

Answering the question from the comment: I do not use xampp. The .bin extension suggests it is a binary file (makes sense as the image file is stored as the byte array).

Below is the snippet which should let you display the image in the browser instead.

IOUtils is from ( import org.apache.tomcat.util.http.fileupload.IOUtils; )

@GetMapping("{id}/recipeimage")
public void renderImageFromDb(@PathVariable Long id, HttpServletResponse response) throws IOException {
    Recipe recipe = recipeRepository.findById(id).get();
    byte[] byteArray = new byte[recipe.getImage().length];

    int i = 0;
    for (Byte wrappedByte: recipe.getImage()) {
        byteArray[i++] = wrappedByte; // auto unboxing
    }

    response.setContentType("image/jpeg");
    InputStream is = new ByteArrayInputStream(byteArray);
    IOUtils.copy(is, response.getOutputStream());
}

If you know the id of the recipe, just type localhost:8080/recipe/<recipe id>/recipeimage

Concerning your problem that the input is not bound to the ModelAttribute:

change th:name to name on your input field.

Concerning your type error :

Maybe this could help you: Upload files to the @ModelAttribute using Thymeleaf

You need to use the correct type which is MultipartFile for your image. Consider using another class called eg RecipeDto on your Controllers method signature. Map this to your Recipe Entity so you can somehow convert the MultipartFile to a Byte array manually.

edit: org.springframework.web.multipart.MultipartFile#getBytes might do this for you


Concerning DTO: What are the DAO, DTO and Service layers in Spring Framework?

https://www.baeldung.com/entity-to-and-from-dto-for-a-java-spring-application

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM