SpringMCV 整合 apache cxf-jaxrs 实现 WebService功能

一、创建项目

首先创建一个 SSM 的项目,我这里用的是一个开源的框架 jeesite1.2.7。大家也可以了解下这个框架。

二、添加 pom.xml 依赖

在项目pom.xml中的 dependencies标签内加入一下代码,添加后下载依赖即可。

        <!-- WebService cxf-jaxrs 开始 -->
        <!-- WebService cxf-jaxrs 架包 -->
        <dependency>
            <groupId>org.apache.cxf</groupId>
            <artifactId>cxf-rt-frontend-jaxrs</artifactId>
            <version>3.0.16</version>
        </dependency>

        <!-- WebService cxf-jaxrs 客户端架包 -->
        <dependency>
            <groupId>org.apache.cxf</groupId>
            <artifactId>cxf-rt-rs-client</artifactId>
            <version>3.0.16</version>
        </dependency>
		
		<!-- 生成 xml 文档 -->
        <dependency>
            <groupId>org.apache.cxf</groupId>
            <artifactId>cxf-rt-rs-service-description</artifactId>
            <version>3.0.16</version>
        </dependency>

        <!-- cxf-jaxrs中转换 json -->
        <dependency>
            <groupId>com.fasterxml.jackson.jaxrs</groupId>
            <artifactId>jackson-jaxrs-json-provider</artifactId>
            <version>2.2.3</version>
        </dependency>
        <!-- WebService cxf-jaxrs 结束 -->

三、web.xml 添加 CXFServlet

WEB-INF文件夹下的web.xml中加入一下代码。这作用是拦截/webService/* 的所有请求

    <!-- WebService cxf-jaxrs -->
    <servlet>
        <servlet-name>cxfServlet</servlet-name>
        <servlet-class>org.apache.cxf.transport.servlet.CXFServlet</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>cxfServlet</servlet-name>
        <url-pattern>/webService/*</url-pattern>
    </servlet-mapping>

四、添加 log4j.properties 文件

resources文件夹下创建log4j.properties文件,添加一下代码。其中log4j.logger.org.apache.cxf=INFO这句代码是打印cxf-jaxrs请求和相应的信息。

# Output pattern : date [thread] priority category - message   FATAL 0  ERROR 3  WARN 4  INFO 6  DEBUG 7 
log4j.rootLogger=WARN, Console, RollingFile

#Console
log4j.appender.Console=org.apache.log4j.ConsoleAppender
log4j.appender.Console.layout=org.apache.log4j.PatternLayout
log4j.appender.Console.layout.ConversionPattern=%d %-5p [%c{5}] - %m%n

#RollingFile
log4j.appender.RollingFile=org.apache.log4j.DailyRollingFileAppender
log4j.appender.RollingFile.File=../logs/jeesite/jeesite.log
log4j.appender.RollingFile.layout=org.apache.log4j.PatternLayout
log4j.appender.RollingFile.layout.ConversionPattern=%d [%t] %-5p [%c] - %m%n

#log4j.logger.java.sql=DEBUG

#Springframework level
#log4j.logger.org.springframework=ERROR

#Hibernate level
#log4j.logger.org.hibernate=ERROR
#log4j.logger.org.hibernate.cache.ehcache.AbstractEhcacheRegionFactory=ERROR
#log4j.logger.org.hibernate.search.impl.ConfigContext=ERROR
#log4j.logger.net.sf.ehcache.config.CacheConfiguration=ERROR

#Project defalult level
#log4j.logger.org.activiti.engine.impl.persistence=DEBUG
#log4j.logger.org.apache.shiro=DEBUG
log4j.logger.com.thinkgem.jeesite=DEBUG
log4j.logger.com.thinkgem.jeesite.common.security.shiro=WARN
log4j.logger.com.thinkgem.jeesite.common.utils.JedisUtils=WARN
log4j.logger.com.thinkgem.jeesite.modules.sys.web.LoginController=WARN
log4j.logger.com.thinkgem.jeesite.modules.oa.dao.OaNotifyDao.findCount=WARN

#项目log信息输出
log4j.logger.com.project=DEBUG

#打印 WebService cxf-jaxrs 的请求日志
log4j.logger.org.apache.cxf=INFO

五、创建 Service 接口

创建一下代码接口。

  • @Produces:表示 server端返回的数据类型(以下代码返回的是JOSN数据)
  • @Consumes:表示 从client端接受的数据类型(以下代码接收的是JOSN数据)
  • @Path:代码请求的路径
  • @POST:POST请求
  • @DELETE:DELETE请求
  • @PUT:PUT请求
  • @GET:GET请求
import com.project.modules.mdm.entity.MdmMaterial;
import com.project.modules.ws.common.MdmRequestData;
import com.project.modules.ws.common.MdmResponseData;
import org.apache.cxf.jaxrs.model.wadl.Description;
import org.apache.cxf.jaxrs.model.wadl.DocTarget;

import javax.ws.rs.Consumes;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;

/**
 * 同步数据 WebService
 * <p>
 * 增:POST
 * 删:DELETE
 * 改:PUT
 * 查:GET
 *
 * @author YJH
 * @date 2019-05-27
 */
