Springboot-WebService 服务端发布与客户端调用

第一章、WebService服务端代码实现:

1.1 pom.xml

xml 复制代码
<!-- CXF WebService框架依赖 -->
        <dependency>
            <groupId>org.apache.cxf</groupId>
            <artifactId>cxf-spring-boot-starter-jaxws</artifactId>
            <version>3.4.5</version>
        </dependency>

        <dependency>
            <groupId>org.apache.cxf</groupId>
            <artifactId>cxf-rt-transports-http</artifactId>
            <version>3.4.5</version>
        </dependency>
        <!-- Lombok简化代码 -->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>

1.2 yml配置

yml 复制代码
cxf:
  path: /webservice/server  # WebService服务访问路径前缀: 向外暴露的接口服务;filter过滤器需放行
  servlet:
    init:
      service-list-path: /list  # 服务列表页面路径

1.3 config配置

java 复制代码
import com.gitee.ht.service.UserService;
import com.gitee.ht.service.impl.UserServiceImpl;
import org.apache.cxf.Bus;
import javax.xml.ws.Endpoint;

import org.apache.cxf.bus.spring.SpringBus;
import org.apache.cxf.jaxws.EndpointImpl;
import org.apache.cxf.transport.servlet.CXFServlet;
import org.springframework.boot.web.servlet.ServletRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
 * CXF WebService配置类
 * 负责配置和发布WebService端点
 */
@Configuration
public class CxfConfig {

    @Bean(name = Bus.DEFAULT_BUS_ID)
    public SpringBus springBus() {
        return new SpringBus();
    }
    @Bean(name = "wsBean")
    public ServletRegistrationBean dispatcherServlet() {
        ServletRegistrationBean wbsServlet = new ServletRegistrationBean(new CXFServlet(), "/webservice/server/*");
        return wbsServlet;
    }

    @Bean
    public UserService userService() {
        return new UserServiceImpl();
    }
    
    @Bean
    public Endpoint userServiceEndpoint(UserService userService, SpringBus bus) {
        EndpointImpl endpoint = new EndpointImpl(bus, userService);
        endpoint.publish("/userService");
        System.out.println("服务发布成功:地址为:http://localhost:8082/webservice/server/userService?wsdl");
        return endpoint;
    }
}

1.4 webService服务器接口代码

java 复制代码
import javax.jws.WebMethod;
import javax.jws.WebParam;
import javax.jws.WebService;

/**
 * WebService服务接口定义
 * @WebService 注解用于标识这是一个WebService接口
 * name: 服务名称
 * targetNamespace: 命名空间,用于区分不同的服务
 */
@WebService(name = "UserService", targetNamespace = "http://localhost:8082/")
public interface UserService {
    
    /**
     * 打招呼方法
     * @WebMethod 标识这是一个WebService方法
     * @param name 用户名
     * @return 问候语
     */
    @WebMethod
    String sayHello(@WebParam(name = "name") String name);
    
    /**
     * 获取用户信息方法
     * @param userId 用户ID
     * @return 用户信息对象
     */
    @WebMethod
    UserInfo getUserInfo(@WebParam(name = "userId") String userId);
    
    /**
     * 更新用户信息方法
     * @param userInfo 用户信息对象
     * @return 更新结果
     */
    @WebMethod
    boolean updateUserInfo(@WebParam(name = "userInfo") UserInfo userInfo);
}

1.5 webService接口的实现类

java 复制代码
import com.gitee.ht.service.UserInfo;
import com.gitee.ht.service.UserService;
import org.springframework.stereotype.Component;

import javax.jws.WebService;
import java.util.HashMap;
import java.util.Map;

/**
 * WebService服务接口实现类
 * @WebService 注解配置:
 *   serviceName: 服务名称
 *   targetNamespace: 命名空间,必须与接口一致
 *   endpointInterface: 指定服务接口类
 * @Component 标识这是一个Spring组件,会被自动扫描和管理
 */
@WebService(
    serviceName = "UserService",
//    targetNamespace = "http://service.webserver.example.com/",
    targetNamespace = "http://localhost:8082/",
    endpointInterface = "com.gitee.ht.service.UserService"
)
@Component
public class UserServiceImpl implements UserService {
    
    // 模拟用户数据存储
    private Map<String, UserInfo> userMap = new HashMap<>();
    
    /**
     * 构造函数,初始化测试数据
     */
    public UserServiceImpl() {
        // 创建测试用户
        UserInfo user1 = new UserInfo();
        user1.setUserId("001");
        user1.setUserName("张三");
        user1.setEmail("zhangsan@example.com");
        user1.setPhone("13800138000");
        user1.setAge(28);
        userMap.put("001", user1);
    }
    
