(4)服务消费者,面向前端或者用户的服务

本模块涉及到很多知识点:比如Swagger的应用,SpringCloud断路器的使用,服务API的检查、token的校验,feign消费者的使用。大致代码框架如下:

先看下简单的配置文件application.properties

spring.application.name=mallservice-app
server.port=4444
eureka.client.serviceUrl.defaultZone=http://server1:1111/eureka/,http://server2:1112/eureka/,http://server3:1113/eureka/
hystrix.command.default.execution.isolation.thread.timeoutInMilliseconds:5000
urifilter.properties

#urllist
url.filterList[0]=/acc/signup
url.filterList[1]=/acc/login
面向用户的Controller类:

package com.mallapp.api;

import com.common.constant.RestApiResult;
import com.common.constant.ReturnCode;
import com.google.gson.Gson;
import com.mallapp.Security.JWTUtils;
import com.mallapp.client.IAccountFeignClient;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import java.util.UUID;

@Api(value="用户服务",tags = "用户服务接口")
@RestController
@RequestMapping("/acc")
public class IAccountController {
@Autowired
IAccountFeignClient accountFeignClient;

@ApiOperation(value="用户注册")
@RequestMapping(value="signup",method = RequestMethod.POST)
public RestApiResult signUp(@RequestParam String phone, @RequestParam String password){
RestApiResult restApiResult = new Gson().fromJson(accountFeignClient.signUp(phone,password),RestApiResult.class);
System.out.println(restApiResult);
return restApiResult;
}
@ApiOperation(value="用户登录")
@RequestMapping(value="login",method = RequestMethod.POST)
public RestApiResult login(@RequestParam String phone ,@RequestParam String password){
RestApiResult restApiResult = new Gson().fromJson(accountFeignClient.login(phone,password),RestApiResult.class);
try{
System.out.println(restApiResult);
if (restApiResult.isSuccess()){
String accessToken = JWTUtils.createJWT(UUID.randomUUID().toString(),(String)restApiResult.getAddmessage(),2*60*60*1000);
restApiResult.setAddmessage(accessToken);
}
}catch (Exception ex){
ex.printStackTrace();
}
return restApiResult;
}
}
@Autowired
IAccountFeignClient accountFeignClient;
 这个是服务发现用的Feign的客户端,看一下它的实现:

package com.mallapp.client;

import com.mallapp.client.hystrix.AccountFeignClientHystrix;
import org.springframework.cloud.netflix.feign.FeignClient;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;

@FeignClient(name="ACCOUNT-SERVICE", fallback = AccountFeignClientHystrix.class)
public interface IAccountFeignClient {
@RequestMapping(value = "/acc/signup",method = RequestMethod.GET)
public String signUp(@RequestParam(value = "phone") String phone, @RequestParam(value = "password") String password);
@RequestMapping(value = "/acc/login",method = RequestMethod.POST)
public String login(@RequestParam(value = "phone") String phone, @RequestParam(value = "password") String password);
}
这个接口必须和服务提供端的controller类的接口完全一致,而且参数注解一定完全一致。

看下SpringCloud所说的断路器类的实现:(意义就是服务消费者端调用服务提供端的时候,调用超时或者服务器异常等,会直接通过此接口返回响应)

package com.mallapp.client.hystrix;

import com.common.constant.RestApiResult;
import com.common.constant.ReturnCode;
import com.google.gson.Gson;
import com.mallapp.client.IAccountFeignClient;
import org.springframework.stereotype.Component;

@Component
public class AccountFeignClientHystrix implements IAccountFeignClient {
@Override
public String signUp(String phone, String password) {
return new Gson().toJson(new RestApiResult(false, ReturnCode.SYSTEM_ERROR,"The server is busy now......"));
}

@Override
public String login(String phone, String password) {
return new Gson().toJson(new RestApiResult(false, ReturnCode.SYSTEM_ERROR,"The server is busy now......"));
}
}

看下所说的AOP中的前置通知、后置通知、环绕通知等实现类:

package com.mallapp.aop;

import com.common.constant.RestApiResult;
import com.common.constant.ReturnCode;
import com.mallapp.Security.JWTUtils;
import io.jsonwebtoken.ExpiredJwtException;
import io.jsonwebtoken.MalformedJwtException;
import io.jsonwebtoken.SignatureException;
import io.jsonwebtoken.UnsupportedJwtException;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.util.Iterator;
import java.util.Map;