@Description(value = "数据同步WebService", target = DocTarget.RESOURCE)
@Produces({MediaType.APPLICATION_JSON})
@Consumes({MediaType.APPLICATION_JSON})
public interface WsSyncDataService {


    /**
     * 保存主数据-物料信息
     *
     * @param requestData MdmRequestData
     * @return MdmResponseData
     */
    @POST
    @Path("/saveMdmMaterialInfo")
    @Description(value = "保存主数据-物料信息(POST请求,携带请求体)", target = DocTarget.METHOD)
    MdmResponseData saveMdmMaterialInfo(MdmRequestData<MdmMaterial> requestData);
}

MdmRequestData类代码

import java.util.List;

/**
 * 主数据接口请求 RequestData
 *
 * @author YJH
 * @date 2019-05-29
 */
public class MdmRequestData<T> {

    private String packId;
    private String packageId;
    private String mdmNameEn;
    private List<T> list;

    public MdmRequestData() {
    }

    public String getPackId() {
        return packId;
    }

    public void setPackId(String packId) {
        this.packId = packId;
    }

    public String getPackageId() {
        return packageId;
    }

    public void setPackageId(String packageId) {
        this.packageId = packageId;
    }

    public String getMdmNameEn() {
        return mdmNameEn;
    }

    public void setMdmNameEn(String mdmNameEn) {
        this.mdmNameEn = mdmNameEn;
    }

    public List<T> getList() {
        return list;
    }

    public void setList(List<T> list) {
        this.list = list;
    }
}

MdmResponseData类代码

import java.util.HashMap;
import java.util.Map;

/**
 * 主数据接口返回 ResponseData
 *
 * @author YJH
 * @date 2019-05-29
 */
public class MdmResponseData extends HashMap<String, Object> {

    private static final long serialVersionUID = 1L;

    /**
     * 标志,成功“1”,失败“0”。
     */
    private static final String RESULT = "result";
    /**
     * 请求返回信息,返回成功或错误信息
     */
    private static final String MSG = "msg";

    public MdmResponseData() {
        put(RESULT, 1);
        put(MSG, "success");
    }

    public static MdmResponseData error() {
        return error(0, "未知异常,请联系管理员");
    }

    public static MdmResponseData error(String msg) {
        return error(0, msg);
    }

    public static MdmResponseData error(int result, String msg) {
        MdmResponseData data = new MdmResponseData();
        data.put(RESULT, result);
        data.put(MSG, msg);
        return data;
    }

    public static MdmResponseData ok(String msg) {
        MdmResponseData data = new MdmResponseData();
        data.put(MSG, msg);
        return data;
    }

    @SuppressWarnings("unchecked")
    public static MdmResponseData ok(Map<String, Object> map) {
        MdmResponseData data = new MdmResponseData();
        data.putAll(map);
        return data;
    }

    public static MdmResponseData ok() {
        return new MdmResponseData();
    }

    @Override
    public MdmResponseData put(String key, Object value) {
        super.put(key, value);
        return this;
    }
}

MdmMaterial实体类代码。这个类命名太不规范了,请大家忽略 !


import com.fasterxml.jackson.annotation.JsonProperty;
import com.google.common.collect.Lists;
import com.thinkgem.jeesite.common.persistence.DataEntity;
import org.hibernate.validator.constraints.Length;

import java.util.List;

/**
 * 生产材料档案Entity
 *
 * @author xp
 * @version 2019-05-28
 */
public class MdmMaterial extends DataEntity<MdmMaterial> {

    private static final long serialVersionUID = 1L;

    public static final String TableName = "mdm_material";  //表名

