-
7주차 목 1005광주인력개발원 일일포스팅(메모장) 2023. 10. 5. 16:53728x90반응형
#잡담
view Template
1순위 Thymeleaf
연관관계 연습
게시글에 좋아요, 즐겨찾기 만들기
1명의 사용자가 지금까지 좋아요 또는 즐겨찾기 한 게시물 목록 보여주기
★복습
1. CRUD (작성, 조회, 수정, 삭제)
2. 비밀번호 암호화(2가지 방식- 기본자바, 스프링 시큐리티)
ㄴ (7.수.1004에는 없음)
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-security</artifactId></dependency>dependency 에 깔고
@Configurationpublic class SecurityConfig {@Beanpublic PasswordEncoder passwordEncoder() {return new BCryptPasswordEncoder();}}Config 추가했었다..
★학습목표
1. 비밀번호 암호화
2. 댓글 작성 및 조회
3. AOP
4. Filter / interceptor
★ 학습
1. 암호화 연습
# 암호화는 가능한데 복호화는 안된다.
@AutowiredPasswordEncoder passwordEncoder;# pw 에 int 를 쓰면 null이라는 값을 못 넣기에 @Column()에 nullable 을 사용해서 오류를 해결할 수 있다
@Entity@Datapublic class Owner {@Idint id;String name;String pwd;.이렇게 해주주면
이제 암호화 코드를 입력
passwordEncoder. encode 와 matches 를 자주 쓴다.
@PostMapping("/signup")public String signupPost(@ModelAttribute Owner owner) {System.out.println(owner);
String newPwd = passwordEncoder.encode(owner.getPwd());owner.setPwd(newPwd);
ownerRepository.save(owner);return "redirect:/auth/signup";그러면 h2에 암호화된 코드가 pwd에 들어가게 된다
passwordEncoder -> matches()를 이용해서 비교
패스워드는 시간에 따라서 매번 다르기에 ==으로 비교 불가
기존의 알고리즘을 수정해서 matches() 이용하게 바꿔야함
id를 이용해서 findById() 이용하고 boolean 으로 맞는지 확인
@PostMapping("/signin")public String signinPost(@ModelAttribute Owner owner) {int id = owner.getId();// List<Owner> result = ownerRepository.findByIdAndName(id, name);Optional<Owner> result = ownerRepository.findById(id);String pwd = result.get().getPwd();// ㄴ h2에 있는 pwd를 의미함String name = result.get().getName();boolean isMatch =passwordEncoder.matches(owner.getPwd(), pwd);// ㄴ 변환전 ㄴ 변환후
if (isMatch) {session.setAttribute("id", id);session.setAttribute("name", name);} else {return "redirect:/auth/signin";}return "redirect:/html/emp";public String signinPost(@ModelAttribute Owner owner) {id 입력시에 @ModelAttribute에 문자가 오면 오류가 날수 있음 조금 보안해준다면
@PostMapping("/signin")public String signinPost(@ModelAttribute Owner owner) {// ㄴ숫자가 아닌 문자가 입력되었을 때 문제가 생길 수 있음int id = owner.getId();// List<Owner> result = ownerRepository.findByIdAndName(id, name);Optional<Owner> result = ownerRepository.findById(id);boolean isPresen = result.isPresent();if (isPresen) {String pwd = result.get().getPwd();// ㄴ h2에 있는 pwd를 의미함String name = result.get().getName();boolean isMatch = passwordEncoder.matches(owner.getPwd(), pwd);// ㄴ 변환전 ㄴ 변환후
if (isMatch) {session.setAttribute("id", id);session.setAttribute("name", name);}}boolean으로 보충이 가능하다
<form action="/auth/signin" method="post"><input type="text" name="id" placeholder="ID를 입력해주세요"><br><input type="password" name="pwd" placeholder="pw를 입력해주세요"><br><button>로그인</button></form>2. 자바 기본 패키지
@Componentpublic class Encrypt {public String encode(String raw) {String hex = null;try {// String raw = "password1234";MessageDigest md;md = MessageDigest.getInstance("SHA-256");md.update(raw.getBytes());hex = String.format("%064x", new BigInteger(1, md.digest()));} catch (NoSuchAlgorithmException e) {e.printStackTrace();}return hex;}}@AutowiredEncrypt encrypt;불러와
@GetMapping("/signin")public String signin() throws NoSuchAlgorithmException {String pwd = passwordEncoder.encode("1");System.out.println(pwd);// ㄴ 스프링부트String pwd2 = encrypt.encode("1");System.out.println(pwd2);// ㄴ 기본패키지$2a$10$f1.BrBkAt27w0z82/BtpuO3U/IqKgqvU0UkywtFLMqKqRVeBiOAZi /// 스프링부트
6b86b273ff34fce19d6b804eff5a3f5747ada4eaa22f1d49c01e52ddb7875b4b /// 기본패키지ㄴ출력값
$2a$10$AaKmA.v.2ykUeR/sCVKjbea2XKrZyuaQax3PmXHi/ovXcW0WoR9Pq
6b86b273ff34fce19d6b804eff5a3f5747ada4eaa22f1d49c01e52ddb7875b4b두번 출력했을 때 스프링부트는 바뀌지만 기본패키지는 안 바뀜
6b86b273ff34fce19d6b804eff5a3f5747ada4eaa22f1d49c01e52ddb7875b4b
6b86b273ff34fce19d6b804eff5a3f5747ada4eaa22f1d49c01e52ddb7875b4b
눈 아픔 ㅠㅠ
2. 연관관계 연습(댓글 작성 및 조회)
1) 데이터베이스 // @Entity @Repository
ㄴ 내용, 작성자, 게시글 아이디(★프라이머리 키-연관관계), 작성일시,
ㄴ @Many To One
@Entity @Datapublic class Comment {@Id @GeneratedValueint id;String content;String writer;Date creDate; // 언더스코어로 바뀜
@ManyToOne Board board; board_id 프라이머리 키짜잔
<form action="/board/comment" method="post"><input type="text" name="content" ><button>입력</button></form>html에 content 해결
@PostMapping("/board/comment")public String comment(@ModelAttribute Comment comment) {String name = (String) session.getAttribute("name");if(name == null) {name= "Anonymous";}comment.setWriter(name);comment.setCreDate((new Date()));return "redirect:/board/comment";}writer와 date 해결 이제 board 해결해야한다.
<form action="/board/comment" method="post"><input type="text" name="content" ><input type="hidden" name="boardId" th:value="${board.id}"><!-- ㄴ 이녀석은 requestParam으로 처리 --><button>입력</button>@PostMapping("/comment")public String comment(@ModelAttribute Comment comment,@RequestParam int boardId) <<<추가 {String name = (String) session.getAttribute("name");if(name == null) {name= "Anonymous";}comment.setWriter(name);comment.setCreDate((new Date()));Board board = new Board(); <<<추가board.setId(boardId);comment.setBoard(board);commentRepository.save(comment);
return "redirect:/board/lsit";}이렇게 코드를 작성해주면 어느정도 완성
상세보기에 게시글 작성하는 칸이 생기고 입력하게되면
h2 comment에 들어오게된다
이제 연관관계를 연습하기위해 양방향을 쓴다
Board.java에 @One To Many 사용
@OneToMany(mappedBy = "board")List<Comment> Comments = new ArrayList<>();<ul th:each="comment : ${board.comments}"><li>[[${comment.content}]][[${comment.writer}]][[${comment.creDate}]]</li>
</ul>반복문 돌리면~
밑에 li가 찍혀나온당
# 댓글 작성 시 게시물 객체를 사용했듯이
게시물 작성 시 회원 객체를 사용해야 됨
회원을 new 시킴 ex) new owner
해서 같이 넣어줘야함!
댓글 삭제하기
Controller
@GetMapping("/comment/remove")public String commentRemove(@ModelAttribute Comment comment) {//1번 new Commnet(), setId()//2번 @ModelAttribute Comment commentcommentRepository.delete(comment);return "redirect:/board/list";}버튼 수정
<ul th:each="comment : ${board.comments}">[[${comment.content}]]/[[${comment.writer}]]/[[${comment.creDate}]]<button th:onclick=" ' removeComment( ' + ${comment.id} + ' ) ' "
>삭제</button></ul>스크립트 수정
function removeComment(id) {const isOk = confirm('댓글을 삭제하시겠습니까?');
if (isOk) {location = `/board/comment/remove?id=${id}`;}}이렇게 개발자도구를 확인해서 id를 확인할 수 있다
삭제하면 h2에서도 삭제가 되는걸 볼 수 있다.
# 아까전에 리스트목록에서 댓글 수를 알 수 있게 설정한게 있다
list.html에서 수정하면
<ul th:each="board : ${boardList}"><li><!-- th:href !! 꼭 th: 를 입력해야 오류가 없음 --><a th:href="@{/board/detail(id=${board.id})}">[[ ${board.id} ]]/ [[ ${board.title} ]]/ [[${board.writer}]]
( [[ ${#lists.size(board.comments)} ]] )
</a></li></ul>Board.java랑 Comment.java를 양방향으로 만들었기에 가능하다.
Comment.java
@Entity @Datapublic class Comment {@Id @GeneratedValueint id;
String content;String writer;Date creDate;
@ManyToOne Board board;}Board.java
@Entity@Datapublic class Board {@Id @GeneratedValue// id 없으면 프라이머리 키가 없어서 작동안하고// @GeneratedValue 순서int id;String title;String content;String writer;
@OneToMany(mappedBy = "board")List<Comment> comments = new ArrayList<>();}짜잔
3. AOP - Aspect Oriented Programming #객체지향의 끝판왕?
공통적으로 적용될 모듈을 만든 후 적용하고자 하는 부분의 코드 밖에서 삽입하는 방법
사용 분야
- 메소드의 성능 테스트 - 예외 반환
- 트랜잭션 처리 - 로깅, 인증, 권한 처리 등
제일 많은 일을 하는건 AOP <<제일 강력한?
주로 프로그램을 만들면서 작성하는건 Interceptor
AOP 용어
1.Advice : 부가 기능을 담은 모듈 (메소드) /
+메소드가 동작할 때 어드바이스가 활성
2.Pointcut : Joinpoint 중 실제 Advice가 적용되는 지점 (위치+시점 지정)
execution을 pointcut이라고 함.
3.Aspect : Advisor의 집합 (Advice + Pointcut)
*은 모드 타입
(* com.example.basic.controller.*(모든클래스).*(모든메소드)(..))")
@Component < Bean 등록
@Aspect < AOP 기능 활성
... AOP는 모든 메소드를 다 활용가능
Filter는 AOP보다 할 수 있는 일이 적음
오로지 url에 대해서만 //으로 접속하는 url에만 동작을 함.
로그를 남기거나 검증해보고 싶을때
웹브라우저 <>서버 (a,<>b <>c <>d )
ㄴ 스프링이라는 위치는 d . tomcat은 ( )
filter는 스프링, AOP, Interceptor보다 먼저 동작함
요청과 응답에 불필요하거나 보여주기 싫은 또는 받기 싫은것들을 거를 수 있음
Interceptor도 url만 가능
일단 스프링 안으로 들어온 이후에 인터셉터가 가로채서 동작 AOP는 그 이후에 작동
AOP는 요청 뿐만 아니라 세부적으로 작업가능
- preHandler() : Controller의 메소드가 실행되기 전 (요청)
- postHandler() : Controller의 메소드가 실행된 후 (응답)
이해가 잘 안됨 ㅠ 우선 여기까지 하고 저녁에 공부해서 올릴게유..
728x90반응형'광주인력개발원 일일포스팅(메모장)' 카테고리의 다른 글
8주차 화 1010 (3) 2023.10.10 7주차 금 1006 (0) 2023.10.10 7주차 수 1004 천사넹 (2) 2023.10.04 6주차 수 0927 (2) 2023.09.27 6주차 화 0926 (1) 2023.09.26