日本综合一区二区|亚洲中文天堂综合|日韩欧美自拍一区|男女精品天堂一区|欧美自拍第6页亚洲成人精品一区|亚洲黄色天堂一区二区成人|超碰91偷拍第一页|日韩av夜夜嗨中文字幕|久久蜜综合视频官网|精美人妻一区二区三区

RELATEED CONSULTING
相關(guān)咨詢
選擇下列產(chǎn)品馬上在線溝通
服務(wù)時(shí)間:8:30-17:00
你可能遇到了下面的問題
關(guān)閉右側(cè)工具欄

新聞中心

這里有您想知道的互聯(lián)網(wǎng)營銷解決方案
一個(gè)項(xiàng)目的SpringCloud微服務(wù)改造過程

SSO是公司一個(gè)已經(jīng)存在了若干年的項(xiàng)目,后端采用SpringMVC、MyBatis,數(shù)據(jù)庫使用MySQL,前端展示使用Freemark。今年,我們對該項(xiàng)目進(jìn)行了一次革命性的改進(jìn),將其改造成SpringCloud架構(gòu),并且把前后端分離,前端采用Vue框架。

創(chuàng)新互聯(lián)是一家專業(yè)提供曲阜企業(yè)網(wǎng)站建設(shè),專注與成都網(wǎng)站制作、成都網(wǎng)站建設(shè)、H5響應(yīng)式網(wǎng)站、小程序制作等業(yè)務(wù)。10年已為曲阜眾多企業(yè)、政府機(jī)構(gòu)等服務(wù)。創(chuàng)新互聯(lián)專業(yè)網(wǎng)站制作公司優(yōu)惠進(jìn)行中。

一、使用SpringCloud架構(gòu)進(jìn)行改造

1.1 為什么使用SpringCloud

SpringCloud的核心是SpringBoot,相比較于傳統(tǒng)的Spring,SpringCloud具有以下優(yōu)點(diǎn):

  • 部署簡單,SpringBoot內(nèi)置了Tomcat容器,可以將程序直接編譯成一個(gè)jar,通過java-jar來運(yùn)行。
  • 編碼簡單,SpringBoot只需要在pom文件中添加一個(gè)starter-web依賴,即可幫助開發(fā)者快速啟動一個(gè)web容器,非常方便。
  • 配置簡單,SpringBoot可以通過簡單的注解方式來代替原先Spring非常復(fù)雜的xml方式。如果我想把一個(gè)普通的類交給Spring管理,只需要添加@Configuration和@Bean兩個(gè)注解即可。
  • 監(jiān)控簡單,我們可以引入spring-boot-start-actuator依賴,直接使用REST方式來獲取進(jìn)程的運(yùn)行期性能參數(shù),從而達(dá)到監(jiān)控的目的。

1.2 一個(gè)常規(guī)項(xiàng)目都需要改造哪些部分

1.2.1 配置文件  

SSO項(xiàng)目改造前充斥著大量的配置文件,主要包含以下這些部分:

  • 靜態(tài)資源相關(guān)
  • 數(shù)據(jù)源
  • mybatis配置
  • redis配置
  • 事務(wù)
  • 攔截器攔截內(nèi)容
  • 監(jiān)聽器、過濾器
  • 組件掃描路徑配置

本文著重介紹以下幾個(gè)部分:

1)靜態(tài)資源處理

SpringMVC中,如果
mvc:interceptors
配置的URL規(guī)則如下,則不會攔截靜態(tài)資源。

 
 
 
 

但是如果配置的是:

 
 
 
 

方案1
: 在web.xml中配置
default
,用
defaultServlet
先處理請求如:

 
 
 
 
  1.         default
  2.         *.jpg
  3.     
  4.     
  5.         default
  6.         *.png
  7.     
  8.     
  9.         default
  10.         *.gif
  11.     
  12.     
  13.         default
  14.         *.ico
  15.     
  16.     
  17.         default
  18.         *.gif
  19.     
  20.     
  21.         default
  22.         *.js
  23.     
  24.     
  25.         default
  26.         *.css
  27.     

 方案2:使用標(biāo)簽聲明靜態(tài)資源路徑

 
 
 
 

方案3:使用mvc:default-servlet-handler/標(biāo)簽