    @JsonProperty(value = "CODE")
    private String CODE;    // 物料编码
    @JsonProperty(value = "NAME")
    private String NAME;    // 物料名称
    @JsonProperty(value = "MAT_TYPE")
    private String MAT_TYPE;    // 物料类型
    @JsonProperty(value = "MAT_BASE_UOM")
    private String MAT_BASE_UOM;    // 物料基地计量单位
    @JsonProperty(value = "MAT_INDUSTRY")
    private String MAT_INDUSTRY;    // 物料业
    @JsonProperty(value = "MAT_APPLY_PLANT")
    private String MAT_APPLY_PLANT; // 物料生产商
    @JsonProperty(value = "MAT_DESC")
    private String MAT_DESC;    // 物料信息描述
    @JsonProperty(value = "MAT_DETAIL_DESC")
    private String MAT_DETAIL_DESC; // 物料信息具体描述
    @JsonProperty(value = "MAT_PRODUCT_GROUP")
    private String MAT_PRODUCT_GROUP;   // 物料生产组
    @JsonProperty(value = "MAT_WEIGHT_UNIT")
    private String MAT_WEIGHT_UNIT; // 物料单位
    @JsonProperty(value = "MAT_GROUP_CODE")
    private String MAT_GROUP_CODE;  // 物料组编码
    @JsonProperty(value = "MAT_NORMAL_PROJ_GROUP")
    private String MAT_NORMAL_PROJ_GROUP;   // 物料标准项目组
    @JsonProperty(value = "MAT_OVER_FACTORY_STATUS")
    private String MAT_OVER_FACTORY_STATUS; // 物料在厂状态
    @JsonProperty(value = "MAT_PROC_STRATEGY")
    private String MAT_PROC_STRATEGY;   // 物料代理商
    @JsonProperty(value = "MAT_STANDARD")
    private String MAT_STANDARD;    // 物料标准化
    @JsonProperty(value = "MAT_DATA_PROVIDER")
    private String MAT_DATA_PROVIDER;   // 物料数据供应商
    @JsonProperty(value = "MAT_OLD_NUM")
    private String MAT_OLD_NUM; // 物料排序号
    private String assignee;    // assignee
    private String assigneemc;  // assigneemc
    private String createdt;    // createdt
    private String createId;    // create_id
    private String createName;  // create_name
    private String deptid;  // deptid
    private String fkid;    // fkid
    private String lcid;    // lcid
    private String mdmNameCn;   // mdm_name_cn
    private String organization;    // organization
    private String packid;  // packid
    private String states;  // states
    private String szhj;    // szhj
    private String szhjmc;  // szhjmc
    private String unit;    // unit
    private String updatedt;    // updatedt
    private String updateId;    // update_id
    private String updateName;  // update_name
    // 子表列表
    @JsonProperty(value = "MDM_MATERIAL_ATTRIBUTE")
    private List<MdmMaterialAttribute> MDM_MATERIAL_ATTRIBUTE = Lists.newArrayList();

    public MdmMaterial() {
        super();
    }

    public MdmMaterial(String id) {
        super(id);
    }

    public String getCODE() {
        return CODE;
    }

    public void setCODE(String CODE) {
        this.CODE = CODE;
    }

    public String getNAME() {
        return NAME;
    }

    public void setNAME(String NAME) {
        this.NAME = NAME;
    }

    public String getMAT_TYPE() {
        return MAT_TYPE;
    }

    public void setMAT_TYPE(String MAT_TYPE) {
        this.MAT_TYPE = MAT_TYPE;
    }

    public String getMAT_BASE_UOM() {
        return MAT_BASE_UOM;
    }

    public void setMAT_BASE_UOM(String MAT_BASE_UOM) {
        this.MAT_BASE_UOM = MAT_BASE_UOM;
    }

    public String getMAT_INDUSTRY() {
        return MAT_INDUSTRY;
    }

    public void setMAT_INDUSTRY(String MAT_INDUSTRY) {
        this.MAT_INDUSTRY = MAT_INDUSTRY;
    }

    public String getMAT_APPLY_PLANT() {
        return MAT_APPLY_PLANT;
    }

    public void setMAT_APPLY_PLANT(String MAT_APPLY_PLANT) {
        this.MAT_APPLY_PLANT = MAT_APPLY_PLANT;
    }

    public String getMAT_DESC() {
        return MAT_DESC;
    }

    public void setMAT_DESC(String MAT_DESC) {
        this.MAT_DESC = MAT_DESC;
    }

    public String getMAT_DETAIL_DESC() {
        return MAT_DETAIL_DESC;
    }

    public void setMAT_DETAIL_DESC(String MAT_DETAIL_DESC) {
        this.MAT_DETAIL_DESC = MAT_DETAIL_DESC;
    }

    public String getMAT_PRODUCT_GROUP() {
        return MAT_PRODUCT_GROUP;
    }

    public void setMAT_PRODUCT_GROUP(String MAT_PRODUCT_GROUP) {
        this.MAT_PRODUCT_GROUP = MAT_PRODUCT_GROUP;
    }

    public String getMAT_WEIGHT_UNIT() {
        return MAT_WEIGHT_UNIT;
    }

    public void setMAT_WEIGHT_UNIT(String MAT_WEIGHT_UNIT) {
        this.MAT_WEIGHT_UNIT = MAT_WEIGHT_UNIT;
    }

    public String getMAT_GROUP_CODE() {
        return MAT_GROUP_CODE;
    }

    public void setMAT_GROUP_CODE(String MAT_GROUP_CODE) {
        this.MAT_GROUP_CODE = MAT_GROUP_CODE;
    }

