Simplify project structure

- harmonize module and directory names
- optimize Gradle settings
- remove unused Grails sample

Resolves: #1447
This commit is contained in:
Vedran Pavic
2019-06-04 23:08:08 +02:00
parent a4ff3682f6
commit 084d1c7286
269 changed files with 17 additions and 858 deletions

View File

@@ -0,0 +1,31 @@
/*
* Copyright 2014-2017 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package sample;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
/**
* @author Rob Winch
*/
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}

View File

@@ -0,0 +1,31 @@
/*
* Copyright 2014-2017 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package sample.config;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration
public class WebMvcConfig implements WebMvcConfigurer {
@Override
public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("/").setViewName("index");
}
}

View File

@@ -0,0 +1,65 @@
/*
* Copyright 2014-2018 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package sample.config;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.security.servlet.PathRequest;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
@Configuration
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
// @formatter:off
@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth,
UserDetailsService userDetailsService) throws Exception {
auth
.userDetailsService(userDetailsService)
.passwordEncoder(new BCryptPasswordEncoder());
}
// @formatter:on
// @formatter:off
@Override
public void configure(WebSecurity web) {
web
.ignoring().requestMatchers(PathRequest.toH2Console());
}
// @formatter:on
// @formatter:off
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.requestMatchers(PathRequest.toStaticResources().atCommonLocations()).permitAll()
.anyRequest().authenticated()
.and()
.formLogin()
.permitAll();
}
// @formatter:on
}

View File

@@ -0,0 +1,45 @@
/*
* Copyright 2014-2017 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package sample.config;
import org.springframework.context.annotation.Configuration;
import org.springframework.messaging.simp.config.MessageBrokerRegistry;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.session.Session;
import org.springframework.session.web.socket.config.annotation.AbstractSessionWebSocketMessageBrokerConfigurer;
import org.springframework.web.socket.config.annotation.EnableWebSocketMessageBroker;
import org.springframework.web.socket.config.annotation.StompEndpointRegistry;
// tag::class[]
@Configuration
@EnableScheduling
@EnableWebSocketMessageBroker
public class WebSocketConfig
extends AbstractSessionWebSocketMessageBrokerConfigurer<Session> { // <1>
@Override
protected void configureStompEndpoints(StompEndpointRegistry registry) { // <2>
registry.addEndpoint("/messages").withSockJS();
}
@Override
public void configureMessageBroker(MessageBrokerRegistry registry) {
registry.enableSimpleBroker("/queue/", "/topic/");
registry.setApplicationDestinationPrefixes("/app");
}
}
// end::class[]

View File

@@ -0,0 +1,50 @@
/*
* Copyright 2014-2017 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package sample.config;
import sample.data.ActiveWebSocketUserRepository;
import sample.websocket.WebSocketConnectHandler;
import sample.websocket.WebSocketDisconnectHandler;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.messaging.simp.SimpMessageSendingOperations;
import org.springframework.session.Session;
/**
* These handlers are separated from WebSocketConfig because they are specific to this
* application and do not demonstrate a typical Spring Session setup.
*
* @author Rob Winch
*/
@Configuration
public class WebSocketHandlersConfig<S extends Session> {
@Bean
public WebSocketConnectHandler<S> webSocketConnectHandler(
SimpMessageSendingOperations messagingTemplate,
ActiveWebSocketUserRepository repository) {
return new WebSocketConnectHandler<>(messagingTemplate, repository);
}
@Bean
public WebSocketDisconnectHandler<S> webSocketDisconnectHandler(
SimpMessageSendingOperations messagingTemplate,
ActiveWebSocketUserRepository repository) {
return new WebSocketDisconnectHandler<>(messagingTemplate, repository);
}
}

View File

@@ -0,0 +1,39 @@
/*
* Copyright 2014-2016 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package sample.config;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.messaging.MessageSecurityMetadataSourceRegistry;
import org.springframework.security.config.annotation.web.socket.AbstractSecurityWebSocketMessageBrokerConfigurer;
/**
* @author Rob Winch
*/
@Configuration
public class WebSocketSecurityConfig
extends AbstractSecurityWebSocketMessageBrokerConfigurer {
// @formatter:off
@Override
protected void configureInbound(MessageSecurityMetadataSourceRegistry messages) {
messages
.simpMessageDestMatchers("/queue/**", "/topic/**").denyAll()
.simpSubscribeDestMatchers("/queue/**/*-user*", "/topic/**/*-user*").denyAll()
.anyMessage().authenticated();
}
// @formatter:on
}

View File

