第1章 准备工作

1.1 微信开放平台

微信扫码登录,需要在微信开放平台注册账号被认证为开发者才能接入官网地址:https://open.weixin.qq.com/

1.1.1 注册账号并认证成为开发者

下图就是官网,我们点击注册,然后根据要求填写必要的信息,点击提交即可。

1.1.2 创建网站应用获取应用AppID 和 AppSecret

1.2 搭建内网穿透

使用免费的内网穿透,官网地址:https://suidao.io/#/

1.2.1 注册账号并登录

先登录网站,然后注册账号。

注册完账号后,就可以登录了

1.2.2 创建隧道

先创建隧道。


  • 得到外网访问路径:

1.2.3 下载客户端

下载解压后直接双击SuiDao.Client.exe运行即可

1.3 修改微信开放平台应用授权回调域

把它修改成内网穿透的地址即可,如图所示:

第2章 后端项目搭建以及开发

2.1 从gitee码云上获取后端demo

gitee地址:https://gitee.com/77jubao2015/springbootdemo

2.1.1 引入相关架包

  <!--httpclient--><dependency><groupId>org.apache.httpcomponents</groupId><artifactId>httpclient</artifactId><version>4.5.13</version></dependency><!--commons-io--><dependency><groupId>commons-io</groupId><artifactId>commons-io</artifactId><version>2.3</version></dependency><dependency><groupId>com.alibaba</groupId><artifactId>fastjson</artifactId><version>1.2.51</version></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-thymeleaf</artifactId></dependency>

2.2 创建数据库xueden_wxcode

打开数据库客户端创建数据库,如图说是:

2.3 修改配置文件application.yml

2.3.1 修改数据库连接账号和密码

修改为自己本地电脑的即可

2.3.2 配置 AppIDAppSecret 以及授权回调域

代码如下所示:

wxcode:appId: wx7aa745fb92387941appSecret: xxxxxxxxxxxxxxredirectUri: http://wxcode.sh1.k9s.run:2271/wechat/callbackfrontUrl: http://localhost:8080/

2.4 编写一个WechatConfig配置类

代码如下所示:

package cn.xueden.config;import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Configuration;/**微信开放平台配置文件* @Auther:梁志杰* @Date:2021/11/13* @Description:cn.xueden.config* @version:1.0*/
@Configuration
@Data
@ConfigurationProperties(prefix = "wxcode")
public class WechatConfig {private String appId;private String appSecret;private String redirectUri;
}

2.5 编写一个WeChatHttpUtils工具类

代码如下所示:

package cn.xueden.utils;import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;/*** @Auther:梁志杰* @Date:2021/11/13* @Description:cn.xueden.utils* @version:1.0*/
public class WeChatHttpUtils {public static CloseableHttpClient getClient(){HttpClientBuilder builder = HttpClientBuilder.create();return builder.build();}
}

2.6 编写WxApiController控制类

2.6.1 编写一个获取code方法getWxCode

生成微信二维码,代码如下所示:

  //1、生成微信二维码@GetMapping("login")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";//对redirect_url进行URLEncoder编码String redirectUrl = wechatConfig.getRedirectUri();try {//对URL进行utf-8的编码URLEncoder.encode(redirectUrl, "utf-8");} catch (UnsupportedEncodingException e) {e.printStackTrace();}String url = String.format( //向指定字符串中按顺序替换%sbaseUrl,wechatConfig.getAppId(),wechatConfig.getRedirectUri(),"Xueden" //自定义(随意设置));//请求微信地址return "redirect:" + url;}

2.6.2 编写一个callback方法

通过code获取access_token 并把扫描人信息添加到数据库里

