# webservicedemo
**Repository Path**: javazhangyin/webservicedemo
## Basic Information
- **Project Name**: webservicedemo
- **Description**: springboot 整合 webservice 添加权限校验
- **Primary Language**: Java
- **License**: MulanPSL-2.0
- **Default Branch**: master
- **Homepage**: None
- **GVP Project**: No
## Statistics
- **Stars**: 7
- **Forks**: 0
- **Created**: 2021-03-23
- **Last Updated**: 2024-10-24
## Categories & Tags
**Categories**: Uncategorized
**Tags**: None
## README
# WebService
## 资料
参考:https://blog.csdn.net/weixin_41671390/article/details/79420765
BUG:需要修改一个pom.xml配置 不然会报
```
java.io.FileNotFoundException: D:\szw\repository\com\sun\xml\bind\jaxb-impl\2.1\jaxb-api.jar (系统找不到指定的文件。)
java.io.FileNotFoundException: D:\szw\repository\com\sun\xml\bind\jaxb-impl\2.1\activation.jar (系统找不到指定的文件。)
java.io.FileNotFoundException: D:\szw\repository\com\sun\xml\bind\jaxb-impl\2.1\jsr173_1.0_api.jar (系统找不到指定的文件。)
java.io.FileNotFoundException: D:\szw\repository\com\sun\xml\bind\jaxb-impl\2.1\jaxb1-impl.jar (系统找不到指定的文件。)
```
```java
org.apache.cxf
cxf-spring-boot-starter-jaxws
3.4.3
```
应该和版本有关系 具体在看
如果你是调用别人系统提供的webservice接口,那么你需要根据wsdl生成对应的接口类,这里我用jdk自带的wsimport工具生成
```
wsimport http://localhost:9020/services/studentService?wsdl -s D:\wsdl
```
-d:生成客户端执行类的class文件的存放目录
-s:生成客户端执行类的源文件的存放目录
-p:定义生成类的包名
```
wsimport http://192.168.0.9:8091/WebService.asmx?WSDL -s C:\Users\Administrator\Desktop\tmp\ws
wsimport http://localhost:8081/services/studentService?wsdl -s C:\Users\Administrator\Desktop\tmp\wsmy
```
不能使用lombok!!! 会报错。
## springboot 使用WebService
### 环境:
1. jdk8
2. springboot2.4.4
### 引入依赖
~~~xml
org.apache.cxf
cxf-spring-boot-starter-jaxws
3.4.3
~~~
> 注意:版本不对可能导致找不到文件的错误
### 服务端:
编写 bean 和 service
bean:
> 注意:bean中不能使用lombok 不然远程调用会有错误
```java
public class Student implements Serializable {
private static final long serialVersionUID = 1L;// 反序列化用的,可以不写
private String name; // 姓名
private Integer age; // 年龄
private String gender; // 性别
//省略get set
}
```
service:
```java
package com.example.webservicedemo.service;
import com.example.webservicedemo.bean.Student;
import javax.jws.WebMethod;
import javax.jws.WebParam;
import javax.jws.WebService;
import java.util.List;
import java.util.Map;
@WebService(targetNamespace = "http://impl.service.webservicedemo.example.com")
public interface StudentService {
@WebMethod
public Integer getStudentAge(@WebParam(name = "name") String name);
@WebMethod
public String getStudentName();
@WebMethod
public Student getOneStudentInfo();
@WebMethod
public List getAllStudentsInfo();
@WebMethod
public Map getSchoolInfo();
}
```
service 实现类
```java
package com.example.webservicedemo.service.impl;
import com.example.webservicedemo.bean.Student;
import com.example.webservicedemo.service.StudentService;
import org.springframework.stereotype.Service;
import javax.jws.WebService;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@Service
@WebService(serviceName = "StudentService", // 服务名
targetNamespace = "http://impl.service.webservicedemo.example.com", // 实现类包名倒写
endpointInterface = "com.example.webservicedemo.service.StudentService") // 接口的全路径
public class StudentServiceImpl implements StudentService {
@Override
public Integer getStudentAge(String name) {
return new Student(name, 18, "男").getAge();
}
@Override
public String getStudentName() {
return "斗战神佛";
}
@Override
public Student getOneStudentInfo() {
Student stu = new Student("紫霞仙子", 18, "女");
return stu;
}
@Override
public List getAllStudentsInfo() {
List stus = new ArrayList<>();
Student stu1 = new Student("唐三藏", 20, "男");
Student stu2 = new Student("孙悟空", 20, "男");
Student stu3 = new Student("猪八戒", 20, "男");
Student stu4 = new Student("沙和尚", 20, "男");
stus.add(stu1);
stus.add(stu2);
stus.add(stu3);
stus.add(stu4);
return stus;
}
@Override
public Map getSchoolInfo() {
Map school = new HashMap<>();
school.put("name", "XX大学");
school.put("location", "广东");
return school;
}
}
```
配置类CxfConfig:
```java
package com.example.webservicedemo.config;
import javax.xml.ws.Endpoint;
import com.example.webservicedemo.service.StudentService;
import org.apache.cxf.Bus;
import org.apache.cxf.jaxws.EndpointImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class CxfConfig {
@Autowired
private Bus bus;
@Autowired
private StudentService studentService;
/**
* studentService
*
* @return
*/
@Bean
public Endpoint studentServiceEndpoint() {
EndpointImpl studentServiceEndpoint = new EndpointImpl(bus, studentService);
studentServiceEndpoint.publish("/studentService");
return studentServiceEndpoint;
}
}
```
启动服务 :
```log
2021-03-22 11:37:29.332 INFO 6780 --- [ restartedMain] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat started on port(s): 8081 (http) with context path ''
2021-03-22 11:37:29.343 INFO 6780 --- [ restartedMain] c.e.w.WebservicedemoApplication : Started WebservicedemoApplication in 3.053 seconds (JVM running for 4.094)
```
访问:http://localhost:8081/services

