JEECG整合WebSocket
1.背景:
最近因为工作需要在倒腾JEECG,JEECG是一款基于代码生成器的快速开发平台,功能是做得挺不错的,但是历史真是有点久远了,使用的框架是SpringMVC+Spring+Hibernate。然而现在早已是微服务遍地开花的时代。
2.JEECG整合WebSocket的步骤:
(1)建立Handler
@Component public class WebSocketHandler extends AbstractWebSocketHandler { private static final ArrayList<WebSocketSession> users; private Logger logger = LoggerFactory.getLogger(WebSocketHandler.class); static { users = new ArrayList<WebSocketSession>(); } @Override public void afterConnectionEstablished(WebSocketSession session) throws Exception { users.add(session); } @Override public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception { users.remove(session); } @Override protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception { super.handleTextMessage(session, message); } public void sendMessgaeToUsers(TextMessage message) { for(WebSocketSession session:users) { if(session.isOpen()) { try { session.sendMessage(message); } catch (IOException e) { e.printStackTrace(); } } } } }
(2)建立Interceptor拦截器
@Component public class WebSocketHandshakeInterceptor implements HandshakeInterceptor { private static final Logger logger = LoggerFactory.getLogger(WebSocketHandshakeInterceptor.class); @Override public boolean beforeHandshake(ServerHttpRequest serverHttpRequest, ServerHttpResponse serverHttpResponse, WebSocketHandler webSocketHandler, Map<String, Object> map) throws Exception { return true; } @Override public void afterHandshake(ServerHttpRequest serverHttpRequest, ServerHttpResponse serverHttpResponse, WebSocketHandler webSocketHandler, Exception e) { } }
(3)进行配置
@Configuration @EnableWebSocket public class WebSocketConfig extends WebMvcConfigurerAdapter implements WebSocketConfigurer { private static final Logger logger = LoggerFactory.getLogger(WebSocketConfig.class); @Resource private WebSocketHandler webSocketHandler; @Resource private WebSocketHandshakeInterceptor webSocketHandshakeInterceptor; @Override public void registerWebSocketHandlers(WebSocketHandlerRegistry webSocketHandlerRegistry) { webSocketHandlerRegistry.addHandler(webSocketHandler,"/webSocketHandler.ws") .addInterceptors(webSocketHandshakeInterceptor); webSocketHandlerRegistry.addHandler(webSocketHandler,"/sockjs/webSocketHandler.ws") .addInterceptors(webSocketHandshakeInterceptor).withSockJS(); } @Bean public ServletServerContainerFactoryBean createWebSocketContainer() { ServletServerContainerFactoryBean container = new ServletServerContainerFactoryBean(); container.setMaxTextMessageBufferSize(8192*4); container.setMaxBinaryMessageBufferSize(8192*4); return container; } }
** 我这里的路径/webSocketHandler.ws是以.ws结尾的。
(4)前端进行WebSocket连接
<script src="sockjs.js"></script> <script type="text/javascript"> var websocket; if ('WebSocket' in window) { websocket = new WebSocket("ws://localhost:9999/webSocketHandler.ws"); } else if ('MozWebSocket' in window) { websocket = new MozWebSocket("ws://localhost:9999/webSocketHandler.ws"); } else { websocket = new SockJS("http://localhost:9999/sockjs/webSocketHandler.ws"); } websocket.onopen = function (evnt) { console.log("open"); }; websocket.onmessage = function (evnt) { console.log(evnt); }; websocket.onerror = function (evnt) { console.log("error"); }; websocket.onclose = function (evnt) { console.log("close"); } </script>
(5)以上四个步骤在网上都可以找到很多,我也是代码搬运工。完成以上四个步骤,运行出现:
出现这个错误的原因是:JEECG在web.xml对路径做了处理,如下:
<servlet> <description>spring mvc servlet</description> <servlet-name>springMvc</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <init-param> <description>spring mvc 配置文件</description> <param-name>contextConfigLocation</param-name> <param-value>classpath*:spring-mvc.xml</param-value> </init-param> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>springMvc</servlet-name> <url-pattern>*.do</url-pattern> </servlet-mapping> <servlet-mapping> <servlet-name>springMvc</servlet-name> <url-pattern>/rest/*</url-pattern> </servlet-mapping>
这里的路径只对后缀是.do和前缀是rest的做了转发,所以在这里需要添加一个servlet-mapping对后缀是.ws的做转发:
<servlet-mapping> <servlet-name>springMvc</servlet-name> <url-pattern>*.ws</url-pattern> </servlet-mapping>
(6)再运行出现:
后台出现如下问题:
javax.servlet.ServletException: No adapter for handler [org.springframework.web.socket.server.support.WebSocketHttpRequestHandler@44ae9ca8]: The DispatcherServlet configuration needs to include a HandlerAdapter that supports this handler at org.springframework.web.servlet.DispatcherServlet.getHandlerAdapter(DispatcherServlet.java:1141) at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:917) at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:870) at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:961) at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:852)
需要在spring-mvx.xml添加以下标签:
<mvc:annotation-driven/>
(7)接着运行,后台出现以下问题:
java.lang.ClassCastException: org.springframework.web.socket.server.support.WebSocketHttpRequestHandler cannot be cast to org.springframework.web.method.HandlerMethod
JEECG定义了一个AuthInterceptor对路径进行登录权限拦截:
AuthInterceptor类的preHandle方法默认是对请求类的方法进行处理,而我这里定义的.ws后缀是不符合这里的格式的,在spring-mvc.xml对AuthInterceptor的拦截路径进行处理:
添加<mvc:exclude-mapping path="/*.ws"/>,对WebSocket的请求路径不做拦截。
(8)运行,已经成功连接了。
(9)建立一个测试类,进行后台消息推送:
@Controller @RequestMapping("/webSocketController") public class WebSocketController { private Logger logger = LoggerFactory.getLogger(this.getClass()); @Resource private WebSocketHandler webSocketHandler; @RequestMapping(params = "sendMessage") @ResponseBody public void sendMessage(String message) { message = "Hello,world"; TextMessage textMessage = new TextMessage(message); webSocketHandler.sendMessgaeToUsers(textMessage); } }
访问http://localhost:9999/webSocketController.do?sendMessage,如下:
运行结果:
以上就是自己在折腾JEECG整合WebSocket的一些心路历程。