mirror of
https://github.com/Prominence/car-repair-site.git
synced 2026-01-09 19:56:43 +03:00
Added CRUD for 'Client' entity. Added common templates and demo data populator.
This commit is contained in:
parent
22f1ebf607
commit
b541e69885
9
.gitignore
vendored
9
.gitignore
vendored
@ -1,15 +1,6 @@
|
|||||||
# Compiled class file
|
|
||||||
*.class
|
|
||||||
|
|
||||||
# Log file
|
# Log file
|
||||||
*.log
|
*.log
|
||||||
|
|
||||||
# BlueJ files
|
|
||||||
*.ctxt
|
|
||||||
|
|
||||||
# Mobile Tools for Java (J2ME)
|
|
||||||
.mtj.tmp/
|
|
||||||
|
|
||||||
# Package Files #
|
# Package Files #
|
||||||
*.jar
|
*.jar
|
||||||
*.war
|
*.war
|
||||||
|
|||||||
13
pom.xml
13
pom.xml
@ -46,11 +46,6 @@
|
|||||||
<groupId>org.liquibase</groupId>
|
<groupId>org.liquibase</groupId>
|
||||||
<artifactId>liquibase-core</artifactId>
|
<artifactId>liquibase-core</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
|
||||||
<groupId>org.liquibase</groupId>
|
|
||||||
<artifactId>liquibase-maven-plugin</artifactId>
|
|
||||||
<version>3.5.3</version>
|
|
||||||
</dependency>
|
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>mysql</groupId>
|
<groupId>mysql</groupId>
|
||||||
@ -63,6 +58,12 @@
|
|||||||
<scope>test</scope>
|
<scope>test</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.github.javafaker</groupId>
|
||||||
|
<artifactId>javafaker</artifactId>
|
||||||
|
<version>0.15</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.webjars</groupId>
|
<groupId>org.webjars</groupId>
|
||||||
<artifactId>bootstrap</artifactId>
|
<artifactId>bootstrap</artifactId>
|
||||||
@ -80,7 +81,7 @@
|
|||||||
<plugin>
|
<plugin>
|
||||||
<groupId>org.liquibase</groupId>
|
<groupId>org.liquibase</groupId>
|
||||||
<artifactId>liquibase-maven-plugin</artifactId>
|
<artifactId>liquibase-maven-plugin</artifactId>
|
||||||
<version>3.5.3</version>
|
<version>3.6.2</version>
|
||||||
<configuration>
|
<configuration>
|
||||||
<propertyFile>src/main/resources/liquibase.properties</propertyFile>
|
<propertyFile>src/main/resources/liquibase.properties</propertyFile>
|
||||||
</configuration>
|
</configuration>
|
||||||
|
|||||||
@ -10,8 +10,10 @@ import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
|
|||||||
@SpringBootApplication
|
@SpringBootApplication
|
||||||
public class CarRepairApplication {
|
public class CarRepairApplication {
|
||||||
|
|
||||||
public static void main(String[] args) {
|
public static void main(String[] args) {
|
||||||
SpringApplication.run(CarRepairApplication.class, args);
|
SpringApplication.run(CarRepairApplication.class, args);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
// TODO: logging
|
||||||
|
// TODO: DTO
|
||||||
@ -1,16 +1,87 @@
|
|||||||
package com.github.prominence.carrepair.controller;
|
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.stereotype.Controller;
|
||||||
import org.springframework.ui.Model;
|
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
|
@Controller
|
||||||
@RequestMapping("/client")
|
@RequestMapping("/client")
|
||||||
public class ClientController {
|
public class ClientController {
|
||||||
|
|
||||||
@RequestMapping
|
private ClientService clientService;
|
||||||
public String index(Model model) {
|
|
||||||
|
public ClientController(ClientService clientService) {
|
||||||
|
this.clientService = clientService;
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping
|
||||||
|
public String index(ModelMap modelMap) {
|
||||||
|
Page<Client> clientList = clientService.findAll((Pageable) modelMap.get("pagination"));
|
||||||
|
|
||||||
|
modelMap.addAttribute("clientList", clientList.getContent());
|
||||||
|
modelMap.addAttribute("totalPages", clientList.getTotalPages());
|
||||||
|
|
||||||
return "client/index";
|
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<Client> 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();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -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<Client> 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);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -3,11 +3,14 @@ package com.github.prominence.carrepair.model;
|
|||||||
import javax.persistence.Column;
|
import javax.persistence.Column;
|
||||||
import javax.persistence.Entity;
|
import javax.persistence.Entity;
|
||||||
import javax.persistence.Table;
|
import javax.persistence.Table;
|
||||||
|
import javax.validation.constraints.Size;
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
@Entity
|
@Entity
|
||||||
@Table(name = "client")
|
@Table(name = "client")
|
||||||
public class Client extends Person {
|
public class Client extends Person {
|
||||||
|
|
||||||
|
@Size(max = 32)
|
||||||
@Column(name = "phoneNo")
|
@Column(name = "phoneNo")
|
||||||
private String phoneNo;
|
private String phoneNo;
|
||||||
|
|
||||||
@ -26,4 +29,29 @@ public class Client extends Person {
|
|||||||
public void setPhoneNo(String phoneNo) {
|
public void setPhoneNo(String phoneNo) {
|
||||||
this.phoneNo = 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 + '\'' +
|
||||||
|
'}';
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -2,24 +2,29 @@ package com.github.prominence.carrepair.model;
|
|||||||
|
|
||||||
import javax.persistence.*;
|
import javax.persistence.*;
|
||||||
import javax.validation.constraints.NotNull;
|
import javax.validation.constraints.NotNull;
|
||||||
|
import javax.validation.constraints.Size;
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
@MappedSuperclass
|
@MappedSuperclass
|
||||||
abstract public class Person {
|
abstract public class Person {
|
||||||
|
|
||||||
@Id
|
@Id
|
||||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||||
private long id;
|
protected long id;
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
|
@Size(max = 64)
|
||||||
@Column(name = "firstName")
|
@Column(name = "firstName")
|
||||||
private String firstName;
|
protected String firstName;
|
||||||
|
|
||||||
|
@Size(max = 64)
|
||||||
@Column(name = "middleName")
|
@Column(name = "middleName")
|
||||||
private String middleName;
|
protected String middleName;
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
|
@Size(max = 64)
|
||||||
@Column(name = "lastName")
|
@Column(name = "lastName")
|
||||||
private String lastName;
|
protected String lastName;
|
||||||
|
|
||||||
public Person(String firstName, String middleName, String lastName) {
|
public Person(String firstName, String middleName, String lastName) {
|
||||||
this.firstName = firstName;
|
this.firstName = firstName;
|
||||||
@ -61,4 +66,20 @@ abstract public class Person {
|
|||||||
public void setLastName(String lastName) {
|
public void setLastName(String lastName) {
|
||||||
this.lastName = 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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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<Client> findAll(Pageable pageable) {
|
||||||
|
return clientRepository.findAll(pageable);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Optional<Client> 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,2 +1,6 @@
|
|||||||
body {
|
body {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.fieldError {
|
||||||
|
border: 1px solid red;
|
||||||
|
}
|
||||||
50
src/main/resources/templates/client/edit.html
Normal file
50
src/main/resources/templates/client/edit.html
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
<!doctype html>
|
||||||
|
<html lang="en" xmlns:th="http://www.thymeleaf.org" xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout"
|
||||||
|
layout:decorate="~{main}">
|
||||||
|
<head>
|
||||||
|
<title th:text="#{default.title}"></title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div layout:fragment="content">
|
||||||
|
<h1 th:text="#{client.title}"></h1>
|
||||||
|
|
||||||
|
<form th:action="'/client/' + ${client.id != null ? 'update/' + client.id : 'create'}" th:object="${client}" method="post">
|
||||||
|
<div class="form-group row">
|
||||||
|
<label for="clientFirstName" class="col-sm-2 col-form-label">First Name</label>
|
||||||
|
<div class="col-sm-10">
|
||||||
|
<input type="text" name="firstName" class="form-control" id="clientFirstName" th:field="*{firstName}" th:errorclass="fieldError" th:value="${client.firstName}">
|
||||||
|
<div th:replace="common::errors('firstName')"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="form-group row">
|
||||||
|
<label for="clientMiddleName" class="col-sm-2 col-form-label">Middle Name</label>
|
||||||
|
<div class="col-sm-10">
|
||||||
|
<input type="text" name="middleName" class="form-control" id="clientMiddleName" th:field="*{middleName}" th:errorclass="fieldError" th:value="${client.middleName}">
|
||||||
|
<div th:replace="common::errors('middleName')"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="form-group row">
|
||||||
|
<label for="clientLastName" class="col-sm-2 col-form-label">Last Name</label>
|
||||||
|
<div class="col-sm-10">
|
||||||
|
<input type="text" name="lastName" class="form-control" id="clientLastName" th:field="*{lastName}" th:errorclass="fieldError" th:value="${client.lastName}">
|
||||||
|
<div th:replace="common::errors('lastName')"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="form-group row">
|
||||||
|
<label for="clientPhoneNo" class="col-sm-2 col-form-label">Phone No</label>
|
||||||
|
<div class="col-sm-10">
|
||||||
|
<input type="text" name="phoneNo" class="form-control" id="clientPhoneNo" th:field="*{phoneNo}" th:errorclass="fieldError" th:value="${client.phoneNo}">
|
||||||
|
<div th:replace="common::errors('phoneNo')"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="form-group row pull-right">
|
||||||
|
<div class="col-sm-12">
|
||||||
|
<a href="/client" class="btn btn-default">Back</a>
|
||||||
|
<button type="submit" class="btn btn-primary">Save</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@ -3,11 +3,58 @@
|
|||||||
layout:decorate="~{main}">
|
layout:decorate="~{main}">
|
||||||
<head>
|
<head>
|
||||||
<title th:text="#{default.title}"></title>
|
<title th:text="#{default.title}"></title>
|
||||||
|
|
||||||
|
<script th:inline="javascript">
|
||||||
|
function deleteClientById(id) {
|
||||||
|
const confirmationResult = confirm("Are you sure to delete?");
|
||||||
|
if (confirmationResult) {
|
||||||
|
const url = /*[[@{/client/delete/}]]*/;
|
||||||
|
|
||||||
|
$.ajax({
|
||||||
|
url: url + id,
|
||||||
|
type: 'DELETE',
|
||||||
|
success: function () {
|
||||||
|
$('#client-row-' + id).remove();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div layout:fragment="content">
|
<div layout:fragment="content">
|
||||||
<h1 th:text="#{client.title}"></h1>
|
<h1 th:text="#{client.title}"></h1>
|
||||||
|
|
||||||
|
<div class="pull-right">
|
||||||
|
<a class="btn btn-success" th:href="@{/client/create}">Create</a>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<table class="table table-striped table-hover">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>First Name</th>
|
||||||
|
<th>Middle Name</th>
|
||||||
|
<th>Last Name</th>
|
||||||
|
<th>Phone No</th>
|
||||||
|
<th> </th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<tr th:each="client : ${clientList}" th:id="'client-row-' + ${client.id}">
|
||||||
|
<td th:text="${client.firstName}"></td>
|
||||||
|
<td th:text="${client.middleName}"></td>
|
||||||
|
<td th:text="${client.lastName}"></td>
|
||||||
|
<td th:text="${client.phoneNo}"></td>
|
||||||
|
<td>
|
||||||
|
<div class="btn-group pull-right">
|
||||||
|
<a th:href="@{/client/edit/{id}(id=${client.id})}" class="btn btn-default">Edit</a>
|
||||||
|
<button type="button" class="btn btn-danger" th:onclick="'deleteClientById(' + ${client.id} + ')'">Delete</button>
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
<div th:replace="common::pagination(@{/client/}, ${page}, ${totalPages})"></div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</body>
|
</body>
|
||||||
|
|||||||
20
src/main/resources/templates/common.html
Normal file
20
src/main/resources/templates/common.html
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
<!doctype html>
|
||||||
|
<html xmlns="http://www.w3.org/1999/xhtml"
|
||||||
|
xmlns:th="http://www.thymeleaf.org">
|
||||||
|
<body>
|
||||||
|
<div th:fragment="pagination(baseUrl, currentPage, totalPages)">
|
||||||
|
<ul class="pagination pagination-small" th:if="${totalPages > 1}">
|
||||||
|
<th:block th:each="page : ${#numbers.sequence(0, totalPages - 1, 1)}" th:if="${page == 0 || page == totalPages - 1 || (page >= currentPage - 2 && page <= currentPage + 2)}">
|
||||||
|
<li class="disabled" th:if="${(page == currentPage - 2 && currentPage > 3) || (page == totalPages - 1 && currentPage < totalPages - 3)}"><a href="javascript:void(0);">...</a></li>
|
||||||
|
<li th:classappend="${currentPage == page ? 'active' : ''}"><a th:href="${page == 0 ? baseUrl : '?page=' + page}" th:text="${page + 1}"></a></li>
|
||||||
|
</th:block>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div th:fragment="errors(fieldName)" th:if="${#fields.hasErrors(fieldName)}">
|
||||||
|
<ul>
|
||||||
|
<li th:each="err : ${#fields.errors(fieldName)}" th:text="${err}"></li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@ -51,6 +51,7 @@
|
|||||||
</footer>
|
</footer>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
|
<script src="/webjars/jquery/3.3.1/jquery.min.js"></script>
|
||||||
<script src="/webjars/bootstrap/3.4.0/js/bootstrap.min.js"></script>
|
<script src="/webjars/bootstrap/3.4.0/js/bootstrap.min.js"></script>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user