文章的最后會提供demo程序,總共有三個實例程序
1、gs-messaging-stomp-websocket:基于請求與響應的websocket實例,基于注解。
2、spring-websocket-portfolio:server定時廣播消息,也可通過請求與響應進行websocket通信,基于注解配置。來源于github開源項目。前端用了angularjs不利于新手閱讀。
3、java-ws:server :端定時廣播、客戶端與服務端請求與響應的websocket通信;基于xml配置。前端是簡單javascript腳本,方便理解閱讀、純基礎的內容,主要說明在整合配置中碰到的問題和解決辦法。
這里主要說明java-ws基于xml配置過程,如果是基于注解請看1、2實例,所有的項目都是maven的項目。
1、運行環境
tomcat 7+或jetty9+(jetty低版本應該也可以,本人用的9+,這里也著重著重說明9+碰到的問題)
servlet3+(java-ws中使用的是servlet3.1)
jdk1.6+(java-ws中用的jdk1.8)
2、環境及項目的配置這里不再詳細說明,直接說配置項目
web.xml
<?xml version="1.0" encoding="UTF-8"?> <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://xmlns.jcp.org/xml/ns/javaee" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd" id="WebApp_ID" version="3.1"> <display-name>java-sm</display-name> <context-param> <param-name>contextConfigLocation</param-name> <param-value> classpath:spring-core.xml </param-value> </context-param> <span style="color:#330099;"><context-param> <param-name>spring.profiles.active</param-name> <param-value>dev</param-value> </context-param> <context-param> <param-name>spring.profiles.default</param-name> <param-value>dev</param-value> </context-param> <context-param> <param-name>spring.liveBeansView.mbeanDomain</param-name> <param-value>dev</param-value> </context-param> </span> <listener> <description>初始化Spring框架</description> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener> <servlet> <description>加載SpringMVC配置信息</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>2</load-on-startup> <span style="color:#ff0000;"><strong><async-supported>true</async-supported></strong></span> </servlet> <servlet-mapping> <servlet-name>springMvc</servlet-name> <url-pattern>/</url-pattern> </servlet-mapping> <!-- HttpSession的失效時間 --> <session-config> <session-timeout>20</session-timeout> </session-config> <welcome-file-list> <welcome-file>time.jsp</welcome-file> </welcome-file-list> </web-app>
藍色的部分配置,項目啟動的過程中會拋出異常,但不影響程序;
注意紅色的部分,如果不配置項目啟動時會出現異常,有明確的提示需要添加此配置,至于原因自行查閱資料。
spring-core.xml
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:c="http://www.springframework.org/schema/c" xmlns:cache="http://www.springframework.org/schema/cache" xmlns:context="http://www.springframework.org/schema/context" xmlns:jdbc="http://www.springframework.org/schema/jdbc" xmlns:jee="http://www.springframework.org/schema/jee" xmlns:lang="http://www.springframework.org/schema/lang" xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:p="http://www.springframework.org/schema/p" xmlns:task="http://www.springframework.org/schema/task" xmlns:tx="http://www.springframework.org/schema/tx" xmlns:util="http://www.springframework.org/schema/util" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd http://www.springframework.org/schema/cache http://www.springframework.org/schema/cache/spring-cache.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/jdbc http://www.springframework.org/schema/jdbc/spring-jdbc.xsd http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee.xsd http://www.springframework.org/schema/lang http://www.springframework.org/schema/lang/spring-lang.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd"> <!-- 自動掃描dao和service包(自動注入) --> <span style="color:#ff0000;"><!-- <context:component-scan base-package="com.sirding" > <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller" /> </context:component-scan> --></span> <task:annotation-driven/> </beans>
注意紅色的部分已被注釋掉,后面說明為什么要注釋掉以及如果不注釋需要做哪些更改。
spring-websocket.xml
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p" xmlns:context="http://www.springframework.org/schema/context" xmlns:websocket="http://www.springframework.org/schema/websocket" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd http://www.springframework.org/schema/cache http://www.springframework.org/schema/cache/spring-cache.xsd http://www.springframework.org/schema/websocket http://www.springframework.org/schema/websocket/spring-websocket.xsd "> <!-- 客戶端向服務端發送消息的前綴 對應 controller的mapping的@MessageMapping("/hello"),客戶端發送請求的地址為/app/hello --> <websocket:message-broker application-destination-prefix="/app"> <!-- 此配置作為備選的切入點,如果客戶端不支持stomp協議,那么將通過sockjs通過如下入口進行數據交互 --> <websocket:stomp-endpoint path="/myws"> <websocket:sockjs/> </websocket:stomp-endpoint> <!-- stomp-broker-relay 和 simple-broker 二者只能出現一次,具體約束見spring-websocket.xsd --> <!-- <websocket:stomp-broker-relay prefix="/topic"/> --> <!-- 返回消息的前綴,對應controller中的@SendTo("/topic/greetings")中前綴的是/topic的將接口 --> <websocket:simple-broker prefix="/topic" /> <!-- 如下配置暫無實際需求 --> <websocket:message-converters register-defaults="true"> <bean class="org.springframework.messaging.converter.StringMessageConverter"/> <bean class="org.springframework.messaging.converter.ByteArrayMessageConverter"/> </websocket:message-converters> </websocket:message-broker> </beans>
spring-mvc.xml配置是關鍵的配置也是坑最多的地方,各種問題都出現在這里,先看配置
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p" xmlns:context="http://www.springframework.org/schema/context" xmlns:cache="http://www.springframework.org/schema/cache" xmlns:task="http://www.springframework.org/schema/task" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd http://www.springframework.org/schema/cache http://www.springframework.org/schema/cache/spring-cache.xsd http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task.xsd "> <!-- 配置1: 自動掃描controller包下的所有類,使其認為spring mvc的控制器 --> <span style="color:#ff0000;"><context:component-scan base-package="com.sirding" > <!-- <context:include-filter type="annotation" expression="org.springframework.stereotype.Controller" /> <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Service" /> <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Repository" /> --> </context:component-scan></span> <task:annotation-driven/>
<span style="color:#000099;"><import resource="spring-websocket.xml"/></span> <!-- 配置解析webjars資源 --> <!-- <mvc:resources mapping="/webjars/**" location="classpath:/META-INF/resources/webjars/"> --> <mvc:annotation-driven/> <mvc:default-servlet-handler/> <mvc:resources mapping="/resources/**" location="/resources/"/> <mvc:resources mapping="/webjars/**" location="/webjars/"> <mvc:resource-chain resource-cache="true"> <mvc:resolvers> <bean class="org.springframework.web.servlet.resource.WebJarsResourceResolver"></bean> <bean class="org.springframework.web.servlet.resource.PathResourceResolver"></bean> </mvc:resolvers> </mvc:resource-chain> </mvc:resources> <bean id="jspViewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <description>初始化jsp視圖解析器 </description> <property name="prefix" value="/WEB-INF/"></property> <property name="suffix" value=".jsp"></property> <property name="order" value="5"></property> </bean> </beans>
紅色部分:中間的有部分配置被注釋掉,如果取消注釋,那么spring-core中注釋的部分就要取消,這樣@Service的注解才能被識別,但是此時
package com.sirding.service; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.messaging.core.MessageSendingOperations; import org.springframework.scheduling.annotation.Scheduled; import org.springframework.stereotype.Service; import com.sirding.domain.SimpleJson; import com.sirding.util.DateUtil; @Service public class AutoPub{ <span style="color:#ff0000;">@Autowired private MessageSendingOperations<String> messagingTemplate;</span> @Scheduled(fixedDelay=10000) public void sendQuotes() { System.out.println("廣播消息"); this.messagingTemplate.convertAndSend("/topic/getTime", new SimpleJson("time", DateUtil.getNow())); } }
紅色部分的自動注入就會在項目啟動時出現無法注入的異常,原因是spring-mvc.xml中藍色的配置是引入websocket配置地方,此時還沒有MessageSendingOperations對應的屬性因此Service注入屬性就會出現異常,如果將spring-mvc.xml中配置放入到spring-core.xml中,那么websocket相關對應的切入點、@MessageMapping將不能正常監聽。因此,如果一定要取消spring-core.xml中注解,只需要將MessageSendingOperations屬性的注入操作放到controller中即可,使用時在通過參數帶到Service層中即可。
【PS:此部分的配置,后期還會更新,本人覺得通過一些配置絕對可以解決注入的問題】
<!-- 配置解析webjars資源 --> <!-- <mvc:resources mapping="/webjars/**" location="classpath:/META-INF/resources/webjars/"> --> <mvc:annotation-driven/> <mvc:default-servlet-handler/> <mvc:resources mapping="/resources/**" location="/resources/"/> <mvc:resources mapping="/webjars/**" location="/webjars/"> <mvc:resource-chain resource-cache="true"> <mvc:resolvers> <bean class="org.springframework.web.servlet.resource.WebJarsResourceResolver"></bean> <bean class="org.springframework.web.servlet.resource.PathResourceResolver"></bean> </mvc:resolvers> </mvc:resource-chain> </mvc:resources>
Spring靜態資源的應用也是一個大坑,所有的實例的js庫都是通過jar映入的,webjars的官網上基本將所有主流的js庫封裝成了jar,好處就是通過配置達到不依賴具體版本,更新時只需要替換一下jar就ok了,具體會配置到的問題可以參考另一篇文章,這里有關于webjars使用的詳細說明。
<span style="white-space:pre"> </span><mvc:annotation-driven/> <span style="white-space:pre"> </span><mvc:default-servlet-handler/>
此處重點說一下,上面的兩行配置,如果你的spring-mvc.xml中是I用的配置,那么項目啟動后控制臺沒有但是訪問controller時十有八九會出現404的提示,后臺還沒有異常只是提示沒有對應的mappping,此時不放加上上述兩行配置,基本可以解決404的問題,如果你的項目中使用spring-security或是spring-oauth2.0,那么上面的配置可以放在security或是oauth2的配置文件中,一樣可以。
整個的配置情況就是這樣,按照上述配置只是第一步,還有第二步。
web容器的選擇及應用,這里只說明jetty9.3及tomcat8,文章開始的三個項目中項目1.直接運行main方法即可,項目2使用的內嵌的jetty,只需要執行mvn jetty:run或是mvn tomcat:run(沒有測試)即可,
這里著重說明項目3,首先應用ecplise中配置的jetty,啟動的過程中會出現如下異常:
java.lang.IllegalStateException: No suitable default RequestUpgradeStrategy found at org.springframework.web.socket.server.support.AbstractHandshakeHandler.initRequestUpgradeStrategy(AbstractHandshakeHandler.java:143) at org.springframework.web.socket.server.support.AbstractHandshakeHandler.<init>(AbstractHandshakeHandler.java:109) at org.springframework.web.socket.server.support.DefaultHandshakeHandler.<init>(DefaultHandshakeHandler.java:35) at org.springframework.web.socket.sockjs.transport.handler.DefaultSockJsService.getDefaultTransportHandlers(DefaultSockJsService.java:91) at org.springframework.web.socket.sockjs.transport.handler.DefaultSockJsService.<init>(DefaultSockJsService.java:77) at org.springframework.web.socket.sockjs.transport.handler.DefaultSockJsService.<init>(DefaultSockJsService.java:53) at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method) at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62) at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45) at java.lang.reflect.Constructor.newInstance(Constructor.java:408) at org.springframework.beans.BeanUtils.instantiateClass(BeanUtils.java:142) at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:122) at org.springframework.beans.factory.support.ConstructorResolver.autowireConstructor(ConstructorResolver.java:271) at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.autowireConstructor(AbstractAutowireCapableBeanFactory.java:1143) at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1046) at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:510) at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:482) at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:306) at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:230) ..省略.....部分內容
沒有關系只是環境的問題,不應實例的運行,因此不用糾結,如果不想看到這個異常,那么就是用內嵌的jetty,通過mvn jetty:run運行即可。
pom.xml已經配置內嵌的jetty和tomcat及websocket依賴的相關jar,如果使用的是tomcat7+的版本直接部署運行即可。
最后說一下js端建立連接時可能出現的404情況,下面是建立連接的js腳本
function connect() { var socket = new SockJS('/myws'); stompClient = Stomp.over(socket); stompClient.connect({}, function (frame) { console.log('===========Connected: ' + frame); stompClient.subscribe('/topic/getTime', function (msg) { console.log(msg); showTime(JSON.parse(msg.body).value); }); });}
注意紅色的部分,如果的你訪問項目時使用的url為http://localhost:8080/java-ws/time.jsp,那么紅色部分中的"/myws"應該改為"/java-ws/myws"。此處在是用jetty:run和tomcat分別運行時就會出現404,如果不仔細看很容易掉進坑里.....
function connect() { <span style="color:#cc0000;"><strong> var socket = new SockJS('/myws');</strong></span> stompClient = Stomp.over(socket); stompClient.connect({}, function (frame) { console.log('===========Connected: ' + frame); stompClient.subscribe('/topic/getTime', function (msg) { console.log(msg); showTime(JSON.parse(msg.body).value); }); }); }
java-ws是基于項目1和項目的簡化與整合,將基于注解的方式轉為基于xml的方式,實例很簡單,但足以方便的整合到現有的項目,相信你接觸的項目都是基于xml配置的。
就愛閱讀www.92to.com網友整理上傳,為您提供最全的知識大全,期待您的分享,轉載請注明出處。
歡迎轉載:http://www.kanwencang.com/bangong/20161216/71634.html
文章列表