提供与消费
文章目录
- 提供与消费
- 创建服务提供者
- 初始化项目
- 项目配置
- 定义User
- 编写UserMapper
- 编写Service层
- 定义api接口返回格式
- 编写Controller层
- 创建服务消费者
- 配置User服务的地址
- 创建RestTemplate Bean
- 创建UserApi
- 编写Controller层
- 总结
微服务属于分布式系统,微服务之间通过网络通信,服务之间的关系可以有很多种,其中一种是服务-消费。
比如购票时,用户直接调用的是购票微服务,而购票微服务需要调用用户微服务来获取用户信息以及余额信息等等,在这个场景下,用户微服务是服务提供者,电影微服务是一个服务消费者。
创建服务提供者
以上面的情景为例,创建一个用户微服务。
初始化项目
Spring Initialzr 创建一个Springboot项目(本文是2.7.10版本),预装 Springboot Web, lombok, Mysql Driver, Mybatis Framework四个工具包。
项目配置
- 在MYSQL中创建一个
micro-example1
数据库
# MySQL
# 驱动
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
# 数据库名
spring.datasource.name=defaultDataSource
# 数据库连接
spring.datasource.url=jdbc:mysql://localhost:3306/micro-example1?useUnicode=true&characterEncoding=utf-8&serverTimezone=GMT
# 用户名密码
spring.datasource.username=root
spring.datasource.password=root
# 数据初始化
spring.sql.init.schema-locations=classpath:db/schema.sql
spring.sql.init.data-locations=classpath:db/data.sql
spring.sql.init.mode=always server.port=8081 spring.application.name=user-service
- schema.sql(resources目录下新建db目录)
DROP TABLE IF EXISTS `user`;
CREATE TABLE user ( `id` INTEGER AUTO_INCREMENT, `username` VARCHAR(40), `name` VARCHAR(20), `age` INTEGER(3), `balance` DECIMAL(10,2) COMMENT '余额', PRIMARY KEY (`id`)
);
- data.sql
INSERT INTO user VALUES (1, 'user1', '用户1', 21, 100.00);
INSERT INTO user VALUES (2, 'user2', '用户2', 22, 200.00);
INSERT INTO user VALUES (3, 'user3', '用户3', 23, 300.00);
定义User
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor; import java.math.BigDecimal; @Data
@AllArgsConstructor
@NoArgsConstructor
public class User { private Integer id; private String username; private String name; private Integer age; private BigDecimal balance;
}
编写UserMapper
定义一个根据id查询user记录的方法
import com.evanpatchouli.example1.model.User;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Select;
import org.springframework.stereotype.Repository; @Mapper
@Repository
public interface UserMapper { @Select("select * from user where id=#{id}") User selById(Integer id);
}
编写Service层
- UserSerice接口
import com.evanpatchouli.example1.model.User; public interface UserService { User selById(Integer id);
}
- UserServiceImpl实现
import com.evanpatchouli.example1.mapper.UserMapper;
import com.evanpatchouli.example1.model.User;
import org.springframework.stereotype.Service; import javax.annotation.Resource; @Service
public class UserServiceImpl implements UserService{ @Resource private UserMapper userMapper; @Override public User selById(Integer id) { return userMapper.selById(id); }
}
定义api接口返回格式
- Result.java
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor; @AllArgsConstructor
@NoArgsConstructor
@Data
public class Result<T> { int code; String msg; T data;
}
- Resp.java(工具类)
public class Resp { public static <T> Result ok(String msg, T data) { return new Result(200,msg,data); } public static <T> Result fail(String msg, T data) { return new Result(200,msg,data); }
}
编写Controller层
import com.evanpatchouli.example1.model.Result;
import com.evanpatchouli.example1.model.User;
import com.evanpatchouli.example1.service.UserService;
import org.springframework.web.bind.annotation.*; import javax.annotation.Resource; @RestController
@CrossOrigin
@RequestMapping("/user")
public class UserController<T> { @Resource private UserService userService; @GetMapping("/{id}") public Result<User> findById(@PathVariable Integer id) { User user = userService.selById(id); return new Result<>(200, "查找成功", user); } }
创建服务消费者
这里创建电影票微服务,准备工作类似,只安装Springboot Web和lombok即可。
配置User服务的地址
写在配置文件里的意图是便于管理和更改地址
server.port=8080
spring.application.name=ticket-service
api.user-service=http://127.0.0.1:8081/user/
创建RestTemplate Bean
入口类内创建一个创建RestTemplate的Bean,作为rest-api客户端
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.web.client.RestTemplate;@SpringBootApplication
public class TicketApplication {@Beanpublic RestTemplate rest() {return new RestTemplate();}public static void main(String[] args) {SpringApplication.run(TicketApplication.class, args);}}
创建UserApi
创建一个UserApi组件,使用rest客户端调用user服务的查询接口
import com.example.ticket.model.Result;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.web.client.RestTemplate;import javax.annotation.Resource;@Component
public class UserApi {@Value("${api.user-service}")private String baseUrl;@Resourceprivate RestTemplate rest;public Result findUserById(Integer id) {//http://localhost:8081/user/:idreturn rest.getForObject(baseUrl+id, Result.class);}
}
编写Controller层
定义一个查询能不能买下票的接口,传入2参数,票价和用户id。在接口内调用UserApi查询用户信息,进行一系列的判断(用户存在?余额充足?),最后返回结果
import com.example.ticket.api.UserApi;
import com.example.ticket.model.Resp;
import com.example.ticket.model.Result;
import org.springframework.web.bind.annotation.*;import javax.annotation.Resource;
import java.util.HashMap;@RestController
@CrossOrigin
@RequestMapping("/ticket")
public class TicketController {@Resourceprivate UserApi userApi;@GetMapping("/canibuy")public Result canIBuy(@RequestParam Double price, @RequestParam Integer id) {Result resp = userApi.findUserById(id);HashMap user = (HashMap) resp.getData();if (user==null){return Resp.fail("用户不存在",user);}if (price.compareTo((Double) user.get("balance")) > 0){return Resp.fail("余额不足",user);}return Resp.ok("余额充足", user);}
}
总结
这是一个最简单的微服务之间的调用,甚至都用不上SpringCloud,但很简洁得为我们展示了服务提供者和消费者之间的关系。