4월 5일

SJY0000·2022년 4월 5일
0

Springboot

목록 보기
8/24

오늘 배운 것

  • Paging으로 결과 전송받기
  • Shoppingmall 프로젝트(1)

Paging으로 결과 전송받기

  • 기존의 CRUDRepository를 PagingAndSortingRepository로 변경
	// Paging 적용 직원리스트
	@GetMapping
	@ResponseStatus(HttpStatus.OK)
	public Iterable<Employee> findpaginatedEmployees(@RequestParam(value = "page", defaultValue = "0") int page,
														@RequestParam(value = "size", defaultValue = "5") int size) {
		
		//page설정 객체를 사용하려면 PagingAndSortingRepository를 참조한다.
		Pageable pageable = PageRequest.of(page, size);
		
		return empRepo.findAll(pageable);
	}
  • Postman으로 메소드 실행 후 결과
  • 페이지는 0부터 시작
{
    "content": [
        {
            "employeeId": 1,
            "firstName": "아지",
            "lastName": "강강",
            "email": "kang@naver.com"
        },
        {
            "employeeId": 2,
            "firstName": "길금",
            "lastName": "홍",
            "email": "hong@naver.com"
        },
        {
            "employeeId": 3,
            "firstName": "순신",
            "lastName": "이",
            "email": "lee@naver.com"
        },
        {
            "employeeId": 4,
            "firstName": "탱이",
            "lastName": "곰",
            "email": "kom@naver.com"
        },
        {
            "employeeId": 9,
            "firstName": "양이",
            "lastName": "고",
            "email": "go@naver.com"
        }
    ],
    "pageable": {
        "sort": {
            "empty": true,
            "sorted": false,
            "unsorted": true
        },
        "offset": 0,
        "pageNumber": 0,
        "pageSize": 5,
        "paged": true,
        "unpaged": false
    },
    "last": false,
    "totalPages": 2,
    "totalElements": 7,
    "size": 5,
    "number": 0,
    "sort": {
        "empty": true,
        "sorted": false,
        "unsorted": true
    },
    "first": true,
    "numberOfElements": 5,
    "empty": false
}

Shoppingmall 프로젝트

초기설정하기

  • Project 생성시 library 추가 (Spring Dev Tools, Spring Web, MySql Driver, Thymeleaf, Spring Data JPA, Lombok)

  • Lombok Library는 pom.xml에 추가하고 따로 설치가 필요함
    .m2\repository\org\projectlombok\lombok\1.18.22

  • DB생성

  • DB사용을 위해 application.properties에 추가

# MySQL DB 설정
spring.datasource.url=jdbc:mysql://localhost:3306/shoppingmall?useSSL=false&serverTimezone=Asia/Seoul
spring.datasource.username=root
spring.datasource.password=1234
  • bootstrap 4버전과 5버전의 차이는 JQuery 사용 유무 (여기선 4버전 사용)

HTML

Thymeleaf를 이용해 th:fragment 와 th:replace 사용하기

  • head(기본 버전과 관리자 버전 2가지 생성)
<head th:fragment="head-front">
  <meta charset="utf-8" />
  <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no" />

  <title>쇼핑몰</title>

  <link rel="canonical" href="https://getbootstrap.com/docs/4.6/examples/starter-template/" />

  <!-- Bootstrap core CSS -->
  <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@4.6.1/dist/css/bootstrap.min.css" />
  <!-- Custom styles for this template -->
  <link rel="stylesheet" th:href="@{/css/style.css}" />
</head>

<head th:fragment="head-admin">
  <meta charset="utf-8" />
  <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no" />

  <title>관리자페이지</title>

  <link rel="canonical" href="https://getbootstrap.com/docs/4.6/examples/starter-template/" />

  <!-- Bootstrap core CSS -->
  <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@4.6.1/dist/css/bootstrap.min.css" />
  <!-- Custom styles for this template -->
  <link rel="stylesheet" th:href="@{/css/style.css}" />
</head>
  • nav(기본 버전과 관리자 버전 2가지 생성)
<nav th:fragment="nav-front" class="navbar navbar-expand-md navbar-dark bg-dark">
  <a class="navbar-brand" href="#">🛒SHOP</a>
  <button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarShop" aria-controls="navbarShop" aria-expanded="false" aria-label="Toggle navigation">
    <span class="navbar-toggler-icon"></span>
  </button>

  <div class="collapse navbar-collapse" id="navbarShop">
    <ul class="navbar-nav mr-auto">
      <li class="nav-item active">
        <a class="nav-link" href="#">Home</a>
      </li>
      <li class="nav-item">
        <a class="nav-link" href="#">Link</a>
      </li>
    </ul>
  </div>
</nav>

<nav th:fragment="nav-admin" class="navbar navbar-expand-md navbar-dark bg-dark">
  <a class="navbar-brand" th:href="@{/}">📱관리자</a>
  <button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarShop" aria-controls="navbarShop" aria-expanded="false" aria-label="Toggle navigation">
    <span class="navbar-toggler-icon"></span>
  </button>

  <div class="collapse navbar-collapse" id="navbarShop">
    <ul class="navbar-nav mr-auto">
      <li class="nav-item active">
        <a class="nav-link" th:href="@{/admin/pages}">Pages</a>
      </li>
      <li class="nav-item">
        <a class="nav-link" href="#">Link</a>
      </li>
    </ul>
  </div>
</nav>
  • footer
<footer th:fragment="footer">
  <script src="https://cdn.jsdelivr.net/npm/jquery@3.5.1/dist/jquery.slim.min.js"></script>
  <script src="https://cdn.jsdelivr.net/npm/bootstrap@4.6.1/dist/js/bootstrap.bundle.min.js"></script>
