【云岚到家】-day02-客户管理-认证授权

第二章 客户管理

1.认证模块

1.1 需求分析

1.基础概念

一般情况有用户交互的项目都有认证授权功能,首先我们要搞清楚两个概念:认证和授权

认证: 就是校验用户的身份是否合法,常见的认证方式有账号密码登录、手机验证码登录等

授权:则是该用户登录系统成功后当用户去点击菜单或操作数据时系统判断该用户是否有权限,有权限则允许继续操作,没有权限则拒绝访问

2.小程序认证

本项目包括四个端:用户端(小程序)、服务端(app)、机构端(PC)、运营管理端(PC)

分别对应四类用户角色:家政需求方即c端用户,家政服务人员、家政服务公司(机构)、平台运营人员

用户端通过小程序使用平台,初次使用小程序会进行认证,如下图:

在这里插入图片描述

点击“快速登录”弹出服务条款窗口

在这里插入图片描述

点击“同意”进行认证,系统与微信进行交互获取用户在小程序中的唯一标识openid

初次认证通过会自动注册用户信息到本平台

下边是小程序的认证流程:

在这里插入图片描述

3.手机验证码认证

服务人员通过app登录采用手机验证码认证方式,输入手机号、发送验证码,验证码校验通过则认证通过,初次认证通过将自动注册服务人员信息

在这里插入图片描述

手机验证码认证流程如下:

在这里插入图片描述

4.账号密码认证

机构端认证方式是账号密码认证方式,通过pc浏览器进入登录界面输入账号和密码登录系统

在这里插入图片描述

机构端提供单独的注册页面,输入手机号,接收验证码进行注册

在这里插入图片描述

管理端的认证方式也是账号密码方式,管理端的账号由管理员在后台录入,不提供注册页面

在这里插入图片描述

1.2 小程序认证

1.2.1 测试小程序认证

1.参考官方流程

小程序认证流程需要三部分:

小程序:即前端程序

开发者服务器:后端微服务程序

微信接口服务:即微信服务器

在这里插入图片描述

1.前端调用wx.login()获取登录凭证code

2.前端请求后端进行认证,发送code

3.后端请求微信获取openid,发送appid、app密钥、code参数,微信返回openid

4.后端生成认证成功凭证返回给前端。

5.前端存储用户认证成功凭证

2.申请小程序账号

