美文网首页
ssm+cxf3.0

ssm+cxf3.0

作者: 九思而行 | 来源:发表于2018-03-14 16:08 被阅读35次

近期需要使用webService,所以看了一下目前比较常用的几个webservie框架,经过比较,最终决定使用能和spring无缝结合的cxf框架。~~从此走上了不归路了

  1. 先上,maven引用,因为好久没有使用ssm框架了,所以直接就上ssm了,当练手了~

  <properties>
    <cxf.version>3.1.12</cxf.version>
  </properties>

  <dependencies>
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>3.8.1</version>
      <scope>test</scope>
    </dependency>

    <!-- 2.数据库 -->
    <dependency>
      <groupId>mysql</groupId>
      <artifactId>mysql-connector-java</artifactId>
      <version>5.1.37</version>
      <scope>runtime</scope>
    </dependency>
    <dependency>
      <groupId>c3p0</groupId>
      <artifactId>c3p0</artifactId>
      <version>0.9.1.2</version>
    </dependency>

    <!-- DAO: MyBatis -->
    <dependency>
      <groupId>org.mybatis</groupId>
      <artifactId>mybatis</artifactId>
      <version>3.3.0</version>
    </dependency>
    <dependency>
      <groupId>org.mybatis</groupId>
      <artifactId>mybatis-spring</artifactId>
      <version>1.2.3</version>
    </dependency>
    <!-- 4.Spring -->
    <!-- 1)Spring核心 -->
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-core</artifactId>
      <version>4.1.7.RELEASE</version>
    </dependency>
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-beans</artifactId>
      <version>4.1.7.RELEASE</version>
    </dependency>
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-context</artifactId>
      <version>4.1.7.RELEASE</version>
    </dependency>
    <!-- 2)Spring DAO层 -->
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-jdbc</artifactId>
      <version>4.1.7.RELEASE</version>
    </dependency>
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-tx</artifactId>
      <version>4.1.7.RELEASE</version>
    </dependency>
    <!-- 3)Spring web -->
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-web</artifactId>
      <version>4.1.7.RELEASE</version>
    </dependency>
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-webmvc</artifactId>
      <version>4.1.7.RELEASE</version>
    </dependency>
    <!--cxf-->
    <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>
  1. 创建spring-dao.xml、mybatis-config.xml、jdbc.properties....反正就是ssm框架那一套,作为本文非主要内容,不做讲解了,主要讲一下cxf的配置——创建spring-cxf.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:jaxws="http://cxf.apache.org/jaxws"
       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">

    <!-- 该文件是在cxf-core-3.1.12.jar的类路径下的META-INF/cxf/cxf.xml -->
    <import resource="classpath:META-INF/cxf/cxf.xml"/>
<!--wsdl的访问地址为web.xml中cxf的前缀+fileReceive-->
  <jaxws:server address="business" serviceClass="com.demo.cxf.FileReceive">
        <!-- 服务接口的实现类 -->
        <jaxws:serviceBean>
            <bean class="com.ssm.service.impl.BaseServiceImpl"></bean>
        </jaxws:serviceBean>
       <!-- <jaxws:inInterceptors>
            <bean class="org.apache.cxf.interceptor.LoggingInInterceptor"></bean>
        </jaxws:inInterceptors>
        <jaxws:outInterceptors>
            <bean class="org.apache.cxf.interceptor.LoggingOutInterceptor"></bean>
        </jaxws:outInterceptors>-->
    </jaxws:server>
