SessionInterceptor 추가
request.setAttribute("sessionEntity", sessionEntity);
UserService
만료시키는 것
UserController 로그아웃 구현
로그아웃을 누르면 로그아웃이 된다.
index.html 추가
<!DOCTYPE html>
<html lang="ko" xmlns:th="http://www.thymeleaf.org">
<!--/*@thymesVar id="userEntity" type="dev.dmchoi.coupang.entities.member.UserEntity"*/-->
<head>
<meta charset="UTF-8">
<title>쿠팡</title>
<link th:href="@{/resources/stylesheets/common.css}" rel="stylesheet">
<link th:href="@{/resources/stylesheets/index.css}" rel="stylesheet">
<link rel="stylesheet" as="style" crossorigin href="https://cdn.jsdelivr.net/gh/orioncactus/pretendard/dist/web/static/pretendard-dynamic-subset.css" />
<script src="https://kit.fontawesome.com/0d51ab0f86.js" crossorigin="anonymous"></script>
</head>
<body>
<th:block th:replace="~{fragments/header.html :: content}"></th:block>
<main class="main">
<aside class="aside">
카테고리 자리임
</aside>
<section class="content">
<section class="controller">
<a class="link selected" href="#">이름순</a>
<a class="link" href="#">낮은가격순</a>
<a class="link" href="#">높은가격순</a>
<span class="spring"></span>
<a class="link" th:href="@{/product/add}" th:if="${userEntity != null && userEntity.isAdmin() == true}">상품 등록</a>
</section>
<section class="products">
<a class="product" href="#">
<img alt="상품이미지" class="image" th:src="@{/resources/images/test-product-image.jpg}">
<span class="title">니베아 맨 센서티브 쉐이빙 폼</span>
<span class="price">
<span class="number">8,920</span>
<span class="won">원</span>
<img alt="로켓프레시" class="rocket" th:src="@{resources/images/rocket-fresh.png}">
</span>
<span class="due">7/9(토) 새벽 도착 보장</span>
<span class="stars three">
<i class="star one two three four five fa-solid fa-star"></i>
<i class="star two three four five fa-solid fa-star"></i>
<i class="star three four five fa-solid fa-star"></i>
<i class="star four five fa-solid fa-star"></i>
<i class="star five fa-solid fa-star"></i>
</span>
</a>
<a class="product" href="#">
<img alt="상품이미지" class="image" th:src="@{/resources/images/test-product-image.jpg}">
<span class="title">니베아 맨 센서티브 쉐이빙 폼</span>
<span class="price">
<span class="number">8,920</span>
<span class="won">원</span>
<img alt="로켓프레시" class="rocket" th:src="@{resources/images/rocket-fresh.png}">
</span>
<span class="due">7/9(토) 새벽 도착 보장</span>
<span class="stars three">
<i class="star one two three four five fa-solid fa-star"></i>
<i class="star two three four five fa-solid fa-star"></i>
<i class="star three four five fa-solid fa-star"></i>
<i class="star four five fa-solid fa-star"></i>
<i class="star five fa-solid fa-star"></i>
</span>
</a>
</section>
</section>
</main>
</body>
</html>
index.css 추가
index.main.css 추가
@charset "UTF-8";
body > .main {
width: var(--content-max-width);
align-items: flex-start;
display: flex;
flex-direction: row;
justify-content: flex-start;
}
body > .main > .aside {
border: 0.0625rem solid rgb(229, 229, 229);
border-top: none;
margin-right: 1rem;
}
body > .main > .content {
flex: 1;
}
body > .main > .content > .controller {
background-color: rgb(239, 239, 239);
align-items: center;
display: flex;
flex-direction: row;
justify-content: flex-start;
margin-top: 1rem;
margin-bottom: 1rem;
padding: 0.75rem 1rem;
}
body > .main > .content > .controller > .spring {
flex: 1;
}
body > .main > .content > .controller > .link:hover {
color: rgb(66, 132, 243);
}
body > .main > .content > .controller > .link.selected {
color: rgb(66, 132, 243);
cursor: default;
font-weight: 500;
pointer-events: none;
}
body > .main > .content > .controller > .link + .link {
margin-left: 0.5rem;
}
body > .main > .content > .products {
display: grid;
grid-gap: 1.5rem;
grid-template-columns: repeat(3, 1fr);
}
body > .main > .content > .products > .product {
align-items: stretch;
display: flex;
flex-direction: column;
justify-content: flex-start;
}
body > .main > .content > .products > .product > .image {
width: 100%;
margin-bottom: 0.75rem;
}
body > .main > .content > .products > .product > .title {
margin-bottom: 0.5rem;
text-align: justify;
}
body > .main > .content > .products > .product:hover > .title {
color: rgb(66, 132, 243);
text-decoration: underline;
}
body > .main > .content > .products > .product > .price {
align-items: center;
color: rgb(174, 0, 0);
display: flex;
flex-direction: row;
justify-content: flex-start;
margin-bottom: 0.2rem;
}
body > .main > .content > .products > .product > .price > .number {
font-size: 1.125rem;
font-weight: 600;
}
body > .main > .content > .products > .product > .price > .rocket {
height: 1.25rem;
margin-left: 0.5rem;
}
body > .main > .content > .products > .product > .due {
color: rgb(0, 137, 26);
margin-bottom: 0.375rem;
}
body > .main > .content > .products > .product > .stars {
color: rgb(205, 205, 205);
letter-spacing: -0.125rem;
}
body > .main > .content > .products > .product > .stars.one > .star.one {
color: rgb(255,151,0);
}
body > .main > .content > .products > .product > .stars.two > .star.two {
color: rgb(255,151,0);
}
body > .main > .content > .products > .product > .stars.three > .star.three {
color: rgb(255,151,0);
}
body > .main > .content > .products > .product > .stars.four > .star.four {
color: rgb(255,151,0);
}
body > .main > .content > .products > .product > .stars.five > .star.five {
color: rgb(255,151,0);
}
ProductController
RequestAttribute을 사용하게 되면 아래 내용을 하지 않아도 된다.
if (request.getAttribute("sessionEntity") instanceof SessionEntity) {
SessionEntity sessionEntity = (SessionEntity) request.getAttribute("sessionEntity");
this.userService.expireSession(sessionEntity);
required = true 이면
비회원 시 들어가면 오류가 터지고, false 해놓으면 null이 들어감 false로 변경
로그인을 안했거나 관리자가 아닐 경우 404페이지로.
product/add.html 추가
<!DOCTYPE html>
<html lang="ko" xmlns:th="http://www.thymeleaf.org">
<!--/*@thymesVar id="userEntity" type="dev.dmchoi.coupang.entities.member.UserEntity"*/-->
<head>
<meta charset="UTF-8">
<title>쿠팡</title>
<link rel="stylesheet" as="style" crossorigin href="https://cdn.jsdelivr.net/gh/orioncactus/pretendard/dist/web/static/pretendard-dynamic-subset.css" />
<link th:href="@{/resources/stylesheets/common.css}" rel="stylesheet">
<link th:href="@{/product/resources/stylesheets/add.css}" rel="stylesheet">
<script src="https://kit.fontawesome.com/0d51ab0f86.js" crossorigin="anonymous"></script>
<script defer th:src="@{/resources/libraries/ckeditor/ckeditor.js}"></script>
<script defer th:src="@{/product/resources/scripts/add.js}"></script>
</head>
<body>
<th:block th:replace="~{fragments/header.html :: content}"></th:block>
<form class="main" method="post">
<label class="label">
<span class="hint">제목</span>
<input autofocus class="input" min="100" name="title" placeholder="상품 제목을 입력해주세요" type="text">
</label>
<label class="label">
<span class="hint">가격</span>
<input class="input" min="100" max="99999990" name="price" placeholder="판매 가격을 입력해주세요" step="10" type="number">
</label>
<label class="label">
<span class="hint">배송</span>
<label class="label">
<input checked class="input" name="delivery" type="radio" value="normal">
<span class="checker"></span>
<span class="text">일반</span>
</label>
<label class="label">
<input class="input" name="delivery" type="radio" value="rocket">
<span class="checker"></span>
<span class="text">로켓</span>
</label>
<label class="label">
<input class="input" name="delivery" type="radio" value="rocketFresh">
<span class="checker"></span>
<span class="text">로켓프레시</span>
</label>
</label>
<textarea class="editor" name="content" id="editor"></textarea>
<div class="buttons">
<input class="button white" type="button" value="돌아가기" onclick="if (confirm('정말로 돌아갈까요? 작성하신 정보가 모두 유실됩니다.')) {window.history.back();}">
<input class="button blue" type="submit" value="상품 등록하기">
</div>
</form>
</body>
</html>
add.css 추가
@charset "UTF-8";
body > .main {
width: var(--content-max-width);
align-items: stretch;
display: flex;
flex-direction: column;
justify-content: flex-start;
margin-top: 1rem;
padding-bottom: 2rem;
}
body > .main > .label {
align-items: center;
display: flex;
flex-direction: row;
justify-content: flex-start;
margin-bottom: 0.5rem;
}
body > .main > .label > .hint {
flex: 0 0 3rem;
white-space: nowrap;
margin-left: 1rem;
}
body > .main > .label > .input {
width: auto;
flex: 1;
border: 0.0625rem solid rgb(229, 229, 229);
padding: 0.625rem 1rem;
border-radius: 0.25rem;
}
body > .main > .label > .label {
align-items: center;
cursor: pointer;
display: flex;
flex-direction: row;
justify-content: flex-start;
}
body > .main > .label > .label + .label {
margin-left: 0.75rem;
}
body > .main > .label > .label > .checker {
border: 0.0625rem solid rgb(229, 229, 229);
border-radius: 50%;
margin-right: 0.375rem;
padding:0.5rem;
}
body > .main > .label > .label > .input:checked + .checker {
border: 0.0625rem solid rgb(229, 229, 229);
background-color: rgb(66,132,243);
}
body > .main > .label > .label > .text {
white-space: nowrap;
}
body > .main > .buttons {
align-items: center;
display: flex;
flex-direction: row;
justify-content: center;
margin-top: 1.5rem;
}
body > .main > .buttons > .button {
width: auto;
border-radius: 0.25rem;
cursor: pointer;
padding: 0.75rem 1.25rem;
}
body > .main > .buttons > .button +.button {
margin-left: 0.5rem;
}
body > .main > .buttons > .button:hover {
filter: brightness(105%);
}
body > .main > .buttons > .button:active {
filter: brightness(95%);
}
body > .main > .buttons > .button.white {
border: 0.0625rem solid rgb(229, 229, 229);
}
body > .main > .buttons > .button.blue {
background-color: rgb(66,132,243);
color: white;
}
https://ckeditor.com/ckeditor-5/demo/
메인에서 상단 메뉴바에 CKEditor5 클릭
Online builder 클릭
Classic 클릭
Cloud Services 및 ck 관련된거 삭제하고 simple 검색
Simple upload adapter ADD
Next step 후 Korean으로 지정
다운로드
build에 있는 내용 ckeditor 디렉토리에 추가
add.html 에 script 추가
product -> resources -> scripts 디렉토리에 add.js 추가
적용완료
테스트해보자
add 클릭해보면
여러 이미지 업로드를 위해 배열로 만들어준다.
이미지를 업로드 해보면
binary이미지를 의미
이미지파일 이름이 뜨면 된다