@@ -0,0 +1,59 @@
/*
* Copyright 2014-2016 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package sample.data;
import java.util.Calendar;
import javax.persistence.Entity;
import javax.persistence.Id;
@Entity
public class ActiveWebSocketUser {
@Id
private String id;
private String username;
private Calendar connectionTime;
public ActiveWebSocketUser() {
}
public ActiveWebSocketUser(String id, String username, Calendar connectionTime) {
super();
this.id = id;
this.username = username;
this.connectionTime = connectionTime;
}
public String getUsername() {
return this.username;
}
public void setUsername(String username) {
this.username = username;
}
public Calendar getConnectionTime() {
return this.connectionTime;
}
public void setConnectionTime(Calendar connectionTime) {
this.connectionTime = connectionTime;
}
}

View File

@@ -0,0 +1,29 @@
/*
* Copyright 2014-2016 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package sample.data;
import java.util.List;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.CrudRepository;
public interface ActiveWebSocketUserRepository
extends CrudRepository<ActiveWebSocketUser, String> {
@Query("select DISTINCT(u.username) from ActiveWebSocketUser u where u.username != ?#{principal?.username}")
List<String> findAllActiveUsers();
}

View File

@@ -0,0 +1,62 @@
/*
* Copyright 2014-2016 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package sample.data;
import java.util.Calendar;
public class InstantMessage {
private String to;
private String from;
private String message;
private Calendar created = Calendar.getInstance();
public String getTo() {
return this.to;
}
public void setTo(String to) {
this.to = to;
}
public String getFrom() {
return this.from;
}
public void setFrom(String from) {
this.from = from;
}
public String getMessage() {
return this.message;
}
public void setMessage(String message) {
this.message = message;
}
public Calendar getCreated() {
return this.created;
}
public void setCreated(Calendar created) {
this.created = created;
}
}

View File

@@ -0,0 +1,114 @@
/*
* Copyright 2014-2017 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package sample.data;
import java.io.Serializable;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.validation.constraints.Email;
import javax.validation.constraints.NotEmpty;
import org.springframework.security.crypto.password.PasswordEncoder;
/**
* Represents a user in our system.
*
* <p>
* In a real system use {@link PasswordEncoder} to ensure the password is secured
* properly. This demonstration does not address this due to time restrictions.
* </p>
*
* @author Rob Winch
*/
@Entity
public class User implements Serializable {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
@NotEmpty(message = "First name is required.")
private String firstName;
@NotEmpty(message = "Last name is required.")
private String lastName;
@Email(message = "Please provide a valid email address.")
@NotEmpty(message = "Email is required.")
@Column(unique = true, nullable = false)
private String email;
@NotEmpty(message = "Password is required.")
private String password;
public User() {
}
public User(User user) {
this.id = user.id;
this.firstName = user.firstName;
this.lastName = user.lastName;
this.email = user.email;
this.password = user.password;
}
public String getPassword() {
return this.password;
}
public void setPassword(String password) {
this.password = password;
}
public Long getId() {
return this.id;
}
public void setId(Long id) {
this.id = id;
}
public String getFirstName() {
return this.firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public String getLastName() {
return this.lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
public String getEmail() {
return this.email;
}
public void setEmail(String email) {
this.email = email;
}
private static final long serialVersionUID = 2738859149330833739L;
}

View File

@@ -0,0 +1,30 @@
/*
* Copyright 2014-2016 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package sample.data;
import org.springframework.data.repository.CrudRepository;
/**
* Allows managing {@link User} instances.
*
* @author Rob Winch
*
*/
public interface UserRepository extends CrudRepository<User, Long> {
User findByEmail(String email);
}

View File

@@ -0,0 +1,30 @@
/*
* Copyright 2014-2016 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package sample.mvc;
import org.springframework.security.web.csrf.CsrfToken;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class CsrfController {
@RequestMapping("/csrf")
public CsrfToken csrf(CsrfToken token) {
return token;
}
}

View File

@@ -0,0 +1,62 @@
/*
* Copyright 2014-2017 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package sample.mvc;
import java.util.List;
import sample.data.ActiveWebSocketUserRepository;
import sample.data.InstantMessage;
import sample.data.User;
import sample.security.CurrentUser;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.messaging.Message;
import org.springframework.messaging.handler.annotation.MessageMapping;
import org.springframework.messaging.simp.SimpMessageSendingOperations;
import org.springframework.messaging.simp.annotation.SubscribeMapping;
import org.springframework.stereotype.Controller;
/**
* Controller for managing {@link Message} instances.
*
* @author Rob Winch
*
*/
@Controller
public class MessageController {
private SimpMessageSendingOperations messagingTemplate;
private ActiveWebSocketUserRepository activeUserRepository;
@Autowired
public MessageController(ActiveWebSocketUserRepository activeUserRepository,
SimpMessageSendingOperations messagingTemplate) {
this.activeUserRepository = activeUserRepository;
this.messagingTemplate = messagingTemplate;
}
@MessageMapping("/im")
public void im(InstantMessage im, @CurrentUser User currentUser) {
im.setFrom(currentUser.getEmail());
this.messagingTemplate.convertAndSendToUser(im.getTo(), "/queue/messages", im);
this.messagingTemplate.convertAndSendToUser(im.getFrom(), "/queue/messages", im);
}
@SubscribeMapping("/users")
public List<String> subscribeMessages() throws Exception {
return this.activeUserRepository.findAllActiveUsers();
}
}

View File

@@ -0,0 +1,49 @@
/*
* Copyright 2014-2016 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package sample.security;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.annotation.AuthenticationPrincipal;
import org.springframework.security.core.context.SecurityContextHolder;
/**
* Annotate Spring MVC method arguments with this annotation to indicate you wish to
* specify the argument with the value of the current
* {@link Authentication#getPrincipal()} found on the {@link SecurityContextHolder}.
*
* <p>
* Creating your own annotation that uses {@link AuthenticationPrincipal} as a meta
* annotation creates a layer of indirection between your code and Spring Security's. For
* simplicity, you could instead use the {@link AuthenticationPrincipal} directly.
* </p>
*
* @author Rob Winch
*
*/
@Target(ElementType.PARAMETER)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@AuthenticationPrincipal
public @interface CurrentUser {
}

View File

@@ -0,0 +1,100 @@
/*
* Copyright 2014-2018 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package sample.security;
import java.util.Collection;
import sample.data.User;
import sample.data.UserRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;
/**
* @author Rob Winch
*
*/
@Service
public class UserRepositoryUserDetailsService implements UserDetailsService {
private final UserRepository userRepository;
@Autowired
public UserRepositoryUserDetailsService(UserRepository userRepository) {
this.userRepository = userRepository;
}
/*
* (non-Javadoc)
*
* @see
* org.springframework.security.core.userdetails.UserDetailsService#loadUserByUsername
* (java.lang.String)
*/
@Override
public UserDetails loadUserByUsername(String username)
throws UsernameNotFoundException {
User user = this.userRepository.findByEmail(username);
if (user == null) {
throw new UsernameNotFoundException("Could not find user " + username);
}
return new CustomUserDetails(user);
}
private static final class CustomUserDetails extends User implements UserDetails {
private CustomUserDetails(User user) {
super(user);
}
@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
return AuthorityUtils.createAuthorityList("ROLE_USER");
}
@Override
public String getUsername() {
return getEmail();
}
@Override
public boolean isAccountNonExpired() {
return true;
}
@Override
public boolean isAccountNonLocked() {
return true;
}
@Override
public boolean isCredentialsNonExpired() {
return true;
}
@Override
public boolean isEnabled() {
return true;
}
private static final long serialVersionUID = 5639683223516504866L;
}
}

View File

@@ -0,0 +1,57 @@
/*
* Copyright 2014-2016 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package sample.websocket;
import java.security.Principal;
import java.util.Arrays;
import java.util.Calendar;
import sample.data.ActiveWebSocketUser;
import sample.data.ActiveWebSocketUserRepository;
import org.springframework.context.ApplicationListener;
import org.springframework.messaging.MessageHeaders;
import org.springframework.messaging.simp.SimpMessageHeaderAccessor;
import org.springframework.messaging.simp.SimpMessageSendingOperations;
import org.springframework.web.socket.messaging.SessionConnectEvent;
public class WebSocketConnectHandler<S>
implements ApplicationListener<SessionConnectEvent> {
private ActiveWebSocketUserRepository repository;
private SimpMessageSendingOperations messagingTemplate;
public WebSocketConnectHandler(SimpMessageSendingOperations messagingTemplate,
ActiveWebSocketUserRepository repository) {
super();
this.messagingTemplate = messagingTemplate;
this.repository = repository;
}
@Override
public void onApplicationEvent(SessionConnectEvent event) {
MessageHeaders headers = event.getMessage().getHeaders();
Principal user = SimpMessageHeaderAccessor.getUser(headers);
if (user == null) {
return;
}
String id = SimpMessageHeaderAccessor.getSessionId(headers);
this.repository.save(
new ActiveWebSocketUser(id, user.getName(), Calendar.getInstance()));
this.messagingTemplate.convertAndSend("/topic/friends/signin",
Arrays.asList(user.getName()));
}
}

View File

@@ -0,0 +1,51 @@
/*
* Copyright 2014-2018 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package sample.websocket;
import java.util.Arrays;
import sample.data.ActiveWebSocketUserRepository;
import org.springframework.context.ApplicationListener;
import org.springframework.messaging.simp.SimpMessageSendingOperations;
import org.springframework.web.socket.messaging.SessionDisconnectEvent;
public class WebSocketDisconnectHandler<S>
implements ApplicationListener<SessionDisconnectEvent> {
private ActiveWebSocketUserRepository repository;
private SimpMessageSendingOperations messagingTemplate;
public WebSocketDisconnectHandler(SimpMessageSendingOperations messagingTemplate,
ActiveWebSocketUserRepository repository) {
super();
this.messagingTemplate = messagingTemplate;
this.repository = repository;
}
@Override
public void onApplicationEvent(SessionDisconnectEvent event) {
String id = event.getSessionId();
if (id == null) {
return;
}
this.repository.findById(id).ifPresent((user) -> {
this.repository.deleteById(id);
this.messagingTemplate.convertAndSend("/topic/friends/signout",
Arrays.asList(user.getUsername()));
});
}
}