如何在spring mvc中使用websockets在实体之间进行通信

时间:2018-02-06 14:32:27

标签: java spring notifications spring-websocket

我一直在研究websockets,并在github上找到了一个信息丰富的例子,我已经开始在我自己的项目中实现了。 链接: https://github.com/netgloo/spring-boot-samples/tree/master/spring-boot-web-socket-user-notifications

我想我对此有很多疑问,但我会尽量不让你们超负荷。

  1. 我打算在用户之间使用websockets进行好友请求通知(接受/拒绝),但目前传递消息的时间很长。您是否会推荐使用带弹簧的websocket方法,或者在实施通知时是否有更简单/更实用的技术?

  2. 目前我的“通知”实体与教程完全相同,将“通知”作为bean并将这些消息保存在我正在使用的数据库中是不错的做法,或者这不适用什么时候使用websockets?

  3. 在控制器类中,正在创建一个新的“通知”对象,传递参数“hello”和“UserA”,我如何将数据库中的硬编码用户名传递给此方法,以便通知将是发送到“g@gmail.com”而不是UserA,因为对我来说显而易见的方式没有造成任何错误,但几乎没有做任何事情(所以看起来如此)并且没有消息传递。

  4. 问题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并在整个项目中对其进行了修改,显然我已在上面提到过。

    如果您需要更多代码,请告诉我,因为我不希望这看起来像一篇文章!

1 个答案:

答案 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();
        }

它有效!