@Aspect
@Component
public class ApiExecuteNoticeService {
private final static Logger LOG = LoggerFactory.getLogger(ApiExecuteNoticeService.class);
private final static String access_token = "accessToken";

/**
* 方法之前执行
* @param joinPoint
* @throws Exception
*/
@Before("execution(public * com.mallapp.api.*.*(..))")
public void doBeforeInService(JoinPoint joinPoint)throws Exception{
System.out.println("Before to check the API......");
}

/**
* 方法之后执行
* @param joinPoint
* @throws Exception
*/
@After("execution(public * com.mallapp.api.*.*(..))")
public void AfterInService(JoinPoint joinPoint)throws Exception{
System.out.println("After to check the API......");
}

/**
* 环绕通知
* @param joinPoint
* @return
* @throws Exception
*/
@Around("execution(public * com.mallapp.api.*.*(..))")
public RestApiResult doAroundInService(ProceedingJoinPoint joinPoint)throws Exception{
System.out.println("Around to check the API......");
RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
ServletRequestAttributes servletRequestAttributes = (ServletRequestAttributes)requestAttributes;
HttpServletRequest request = servletRequestAttributes.getRequest();
String requestPath = request.getRequestURI();
System.out.println("uri: " + requestPath);
/*需要过滤不进行检查的url地址*/
// if (requestPath.contains("acc")){
// try {
// return (RestApiResult)joinPoint.proceed();
// } catch (Throwable throwable) {
// throwable.printStackTrace();
// }
// System.out.println("url /acc does not to check.");
// return null;
// }
Map<String,String[]> inputMap = request.getParameterMap();
Iterator<String> keyIter = inputMap.keySet().iterator();
boolean result = false;
while(keyIter.hasNext()){
String currKey = keyIter.next();
String value = ((String[])inputMap.get(currKey))[0].toString();
if (!access_token.equals(currKey)){
continue;
}
try{
JWTUtils.parseJWT(value);
System.out.println("cuurKey="+currKey+",value="+value);
result = true;
}catch(ExpiredJwtException ex){
ex.printStackTrace();
}catch (UnsupportedJwtException ex){
ex.printStackTrace();
}catch (MalformedJwtException ex){
ex.printStackTrace();
}catch (SignatureException ex){
ex.printStackTrace();
}catch (IllegalArgumentException ex){
ex.printStackTrace();
}
}
if (!result){
return new RestApiResult(false,ReturnCode.INVALID_VALUE,"token校验失败.");
}
try {
return (RestApiResult) joinPoint.proceed();
} catch (Throwable throwable) {
throwable.printStackTrace();
}
return new RestApiResult(false,ReturnCode.SYSTEM_ERROR,"unkonwn exception");
}
}
 token校验所涉及到类:

package com.mallapp.Security;

import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;

import io.jsonwebtoken.*;
import org.apache.tomcat.util.codec.binary.Base64;

import java.util.Date;
import java.util.UUID;

public class JWTUtils {
private final static String SECRETKEY = "OVlpXYjNwaFJYUllVbXhXTkZaR1pEQlNiVkYzWTBac1YxWkZXbE";
/**
* 由字符串生成加密key
*/
public static SecretKey generateKsy(String keyStr){
byte[] encodeKey = Base64.decodeBase64(keyStr);
SecretKey secretKey = new SecretKeySpec(encodeKey,0,encodeKey.length,"AES");
return secretKey;
}
/**
* 创建JWT,加密过程
*/
public static String createJWT(String id,String subject,long ttlMillis)throws Exception{
SignatureAlgorithm signatureAlgorithm = SignatureAlgorithm.HS256;
long nowMillis = System.currentTimeMillis();
Date now = new Date(nowMillis);
SecretKey key = generateKsy(SECRETKEY);
JwtBuilder jwtBuilder = Jwts.builder().setIssuer("").setId(id).setIssuedAt(now).setSubject(subject)
.signWith(signatureAlgorithm,key);
if (ttlMillis >= 0){
long expireMillis = nowMillis + ttlMillis;
Date expireDate = new Date(expireMillis);
jwtBuilder.setExpiration(expireDate);
}
return jwtBuilder.compact();
}
/**
* 解析JWT,解密过程
*/
public static Claims parseJWT(String jwt) throws ExpiredJwtException,UnsupportedJwtException,MalformedJwtException,
SignatureException,IllegalArgumentException{
SecretKey key = generateKsy(SECRETKEY);
Claims claims = Jwts.parser().setSigningKey(key).parseClaimsJws(jwt).getBody();
return claims;
}

// public static void main(String[] args){
// try{
// String token = createJWT(UUID.randomUUID().toString(),"",20000);
// System.out.println(token);
// Claims claims = parseJWT(token);
// System.out.println(claims.getExpiration()+" : "+claims.getExpiration().getTime());
// }catch (Exception ex){
// ex.printStackTrace();
// }
// }
}
 