    public String getMAT_NORMAL_PROJ_GROUP() {
        return MAT_NORMAL_PROJ_GROUP;
    }

    public void setMAT_NORMAL_PROJ_GROUP(String MAT_NORMAL_PROJ_GROUP) {
        this.MAT_NORMAL_PROJ_GROUP = MAT_NORMAL_PROJ_GROUP;
    }

    public String getMAT_OVER_FACTORY_STATUS() {
        return MAT_OVER_FACTORY_STATUS;
    }

    public void setMAT_OVER_FACTORY_STATUS(String MAT_OVER_FACTORY_STATUS) {
        this.MAT_OVER_FACTORY_STATUS = MAT_OVER_FACTORY_STATUS;
    }

    public String getMAT_PROC_STRATEGY() {
        return MAT_PROC_STRATEGY;
    }

    public void setMAT_PROC_STRATEGY(String MAT_PROC_STRATEGY) {
        this.MAT_PROC_STRATEGY = MAT_PROC_STRATEGY;
    }

    public String getMAT_STANDARD() {
        return MAT_STANDARD;
    }

    public void setMAT_STANDARD(String MAT_STANDARD) {
        this.MAT_STANDARD = MAT_STANDARD;
    }

    public String getMAT_DATA_PROVIDER() {
        return MAT_DATA_PROVIDER;
    }

    public void setMAT_DATA_PROVIDER(String MAT_DATA_PROVIDER) {
        this.MAT_DATA_PROVIDER = MAT_DATA_PROVIDER;
    }

    public String getMAT_OLD_NUM() {
        return MAT_OLD_NUM;
    }

    public void setMAT_OLD_NUM(String MAT_OLD_NUM) {
        this.MAT_OLD_NUM = MAT_OLD_NUM;
    }

    @Length(min = 0, max = 32, message = "assignee长度必须介于 0 和 32 之间")
    public String getAssignee() {
        return assignee;
    }

    public void setAssignee(String assignee) {
        this.assignee = assignee;
    }

    @Length(min = 0, max = 240, message = "assigneemc长度必须介于 0 和 240 之间")
    public String getAssigneemc() {
        return assigneemc;
    }

    public void setAssigneemc(String assigneemc) {
        this.assigneemc = assigneemc;
    }

    @Length(min = 0, max = 128, message = "createdt长度必须介于 0 和 128 之间")
    public String getCreatedt() {
        return createdt;
    }

    public void setCreatedt(String createdt) {
        this.createdt = createdt;
    }

    @Length(min = 0, max = 32, message = "create_id长度必须介于 0 和 32 之间")
    public String getCreateId() {
        return createId;
    }

    public void setCreateId(String createId) {
        this.createId = createId;
    }

    @Length(min = 0, max = 128, message = "create_name长度必须介于 0 和 128 之间")
    public String getCreateName() {
        return createName;
    }

    public void setCreateName(String createName) {
        this.createName = createName;
    }

    @Length(min = 0, max = 128, message = "deptid长度必须介于 0 和 128 之间")
    public String getDeptid() {
        return deptid;
    }

    public void setDeptid(String deptid) {
        this.deptid = deptid;
    }

    @Length(min = 0, max = 32, message = "fkid长度必须介于 0 和 32 之间")
    public String getFkid() {
        return fkid;
    }

    public void setFkid(String fkid) {
        this.fkid = fkid;
    }

    @Length(min = 0, max = 100, message = "lcid长度必须介于 0 和 100 之间")
    public String getLcid() {
        return lcid;
    }

    public void setLcid(String lcid) {
        this.lcid = lcid;
    }

    @Length(min = 0, max = 128, message = "mdm_name_cn长度必须介于 0 和 128 之间")
    public String getMdmNameCn() {
        return mdmNameCn;
    }

    public void setMdmNameCn(String mdmNameCn) {
        this.mdmNameCn = mdmNameCn;
    }

    @Length(min = 0, max = 128, message = "organization长度必须介于 0 和 128 之间")
    public String getOrganization() {
        return organization;
    }

    public void setOrganization(String organization) {
        this.organization = organization;
    }

    @Length(min = 0, max = 32, message = "packid长度必须介于 0 和 32 之间")
    public String getPackid() {
        return packid;
    }

    public void setPackid(String packid) {
        this.packid = packid;
    }

    @Length(min = 0, max = 32, message = "states长度必须介于 0 和 32 之间")
    public String getStates() {
        return states;
    }

    public void setStates(String states) {
        this.states = states;
    }

    @Length(min = 0, max = 100, message = "szhj长度必须介于 0 和 100 之间")
    public String getSzhj() {
        return szhj;
    }

    public void setSzhj(String szhj) {
        this.szhj = szhj;
    }

    @Length(min = 0, max = 200, message = "szhjmc长度必须介于 0 和 200 之间")
    public String getSzhjmc() {
        return szhjmc;
    }