</footer>
  • 기본 페이지
<!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"></main>
    <footer th:replace="/fragments/footer :: footer"></footer>
  </body>
</html>

  • 관리자 페이지
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
  <head th:replace="/fragments/head :: head-admin"></head>
  <body>
    <nav th:replace="/fragments/nav :: nav-admin"></nav>
    <main role="main" class="container">
      <div class="display-2">Pages</div>
      <a th:href="@{/admin/pages/add}" class="btn btn-primary my-3">추가하기</a>
      <div th:if="${!pages.empty}">
        <table class="table" id="pages">
          <tr class="home">
            <th>제 목</th>
            <th>슬러그</th>
            <th>수 정</th>
            <th>삭 제</th>
          </tr>
          <tr th:each="page : ${pages}">
            <td th:text="${page.title}"></td>
            <td th:text="${page.slug}"></td>
            <td><a th:href="@{'/admin/pages/edit/' + ${page.id}}">수정</a></td>
            <td><a th:href="@{'/admin/pages/delete/' + ${page.id}}">삭제</a></td>
          </tr>
        </table>
      </div>
      <div th:if="${pages.empty}">
        <div class="display-4">현재 페이지가 없습니다.</div>
      </div>
    </main>
    <footer th:replace="/fragments/footer :: footer"></footer>
  </body>
</html>

  • 추가페이지
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
  <head th:replace="/fragments/head :: head-admin"></head>
  <body>
    <nav th:replace="/fragments/nav :: nav-admin"></nav>
    <main role="main" class="container">
      <div class="display-2">페이지 추가</div>
      <a th:href="@{/admin/pages}" class="btn btn-primary my-3">돌아가기</a>
      <form method="post" th:object="${page}" th:action="@{/admin/pages/add}">
        <div th:if="${#fields.hasErrors('*')}" class="alert alert-danger">에러 발생</div>
        <div class="form-group">
          <label for="">제 목</label>
          <input type="text" class="form-control" th:field="*{title}" placeholder="제목" />
          <span class="error" th:if="${#fields.hasErrors('title')}" th:errors="*{title}"></span>
        </div>
        <div class="form-group">
          <label for="">슬러그</label>
          <input type="text" class="form-control" th:field="*{slug}" placeholder="슬러그" />
        </div>
        <div class="form-group">
          <label for="">내용</label>
          <textarea class="form-control" th:field="*{content}" cols="30" rows="10" placeholder="내용"></textarea>
          <span class="error" th:if="${#fields.hasErrors('content')}" th:errors="*{content}"></span>
        </div>
        <button type="submit" class="btn btn-danger">추 가</button>
      </form>
    </main>
    <footer th:replace="/fragments/footer :: footer"></footer>
  </body>
</html>

  • Validation 적용

JAVA

Bean 객체 만들기

  • Lombok의 @DATA를 사용하여 GET,SET 등의 메소드를 만들지 않아도 됨
package com.myapp.shoppingmall.entities;

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.Size;

import lombok.Data;

// 실제 Table과 매칭
@Entity
@Table(name = "pages")
@Data // Get, Set, Construct, toSring 생성됨
public class Page {

	@Id
	@GeneratedValue(strategy = GenerationType.IDENTITY)
	private int id;
	@NotBlank(message = "제목을 입력해주세요.")
	@Size(min = 2, message = "최소 2글자 이상 입력해주세요.")
	private String title;
	private String slug; // title을 소문자 띄워쓰기 특수문자등을 - 으로 변환
	@NotBlank(message = "내용을 입력해주세요.")
	@Size(min = 5, message = "최소 5글자 이상 입력해주세요.")
	private String content;
	private int sorting; // 정렬 순서
}

Repository 만들기

package com.myapp.shoppingmall.dao;

import org.springframework.data.jpa.repository.JpaRepository;

import com.myapp.shoppingmall.entities.Page;

public interface PageRepository extends JpaRepository<Page, Integer> {
	// List<Page>로 리턴되는 findAll() 등 여러 메소드가 이미 생성되어 있음
}

Controller 만들기

package com.myapp.shoppingmall.controller;

import java.util.List;

import javax.validation.Valid;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;

import com.myapp.shoppingmall.dao.PageRepository;
import com.myapp.shoppingmall.entities.Page;

@Controller
@RequestMapping("/admin/pages")
public class AdminPageController {

	@Autowired
	private PageRepository pageRepo;
	
	@GetMapping
	public String index(Model model) {
		List<Page> pages = pageRepo.findAll();
		model.addAttribute("pages", pages);
		return "admin/pages/index";
	}
	
    // page값을 자동으로 model에 전송
	@GetMapping("/add")
	public String add(@ModelAttribute Page page) {
//		model.addAttribute("page", new Page());
		return "admin/pages/add"; // templates의 admin안의 pages폴더 안에 add.html로 이동
	}
	
	@PostMapping("/add")
	public String add(@Valid Page page, BindingResult bindingResult) {
		//Validation 결과 Error가 있으면 이전페이지로 이동
		if (bindingResult.hasErrors()) {
			return "admin/pages/add";
		}
		return "redirect:admin/pages/add";
	}
}
  • View를 이동하는 다른 방법
package com.myapp.shoppingmall;

import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

@Configuration
public class WebConfig implements WebMvcConfigurer {

	@Override
	public void addViewControllers(ViewControllerRegistry registry) {
		// Controller 대신에 View를 Mapping 가능
		registry.addViewController("/").setViewName("home");
	}
}

0개의 댓글