</beans>


  1. 接下来是web.xml
 <!--spring-->
  <context-param>
    <param-name>contextConfigLocation</param-name>
    <!--因为在这就已经将cxf的xml导入进来了,所以别地方不用特殊导入了 -->
    <param-value>classpath:spring-*.xml</param-value>
  </context-param>
  <listener>
    <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
  </listener>


  <!-- 配置DispatcherServlet -->
  <servlet>
    <servlet-name>seckill-dispatcher</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <!-- 配置springMVC需要加载的配置文件
        spring-dao.xml,spring-service.xml,spring-web.xml
        Mybatis - > spring -> springmvc
     -->
    <init-param>
      <param-name>contextConfigLocation</param-name>
      <param-value>classpath:spring-*.xml</param-value>
    </init-param>
  </servlet>

  <servlet-mapping>
    <servlet-name>seckill-dispatcher</servlet-name>
    <!-- 默认匹配所有的请求 -->
    <url-pattern>/</url-pattern>
  </servlet-mapping>


  <!--cxf-->
  <servlet>
    <servlet-name>cxf</servlet-name>
    <servlet-class>org.apache.cxf.transport.servlet.CXFServlet</servlet-class>
  </servlet>
  <servlet-mapping>
    <servlet-name>cxf</servlet-name>
    <url-pattern>/ws/*</url-pattern>
  </servlet-mapping>
  1. 紧接着是要创建将要发布的接口和类
@WebService
@MTOM  //开启MTOM功能之后,能够发送文件信息
public interface BaseService {
    
     String sayHello(@XmlMimeType(value = "application/octet-stream") DataHandler name);
     //@XmlMimeType(value = "application/octet-stream")如果发送文件,这个是死格式,而且必须声明
}
  1. 然后是实现它,这个地方有个坑,就是如果你想传入文件进来,那么必须用InputStream.read(byte[] b)的方式获取文件,不然文件就是乱码(猜想了一下,因为cxf传输文件的类型必须是DataHandler,而这个类型是byte数组的),还有一个坑,就是必须把targetNamespace给写出来,value是类所在包名反过来(这个没怎么懂必须要这样的目的,暂时先按照教程来吧)
@WebService(endpointInterface="com.ssm.service.BaseService",targetNamespace="http://service.ssm.com/")
public class BaseServiceImpl implements BaseService {
   

    public String sayHello(DataHandler name) {
        InputStream sn = null;
        OutputStream bw = null;
        try{
            bw = new FileOutputStream("d:/dsd.jpg");
            sn = name.getInputStream();

            byte[] bytes = new byte[1024];
            int i=-1;
            while ((i=sn.read(bytes))!=-1){
                bw.write(bytes,0,i);
            }
        }catch (Exception e){
            e.printStackTrace();
        }finally {
            try{
                sn.close();
                bw.close();
            }catch (Exception e){
                e.printStackTrace();
            }
        }

        return "ok";
    }


}

  1. 好了,这就是最简单的cxf服务端配置方式了,装上tomcat测试一下看看有没有发布成功吧

路径: http://localhost:9090/ws/business?wsdl

简单的说一下路径为什么是这个,前面的就不说了,主要说说为什么是/ws,这个实在web.xml中定义的,在servlet-mapping中的url上,/business就是在spring-cxf.xml中定义的了,在发布时定义的——jaxws:endpoint的address指定了url最终路径。

  1. 简单的创建一个客户端访问一下吧(采用JaxWsDynamicClientFactory的方式访问,有点和服务端完全解耦,不依靠服务端的任何文件)
  JaxWsDynamicClientFactory dynamicClient = JaxWsDynamicClientFactory.newInstance();
        Client client = dynamicClient.createClient("http://localhost:9090/ws/business?wsdl");


        DataHandler dataHandler = new DataHandler( new FileDataSource(new File("98226cffc175d.jpg")));

        Object[] o = client.invoke("sayHello",dataHandler);

一下为加入账号密码验证

  1. 服务端现在加入账号验证(在接受时拦截,查看账号密码,匹配)
import java.util.List;

import javax.xml.soap.SOAPException;

import org.apache.cxf.binding.soap.SoapHeader;
import org.apache.cxf.binding.soap.SoapMessage;
import org.apache.cxf.common.util.StringUtils;
import org.apache.cxf.headers.Header;
import org.apache.cxf.interceptor.Fault;
import org.apache.cxf.phase.AbstractPhaseInterceptor;
import org.apache.cxf.phase.Phase;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;

public class AuthIntercetpr extends  AbstractPhaseInterceptor<SoapMessage> {
    private static final String USERNAME="root";
    private static final String PASSWORD="admin";

    public AuthIntercetpr() {
        //定义在哪个阶段进行拦截
        super(Phase.PRE_PROTOCOL);
    }



    public void handleMessage(SoapMessage soapMessage) throws Fault {
        List<Header> headers = null;
        String username=null;
        String password=null;
        try {
            headers = soapMessage.getHeaders();
        } catch (Exception e) {
        }

        if (headers == null) {
            throw new Fault(new IllegalArgumentException("找不到Header,无法验证用户信息"));
        }
        //获取用户名,密码
        for (Header header : headers) {
            SoapHeader soapHeader = (SoapHeader) header;
            Element e = (Element) soapHeader.getObject();
            NodeList usernameNode = e.getElementsByTagName("username");
            NodeList pwdNode = e.getElementsByTagName("password");
            username=usernameNode.item(0).getTextContent();
            password=pwdNode.item(0).getTextContent();
            if( StringUtils.isEmpty(username)||StringUtils.isEmpty(password)){
                throw new Fault(new IllegalArgumentException("用户信息为空"));
            }
        }
        //校验用户名密码
        if(!(username.equals(USERNAME) && password.equals(PASSWORD))){
            SOAPException soapExc = new SOAPException("认证失败");
            throw new Fault(soapExc);
        }

    }
}
  1. spring-cxf.xml修改为
<!-- 该文件是在cxf-core-3.1.12.jar的类路径下的META-INF/cxf/cxf.xml -->
    <import resource="classpath:META-INF/cxf/cxf.xml"/>
    <!--发布出去,请求就是http:xxxxxxxxxx/business?wsdl-->
      <jaxws:server address="business" serviceClass="com.demo.cxf.FileReceive">
        <!-- 服务接口的实现类 -->
        <jaxws:serviceBean>
            <bean class="com.ssm.service.impl.BaseServiceImpl"></bean>
        </jaxws:serviceBean>
      <jaxws:inInterceptors>
            <bean class="com.ssm.interceptor.AuthIntercetpr"></bean>
        </jaxws:inInterceptors>
        <!-- <jaxws:outInterceptors>
           <bean class="org.apache.cxf.interceptor.LoggingOutInterceptor"></bean>
       </jaxws:outInterceptors>-->
    </jaxws:server>
  1. 客户端也要加入拦截器
import org.apache.cxf.binding.soap.SoapMessage;
import org.apache.cxf.headers.Header;
import org.apache.cxf.helpers.DOMUtils;
import org.apache.cxf.interceptor.Fault;
import org.apache.cxf.phase.AbstractPhaseInterceptor;
import org.apache.cxf.phase.Phase;
import org.w3c.dom.Document;
import org.w3c.dom.Element;

import javax.xml.namespace.QName;
import java.util.List;

public class LoginInterceptor extends AbstractPhaseInterceptor<SoapMessage> {
    private String username="root";
    private String password="admin";
    public LoginInterceptor(String username, String password) {
        //设置在发送请求前阶段进行拦截
        super(Phase.PREPARE_SEND);
        this.username=username;
        this.password=password;
    }

    @Override
    public void handleMessage(SoapMessage soapMessage) throws Fault {
        List<Header> headers = soapMessage.getHeaders();
        Document doc = DOMUtils.createDocument();
        Element auth = doc.createElementNS("http://service.ssm.com/","SecurityHeader");
        Element UserName = doc.createElement("username");
        Element UserPass = doc.createElement("password");

        UserName.setTextContent(username);
        UserPass.setTextContent(password);

        auth.appendChild(UserName);
        auth.appendChild(UserPass);

        headers.add(new Header(new QName("SecurityHeader"),auth));
    }
}

  1. 在请求时加入拦截器
  JaxWsDynamicClientFactory dynamicClient = JaxWsDynamicClientFactory.newInstance();
        Client client = dynamicClient.createClient("http://localhost:9090/ws/business?wsdl");

        //加入拦截器
        client.getOutInterceptors().add(new LoginInterceptor("root","admin"));

        DataHandler dataHandler = new DataHandler(
                new FileDataSource(new File("C:\\Users\\lht\\Desktop\\a\\a.jpg")));
        Object[] o = client.invoke("sayHello",dataHandler);
        System.out.println();

留下点问题,看看等什么时候去研究一下

  1. 因为这个还是传统的SOAP方式,什么时候看一下REST风格WebService,据说很厉害的样子
  2. ...

相关文章

  • ssm+cxf3.0

    近期需要使用webService,所以看了一下目前比较常用的几个webservie框架,经过比较,最终决定使用能和...

网友评论

      本文标题:ssm+cxf3.0

      本文链接:https://www.haomeiwen.com/subject/olvfqftx.html