// websocket
// socket.io
// mqtt, xmpp
// SSE => Server send Events
@Slf4j
@RestController
public class RestSseController {
// 접속하는 클라이언트의 정보를 보관할 변수
private static final Map<String, SseEmitter> clients = new HashMap<>();
// 클라이언트 접속했을때 수행
@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;
}
// 클라이언트가 전송을 했을 때 수행
// {"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);
}
}
}
}
RestController폴더에 RestSseController.java를 생성한다.
@Slf4j
@Controller
public class ChatController {
@GetMapping(value="/chat.do")
public String chatGET() {
return "/chat";
}
}
Controller폴더에 ChatController.java도 생성한다.
<body>
<h3>chat</h3>
<div>
<input type="text" id="input"/>
<button id="send" onclick="sendMessage()">send</button>
<div id="messages" style="border:1px solid #cccccc;"></div>
</div>
<script>
// 고유한 아이디 만들기
const id = `ds200_${new Date().getTime()}`;
// 접속하기 => 내가전달한 아이디를 map에 변수에 보관(2분간)
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>
</body>
templates 폴더에 chat.html을 생성한다.
다른 곳에서 전송을 해도 전송한 값을 받아와 콘솔에 출력된다.
@Component
@Slf4j
@RequiredArgsConstructor
public class MyScheduler {
final Board1Repository board1Repository;
// cron tab
// 초, 분, 시간, 일, 월, 요일
// */5 * * * * * 5초 간격으로 동작
// */20 * * * * * 20초 간격
// 0 * * * * * 0초가 될 때마다 (1분 간격)
@Scheduled(cron = "*/5 * * * * *")
public void printDate(){
log.info("{}", new Date().toString());
List<Board1> list = board1Repository.findAll();
log.info("{}", list.toString());
}
}
scheduler 폴더를 생성하여 MyScheduler.java를 생성한다.
@EnableScheduling
@ComponentScan(basePackages = {
...
"com.example.scheduler" })
Boot20230427Application.java에 위 코드를 추가한다.
5초마다 board1Repository의 값이 출력된다.
// @Scheduled(cron = "*/5 * * * * *")
이렇게 주석처리를 하면 더이상 출력되지 않는다.