SpringBoot解決方案:繼承WebMvcConfigurerAdapter實(shí)現(xiàn)addResourceHandlers方法。

 
 
 
 
  1. public void addResourceHandlers(ResourceHandlerRegistry registry) {
  2.     registry.addResourceHandler("/**")
  3.     .addResourceLocations("classpath:/resource/")//sso靜態(tài)資源
  4.     .addResourceLocations("classpath:/META-INF/resources/")//swagger靜態(tài)資源
  5.     .setCachePeriod(0);//0表示不緩存
  6. }

 sso靜態(tài)資源文件路徑如圖:

2)攔截器

SpringMVC配置文件內(nèi)容:

攔截任何請求并且初始化參數(shù),有些請求是不需要攔截的,有的請求登錄后不需要經(jīng)過權(quán)限校驗(yàn)直接放行。

 
 
 
 
  1.     
  2.         
  3.            
  4.            
  5.           
  6.           請求地址
  7.           
  8.           
  9.           
  10.           請求地址
  11.           
  12.          
  13.    
  14.  

 SpringBoot中添加攔截器只需繼承WebMvcConfigurerAdapter,并重寫addInterceptors方法即可。

 
 
 
 
  1. /*** 攔截器
  2. * @param registry
  3. */
  4. @Override
  5. public void addInterceptors(InterceptorRegistry registry) {
  6.    registry.addInterceptor(permissionInterceptor).
  7.            addPathPatterns("/**");
  8.    super.addInterceptors(registry);
  9. }

自定義的攔截器需要初始化一些參數(shù),因此需要在注冊攔截器之前注冊,這里我們設(shè)置為懶加載。免登錄攔截的路徑,以及登錄后不需要判斷權(quán)限的路徑都寫在yml文件了,通過系統(tǒng)環(huán)境變量Environment獲取值。

 
 
 
 
  1. @Autowired 
  2. @Lazy 
  3. private PermissionInterceptor permissionInterceptor; 
  4. @Autowired 
  5. private Environment environment; 
  6. /**
  7. *
  8. */
  9. @Bean
  10. public PermissionInterceptor permissionInterceptor() {
  11. PermissionInterceptor permissionInterceptor = new PermissionInterceptor();
  12. List excludeUrls = Arrays.asList(environment.getProperty("intercept.exclude.path").split(","));
  13. List commonUrls = Arrays.asList(environment.getProperty("intercept.login.exclude.path").split(","));
  14. permissionInterceptor.setCommonUrls(commonUrls);
  15. permissionInterceptor.setExcludeUrls(excludeUrls);
  16. return permissionInterceptor;
  17. }

 3)數(shù)據(jù)庫和MyBatis配置

A、數(shù)據(jù)源配置
數(shù)據(jù)源注入的三種情況:
【情況一】

  • 條件:不引?druid-spring-boot-starter只依賴druid.jar,不指定spring.datasource.type。

  • 結(jié)果:注入的數(shù)據(jù)源是tomcat的數(shù)據(jù)源。

  • 解析:依賴的mybatis-spring-boot-starter工程依賴了tomcat的數(shù)據(jù)源,spring-boot-autoconfigure-starter的DataSourceAutoConfiguration自動注入類會在不指定數(shù)據(jù)源的情況下,判斷路徑中是否存在默認(rèn)的4種數(shù)據(jù)源(Hikari,Tomcat,Dbcp,Dbcp2)的其一,如果有就注入。

【情況二】

  • 條件: 不引入druid-spring-boot-starter只依賴druid.jar ,指定spring.datasource.type為DruidDataSource。
  • 結(jié)果: 注入了DruidDataSource數(shù)據(jù)源,但配置文件中的druid配置不會生效。  
  • 解析: 指定了依賴的數(shù)據(jù)源后,spring自動注入的starter會將指定的數(shù)據(jù)源注入,yml指定了druid數(shù)據(jù)源。 @ConfigurationProperties注解的DataSourceProperties沒處理druid部分的性能參數(shù)屬性,只處理了數(shù)據(jù)源部分的屬性。

 【情況三】

  • 條件: 引??druid-spring-boot-starter?不依賴druid.jar,指定spring.datasource.type為DruidDataSource。
  • 結(jié)果: 注入了DruidDataSource數(shù)據(jù)源, 配置文件中的druid配置也會生效。  
  • 解析: druid-spring-boot-starter自動配置類會在DataSourceAutoConfiguration之前先創(chuàng)建數(shù)據(jù)源,并且@ConfigurationProperties注入的DataSourceProperties包含了配置文件中druid的屬性。

 pom.xml依賴:

 
 
 
 
  1.   
  2.       
  3.       
  4.       
  5.   
  6.   
  7.       com.alibaba
  8.       druid-spring-boot-starter
  9.       1.1.10
  10.   
  11.   
  12.       org.mybatis.spring.boot
  13.       mybatis-spring-boot-starter
  14.       RELEASE
  15.   

