Skip to content
Draft
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
Original file line number Diff line number Diff line change
Expand Up @@ -99,9 +99,13 @@ public String processFindForm(@RequestParam(defaultValue = "1") int page, Owner
if (lastName == null) {
lastName = ""; // empty string signifies broadest possible search
}
String firstName = owner.getFirstName();
if (firstName == null) {
firstName = ""; // empty string signifies broadest possible search
}

// find owners by last name
Page<Owner> ownersResults = findPaginatedForOwnersLastName(page, lastName);
// find owners by first name and last name
Page<Owner> ownersResults = findPaginatedForOwners(page, firstName, lastName);
if (ownersResults.isEmpty()) {
// no owners found
result.rejectValue("lastName", "notFound", "not found");
Expand All @@ -115,6 +119,8 @@ public String processFindForm(@RequestParam(defaultValue = "1") int page, Owner
}

// multiple owners found
model.addAttribute("firstName", firstName);
model.addAttribute("lastName", lastName);
return addPaginationModel(page, model, ownersResults);
}

Expand All @@ -127,10 +133,10 @@ private String addPaginationModel(int page, Model model, Page<Owner> paginated)
return "owners/ownersList";
}

private Page<Owner> findPaginatedForOwnersLastName(int page, String lastname) {
private Page<Owner> findPaginatedForOwners(int page, String firstName, String lastName) {
int pageSize = 5;
Pageable pageable = PageRequest.of(page - 1, pageSize);
return owners.findByLastNameStartingWith(lastname, pageable);
return owners.findByFirstNameStartingWithAndLastNameStartingWith(firstName, lastName, pageable);
}

@GetMapping("/owners/{ownerId}/edit")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,18 @@ public interface OwnerRepository extends JpaRepository<Owner, Integer> {
*/
Page<Owner> findByLastNameStartingWith(String lastName, Pageable pageable);

/**
* Retrieve {@link Owner}s from the data store by first name and last name, returning
* all owners whose first name <i>starts</i> with the given first name and whose last
* name <i>starts</i> with the given last name.
* @param firstName Value to search for in first name
* @param lastName Value to search for in last name
* @return a Collection of matching {@link Owner}s (or an empty Collection if none
* found)
*/
Page<Owner> findByFirstNameStartingWithAndLastNameStartingWith(String firstName, String lastName,
Pageable pageable);

/**
* Retrieve an {@link Owner} from the data store by id.
* <p>
Expand Down
8 changes: 8 additions & 0 deletions src/main/resources/templates/owners/findOwners.html
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,14 @@
<h2 th:text="#{findOwners}">Find Owners</h2>

<form th:object="${owner}" th:action="@{/owners}" method="get" class="form-horizontal" id="search-owner-form">
<div class="form-group">
<div class="control-group" id="firstNameGroup">
<label class="col-sm-2 control-label" th:text="#{firstName}">First name </label>

Check warning on line 12 in src/main/resources/templates/owners/findOwners.html

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

A form label must be associated with a control and have accessible text.

See more on https://sonarcloud.io/project/issues?id=ona-samples_spring-petclinic&issues=AZ0Err3VQsj-WQT-UgGv&open=AZ0Err3VQsj-WQT-UgGv&pullRequest=86
<div class="col-sm-10">
<input class="form-control" th:field="*{firstName}" size="30" maxlength="80" />
</div>
</div>
</div>
<div class="form-group">
<div class="control-group" id="lastNameGroup">
<label class="col-sm-2 control-label" th:text="#{lastName}">Last name </label>
Expand Down
10 changes: 5 additions & 5 deletions src/main/resources/templates/owners/ownersList.html
Original file line number Diff line number Diff line change
Expand Up @@ -32,26 +32,26 @@ <h2 th:text="#{owners}">Owners</h2>
<span th:text="#{pages}">Pages:</span>
<span>[</span>
<span th:each="i: ${#numbers.sequence(1, totalPages)}">
<a th:if="${currentPage != i}" th:href="@{'/owners?page=' + ${i}}">[[${i}]]</a>
<a th:if="${currentPage != i}" th:href="@{/owners(page=${i},firstName=${firstName},lastName=${lastName})}">[[${i}]]</a>
<span th:unless="${currentPage != i}">[[${i}]]</span>
</span>
<span>]&nbsp;</span>
<span>
<a th:if="${currentPage > 1}" th:href="@{'/owners?page=1'}" th:title="#{first}" class="fa fa-fast-backward"></a>
<a th:if="${currentPage > 1}" th:href="@{/owners(page=1,firstName=${firstName},lastName=${lastName})}" th:title="#{first}" class="fa fa-fast-backward"></a>
<span th:unless="${currentPage > 1}" th:title="#{first}" class="fa fa-fast-backward"></span>
</span>
<span>
<a th:if="${currentPage > 1}" th:href="@{'/owners?page=__${currentPage - 1}__'}" th:title="#{previous}"
<a th:if="${currentPage > 1}" th:href="@{/owners(page=${currentPage - 1},firstName=${firstName},lastName=${lastName})}" th:title="#{previous}"
class="fa fa-step-backward"></a>
<span th:unless="${currentPage > 1}" th:title="#{previous}" class="fa fa-step-backward"></span>
</span>
<span>
<a th:if="${currentPage < totalPages}" th:href="@{'/owners?page=__${currentPage + 1}__'}" th:title="#{next}"
<a th:if="${currentPage < totalPages}" th:href="@{/owners(page=${currentPage + 1},firstName=${firstName},lastName=${lastName})}" th:title="#{next}"
class="fa fa-step-forward"></a>
<span th:unless="${currentPage < totalPages}" th:title="#{next}" class="fa fa-step-forward"></span>
</span>
<span>
<a th:if="${currentPage < totalPages}" th:href="@{'/owners?page=__${totalPages}__'}" th:title="#{last}"
<a th:if="${currentPage < totalPages}" th:href="@{/owners(page=${totalPages},firstName=${firstName},lastName=${lastName})}" th:title="#{last}"
class="fa fa-fast-forward"></a>
<span th:unless="${currentPage < totalPages}" th:title="#{last}" class="fa fa-fast-forward"></span>
</span>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,8 @@ private Owner george() {
void setup() {

Owner george = george();
given(this.owners.findByLastNameStartingWith(eq("Franklin"), any(Pageable.class)))
given(this.owners.findByFirstNameStartingWithAndLastNameStartingWith(eq(""), eq("Franklin"),
any(Pageable.class)))
.willReturn(new PageImpl<>(List.of(george)));

given(this.owners.findById(TEST_OWNER_ID)).willReturn(Optional.of(george));
Expand Down Expand Up @@ -142,29 +143,67 @@ void testInitFindForm() throws Exception {
@Test
void testProcessFindFormSuccess() throws Exception {
Page<Owner> tasks = new PageImpl<>(List.of(george(), new Owner()));
when(this.owners.findByLastNameStartingWith(anyString(), any(Pageable.class))).thenReturn(tasks);
when(this.owners.findByFirstNameStartingWithAndLastNameStartingWith(anyString(), anyString(),
any(Pageable.class)))
.thenReturn(tasks);
mockMvc.perform(get("/owners?page=1")).andExpect(status().isOk()).andExpect(view().name("owners/ownersList"));
}

@Test
void testProcessFindFormByLastName() throws Exception {
Page<Owner> tasks = new PageImpl<>(List.of(george()));
when(this.owners.findByLastNameStartingWith(eq("Franklin"), any(Pageable.class))).thenReturn(tasks);
when(this.owners.findByFirstNameStartingWithAndLastNameStartingWith(eq(""), eq("Franklin"),
any(Pageable.class)))
.thenReturn(tasks);
mockMvc.perform(get("/owners?page=1").param("lastName", "Franklin"))
.andExpect(status().is3xxRedirection())
.andExpect(view().name("redirect:/owners/" + TEST_OWNER_ID));
}

@Test
void testProcessFindFormByFirstName() throws Exception {
Page<Owner> tasks = new PageImpl<>(List.of(george()));
when(this.owners.findByFirstNameStartingWithAndLastNameStartingWith(eq("George"), eq(""), any(Pageable.class)))
.thenReturn(tasks);
mockMvc.perform(get("/owners?page=1").param("firstName", "George"))
.andExpect(status().is3xxRedirection())
.andExpect(view().name("redirect:/owners/" + TEST_OWNER_ID));
}

@Test
void testProcessFindFormByFirstNameAndLastName() throws Exception {
Page<Owner> tasks = new PageImpl<>(List.of(george()));
when(this.owners.findByFirstNameStartingWithAndLastNameStartingWith(eq("George"), eq("Franklin"),
any(Pageable.class)))
.thenReturn(tasks);
mockMvc.perform(get("/owners?page=1").param("firstName", "George").param("lastName", "Franklin"))
.andExpect(status().is3xxRedirection())
.andExpect(view().name("redirect:/owners/" + TEST_OWNER_ID));
}

@Test
void testProcessFindFormNoOwnersFound() throws Exception {
Page<Owner> tasks = new PageImpl<>(List.of());
when(this.owners.findByLastNameStartingWith(eq("Unknown Surname"), any(Pageable.class))).thenReturn(tasks);
when(this.owners.findByFirstNameStartingWithAndLastNameStartingWith(eq(""), eq("Unknown Surname"),
any(Pageable.class)))
.thenReturn(tasks);
mockMvc.perform(get("/owners?page=1").param("lastName", "Unknown Surname"))
.andExpect(status().isOk())
.andExpect(model().attributeHasFieldErrors("owner", "lastName"))
.andExpect(model().attributeHasFieldErrorCode("owner", "lastName", "notFound"))
.andExpect(view().name("owners/findOwners"));
}

@Test
void testProcessFindFormByFirstNameNoOwnersFound() throws Exception {
Page<Owner> tasks = new PageImpl<>(List.of());
when(this.owners.findByFirstNameStartingWithAndLastNameStartingWith(eq("Unknown"), eq(""), any(Pageable.class)))
.thenReturn(tasks);
mockMvc.perform(get("/owners?page=1").param("firstName", "Unknown"))
.andExpect(status().isOk())
.andExpect(model().attributeHasFieldErrors("owner", "lastName"))
.andExpect(model().attributeHasFieldErrorCode("owner", "lastName", "notFound"))
.andExpect(view().name("owners/findOwners"));
}

@Test
Expand Down
Loading