ssm+cxf3.0

近期需要使用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. ...
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 220,809评论 6 513
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 94,189评论 3 395
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 167,290评论 0 359
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 59,399评论 1 294
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 68,425评论 6 397
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 52,116评论 1 308
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,710评论 3 420
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,629评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 46,155评论 1 319
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 38,261评论 3 339
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,399评论 1 352
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 36,068评论 5 347
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,758评论 3 332
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,252评论 0 23
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,381评论 1 271
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,747评论 3 375
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,402评论 2 358

推荐阅读更多精彩内容

  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,681评论 18 139
  • Spring Boot 参考指南 介绍 转载自:https://www.gitbook.com/book/qbgb...
    毛宇鹏阅读 46,836评论 6 342
  • 授课教师Tal。【本讲简介】根据六度分隔理论,全人类都是相互关联的,能相互影响,改变有很大的力量。改变是困难的,但...
    金石明镜阅读 1,374评论 0 8
  • 烤了芝士饺子皮 好吃 饼干失败了 需要温度低一点 多烤一会儿 配方:鸡蛋 面粉 小苏打 蜂蜜 柠檬 因为家里只有水...
    角落蜷缩阅读 160评论 0 0
  • # adf
    没我怎么行阅读 95评论 0 1