代码如下所示:

  @GetMapping("callback")//1、获取code值,临时票据、类似于验证码(该数据为扫码后跳转时微信方传来)public String callback(String code,String state, Model model) {//2、拿着code请求微信固定的地址,得到两个值access_token 和 openidString baseAccessTokenUrl ="https://api.weixin.qq.com/sns/oauth2/access_token" +"?appid=%s" +"&secret=%s" +"&code=%s" +"&grant_type=authorization_code";//3、拼接三个参数:id   密钥   code值String accessTokenUrl = String.format(baseAccessTokenUrl,wechatConfig.getAppId(),wechatConfig.getAppSecret(),code);HttpGet httpGet = null;CloseableHttpResponse response = null;URIBuilder uriBuilder = null;WxMember wxMember = new WxMember();try {//请求这个拼接好的地址,得到两个值access_token 和 openid//使用httpClient发送请求,得到返回结果httpGet = new HttpGet(accessTokenUrl);response = WeChatHttpUtils.getClient().execute(httpGet);int statusCode = response.getStatusLine().getStatusCode();JSONObject jsonObject = JSON.parseObject(EntityUtils.toString(response.getEntity()));String access_token = jsonObject.getString("access_token");String openid = jsonObject.getString("openid");String unionid = jsonObject.getString("unionid");// 获取扫码人信息uriBuilder = new URIBuilder("https://api.weixin.qq.com/sns/userinfo");uriBuilder.setParameter("access_token",access_token);uriBuilder.setParameter("openid",openid);uriBuilder.setParameter("lang","zh_CN");httpGet.setHeader("Accept", "application/json");httpGet.addHeader("Content-type","application/json; charset=utf-8");httpGet = new HttpGet(uriBuilder.build());response = WeChatHttpUtils.getClient().execute(httpGet);JSONObject jsonUserinfo = JSON.parseObject(EntityUtils.toString(response.getEntity()));log.info("access_token{},openid{},unionid{},获取信息{}",access_token, openid,unionid,jsonUserinfo);wxMember.setCity(jsonUserinfo.getString("city"));wxMember.setCountry(jsonUserinfo.getString("country"));wxMember.setProvince(jsonUserinfo.getString("province"));wxMember.setHeadimgurl(jsonUserinfo.getString("headimgurl"));String nickname = new String(jsonUserinfo.getString("nickname").getBytes("ISO-8859-1"), "UTF-8");wxMember.setNickname(nickname);wxMember.setOpenid(openid);wxMember.setUnionid(unionid);wxMember.setSex(jsonUserinfo.getInteger("sex"));wxMemberService.saveOrUpdate(wxMember);} catch (Exception e) {e.printStackTrace();}model.addAttribute("wxmember",wxMember);model.addAttribute("frontUrl", wechatConfig.getFrontUrl());return "result";}

2.6.3 编写一个获取用户列表的方法

代码如下所示:

 /*** 带条件分页查询用户列表*/@GetMappingpublic ResponseEntity<Object> getList(WxMemberQueryCriteria criteria, PageVo pageVo) throws Exception {int pageNo = pageVo.getPageIndex()-1;Pageable pageable = PageRequest.of(  pageNo<0?0:pageNo, pageVo.getPageSize() , Sort.Direction.DESC, "id" );return new ResponseEntity<>(wxMemberService.getList(criteria,pageable), HttpStatus.OK);}

2.6.4 编写一个获取用户列表的业务接口和实现方法

代码如下所示:

 /**** @param criteria* @param pageable* @return*/Object getList(WxMemberQueryCriteria criteria, Pageable pageable);
/*** 根据条件分页获取系统管理员列表信息* @param criteria 查询条件* @param pageable 分页信息* @return*/@Overridepublic Object getList(WxMemberQueryCriteria criteria, Pageable pageable) {Page<WxMember> page = wxMemberRepository.findAll((root, criteriaQuery, criteriaBuilder) -> QueryHelp.getPredicate(root,criteria,criteriaBuilder),pageable);return PageUtil.toPage(page);}

2.6.5 编写用户实体类WxMember

代码如下所示:

package cn.xueden.domain;import lombok.Data;
import org.hibernate.annotations.CreationTimestamp;import javax.validation.constraints.NotNull;
import javax.persistence.*;
import java.sql.Timestamp;/*** @Auther:梁志杰* @Date:2021/5/16* @Description:cn.xueden* @version:1.0*/
@Data
@Entity
@Table(name="t_member")
@org.hibernate.annotations.Table(appliesTo = "t_member",comment="微信用户信息表")
public class WxMember {/*** 自增 id*/@Id@GeneratedValue(strategy = GenerationType.IDENTITY)@Column(name = "id")@NotNull(groups = Update.class)private Long id;/*** 用户openid*/private String openid;/*** 用户unionid*/private String unionid;/*** 用户昵称*/private String nickname;/*** 性别*/private Integer sex;/*** 用户所属省份*/private String province;/*** 用户所属城市*/private String city;/*** 用户所属国家*/private String country;/*** 用户头像*/private String headimgurl;/*** 创建时间*/@Column(name = "create_time",nullable = false)@CreationTimestampprivate Timestamp createTime;public @interface Update {}
}

