SpringCloud框架搭建+實際例子+講解+系列五

(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

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/449750.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/449750.shtml
英文地址,請注明出處:http://en.pswp.cn/news/449750.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

軟件開發者最重要的四大技能

摘要&#xff1a;現如今&#xff0c;可供選擇的技術、語言及平臺可謂五花八門&#xff0c;因此要弄明白哪里是花時間訓練的最佳投資點也就難上加難…… 現如今&#xff0c;可供選擇的技術、語言及平臺可謂五花八門&#xff0c;因此作為軟件開發者&#xff0c;要弄明白哪里是花時…

數據缺失的補充與修改

1查看數據情況 df.shape df.info() 2.用指定值填充 df df.fillna(x) 3.判斷是否缺失 df.isnull() 4.刪除缺失數據 df df.dropna() 5.補充平均值 df df.fillna(df.mean()) 6.填充他前面一個元素值(ffill向前填充&#xff0c;bfill向后填充)&#xff08;limit:可以…

其他-私人♂收藏(比賽記錄 Mar, 2019)

OwO 03.03 [USACO19JAN] A. Redistricting 題意&#xff1a;給 \(g\) &#xff0c;求 \(f(n)\) 。 \(f(i)f(j)[g(i)\ge g(j)],j \in (i-k,i]\) 。 離散化之后線段樹優化 DP &#xff1b;或者發現額外貢獻最多只有 \(1\) &#xff0c;單調隊列。 B. Exercise Route 題意&#xf…

JSR 303 - Bean Validation 簡介及使用方法

前些天發現了一個巨牛的人工智能學習網站&#xff0c;通俗易懂&#xff0c;風趣幽默&#xff0c;忍不住分享一下給大家。點擊跳轉到教程。 一、JSR-303簡介 JSR-303 是 JAVA EE 6 中的一項子規范&#xff0c;叫做 Bean Validation&#xff0c;官方參考實現是Hibernate Valida…

POJ 3683 Priest John's Busiest Day(2-ST)

題目鏈接&#xff1a;http://poj.org/problem?id3683 題意&#xff1a;有n個婚禮要舉行&#xff0c;但是只有一個牧師。第i個婚禮使用牧師的時間長為leni&#xff0c;可以在開始時或結束時使用。問能否使得n個婚禮均舉行&#xff1f; 思路:對于婚禮i&#xff0c;i*2-1表示在開…

12個git實戰建議和技巧

摘要&#xff1a;git無疑是現在最熱門的版本控制工具&#xff0c;而且正在進一步侵占SVN以及CVS的市場。本文作者從國外技術問答社區Stack Overflow整理的12個很實用的git使用技巧和建議&#xff0c;希望對你有幫助。 1.使用“git diff”來折疊多行 用git diff經常會出現很多內…

python讀寫json和txt

讀寫json #數據保存如json文件 import json jsObj json.dumps(code_sec) fileObject open(jsonFile.json, w) fileObject.write(jsObj) fileObject.close() #讀取json文件 # 將類文件對象中的JSON字符串直接轉換成 Python 字典 with open(jsonFile.json, r, encoding…

Java 12 將于3月19日發布,8 個最終 JEP 一覽

開發四年只會寫業務代碼&#xff0c;分布式高并發都不會還做程序員&#xff1f; JDK 12 已于2018年12月進入 Rampdown Phase One 階段&#xff0c;這意味著該版本所有新的功能特性被凍結&#xff0c;不會再加入更多的 JEP 。該階段將持續一個月&#xff0c;主要修復 P1-P3 級…

股票期貨數據的resample處理

? import pandas as pd stock_day pd.read_csv("stock_day.csv") stock_day stock_day.sort_index() # 對每日交易數據進行重采樣 &#xff08;頻率轉換&#xff09; stock_day.index# 1、必須將時間索引類型轉換成Pandas默認的類型 stock_day.index pd.to_datet…

ArcEngine調用FeatureToLine工具傳參問題

FeatureToLine工具的in_features參數不能為內存圖層&#xff0c;否則會報內存錯誤&#xff0c;正確的寫法如下&#xff1a; FeatureToLine ftrToLine new FeatureToLine(); ftrToLine.in_features cpj.TempWs.PathName "\OriginDataset\" currentFc.Key; ftrToLi…

程序員如何做出“不難看”的設計

摘要&#xff1a;程序員在寫代碼的時候往往只注重功能的實現和性能的提升&#xff0c;忽視了外觀和易用性&#xff0c;其實很多時候只要注意一些基本的規則&#xff0c;就可以大幅度提高產品的觀感。 經常看到程序員展示自己做的東西&#xff0c;有一些是創業項目&#xff0c;有…

微服務實戰(二):使用API Gateway

前些天發現了一個巨牛的人工智能學習網站&#xff0c;通俗易懂&#xff0c;風趣幽默&#xff0c;忍不住分享一下給大家。點擊跳轉到教程。 當你決定將應用作為一組微服務時&#xff0c;需要決定應用客戶端如何與微服務交互。在單體式程序中&#xff0c;通常只有一組冗余的或者…

sql數據庫挖坑

sql數據庫存入數據時&#xff0c;因為列 名不允許有括號&#xff0c;無法識別&#xff0c;需要對括號進行剔除 df df.rename(columnslambda x: x.replace("(","").replace(),))

力扣——頂端迭代器

給定一個迭代器類的接口&#xff0c;接口包含兩個方法&#xff1a; next() 和 hasNext()。設計并實現一個支持 peek() 操作的頂端迭代器 -- 其本質就是把原本應由 next() 方法返回的元素 peek() 出來。 示例: 假設迭代器被初始化為列表 [1,2,3]。調用 next() 返回 1&#xff0c…

五步讓你成為專家級程序員

摘要&#xff1a;Mark Lassoff是一位高級技術培訓師&#xff0c;從事培訓工作已有10余年。他培訓的客戶包括美國國防部、Lockheed Martin等。在多年的培訓生涯中&#xff0c;他總結了一些如何快速學習一門語言的技巧&#xff0c;這些技巧非常簡單&#xff0c;但是卻讓人受益匪淺…

Ionic混合移動app框架學習

第一章 緒論創建移動app有三種安卓原生App&#xff0c;使用java語言&#xff0c;目前推薦kotlin語言&#xff0c;開發工具Android studioIOS原生App&#xff0c;使用Objective-C或者Swift語言&#xff0c;開發工具Xcode混合移動App&#xff0c;使用web通用語言&#xff08;HTML…

IPC 中 LPC、RPC 的區別和聯系

前些天發現了一個巨牛的人工智能學習網站&#xff0c;通俗易懂&#xff0c;風趣幽默&#xff0c;忍不住分享一下給大家。點擊跳轉到教程。 進程間通信&#xff08;IPC&#xff0c;Inter-Process Communication&#xff09;&#xff0c;指至少兩個進程或線程間傳送數據或信號的…

Laravel 使用 Aliyun OSS 云存儲

對象存儲 ( Object Storage Service, 簡稱 OSS ) OSS 相信大家都聽過, 它是阿里云對外提供的海量, 安全和高可靠的云存儲服務. 大家可以把自己網站的資源存上面加快自己網站速度, aliyun 官網也有文檔不過對于新手來說有點難, 那么這里我給大家推薦一個組件和組件的使用. johnl…

python多級索引修改

創建多級索引 cols pd.MultiIndex.from_tuples([("a","b"), ("a","c")]) pd.DataFrame([[1,2], [3,4]], columnscols) abc012134 df.columns df.columns.droplevel() df bc012134

在線學習新編程 技巧全攻略

摘要&#xff1a;有句俗語叫&#xff1a;“技多不壓身”&#xff0c;如果你有時間和興趣&#xff0c;不妨多了解和掌握編程技能&#xff0c;或許隨時可能有用。本文為你收集了一些編程技巧&#xff0c;讓你輕松學編程。 有句俗語叫&#xff1a;“技多不壓身”&#xff0c;如果你…