SSM專案中整合WebService
先了解一下 WebService的一些相關術語 吧:
WebService :
WebService是一種跨程式語言和跨作業系統平臺的遠端呼叫技術。
WSDL(web service definition language) :
WSDL是webservice定義語言, 對應.wsdl文件, 一個webservice會對應一個唯一的wsdl文件, 定義了客戶端與服務端傳送請求和響應的資料格式和過程
SOAP(simple object access protocal) :
SOAP/">SOAP是"簡單物件訪問協議"
是一種簡單的、基於HTTP和XML的協議, 用於在WEB上交換結構化的資料
soap訊息:請求訊息和響應訊息
SEI(WebService EndPoint Interface) :
SEI是web service的終端介面,就是WebService伺服器端用來處理請求的介面
CXF(Celtix + XFire) :
一個apache的用於開發webservice伺服器端和客戶端的框架。
本次採用的就是CXF框架來整合,
首先引入相關的pom包:
<!-- webservice --> <dependency> <groupId>org.apache.cxf</groupId> <artifactId>cxf-rt-frontend-jaxws</artifactId> <version>${cxf.version}</version> </dependency> <dependency> <groupId>org.apache.cxf</groupId> <artifactId>cxf-rt-transports-http</artifactId> <version>${cxf.version}</version> </dependency>
由於版本的衝突,我將spring的版本調了,並且由於cglib包中的asm包和cxf框架中的asm包有衝突,我做了以下更改:
<!-- spring版本號 --> <spring.version>4.1.9.RELEASE</spring.version>
<dependency> <groupId>cglib</groupId> <artifactId>cglib</artifactId> <version>3.2.5</version> <exclusions> <exclusion> <groupId>org.ow2.asm</groupId> <artifactId>asm</artifactId> </exclusion> </exclusions> </dependency>
2. 接著引入spring-context-webservice.xml和cxf-config.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:cxf="http://cxf.apache.org/core" xmlns:jaxws="http://cxf.apache.org/jaxws" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://cxf.apache.org/jaxws http://cxf.apache.org/schemas/jaxws.xsd http://cxf.apache.org/core http://cxf.apache.org/schemas/core.xsd"> <import resource="cxf-config.xml"/> </beans>
<?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:jaxws="http://cxf.apache.org/jaxws" xmlns:context="http://www.springframework.org/schema/context" xmlns:jaxrs="http://cxf.apache.org/jaxrs" xsi:schemaLocation="http://cxf.apache.org/jaxws http://cxf.apache.org/schemas/jaxws.xsd 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://cxf.apache.org/jaxrs http://cxf.apache.org/schemas/jaxrs.xsd"> <import resource="classpath*:META-INF/cxf/cxf.xml" /> <import resource="classpath*:META-INF/cxf/cxf-extension-soap.xml" /> <import resource="classpath*:META-INF/cxf/cxf-servlet.xml" /> <!-- id 不能重複 --> <jaxws:endpoint id="servicemanWebService" implementor="clack.webserviceImp.ServicemanWebServiceImp"address="/servicemanws" /> <!-- <jaxrs:server id="restContainer" address="/"> <jaxrs:serviceBeans> <ref bean="roomService" /> </jaxrs:serviceBeans> <jaxrs:providers> <bean class="org.codehaus.jackson.jaxrs.JacksonJaxbJsonProvider" /> </jaxrs:providers> <jaxrs:extensionMappings> <entry key="json" value="application/json" /> <entry key="xml" value="application/xml" /> </jaxrs:extensionMappings> </jaxrs:server> --> </beans>
其中 <jaxws:endpoint id="servicemanWebService" implementor="clack.webserviceImp.ServicemanWebServiceImp" address="/servicemanws" />
中的設定後續會用到。
3. 更改相應的web.xml載入順序並加入cxf配置(反正是先載入spring,後加載springmvc)
<?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>Archetype Created Web Application</display-name> <context-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:spring-context*.xml</param-value> </context-param> <listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener> <listener> <listener-class>org.springframework.web.context.request.RequestContextListener</listener-class> </listener> <!-- ================配置SpringMVC核心排程器================ --> <!-- 不指定具體檔案的話,預設為"/WEB-INF/<servlet name>-servlet.xml" --> <!-- load-on-startup代表啟動順序,設定為大於等於0表示容器在應用啟動時就載入並初始化這個servlet --> <!-- 推薦攔截/,風格優雅 --> <servlet> <servlet-name>SpringMVC</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <init-param> <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>/</url-pattern> </servlet-mapping> <servlet> <servlet-name>CXFServlet</servlet-name> <servlet-class>org.apache.cxf.transport.servlet.CXFServlet</servlet-class> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>CXFServlet</servlet-name> <url-pattern>/ws/*</url-pattern> </servlet-mapping> </web-app>
4. 接著新增一個工具類用於調出springmvc中載入的service註解
package clack.utils; import java.util.Enumeration; import javax.servlet.ServletContext; import org.springframework.web.context.ContextLoader; import org.springframework.web.context.WebApplicationContext; import org.springframework.web.context.support.WebApplicationContextUtils; public class ContextUtils { public static WebApplicationContext getSpringMVCContext() { WebApplicationContext rootWac = ContextLoader.getCurrentWebApplicationContext(); // 獲取servletContext System.out.println(rootWac+"ddddd"); ServletContext servletContext = rootWac.getServletContext(); // 獲取子容器,名字最後對應servlet名字 //1.檢視spring容器中的物件名稱 String[] beannames = rootWac.getBeanDefinitionNames(); for(String beanname:beannames){ System.out.println(beanname); } System.out.println(servletContext); //2.檢視servlet中容器列表 Enumeration<String> servletnames= servletContext.getAttributeNames(); while(servletnames.hasMoreElements()){ System.out.println(servletnames.nextElement()); } WebApplicationContext springmvc = WebApplicationContextUtils.getWebApplicationContext(servletContext, "org.springframework.web.servlet.FrameworkServlet.CONTEXT.SpringMVC"); //System.out.println(springmvc+"eee"); return springmvc; } }
5. 準備工作就緒後就建立webservice介面和webservice實現類:
package clack.webservice; import java.util.List; import javax.jws.WebMethod; import javax.jws.WebService; import clack.entity.Serviceman; @WebService public interface ServicemanWebService { //使用@WebMethod註解標註WebServiceI介面中的方法 @WebMethod List<Serviceman> getAllServiceman() throws Exception; }
其中使用的 getAllServiceman()方法是本身的service中的方法呼叫。
package clack.webserviceImp; import java.util.List; import javax.jws.WebService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import clack.entity.Serviceman; import clack.service.ServicemanService; import clack.utils.ContextUtils; import clack.webservice.ServicemanWebService; //endpointInterface 編寫實現介面類名 service name 網路訪問的名字 對應<wsdl:service name="studentws"> @Component("servicemanWebService") @WebService(endpointInterface = "clack.webservice.ServicemanWebService", serviceName = "servicemanws") public class ServicemanWebServiceImp implements ServicemanWebService{ @Autowired private ServicemanService servicemanService; public ServicemanService getServicemanService() { return servicemanService; } public void setServicemanService(ServicemanService servicemanService) { this.servicemanService = servicemanService; } @Override public List<Serviceman> getAllServiceman() throws Exception { // TODO Auto-generated method stub servicemanService = (ServicemanService)ContextUtils.getSpringMVCContext().getBean("servicemanService"); List<Serviceman> servicemans = servicemanService.getAllServiceman(); return servicemans; } }
理清其中註解的對應關係後問題不大,
啟動專案,輸入地址: http://localhost:8080/StudyMaven1/ws/servicemanws?wsdl
測試:
建立一個簡單的maven專案並匯入相關的cxf包:
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>clack</groupId> <artifactId>MyWebService</artifactId> <version>0.0.1-SNAPSHOT</version> <properties> <cxf.version>2.2.3</cxf.version> </properties> <dependencies> <!-- webservice --> <dependency> <groupId>org.apache.cxf</groupId> <artifactId>cxf-rt-frontend-jaxws</artifactId> <version>${cxf.version}</version> </dependency> <dependency> <groupId>org.apache.cxf</groupId> <artifactId>cxf-rt-transports-http</artifactId> <version>${cxf.version}</version> </dependency> </dependencies> <build> <defaultGoal>compile</defaultGoal> <finalName>MyWebService</finalName> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <version>3.1</version> <configuration> <source>1.8</source> <target>1.8</target> <encoding>utf-8</encoding> </configuration> </plugin> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-resources-plugin</artifactId> <version>2.6</version> <configuration> <failOnMissingWebXml>false</failOnMissingWebXml> </configuration> </plugin> </plugins> <resources> <!--編譯之後包含xml --> <resource> <directory>src/main/java</directory> <includes> <include>**/*.xml</include> </includes> </resource> <resource> <directory>src/main/resources</directory> <includes> <include>**/*</include> </includes> </resource> </resources> </build> </project>
2. 使用了一個外掛生成相關的檔案 apache-cxf-3.2.7
3. 將所得的檔案拷入maven專案中,並新建一個測試類測試是否能取得資料:
目錄樹如下:
其中WebServiceApp是測試類:
package clack.webserviceimp; import java.net.URL; import java.util.List; import javax.xml.namespace.QName; import javax.xml.ws.Service; import org.apache.cxf.endpoint.Client; import org.apache.cxf.jaxws.endpoint.dynamic.JaxWsDynamicClientFactory; import clack.webservice.Serviceman; import clack.webservice.ServicemanWebService; /** * 通過客戶端程式設計的方式呼叫Webservice服務 * */ public class WebServiceApp { //1. 自定義方法 public void mysoap() throws Exception { // CXF動態客戶端工廠 JaxWsDynamicClientFactory dcf = JaxWsDynamicClientFactory.newInstance(); // WSDL文件url配置() String wsdlUrl = "http://localhost:8080/StudyMaven1/ws/servicemanws?wsdl"; Object[] objects = null; try { // 獲取CXF客戶端 Client client = dcf.createClient(wsdlUrl); // 呼叫Web Service方法 objects = client.invoke("add", 1, 2); } catch (Exception e) { e.printStackTrace(); } // 獲取呼叫結果 System.out.println("呼叫結果:" + objects[0]); System.out.println("=========>"); try { // 獲取CXF客戶端 Client client = dcf.createClient(wsdlUrl); // 呼叫Web Service方法 objects = client.invoke("sayHello", "World!"); } catch (Exception e) { e.printStackTrace(); } // 獲取呼叫結果 System.out.println("呼叫結果:" + objects[0]); } //第二種 client工具生成輔助類 需使用apche cxf工具 //步驟 cmd wsdl2java-encodingutf8 http://localhost:8080/StudyMavenSSM/ws/studentws?wsdl // public void clientsoap() throws Exception{ // 建立WSDL的URL,注意不是服務地址 URL url = new URL("http://localhost:8080/StudyMaven1/ws/servicemanws?wsdl"); // 建立服務名稱 // 1.namespaceURI - 名稱空間地址 (wsdl文件中的targetNamespace // targetNamespace="http://webserviceImp.gxa/") // 2.localPart - 服務檢視名 (wsdl文件中服務名稱,例如<wsdl:service name="studentws">) QName qname = new QName("http://webserviceImp.clack/", "servicemanws"); // 建立服務檢視 // 引數解釋: // 1.wsdlDocumentLocation - wsdl地址 // 2.serviceName - 服務名稱 Service service = Service.create(url, qname); // 獲取服務實現類 // 引數解釋:serviceEndpointInterface - 服務埠(wsdl文件中服務埠的name屬性,例如<wsdl:port // binding="tns:studentwsSoapBinding" name="StudentWebServiceImpPort">) ServicemanWebService studentWebService = service.getPort(ServicemanWebService.class); //呼叫查詢方法 List<Serviceman> students = studentWebService.getAllServiceman(); for(Serviceman serviceman:students){ System.out.println(serviceman.getSname()); } } public static void main(String[] args) throws Exception { new WebServiceApp().clientsoap(); } }
4. 最後執行如下,成功呼叫:
至此,一個簡單的webservice就整合進去了,但是,其中還有很多細節無法言說,學而無涯。