微服务学习1——微服务环境搭建
(参考黑马程序员项目)
个人仓库地址:https://gitee.com/jkangle/springboot-exercise.git
微服务就是将单体应用进一步拆分,拆成更小的服务,拆完之后怎么调用,主流的技术有RESTful和RPC,(首先以RESTful为例子)
1.模块设计
shop-common 公共模块——相当于工具类
shop-user 用户微服务——存储用户的信息
shop-product 商品微服务——存储商品的所有信息
shop-order 订单微服务——存储订单的所有信息
【注意】所有的对数据库的操作是结合JPA
2.实现目标
通过订单微服务来查询商品的信息,也就是通过订单的微服务调用商品的微服务
3.具体实现
3.1创建一个父工程test
父工程做的内容就是规定好这个项目所有的版本号这些,因此只需要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 http://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><groupId>org.example</groupId><artifactId>test</artifactId><version>1.0-SNAPSHOT</version><packaging>pom</packaging><modules><module>shop-common</module><module>shop-users</module><module>shop-product</module><module>shop-order</module></modules><properties><maven.compiler.source>1.8</maven.compiler.source><maven.compiler.target>1.8</maven.compiler.target><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding><spring-boot.version>2.7.3</spring-boot.version><spring-cloud.version>2021.0.7</spring-cloud.version><spring-cloud-alibaba.version>2.1.0.RELEASE</spring-cloud-alibaba.version><fastjson.version>1.2.57</fastjson.version></properties><dependencyManagement><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-dependencies</artifactId><version>${spring-boot.version}</version><type>pom</type><scope>import</scope></dependency><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-dependencies</artifactId><version>${spring-cloud.version}</version><type>pom</type><scope>import</scope></dependency><dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-alibaba-dependencies</artifactId><version>${spring-cloud-alibaba.version}</version><type>pom</type><scope>import</scope></dependency><dependency><groupId>com.alibaba</groupId><artifactId>fastjson</artifactId><version>${fastjson.version}</version></dependency></dependencies></dependencyManagement></project>
3.2在父工程中创建公共模块
公共模块就是相当于是一个工具类,里面有数据库信息的实体类
package pojo;import lombok.Data;import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;/*** 订单的实体类*/
@Entity(name = "shop_order")
@Data
public class Order {@Id@GeneratedValue(strategy = GenerationType.IDENTITY)/*** 订单id*/private int oid;/*** 用户id*/private Integer uid;/*** 物品id*/private Integer pid;/*** 物品名称*/private String pname;/*** 物品价格*/private Double pprice;/*** 用户姓名*/private String username;/*** 购买数量*/private Integer number;
}
package pojo;import lombok.Data;import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;/***** @author jkk* @since 2020-03-20-20:25*/
@Entity(name = "shop_product")
@Data
public class Product {/*** 主键*/@Id@GeneratedValue(strategy = GenerationType.IDENTITY)private Integer pid;/*** 商品名称*/private String pname;/*** 商品价格*/private double pprice;/*** 库存*/private Integer stock;}
3.3在父工程中创建用户模块
用户模块就是实现与用户的表相关的操作,对用户的业务就放到这个模块中,所以每一个模块中必须有一个启动类Application,当然需要配置它的yml文件
package org.example.users;import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;/*** @author jkk*/
@SpringBootApplication
@EnableDiscoveryClient
public class ShopUsersApplications {public static void main(String[] args) {SpringApplication.run(ShopUsersApplications.class, args);}
}
server:port: 8071
spring:application:name: service-productdatasource:url: jdbc:mysql://localhost:3306/shop?characterEncoding=UTF-8username: rootpassword:driver-class-name: com.mysql.cj.jdbc.Driverjpa:properties:hibernate:hbm2ddl:auto: updatedialect: org.hibernate.dialect.MySQL5InnoDBDialect
当前微服务并没有使用,所以没有写相关的具体业务
3.4在父工程中创建商品模块
同理将商品所需要的业务写在里面
controller
package org.example.product.controller;import com.alibaba.fastjson.JSON;
import org.example.product.service.ProductService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
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.RestController;
import pojo.Product;@RestController
public class ProductController {private static final Logger log = LoggerFactory.getLogger(ProductController.class);@Autowiredprivate ProductService productService;@GetMapping("/product/{pid}")public Product product(@PathVariable("pid") Integer pid) {Product product = productService.findByPid(pid);log.info("查询到商品:" + JSON.toJSONString(product));return product;}
}
dao
package org.example.product.dao;import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
import pojo.Product;@Repository
public interface ProductDao extends JpaRepository<Product,Integer> {}
service
package org.example.product.service;import pojo.Product;public interface ProductService {Product findByPid(Integer pid);
}
package org.example.product.service.impl;import org.example.product.dao.ProductDao;
import org.example.product.service.ProductService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import pojo.Product;import java.util.Optional;@Service
public class ProductServiceImpl implements ProductService {@Autowiredprivate ProductDao productDao;@Overridepublic Product findByPid(Integer pid) {Optional<Product> optional = productDao.findById(pid);if (optional.isPresent()) {return optional.get();}return null;}}
启动类
package org.example.product;import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.domain.EntityScan;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;@EnableJpaRepositories
@SpringBootApplication
@EntityScan(basePackages = "pojo")
public class ProductApplication {public static void main(String[] args) {SpringApplication.run(ProductApplication.class,args);}
}
配置文件
server:port: 8081spring:application:name: service-productdatasource:driver-class-name: com.mysql.cj.jdbc.Driverurl: jdbc:mysql://localhost:3306/shop?characterEncoding=UTF-8username: rootpassword:jpa:properties:hibernate:hbm2ddl:auto: updatedialect: org.hibernate.dialect.MySQL5InnoDBDialect
3.5在父工程中创建订单模块
controller
package org.example.controller;import com.alibaba.fastjson.JSON;
import org.example.service.OrderService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
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.RestController;
import org.springframework.web.client.RestTemplate;
import pojo.Order;
import pojo.Product;/*** 使用restTemplate对象调用shop-product的请求方法*/
@RestController
public class OrderController {private static final Logger log = LoggerFactory.getLogger(OrderController.class);@Autowiredprivate RestTemplate restTemplate;@Autowiredprivate OrderService orderService;@GetMapping("/order/prod/{pid}")public Order order(@PathVariable("pid") Integer pid){Product product = restTemplate.getForObject("http://localhost:8081/product/" + pid, Product.class);log.info(">>商品信息,查询结果:" + JSON.toJSONString(product));Order order = new Order();order.setOid(1);order.setUid(1);order.setPid(product.getPid());order.setPname(product.getPname());order.setPprice(product.getPprice());order.setNumber(1);orderService.save(order);return order;}}
dao
package org.example.dao;import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
import pojo.Order;
@Repository
public interface OrderDao extends JpaRepository<Order,Integer> {
}
service
package org.example.service;import pojo.Order;/*** 订单的service层接口*/
public interface OrderService {/*** 将订单存到数据库* @param order*/public void save(Order order);
}
package org.example.service.impl;import org.example.dao.OrderDao;
import org.example.service.OrderService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import pojo.Order;/*** service接口的实现*/
@Service
public class OrderServiceImpl implements OrderService {@Autowiredprivate OrderDao orderDao;/*** 存储订单* @param order*/@Overridepublic void save(Order order) {orderDao.save(order);}
}
启动类
package org.example;import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.domain.EntityScan;
import org.springframework.context.annotation.Bean;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
import org.springframework.web.client.RestTemplate;/*** shop-order的启动类* @author jkk*/
@SpringBootApplication
@EnableJpaRepositories
@EntityScan(basePackages = "pojo")
public class OrderApplication {public static void main(String[] args) {SpringApplication.run(OrderApplication.class,args);}@Beanpublic RestTemplate getRestTemplate() {return new RestTemplate();}
}
yml配置文件
server:port: 8091spring:application:name: service-productdatasource:driver-class-name: com.mysql.cj.jdbc.Driverurl: jdbc:mysql://localhost:3306/shop?characterEncoding=UTF-8username: rootpassword:jpa:properties:hibernate:hbm2ddl:auto: updatedialect: org.hibernate.dialect.MySQL5InnoDBDialect
4.运行
可以注意到,当前调用另一个微服务的时候是通过把服务提供者的网络地址 (ip,端口)等硬编码到了代码中