springcloud微服务

要会用,首先要了解。图懒得画,借鉴网上大牛的图吧,springcloud组建架构如图:

微服务架构的应用场景:

1、系统拆分,多个子系统

2、每个子系统可部署多个应用,应用之间负载均衡实现

3、需要一个服务注册中心,所有的服务都在注册中心注册,负载均衡也是通过在注册中心注册的服务来使用一定策略来实现。

4、所有的客户端都通过同一个网关地址访问后台的服务,通过路由配置,网关来判断一个URL请求由哪个服务处理。请求转发到服务上的时候也使用负载均衡。

5、服务之间有时候也需要相互访问。例如有一个用户模块,其他服务在处理一些业务的时候,要获取用户服务的用户数据。

6、需要一个断路器,及时处理服务调用时的超时和错误,防止由于其中一个服务的问题而导致整体系统的瘫痪。

7、还需要一个监控功能,监控每个服务调用花费的时间等。

 

Spring Cloud的优势

  • 产出于spring大家族,spring在企业级开发框架中无人能敌,来头很大,可以保证后续的更新、完善。比如dubbo现在就差不多死了
  • 有spring Boot 这个独立干将可以省很多事,大大小小的活spring boot都搞的挺不错。
  • 作为一个微服务治理的大家伙,考虑的很全面,几乎服务治理的方方面面都考虑到了,方便开发开箱即用。
  • Spring Cloud 活跃度很高,教程很丰富,遇到问题很容易找到解决方案
  • 轻轻松松几行代码就完成了熔断、均衡负责、服务中心的各种平台功能

废话少说,看代码:

项目架构:

一、discovery服务注册发现

①、pom.xml

 


 
  1. <?xml version="1.0"?>

  2. <project

  3. xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"

  4. xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">

  5. <modelVersion>4.0.0</modelVersion>

  6. <parent>

  7. <groupId>com.gt</groupId>

  8. <artifactId>popuserver</artifactId>

  9. <version>0.0.1-SNAPSHOT</version>

  10. </parent>

  11.  
  12.  
  13. <artifactId>discovery</artifactId>

  14. <name>discovery</name>

  15. <url>http://www.popumusic</url>

  16.  
  17. <properties>

  18. <start-class>com.wisely.discovery.DiscoveryApplication</start-class>

  19. </properties>

  20.  
  21. <dependencies>

  22. <dependency>

  23. <groupId>org.springframework.cloud</groupId>

  24. <artifactId>spring-cloud-starter-eureka-server</artifactId>

  25. </dependency>

  26. </dependencies>

  27.  
  28. <build>

  29. <plugins>

  30. <plugin>

  31. <groupId>org.springframework.boot</groupId>

  32. <artifactId>spring-boot-maven-plugin</artifactId>

  33. </plugin>

  34. </plugins>

  35. </build>

  36.  
  37.  
  38. </project>

  39.  


②、DiscoveryApplication

 

 


 
  1. package com.wisely.discovery;

  2.  
  3. import org.springframework.boot.SpringApplication;

  4. import org.springframework.boot.autoconfigure.SpringBootApplication;

  5. import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;

  6.  
  7. @SpringBootApplication

  8. @EnableEurekaServer //1

  9. public class DiscoveryApplication {

  10.  
  11. public static void main(String[] args) {

  12. SpringApplication.run(DiscoveryApplication.class, args);

  13. }

  14.  
  15. }


③、application.yml

 

 


 
  1. server:

  2. port: 8761

  3.  
  4. endpoints:

  5. shutdown:

  6. enabled: true

  7. sensitive: false

  8. eureka:

  9. instance:

  10. prefer-ip-address: true #启用IP方式

  11. ip-address: 127.0.0.1

  12. client:

  13. register-with-eureka: false #指向其他注册中心地址

  14. fetch-registry: false

  15. service-url:

  16. defualtZone: http://127.0.0.1:8762/eureka/


二、monitor监控服务

 

