目前主流采用手机号注册方式,因为收集到手机号对用户推广、业务推广有极其重要的价值。结合上篇采用阿里云短信服务实现手机验证码的发送,这里整合实现用手机号实现用户注册。
思路:前端在输入手机号之后,需要对手机号进行校验,用户需要接收短信验证码并完成验证码校验之后即可成功注册。具体步骤:
1、判断当前手机号是否已注册;
2、调用阿里云短信服务api实现验证码发送;
3、验证码发送成功并存放至redis缓存,利用缓存淘汰机制(设置有效时间)实现验证码过期;
4、验证码校验,通过即注册成功。
package com.zhmsky.service_ucenter.entity;
import com.baomidou.mybatisplus.annotation.*;
import java.util.Date;
import java.io.Serializable;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.EqualsAndHashCode;
/**
* <p>
* 会员表
* </p>
*
* @author zhmsky
* @since 2022-07-16
*/
@Data
@EqualsAndHashCode(callSuper = false)
@ApiModel(value="UcenterMember对象", description="会员表")
public class UcenterMember implements Serializable {
private static final long serialVersionUID = 1L;
@ApiModelProperty(value = "会员id")
@TableId(value = "id", type = IdType.ASSIGN_ID)
private String id;
@ApiModelProperty(value = "微信openid")
private String openid;
@ApiModelProperty(value = "手机号")
private String mobile;
@ApiModelProperty(value = "密码")
private String password;
@ApiModelProperty(value = "昵称")
private String nickname;
@ApiModelProperty(value = "性别 1 女,2 男")
private Integer sex;
@ApiModelProperty(value = "年龄")
private Integer age;
@ApiModelProperty(value = "用户头像")
private String avatar;
@ApiModelProperty(value = "用户签名")
private String sign;
@ApiModelProperty(value = "是否禁用 1(true)已禁用, 0(false)未禁用")
private Boolean isDisabled;
@ApiModelProperty(value = "逻辑删除 1(true)已删除, 0(false)未删除")
private Boolean isDeleted;
@ApiModelProperty(value = "创建时间")
@TableField(fill = FieldFill.INSERT)
private Date createTime;
@ApiModelProperty(value = "更新时间")
@TableField(fill = FieldFill.UPDATE)
private Date updateTime;
}
package com.zhmsky.service_ucenter.entity.VO;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
/**
* @author zhmsky
* @date 2022/7/16 17:18
*/
@Data
@ApiModel(value="注册对象", description="注册对象")
public class RegisterVO {
@ApiModelProperty(value = "昵称")
private String nickname;
@ApiModelProperty(value = "手机号")
private String mobile;
@ApiModelProperty(value = "密码")
private String password;
@ApiModelProperty(value = "验证码")
private String code;
}
调用阿里云短信服务实现短信验证码发送
package com.zhmsky.msmService.service.impl;
import com.aliyuncs.DefaultAcsClient;
import com.aliyuncs.IAcsClient;
import com.aliyuncs.dysmsapi.model.v20170525.SendSmsRequest;
import com.aliyuncs.dysmsapi.model.v20170525.SendSmsResponse;
import com.aliyuncs.exceptions.ClientException;
import com.aliyuncs.exceptions.ServerException;
import com.aliyuncs.profile.DefaultProfile;
import com.zhmsky.msmService.service.MsmService;
import org.springframework.stereotype.Service;
/**
* @author zhmsky
* @date 2022/7/6 21:01
* 短信验证码实现类
*/
@Service
public class MsmServiceImpl implements MsmService {
/**
* 发送短信验证码
* @param phone 手机号
* @param code 被发送的验证码
* @return
*/
@Override
public String sendCodeMsg(String phone, String code) {
String checkCode="";
DefaultProfile profile = DefaultProfile.getProfile("cn-hangzhou", "LTAI5tDfHQPQ5WA5dBkrfFxu", "eRID7ZigveAH7fMRKbCDq92jjRl68R");
IAcsClient client = new DefaultAcsClient(profile);
SendSmsRequest request = new SendSmsRequest();
request.setSignName("阿里云短信测试");
request.setTemplateCode("SMS_154950909");
request.setPhoneNumbers(phone);
request.setTemplateParam("{\"code\":\""+code+"\"}");
try {
SendSmsResponse response = client.getAcsResponse(request);
checkCode = response.getCode();
} catch (ServerException e) {
e.printStackTrace();
} catch (ClientException e) {
System.out.println("ErrCode:" + e.getErrCode());
System.out.println("ErrMsg:" + e.getErrMsg());
System.out.println("RequestId:" + e.getRequestId());
}
return checkCode;
}
}
短信验证码发送接口
package com.zhmsky.msmService.controller;
import com.zhmsky.msmService.service.MsmService;
import com.zhmsky.msmService.utils.RandomUtil;
import com.zhmsky.result.Result;
import com.zhmsky.result.ResultUtil;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.*;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;
/**
* @author zhmsky
* @date 2022/7/6 20:58
*/
@RestController
@Api("短信注册控制器")
@CrossOrigin
@RequestMapping("/msmService")
public class MsmController {
@Autowired
private MsmService msmService;
@Autowired
private RedisTemplate<String,String> redisTemplate;
@GetMapping("/send/{phone}")
@ApiOperation("发送短信验证码")
public Result<String> sendMsg(@PathVariable String phone){
//通过redis设置缓存时间实现验证码过期
String code = redisTemplate.opsForValue().get(phone);
if(!StringUtils.isEmpty(code)){
return new ResultUtil<String>().setSuccessMsg("请勿重复发送!");
}
/** 如果缓存里面没有那么就重新发送 **/
//生成随机验证码
String fourBitRandom = RandomUtil.getFourBitRandom();
//调用阿里云api实现短信发送
String checkCode = msmService.sendCodeMsg(phone, fourBitRandom);
if("OK".equals(checkCode)){
//将验证码保存到redis中并设置有效时间为5分钟
redisTemplate.opsForValue().set(phone,fourBitRandom,5, TimeUnit.MINUTES);
return new ResultUtil<String>().setData(fourBitRandom,"验证码发送成功!");
}else{
return new ResultUtil<String>().setErrorMsg("验证码发送给失败!");
}
}
}
1、接口保护,参数非空判断;
2、验证手机号是否已注册;
3、验证码校验;
4、入库
/**
* 用户注册
* @param registerVO
* @return
*/
@Override
public boolean register(RegisterVO registerVO) {
//获取注册数据,接口保护,参数校验
String code = registerVO.getCode();
String mobile = registerVO.getMobile();
String nickname = registerVO.getNickname();
String password = registerVO.getPassword();
if(StringUtils.isEmpty(mobile)||StringUtils.isEmpty(password)||StringUtils.isEmpty(code)||StringUtils.isEmpty(nickname)){
throw new MyException(20005,"注册失败!");
}
//判断手机号是否已注册
QueryWrapper<UcenterMember> wrapper = new QueryWrapper<>();
wrapper.eq("mobile",mobile);
Long count = baseMapper.selectCount(wrapper);
if(count>0){
throw new MyException(20005,"注册失败!");
}
//验证码校验
//先从redis中获取验证码
String cacheCode = redisTemplate.opsForValue().get(mobile);
if(!code.equals(cacheCode)){
throw new MyException(20005,"注册失败!");
}
//入库
UcenterMember ucenterMember = new UcenterMember();
ucenterMember.setMobile(mobile);
ucenterMember.setNickname(nickname);
ucenterMember.setPassword(MD5.encrypt(password));
ucenterMember.setIsDisabled(false);
ucenterMember.setAvatar("http://thirdwx.qlogo.cn/mmopen/vi_32/DYAIOgq83eoj0hHXhgJNOTSOFsS4uZs8x1ConecaVOB8eIl115xmJZcT4oCicvia7wMEufibKtTLqiaJeanU2Lpg3w/132");
int insert = baseMapper.insert(ucenterMember);
if(insert>0){
return true;
}else{
return false;
}
}
登录流程:
1、调用登录接口并返回token字符串
2、将返回的token字符串放到cookie里面
3、创建前端拦截器,判断cookie里面是否有token字符串,如果有则将token放到request的header中
4、调用接口,根据token获取用户信息并再次放到cookie中(为了首页面展示)
5、再从cookie中取出用户信息进行展示
思路:
1、接口保护,参数非空校验;
2、验证账号是否注册;
3、验证账号是否禁用;
4、验证密码;
5、登录并返回token。
为了实现单点登录,采用token令牌方式,引入jwt
jwt工具类:
package com.zhmsky.jwt;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jws;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import org.springframework.util.StringUtils;
import javax.servlet.http.HttpServletRequest;
import java.util.Date;
/**
* @author zhmsky
* @date 2022/7/6 17:53
*/
public class JwtUtils {
//设置token过期时间
public static final long EXPIRE = 1000 * 60 * 60 * 24; //一天
//签名加密密钥
public static final String APP_SECRET = "ukc8BDbRigUDaY6pZFfWus2jZWLPHO";
/**
* 生成token
* @param id
* @param nickname
* @return
*/
public static String getJwtToken(String id, String nickname){
String JwtToken = Jwts.builder()
//设置头信息
.setHeaderParam("typ", "JWT")
.setHeaderParam("alg", "HS256")
//设置token过期时间
.setSubject("user") //随便写
.setIssuedAt(new Date())
//当前时间加上设置的过期时间
.setExpiration(new Date(System.currentTimeMillis() + EXPIRE))
//设置token主体,可存储用户信息
.claim("id", id)
.claim("nickname", nickname)
//签名哈希
.signWith(SignatureAlgorithm.HS256, APP_SECRET)
.compact();
return JwtToken;
}
/**
* 判断token是否存在与有效
* @param jwtToken
* @return
*/
public static boolean checkToken(String jwtToken) {
if(StringUtils.isEmpty(jwtToken)) return false;
try {
Jwts.parser().setSigningKey(APP_SECRET).parseClaimsJws(jwtToken);
} catch (Exception e) {
e.printStackTrace();
return false;
}
return true;
}
/**
* 判断token是否存在与有效
* @param request
* @return
*/
public static boolean checkToken(HttpServletRequest request) {
try {
String jwtToken = request.getHeader("token");
if(StringUtils.isEmpty(jwtToken)) return false;
Jwts.parser().setSigningKey(APP_SECRET).parseClaimsJws(jwtToken);
} catch (Exception e) {
e.printStackTrace();
return false;
}
return true;
}
/**
* 根据token获取会员id
* @param request
* @return
*/
public static String getMemberIdByJwtToken(HttpServletRequest request) {
String jwtToken = request.getHeader("token");
if(StringUtils.isEmpty(jwtToken)) return "";
Jws<Claims> claimsJws = Jwts.parser().setSigningKey(APP_SECRET).parseClaimsJws(jwtToken);
Claims claims = claimsJws.getBody();
return (String)claims.get("id");
}
}
登录业务:
/**
* 用户登录
* @param member
* @return token
*/
@Override
public String login(UcenterMember member) {
//获取账号和密码
String mobile = member.getMobile();
String password = member.getPassword();
if(StringUtils.isEmpty(mobile)||StringUtils.isEmpty(password)){
throw new MyException(20010,"账号和密码不能为空!");
}
//判断账号和密码是否存在
QueryWrapper<UcenterMember> wrapper = new QueryWrapper<>();
wrapper.eq("mobile",mobile);
UcenterMember ucenterMember = baseMapper.selectOne(wrapper);
if(ObjectUtils.isEmpty(ucenterMember)){
throw new MyException(20011,"账号不存在,请重新输入!");
}
//判断该用户是否被禁用
Boolean isDisabled = ucenterMember.getIsDisabled();
if(isDisabled){
throw new MyException(20013,"该账号已禁用!");
}
//判断密码是否正确
//密码存储肯定是加密的,实际开发中数据库不会存储明文密码
//先将输入的密码加密,再和数据库密码比较
//MD5加密
String realPassword = ucenterMember.getPassword();
if(!MD5.encrypt(password).equals(realPassword)){
throw new MyException(20012,"密码错误,请重新输入!");
}
//登录成功,返回token(通过查出来的用户数据去生成token)
return JwtUtils.getJwtToken(ucenterMember.getId(), ucenterMember.getNickname());
}
登录接口:
@PostMapping ("/login")
@ApiOperation("用户登录")
public Result<String> login(@RequestBody(required = false) UcenterMember ucenterMember){
//登录生成token并返回
String token = memberService.login(ucenterMember);
return new ResultUtil<String>().setData(token);
}
登录成功后,前端每次请求都携带token,从request对象中获取token再解析token获取用户信息。
@GetMapping("/getUserInfo")
@ApiOperation("根据token获取用户信息")
public Result<UcenterMember> getUserInfo(HttpServletRequest httpServletRequest){
//从request对象中获取token,再根据token获取用户信息
String userId = JwtUtils.getMemberIdByJwtToken(httpServletRequest);
//根据用户id获取用户信息
UcenterMember ucenterMember = memberService.getById(userId);
return new ResultUtil<UcenterMember>().setData(ucenterMember);
}
网站应用微信登录是基于OAuth2.0协议标准构建的微信OAuth2.0授权登录系统。
在进行微信OAuth2.在进行微信OAuth2.0授权登录接入之前,在微信开放平台注册开发者帐号,并拥有一个已审核通过的网站应用,并获得相应的AppID和AppSecret,申请微信登录且通过审核后,可开始接入流程。