2.6.6 编写一个查询参数类WxMemberQueryCriteria

代码如下所示:

package cn.xueden.dto;import cn.xueden.annotation.EnableXuedenQuery;
import lombok.Data;/**功能描述:查询条件* @Auther:梁志杰* @Date:2021/5/16* @Description:cn.xueden.dto* @version:1.0*/
@Data
public class WxMemberQueryCriteria {/*** 根据性别查询*/@EnableXuedenQueryprivate int sex;/*** 根据昵称模糊查询*/@EnableXuedenQuery(blurry = "nickname")private String nickname;
}

2.6.7 添加一个result.html页面

在resources文件夹下新建一个名为templates文件夹,并在此文件夹下新建result.html页面

代码如下所示:

<!DOCTYPE html>
<html lang="ch" xmlns:th="http://www.thymeleaf.org">
<head><meta charset="UTF-8"><meta content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0"name="viewport"><meta content="ie=edge" http-equiv="X-UA-Compatible"><link rel="icon" th:href="@{resource/favicon.ico}" type="image/x-icon"/><title>登录跳转中</title>
</head>
<body>
登录中..
<script th:inline="javascript">var response = [[${wxmember}]];var frontUrl = [[${frontUrl}]];window.onload = function () {window.opener.postMessage(response, frontUrl);window.close();}
</script>
</body>
</html>

第3章 前端项目搭建以及开发

3.1 从gitee获取前端demo

gitee地址:https://gitee.com/77jubao2015/wxpaydemo

3.2 修改订单列表组件index.vue

代码如下所示:

