diff --git a/.gitignore b/.gitignore index 98f3619..d7dcf6f 100644 --- a/.gitignore +++ b/.gitignore @@ -1,15 +1,6 @@ -# Compiled class file -*.class - # Log file *.log -# BlueJ files -*.ctxt - -# Mobile Tools for Java (J2ME) -.mtj.tmp/ - # Package Files # *.jar *.war diff --git a/pom.xml b/pom.xml index 225d154..e716569 100644 --- a/pom.xml +++ b/pom.xml @@ -46,11 +46,6 @@ org.liquibase liquibase-core - - org.liquibase - liquibase-maven-plugin - 3.5.3 - mysql @@ -63,6 +58,12 @@ test + + com.github.javafaker + javafaker + 0.15 + + org.webjars bootstrap @@ -80,7 +81,7 @@ org.liquibase liquibase-maven-plugin - 3.5.3 + 3.6.2 src/main/resources/liquibase.properties diff --git a/src/main/java/com/github/prominence/carrepair/CarRepairApplication.java b/src/main/java/com/github/prominence/carrepair/CarRepairApplication.java index f0394bf..52296f1 100644 --- a/src/main/java/com/github/prominence/carrepair/CarRepairApplication.java +++ b/src/main/java/com/github/prominence/carrepair/CarRepairApplication.java @@ -10,8 +10,10 @@ import org.springframework.data.jpa.repository.config.EnableJpaRepositories; @SpringBootApplication public class CarRepairApplication { - public static void main(String[] args) { - SpringApplication.run(CarRepairApplication.class, args); - } + public static void main(String[] args) { + SpringApplication.run(CarRepairApplication.class, args); + } -} \ No newline at end of file +} +// TODO: logging +// TODO: DTO \ No newline at end of file diff --git a/src/main/java/com/github/prominence/carrepair/controller/ClientController.java b/src/main/java/com/github/prominence/carrepair/controller/ClientController.java index 34c5489..74ca59a 100644 --- a/src/main/java/com/github/prominence/carrepair/controller/ClientController.java +++ b/src/main/java/com/github/prominence/carrepair/controller/ClientController.java @@ -1,16 +1,87 @@ package com.github.prominence.carrepair.controller; +import com.github.prominence.carrepair.model.Client; +import com.github.prominence.carrepair.service.ClientService; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.http.ResponseEntity; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; -import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.ui.ModelMap; +import org.springframework.validation.BindingResult; +import org.springframework.web.bind.annotation.*; + +import javax.validation.Valid; +import java.util.Optional; @Controller @RequestMapping("/client") public class ClientController { - @RequestMapping - public String index(Model model) { + private ClientService clientService; + + public ClientController(ClientService clientService) { + this.clientService = clientService; + } + + @GetMapping + public String index(ModelMap modelMap) { + Page clientList = clientService.findAll((Pageable) modelMap.get("pagination")); + + modelMap.addAttribute("clientList", clientList.getContent()); + modelMap.addAttribute("totalPages", clientList.getTotalPages()); return "client/index"; } + + @GetMapping(value = "/create") + public String create(Model model) { + model.addAttribute("client", new Client()); + + return "client/edit"; + } + + @GetMapping(value = "/edit/{id}") + public String edit(@PathVariable Long id, Model model) { + Optional clientOptional = clientService.findById(id); + if (clientOptional.isPresent()) { + model.addAttribute("client", clientOptional.get()); + return "client/edit"; + } else { + // TODO: need to show warning + return "redirect:/client"; + } + } + + @PostMapping(value = "/update/{id}") + public String update(@Valid Client client, BindingResult bindingResult, @PathVariable long id) { + if (bindingResult.hasErrors()) { + client.setId(id); // why should we do this? + return "client/edit"; + } + + clientService.save(client); + return "redirect:/client"; + } + + @PostMapping(value = "/create") + public String save(@Valid Client client, BindingResult bindingResult) { + if (bindingResult.hasErrors()) { + return "client/edit"; + } + + clientService.save(client); + return "redirect:/client"; + } + + @DeleteMapping(value = "/delete/{id}") + public ResponseEntity delete(@PathVariable Long id) { + boolean deleteSuccess = clientService.deleteClientById(id); + + if (deleteSuccess) { + return ResponseEntity.ok().build(); + } else { + return ResponseEntity.notFound().build(); + } + } } diff --git a/src/main/java/com/github/prominence/carrepair/controller/advice/PaginationAdvice.java b/src/main/java/com/github/prominence/carrepair/controller/advice/PaginationAdvice.java new file mode 100644 index 0000000..5d9d482 --- /dev/null +++ b/src/main/java/com/github/prominence/carrepair/controller/advice/PaginationAdvice.java @@ -0,0 +1,24 @@ +package com.github.prominence.carrepair.controller.advice; + +import org.springframework.data.domain.PageRequest; +import org.springframework.data.domain.Pageable; +import org.springframework.ui.Model; +import org.springframework.web.bind.annotation.ControllerAdvice; +import org.springframework.web.bind.annotation.ModelAttribute; +import org.springframework.web.bind.annotation.RequestParam; + +@ControllerAdvice +public class PaginationAdvice { + + private static final int DEFAULT_PAGE_SIZE = 10; + + @ModelAttribute("pagination") + public void addPagination(@RequestParam(required = false) Integer size, @RequestParam(required = false) Integer page, Model model) { + final int pageValue = page == null ? 0 : page; + final int sizeValue = size == null ? DEFAULT_PAGE_SIZE : size; + Pageable pagination = PageRequest.of(pageValue, sizeValue); + + model.addAttribute("pagination", pagination); + model.addAttribute("page", pageValue); + } +} diff --git a/src/main/java/com/github/prominence/carrepair/demo/DemoDataPopulator.java b/src/main/java/com/github/prominence/carrepair/demo/DemoDataPopulator.java new file mode 100644 index 0000000..21febfe --- /dev/null +++ b/src/main/java/com/github/prominence/carrepair/demo/DemoDataPopulator.java @@ -0,0 +1,37 @@ +package com.github.prominence.carrepair.demo; + +import com.github.javafaker.Faker; +import com.github.prominence.carrepair.model.Client; +import com.github.prominence.carrepair.repository.ClientRepository; +import org.springframework.boot.CommandLineRunner; +import org.springframework.context.annotation.Bean; +import org.springframework.stereotype.Component; + +import java.util.List; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +@Component +public class DemoDataPopulator { + private static final int COUNT = 10; + + @Bean + public CommandLineRunner demoData(ClientRepository clientRepository) { + Faker faker = new Faker(); + + List demoClientList = Stream.generate(() -> { + Client client = new Client(); + client.setFirstName(faker.name().firstName()); + client.setLastName(faker.name().lastName()); + client.setMiddleName(faker.name().username()); + client.setPhoneNo(faker.phoneNumber().phoneNumber()); + System.out.println(client); // demo output + return client; + }).limit(COUNT).collect(Collectors.toList()); + + return args -> { + demoClientList.forEach(clientRepository::save); + }; + } + +} diff --git a/src/main/java/com/github/prominence/carrepair/model/Client.java b/src/main/java/com/github/prominence/carrepair/model/Client.java index b146499..95ad174 100644 --- a/src/main/java/com/github/prominence/carrepair/model/Client.java +++ b/src/main/java/com/github/prominence/carrepair/model/Client.java @@ -3,11 +3,14 @@ package com.github.prominence.carrepair.model; import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.Table; +import javax.validation.constraints.Size; +import java.util.Objects; @Entity @Table(name = "client") public class Client extends Person { + @Size(max = 32) @Column(name = "phoneNo") private String phoneNo; @@ -26,4 +29,29 @@ public class Client extends Person { public void setPhoneNo(String phoneNo) { this.phoneNo = phoneNo; } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (!(o instanceof Client)) return false; + if (!super.equals(o)) return false; + Client client = (Client) o; + return Objects.equals(phoneNo, client.phoneNo); + } + + @Override + public int hashCode() { + return Objects.hash(super.hashCode(), phoneNo); + } + + @Override + public String toString() { + return "Client{" + + "id=" + id + + ", firstName='" + firstName + '\'' + + ", middleName='" + middleName + '\'' + + ", lastName='" + lastName + '\'' + + ", phoneNo='" + phoneNo + '\'' + + '}'; + } } diff --git a/src/main/java/com/github/prominence/carrepair/model/Person.java b/src/main/java/com/github/prominence/carrepair/model/Person.java index 28924d3..d877caa 100644 --- a/src/main/java/com/github/prominence/carrepair/model/Person.java +++ b/src/main/java/com/github/prominence/carrepair/model/Person.java @@ -2,24 +2,29 @@ package com.github.prominence.carrepair.model; import javax.persistence.*; import javax.validation.constraints.NotNull; +import javax.validation.constraints.Size; +import java.util.Objects; @MappedSuperclass abstract public class Person { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) - private long id; + protected long id; @NotNull + @Size(max = 64) @Column(name = "firstName") - private String firstName; + protected String firstName; + @Size(max = 64) @Column(name = "middleName") - private String middleName; + protected String middleName; @NotNull + @Size(max = 64) @Column(name = "lastName") - private String lastName; + protected String lastName; public Person(String firstName, String middleName, String lastName) { this.firstName = firstName; @@ -61,4 +66,20 @@ abstract public class Person { public void setLastName(String lastName) { this.lastName = lastName; } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (!(o instanceof Person)) return false; + Person person = (Person) o; + return id == person.id && + Objects.equals(firstName, person.firstName) && + Objects.equals(middleName, person.middleName) && + Objects.equals(lastName, person.lastName); + } + + @Override + public int hashCode() { + return Objects.hash(id, firstName, middleName, lastName); + } } diff --git a/src/main/java/com/github/prominence/carrepair/service/ClientService.java b/src/main/java/com/github/prominence/carrepair/service/ClientService.java new file mode 100644 index 0000000..6fa19b9 --- /dev/null +++ b/src/main/java/com/github/prominence/carrepair/service/ClientService.java @@ -0,0 +1,40 @@ +package com.github.prominence.carrepair.service; + +import com.github.prominence.carrepair.model.Client; +import com.github.prominence.carrepair.repository.ClientRepository; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.stereotype.Service; + +import java.util.Optional; + +@Service +public class ClientService { + + private ClientRepository clientRepository; + + public ClientService(ClientRepository clientRepository) { + this.clientRepository = clientRepository; + } + + public Page findAll(Pageable pageable) { + return clientRepository.findAll(pageable); + } + + public Optional findById(Long id) { + return clientRepository.findById(id); + } + + public Client save(Client client) { + return clientRepository.save(client); + } + + public boolean deleteClientById(Long id) { + try { + clientRepository.deleteById(id); + return true; + } catch (Exception e) { + return false; + } + } +} diff --git a/src/main/resources/static/css/main.css b/src/main/resources/static/css/main.css index 47e1dc8..01e225a 100644 --- a/src/main/resources/static/css/main.css +++ b/src/main/resources/static/css/main.css @@ -1,2 +1,6 @@ body { +} + +.fieldError { + border: 1px solid red; } \ No newline at end of file diff --git a/src/main/resources/templates/client/edit.html b/src/main/resources/templates/client/edit.html new file mode 100644 index 0000000..7a32bf9 --- /dev/null +++ b/src/main/resources/templates/client/edit.html @@ -0,0 +1,50 @@ + + + + + + +
+

