英文:
uploading a image to the database using springboot , jpa ,thymeleaf
问题
@Controller
@RequestMapping("/recipe")
public class RecipeController {
RecipeRepository recipeRepository;
IngredientRepository ingredientRepository;
public RecipeController(RecipeRepository recipeRepository, IngredientRepository ingredientRepository) {
this.recipeRepository = recipeRepository;
this.ingredientRepository = ingredientRepository;
}
@GetMapping("/insert_recipe")
public String insetRecipe(Model model) {
model.addAttribute("addRecipe", new Recipe());
model.addAttribute("addingredient", new Ingredient());
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);
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 id);
}
@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 methods are also 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链接: https://github.com/pooyafils/Recipe
英文:
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']]
答案1
得分: 2
让我们看一下Thymeleaf片段:
上传图片 <input type="file" th:name="image">
以及我们得到的错误信息:
对象'addRecipe'中字段'image'的字段错误:(...)
无法将类型为'(...) StandardMultipartHttpServletRequest$StandardMultipartFile'的值转换为属性'image[0]'所需的类型'java.lang.Byte':PropertyEditor(...)
上传图片 <input type="file" th:name="image">
名称image
与具有不同类型(Byte[]
与我们试图在请求中传递的MultipartFile
不同)的Recipe
字段发生冲突。
一种方法是:
第一步:将th:name="image"
更改为其他内容(不与字段名称冲突),例如th:name="imagefile"
上传图片 <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, // 从'image'更改而来
@RequestParam("unitid") long id) throws IOException {
// ...
}
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如何处理图像上传并在tutorial repository中显示图像。
- 最好将
MultiPartFile
到Byte[]
的转换移到单独的服务中(参见Sfg的repo / tutorial)。
编辑:
回答评论中的问题:
我不使用xampp。
.bin
扩展名表明它是一个二进制文件(因为图像文件存储为字节数组,所以有道理)。
以下是应该让您在浏览器中显示图像的代码片段。
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; // 自动拆箱
}
response.setContentType("image/jpeg");
InputStream is = new ByteArrayInputStream(byteArray);
IOUtils.copy(is, response.getOutputStream());
}
如果您知道食谱的id,只需键入localhost:8080/recipe/<recipe id>/recipeimage
。
英文:
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), e.g. 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
toByte[]
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
答案2
得分: 0
关于您的问题,即输入未绑定到ModelAttribute:
将您的输入字段上的th:name更改为name。
关于您的类型错误:
也许这可以帮助您:https://stackoverflow.com/questions/47476733/upload-files-to-the-modelattribute-using-thymeleaf
您需要使用正确的类型,即MultipartFile来处理您的图像。考虑在您的控制器方法签名中使用另一个类,例如RecipeDto。将其映射到您的Recipe实体,以便您可以手动将MultipartFile转换为字节数组。
编辑:org.springframework.web.multipart.MultipartFile#getBytes可能会为您执行此操作。
关于DTO:
https://www.baeldung.com/entity-to-and-from-dto-for-a-java-spring-application
英文:
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: https://stackoverflow.com/questions/47476733/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 e.g. 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:
https://stackoverflow.com/questions/35078383/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
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论