日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

搭建一个完整的微服务项目

發布時間:2025/3/12 编程问答 18 豆豆
生活随笔 收集整理的這篇文章主要介紹了 搭建一个完整的微服务项目 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

一.項目技術架構

1.技術棧

前臺技術
Node.js、Npm、Vue.js、WebPack、Vue Cli、Element UI
后臺架構
微服務架構:按照功能拆分N多個服務,每個服務可以獨立技術選型,獨立開發,獨立部署,獨立運維.,單個服務使用基于ssm的springboot,服務間通過spring cloud協調。

2.后端項目微服務原型搭建

2.1 項目基本模塊搭建

hrm-parent hrm-basic-parent //項目基本模塊hrm-basic-utils //公共工具模塊hrm-basic-common //公共代碼模塊hrm-support-parent //springcloud微服務支持模塊hrm-eureka-server-1010 hrm-gateway-zuul-1020hrm-config-server-1030hrm-system-parent hrm-systemmanage-common //針對系統管理服務公共代碼如:domain,queryhrm-systemmanage-service-2010 //針對于系統管理的微服務

2.1.1 hrm-parent的搭建

Maven結構 先在頂層父模塊進行設置管理依賴包和版本號以及一些公共的jar包。 <parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.0.5.RELEASE</version> </parent><properties><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding><project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding><java.version>1.8</java.version><spring-cloud.version>Finchley.SR1</spring-cloud.version> </properties><!--所有子模塊一定要用到的公共的jar包--> <dependencies><dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>4.12</version></dependency> </dependencies><dependencyManagement><dependencies><dependency><!--springcloud版本管理,springcloud相關模塊引入是就不需要制定版本了--><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-dependencies</artifactId><version>${spring-cloud.version}</version><type>pom</type><scope>import</scope></dependency></dependencies> </dependencyManagement> SpringCloud組件之五大神獸: 服務注冊發現——Netflix Eureka : 幫我們服務的通信地址的 客服端負載均衡——Netflix Ribbon\Feign : 解決網絡通信的 斷路器——Netflix Hystrix :解決微服務故障的 服務網關——Netflix Zuul :微服務的大門(安保部門) 分布式配置——Spring Cloud Config :統一管理微服務的配置

2.1.2.Eureka注冊中心

Eureka是netflix的一個子模塊,也是核心模塊之一,Eureka是一個基于REST的服務,用于定位服務,以實現云端中間層服務發現和故障轉移。服務注冊與發現對于微服務架構來說是非常重要的,有了服務發現和注冊,只需要使用服務的標識符,就可以訪問到服務,而不需要修改服務,而不需要修改服務調用的配置文件了,功能類似于dubbo的注冊中心,比如zookeeper。

2.1.2.1創建項目

在hrm-parent里面的hrm-support-parent進行模塊化搭建注冊中心

在注冊中心的pom.xml導包

<!--Eureka服務端支持--><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-netflix-eureka-server</artifactId></dependency>

配置yml

server:port: 1010 eureka: #Eureka的配置instance:hostname: localhost #主機client: #對Eureka客戶端配置registerWithEureka: false #注冊中心自己 , 不準向注冊中心自己注冊fetchRegistry: false #注冊中心不需要 獲取服務的通信地址清單serviceUrl: #注冊中心 服務的注冊地址#defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/defaultZone: http://localhost:1010/eureka/

在配置類上寫上相應注解之后main啟動

@SpringBootApplication @EnableEurekaClient public class EurekaServerApplication1010 {public static void main(String[] args) {SpringApplication.run(EurekaServerApplication1010.class);} }

2.1.3.config-server

創建網關項目
導包

<dependencies><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-netflix-eureka-client</artifactId></dependency><!-- 集成Web的jar包--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-config-server</artifactId></dependency></dependencies>

配置yml文件

eureka:client:serviceUrl:defaultZone: http://localhost:1010/eureka/ #注冊中心服務端的注冊地址instance:prefer-ip-address: true #使用ip進行注冊instance-id: config-server:1030 #服務注冊到注冊中心的id server:port: 1030 #應用的名字 spring:application:name: config-server#碼云配置cloud:config:server:git:uri: https://gitee.com/lxx/xx.git #你的倉庫地址(gtihub、gtilab、碼云)username: xx@qq.com #你的倉庫的賬戶password: xxx #你賬戶的密碼search-paths: hrm-parent/configfiles #從git 倉庫的哪個目錄找配置文件

配置類打上注解

