유저컨트롤러에서 로그아웃 부분
1. 어디선가 UserEntity 타입의 객체를 받아와서 이가 가진 email 이 null이 아니라면 sessions 테이블에서 이 이메일을 가진 유효한 세션 만료시키기
2. sk라는 이름을 가지는 쿠키 삭제
-> SessionInterceptor sessionEntity
추가
-> UserController getLogout
- (SessionEntity) request.~ : SessionEntity로 형변환한 request
-> UserService expireSession
- expired : 만료시키는 것.
-> UserController
여기까지 했다면 로그아웃이 되는 것을 확인하면 된다.
- 로그아웃 잘된다!
-> index.html
<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/cider-product.png}">
<span class="title">칠성사이다 210ml, 30개 </span>
<span class="price">
<span class="number">45,550</span>
<span class="won">원</span>
<img alt="로켓프레시" class="rocket" th:src="@{/resources/images/rocket-fresh.png}">
</span>
<span class="due">새벽 도착 보장</span>
<span class="stars">
<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>
</main>
-> index.css -> index.main.css 생성 (import)
<style>
@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);
font-weight: 500;
cursor: default;
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 {
text-align: justify;
margin-top: 0.5rem;
}
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.5rem;
}
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);
}
</style>
-> add.html 상품추가
<form class="main" method="post">
<label class="label">
<span class="hint">제목</span>
<input autofocus class="input" maxlength="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 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>
-> add.css
<style>
@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: 1rem;
}
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-bottom: 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;
}
</style>
-> ProductController
.
- 관리자가 아니면 다른 사람이 상품 등록을 클릭하게 되면 404 뜨게 설정.
- 관리자 아이디로 로그인 하게 되면 상품정보를 수정할 수 있게 된다.
: What you see is what you get
- 상품 추가를 위해 CKEditor을 사용할 것이다.
- CKEditor 5 클릭
- Online builder 클릭
- Classic으로 추가한다.
simple upload adapter
추가 / 필요한 기능을 추가해서 사용하면 된다.cloudService
,ckuploadadaptor
,ckfinder
제외.
- 최종 editor plugins
- 한국어 선택
- 다운로드 !
- html 파일을 보면서 사용하면 된다.
-> CKEditor
옮길 파일 위치
- 다운로드한 파일 압축 풀고
build
폴더안에 있는 폴더랑 파일들을 intellj로 옮긴다. (아래에서 파일 위치 확인)
-> ckeditor 파일 추가 / add.html srcipt
링크 추가
resources-> libraries -> ckeditor
디렉터리 생성하고 파일 추가한다.add.html
script 링크 추가
-> add.html ckeditor
이 들어갈 박스 추가
ckeditor
는 상품 제목/가격을 적는 곳과 등록 버튼 사이에 위치한다.
textarea
로 추가!
-> add.js
추가
-> add.js
- 현재 뜨는 화면
- maxheight를 설정해두었기 때문에 70vh를 넘어가면 화면이 더 이상 늘어나지 않는다.
-> submit
- submit(상품등록하기 버튼 클릭)을 하게 되면 지금은 경로가 없어서 이렇게 뜬다.
- CKEditor을 통해 작성한 내용과 이미지는 서버의 html의 코드로 넘어간다.
- src는 우리의 주소여야한다. 우리가 이미지를 제공한다는 의미.
이미지 버튼을 눌러서 이미지를 업로드하는데 버튼을 누르기 전에 이미 이미지는 서버에 업로드가 되어있어야한다.
이미지선택하고 서버의 xhr통해 이미지를 업로드하면 DB에 저장에 된다. 그 다음 그 이미지를 화면에 표시해 줄수 있게 하는 주소(맵핑)하나 만들고
그 주소를 얘한테 알려주면 여기에 태그가 생기면서 이미지가 뜬다.
그 다음 작성을 누르면 img태그를 포함한 html코드가 서버로 넘어가서 실제 게시글 내용은 html 코드가 저장이 되는 것이다.
-> add.js 추가
- create할 때 오브젝트로 매개변수를 전달해준다.
- 개발자 도구를 켜놓고 이미지를 하나 업로드해보자.
payload
를 보면 방금 js에 작성했던 주소로 요청이 들어갔고 저 맵핑을 만들어서 formData로 들어오고 있는 업로드 된 이미지를 받아야한다.binary
는 이미지 데이터의 이진데이터를 의미하고upload
는 이름이 upload 라는 것인데 사실상 고정이라고 보면된다.
-> ProductController postAddUploadImage
- 타입은
MultipartFile[]
로 한다.
postAddUploadImage
이미지를 드래그해서 여러개를 넣을 수 있기 때문에 배열로 만든다.
-> Check
- 이미지를 추가해서 확인해보자. (alert는 아직은 떠도 상관없다.)
- sout으로 찍어보았고 이미지 파일이름이 찍히면 성공