- As a user with a Spring MVC with servlet (not Spring Boot), JSP and PostgreSQL DB project
- I want to be able to use an HTML form to upload an image to my server
- and store the image a a PostgreSQL DB
- and retrieve and display the image on an HTML page
The database directory has a shell script that will automatically create a thing
database with a thing
table for your use.
- In your
pom.xml
file add the commons-fileupload dependency
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.4</version>
</dependency>
springmvc-servlet.xml
add aMultipartResolver
bean
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<property name="maxUploadSize" value="268435456"/>
</bean>
- In your JSP form
- Add the encoding type to the form element
<form:form class="form" action="thing" method="POST" modelAttribute="thingToUpdate" enctype="multipart/form-data">
- Add a file input
<input type="file" class="form-control" id="avatarContainer" name="avatarContainer" value=""/>
- In your Model, include a
byte[]
field
private byte[] avatar;
- In your DB, add a column of type
bytea
alter table thing alter column avatar type bytea using avatar::bytea;
- In your DAO add your new DB field to your update statement and your row mapper
- For
ResultSet
objects fromjdbcTemplate.query()
d.setAvatar(resultSet.getBytes("avatar"));
- For
SqlRowSet
objects fromjdbcTemplate.queryForRowSet()
user.setAvatar((byte[]) results.getObject("avatar"));
- In your controller:
- Add the
consumes
setting to your@ParamMapping
annotation
@RequestMapping(value = "/thing", method = RequestMethod.POST, consumes = {MULTIPART_FORM_DATA_VALUE})
- Add a parameter to your controller action method for a MultipartFile
@RequestParam("avatarContainer") MultipartFile avatarContainer
- Set the Model
byte[]
to the image provided in the MultipartFile object
thing.setAvatar(avatarContainer.getBytes())
- Here is the entire controller post method:
@RequestMapping(value = "/thing", method = RequestMethod.POST, consumes = {MULTIPART_FORM_DATA_VALUE})
public String handleUpdateThing(@Valid @ModelAttribute("thing") Thing thing, BindingResult result, @RequestParam("avatarContainer") MultipartFile avatarContainer, ModelMap model) throws IOException {
if (result.hasErrors()) {
model.put("thingToUpdate", thing);
model.put("error", "Name cannot be empty.");
return "thingUpdateForm";
}
if(avatarContainer.isEmpty()) {
thing.setAvatar(null);
} else {
thing.setAvatar(avatarContainer.getBytes());
}
thingDao.updateThing(thing);
return "redirect:/things";
}
- Add a method to your controller that will return an image. Use the URL as the
src
attribute of any<img>
element
@RequestMapping(path = "/thing/image", method = RequestMethod.GET)
public ResponseEntity<byte[]> getThingImage(@RequestParam("id") Long id) throws IOException {
HttpHeaders headers = new HttpHeaders();
BufferedImage img;
headers.setContentType(MediaType.IMAGE_PNG);
headers.setCacheControl(CacheControl.noCache().getHeaderValue());
byte[] media = thingDao.getThing(id).getAvatar();
if (media == null) {
media = FileUtils.readFileToByteArray(ResourceUtils.getFile("classpath:../../img/150.png"));
}
return new ResponseEntity<>(media, headers, HttpStatus.OK);
}