@SpringBootApplication @EnableConfigServer public class ConfigServerApplication1030 {public static void main(String[] args) {SpringApplication.run(ConfigServerApplication1030.class);} }

啟動之后測試
http://localhost:1030/application-zuul-dev.yml 能讀取配置文件,配置中心就ok了

2.1.4.Zuul GateWay

創建項目
導包

<dependencies><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-netflix-eureka-client</artifactId></dependency><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-netflix-zuul</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-config</artifactId></dependency></dependencies>

配置application-zuul-dev.yml文件,上傳你的倉庫。

server:port: 1020 #應用的名字 spring:application:name: zuul-gateway zuul:ignored-services: "*" #禁止使用服務名字進行訪問prefix: "/hrm" #統一的前綴routes: #配置路由,指定服務的訪問路徑pay-server: "/pay/**"course-server: "/course/**"system-server: "/system/**"redis-server: "/redis/**" ribbon:ConnectTimeout: 250 # 連接超時時間(ms)ReadTimeout: 2000 # 通信超時時間(ms)OkToRetryOnAllOperations: true # 是否對所有操作重試MaxAutoRetriesNextServer: 2 # 同一服務不同實例的重試次數MaxAutoRetries: 1 # 同一實例的重試次數 hystrix:command:default:execution:isolation:thread:timeoutInMillisecond: 3000 # 熔斷超時時長:3000ms

配置bootstrap.yml文件

spring:cloud:config:uri: http://localhost:1030name: application-zuulprofile: dev #環境 組成完整的文件名

在配置類配置

@SpringBootApplication @EnableZuulProxy public class ZuulServerApplication1020 {public static void main(String[] args) {SpringApplication.run(ZuulServerApplication1020.class);} }

啟動之后能從你的倉庫拿到你配置文件啟動就ok了(如果報錯,例如端口8080或者其他都是沒有從你倉庫拿到你的配置文件)。

2.1.5 system-2010(步驟同上,差不多)

創建項目
導包

<dependencies><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-netflix-eureka-client</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-config</artifactId></dependency></dependencies>

在application-system-dev.yml配置之后上傳你的倉庫

eureka:client:serviceUrl:defaultZone: http://localhost:1010/eureka/ #注冊中心服務端的注冊地址instance:prefer-ip-address: true #使用ip進行注冊instance-id: system-server:2010 #服務注冊到注冊中心的id server:port: 2010 #應用的名字 spring:application:name: system-server

配置bootstrap.yml文件

spring:cloud:config:uri: http://localhost:1030name: application-systemprofile: dev #環境 組成完整的文件名

在配置類打上注解并啟動,啟動成功就OK

@SpringBootApplication public class SystemServerApplication2010 {public static void main(String[] args) {SpringApplication.run(SystemServerApplication2010.class);} }

在hrm-basic-parent里面創建hrm-code-generate(代碼生成)
創建項目
導包

<dependencies><dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-boot-starter</artifactId></dependency><!--模板引擎--><dependency><groupId>org.apache.velocity</groupId><artifactId>velocity-engine-core</artifactId><version>2.0</version></dependency><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId></dependency></dependencies>

創建代碼生成的類

