前言

本系统技术栈用到了Dubbo、Zookeeper、SpringBoot、Oauth2、Swagger、Nginx,项目刚开始起步,没完成一个大功能都会专门写一篇博文来记录技术细节以及遇到的技术难点,如项目中有哪些设计或者架构不太正确的地方,请大家在留言区中提出,互相学习~

光学习理论源码不动手实践是不得行的,阅读底层源码能力上来了,编码工程能力也要齐头并进!!

正文

1. 项目工程目录介绍

先声明下版本:

SpringBoot: 2.1.14.RELEASE
Dubbo: 2.6.2
Zookeeper: 3.4.6
OAuth2: 2.3.5
Swagger2: 2.9.2
在这里插入图片描述
项目刚起步,模块也比较简单明了,api模块定义了服务的接口定义,core模块定义了需要用到的pojo、model、dto以及公共组件、工具类等。gateway表示的是网关服务,外部访问系统统一走网关。oauth服务用于提供基于oauth2的认证和授权服务,所有走网关的接口请求都需要经过oauth2服务的认证、授权。order和product服务就是写业务服务的模块。

关于如何创建子模块,通过右键dubboproject工程——>New——>Module,然后选择maven
在这里插入图片描述
比如此处我们需要新建一个backend模块。
在这里插入图片描述
此时,backend服务已经创建成功了。
在这里插入图片描述
可以看到backend已经导入了父pom.xml引入的相关依赖了
在这里插入图片描述

看下父pom.xml的配置内容:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><packaging>pom</packaging><!-- 子模块 --><modules><module>product</module><module>gateway</module><module>order</module><module>core</module><module>api</module><module>oauth</module></modules><parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.1.14.RELEASE</version><relativePath/> <!-- lookup parent from repository --></parent><groupId>com.bruis</groupId><artifactId>dubboproject</artifactId><version>0.0.1-SNAPSHOT</version><name>dubboproject</name><description>dubboproject</description><properties><java.version>1.8</java.version></properties><dependencies>  <!-- redis依赖 --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis</artifactId></dependency><!-- 如果在properties中配置了pool,则需要引入这个依赖 --><!--<dependency><groupId>org.apache.commons</groupId><artifactId>commons-pool2</artifactId></dependency>--><dependency><groupId>io.springfox</groupId><artifactId>springfox-swagger2</artifactId><version>2.9.2</version></dependency><!-- swagger ui  --><dependency><groupId>io.springfox</groupId><artifactId>springfox-swagger-ui</artifactId><version>2.9.2</version></dependency><!-- https://mvnrepository.com/artifact/com.alibaba/fastjson --><dependency><groupId>com.alibaba</groupId><artifactId>fastjson</artifactId><version>1.2.68</version></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-security</artifactId></dependency><dependency><groupId>org.springframework.security.oauth</groupId><artifactId>spring-security-oauth2</artifactId><version>2.3.5.RELEASE</version></dependency><dependency><groupId>org.springframework.security</groupId><artifactId>spring-security-jwt</artifactId><version>1.1.0.RELEASE</version></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency><!-- Dubbo --><dependency><groupId>com.alibaba.boot</groupId><artifactId>dubbo-spring-boot-starter</artifactId><version>0.2.0</version></dependency><!-- Zookeeper --><dependency><groupId>org.apache.zookeeper</groupId><artifactId>zookeeper</artifactId><version>3.4.6</version><type>pom</type></dependency><!-- Web --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency></dependencies><build><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId></plugin></plugins></build></project>

2. 搭建oauth服务,提供OAuth2的认证和授权功能

搭建oauth服务的目的是为了希望各个服务都是受保护的,只有通过合法的认证信息才能访问相关资源,所以这里借助SpringSecurity+OAuth2来搭建一个给各个服务发放访问令牌的认证服务器oauth服务。

由于网上已经有很多OAuth2相关知识内容的博客了,这里就不再赘述了。
在这里插入图片描述
(这里给读者提供了一个白嫖OAuth2的学习视频白嫖OAuth2学习视频)

2.1 配置WebSecurity类型的安全配置类

首先得配置一个WebSecurity类型的安全配置类,在oauth服务下的config包中,定义了WebSecurityConfig类,代码如下:

package com.bruis.oauth.config;import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.core.annotation.Order;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.oauth2.provider.error.OAuth2AccessDeniedHandler;/*** @author LuoHaiYang*/
@Order(2)
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {/*** 自定义用户服务类、用于用户名、密码校验、权限授权*/@Autowiredprivate UserDetailsService userDetailsService;@Overrideprotected void configure(AuthenticationManagerBuilder auth) throws Exception {auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder());}@Override@Beanpublic AuthenticationManager authenticationManagerBean() throws Exception {return super.authenticationManagerBean();}/*** 安全拦截机制* @param http* @throws Exception*/@Overrideprotected void configure(HttpSecurity http) throws Exception {http.csrf().disable().requestMatchers().anyRequest().and().authorizeRequests().antMatchers("/oauth/**").permitAll() //oauth下的所有方法,无须认证.and().exceptionHandling().accessDeniedHandler(new OAuth2AccessDeniedHandler());}/*** 密码加密策略* @return*/@Beanpublic PasswordEncoder passwordEncoder() {return new BCryptPasswordEncoder();}
}

2.2 配置认证服务器相关的安全配置类

紧接着就要配置认证服务器配置类:AuthorizationServerConfiguration,该类用于进行认证和授权。

