我正在尝试使用spring websocket与jhipster 5构建聊天应用程序。 这些是我创建和配置的文件:
后端:
// WebsocketConfiguration.java
hostNetwork: true
// ChatService.java
public static final String IP_ADDRESS = "IP_ADDRESS";
private final JHipsterProperties jHipsterProperties;
public WebsocketConfiguration(JHipsterProperties jHipsterProperties) {
this.jHipsterProperties = jHipsterProperties;
}
@Override
public void configureMessageBroker(MessageBrokerRegistry config) {
config.enableSimpleBroker("/topic", "/chat");
}
@Override
public void registerStompEndpoints(StompEndpointRegistry registry) {
String[] allowedOrigins = Optional.ofNullable(jHipsterProperties.getCors().getAllowedOrigins()).map(origins -> origins.toArray(new String[0])).orElse(new String[0]);
registry.addEndpoint("/websocket/tracker", "/websocket/chat")
.setHandshakeHandler(defaultHandshakeHandler())
.setAllowedOrigins(allowedOrigins)
.withSockJS()
.setInterceptors(httpSessionHandshakeInterceptor());
}
@Bean
public HandshakeInterceptor httpSessionHandshakeInterceptor() {
return new HandshakeInterceptor() {
@Override
public boolean beforeHandshake(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler wsHandler, Map<String, Object> attributes) throws Exception {
if (request instanceof ServletServerHttpRequest) {
ServletServerHttpRequest servletRequest = (ServletServerHttpRequest) request;
attributes.put(IP_ADDRESS, servletRequest.getRemoteAddress());
}
return true;
}
@Override
public void afterHandshake(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler wsHandler, Exception exception) {
}
};
}
private DefaultHandshakeHandler defaultHandshakeHandler() {
return new DefaultHandshakeHandler() {
@Override
protected Principal determineUser(ServerHttpRequest request, WebSocketHandler wsHandler, Map<String, Object> attributes) {
Principal principal = request.getPrincipal();
if (principal == null) {
Collection<SimpleGrantedAuthority> authorities = new ArrayList<>();
authorities.add(new SimpleGrantedAuthority(AuthoritiesConstants.ANONYMOUS));
principal = new AnonymousAuthenticationToken("WebsocketConfiguration", "anonymous", authorities);
}
return principal;
}
};
}
}
前端:
// chat.service.ts
private static final Logger log = LoggerFactory.getLogger(ChatService.class);
private DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
private final SimpMessageSendingOperations messagingTemplate;
public ChatService(SimpMessageSendingOperations messagingTemplate) {
this.messagingTemplate = messagingTemplate;
}
@SubscribeMapping("/chat/public")
public void subscribe(StompHeaderAccessor stompHeaderAccessor, Principal principal) {
String login =principal.getName();
String ipAddress = stompHeaderAccessor.getSessionAttributes().get(IP_ADDRESS).toString();
log.debug("User {} subscribed to Chat from IP {}", login, ipAddress);
MessageDTO messageDTO = new MessageDTO();
messageDTO.setUserLogin("System");
messageDTO.setTime(dateTimeFormatter.format(ZonedDateTime.now()));
messageDTO.setMessage(login + " joined the chat");
messagingTemplate.convertAndSend("/chat/public", messageDTO);
}
@MessageMapping("/chat")
@SendTo("/chat/public")
public MessageDTO sendChat(@Payload MessageDTO messageDTO, StompHeaderAccessor stompHeaderAccessor, Principal principal) {
messageDTO.setUserLogin(principal.getName());
return setupMessageDTO(messageDTO, stompHeaderAccessor, principal);
}
@Override
public void onApplicationEvent(SessionDisconnectEvent event) {
// when the user disconnects, send a message saying that hey are leaving
log.info("{} disconnected from the chat websockets", event.getUser().getName());
MessageDTO messageDTO = new MessageDTO();
messageDTO.setUserLogin("System");
messageDTO.setTime(dateTimeFormatter.format(ZonedDateTime.now()));
messageDTO.setMessage(event.getUser().getName() + " left the chat");
messagingTemplate.convertAndSend("/chat/public", messageDTO);
}
private MessageDTO setupMessageDTO (MessageDTO messageDTO, StompHeaderAccessor stompHeaderAccessor, Principal principal) {
messageDTO.setTime(dateTimeFormatter.format(ZonedDateTime.now()));
log.debug("Sending user chat data {}", messageDTO);
return messageDTO;
}
}
// chat.component.ts
constructor(
private router: Router,
private authServerProvider: AuthServerProvider,
private $document: Document,
private $window: Window,
private csrfService: CSRFService
) {
this.connection = this.createConnection();
this.listener = this.createListener();
}
connect() {
if (this.connectedPromise === null) {
this.connection = this.createConnection();
}
// building absolute path so that websocket doesnt fail when
deploying with a context path
const loc = this.$window.location;
let url = '//' + loc.host + loc.pathname + 'websocket/chat';
const authToken = this.authServerProvider.getToken();
if (authToken) {
url += '?access_token=' + authToken;
}
const socket = new SockJS(url);
this.stompClient = Stomp.over(socket);
const headers = {};
this.stompClient.connect(headers, () => {
this.connectedPromise('success');
this.connectedPromise = null;
this.subscribe();
if (!this.alreadyConnectedOnce) {
this.alreadyConnectedOnce = true;
}
});
}
disconnect() {
if (this.stompClient !== null) {
this.stompClient.disconnect();
this.stompClient = null;
}
if (this.subscription) {
this.subscription.unsubscribe();
this.subscription = null;
}
this.alreadyConnectedOnce = false;
}
receive() {
return this.listener;
}
sendMessage(message) {
if (this.stompClient !== null && this.stompClient.connected) {
this.stompClient.send(
'/chat', // destination
JSON.stringify({'message': message}), // body
{} // header
);
}
}
subscribe() {
this.connection.then(() => {
this.subscriber = this.stompClient.subscribe('/chat/public', data
=> {
this.listenerObserver.next(JSON.parse(data.body));
});
});
}
unsubscribe() {
if (this.subscriber !== null) {
this.subscriber.unsubscribe();
}
this.listener = this.createListener();
}
private createListener(): Observable<any> {
return new Observable(observer => {
this.listenerObserver = observer;
});
}
private createConnection(): Promise<any> {
return new Promise((resolve, reject) => this.connectedPromise =
resolve);
}
当我运行./mvnw或npm start时,出现空白页。我找不到问题。
这是我的控制台浏览器上的错误:
messages: Array<Object> = [];
message = '';
constructor(private chatService: ChatService) { }
ngOnInit() {
this.chatService.connect();
this.chatService.receive().subscribe(message => {
this.messages.push(message);
});
}
ngOnDestroy() {
this.chatService.unsubscribe();
}
sendMessage(message) {
if (message.length === 0) {
return;
}
this.chatService.sendMessage(message);
this.message = '';
}
这是我的mvnw错误:
ERROR Error: Uncaught (in promise): Error: StaticInjectorError(ChatFinalAppModule)[Document]:
StaticInjectorError(Platform: core)[Document]:
NullInjectorError: No provider for Document!
Error: StaticInjectorError(ChatFinalAppModule)[Document]:
StaticInjectorError(Platform: core)[Document]:
NullInjectorError: No provider for Document!
at NullInjector.get (core.js?09c9:8894)
at resolveToken (core.js?09c9:9139)
at tryResolveToken (core.js?09c9:9083)
at StaticInjector.get (core.js?09c9:8980)
at resolveToken (core.js?09c9:9139)
at tryResolveToken (core.js?09c9:9083)
at StaticInjector.get (core.js?09c9:8980)
at resolveNgModuleDep (core.js?09c9:21119)
at NgModuleRef_.get (core.js?09c9:21808)
at injectInjectorOnly (core.js?09c9:1772)
at resolvePromise (zone.js?d135:831)
at resolvePromise (zone.js?d135:788)
at eval (zone.js?d135:892)
at ZoneDelegate.invokeTask (zone.js?d135:423)
at Object.onInvokeTask (core.js?09c9:17279)
at ZoneDelegate.invokeTask (zone.js?d135:422)
at Zone.runTask (zone.js?d135:195)
at drainMicroTaskQueue (zone.js?d135:601)
at ZoneTask.invokeTask (zone.js?d135:502)
at ZoneTask.invoke (zone.js?d135:487)
这是我使用管理员帐户登录时的mvn日志:
2019-04-28 23:28:43.153 DEBUG 12652 --- [ XNIO-2 task-2] c.p.a.aop.logging.LoggingAspect : Enter: com.pu.askanexpert.repository.CustomAuditEventRepository.add() with argument[s] = [AuditEvent [timestamp=2019-04-28T21:28:43.136Z, principal=anonymousUser, type=AUTHORIZATION_FAILURE, data={details=org.springframework.security.web.authentication.WebAuthenticationDetails@957e: RemoteIpAddress: 127.0.0.1; SessionId: null, type=org.springframework.security.access.AccessDeniedException, message=Access is denied}]]
2019-04-28 23:28:43.163 DEBUG 12652 --- [ XNIO-2 task-2] c.p.a.aop.logging.LoggingAspect : Exit: com.pu.askanexpert.repository.CustomAuditEventRepository.add() with result = null
2019-04-28 23:28:43.179 WARN 12652 --- [ XNIO-2 task-2] o.z.problem.spring.common.AdviceTrait : Unauthorized: Full authentication is required to access this resource
2019-04-28 23:28:43.294 WARN 12652 --- [ XNIO-2 task-2] .m.m.a.ExceptionHandlerExceptionResolver : Resolved exception caused by handler execution: org.springframework.security.authentication.InsufficientAuthenticationException: Full authentication is required to access this resource