yml配置:

 
 
 
 
  1. spring:
  2.   datasource:
  3.     type: com.alibaba.druid.pool.DruidDataSource            # 當(dāng)前數(shù)據(jù)源操作類型
  4.     driver-class-name: com.mysql.jdbc.Driver            # mysql驅(qū)動包
  5.     url: jdbc:mysql://yourURL        # 數(shù)據(jù)庫名稱
  6.     username: yourusername
  7.     password: yourpassword
  8.     druid:
  9.       initial-size: 5  # 初始化大小
  10.       min-idle: 5  # 最小
  11.       max-active: 20  # 最大
  12.       max-wait: 60000  # 連接超時(shí)時(shí)間
  13.       time-between-eviction-runs-millis: 60000  # 配置間隔多久才進(jìn)行一次檢測,檢測需要關(guān)閉的空閑連接,單位是毫秒
  14.       min-evictable-idle-time-millis: 300000  # 指定一個(gè)空閑連接最少空閑多久后可被清除,單位是毫秒
  15.       validationQuery: select 'x'
  16.       test-while-idle: true  # 當(dāng)連接空閑時(shí),是否執(zhí)行連接測試
  17.       test-on-borrow: false  # 當(dāng)從連接池借用連接時(shí),是否測試該連接
  18.       test-on-return: false  # 在連接歸還到連接池時(shí)是否測試該連接
  19.       filters: config,wall,stat

 B、MyBatis配置

通過引入mybatis-spring-boot-starter依賴,可以簡單配置mybatis上手使用。
下面簡單分析mybatis-starter的源碼以及如何配置mybatis。
 
先看mybatis-spring-boot-starter中mybatis-spring-boot-autoconfigure的spring.factories文件。

 
 
 
 
  1. # Auto Configure
  2. org.springframework.boot.autoconfigure.EnableAutoConfiguration=org.mybatis.spring.boot.autoconfigure.MybatisAutoConfiguration

 可以看到自動注入類是MybatisAutoConfiguration,我們從這個(gè)類入手分析可以知道,必須先創(chuàng)建好了數(shù)據(jù)源后,才會加載MyBatis的sqlSessionFactory。

@EnableConfigurationProperties({MybatisProperties.class})注解指定了配置文件中 prefix = "mybatis" 那部分屬性有效,這部分屬性值將注入到已創(chuàng)建的SqlSessionFactoryBean中,最后生成SqlSessionFactory對象。

 
 
 
 
  1. @Configuration
  2. //當(dāng)SqlSessionFactory,SqlSessionFactoryBean存在的情況下加載當(dāng)前Bean
  3. @ConditionalOnClass({SqlSessionFactory.class, SqlSessionFactoryBean.class})
  4. //當(dāng)指定數(shù)據(jù)源在容器中只有一個(gè)或者有多個(gè)但是只指定選擇數(shù)據(jù)源
  5. @ConditionalOnSingleCandidate(DataSource.class)
  6. @EnableConfigurationProperties({MybatisProperties.class})
  7. //當(dāng)數(shù)據(jù)源注入到Spring容器后才開始加載當(dāng)前Bean
  8. @AutoConfigureAfter({DataSourceAutoConfiguration.class})
  9. public class MybatisAutoConfiguration implements InitializingBean {
  10.     private final MybatisProperties properties;
  11.     @Bean
  12.     @ConditionalOnMissingBean
  13.     public SqlSessionFactory sqlSessionFactory(DataSource dataSource) throws Exception {
  14.         SqlSessionFactoryBean factory = new SqlSessionFactoryBean();
  15.         factory.setDataSource(dataSource);
  16.         factory.setVfs(SpringBootVFS.class);
  17.        //設(shè)置mybatis配置文件所在路徑
  18.         if (StringUtils.hasText(this.properties.getConfigLocation())) {
  19.           factory.setConfigLocation(this.resourceLoader.getResource
  20.           (this.properties.getConfigLocation())); }
  21.         }
  22.       //設(shè)置其他MyBatisProperties對象中有的屬性略....
  23.        return factory.getObject();
  24.    }
  25. }

 MybatisProperties含有的屬性:

 
 
 
 
  1. @ConfigurationProperties(prefix = "mybatis" )
  2. public class MybatisProperties {
  3.  public static final String MYBATIS_PREFIX = "mybatis";
  4.  private static final ResourcePatternResolver resourceResolver = new PathMatchingResourcePatternResolver();
  5.  private String configLocation;
  6.  private String[] mapperLocations;
  7.  private String typeAliasesPackage;
  8.  private Class typeAliasesSuperType;
  9.  private String typeHandlersPackage;
  10.  private boolean checkConfigLocation = false;
  11.  private ExecutorType executorType;
  12.  private Properties configurationProperties;
  13.  @NestedConfigurationProperty
  14.  private Configuration configuration;
  15. }

 C、使用MyBatis

  • 配置文件