UriFilterConfig类是用来接受Spring配置的xml文件的:urlifilter.properties

package com.mallapp.config;

import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.PropertySource;
import org.springframework.stereotype.Component;

import java.util.ArrayList;
import java.util.List;
import java.util.Set;

/**
* Created by c00415904 on 2018/5/29.
*/
@Component
@ConfigurationProperties(prefix = "url")
@PropertySource(value = {"classpath:urifilter.properties"} ,ignoreResourceNotFound = true)
public class UriFilterConfig {
private List<String> filterList = new ArrayList<String>();
public List<String> getFilterList() {
return filterList;
}

public void setFilter(List<String> filterList) {
this.filterList = filterList;
}
}
Awagger2Config类用来生成在线API文档: http://127.0.0.1:4444/swagger-ui.html 4444为消费者提供的端口号
package com.mallapp.config;

import io.swagger.annotations.ApiOperation;
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.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.annotations.EnableSwagger2;

@Configuration
@EnableSwagger2
public class Awagger2Config {
@Bean
public Docket createRestApi(){
return new Docket(DocumentationType.SWAGGER_2).apiInfo(getApiInfo()).select()
.apis(RequestHandlerSelectors.basePackage("com.mallapp.api"))
.apis(RequestHandlerSelectors.withMethodAnnotation(ApiOperation.class))
.paths(PathSelectors.any())
.build();
}
private ApiInfo getApiInfo(){
return new ApiInfoBuilder().title("Mall App Swagger Apis").description("For mall-service 's app use")
.version("V1.0").build();
}
}

服务启动类:

FeignApplication

package com.mallapp;

import com.common.constant.SystemConstant;
import com.common.util.JedisUtil;
import com.mallapp.config.UriFilterConfig;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
import org.springframework.cloud.netflix.feign.EnableFeignClients;

import java.util.Date;

@SpringBootApplication
@EnableFeignClients
@EnableEurekaClient
@EnableDiscoveryClient
public class FeignApplication implements CommandLineRunner{
@Autowired
private UriFilterConfig uriFilterConfig;
public static void main(String[] args){
SpringApplication.run(FeignApplication.class,args);
}
@Override
public void run(String... strings) throws Exception {
System.out.println("Begin to init data......"+new Date());
System.out.println(uriFilterConfig.getFilterList());
for(String url : uriFilterConfig.getFilterList()){
JedisUtil.SETS.sadd(SystemConstant.URL_NEED_CHECK_KEY,url);
}
}
}

我们分别启动服务消费者和服务提供者,然后进行postman测试或者前端测试:

转载于:https://www.cnblogs.com/huangwentian/p/10469196.html

