7주차 목 1005 :: newb

ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 7주차 목 1005
    광주인력개발원 일일포스팅(메모장) 2023. 10. 5. 16:53
    728x90
    반응형

    #잡담

     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 에 깔고

    @Configuration
    public class SecurityConfig {
    @Bean
    public PasswordEncoder passwordEncoder() {
    return new BCryptPasswordEncoder();
    }
    }

    Config 추가했었다..

     

    ★학습목표

    1. 비밀번호 암호화

    2.  댓글 작성 및 조회

    3. AOP                        

    4. Filter / interceptor  

     

    ★ 학습

    1. 암호화 연습

    # 암호화는 가능한데 복호화는 안된다.

        @Autowired
        PasswordEncoder passwordEncoder;

    # pw 에 int 를 쓰면 null이라는 값을 못 넣기에 @Column()에 nullable 을 사용해서 오류를 해결할 수 있다

    @Entity
    @Data
    public class Owner {
        @Id
        int 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. 자바 기본 패키지 

     
     
    @Component
    public 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;
        }
    }
        @Autowired
        Encrypt 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 @Data
    public class Comment {
        @Id @GeneratedValue
        int 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 comment
            commentRepository.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 @Data
    public class Comment {
        @Id @GeneratedValue
        int id;

        String content;
        String writer;
        Date creDate;

        @ManyToOne Board board;
    }

    Board.java

    @Entity
    @Data
    public 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
Designed by Tistory.