亿级高并发电商项目-- 实战篇 --万达商城项目 十二(编写用户服务、发送短信功能、发送注册验证码功能、手机号验证码登录功能、单点登录等模块)

news/2024/5/20 21:21:09/文章来源:https://blog.csdn.net/m0_58719994/article/details/129105424

 

 

👏作者简介:大家好,我是小童,Java开发工程师,CSDN博客博主,Java领域新星创作者
📕系列专栏:前端、Java、Java中间件大全、微信小程序、微信支付、若依框架、Spring全家桶
📧如果文章知识点有错误的地方,请指正!和大家一起学习,一起进步👀
🔥如果感觉博主的文章还不错的话,请👍三连支持👍一下博主哦
🍂博主正在努力完成2023计划中:以梦为马,扬帆起航,2023追梦人 

专栏:高并发项目 

编写用户服务接口

在通用模块编写用户服务接口:

/**
* 商城用户服务
*/
public interface ShoppingUserService {// 注册时向redis保存手机号+验证码void saveRegisterCheckCode(String phone,String checkCode);// 注册时验证手机号void registerCheckCode(String phone,String checkCode);// 用户注册void register(ShoppingUser shoppingUser);// 用户名密码登录String loginPassword(String username,String password);// 登录时向redis保存手机号+验证码void saveLoginCheckCode(String phone,String checkCode);// 手机号验证码登录String loginCheckCode(String phone, String checkCode);   // 获取登录用户名String getName(String token);// 获取登录用户ShoppingUser getLoginUser(String token);
}

创建网站用户服务模块

1、创建名为 shopping_user_service 的SpringBoot工程,添加相关依赖。

<dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter</artifactId></dependency><!-- MyBatisPlus --><dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-boot-starter</artifactId><version>3.5.0</version></dependency><!-- mysql驱动 --><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><scope>runtime</scope></dependency><dependency><groupId>com.itbaizhan</groupId><artifactId>shopping_common</artifactId><version>0.0.1-SNAPSHOT</version></dependency><!-- dubbo --><dependency><groupId>org.apache.dubbo</groupId><artifactId>dubbo-spring-boot-starter</artifactId><version>2.7.8</version></dependency><!-- 操作zookeeper --><dependency><groupId>org.apache.curator</groupId><artifactId>curator-recipes</artifactId><version>4.2.0</version></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency><!-- redis --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis</artifactId></dependency>
</dependencies>

 2、设置该工程的父工程为 shopping 。

<parent><groupId>com.ittxc</groupId><artifactId>shopping</artifactId><version>1.0-SNAPSHOT</version>
</parent>

3、给 shopping 工程设置子模块

<!-- 子模块 -->
<modules><!-- 用户服务 --><module>shopping_user_service</module>
</modules>

4、编写配置文件 application.yml

# 端口号
server:port: 9006# 日志格式
logging:pattern:console: '%d{HH:mm:ss.SSS} %clr(%-5level) --- [%-15thread] %cyan(%-50logger{50}):%msg%n'
#配置mybatis-plus
mybatis-plus:global-config:db-config:# 表名前缀table-prefix: bz_# 主键生成策略为自增id-type: autoconfiguration:# 关闭列名自动驼峰命名规则映射map-underscore-to-camel-case: falselog-impl: org.apache.ibatis.logging.stdout.StdOutImpl #开启sql日志
spring:# 数据源datasource:driver-class-name: com.mysql.cj.jdbc.Driverurl: jdbc:mysql:///baizhanshopping?serverTimezone=UTCusername: rootpassword01: 123456# redisredis:host: 192.168.100.131port: 6379timeout: 30000jedis:pool:max-active: 8max-wait: -1max-idle: 8min-idle: 0
dubbo:application:name: shopping_user_service # 项目名registry:address: zookeeper://192.168.100.131 #注册中心地址port: 2181       # 注册中心的端口timeout: 10000 # 注册到zk上超时时间,msprotocol:name: dubbo # dubbo使用的协议port: -1 # dubbo自动分配端口scan:base-packages: com.ittxc.shopping_user_service.service # 包扫描

创建网站用户Api模块

1、创建名为 shopping_user_customer_api 的SpringBoot工程,添加相关依赖。

<dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><!-- dubbo --><dependency><groupId>org.apache.dubbo</groupId><artifactId>dubbo-spring-boot-starter</artifactId><version>2.7.8</version></dependency><!-- 操作zookeeper --><dependency><groupId>org.apache.curator</groupId><artifactId>curator-recipes</artifactId><version>4.2.0</version></dependency><dependency><groupId>com.itbaizhan</groupId><artifactId>shopping_common</artifactId><version>0.0.1-SNAPSHOT</version></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency>
</dependencies>

 2、设置该工程的父工程为 shopping 。

<parent><groupId>com.ittxc</groupId><artifactId>shopping</artifactId><version>1.0-SNAPSHOT</version>
</parent>

3、给 shopping 工程设置子模块

<!-- 子模块 -->
<modules><!-- 用户业务的api --><module>shopping_user_customer_api</module>
</modules>

4、编写配置文件 application.yml

# 端口号
server:port: 8003
# 日志格式
logging:pattern:console: '%d{HH:mm:ss.SSS} %clr(%-5level) --- [%-15thread] %cyan(%-50logger{50}):%msg%n'
dubbo:application:name: shopping_user_customer_api # 项目名registry:address: zookeeper://192.168.100.131 #注册中心地址port: 2181       # 注册中心的端口timeout: 10000 # 注册到zk上超时时间,msprotocol:name: dubbo # dubbo使用的协议port: -1 # dubbo自动分配端口

5、启动类忽略数据源自动配置

@SpringBootApplication(exclude= {DataSourceAutoConfiguration.class})
public class ShoppingUserCustomerApiApplication {public static void main(String[] args){SpringApplication.run(ShoppingUserCustomerApiApplication.class, args);}
}

用户注册的步骤

在用户注册时,我们要保证用户输入的手机号就是他本人使用的手 机号,方便后期的广告推送、安全认证等。所以在注册前,会向用 户手机发送一个四位随机数验证码,如果用户能获取到该验证码, 证明该手机就是用户本人使用。用户注册的步骤如下:

申请阿里短信服务 

1、访问阿里云 https://www.aliyun.com/,完成登录

2、进入短信服务 

3、开通短信服务 

4、购买短信条数 

 5、购买完成进入阿里云短信控制台https://dysms.console.aliyun.c om/overview

6、绑定测试手机号 

 7、点击调用API发送短信,可以看到发送短信的JAVA代码。

8、申请阿里云秘钥,该秘钥在发送短信时会作为参数传入 

编写发送短信功能 

1、创建名为 shopping_message_service 的SpringBoot工程,添加相关依赖。

<dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter</artifactId></dependency>
<dependency><groupId>com.ittxc</groupId><artifactId>shopping_common</artifactId><version>0.0.1-SNAPSHOT</version></dependency><!-- 阿里短信平台 --><dependency><groupId>com.aliyun</groupId><artifactId>dysmsapi20170525</artifactId><version>2.0.9</version></dependency><!-- dubbo --><dependency><groupId>org.apache.dubbo</groupId><artifactId>dubbo-spring-boot-starter</artifactId><version>2.7.8</version></dependency><!-- 操作zookeeper --><dependency><groupId>org.apache.curator</groupId><artifactId>curator-recipes</artifactId><version>4.2.0</version></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency>
</dependencies>

2、设置该工程的父工程为 shopping 。

<parent><groupId>com.ittxc</groupId><artifactId>shopping</artifactId><version>1.0-SNAPSHOT</version>
</parent>

3、给 shopping 工程设置子模块

<!-- 子模块 -->
<modules><!-- 短信服务 --><module>shopping_message_service</module>
</modules>

4、编写配置文件 application.yml

# 端口号
server:port: 9007
# 日志格式
logging:pattern:console: '%d{HH:mm:ss.SSS} %clr(%-5level) --- [%-15thread]
%cyan(%-50logger{50}):%msg%n'
dubbo:application:name: shopping_message_service # 项目名registry:address: zookeeper://192.168.100.131 #注册中心地址port: 2181       # 注册中心的端口timeout: 10000 # 注册到zk上超时时间,msprotocol:name: dubbo # dubbo使用的协议port: -1 # dubbo自动分配端口scan:base-packages: com.ittxc.shopping_message_service.service # 包扫描
message:accessKeyId: LTAI5tBUnRMTgKmRR92yxrFfaccessKeySecret: RN7umfy3mMA2xlGa8rP0IzwQdTc6Pb

