版本:SpringBoot 2.6.5
SpringCloud 2021.0.3
Eureka,OpenFeign无需设置版本 (要设置的话,选择3.1.3)
在这里提一句,SpringBoot整合SpringCloud时,一定要注意版本的匹配。
springcloud官网
关于Eureka,诚心感谢这篇文章,它给我提供了主要的思路和代码参考,其中也涉及到什么是CAP。重要Eureka参考文章
OpenFeign 和Feign的一些区别。区别feign
我的整个项目分享链接:
链接:https://pan.baidu.com/s/185Tb_hEcCmQKzawL4BiEhw
提取码:ljl6
有三个模块:eureka-server-demo(注册中心),orderservice(服务消费方),userservice(服务提供方)
一:eureka-server-demo(注册中心) |
pom.xml
<?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>2.6.5</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.practice</groupId>
<artifactId>eureka-server-demo</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>eureka-server-demo</name>
<properties>
<java.version>1.8</java.version>
<spring-boot.version>2.6.5</spring-boot.version>
<spring-cloud.version>2021.0.3</spring-cloud.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
yaml文件
server:
port: 8761
spring:
application:
name: eureka-server
eureka:
client:
service-url:
defaultZone: http://127.0.0.1:8761/eureka/
fetch-registry: false
register-with-eureka: false
启动类:
三:userservice(服务提供方) |
项目结构:
Swagger配置
package com.practice.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import springfox.documentation.builders.ApiInfoBuilder;
import springfox.documentation.builders.PathSelectors;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.service.ApiInfo;
import springfox.documentation.service.Contact;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;
/**
* @author:ljl
* @create: 2022-07-13 16:44
* @Description: SwaggerConfig的配置
* @Version: 1.0
*/
@Configuration // 标明是配置类
public class SwaggerConfig {
@Bean
public Docket createRestApi() {
return new Docket(DocumentationType.SWAGGER_2) // DocumentationType.SWAGGER_2 固定的,代表swagger2
.groupName("练习Mybaits-User") // 如果配置多个文档的时候,那么需要配置groupName来分组标识
.apiInfo(apiInfo()) // 用于生成API信息
.select() // select()函数返回一个ApiSelectorBuilder实例,用来控制接口被swagger做成文档
.apis(RequestHandlerSelectors.basePackage("com.practice.web")) // 用于指定扫描哪个包下的接口
.paths(PathSelectors.any())// 选择所有的API,如果你想只为部分API生成文档,可以配置这里
.build();
}
/**
* 用于定义API主界面的信息,比如可以声明所有的API的总标题、描述、版本
* @return
*/
private ApiInfo apiInfo() {
return new ApiInfoBuilder()
.title("网站-API文档") // 可以用来自定义API的主标题
.description("本文档描述了网站微服务接口定义") // 可以用来描述整体的API
.termsOfServiceUrl("") // 用于定义服务的域名
.version("1.0") // 可以用来定义版本。
.contact(new Contact("practice-lij", null, null))
.build();
}
}
UserMapper(接口)
package com.practice.mapper;
import com.practice.model.User;
import org.apache.ibatis.annotations.Mapper;
import org.springframework.stereotype.Repository;
import java.util.List;
@Mapper
@Repository
public interface UserMapper {
/**
*@Param: @param id:
*@return: User
*@Description: 根据ID查找用户
*/
User findUserById(Integer id);
/**
*@Param: @param null:
*@return: List<User>
*@Description: 查找所有用户
*/
List<User> findAllUser();
/**
*@Param: @param id:
*@return: User
*@Description: 根据订单查找用户
*/
User findByOrder(Integer order_id);
}
UserMapper(xml)
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.practice.mapper.UserMapper">
<resultMap id="userMap" type="com.practice.model.User">
<id column="id" property="id" jdbcType="BIGINT"></id>
<result column="username" property="username" jdbcType="VARCHAR"></result>
<result column="address" property="address" jdbcType="VARCHAR"></result>
</resultMap>
<sql id="userInfo">
u.id,u.username,u.address
</sql>
<select id="findUserById" resultMap="userMap">
SELECT
<include refid="userInfo"></include>
FROM tb_user AS u
WHERE u.id=#{id,jdbcType=INTEGER}
</select>
<select id="findAllUser" resultMap="userMap">
SELECT
<include refid="userInfo"></include>
FROM tb_user AS u
</select>
<select id="findByOrder" resultMap="userMap">
SELECT
<include refid="userInfo"></include>
FROM tb_user AS u
LEFT JOIN tb_order AS o ON u.id=o.user_id
WHERE o.id=#{order_id,jdbcType=BIGINT}
</select>
</mapper>
yaml文件
server:
port: 8081
spring:
application:
name: UserServiceProvider
datasource:
druid:
url: jdbc:mysql://127.0.0.1:3306/spring-cloud-demo?serverTimezone=GMT%2B8
driver-class-name: com.mysql.cj.jdbc.Driver
username: root
password: 1234
max-active: 100
max-wait: 60000
mvc:
pathmatch:
matching-strategy: ant_path_matcher
mybatis:
mapper-locations: classpath:mapper/*.xml
type-aliases-package: com.practice.entity
configuration:
map-underscore-to-camel-case: true
pagehelper:
helperDialect: mysql
reasonable: true
supportMethodsArguments: false
params: count=countSql
eureka:
client:
service-url:
defaultZone: http://127.0.0.1:8761/eureka/
UserController
package com.practice.web;
import com.practice.model.User;
import com.practice.service.UserService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
/**
* @author:ljl
* @create: 2022-07-28 09:22
* @Description: 用户控制类
* @Version: 1.0
*/
@RestController("/userServer")
@Api(tags = "用户管理")
public class UserController {
@Autowired
private UserService userService;
@ApiOperation("根据ID查找用户")
@GetMapping("/findById")
public User getById(Integer id){
User user = userService.findUserById(id);
return user;
}
@ApiOperation("查找所有用户")
@GetMapping("/findAll")
public List<User> get(){
return userService.findAllUser();
}
@ApiOperation("根据订单查找用户")
@GetMapping("/findByOrder")
public User getByOrder(Integer order_id){
return userService.findByOrder(order_id);
}
}
启动类:
对应的Service 和ServiceImpl不在此展示,以及Order中和User中重复的内容也不展示。
二:orderservice(服务消费方) |
项目结构:
这个部分主要有userClient 和 User 和 OrderController 和 SwagerConfig就足够了,
因为此时的order是服务消费方
yaml文件
server:
port: 8086
spring:
application:
name: OrderServiceConsumer
datasource:
druid:
url: jdbc:mysql://127.0.0.1:3306/spring-cloud-demo?serverTimezone=GMT%2B8
driver-class-name: com.mysql.cj.jdbc.Driver
username: root
password: 1234
max-active: 100
max-wait: 60000
mvc:
pathmatch:
matching-strategy: ant_path_matcher
mybatis:
mapper-locations: classpath:mapper/*.xml
type-aliases-package: com.practice.entity
configuration:
map-underscore-to-camel-case: true
pagehelper:
helperDialect: mysql
reasonable: true
supportMethodsArguments: false
params: count=countSql
eureka:
client:
service-url:
defaultZone: http://127.0.0.1:8761/eureka/
UserClient(重点)
package com.practice.client;
import com.practice.model.User;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
@FeignClient(name = "UserServiceProvider",contextId = "userServer")
public interface UserClient {
/**
*@Param: @param id:
*@return: User
*@Description: 根据订单查找用户
*/
@GetMapping("/findByOrder")
User findUserByOrder(@RequestParam("order_id")Integer order_id);
}
配置要点:
1.name的取值在服务提供方,也就是这个项目的user中的yaml配置的名称 |
2.contexId的值取user控制类(RestController) |
3.接口上一定要加对应的注解比如@GetMapping |
4.接口名称一定要和User提供的一致(findUserByOrder) |
5.参数使用@RequestParam |
OrderController
package com.practice.web;
import com.practice.client.UserClient;
import com.practice.model.User;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
/**
* @author:ljl
* @create: 2022-07-28 10:07
* @Description: 订单控制类
* @Version: 1.0
*/
@RestController
@RequestMapping("/orderServer")
@Api(tags = "订单管理")
public class OrderController {
@Autowired
private UserClient userClient;
//测试userClient
@ApiOperation("根据订单查找用户")
@GetMapping("/findByOrder")
public User getByOrder(@RequestParam("order_id") Integer order_id){
return userClient.findUserByOrder(order_id);
}
}
启动类:
结果验证:
8081服务提供方
8086:服务消费方
数据库查询
在order的Swagger查询
文章最后一些可能出现的错误提示:
Method search not annotated with HTTP method type (ex. GET, POST)–》表格中的第3条链接
提示feign.FeignException$NotFound: [404] during [GET] to [http://userservice/fin
This application has no explicit mapping for /error…
提示:EMERGENCY! EUREKA MAY BE INCORRECTLY CLAIMING INSTANCES ARE UP WHEN THEY’RE NOT. 可能是忘记启动某个服务,比如你之前启动两个userService 现在调试只启动了一个,解决办法要么都启动,要么删除一个。链接
小提示:如果在参考过程中发现了错误或者建议都可以私信我,一起成长。