①、pom.xml

 


 
  1. <?xml version="1.0"?>

  2. <project

  3. xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"

  4. xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">

  5. <modelVersion>4.0.0</modelVersion>

  6. <parent>

  7. <groupId>com.gt</groupId>

  8. <artifactId>popuserver</artifactId>

  9. <version>0.0.1-SNAPSHOT</version>

  10. </parent>

  11. <groupId>com.poputar</groupId>

  12. <artifactId>popumonitor</artifactId>

  13. <version>0.0.1-SNAPSHOT</version>

  14. <name>popumonitor</name>

  15. <url>http://maven.apache.org</url>

  16. <properties>

  17. <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>

  18. </properties>

  19. <dependencies>

  20. <dependency>

  21. <groupId>org.springframework.cloud</groupId>

  22. <artifactId>spring-cloud-starter</artifactId>

  23. <version>1.1.7.RELEASE</version>

  24. </dependency>

  25. <dependency>

  26. <groupId>org.springframework.cloud</groupId>

  27. <artifactId>spring-cloud-starter-hystrix-dashboard</artifactId>

  28. <version>1.2.2.RELEASE</version>

  29. </dependency>

  30. <dependency>

  31. <groupId>org.springframework.cloud</groupId>

  32. <artifactId>spring-cloud-starter-turbine</artifactId>

  33. <version>1.1.7.RELEASE</version>

  34. </dependency>

  35. <dependency>

  36. <groupId>junit</groupId>

  37. <artifactId>junit</artifactId>

  38. <version>3.8.1</version>

  39. <scope>test</scope>

  40. </dependency>

  41. </dependencies>

  42. <build>

  43. <plugins>

  44. <plugin>

  45. <groupId>com.spotify</groupId>

  46. <artifactId>docker-maven-plugin</artifactId>

  47. <configuration>

  48. <imageName>${project.name}:${project.version}</imageName>

  49. <dockerDirectory>${project.basedir}/src/main/docker</dockerDirectory>

  50. <skipDockerBuild>false</skipDockerBuild>

  51. <resources>

  52. <resource>

  53. <directory>${project.build.directory}</directory>

  54. <include>${project.build.finalName}.jar</include>

  55. </resource>

  56. </resources>

  57. </configuration>

  58. </plugin>

  59. </plugins>

  60. </build>

  61. </project>


②、PopumonitorApplication

 

 


 
  1. package com.poputar;

  2.  
  3. import org.springframework.boot.SpringApplication;

  4. import org.springframework.boot.autoconfigure.SpringBootApplication;

  5. import org.springframework.cloud.netflix.eureka.EnableEurekaClient;

  6. import org.springframework.cloud.netflix.hystrix.dashboard.EnableHystrixDashboard;

  7. import org.springframework.cloud.netflix.turbine.EnableTurbine;

  8.  
  9. /**

  10. * 监控服务

  11. *

  12. */

  13. @SpringBootApplication

  14. @EnableEurekaClient

  15. @EnableHystrixDashboard

  16. @EnableTurbine

  17. public class PopumonitorApplication

  18. {

  19. public static void main( String[] args )

  20. {

  21. SpringApplication.run(PopumonitorApplication.class, args);

  22. }

  23. }


③、application.yml

 

 


 
  1. server:

  2. port: 8989

  3.  


④、bootstrap.yml

 

 


 
  1. spring:

  2. application:

  3. name: monitor

  4.  
  5. eureka:

  6. instance:

  7. nonSecurePort: ${server.port:8989}

  8. client:

  9. serviceUrl:

  10. defaultZone: http://${eureka.host:localhost}:${eureka.port:8761}/eureka/

 

 

三、配置服务