5、启动类忽略数据源自动配置

@SpringBootApplication(exclude= {DataSourceAutoConfiguration.class})
public class ShoppingMessageServiceApplication {public static void main(String[] args){SpringApplication.run(ShoppingMessageServiceApplication.class, args);}
}

6、在通用模块编写发送短信服务接口

/**
* 短信服务
*/
public interface MessageService {/*** 发送短信* @param phoneNumber 手机号* @param code 验证码* @return 返回结果*/BaseResult sendMessage(String phoneNumber,String code);
}

7、在短信服务模块编写发送短信实现类

@DubboService
public class MessageServiceImpl implements
MessageService {@Value("${message.accessKeyId}")private String accessKeyId;@Value("${message.accessKeySecret}")private String accessKeySecret;/*** 使用AK&SK初始化账号Client* @param accessKeyId* @param accessKeySecret* @return Client* @throws Exception*/@SneakyThrowsprivate Client createClient(String accessKeyId, String accessKeySecret) {Config config = new Config().setAccessKeyId(accessKeyId).setAccessKeySecret(accessKeySecret);// 访问的域名config.endpoint = "dysmsapi.aliyuncs.com";return new Client(config);}@SneakyThrows@Overridepublic BaseResult sendMessage(String phoneNumber,String code) {Client client = createClient(accessKeyId,accessKeySecret);SendSmsRequest sendSmsRequest = new SendSmsRequest().setSignName("阿里云短信测试").setTemplateCode("SMS_154950909").setPhoneNumbers(phoneNumber).setTemplateParam("{\"code\":\""+code+"\"}");RuntimeOptions runtime = new RuntimeOptions();// 复制代码运行请自行打印API的返回值SendSmsResponse sendSmsResponse = client.sendSmsWithOptions(sendSmsRequest,
runtime);SendSmsResponseBody body = sendSmsResponse.getBody();if ("OK".equals(body.getCode())){return new BaseResult(200,body.getCode(),body.getMessage());}else{return new BaseResult(500,body.getCode(),body.getMessage());}}
}

8、测试该方法

编写发送注册验证码功能

1、在通用模块编写生成随机数的工具类

public class RandomUtil {/*** 生成验证码* @param digit 位数* @return*/public static String buildCheckCode(int digit){String str = "0123456789";StringBuilder sb = new StringBuilder();Random random = new Random();for (int i = 0; i < digit; i++) {char ch = str.charAt(random.nextInt(str.length()));sb.append(ch);}return sb.toString();}
}

2、在用户服务模块编写用户服务接口实现类