    public void setSzhjmc(String szhjmc) {
        this.szhjmc = szhjmc;
    }

    @Length(min = 0, max = 32, message = "unit长度必须介于 0 和 32 之间")
    public String getUnit() {
        return unit;
    }

    public void setUnit(String unit) {
        this.unit = unit;
    }

    @Length(min = 0, max = 128, message = "updatedt长度必须介于 0 和 128 之间")
    public String getUpdatedt() {
        return updatedt;
    }

    public void setUpdatedt(String updatedt) {
        this.updatedt = updatedt;
    }

    @Length(min = 0, max = 32, message = "update_id长度必须介于 0 和 32 之间")
    public String getUpdateId() {
        return updateId;
    }

    public void setUpdateId(String updateId) {
        this.updateId = updateId;
    }

    @Length(min = 0, max = 128, message = "update_name长度必须介于 0 和 128 之间")
    public String getUpdateName() {
        return updateName;
    }

    public void setUpdateName(String updateName) {
        this.updateName = updateName;
    }

    public List<MdmMaterialAttribute> getMDM_MATERIAL_ATTRIBUTE() {
        return MDM_MATERIAL_ATTRIBUTE;
    }

    public void setMDM_MATERIAL_ATTRIBUTE(List<MdmMaterialAttribute> MDM_MATERIAL_ATTRIBUTE) {
        this.MDM_MATERIAL_ATTRIBUTE = MDM_MATERIAL_ATTRIBUTE;
    }
}

六、实现 Service 接口

实现上一步创建的接口创建WsSyncDataServiceImpl

import com.fasterxml.jackson.core.type.TypeReference;
import com.project.modules.mdm.entity.MdmMaterial;
import com.project.modules.mdm.entity.MdmMaterialAttribute;
import com.project.modules.mdm.service.MdmMaterialService;
import com.project.modules.ws.common.MdmRequestData;
import com.project.modules.ws.common.MdmResponseData;
import com.project.modules.ws.service.WsSyncDataService;
import com.thinkgem.jeesite.common.mapper.JsonMapper;
import org.apache.commons.collections.CollectionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.List;

/**
 * WebService 同步数据 Service
 *
 * @author YJH
 * @date 2019-05-27
 */
@Component("wsSyncDataServiceImpl")
@Transactional(readOnly = true)
public class WsSyncDataServiceImpl implements WsSyncDataService {

    @Autowired
    private MdmMaterialService mdmMaterialService;

    /**
     * 保存主数据-物料信息
     *
     * @param requestData MdmRequestData
     * @return MdmResponseData
     */
    @Transactional
    @Override
    public MdmResponseData saveMdmMaterialInfo(MdmRequestData<MdmMaterial> requestData) {
        try {
            String tableName = requestData.getMdmNameEn();
            if (tableName.equalsIgnoreCase(MdmMaterial.TableName)) {
                mdmMaterialSave(requestData);
            }
            return MdmResponseData.ok();
        } catch (Exception e) {
            e.printStackTrace();
            return MdmResponseData.error();
        }
    }

    /**
     * 物料保存
     *
     * @param requestData MdmRequestData
     */
    private void mdmMaterialSave(MdmRequestData<MdmMaterial> requestData) {
        List<MdmMaterial> mapList = new ArrayList<>();
        CollectionUtils.addAll(mapList, requestData.getList().toArray());

        List<MdmMaterial> list = JsonMapper.getInstance().convertValue(mapList, new TypeReference<List<MdmMaterial>>() {
        });
        for (MdmMaterial material : list) {
            List<MdmMaterialAttribute> mdmMaterialAttributeList = material.getMDM_MATERIAL_ATTRIBUTE();
            for (MdmMaterialAttribute attribute : mdmMaterialAttri            mdmMaterialService.save(material);
        }
    }
}

七、创建一些整合的基本类

  • 创建解析 cxf-jaxrs 的提供者
import com.fasterxml.jackson.databind.DeserializationFeature;

/**
 * 解析 cxf-jaxrs 的提供者
 *
 * @author YJH
 * @date 2019-05-27
 */
public class JacksonJaxbJsonProvider extends com.fasterxml.jackson.jaxrs.json.JacksonJaxbJsonProvider {

    public JacksonJaxbJsonProvider() {
        configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
    }
}
  • 创建 WebService录认证异常类
/**
 * WebService 登录认证异常
 *
 * @author YJH
 * @date 2019-05-27
 */
public class WsAuthenticateException extends Exception {

    public WsAuthenticateException(String message) {
        super(message);
    }
}
  • 创建 WebService 统一异常处理提供者
import javax.ws.rs.core.Response;
import javax.ws.rs.ext.ExceptionMapper;

/**
 * WebService 统一异常处理
 * 参考:
 * <a>https://blog.csdn.net/forlinkext/article/details/78115640</a>
 * <a>https://blog.csdn.net/love_hanyu/article/details/84352763</a>
 *
 * @author YJH
 * @date 2019-05-27
 */
public class WsExceptionMapper implements ExceptionMapper<Exception> {

