微服务各组件整合
nacos
第一步,引入依赖
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
第二步,增加配置
spring:
application:
name: order
cloud:
nacos:
discovery:
server-addr: localhost:8848
调用(手写一个负载均衡)
@RequestMapping("/hello")
public String hello(){
List<ServiceInstance> instances = discoveryClient.getInstances("user-service");
ServiceInstance serviceInstance = instances.get(RandomUtil.randomInt(instances.size()));
URI uri = serviceInstance.getUri();
String url = uri + "/user-service/user/hello";
log.info("调用地址:" + url);
ResponseEntity<String> result = restTemplate.exchange(url, HttpMethod.GET, null,
new ParameterizedTypeReference<String>() {
},
String.class);
String msg = result.getBody();
log.info("接口返回:" + msg);
return msg;
}
openfeign
1、引入依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-loadbalancer</artifactId>
</dependency>
2、启动类上添加@EnableFeignClients
3、编写FeignClient
package com.niuniu.product.feignclient;
import com.niuniu.product.model.Order;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import java.util.List;
@FeignClient(value = "order-service")
public interface OrderClient {
@GetMapping(value = "/order-service/order/queryOrderByIds")
List<Order> queryOrderByIds(@RequestParam("ids") List<String> ids);
}
4、调用
package com.niuniu.product.controller;
import com.google.common.collect.Lists;
import com.niuniu.product.feignclient.OrderClient;
import com.niuniu.product.model.Order;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
@RestController
@RequestMapping(value = "/product")
public class ProductController {
@Autowired
private OrderClient orderClient;
/**
* 调用user-service
* @return
*/
@RequestMapping("/testFeign")
public List<Order> testFeign(){
List<Order> orders = orderClient.queryOrderByIds(Lists.newArrayList("1", "2"));
return orders;
}
}
openfeign连接池
1、引入依赖
<!-- openfeign连接池 -->
<dependency>
<groupId>io.github.openfeign</groupId>
<artifactId>feign-okhttp</artifactId>
</dependency>
2、application.yml中开启
#openfeign连接池
feign:
okhttp:
enabled: true
3、debug查看效果
openfeign日志
openfeign有自己的日志级别
网关
1、引入依赖
<!-- 负载均衡 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-loadbalancer</artifactId>
</dependency>
<!--用于被nacos发现该服务 被gateway发现-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<!-- 网关 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
2、application.yaml配置
spring:
application:
name: gateway-service
cloud:
nacos:
discovery:
server-addr: localhost:8848
gateway:
routes:
- id: order-service
uri: lb://order-service
predicates:
- Path=/order-service/**
- id: product-service
uri: lb://product-service
predicates:
- Path=/product-service/**
- id: user-service
uri: lb://user-service
predicates:
- Path=/user-service/**
server:
port: 8080
servlet:
context-path: /gateway-service
注意:
如果直接访问product微服务的地址是http://localhost:8086/product-service/product/testFeign,
- Path=/product-service/**。
如果 直接访问product微服务的地址是http://localhost:8086/product/testFeign,(省略掉了微服务名称)
- Path=/product/**。
实现登录校验
配置管理
jwt登录功能
1、引入依赖
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
<version>0.9.1</version>
</dependency>
2、Jwt工具类
package com.niuniu.gateway.util;
import io.jsonwebtoken.Jwt;
import io.jsonwebtoken.JwtBuilder;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
public class JWTUtil {
/**
* 密钥
*/
private static final String jwtToken = "niuniu";
public static String createToken(Long userId) {
Map<String, Object> claims = new HashMap<>();
claims.put("userId", userId);
JwtBuilder jwtBuilder = Jwts.builder()
.signWith(SignatureAlgorithm.HS256, jwtToken) // 签发算法,密钥为jwtToken
.setClaims(claims) // body数据,要唯一,自行设置
.setIssuedAt(new Date()) // 设置签发时间
.setExpiration(new Date(System.currentTimeMillis() + 24 * 60 * 60 * 60 * 1000)); // 一天的有效时间
String token = jwtBuilder.compact();
return token;
}
public static Map<String, Object> checkToken(String token) {
try {
Jwt parse = Jwts.parser().setSigningKey(jwtToken).parse(token);
return (Map<String, Object>) parse.getBody();
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
/**
* main方法验证一下工具类
* @param args
*/
public static void main(String[] args) {
String token = JWTUtil.createToken(1000L);
System.out.println("生成的token" + token);
System.out.println("解析token" + JWTUtil.checkToken(token));
}
}
3、登录,成功,返回token
@GetMapping("/login")
public ResponseEntity login(@RequestParam(name = "name") String name, @RequestParam(name = "password") String password){
// 1、参数是否合法
if (StringUtil.isEmpty(name) || StringUtil.isEmpty(password)) {
return ResponseEntity.ok("用户名或密码不能为空");
}
// 2、用户是否存在
User user = userMapper.login(name, password);
// 3、用户不存在,登录失败
if (user == null) {
return ResponseEntity.ok("用户不存在");
}
// 4、用户存在,使用jwt生成token返给前端
String token = JWTUtil.createToken(user.getId());
// 5、将token放入redis
redisTemplate.opsForValue().set("token_" + user.getId(), token);
return ResponseEntity.ok(token);
}
jwt登录
1、用户登录,根据用户id生成token并返回给前端;
2、登录后的所有请求,都将token传递给后端;
3、后端拿到token,判断是否登录(把token转成用户id),登录是否失效(使用redis缓存)。
将登录的用户信息传递到微服务
1、登录生成token;
2、在gateway微服务里写一个过滤器,校验token。
校验通过,保存用户信息到请求头(将token转成用户id);
校验不通过,终止请求。
3、写拦截器从请求头中取出用户信息保存到ThreadLocal。(拦截器放到common模块,供所有需要的微服务引用)
4、在业务处理过程中就可以从ThreadLocal中取到用户信息。