application.yml

 
 
 
 
  1. mybatis:
  2. config-location: classpath:mybatis.xml        # mybatis配置文件所在路徑
  3. type-aliases-package: com.creditease.permission.model    # 所有Entity別名類所在包
  4. mapper-locations: classpath:mybatis/**/*.xml

 從上面的MybatisProperties可以看出,mybatis可以指定一些configuration,比如自定義攔截器pageHelper。

mybatis.xml

 
 
 
 
  1.     "http://mybatis.org/dtd/mybatis-3-config.dtd">
  2.     
  3.         
  4.         
  5.     
  • 在啟動類上加入@MapperScan注解
 
 
 
 
  1. @MapperScan("com.creditease.permission.dao")//mapper類所在目錄
  2. public class SsoApplication {
  3.     public static void main(String[] args) {
  4.         SpringApplication.run(SsoApplication.class, args);
  5.     }
  6. }
4)事務(wù) 

Spring事務(wù)有兩種處理方式:

  • 編程式

用TransactionTemplate或者直接使用底層的PlatformTransactionManager將事務(wù)代碼寫在業(yè)務(wù)代碼中。
優(yōu)點(diǎn):
可以在代碼塊中處理事務(wù),比較靈活。
 
缺點(diǎn):對代碼具有侵入性。

  • 聲明式

采用@Transactional注解或者基于配置文件方式,在方法前后進(jìn)行攔截。
優(yōu)點(diǎn):
非侵入性不會污染代碼。
缺點(diǎn):
事務(wù)只能在方法和類上控制,粒度較小。
A、使用@Transactional注解
非SpringBoot工程,需要在配置文件中加入配置:

 
 
 
 


SpringBoot工程可以用@EnableTransactionManagement注解代替上面的配置內(nèi)容。
B、采用配置文件方式 
之前的sso是基于配置的方式,配置代碼如下:

 
 
 
 
  1.       
  2.       
  3.   
  4.   
  5.       
  6.           
  7.           
  8.           
  9.           
  10.           
  11.           
  12.       
  13.   

 改造后的SpringBoot基于Java代碼:

 
 
 
 
  1.  @Aspect
  2. @Configuration
  3. public class TransactionAdviceConfig {
  4. /**
  5. * 指定切入點(diǎn)
  6. */
  7. private static final String AOP_POINTCUT_EXPRESSION = "execution(public * com.creditease.permission.service.impl.*Impl.*(..))";
  8. @Resource
  9. DruidDataSource dataSource;
  10. /**
  11. * 指定處理事務(wù)的PlatformTransactionManager
  12. * @return
  13. */
  14. @Bean
  15. public DataSourceTransactionManager transactionManager() {
  16. return new DataSourceTransactionManager(dataSource);
  17. }
  18. /**
  19. * 指定切入點(diǎn)處理邏輯,執(zhí)行事務(wù)
  20. * @return
  21. */
  22. @Bean
  23. public TransactionInterceptor txAdvice() {
  24. DefaultTransactionAttribute txAttrRequired = new DefaultTransactionAttribute();
  25. txAttrRequired.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
  26. DefaultTransactionAttribute txAttrRequiredReadonly = new DefaultTransactionAttribute();
  27. txAttrRequiredReadonly.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
  28. txAttrRequiredReadonly.setReadOnly(true);
  29. NameMatchTransactionAttributeSource source = new NameMatchTransactionAttributeSource();
  30. source.addTransactionalMethod("query*", txAttrRequiredReadonly);
  31. source.addTransactionalMethod("find*", txAttrRequiredReadonly);
  32. source.addTransactionalMethod("save*", txAttrRequired);
  33. source.addTransactionalMethod("delete*", txAttrRequired);
  34. source.addTransactionalMethod("add*", txAttrRequired);
  35. source.addTransactionalMethod("modify*", txAttrRequired);
  36. return new TransactionInterceptor(transactionManager(), source);
  37. }
  38. /**
  39. * Advisor組裝配置,將Advice的代碼邏輯注入到Pointcut位置
  40. * @return
  41. */
  42. @Bean
  43. public Advisor txAdviceAdvisor() {
  44. AspectJExpressionPointcut pointcut = new AspectJExpressionPointcut();
  45. pointcut.setExpression(AOP_POINTCUT_EXPRESSION);
  46. return new DefaultPointcutAdvisor(pointcut, txAdvice());
  47. }
5)全局異常處理