@DubboService
public class ShoppingUserServiceImpl implements ShoppingUserService {@Autowiredprivate RedisTemplate redisTemplate;@Autowiredprivate ShoppingUserMapper shoppingUserMapper;@Overridepublic void saveRegisterCheckCode(String phone, String checkCode) {ValueOperations valueOperations = redisTemplate.opsForValue();// redis键为手机号,值为验证码,过期时间5分钟valueOperations.set("registerCode:" + phone, checkCode, 300, TimeUnit.SECONDS);}
}

3、在用户API模块编写控制器

/**
* 商城用户
*/
@RestController
@RequestMapping("/shoppingUser")
public class ShoppingUserController {@DubboReferenceprivate ShoppingUserService shoppingUserService;/*** 发送注册短信* @param phone 注册手机号* @return 操作结果*/@GetMapping("/sendMessage")public BaseResult sendMessage(String phone){// 1.生成随机四位数String checkCode = RandomUtil.buildCheckCode(4);// 2.发送短信BaseResult result = messageService.sendMessage(phone,checkCode);// 3.发送成功,将验证码保存到redis中,发送失败,返回发送结果if (200 == result.getCode()) {shoppingUserService.saveRegisterCheckCode(phone, checkCode);return BaseResult.ok();} else {return result;}}
}

4、测试控制器

编写验证注册验证码功能

1、在用户服务模块编写用户服务接口实现类

@Override
public void registerCheckCode(String phone, String checkCode) {// 验证验证码ValueOperations valueOperations = redisTemplate.opsForValue();Object checkCodeRedis = valueOperations.get("registerCode:" + phone);if (!checkCode.equals(checkCodeRedis)){throw new BusException(CodeEnum.REGISTER_CODE_ERROR);}
}

2、在用户API模块编写控制器

/*** 验证用户注册验证码* @param phone 手机号* @param checkCode 验证码* @return 200验证成功,605验证码不正确*/
@GetMapping("/registerCheckCode")
public BaseResult register(String phone,String checkCode){shoppingUserService.registerCheckCode(phone,checkCode);return BaseResult.ok();
}

3、测试控制器

编写用户注册功能

1、在通用模块编写MD5加密工具类,用于给用户密码进行加密和验证

public class Md5Util {public final static String md5key = "BAIZHAN"; // 秘钥/*** 加密* @param text 明文* @return 密文*/public static String encode(String text){return DigestUtils.md5Hex(text + md5key);}/*** 验证** @param text 明文* @param cipher 密文* @return true/false*/public static boolean verify(String text, String cipher){// 将明文转为密文进行比对String md5Text = encode(text);if (md5Text.equalsIgnoreCase(cipher)) {return true;}return false;}
}

2、在用户服务模块编写用户服务接口实现类

@Override
public void register(ShoppingUser
shoppingUser) {// 1.验证手机号是否存在String phone = shoppingUser.getPhone();QueryWrapper<ShoppingUser> queryWrapper = new QueryWrapper();queryWrapper.eq("phone", phone);List<ShoppingUser> shoppingUsers = shoppingUserMapper.selectList(queryWrapper);if (shoppingUsers != null && shoppingUsers.size() > 0) {throw new BusException(CodeEnum.REGISTER_REPEAT_PHONE_ERROR);}// 2.验证用户名是否存在String username = shoppingUser.getUsername();QueryWrapper<ShoppingUser> queryWrapper1 = new QueryWrapper();queryWrapper1.eq("username",username);List<ShoppingUser> shoppingUsers1 = shoppingUserMapper.selectList(queryWrapper1);if (shoppingUsers1 != null && shoppingUsers1.size() > 0) {throw new BusException(CodeEnum.REGISTER_REPEAT_NAME_ERROR);}// 3.新增用户shoppingUser.setStatus("Y");shoppingUser.setPassword(Md5Util.encode(shoppingUser.getPassword()));shoppingUserMapper.insert(shoppingUser);
}

3、在用户API模块编写控制器

/*** 用户注册* @param shoppingUser 用户信息* @return 注册结果*/
@PostMapping("/register")
public BaseResult register(@RequestBody ShoppingUser shoppingUser){shoppingUserService.register(shoppingUser);return BaseResult.ok();
}

4、测试控制器

编写用户名密码登录功能

1、在用户服务模块编写用户服务接口实现类

@Override
public String loginPassword(String username, String password) {QueryWrapper<ShoppingUser> queryWrapper = new QueryWrapper();queryWrapper.eq("username", username);ShoppingUser shoppingUser = shoppingUserMapper.selectOne(queryWrapper);// 验证用户名if (shoppingUser == null) {throw new BusException(CodeEnum.LOGIN_NAME_PASSWORD_ERROR);}// 验证密码boolean verify = Md5Util.verify(password,shoppingUser.getPassword());if (!verify) {throw new BusException(CodeEnum.LOGIN_NAME_PASSWORD_ERROR);}// 返回用户名return username;
}

2、在用户API模块编写控制器

/*** 用户名密码登录* @param shoppingUser 用户对象* @return 登录结果*/
@PostMapping("/loginPassword")
public BaseResult loginPassword(@RequestBody ShoppingUser shoppingUser){shoppingUserService.loginPassword(shoppingUser.getUsername(),shoppingUser.getPassword());return BaseResult.ok();
}

3、测试控制器

编写手机号验证码登录功能

手机号验证码登录的流程为:用户先输入手机号,向手机号发送随 机验证码,并将验证码保存到redis中。用户收到短信后将验证码输入,如果验证码和redis中的验证码匹配成功,证明登录者就是使用 该手机的用户,登录成功。

向用户发送登录验证码 

1、在用户服务模块编写用户服务接口实现类

// 保存登录验证码到redis
@Override
public void saveLoginCheckCode(String phone, String checkCode) {ValueOperations valueOperations = redisTemplate.opsForValue();// redis键为手机号,值为验证码,过期时间5分钟valueOperations.set("loginCode:" + phone, checkCode, 300, TimeUnit.SECONDS);
}

2、在用户API模块编写控制器

/*** 发送登录短信验证码** @param phone 手机号* @return 操作结果*/
@GetMapping("/sendLoginCheckCode")
public BaseResult sendLoginCheckCode(String phone) {// 1.生成随机四位数String checkCode = RandomUtil.buildCheckCode(4);// 2.发送短信BaseResult result = messageService.sendMessage(phone,checkCode);// 3.发送成功,将验证码保存到redis中,发送失败,返回发送结果if (200 == result.getCode()) {shoppingUserService.saveLoginCheckCode(phone, checkCode);return BaseResult.ok();} else {return result;}
}

3、测试控制器

验证登录验证码

1、在用户服务模块编写用户服务接口实现类

// 验证登录验证码
@Override
public String loginCheckCode(String phone, String checkCode) {ValueOperations valueOperations = redisTemplate.opsForValue();Object checkCodeRedis = valueOperations.get("loginCode:" + phone);if (!checkCode.equals(checkCodeRedis)){throw new BusException(CodeEnum.LOGIN_CODE_ERROR);}// 登录成功,查询用户QueryWrapper<ShoppingUser> queryWrapper = new QueryWrapper();queryWrapper.eq("phone", phone);ShoppingUser shoppingUser = shoppingUserMapper.selectOne(queryWrapper);// 返回用户名return shoppingUser.getUsername();
}

2、在用户API模块编写控制器

/*** 手机号验证码登录* @param phone 手机号* @param checkCode 验证码* @return 登录结果*/
@PostMapping("/loginCheckCode")
public BaseResult loginCheckCode(String phone, String checkCode){shoppingUserService.loginCheckCode(phone,checkCode);return BaseResult.ok();
}

3、测试控制器

单点登录的概念

目前登录成功后我们并没有保存用户信息,也没有在访问接口前验 证用户信息。如果使用传统的session保存用户信息,使用filter验证 用户是否登录。存在一个问题:session保存在服务器中,而我们的 系统存在诸多子系统,这些子系统是分别部署在不同的服务器中,互相无法访问(登录后的session保存在用户模块,搜索模块无法访问用户模块的session,无法验证用户是否登录)。此时我们需要使用单点登录技术解决这一问题。

单点登录 

单点登录(Single Sign On)简称为 SSO。即在多个应用系统中, 用户只需要登录一次就可以访问所有相互信任的应用系统。JWT是一种常用的单点登录解决方案。

JWT 

JWT是Json Web Token的简称,是一种令牌生成算法。使用JWT能 够保证Token的安全性,且能够进行Token时效性的检验。 使用JWT时,登录成功后将用户信息生成一串令牌字符串。将该字 符串返回给客户端,客户端每次请求时都在请求头携带该令牌字符串。在其他模块验证令牌,通过则证明用户处于登录状态,并拿到 解析后的用户信息,未通过证明用户处于未登录状态。

编写单点登录功能 

1、在通用模块引入JWT依赖

<!-- JWT -->
<dependency><groupId>com.auth0</groupId><artifactId>java-jwt</artifactId><version>3.4.0</version>
</dependency>

2、在通用模块编写JWT工具类

public class JWTUtil {//token过期时间,一天private static final Long EXPIRE_DATE = 1000*60*60*24L;// 秘钥private static final String SECRET = "txc";// 签发者private static final String ISSUER = "TXC";/*** 签名生成* @param shoppingUser* @return*/public static String sign(ShoppingUser shoppingUser){String token = JWT.create().withIssuer(ISSUER) // 签发者.withIssuedAt(new Date())// 签发时间.withExpiresAt(new Date(new Date().getTime() + EXPIRE_DATE))// 过期时间.withSubject(shoppingUser.getUsername())// 保存用户名.sign(Algorithm.HMAC256(SECRET)); // 秘钥return token;}/*** 签名解析* @param token 签名字符串* @return 解析得出的用户名*/public static String verify(String token){try {String username = JWT.require(Algorithm.HMAC256(SECRET)).withIssuer(ISSUER).build().verify(token).getSubject();return username;} catch (Exception e){throw new BusException(CodeEnum.VERIFY_TOKEN_ERROR);}}
}

3、登录后生成令牌

@Override
public String loginPassword(String
username, String password) {// 1.验证用户名QueryWrapper<ShoppingUser> queryWrapper = new QueryWrapper();queryWrapper.eq("username",username);ShoppingUser shoppingUser = shoppingUserMapper.selectOne(queryWrapper);if (shoppingUser == null){throw new BusException(CodeEnum.LOGIN_NAME_PASSWORD_ERROR);}// 2.验证密码boolean verify = Md5Util.verify(password, shoppingUser.getPassword());if (!verify){throw new BusException(CodeEnum.LOGIN_NAME_PASSWORD_ERROR);}// 3.生成JWT令牌,返回令牌String sign = JWTUtil.sign(shoppingUser);return sign;
}
@Override
public String loginCheckCode(String phone,String checkCode) {ValueOperations valueOperations = redisTemplate.opsForValue();Object checkCodeRedis = valueOperations.get("loginCode:" + phone);if (!checkCode.equals(checkCodeRedis)){throw new BusException(CodeEnum.LOGIN_CODE_ERROR);}// 登录成功,查找用户,返回用户名QueryWrapper<ShoppingUser> queryWrapper = new QueryWrapper();queryWrapper.eq("phone",phone);ShoppingUser shoppingUser = shoppingUserMapper.selectOne(queryWrapper);// 生成JWT令牌,返回令牌String sign = JWTUtil.sign(shoppingUser);return sign;
}

4、将令牌返回给客户端

/*** 用户名密码登录* @param shoppingUser 用户对象* @return 登录结果*/
@PostMapping("/loginPassword")
public BaseResult loginPassword(@RequestBody ShoppingUser shoppingUser){String sign = shoppingUserService.loginPassword(shoppingUser.getUsername(),shoppingUser.getPassword());return BaseResult.ok(sign);
}
/**
* 手机号验证码登录
* @param phone 手机号
* @param checkCode 验证码
* @return 登录结果
*/
@PostMapping("/loginCheckCode")
public BaseResult loginCheckCode(Stringphone,String checkCode){String sign = shoppingUserService.loginCheckCode(phone,checkCode);return BaseResult.ok(sign);
}

编写拦截器验证令牌

在通用模块编写JWT拦截器

// 拦截器,验证令牌
public class JWTInterceptor implements HandlerInterceptor {@Overridepublic boolean preHandle(HttpServletRequest request,HttpServletResponse response, Objecthandler) throws Exception {// 获取请求头中的tokenString token = request.getHeader("token");// 验证tokenJWTUtil.verify(token);return true;}
}

注:请求时要在请求头添加token=令牌数据

配置拦截的接口 

在不同API模块都要配置拦截的接口

1、配置用户API模块拦截的接口

// 拦截器配置
@Configuration
public class InterceptorConfig implements WebMvcConfigurer {@Overridepublic void addInterceptors(InterceptorRegistry registry) {registry.addInterceptor(new JWTInterceptor()).addPathPatterns("/**") //拦截的接口.excludePathPatterns("/user/shoppingUser/sendMessage","/user/shoppingUser/registerCheckCode","/user/shoppingUser/register","/user/shoppingUser/loginPassword","/user/shoppingUser/sendLoginCheckCode","/user/shoppingUser/loginCheckCode"); //放行的接口}
}

2、配置搜索API模块拦截的接口

// 拦截器配置
@Configuration
public class InterceptorConfig implements WebMvcConfigurer {@Overridepublic void addInterceptors(InterceptorRegistry registry) {registry.addInterceptor(new JWTInterceptor()).addPathPatterns("/**") //拦截的接口.excludePathPatterns("/user/goodsSearch/autoSuggest"); //放行的接口}
}

3、广告用户API模块不拦截

编写获取用户名功能

1、在用户服务模块编写用户服务接口实现类

@Override
public String getName(String token) {String name = JWTUtil.verify(token);return name;
}
@Override
public ShoppingUser getLoginUser(String token) {String username = JWTUtil.verify(token);QueryWrapper<ShoppingUser> queryWrapper = new QueryWrapper();queryWrapper.eq("username", username);ShoppingUser shoppingUser = shoppingUserMapper.selectOne(queryWrapper);return shoppingUser;
}

2、在用户API模块编写控制器

/*** 获取登录的用户名* @param token 令牌* @return 用户名*/
@GetMapping("/getName")
public BaseResult<String> getName(@RequestHeader("token") String token){String name = shoppingUserService.getName(token);return BaseResult.ok(name);
}

3、使用Postman测试控制器

编写退出登录功能

后端无需编写退出登录功能,前端删除令牌即可退出登录。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.luyixian.cn/news_show_261014.aspx

如若内容造成侵权/违法违规/事实不符,请联系dt猫网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

ES6的迭代器与迭代协议Symbol.iterator

前言ES6新增了两个协议&#xff1a;可迭代协议&#xff1a;对象必须具有Symbol.Iterator属性&#xff0c;属性值为一个函数&#xff0c;当这个对象被迭代时&#xff0c;就会调用该函数&#xff0c;返回一个迭代器。迭代器协议&#xff1a;描述了迭代器对象的具体规则。迭代器迭…

数据分析-深度学习 NLP Day2关键词提取案例

训练一个关键词提取算法需要以下几个步骤&#xff1a;1&#xff09;加载已有的文档数据集&#xff1b;2&#xff09;加载停用词表&#xff1b;3&#xff09;对数据集中的文档进行分词&#xff1b;4&#xff09;根据停用词表&#xff0c;过滤干扰词&#xff1b;5&#xff09;根据…

推荐5款免费且无广告的软件,助你提升效率

有时候一些小工具&#xff0c;能给你带来一些意想不到的效果&#xff0c;我们来看看下面这5款工具&#xff0c;你又用过其中几款呢&#xff1f; 1.文件大小查看——Folder Size Folder Size是一个可以查看文件大小的软件&#xff0c;使用它可以一键查看文件夹里的文件大小。你…

容器技术概述

容器化应用程序 软件应用程序通常依赖于运行时环境提供的其他库、配置文件或服务。软件应用程序的传统运行环境是物理主机或虚拟机&#xff0c;应用程序依赖项作为主机的一部分安装。 例如&#xff0c;考虑一个 Python 应用程序&#xff0c;它需要访问实现 TLS 协议的公共共享…

Leaf说明

什么是Leafleaf是叶子的意思我们使用的Leaf是美团公司开源的一个分布式序列号(id)生成系统我们可以在Github网站上下载项目直接使用为什么需要Leaf上面的图片中是一个实际开发中常见的读写分离的数据库部署格式专门进行数据更新(写)的有两个数据库节点它们同时新增数据可能产生…

性能测试学习和性能瓶颈分析路线

很多企业招聘都只写性能测试&#xff0c;会使用LR&#xff0c;jmeter工具。其实会使用jmeter和LR进行性能测试还只是性能测试的第一步&#xff0c;离真正的性能测试工程师还很远&#xff0c;笔者也还在路上 .。 性能测试&#xff0c;都是要求测试系统性能&#xff0c;系统自然…

【nas折腾篇】抉择吧,是入门还是放弃

2018年公司一位女同事问群晖的nas是否值得买。我一脸懵&#xff0c;以前给公司买云服务有采购nas盘&#xff0c;直接mount挂到服务器上当存储&#xff0c;但对于单独的nas服务器没有什么概念。一晃几年过去了&#xff0c;陆续刷到些nas服务的视频&#xff0c;周边朋友用nas的也…

2021-08-29

服务器 主&#xff1a;172.17.0.2 master 备:172.17.0.3 slave1 lvs虚拟IP:172.17.0.100 #nginx下载地址 http://nginx.org/download/ 本地文件路径 1.dockerfile构建nginx FROM centos:7 ADD nginx-1.6.0.tar.gz /usr/local COPY nginx_install.sh /usr/local RUN sh …

k8s种的kubectl命令

一.kubectl基本命令1.1 称述式资源管理的方法kubernetes集群管理集群资源的唯一入口是通过相应的方法调用apiserver的接口kubectl是官方的CLI命令行工具&#xff0c;用于与apiserver进行通信&#xff0c;将用户在命令行输入的命令&#xff0c;组织并转化为apiserver能识别的信息…

【单目标优化算法】海鸥优化算法(Matlab代码实现)

&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密&#xff0c;逻辑清晰&#xff0c;为了方便读者。 ⛳️座右铭&a…

数组(一)-- LeetCode[26][80] 删除有序数组中的重复元素

1 删除有序数组中的重复项 1.1 题目描述 给你一个 升序排列 的数组 nums &#xff0c;请你 原地 删除重复出现的元素&#xff0c;使每个元素 只出现一次&#xff0c;返回删除后数组的新长度。元素的 相对顺序 应该保持 一致 。 由于在某些语言中不能改变数组的长度&#xff0c…

内部知识管理应该怎么做?

许多公司都知道需要有一个面向客户的知识库&#xff0c;以加强客户服务&#xff0c;提供更好的客户体验。 但是很多企业没有意识到的是&#xff0c;拥有一个内部知识库软件对于员工改善沟通和促进知识共享的重要性。 协作是组织成功的关键部分&#xff0c;通过明确的远景和使命…

消灭EMC的三大利器:电容器/电感/磁珠

滤波电容器、共模电感、磁珠在EMC设计电路中是常见的身影&#xff0c;也是消灭电磁干扰的三大利器。 对于这三者在电路中的作用&#xff0c;相信还有很多工程师搞不清楚&#xff0c;文章从设计中详细分析了消灭EMC三大利器的原理。 1 、滤波电容 尽管从滤除高频噪声的角度…

Java数组,超详细整理,适合新手入门

目录 一、什么是Java中的数组&#xff1f; 二、数组有哪些常见的操作&#xff1f; 三、数组的五种赋值方法和使用方法 声明数组 声明数组并且分配空间 声明数组同时赋值(1) 声明数组同时赋值(2) 从控制台输入向数组赋值 四、求总和平均 五、求数组中最大值最小值 六…

​一致魔芋在北交所上市:市值突破11亿元,吴平夫妇为实控人​

2月21日&#xff0c;湖北一致魔芋生物科技股份有限公司&#xff08;下称“一致魔芋”&#xff0c;BJ:839273&#xff09;在北京证券交易所上市。本次上市&#xff0c;一致魔芋的发行价为11.38元/股&#xff0c;发行1350万股&#xff0c;募资总额约为1.54亿元。 本次发行后&…

以假乱真的手写模拟器?

前些时候给大家推荐了一款word插件叫做“不坑盒子”&#xff0c;这款盒子不仅方便了word的操作&#xff0c;还附带了手写模拟器这样的效果只是在使用的时候不仅需要手动下载字体&#xff0c;而且效果也并不是太理想。 今天小编找到了一款软件--手写模拟器&#xff0c;不仅一键生…

做外贸怎么找客户

现在国内贸易内卷非常严重&#xff0c;很多商家都转向海外市场了&#xff0c;总结而言&#xff0c;目前所有做外贸的人&#xff0c;核心的点就是要找到重点意向客户&#xff0c;今天就和大家分享一下目前市面上外贸找客户的几种方法。主动出击式开发外贸客户1、参加展会找外贸客…

.NET6中使用GRPC详细描述

Supported languages | gRPC&#xff0c;官网。至于原理就不说了&#xff0c;可以百度原理之后&#xff0c;然后再结合代码&#xff0c;事半功倍&#xff0c;就能很好理解GRPC了。 目录 一、简单使用 二、实际应用 一、简单使用 1.使用vs2022创建一个grpc程序&#xff0c;…

同城小程序应该怎么做?

同城小程序应该怎么做?同城小程序开发&#xff0c;微信同城小程序&#xff0c;同城生活小程序&#xff0c;同城信息发布小程序#同城小程序开发#微信同城小程序#同城生活小程序#同城信息发布小程序百收网 同城信息发布的小程序怎么做&#xff1f; 实际上跟 58 同城类似的&…

RPC框架dubbo的学习

一、基础知识 1、分布式基础理论 1.1&#xff09;、什么是分布式系统&#xff1f; 《分布式系统原理与范型》定义&#xff1a; “分布式系统是若干独立计算机的集合&#xff0c;这些计算机对于用户来说就像单个相关系统” 分布式系统&#xff08;distributed system&#…