이전 게시글 프로젝트 3 엔티티, 비밀번호 암호화
[스프링 부트] 프로젝트 3 엔티티, 로그인 (비밀번호 암호화)
이전 게시글 프로젝트 2 프론트엔드 구현 https://hoozy.tistory.com/entry/%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-2-%ED%94%84%EB%A1%A0%ED%8A%B8%EC%97%94%EB%93%9C-%EA%B5%AC%ED%98%84 테이블과 매칭된 엔티티를 생성. 회원가입할 때
hoozy.tistory.com
Application
- @RequiredArgsConstructor : final 의 생성자를 자동으로 생성해줘서 @Autowired 사용 없이 의존성 주입 가능하게 하는 어노테이션
자바의 @Scheduled
@Scheduled
어노테이션은 프로젝트 Application에@EnableScheduling
어노테이션을 추가해야 합니다.- 옵션이 fixedRate, fixedDelay, cron 세 가지가 있지만, 여기서는 cron 만 알아보겠습니다.
@Scheduled(cron = "0 0 0 * * *")
형태로 쓰며, 왼쪽부터 초 분 시간 일 월 요일 순으로 넣을 수 있다.- 위 이미지는 매일 모든요일 00시 0분 0초 마다 반복한다는 의미를 지닌다.
- 위의 이미지는 스케쥴러로 매일 오늘의 문제를 랜덤으로 생성해서 today 테이블로 넣는 과정이다.
아래에는 Controller만 설명했습니다. 자세한 코드는 github에 올려놓았습니다.
홈페이지
HomeController
- loggedInUsers 는 서버의 세션들의 리스트이다. -> 나중에 따로 자세하게 설명하겠습니다.
- 타임리프 form 의 th:object 에 user를 사용하려면 model에 user의 빈 객체를 생성해서 보내줘야 user를 인식해서 에러가 안난다.
- 세션에서 loginUser의 해당하는 세션들을 가져와서 로그인 한 유저들의 리스트를 뽑아서 보내준다.
- 주석은 application의 오늘의 문제 생성 코드와 같으며, DB를 처음 생성했을때만 쓰는 코드이다.
- 아래 list는 today 테이블에서 오늘의 문제 카테고리 별 3문제씩 리스트를 가져와서 넣고, 보내준다.
지식 페이지
KnowController
- know 테이블에서 카테고리 별 모든 지식의 이름만 가져와서 보내기. -> 이름 클릭 시 ajax로 정보 보이게 구현.
- check 가 1 일 때에는, 좋아요 추가 -> 좋아요 원래 값 + 1 로 update. check 가 0 일 때에는, 좋아요 제거. -> 좋아요 원래 값 - 1 로 update.
- 문제 바꾸기는 만약 no3이 0 이면 현재 카테고리의 문제가 2개이기 때문에 주관식 문제로 인식하고 현재 바꾸기를 클릭한 카테고리 문제 2개 번호를 가져와 2개 번호를 제외한 같은 카테고리 중의 랜덤 문제를 한 개 가져온다. no3 이 0 이아니면 단답형으로 인식하고 같은 방식으로 랜덤으로 문제를 가져온다.
ReplyController
- 지식의 번호로 지식의 댓글을 모두 가져와서 ajax로 보내는 메소드.
- 모댓글 작성 메소드는 지식 번호와 내용을 가져와서 no는 마지막 auto_increment 번호를 가져와서 + 1 해서 넣어주고, 넣은 댓글 정보를 가져온다.
- 답글은 현재 지식 번호와 모댓글의 번호, 내용을 가져와서 repn에 모댓글 번호를 넣고, 레벨을 1로 만들고, repo는 모댓글의 답글 중 순서여서 현재 모댓글의 번호를 가지고 답글의 개수를 가져와서 + 1 해서 넣는다.
- 수정은 현재 댓글 번호와 내용을 가져와서 바꾼 후 보내준다.
- 모댓글의 번호인 repn에 현재 모댓글의 번호를 넣어서 답글 리스트를 list에 넣고 보내준다.
문제(단답형) 페이지
ProbController
- 홈페이지의 코드와 같다. -> 프론트의 코드만 다름.
문제(주관식) 페이지
ProbController
- 주관식 문제에는 테이블 형식 문제가 있어서 만약 랜덤으로 가져온 2개의 문제 중에서 추가 정보가 있는 know 의 번호가 있을 때 이 번호로 addi 테이블에서 추가 정보들을 가져와서 프론트로 보내준다.
- 이때 프론트에서 가져오기 위해 addiList에 카테고리 상관없이 넣는다. -> 카테고리 나누어서는 하기 힘들어서 카테고리 없이 가져가서 프론트에서 문제 번호로만 가져오도록 설계했습니다.
오픈 채팅 페이지
RoomController
- form 태그의
th:field
에 객체를 넣으려면 빈 객체를 넣어서 가야하기 때문에, 빈 객체를 넣고, 현재 room 테이블의 모든 채팅방을 가져와서 보내준다. - 채팅방 검색과 채팅방 생성은 ajax로 보내준다.
- get 메소드는 roomid로 room 정보 가져오는 메소드이다.
- delete 메소드는 room을 삭제하는데 이 때 이 채팅방의 채팅들을 다 삭제해야 한다.
- 테이블의 값을 삭제할 때 참조하는 테이블이 있으면 참조하는 테이블 값까지 삭제해야 db 공간을 절약할 수 있다.
채팅을 알아보기 전에 웹소켓과 STOMP를 먼저 알아보자
웹소켓(WebSocket)이란,
- 클라이언트가 HTTP 프로토콜을 통해 서버로 요청을 보내야 응답을 받을 수 있기 때문에, 이를 해결하기 위해 서버와 클라이언트 사이에 양방향 소통이 가능하게 개발된 프로토콜이다. 일반 Socket 통신과 달리 HTTP 80 Port를 사용하므로 방화벽에 제약이 없다. 접속까지는 HTTP 프로토콜을 이용하고, 그 이후 통신은 자체적인 웹소켓 프로토콜로 통신한다.
웹소켓 작동원리
- 서버와 클라이언트간의 웹소켓 연결은 HTTP 프로토콜을 기반으로 이루어지고, 성공적으로 이루어지면, 서로 간에 웹소켓 연결(TCP/IP 기반)이 이루어지고 일정 시간 이후에 HTTP 연결은 자동으로 끊어진다.
- 클라이언트에서 서버로 TCP/IP 접속 요청
- 서버가 TCP/IP 접속 수락
- 클라이언트에서 서버로 웹소켓 열기(핸드쉐이크) 요청
- 서버가 웹소켓 열기 수락
- 서로 간의 웹소켓 데이터 송,수신
STOMP
- Simple Text Oriented Messaging Protocol의 약자로, 메시징 전송을 효율적으로 하기 위해 만들어진 프로토콜이다.
- 기본적으로 pub / sub 구조로 되어있어, 메시지를 전송하고 메시지를 받아 처리하는 부분이 확실히 정해져 있어서 개발자 입장에서 명확하게 인지하고 개발이 용이하다.
- 정리하면, 웹소켓 위에서 동작하는 프로토콜로서 클라이언트와 서버가 전송할 메시지의 유형, 형식, 내용들을 정의하는 매커니즘이다.
ChatConfig
- 웹소켓과 sockjs를 사용하려면 gradle에 추가해야 한다.
- 스프링에서 지원하는 stomp를 사용하려면
@EnableWebSocketMessageBroker
어노테이션을 붙인 후,WebSocketMessageBrokerConfigurer
인터페이스를 구현한다. registerStompEndPoints
메소드는 클라이언트에서 서버의 웹소켓에 연결할 때 API경로를 /ws/chat를 경로로 설정해준다는 의미이다.setAllowedOriginPatterns
는 CORS 정책에 의해 origin이 다를 때 리소스 교환을 못할 때 origin을 *로 전체로 설정해서 url이 어디든 리소스를 교환할 수 있다는 의미이다.- CORS : 보안 목적으로 클라이언트와 서버의 origin(서버의 기본 url 주소와 포트까지의 주소)이 같을 때 리소스를 공유할 수 있다는 정책이다.
configureMessageBroker
메소드의enableSimpleBroker
는 채팅방 구독(.subscribe)할 때 메시지 브로커를/queue, /topic
으로 설정한다는 의미이다.- /queue : 1:1 교환할 때 사용. -> 1대1 채팅일 때
- /topic : 1:N 교환할 때 사용. -> 채팅방 전체 메시지
setApplicationDestinationPrefixes
는 위와 아래 예시에서는 mapping 앞에 /app을 붙여서/app/chat/join
으로 메시지를 .send 했을 때 ChatController의 join 메소드에 전달된다.
ChatController
- join 메소드에서 클라이언트에서 .send로 메시지에 정보를 담아서 보내면, 룸 id를 가져와서 채팅방 정보를 가져오고, 채팅방의 최근 5개의 채팅 정보를 가져와서 '/'로 구분하여 문자열로 만든 후 먼저 넘겨주고, 환영 메시지를 마지막에 전송해준다.
- FIRST 타입은 기존 DB에 있는 최근 채팅 5개 타입이고, JOIN 타입은 구독자가 들어올 때만 나오는 환영 메시지 타입이다.
SimpMessagingTemplate
객체에서convertAndSend
메소드는/topic/chat/room+roomid
채팅방에 구독한 구독자에게 전체 메시지인 chat을 보내는 것이다.
- leave 메소드는 구독자가 나갈 때에만 메시지 타입인 LEAVE 타입의 chat을 /topic으로 보내준다.
- message 메소드는 구독자가 메시지를 보내면 그 메시지의 내용과 작성자를 받고, /topic으로 보내주고, create 메소드로 현재 시간을 입력해서 DB에 저장한다.
기타
LoggedInUsersListener
- 현재 서버의 들어가 있는 로그인 세션 리스트 가져오는 클래스 ->
HttpSessionLister
인터페이스를 구현해야 한다. - 로그인 할 때마다 서버의 세션 목록에 로그인 세션 넣기
- 로그아웃 할 때마다 서버의 세션 목록에서 로그인 세션 제거하기
- 사용법은 각 컨트롤러처럼 sessions의 session에서
getAttribute("로그인 세션 이름");
으로 가져와서 User 객체의 리스트로 넣어서 보내면 된다.
ImageController
- 서버 외부의 로컬(현재 서버가 있는 컴퓨터) 폴더에 이미지를 저장했기 때문에, 외부에서 로컬에 접근하는 대신 img 태그의 src 속성 내부의
/upload/images?file=파일이름
로 접근했을 때 파일 명을 받아서 로컬 이미지 폴더의 파일이름에 해당하는 이미지를 파일 스트림을 사용해 바이트로 가져와서 저장한다. - 이후 이미지의 바이트 배열을 읽어서
ByteArrayOutPutStream
에 저장 후 이baos
에 저장된 바이트 배열을fileArray
배열에 저장해 rest api로 반환해 img 태그에 이미지가 뜨게 하는 컨트롤러이다.
다음 게시글 프로젝트 5 S3 관련 설정 추가
[스프링 부트] 프로젝트 5 S3 관련 설정 추가
이전 게시글 프로젝트 4 백엔드 구현 https://hoozy.tistory.com/entry/%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-4-%EB%B0%B1%EC%97%94%EB%93%9C-%EA%B5%AC%ED%98%84 회원의 프로필 사진을 EC2 인스턴스에서 업로드 하고 다운로드 하기
hoozy.tistory.com
참고 자료
https://dev-gorany.tistory.com/212
https://dev-gorany.tistory.com/235
'Spring Boot (프로젝트)' 카테고리의 다른 글
[스프링 부트] 프로젝트 5 S3 관련 설정 추가 (0) | 2023.04.17 |
---|---|
[스프링 부트] EC2 인스턴스에 스프링부트, MySQL, S3, 도커 연결(아마존 리눅스 2) (0) | 2023.04.16 |
[스프링 부트] 프로젝트 3 엔티티, 로그인 (비밀번호 암호화) (0) | 2023.03.12 |
[스프링 부트] 프로젝트 2 프론트엔드 구현 (0) | 2023.03.10 |
프로젝트 1 설정 (Spring Boot, MySQL) (0) | 2023.03.08 |
댓글