appid:微信开放平台申请通过后颁发的唯一标识
redirect_uri:微信扫码授权后的回调地址
response_type:code
scope:授权作用域,web应用直接填snsapi_login即可
准备好以上参数,在properties文件中完成初始值设置
wx.open.app_id=wxed9954c01bb89b47
wx.open.app_secret=a7482517235173ddb4083788de60b90e
wx.open.redirect_url=http://localhost:8160/api/ucenter/wx/callback
编写参数初始化工具类:
package com.zhmsky.service_ucenter.utils;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
/**
* @author zhmsky
* @date 2022/7/17 17:06
*/
@Component
public class ConstWxUtil implements InitializingBean {
@Value("${wx.open.app_id}")
private String appId;
@Value("${wx.open.app_secret}")
private String appSecret;
@Value("${wx.open.redirect_url}")
private String redirectUrl;
public static String WX_OPEN_APP_ID;
public static String WX_OPEN_APP_SECRET;
public static String WX_OPEN_REDIRECT_URL;
@Override
public void afterPropertiesSet() throws Exception {
WX_OPEN_APP_ID = appId;
WX_OPEN_APP_SECRET = appSecret;
WX_OPEN_REDIRECT_URL = redirectUrl;
}
}
二维码生成接口:
@GetMapping("/getWxCode")
@ApiOperation("生成微信二维码")
public String getWxCode() {
// 微信开放平台授权baseUrl
String baseUrl = "https://open.weixin.qq.com/connect/qrconnect" +
"?appid=%s" +
"&redirect_uri=%s" +
"&response_type=code" +
"&scope=snsapi_login" +
"&state=%s" +
"#wechat_redirect";
// 回调地址
String redirectUrl = ConstWxUtil.WX_OPEN_REDIRECT_URL;
try {
redirectUrl = URLEncoder.encode(redirectUrl, "UTF-8"); //url编码
} catch (UnsupportedEncodingException e) {
throw new MyException(20001, e.getMessage());
}
String state = "imhelen";
//生成qrcodeUrl
String qrcodeUrl = String.format(
baseUrl,
ConstWxUtil.WX_OPEN_APP_ID,
redirectUrl,
state);
return "redirect:" + qrcodeUrl;
}
第二步:微信扫码后执行回调
@GetMapping("/callback")
@ApiOperation("微信扫码确认后执行回调")
public String callback(String code,String state){
//TODO
return "redirect:http://localhost:3000";
}
再接着,

