【问题标题】:uploading a image to the database using springboot , jpa ,thymeleaf使用 springboot , jpa ,thymeleaf 将图像上传到数据库
【发布时间】:2020-12-08 01:21:33
【问题描述】:

我正在开发一个使用 spring boot 和 jpa 和 thymeleaf 的简单应用程序,我需要将图像上传到我的数据库,但是当我在我的页面上单击提交时,除了图像字段之外,其他字段都会插入到数据库中。我阅读了网站上的不同帖子,但没有一个真正接近我的问题,我不知道为什么它不将文件插入数据库。我不得不说位于配方实体中的图像字段

控制器

@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";
    }
}

查看页面

<!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>

回购

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


}

实体

@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

错误

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

【问题讨论】:

  • 我对 thymeleaf 了解不多,但是您的视图页面上的每个输入字段都有一个属性“name”,除了类型为“file”的输入,它具有“th:name”是设置正确吗?
  • 我把它改成name= 现在我有一个错误。我现在就发布它
  • 只需使用 name html input 标签的属性,并在控制器中使用相同的名称使用 @RequestParam("user_custom_name") MultipartFile user_custom_name

标签: java spring spring-boot jpa


【解决方案1】:

我们来看看百里香片段

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

以及我们得到的错误信息:

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">

名称image 与具有不同类型的Recipe 字段相冲突(Byte[] 与我们试图在请求中传递的MultipartFile)。

一种方法可能是:

步骤 I. 将 th:name="image" 更改为其他内容(不与字段名称冲突),例如th:name="imagefile"

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

第二步。将@RequestParam 名称更改为imagefile 并将MultipartFile 转换为Byte[],然后再保存。

    @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;
    }

补充说明:

  • 看看 Sfg 如何处理图片上传以及在the tutorial repository 中的显示
  • 最好将MultiPartFile 转换为Byte[] 转换到单独的服务(请参阅Sfg 的回购/教程)

编辑:

从评论中回答问题: 我不使用 xampp。 .bin 扩展名表明它是一个二进制文件(因为图像文件存储为字节数组,所以有意义)。

下面是 sn-p,它应该让您在浏览器中显示图像。

IOUtils 来自 (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());
}

如果您知道配方的 ID,只需输入 localhost:8080/recipe/&lt;recipe id&gt;/recipeimage

【讨论】:

  • 感谢您的关注。有一点我必须说,在我按照您在此处发布的操作之后,u.setImage(byteObjects) 出现错误,它要求我将setimage() 的第一个参数从 byte[] 更改为 Byte[] 然后我做了对图像字段和获取方法进行相同的修改,因此之后我运行程序,我可以将图像上传到数据库,但仍然有些事情似乎不太好! .我使用 xampp 作为我的数据库,所以当我转到 xampp 中的表格页面并且我想下载我上传的文件时,我收到格式为 .bin 的文件你知道为什么吗?
【解决方案2】:

关于输入未绑定到 ModelAttribute 的问题:

在您的输入字段中将 th:name 更改为 name。

关于您的类型错误

也许这可以帮助你:Upload files to the @ModelAttribute using Thymeleaf

您需要为图像使用正确的类型,即 MultipartFile。考虑使用另一个名为例如的类RecipeDto 在您的控制器方法签名上。将此映射到您的配方实体,以便您可以以某种方式手动将 MultipartFile 转换为字节数组。

编辑:org.springframework.web.multipart.MultipartFile#getBytes 可能会为您执行此操作


关于 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

【讨论】:

  • 感谢您的关注,但我对我应该在控制器和 dao 中编码什么感到困惑。我知道服务层和 dao,但是必须如何为这项任务编码让我感到困惑和绝望。可以贴出 dao 和 controller 的代码吗?
  • 我实际上是在谈论 DTO。所以你有另一个食谱类(RecipeDto),用于你的后食谱签名。 RecipeDto 有一个名为 image 的字段(以及所有其他输入字段作为类字段)。图像的类型为 MultipartFile。在您的 postrecipe 方法中,您将 RecipeDto 映射到您的 Recipe 实体,从 MultipartFile 设置字节。我现在在手机上,无法生成代码 atm。
  • 我会像你说的那样继续,如果它再次不起作用我会在这里再次评论
  • 我在帖子上添加了一张图片,我试图看看 debager 发生了什么,我发现它没有达到postRecipe() 方法我检查我的方法没有图片字段它工作正常所以当我想插入其他字段时该方法有效。我还在这里添加了 github 链接
猜你喜欢
  • 1970-01-01
  • 2011-04-21
  • 2015-09-18
  • 2019-04-21
  • 1970-01-01
  • 2016-04-20
  • 2016-08-28
  • 2012-08-27
相关资源
最近更新 更多