빅데이터 Java 개발자 교육 (Spring - 채팅(+JS기본) 및 스케쥴링)]

Jun_Gyu·2023년 5월 18일
0
post-thumbnail

금일 수업에서는 실시간 채팅 기능과 스케쥴링을 활성화해보도록 하겠다.

채팅

먼저 채팅을 위한 서버 클라이언트를 설정해보도록 하겠다.

서버는 채팅 환경에 알맞도록 실시간 적용이 가능한 Rest 방식의 컨트롤러를 이용했다.

RestSseController

ⓐ 클라이언트 접속시 수행

/* ---------- 클라이언트 접속했을때 수행 ---------- */
    @GetMapping(value="/api/sse/subscribe")
    public SseEmitter subscribe( @RequestParam(name="id") String id) {
        // sse 객체 생성
        SseEmitter emitter = new SseEmitter( 1000L * 1200 ); //20분 동안 접속 유지
        clients.put(id, emitter);

        // 클라이언트 연결 중지 및 완료 되면 clients변수에서 정보 제거
        emitter.onTimeout(() ->  clients.remove(id));
        emitter.onCompletion(() ->  clients.remove(id));

        return emitter;
    }

클라이언트에 접속하게되면 접속을 20분동안 유지할 수 있도록 Ssemitter의 시간을 설정해두었으며,

이용자와 클라이언트의 연결이 중지되면 클라이언트 변수에서 이용자의 id값이 삭제되도록 했다.

ⓑ 클라이언트 전송시 수행

/* ---------- 클라이언트가 전송을 했을 때 수행 ---------- */
    // {"ret":1, "abc":"def"}
    @GetMapping(value="/api/sse/publish")
    public void publish(@RequestParam(name="message") String message) {
        // map에 보관된 개수만큼 반복하면 키값을 꺼냄
        for (String id : clients.keySet()) {
            try {
                // map의 키를 이용해서 value값을 꺼냄
                SseEmitter emitter = clients.get(id);

                // 클라이언트로 메시지 전송
                emitter.send(message, MediaType.APPLICATION_JSON);
            }
            catch(Exception e) {
                clients.remove(id);
            }
        }
    }

위의 메소드에서 클라이언트에 유저의 아이디를 저장했다면, 이번에는 클라이언트에 저장된 id값을 불러온 뒤 해당 아이디의 메세지들을 전송하는 방식이다.

위와같이 클라이언트를 설정해 준 뒤, 간단하게 컨트롤러를 생성해준 뒤, 템플릿을 만들어보겠다.

@Controller
public class ChatController {

    // http://127.0.0.1:9090/ROOT/chat.do
    @GetMapping(value = "/chat.do")
    public String chatGET() {
        return "/chat";
    }
}

(진짜 간단히 만들었음.)


chat.html

<div>
   <input type="text" id="input" />
   <button id="send" onclick="sendMessage()">send</button>
   <div id="messages" style="border:1px solid #cccccc;"></div>
</div>

채팅기능을 확인하기 위한 와이어프레임을 먼저 만들고,

전송버튼을 누르면 이전에 만들어둔 클라이언트 메소드를 이용하여 클라이언트로 데이터를 전송할 수 있도록 <script>를 생성해보도록 하겠다.

<script>
    // 고유한 아이디 만들기
    const id = `ds209_${new Date().getTime()}`;
        
    // 접속하기 => 내가 전달한 아이디를 map에 변수에 보관하기 (20분)
    const eventSource = new EventSource(`/ROOT/api/sse/subscribe?id=${id}`);

    // callback1
    eventSource.onopen = (e) => {
        console.log('onopen', e);
    };

    // callback2
    eventSource.onmessage = (e) => {
        const div = document.querySelector('#messages');
        div.innerHTML = `${e.data}<br />` + div.innerHTML;
        console.log('onmessage', e.data);
    };

    // callback3
    eventSource.onerror = (e) => {
        console.log('onerror', e);
    };

    const sendMessage = () => {
    	const msg = document.querySelector('#input').value; 
        fetch(`/ROOT/api/sse/publish?message=${msg}`); // 메시지 보내기
    };
</script>

클라이언트에 저장하기 위한 id값은 임의로 시간을 부여했다. (계속 바뀌기때문에 테스트할때마다 바꿀 필요가 없다 ㅎㅎ)

전송 버튼을 클릭하면 자바 스크립트의 sendMessage() 객체를 통해 메세지가 전송되는 방식이다.

크롬에서 실행 후, 개발자모드를 켜 log 기록을 확인해보면 채팅 메세지가 클라이언트와 상호작용이 잘 이루어짐을 볼 수 있다.


여기서 가물가물하기 전 JS의 기본적인 문법에 대해서 간단하게 메모해두고 넘어가도록 하겠다.

JavaScript 문법

 const str = "hello";
 const a = "aa" + str + "aa"; // aahelloaa
 const b = `aa${str}aa`; // aahelloaa
        
함수 생성 방법
const constName = () => {
}

function functionName() {
}

// 위 둘다 동일한 기능이지만, 현재 const방식을 많이 사용하는 상황.

스케쥴링

스케쥴링이라함은 간단히 말해서 약속된 시간에 작업이 수행되도록 하는 기능이다.

스케쥴링을 사용하는 실생활의 예시로는 매일 새벽 12시경 은행별로 ATM기기 점검이 이루어지는 것을 예로 들 수 있다.

이러한 스케쥴링 기능을 사용하는것에 대해서 간략하게나마 필기를 해두고 넘어가고자 한다.

MyScheduler.java

@Slf4j
@Component
@RequiredArgsConstructor
public class MyScheduler {

    final Board1Repository board1Repository;

    // cron tap
    // 초, 분, 시간, 일, 월, 요일
    // */5 * * * * * 5초 간격으로 동작
    // ex) */20 * * * * * 20초 간격동작 
    // ex) (0 * * * * *) 0 초가 될때 1분간격
    
    @Scheduled(cron = "*/5 * * * * *") 
    // 사용시 application에 @EnableScheduling 어노테이션 추가할 것 
    public void printDate() {
        log.info("{}", new Date().toString());

        List<Board1> list = board1Repository.findAll();
        log.info("{}", list.toString());
        
    }
    
}

스케쥴러의 경우에는 컨트롤러, 서비스, 매퍼 등 과는 별개의 다른 기능이기에
@Component 어노테이션을 사용해주었다.

스케쥴러를 원하는 시간에 동작하기 위해서는 cron tap에 대해 검색하여 좀 더 자세히 다루어보아야 한다.

위의 경우에는 간략한 몇가지의 예시만을 정리했다.

Board1Repository를 불러와 List 방식으로 전체를 조회했는데,

실제로 터미널의 로그에 초 간격으로 계속해서 표시가 된다.


추가적으로 , application.java에 스케쥴링 어노테이션을 추가해주어야 한다!

profile
시작은 미약하지만, 그 끝은 창대하리라

0개의 댓글