获取随机code,请求微信资源服务器固定地址拿到accessToken(访问凭证)和openId(用户唯一标识),再通过accessToken和openId请求微信资源服务器固定地址拿到扫码人的基本信息。获取到用户基本信息后就可以进行校验完成入库等操作。
@GetMapping("/callback")
@ApiOperation("微信扫码确认后执行回调")
public String callback(String code,String state){
//1、接收code值
//用code去请求微信的固定地址,得到accessToken和openId
//向认证服务器发送请求换取access_token
String baseAccessTokenUrl = "https://api.weixin.qq.com/sns/oauth2/access_token" +
"?appid=%s" +
"&secret=%s" +
"&code=%s" +
"&grant_type=authorization_code";
//带参数的真实认证服务器请求地址
String accessTokenUrl = String.format(baseAccessTokenUrl,
ConstWxUtil.WX_OPEN_APP_ID,
ConstWxUtil.WX_OPEN_APP_SECRET,
code
);
//2、请求认证服务器获取接口调用凭证access_token和用户唯一标识openId
try {
String accessTokenInfo = HttpClientUtils.get(accessTokenUrl);
//将上述json字符串转换成map对象
/*
{
"access_token":"ACCESS_TOKEN",
"expires_in":7200,
"refresh_token":"REFRESH_TOKEN",
"openid":"OPENID",
"scope":"SCOPE",
"unionid": "o6_bmasdasdsad6_2sgVt7hMZOPfL"
}
*/
Gson gson = new Gson();
HashMap mapAccessTokenInfo = gson.fromJson(accessTokenInfo, HashMap.class);
//取出的access_token
String access_token = (String)mapAccessTokenInfo.get("access_token");
//取出的openid
String openid = (String)mapAccessTokenInfo.get("openid");
//3、再通过获取出来的access_token和openid去请求微信开放平台服务器获取扫码人信息
//访问微信的资源服务器,获取用户信息
String baseUserInfoUrl = "https://api.weixin.qq.com/sns/userinfo" +
"?access_token=%s" +
"&openid=%s";
String userInfoUrl = String.format(baseUserInfoUrl, access_token, openid);
//发送请求获取扫码人基本信息
String userInfo = HttpClientUtils.get(userInfoUrl);
/*
{
"openid":"o3_SC5_eI--mIC9ikI2pvTuZhYnk",
"nickname":"Kong",
"sex":0,
"language":"",
"city":"",
"province":"",
"country":"",
"headimgurl":"https:\/\/thirdwx.qlogo.cn\/mmopen\/vi_32\/hAqkcbxzEJzic0WYl9pHDglAvYBI4iagLsSLXb2ialcxa3Au6UmwibSiadGMtbQia0oAzmzq26k2f1ES4q1HbS6aIYuA\/132",
"privilege":[],
"unionid":"oWgGz1OqVll-tTU4R_DM_zRp7Rjc"
}
*/
//将上面的json字符串转换成map对象
HashMap mapUserInfo = gson.fromJson(userInfo, HashMap.class);
//扫码人基础信息
String nickname = (String)mapUserInfo.get("nickname");
String headImgurl=(String)mapUserInfo.get("headimgurl");
String openId=(String)mapUserInfo.get("openid");
//扫码后自动注册(入库)
//先判断是否已注册
boolean isExist = memberService.getUserOpenId(openId);
if(!isExist){
//入库
UcenterMember member = new UcenterMember();
member.setNickname(nickname);
member.setOpenid(openid);
member.setAvatar(headImgurl);
memberService.save(member);
}
UcenterMember ucenterMember = memberService.getUserByOpenId(openId);
String token = JwtUtils.getJwtToken(ucenterMember.getId(), ucenterMember.getNickname());
//因为端口号不同存在跨域问题,cookie不能跨域,所以这里使用url重写
return "redirect:http://localhost:3000?token="+token;
} catch (Exception e) {
e.printStackTrace();
throw new MyException(20010,"登录失败!");
}
}
总结:
实现微信授权登录就好比开宝箱,一共需要3把钥匙,第一把钥匙是appid(这个需要在微信开放平台完成注册和认证由平台颁发);通过appid请求固定地址可以生成微信二维码;用户扫描二维码授权后拿到第二把钥匙code(随机唯一值);再通过code去请求固定服务器地址拿到第三把钥匙openid(用户唯一标识)和accessToken(访问凭证);最后再通过openid和accessToken请求固定地址拿到微信用户基本信息。
我试图获取一个长度在1到10之间的字符串,并输出将字符串分解为大小为1、2或3的连续子字符串的所有可能方式。例如:输入:123456将整数分割成单个字符,然后继续查找组合。该代码将返回以下所有数组。[1,2,3,4,5,6][12,3,4,5,6][1,23,4,5,6][1,2,34,5,6][1,2,3,45,6][1,2,3,4,56][12,34,5,6][12,3,45,6][12,3,4,56][1,23,45,6][1,2,34,56][1,23,4,56][12,34,56][123,4,5,6][1,234,5,6][1,2,345,6][1,2,3,456][123
我主要使用Ruby来执行此操作,但到目前为止我的攻击计划如下:使用gemsrdf、rdf-rdfa和rdf-microdata或mida来解析给定任何URI的数据。我认为最好映射到像schema.org这样的统一模式,例如使用这个yaml文件,它试图描述数据词汇表和opengraph到schema.org之间的转换:#SchemaXtoschema.orgconversion#data-vocabularyDV:name:namestreet-address:streetAddressregion:addressRegionlocality:addressLocalityphoto:i
我有一个用户工厂。我希望默认情况下确认用户。但是鉴于unconfirmed特征,我不希望它们被确认。虽然我有一个基于实现细节而不是抽象的工作实现,但我想知道如何正确地做到这一点。factory:userdoafter(:create)do|user,evaluator|#unwantedimplementationdetailshereunlessFactoryGirl.factories[:user].defined_traits.map(&:name).include?(:unconfirmed)user.confirm!endendtrait:unconfirmeddoenden
question的一些答案关于redirect_to让我想到了其他一些问题。基本上,我正在使用Rails2.1编写博客应用程序。我一直在尝试自己完成大部分工作(因为我对Rails有所了解),但在需要时会引用Internet上的教程和引用资料。我设法让一个简单的博客正常运行,然后我尝试添加评论。靠我自己,我设法让它进入了可以从script/console添加评论的阶段,但我无法让表单正常工作。我遵循的其中一个教程建议在帖子Controller中创建一个“评论”操作,以添加评论。我的问题是:这是“标准”方式吗?我的另一个问题的答案之一似乎暗示应该有一个CommentsController参
华为OD机试题本篇题目:明明的随机数题目输入描述输出描述:示例1输入输出说明代码编写思路最近更新的博客华为od2023|什么是华为od,od薪资待遇,od机试题清单华为OD机试真题大全,用Python解华为机试题|机试宝典【华为OD机试】全流程解析+经验分享,题型分享,防作弊指南华为o
在应用开发中,有时候我们需要获取系统的设备信息,用于数据上报和行为分析。那在鸿蒙系统中,我们应该怎么去获取设备的系统信息呢,比如说获取手机的系统版本号、手机的制造商、手机型号等数据。1、获取方式这里分为两种情况,一种是设备信息的获取,一种是系统信息的获取。1.1、获取设备信息获取设备信息,鸿蒙的SDK包为我们提供了DeviceInfo类,通过该类的一些静态方法,可以获取设备信息,DeviceInfo类的包路径为:ohos.system.DeviceInfo.具体的方法如下:ModifierandTypeMethodDescriptionstatic StringgetAbiList()Obt
C#实现简易绘图工具一.引言实验目的:通过制作窗体应用程序(C#画图软件),熟悉基本的窗体设计过程以及控件设计,事件处理等,熟悉使用C#的winform窗体进行绘图的基本步骤,对于面向对象编程有更加深刻的体会.Tutorial任务设计一个具有基本功能的画图软件**·包括简单的新建文件,保存,重新绘图等功能**·实现一些基本图形的绘制,包括铅笔和基本形状等,学习橡皮工具的创建**·设计一个合理舒适的UI界面**注明:你可能需要先了解一些关于winform窗体应用程序绘图的基本知识,以及关于GDI+类和结构的知识二.实验环境Windows系统下的visualstudio2017C#窗体应用程序三.
MIMO技术的优缺点优点通过下面三个增益来总体概括:阵列增益。阵列增益是指由于接收机通过对接收信号的相干合并而活得的平均SNR的提高。在发射机不知道信道信息的情况下,MIMO系统可以获得的阵列增益与接收天线数成正比复用增益。在采用空间复用方案的MIMO系统中,可以获得复用增益,即信道容量成倍增加。信道容量的增加与min(Nt,Nr)成正比分集增益。在采用空间分集方案的MIMO系统中,可以获得分集增益,即可靠性性能的改善。分集增益用独立衰落支路数来描述,即分集指数。在使用了空时编码的MIMO系统中,由于接收天线或发射天线之间的间距较远,可认为它们各自的大尺度衰落是相互独立的,因此分布式MIMO
文章目录git常用命令(简介,详细参数往下看)Git提交代码步骤gitpullgitstatusgitaddgitcommitgitpushgit代码冲突合并问题方法一:放弃本地代码方法二:合并代码常用命令以及详细参数gitadd将文件添加到仓库:gitdiff比较文件异同gitlog查看历史记录gitreset代码回滚版本库相关操作远程仓库相关操作分支相关操作创建分支查看分支:gitbranch合并分支:gitmerge删除分支:gitbranch-ddev查看分支合并图:gitlog–graph–pretty=oneline–abbrev-commit撤消某次提交git用户名密码相关配置g
作为新的阿里云用户,您可以50免费试用多种优惠,价值高达1,700美元(或8,500美元)。这将让您了解和体验阿里云平台上提供的一系列产品和服务。如果您以个人身份注册免费试用,您将获得价值1,700美元的优惠。但是,如果您是注册公司,您可以选择企业免费试用,提交基本信息通过企业实名注册验证,即可开始价值$8,500的免费试用!本教程介绍了如何设置您的帐户并使用您的免费试用版。关于免费试用在我们开始此试用之前,您还必须遵守以下条款和条件才能访问您的免费试用:只有在一年内创建的账户才有资格获得阿里云免费试用。通过此免费试用优惠,用户可以免费试用免费试用活动页面上列出的每种产品一次。如果您有多个帐