SpringCloud框架搭建+实际例子+讲解+系列五相关推荐

  1. springCloud框架搭建,添加feign和Zuul

    6.Feign远程调用工具 接着上一篇搭建springCloud框架,Feign作为springCloud框架中的一个组件,而不是一个服务.添加位置:服务消费方. 6.1 首先添加依赖:(pom工程, ...

  2. IDEA下Springcloud框架搭建(一)之服务注册与发现

    首先,创建一个 Maven 主工程,主工程的 pom.xml 添加如下内容: <parent><groupId>org.springframework.boot</gro ...

  3. spring cloud多模块项目框架搭建-集成lombok

    第五章: spring cloud多模块项目框架搭建-集成lombok 本系列博客旨在搭建一套能用于实际开发使用的spring cloud多模块微服务项目框架,并不是一个spring cloud的de ...

  4. android应用框架搭建之BaseActivity

    网上有很多介绍BaseActivity的博文,多数是从应用的角度去描述的. 这里,我所介绍的BaseActivity不同,主要从框架搭建的角度去介绍BaseActivity的使用. 先看代码: ? 1 ...

  5. 网站框架搭建——基于Django框架的天天生鲜电商网站项目系列博客(二)

    系列文章目录 需求分析--基于Django框架的天天生鲜电商网站项目系列博客(一) 网站框架搭建--基于Django框架的天天生鲜电商网站项目系列博客(二) 用户注册模块--基于Django框架的天天 ...

  6. class unity 定义类_Unity 游戏框架搭建 2019 (二十五) 类的第一个作用 与 Obselete 属性...

    在上一篇我们整理到了第七个示例,我们今天再接着往下整理.我们来看第八个示例: #if UNITY_EDITORusing UnityEditor; #endif using UnityEngine; ...

  7. ASP.NET MVC+EF框架+EasyUI实现权限管理系列(14)-主框架搭建

    ASP.NET MVC+EF框架+EasyUI实现权限管理系列(14)-主框架搭建 原文:ASP.NET MVC+EF框架+EasyUI实现权限管理系列(14)-主框架搭建    ASP.NET MV ...

  8. Unity 游戏框架搭建 (五) 简易消息机制

    什么是消息机制? 23333333,让我先笑一会. 为什么用消息机制? 三个字,解!!!!耦!!!!合!!!!. 我的框架中的消息机制用例: 1.接收者 using UnityEngine;names ...

  9. APP自动化测试框架搭建(五)--Python+Appium+pytest-html

    第一章 APP自动化环境搭建(Mac版) 第二章 APP自动化环境搭建(Windows版) 第三章 adb命令 第四章 元素定位.元素操作 第五章 APP自动化测试框架搭建 Python+Appium ...

最新文章

  1. 一次完整的HTTP请求所经历的7个步骤
  2. 使用Spring 3.1和基于Java的配置构建RESTful Web服务,第2部分
  3. 响应服务器535.5.7.0AUTH,javax.mail.AuthenticationFailedException:535 5.7.3无法发送邮件
  4. 求出数组中超过一半的数
  5. 以图搜图:Python实现dHash算法
  6. 现在大火的Web3是什么 web1 web2
  7. SpingMVC之拦截器
  8. qt double 相减不为0_Qt线程同步单生产者多消费者
  9. 张雨石:关于深度学习中的dropout的两种理解
  10. iOS 清理缓存方法
  11. python爬取百度街景图像
  12. 手把手教你写电商爬虫-第四课 淘宝网商品爬虫自动JS渲染 1
  13. 注册中心开源方案选型
  14. 英语常见缩写,职业,公司
  15. Character.UnicodeBlock中cjk的说明
  16. 扫雷游戏 (15 分)
  17. 关于win10输入法问题(打不出中文)解决方法
  18. 人脸识别face recognition
  19. Python多线程下调用win32com包相关问题:pywintypes.com_error: (-2147221008, ‘尚未调用 CoInitialize。‘, None, None)问题处理
  20. 2023年中职网络安全竞赛试题—竞赛样题

热门文章

  1. 数据结构与算法 - 递归回溯(迷宫问题)
  2. python如何引发和处理异常_在python3.6中,如何捕捉异常并引发异常以便稍后处理?...
  3. fmc是fpga直接引出来的吗_家长速看!你还在用“不要和陌生人说话”糊弄孩子的安全教育吗?...
  4. 【深度学习】 - MobileNet使用的可分离卷积
  5. 【Codeforces - 127D】Password(思维,二分+字符串Hash)
  6. 【CodeForces - 673D】Bear and Two Paths(构造,tricks)
  7. 【CodeForces - 518D】Ilya and Escalator(概率dp,数学期望)
  8. 【ZOJ - 2972】Hurdles of 110m (dp)
  9. 【CodeForces - 1060C】Maximum Subrectangle (思维,预处理前缀和,dp,枚举长度)
  10. python访问网页速度_python实现用于测试网站访问速率的方法