微服务的实现
实体类:
在shop_service_common中创建 com.yyj.entity.Product实体类,并配置
package com.yyj.entity; import lombok.Data; import javax.persistence.Entity; import javax.persistence.Id; import javax.persistence.Table; import java.math.BigDecimal; @Entity @Table(name="tb_product") @Data public class Product { @Id private Long id; private String productName; private Integer status; private BigDecimal price; private String productDesc; private String caption; private Integer inventory; }
这里使用了lombok简化实体类的开发,Lombok能以简单的注解形式来简化java代码,提高开发人员的开发效率
dao层接口:
在shop_service_product中创建 com.yyj.product.dao.ProductDao 接口
package com.yyj.product.dao; import com.yyj.entity.Product; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.JpaSpecificationExecutor; public interface ProductDao extends JpaRepository<Product,Long>, JpaSpecificationExecutor<Product> { }
service层:
在shop_service_product中创建 com.yyj.product.service.ProductService
package com.yyj.product.service;
import com.yyj.entity.Product;
import java.util.List;
public interface ProductService {
//根据id查询
Product findById(Long id);
//查询全部
List findAll();
//保存
void save(Product product);
//更新
void update(Product product);
//删除
void delete(Long id);
}
在shop_service_product中创建 com.yyj.product.service.impl.ProductServiceImpl 实现类
package com.yyj.product.service.impl;
import com.yyj.entity.Product;
import com.yyj.product.dao.ProductDao;
import com.yyj.product.service.ProductService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
@Service
public class ProductServiceImpl implements ProductService {
@Autowired
private ProductDao productDao;
@Override
public Product findById(Long id) {
return productDao.findById(id).get();
}
@Override
public List findAll() {
return productDao.findAll();
}
@Override
public void save(Product product) {
productDao.save(product);
}
@Override
public void update(Product product) {
productDao.save(product);
}
@Override
public void delete(Long id) {
productDao.deleteById(id);
}
}
controller层:
在shop_service_product中创建 com.yyj.product.controller.ProductController
package com.yyj.product.controller;
import com.yyj.entity.Product;
import com.yyj.product.service.ProductService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.List;
@RestController
@RequestMapping("/product")
public class ProductController {
@Autowired
private ProductService productService;
@GetMapping
public List findAll() {
return productService.findAll();
}
@GetMapping("/{id}")
public Product findById(@PathVariable Long id) {
return productService.findById(id);
}
@PostMapping
public String save(@RequestBody Product product) {
productService.save(product);
return "保存成功";
}
@PutMapping("/{id}")
public String update(@RequestBody Product product) {
productService.update(product);
return "修改成功";
}
@DeleteMapping("/{id}")
public String delete(Long id) {
productService.delete(id);
return "删除成功";
}
}
controller中使用的@GetMapping是一个组合注解,相当与@RequestMapping(method="get")。
类似的注解还有@PostMapping,@PutMapping,@DeleteMapping
配置启动类
在shop_service_product中创建 com.yyj.product.ProductApplication 启动类
package com.yyj.product;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.domain.EntityScan;
@SpringBootApplication(scanBasePackages = {"com.yyj.product"})
@EntityScan("com.yyj.entity")
public class ProductApplication {
public static void main(String[] args) {
SpringApplication.run(ProductApplication.class,args);
}
}
配置application.yml文件
server: port: 9002 spring: application: name: shop-service-product datasource: driver-class-name: com.mysql.cj.jdbc.Driver url: jdbc:mysql://localhost:3306/shop?useUnicode=true&characterEncoding=utf8&serverTimezone=UTC username: root password: 123 jpa: database: MySQL show-sql: true open-in-view: true
用户和订单微服务与上述微服务类似,根据商品微服务进行编写
服务调用
前文已经编写了三个基础的微服务,在用户下单时需要调用商品微服务获取商品数据。那应该怎么做呢?显然,商品微服务提供了供人调用的HTTP接口。所以可以再下定单的时候使用http请求的相关工具类完成,如常见的HttpClient,OkHttp,当然也可以使用Spring提供的RestTemplate
RestTemplate介绍
Spring框架提供的RestTemplate类可用于在应用中调用rest服务,它简化了与http服务的通信方式,统一了RESTful的标准,封装了http链接, 我们只需要传入url及返回值类型即可。相较于之前常用的HttpClient,RestTemplate是一种更优雅的调用RESTful服务的方式。
在Spring应用程序中访问第三方REST服务与使用Spring RestTemplate类有关。RestTemplate类的设计原则与许多其他Spring 模板类(例如JdbcTemplate、JmsTemplate)相同,为执行复杂任务提供了一种具有默认行为的简化方法。
RestTemplate默认依赖JDK提供http连接的能力(HttpURLConnection),如果有需要的话也可以通过setRequestFactory方法替换为例如 Apache HttpComponents、Netty或OkHttp等其它HTTP library。考虑到RestTemplate类是为调用REST服务而设计的,因此它的主要方法与REST的基础紧密相连就不足为奇了,后者是HTTP协议的方法:HEAD、GET、POST、PUT、DELETE和OPTIONS。例如,RestTemplate类具有headForHeaders()、getForObject()、postForObject()、put()和delete()等方法。
RestTemplate方法介绍
通过RestTemplate调用微服务
(1) 在 shop_service_order工程中ProductApplication启动类 中配置RestTemplate
//配置RestTemplate交给spring管理 @Bean public RestTemplate getRestTemplate() { return new RestTemplate(); }
(2) 编写下订单方法
@PostMapping("/{id}") public String order(Integer num) { //通过restTemplate调用商品微服务 Product object = restTemplate.getForObject("http://127.0.0.1:9002/product/1", Product.class); System.out.println(object); return "操作成功"; }
硬编码存在的问题
至此已经可以通过RestTemplate调用商品微服务的RESTFul API接口。但是我们把提供者的网络地址(ip,端口)等硬编码到了代码中,这种做法存在许多问题:
应用场景有局限
无法动态调整
那么应该怎么解决呢,就需要通过注册中心动态的对服务注册和服务发现