Spring WebSocket @SendToSession: 특정 세션으로 메시지 보내기
특정 세션에 메시지를 보낼 수 있습니까?
클라이언트와 Spring 서블릿 간에 인증되지 않은 웹 소켓이 있습니다.비동기 작업이 종료되면 특정 연결로 요청되지 않은 메시지를 보내야 합니다.
@Controller
public class WebsocketTest {
@Autowired
public SimpMessageSendingOperations messagingTemplate;
ExecutorService executor = Executors.newSingleThreadExecutor();
@MessageMapping("/start")
public void start(SimpMessageHeaderAccessor accessor) throws Exception {
String applicantId=accessor.getSessionId();
executor.submit(() -> {
//... slow job
jobEnd(applicantId);
});
}
public void jobEnd(String sessionId){
messagingTemplate.convertAndSend("/queue/jobend"); //how to send only to that session?
}
}
이 코드에서 볼 수 있듯이 클라이언트는 비동기 작업을 시작할 수 있으며 작업이 완료되면 종료 메시지가 필요합니다.분명히, 저는 지원자에게만 메시지를 보내야 하고 모든 사람에게 방송을 하면 안 됩니다.당신과 함께라면 정말 좋을 것입니다.@SendToSession주석 또는messagingTemplate.convertAndSendToSession방법.
갱신하다
시도해 봤습니다.
messagingTemplate.convertAndSend("/queue/jobend", true, Collections.singletonMap(SimpMessageHeaderAccessor.SESSION_ID_HEADER, sessionId));
그러나 지정된 세션뿐만 아니라 모든 세션으로 브로드캐스트됩니다.
업데이트 2
convertAndSendToUser() 메서드를 사용하여 테스트합니다.이 테스트는 공식적인 봄 튜토리얼의 해킹입니다. https://spring.io/guides/gs/messaging-stomp-websocket/
다음은 서버 코드입니다.
@Controller
public class WebsocketTest {
@PostConstruct
public void init(){
ScheduledExecutorService statusTimerExecutor=Executors.newSingleThreadScheduledExecutor();
statusTimerExecutor.scheduleAtFixedRate(new Runnable() {
@Override
public void run() {
messagingTemplate.convertAndSendToUser("1","/queue/test", new Return("test"));
}
}, 5000,5000, TimeUnit.MILLISECONDS);
}
@Autowired
public SimpMessageSendingOperations messagingTemplate;
}
다음은 클라이언트 코드입니다.
function connect() {
var socket = new WebSocket('ws://localhost:8080/hello');
stompClient = Stomp.over(socket);
stompClient.connect({}, function(frame) {
setConnected(true);
console.log('Connected: ' + frame);
stompClient.subscribe('/user/queue/test', function(greeting){
console.log(JSON.parse(greeting.body));
});
});
}
유감스럽게도 클라이언트는 예상대로 5000ms마다 세션별 회신을 받지 못합니다."1"은 연결된 두 번째 클라이언트에 유효한 sessionId입니다. 디버그 모드에서 볼 수 있기 때문입니다.SimpMessageHeaderAccessor.getSessionId()
배경 시나리오
원격 작업에 대한 진행률 표시줄을 만들고 싶습니다. 클라이언트가 서버에 비동기 작업을 요청하고 서버에서 보낸 웹 소켓 메시지로 진행률을 확인합니다.이것은 파일 업로드가 아니라 원격 계산이므로 서버만 각 작업의 진행 상황을 알 수 있습니다.각 작업이 세션별로 시작되기 때문에 특정 세션에 메시지를 보내야 합니다.클라이언트에서 원격 계산 서버가 이 작업을 시작하도록 요청하고 모든 작업 단계에 대해 작업 진행 상태가 표시된 지원자 클라이언트에 회신합니다.클라이언트는 작업에 대한 메시지를 받고 진행률/상태 표시줄을 작성합니다.이것이 제가 세션별 메시지가 필요한 이유입니다.사용자별 메시지를 사용할 수도 있지만 Spring은 사용자별로 요청되지 않은 메시지를 제공하지 않습니다. (Spring Websocket으로 사용자 메시지를 보낼 수 없음)
작동 솔루션
__ __ ___ ___ _ __ ___ _ _ ___ ___ ___ _ _ _ _____ ___ ___ _ _
\ \ / // _ \ | _ \| |/ /|_ _|| \| | / __| / __| / _ \ | | | | | ||_ _||_ _|/ _ \ | \| |
\ \/\/ /| (_) || /| ' < | | | .` || (_ | \__ \| (_) || |__| |_| | | | | || (_) || .` |
\_/\_/ \___/ |_|_\|_|\_\|___||_|\_| \___| |___/ \___/ |____|\___/ |_| |___|\___/ |_|\_|
UPDATE2 솔루션부터 마지막 매개 변수(메시지)로 convertAndSendToUser 메서드를 완료해야 했습니다.머리글):
messagingTemplate.convertAndSendToUser("1","/queue/test", new Return("test"), createHeaders("1"));
어디에createHeaders()다음 방법입니다.
private MessageHeaders createHeaders(String sessionId) {
SimpMessageHeaderAccessor headerAccessor = SimpMessageHeaderAccessor.create(SimpMessageType.MESSAGE);
headerAccessor.setSessionId(sessionId);
headerAccessor.setLeaveMutable(true);
return headerAccessor.getMessageHeaders();
}
특정 목적지를 생성할 필요가 없으며, 봄 4.1부터 이미 즉시 사용할 수 있습니다(SPR-11309 참조).
는 "지된사는자용정"에합니다./user/queue/something은 다음과 같은 수 .
SimpMessageSendingOperations Javaadoc에 명시된 바와 같이 사용자 이름이 실제로 sessionId이기 때문에 그렇지 않으면 헤더로도 설정해야 합니다.DefaultUserDestinationResolver메시지를 라우트할 수 없으며 메시지를 삭제합니다.
SimpMessageHeaderAccessor headerAccessor = SimpMessageHeaderAccessor
.create(SimpMessageType.MESSAGE);
headerAccessor.setSessionId(sessionId);
headerAccessor.setLeaveMutable(true);
messagingTemplate.convertAndSendToUser(sessionId,"/queue/something", payload,
headerAccessor.getMessageHeaders());
사용자를 인증할 필요가 없습니다.
그것은 매우 복잡하고 제 생각에는 그럴 가치가 없습니다.인증되지 않은 사용자라도 세션 ID를 기준으로 모든 사용자에 대한 헤드라인 등록해야 합니다.
모든 사용자가 자신의 고유 대기열에만 가입한다고 가정해 보겠습니다.
stompClient.subscribe('/session/specific' + uuid, handler);
서버에서 사용자가 등록하기 전에 특정 세션에 대해 통지하고 메시지를 발송한 후 지도에 저장해야 합니다.
@MessageMapping("/putAnonymousSession/{sessionId}")
public void start(@DestinationVariable sessionId) throws Exception {
anonymousUserSession.put(key, sessionId);
}
그런 다음 사용자에게 메시지를 보내려면 다음 작업을 수행해야 합니다.
messagingTemplate.convertAndSend("/session/specific" + key);
하지만 저는 당신이 무엇을 하려고 하는지, 그리고 어떻게 특정 세션(익명인)을 찾을지 잘 모르겠습니다.
세션 ID를 다음에 추가하기만 하면 됩니다.
서버측
convertAndSendToUser(sessionId,apiName,responseObject);
클라이언트 측
$stopp.subscribe('/user/+sessionId+'/apiName', 처리기);
참조:
추가하는 것을 잊지 마십시오.'/user'서버 측의 엔드포인트에 있습니다.
저는 같은 문제로 어려움을 겪고 있었지만 제시된 해결책이 저에게 효과가 없었기 때문에 다른 접근 방식을 취해야 했습니다.
- 사용자가 세션 ID로 식별되도록 웹 소켓 구성을 수정합니다.
@Override
public void registerStompEndpoints(StompEndpointRegistry registry) {
registry.addEndpoint("/ws-endpoint")
.setHandshakeHandler(new DefaultHandshakeHandler() {
@Override
protected Principal determineUser(ServerHttpRequest request, WebSocketHandler wsHandler, Map<String, Object> attributes) {
if (request instanceof ServletServerHttpRequest) {
ServletServerHttpRequest servletRequest = (ServletServerHttpRequest) request;
HttpSession session = servletRequest.getServletRequest().getSession();
return new Principal() {
@Override
public String getName() {
return session.getId();
}
};
} else {
return null;
}
}
}).withSockJS();
}
- 해당 세션 ID로 메시지 보내기(헤더 없음):
simpMessagingTemplate.convertAndSendToUser(sessionId, "/queue", payload);
가장 간단한 방법은 @SendToUser의 브로드캐스트 매개 변수를 활용하는 것입니다.문서:
메시지를 사용자와 관련된 모든 세션으로 보낼 것인지, 처리 중인 입력 메시지의 세션으로만 보낼 것인지 여부.기본적으로 이 값은 true로 설정되어 있으며, 이 경우 메시지는 모든 세션에 브로드캐스트됩니다.
당신의 정확한 경우에는 이렇게 보일 것입니다.
@MessageMapping("/start")
@SendToUser(value = "/queue/jobend", broadcast = false)
//...
언급URL : https://stackoverflow.com/questions/34929578/spring-websocket-sendtosession-send-message-to-specific-session
'codememo' 카테고리의 다른 글
| 뷰의 절대 위치 설정 (0) | 2023.08.26 |
|---|---|
| VBA가 자동으로 변경됩니다.범위는 .range입니다. (0) | 2023.08.26 |
| 도커와 도커 구성의 차이점은 무엇입니까? (0) | 2023.08.26 |
| jQuery AJAX는 해서는 안 될 304개의 응답을 생성합니다. (0) | 2023.08.26 |
| Angular 5 반응형 - 라디오 버튼 그룹 (0) | 2023.08.26 |