package com.tys.hrm;import com.baomidou.mybatisplus.generator.AutoGenerator; import com.baomidou.mybatisplus.generator.InjectionConfig; import com.baomidou.mybatisplus.generator.config.*; import com.baomidou.mybatisplus.generator.config.converts.MySqlTypeConvert; import com.baomidou.mybatisplus.generator.config.po.TableInfo; import com.baomidou.mybatisplus.generator.config.rules.DbType; import com.baomidou.mybatisplus.generator.config.rules.NamingStrategy;import java.util.*;//代碼生成的主類 public class GenteratorCode {//運行main方法就可以生成代碼了public static void main(String[] args) throws InterruptedException {//用來獲取Mybatis-Plus.properties文件的配置信息//不要加后綴ResourceBundle rb = ResourceBundle.getBundle("mybatiesplus-config-course");AutoGenerator mpg = new AutoGenerator();// 全局配置GlobalConfig gc = new GlobalConfig();gc.setOutputDir(rb.getString("OutputDir"));gc.setFileOverride(true);gc.setActiveRecord(true);// 開啟 activeRecord 模式gc.setEnableCache(false);// XML 二級緩存gc.setBaseResultMap(true);// XML ResultMapgc.setBaseColumnList(false);// XML columListgc.setAuthor(rb.getString("author"));mpg.setGlobalConfig(gc);// 數據源配置DataSourceConfig dsc = new DataSourceConfig();dsc.setDbType(DbType.MYSQL);dsc.setTypeConvert(new MySqlTypeConvert());dsc.setDriverName("com.mysql.jdbc.Driver");dsc.setUsername(rb.getString("jdbc.user"));dsc.setPassword(rb.getString("jdbc.pwd"));dsc.setUrl(rb.getString("jdbc.url"));mpg.setDataSource(dsc);// 策略配置StrategyConfig strategy = new StrategyConfig();strategy.setTablePrefix(new String[] { "t_" });// 此處可以修改為您的表前綴strategy.setNaming(NamingStrategy.underline_to_camel);// 表名生成策略strategy.setInclude(new String[]{"t_course_type"}); // 需要生成的表 :mpg.setStrategy(strategy);// 包配置PackageConfig pc = new PackageConfig();pc.setParent(rb.getString("parent")); //基本包 cn.itsource.systempc.setController("web.controller");pc.setService("service");pc.setServiceImpl("service.impl");pc.setEntity("domain");pc.setMapper("mapper");mpg.setPackageInfo(pc);// 注入自定義配置,可以在 VM 中使用 cfg.abc 【可無】InjectionConfig cfg = new InjectionConfig() {@Overridepublic void initMap() {Map<String, Object> map = new HashMap<String, Object>();map.put("abc", this.getConfig().getGlobalConfig().getAuthor() + "-rb");this.setMap(map);}};List<FileOutConfig> focList = new ArrayList<FileOutConfig>();// 調整 controller 生成目錄演示focList.add(new FileOutConfig("/templates/controller.java.vm") {@Overridepublic String outputFile(TableInfo tableInfo) {//controller輸出完整路徑return rb.getString("OutputDir")+ "/com/tys/hrm/course/web/controller/" + tableInfo.getEntityName() + "Controller.java";}});// 調整 query 生成目錄演示focList.add(new FileOutConfig("/templates/query.java.vm") {@Overridepublic String outputFile(TableInfo tableInfo) {//query輸出完整路徑return rb.getString("OutputDirBase")+ "/com/tys/hrm/course/query/" + tableInfo.getEntityName() + "Query.java";}});// 調整 domain 生成目錄演示 , 你的domain到底要輸出到哪兒????,你的domain怎么輸出focList.add(new FileOutConfig("/templates/entity.java.vm") {@Overridepublic String outputFile(TableInfo tableInfo) {//domain輸出完整路徑return rb.getString("OutputDirBase")+ "/com/tys/hrm/course/domain/" + tableInfo.getEntityName() + ".java";}});// 調整 xml 生成目錄演示focList.add(new FileOutConfig("/templates/mapper.xml.vm") {@Overridepublic String outputFile(TableInfo tableInfo) {return rb.getString("OutputDirXml")+ "/com/tys/course/mapper/" + tableInfo.getEntityName() + "Mapper.xml";}});cfg.setFileOutConfigList(focList);mpg.setCfg(cfg);// 自定義模板配置,可以 copy 源碼 mybatis-plus/src/main/resources/templates 下面內容修改,// 放置自己項目的 src/main/resources/templates 目錄下, 默認名稱一下可以不配置,也可以自定義模板名稱TemplateConfig tc = new TemplateConfig();tc.setService("/templates/service.java.vm");tc.setServiceImpl("/templates/serviceImpl.java.vm");tc.setEntity(null);tc.setMapper("/templates/mapper.java.vm");tc.setController(null);tc.setXml(null);// 如上任何一個模塊如果設置 空 OR Null 將不生成該模塊。mpg.setTemplate(tc);// 執行生成mpg.execute();} }

創建mybatiesplus-config-course.properties文件

#此處為本項目src所在路徑(代碼生成器輸出路徑),注意一定是當前項目所在的目錄喲 #mapper,servier,controller輸出目錄 OutputDir=E:/IdeaProjects/hrm/hrm-parent/hrm-course-parent/hrm-course-service-2020/src/main/java#mapper.xml SQL映射文件目錄 OutputDirXml=E:/IdeaProjects/hrm/hrm-parent/hrm-course-parent/hrm-course-service-2020/src/main/resources#domain,query輸出的目錄 OutputDirBase=E:/IdeaProjects/hrm/hrm-parent/hrm-course-parent/hrm-course-common/src/main/java #設置作者 author=tys #自定義包路徑 parent=com.tys.hrm.course #數據庫連接信息 jdbc.driver=com.mysql.jdbc.Driver jdbc.url=jdbc:mysql:///hrm-course jdbc.user=root jdbc.pwd=123456