一般編碼時(shí)有異常我們都會try-catch捕獲異常,有時(shí)為了區(qū)分不同的異常還會一次catch多個(gè)異常,大量的try-catch語句,這樣使得代碼也不夠優(yōu)雅;
一個(gè)相同的異常處理寫多次代碼也比較冗余,所以引入全局的異常處理非常必要。
改造前的異常處理配置文件:

 
 
 
 
  1.         
  2.             
  3.                 /permission/noSecurity
  4.             
  5.         
  6.  

使用SimpleMappingExceptionResolver類處理異常,設(shè)置自定義異常類型NopermissionException,以及異常發(fā)生后的請求路徑/permission/noSecurity。

SpringBoot中采用@RestControllerAdvice或者@ControllerAdvice設(shè)置全局異常類。這兩者區(qū)別類似于@Controller和@RestController注解。
SSO中定義了三種全局的異常處理:普通的Exception處理;自定的NopermissionException異常和參數(shù)校驗(yàn)異常。

全局異常處理代碼如下:

 
 
 
 
  1. @Configuration
  2. @Slf4j
  3. @RestControllerAdvice
  4. public class GlobalExceptionConfig {
  5. //無權(quán)限處理
  6. @ExceptionHandler(value = {NopermissionException.class})
  7. public void noPermissionExceptionHandler(HttpServletRequest request, Exception ex, HttpServletResponse response, @Value("${sso.server.prefix}") String domain) throws IOException {
  8. printLog(request,ex);
  9. response.sendRedirect("跳轉(zhuǎn)到無權(quán)限頁面地址");
  10. }
  11. //參數(shù)校驗(yàn)處理
  12. @ExceptionHandler(value = {BindException.class})
  13. public ResultBody BindExceptionHandler(BindException bindException){
  14. List errors = bindException.getBindingResult().getAllErrors();
  15. //這個(gè)ResultBody是一個(gè)返回結(jié)果對象,這里需要返回json,里面包含了狀態(tài)碼和提示信息
  16. return ResultBody.buildFailureResult(errors.get(0).getDefaultMessage());
  17. }
  18. //所有未捕獲的異常處理邏輯
  19. @ExceptionHandler(value = {Exception.class})
  20. public ResultBody exceptionHandler(HttpServletRequest request,Exception ex){
  21. printLog(request,ex);
  22. return ResultBody.buildExceptionResult();
  23. }
  24. //將請求參數(shù)和異常打印出來,結(jié)合@slf4j注解
  25. public void printLog(HttpServletRequest request,Exception ex){
  26. String parameters = JsonHelper.toString(request.getParameterMap());
  27. log.error("url>>>:{},params>>>:{} ,printLog>>>:{}",request.getRequestURL(),parameters,ex);
  28. }
  29. }