    /**
     * 打招呼方法实现
     * @param name 用户名
     * @return 个性化问候语
     */
    @Override
    public String sayHello(String name) {
        return "Hello, " + name + "! Welcome to User WebService.";
    }
    
    /**
     * 获取用户信息方法实现
     * @param userId 用户ID
     * @return 用户信息对象,如果用户不存在则返回默认信息
     */
    @Override
    public UserInfo getUserInfo(String userId) {
        // 从Map中获取用户信息
        UserInfo userInfo = userMap.get(userId);
        if (userInfo == null) {
            // 如果用户不存在,创建默认用户信息
            userInfo = new UserInfo();
            userInfo.setUserId(userId);
            userInfo.setUserName("Unknown User");
            userInfo.setEmail("unknown@example.com");
            userInfo.setPhone("00000000000");
            userInfo.setAge(0);
            userInfo.setAddress("Unknown Address");
            userMap.put(userId, userInfo);  // 缓存默认用户信息
            System.out.println("创建默认用户信息:" + userId);
        } else {
            System.out.println("查询用户信息:" + userId);
        }
        return userInfo;
    }
    
    /**
     * 更新用户信息方法实现
     * @param userInfo 要更新的用户信息
     * @return 更新结果,成功返回true,失败返回false
     */
    @Override
    public boolean updateUserInfo(UserInfo userInfo) {
        // 验证参数有效性
        if (userInfo != null && userInfo.getUserId() != null) {
            userMap.put(userInfo.getUserId(), userInfo);  // 更新用户信息
            System.out.println("更新用户信息:" + userInfo.getUserId());
            return true;
        }
        return false;
    }
}

1.6 实体类

java 复制代码
import lombok.Data;
import javax.xml.bind.annotation.XmlRootElement;

/**
 * 用户信息数据传输对象
 * @Data Lombok注解,自动生成getter/setter等方法
 * @XmlRootElement 标识该类可以被XML序列化和反序列化
 */
@Data
@XmlRootElement
public class UserInfo {
    private String userId;      // 用户ID
    private String userName;   // 用户名
    private String email;      // 邮箱
    private String phone;      // 电话
    private Integer age;       // 年龄
    private String address;    // 地址
}

1.7 WebService 服务端启用与测试

项目启动后访问如下地址:http://localhost:8082/webservice/server?wsdl 显示你定义的方法名称说明服务端已经发布成功

第二章、WebService 客户端代码实现

2.1 pom

xml 复制代码
 <!-- CXF WebService客户端依赖 -->
        <dependency>
            <groupId>org.apache.cxf</groupId>
            <artifactId>cxf-spring-boot-starter-jaxws</artifactId>
            <version>3.4.5</version>
        </dependency>

        <dependency>
            <groupId>org.apache.cxf</groupId>
            <artifactId>cxf-rt-transports-http</artifactId>
            <version>3.4.5</version>
        </dependency>

        <!-- Lombok简化代码 -->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>

2.2 yml

yml 复制代码
webservice:
  server:
    url: http://localhost:8082/webservice/server/userService  # 远程WebService服务地址

2.3 config

java 复制代码
import com.gitee.ht.client.UserServiceClient;
import org.apache.cxf.jaxws.JaxWsProxyFactoryBean;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
 * 客户端WebService配置类
 * 负责创建WebService客户端代理
 */
@Configuration
public class WebServiceClientConfig {
    
    // 从配置文件中注入远程服务地址
    @Value("${webservice.server.url}")
    private String serviceUrl;
    
    /**
     * 创建WebService客户端代理Bean
     * @return WebService客户端代理实例
     */
    @Bean
    public UserServiceClient userServiceClient() {
        // 创建JAX-WS代理工厂
        JaxWsProxyFactoryBean factory = new JaxWsProxyFactoryBean();
        // 设置服务接口类
        factory.setServiceClass(UserServiceClient.class);
        // 设置远程服务地址
        factory.setAddress(serviceUrl);
        // 创建并返回服务代理
        UserServiceClient client = (UserServiceClient) factory.create();
        System.out.println("WebService客户端代理创建成功,服务地址:" + serviceUrl);
        return client;
    }
}

2.4 bean实体类,需要与服务端定义一致,用于数据交换

java 复制代码
/**
 * 客户端用户信息对象
 * 与服务端的UserInfo类对应,用于数据交换
 * @Data Lombok注解,自动生成getter/setter等方法
 * @XmlRootElement 标识该类可以被XML序列化和反序列化
 */