<template><div><div class="search__example--wrap"><com-search:data="searchData"@search-submit="searchSubmit"@reset-submit="resetSubmit"/></div><com-tablev-loading="loading":columns="columns":data="tableData":pagination="{currentPage: defalutParams.pageIndex,total: total,onSizeChange: handleSizeChange,onCurrentChange: handleCurrentChange}"@selection-change="handleSelectionChange"><template #sex="scope"><el-tag:type="scope.row.sex === 0? 'success': (scope.row.sex === 1? 'warning': 'danger')">{{ scope.row.sex === 0? '男性': (scope.row.sex === 1? '女性': '未知') }}</el-tag></template></com-table><com-dialog v-model="dialogVisible" :title="title"><info-writev-if="comName === 'InfoWrite'":info="info"@close="toggleVisible"@success="success"/><face-payv-if="comName === 'FacePay'":info="info"@close="toggleVisible"@success="success"/><detailv-if="comName === 'Detail'":info="info"@close="toggleVisible"/></com-dialog></div>
</template><script lang="ts">
import { defineComponent, ref } from 'vue'
import InfoWrite from './components/InfoWrite.vue'
import Detail from './components/Detail.vue'
import FacePay from './components/FacePay.vue'
import { useExample } from '@/hooks/useExample'
import { Message } from '_c/Message'import { getListApi, delsApi, nativePayApi, huaBeiPayApi } from './api'
import { formatTime } from '@/utils'const searchData = [{label: '用户昵称',value: '',itemType: 'input',field: 'nickname',placeholder: '请输入用户昵称',clearable: true},{label: '用户性别',value: '',itemType: 'select',field: 'sex',options: [{title: '男性',value: '0'}, {title: '女性',value: '1'}]}
]const columns = [{field: 'createTime',label: '登录时间',formatter: (row: any, column: any, cellValue: any, index: number) => {return formatTime(row.createTime, 'yyyy-MM-dd HH:mm:ss')}},{field: 'nickname',label: '昵称'},{field: 'openid',label: 'openid',showOverflowTooltip: true},{field: 'sex',label: '性别',slots: {default: 'sex'}},{field: 'unionid',label: 'unionid'}
]export default defineComponent({// name: 'ExampleDialog',components: {InfoWrite,Detail,FacePay},setup() {const info = ref<any>(null)const {defalutParams,tableData,loading,total,dialogVisible,title,currentChange,sizeChange,handleSelectionChange,selectionData,delData,comName,toggleVisible} = useExample()// 请求数据async function getExampleList(data?: any): Promise<void> {try {const res = await getListApi({params: Object.assign(defalutParams, data || {})})total.value = res.totalElementstableData.value = res.content} finally {loading.value = false}}// 查询function searchSubmit(data: any) {// 该方法重置了一些默认参数currentChange(1)getExampleList(data)}// 重置function resetSubmit(data: any) {// 该方法重置了一些默认参数currentChange(1)getExampleList(data)}// 展示多少条function handleSizeChange(val: number) {// 该方法重置了一些默认参数sizeChange(val)getExampleList()}// 展示第几页function handleCurrentChange(val: number) {// 该方法重置了一些默认参数currentChange(val)getExampleList()}// 删除多选function dels(item?: any) {delData(async() => {let ids: number[] = []if (item.id) {ids.push(item.id)} else {ids = selectionData.value.map((v: any) => {return v.id})}const res = await delsApi({data: JSON.stringify(ids)})if (res.status === 200) {Message.success(res.message)getExampleList()}}, { hiddenVerify: item.id, text: '此操作将申请退款, 是否继续?' })}// 打开弹窗function open(row: any, component: string) {comName.value = componenttitle.value = !row ? '新增' : (component === 'Detail' ? '刷脸付' : '当面付(打开支付宝扫一扫)')info.value = row || nulltoggleVisible(true)}// 成功之后的回调function success(type: string) {if (type === 'add') {currentChange(1)}toggleVisible()getExampleList()}getExampleList()// 调用支付宝网站支付async function getAliDet(id: number) {try {const res = await nativePayApi({params: {id: id}})if (res.status === 200) {const body = document.querySelector('body')if (body != null) {body.innerHTML = res.message // 查找到当前页面的body,将后台返回的form替换掉他的内容}document.forms[0].setAttribute('target', '_blank') // 新开窗口跳转document.forms[0].submit() // 执行submit表单提交,让页面重定向,跳转到支付宝页面}} catch (e) {console.log(e)}}// 调用支付宝花呗分期支付async function getHuaBeiDet(id: number) {try {const res = await huaBeiPayApi({params: {id: id}})if (res.status === 200) {console.info('返回信息:', res)}} catch (e) {console.log(e)}}return {info, open,searchData, searchSubmit, resetSubmit,columns,defalutParams,loading,tableData,total,title,dialogVisible,handleSizeChange,handleCurrentChange,handleSelectionChange,dels,close, success,comName,toggleVisible,getAliDet,getHuaBeiDet}}
})
</script><style>
</style>

3.3 修改api.ts文件

代码如下所示:

export const getListApi = ({ params }: PropsData): any => {return fetch({ url: '/wechat', method: 'get', params })
}

3.4 修改登录页面

代码所示:

