今天在springboot 中调试websocket,然后发现被shiro拦截了,具体解决办法如下:
在shiro 拦截器中配置websoket不需认证:
- @Bean("shiroFilter")
- public ShiroFilterFactoryBean shiroFilter(SecurityManager securityManager) {
- ShiroFilterFactoryBean shiroFilter = new ShiroFilterFactoryBean();
- shiroFilter.setSecurityManager(securityManager);
-
- //oauth过滤
- Map<String, Filter> filters = new HashMap<>();
- filters.put("oauth2", new OAuth2Filter());
- shiroFilter.setFilters(filters);
-
- Map<String, String> filterMap = new LinkedHashMap<>();
- filterMap.put("/sys/login", "anon");
- filterMap.put("/swagger/**", "anon");
- filterMap.put("/index/**", "anon");
- filterMap.put("/libs/**", "anon");
- filterMap.put("/home/**", "anon");
- filterMap.put("/v2/api-docs", "anon");
- filterMap.put("/swagger-ui.html", "anon");
- filterMap.put("/swagger-resources/**", "anon");
- filterMap.put("/captcha.jpg", "anon");
- filterMap.put("/aaa.txt", "anon");
- filterMap.put("/webSocket/**", "anon"); //配置websocket不需认证
- filterMap.put("/**", "oauth2");
- shiroFilter.setFilterChainDefinitionMap(filterMap);
-
- return shiroFilter;
- }
websocket服务器端代码如下:
pom.xml中引入
- <dependency>
- <groupId>org.springframework.boot</groupId>
- <artifactId>spring-boot-starter-websocket</artifactId>
- </dependency>
开启注解
-
- /**
- * websocket 配置类
- */
- @Configuration
- public class WebSocketConfig {
-
- /**
- * ServerEndpointExporter 作用
- *
- * 这个Bean会自动注册使用@ServerEndpoint注解声明的websocket endpoint
- *
- * @return
- */
- @Bean
- public ServerEndpointExporter serverEndpointExporter() {
- return new ServerEndpointExporter();
- }
- }
新建websocket服务类
-
- import lombok.extern.slf4j.Slf4j;
- import org.springframework.stereotype.Component;
-
- import javax.websocket.*;
- import javax.websocket.server.PathParam;
- import javax.websocket.server.ServerEndpoint;
- import java.io.IOException;
- import java.util.concurrent.ConcurrentHashMap;
- import java.util.concurrent.atomic.AtomicInteger;
-
- /**
- * websocket 服务类
- */
- @ServerEndpoint("/webSocket/{token}")
- @Component
- @Slf4j
- public class WebSocketServer {
- //静态变量,用来记录当前在线连接数
- private static AtomicInteger onlineNum = new AtomicInteger();
- //concurrent包的线程安全set,用来存放每个客户端对应的webSocketServer对象;
- private static ConcurrentHashMap<String, Session> sessionPools = new ConcurrentHashMap<String, Session>();
-
- //发送消息
- public void sendMessage(Session session, String message) throws IOException {
- if (session != null) {
- synchronized (session) {
- session.getBasicRemote().sendText(message);
- }
- }
- }
-
- //给指定的用户发送消息,token为用户登录后的令牌
- public void sendInfo(String token, String message) {
- Session session = sessionPools.get(token);
- try {
- sendMessage(session, message);
- } catch (Exception e) {
- log.error("webSocket发送消息失败:"+token, e);
- }
- }
-
- //建立连接成功调用
- @OnOpen
- public void onOpen(Session session, @PathParam(value="token") String token) {
- sessionPools.put(token, session);
- addOnlineCount();
- }
-
- //关闭连接时调用
- @OnClose
- public void onClose(@PathParam(value="token") String token) {
- if (StringUtils.isNotEmpty(token)) {
- sessionPools.remove(token);
- subOnlineCount();
- }
-
- }
-
- //收到客户端消息
- @OnMessage
- public void onMessage(String message) {
- for (Session session : sessionPools.values()) {
- try {
- sendMessage(session, message);
- } catch (Exception e) {
- log.error("webSocket 发送消息失败:", e);
- continue;
- }
- }
- }
-
- @OnError
- public void onError(Throwable error) {
- log.error("websocket出错", error.getMessage());
-
- }
-
- public static void addOnlineCount() {
- onlineNum.incrementAndGet();
- }
-
- public static void subOnlineCount() {
- onlineNum.decrementAndGet();
- }
-
- }
服务器调用直接注入服务
- @Autowired
- private WebSocketServer webSocketServer;
-
- WebSocketInfo info = WebSocketInfo.builder().message("你有一条消息需要处理!").build();
- webSocketServer.sendInfo(token, JsonMapper.toJsonString(info));
前端代码:
- mounted() {
- this.initWebSocket()
- },
- methods: {
- initWebSocket () {
- let host = document.location.host;
- let token = this.$cookie.get("token")
- let socketUrl = "ws://localhost:8090/jg/webSocket/" + token
- this.websock = new WebSocket(socketUrl);//这个连接ws://固定,后面的根据自己的IP和端口进行改变,我设置监听是8090
- this.websock.onmessage = this.webSocketOnMessage
- this.websock.onerror = this.webSocketOnError
- this.websock.onopen = this.webSocketOnOpen
- this.websock.onclose = this.webSocketClose
- },
- webSocketOnOpen () { //打开
- this.websock.send("发送数据");
- },
- webSocketOnError () { //连接错误
- console.log( 'WebSocket连接失败')
- },
- webSocketOnMessage (e) { // 数据接收
- let obj = JSON.parse(e.data)
- this.$message({
- type: 'info',
- message: obj.message,
- duration: 1000,
- })
- },
- webSocketClose (e) { // 关闭连接
- console.log('已关闭连接', e)
- }
- },
-
- destroyed () {
- if (this.websock != null) {
- this.websock.close() // 页面销毁后断开websocket连接
- }
- }
其中websocket路径配置:ws://localhost:8090/jg/webSocket/ 加了前缀是因为springboot配置了前缀:
- server:
- tomcat:
- uri-encoding: UTF-8
- max-threads: 1000
- min-spare-threads: 30
- port: 8090
- connection-timeout: 5000ms
- servlet:
- context-path: /jg
《思考中医》