@GetMapping
public String index(Model model, @RequestParam(value = "page", defaultValue = "0") Integer page) {
int perPage = 6; // @RequestParam에 같이 적어도 되지만 이번엔 따로 적기 (한 페이지당 최대 6개)
Pageable pageable = PageRequest.of(page, perPage); // 표시할 페이지, 한 페이지에 표시할 데이터 수(6개)
// data.domain.page
Page<Product> products = productRepo.findAll(pageable);
List<Category> categories = categoryRepo.findAll();
// Category id와 name을 map에 담아 index페이지에 전송
HashMap<Integer, String> cateIdAndName = new HashMap<>();
for (Category category : categories) {
cateIdAndName.put(category.getId(), category.getName());
}
model.addAttribute("products", products);
model.addAttribute("cateIdAndName", cateIdAndName);
// Pagenation을 위해 필요한 정보
long count = productRepo.count(); // 전체 갯수 (long 타입으로 Return)
double pageCount = Math.ceil((double)count / (double)perPage); // 13/ 6 = 2.12, int로 나누면 소수점이 출력이 안되기때문에 double타입으로 계산한다.
model.addAttribute("pageCount",pageCount); // 총페이지
model.addAttribute("perPage", perPage); // 페이지당 표시 아이템수
model.addAttribute("count", count); // 총 아이템 갯수
model.addAttribute("page", page); // 현재 페이지
return "/admin/products/index";
}
<!-- 부트스트랩 페이지네이션 -->
<nav class="mt-3" th:if="${count > perPage}">
<ul class="pagination">
<li class="page-item" th:if="${page > 0}">
<a th:href="@{/admin/products/} + '?page=__${page-1}__'" class="page-link">이전</a>
</li>
<!-- sequence(a,b) a와 b 사이의 숫자들을 가지고 있음-->
<li class="page-item" th:each="number : ${#numbers.sequence(0, pageCount-1)}" th:classappend="${page==number} ? 'active' : ''">
<a th:href="@{/admin/products/} + '?page=__${number}__'" class="page-link" th:text="${number+1}"></a>
</li>
<li class="page-item" th:if="${page < pageCount-1}">
<a th:href="@{/admin/products/} + '?page=__${page+1}__'" class="page-link">다음</a>
</li>
</ul>
</nav>
https://ckeditor.com/docs/ckeditor5/latest/builds/guides/quick-start.html
// page conenet ck에디터 추가
if ($('#content').length) {
// JQuery에서는 태그선택시 무조건 true이기 때문에 length(없으면 0, 있으면 1)를 사용
ClassicEditor.create(document.querySelector('#content')).catch((error) => {
console.error(error);
});
}
// product description ck에디터 추가
if ($('#description').length) {
// JQuery에서는 태그선택시 무조건 true이기 때문에 length(없으면 0, 있으면 1)를 사용
ClassicEditor.create(document.querySelector('#description')).catch((error) => {
console.error(error);
});
}
package com.myapp.shoppingmall;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ModelAttribute;
import com.myapp.shoppingmall.dao.CategoryRepository;
import com.myapp.shoppingmall.dao.PageRepository;
import com.myapp.shoppingmall.entities.Category;
import com.myapp.shoppingmall.entities.Page;
// 모든 Controller에 적용
@ControllerAdvice
public class Common {
@Autowired
private PageRepository pageRepo;
@Autowired
private CategoryRepository categoryRepo;
@ModelAttribute
public void sharedData(Model model) {
// cpages에 모든 페이지들을 순서대로 담아서 전달
List<Page> cpages = pageRepo.findAllByOrderBySortingAsc();
List<Category> categories = categoryRepo.findAll();
model.addAttribute("cpages", cpages);
model.addAttribute("ccategories", categories);
}
}
package com.myapp.shoppingmall.controller;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
/**
*
* 쇼핑몰 기본 홈페이지
*
*/
import com.myapp.shoppingmall.dao.PageRepository;
import com.myapp.shoppingmall.entities.Page;
@Controller
@RequestMapping("/")
public class PageController {
@Autowired
private PageRepository pageRepo;
@GetMapping
public String home(Model model) {
// entities의 page
Page page = pageRepo.findBySlug("home");
model.addAttribute("page", page);
return "page"; // page.html로 이동
}
@GetMapping("/{slug}")
public String page(@PathVariable("slug") String slug, Model model) {
Page page = pageRepo.findBySlug(slug);
if (page == null) {
return "redirect:/"; // 페이지가 없으면 home으로 이동
}
model.addAttribute("page", page);
return "page";
}
}
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head th:replace="/fragments/head :: head-front"></head>
<body>
<nav th:replace="/fragments/nav :: nav-front"></nav>
<main role="main" class="container-fluid mt-5">
<div class="row">
<div th:replace="/fragments/categories :: categories"></div>
<div class="col"></div>
<div class="col-7" th:utext="${page.content}"></div>
<div class="col"></div>
</div>
</main>
<footer th:replace="/fragments/footer :: footer"></footer>
</body>
</html>
package com.myapp.shoppingmall.controller;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import com.myapp.shoppingmall.dao.CategoryRepository;
import com.myapp.shoppingmall.dao.ProductRepository;
import com.myapp.shoppingmall.entities.Category;
import com.myapp.shoppingmall.entities.Product;
@Controller
@RequestMapping("/category")
public class CategoryController {
@Autowired
private CategoryRepository categoryRepo;
@Autowired
private ProductRepository productRepo;
/**
* 입력된 slug 카테고리별로 제품리스트 표시(페이징 포함)
* @param slug 카테고리 slug
* @param page 표시할 페이지 번호
* @return products 페이지로 이동
*/
@GetMapping("/{slug}")
public String category(@PathVariable("slug") String slug, Model model, @RequestParam(value = "page", defaultValue = "0") Integer page) {
int perPage = 6; // @RequestParam에 같이 적어도 되지만 이번엔 따로 적기 (한 페이지당 최대 6개)
Pageable pageable = PageRequest.of(page, perPage); // 표시할 페이지, 한 페이지에 표시할 데이터 수(6개)
long count = 0;
// Category 선택(all , 그외 개별 가테고리)
if(slug.equals("all")) {
Page<Product> products = productRepo.findAll(pageable);
count = productRepo.count(); // 전체 상품 수
model.addAttribute("products", products); // 모든 카테고리 상품들
} else { // Category 개별 선택
Category category = categoryRepo.findBySlug(slug);
if(category == null) {
return "redirect:/"; // Category가 없으면 home으로 이동
}
String categoryId = Integer.toString(category.getId());
String categoryName = category.getName();
List<Product> products = productRepo.findAllByCategoryId(categoryId, pageable);
count =productRepo.countByCategoryId(categoryId);
model.addAttribute("products", products); // 선택한 Category의 상품들
model.addAttribute("categoryName", categoryName);
}
// Pagenation을 위해 필요한 정보
double pageCount = Math.ceil((double)count / (double)perPage); // 13/ 6 = 2.12, int로 나누면 소수점이 출력이 안되기때문에 double타입으로 계산한다.
model.addAttribute("pageCount",pageCount); // 총페이지
model.addAttribute("perPage", perPage); // 페이지당 표시 아이템수
model.addAttribute("count", count); // 총 아이템 갯수
model.addAttribute("page", page); // 현재 페이지
return "products"; // products.html 페이지로 이동
}
}
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head th:replace="/fragments/head :: head-front"></head>
<body>
<nav th:replace="/fragments/nav :: nav-front"></nav>
<main role="main" class="container-fluid mt-5">
<div class="row">
<div th:replace="/fragments/categories :: categories"></div>
<div class="col"></div>
<div class="col-8">
<!-- CategoryName이 있으면 출력하고 없으면 모든제품 출력-->
<h2 class="display-3 mb-5" th:text="${categoryName} ?: '모든상품'"></h2>
<div class="row">
<div class="col-4" th:each="product : ${products}">
<p>
<img th:src="@{'/media/' + ${product.image}}" style="width: 200px" />
</p>
<h4 th:text="${product.name}"></h4>
<div class="desc" th:utext="${product.description}"></div>
<p th:text="${product.price}+ '원'"></p>
</div>
</div>
<!-- 부트스트랩 페이지네이션 -->
<nav class="mt-3" th:if="${count > perPage}">
<ul class="pagination">
<!-- @{${#httpServletRequest.requestURI}} 현재 페이지 주소, 지금은 @{/category/category.slug} -->
<li class="page-item" th:if="${page > 0}">
<a th:href="@{${#httpServletRequest.requestURI}} + '?page=__${page-1}__'" class="page-link">이전</a>
</li>
<!-- sequence(a,b) a와 b 사이의 숫자들을 가지고 있음-->
<li class="page-item" th:each="number : ${#numbers.sequence(0, pageCount-1)}" th:classappend="${page==number} ? 'active' : ''">
<a th:href="@{${#httpServletRequest.requestURI}} + '?page=__${number}__'" class="page-link" th:text="${number+1}"></a>
</li>
<li class="page-item" th:if="${page < pageCount-1}">
<a th:href="@{${#httpServletRequest.requestURI}} + '?page=__${page+1}__'" class="page-link">다음</a>
</li>
</ul>
</nav>
</div>
</div>
</main>
<footer th:replace="/fragments/footer :: footer"></footer>
</body>
</html>