基于eureka+spring-boot+spring-cloud搭建 订单-商品 微服务框架
# 环境说明:
spring-boot version:2.5.3
java version:11
spring-cloud version 2020.0.3
# 笔记目的,熟悉、演示微服务系统架构的搭建步骤
# 节点服务搭建
## eureka
1、添加依赖
```
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.5.3</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<properties>
<java.version>11</java.version>
<spring-cloud.version>2020.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-security</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>
```
2、配置属性
```
server.port=8091
spring.application.name=myeureka
# eureka server's configure
eureka.instance.hostname=127.0.0.1
eureka.instance.prefer-ip-address=true
eureka.instance.instance-id=${eureka.instance.hostname}:${server.port}/eureka
# eureka client's configure
eureka.client.register-with-eureka=false
eureka.client.fetch-registry=false
eureka.client.service-url.defaultZone=http://mark6666:markpasswd@127.0.0.1:8091/eureka/
#security
spring.security.user.name=mark6666
spring.security.user.password=markpasswd
```
3、主类注入eureka服务依赖
```
package com.demo.eureka2;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;
/**
* Hello world!
*
*/
@EnableEurekaServer
@SpringBootApplication
public class App
{
public static void main( String[] args )
{
SpringApplication.run(App.class, args);
}
}
```
4、关闭CSRF验证,不然服务注册不了
configuration/WebSecurityConfig.java
```
package com.demo.eureka2.configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.anyRequest().authenticated()
.and()
.httpBasic()
.and()
.csrf().disable();//ignoringAntMatchers("/eureka/**");//不建议完全禁用掉csrf
}
}
```
5、 启动服务
6、登录并查看控制台
登录地址:http://127.0.0.1:8091/
备注:控制台地址不带"eureka"后缀;但服务注册地址中需要带这个后缀
## product
1、添加依赖
```
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.5.3</version>
</parent>
<properties>
<java.version>11</java.version>
<spring-cloud.version>2020.0.3</spring-cloud.version>
</properties>
<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>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
<exclusions>
<exclusion>
<groupId>com.fasterxml.jackson.dataformat</groupId>
<artifactId>jackson-dataformat-xml</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>1.1.1</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
</dependency>
</dependencies>
```
2、配置属性
```
server.port=8086
spring.application.name=product-service
spring.jackson.date-format=yyyy-MM-dd HH:mm:ss
spring.jackson.time-zone=Asia/Shanghai
# database setting
spring.datasource.url=jdbc:mysql://localhost:3306/java_demo?serverTimezone=UTC&useUnicode=true&characterEncoding=utf-8
spring.datasource.username=root
spring.datasource.password=root
#mybatis mapper path
mybatis.mapper-locations: classpath:mybatis/*.xml
eureka.client.register-with-eureka=false
eureka.client.fetch-registry=false
eureka.client.service-url.defaultZone=http://mark6666:markpasswd@127.0.0.1:8091/eureka
# register itsself ip to eureka
eureka.instance.prefer-ip-address=true
# set ip of the service
# eureka.instance.ip-address=127.0.0.1
# set id of the instance
# eureka.instance.instance-id=${spring.application.name}:${server.port}/productSrv
```
3、主类注入eureka客户端发现服务依赖-@EnableDiscoveryClient
```
package com.demo.product_center;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
/**
* Hello world!
*
*/
@EnableDiscoveryClient
@SpringBootApplication
public class App
{
public static void main( String[] args )
{
SpringApplication.run( App.class, args );
}
}
```
4、编写API控制器
controller/ApiController.java
```
@RestController
@RequestMapping("/product-service")
public class ProductController {
@Autowired
private ProductService productService;
@RequestMapping("product/{id}")
public Product getProduct(@PathVariable("id") int id) {
return this.productService.getProduct(id);
}
}
```
5、编写service
service/ProductService.java
```
@Service
public class ProductService {
@Autowired
private ProductMapper productMapper;
public Product getProduct(int id) {
return this.productMapper.getProduct(id);
}
}
```
6、编写mapper Interface
mapper/ProductMapper.java
```
@Mapper
public interface ProductMapper {
List<Product> products();
Product getProduct(int id);
int updateById(Product product);
int deleteById(int id);
}
```
7、编写mybatis mapper
resources/mybatis/Product.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.demo.product_center.mapper.ProductMapper" >
<resultMap id="BaseResultMap" type="com.demo.product_center.bean.Product" >
<id column="id" property="id" jdbcType="INTEGER" />
<result column="name" property="name" jdbcType="VARCHAR" />
<result column="quantity" property="quantity" jdbcType="INTEGER" />
<result column="price" property="price" jdbcType="DECIMAL" />
<result column="create_time" property="createTime" jdbcType="TIMESTAMP" />
<result column="update_time" property="updateTime" jdbcType="TIMESTAMP" />
</resultMap>
<sql id="Base_Column_List" >
id, name, quantity, price, create_time, update_time
</sql>
<sql id="Base_Table_Name" >
`products`
</sql>
<select id="products" resultMap="BaseResultMap">
select
<include refid="Base_Column_List" />
from
<include refid="Base_Table_Name" />
order by id limit 10
</select>
<select id="getProduct" resultMap="BaseResultMap" parameterType="java.lang.Integer" >
select
<include refid="Base_Column_List" />
from
<include refid="Base_Table_Name" />
where id = #{id,jdbcType=INTEGER}
</select>
<delete id="deleteById" parameterType="java.lang.Integer" >
delete from
<include refid="Base_Table_Name" />
where id = #{id,jdbcType=INTEGER}
</delete>
<insert id="insert" parameterType="com.demo.product_center.bean.Product" >
insert into
<include refid="Base_Table_Name" />
(id, name, quantity, price,create_time, update_time
)
values (#{id,jdbcType=INTEGER}, #{name,jdbcType=VARCHAR}, #{quantity,jdbcType=INTEGER}, #{price,jdbcType=DECIMAL}, #{createTime,jdbcType=TIMESTAMP}, #{updateTime,jdbcType=TIMESTAMP}
)
</insert>
<update id="updateById" parameterType="com.demo.product_center.bean.Product" >
update product
set quantity = #{quantity,jdbcType=INTEGER},
update_time = #{updateTime,jdbcType=TIMESTAMP}
where id = #{id,jdbcType=INTEGER}
</update>
</mapper>
```
8、编写Product bean
bean/Product.java
```
public class Product {
private Integer id;
private String name;
private Integer quantity;
private Float price;
private Date createTime;
private Date updateTime;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getQuantity() {
return quantity;
}
public void setQuantity(Integer quantity) {
this.quantity = quantity;
}
public Float getPrice() {
return price;
}
public void setPrice(Float price) {
this.price = price;
}
public Date getCreateTime() {
return createTime;
}
public void setCreateTime(Date createTime) {
this.createTime = createTime;
}
public Date getUpdateTime() {
return updateTime;
}
public void setUpdateTime(Date updateTime) {
this.updateTime = updateTime;
}
}
```
9、启动服务
10、访问API
http://10.12.30.49:8086/product-service/product/1
## order
1、添加依赖
```
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.5.3</version>
</parent>
<properties>
<java.version>11</java.version>
<spring-cloud.version>2020.0.3</spring-cloud.version>
</properties>
<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>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
<exclusions>
<exclusion>
<groupId>com.fasterxml.jackson.dataformat</groupId>
<artifactId>jackson-dataformat-xml</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>1.1.1</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
</dependency>
</dependencies>
```
2、配置属性
```
server.port=8085
spring.application.name=order-service
# debug=true
spring.jackson.date-format=yyyy-MM-dd HH:mm:ss
spring.jackson.time-zone=Asia/Shanghai
# database setting
spring.datasource.url=jdbc:mysql://localhost:3306/java_demo?serverTimezone=UTC&useUnicode=true&characterEncoding=utf-8
spring.datasource.username=root
spring.datasource.password=root
#mybatis mapper path
mybatis.mapper-locations: classpath:mybatis/*.xml
eureka.client.register-with-eureka=false
eureka.client.fetch-registry=false
eureka.client.service-url.defaultZone=http://mark6666:markpasswd@127.0.0.1:8091/eureka
# register itsself ip to eureka
eureka.instance.prefer-ip-address=true
```
3、主类注入eureka客户端发现服务依赖-@EnableDiscoveryClient
```
@EnableDiscoveryClient
@SpringBootApplication
public class App
{
public static void main( String[] args )
{
SpringApplication.run( App.class, args );
}
@Bean
public RestTemplate restTemplate() {
return new RestTemplate();
}
}
```
4、编写API控制器
```
package com.demo.order_center.controller;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.demo.order_center.bean.Order;
import com.demo.order_center.service.OrderService;
@RestController
@RequestMapping("/order-service")
public class OrderController {
@Autowired
private OrderService orderService;
@RequestMapping("order/{id}")
public Order getProduct(@PathVariable("id") String id) {
return this.orderService.getOrder(id);
}
}
```
5、编写service
service/OrderService.java
```
@Service
public class OrderService {
@Autowired
private OrderMapper orderMapper;
@Autowired
private OrderDetailMapper orderDetailMapper;
@Autowired
private ProductService productService;
public Order getOrder(String id) {
Order order = orderMapper.getOrder(id);
if(null == order) return null;
List<OrderDetail> orderDetails = orderDetailMapper.orderDetails(id);
if(null == orderDetails) return null;
for(OrderDetail orderDetail : orderDetails) {
Product product = this.productService.getProduct(orderDetail.getProductId());
if(null == product) continue;
orderDetail.setProduct(product);
}
order.setOrderDetail(orderDetails);
return order;
}
}
```
service/ProductService.java
```
package com.demo.order_center.service;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;
import com.demo.order_center.bean.Product;
@Service
public class ProductService {
@Autowired
private RestTemplate restTemplate;
@Autowired
private DiscoveryClient discoveryClient;
public Product getProduct(int id) {
String serviceId = "product-service";
List<ServiceInstance> instances = this.discoveryClient.getInstances(serviceId);
if(instances.isEmpty()) return null;
ServiceInstance serviceInstance = instances.get(0);
String url = "http://" + serviceInstance.getHost() + ":" + serviceInstance.getPort() + "/product-service/product/" + id;
Product product = restTemplate.getForObject(url, Product.class);
return product;
}
}
```
6、编写mapper interface
mapper/OrderMapper.java
```
@Mapper
public interface OrderMapper {
List<Order> orders();
Order getOrder(String id);
int deleteById(String id);
int insert(Order order);
}
```
mapper/OrderDetailMapper.java
```
@Mapper
public interface OrderDetailMapper {
List<OrderDetail> orderDetails(String orderId);
OrderDetail getOrderDetail(String orderId);
int deleteById(String orderId);
int insert(OrderDetail orderDetail);
}
```
7、编写mybatis mapper
resources/mybatis/order.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.demo.order_center.mapper.OrderMapper" >
<resultMap id="BaseResultMap" type="com.demo.order_center.bean.Order" >
<id column="id" property="id" jdbcType="VARCHAR" />
<result column="user_id" property="userId" jdbcType="INTEGER" />
<result column="state" property="state" jdbcType="INTEGER" />
<result column="create_time" property="createTime" jdbcType="TIMESTAMP" />
<result column="update_time" property="updateTime" jdbcType="TIMESTAMP" />
</resultMap>
<sql id="Base_Column_List" >
id, user_id, state, create_time, update_time
</sql>
<sql id="Base_Table_Name" >
`orders`
</sql>
<select id="orders" resultMap="BaseResultMap">
select
<include refid="Base_Column_List" />
from
<include refid="Base_Table_Name" />
order by id limit 10
</select>
<select id="getOrder" resultMap="BaseResultMap" parameterType="java.lang.String" >
select
<include refid="Base_Column_List" />
from
<include refid="Base_Table_Name" />
where id = #{id,jdbcType=VARCHAR}
</select>
<delete id="deleteById" parameterType="java.lang.String" >
update
<include refid="Base_Table_Name" />
set state = 0
where id = #{id,jdbcType=VARCHAR}
</delete>
<insert id="insert" parameterType="com.demo.order_center.bean.Order" >
insert into
<include refid="Base_Table_Name" />
(id, user_id, state, create_time, update_time
)
values (#{id,jdbcType=VARCHAR}, #{userId,jdbcType=INTEGER}, #{state,jdbcType=INTEGER}, #{createTime,jdbcType=TIMESTAMP}, #{updateTime,jdbcType=TIMESTAMP}
)
</insert>
</mapper>
```
resources/mybatis/orderDetail.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.demo.order_center.mapper.OrderDetailMapper" >
<resultMap id="BaseResultMap" type="com.demo.order_center.bean.OrderDetail" >
<id column="id" property="id" jdbcType="INTEGER" />
<result column="order_id" property="orderId" jdbcType="VARCHAR" />
<result column="product_id" property="productId" jdbcType="INTEGER" />
</resultMap>
<sql id="Base_Column_List" >
id, order_id, product_id
</sql>
<sql id="Base_Table_Name" >
`order_details`
</sql>
<select id="orderDetails" resultMap="BaseResultMap" parameterType="java.lang.String" >
select
<include refid="Base_Column_List" />
from
<include refid="Base_Table_Name" />
where order_id = #{orderId,jdbcType=VARCHAR}
order by id limit 100
</select>
<select id="getOrderDetail" resultMap="BaseResultMap" parameterType="java.lang.String" >
select
<include refid="Base_Column_List" />
from
<include refid="Base_Table_Name" />
where order_id = #{orderId,jdbcType=VARCHAR}
</select>
<delete id="deleteById" parameterType="java.lang.String" >
update from
<include refid="Base_Table_Name" />
set state = 0
where id = #{orderId,jdbcType=VARCHAR}
</delete>
<insert id="insert" parameterType="com.demo.order_center.bean.OrderDetail" >
insert into
<include refid="Base_Table_Name" />
(id, order_id, product_id, state
)
values (#{id,jdbcType=INTEGER}, #{orderId,jdbcType=VARCHAR}, #{productId,jdbcType=INTEGER}, 1
)
</insert>
</mapper>
```
8、编写bean
bean/Order.java
```
public class Order{
private String id;
private int userId;
private int state;
private Date createTime;
private Date updateTime;
private List<OrderDetail> orderDetails;
public Order() {
}
public Order(String id, int userId, Date createTime, Date updateTime) {
this.id = id;
this.userId = userId;
this.createTime = createTime;
this.updateTime = updateTime;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public int getUserId() {
return userId;
}
public void setUserId(int userId) {
this.userId = userId;
}
public int getState() {
return state;
}
public void setState(int state) {
this.state = state;
}
public Date getCreateTime() {
return createTime;
}
public void setCreateTime(Date createTime) {
this.createTime = createTime;
}
public Date getUpdateTime() {
return updateTime;
}
public void setUpdateTime(Date updateTime) {
this.updateTime = updateTime;
}
public List<OrderDetail> getOrderDetail() {
return orderDetails;
}
public void setOrderDetail(List<OrderDetail> orderDetails) {
this.orderDetails = orderDetails;
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append(getClass().getSimpleName());
sb.append("[");
sb.append("Hash =").append(hashCode());
sb.append(", id=").append(id);
sb.append(", userId=").append(userId);
sb.append(", createTime=").append(createTime);
sb.append(", updateTime=").append(updateTime);
sb.append("]");
return sb.toString();
}
}
```
bean/OrderDetail.java
```
public class OrderDetail {
private int id;
private String orderId;
private int productId;
private Product product = new Product();
public OrderDetail() {
}
public OrderDetail(String orderId, Product product) {
this.orderId = orderId;
this.product = product;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getOrderId() {
return orderId;
}
public void setOrderId(String orderId) {
this.orderId = orderId;
}
public int getProductId() {
return productId;
}
public void setProductId(int productId) {
this.productId = productId;
}
public Product getProduct() {
return product;
}
public void setProduct(Product product) {
this.product = product;
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append(getClass().getSimpleName());
sb.append("[");
sb.append("Hash =").append(hashCode());
sb.append(", orderId=").append(orderId);
sb.append(", productId=").append(productId);
sb.append(", products=").append(product.toString());
sb.append("]");
return sb.toString();
}
}
```
bean/Product.java
```
public class Product {
private Integer id;
private String name;
private Integer quantity;
private Float price;
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
private Date createTime;
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
private Date updateTime;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getQuantity() {
return quantity;
}
public void setQuantity(Integer quantity) {
this.quantity = quantity;
}
public Float getPrice() {
return price;
}
public void setPrice(Float price) {
this.price = price;
}
public Date getCreateTime() {
return createTime;
}
public void setCreateTime(Date createTime) {
this.createTime = createTime;
}
public Date getUpdateTime() {
return updateTime;
}
public void setUpdateTime(Date updateTime) {
this.updateTime = updateTime;
}
}
```
9、启动服务
10、访问API
http://127.0.0.1:8085/order-service/order/1