我一直在研究websockets,并在github上找到了一个信息丰富的例子,我已经开始在我自己的项目中实现了。 链接: https://github.com/netgloo/spring-boot-samples/tree/master/spring-boot-web-socket-user-notifications
我想我对此有很多疑问,但我会尽量不让你们超负荷。
我打算在用户之间使用websockets进行好友请求通知(接受/拒绝),但目前传递消息的时间很长。您是否会推荐使用带弹簧的websocket方法,或者在实施通知时是否有更简单/更实用的技术?
目前我的“通知”实体与教程完全相同,将“通知”作为bean并将这些消息保存在我正在使用的数据库中是不错的做法,或者这不适用什么时候使用websockets?
在控制器类中,正在创建一个新的“通知”对象,传递参数“hello”和“UserA”,我如何将数据库中的硬编码用户名传递给此方法,以便通知将是发送到“g@gmail.com”而不是UserA,因为对我来说显而易见的方式没有造成任何错误,但几乎没有做任何事情(所以看起来如此)并且没有消息传递。
问题1和2是建议,问题3是与代码相关的问题
这是我的控制器代码(相关部分):
//websocket
@Autowired
private NotificationService notificationService;
/**
* GET / -> show the index page.
*/
@RequestMapping("/index2")
public String index2() {
return "index2";
}
/**
* GET /notifications -> show the notifications page.
*/
@RequestMapping("/notifications")
public String notifications() {
return "notifications";
}
/**
* POST /some-action -> do an action.
*
* After the action is performed will be notified UserA.
*/
@RequestMapping(value = "/some-action", method = RequestMethod.POST)
@ResponseBody
public ResponseEntity<?> someAction() {
// Do an action here
// ...
//me messing about to try and map the correct user (ignore)
UserLogin testuser = userRepository.findByUserName("g@gmail.com");
String name = testuser.getUserName();
// Send the notification to "UserA" (by username)
notificationService.notify(
new Notification("hello"), // notification object
"g@gmail.com" // username
);
// Return an http 200 status code
return new ResponseEntity<>(HttpStatus.OK);
}
/////////////////////////////
通知服务(请注意,我在绝望的测试尝试中将变量String username更改为String userName):
@Service
public class NotificationService {
// The SimpMessagingTemplate is used to send Stomp over WebSocket messages.
@Autowired
private SimpMessagingTemplate messagingTemplate;
/**
* Send notification to users subscribed on channel "/user/queue/notify".
*
* The message will be sent only to the user with the given username.
*
* @param notification The notification message.
* @param username The username for the user to send notification.
*/
public void notify(Notification notification, String userName) {
messagingTemplate.convertAndSendToUser(
userName,
"/queue/notify",
notification
);
return;
}
}
我没有将教程中的WebSecurityConfig.java类包含到我的项目中,因为我已经存在了一个。 (这可能是问题所在) 这是我的websecurityconfig文件:
@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
UserLoginRepository userLoginRepository;
//http.authorizeRequests().antMatchers("/", "/home", "/registeruser").permitAll().antMatchers("/admin").hasRole("ADMIN")
@Autowired
DataSource dataSource;
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests().antMatchers("/", "/home", "/registeruser").permitAll().antMatchers("/admin").hasRole("ADMIN")
.anyRequest().authenticated().and().formLogin().loginPage("/login").permitAll().and().logout()
.permitAll();
http.exceptionHandling().accessDeniedPage("/403");
}
@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
//authorities at the moment is the manager i.e. 'Manager' from user_login
auth.jdbcAuthentication().dataSource(dataSource)
.usersByUsernameQuery("select user_name,password,user_status from user_login where user_name=?")
.authoritiesByUsernameQuery("select user_name,password, 'Manager' from user_login where user_name=?");
}
}
这是我的userlogin模型,这是我想要接收消息而不是“UserA”的对象。
@Entity
public class UserLogin {
@Id
@GeneratedValue(strategy=GenerationType.AUTO)
private Long id;
private String firstName;
private String lastName;
private Long phone;
private String userName;
private String address;
private String password;
private boolean userStatus;
private String userType;
private String position;
@OneToMany(fetch=FetchType.LAZY, cascade=CascadeType.ALL)
public Set<PlayerSeasonStat> playerStats;
public UserLogin()
{
}
public UserLogin(Long id, String firstName, String lastName, Long phone,
String userName, String address, String password,
boolean userStatus, String userType, String position,
Set<PlayerSeasonStat> playerStats) {
super();
this.id = id;
this.firstName = firstName;
this.lastName = lastName;
this.phone = phone;
this.userName = userName;
this.address = address;
this.password = password;
this.userStatus = userStatus;
this.userType = userType;
this.position = position;
this.playerStats = playerStats;
}
////getters and setters
我也在控制台上获得一些信息,说sockJsScheduler中有一个活动线程:
2018-02-07 12:54:14.526 INFO 11776 --- [MessageBroker-1] o.s.w.s.c.WebSocketMessageBrokerStats : WebSocketSession[0 current WS(0)-HttpStream(0)-HttpPoll(0), 0 total, 0 closed abnormally (0 connect failure, 0 send limit, 0 transport error)], stompSubProtocol[processed CONNECT(0)-CONNECTED(0)-DISCONNECT(0)], stompBrokerRelay[null], inboundChannel[pool size = 0, active threads = 0, queued tasks = 0, completed tasks = 0], outboundChannelpool size = 0, active threads = 0, queued tasks = 0, completed tasks = 0], sockJsScheduler[pool size = 1, active threads = 1, queued tasks = 0, completed tasks = 0]
请注意,我的项目中所有其他java / jsp / html页面与教程中的相同(除了index.html页面,我已将其重命名为index2.html并在整个项目中对其进行了修改,显然我已在上面提到过。
如果您需要更多代码,请告诉我,因为我不希望这看起来像一篇文章!
答案 0 :(得分:0)
更新: 所以我搞乱了我的项目,并发现websocket技术无法通信的原因是因为在我的项目中WebSecurityConfig.java类(与教程WebSecurityConfig.java类完全不同)我没有禁用csrf,这显然允许websockets在禁用后进行通信!
所以我补充道:
http.csrf().disable();
进入此方法(在WebSecurityConfig中):
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests().antMatchers("/", "/home", "/registeruser").permitAll().antMatchers("/admin").hasRole("ADMIN")
.anyRequest().authenticated().and().formLogin().loginPage("/login").permitAll().and().logout()
.permitAll();
http.exceptionHandling().accessDeniedPage("/403");
http.csrf().disable();
}
它有效!