然后去system模塊添加依賴包
在hrm-system-common導包

<dependencies><dependency><groupId>com.tys</groupId><artifactId>hrm-basic-common</artifactId></dependency><dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-boot-starter</artifactId><version>2.2.0</version></dependency></dependencies>

因為生成的mapper、service、controller需連接數據庫,所以hrm-system-service-2010也要導包

<dependency><groupId>com.tys</groupId><artifactId>hrm-system-common</artifactId></dependency><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId></dependency><dependency><groupId>com.alibaba</groupId><artifactId>druid</artifactId><version>1.1.11</version></dependency><dependency><groupId>com.tys</groupId><artifactId>hrm-basic-utils</artifactId></dependency>

讓后直接點代碼生成類的main方法自動生成代碼,這樣,domain、query、mapper、service、controller都創建完成了

2.1.6 course-server(步驟同system,差不多)

創建完成之后,用代碼生成器生成course的所有。

2.2.接口文檔Swagger

在創建的所有代碼生成的服務(system、course)導包 和網關zuul服務也到入swagger包

<!--引入swagger支持--><dependency><groupId>io.springfox</groupId><artifactId>springfox-swagger2</artifactId><version>2.9.2</version></dependency><!-- https://mvnrepository.com/artifact/io.springfox/springfox-swagger-ui --><dependency><groupId>io.springfox</groupId><artifactId>springfox-swagger-ui</artifactId><version>2.9.2</version></dependency>

