Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added Bootstrap Error Page and CrashController. Closes #58 Closes #78 #136

Open
wants to merge 6 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 27 additions & 0 deletions pet-clinic-data/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@

<properties>
<spring-boot.repackage.skip>true</spring-boot.repackage.skip>
<hibernate.validator.version>6.1.2.Final</hibernate.validator.version>
</properties>

<dependencies>
Expand All @@ -34,6 +35,32 @@
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>javax.validation</groupId>
<artifactId>validation-api</artifactId>
<version>2.0.1.Final</version>
</dependency>
<dependency>
<groupId>org.hibernate.validator</groupId>
<artifactId>hibernate-validator</artifactId>
<version>${hibernate.validator.version}</version>
</dependency>
<dependency>
<groupId>org.hibernate.validator</groupId>
<artifactId>hibernate-validator-annotation-processor</artifactId>
<version>${hibernate.validator.version}</version>
</dependency>

<!-- caching -->
<dependency>
<groupId>javax.cache</groupId>
<artifactId>cache-api</artifactId>
</dependency>
<dependency>
<groupId>org.ehcache</groupId>
<artifactId>ehcache</artifactId>
</dependency>

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package guru.springframework.sfgpetclinic.cache;

import org.springframework.boot.autoconfigure.cache.JCacheManagerCustomizer;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import javax.cache.configuration.MutableConfiguration;

