Jumbo96 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
반응형