sidebar 는 특정 페이지로 이동, 메인 페이지의 교체 등의 역할을 하고 있습니다.
이번 블로그 프로젝트에서는 메인 페이지의 교체의 역할을 하는 sidebar 를 구현하려고 합니다.
sidebar 에는 category 를 표시할 것입니다. category 를 선택하는 경우 메인 페이지를 교체하도록 합니다.
category 는 관리자가 추가, 변경, 삭제 가능하게 할 것이므로, 어플리케이션 구현 전에 데이터베이스 설계 및 생성이 필요합니다.
관리자에 대한 기능을 추후 작성할 예정입니다.
데이터베이스
테이블 정의
엔티티
DDL
CREATE TABLE `category` ( `nm` varchar(100) NOT NULL COMMENT '카테고리 식별자', `label_nm` varchar(500) NOT NULL COMMENT '카테고리 라벨명', `order_no` int(11) NOT NULL COMMENT '카테고리 순서', PRIMARY KEY (`nm`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
Dependencies
build.gradle
dependencies { compile('org.springframework.boot:spring-boot-starter-data-jpa') compile('org.modelmapper:modelmapper:0.7.4') compileOnly('org.projectlombok:lombok') }
'jpa' 이용하여 'Repository' 를 구현할 것입니다.
'modelmapper' 이용하여 'Domain' 과 'DTO' 사이의 변환을 수월하게 할 수 있도록 합니다.
'lombok' 이용하여 'Domain' 을 구현할 것입니다. 'Getter', 'Settger', 'Contructor' 등을 자동으로 생성하도록 합니다.
소스
common.js
/**
* Global Variables
*/
var BASE_CONTEXT_PATH = $('meta[name=context-path]').attr("content");
/**
* Global Functions
* @returns
*/
|
cs |
static/js 경로에 'common.js' 파일을 만들었습니다.
글로벌 변수 혹은 글로벌 기능을 선언합니다.
<head> 태그에 정의되어 있는 값을 가져와서 세팅합니다.
<head> 태그의 자세한 부분은 다음의 글을 참조 해주세요.
common-sidebar.html
<nav id="sidebar">
<th:block th:include="common/common-sidebar-js"></th:block>
<div class="sidebar-header">
<h3><a th:href="@{/}">Category</a></h3>
</div>
<ul id="category" class="list-unstyled components">
</ul>
</nav>
|
cs |
templates/common 패키지에 common-sidebar.html 파일을 생성하고, 코딩을 하였습니다.
javascript 를 이용하여 서버에서 category 목록을 가져오도록 합니다.
javascript 는 'common-sidebar-js.html' 에 구현하여, 현재 페이지에서 포함합니다.
th:include : 특정 페이지를 포함
common-sidebar-js.html
<script th:inline="javascript">
$(function(){
// Collapse button event
$('#sidebarCollapse').on('click', function() {
$('#sidebarCollapseBtn').toggleClass('active');
$('#sidebar').toggleClass('active');
});
// Create sidebar from category
$.ajax({
method : 'GET',
url: BASE_CONTEXT_PATH + 'category',
}).done(function(result){
// Append tag
var list = '';
var class_name = 'nav-link';
$.each(result, function(i, category){
list += '<li><a href="'+BASE_CONTEXT_PATH+'main?categoryNm='+category.nm+'&categoryLabelNm='+category.labelNm+'">'+category.labelNm+'</a></li>';
});
$('#category').html(list);
}).fail(function(xhr, ajaxOptions, thrownError){
alert(xhr);
});
})
</script>
|
cs |
버튼으로 sidebar 를 show/hide 하는 부분입니다.
header 를 구현하는 글에서 자세히 다루도록 하겠습니다.
common-sidebar.html 페이지가 로딩 되면서 ajax 를 수행하도록 하였습니다.
RequestMapping 이 'category' 로 되어 있는 Controller 를 'GET' 으로 호출하고 있습니다.
결과를 성공적으로 받은 경우 <li><a> 태그를 생성 하였습니다.
<a> 태그에서는 href 속성을 이용하여 선택되는 경우, RequestMapping 이 'main' 인 Controller 를 호출하며, 파라미터로 'categoryNm', 'categoryLabelNm' 을 담아서 'GET' 으로 호출하도록 합니다.
WebMvcConfig.java
... @Bean public ModelMapper modelMapper() { return new ModelMapper(); } ...
ModelMapper 클래스는 Service 에서 공통적으로 사용할 예정이므로, 'WebMvcConfig.java' 에서 Bean 으로 생성 하였습니다.
각각 Service 클래스에서는 '@Autowired' 어노테이션을 이용하여 사용합니다.
CategoryController.java
import java.util.List; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.ResponseBody; import project.blog.dto.CategoryDto; import project.blog.service.CategoryService; @Controller @RequestMapping("/category") public class CategoryController { @Autowired private CategoryService categoryService; @GetMapping public @ResponseBody List<CategoryDto> getCategories() { return categoryService.getCategories(); } }
controller 패키지에 CategoryController.java 를 생성 하였습니다.
Service를 호출하도록 합니다.
CategoryService.java
import java.util.List; import java.util.stream.Collectors; import org.modelmapper.ModelMapper; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import project.blog.dto.CategoryDto; import project.blog.repository.CategoryRepository; @Service public class CategoryService { @Autowired private CategoryRepository categoryRepository; @Autowired private ModelMapper modelMapper; public List<CategoryDto> getCategories(){ return categoryRepository.findAll().stream().map(category -> modelMapper.map(category, CategoryDto.class)).collect(Collectors.toList()); } }
service 패키지에 CategoryService.java 를 생성 하였습니다.
Repository 를 호출하도록 합니다.
Java 8 에서 제공하는 lambda 식을 이용하여, Repository 에서 가져온 결과를 리스트로 변환합니다. 변환을 수월하게 해주는 ModelMapper 를 이용 하여 'Domain' 을 'DTO' 로 변환하였습니다.
CategoryRepository.java
import org.springframework.data.jpa.repository.JpaRepository; import project.blog.domain.Category; public interface CategoryRepository extends JpaRepository<Category, String> { Category findByNm(String nm); }
repository 패키지에 CategoryRepository.java 를 생성 하였습니다.
'JpaRepository' 를 상속 받아서 구현합니다.
Category findByNm(String nm) : 'nm' 값을 받아서 결과를 반환합니다. JPA 표준 사용법에 맞추어 작성한 것입니다.
JPA 참조 문서
Category.java
import javax.persistence.Entity; import javax.persistence.Id; import lombok.AccessLevel; import lombok.Builder; import lombok.Getter; import lombok.NoArgsConstructor; @NoArgsConstructor(access = AccessLevel.PROTECTED) @Getter @Entity public class Category { @Id private String nm; private String labelNm; private int orderNo; @Builder public Category(String nm, String labelNm, int orderNo) { this.nm = nm; this.labelNm = labelNm; this.orderNo = orderNo; } }
domain 패키지에 Category.java 를 생성 하였습니다.
'Category' 클래스는 'category' 라는 테이블과 1:1 매핑되고, 각 멤버 변수는 테이블의 컬럼과 1:1 매핑됩니다.
'lombok' 라이브러리를 이용하여, 'Getter', 'Setter' 를 자동으로 생성 합니다.
AccessLevel.PROTECTED : 접근 제어 레벨을 설정
@Id : 'JPA' 의 어노테이션으로 'primary key' 컬럼에 지정합니다.
@Builder : 빌더 패턴으로 생성자를 지정합니다. 빌더 패턴을 이용하면, 코드를 간결하고 가독성 높게 유지할 수 있습니다.
lombok 참조 문서
CategoryDto.java
import lombok.Getter; import lombok.NoArgsConstructor; import lombok.Setter; import project.blog.domain.Category; @Getter @Setter @NoArgsConstructor public class CategoryDto { private String nm; private String labelNm; private int orderNo; public Category toEntity(){ return Category.builder() .nm(nm) .labelNm(labelNm) .orderNo(orderNo) .build(); } }
dto 패키지에 CategoryDto.java 를 생성 하였습니다.
dto 는 domain 과 같은 멤버 변수를 가질 수도 있고, 다른 멤버 변수를 가질 수도 있습니다. domain 에는 존재하지 않지만, dto 에는 특정 멤버 변수가 필요한 경우 확장하여 사용합니다.
Service 에서는 domain 을 직접 접근하는 것보다 dto 를 이용하여 반환하도록 합니다.
@NoArgsConstructor : 생성자 없는 클래스
toEntity() : toEntity() 메소드를 이용하여 domain 을 호출할 수 있도록 빌더 패턴으로 만들었습니다.
결과
'sidebar' 에 있는 'Category' 의 메뉴 중 하나를 선택 시 메인 페이지가 변경됩니다.
참조 라이브러리 사이트 목록 - 도움에 감사를 드립니다.
https://spring.io/projects/spring-data-jpa
http://modelmapper.org/getting-started/
참조 도구 사이트 목록 - 도움에 감사를 드립니다.
'IT 프로젝트 > 블로그 만들기' 카테고리의 다른 글
[Spring Boot] 스프링 부트 프로젝트/블로그 만들기 - 관리자(admin) index 페이지 만들기 (0) | 2018.11.18 |
---|---|
[Spring Boot] 스프링 부트 프로젝트/블로그 만들기 - 로그인(login) 페이지 만들기 (0) | 2018.11.17 |
[Spring Boot] 스프링 부트 프로젝트/블로그 만들기 - Welcome 페이지 만들기 (3) | 2018.11.15 |
[Spring Boot] 스프링 부트 프로젝트/블로그 만들기 - Resource 경로 지정 (2) | 2018.11.15 |
[Spring Boot] 스프링 부트 프로젝트/블로그 만들기 - index 페이지 작성 - UI 레이아웃 [Bootstrap + Thymeleaf] (6) | 2018.11.11 |