    @Override
    public Response toResponse(Exception e) {
        String type = "application/json;charset=UTF-8";
        if (e instanceof WsAuthenticateException) {
            MdmResponseData responseData = MdmResponseData.error(e.getMessage());
            return Response.status(Response.Status.BAD_REQUEST).entity(responseData).type(type).build();
        } else {
            MdmResponseData responseData = MdmResponseData.error("未知错误,请稍后重试");
            return Response.status(Response.Status.BAD_REQUEST).entity(responseData).type(type).build();
        }
    }
}

  • 创建认证拦截器
import com.thinkgem.jeesite.common.utils.StringUtils;
import org.apache.cxf.configuration.security.AuthorizationPolicy;
import org.apache.cxf.interceptor.Fault;
import org.apache.cxf.message.Message;
import org.apache.cxf.phase.AbstractPhaseInterceptor;
import org.apache.cxf.phase.Phase;

/**
 * WebService 登录认证拦截器
 * 参考:
 * <a>https://blog.csdn.net/u014695188/article/details/51731116</a> *
 *
 * @author YJH
 * @date 2019-05-27
 */
public class AuthenticateInterceptor extends AbstractPhaseInterceptor {

    public static final String userName = "username";
    public static final String password = "password";

    public AuthenticateInterceptor() {
        this(Phase.PRE_PROTOCOL);
        //this(Phase.PRE_INVOKE);
    }

    public AuthenticateInterceptor(String phase) {
        super(phase);
        System.out.println("CheckUserInterceptor(String phase)");
    }

    @Override
    public void handleMessage(Message message) throws Fault {
        try {
            AuthorizationPolicy authorizationPolicy = (AuthorizationPolicy) message.get("org.apache.cxf.configuration.security.AuthorizationPolicy");
            String userName = authorizationPolicy.getUserName();
            String password = authorizationPolicy.getPassword();
            if (StringUtils.isBlank(userName) || StringUtils.isBlank(password)) {
                throw new Fault(new WsAuthenticateException("账号和密码都不能为空"));
            }
            if (!AuthenticateInterceptor.userName.equals(userName) || !AuthenticateInterceptor.password.equals(password)) {
                throw new Fault(new WsAuthenticateException("账号或密码校验失败"));
            }
        } catch (Exception e) {
            throw new Fault(new WsAuthenticateException("账号和密码都不能为空"));
        }
    }

    @Override
    public void handleFault(Message message) {
    }
}

以上就完成了服务端的kbd>java代码编写

八、添加 cxf-jaxrs 和 spring 整合的 xml

resources文件夹下创建spring-context-cxf-jaxrs.xml。
这里要注意由于我用的是jeesite框架,可以把这个spring配置文件直接引用,如果不是用这个框架需要手动引用这个文件

  • <jaxrs:server address="/wsUserService">这表示暴露出的接口的地址
  • <ref bean=“wsUserServiceImpl”/>WsUserService接口的实现类
<?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:context="http://www.springframework.org/schema/context"
       xmlns:jaxrs="http://cxf.apache.org/jaxrs"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans-4.1.xsd
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context-4.1.xsd
        http://cxf.apache.org/jaxrs
        http://cxf.apache.org/schemas/jaxrs.xsd"
       default-lazy-init="true">

    <description>cxf-jaxrs Configuration</description>

    <!-- 加载配置属性文件 -->
    <context:property-placeholder ignore-unresolvable="true" location="classpath:jeesite.properties"/>

    <bean id="jacksonJaxbJsonProvider" class="com.project.modules.ws.common.JacksonJaxbJsonProvider"/>
    <!--<bean id="jacksonJaxbJsonProvider" class="com.fasterxml.jackson.jaxrs.json.JacksonJsonProvider"/>-->

    <bean id="loggingInInterceptor" class="org.apache.cxf.interceptor.LoggingInInterceptor"/>
    <bean id="loggingOutInterceptor" class="org.apache.cxf.interceptor.LoggingOutInterceptor"/>

    <bean id="wsAuthenticateInterceptor" class="com.project.modules.ws.common.AuthenticateInterceptor"/>
    <bean id="wsExceptionMapper" class="com.project.modules.ws.common.WsExceptionMapper"/>