<template><div class="login-wrap" @keydown.enter="login"><div class="login-con"><el-card class="box-card"><template #header><span class="login--header">登录</span></template><el-formref="loginForm":model="form":rules="rules"class="login-form"><el-form-item prop="userName"><el-inputv-model="form.userName"placeholder="请输入账号 admin or test"class="form--input"><template #prefix><span class="svg-container"><svg-icon icon-class="user" /></span></template></el-input></el-form-item><el-form-item prop="passWord"><el-inputv-model="form.passWord"show-password:minlength="3":maxlength="18"placeholder="请输入密码 admin or test"class="form--input"><template #prefix><span class="svg-container"><svg-icon icon-class="password" /></span></template></el-input></el-form-item><el-form-item><el-button:loading="loading"type="primary"class="login--button"@click="login">登录</el-button></el-form-item><el-form-item><el-button:loading="loading"type="success"class="login--button"@click="wxlogin">微信扫码登录</el-button></el-form-item></el-form></el-card></div></div>
</template><script lang="ts">
import { defineComponent, ref, unref, reactive, watch } from 'vue'
import { useRouter } from 'vue-router'
import type { RouteRecordRaw } from 'vue-router'
import { permissionStore } from '@/store/modules/permission'
import { appStore } from '@/store/modules/app'
import wsCache from '@/cache'
import { ElNotification } from 'element-plus'interface FormModule {userName: string,passWord: string
}
interface RulesModule {userName: any[],passWord: any[]
}export default defineComponent({name: 'Login',setup() {const { push, addRoute, currentRoute } = useRouter()const loginForm = ref<HTMLElement | null>(null)const loading = ref<boolean>(false)const redirect = ref<string>('')watch(() => {return currentRoute.value}, (route) => {redirect.value = (route.query && route.query.redirect) as string}, {immediate: true})const page = reactive({width: window.screen.width * 0.5,height: window.screen.height * 0.5})const form = reactive<FormModule>({userName: '',passWord: ''})const rules = reactive<RulesModule>({userName: [{ required: true, message: '请输入账号' }],passWord: [{ required: true, message: '请输入密码' }]})async function login(): Promise<void> {const formWrap = unref(loginForm) as anyif (!formWrap) returnloading.value = truetry {formWrap.validate(async(valid: boolean) => {if (valid) {wsCache.set(appStore.userInfo, form)permissionStore.GenerateRoutes().then(() => {permissionStore.addRouters.forEach(async(route: RouteRecordRaw) => {await addRoute(route.name!, route) // 动态添加可访问路由表})permissionStore.SetIsAddRouters(true)push({ path: redirect.value || '/' })})} else {console.log('error submit!!')return false}})} catch (err) {console.log(err)} finally {loading.value = false}}async function resolveSocialLogin(e: any): Promise<void> {console.info('传入参数', e.data)wsCache.set(appStore.userInfo, e.data)permissionStore.GenerateRoutes().then(() => {permissionStore.addRouters.forEach(async(route: RouteRecordRaw) => {await addRoute(route.name!, route) // 动态添加可访问路由表})permissionStore.SetIsAddRouters(true)push({ path: redirect.value || '/' })})}async function wxlogin(): Promise<void> {const url = 'http://wxcode.sh1.k9s.run:2271/wechat/login'window.open(url, 'newWindow', `resizable=yes, height=${page.height}, width=${page.width}, top=10%, left=10%, toolbar=no, menubar=no, scrollbars=no, resizable=no,location=no, status=no`)window.addEventListener('message', resolveSocialLogin, false)}ElNotification({title: '提示',message: '账号 admin 为 前端 控制路由权限,账号 test 为 后端 控制路由权限。密码与账号相同',duration: 60000})return {loginForm,loading, redirect, form, rules, page,login,wxlogin}}
})
</script><style lang="less" scoped>
.login-wrap {width: 100%;height: 100%;background-image: url('~@/assets/img/login-bg.jpg');background-size: cover;background-position: center;position: relative;.box-card {width: 400px;.login--header {font-size: 24px;font-weight: 600;}.svg-container {color: #889aa4;vertical-align: middle;width: 30px;display: inline-block;}.form--input {width: 100%;@{deep}(.el-input__inner) {padding-left: 40px;}}.login--button {width: 100%;}}.login-con {position: absolute;right: 160px;top: 50%;transform: translateY(-60%);}
}
</style>

e’, resolveSocialLogin, false)
}

ElNotification({title: '提示',message: '账号 admin 为 前端 控制路由权限,账号 test 为 后端 控制路由权限。密码与账号相同',duration: 60000
})return {loginForm,loading, redirect, form, rules, page,login,wxlogin
}

}
})

基于Springboot2.x+vue3.x整合实现微信扫码登录相关推荐

  1. 微信官方你真的懂OAuth2?Spring Security OAuth2整合企业微信扫码登录

    ❝ 企业微信扫码登录DEMO参见文末. 现在很多企业都接入了企业微信,作为私域社群工具,企业微信开放了很多API,可以打通很多自有的应用.既然是应用,那肯定需要做登录.正好企业微信提供了企业微信扫码授 ...

  2. SpringBoot整合微信扫码登录

    SpringBoot整合微信扫码登录 准备工作 基本思路流程 搭建SpringBoot 引入依赖 加入配置文件 代码实现 工具类 controller层 结果 准备工作 1.登录官网了解到,学习者想本 ...

  3. 项目整合微信扫码登录功能

    项目整合微信登录功能 一.准备工作 https://open.weixin.qq.com 1.注册 2.邮箱激活 3.完善开发者资料 4.开发者资质认证 准备营业执照,1-2个工作日审批.300元 5 ...

  4. 基于Spring Boot实现电脑端网页微信扫码授权登录方式一(附带完整源码)

    简介 电脑端微信网页扫码授权登录有2种方式: 第一种:基于微信公众号,单独获取登录二维码扫码,然后扫码登录,程序控制跳转逻辑,例如CSDN: 第二种:基于微信开放平台,跳转到微信二维码页面进行扫码登录 ...

  5. vue3、vue2 实现网站微信扫码登录

    其实前端实现没什么难点,重点都是在后端,这里我记录了一下前端实现扫码登录的做法 准备工作 | 微信开放文档  做之前我们先去看一下大致流程 记得要看一下参数 都讲的很清楚了 实现网页微信扫码登录有两种 ...

  6. vue3 微信扫码登录及获取个人信息实现的三种方法

    一.流程: 微信提供的扫码方式有两种,分别是: 跳转二维码扫描页面 内嵌式二维码 根据文档我们可以知道关于扫码授权的模式整体流程为: 1. 第三方发起微信授权登录请求,微信用户允许授权第三方应用后,微 ...

  7. 前后端分离项目知识汇总(微信扫码登录,手机验证码登录,JWT)

    整合篇二 前言 整合JWT 用户登录业务介绍 单一服务器模式 SSO(single sign on)模式 SSO登录三种常见的方式 传统用户身份验证 解决方案 JWT令牌 JWT的原则 整合 整合腾讯 ...

  8. Vue+abp微信扫码登录

    最近系统中要使用微信扫码登录,根据微信官方文档和网络搜索相关文献实现了.分享给需要的人,也作为自己的一个笔记.后端系统是基于ABP的,所以部分代码直接使用了abp的接口,直接拷贝代码编译不通过. 注册 ...

  9. 微信开放平台开发——网页微信扫码登录(OAuth2.0)

    1.OAuth2.0 OAuth(开放授权)是一个开放标准,允许用户让第三方应用访问该用户在某一网站上存储的私密的资源(如照片,视频,联系人列表),而无需将用户名和密码提供给第三方应用. 允许用户提供 ...

最新文章

  1. [原]消耗CPU资源的shell脚本
  2. can a select block a truncate (ZT)
  3. 快速排序与合并排序的分而治之
  4. NYOJ 128 前缀式计算
  5. Hive学习之路 (十六)Hive分析窗口函数(四) LAG、LEAD、FIRST_VALUE和LAST_VALUE
  6. SAP UI5应用点了search按钮后的实现调试
  7. junit testng_TestNG或JUnit
  8. pat 乙级 1002 写出这个数(C++)
  9. IDEA中引入和启动TOMCAT的本质
  10. scrolling=no 无法根据坐标获取元素_科曼尼KOMANIE三坐标测量仪命令不执行【维修】北京303所...
  11. [logstash-input-log4j]插件使用详解
  12. 对方启用和留言是什么意思_男子花八万元装修,装修到一半要求加价,对方:补给我一万两天就能装好...
  13. 网页特效offset、client、scroll系列属性的作用
  14. java开发工作找不到要放弃吗,这样学习Java,才能找到一份Java开发的工作。不要盲目的学!...
  15. Idea2020版本设置编码格式
  16. 【IDEA】解决: alt+/快捷键 冲突的问题
  17. HandlerSocket简介及安装及卸载
  18. 领扣(LeetCode)最长和谐子序列 个人题解
  19. 一个牛人在美国的跳槽经历(转)
  20. java计算机毕业设计南通大学福利发放管理系统源码+系统+数据库+lw文档+mybatis+运行部署

热门文章

  1. Linux 源码分析 之 raw socket 分析 一 recvfrom过程
  2. 线性规划:单纯形算法之处理退化
  3. 第3周课件-全网最详细的ORB-SLAM2精讲
  4. Mysql数据库基本知识四:视图
  5. STM32中断分配——抢占优先级与响应优先级
  6. Matlab中function定义的函数与匿名函数区别一
  7. createprocess函数的参数说明:
  8. 区块链与大数据结合分析
  9. MPP(大规模并行处理)简介
  10. 计算机系统(1) 实验五 中断实验