为了后续顺利学习 Hystrix Feign,我们需要提前开发一个简单的服务,供 Hystrix Feign 进行调用。
该服务仅是一个简单的 Spring Boot 项目,提供几个简单服务,具体搭建步骤如下:
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>3.2.9</version> <relativePath/> <!-- lookup parent from repository --> </parent> <groupId>com.hxstrive</groupId> <artifactId>service-demo</artifactId> <version>0.0.1-SNAPSHOT</version> <name>service-demo</name> <description>service-demo</description> <properties> <java.version>17</java.version> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-devtools</artifactId> <scope>runtime</scope> <optional>true</optional> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> </dependency> </dependencies> <build> <finalName>service-demo</finalName> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> </project>
创建一个简单的 User 实体,包含用户ID、用户名和年龄,如下:
package com.hxstrive.service_demo.entity;
import lombok.Builder;
import lombok.Data;
import lombok.ToString;
/**
* 用户实体
* @author hxstrive.com
*/
@Data
@Builder
@ToString
public class User {
private Long id;
private String name;
private Integer age;
}为了开发的所有接口返回数据时采用统一的格式,我们专门开发一个通用的DTO泛型对象。代码如下:
package com.hxstrive.service_demo.dto;
import lombok.Data;
/**
* 通用返回对象
* @author hxstrive.com
*/
@Data
public class CommonReturn<T> {
private int code;
private String message;
private T data;
private String appName;
private String port;
public static <T> CommonReturn<T> success(T data) {
CommonReturn<T> commonReturn = new CommonReturn<>();
commonReturn.setCode(1);
commonReturn.setData(data);
return commonReturn;
}
public static <T> CommonReturn<T> success() {
return success(null);
}
public static <T> CommonReturn<T> fail(String message) {
CommonReturn<T> commonReturn = new CommonReturn<>();
commonReturn.setCode(0);
commonReturn.setMessage(message);
return commonReturn;
}
public CommonReturn<T> ext(String appName, String port) {
this.setAppName(appName);
this.setPort(port);
return this;
}
}下面将开发三个简单的 Controller,分别如下:
该控制器仅仅提供一个返回字符串的“hello”方法,代码如下:
package com.hxstrive.service_demo.controller;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.*;
import java.util.UUID;
/**
* 简单控制器
* @author hxstrive.com
*/
@RestController
@RequestMapping("/simple")
public class SimpleController {
@Value("${spring.application.name}")
private String appName;
@Value("${server.port}")
private String appPort;
@GetMapping("/hello")
public String hello() {
return "Hello World";
}
@GetMapping("/info")
public String info() {
return "appName=" + appName + " appPort=" + appPort + " uuid=" + UUID.randomUUID().toString();
}
@GetMapping("/get")
public String get(@RequestParam("id") Long id) {
return "appName=" + appName + " appPort=" + appPort + " id=" + id;
}
}该类提供传统风格的RUD操作,实现对用户进行正删改查,代码如下:
package com.hxstrive.service_demo.controller;
import com.hxstrive.service_demo.dto.CommonReturn;
import com.hxstrive.service_demo.entity.User;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.*;
import java.util.ArrayList;
import java.util.List;
/**
* 用户控制器
* @author hxstrive.com
*/
@Slf4j
@RestController
@RequestMapping("/user")
public class UserController {
private final static List<User> USERS = new ArrayList<>();
static {
USERS.add(User.builder().id(1L).name("Tom").age(20).build());
USERS.add(User.builder().id(2L).name("Helen").age(30).build());
USERS.add(User.builder().id(3L).name("Bill").age(40).build());
}
@Value("${spring.application.name}")
private String appName;
@Value("${server.port}")
private String appPort;
// GET 请求,获取所有用户信息
@GetMapping("/getAllUsers")
public CommonReturn<List<User>> getAllUsers() {
log.info("getAllUsers()");
return CommonReturn.success(USERS).ext(appName, appPort);
}
// GET 请求,根据用户 ID 获取用户信息
@GetMapping("/getUserById")
public CommonReturn<User> getUserById(@RequestParam("id") Long id) {
log.info("getUserById() id={}", id);
return USERS.stream()
.filter(user -> user.getId().equals(id))
.findFirst()
.map(u -> CommonReturn.success(u).ext(appName, appPort))
.orElse(CommonReturn.fail("用户不存在"));
}
// POST 请求,创建新用户
@PostMapping("/createUser")
public CommonReturn<User> createUser(@RequestBody User user) {
log.info("createUser() user={}", user);
USERS.add(user);
return CommonReturn.success(user).ext(appName, appPort);
}
// PUT 请求,更新用户信息
@PutMapping("/updateUser")
public CommonReturn<User> updateUser(@RequestParam("id") Long id, @RequestBody User updatedUser) {
log.info("updateUser() id={}, updateUser={}", id, updatedUser);
for (int i = 0; i < USERS.size(); i++) {
if (USERS.get(i).getId().equals(id)) {
USERS.set(i, updatedUser);
return CommonReturn.success(updatedUser).ext(appName, appPort);
}
}
return CommonReturn.fail("更新用户信息失败");
}
// DELETE 请求,删除用户
@DeleteMapping("/deleteUser")
public CommonReturn<String> deleteUser(@RequestParam("id") Long id) {
log.info("deleteUser() id={}", id);
USERS.removeIf(user -> user.getId().equals(id));
return CommonReturn.success("删除成功").ext(appName, appPort);
}
}该类提供Restful分隔的CRUD操作,实现对用户进行正删改查,代码如下:
package com.hxstrive.service_demo.controller;
import com.hxstrive.service_demo.dto.CommonReturn;
import com.hxstrive.service_demo.entity.User;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.*;
import java.util.ArrayList;
import java.util.List;
/**
* Restful 风格的用户控制器
* @author hxstrive.com
*/
@Slf4j
@RestController
@RequestMapping("/user/restful")
public class UserRestfulController {
private final static List<User> USERS = new ArrayList<>();
static {
USERS.add(User.builder().id(1L).name("Tom").age(20).build());
USERS.add(User.builder().id(2L).name("Helen").age(30).build());
USERS.add(User.builder().id(3L).name("Bill").age(40).build());
}
@Value("${spring.application.name}")
private String appName;
@Value("${server.port}")
private String appPort;
// GET 请求,获取所有用户信息
@GetMapping("/getAllUsers")
public CommonReturn<List<User>> getAllUsers() {
log.info("getAllUsers()");
return CommonReturn.success(USERS).ext(appName, appPort);
}
// GET 请求,根据用户 ID 获取用户信息
@GetMapping("/{id}")
public CommonReturn<User> getUserById(@PathVariable Long id) {
log.info("getUserById() id={}", id);
return USERS.stream()
.filter(user -> user.getId().equals(id))
.findFirst()
.map((u) -> CommonReturn.success(u).ext(appName, appPort))
.orElse(CommonReturn.fail("用户不存在"));
}
// POST 请求,创建新用户
@PostMapping("/createUser")
public CommonReturn<User> createUser(@RequestBody User user) {
log.info("createUser() user={}", user);
USERS.add(user);
return CommonReturn.success(user).ext(appName, appPort);
}
// PUT 请求,更新用户信息
@PutMapping("/{id}")
public CommonReturn<User> updateUser(@PathVariable Long id, @RequestBody User updatedUser) {
log.info("updateUser() id={}, updateUser={}", id, updatedUser);
for (int i = 0; i < USERS.size(); i++) {
if (USERS.get(i).getId().equals(id)) {
USERS.set(i, updatedUser);
return CommonReturn.success(updatedUser).ext(appName, appPort);
}
}
return CommonReturn.fail("更新用户信息失败");
}
// DELETE 请求,删除用户
@DeleteMapping("/{id}")
public CommonReturn<String> deleteUser(@PathVariable Long id) {
log.info("deleteUser() id={}", id);
USERS.removeIf(user -> user.getId().equals(id));
return CommonReturn.success("删除成功");
}
}开发一个非常简单的 Spring Boot 启动类,什么也不做,仅添加了 @SpringBootApplication 注解,代码如下:
package com.hxstrive.service_demo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
/**
* 入口
* @author hxstrive.com
*/
@SpringBootApplication
public class ServiceDemoApplication {
public static void main(String[] args) {
SpringApplication.run(ServiceDemoApplication.class, args);
}
}到这里,我们的准备工作已经做完了,下章节将介绍如何使用 Netflix Feign 调用这些 API。