    <!-- 配置需要暴露的 Service -->
    <jaxrs:server address="/wsSyncDataService">
        <jaxrs:serviceBeans>
            <ref bean="wsSyncDataServiceImpl"/>
        </jaxrs:serviceBeans>
        <!-- 提供一个json转化,没有这个不能自动返回json -->
        <jaxrs:providers>
            <ref bean="jacksonJaxbJsonProvider"/>
            <ref bean="wsExceptionMapper"/>
        </jaxrs:providers>
        <!-- 请求日志拦截器 -->
        <jaxrs:inInterceptors>
            <ref bean="loggingInInterceptor"/>
            <ref bean="wsAuthenticateInterceptor"/>
        </jaxrs:inInterceptors>
        <!-- 响应日志拦截器 -->
        <jaxrs:outInterceptors>
            <ref bean="loggingOutInterceptor"/>
        </jaxrs:outInterceptors>
    </jaxrs:server>

九、测试

在测试包下创建测试类

import com.fasterxml.jackson.databind.DeserializationFeature;
import com.project.modules.ws.common.AuthenticateInterceptor;
import com.project.modules.ws.common.JacksonJaxbJsonProvider;
import com.project.modules.ws.common.MdmRequestData;
import com.project.modules.ws.common.MdmResponseData;
import com.thinkgem.jeesite.common.mapper.JsonMapper;
import com.thinkgem.jeesite.common.utils.StreamUtils;
import org.apache.cxf.jaxrs.client.ClientConfiguration;
import org.apache.cxf.jaxrs.client.WebClient;
import org.apache.cxf.transport.Conduit;
import org.apache.cxf.transport.http.HTTPConduit;
import org.apache.cxf.transports.http.configuration.HTTPClientPolicy;
import org.junit.Test;

import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;

/**
 * 测试同步数据 WebService
 */
public class testWsSyncDataService {

    private String baseUrl = "http://localhost:8080/znzyc/webService/wsSyncDataService";

    @Test
    public void testSaveMdmInfo() {
        //假数据
        MdmRequestData<MdmRequestData> requestData = (MdmRequestData<MdmRequestData>) JsonMapper.fromJsonString("{\"packId\":\"a323c1b379d74ed897264f2f4a479d2b\",\"packageId\":\"dd9189c10b06471fb1d3f658fb4349e8\",\"mdmNameEn\":\"MDM_MATERIAL\",\"list\":[{\"MDM_MATERIAL_ATTRIBUTE\":[{\"MAT_ATTR_NAME\":\"011102:1配件名称*\",\"MAT_ATTR_VALUE\":\"螺栓\",\"MAT_CODE\":\"10090315\"},{\"MAT_ATTR_NAME\":\"011102:2规格型号/配件号/图号*\",\"MAT_ATTR_VALUE\":\"00925441-0819\",\"MAT_CODE\":\"10090315\"},{\"MAT_ATTR_NAME\":\"011102:3主机名称*\",\"MAT_ATTR_VALUE\":\"采煤机\",\"MAT_CODE\":\"10090315\"},{\"MAT_ATTR_NAME\":\"011102:4主机型号*\",\"MAT_ATTR_VALUE\":\"6LS05\",\"MAT_CODE\":\"10090315\"},{\"MAT_ATTR_NAME\":\"011102:5国产/进口*\",\"MAT_ATTR_VALUE\":\"进口\",\"MAT_CODE\":\"10090315\"}],\"MAT_WEIGHT_UNIT\":\"KG\",\"MAT_INDUSTRY\":\"K\",\"MAT_PRODUCT_GROUP\":\"WZ\",\"MAT_NORMAL_PROJ_GROUP\":\"NORM\",\"NAME\":\"\",\"MAT_PROC_STRATEGY\":\"001\",\"MAT_TYPE\":\"Z100\",\"MAT_DESC\":\"螺栓\\\\00925441-0819\\\\采煤机\\\\6LS05\\\\进口\",\"MAT_DATA_PROVIDER\":\"\",\"CODE\":\"10090315\",\"MAT_GROUP_CODE\":\"011102\",\"MAT_OLD_NUM\":\"44412011J021716\",\"MAT_APPLY_PLANT\":\"SD00\",\"MAT_DETAIL_DESC\":\"螺栓\\\\00925441-0819\\\\采煤机\\\\6LS05\\\\进口\",\"MAT_OVER_FACTORY_STATUS\":\"\",\"MAT_BASE_UOM\":\"PC\",\"MAT_STANDARD\":\"\"},{\"MDM_MATERIAL_ATTRIBUTE\":[{\"MAT_ATTR_NAME\":\"011102:1配件名称*\",\"MAT_ATTR_VALUE\":\"胶管总成\",\"MAT_CODE\":\"10069869\"},{\"MAT_ATTR_NAME\":\"011102:2规格型号/配件号/图号*\",\"MAT_ATTR_VALUE\":\"S 217277 00\",\"MAT_CODE\":\"10069869\"},{\"MAT_ATTR_NAME\":\"011102:3主机名称*\",\"MAT_ATTR_VALUE\":\"采煤机\",\"MAT_CODE\":\"10069869\"},{\"MAT_ATTR_NAME\":\"011102:4主机型号*\",\"MAT_ATTR_VALUE\":\"SL500\",\"MAT_CODE\":\"10069869\"},{\"MAT_ATTR_NAME\":\"011102:5国产/进口*\",\"MAT_ATTR_VALUE\":\"进口\",\"MAT_CODE\":\"10069869\"}],\"MAT_WEIGHT_UNIT\":\"KG\",\"MAT_INDUSTRY\":\"K\",\"MAT_PRODUCT_GROUP\":\"WZ\",\"MAT_NORMAL_PROJ_GROUP\":\"NORM\",\"NAME\":\"\",\"MAT_PROC_STRATEGY\":\"001\",\"MAT_TYPE\":\"Z100\",\"MAT_DESC\":\"胶管总成\\\\S 217277 00\\\\采煤机\\\\SL500\\\\进口\",\"MAT_DATA_PROVIDER\":\"\",\"CODE\":\"10069869\",\"MAT_GROUP_CODE\":\"011102\",\"MAT_OLD_NUM\":\"44412011J060033\",\"MAT_APPLY_PLANT\":\"SD00\",\"MAT_DETAIL_DESC\":\"胶管总成\\\\S 217277 00\\\\采煤机\\\\SL500\\\\进口\",\"MAT_OVER_FACTORY_STATUS\":\"\",\"MAT_BASE_UOM\":\"PC\",\"MAT_STANDARD\":\"\"}]}", MdmRequestData.class);

        WebClient webClient = createWebClient("/saveMdmMaterialInfo");
        Response response = webClient.post(requestData);

        String jsonStr = StreamUtils.InputStreamTOString((InputStream) response.getEntity());
        System.out.println(jsonStr);
        MdmResponseData responseData = (MdmResponseData) JsonMapper.fromJsonString(jsonStr, MdmResponseData.class);
        System.out.println(responseData.toString());

        webClient.close();
    }