在這些包里面創建swagger的類創建接口文檔

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.service.Contact; import springfox.documentation.spi.DocumentationType; import springfox.documentation.spring.web.plugins.Docket; import springfox.documentation.swagger2.annotations.EnableSwagger2;@Configuration @EnableSwagger2 public class Swagger2 {@Beanpublic Docket createRestApi() {return new Docket(DocumentationType.SWAGGER_2).apiInfo(apiInfo()).select()//對外暴露服務的包,以controller的方式暴露,所以就是controller的包..apis(RequestHandlerSelectors.basePackage("com.tys.hrm.course.web.controller")).paths(PathSelectors.any()).build();}private ApiInfo apiInfo() {return new ApiInfoBuilder().title("平臺服務api").description("平臺服務接口文檔說明").contact(new Contact("yhptest", "", "yhp@itsource.cn")).version("1.0").build();} }

然后重新啟動,訪問http://localhost:2020/swagger-ui.html、http://localhost:2010/swagger-ui.html
在zuul創建一個配置config包,創建swagger類

package com.tys.hrm.config;import org.springframework.context.annotation.Primary; import org.springframework.stereotype.Component; import springfox.documentation.swagger.web.SwaggerResource; import springfox.documentation.swagger.web.SwaggerResourcesProvider;import java.util.ArrayList; import java.util.List;@Component @Primary public class DocumentationConfig implements SwaggerResourcesProvider {@Overridepublic List<SwaggerResource> get() {List resources = new ArrayList<>();resources.add(swaggerResource("系統管理", "/hrm/system/v2/api-docs", "2.0"));resources.add(swaggerResource("課程管理", "/hrm/course/v2/api-docs", "2.0"));return resources;}private SwaggerResource swaggerResource(String name, String location, String version) {SwaggerResource swaggerResource = new SwaggerResource();swaggerResource.setName(name);swaggerResource.setLocation(location);swaggerResource.setSwaggerVersion(version);return swaggerResource;} } package com.tys.hrm.config;import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import springfox.documentation.builders.ApiInfoBuilder; import springfox.documentation.service.ApiInfo; import springfox.documentation.service.Contact; import springfox.documentation.spi.DocumentationType; import springfox.documentation.spring.web.plugins.Docket; import springfox.documentation.swagger2.annotations.EnableSwagger2;@Configuration @EnableSwagger2 public class SwaggerConfig {@Beanpublic Docket createRestApi() {return new Docket(DocumentationType.SWAGGER_2).apiInfo(apiInfo());}private ApiInfo apiInfo() {return new ApiInfoBuilder().title("資源管理系統").description("資源管理系統接口文檔說明").termsOfServiceUrl("http://localhost:1020").contact(new Contact("yphtest", "", "yhp@itsoruce.cn")).version("1.0").build();} }

然后重啟zuul服務,訪問http://localhost:1020/swagger-ui.html

2.3.elementui+vue

前端啟動 npm run dev
因為前后端分離,訪問后臺會出現跨域問題,跨越配置-在zuul進行配置(所有前端統一入口)。

import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.web.cors.CorsConfiguration; import org.springframework.web.cors.UrlBasedCorsConfigurationSource; import org.springframework.web.filter.CorsFilter;@Configuration public class GlobalCorsConfig {@Beanpublic CorsFilter corsFilter() {//1.添加CORS配置信息CorsConfiguration config = new CorsConfiguration();//1) 允許的域,不要寫*,否則cookie就無法使用了config.addAllowedOrigin("http://127.0.0.1:6001"); config.addAllowedOrigin("http://localhost:6001");//2) 是否發送Cookie信息config.setAllowCredentials(true);//3) 允許的請求方式config.addAllowedMethod("OPTIONS");config.addAllowedMethod("HEAD");config.addAllowedMethod("GET");config.addAllowedMethod("PUT");config.addAllowedMethod("POST");config.addAllowedMethod("DELETE");config.addAllowedMethod("PATCH");// 4)允許的頭信息config.addAllowedHeader("*");//2.添加映射路徑,我們攔截一切請求UrlBasedCorsConfigurationSource configSource = newUrlBasedCorsConfigurationSource();configSource.registerCorsConfiguration("/**", config);//3.返回新的CorsFilter.return new CorsFilter(configSource);} }

配置之后重啟zuul服務。刷新前端就能訪問了。

2.4.redis+feign

2.4.1.搭建項目結構

hrm-redis-parenthrm-redis-clienthrm-redis-service-2030
2.4.1.1 redis

搭建 hrm-redis-service-2030 導入依賴

<dependencies><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-netflix-eureka-client</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-config</artifactId></dependency><dependency><groupId>redis.clients</groupId><artifactId>jedis</artifactId></dependency><dependency><groupId>com.tys</groupId><artifactId>hrm-basic-utils</artifactId></dependency></dependencies>

準備Redis工具類

配置文件 redis.properties redis.host=127.0.0.1 redis.port=6379 redis.password=123456 redis.timeout=5000

RedisUtil

import redis.clients.jedis.Jedis; import redis.clients.jedis.JedisPool; import redis.clients.jedis.JedisPoolConfig;import java.io.IOException; import java.util.Properties;/*** 獲取連接池對象*/ public enum RedisUtils {INSTANCE;static JedisPool jedisPool = null;static {//1 創建連接池配置對象JedisPoolConfig config = new JedisPoolConfig();//2 進行配置-四個配置config.setMaxIdle(1);//最小連接數config.setMaxTotal(11);//最大連接數config.setMaxWaitMillis(10 * 1000L);//最長等待時間config.setTestOnBorrow(true);//測試連接時是否暢通//3 通過配置對象創建連接池對象Properties properties = null;try {properties = new Properties(); properties.load(RedisUtils.class.getClassLoader().getResourceAsStream("redis.properties"));} catch (IOException e) {e.printStackTrace();}String host = properties.getProperty("redis.host");String port = properties.getProperty("redis.port");String password = properties.getProperty("redis.password");String timeout = properties.getProperty("redis.timeout");jedisPool = new JedisPool(config, host, Integer.valueOf(port),Integer.valueOf(timeout), password);}//獲取連接public Jedis getSource() {return jedisPool.getResource();}//關閉資源public void closeSource(Jedis jedis) {if (jedis != null) {jedis.close();}}/*** 設置字符值** @param key* @param value*/public void set(String key, String value) {Jedis jedis = getSource();jedis.set(key, value);closeSource(jedis);}/*** 設置* @param key* @param value*/public void set(byte[] key, byte[] value) {Jedis jedis = getSource();jedis.set(key, value);closeSource(jedis);}/**** @param key* @return*/public byte[] get(byte[] key) {Jedis jedis = getSource();try {return jedis.get(key);} catch (Exception e) {e.printStackTrace();} finally {closeSource(jedis);}return null;}/*** 設置字符值** @param key*/public String get(String key) {Jedis jedis = getSource();try {return jedis.get(key);} catch (Exception e) {e.printStackTrace();} finally {closeSource(jedis);}return null;} }

編寫RedisController

/*** redis的接口*/ @RestController @RequestMapping("/redis") public class RedisController {@GetMapping("/get/{key}")public AjaxResult get(@PathVariable("key")String key){String result = RedisUtils.INSTANCE.get(key);return AjaxResult.me().setResultObj(result);}@PostMapping("/set")public AjaxResult set(@RequestParam("key")String key,@RequestParam("value")String value){RedisUtils.INSTANCE.set(key,value);return AjaxResult.me();}@PostMapping("/setex")public AjaxResult setex(@RequestParam("key")String key,@RequestParam("value")String value,@RequestParam("seconds")int seconds){RedisUtils.INSTANCE.setex(key,value,seconds);return AjaxResult.me();} }

配置application-redis-dev.yml,配置成功上傳倉庫

eureka:client:serviceUrl:defaultZone: http://localhost:1010/eureka/ #注冊中心地址 instance:prefer-ip-address: true #使用ip地址注冊instance-id: redis-service #指定服務的id server:port: 2030 spring:application:name: redis-service

再配合bootstrap.yml

spring:cloud:config:uri: http://localhost:1030name: application-redisprofile: dev #環境 組成完整的文件名
2.4.1.2 feign

hrm-redis-feign導包

<dependencies><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-openfeign</artifactId></dependency><dependency><groupId>com.tys</groupId><artifactId>hrm-basic-utils</artifactId></dependency></dependencies>

再里面寫一個feign接口

//value屬性:調用目標服務的服務名 @FeignClient(value = "redis-server") public interface RedisFeignClient {//設置值@PostMapping("/redis/set")AjaxResult set(@RequestParam("key")String key, @RequestParam("value")String value);@GetMapping("/redis/get/{key}")AjaxResult get(@PathVariable("key")String key); }

在需要緩存的地方依賴hrm-redis-feign項目
在這個微服務類開啟配置

@SpringBootApplication @MapperScan("com.tys.hrm.course.mapper") @EnableTransactionManagement @EnableFeignClients("com.tys.hrm.feignclients") public class CourseServerApplication2020 {public static void main(String[] args) {SpringApplication.run(CourseServerApplication2020.class);}/*** 分頁插件*/@Beanpublic PaginationInterceptor paginationInterceptor() {return new PaginationInterceptor();} }

修改這個服務的service.iml的增刪改查方法,添加緩存

package com.tys.hrm.course.service.impl;import com.alibaba.fastjson.JSON; import com.baomidou.mybatisplus.service.impl.ServiceImpl; import com.tys.hrm.constants.RedisKeyConstants; import com.tys.hrm.course.domain.CourseType; import com.tys.hrm.course.mapper.CourseTypeMapper; import com.tys.hrm.course.service.ICourseTypeService; import com.tys.hrm.feignclients.RedisFeignClient; import com.tys.hrm.util.AjaxResult; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service;import java.io.Serializable; import java.util.ArrayList; import java.util.List;/*** <p>* 課程目錄 服務實現類* </p>*/ @Service public class CourseTypeServiceImpl extends ServiceImpl<CourseTypeMapper, CourseType> implements ICourseTypeService {@Autowiredprivate RedisFeignClient redisFeignClient;//重置Redis中的課程分類private List<CourseType> resetRedisForCourseType(){// 如果Reids沒有就從Mysql中查List<CourseType> courseTypes = baseMapper.selectList(null);// Mysql查到之后同步一份到RedisredisFeignClient.set(RedisKeyConstants.COURSE_TYPE, JSON.toJSONString(courseTypes));return courseTypes;}@Overridepublic boolean insert(CourseType entity) {boolean insertSucess = super.insert(entity);resetRedisForCourseType();return insertSucess;}@Overridepublic boolean deleteById(Serializable id) {boolean deleteSucess = super.deleteById(id);resetRedisForCourseType();return deleteSucess;}@Overridepublic boolean updateById(CourseType entity) {boolean updateSuccess = super.updateById(entity);resetRedisForCourseType();return updateSuccess;}@Overridepublic List<CourseType> treeData() {List<CourseType> courseTypes = null;// 查詢課程分類的時候先查詢RedisAjaxResult ajaxResult = redisFeignClient.get(RedisKeyConstants.COURSE_TYPE);//判斷是否有結果if(ajaxResult.isSuccess() && null != ajaxResult.getResultObj()){//Redis中有數據//如果Redis有就直接返回、String jsonFromRedis = ajaxResult.getResultObj().toString();//存在redis中的數據 ,要不要有層級結構 :放沒有處理過的listcourseTypes = JSON.parseArray(jsonFromRedis , CourseType.class);}else{courseTypes = resetRedisForCourseType();}//1.查詢所有的課程類型//List<CourseType> courseTypes = baseMapper.selectList(null);//2.先過濾出一級分類//用來封裝一級分類,當然每個一級分類的children中有其子分類List<CourseType> primaryCourseType = new ArrayList<>();for(CourseType courseType : courseTypes){//如果pid==0,那么就是一級分類if(courseType.getPid().longValue() == 0){primaryCourseType.add(courseType);//1037}else{//2.如果不是一級分類,就要知道自己的父分類,裝到自己的父分類的 children//courseType :當前分類,根據當前分類的pid 就是父分類的idCourseType currentPrimaryCourseType = null; //1037for(CourseType pcourseType : courseTypes ){if(courseType.getPid().longValue() == pcourseType.getId().longValue()){//如果當前分類(courseType)的pid 和某個分類的id相等,那么這個某個分類就是當前分類的父分類currentPrimaryCourseType = pcourseType;break;}}if(currentPrimaryCourseType != null){//3.如果找到了父分類,就把當前分類加入父分類的children中currentPrimaryCourseType.getChildren().add(courseType);}}}return primaryCourseType;} }

重啟這個微服務和redis服務,開啟redis

redis-server.exe redis.windows.conf

然后去測試,第一次進數據庫查詢,并緩存到redis中,第二次查詢則直接進緩存,其他操作 增刪改 操作之后,進行更新緩存。

在feign接口打上注解,調用托底類

@FeignClient(value = "redis-server",fallbackFactory = RedisFeignFallbackFactory.class)

在feign接口實現方法 重寫方法

package com.tys.hrm.fallback;import com.tys.hrm.feignclients.RedisFeignClient; import com.tys.hrm.util.AjaxResult; import feign.hystrix.FallbackFactory; import org.springframework.stereotype.Component; @Component public class RedisFeignFallbackFactory implements FallbackFactory<RedisFeignClient> {@Overridepublic RedisFeignClient create(Throwable throwable) {return new RedisFeignClient() {//托底方法@Overridepublic AjaxResult set(String key, String value) {throwable.printStackTrace();return AjaxResult.me().setSuccess(false).setMessage("Redis服務不可用["+throwable.getMessage()+"]");}@Overridepublic AjaxResult get(String key) {throwable.printStackTrace();return AjaxResult.me().setSuccess(false).setMessage("Redis服務不可用["+throwable.getMessage()+"]");}};} }
2.4.1.3 fastdfs

導包

<dependencies><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-netflix-eureka-client</artifactId></dependency><!-- 集成Web的jar包--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-config</artifactId></dependency><dependency><groupId>com.tys</groupId><artifactId>hrm-basic-utils</artifactId></dependency><!--引入swagger支持--><dependency><groupId>io.springfox</groupId><artifactId>springfox-swagger2</artifactId></dependency><dependency><groupId>io.springfox</groupId><artifactId>springfox-swagger-ui</artifactId></dependency><dependency><groupId>org.csource</groupId><artifactId>fastdfs-client-java</artifactId><exclusions><exclusion><groupId>org.slf4j</groupId><artifactId>slf4j-log4j12</artifactId></exclusion></exclusions></dependency><dependency><groupId>commons-io</groupId><artifactId>commons-io</artifactId></dependency></dependencies>

導入工具類fastdfs

package com.tys.hrm.utils;import org.csource.common.NameValuePair; import org.csource.fastdfs.*;public class FastDfsApiOpr {public static String CONF_FILENAME = FastDfsApiOpr.class.getClassLoader().getResource("fdfs_client.conf").getFile();/*** 上傳文件* @param file* @param extName* @return*/public static String upload(byte[] file,String extName) {try {ClientGlobal.init(CONF_FILENAME);TrackerClient tracker = new TrackerClient();TrackerServer trackerServer = tracker.getTrackerServer();//TrackerServer trackerServer = tracker.getConnection();StorageServer storageServer = null;StorageClient storageClient = new StorageClient(trackerServer, storageServer);NameValuePair nvp [] = new NameValuePair[]{new NameValuePair("age", "18"),new NameValuePair("sex", "male")};String fileIds[] = storageClient.upload_file(file,extName,nvp);System.out.println(fileIds.length);System.out.println("組名:" + fileIds[0]);System.out.println("路徑: " + fileIds[1]);return "/"+fileIds[0]+"/"+fileIds[1];} catch (Exception e) {e.printStackTrace();return null;}}/*** 上傳文件* @param extName* @return*/public static String upload(String path,String extName) {try { ClientGlobal.init(CONF_FILENAME);TrackerClient tracker = new TrackerClient();TrackerServer trackerServer = tracker.getTrackerServer();//TrackerServer trackerServer = tracker.getConnection();StorageServer storageServer = null;StorageClient storageClient = new StorageClient(trackerServer, storageServer);String fileIds[] = storageClient.upload_file(path, extName,null);System.out.println(fileIds.length); System.out.println("組名:" + fileIds[0]); System.out.println("路徑: " + fileIds[1]);return "/"+fileIds[0]+"/"+fileIds[1];} catch (Exception e) {e.printStackTrace();return null;}}/*** 下載文件* @param groupName* @param fileName* @return*/public static byte[] download(String groupName,String fileName) {try {ClientGlobal.init(CONF_FILENAME);TrackerClient tracker = new TrackerClient();TrackerServer trackerServer = tracker.getTrackerServer();//TrackerServer trackerServer = tracker.getConnection();StorageServer storageServer = null;StorageClient storageClient = new StorageClient(trackerServer, storageServer);byte[] b = storageClient.download_file(groupName, fileName);return b;} catch (Exception e) {e.printStackTrace();return null;}}/*** 刪除文件* @param groupName* @param fileName*/public static void delete(String groupName,String fileName){try {ClientGlobal.init(CONF_FILENAME);TrackerClient tracker = new TrackerClient();TrackerServer trackerServer = tracker.getTrackerServer();//TrackerServer trackerServer = tracker.getConnection();StorageServer storageServer = null;StorageClient storageClient = new StorageClient(trackerServer,storageServer);int i = storageClient.delete_file(groupName,fileName);System.out.println( i==0 ? "刪除成功" : "刪除失敗:"+i);} catch (Exception e) {e.printStackTrace();throw new RuntimeException("刪除異常,"+e.getMessage());}} }

直接復制swagger
創建web.controller層

package com.tys.hrm.web.controller;import com.tys.hrm.util.AjaxResult; import com.tys.hrm.utils.FastDfsApiOpr; import org.apache.commons.io.FilenameUtils; import org.springframework.web.bind.annotation.*; import org.springframework.web.multipart.MultipartFile;import java.io.IOException;//文件統一處理 @RestController @RequestMapping("/fastdfs") public class FastDfsController {//文件上傳@PostMapping("/upload")public AjaxResult upload(MultipartFile file) throws Exception {//把文件上傳到Fastdfs云服務器try {//原生的文件名:a.jpg :commons-ioString extension = FilenameUtils.getExtension(file.getOriginalFilename());String filePath = FastDfsApiOpr.upload(file.getBytes() , extension);return AjaxResult.me().setResultObj(filePath);} catch (Exception e) {e.printStackTrace();return AjaxResult.me().setSuccess(false).setMessage("文件上傳失敗");}}@DeleteMapping("/remove")public AjaxResult delete(@RequestParam("path") String path) throws Exception{try{/*把組名前面的/去掉* substring(int beginIndex) 返回字符串的子字符串。* substring(int beginIndex, int endIndex) beginIndex起始索引(包含)索引從0開始。endIndex結束索引(不包括).* indexOf() 方法可返回某個指定的字符串值在字符串中首次出現的位置。* */String pathTmp = path.substring(1);//得到groupNameString groupName = pathTmp.substring(0, pathTmp.indexOf("/"));//得到fileNameString fileName = pathTmp.substring(pathTmp.indexOf("/")+1);System.out.println(groupName);System.out.println(fileName);FastDfsApiOpr.delete(groupName, fileName);return AjaxResult.me();}catch (Exception e){e.printStackTrace();return AjaxResult.me().setSuccess(false).setResultObj("刪除失敗!" + e.getMessage());}} }

設置fastDFS配置文件(fdfs_client.conf)

connect_timeout = 2 network_timeout = 30 charset = UTF-8 http.tracker_http_port = 80 http.anti_steal_token = no http.secret_key = FastDFS1234567890tracker_server=118.25.154.214:22122 #服務器配置了fastDFS的IPconnection_pool.enabled = true connection_pool.max_count_per_entry = 500 connection_pool.max_idle_time = 3600 connection_pool.max_wait_time_in_ms = 1000

總結

以上是生活随笔為你收集整理的搭建一个完整的微服务项目的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。