开发小程序首先要申请小程序账号,点击注册小程序(https://mp.weixin.qq.com/wxopen/waregister?action=step1)填写信息

在这里插入图片描述

进入邮箱激活小程序,进入下一步信息登记,选择“个人”
进入小程序管理界面

在这里插入图片描述

填写小程序信息,点击上图中小程序信息栏目的“去填写按钮”,小程序名称一定谨慎填写,每年是有一定修改次数限制的

注意:小程序名称不能重复

在这里插入图片描述

下边配置最关键的appid和密钥,通过左侧菜单找到开发管理菜单,点击“开发管理”菜单进入下图界面,点击“开发设置”

在这里插入图片描述

使用自己的微信扫描二维码生成密钥成功,点击“复制”将密钥和AppID妥善保存,开发小程序要使用

AppID(小程序ID):wxec21e59c983b806f

AppSecret(小程序密钥) :758cd204a5e49a9c5df95e1b48ca4d70

在这里插入图片描述

3.创建jzo2o-customer在这里插入图片描述

小程序账号申请成功,下边部署配置后端程序

客户管理工程jzo2o-customer提供了小程序认证接口支持,jzo2o-customer通过jzo2o-publics请求微信获取openid

下边创建jzo2o-customer工程,创建过程参考jzo2o-foundations工程,工程创建完成修改bootstrap-dev.yml配置文件:

接下来进入nacos修改jzo2o-publics.yaml中小程序的appid和密钥

在这里插入图片描述

小程序认证需要启动的微服务包括:网关jzo2o-gateway、客户管理jzo2o-customer、公共服务jzo2o-publics,将其它服务也正常启动,启动这三个微服务成功,下边开始部署前端

4.部署前端

用户端是基于微信小程序开发的,首先需要下载并安装微信开发者工具

配置小程序开发环境

打开微信开发者工具,初次使用弹出身份确认,如下图,使用申请小程序账号时用的微信进行扫码,扫码通过进入下边的界面:

在这里插入图片描述

进入添加小程序项目界面

目录:选择小程序前端工程的 project-xzb-xcx-uniapp-java\unpackage\dist\dev\mp-weixin目录

AppID:填写申请小程序号获取的AppID

选择不使用云服务

在这里插入图片描述

修改project-xzb-xcx-uniapp-java\unpackage\dist\dev\mp-weixin\utils\env.js 配置文件,指定后端网关的地址

在这里插入图片描述

设置代理

在这里插入图片描述

在这里插入图片描述

如果要选择其它目录可以关闭当前项目,重新选择

在这里插入图片描述

5.编译运行

小程序认证需要启动的微服务包括:网关jzo2o-gateway、客户管理jzo2o-customer、公共服务jzo2o-publics,保证这三个服务全部启动

注意:保证jzo2o-publics服务配置高德地图key(参考:高德地图web服务配置文档)、微信的appid和app密钥。配置完成将jzo2o-publics服务重新启动。

首先清除缓存

在这里插入图片描述

然后编译运行

在这里插入图片描述

编译运行到登录界面

在这里插入图片描述

点击“快速登录”按照前边讲的小程序认证流程进行操作,请求认证接口进行认证,进入调试器–>Network观察请求记录

在这里插入图片描述

认证接口的地址是:/customer/open/login/common/user

此接口最终从微信拿到用户的openid(微信给用户分配的唯一标识),并将openid存储到数据库,认证通过生成token令牌返回给前端

认证通过进入下边的界面

在这里插入图片描述

7.小结

首先申请小程序账号,然后配置后端工程(网关jzo2o-gateway、客户管理jzo2o-customer、公共服务jzo2o-publics)、保证启动成功

再部署前端工程,这里需要安装微信小程序开发工具等,最后编译运行前端工程测试认证流程,测试过程可进入调试界面跟踪前后端的交互数据

1.2.2 阅读代码

1.小程序认证流程

整个过程包括三部分:

小程序:即前端程序

开发者服务器:后端微服务程序

微信接口服务:即微信服务器

具体的流程如下:

1.前端调用wx.login()获取登录凭证code

2.前端请求后端进行认证,发送code

3.后端请求微信获取openid

4.后端生成认证成功凭证返回给前端

在这里插入图片描述

根据官方的认证流程我们定义本项目小程序认证的交互流程:

customer工程提供认证接口,publics工程作为一个公共服务提供与微信通信的接口

前端与cutomer交互不与publics交互

token包含用户信息

在这里插入图片描述

2.阅读代码

下边根据认证流程阅读代码,我们以断点调试的方式跟踪接口交互过程

customer提供的小程序认证接口

前端点击快速登录,授权获取手机号,请求jzo2o-customer的普通用户登录接口LoginController,普通用户登录接口如下:

在这里插入图片描述

customer请求publics申请获取openid

和微信相关的都在publics,publics服务获取openid接口InnerWechatController如下:

在这里插入图片描述

publics请求weixin 获取openid

在这里插入图片描述

customer收到openid查询数据库获取用户信息并生成token.

openid是微信用户在家政o2o平台的唯一标识,首先根据openid查询jzo2o-customer的common_user表,是否存在用户,如果不存在则自动注册用户信息,用户信息token存储到jzo2o-customer数据库的common_user表中

在这里插入图片描述

common_user表的结构如下:

create table `jzo2o-customer`.common_user
(
    id   bigint not null comment '用户id' constraint `PRIMARY` primary key,
    status  int default 0   not null comment '状态,0:正常,1:冻结',
    nickname  varchar(255) null comment '昵称',
    phone     varchar(25)  null comment '电话',
    avatar    varchar(255) null comment '头像',
    open_id   varchar(100) null,account_lock_reason varchar(255) null comment '账号冻结原因',
    create_time datetime default CURRENT_TIMESTAMP not null comment '创建时间',
    update_time datetime default CURRENT_TIMESTAMP not null on update CURRENT_TIMESTAMP comment '更新时间',
    is_deleted  int  default 0  not null
) charset = utf8mb4;

认证通过生成用户token返回给前端

在这里插入图片描述

token令牌的格式我们使用的是JWT格式,JWT是一种常用的令牌格式,它可以防篡改

在JWT令牌中存储了当前登录用户的信息(json),包括如下属性:

用户id: id,对应common_user表的主键
用户名称:String name,对应common_user表的nickname字段
用户头像:String avatar,对应common_user表的avatar字段
用户类型:Integer userType,c端用户的用户类型代码为1,具体定义在common.constants.UserType中

网关对token统一校验

在网关对token进行解析校验,token不合法直接返回失败信息,token合法解析出用户信息放在http的head中继续请求微服务

在这里插入图片描述

在微服务中解析http头信息中的用户信息,写入ThreadLocal方便应用程序使用

在这里插入图片描述

1.3 手机验证码认证

1.3.1 测试手机验证码认证

服务人员使用APP登录平台使用的是手机验证码认证方式,整个认证流程也需要部署前端、后端

客户管理工程jzo2o-customer与公共服务jzo2o-publics提供手机验证码的接口,这两个服务在小程序认证时已经部署这里不再部署,我们只需要部署前端工程即可

1.部署前端

服务端的前端工程需要使用 HBuilder 3.8.7 X 软件编译运行,启动HBuilderX,打开project-xzb-app-uniapp-java目录

在这里插入图片描述

配置网关地址,配置完成,使用HBuilderX运行到浏览器

在这里插入图片描述

运行成功进入登录页面:

在这里插入图片描述

2.认证测试

首先输入手机号,服务人员的信息存储在jzo2o-customer数据库的serve_provider表中,从表中找一个手机号录入

点击发送验证码,此时前端请求后端发送验证码,在开发环境我们从控制台获取验证码,稍后后带大家分析发送验证码的程序

注意此时因为请求后端发送验证码我们观察在浏览器的Network窗口有一条记录,如下图,该请求必须响应状态为200方可正常发送验证

在这里插入图片描述

从控制台获取刚才发送的验证码

在这里插入图片描述

将从控制台获取的验证码填入验证码输入框

在这里插入图片描述

点击登录进行认证,认证过程会先校验验证码是否正确,如果验证码正确再根据手机号查询serve_provider表是否存在相应记录且用户未被冻结,全部成功则认证通过。

认证通过进入首页。

在这里插入图片描述

1.3.2 阅读代码

1.手机验证码认证流程

customer工程提供认证接口,publics工程作为一个公共服务提供与发送验证码接口

在这里插入图片描述

2.阅读代码

1.找到具体的接口

前端请求publics服务发送验证码接口:publics/sms-code/send

在这里插入图片描述

在这里插入图片描述

具体发送验证码逻辑:

在这里插入图片描述

前端请求customer服务的认证接口:/customer/open/login/worker,代码如下:

在这里插入图片描述

机构和和服务人员认证接口是同一个,根据类型判断是机构还是服务人员,下图中红色箭头指向的代码是服务人员认证的方法

在这里插入图片描述

customer服务请求publics服务校验验证码

在这里插入图片描述

publics服务提供校验验证码接口,如下图:

在这里插入图片描述

2.具体校验验证码逻辑

具体的验证码校验逻辑是先查询redis中的正确的验证码,再和用户输入的进行对比,如果不一致则说明输入错误,输入正确删除验证码

在这里插入图片描述

在使用redisTemplate时需要在工程中引入下边的依赖:

<dependency>
    <groupId>com.jzo2o</groupId>
    <artifactId>jzo2o-redis</artifactId>
</dependency>

在jzo2o-redis中定义了redisTemplate的定义,如下图:

在这里插入图片描述

在使用时注入上图中定义的redisTemplate即可

在测试验证码发送时可以打开redis进行跟踪,下图显示了存入redis中的验证码,注意观察key和value:

在这里插入图片描述

3.自动注册

校验验证码完成customer服务根据手机号查询数据库,如果用户冻结则认证失败,如果用户不存在则自动注册

在这里插入图片描述

服务人员和机构都存储到serve_provider表,结果如下:

create table `jzo2o-customer`.serve_provider
(
    id  bigint not null comment '主键'  constraint `PRIMARY`  primary key,
    code  varchar(255)  null comment '编号',
    type int    not null comment '类型,2:服务人员,3:服务机构',
    name  varchar(255)   null comment '姓名',
    phone  varchar(255)  not null comment '电话',
    avatar  varchar(255)  null comment '头像',
    status   int   not null comment '状态,0:正常,1:冻结',
    settings_status  int  default 0  null comment '首次设置状态,0:未完成设置,1:已完成设置',
    password  varchar(255)  null comment '机构登录密码',
    account_lock_reason varchar(255)  null comment '账号冻结原因',
    score   double        null comment '综合评分',
    good_level_rate  varchar(50)  null comment '好评率',
    create_time  datetime default CURRENT_TIMESTAMP not null comment '创建时间',
    update_time  datetime default CURRENT_TIMESTAMP not null on update CURRENT_TIMESTAMP comment '更新时间',
    is_deleted int default 0  not null comment '是否已删除,0:未删除,1:已删除',
  constraint serve_provider_phone_type_uindex  unique (phone, type)
) comment '服务人员/机构表' charset = utf8mb4;

最后生成token返回给前端

在这里插入图片描述

注意:为了方便验证码测试前端会自动填入123456,更改验证码发送接口固定生成的验证码为123456

在这里插入图片描述

1.4 完成机构注册功能开发

界面原型:进入登录页面,点击“去注册”进入注册页面

在这里插入图片描述

在这里插入图片描述

接口定义如下:

接口地址:POST/customer/open/serve-provider/institution/register

在这里插入图片描述

注意:机构端注册和服务端注册完成要向serve_provider表写入数据,具体查阅上图的方法。

密码加密方式:使用BCrypt方式,BCrypt是一种密码哈希函数,通常用于存储用户密码的安全性。它是基于 Blowfish 密码算法的一种单向哈希函数

在这里插入图片描述

测试方法:

public static void main(String[] args) {
    BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
    /**
     $2a$10$1sp7I0OdYH3Azs/2lK8YYeuiaGZzOGshGT9j.IYArZftsGNsXqlma
     $2a$10$m983E2nmJ7ITlesbXzjbzO/M7HL2wP8EgpgX.pPACDm1wG38Lt.na
     $2a$10$rZvathrW98vVPenLhOnl0OMpUtRTdBkWJ45IkIsTebITS9AFgKqGK
     $2a$10$2gaMKWCRoKdc42E0jsq7b.munjzOSPOM4yr3GG9M6194E7dOH5LyS
     $2a$10$I/n93PIKpKL8m4O3AuT5kuZncZhfqV51bfx5sJrplnYoM7FimdboC
     */
    for (int i = 0; i < 5; i++) {
        //对密码进行哈希
        String encode = passwordEncoder.encode("11111");
        System.out.println(encode);
    }
    //校验哈希串和密码是否匹配
    boolean matches = passwordEncoder.matches("11111", "$2a$10$m983E2nmJ7ITlesbXzjbzO/M7HL2wP8EgpgX.pPACDm1wG38Lt.na");
    System.out.println(matches);
}

根据上边的测试代码可知,BCrypt的使用方法如下:

用户输入密码,通过passwordEncoder.encode(“输入的密码”)得到哈希串,将哈希串存储到数据库。

用户登录校验密码,从数据库取出哈希串,连同用户输入的密码,调用下边的方法:

passwordEncoder.matches(“用户输入的密码”, “从数据库查询的密码哈希串”);

1.4.1 mapper

单表查询,用mybatisplus即可

1.4.2 service

在com.jzo2o.customer.service.IServeProviderService接口:

package com.jzo2o.customer.service;

/**
 * 服务人员/机构表 服务类
 */
public interface IServeProviderService extends IService<ServeProvider> {

    /**
     * 机构人员注册
     */
    ServeProvider registerInstitution(InstitutionRegisterReqDTO institutionRegisterReqDTO);

}

实现:

package com.jzo2o.customer.service.impl;

/**
 * 服务人员/机构表 服务实现类
 */
@Service
public class ServeProviderServiceImpl extends ServiceImpl<ServeProviderMapper, ServeProvider> implements IServeProviderService {

    /**
     * 机构人员注册
     */
    @Override
    public ServeProvider registerInstitution(InstitutionRegisterReqDTO institutionRegisterReqDTO) {
        
        //1.校验手机验证码是否正确
        //1.1.数据校验
        if(StringUtils.isEmpty(institutionRegisterReqDTO.getVerifyCode())){
            throw new BadRequestException("验证码错误,请重新获取");
        }
        //1.2.远程调用publics服务校验验证码是否正确
        boolean verifyResult = smsCodeApi.verify(institutionRegisterReqDTO.getPhone(), SmsBussinessTypeEnum.INSTITION_REGISTER, institutionRegisterReqDTO.getVerifyCode()).getIsSuccess();
        if(!verifyResult) {
            throw new BadRequestException("验证码错误,请重新获取");
        }
        
        //2.检查手机号是否被注册过
        BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
        String encode = passwordEncoder.encode(institutionRegisterReqDTO.getPassword());
        ServeProvider serveProvider = add(institutionRegisterReqDTO.getPhone(), UserType.INSTITUTION, encode);
        return serveProvider;
    }


}
1.4.3 测试

手机号随便输入

在这里插入图片描述

在这里插入图片描述

成功返回,查看数据库

在这里插入图片描述

1.5 完成忘记密码功能开发

界面原型:进入登录页面,点击“忘记密码”进入找回密码页面

在这里插入图片描述

在这里插入图片描述

接口定义如下:

接口名称:机构登录密码重置接口

接口路径:POST/customer/agency/serve-provider/institution/resetPassword

在这里插入图片描述

设计须知:

首先校验验证码是否正确

校验手机号是否存在数据库

通过校验最后修改密码,密码的加密方式参考机构注册接口

1.5.1 mapper

单表查询,用mybatisplus即可,不用自己去写SQL语句

1.5.2 service

在com.jzo2o.customer.service.IServeProviderService接口

package com.jzo2o.customer.service;

/**
 * 服务人员/机构表 服务类
 */
public interface IServeProviderService extends IService<ServeProvider> {

    /**
     * 忘记密码
     */
    ServeProvider resetPassword(InstitutionResetPasswordReqDTO institutionResetPasswordReqDTO);
}

InstitutionResetPasswordReqDTO,前端传递过来的

package com.jzo2o.customer.model.dto.request;

@Data
@ApiModel("机构密码重置接口")
public class InstitutionResetPasswordReqDTO {
    @ApiModelProperty(value = "新密码",required = true)
    private String password;

    @ApiModelProperty(value = "手机号",required = true)
    private String phone;

    @ApiModelProperty(value = "短信验证码",required = true)
    @NotNull(message = "验证码错误,请重新输入")
    private String verifyCode;

}

实现:

package com.jzo2o.customer.service.impl;

@Service
public class ServeProviderServiceImpl extends ServiceImpl<ServeProviderMapper, ServeProvider> implements IServeProviderService {

    /**
     * 忘记密码
     */
    @Override
    public ServeProvider resetPassword(InstitutionResetPasswordReqDTO institutionResetPasswordReqDTO) {

        //0.校验手机号是否存在
        ServeProvider existServeProvider = lambdaQuery().eq(ServeProvider::getPhone, institutionResetPasswordReqDTO.getPhone()).one();
        if (existServeProvider == null) {
            throw new BadRequestException("手机号不存在");
        }

        //1.校验手机验证码是否正确
        //1.1.数据校验
        if (StringUtils.isEmpty(institutionResetPasswordReqDTO.getVerifyCode())){
            throw new BadRequestException("验证码不能为空");
        }
        //1.2.远程调用publics服务校验验证码是否正确
        boolean verifyResult = smsCodeApi.verify(institutionResetPasswordReqDTO.getPhone(), SmsBussinessTypeEnum.INSTITUTION_RESET_PASSWORD, institutionResetPasswordReqDTO.getVerifyCode()).getIsSuccess();
        if(!verifyResult) {
            throw new BadRequestException("验证码错误,请重新获取");
        }

        //2.修改密码
        BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
        String encode = passwordEncoder.encode(institutionResetPasswordReqDTO.getPassword());
        boolean update = lambdaUpdate().eq(ServeProvider::getPhone, institutionResetPasswordReqDTO.getPhone())
                .set(ServeProvider::getPassword, encode)
                .update();

        if (!update) {
            throw new BadRequestException("修改密码失败");
        }
        
        existServeProvider.setPassword(encode);
        return existServeProvider;
    }

}
1.5.3 controller

在com.jzo2o.customer.controller.agency.ServeProviderController中

package com.jzo2o.customer.controller.agency;

/**
 * 服务人员/机构表 前端控制器
 */
@RestController("agencyServeProviderController")
@RequestMapping("/agency/serve-provider")
@Api(tags = "机构端 - 服务人员或机构相关接口")
public class ServeProviderController {
    @Resource
    private IServeProviderService serveProviderService;

    @PostMapping("/institution/resetPassword")
    @ApiOperation("机构人员重置密码")
    public void resetPassword(@RequestBody InstitutionResetPasswordReqDTO institutionResetPasswordReqDTO) {
        serveProviderService.resetPassword(institutionResetPasswordReqDTO);
    }

}

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

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

相关文章

html全局遮罩,通过websocket来实现实时发布公告

1.index.html代码示例 <div id"websocket" style"display:none;position: absolute;color:red;background-color: black;width: 100%;height: 100%;z-index: 100; opacity: 0.9; padding-top: 30%;padding-left: 30%; padding-border:1px; "onclick&q…

Mysql 主从复制原理及其工作过程,配置一主两从实验

主从原理&#xff1a;MySQL 主从同步是一种数据库复制技术&#xff0c;它通过将主服务器上的数据更改复制到一个或多个从服务器&#xff0c;实现数据的自动同步。 主从同步的核心原理是将主服务器上的二进制日志复制到从服务器&#xff0c;并在从服务器上执行这些日志中的操作…

C++的auto_ptr智能指针:从诞生到被弃用的历程

C作为一种功能强大的编程语言&#xff0c;为开发者提供了众多便捷的特性和工具&#xff0c;其中智能指针是其重要特性之一。智能指针能够自动管理内存&#xff0c;有效避免内存泄漏等常见问题。然而&#xff0c;并非所有智能指针都尽善尽美&#xff0c;auto_ptr便是其中的一个例…

Spring Security 6.X + JWT + RBAC 权限管理实战教程(上)

前言 本教程基于 Spring Boot 3.x Spring Security 6.x 实现&#xff0c;采用 JWT Redis 的认证方案&#xff0c;结合 RBAC 权限模型&#xff0c;实现了一个完整的权限管理系统。 一、项目依赖配置 关键依赖说明&#xff1a; <!-- SpringWeb --><dependency><…

flutter 常用UI组件

文章目录 1. Toast 文本提示框oktoastbot_toast2. loading 加载窗flutter_easyloading3. 对话框gex dialog4.下拉刷新pull_to_refresh5. pop 窗custom_pop_up_menu6. pin code 密码框pinput7. 二维码qr_flutter8. swiper 滚动组件carousel_sliderflutter_swiper_view9. Badge 角…

《汽车维修技师》是什么级别的期刊?是正规期刊吗?能评职称吗?

​问题解答&#xff1a; 问&#xff1a;《汽车维修技师》是不是核心期刊&#xff1f; 答&#xff1a;不是&#xff0c;是知网收录的正规学术期刊。 问&#xff1a;《汽车维修技师》级别&#xff1f; 答&#xff1a;省级。主管单位&#xff1a;北方联合出版传媒&#xff08;…

大语言模型的语境中“越狱”和思维链

大语言模型的语境中“越狱”和思维链 越狱(Jailbreaking) 含义:在大语言模型的语境中,“越狱”是指用户试图绕过语言模型的安全限制和使用规则,让模型生成违反伦理道德、包含有害内容(如暴力、歧视、恶意软件代码等)的输出。这些安全限制是由模型开发者设置的,目的是确…

【Rust自学】13.2. 闭包 Pt.2:闭包的类型推断和标注

13.2.0. 写在正文之前 Rust语言在设计过程中收到了很多语言的启发&#xff0c;而函数式编程对Rust产生了非常显著的影响。函数式编程通常包括通过将函数作为值传递给参数、从其他函数返回它们、将它们分配给变量以供以后执行等等。 在本章中&#xff0c;我们会讨论 Rust 的一…

Spring篇 解决因为Bean的循环依赖——理论篇

Spring Bean 循环依赖 循环依赖是指两个或多个 Bean 互相依赖&#xff0c;形成一个闭环。例如&#xff0c;A 依赖 B&#xff0c;B 又依赖 A。Spring则 提供了几种方式来解决这种循环依赖问题。 常见的几类 Bean 循环依赖场景 场景1&#xff1a; 解释&#xff1a;由于Bean A依…

三天急速通关Java基础知识:Day1 基本语法

三天急速通关JAVA基础知识&#xff1a;Day1 基本语法 0 文章说明1 关键字 Keywords2 注释 Comments2.1 单行注释2.2 多行注释2.3 文档注释 3 数据类型 Data Types3.1 基本数据类型3.2 引用数据类型 4 变量与常量 Variables and Constant5 运算符 Operators6 字符串 String7 输入…

Excel 技巧10 - 如何检查输入重复数据(★★)

本文讲了如何在Excel中通过COUNTIF来检查输入重复数据。 当输入重复数据时&#xff0c;显示错误提示。 1&#xff0c;通过COUNTIF来检查输入重复数据 比如下面是想检查不要输入重复的学号。 选中C列&#xff0c;点 Menu > 数据 > 数据验证 在数据验证页面&#xff0c…

请求响应-

一.DispatcherServlet 前端控制器 二.HttpServletRequest 请求:获取请求数据 三.HttpServletResponse 响应:设置响应数据 四.简单参数接收 简单参数:参数名与形参变量名相同,定义形参即可接收参数。 如果参数对应不上需要通过RequestParam完成映射,注意事项:加上了参数就必须…

MySQL中的GROUP_CONCAT函数将分组后的多个行值合并成一个字符串,并用指定分隔符连接

文章目录 前言什么是GROUP_CONCAT&#xff1f;基本语法 使用示例示例1: 基本用法示例2: 去重并排序 高级应用应用场景示例注意事项 结论表结构1. Orders 表 (订单表)2. Order_Details 表 (订单详情表) 示例数据Orders 表的数据Order_Details 表的数据 使用 GROUP_CONCAT 的查询…

游戏开发中常用的设计模式

目录 前言一、工厂模式二、单例模式三、观察者模式观察者模式的优势 四、状态模式状态模式的优势 五、策略模式策略模式的优势策略模式与状态模式有什么区别呢? 六、组合模式七、命令模式八、装饰器模式 前言 本文介绍了游戏开发中常用的设计模式&#xff0c;如工厂模式用于创…

【前端】用OSS增强Hexo的搜索功能

文章目录 前言配置 _config.fluid.yml云端实时更新 local-search.xml解决 OSS.Bucket 的跨域问题 前言 原文地址&#xff1a;https://blog.dwj601.cn/FrontEnd/Hexo/hexo-enhance-local-search-with-oss/ 考虑到某著名云服务商提供的云服务器在两年的 99 计划后续费价格高达四…

Redis和MongoDB的区别

前言 在项目选型阶段&#xff0c;MongoDB被选中主要是基于其处理大规模数据集的能力&#xff0c;而当时并未深入探讨其他替代方案。此前&#xff0c;Redis被用于管理少量但访问频繁的热数据。目前&#xff0c;项目采用MongoDB存储百万级数据&#xff0c;预计未来数据量将增长至…

[JavaScript] 深入理解流程控制结构

文章目录 1. **if-else 语句**基本语法&#xff1a;示例&#xff1a;扩展&#xff1a;else if 2. **switch-case 语句**基本语法&#xff1a;示例&#xff1a;注意事项&#xff1a; 3. **for 循环**基本语法&#xff1a;示例&#xff1a;扩展&#xff1a;for-in 和 for-of 4. *…

渗透笔记1

第一天 工具&#xff1a;cs cobalt strike 4.9 / msf kali &#xff08;自带 Ubuntu&#xff09; cs cobalt strike 4.9&#xff1a;server-client server部署在云服务器上&#xff0c;client分别在各地&#xff0c;与server相连接&#xff1b;连接上后就可以共享上线主机。…

C#--在多线程中使用任务并行库(TPL)--15

目录 一.任务并行库的概念以及定义 二.主要特性 三.代码使用示例 1.最基础的Parallel.For使用方式 2.使用 ParallelOptions 来控制并行执行 3.Parallel.ForEach的使用(用于处理集合) 4.带有本地变量的并行循环(用于需要累加或统计的场景) 5.结合Task和Parallel的高级示…

与“神”对话:Swift 语言在 2025 中的云霓之望

0. 引子 夜深人静&#xff0c;是一片极度沉醉的黑&#xff0c;这便于我与深沉的 macbook 悄悄隐秘于其中。一股异香袭来&#xff0c;恍惚着&#xff0c;撸码中身心极度疲惫、头脑昏沉的我仿佛感觉到了一束淡淡的微光轻洒在窗边。 我的对面若隐若现逐渐浮现出一个熟悉的身影。他…