I'm trying to use a form to save text and a file name along with uploading a file to a specific folder. I have used entities here and will share all the code.
package com.rx.healthtechhub.entities;
import java.util.Date;
import org.springframework.format.annotation.DateTimeFormat;
import org.springframework.format.annotation.DateTimeFormat.ISO;
import jakarta.persistence.CascadeType;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import jakarta.persistence.JoinColumn;
import jakarta.persistence.ManyToOne;
import jakarta.persistence.Table;
@Entity
@Table(name = "medrx")
public class MedRx {
@Id
@Column(name = "id_medrx")
@GeneratedValue(strategy = GenerationType.IDENTITY)
private int idMedrx;
private String nameMed;
@Column(columnDefinition = "TEXT")
private String icon;
@Column(columnDefinition = "TEXT")
private String pic;
@ManyToOne(cascade = CascadeType.ALL)
@JoinColumn(name = "id_medrxgroup")
private MedRxGroups medRxGroups;
@ManyToOne(cascade = CascadeType.ALL)
@JoinColumn(name = "id_manufacturer")
private Manufacturer manufacturer;
private String packSize;
private Double unitPrice;
@DateTimeFormat(iso = ISO.DATE_TIME)
private Date lastUpdate;
@DateTimeFormat(iso = ISO.DATE_TIME)
private Date createDate;
public MedRx() {
}
public int getIdMedrx() {
return idMedrx;
}
public void setIdMedrx(int idMedrx) {
this.idMedrx = idMedrx;
}
public String getNameMed() {
return nameMed;
}
public void setNameMed(String nameMed) {
this.nameMed = nameMed;
}
public String getIcon() {
return icon;
}
public void setIcon(String icon) {
this.icon = icon;
}
public String getPic() {
return pic;
}
public void setPic(String pic) {
this.pic = pic;
}
public MedRxGroups getMedRxGroups() {
return medRxGroups;
}
public void setMedRxGroups(MedRxGroups medRxGroups) {
this.medRxGroups = medRxGroups;
}
public Manufacturer getManufacturer() {
return manufacturer;
}
public void setManufacturer(Manufacturer manufacturer) {
this.manufacturer = manufacturer;
}
public String getPackSize() {
return packSize;
}
public void setPackSize(String packSize) {
this.packSize = packSize;
}
public Double getUnitPrice() {
return unitPrice;
}
public void setUnitPrice(Double unitPrice) {
this.unitPrice = unitPrice;
}
public Date getLastUpdate() {
return lastUpdate;
}
public void setLastUpdate(Date lastUpdate) {
this.lastUpdate = lastUpdate;
}
public Date getCreateDate() {
return createDate;
}
public void setCreateDate(Date createDate) {
this.createDate = createDate;
}
@Override
public String toString() {
return "MedRx [idMedrx=" + idMedrx + ", nameMed=" + nameMed + ", icon=" + icon + ", pic=" + pic
+ ", medRxGroups=" + medRxGroups + ", manufacturer=" + manufacturer + ", packSize=" + packSize
+ ", unitPrice=" + unitPrice + ", lastUpdate=" + lastUpdate + ", createDate=" + createDate + "]";
}
}
And here is my Controller -
@PostMapping("/add_medrx")
public String saveMedRxPg(@ModelAttribute("medRx") MedRx medRx,
@RequestParam("icon") MultipartFile icon,
@RequestParam("pic") MultipartFile pic,
Model model, RedirectAttributes redirectAttributes) {
String msg;
try {
String newIcon = fileUploadService.save(icon);
String newPic = fileUploadService.save(pic);
medRx.setCreateDate(new Date());
medRx.setLastUpdate(new Date());
medRx.setIcon(newIcon);
medRx.setPic(newPic);
medRxService.addMedRx(medRx);
msg = "Files uploaded successfully!";
redirectAttributes.addFlashAttribute("message", msg);
} catch (Exception e) {
msg = "Could not upload the files. Error: " + e.getMessage();
redirectAttributes.addFlashAttribute("message", msg);
}
return "redirect:/admin/medicines";
}
@GetMapping("/add_medrx")
public String addMedRxPg(Model model) {
model.addAttribute("classActiveSettingsMedicines","active");
return "admin/medicines";
}
@GetMapping("/new_medicine")
public String newMedRxPg(Model model) {
List<MedRxGroups> medRxGroups = medRxGroupService.getMedRxGroups();
List<Manufacturer> manufacturers = manufacturerService.getManufacturers();
model.addAttribute("classActiveSettingsMedicines","active");
model.addAttribute("medrx", new MedRx());
model.addAttribute("medRxGroups", medRxGroups);
model.addAttribute("manufacturers", manufacturers);
return "admin/newmedex";
}
And here is my Form code --
<form class="form-horizontal" th:action="@{/add_medrx}" enctype="multipart/form-data" method="post" th:object="${medrx}">
<div class="panel panel-default">
<div class="panel-heading">
<h3 class="panel-title"><strong>New Medicine</strong></h3>
<ul class="panel-controls">
<li><a href="#" class="panel-remove"><span class="fa fa-times"></span></a></li>
</ul>
</div>
<div class="panel-body">
</div>
<div class="panel-body">
<div class="form-group">
<label class="col-md-3 col-xs-12 control-label">Name</label>
<div class="col-md-6 col-xs-12">
<div class="input-group">
<span class="input-group-addon"><span class="fa fa-pencil"></span></span>
<input type="text" class="form-control" th:field="*{nameMed}"/>
</div>
<span class="help-block">This is sample of text field</span>
</div>
</div>
<div class="form-group">
<label class="col-md-3 col-xs-12 control-label">Icon</label>
<div class="col-md-6 col-xs-12">
<!-- <input type="file" class="fileinput btn-primary" th:text="${icon}" id="icon" th:name="icon" title="Browse file" /> -->
<input type="file" id="icon" name="icon" class="fileinput btn-primary" title="Browse file" />
<span class="help-block">Upload your icon (.png) file</span>
</div>
</div>
<div class="form-group">
<label class="col-md-3 col-xs-12 control-label">Picture</label>
<div class="col-md-6 col-xs-12">
<!-- <input type="file" class="fileinput btn-primary" th:text="${pic}" id="pic" th:name="pic" title="Browse file" /> -->
<input type="file" id="pic" name="pic" class="fileinput btn-primary" title="Browse file" />
<span class="help-block">Upload your image (.jpg) file</span>
</div>
</div>
<div class="form-group">
<label class="col-md-3 col-xs-12 control-label">Group</label>
<div class="col-md-6 col-xs-12">
<select class="form-control select" th:field="*{medRxGroups}">
<option value=0>Select</option>
<option th:each="medRxGroup : ${medRxGroups}" th:value="${medRxGroup.idMedrxgroup}" th:text="${medRxGroup.nameGeneric}">Option 2</option>
</select>
<span class="help-block">Select your Group <strong> Or </strong> <a th:href="@{/new_group}" class="btn btn-success" type="button">Add Group</a></span>
</div>
</div>
<div class="form-group">
<label class="col-md-3 col-xs-12 control-label">Manufacturer</label>
<div class="col-md-6 col-xs-12">
<select class="form-control select" th:field="*{manufacturer}">
<option value=0>Select</option>
<option th:each="manufacturer : ${manufacturers}" th:value="${manufacturer.idManufacturer}" th:text="${manufacturer.companyName}">Option 2</option>
</select>
<span class="help-block">Select your manufacturer <strong> Or </strong> <a th:href="@{/new_manufacturer}" class="btn btn-success" type="button">Add Manufacturer</a></span>
</div>
</div>
<div class="form-group">
<label class="col-md-3 col-xs-12 control-label">Pack Size</label>
<div class="col-md-6 col-xs-12">
<div class="input-group">
<span class="input-group-addon"><span class="fa fa-pencil"></span></span>
<input type="text" class="form-control" th:field="*{packSize}"/>
</div>
<span class="help-block">Write packet size</span>
</div>
</div>
<div class="form-group">
<label class="col-md-3 col-xs-12 control-label">Unit Price</label>
<div class="col-md-6 col-xs-12">
<div class="input-group">
<span class="input-group-addon"><span class="fa fa-pencil"></span></span>
<input type="text" class="form-control" th:field="*{unitPrice}"/>
</div>
<span class="help-block">Write Unit Price</span>
</div>
</div>
<div class="panel-footer">
<button class="btn btn-default">Clear Form</button>
<button class="btn btn-primary pull-right">Submit</button>
</div>
</div>
</form>
To manage file uploads, I have used a file upload service, which might help you understand the process better.
FileUploadService --
package com.rx.healthtechhub.services;
import java.nio.file.Path;
import java.util.stream.Stream;
import org.springframework.core.io.Resource;
import org.springframework.web.multipart.MultipartFile;
public interface FileUploadService {
public void init();
public String save(MultipartFile file);
public Resource load(String filename);
public void deleteAll();
public Stream<Path> loadAll();
}
FileStorageServiceImpl --
package com.rx.healthtechhub.services;
import java.io.IOException;
import java.net.MalformedURLException;
import java.nio.file.FileAlreadyExistsException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.UUID;
import java.util.stream.Stream;
import org.springframework.core.io.Resource;
import org.springframework.core.io.UrlResource;
import org.springframework.stereotype.Service;
import org.springframework.util.FileSystemUtils;
import org.springframework.web.multipart.MultipartFile;
@Service
public class FilesStorageServiceImpl implements FileUploadService {
private final Path root = Paths.get("./src/main/resources/static/img/uploads/");
@Override
public void init() {
try {
Files.createDirectories(root);
} catch (IOException e) {
throw new RuntimeException("Could not initialize folder for upload!");
}
}
@Override
public String save(MultipartFile file) {
try {
String newFileName = generateNewFileName(file.getOriginalFilename());
Files.copy(file.getInputStream(), this.root.resolve(newFileName));
return newFileName;
} catch (Exception e) {
if (e instanceof FileAlreadyExistsException) {
throw new RuntimeException("A file of that name already exists.");
}
throw new RuntimeException(e.getMessage());
}
}
private String generateNewFileName(String originalFilename) {
String extension = originalFilename.substring(originalFilename.lastIndexOf('.'));
String dateTime = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMddHHmmss"));
String randomId = UUID.randomUUID().toString().replace("-", "");
return "manufacturer_" + dateTime + "_" + randomId + extension;
}
@Override
public Resource load(String filename) {
try {
Path file = root.resolve(filename);
Resource resource = new UrlResource(file.toUri());
if (resource.exists() || resource.isReadable()) {
return resource;
} else {
throw new RuntimeException("Could not read the file!");
}
} catch (MalformedURLException e) {
throw new RuntimeException("Error: " + e.getMessage());
}
}
@Override
public void deleteAll() {
FileSystemUtils.deleteRecursively(root.toFile());
}
@Override
public Stream<Path> loadAll() {
try {
return Files.walk(this.root, 1).filter(path -> !path.equals(this.root)).map(this.root::relativize);
} catch (IOException e) {
throw new RuntimeException("Could not load the files!");
}
}
}
I can't understand where I missed something, which is why I'm getting the following error.
[2m2024-06-18T12:17:29.770+06:00[0;39m [33m WARN[0;39m [35m6836[0;39m [2m---[0;39m [2m[rx.healthtechhub.co] [nio-8080-exec-9][0;39m [2m[0;39m[36m.w.s.m.s.DefaultHandlerExceptionResolver[0;39m [2m:[0;39m Resolved [org.springframework.web.bind.MethodArgumentNotValidException: Validation failed for argument [0] in public java.lang.String com.rx.healthtechhub.controller.HomeController.saveMedRxPg(com.rx.healthtechhub.entities.MedRx,org.springframework.web.multipart.MultipartFile,org.springframework.web.multipart.MultipartFile,org.springframework.ui.Model,org.springframework.web.servlet.mvc.support.RedirectAttributes) with 2 errors: [Field error in object 'medRx' on field 'icon': rejected value [org.springframework.web.multipart.support.StandardMultipartHttpServletRequest$StandardMultipartFile@3c008fd6]; codes [typeMismatch.medRx.icon,typeMismatch.icon,typeMismatch.java.lang.String,typeMismatch]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [medRx.icon,icon]; arguments []; default message [icon]]; default message [Failed to convert property value of type 'org.springframework.web.multipart.support.StandardMultipartHttpServletRequest$StandardMultipartFile' to required type 'java.lang.String' for property 'icon'; Cannot convert value of type 'org.springframework.web.multipart.support.StandardMultipartHttpServletRequest$StandardMultipartFile' to required type 'java.lang.String' for property 'icon': no matching editors or conversion strategy found]] [Field error in object 'medRx' on field 'pic': rejected value [org.springframework.web.multipart.support.StandardMultipartHttpServletRequest$StandardMultipartFile@5321c0cb]; codes [typeMismatch.medRx.pic,typeMismatch.pic,typeMismatch.java.lang.String,typeMismatch]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [medRx.pic,pic]; arguments []; default message [pic]]; default message [Failed to convert property value of type 'org.springframework.web.multipart.support.StandardMultipartHttpServletRequest$StandardMultipartFile' to required type 'java.lang.String' for property 'pic'; Cannot convert value of type 'org.springframework.web.multipart.support.StandardMultipartHttpServletRequest$StandardMultipartFile' to required type 'java.lang.String' for property 'pic': no matching editors or conversion strategy found]] ]
I'm trying to upload information through my application using a form. The form includes text fields, a file upload, and some options. However, I'm encountering an error when I fill out and submit the form. I suspect it might be a multipart file validation error, but I'm unsure how to resolve it.
I have resolved my issue. I missed a few things earlier. In my form code, I have kept everything the same. However, in my controller code, I have changed a few things. I’ve shared my code below.
@PostMapping("/add_medrx")
public String saveMedRx(@Valid @ModelAttribute("medRx") MedRx medRx,
final @RequestParam(value = "file") MultipartFile file,
final @RequestParam(value = "file2") MultipartFile file2,
Model model) throws IOException {
String msg = "";
try {
String iconString = fileUploadService.save(file);
String picString = fileUploadService.save(file2);
medRx.setCreateDate(new Date());
medRx.setLastUpdate(new Date());
medRx.setIcon(iconString);
medRx.setPic(picString);
medRxService.addMedRx(medRx);
msg = "File Upload Successfully " + file + " & " + file2;
System.out.println(msg);
} catch (Exception e) {
msg = "Could not upload the file: " + file + " & " + file2 + ". Error: " + e.getMessage();
System.out.println(msg);
e.printStackTrace();
}
List<MedRx> medRxs = medRxService.getMedRxs();
model.addAttribute("medRxs", medRxs);
model.addAttribute("classActiveSettingsMedicines","active");
return "admin/medicines";
}
In my form code, I just changed the input names. The updated input code is shared below:
<input type="file" name="file" class="fileinput btn-primary" title="Browse file" />
<input type="file" name="file2" class="fileinput btn-primary" title="Browse file" />
Thats it. Now it's working. Thank you so much.