728x90
출처:
https://www.youtube.com/watch?v=qz4yyaRANBQ&list=PL93mKxaRDidECgjOBjPgI3Dyo8ka6Ilqm&index=55
https://summernote.org/getting-started/
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Summernote with Bootstrap 4</title>
<script src="https://code.jquery.com/jquery-3.5.1.min.js" crossorigin="anonymous"></script>
<script src="https://cdn.jsdelivr.net/npm/popper.js@1.16.0/dist/umd/popper.min.js" integrity="sha384-Q6E9RHvbIyZFJoft+2mJbHaEWldlvI9IOYy5n3zV9zzTtmI3UksdQRVvoxMfooAo" crossorigin="anonymous"></script>
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/css/bootstrap.min.css" integrity="sha384-Vkoo8x4CGsO3+Hhxv8T/Q5PaXtkKtu6ug5TOeNV6gBiFeWPGFN9MuhOf23Q9Ifjh" crossorigin="anonymous">
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/js/bootstrap.min.js" integrity="sha384-wfSDF2E50Y2D1uUdj0O3uMBJnjuUD4Ih7YwaYd1iqfktj0Uod8GCExl3Og8ifwB6" crossorigin="anonymous"></script>
<!-- summer note -->
<link href="https://cdn.jsdelivr.net/npm/summernote@0.8.18/dist/summernote-bs4.min.css" rel="stylesheet">
<script src="https://cdn.jsdelivr.net/npm/summernote@0.8.18/dist/summernote-bs4.min.js"></script>
</head>
<body>
<div id="summernote"></div>
<script>
$('#summernote').summernote({
placeholder: 'Hello Bootstrap 4',
tabsize: 2,
height: 100
});
</script>
</body>
</html>
위 문장 중 복사해서
<!-- summer note -->
<link href="https://cdn.jsdelivr.net/npm/summernote@0.8.18/dist/summernote-bs4.min.css" rel="stylesheet">
<script src="https://cdn.jsdelivr.net/npm/summernote@0.8.18/dist/summernote-bs4.min.js">
<!-- summer note -->
<script>
$('#summernote').summernote({
placeholder : 'Hello Bootstrap 4',
tabsize : 2,
height : 100
});
</script>
클래스로 찾게 변경
굿
23분30초부터 흘러가는 맥락 잡아 줌
package com.cosblog.controller;
import org.springframework.security.core.annotation.AuthenticationPrincipal;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import com.cosblog.config.auth.PrincipalDetail;
@Controller
public class BoardController {
//public String index(@AuthenticationPrincipal PrincipalDetail principal)
@GetMapping({"","/"})
public String index() {
return "index";
}
@GetMapping("/board/saveForm")
public String saveForm() {
return "board/saveForm";
}
}
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<%@ taglib prefix="sec" uri="http://www.springframework.org/security/tags"%>
<sec:authorize access="isAuthenticated()">
<sec:authentication property="principal" var="principal" />
</sec:authorize>
<!DOCTYPE html>
<html lang="en">
<head>
<title>Cos 블로그</title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@4.6.1/dist/css/bootstrap.min.css">
<script src="https://cdn.jsdelivr.net/npm/jquery@3.5.1/dist/jquery.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/popper.js@1.16.1/dist/umd/popper.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@4.6.1/dist/js/bootstrap.bundle.min.js"></script>
<!-- summer note -->
<link href="https://cdn.jsdelivr.net/npm/summernote@0.8.18/dist/summernote-bs4.min.css" rel="stylesheet">
<script src="https://cdn.jsdelivr.net/npm/summernote@0.8.18/dist/summernote-bs4.min.js"></script>
</head>
<body>
<nav class="navbar navbar-expand-md bg-dark navbar-dark">
<a class="navbar-brand" href="/">Cos</a>
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#collapsibleNavbar">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="collapsibleNavbar">
<c:choose>
<c:when test="${empty principal}">
<ul class="navbar-nav">
<li class="nav-item"><a class="nav-link" href="/auth/loginForm">로그인</a></li>
<li class="nav-item"><a class="nav-link" href="/auth/joinForm">회원가입</a></li>
</ul>
</c:when>
<c:otherwise>
<ul class="navbar-nav">
<li class="nav-item"><a class="nav-link" href="/board/saveForm">글쓰기</a></li>
<li class="nav-item"><a class="nav-link" href="/user/updateForm">회원정보</a></li>
<li class="nav-item"><a class="nav-link" href="/logout">로그아웃</a></li>
</ul>
</c:otherwise>
</c:choose>
</div>
</nav>
<br />
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ include file="../layout/header.jsp"%>
<div class="container">
<form action="/auth/loginProc" method="POST">
<div class="form-group">
<label for="email">Title</label> <input type="text" class="form-control" placeholder="Enter title" id="title">
</div>
<div class="form-group">
<label for="comment">Content:</label>
<textarea class="form-control summernote" rows="5" id="content"></textarea>
</div>
</form>
<button id="btn-save" class="btn btn-primary">글 저장</button>
</div>
<!-- summer note -->
<script>
$('.summernote').summernote({
tabsize : 2,
height : 300
});
</script>
<script src="/js/board.js"></script>
<%@ include file="../layout/footer.jsp"%>
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ include file="../layout/header.jsp"%>
<div class="container">
<form action="/auth/loginProc" method="POST">
<div class="form-group">
<label for="email">Username</label>
<input type="text" name="username" class="form-control" placeholder="Enter Username" id="username">
</div>
<div class="form-group">
<label for="pwd">Password</label>
<input type="password" name="password" class="form-control" placeholder="Enter password" id="password">
</div>
<button id="btn-login" class="btn btn-primary">로그인</button>
</form>
</div>
<!-- 로그인때 자바스크립트 사용 안할거임.
<script src="/js/user.js"></script> -->
<%@ include file="../layout/footer.jsp"%>
let index = {
init: function () {
$("#btn-save").on("click", () => {
this.save();
});
},
save: function () {
let data = {
title: $("#title").val(),
content: $("#content").val(),
};
$.ajax({
type: "POST",
url: "/api/board",
data: JSON.stringify(data),
contentType: "application/json; charset=utf-8",
dataType: "json",
})
.done(function (resp) {
alert("글쓰기가 완료되었습니다.");
location.href = "/";
})
.fail(function (error) {
alert(JSON.stringify(error));
});
},
};
index.init();
package com.cosblog.controller.api;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.security.core.annotation.AuthenticationPrincipal;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
import com.cosblog.config.auth.PrincipalDetail;
import com.cosblog.dto.ResponseDto;
import com.cosblog.model.Board;
import com.cosblog.service.BoardService;
@RestController
public class BoardApiController {
@Autowired
private BoardService boardService;
@PostMapping("/api/board")
public ResponseDto<Integer> save(@RequestBody Board board,@AuthenticationPrincipal PrincipalDetail principal) {
boardService.글쓰기(board, principal.getUser());
return new ResponseDto<Integer>(HttpStatus.OK.value(), 1);
}
}
package com.cosblog.repository;
import org.springframework.data.jpa.repository.JpaRepository;
import com.cosblog.model.Board;
public interface BoardRepository extends JpaRepository<Board, Integer>{
}
package com.cosblog.service;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import com.cosblog.model.Board;
import com.cosblog.model.RoleType;
import com.cosblog.model.User;
import com.cosblog.repository.BoardRepository;
//스프링이 컴포넌트 스캔을 통해서 bean에 등록을 해줌
@Service
public class BoardService {
@Autowired
private BoardRepository boardRepository;
@Transactional
public void 글쓰기(Board board, User user) {
board.setCount(0);
board.setUser(user);
boardRepository.save(board);
}
/* 이 로그인도 사용 안 할거라 삭제
* @Transactional(readOnly = true)//Select할 때 트랜잭션 시작, 서비스 종료시에 트랜잭션 종료(정합성)
* public User 로그인(User user) { return
* userRepository.findByUsernameAndPassword(user.getUsername(),
* user.getPassword()); }
*/
}
package com.cosblog.model;
import java.sql.Timestamp;
import java.util.List;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.Lob;
import javax.persistence.ManyToOne;
import javax.persistence.OneToMany;
import org.hibernate.annotations.ColumnDefault;
import org.hibernate.annotations.CreationTimestamp;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
@Entity
public class Board {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
@Column(nullable = false, length = 100)
private String title;
@Lob //대용량 데이터
private String content; //섬머노트 라이브러리<html>태그가 섞여서 디자인 됨.
//@ColumnDefault("0") //조회수 강제로 넣어줄 것임.
private int count;
@ManyToOne(fetch = FetchType.EAGER) //Many = Board, User = One
@JoinColumn(name="userId")//DB테이블 필드값은 userId로 만들어지고 연관관계는 ManyToOne으로 만들어진다.
private User user;//DB는 오브젝트를 저장할 수 없다. FK, 자바는 오브젝트를 저장할 수 있다.
@OneToMany(mappedBy = "board", fetch = FetchType.EAGER) //Many = Board, User = One
private List<Reply> reply;//DB는 오브젝트를 저장할 수 없다. FK, 자바는 오브젝트를 저장할 수 있다.
@CreationTimestamp
private Timestamp createDate;
}
package com.cosblog.controller.api;
import javax.servlet.http.HttpSession;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
import com.cosblog.dto.ResponseDto;
import com.cosblog.model.RoleType;
import com.cosblog.model.User;
import com.cosblog.service.UserService;
@RestController
public class UserApiController {
@Autowired
private UserService userService;
//@Autowired //메서드 파라메터 대신 이렇게 넣어줘도 가능하다.
//private HttpSession session;
@PostMapping("/auth/joinProc")
public ResponseDto<Integer> save(@RequestBody User user) {
System.out.println("UserApiController : save 호출됨");
userService.회원가입(user);
return new ResponseDto<Integer>(HttpStatus.OK.value(), 1);//자바오브젝트를 JSON으로 변환해서 리턴
}
//전통적인 로그인 방식, 스프링 시큐리티 이용해서 로그인하면 이 방식 사용하지 않는다.
/*
* @PostMapping("/api/user/login") public ResponseDto<Integer>
* login(@RequestBody User user, HttpSession session){
* System.out.println("UserApiController:login호출됨"); User principal =
* userService.로그인(user); //접근주체
*
* if(principal != null) { session.setAttribute("principal", principal); }
*
* return new ResponseDto<Integer>(HttpStatus.OK.value(),1);
*
* }
*/
}
package com.cosblog.config.auth;
import java.util.ArrayList;
import java.util.Collection;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import com.cosblog.model.User;
import lombok.Getter;
//스프링 시큐리티가 로그인 요청을 가로채서 로그인을 진행하고 완료가 되면 UserDeatils 타입의 오브젝트를
//스프링 시큐리티의 고유한 세션저장소에 저장을 해준다.
@Getter
public class PrincipalDetail implements UserDetails {
private User user;//콤포지션 :객체를 품고 있는거
public PrincipalDetail(User user) {
this.user = user;
}
@Override
public String getPassword() {
// TODO Auto-generated method stub
return user.getPassword();
}
@Override
public String getUsername() {
// TODO Auto-generated method stub
return user.getUsername();
}
//계정이 만료되지 않았는지 리턴한다. (true:만료안됨)
@Override
public boolean isAccountNonExpired() {
// TODO Auto-generated method stub
return true;
}
//계정이 잠겨있지 않았는지 리턴한다. (true:잠기지 않음)
@Override
public boolean isAccountNonLocked() {
// TODO Auto-generated method stub
return true;
}
//비밀번호가 만료되지 않았는지 리턴한다.(true:만료안됨)
@Override
public boolean isCredentialsNonExpired() {
// TODO Auto-generated method stub
return true;
}
//계정이 활성화(사용가능)인지 리턴한다.(true:활성화)
@Override
public boolean isEnabled() {
// TODO Auto-generated method stub
return true;
}
//계정이 갖고있는 권한 목록을 리턴한다. (권한이 여러개 있을 수 있어서 루프를 돌아야 하는데 우리는 한개만)
//권한이 여러개면 for문을 돌려야 함.
@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
Collection<GrantedAuthority> collectors = new ArrayList<>();
collectors.add(()->{return "ROLE_"+user.getRole();});
return collectors;
}
}
728x90
'Spring > Spring boot' 카테고리의 다른 글
스프링부트 강좌 55강(블로그 프로젝트) - 글목록 페이징하기 (0) | 2022.01.25 |
---|---|
스프링부트 강좌 54강(블로그 프로젝트) - 글목록보기 (0) | 2022.01.25 |
스프링부트 강좌 52강(블로그 프로젝트) - 스프링 시큐리티 로그인 (0) | 2022.01.24 |
스프링부트 강좌 51강(블로그 프로젝트) - XSS와 CSRF (0) | 2022.01.24 |
스프링부트 강좌 50강(블로그 프로젝트) - 비밀번호 해쉬 후 회원가입하기 (0) | 2022.01.24 |
댓글