Last active
May 17, 2021 07:55
-
-
Save christherama/f35599c6084cfdc2834311c4f44358a5 to your computer and use it in GitHub Desktop.
These files demonstrate how to implement a custom Spring validator for a Gif entity that includes as a mapped property a Category entity.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!-- gif/form.html --> | |
<!-- Notice that the "file" field now uses object binding with th:field="*{file}" --> | |
<!-- since the "file" is now part of the Gif entity class (see Gif.java). --> | |
<!DOCTYPE html> | |
<html lang="en" xmlns:th="http://www.thymeleaf.org"> | |
<head th:replace="layout :: head('upload')"></head> | |
<body> | |
<div th:replace="layout :: nav"></div> | |
<div th:replace="layout :: flash"></div> | |
<div class="container upload"> | |
<div class="row"> | |
<div class="col s12"> | |
<h2 th:text="${heading}">Category</h2> | |
<div class="subtitle" th:if="${heading == 'Upload'}">Upload and share your GIFs with friends and family on Facebook, Twitter, and everywhere else.</div> | |
</div> | |
</div> | |
<div class="divider"></div> | |
<form action="#" th:action="@{${action}}" th:object="${gif}" method="post" enctype="multipart/form-data"> | |
<input type="hidden" th:field="*{id}"/> | |
<input type="hidden" th:field="*{username}"/> | |
<input type="hidden" th:field="*{favorite}" /> | |
<input type="hidden" th:field="*{hash}"/> | |
<div class="row"> | |
<div class="col s12 l8"> | |
<div class="file-wrapper" th:classappend="${#fields.hasErrors('file')}? 'error' : ''"> | |
<input type="file" th:field="*{file}"/> | |
<span class="placeholder" data-placeholder="Choose an image...">Choose an image...</span> | |
<label th:for="file" class="button">Browse</label> | |
<div class="error-message" th:if="${#fields.hasErrors('file')}" th:errors="*{file}"></div> | |
</div> | |
</div> | |
</div> | |
<div class="row"> | |
<div class="col s12 l8" th:classappend="${#fields.hasErrors('description')}? 'error' : ''"> | |
<input type="text" th:field="*{description}" placeholder="Description"/> | |
<div class="error-message" th:if="${#fields.hasErrors('description')}" th:errors="*{description}"></div> | |
</div> | |
</div> | |
<div class="row"> | |
<div class="col s12 l8" th:classappend="${#fields.hasErrors('category')}? 'error' : ''"> | |
<select th:field="*{category.id}" class="cs-select cs-skin-border"> | |
<option value="" disabled="disabled">Select a category</option> | |
<option th:each="cat : ${categories}" th:value="${cat.id}" th:text="${cat.name}" th:style="|color:${cat.colorCode}|"></option> | |
</select> | |
<div class="error-message" th:if="${#fields.hasErrors('category')}" th:errors="*{category}"></div> | |
</div> | |
</div> | |
<div class="row"> | |
<div class="col s12"> | |
<button type="submit" th:text="${submit}" class="button">Upload</button> | |
<a href="javascript:window.location = document.referrer;" class="button">Cancel</a> | |
</div> | |
</div> | |
</form> | |
</div> | |
<div th:replace="layout :: scripts"></div> | |
</body> | |
</html> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
Notice the @Transient annotation on the MultipartFile field. | |
This means that the field value will NOT be persisted to the database. | |
*/ | |
package com.teamtreehouse.giflib.model; | |
import org.springframework.web.multipart.MultipartFile; | |
import javax.persistence.*; | |
import java.time.LocalDateTime; | |
import java.time.temporal.ChronoUnit; | |
@Entity | |
public class Gif { | |
@Id | |
@GeneratedValue(strategy = GenerationType.IDENTITY) | |
private Long id; | |
@Lob | |
private byte[] bytes; | |
@Transient | |
private MultipartFile file; | |
private String description; | |
@ManyToOne | |
private Category category; | |
private LocalDateTime dateUploaded = LocalDateTime.now(); | |
private String username = "You"; | |
private boolean favorite; | |
private String hash; | |
public Gif(){} | |
/* Getters, setters, and unrelated methods omitted for brevity */ | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
Notice the method annotated with @InitBinder("gif"). | |
This ensures that the GifValidator is used for validating @Valid parameters named "gif" | |
*/ | |
package com.teamtreehouse.giflib.web.controller; | |
import com.teamtreehouse.giflib.model.Gif; | |
import com.teamtreehouse.giflib.service.CategoryService; | |
import com.teamtreehouse.giflib.service.GifService; | |
import com.teamtreehouse.giflib.validator.GifValidator; | |
import com.teamtreehouse.giflib.web.FlashMessage; | |
import com.teamtreehouse.giflib.web.FlashMessage.Status; | |
import org.springframework.beans.factory.annotation.Autowired; | |
import org.springframework.stereotype.Controller; | |
import org.springframework.ui.Model; | |
import org.springframework.validation.BindingResult; | |
import org.springframework.web.bind.WebDataBinder; | |
import org.springframework.web.bind.annotation.*; | |
import org.springframework.web.servlet.mvc.support.RedirectAttributes; | |
import javax.servlet.http.HttpServletRequest; | |
import javax.validation.Valid; | |
import java.util.List; | |
/* | |
Unrelated code omitted for brevity. | |
*/ | |
@Controller | |
public class GifController { | |
@Autowired | |
private GifService gifService; | |
@InitBinder("gif") | |
protected void initBinder(WebDataBinder binder) { | |
binder.setValidator(new GifValidator()); | |
} | |
// Upload a new GIF | |
@RequestMapping(value = "/gifs", method = RequestMethod.POST) | |
public String addGif(@Valid Gif gif, BindingResult result, RedirectAttributes redirectAttributes) { | |
if(result.hasErrors()) { | |
redirectAttributes.addFlashAttribute("org.springframework.validation.BindingResult.gif",result); | |
redirectAttributes.addFlashAttribute("gif",gif); | |
return "redirect:/upload"; | |
} | |
gifService.save(gif, gif.getFile()); | |
redirectAttributes.addFlashAttribute("flash",new FlashMessage("GIF added!", Status.SUCCESS)); | |
return String.format("redirect:/gifs/%s",gif.getId()); | |
} | |
// Update an existing GIF | |
@RequestMapping(value = "/gifs/{gifId}", method = RequestMethod.POST) | |
public String updateGif(@Valid Gif gif, BindingResult result, RedirectAttributes redirectAttributes) { | |
if(result.hasErrors()) { | |
redirectAttributes.addFlashAttribute("org.springframework.validation.BindingResult.gif",result); | |
redirectAttributes.addFlashAttribute("gif",gif); | |
return String.format("redirect:/gifs/%s/edit",gif.getId()); | |
} | |
gifService.update(gif,gif.getFile()); | |
redirectAttributes.addFlashAttribute("flash",new FlashMessage("GIF updated!", Status.SUCCESS)); | |
return String.format("redirect:/gifs/%s",gif.getId()); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package com.teamtreehouse.giflib.service; | |
import com.teamtreehouse.giflib.dao.GifDao; | |
import com.teamtreehouse.giflib.model.Gif; | |
import org.hashids.Hashids; | |
import org.springframework.beans.factory.annotation.Autowired; | |
import org.springframework.stereotype.Service; | |
import org.springframework.web.multipart.MultipartFile; | |
import java.io.IOException; | |
import java.util.List; | |
/* | |
Unrelated code omitted for brevity | |
*/ | |
@Service | |
public class GifServiceImpl implements GifService { | |
@Autowired | |
private GifDao gifDao; | |
@Override | |
public void save(Gif gif, MultipartFile file) { | |
try { | |
gif.setBytes(file.getBytes()); | |
} catch (IOException e) { | |
} | |
gifDao.save(gif); | |
} | |
@Override | |
public void update(Gif gif, MultipartFile file) { | |
if(file != null && !file.isEmpty()) { | |
try { | |
gif.setBytes(file.getBytes()); | |
} catch (IOException e) { | |
} | |
} else { | |
Gif oldGif = gifDao.findById(gif.getId()); | |
gif.setBytes(oldGif.getBytes()); | |
} | |
gifDao.save(gif); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
This is the custom validator class. | |
*/ | |
package com.teamtreehouse.giflib.validator; | |
import com.teamtreehouse.giflib.model.Gif; | |
import org.springframework.beans.factory.annotation.Autowired; | |
import org.springframework.stereotype.Component; | |
import org.springframework.validation.Errors; | |
import org.springframework.validation.ValidationUtils; | |
import org.springframework.validation.Validator; | |
@Component | |
public class GifValidator implements Validator { | |
@Autowired | |
private Validator validator; | |
@Override | |
public boolean supports(Class<?> clazz) { | |
return Gif.class.equals(clazz); | |
} | |
@Override | |
public void validate(Object target, Errors errors) { | |
Gif gif = (Gif)target; | |
// Validate file only if the Gif's id is null (with a null id, it must be a new Gif), | |
// so that existing Gif can be updated without uploading new file | |
if(gif.getId() == null && (gif.getFile() == null || gif.getFile().isEmpty())) { | |
errors.rejectValue("file","file.required","Please choose a file to upload"); | |
} | |
// Validate description | |
ValidationUtils.rejectIfEmptyOrWhitespace(errors,"description","description.empty","Please enter a description"); | |
// Validate category | |
ValidationUtils.rejectIfEmpty(errors,"category","category.empty","Please choose a category"); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment