WebService --- apache axis 1.4 --- wsdl --- 整合第三方短信
公司需要对接的短信服务接口,用的技术有点老,之前没用过,记录一下
环境搭建
首先,从官网下载APACHE AXIS 1.4,下载好之后解压
还需要下载:activation.jar、mail.jar,将这俩拷贝到axis的lib目录下
这俩jar包的百度网盘:通过网盘分享的文件:axis1.4
链接: https://pan.baidu.com/s/1pK1HztCYHHtbQanJEFhYNg?pwd=gn66 提取码: gn66

设置环境变量:
AXIS_HOME E:\LP\zkr\DX\axis-bin-1_4\axis-1_4
AXIS_LIB E:\LP\zkr\DX\axis-bin-1_4\axis-1_4\lib\axis.jar
在Path环境变量中,添加:%AXIS_HOME%\bin
wsdl文件获取
你可以使用第三方的在线wsdl文件
或者本地的wsdl文件
反正不管怎么样,你都得需要一个wsdl文件!
我的是这个:http://ip:port/WSSMSIF/services/SmsService?wsdl
xml
<?xml version="1.0" encoding="UTF-8"?>
<wsdl:definitions targetNamespace="http://http.net.sms.wisdom.com" xmlns:apachesoap="http://xml.apache.org/xml-soap" xmlns:impl="http://http.net.sms.wisdom.com" xmlns:intf="http://http.net.sms.wisdom.com" xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/" xmlns:tns1="http://messages.net.sms.wisdom.com" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" xmlns:wsdlsoap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<!--WSDL created by Apache Axis version: 1.2.1
Built on Aug 08, 2005 (11:49:10 PDT)-->
<wsdl:types>
<schema targetNamespace="http://messages.net.sms.wisdom.com" xmlns="http://www.w3.org/2001/XMLSchema">
<import namespace="http://xml.apache.org/xml-soap"/>
<import namespace="http://http.net.sms.wisdom.com"/>
<import namespace="http://schemas.xmlsoap.org/soap/encoding/"/>
<complexType abstract="true" name="AbstractMessage">
<sequence>
<element name="packetLength" type="xsd:int"/>
</sequence>
</complexType>
<complexType name="Label">
<complexContent>
<extension base="tns1:AbstractMessage">
<sequence>
<element name="labelName" nillable="true" type="xsd:string"/>
<element name="labelValue" nillable="true" type="xsd:string"/>
</sequence>
</extension>
</complexContent>
</complexType>
<complexType name="SmsMessage">
<complexContent>
<extension base="tns1:AbstractMessage">
<sequence>
<element name="contents" nillable="true" type="xsd:string"/>
<element name="labels" nillable="true" type="impl:ArrayOf_tns1_Label"/>
<element name="orgCode" nillable="true" type="xsd:string"/>
<element name="receiver" nillable="true" type="xsd:string"/>
</sequence>
</extension>
</complexContent>
</complexType>
<complexType name="SmsMessages">
<complexContent>
<extension base="tns1:AbstractMessage">
<sequence>
<element name="access" nillable="true" type="xsd:string"/>
<element name="endDate" nillable="true" type="xsd:string"/>
<element name="endTime" nillable="true" type="xsd:string"/>
<element name="extension" nillable="true" type="xsd:string"/>
<element name="extensionValue" nillable="true" type="xsd:string"/>
<element name="hashMap" nillable="true" type="apachesoap:Map"/>
<element name="hashMapExten" nillable="true" type="apachesoap:Map"/>
<element name="messages" nillable="true" type="impl:ArrayOf_tns1_SmsMessage"/>
<element name="needUseTemplateFlag" nillable="true" type="xsd:string"/>
<element name="organizationId" nillable="true" type="xsd:string"/>
<element name="serviceType" nillable="true" type="xsd:string"/>
<element name="smTaskID" nillable="true" type="xsd:string"/>
<element name="startDate" nillable="true" type="xsd:string"/>
<element name="startTime" nillable="true" type="xsd:string"/>
<element name="taskId" nillable="true" type="xsd:string"/>
<element name="taskValue" nillable="true" type="xsd:string"/>
<element name="templatId" nillable="true" type="xsd:string"/>
</sequence>
</extension>
</complexContent>
</complexType>
</schema>
<schema targetNamespace="http://xml.apache.org/xml-soap" xmlns="http://www.w3.org/2001/XMLSchema">
<import namespace="http://messages.net.sms.wisdom.com"/>
<import namespace="http://http.net.sms.wisdom.com"/>
<import namespace="http://schemas.xmlsoap.org/soap/encoding/"/>
<complexType name="mapItem">
<sequence>
<element name="key" nillable="true" type="xsd:anyType"/>
<element name="value" nillable="true" type="xsd:anyType"/>
</sequence>
</complexType>
<complexType name="Map">
<sequence>
<element maxOccurs="unbounded" minOccurs="0" name="item" type="apachesoap:mapItem"/>
</sequence>
</complexType>
</schema>
<schema targetNamespace="http://http.net.sms.wisdom.com" xmlns="http://www.w3.org/2001/XMLSchema">
<import namespace="http://messages.net.sms.wisdom.com"/>
<import namespace="http://xml.apache.org/xml-soap"/>
<import namespace="http://schemas.xmlsoap.org/soap/encoding/"/>
<complexType name="ArrayOf_tns1_Label">
<complexContent>
<restriction base="soapenc:Array">
<attribute ref="soapenc:arrayType" wsdl:arrayType="tns1:Label[]"/>
</restriction>
</complexContent>
</complexType>
<complexType name="ArrayOf_tns1_SmsMessage">
<complexContent>
<restriction base="soapenc:Array">
<attribute ref="soapenc:arrayType" wsdl:arrayType="tns1:SmsMessage[]"/>
</restriction>
</complexContent>
</complexType>
<complexType name="Response">
<sequence>
<element name="message" nillable="true" type="xsd:string"/>
<element name="status" nillable="true" type="xsd:string"/>
</sequence>
</complexType>
</schema>
</wsdl:types>
<wsdl:message name="sendSMSResponse">
<wsdl:part name="sendSMSReturn" type="impl:Response"/>
</wsdl:message>
<wsdl:message name="sendSMSRequest">
<wsdl:part name="UserName" type="xsd:string"/>
<wsdl:part name="Password" type="xsd:string"/>
<wsdl:part name="msgs" type="tns1:SmsMessages"/>
</wsdl:message>
<wsdl:portType name="SmsService">
<wsdl:operation name="sendSMS" parameterOrder="UserName Password msgs">
<wsdl:input message="impl:sendSMSRequest" name="sendSMSRequest"/>
<wsdl:output message="impl:sendSMSResponse" name="sendSMSResponse"/>
</wsdl:operation>
</wsdl:portType>
<wsdl:binding name="SmsServiceSoapBinding" type="impl:SmsService">
<wsdlsoap:binding style="rpc" transport="http://schemas.xmlsoap.org/soap/http"/>
<wsdl:operation name="sendSMS">
<wsdlsoap:operation soapAction=""/>
<wsdl:input name="sendSMSRequest">
<wsdlsoap:body encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" namespace="http://http.net.sms.wisdom.com" use="encoded"/>
</wsdl:input>
<wsdl:output name="sendSMSResponse">
<wsdlsoap:body encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" namespace="http://http.net.sms.wisdom.com" use="encoded"/>
</wsdl:output>
</wsdl:operation>
</wsdl:binding>
<wsdl:service name="SmsServiceService">
<wsdl:port binding="impl:SmsServiceSoapBinding" name="SmsService">
<wsdlsoap:address location="http://10.0.118.52:7001/WSSMSIF/services/SmsService"/>
</wsdl:port>
</wsdl:service>
</wsdl:definitions>
根据wsdl文件生成代码
编写一个bat文件:
bash
set Axis_Lib=E:\LP\zkr\DX\axis-bin-1_4\axis-1_4\lib
set Java_Cmd=java -Djava.ext.dirs=%Axis_Lib%
set Output_Path=E:\LP\zkr\DX\messagedx
set Package=lp.dx.test
%Java_Cmd% org.apache.axis.wsdl.WSDL2Java -o%Output_Path% -p%Package% http://ip:port/WSSMSIF/services/SmsService?wsdl
里面需要改动的都很好看懂,自己按需修改吧。
直接双击这个bat文件,就可以生成代码了。
生成的代码如下:

