# 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 ![image.png](http://ww1.sinaimg.cn/large/9c95fcf5ly1gosj5nis95j20un07vq3g.jpg) 后端部署完毕。 ### 客户端 客户端有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 ``` ![image.png](http://ww1.sinaimg.cn/large/9c95fcf5ly1gotl5xitzmj20ut0dqack.jpg) 选择 ![image.png](http://ww1.sinaimg.cn/large/9c95fcf5ly1gotl8ddlruj20ea0dzaan.jpg) 输入正确的URL即可生成 ![image-20210323093715078](C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20210323093715078.png) 生成的代码和使用命令行生成的差别不大,可用性不太强,不建议直接使用。 ## 参与贡献 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/)