/**
* Cache configuration intended for caches providing the JCache API. This configuration
* creates the used cache for the application and enables statistics that become
* accessible via JMX.
*/
@Configuration
@EnableCaching
class CacheConfiguration {

@Bean
public JCacheManagerCustomizer petclinicCacheConfigurationCustomizer() {
return cm -> {
cm.createCache("vets", cacheConfiguration());
};
}

/**
* Create a simple configuration that enable statistics via the JCache programmatic
* configuration API.
* <p>
* Within the configuration object that is provided by the JCache API standard, there
* is only a very limited set of configuration options. The really relevant
* configuration options (like the size limit) must be set via a configuration
* mechanism that is provided by the selected JCache implementation.
*/
private javax.cache.configuration.Configuration<Object, Object> cacheConfiguration() {
return new MutableConfiguration<>().setStatisticsEnabled(true);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@
import lombok.Setter;

import javax.persistence.*;
import javax.validation.constraints.Digits;
import javax.validation.constraints.NotEmpty;
import java.util.HashSet;
import java.util.Set;

Expand Down Expand Up @@ -33,12 +35,16 @@ public Owner(Long id, String firstName, String lastName, String address, String
}

@Column(name = "address")
@NotEmpty
private String address;

@Column(name = "city")
@NotEmpty
private String city;

@Column(name = "telephone")
@NotEmpty
@Digits(fraction = 0, integer = 10)
private String telephone;

@OneToMany(cascade = CascadeType.ALL, mappedBy = "owner")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@

import javax.persistence.Column;
import javax.persistence.MappedSuperclass;
import javax.validation.constraints.NotEmpty;

/**
* Created by jt on 7/13/18.
Expand All @@ -25,9 +26,11 @@ public Person(Long id, String firstName, String lastName) {
}

@Column(name = "first_name")
@NotEmpty
private String firstName;

@Column(name = "last_name")
@NotEmpty
private String lastName;

}
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import org.springframework.format.annotation.DateTimeFormat;

import javax.persistence.*;
import javax.validation.constraints.NotEmpty;
import java.time.LocalDate;
import java.util.HashSet;
import java.util.Set;
Expand Down Expand Up @@ -33,6 +34,7 @@ public Pet(Long id, String name, PetType petType, Owner owner, LocalDate birthDa
}

@Column(name = "name")
@NotEmpty
private String name;

@ManyToOne
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
package guru.springframework.sfgpetclinic.model;

import lombok.*;
import org.springframework.format.annotation.DateTimeFormat;

import javax.persistence.*;
import javax.validation.constraints.NotEmpty;
import java.time.LocalDate;

/**
Expand All @@ -18,9 +20,11 @@
public class Visit extends BaseEntity {

@Column(name = "date")
@DateTimeFormat(pattern = "yyyy-MM-dd")
private LocalDate date;

@Column(name = "description")
@NotEmpty
private String description;

@ManyToOne
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,18 @@
package guru.springframework.sfgpetclinic.repositories;

import guru.springframework.sfgpetclinic.model.Vet;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.dao.DataAccessException;
import org.springframework.data.repository.CrudRepository;

import javax.transaction.Transactional;
import java.util.Collection;

/**
* Created by jt on 8/5/18.
*/
public interface VetRepository extends CrudRepository<Vet, Long> {
@Transactional
@Cacheable("vets")
Collection<Vet> findAll() throws DataAccessException;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
package guru.springframework.sfgpetclinic.validators;

import guru.springframework.sfgpetclinic.model.Pet;
import org.springframework.util.StringUtils;
import org.springframework.validation.Errors;
import org.springframework.validation.Validator;

/**
* @author Gaetan Bloch
* Created on 30/03/2020
*/
public final class PetValidator implements Validator {
private static final String REQUIRED = "required";

@Override
public void validate(Object obj, Errors errors) {
Pet pet = (Pet) obj;
String name = pet.getName();
// name validation
if (!StringUtils.hasLength(name)) {
errors.rejectValue("name", REQUIRED, REQUIRED);
}

// type validation
if (pet.isNew() && pet.getPetType() == null) {
errors.rejectValue("petType", REQUIRED, REQUIRED);
}

// birth date validation
if (pet.getBirthDate() == null) {
errors.rejectValue("birthDate", REQUIRED, REQUIRED);
}
}

/**
* This Validator validates *just* Pet instances
*/
@Override
public boolean supports(Class<?> clazz) {
return Pet.class.isAssignableFrom(clazz);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package guru.springframework.sfgpetclinic.controllers;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;

/**
* @author Gaetan Bloch
* Created on 30/03/2020
*/
@Controller
final class CrashController {
static final String URL_OUPS = "/oups";

@GetMapping(URL_OUPS)
public String triggerException() {
throw new RuntimeException("Expected: controller used to showcase what happens when an exception is thrown");
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,4 @@ public String index(){

return "index";
}

@RequestMapping("/oups")
public String oupsHandler(){
return "notimplemented";
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
@RequestMapping("/owners")
@Controller
public class OwnerController {
private static final String VIEWS_OWNER_CREATE_OR_UPDATE_FORM = "owners/createOrUpdateOwnerForm";
static final String VIEWS_OWNER_CREATE_OR_UPDATE_FORM = "owners/createOrUpdateOwnerForm";

private final OwnerService ownerService;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import guru.springframework.sfgpetclinic.services.OwnerService;
import guru.springframework.sfgpetclinic.services.PetService;
import guru.springframework.sfgpetclinic.services.PetTypeService;
import guru.springframework.sfgpetclinic.validators.PetValidator;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.ui.ModelMap;
Expand All @@ -24,7 +25,7 @@
@RequestMapping("/owners/{ownerId}")
public class PetController {

private static final String VIEWS_PETS_CREATE_OR_UPDATE_FORM = "pets/createOrUpdatePetForm";
static final String VIEWS_PETS_CREATE_OR_UPDATE_FORM = "pets/createOrUpdatePetForm";

private final PetService petService;
private final OwnerService ownerService;
Expand All @@ -51,6 +52,11 @@ public void initOwnerBinder(WebDataBinder dataBinder) {
dataBinder.setDisallowedFields("id");
}

@InitBinder("pet")
public void initPetBinder(WebDataBinder dataBinder) {
dataBinder.setValidator(new PetValidator());
}

@GetMapping("/pets/new")
public String initCreationForm(Owner owner, Model model) {
Pet pet = new Pet();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@
@Controller
public class VisitController {

static final String PETS_CREATE_OR_UPDATE_VISIT_FORM = "pets/createOrUpdateVisitForm";

private final VisitService visitService;
private final PetService petService;

Expand Down Expand Up @@ -64,14 +66,14 @@ public Visit loadPetWithVisit(@PathVariable("petId") Long petId, Map<String, Obj
// Spring MVC calls method loadPetWithVisit(...) before initNewVisitForm is called
@GetMapping("/owners/*/pets/{petId}/visits/new")
public String initNewVisitForm(@PathVariable("petId") Long petId, Map<String, Object> model) {
return "pets/createOrUpdateVisitForm";
return PETS_CREATE_OR_UPDATE_VISIT_FORM;
}

// Spring MVC calls method loadPetWithVisit(...) before processNewVisitForm is called
@PostMapping("/owners/{ownerId}/pets/{petId}/visits/new")
public String processNewVisitForm(@Valid Visit visit, BindingResult result) {
if (result.hasErrors()) {
return "pets/createOrUpdateVisitForm";
return PETS_CREATE_OR_UPDATE_VISIT_FORM;
} else {
visitService.save(visit);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
* Created by jt on 9/22/18.
*/
@Component
public class PetTypeFormatter implements Formatter<PetType> {
public final class PetTypeFormatter implements Formatter<PetType> {

private final PetTypeService petTypeService;

Expand Down
5 changes: 4 additions & 1 deletion pet-clinic-web/src/main/resources/application.properties
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,7 @@ spring.banner.image.location=vizsla.jpg
# Internationalization
spring.messages.basename=messages/messages

spring.profiles.active=springdatajpa
spring.profiles.active=springdatajpa

# Maximum time static resources should be cached
spring.resources.cache.cachecontrol.max-age=12h
11 changes: 11 additions & 0 deletions pet-clinic-web/src/main/resources/templates/error.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<!DOCTYPE html>

<html xmlns:th="https://www.thymeleaf.org" th:replace="~{fragments/layout :: layout (~{::body},'error')}">

<body>
<img src="../static/resources/images/pets.png" th:src="@{/resources/images/pets.png}"/>
<h2>Something happened...</h2>
<p th:text="${message}">Exception message</p>
</body>

</html>
10 changes: 0 additions & 10 deletions pet-clinic-web/src/main/resources/templates/notimplemented.html

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package guru.springframework.sfgpetclinic;

import guru.springframework.sfgpetclinic.services.VetService;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

@SpringBootTest
public class PetClinicIntegrationTest {

@Autowired
private VetService vetService;

@Test
void testFindAll() {
vetService.findAll();
vetService.findAll(); // served from cache
}
}
Loading