①、pom.xml

 


 
  1. <?xml version="1.0"?>

  2. <project

  3. xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"

  4. xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">

  5. <modelVersion>4.0.0</modelVersion>

  6. <parent>

  7. <groupId>com.gt</groupId>

  8. <artifactId>popuserver</artifactId>

  9. <version>0.0.1-SNAPSHOT</version>

  10. </parent>

  11. <groupId>com.poputar</groupId>

  12. <artifactId>popuconfig</artifactId>

  13. <version>0.0.1-SNAPSHOT</version>

  14. <name>popuconfig</name>

  15. <url>http://maven.apache.org</url>

  16. <properties>

  17. <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>

  18. </properties>

  19. <dependencies>

  20. <dependency>

  21. <groupId>org.springframework.cloud</groupId>

  22. <artifactId>spring-cloud-starter</artifactId>

  23. <version>1.1.7.RELEASE</version>

  24. </dependency>

  25. <dependency>

  26. <groupId>org.springframework.cloud</groupId>

  27. <artifactId>spring-cloud-config-server</artifactId>

  28. <version>1.2.2.RELEASE</version>

  29. </dependency>

  30. <dependency>

  31. <groupId>org.springframework.cloud</groupId>

  32. <artifactId>spring-cloud-starter-eureka</artifactId>

  33. <version>1.1.7.RELEASE</version>

  34. </dependency>

  35. <dependency>

  36. <groupId>junit</groupId>

  37. <artifactId>junit</artifactId>

  38. <version>3.8.1</version>

  39. <scope>test</scope>

  40. </dependency>

  41. </dependencies>

  42. <build>

  43. <plugins>

  44. <plugin>

  45. <groupId>com.spotify</groupId>

  46. <artifactId>docker-maven-plugin</artifactId>

  47. <configuration>

  48. <imageName>${project.name}:${project.version}</imageName>

  49. <dockerDirectory>${project.basedir}/src/main/docker</dockerDirectory>

  50. <skipDockerBuild>false</skipDockerBuild>

  51. <resources>

  52. <resource>

  53. <directory>${project.build.directory}</directory>

  54. <include>${project.build.finalName}.jar</include>

  55. </resource>

  56. </resources>

  57. </configuration>

  58. </plugin>

  59. </plugins>

  60. </build>

  61. </project>

 

 

②、PopuconfigApplication

 


 
  1. package org.popuconfig;

  2.  
  3. import org.springframework.boot.SpringApplication;

  4. import org.springframework.boot.autoconfigure.SpringBootApplication;

  5. import org.springframework.cloud.config.server.EnableConfigServer;

  6. import org.springframework.cloud.netflix.eureka.EnableEurekaClient;

  7.  
  8. /**

  9. * 配置服务

  10. *

  11. */

  12. @SpringBootApplication

  13. @EnableConfigServer

  14. @EnableEurekaClient

  15. public class PopuconfigApplication

  16. {

  17. public static void main( String[] args )

  18. {

  19. SpringApplication.run(PopuconfigApplication.class, args);

  20. }

  21. }


③、application.yml 配置文件放本地,读者可以自己研究下放在git服务上

 

 


 
  1. spring:

  2. cloud:

  3. config:

  4. server:

  5. native:

  6. search-locations: classpath:/config

  7.  
  8. server:

  9. port: 8762


④、bootstrap.yml

 

 


 
  1. spring:

  2. application:

  3. name: config #1

  4. profiles:

  5. active: native #2

  6.  
  7. eureka:

  8. instance:

  9. non-secure-port: ${server.port:8762} #3

  10. metadata-map:

  11. instanceId: ${spring.application.name}

  12. client:

  13. service-url:

  14. defaultZone: http://${eureka.host:localhost}:${eureka.port:8761}/eureka/ #5

  15.  


⑤、src/main/resources/config下放应用所需的配置文件,命名方式跟appname相同,切记此处的命名是有规范的

四、用户服务