后端部署完毕。
### 客户端
客户端有2种调用方法:
1 JaxWs方式
```java
public static void main(String[] args) {
JaxWsProxyFactoryBean factory = new JaxWsProxyFactoryBean();//JaxWs方式,因为pom文件导的包是cxf-spring-boot-starter-jaxws
factory.setServiceClass(StudentService.class);
factory.setAddress("http://localhost:8081/services/studentService?wsdl");
StudentService service = (StudentService) factory.create();
String name = service.getStudentName();
System.out.println("student name:"+name);
Student stu = service.getOneStudentInfo();
System.out.println("学生信息:"+stu);
System.out.println("调用带参数的:"+service.getStudentAge("212"));
}
```
2JaxRs的方式
```java
public static void main(String[] args) throws Exception{
//获取wsdl文档资源地址
URL wsdlDocumentLocation = new URL("http://localhost:8081/services/studentService?wsdl");
//获取服务名称
//1.namespaceURI - 命名空间地址
//2.localPart - 服务视图名
QName serviceName=new QName("http://impl.service.webservicedemo.example.com","StudentService");
Service service= Service.create(wsdlDocumentLocation, serviceName);
//获取服务实现类
StudentService mobileCodeWSSoap = service.getPort(StudentService.class);
//调用方法
Integer result = mobileCodeWSSoap.getStudentAge("测试");
System.out.println(result);
String str = null;
}
```
### 服务端添加验证
参考:https://blog.csdn.net/qq_26264237/article/details/105396937
添加依赖
```xml
org.springframework.ws
spring-ws-security
```
服务端添加拦截器 进行校验:
```java
@Component
public class AuthInterceptor extends AbstractPhaseInterceptor {
private static final String USERNAME = "user";
private static final String PASSWORD = "123";
public AuthInterceptor() {
// 定义在哪个阶段进行拦截
super(Phase.PRE_PROTOCOL);
}
@Override
public void handleMessage(SoapMessage soapMessage) throws Fault {
List headers = soapMessage.getHeaders();
String username = null;
String password = null;
if (headers == null || headers.isEmpty()) {
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("认证失败");
System.err.println("用户认证信息错误");
throw new Fault(soapExc);
}
}
}
```
在config中添加拦截器:
```java
@Configuration
public class CxfConfig {
@Autowired
private Bus bus;
@Autowired
private StudentService studentService;
@Autowired
AuthInterceptor authInterceptor;
@Bean
public Endpoint studentServiceEndpoint() {
EndpointImpl studentServiceEndpoint = new EndpointImpl(bus, studentService);
studentServiceEndpoint.publish("/studentService");
studentServiceEndpoint.getInInterceptors().add(authInterceptor);
return studentServiceEndpoint;
}
}
```
客户端访问时也需要添加校验:
```java
package com.example.webservicedemo.interceptor;
import com.example.webservicedemo.common.StaticParam;
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 ClientCheckInterceptor extends AbstractPhaseInterceptor {
private String username="user";
private String password="123";
public ClientCheckInterceptor() {
//设置在发送请求前阶段进行拦截
super(Phase.PREPARE_SEND);
}
@Override
public void handleMessage(SoapMessage soapMessage) throws Fault {
List headers = soapMessage.getHeaders();
Document doc = DOMUtils.createDocument();
Element auth = doc.createElementNS(StaticParam.TARGETNAMESPACE,StaticParam.MYSOAPHEADER);
Element UserName = doc.createElement("username");
Element UserPass = doc.createElement("password");
UserName.setTextContent(username);
UserPass.setTextContent(password);
auth.appendChild(UserName);
auth.appendChild(UserPass);
headers.add(0, new Header(new QName("SecurityHeader"),auth));
}
}
```
请求后端:
```java
JaxWsProxyFactoryBean factory = new JaxWsProxyFactoryBean();//JaxWs方式,因为pom文件导的包是cxf-spring-boot-starter-jaxws
factory.setServiceClass(StudentService.class);
factory.setAddress("http://localhost:8081/services/studentService?wsdl");
//添加用户名密码拦截器
factory.getOutInterceptors().add(new ClientCheckInterceptor());
StudentService service = (StudentService) factory.create();
String name = service.getStudentName();
System.out.println("student name:"+name);
Student stu = service.getOneStudentInfo();
System.out.println("学生信息:"+stu);
System.out.println("调用带参数的:"+service.getStudentAge("212"));
```
### 使用IDEA 导入第三方接口
将相关依赖引入,我使用得还是上文提到的 JaxWs方式
```xml
org.apache.cxf
cxf-rt-frontend-jaxrs
3.2.4
org.apache.cxf
cxf-rt-rs-client
3.2.4
org.apache.cxf
cxf-rt-rs-extension-providers
3.2.4
```

选择

输入正确的URL即可生成

生成的代码和使用命令行生成的差别不大,可用性不太强,不建议直接使用。
## 参与贡献
1. Fork 本仓库
2. 新建 Feat_xxx 分支
3. 提交代码
4. 新建 Pull Request
## 特技
1. 使用 Readme\_XXX.md 来支持不同的语言,例如 Readme\_en.md, Readme\_zh.md
2. Gitee 官方博客 [blog.gitee.com](https://blog.gitee.com)
3. 你可以 [https://gitee.com/explore](https://gitee.com/explore) 这个地址来了解 Gitee 上的优秀开源项目
4. [GVP](https://gitee.com/gvp) 全称是 Gitee 最有价值开源项目,是综合评定出的优秀开源项目
5. Gitee 官方提供的使用手册 [https://gitee.com/help](https://gitee.com/help)
6. Gitee 封面人物是一档用来展示 Gitee 会员风采的栏目 [https://gitee.com/gitee-stars/](https://gitee.com/gitee-stars/)