@Data
@XmlRootElement
public class UserInfo {
    private String userId;      // 用户ID
    private String userName;   // 用户名
    private String email;      // 邮箱
    private String phone;      // 电话
    private Integer age;       // 年龄
    private String address;    // 地址
}

2.5 客户端接口层

java 复制代码
import javax.jws.WebMethod;
import javax.jws.WebParam;
import javax.jws.WebService;

/**
 * 客户端WebService接口定义
 * 必须与服务端接口保持一致,包括方法签名和命名空间
 * @WebService 注解配置必须与服务端一致
 */
@WebService(name = "UserService",
//        targetNamespace = "http://service.webserver.example.com/"
        targetNamespace = "http://localhost:8082/"
)
public interface UserServiceClient {
    
    /**
     * 打招呼方法
     * @param name 用户名
     * @return 问候语
     */
    @WebMethod
    String sayHello(@WebParam(name = "name") String name);
    
    /**
     * 获取用户信息方法
     * @param userId 用户ID
     * @return 用户信息对象
     */
    @WebMethod
    UserInfo getUserInfo(@WebParam(name = "userId") String userId);
    
    /**
     * 更新用户信息方法
     * @param userInfo 用户信息对象
     * @return 更新结果
     */
    @WebMethod
    boolean updateUserInfo(@WebParam(name = "userInfo") UserInfo userInfo);
}

2.6 请求调用webService

java 复制代码
import com.gitee.ht.client.UserInfo;
import com.gitee.ht.client.UserServiceClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

/**
 * 用户信息REST控制器
 * 提供RESTful接口,内部调用远程WebService服务
 */
@RestController
@RequestMapping("/api/user")
public class UserController {
    
    @Autowired
    private UserServiceClient userServiceClient;  // 注入WebService客户端代理
    
    /**
     * 测试打招呼功能的REST接口
     * @param name 用户名
     * @return 问候语
     */
    @GetMapping("/hello")
    public String sayHello(@RequestParam String name) {
        System.out.println("接收到打招呼请求,用户名:" + name);
        // 调用远程WebService的sayHello方法
        return userServiceClient.sayHello(name);
    }
    
    /**
     * 获取用户信息的REST接口
     * @param userId 用户ID
     * @return 用户信息对象
     */
    @GetMapping("/{userId}")
    public UserInfo getUserInfo(@PathVariable String userId) {
        System.out.println("接收到获取用户信息请求,用户ID:" + userId);
        // 调用远程WebService的getUserInfo方法
        return userServiceClient.getUserInfo(userId);
    }
    
    /**
     * 更新用户信息的REST接口
     * @param userInfo 用户信息对象
     * @return 操作结果
     */
    @PutMapping("/update")
    public String updateUserInfo(@RequestBody UserInfo userInfo) {
        System.out.println("接收到更新用户信息请求,用户ID:" + userInfo.getUserId());
        // 调用远程WebService的updateUserInfo方法
        boolean result = userServiceClient.updateUserInfo(userInfo);
        return result ? "更新成功" : "更新失败";
    }
    
    /**
     * WebService连接测试接口
     * @param userId 测试用户ID
     * @return 测试结果
     */
    @PostMapping("/test")
    public String testWebService(@RequestParam String userId) {
        System.out.println("开始测试WebService连接,用户ID:" + userId);
        try {
            // 尝试调用远程服务
            UserInfo userInfo = userServiceClient.getUserInfo(userId);
            String result = "WebService调用成功,用户信息:" + userInfo.getUserName();
            System.out.println(result);
            return result;
        } catch (Exception e) {
            String errorMsg = "WebService调用失败:" + e.getMessage();
            System.out.println(errorMsg);
            return errorMsg;
        }
    }
}

2.8 请求测试,需保证服务端项目已启动或部署

启动客户端项目,浏览器访问客户端接口,程序调用webService服务端,拿到返回结果,输出浏览器

相关推荐
今天的砖很烫2 小时前
ThreadLocal 结构设计的精妙之处
java·开发语言
绝无仅有2 小时前
Redis 面试题解析:某度互联网大厂
后端·面试·架构
绝无仅有2 小时前
某度互联网大厂 MySQL 面试题解析
后端·面试·架构
Q_Q5110082852 小时前
python+django/flask的图书馆管理系统vue
spring boot·python·django·flask·node.js·php
q***69772 小时前
Spring boot启动原理及相关组件
数据库·spring boot·后端
q***46522 小时前
Spring Boot 整合 Keycloak
java·spring boot·后端
LSL666_2 小时前
spring多配置文件
java·服务器·前端·spring
jakeswang2 小时前
JDK 25 重大兼容性 Bug
java
麦麦鸡腿堡2 小时前
Java_HashMap底层机制与原码解读
java·开发语言·jvm