①、pom.xml 需要引入外部jar包时,我已做注释,如下:

 


 
  1. <?xml version="1.0"?>

  2. <project

  3. xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"

  4. xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">

  5. <modelVersion>4.0.0</modelVersion>

  6. <parent>

  7. <groupId>com.gt</groupId>

  8. <artifactId>popuserver</artifactId>

  9. <version>0.0.1-SNAPSHOT</version>

  10. </parent>

  11. <artifactId>popuman</artifactId>

  12. <name>popuman</name>

  13. <url>http://www.popumusic</url>

  14.  
  15. <dependencies>

  16. <dependency>

  17. <groupId>org.springframework.boot</groupId>

  18. <artifactId>spring-boot-starter-data-redis</artifactId>

  19. </dependency>

  20. <dependency>

  21. <groupId>org.springframework.cloud</groupId>

  22. <artifactId>spring-cloud-starter-eureka</artifactId>

  23. </dependency>

  24. <dependency>

  25. <groupId>org.springframework.boot</groupId>

  26. <artifactId>spring-boot-starter-data-jpa</artifactId>

  27. </dependency>

  28. <dependency>

  29. <groupId>mysql</groupId>

  30. <artifactId>mysql-connector-java</artifactId>

  31. </dependency>

  32. <dependency>

  33. <groupId>org.springframework.cloud</groupId>

  34. <artifactId>spring-cloud-starter-config</artifactId>

  35. </dependency>

  36.  
  37. <dependency>

  38. <groupId>aliyun-java-sdk-dysmsapit</groupId>

  39. <artifactId>aliyun-java-sdk-dysmsapi</artifactId>

  40. <version>1.0.0</version>

  41. <scope>system</scope>

  42. <systemPath>${project.basedir}/lib/aliyun-java-sdk-dysmsapi-1.0.0.jar</systemPath>

  43. </dependency>

  44.  
  45. <dependency>

  46. <groupId>aliyun-java-sdk-core</groupId>

  47. <artifactId>aliyun-java-sdk-core</artifactId>

  48. <version>3.3.1</version>

  49. <scope>system</scope>

  50. <systemPath>${project.basedir}/lib/aliyun-java-sdk-core-3.3.1.jar</systemPath>

  51. </dependency>

  52.  
  53. </dependencies>

  54.  
  55. <build>

  56. <plugins>

  57. <plugin>

  58. <groupId>org.springframework.boot</groupId>

  59. <artifactId>spring-boot-maven-plugin</artifactId>

  60. </plugin>

  61. </plugins>

  62.  
  63. <!-- 将外部包打入jar docker部署时需要打开,否则报错,找不到jar -->

  64. <!-- <resources>

  65. <resource>

  66. <directory>lib</directory>

  67. <targetPath>BOOT-INF/lib/</targetPath>

  68. <includes>

  69. <include>**/*.jar</include>

  70. </includes>

  71. </resource>

  72. <resource>

  73. <directory>src/main/resources</directory>

  74. <targetPath>BOOT-INF/classes/</targetPath>

  75. </resource>

  76. </resources> -->

  77. </build>

  78. </project>

  79.  


②、PopumanApplication 增加了国际化配置

 

 


 
  1. package com.gt;

  2.  
  3. import javax.validation.Validator;

  4.  
  5. import org.springframework.boot.SpringApplication;

  6. import org.springframework.boot.autoconfigure.SpringBootApplication;

  7. import org.springframework.cloud.netflix.eureka.EnableEurekaClient;

  8. import org.springframework.context.annotation.Bean;

  9. import org.springframework.context.support.ResourceBundleMessageSource;

  10. import org.springframework.validation.beanvalidation.LocalValidatorFactoryBean;

  11.  
  12. @SpringBootApplication

  13. @EnableEurekaClient

  14. public class PopumanApplication {

  15. public static void main(String[] args) {

  16. SpringApplication.run(PopumanApplication.class, args);

  17. }

  18.  
  19. public ResourceBundleMessageSource getMessageSource() throws Exception {

  20. ResourceBundleMessageSource rbms = new ResourceBundleMessageSource();

  21. rbms.setDefaultEncoding("UTF-8");

  22. rbms.setBasenames("i18n/ValidationMessages");

  23. return rbms;

  24. }

  25.  
  26. @Bean

  27. public Validator getValidator() throws Exception {

  28. LocalValidatorFactoryBean validator = new LocalValidatorFactoryBean();

  29. validator.setValidationMessageSource(getMessageSource());

  30. return validator;

  31. }

  32. }


③、LocaleConfig 拦截器


 
  1. package com.gt;

  2.  
  3. import java.util.Locale;

  4.  
  5. import org.springframework.boot.autoconfigure.EnableAutoConfiguration;

  6. import org.springframework.context.annotation.Bean;

  7. import org.springframework.context.annotation.ComponentScan;

  8. import org.springframework.context.annotation.Configuration;

  9. import org.springframework.web.servlet.LocaleResolver;

  10. import org.springframework.web.servlet.config.annotation.InterceptorRegistry;

  11. import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;

  12. import org.springframework.web.servlet.i18n.LocaleChangeInterceptor;

  13. import org.springframework.web.servlet.i18n.SessionLocaleResolver;

  14.  
  15. @Configuration

  16. @EnableAutoConfiguration

  17. @ComponentScan

  18. public class LocaleConfig extends WebMvcConfigurerAdapter {

  19.  
  20. @Bean

  21. public LocaleResolver localeResolver() {

  22. SessionLocaleResolver slr = new SessionLocaleResolver();

  23. // 默认语言

  24. slr.setDefaultLocale(Locale.US);

  25. return slr;

  26. }

  27.  
  28. @Bean

  29. public LocaleChangeInterceptor localeChangeInterceptor() {

  30. LocaleChangeInterceptor lci = new LocaleChangeInterceptor();

  31. // 参数名

  32. lci.setParamName("lang");

  33. return lci;

  34. }

  35.  
  36. @Override

  37. public void addInterceptors(InterceptorRegistry registry) {

  38. registry.addInterceptor(localeChangeInterceptor());

  39. }

  40.  
  41. }

 

 

④、MessageManager 读取国际化文件内容

 


 
  1. package com.gt;

  2.  
  3. import java.util.Locale;

  4.  
  5. import org.springframework.beans.factory.annotation.Autowired;

  6. import org.springframework.context.MessageSource;

  7. import org.springframework.context.i18n.LocaleContextHolder;

  8. import org.springframework.stereotype.Component;

  9.  
  10. @Component

  11. public class MessageManager {

  12.  
  13. private static MessageSource messageSource;

  14.  
  15. public static String getMsg(String key) {

  16. Locale locale = LocaleContextHolder.getLocale();

  17. return messageSource.getMessage(key, null, locale);

  18. }

  19.  
  20. public static String getMsg(String key, String... arg) {

  21. Locale locale = LocaleContextHolder.getLocale();

  22. Object[] args = new Object[arg.length];

  23. for (int i = 0; i < arg.length; i++) {

  24. args[i] = arg[i];

  25. }

  26. return messageSource.getMessage(key, args, locale);

  27. }

  28.  
  29. @Autowired(required = true)

  30. public void setMessageSource(MessageSource messageSource) {

  31. MessageManager.messageSource = messageSource;

  32. }

  33. }

 

⑤、application.yml

 


 
  1. debug: true

  2. server:

  3. port: 8781


⑥、bootstrap.yml docker环境下部署时需要指定ip,否则找不到配置服务,读取不了配置中心的相关配置

 

 


 
  1. spring:

  2. application:

  3. name: popuman

  4. cloud:

  5. config:

  6. enabled: true

  7. discovery: #配置服务发现,获取配置信息 配置文件命名要按照springcloud config配置文件命名规则命名

  8. enabled: true

  9. service-id: config

  10. eureka:

  11. instance:

  12. appname: popuman

  13. client:

  14. service-url:

  15. defaultZone: http://${eureka.host:localhost}:${eureka.port:8761}/eureka/

  16.  
  17. #docker环境下需指定ip才能访问

  18. #eureka:

  19. # instance:

  20. # appname: popuman

  21. # prefer-ip-address: true #启用IP方式

  22. # ip-address: 192.168.*.**

  23. # client:

  24. # service-url:

  25. # defaultZone: http://192.168.*.**:8761/eureka/


⑦、logback.xml 日志分级别输出到文件,dubug,error级别日志输出到各自的日志文件

 

 


 
  1. <configuration>

  2. <!-- %m输出的信息,%p日志级别,%t线程名,%d日期,%c类的全名,,,, -->

  3. <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">

  4. <encoder>

  5. <pattern>%d %p (%file:%line\)- %m%n</pattern>

  6. <charset>UTF-8</charset>

  7. </encoder>

  8. </appender>

  9. <appender name="popuman"

  10. class="ch.qos.logback.core.rolling.RollingFileAppender">

  11. <File>/Users/david/Documents/Poputar/logs/popuman.log</File>

  12. <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">

  13. <fileNamePattern>/Users/david/Documents/Poputar/logs/popuman.%d.%i</fileNamePattern>

  14. <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">

  15. <!-- or whenever the file size reaches 64 MB -->

  16. <maxFileSize>64 MB</maxFileSize>

  17. </timeBasedFileNamingAndTriggeringPolicy>

  18. </rollingPolicy>

  19. <encoder>

  20. <pattern>

  21. %d %p (%file:%line\)- %m%n

  22. </pattern>

  23. <charset>UTF-8</charset> <!-- 此处设置字符集 -->

  24. </encoder>

  25. <filter class="ch.qos.logback.classic.filter.LevelFilter"> <!-- 过滤错误日志 -->

  26. <level>ERROR</level>

  27. <onMatch>DENY</onMatch>

  28. <onMismatch>ACCEPT</onMismatch>

  29. </filter>

  30. </appender>

  31. <appender name="popuman_err"

  32. class="ch.qos.logback.core.rolling.RollingFileAppender">

  33. <File>/Users/david/Documents/Poputar/logs/popuman_err.log</File>

  34. <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">

  35. <fileNamePattern>/Users/david/Documents/Poputar/logs/popuman_err.%d.%i</fileNamePattern>

  36. <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">

  37. <!-- or whenever the file size reaches 64 MB -->

  38. <maxFileSize>64 MB</maxFileSize>

  39. </timeBasedFileNamingAndTriggeringPolicy>

  40. </rollingPolicy>

  41. <encoder>

  42. <pattern>

  43. %d %p (%file:%line\)- %m%n

  44. </pattern>

  45. <charset>UTF-8</charset> <!-- 此处设置字符集 -->

  46. </encoder>

  47. <filter class="ch.qos.logback.classic.filter.LevelFilter"><!-- 只打印错误日志 -->

  48. <level>ERROR</level>

  49. <onMatch>ACCEPT</onMatch>

  50. <onMismatch>DENY</onMismatch>

  51. </filter>

  52. </appender>

  53. <root level="info">

  54. <appender-ref ref="STDOUT" />

  55. </root>

  56. <!-- 输出日志 -->

  57. <logger name="com.gt" level="DEBUG">

  58. <appender-ref ref="popuman" />

  59. <appender-ref ref="popuman_err" />

  60. </logger>

  61. </configuration>


五、popumusic项目代码就不贴了,同popuman项目类似。

 

部署到docker时,切记端口映射好,否则调不通。

六、应用之间服务的调用是通过springcloud的FeignClient调用,这种调用方式同样也是基于http协议,好处是不用我们再去封装httpclient手写post,get请求,通过调用方法的方式就可以调用其他服务接口

本架构采用springboot推荐的JPA方式来处理数据层,缓存采用redis,如果您要问,redis挂掉怎么办?那就要考虑redis的分布式,主从等,这里不做赘述。

spriingcloud是近两年新兴的微服务技术,目前我也是在学习中,如有觉得我写的有不对的地方,还请批评指正,共同交流,学习一门新技术是枯燥的,难免走很多弯路,但是当你突破难关时,那样的轻松是何等畅快!在这里也感谢优快云上大牛的技术文章分享,有分享才会有进步。希望本文对学习springcloud的同学有所帮助。

 

推荐几篇springcloud总结比较全的博客,也是本文项目搭建过程借鉴的技术文章

方志鹏大牛博客地址:http://blog.youkuaiyun.com/forezp/article/category/6830968/1

司青博客:http://blog.youkuaiyun.com/neosmith/article/details/52449921

http://blog.youkuaiyun.com/f1576813783/article/details/76805195

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值