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

Remove unnecessary servlet response manipulations #5

Merged
merged 4 commits into from
Oct 22, 2023
Merged
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 @@ -33,9 +33,8 @@
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.servlet.ModelAndView;

import io.github.wimdeblauwe.htmx.spring.boot.mvc.HtmxResponse;
import io.github.wimdeblauwe.htmx.spring.boot.mvc.HxRequest;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.validation.Valid;

/**
Expand Down Expand Up @@ -119,21 +118,22 @@ public String htmxInitFindForm() {
}

@GetMapping("/owners")
public String ownersList(@RequestParam(defaultValue = "1") int page, Owner owner, BindingResult result, Model model,
HttpServletResponse response) {
return processFindForm(page, owner, result, model, response, "owners/findOwners", "owners/ownersList");
public String ownersList(@RequestParam(defaultValue = "1") int page, Owner owner, BindingResult result,
Model model) {
return processFindForm(page, owner, result, model, "owners/findOwners", "owners/ownersList");
}

@HxRequest
@GetMapping("/owners")
public String htmxOwnersList(@RequestParam(defaultValue = "1") int page, Owner owner, BindingResult result,
Model model, HttpServletResponse response) {
return processFindForm(page, owner, result, model, response, FRAGMENTS_OWNERS_FIND_FORM,
public HtmxResponse htmxOwnersList(@RequestParam(defaultValue = "1") int page, Owner owner, BindingResult result,
Model model) {
String view = processFindForm(page, owner, result, model, FRAGMENTS_OWNERS_FIND_FORM,
"fragments/owners :: list");
return new HtmxResponse().addTemplate(view);
}

public String processFindForm(@RequestParam(defaultValue = "1") int page, Owner owner, BindingResult result,
Model model, HttpServletResponse response, String emptyView, String listView) {
Model model, String emptyView, String listView) {
// allow parameterless GET request for /owners to return all records
if (owner.getLastName() == null) {
owner.setLastName(""); // empty string signifies broadest possible search
Expand All @@ -154,18 +154,16 @@ public String processFindForm(@RequestParam(defaultValue = "1") int page, Owner
}

// multiple owners found
return addPaginationModel(owner.getLastName(), page, model, ownersResults, response, listView);
return addPaginationModel(owner.getLastName(), page, model, ownersResults, listView);
}

private String addPaginationModel(String lastName, int page, Model model, Page<Owner> paginated,
HttpServletResponse response, String listView) {
private String addPaginationModel(String lastName, int page, Model model, Page<Owner> paginated, String listView) {
model.addAttribute("listOwners", paginated);
List<Owner> listOwners = paginated.getContent();
model.addAttribute("currentPage", page);
model.addAttribute("totalPages", paginated.getTotalPages());
model.addAttribute("totalItems", paginated.getTotalElements());
model.addAttribute("listOwners", listOwners);
response.addHeader("HX-Push-Url", "/owners?lastName=" + lastName + "&page=" + page);
return listView;
}

Expand All @@ -182,9 +180,7 @@ public String initUpdateOwnerForm(@PathVariable("ownerId") int ownerId, Model mo

@HxRequest
@GetMapping("/owners/{ownerId}/edit")
public String htmxInitUpdateOwnerForm(@PathVariable("ownerId") int ownerId, Model model, HttpServletRequest request,
HttpServletResponse response) {
response.addHeader("HX-Push-Url", request.getServletPath());
public String htmxInitUpdateOwnerForm(@PathVariable("ownerId") int ownerId, Model model) {
return handleInitUpdateOwnerForm(ownerId, model, FRAGMENTS_OWNERS_EDIT);
}

Expand Down Expand Up @@ -229,8 +225,7 @@ public ModelAndView showOwner(@PathVariable("ownerId") int ownerId) {

@HxRequest
@GetMapping("/owners/{ownerId}")
public ModelAndView htmxShowOwner(@PathVariable("ownerId") int ownerId, HttpServletResponse response) {
response.addHeader("HX-Push-Url", "/owners/" + ownerId);
public ModelAndView htmxShowOwner(@PathVariable("ownerId") int ownerId) {
return handleShowOwner(ownerId, "fragments/owners :: details");
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,6 @@
import org.springframework.web.bind.annotation.RequestMapping;

import io.github.wimdeblauwe.htmx.spring.boot.mvc.HxRequest;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.validation.Valid;

/**
Expand Down Expand Up @@ -87,9 +85,7 @@ public String initCreationForm(Owner owner, ModelMap model) {

@HxRequest
@GetMapping("/pets/new")
public String htmxInitCreationForm(Owner owner, ModelMap model, HttpServletRequest request,
HttpServletResponse response) {
response.addHeader("HX-Push-Url", request.getServletPath());
public String htmxInitCreationForm(Owner owner, ModelMap model) {
return handleInitCreationForm(owner, model, FRAGMENTS_PETS_EDIT);
}

Expand Down Expand Up @@ -135,8 +131,7 @@ public String initUpdateForm(Owner owner, @PathVariable("petId") int petId, Mode
@HxRequest
@GetMapping("/pets/{petId}/edit")
public String htmxInitUpdateForm(@PathVariable("ownerId") int ownerId, Owner owner,
@PathVariable("petId") int petId, ModelMap model, HttpServletResponse response) {
response.addHeader("HX-Push-Url", "/owners/" + ownerId + "/pets/" + petId + "/edit");
@PathVariable("petId") int petId, ModelMap model) {
return handleInitUpdateForm(owner, petId, model, FRAGMENTS_PETS_EDIT);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,6 @@
import org.springframework.web.bind.annotation.PostMapping;

import io.github.wimdeblauwe.htmx.spring.boot.mvc.HxRequest;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.validation.Valid;

/**
Expand Down Expand Up @@ -85,8 +83,7 @@ public String initNewVisitForm() {

@HxRequest
@GetMapping("/owners/{ownerId}/pets/{petId}/visits/new")
public String htmxInitNewVisitForm(HttpServletRequest request, HttpServletResponse response) {
response.addHeader("HX-Push-Url", request.getServletPath());
public String htmxInitNewVisitForm() {
return FRAGMENTS_PETS_VISITS;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@
import org.springframework.web.bind.annotation.ResponseBody;

import io.github.wimdeblauwe.htmx.spring.boot.mvc.HxRequest;
import jakarta.servlet.http.HttpServletResponse;

/**
* @author Juergen Hoeller
Expand All @@ -46,34 +45,31 @@ public VetController(VetRepository clinicService) {
}

@GetMapping("/vets.html")
public String showVetList(@RequestParam(defaultValue = "1") int page, Model model, HttpServletResponse response) {
return handleVetList(page, model, "vets/vetList", response);
public String showVetList(@RequestParam(defaultValue = "1") int page, Model model) {
return handleVetList(page, model, "vets/vetList");
}

@HxRequest
@GetMapping("/vets.html")
public String htmxShowVetList(@RequestParam(defaultValue = "1") int page, Model model,
HttpServletResponse response) {
return handleVetList(page, model, "fragments/vets :: list", response);
public String htmxShowVetList(@RequestParam(defaultValue = "1") int page, Model model) {
return handleVetList(page, model, "fragments/vets :: list");
}

protected String handleVetList(int page, Model model, String view, HttpServletResponse response) {
protected String handleVetList(int page, Model model, String view) {
// Here we are returning an object of type 'Vets' rather than a collection of Vet
// objects so it is simpler for Object-Xml mapping
Vets vets = new Vets();
Page<Vet> paginated = findPaginated(page);
vets.getVetList().addAll(paginated.toList());
return addPaginationModel(page, paginated, model, view, response);
return addPaginationModel(page, paginated, model, view);
}

private String addPaginationModel(int page, Page<Vet> paginated, Model model, String view,
HttpServletResponse response) {
private String addPaginationModel(int page, Page<Vet> paginated, Model model, String view) {
List<Vet> listVets = paginated.getContent();
model.addAttribute("currentPage", page);
model.addAttribute("totalPages", paginated.getTotalPages());
model.addAttribute("totalItems", paginated.getTotalElements());
model.addAttribute("listVets", listVets);
response.addHeader("HX-Push-Url", "/vets.html");
return view;
}

Expand Down
2 changes: 1 addition & 1 deletion src/main/resources/templates/fragments/layout.html
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@
<li th:fragment="menuItem (link,active,title,glyph,text,target)" th:class="nav-item"
_="on htmx:afterOnLoad take .active for event.target">
<a th:class="${active==menu ? 'nav-link active' : 'nav-link'}" th:href="@{__${link}__}" th:title="${title}"
hx:get="@{__${link}__}" hx:target="${target}" hx:push-url="@{__${link}__}">
hx:get="@{__${link}__}" hx:target="${target}" hx-push-url="true">
<span th:class="'fa fa-'+${glyph}" class="fa fa-home"></span>
<span th:text="${text}">Template</span>
</a>
Expand Down
18 changes: 11 additions & 7 deletions src/main/resources/templates/fragments/owners.html
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<div th:fragment="find-form" th:remove="tag">
<h2>Find Owners</h2>

<form th:object="${owner}" th:action="@{/owners}" method="get"
<form th:object="${owner}" th:action="@{/owners}" method="get" hx-push-url="true"
hx:get="@{/owners}" hx-swap="innerHTML" hx-target="#block-content"
class="form-horizontal" id="search-owner-form">
<div class="form-group">
Expand All @@ -25,7 +25,7 @@ <h2>Find Owners</h2>
</div>

<a class="btn btn-primary" hx:get="@{/owners/new}" hx-swap="innerHTML" hx-target="#block-content"
hx:push-url="@{/owners/new}" th:href="@{/owners/new}">Add Owner</a>
hx-push-url="true" th:href="@{/owners/new}">Add Owner</a>

</form>
</div>
Expand All @@ -47,7 +47,7 @@ <h2>Owners</h2>
<tr th:each="owner : ${listOwners}">
<td>
<a th:href="@{/owners/__${owner.id}__}" th:text="${owner.firstName + ' ' + owner.lastName}"
hx:get="@{/owners/__${owner.id}__}" hx-target="#block-content"/></a>
hx:get="@{/owners/__${owner.id}__}" hx-push-url="true" hx-target="#block-content"/></a>
</td>
<td th:text="${owner.address}"/>
<td th:text="${owner.city}"/>
Expand Down Expand Up @@ -83,10 +83,10 @@ <h2>Owner Information</h2>
</tr>
</table>

<a hx:get="@{__${owner.id}__/edit}" hx-target="#block-content" th:href="@{__${owner.id}__/edit}"
<a hx:get="@{__${owner.id}__/edit}" hx-push-url="true" hx-target="#block-content" th:href="@{__${owner.id}__/edit}"
class="btn btn-primary">Edit
Owner</a>
<a hx:get="@{__${owner.id}__/pets/new}" th:href="@{__${owner.id}__/pets/new}" hx-target="#block-content" class="btn btn-primary">Add
<a hx:get="@{__${owner.id}__/pets/new}" hx-push-url="true" th:href="@{__${owner.id}__/pets/new}" hx-target="#block-content" class="btn btn-primary">Add
New Pet</a>
</div>

Expand Down Expand Up @@ -122,9 +122,13 @@ <h2>Pets and Visits</h2>
</tr>
<tr>
<td><a th:href="@{__${owner.id}__/pets/__${pet.id}__/edit}"
hx-get="@{__${owner.id}__/pets/__${pet.id}__/edit}" hx-target="#block-content">Edit Pet</a></td>
hx:get="@{__${owner.id}__/pets/__${pet.id}__/edit}"
hx-push-url="true"
hx-target="#block-content">Edit Pet</a></td>
<td><a th:href="@{__${owner.id}__/pets/__${pet.id}__/visits/new}"
hx:get="@{__${owner.id}__/pets/__${pet.id}__/visits/new}" hx-target="#block-content">Add Visit</a></td>
hx:get="@{__${owner.id}__/pets/__${pet.id}__/visits/new}"
hx-push-url="true"
hx-target="#block-content">Add Visit</a></td>
</tr>
</table>
</td>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,28 @@

package org.springframework.samples.petclinic.owner;

import static org.hamcrest.Matchers.empty;
import static org.hamcrest.Matchers.hasProperty;
import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.not;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.BDDMockito.given;
import static org.springframework.samples.petclinic.htmx.HtmxTestUtils.toggleHtmx;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.model;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.view;

import java.time.LocalDate;
import java.util.List;

import org.assertj.core.util.Lists;
import org.hamcrest.BaseMatcher;
import org.hamcrest.Description;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.CsvSource;
import org.junit.jupiter.params.provider.ValueSource;
Expand All @@ -32,19 +49,6 @@
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.Pageable;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.request.MockHttpServletRequestBuilder;

import java.time.LocalDate;
import java.util.List;

import static org.hamcrest.Matchers.*;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.*;
import static org.mockito.BDDMockito.given;
import static org.springframework.samples.petclinic.htmx.HtmxTestUtils.toggleHtmx;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;

/**
* Test class for {@link OwnerController}
Expand Down Expand Up @@ -151,7 +155,7 @@ void testProcessFindFormSuccess(boolean hxRequest, String expectedViewName) thro
Mockito.when(this.owners.findByLastName(anyString(), any(Pageable.class))).thenReturn(tasks);
mockMvc.perform(toggleHtmx(get("/owners?page=1"), hxRequest))
.andExpect(status().isOk())
.andExpect(view().name(expectedViewName));
.andExpect(view().name(expectedViewName.contains("::") ? null : expectedViewName));
}

@ValueSource(booleans = { false, true })
Expand All @@ -161,7 +165,7 @@ void testProcessFindFormByLastName(boolean hxRequest) throws Exception {
Mockito.when(this.owners.findByLastName(eq("Franklin"), any(Pageable.class))).thenReturn(tasks);
mockMvc.perform(toggleHtmx(get("/owners?page=1"), hxRequest).param("lastName", "Franklin"))
.andExpect(status().is3xxRedirection())
.andExpect(view().name("redirect:/owners/" + TEST_OWNER_ID));
.andExpect(view().name(!hxRequest ? "redirect:/owners/" + TEST_OWNER_ID : null));
}

@CsvSource({ "false,owners/findOwners", "true,fragments/owners :: find-form" })
Expand All @@ -173,7 +177,7 @@ void testProcessFindFormNoOwnersFound(boolean hxRequest, String expectedViewName
.andExpect(status().isOk())
.andExpect(model().attributeHasFieldErrors("owner", "lastName"))
.andExpect(model().attributeHasFieldErrorCode("owner", "lastName", "notFound"))
.andExpect(view().name(expectedViewName));
.andExpect(view().name(expectedViewName.contains("::") ? null : expectedViewName));

}

Expand Down
Loading