整合到项目中
添加依赖:
xml
<!-- 短信所需依赖开始 -->
<!-- Axis 1.4核心 -->
<dependency>
<groupId>org.apache.axis</groupId>
<artifactId>axis</artifactId>
<version>1.4</version>
</dependency>
<!-- JAX-RPC支持 -->
<dependency>
<groupId>org.apache.axis</groupId>
<artifactId>axis-jaxrpc</artifactId>
<version>1.4</version>
</dependency>
<!-- SAAJ API(包含 SOAPException 等核心类) -->
<dependency>
<groupId>javax.xml.soap</groupId>
<artifactId>saaj-api</artifactId>
<version>1.3</version>
</dependency>
<!-- SAAJ 实现 -->
<dependency>
<groupId>com.sun.xml.messaging.saaj</groupId>
<artifactId>saaj-impl</artifactId>
<version>1.3.10</version>
<!-- 排除冲突的依赖(如果项目中已有) -->
<exclusions>
<exclusion>
<groupId>javax.xml.soap</groupId>
<artifactId>saaj-api</artifactId>
</exclusion>
</exclusions>
</dependency>
<!-- 服务发现 -->
<dependency>
<groupId>commons-discovery</groupId>
<artifactId>commons-discovery</artifactId>
<version>0.2</version>
</dependency>
<!-- 日志支持 -->
<dependency>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
<version>1.0.4</version>
</dependency>
<!-- WSDL处理 -->
<dependency>
<groupId>wsdl4j</groupId>
<artifactId>wsdl4j</artifactId>
<version>1.5.1</version>
</dependency>
<!-- 短信所需依赖结束 -->
然后将生成的代码拷贝到项目中。
然后整合代码:
java
public class DateUtils {
/**
* 获取当前日期,格式为 'yyyy-MM-dd'
* @return 格式化后的当前日期字符串
*/
public static String getCurrentDate() {
return LocalDate.now().format(DateTimeFormatter.ISO_LOCAL_DATE);
}
/**
* 获取当前时间,格式为 'HH:mm'
* @return 格式化后的当前时间字符串
*/
public static String getCurrentTime() {
return LocalTime.now().format(DateTimeFormatter.ofPattern("HH:mm"));
}
/**
* 格式化指定的日期
* @param date 要格式化的 LocalDate 对象
* @param pattern 格式模式,例如 "yyyy-MM-dd"
* @return 格式化后的日期字符串
*/
public static String formatDate(LocalDate date, String pattern) {
if (date == null) {
return null;
}
return date.format(DateTimeFormatter.ofPattern(pattern));
}
public static String formatDate(LocalTime date, String pattern) {
if (date == null) {
return null;
}
return date.format(DateTimeFormatter.ofPattern(pattern));
}
/**
* 格式化指定的时间
* @param time 要格式化的 LocalTime 对象
* @param pattern 格式模式,例如 "HH:mm:ss"
* @return 格式化后的时间字符串
*/
public static String formatTime(LocalTime time, String pattern) {
if (time == null) {
return null;
}
return time.format(DateTimeFormatter.ofPattern(pattern));
}
/**
* 对日期进行加减操作
* @param date 原始日期
* @param amount 加减的数量,正数为加,负数为减
* @param unit 单位,例如 ChronoUnit.DAYS, ChronoUnit.MONTHS
* @return 操作后的日期
*/
public static LocalDateTime addDate(LocalDateTime date, long amount, ChronoUnit unit) {
if (date == null) {
return null;
}
return date.plus(amount, unit);
}
/**
* 将字符串解析为 LocalDate 对象
* @param dateStr 日期字符串
* @param pattern 格式模式,例如 "yyyy-MM-dd"
* @return 解析后的 LocalDate 对象
*/
public static LocalDate parseDate(String dateStr, String pattern) {
if (dateStr == null || dateStr.trim().isEmpty()) {
return null;
}
return LocalDate.parse(dateStr, DateTimeFormatter.ofPattern(pattern));
}
}
java
public class AuthServerConstant {
public static final String SMS_CODE_CACHE_PREFIX = "sms:code:";
public static final String ORGANIZATION_ID = "0200000000230";
}
java
@Data
public class SmsMessageVO {
private String organizationId;//该条短信的发送机构
// private String serviceType;
private List<MessageVO> messages;
@Data
public static class MessageVO {
private String contents; //短信内容
private String receiver; //短信的接收人
// public String orgCode; //该条短信的发送机构,使用上面的
}
}
java
@Slf4j
@RestController
@RequestMapping("/sms/message")
public class SmsMessageApi {
@Autowired
private StringRedisTemplate stringRedisTemplate;
/**
* 校验验证码
*/
@PostMapping("/validcode")
public Result<Boolean> validcode(@RequestBody SmsMessageVO.MessageVO messageVO) {
if (messageVO == null) {
throw new RuntimeException("参数传递有问题");
}
String receiver = messageVO.getReceiver();
String code = messageVO.getContents();
if (StringUtils.isEmpty(receiver) || StringUtils.isEmpty(code)) {
throw new RuntimeException("手机号和验证码必须传!");
}
String key = AuthServerConstant.SMS_CODE_CACHE_PREFIX + receiver;
String redisSavedCode = stringRedisTemplate.opsForValue().get(key);
if (!org.springframework.util.StringUtils.isEmpty(redisSavedCode)) { // 不为空,说明给该用户发送过验证码,并且验证码没有过期
String realCode = codeUnResolve(redisSavedCode)[0];
if (code.equals(realCode)) {
// 验证码正确 删除验证码
CompletableFuture.runAsync(() -> stringRedisTemplate.delete(key));
//TODO 登录
return Result.build(true, HttpStatus.OK.value(), "验证码校验成功");
}
}
return Result.build(false, HttpStatus.BAD_REQUEST.value(), "验证码校验失败");
}
/**
* 获取验证码
*
* @param receiver 接收人的手机号
*/
@GetMapping("/sendcode")
@ResponseBody
public R sendCode(@RequestParam("receiver") String receiver) {
// Redis缓存验证码:存起来方便下次校验 以及 可以给验证码设置有效期
final String code = getRandomCode().toString();
// 防止同一个手机号在60s内再次发送验证码
String key = AuthServerConstant.SMS_CODE_CACHE_PREFIX + receiver;
String redisSavedCode = stringRedisTemplate.opsForValue().get(key);
if (!org.springframework.util.StringUtils.isEmpty(redisSavedCode)) {
long l = Long.parseLong(codeUnResolve(redisSavedCode)[1]);
if (System.currentTimeMillis() - l < 60000) { // 如果时间间隔小于60s
return R.error("时间间隔小于60s,60秒后再试");
}
}
CompletableFuture.runAsync(() -> {
Result<Response> responseResult = donotUseTemplate(buildMessage(receiver, code));
if (responseResult.getCode() == HttpStatus.BAD_REQUEST.value()) {
stringRedisTemplate.delete(key);// 短信发送失败删除验证码
}
});
CompletableFuture.runAsync(() -> {
//过期时间5分钟
stringRedisTemplate.opsForValue().set(key, codeResolve(code), 5, TimeUnit.MINUTES);
});
return R.ok();
}
private SmsMessageVO buildMessage(String receiver, String content) {
SmsMessageVO smsMessageVO = new SmsMessageVO();
SmsMessageVO.MessageVO message = new SmsMessageVO.MessageVO();
message.setContents(content);
message.setReceiver(receiver);
smsMessageVO.setMessages(List.of(message));
smsMessageVO.setOrganizationId(AuthServerConstant.ORGANIZATION_ID);
return smsMessageVO;
}
private String codeResolve(String code) {
return code + "_" + System.currentTimeMillis();
}
private String[] codeUnResolve(String code) {
return code.split("_");
}
private Integer getRandomCode() {
//4位数字验证码:想要[1000,9999],也就是[1000,10000)
// Math.random() -> [0, 1) // (int) Math.random()永远为0
// Math.random() * (end - begin) -> [0, end - begin)
// begin + Math.random() * (end - begin) -> [begin, end)
int code = (int) (1000 + Math.random() * (10000 - 1000));
return code;
}
// @PostMapping("/donotUseTemplate")
public Result<Response> donotUseTemplate(/*@RequestBody */SmsMessageVO smsMessageVO) {
if (smsMessageVO == null || smsMessageVO.getMessages() == null || smsMessageVO.getMessages().isEmpty()) {
throw new RuntimeException("至少发送1条信息!");
}
SmsServiceSoapBindingStub binding = null;
try {
binding = (SmsServiceSoapBindingStub) new SmsServiceServiceLocator().getSmsService();//创建binding对象
} catch (javax.xml.rpc.ServiceException jre) {
jre.printStackTrace();
}
binding.setTimeout(60000);
Response value = null;//声明Response对象,该对象将在提交短信后包含提交的结果。
SmsMessages msgs = new SmsMessages();//创建SmsMessages对象,该对象对应于上文下行短信格式中的Messages元素
msgs.setOrganizationId(smsMessageVO.getOrganizationId());//保信通系统模块-》系统管理-》机构管理页面中的机构代码,不能为空
msgs.setNeedUseTemplateFlag("false");//设置是否调用的接口模板 true:使用 false:不使用 此实例为不带模板的接口,设置为false
msgs.setTaskId(UUID.randomUUID().toString());//请确保此值在每次通过接口发送时唯一
// msgs.setTaskValue("");//taskid对应的备注字段 此字段没有用处,只是做备注用
// msgs.setExtension("024");//设置该批短信的Extension,扩展尾号,此功能做为系统的备用备用,一般使用不用填写。
msgs.setServiceType("srzf");//设置该批短信的ServiceType,保信通系统模块-》系统管理-》参数配置-》服务类型-》服务类型代码,请填写专门为webservice发送使用的服务类型,方便统计分析。不能为空
msgs.setStartDate(DateUtils.getCurrentDate());//设置该批短信的StartDate,不能为空
msgs.setStartTime(DateUtils.getCurrentTime());//设置该批短信的StartTime,不能为空
LocalDateTime oneDayLater = DateUtils.addDate(LocalDateTime.now(), 24, ChronoUnit.HOURS);
msgs.setEndDate(DateUtils.formatDate(oneDayLater.toLocalDate(), "yyyy-MM-dd"));//设置该批短信的EndDate,不能为空
msgs.setEndTime(DateUtils.formatDate(oneDayLater.toLocalTime(), "HH:m"));//设置该批短信的EndTime,不能为空
java.util.Vector vec = new java.util.Vector(); //支持一个任务多条短信,不能为空
for (SmsMessageVO.MessageVO message : smsMessageVO.getMessages()) {
String receiver = message.getReceiver();
String contents = message.getContents();
if (StringUtils.isBlank(receiver)) {
throw new RuntimeException("消息接收人不能为空!");
}
SmsMessage msg = new SmsMessage();//创建SmsMessage对象,定义同上文下行短信格式中的Message元素
msg.setReceiver(receiver);//短信接收人号码,不能为空
msg.setContents(contents); //短信内容,不能为空
msg.setOrgCode(smsMessageVO.getOrganizationId());//设置该条短信的发送机构orgCode
vec.add(msg);
}
msgs.setMessages((SmsMessage[]) vec.toArray(new SmsMessage[vec.size()]));//设置该批短信的每一条短信,一批短信可以包含多条短信
log.info("发送:{}", JSON.toJSON(msgs));
try {
//TODO 项目上线将userName和password更改为配置文件的形式
//提交该批短信
//UserName是短信服务平台管理员分配的用户名, Password则是其对应的密码
//用户名和密码用于验证发送者,只有验证通过才可能提交短信,msgs即为刚才创建的短信对象。
value = binding.sendSMS("", "", msgs);
log.info("返回:{}", JSON.toJSON(value));
// {"message":"SMS has been queued for processing.","status":"OK"}
return Result.build(value, HttpStatus.OK.value(), "发送成功");
} catch (RemoteException ex) {
ex.printStackTrace();
}
return Result.build(null, HttpStatus.BAD_REQUEST.value(), "发送失败");
}
// @PostMapping("/useTemplate")
// public void useTemplate() {
// SmsServiceSoapBindingStub binding = null;
// try {
// binding = (SmsServiceSoapBindingStub) new SmsServiceServiceLocator().getSmsService();//创建binding对象
// } catch (javax.xml.rpc.ServiceException jre) {
// jre.printStackTrace();
// }
// binding.setTimeout(60000);
// Response value = null;//声明Response对象,该对象将在提交短信后包含提交的结果。
// SmsMessages msgs = new SmsMessages();//创建SmsMessages对象,该对象对应于上文下行短信格式中的Messages元素
// msgs.setNeedUseTemplateFlag("true");//设置是否调用的接口模板 true:使用 false:不使用
// msgs.setTemplatId("IFTemplate1");//要使用的接口模板的id
// msgs.setTaskId("1234321");//请确保此值在每次通过接口发送时唯一
// msgs.setTaskValue("admin123");//taskid对应的备注字段
// msgs.setOrganizationId("");//设置该批短信的OrganizationId,定义同上文下行短信格式中的Organization元素
// msgs.setExtension("024");//设置该批短信的Extension,定义同上文下行短信格式中的Extension元素
// msgs.setServiceType("srzf");//设置该批短信的ServiceType,定义同上文下行短信格式中的ServiceType元素
// msgs.setStartDate("2006-04-11");//设置该批短信的StartDate,定义同上文下行短信格式中的StartDate元素
// msgs.setStartTime("10:25");//设置该批短信的StartTime,定义同上文下行短信格式中的StartTime元素
// msgs.setEndDate("2006-04-11");//设置该批短信的EndDate,定义同上文下行短信格式中的EndDate元素
// msgs.setEndTime("10:25");//设置该批短信的EndTime,定义同上文下行短信格式中的EndTime元素
//
// java.util.Vector vec = new java.util.Vector();
// for (int i = 0; i < 100; i++) {
// SmsMessageVO msg = new SmsMessageVO();//创建SmsMessage对象,定义同上文下行短信格式中的Message元素
// msg.setReceiver("13012345678");//设置该条短信的Receiver,定义同上文下行短信格式中的Receiver元素
// msg.setOrgCode("");//设置该条短信的发送机构orgCode,定义同上文下行短信格式中的orgCode元素
//
// java.util.Vector label_vec = new java.util.Vector();
//
// Label label = new Label();//创建标签对象
// label.setLabelName("Name");//设置标签名称
// label.setLabelName("张三");//设置标签值
// label_vec.add(label);
// label = new Label();//创建标签对象
// label.setLabelName("Age");//设置标签名称
// label.setLabelName("25");//设置标签值
// label_vec.add(label);
//
// msg.setLabels((Label[]) label_vec.toArray(new Label[label_vec.size()]));//设置该条短信的标签,每条短信可以使用多组标签。
//
// vec.add(msg);
// }
// msgs.setMessages((SmsMessageVO[]) vec.toArray(new SmsMessageVO[vec.size()]));//设置该批短信的每一条短信,一批短信可以包含多条短信
//
// try {
// value = binding.sendSMS("", "", msgs);//提交该批短信,UserName是短信服务平台管理员分配的用户名, Password则是其对应的密码,用户名和密码用于验证发送者,只有验证通过才可能提交短信,msgs即为刚才创建的短信对象。
// System.out.println(value.getStatus());
// System.out.println(value.getMessage());
//
// System.out.println(value);
// } catch (RemoteException ex) {
// ex.printStackTrace();
// }
// }
}