+ +
+
+ +
+ +
+
+
+
+ +
+ +
+
+
+
+ +
+ +
+
+
+
+ +
+ +
+
+
+
+
+ Back + +
+
+
+
+ + + \ No newline at end of file diff --git a/src/main/resources/templates/client/index.html b/src/main/resources/templates/client/index.html index f6deaf3..2c61b0f 100644 --- a/src/main/resources/templates/client/index.html +++ b/src/main/resources/templates/client/index.html @@ -3,11 +3,58 @@ layout:decorate="~{main}"> + +

+
+ Create +
+ + + + + + + + + + + + + + + + + + + + +
First NameMiddle NameLast NamePhone No 
+
+ Edit + +
+
+
diff --git a/src/main/resources/templates/common.html b/src/main/resources/templates/common.html new file mode 100644 index 0000000..bfbe2b3 --- /dev/null +++ b/src/main/resources/templates/common.html @@ -0,0 +1,20 @@ + + + +
+
    + +
  • ...
  • +
  • +
    +
+
+ +
+
    +
  • +
+
+ + \ No newline at end of file diff --git a/src/main/resources/templates/main.html b/src/main/resources/templates/main.html index bf6257d..60494c1 100644 --- a/src/main/resources/templates/main.html +++ b/src/main/resources/templates/main.html @@ -51,6 +51,7 @@
+