12.1 강좌 카테고리 목록 구현 및 추가
Ex)
- admin 아래에 새로운 패키지를 만든다.category아래 리스트 파일 만든다.
- 새로운 카테고리 컨트롤러
<hide/>
@Controller
@RequiredArgsConstructor
public class AdminCategoryController {
private final MemberService memberService;
@GetMapping("/admin/category/list.do")
public String list(Model model, MemberParam parameter){
return "admin/category/list";
}
}
- 레이아웃에 관리자 메인 페이지도 추가한다.
<hide/>
<!DOCTYPE html>
<html lang="ko" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>fastlms</title>
</head>
<body>
<div th:fragment="fragment-body-menu">
<div>
<a href="/member/register">회원 가입</a>
|
<a href="/member/info">회원 정보</a>
|
<a href="/member/login">로그인</a>
|
<a href="/member/logout">로그아웃</a>
</div>
<hr/>
</div>
<div th:fragment="fragment-admin-body-menu">
<a href="/admin/main.do">관리자 메인</a>
|
<a href="/admin/member/list.do">회원 관리</a>
|
<a href="#">카테고리 관리</a>
|
<a href="#">강의 관리</a>
|
<a href="/member/logout">로그 아웃</a>
<br>
<hr/>
</div>
</body>
</html>
<hide/>
<!doctype html>
<html lang="ko" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>관리자 화면</title>
<style>
</style>
</head>
<body>
<h1>카테고리 관리</h1>
<div th:replace="/fragments/layout.html :: fragment-admin-body-menu" ></div>
<div class="list">
<table>
<thead>
<tr>
<th>ID</th>
<th>카테고리명</th>
<th>순서</th>
</tr>
</thead>
<tbody>
</tbody>
</table>
</div>
</body>
</html>
Note) 실행 결과
Ex) 카테고리 클래스 만들고 데이터베이스에 들어갔는지 확인하기
- 카테고리 창에 입력창 추가한다.
- 컨트롤러에 add.do 추가한다.
<hide/>
@GetMapping("/admin/category/add.do")
public String list(Model model, CategoryInput parameter){
return "admin/category/list";
}
- CategoryInput() 클래스를 만든다.
- Category 클래스 만들기 => @Entity를 붙이면 빨간 줄 생긴다.
->자동 증가?
-> 그럼 다음과 같이 키가 만들어진다.
<hide/>
package com.zerobase.fastlms.admin;
import javax.persistence.*;
@Entity
public class Category {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "id", nullable = false)
private Long id;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
}
- 레포지토리
-> yml 파일에 자동으로 DDL 만들어주는 부분이 세팅되어 있기 때문에 이렇게 하면 테이블이 만들어질 것이다.
<hide/>
package com.zerobase.fastlms.admin.repository;
import com.zerobase.fastlms.admin.entity.Category;
import com.zerobase.fastlms.member.entity.Member;
import org.springframework.data.jpa.repository.JpaRepository;
import java.util.Optional;
public interface CategoryRepository extends JpaRepository<Category, Long> {
}
Note) 실행 결과
Ex) 카테고리 리스트 구현하기
- 카테고리 서비스 인터페이스
<hide/>
package com.zerobase.fastlms.admin.repository;
public interface CategoryService {
/**
* 카테고리 신규 추가
*/
boolean add(String categoryName);
/**
* 카테고리 수정
*/
boolean update(CategoryDto parameter);
/**
* 카테고리 삭제
*/
boolean del(long id);
}
- Dto 클래스
<hide/>
package com.zerobase.fastlms.admin.dto;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@AllArgsConstructor
@NoArgsConstructor
public class CategoryDto {
private Long id;
String categoryName;
int sortValue;
boolean usingYn; // 사용가능한지
}
- 카테고리 서비스 임플
<hide/>
package com.zerobase.fastlms.admin.service;
import com.zerobase.fastlms.admin.dto.CategoryDto;
import com.zerobase.fastlms.admin.entity.Category;
import com.zerobase.fastlms.admin.repository.CategoryRepository;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
@Service
@RequiredArgsConstructor
public class CategoryServiceImpl implements CategoryService {
private final CategoryRepository categoryRepository;
@Override
public List<CategoryDto> list(){
List<CategoryDto> categoryDtoList = categoryRepository.findAll();
List<Category> categories = categoryRepository.findAll();
if(!CollectionUtils.isEmpty(categories)){
categories.forEach( e-> {
CategoryDto category= new CategoryDto();
category.setId(e.getId());
category.setCategoryName(e.getCategoryName());
categoryDtoList.add(category);
});
}
return categoryDtoList;
}
@Override
public boolean update(CategoryDto parameter) {
return false;
}
@Override
public boolean del(long id) {
return false;
}
}
- 카테고리 Dto 클래스
<hide/>
package com.zerobase.fastlms.admin.dto;
import com.zerobase.fastlms.admin.entity.Category;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.ArrayList;
import java.util.List;
@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class CategoryDto {
private Long id;
String categoryName;
int sortValue;
boolean usingYn; // 사용가능한지
public static List<CategoryDto> of (List<Category> categories){
if(categories != null){
List<CategoryDto> categoryList = new ArrayList<>();
for(Category x: categories){
categoryList.add(of(x));
}
return categoryList;
}
return null;
}
public static CategoryDto of(Category category){
return CategoryDto.builder()
.id(category.getId())
.categoryName(category.getCategoryName())
.sortValue(category.getSortValue())
.build();
}
}
- Impl의 list() 메서드 => 카테고리를 카테고리 DTO형태로 바꿔준다.
<hide/>
@Override
public List<CategoryDto> list(){
List<Category> categories = new ArrayList<>();
return CategoryDto.of(categories);
}
- 컨트롤러
-> 모델에 add해주면 클라이언트(뷰) 페이지까지 내려간다.
<hide/>
@GetMapping("/admin/category/list.do")
public String list(Model model, MemberParam parameter){
List<CategoryDto> list = categoryService.list();
model.addAttribute("list", list);
return "admin/category/list";
}
<hide/>
@PostMapping("/admin/category/add.do")
public String add(Model model, CategoryInput parameter){
boolean result = categoryService.add(parameter.getCategoryName());
return "redirect:/admin/category/list.do";
}
- 카테고리 리스트
<hide/>
<table>
<thead>
<tr>
<th>ID</th>
<th>카테고리명</th>
<th>순서</th>
<th>사용 여부</th>
</tr>
</thead>
<tbody>
<tr th:each="x : ${list}">
<td th:text="${x.id}">1</td>
<td th:text="${x.categoryName}">홍길동</td>
<td th:text="${x.sortValue}">000</td>
<td th:text="${x.usingYn}">1111</td>
</tr>
</tbody>
</table>
Note) 실행 결과 - 데이터베이스에 행 추가
- aaaaa를 입력한 결과
<hide/>
<!doctype html>
<html lang="ko" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>관리자 화면</title>
<style>
.list table{
width: 100%;
border-collapse: collapse;
}
.list table th, .list table td{
border: solid 1px #000;
}
</style>
</head>
<body>
<h1>카테고리 관리</h1>
<!-- <div th:replace="/fragments/layout.html :: fragment-admin-body-menu" ></div>-->
<div class="list">
<div>
<form method="post" action="/admin/category/add.do">
<input type="text" name="categoryName" required placeholder="카테고리명 입력"/>
<button type="submit">추가</button>
</form>
</div>
<!-- <div th:text="${list}">-->
<!-- </div>-->
<table>
<thead>
<tr>
<th>ID</th>
<th>카테고리명</th>
<th>순서</th>
<th>사용 여부</th>
<th>비고</th>
</tr>
</thead>
<tbody>
<tr th:each="x : ${list}">
<td th:text="${x.id}">1</td>
<td th:text="${x.categoryName}">홍길동</td>
<td th:text="${x.sortValue}">000</td>
<td>
<p th:text="${x.usingYn}">1111</p>
</td>
<td>
<button type="submit">삭제</button>
</td>
</tr>
</tbody>
</table>
</div>
</body>
</html>
====================== 오류 ======================
- 오류: 추가 버튼을 누르면 데이터베이스에는 들어가는데 표에는 보이지가 않는다.
- 원인: 임플 클래스 구현에 문제가 있었다.
Note) 실행 결과
12.2 강좌 카테고리 수정, 삭제, 정렬
Ex) 삭제 버튼 만들기
- 리스트 파일
-> 테스트 목적으로 alert(1)
<hide/>
<!doctype html>
<html lang="ko" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>관리자 화면</title>
<style>
.list table{
width: 100%;
border-collapse: collapse;
}
.list table th, .list table td{
border: solid 1px #000;
}
</style>
<script src="https://code.jquery.com/jquery-3.6.0.min.js" integrity="sha256-/xUj+3OJU5yExlq6GSYGSHk7tPXikynS7ogEvDej/m4=" crossorigin="anonymous"></script>
<script>
$(document).ready(function (){
$('form[name=deleteForm]').on('submit', function(){
alert('1');
return false;
});
});
</script>
</head>
<body>
<h1>카테고리 관리</h1>
<!-- <div th:replace="/fragments/layout.html :: fragment-admin-body-menu" ></div>-->
<div class="list">
<div>
<form method="post" action="/admin/category/add.do">
<input type="text" name="categoryName" required placeholder="카테고리명 입력"/>
<button type="submit">추가</button>
</form>
</div>
<table>
<thead>
<tr>
<th>ID</th>
<th>카테고리명</th>
<th>순서</th>
<th>사용 여부</th>
<th>비고</th>
</tr>
</thead>
<tbody>
<tr th:each="x : ${list}">
<td th:text="${x.id}">1</td>
<td th:text="${x.categoryName}">홍길동</td>
<td th:text="${x.sortValue}">000</td>
<td>
<p th:text="${x.usingYn}">1111</p>
</td>
<td>
<form name="deleteForm" method="post" action="/admin/category/delete.do">
<input type="hidden" name="id" th:value="${x.id}"/>
<button type="submit">삭제</button>
</form>
</td>
</tr>
</tbody>
</table>
</div>
</body>
</html>
- 1번 삭제 눌렀을 때
- 삭제 css
<hide/>
<script>
$(document).ready(function (){
$('form[name=deleteForm]').on('submit', function(){
if(!confirm('카테고리를 삭제하시겠습니다.? ')){
return false;
}
});
});
</script>
- > 확인 누르면 아직까지는 화이트라벨
- 삭제 버튼 확인 누르고 난 다음 화면 만들기위해 컨트롤러에 내용 추가
<hide/>
@PostMapping("/admin/category/delete.do")
public String del(Model model,CategoryInput parameter){
boolean result = categoryService.del(parameter.getId());
return "redirect:/admin/category/list.do";
}
- 임플에 del 구현
<hide/>
@Override
public boolean del(long id) {
categoryRepository.deleteById(id);
return true;
}
Note) 실행 결과 - 1번 카테고리가 삭제되었다.
Ex) 카테고리 리스트에 데이터가 없는 경우 보여줄 화면 구성하기
- colspan
<hide/>
<tr th:each="x : ${list}">
<td th:text="${x.id}">1</td>
<td th:text="${x.categoryName}">홍길동</td>
<td th:text="${x.sortValue}">000</td>
<td>
<p th:text="${x.usingYn}">1111</p>
</td>
<td>
<form name="deleteForm" method="post" action="/admin/category/delete.do">
<input type="hidden" name="id" th:value="${x.id}"/>
<button type="submit">삭제</button>
</form>
</td>
</tr>
<tr>
<td colspan="5">
<p class="nothing">내용이 없습니다.</p>
</td>
</tr>
Note) 실행 결과
Ex) 카테고리 창에서 바로 수정하기
- 체크 박스는 두 가지 옵션 중 선택해야하는 상황이라면 두 개에 대해 같은 이름의 변수를 줘야한다.
- name을 왜 복잡하게 주나 했는데 아이디 별로 usingYn 이 다르므로 각각 변수 이름을 다르게 줘서 구분이 가능하다
<hide/>
<tbody>
<tr th:each="x : ${list}">
<td th:text="${x.id}">1</td>
<td>
<input th:value="${x.categoryName}" type="text" name="categoryName" />
</td>
<td>
<input th:value="${x.sortValue}" type="text" name="sortValue"/>
</td>
<td>
<input th:checked="${x.usingYn}" type="radio" th:name="'usingYn_' + ${x.id}" value="true"/>
<input th:checked="${!x.usingYn}" type="radio" th:name="'usingYn_' + ${x.id}" value="false"/>
</td>
<td>
<form name="deleteForm" method="post" action="/admin/category/delete.do">
<input type="hidden" name="id" th:value="${x.id}"/>
<button type="submit">삭제</button>
</form>
</td>
</tr>
<tr th:if="${#lists.size(list) < 1}">
<td colspan="5">
<p class="nothing">내용이 없습니다.</p>
</td>
</tr>
</tbody>
Note) 실행 결과
Ex) 사용 여부 y/n 선택 기능
<hide/>
<td>
<label th:for="'usingYn_yes_' + ${x.id}">Y</label>
<input th:checked="${x.usingYn}" type="radio" th:id="'usingYn_yes_' + ${x.id}" th:name="'usingYn_' + ${x.id}" value="true"/>
<label th:for="'usingYn_no_' + ${x.id}">N</label>
<input th:checked="${x.usingYn}" type="radio" th:id="'usingYn_no_' + ${x.id}" th:name="'usingYn_' + ${x.id}" value="false"/>
</td>
Note) 실행 결과
Ex) 체크 박스
<hide/>
<td>
<input th:checked="${x.usingYn}" type="checkbox" th:id="'usingYn_' + ${x.id}" th:name="'usingYn_' + ${x.id}" value="true"/>
<label th:for="'usingYn_yes_' + ${x.id}">사용</label>
</td>
Note) 실행 결과
Ex) 수정 삭제 버튼에 대해 같은 클래스 이름을 적용
- CSS에서 display에 inline-block으로 지정하면 나란히 옆으로 배치된다.
<hide/>
<div class="inline-div">
<button type="button">수정</button>
</div>
<div class="inline-div">
<form name="deleteForm" method="post" action="/admin/category/delete.do">
<input type="hidden" name="id" th:value="${x.id}"/>
<button type="submit">삭제</button>
</form>
</div>
Note) 실행 결과 - 성공
Ex) 자바스크립트
<hide/>
<script src="https://code.jquery.com/jquery-3.6.0.min.js" integrity="sha256-/xUj+3OJU5yExlq6GSYGSHk7tPXikynS7ogEvDej/m4=" crossorigin="anonymous"></script>
<script>
$(document).ready(function (){
$('form[name=deleteForm]').on('submit', function(){
if(!confirm('카테고리를 삭제하시겠습니다.?')){
return false;
}
});
$('button.update-button').on('click', function() {
var $this = $(this);
var $tr = $this.closest('tr');
var id = $tr.find('input[name=id]').val();
var categoryName = $tr.find('input[name=categoryName]').val();
var sortValue = $tr.find('input[name=sortValue]').val();
var usingYn = $tr.find('input[type=checkbox]')[0].checked;
console.log(id, categoryName, sortValue, usingYn);
});
});
</script>
Note) 실행 결과
Ex) 수정하기
- 컨트롤러 수정 메서드
<hide/>
@PostMapping("/admin/category/update.do")
public String update(Model model,CategoryInput parameter){
boolean result = categoryService.update(parameter);
return "redirect:/admin/category/list.do";
}
- 자바스크립트
-> 수정은 on('click') / 삭제는 on('submit') => 뭐가 다를까???
cf) val와 var의 차이는?
- val: 데이터를 바꿀 수 없는 읽기 전용 변수 (자바의 final과 같다.)
- var: 값을 변경 가능한 변수
<hide/>
<script src="https://code.jquery.com/jquery-3.6.0.min.js" integrity="sha256-/xUj+3OJU5yExlq6GSYGSHk7tPXikynS7ogEvDej/m4=" crossorigin="anonymous"></script>
<script>
$(document).ready(function (){
$('form[name=deleteForm]').on('submit', function(){
if(!confirm('카테고리를 삭제하시겠습니까?')){
return false;
}
});
$('button.update-button').on('click', function() {
if(!confirm('카테고리를 수정하시겠습니다?')){
return false;
}
var $this = $(this);
var $tr = $this.closest('tr');
var id = $tr.find('input[name=id]').val();
var categoryName = $tr.find('input[name=categoryName]').val();
var sortValue = $tr.find('input[name=sortValue]').val();
var usingYn = $tr.find('input[type=checkbox]')[0].checked;
$updateForm = ${'form[name=updateForm]'}
$updateForm.find('input[name=id]').val(id);
$updateForm.find('input[name=categoryName]').val(categoryName);
$updateForm.find('input[name=sortValue]').val(sortValue);
$updateForm.find('input[name=usingYn]').val(usingYn);
$updateForm.submit();
});
});
</script>
- 임플에서 update() 메서드 구현
<hide/>
@Override
public boolean update(CategoryInput parameter) {
Optional<Category> optionalCategory = categoryRepository.findById(parameter.getId());
if(optionalCategory.isPresent()){
Category category = optionalCategory.get();
category.setCategoryName(parameter.getCategoryName());
category.setSortValue(parameter.getSortValue());
category.setUsingYn(parameter.isUsingYn());
categoryRepository.save(category);
}
return true;
}
Note) 실행 결과 - 정상
========================오류 =========================
- 오류: 삭제할 때, 알림창이 나와야하는데 갑자기 안 나온다. 삭제는 정상으로 실행된다.
- 원인: 정확한 이유는 모르겠으나 다시 돌려보니까 정상 실행된다.
Ex) 리스트에서 순서에 맞춰 카테고리를 가져오기
- 카테고리 리포지토리
<hide/>
package com.zerobase.fastlms.admin.repository;
import com.zerobase.fastlms.admin.entity.Category;
import org.springframework.data.jpa.repository.JpaRepository;
import java.util.List;
import java.util.Optional;
public interface CategoryRepository extends JpaRepository<Category, Long> {
Optional<List<Category>> findAllOrderBySortValueDesc();
}
- 카테고리 임플 클래스
<hide/>
private Sort getSortBySortValueDesc(){
return Sort.by(Sort.Direction.DESC, "sortValue");
}
@Override
public List<CategoryDto> list(){
List<Category> categories = categoryRepository.findAll(getSortBySortValueDesc());
return CategoryDto.of(categories);
}
Note) 실행 결과
====================== 오류 ======================
<hide/>
org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'adminCategoryController' defined in file [C:\Users\Ran\Desktop\R\zerobase\Spring\fastlms-main\fastlms-main\target\classes\com\zerobase\fastlms\admin\controller\AdminCategoryController.class]: Unsatisfied dependency expressed through constructor parameter 1; nested exception is org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'categoryServiceImpl' defined in file [C:\Users\Ran\Desktop\R\zerobase\Spring\fastlms-main\fastlms-main\target\classes\com\zerobase\fastlms\admin\service\CategoryServiceImpl.class]: Unsatisfied dependency expressed through constructor parameter 0; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'categoryRepository' defined in com.zerobase.fastlms.admin.repository.CategoryRepository defined in @EnableJpaRepositories declared on JpaRepositoriesRegistrar.EnableJpaRepositoriesConfiguration: Invocation of init method failed; nested exception is org.springframework.data.repository.query.QueryCreationException: Could not create query for public abstract java.util.Optional com.zerobase.fastlms.admin.repository.CategoryRepository.findAllOrderBySortValueDesc()! Reason: Failed to create query for method public abstract java.util.Optional com.zerobase.fastlms.admin.repository.CategoryRepository.findAllOrderBySortValueDesc()! No property desc found for type int! Traversed path: Category.sortValue.; nested exception is java.lang.IllegalArgumentException: Failed to create query for method public abstract java.util.Optional com.zerobase.fastlms.admin.repository.CategoryRepository.findAllOrderBySortValueDesc()! No property desc found for type int! Traversed path: Category.sortValue.
at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:800) ~[spring-beans-5.3.9.jar:5.3.9]
at org.springframework.beans.factory.support.ConstructorResolver.autowireConstructor(ConstructorResolver.java:229) ~[spring-beans-5.3.9.jar:5.3.9]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.autowireConstructor(AbstractAutowireCapableBeanFactory.java:1354) ~[spring-beans-5.3.9.jar:5.3.9]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1204) ~[spring-beans-5.3.9.jar:5.3.9]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:564) ~[spring-beans-5.3.9.jar:5.3.9]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:524) ~[spring-beans-5.3.9.jar:5.3.9]
at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:335) ~[spring-beans-5.3.9.jar:5.3.9]
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234) ~[spring-beans-5.3.9.jar:5.3.9]
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:333) ~[spring-beans-5.3.9.jar:5.3.9]
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:208) ~[spring-beans-5.3.9.jar:5.3.9]
at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:944) ~[spring-beans-5.3.9.jar:5.3.9]
at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:918) ~[spring-context-5.3.9.jar:5.3.9]
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:583) ~[spring-context-5.3.9.jar:5.3.9]
at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:145) ~[spring-boot-2.5.4.jar:2.5.4]
at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:754) [spring-boot-2.5.4.jar:2.5.4]
at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:434) [spring-boot-2.5.4.jar:2.5.4]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:338) [spring-boot-2.5.4.jar:2.5.4]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1343) [spring-boot-2.5.4.jar:2.5.4]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1332) [spring-boot-2.5.4.jar:2.5.4]
at com.zerobase.fastlms.FastlmsApplication.main(FastlmsApplication.java:12) [classes/:na]
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_342]
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:1.8.0_342]
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.8.0_342]
at java.lang.reflect.Method.invoke(Method.java:498) ~[na:1.8.0_342]
at org.springframework.boot.devtools.restart.RestartLauncher.run(RestartLauncher.java:49) [spring-boot-devtools-2.7.2.jar:2.7.2]
Caused by: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'categoryServiceImpl' defined in file [C:\Users\Ran\Desktop\R\zerobase\Spring\fastlms-main\fastlms-main\target\classes\com\zerobase\fastlms\admin\service\CategoryServiceImpl.class]: Unsatisfied dependency expressed through constructor parameter 0; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'categoryRepository' defined in com.zerobase.fastlms.admin.repository.CategoryRepository defined in @EnableJpaRepositories declared on JpaRepositoriesRegistrar.EnableJpaRepositoriesConfiguration: Invocation of init method failed; nested exception is org.springframework.data.repository.query.QueryCreationException: Could not create query for public abstract java.util.Optional com.zerobase.fastlms.admin.repository.CategoryRepository.findAllOrderBySortValueDesc()! Reason: Failed to create query for method public abstract java.util.Optional com.zerobase.fastlms.admin.repository.CategoryRepository.findAllOrderBySortValueDesc()! No property desc found for type int! Traversed path: Category.sortValue.; nested exception is java.lang.IllegalArgumentException: Failed to create query for method public abstract java.util.Optional com.zerobase.fastlms.admin.repository.CategoryRepository.findAllOrderBySortValueDesc()! No property desc found for type int! Traversed path: Category.sortValue.
at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:800) ~[spring-beans-5.3.9.jar:5.3.9]
at org.springframework.beans.factory.support.ConstructorResolver.autowireConstructor(ConstructorResolver.java:229) ~[spring-beans-5.3.9.jar:5.3.9]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.autowireConstructor(AbstractAutowireCapableBeanFactory.java:1354) ~[spring-beans-5.3.9.jar:5.3.9]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1204) ~[spring-beans-5.3.9.jar:5.3.9]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:564) ~[spring-beans-5.3.9.jar:5.3.9]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:524) ~[spring-beans-5.3.9.jar:5.3.9]
at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:335) ~[spring-beans-5.3.9.jar:5.3.9]
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234) ~[spring-beans-5.3.9.jar:5.3.9]
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:333) ~[spring-beans-5.3.9.jar:5.3.9]
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:208) ~[spring-beans-5.3.9.jar:5.3.9]
at org.springframework.beans.factory.config.DependencyDescriptor.resolveCandidate(DependencyDescriptor.java:276) ~[spring-beans-5.3.9.jar:5.3.9]
at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1380) ~[spring-beans-5.3.9.jar:5.3.9]
at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1300) ~[spring-beans-5.3.9.jar:5.3.9]
at org.springframework.beans.factory.support.ConstructorResolver.resolveAutowiredArgument(ConstructorResolver.java:887) ~[spring-beans-5.3.9.jar:5.3.9]
at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:791) ~[spring-beans-5.3.9.jar:5.3.9]
... 24 common frames omitted
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'categoryRepository' defined in com.zerobase.fastlms.admin.repository.CategoryRepository defined in @EnableJpaRepositories declared on JpaRepositoriesRegistrar.EnableJpaRepositoriesConfiguration: Invocation of init method failed; nested exception is org.springframework.data.repository.query.QueryCreationException: Could not create query for public abstract java.util.Optional com.zerobase.fastlms.admin.repository.CategoryRepository.findAllOrderBySortValueDesc()! Reason: Failed to create query for method public abstract java.util.Optional com.zerobase.fastlms.admin.repository.CategoryRepository.findAllOrderBySortValueDesc()! No property desc found for type int! Traversed path: Category.sortValue.; nested exception is java.lang.IllegalArgumentException: Failed to create query for method public abstract java.util.Optional com.zerobase.fastlms.admin.repository.CategoryRepository.findAllOrderBySortValueDesc()! No property desc found for type int! Traversed path: Category.sortValue.
- 오류: 서버가 안뜬다.
-> UnsatisfiedDependencyException: 빈을 생성하는데 해당 빈이 충돌이 된 것이다.
- 원인: 카테고리 리포지토리 인터페이스에 구현된 함수를 잠시 주석 처리 하니까 해결 (이유는 잘 모르겠으나 아직 사용중인 메서드가 아니라 주석 처리)
-> findBy... ()와 같은 메서드를 만들 때는 반드시 엔티티 안에 있는 변수명, 매개변수의 타입을 맞춰서 만들어야한다.
-> 따라서, 엔티티 안에 변수명이 없는 경우는 에러가 난다.
=========================== 오류 -===========================
- 오류: 수정 버튼을 누르고 나면 name부분이 null로 초기화 되버린다.
- 원인: 카테고리 리스트에 updateForm부분에 name="categoryName"이라고 써야하는데 오타가 나서 값이 안 들어갔다.
-> HTML에서는 카테고리 엔티티에 대한 필드값을 잘못 적더라도 빨간줄이 그인다거나 하지 않아서 주의해야한다.
-> 자바스크립트에서는 중괄호나 괄호가 짝이 맞지 않는 경우도 주의해야한다.
'Spring Projcect > 학습 관리 시스템 & 백오피스 구축' 카테고리의 다른 글
Chapter 14. 스프링 부트(Spring Boot) (0) | 2022.08.24 |
---|---|
Chapter 13. 강좌 목록 (0) | 2022.08.23 |
Chapter 11. 회원 상세 및 상태 처리 (0) | 2022.08.21 |
Chapter 10. 회원 목록 (0) | 2022.08.20 |
Chapter 09. 관리자 로그인 구현 (0) | 2022.08.20 |