@RestControllerAdvice結(jié)合@Validation,可以對Bean進(jìn)行校驗(yàn),校驗(yàn)不通過會拋出BindException異常。通過注解可以少寫if-else代碼,判斷請求的接口參數(shù)是否為空,提高代碼的美觀性。例如:

 
 
 
 
  1.  //常規(guī)做法
  2.     if(StringUtils.isEmpty(ssoSystem.getSysCode())
  3. //SSO做法
  4. //在Controller請求方法上添加@Valid注解
  5. @RequestMapping(value = "/add", method = RequestMethod.POST)
  6. public ResultBody add(@Valid @RequestBody SsoSystem ssoSystem) {
  7. }
  8. //在需要處理的SsoSystem Bean的屬性上加@NotNull注解
  9. @NotNull(message = "系統(tǒng)編號不能為空")
  10. private String sysCode;

 當(dāng)sysCode傳入?yún)?shù)為空時(shí),就會拋出BindException被全局的異常處理類,捕獲處理返回json格式的參數(shù):

 
 
 
 
  1. {
  2.     "resultCode":2,
  3.     "resultMsg":"系統(tǒng)編號不能為空",
  4.     "resultData":null
  5. }

1.3 注意事項(xiàng)

1.3.1 內(nèi)置tomcat版本太高引發(fā)的問題 

SpringBoot1.5默認(rèn)使用內(nèi)嵌tomcat8.5版本,而原來SpringMVC的SSO部署在tomcat7上。tomcat的升級對這次改造影響最明顯的就是cookie。tomcat8后采用的cookie校驗(yàn)協(xié)議是Rfc6265CookieProcessor。該協(xié)議要求domain的命名必須遵循以下規(guī)則:

  • 必須是1-9、a-z、A-Z、. 、- 這幾個(gè)字符組成。
  • 必須是數(shù)字或字母開頭 (之前是以.creditease.corp 會報(bào)錯(cuò)tomcat cookie domain validation異常,最后改成了 creditease.corp)。
  • 必須是數(shù)字或字母結(jié)尾。

二、前后端分離
2.1 解決跨域問題

由于是兩個(gè)不同的應(yīng)用,必然會有兩個(gè)不同的端口。不同的端口就會有跨域問題,SSO采用的方式是通過nginx區(qū)分來自前后端的請求,反向代理請求對應(yīng)到不同的服務(wù)去。

  • sso.creditease.com對應(yīng)的是后端的應(yīng)用服務(wù)。
  • sso.creditease.com/web對應(yīng)的是前端的靜態(tài)資源應(yīng)用服務(wù)。

2.2 方便聯(lián)調(diào)效率,引入swagger 

swagger是后端接口展示的插件,通過修改攔截器代碼,mock登錄對象免登錄,直接訪問接口進(jìn)行前后端的調(diào)試。在swagger插件上可以看到具體接口請求路徑和參數(shù)、參數(shù)是否必須、返回值、接口統(tǒng)計(jì)信息等。

  • 接口統(tǒng)計(jì)信息
  • 請求參數(shù)和路徑

  • 返回值

2.3 跳轉(zhuǎn)接口修改

之前是通過SpringMvc的modeAndview方式跳轉(zhuǎn)的,現(xiàn)在做了兩種處理:

  • 改成restful接口的形式,前端控制跳轉(zhuǎn)然后直接獲取數(shù)據(jù)。  
  • 直接通過response.sendRedirect跳轉(zhuǎn)頁面。

 注意:老代碼跳轉(zhuǎn)采用的是通過SpringMvc在return的頁面路徑前加redirect的形式,如:return "redirect:index",這樣默認(rèn)會在return的URL后加jessionID。

2.4 靜態(tài)資源地址變更可能引發(fā)的問題 

特別需要注意代碼中的相關(guān)校驗(yàn)路徑的地方。比如在這次改造過程中路徑修改會影響以下幾個(gè)方面。

  • 菜單權(quán)限校驗(yàn)的時(shí)候,之前人、角色和路徑已經(jīng)綁定了,修改菜單訪問路徑會導(dǎo)致沒權(quán)限。
  • 掃碼登錄的接口判斷了refer來源,修改路徑會導(dǎo)致請求失敗。
  • 之前的sso-dome工程引用了靜態(tài)資源,修改路徑會報(bào)404。

【本文是專欄機(jī)構(gòu)宜信技術(shù)學(xué)院的原創(chuàng)文章,微信公眾號“宜信技術(shù)學(xué)院( id: CE_TECH)”】


文章標(biāo)題:一個(gè)項(xiàng)目的SpringCloud微服務(wù)改造過程
網(wǎng)頁網(wǎng)址:http://www.dlmjj.cn/article/cdeodcs.html