package com.bruis.oauth.config;import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.http.HttpMethod;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.oauth2.config.annotation.configurers.ClientDetailsServiceConfigurer;
import org.springframework.security.oauth2.config.annotation.web.configuration.AuthorizationServerConfigurerAdapter;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableAuthorizationServer;
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerEndpointsConfigurer;
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerSecurityConfigurer;
import org.springframework.security.oauth2.provider.token.DefaultTokenServices;
import org.springframework.security.oauth2.provider.token.ResourceServerTokenServices;
import org.springframework.security.oauth2.provider.token.TokenStore;
import org.springframework.security.oauth2.provider.token.store.JwtAccessTokenConverter;
import org.springframework.security.oauth2.provider.token.store.JwtTokenStore;
import org.springframework.security.oauth2.provider.token.store.redis.RedisTokenStore;import java.util.UUID;/*** @author LuoHaiYang** 开启授权服务器**/
@Configuration
@EnableAuthorizationServer
public class AuthorizationServerConfiguration extends AuthorizationServerConfigurerAdapter {/*** 设置jwt加密key*/private static final String JWT_SIGNING_KEY = "jwt_MC43A6m0Xt9jUIV";/*** 认证方式*/@Autowiredprivate AuthenticationManager authenticationManager;/*** 自定义用户服务*/@Autowiredprivate UserDetailsService userDetailsService;@Autowiredprivate PasswordEncoder passwordEncoder;@Autowiredprivate RedisConnectionFactory redisConnectionFactory;/*** 配置客户端对应授权方式及客户端密码* 当前使用内存模式** withClient + secret需要进行base64为加密:** 明文:bruis:123456    BASE64:**/@Overridepublic void configure(ClientDetailsServiceConfigurer clients) throws Exception {clients.inMemory().withClient("bruis").secret(passwordEncoder.encode("123456")).authorizedGrantTypes("password", "refresh_token").scopes("all");}@Overridepublic void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {endpoints.tokenStore(tokenStore()).authenticationManager(authenticationManager).accessTokenConverter(accessTokenConverter()).allowedTokenEndpointRequestMethods(HttpMethod.GET, HttpMethod.POST)  //支持GET  POST  请求获取token.userDetailsService(userDetailsService) //必须注入userDetailsService否则根据refresh_token无法加载用户信息
//                .exceptionTranslator(customWebResponseExceptionTranslator).reuseRefreshTokens(true);  //开启刷新token}/*** 认证服务器的安全配置** @param security* @throws Exception*/@Overridepublic void configure(AuthorizationServerSecurityConfigurer security) throws Exception {security.tokenKeyAccess("permitAll()").checkTokenAccess("isAuthenticated()") //isAuthenticated():排除anonymous   isFullyAuthenticated():排除anonymous以及remember-me.allowFormAuthenticationForClients();  //允许表单认证}/*** jwt令牌增强,添加加密key*/@Beanpublic JwtAccessTokenConverter accessTokenConverter() {JwtAccessTokenConverter converter = new JwtAccessTokenConverter();converter.setSigningKey(JWT_SIGNING_KEY);return converter;}/*** 使用JWT存储令牌信息* @return*/@Beanpublic TokenStore tokenStore() {RedisTokenStore redisTokenStore = new RedisTokenStore(redisConnectionFactory);// 解决每次生成的 token都一样的问题redisTokenStore.setAuthenticationKeyGenerator(oAuth2Authentication -> UUID.randomUUID().toString());return redisTokenStore;}/*** token认证服务*/@Beanpublic ResourceServerTokenServices tokenService() {// 授权服务和资源服务在统一项目内,可以使用本地认证方式,如果再不同工程,需要使用远程认证方式DefaultTokenServices defaultTokenServices = new DefaultTokenServices();defaultTokenServices.setTokenStore(tokenStore());defaultTokenServices.setSupportRefreshToken(true);return defaultTokenServices;}}

2.3 配置资源服务器相关的安全配置类

配置一个资源服务器的安全配置类。

package com.bruis.oauth.config;import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableResourceServer;
import org.springframework.security.oauth2.config.annotation.web.configuration.ResourceServerConfigurerAdapter;
import org.springframework.security.oauth2.config.annotation.web.configurers.ResourceServerSecurityConfigurer;
import org.springframework.security.oauth2.provider.token.ResourceServerTokenServices;/*** @author LuoHaiYang** 资源服务器配置**/
@Configuration
@EnableResourceServer
public class ResourceServerConfiguration extends ResourceServerConfigurerAdapter {private static final String RESOURCE_ID = "ALL";@Autowiredprivate ResourceServerTokenServices tokenServices;/*** 验证令牌配置* RESOURCE_ID 必须和授权服务器中保持一致* @param config*/@Overridepublic void configure(ResourceServerSecurityConfigurer config) {config.resourceId(RESOURCE_ID).tokenServices(tokenServices).stateless(true);}@Overridepublic void configure(HttpSecurity http) throws Exception {http.authorizeRequests().antMatchers("/users/**").authenticated() //配置users访问控制,必须认证过后才可以访问.antMatchers("/test/**").permitAll() //配置test无须认证,可以匿名访问.antMatchers("/webjars/**", "/resources/**", "/swagger-ui.html", "/swagger-resources/**", "/v2/api-docs", "index.html").permitAll().anyRequest().authenticated();}}

2.4 配置Swagger整合OAuth2的配置类

由于Swagger整合OAuth2时,由于也需要进行认证操作,所以需要配置一下两个类:SwaggerAutoConfiguration和Swagger2Config

package com.bruis.oauth.config;import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;/*** @author LuoHaiYang*/
@Configuration
public class SwaggerAutoConfiguration extends WebMvcConfigurerAdapter {/*** 因为swagger-ui.html 是在springfox-swagger-ui.jar里的,* 修改了路径后,Spring Boot不会自动把/swagger-ui.html这个路径映射到对应的目录META-INF/resources/下面,* 所以需要修改springboot配置类,为swagger建立新的静态文件路径映射就可以了* @param registry*/@Overridepublic void addResourceHandlers(ResourceHandlerRegistry registry) {registry.addResourceHandler("swagger-ui.html").addResourceLocations("classpath:/META-INF/resources/");registry.addResourceHandler("/webjars/**").addResourceLocations("classpath:/META-INF/resources/webjars/");}}
package com.bruis.oauth;import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import springfox.documentation.builders.ApiInfoBuilder;
import springfox.documentation.builders.OAuthBuilder;
import springfox.documentation.builders.PathSelectors;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.service.*;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.annotations.EnableSwagger2;
import springfox.documentation.spi.service.contexts.SecurityContext;import java.util.Arrays;
import java.util.Collections;/*** @author LuoHaiYang*/
@Configuration
@EnableSwagger2
public class Swagger2Config {private static final String VERSION = "1.0";private static final String TITLE = "分布式电商授权服务接口文档";private static final String DESCRIPTION = "接口文档";private static final String BASEPACKAGE = "com.bruis.oauth.controller";private static final String SERVICE_URL = "http://localhost:8902";private static final String CLIENT_ID = "swagger";private static final String CLIENT_SECRET = "123456";private static final String GRANT_TYPE = "password";private static final String SCOPE = "test";@Beanpublic Docket createRestApi(){return new Docket(DocumentationType.SWAGGER_2).apiInfo(apiInfo())
//                .enable(true).select()// 所有ApiOperation注解的方法,生成接口文档//.apis(RequestHandlerSelectors.withMethodAnnotation(ApiOperation.class)).apis(RequestHandlerSelectors.basePackage(BASEPACKAGE)).paths(PathSelectors.any()).build().securitySchemes(Collections.singletonList(securityScheme())).securityContexts(Collections.singletonList(securityContext()));}private ApiInfo apiInfo() {return new ApiInfoBuilder().title(TITLE).description(DESCRIPTION).termsOfServiceUrl(SERVICE_URL).version(VERSION).build();}/*** 设置安全策略* @return*/private SecurityScheme securityScheme() {GrantType grantType = new ResourceOwnerPasswordCredentialsGrant("http://localhost:8902/oauth/token");return new OAuthBuilder().name("OAuth2").grantTypes(Collections.singletonList(grantType)).scopes(Arrays.asList(scopes())).build();}/*** 安全上下文* @return*/private SecurityContext securityContext() {return SecurityContext.builder().securityReferences(Collections.singletonList(new SecurityReference("OAuth2", scopes()))).forPaths(PathSelectors.any()).build();}private AuthorizationScope[] scopes() {return new AuthorizationScope[]{new AuthorizationScope("test", "")};}}

类在模块中的位置:
在这里插入图片描述
配置好相关安全配置类后,还需要定义一个校验用户名密码的类:

package com.bruis.oauth.impl;import com.alibaba.fastjson.JSON;
import com.bruis.common.model.dataObject.UserDTO;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;/*** @author LuoHaiYang*/
@Service(value = "userDetailsService")
public class UserServiceImpl implements UserDetailsService {@Autowiredprivate PasswordEncoder passwordEncoder;@Overridepublic UserDetails loadUserByUsername(String s) throws UsernameNotFoundException {// 这里需要写根据用户名查询用户逻辑。。。。。。UserDTO user = new UserDTO();user.setId(1);user.setUsername("admin");user.setPhone("188103956897");user.setStatus(6);UserDTO userDTO = new UserDTO();// 为了增强jwt令牌内容,可以将整个对象转json存放到username中userDTO.setUsername(JSON.toJSONString(user));userDTO.setAuthorities(AuthorityUtils.commaSeparatedStringToAuthorityList("ROLE_NORMAL,ROLE_MEDIUM, user:select"));userDTO.setPassword(passwordEncoder.encode("123"));return userDTO;}}

由于tokenStore使用的是RedisTokenStore,认证服务器生成的令牌将被存储到Redis中,所以需要在oauth配置中加入redis的配置。
oauth服务配置文件如下:

server.port=8902
spring.application.name=oauth-service
spring.redis.host=127.0.0.1
spring.redis.port=6379
swagger2.auth.clientId=hiauth_swagger2
swagger2.auth.clientSecret=123456
swagger2.auth.authorizationuri=http://localhost:8902/auth/authorize
swagger2.auth.tokenUri=http://localhost:8902/oauth/token
swagger2.auth.scopes=AUTU

需要注意的是,如果需要对接口进行权限拦截,需要在启动类中加入以下配置,否则不生效:
在这里插入图片描述

3. 搭建product和order服务

以product服务为例,配置文件如下:

server.port=8904
# redis
spring.redis.host=127.0.0.1
spring.redis.port=6379
# 连接池最大连接数
spring.redis.lettuce.pool.max-active=8
# 连接池最大阻塞等待时间
spring.redis.lettuce.pool.max-wait=8
# dubbo
dubbo.application.name=product
dubbo.protocol.port=20881
dubbo.registry.address=zookeeper://127.0.0.1:2181
dubbo.consumer.timeout=5000

启动类中引入@EnableDubbo注解
在这里插入图片描述

3.1 引入api服务的接口并实现

在product服务中,需要引入core和api的依赖,pom.xml相关配置如下:
在这里插入图片描述
则在serviceImpl包中,可以直接实现api服务中的ProductService接口:

package com.bruis.api.product.service.impl;import com.alibaba.dubbo.config.annotation.Service;
import com.bruis.api.service.ProductService;/*** @author LuoHaiYang*/
@Service
public class ProductServiceImpl implements ProductService {@Overridepublic String getProductName(Integer productId) {return "Dubbo: " + productId;}
}

需要注意的是,@Service注解使用的是dubbo包下的注解,并非Spring中的@Service。

order服务搭建过程和product相似,就不说明了。

4. 搭建gateway服务

下面详细说明下gateway服务模块
在这里插入图片描述

4.1 配置资源服务器配置类

config包中定义了资源服务配置,由于gateway属于资源服务器,所以需要ResourceServerConfigure配置资源服务器配置,使得gateway有能力去oauth服务中进行认证和授权。

package com.bruis.api.gateway.config;import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableResourceServer;
import org.springframework.security.oauth2.config.annotation.web.configuration.ResourceServerConfigurerAdapter;
import org.springframework.security.oauth2.config.annotation.web.configurers.ResourceServerSecurityConfigurer;
import org.springframework.security.oauth2.provider.token.store.redis.RedisTokenStore;/*** @author LuoHaiYang*/
@Configuration
@EnableResourceServer
public class ResourceServerConfigure extends ResourceServerConfigurerAdapter {@Autowiredprivate RedisConnectionFactory redisConnectionFactory;@Beanpublic RedisTokenStore tokenStore() {RedisTokenStore tokenStore = new RedisTokenStore(redisConnectionFactory);return tokenStore;}@Overridepublic void configure(HttpSecurity http) throws Exception {http.csrf().disable()//.requestMatchers().antMatchers("/**")//.and().authorizeRequests().antMatchers("/api/**").authenticated().antMatchers("/webjars/**", "/resources/**", "/swagger-ui.html", "/swagger-resources/**", "/v2/api-docs", "index.html").permitAll().anyRequest().authenticated();}@Overridepublic void configure(ResourceServerSecurityConfigurer resources) throws Exception {resources.tokenStore(tokenStore());}
}

4.2 引入Swagger2相关配置类

引入Swagger需要配置SwaggerAutoConfiguration

package com.bruis.api.gateway.config;import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;/*** @author LuoHaiYang*/
@Configuration
public class SwaggerAutoConfiguration extends WebMvcConfigurerAdapter {/*** 因为swagger-ui.html 是在springfox-swagger-ui.jar里的,* 修改了路径后,Spring Boot不会自动把/swagger-ui.html这个路径映射到对应的目录META-INF/resources/下面,* 所以需要修改springboot配置类,为swagger建立新的静态文件路径映射就可以了* @param registry*/@Overridepublic void addResourceHandlers(ResourceHandlerRegistry registry) {registry.addResourceHandler("swagger-ui.html").addResourceLocations("classpath:/META-INF/resources/");registry.addResourceHandler("/webjars/**").addResourceLocations("classpath:/META-INF/resources/webjars/");}}

下面看下gateway服务的controller接口,目前就实现了OrderController和ProductController,属于Demo级别用于演示作用。

package com.bruis.api.gateway.controller;import com.alibaba.dubbo.config.annotation.Reference;
import com.bruis.api.service.OrderService;
import io.swagger.annotations.ApiOperation;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.*;/*** @author LuoHaiYang*/
@RestController
@RequestMapping("/order")
public class OrderController {// 需要调用order服务的OrderService@ReferenceOrderService orderService;@ApiOperation("根据产品名称获取订单号")@GetMapping("/getOrderId/{productName}")@PreAuthorize("hasAuthority('user:write')")public String getOrderId(@PathVariable("productName") String productName) {return orderService.getOrderId(productName);}}
package com.bruis.api.gateway.controller;import com.alibaba.dubbo.config.annotation.Reference;
import com.bruis.api.service.ProductService;
import io.swagger.annotations.ApiOperation;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;/*** @author LuoHaiYang*/
@RestController
@RequestMapping("/product")
public class ProductController {// 需要调用produc服务的ProductService@ReferenceProductService productService;@ApiOperation("根据产品编号取产品名称")@GetMapping("/getProductName/{productId}")//@PreAuthorize("hasAuthority('ROLE_MEDIUM')")@PreAuthorize("hasRole('ROLE_MEDIUM2')")public String getProductName(@PathVariable("productId") Integer productId) {return productService.getProductName(productId);}
}

在启动类中引入@EnableDubbo来开启Dubbo的使用

package com.bruis.api.gateway;import com.alibaba.dubbo.config.spring.context.annotation.EnableDubbo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import springfox.documentation.swagger2.annotations.EnableSwagger2;/*** @author LuoHaiYang*/
@SpringBootApplication
// 开启dubbo
@EnableDubbo
// 开启Swagger2
@EnableSwagger2
// 开启权限控制
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class GatewayApplication {public static void main(String[] args) {SpringApplication.run(GatewayApplication.class, args);}
}

gateway服务配置文件比较简单,如下:

server.port=8901
spring.redis.host=127.0.0.1
spring.redis.port=6379
dubbo.application.name=gateway
dubbo.protocol.port=20880
dubbo.protocol.name=dubbo
dubbo.registry.address=zookeeper://127.0.0.1:2181

4.3 Swagger OAuth2 跨域认证

由于引入的Swagger 也需要OAuth2进行认证,同时存在了跨域的认证,所以不进行处理的话会报错。
先看下Swagger2Config配置类内容

package com.bruis.api.gateway;import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import springfox.documentation.builders.ApiInfoBuilder;
import springfox.documentation.builders.OAuthBuilder;
import springfox.documentation.builders.PathSelectors;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.service.*;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spi.service.contexts.SecurityContext;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.annotations.EnableSwagger2;import java.util.Arrays;
import java.util.Collections;/*** @author LuoHaiYang*/
@Configuration
@EnableSwagger2
public class Swagger2Config {private static final String VERSION = "1.0";private static final String TITLE = "分布式电商网关服务接口文档";private static final String DESCRIPTION = "接口文档";private static final String BASEPACKAGE = "com.bruis.api.gateway.controller";private static final String SERVICE_URL = "http://localhost:8902";@Beanpublic Docket createRestApi(){return new Docket(DocumentationType.SWAGGER_2).apiInfo(apiInfo()).select().apis(RequestHandlerSelectors.basePackage(BASEPACKAGE)).paths(PathSelectors.any()).build().securitySchemes(Collections.singletonList(securityScheme())).securityContexts(Collections.singletonList(securityContext()));}private ApiInfo apiInfo() {return new ApiInfoBuilder().title(TITLE).description(DESCRIPTION).termsOfServiceUrl(SERVICE_URL).version(VERSION).build();}/*** 设置安全策略* @return*/private SecurityScheme securityScheme() {GrantType grantType = new ResourceOwnerPasswordCredentialsGrant("http://dubbo-swagger.cn");//GrantType grantType = new ResourceOwnerPasswordCredentialsGrant("http://localhost:8902/oauth/token");return new OAuthBuilder().name("OAuth2").grantTypes(Collections.singletonList(grantType)).scopes(Arrays.asList(scopes())).build();}/*** 安全上下文* @return*/private SecurityContext securityContext() {return SecurityContext.builder().securityReferences(Collections.singletonList(new SecurityReference("OAuth2", scopes()))).forPaths(PathSelectors.any()).build();}private AuthorizationScope[] scopes() {return new AuthorizationScope[]{new AuthorizationScope("test", "")};}}

由于oauth服务端口是8902,gateway服务端口是8901,所以gateway进行认证请求访问时,访问的是http://localhost:8902/oauth/token需要进行跨域请求,所以需要处理掉跨域问题,先看下同域情况下即oauth服务本身的Swagger OAuth2认证以及gateway没有处理跨域时的Swagger OAuth2跨域认证。

启动zk、启动redis、启动order服务、product服务、oauth服务以及gateway服务。

在这里插入图片描述

5. 效果展示

5.1 oauth服务本身的Swagger OAuth2认证

访问http://localhost:8902/swagger-ui.html

在这里插入图片描述
在这里插入图片描述
需要注意到的是Token URL是:http://localhost:8902/oauth/token。

username和password是在UserServiceImpl中定义的,账号密码为:admin/123
而client_id和client_secret是在AuthorizationServerConfiguration配置类中定义的:分别为 bruis/123456

认证后结果如下:
在这里插入图片描述
在这里插入图片描述

5.2 gateway服务的Swagger OAuth2跨域认证

没有解决gateway跨域认证时,去进行认证,效果如下:
在这里插入图片描述
所以有两种方案解决:

  1. 在oauth服务端配置跨域请求;
  2. 通过nginx代理解决跨域请求;

5.3 通过nginx来解决跨域

本人通过nginx跨域来解决的。
下面看下本人nginx的配置内容:

server {
listen 80;
autoindex on;
## server_name需要修改为你的服务地址
server_name dubbo-swagger.cn;
access_log /usr/local/nginx/logs/access.log combined;
index index.html index.htm index.jsp index.php;
if ( $query_string ~* ".*[\;'\<\>].*" ){return 404;}location / {proxy_pass http://127.0.0.1:8902/oauth/token;if ($request_method = 'OPTIONS') {add_header 'Access-Control-Allow-Origin' '*';add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range,Authorization';add_header 'Access-Control-Max-Age' 1728000;add_header 'Content-Type' 'text/plain; charset=utf-8';add_header 'Content-Length' 0;return 204;}if ($request_method = 'POST') {add_header 'Access-Control-Allow-Origin' '*';add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range,Authorization';add_header 'Access-Control-Expose-Headers' 'Content-Length,Content-Range';}if ($request_method = 'GET') {add_header 'Access-Control-Allow-Origin' '*';add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range,Authorization';add_header 'Access-Control-Expose-Headers' 'Content-Length,Content-Range';}}}

该配置文件的意思就是将所有访问http://dubbo-swagger.cn路径的请求都代理到http://localhost:8902/oauth/token路径,注意该文件是在nginx.conf同路径下的vhost_swagger目录中,需要在nginx.conf中引入以下配置:
在这里插入图片描述
配置好nginx后,还需要在 hosts文件中加入如下配置:

127.0.0.1 dubbo-swagger.cn

启动nginx!

然后在gateway服务中,修改类Swagger2Config的配置如下:
在这里插入图片描述
然后重启gateway。

值得注意的是,此时swagger的授权地址已经变成了http://dubbo-swagger.cn
在这里插入图片描述
终于,gateway服务认证成功了。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
由于没有接口权限,所以这里报403,access_denied。

下面用postman来展示下通过token来访问接口。

先以密码模式进行认证获取token。
在这里插入图片描述
除了这几个参数外,我们需要在请求头中配置Authorization信息,否则请求将返回401:
在这里插入图片描述
值为Basic加空格加client_id:client_secret(就是在FebsAuthorizationServerConfigure类configure(ClientDetailsServiceConfigurer clients)方法中定义的client和secret)经过base64加密后的值(可以使用http://tool.oschina.net/encrypt?type=3)
在这里插入图片描述
然后携带token去访问gateway服务接口
在这里插入图片描述
重新调整下接口权限,重新访问接口
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
通过postman请求结果如下:
在这里插入图片描述
搞定!

每个人都有一颗白嫖的心,
在这里插入图片描述
下面贴上github源码地址,觉得博主写的不错,关注、点赞、star三连。。。

https://github.com/coderbruis/dubboproject

后续博主会继续完善项目…

查看全文
如若内容造成侵权/违法违规/事实不符,请联系编程学习网邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!

相关文章

  1. java操作数据库,CLOB类型,处理 ORA-01704: 文字字符串太长 的问题

    String str = "很长的字符串"; StringBuffer sb=new StringBuffer();int len=String.valueOf(mapValue).length(); if(len>2000){int s=0;int el=1000;while(s<len){if(s>0){sb.append("||");}String subVal=String.valueOf(mapValue).substring(…...

    2024/4/15 17:58:07
  2. 攻防世界 后面持续更新

    XCTF 4th-CyberEarth 打开之后乱点,点到报表中心的时候连接到一个新网址 连接到id=1这里 抓包爆破得到flagHCTF 2018 审查源码发现有一个source.php 打开 有一个hint.php打开之后是 flag not here, and flag in ffffllllaaaagggg 在代码审核,关键代码检查是否为空,是不是字符…...

    2024/4/15 3:45:49
  3. 在关键字有序序列中采用二分查找法查找关键字为给定值k的元素,输出查找结果。 要求:有序序列和给定值k都从键盘输入。

    #include "stdio.h" #include<iostream>//蓝多多算法实验七 #define MAX 100 using namespace std; int Binary_Search(const int *array, int n, int key) {int low = 1;int high = n;int mid;while(low <= high){if (array[0] < array[1]){mid = (low …...

    2024/4/15 3:45:48
  4. for循环语句的逻辑剖析—JavaScript

    for 语句 : 整体性特别强,语法特别简练 (所以相对于其他循环语句开发中更推荐使用) 书写格式 : for ( 1.计数器的声明; 2.循环执行条件判定;3.计算器的计算 ){ // 循环执行代码块; } 简单示例 for(var count = 0; count < 10 ; count++ ){// {} => 专心写需要重复执…...

    2024/5/7 3:34:11
  5. 移动Ad Hoc网络路由协议汇总

    移动Ad Hoc网络路由协议汇总: 我们人与人之间的交流需要语言作为一种媒介,同理,节点之间的通信也需要一种语言,这种语言被称为协议,在同一个网络中的所有节点,采用相同的语言。 在Ad Hoc网络中的路由协议主要分为三大类: (1)平面路由协议 (2)分层路由协议 (3)基于…...

    2024/4/15 3:45:46
  6. JAVA泛型机制和集合框架机制

    目录(一)泛型(1.1)泛型的声明(1.2)使用泛型声明对象(1.3)通配符(二)链表(2.1)LinkedList泛型类(2.2)常用方法(2.3)遍历链表(2.4)排序与查找(2.5)洗牌与旋转(三)堆栈(四)散列映射(4.1)HashMap泛型类(4.2)常用方法(4.3)遍历散列映射(4.4)基于散列…...

    2024/5/7 5:34:22
  7. 零、爬虫基础(通用爬虫)

    一、response响应参数 1、response六个参数 response.read().decode().encode() # decode()解码 encode()编码 response.readline()#读取一行 response.readlines()# 读取所有,是二进制 response.geturl()#请求的路由 response.getheaders()#获取响应头 response.getcode()#2…...

    2024/5/7 6:49:51
  8. Scrapy初窥

    Scrapy入门项目1 https://github.com/scrapy/quotesbot Scrapy入门项目2 https://github.com/scrapy/dirbot Scrapy中文文档 http://scrapy-chs.readthedocs.io/zh_CN/latest/ Scrapy初窥 https://scrapy-chs.readthedocs.io/zh_CN/latest/intro/overview.html#intro-overview...

    2024/4/22 18:18:51
  9. AI票据/信用报告/卡证类OCR识别落地产品-深源恒际科技有限公司

    ...

    2024/4/15 3:45:42
  10. Art of Pull Requests(翻译)

    本文链接: https://blog.openacid.com/culture/pr/ 原文: Art of Pull Requests正如我之前写的, 我们是一个远程团队,团队成员遍布世界各地。 这意味着code reviews 和 pull requests必须远程完成。 最近,我们团队的一位成员提出了这样的宣言:作为 PR writer 我会:保持PR够小…...

    2024/4/25 12:15:05
  11. axios请求获取到返回值

    axios请求获取到返回值 最近在学习Vue,碰到一个问题就是需要从后端获取到某个返回值之后再运行后面的代码。 一般调用axios接口都是这样的格式。 this.$axios.post(api/xxxx/xxxxx, this.$qs.stringify({username: qwerqw,password: 123456 })).then(res => {...... }).cat…...

    2024/5/6 21:35:42
  12. Spring的自我修养之五

    Spring+Mybatis ①pom.xml配置导入Spring和mybatis整合包spring和第三方框架整合的开启项目依赖架构图②在applicationContext.xml中配置导入数据源,用于applicationContext.xml中数据源配置...

    2024/5/6 20:32:31
  13. 把本地项目上传到码云的整个过程(图文详解)超级超级详细!!!!!!

    这里写自定义目录标题第一步第二步第三步第四步第五步第六步第七步第八步错误 第一步 我们现在码云的个人首页点击创建仓库并根据要求填写相关信息根据图片所示 跟据自己内容可以进行添加 可以选择是公开还是私有的 并点击创建第二步 我们把创建仓库产生的README.en.md和READM…...

    2024/4/20 9:11:33
  14. “十步天才型思维理解”方法

    第一步:学习Java方法的目的 在计算机的编程中,随着程序员们编写的代码越来越多,代码的维护变得也越来越差。为了解决这一问题设计者们提出了方法的处理机制,把一行或多行代码封装起来,给它们起一个特定的名称,在需要使用这些特定的代码片段时,就根据所给定的特定名称进行…...

    2024/4/19 5:18:27
  15. ctf.show web write up

    web签到题 直接审查源码,就有一个base64加密的flag,直接解码就行 ctf.show_web2 进去之后是一个登陆框 试一下万能密码 admin ‘or 1=1#发现成功了 试了之后发现一共有三个字段 根据回显点再来测试查询数据库和表字段 数据库 username=admin&password=’ union select 1,…...

    2024/4/20 2:42:27
  16. win7系统卸载补丁包更新的解决方法【系统天地】

    无论谁在使用电脑的时候都可能会发现无法卸载补丁包更新的问题,无法卸载补丁包更新让用户们很苦恼,这是怎么回事呢,无法卸载补丁包更新有什么简便的处理方式呢,下面就给大家讲解一下无法卸载补丁包更新的快速处理方法: 如果安装某个更新后,某个程序无法正常工作或系统运行…...

    2024/4/15 3:45:30
  17. CentOS 8 Broadcom无线网卡配置

    查看网卡型号等硬件信息:lspci | grep -i wireless我的网卡信息如下:2:00.0 Network controller: Broadcom Inc. and subsidiaries BCM4352 802.11ac Wireless Network Adapter (rev 03)下载并安装驱动:dnf install https://download1.rpmfusion.org/free/el/rpmfusion-free…...

    2024/4/15 3:45:38
  18. Linux服务器下Matlab无权限安装指南 (转载)

    参考这位大佬的博客:https://blog.csdn.net/sinat_27318881/article/details/83184497注意点:1 如果使用vim编辑不好用,就是用gedit编辑器(有警告忽略就行了)2 注意这两步,因为使用mv(移动),所以说MATLABR2017b_Linux_Crack_20190822_213304中没有license_standalone.l…...

    2024/4/18 7:44:04
  19. 写代码超好用网站

    原文链接:https://blog.csdn.net/qq_43901693/article/details/104750730 总结了 150 余个神奇网站,你不来瞅瞅吗? 写代码的网址 程序员在线工具:https://tool.lu/ 菜鸟工具:https://c.runoob.com/ toolfk:https://www.toolfk.com/...

    2024/4/19 17:19:27
  20. CentOS7配置网卡为静态IP

    vim /etc/sysconfig/network-scripts/ifcfg-ens33TYPE=Ethernet # 网卡类型:为以太网 PROXY_METHOD=none # 代理方式:关闭状态 BROWSER_ONLY=no # 只是浏览器:否 BOOTPROTO=dhcp # 网卡的引导协议:DHCP[中文名称…...

    2024/5/3 5:55:25

最新文章

  1. 软件工程案例学习-图书管理系统-面向对象方法

    文档编号&#xff1a;LMS_1 版 本 号&#xff1a;V1.0 ** ** ** ** ** ** 文档名称&#xff1a;需求分析规格说明书 项目名称&#xff1a;图书管理系统 项目负责人&#xff1a;计敏 胡杰 ** ** …...

    2024/5/7 7:27:04
  2. 梯度消失和梯度爆炸的一些处理方法

    在这里是记录一下梯度消失或梯度爆炸的一些处理技巧。全当学习总结了如有错误还请留言&#xff0c;在此感激不尽。 权重和梯度的更新公式如下&#xff1a; w w − η ⋅ ∇ w w w - \eta \cdot \nabla w ww−η⋅∇w 个人通俗的理解梯度消失就是网络模型在反向求导的时候出…...

    2024/5/6 9:38:23
  3. 01背包问题 小明的背包

    2.小明的背包1 - 蓝桥云课 (lanqiao.cn) #include <bits/stdc.h> using namespace std; const int N1010;//开始写的105 开小了 样例过了但最后只过了很少一部分 int n,m; int v[N],w[N]; int f[N][N];int main() {cin>>n>>m;for(int i1;i<n;i){cin>&…...

    2024/5/5 8:41:06
  4. 蓝桥杯第十五届抱佛脚(十)贪心算法

    蓝桥杯第十五届抱佛脚&#xff08;十&#xff09;贪心算法 贪心算法基本概念 贪心算法是一种在算法设计中常用的方法&#xff0c;它在每一步选择中都采取在当前状态下最好或最优&#xff08;即最有利&#xff09;的选择&#xff0c;从而希望导致结果是最好或最优的算法。 贪…...

    2024/5/5 8:38:28
  5. 【外汇早评】美通胀数据走低,美元调整

    原标题:【外汇早评】美通胀数据走低,美元调整昨日美国方面公布了新一期的核心PCE物价指数数据,同比增长1.6%,低于前值和预期值的1.7%,距离美联储的通胀目标2%继续走低,通胀压力较低,且此前美国一季度GDP初值中的消费部分下滑明显,因此市场对美联储后续更可能降息的政策…...

    2024/5/7 5:50:09
  6. 【原油贵金属周评】原油多头拥挤,价格调整

    原标题:【原油贵金属周评】原油多头拥挤,价格调整本周国际劳动节,我们喜迎四天假期,但是整个金融市场确实流动性充沛,大事频发,各个商品波动剧烈。美国方面,在本周四凌晨公布5月份的利率决议和新闻发布会,维持联邦基金利率在2.25%-2.50%不变,符合市场预期。同时美联储…...

    2024/5/4 23:54:56
  7. 【外汇周评】靓丽非农不及疲软通胀影响

    原标题:【外汇周评】靓丽非农不及疲软通胀影响在刚结束的周五,美国方面公布了新一期的非农就业数据,大幅好于前值和预期,新增就业重新回到20万以上。具体数据: 美国4月非农就业人口变动 26.3万人,预期 19万人,前值 19.6万人。 美国4月失业率 3.6%,预期 3.8%,前值 3…...

    2024/5/4 23:54:56
  8. 【原油贵金属早评】库存继续增加,油价收跌

    原标题:【原油贵金属早评】库存继续增加,油价收跌周三清晨公布美国当周API原油库存数据,上周原油库存增加281万桶至4.692亿桶,增幅超过预期的74.4万桶。且有消息人士称,沙特阿美据悉将于6月向亚洲炼油厂额外出售更多原油,印度炼油商预计将每日获得至多20万桶的额外原油供…...

    2024/5/6 9:21:00
  9. 【外汇早评】日本央行会议纪要不改日元强势

    原标题:【外汇早评】日本央行会议纪要不改日元强势近两日日元大幅走强与近期市场风险情绪上升,避险资金回流日元有关,也与前一段时间的美日贸易谈判给日本缓冲期,日本方面对汇率问题也避免继续贬值有关。虽然今日早间日本央行公布的利率会议纪要仍然是支持宽松政策,但这符…...

    2024/5/4 23:54:56
  10. 【原油贵金属早评】欧佩克稳定市场,填补伊朗问题的影响

    原标题:【原油贵金属早评】欧佩克稳定市场,填补伊朗问题的影响近日伊朗局势升温,导致市场担忧影响原油供给,油价试图反弹。此时OPEC表态稳定市场。据消息人士透露,沙特6月石油出口料将低于700万桶/日,沙特已经收到石油消费国提出的6月份扩大出口的“适度要求”,沙特将满…...

    2024/5/4 23:55:05
  11. 【外汇早评】美欲与伊朗重谈协议

    原标题:【外汇早评】美欲与伊朗重谈协议美国对伊朗的制裁遭到伊朗的抗议,昨日伊朗方面提出将部分退出伊核协议。而此行为又遭到欧洲方面对伊朗的谴责和警告,伊朗外长昨日回应称,欧洲国家履行它们的义务,伊核协议就能保证存续。据传闻伊朗的导弹已经对准了以色列和美国的航…...

    2024/5/4 23:54:56
  12. 【原油贵金属早评】波动率飙升,市场情绪动荡

    原标题:【原油贵金属早评】波动率飙升,市场情绪动荡因中美贸易谈判不安情绪影响,金融市场各资产品种出现明显的波动。随着美国与中方开启第十一轮谈判之际,美国按照既定计划向中国2000亿商品征收25%的关税,市场情绪有所平复,已经开始接受这一事实。虽然波动率-恐慌指数VI…...

    2024/5/4 23:55:16
  13. 【原油贵金属周评】伊朗局势升温,黄金多头跃跃欲试

    原标题:【原油贵金属周评】伊朗局势升温,黄金多头跃跃欲试美国和伊朗的局势继续升温,市场风险情绪上升,避险黄金有向上突破阻力的迹象。原油方面稍显平稳,近期美国和OPEC加大供给及市场需求回落的影响,伊朗局势并未推升油价走强。近期中美贸易谈判摩擦再度升级,美国对中…...

    2024/5/4 23:54:56
  14. 【原油贵金属早评】市场情绪继续恶化,黄金上破

    原标题:【原油贵金属早评】市场情绪继续恶化,黄金上破周初中国针对于美国加征关税的进行的反制措施引发市场情绪的大幅波动,人民币汇率出现大幅的贬值动能,金融市场受到非常明显的冲击。尤其是波动率起来之后,对于股市的表现尤其不安。隔夜美国股市出现明显的下行走势,这…...

    2024/5/6 1:40:42
  15. 【外汇早评】美伊僵持,风险情绪继续升温

    原标题:【外汇早评】美伊僵持,风险情绪继续升温昨日沙特两艘油轮再次发生爆炸事件,导致波斯湾局势进一步恶化,市场担忧美伊可能会出现摩擦生火,避险品种获得支撑,黄金和日元大幅走强。美指受中美贸易问题影响而在低位震荡。继5月12日,四艘商船在阿联酋领海附近的阿曼湾、…...

    2024/5/4 23:54:56
  16. 【原油贵金属早评】贸易冲突导致需求低迷,油价弱势

    原标题:【原油贵金属早评】贸易冲突导致需求低迷,油价弱势近日虽然伊朗局势升温,中东地区几起油船被袭击事件影响,但油价并未走高,而是出于调整结构中。由于市场预期局势失控的可能性较低,而中美贸易问题导致的全球经济衰退风险更大,需求会持续低迷,因此油价调整压力较…...

    2024/5/4 23:55:17
  17. 氧生福地 玩美北湖(上)——为时光守候两千年

    原标题:氧生福地 玩美北湖(上)——为时光守候两千年一次说走就走的旅行,只有一张高铁票的距离~ 所以,湖南郴州,我来了~ 从广州南站出发,一个半小时就到达郴州西站了。在动车上,同时改票的南风兄和我居然被分到了一个车厢,所以一路非常愉快地聊了过来。 挺好,最起…...

    2024/5/4 23:55:06
  18. 氧生福地 玩美北湖(中)——永春梯田里的美与鲜

    原标题:氧生福地 玩美北湖(中)——永春梯田里的美与鲜一觉醒来,因为大家太爱“美”照,在柳毅山庄去寻找龙女而错过了早餐时间。近十点,向导坏坏还是带着饥肠辘辘的我们去吃郴州最富有盛名的“鱼头粉”。说这是“十二分推荐”,到郴州必吃的美食之一。 哇塞!那个味美香甜…...

    2024/5/4 23:54:56
  19. 氧生福地 玩美北湖(下)——奔跑吧骚年!

    原标题:氧生福地 玩美北湖(下)——奔跑吧骚年!让我们红尘做伴 活得潇潇洒洒 策马奔腾共享人世繁华 对酒当歌唱出心中喜悦 轰轰烈烈把握青春年华 让我们红尘做伴 活得潇潇洒洒 策马奔腾共享人世繁华 对酒当歌唱出心中喜悦 轰轰烈烈把握青春年华 啊……啊……啊 两…...

    2024/5/4 23:55:06
  20. 扒开伪装医用面膜,翻六倍价格宰客,小姐姐注意了!

    原标题:扒开伪装医用面膜,翻六倍价格宰客,小姐姐注意了!扒开伪装医用面膜,翻六倍价格宰客!当行业里的某一品项火爆了,就会有很多商家蹭热度,装逼忽悠,最近火爆朋友圈的医用面膜,被沾上了污点,到底怎么回事呢? “比普通面膜安全、效果好!痘痘、痘印、敏感肌都能用…...

    2024/5/5 8:13:33
  21. 「发现」铁皮石斛仙草之神奇功效用于医用面膜

    原标题:「发现」铁皮石斛仙草之神奇功效用于医用面膜丽彦妆铁皮石斛医用面膜|石斛多糖无菌修护补水贴19大优势: 1、铁皮石斛:自唐宋以来,一直被列为皇室贡品,铁皮石斛生于海拔1600米的悬崖峭壁之上,繁殖力差,产量极低,所以古代仅供皇室、贵族享用 2、铁皮石斛自古民间…...

    2024/5/4 23:55:16
  22. 丽彦妆\医用面膜\冷敷贴轻奢医学护肤引导者

    原标题:丽彦妆\医用面膜\冷敷贴轻奢医学护肤引导者【公司简介】 广州华彬企业隶属香港华彬集团有限公司,专注美业21年,其旗下品牌: 「圣茵美」私密荷尔蒙抗衰,产后修复 「圣仪轩」私密荷尔蒙抗衰,产后修复 「花茵莳」私密荷尔蒙抗衰,产后修复 「丽彦妆」专注医学护…...

    2024/5/4 23:54:58
  23. 广州械字号面膜生产厂家OEM/ODM4项须知!

    原标题:广州械字号面膜生产厂家OEM/ODM4项须知!广州械字号面膜生产厂家OEM/ODM流程及注意事项解读: 械字号医用面膜,其实在我国并没有严格的定义,通常我们说的医美面膜指的应该是一种「医用敷料」,也就是说,医用面膜其实算作「医疗器械」的一种,又称「医用冷敷贴」。 …...

    2024/5/6 21:42:42
  24. 械字号医用眼膜缓解用眼过度到底有无作用?

    原标题:械字号医用眼膜缓解用眼过度到底有无作用?医用眼膜/械字号眼膜/医用冷敷眼贴 凝胶层为亲水高分子材料,含70%以上的水分。体表皮肤温度传导到本产品的凝胶层,热量被凝胶内水分子吸收,通过水分的蒸发带走大量的热量,可迅速地降低体表皮肤局部温度,减轻局部皮肤的灼…...

    2024/5/4 23:54:56
  25. 配置失败还原请勿关闭计算机,电脑开机屏幕上面显示,配置失败还原更改 请勿关闭计算机 开不了机 这个问题怎么办...

    解析如下&#xff1a;1、长按电脑电源键直至关机&#xff0c;然后再按一次电源健重启电脑&#xff0c;按F8健进入安全模式2、安全模式下进入Windows系统桌面后&#xff0c;按住“winR”打开运行窗口&#xff0c;输入“services.msc”打开服务设置3、在服务界面&#xff0c;选中…...

    2022/11/19 21:17:18
  26. 错误使用 reshape要执行 RESHAPE,请勿更改元素数目。

    %读入6幅图像&#xff08;每一幅图像的大小是564*564&#xff09; f1 imread(WashingtonDC_Band1_564.tif); subplot(3,2,1),imshow(f1); f2 imread(WashingtonDC_Band2_564.tif); subplot(3,2,2),imshow(f2); f3 imread(WashingtonDC_Band3_564.tif); subplot(3,2,3),imsho…...

    2022/11/19 21:17:16
  27. 配置 已完成 请勿关闭计算机,win7系统关机提示“配置Windows Update已完成30%请勿关闭计算机...

    win7系统关机提示“配置Windows Update已完成30%请勿关闭计算机”问题的解决方法在win7系统关机时如果有升级系统的或者其他需要会直接进入一个 等待界面&#xff0c;在等待界面中我们需要等待操作结束才能关机&#xff0c;虽然这比较麻烦&#xff0c;但是对系统进行配置和升级…...

    2022/11/19 21:17:15
  28. 台式电脑显示配置100%请勿关闭计算机,“准备配置windows 请勿关闭计算机”的解决方法...

    有不少用户在重装Win7系统或更新系统后会遇到“准备配置windows&#xff0c;请勿关闭计算机”的提示&#xff0c;要过很久才能进入系统&#xff0c;有的用户甚至几个小时也无法进入&#xff0c;下面就教大家这个问题的解决方法。第一种方法&#xff1a;我们首先在左下角的“开始…...

    2022/11/19 21:17:14
  29. win7 正在配置 请勿关闭计算机,怎么办Win7开机显示正在配置Windows Update请勿关机...

    置信有很多用户都跟小编一样遇到过这样的问题&#xff0c;电脑时发现开机屏幕显现“正在配置Windows Update&#xff0c;请勿关机”(如下图所示)&#xff0c;而且还需求等大约5分钟才干进入系统。这是怎样回事呢&#xff1f;一切都是正常操作的&#xff0c;为什么开时机呈现“正…...

    2022/11/19 21:17:13
  30. 准备配置windows 请勿关闭计算机 蓝屏,Win7开机总是出现提示“配置Windows请勿关机”...

    Win7系统开机启动时总是出现“配置Windows请勿关机”的提示&#xff0c;没过几秒后电脑自动重启&#xff0c;每次开机都这样无法进入系统&#xff0c;此时碰到这种现象的用户就可以使用以下5种方法解决问题。方法一&#xff1a;开机按下F8&#xff0c;在出现的Windows高级启动选…...

    2022/11/19 21:17:12
  31. 准备windows请勿关闭计算机要多久,windows10系统提示正在准备windows请勿关闭计算机怎么办...

    有不少windows10系统用户反映说碰到这样一个情况&#xff0c;就是电脑提示正在准备windows请勿关闭计算机&#xff0c;碰到这样的问题该怎么解决呢&#xff0c;现在小编就给大家分享一下windows10系统提示正在准备windows请勿关闭计算机的具体第一种方法&#xff1a;1、2、依次…...

    2022/11/19 21:17:11
  32. 配置 已完成 请勿关闭计算机,win7系统关机提示“配置Windows Update已完成30%请勿关闭计算机”的解决方法...

    今天和大家分享一下win7系统重装了Win7旗舰版系统后&#xff0c;每次关机的时候桌面上都会显示一个“配置Windows Update的界面&#xff0c;提示请勿关闭计算机”&#xff0c;每次停留好几分钟才能正常关机&#xff0c;导致什么情况引起的呢&#xff1f;出现配置Windows Update…...

    2022/11/19 21:17:10
  33. 电脑桌面一直是清理请关闭计算机,windows7一直卡在清理 请勿关闭计算机-win7清理请勿关机,win7配置更新35%不动...

    只能是等着&#xff0c;别无他法。说是卡着如果你看硬盘灯应该在读写。如果从 Win 10 无法正常回滚&#xff0c;只能是考虑备份数据后重装系统了。解决来方案一&#xff1a;管理员运行cmd&#xff1a;net stop WuAuServcd %windir%ren SoftwareDistribution SDoldnet start WuA…...

    2022/11/19 21:17:09
  34. 计算机配置更新不起,电脑提示“配置Windows Update请勿关闭计算机”怎么办?

    原标题&#xff1a;电脑提示“配置Windows Update请勿关闭计算机”怎么办&#xff1f;win7系统中在开机与关闭的时候总是显示“配置windows update请勿关闭计算机”相信有不少朋友都曾遇到过一次两次还能忍但经常遇到就叫人感到心烦了遇到这种问题怎么办呢&#xff1f;一般的方…...

    2022/11/19 21:17:08
  35. 计算机正在配置无法关机,关机提示 windows7 正在配置windows 请勿关闭计算机 ,然后等了一晚上也没有关掉。现在电脑无法正常关机...

    关机提示 windows7 正在配置windows 请勿关闭计算机 &#xff0c;然后等了一晚上也没有关掉。现在电脑无法正常关机以下文字资料是由(历史新知网www.lishixinzhi.com)小编为大家搜集整理后发布的内容&#xff0c;让我们赶快一起来看一下吧&#xff01;关机提示 windows7 正在配…...

    2022/11/19 21:17:05
  36. 钉钉提示请勿通过开发者调试模式_钉钉请勿通过开发者调试模式是真的吗好不好用...

    钉钉请勿通过开发者调试模式是真的吗好不好用 更新时间:2020-04-20 22:24:19 浏览次数:729次 区域: 南阳 > 卧龙 列举网提醒您:为保障您的权益,请不要提前支付任何费用! 虚拟位置外设器!!轨迹模拟&虚拟位置外设神器 专业用于:钉钉,外勤365,红圈通,企业微信和…...

    2022/11/19 21:17:05
  37. 配置失败还原请勿关闭计算机怎么办,win7系统出现“配置windows update失败 还原更改 请勿关闭计算机”,长时间没反应,无法进入系统的解决方案...

    前几天班里有位学生电脑(windows 7系统)出问题了&#xff0c;具体表现是开机时一直停留在“配置windows update失败 还原更改 请勿关闭计算机”这个界面&#xff0c;长时间没反应&#xff0c;无法进入系统。这个问题原来帮其他同学也解决过&#xff0c;网上搜了不少资料&#x…...

    2022/11/19 21:17:04
  38. 一个电脑无法关闭计算机你应该怎么办,电脑显示“清理请勿关闭计算机”怎么办?...

    本文为你提供了3个有效解决电脑显示“清理请勿关闭计算机”问题的方法&#xff0c;并在最后教给你1种保护系统安全的好方法&#xff0c;一起来看看&#xff01;电脑出现“清理请勿关闭计算机”在Windows 7(SP1)和Windows Server 2008 R2 SP1中&#xff0c;添加了1个新功能在“磁…...

    2022/11/19 21:17:03
  39. 请勿关闭计算机还原更改要多久,电脑显示:配置windows更新失败,正在还原更改,请勿关闭计算机怎么办...

    许多用户在长期不使用电脑的时候&#xff0c;开启电脑发现电脑显示&#xff1a;配置windows更新失败&#xff0c;正在还原更改&#xff0c;请勿关闭计算机。。.这要怎么办呢&#xff1f;下面小编就带着大家一起看看吧&#xff01;如果能够正常进入系统&#xff0c;建议您暂时移…...

    2022/11/19 21:17:02
  40. 还原更改请勿关闭计算机 要多久,配置windows update失败 还原更改 请勿关闭计算机,电脑开机后一直显示以...

    配置windows update失败 还原更改 请勿关闭计算机&#xff0c;电脑开机后一直显示以以下文字资料是由(历史新知网www.lishixinzhi.com)小编为大家搜集整理后发布的内容&#xff0c;让我们赶快一起来看一下吧&#xff01;配置windows update失败 还原更改 请勿关闭计算机&#x…...

    2022/11/19 21:17:01
  41. 电脑配置中请勿关闭计算机怎么办,准备配置windows请勿关闭计算机一直显示怎么办【图解】...

    不知道大家有没有遇到过这样的一个问题&#xff0c;就是我们的win7系统在关机的时候&#xff0c;总是喜欢显示“准备配置windows&#xff0c;请勿关机”这样的一个页面&#xff0c;没有什么大碍&#xff0c;但是如果一直等着的话就要两个小时甚至更久都关不了机&#xff0c;非常…...

    2022/11/19 21:17:00
  42. 正在准备配置请勿关闭计算机,正在准备配置windows请勿关闭计算机时间长了解决教程...

    当电脑出现正在准备配置windows请勿关闭计算机时&#xff0c;一般是您正对windows进行升级&#xff0c;但是这个要是长时间没有反应&#xff0c;我们不能再傻等下去了。可能是电脑出了别的问题了&#xff0c;来看看教程的说法。正在准备配置windows请勿关闭计算机时间长了方法一…...

    2022/11/19 21:16:59
  43. 配置失败还原请勿关闭计算机,配置Windows Update失败,还原更改请勿关闭计算机...

    我们使用电脑的过程中有时会遇到这种情况&#xff0c;当我们打开电脑之后&#xff0c;发现一直停留在一个界面&#xff1a;“配置Windows Update失败&#xff0c;还原更改请勿关闭计算机”&#xff0c;等了许久还是无法进入系统。如果我们遇到此类问题应该如何解决呢&#xff0…...

    2022/11/19 21:16:58
  44. 如何在iPhone上关闭“请勿打扰”

    Apple’s “Do Not Disturb While Driving” is a potentially lifesaving iPhone feature, but it doesn’t always turn on automatically at the appropriate time. For example, you might be a passenger in a moving car, but your iPhone may think you’re the one dri…...

    2022/11/19 21:16:57