    /**
     * 创建一个客户端
     *
     * @param path 路径
     * @return WebClient
     */
    private WebClient createWebClient(String path) {
        return createWebClient(path, 0);
    }

    /**
     * 创建一个客户端
     *
     * @param path    路径
     * @param timeOut 超时时间,单位毫秒。0表示不限制
     * @return WebClient
     */
    private WebClient createWebClient(String path, long timeOut) {
        WebClient webClient = WebClient.create(baseUrl, getProviderList(), AuthenticateInterceptor.USER_NAME, AuthenticateInterceptor.PASSWORD, null)
                .path(path)
                .type(MediaType.APPLICATION_JSON)   //指定请求的数据格式为 JSON
                .accept(MediaType.APPLICATION_JSON); //指定响应的数据格式为 JSON;
        ClientConfiguration config = WebClient.getConfig(webClient);

        Conduit conduit = config.getConduit();
        HTTPClientPolicy client = ((HTTPConduit) conduit).getClient();

        //指定时间量(以毫秒为单位),消费者在超时前等待响应。 0是无限的。
        client.setReceiveTimeout(timeOut);
        //指定时间量(以毫秒为单位),消费者将在超时之前尝试建立连接。 0是无限的。
        client.setConnectionTimeout(timeOut);
        return webClient;
    }

    /**
     * 添加 JSON 转换提供者
     *
     * @return List<Object>
     */
    private List<Object> getProviderList() {
        List<Object> providerList = new ArrayList<Object>();
        JacksonJaxbJsonProvider jsonProvider = new JacksonJaxbJsonProvider();
        //使用 jackson 发生 UnrecognizedPropertyException 异常
        //参考:https://yunix.iteye.com/blog/2043909
        jsonProvider.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);

        providerList.add(jsonProvider);
        return providerList;
    }
}

执行testSaveMdmInfo()方法Tomcat控制台输出
后台请求输出打印
后台响应输出打印
请求输出
在这里插入图片描述

十、wadl 生成

在浏览器中输入你所发布的service的地址后面加上?_wadl就会生成xml描述
在这里插入图片描述
到此已经完结

十一、参考

https://www.cnblogs.com/huangcongcong/p/4761732.html
https://blog.csdn.net/u014695188/article/details/51731116
https://blog.csdn.net/wk52525/article/details/79113978
https://blog.csdn.net/XiaopinOo/article/details/76851310
https://blog.csdn.net/u013313550/article/details/53409735
https://blog.csdn.net/forlinkext/article/details/78115640
https://blog.csdn.net/love_hanyu/article/details/84352763
https://blog.csdn.net/u014695188/article/details/51731116
http://www.doc88.com/p-9032352995964.html
https://blog.csdn.net/qq_36504446/article/details/79116027
https://www.cnblogs.com/sumingk/p/7243924.html
https://www.bilibili.com/video/av37531805

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值