爽易购商城--后台管理
一、项目简介
1、项目背景
1)、电商模式
市面上有5种常见的电商模式:B2B、B2C、C2B、C2C、O2O;
- B2B模式
Business to Business,是指商家之间的商业关系,如:阿里巴巴;
- B2C模式
Business to Consumer,就是我们经常看到的供应商直接把商品卖给用户,即“商对客”模式,也就是通常说的商业零售,直接面向消费者销售产品和服务。如:苏宁易购、京东、天猫等;
- C2B模式
Customer to Business,即消费者对企业。先有消费者提出需求,后有企业组织生产;
- C2C模式
Customer to Consumer,客户之间的交易,如:淘宝、咸鱼等;
- O2O模式
Online to Offline,即是将线下商务的机会与互联网结合,让互联网称为线下交易的前台。线上快速支付,线下优质服务。如:饿了么、美团、淘票票、京东到家等;
2、架构图
技术架构图
服务架构图
3、项目技术
- 前后分离开发,基于vue的后台管理系统
- SpringCloud全新解决方案
- 应用监控、限流、网关、熔断降级等分布式方案
- SpringBoot
- SpringCloud
- Nacos、Sentinel、Elasticsearch、git、redis、linux、vue、k8s
二、分布式基础概念
1、微服务
微服务架构风格,就像是把一个单独的应用程序开发为一套小服务,每个小服务运行在自己的进程中,并使用轻量级机制通信,通常是HTTP API。这些服务围绕业务能力来构建,并通过完全自动化部署机制来独立部署。这些服务可以使用不同的编程语言书写,以及不同数据存储技术,并保持最低限度的集中式管理。
简而言之:拒绝大型单体应用,基于业务边界进行服务微化拆分,各个服务独立部署运行。
2、集群&分布式&节点
集群是个物理形态,分布式是个工作方式。
只要是一堆机器,就可以叫集群,他们是不是一起协作工作,这个谁也不知道。
《分布式系统原理与规范》
定义:
“分布式系统是若干独立计算机的集合,这些计算机对于用户来说就像单个相关系统”
分布式系统(distribution system)是建立在网络之上的软件系统。
分布式是指将不同的业务分布在不同的地方。
集群是指将几台服务器集中在一起,实现同一业务。
例如:京东是一个分布式系统,众多业务运行在不同的机器,所有业务构成一个大型业务集群。每一个小的业务,比如用户系统,访问压力大时一个服务器不够用,我们就应该将用户系统部署到多个服务器,也就是每一个业务系统都可以做集群。
分布式中的每一个节点都可以做集群。集群并不一定是分布式。
节点:集群中的一个服务器。
3、远程调用
在分布式系统中,各个服务可能处于不同主机,但服务之间不可避免要互相调用,我们称为远程调用。
SpringCloud中使用HTTP + JSON的方式来完成远程调用
4、负载均衡
分布式系统中,A服务调用B服务,B服务部署集群,A调用任意一个均可完成功能。
为了使每一台服务器都不要太忙或太闲,我们可以负载均衡的调用每一个服务器,提升网站的健壮性。
常见的负载均衡算法:
**轮询:**按照顺序访问每一台服务器。
**最小连接:**优先选择连接数最少,也就是压力最小的服务器。
**散列:**根据请求源IP的hash值来选择要转发的服务器。可以解决session的问题。
5、服务注册/发现&注册中心
A服务调用B服务,但不知道B服务在哪台服务器上,哪些是正常或下线的。解决这个问题可以引入注册中心;
我们可以实时感知到服务的状态,从而避免调用不可用的服务。
6、配置中心
每一个服务最终都有大量配置,并且每个服务都可能部署在多台服务器上。我们经常需要变更配置,因此工作量巨大。我们可以引入配置中心,让每个服务在配置中心获取自己的配置。
**配置中心用来集中管理微服务的配置信息 **
7、服务熔断&服务降级
在微服务架构中,微服务之间通过网络通信,存在相互依赖,当一个服务不可用,有可能出现雪崩效应。要防止这样的情况,必须要有容错机制。
1)、服务熔断
设置服务的超时,当被调用的服务经常失败到达某个阈值,我们可以开启断路保护机制,后来的请求不再去调用这个服务。本地直接返回默认数据。
2)、服务降级
在运维期间,当系统处于高峰期,系统资源紧张,我们可以让非核心业务奖及运行。
降级:某些服务不处理,或者简单处理——抛异常 | 返回Null、调用Mock数据、调用faullback处理逻辑。
8、API网关
在微服务架构中,API Gateway作为整体架构的重要组件,它抽象了微服务中都需要的功能,同时提供客户端负载均衡,服务自动熔断,灰度发布,统一认证,限流留空、日志统计等丰富功能,帮助我们解决很多API管理难题。
三、环境搭建
安装Linux虚拟机
本次项目使用阿里的云服务器:ip:112.124.32.136
安装docker
docker安装mysql
docker安装redis
5、 开发环境
- Maven
- Idea插件
lombok
mybatisx
- VS Code 插件
- Git
6、创建项目微服务
商品服务、仓储服务、订单服务、优惠券服务、用户服务
共同:
- 依赖: web、openfeign
- groupId: com.qhit.shuang
- 包名: com.qhit.shuang.xxx(product/ware/order/coupon/member)
- 模块名: shuang-xxx((product/ware/order/coupon/member)
.gitignore添加以下内容
**/mvnw
**/mvnw.cmd
**/.mvn
**/target/
.idea
**/.gitignore
四、后台管理系统
本项目的后台管理系统采用人人开源提供的后台系统快速进行搭建
接下来使用renren-generator对各个模块进行代码生成
成功生成!
接下来创建公共模块shuang-common
<!--mybatis-plus-->
<dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-boot-starter</artifactId><version>3.4.2</version>
</dependency>
<dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><version>1.18.22</version>
</dependency>
<!--mysql驱动-->
<dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>8.0.21</version>
</dependency>
<dependency><groupId>javax.servlet</groupId><artifactId>servlet-api</artifactId><version>2.5</version><scope>provided</scope>
</dependency>
<!-- https://mvnrepository.com/artifact/org.apache.httpcomponents/httpcore -->
<dependency><groupId>org.apache.httpcomponents</groupId><artifactId>httpcore</artifactId><version>4.4.15</version>
</dependency>
<dependency><groupId>commons-lang</groupId><artifactId>commons-lang</artifactId><version>${commons.lang.version}</version>
</dependency>
<!--AOP-->
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-aop</artifactId>
</dependency>
五、技术整合
1、mybatis-plus
1)、引入依赖
<dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-boot-starter</artifactId><version>3.4.2</version>
</dependency>
2)、配置
配置数据源
1)、导入数据库驱动
<!--mysql驱动--> <dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>8.0.21</version> </dependency>
2)、在application.yml中配置数据源
spring:# 数据源配置datasource:type: com.alibaba.druid.pool.DruidDataSourcedriverClassName: com.mysql.cj.jdbc.Driverurl: jdbc:mysql://112.124.32.136:3306/shuang_oms?useUnicode=true&characterEncoding=UTF-8&useSSL=false&serverTimezone=Asia/Shanghaiusername: rootpassword: root
配置mybatis-plus
1)、启动类添加MapperScan注解
@MapperScan("com.qhit.shuang.product.dao") //dao层接口全路径
2)、application.yml中配置sql映射文件位置
mybatis-plus: mapper-locations: classpath:/mapper/**/*.xml
2、微服务
1)、简介
SpringCloud的几大痛点
- 部分组件停止维护和更新,给开发带来不便
- 部分环境搭建复杂,没有完善的可视化界面,我们需要大量的二次开发和定制
- 配置复杂,难以上手,部分配置差别难以区分和合理应用
SpringCloud Alibaba的优势
- 性能强悍,设计合理,开源
- 成套的产品搭配,完善的可视化界面
- 搭建简单
结合Alibaba最终的技术搭配方案
- SpringCloud Alibaba - Nacos:
注册中心
(服务发现和注册) - SpringCloud Alibaba - Nacos:
配置中心
(动态配置管理) - SpringCloud - Ribbon:
负载均衡
- SpringCloud - Open Feign:
远程调用
(声明式HTTP客户端) - SpringCloud Alibaba - Sentinel:
服务容错
(限流、降级、熔断) - SpringCloud - Gateway:API
网关
(webflux编程模式) - SpringCloud - Sleuth:
调用链监控
- SpringCloud Alibaba - Seata:原Fescar,即
分布式事务
解决方案
github地址:https://github.com/alibaba/spring-cloud-alibaba
版本对应关系
2)、远程调用
引入
open-feign
依赖<dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-openfeign</artifactId> </dependency>
编写本地
接口
作为远程方法映射
@FeignClient("服务名:application.name") public interface 接口名:自定义|示例:feign/UserFeignService.java {@RequestMapping("远程方法全路径")public R list(@RequestParam Map<String, Object> params); // 远程方法签名 }
开启远程调用功能
启动类上添加注解
@EnableFeignClients(basePackages = "映射接口所在包的全路径,以‘.’分隔")
3)、API网关
当请求到达网关,网关会断言请求是否符合某个路由规则,若符合,就按照路由规则将请求路由到指定服务,中间会经过一系列过滤器
断言文档:https://docs.spring.io/spring-cloud-gateway/docs/2.2.9.RELEASE/reference/html/#gateway-request-predicates-factories
过滤器文档:https://docs.spring.io/spring-cloud-gateway/docs/2.2.9.RELEASE/reference/html/#gatewayfilter-factories
- 创建项目shuang-gateway
- 添加依赖
<dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-gateway</artifact>
</dependency>
- 使用断言
spring:cloud:gateway:routes:- id: after_route # 路由iduri: https://example.org #路由地址predicates:#After断言:会匹配指定时间点之后的请求- After=2017-01-20T17:42:47.789-07:00[America/Denver]
- 使用过滤器
spring:cloud:gateway:routes:- id: add_request_header_route # 路由iduri: https://example.org #路由地址filters:# 添加请求头过滤器:将为请求头添加red,blue键值对- AddRequestHeader=X-Request-red, blue
前后端技术栈类比
4)、Nacos
https://blog.csdn.net/weixin_44338156/article/details/122338287
六、前端
前端使用Vue
和ElementUI
vue官网文档:https://cn.vuejs.org/v2/guide/
ElementUI官网文档:https://element-plus.gitee.io/zh-CN/
Vue组件模板:https://www.cnblogs.com/songjilong/p/12635448.html
1、分类维护
1)、三级分类
- 在后台管理系统添加商品系统目录
- 添加分类维护菜单
- 创建category视图
- 添加分类
ElementUI官网的树形控件:https://element.eleme.cn/#/zh-CN/component/tree
- 增加单个增删改功能
<el-buttontype="text"size="mini"@click="append(data)"v-if="node.level < 3" <!--三级菜单不允许添加子菜单-->>Append
</el-button>
<el-buttontype="text"size="mini"@click="edit(data)"
>Edit
</el-button>
<el-buttontype="text"size="mini"@click="remove(node, data)"v-if="node.childNodes.length == 0" <!--当子节点为空时显示删除按钮-->
>Delete
</el-button>
在开发中,相较于物理删除,多使用逻辑删除
这里使用mybatis-plus提供的逻辑删除功能:https://mp.baomidou.com/guide/logic-delete.html
2)、拖拽节点
ElementUI的树形控件有一个参数draggable,将其设为true即可拖拽
但仅仅这样,拖拽可到达任意位置的同时,也会产生超过三级的列表;我们可以设置allow-drop参数来判断当前位置能否被放置
拖拽成功执行的函数
allowDrop(draggingNode, dropNode, type) { //是否允许拖拽//求出被拖拽节点最大深度this.countNodeLevel(draggingNode)//被拖拽节点作为顶级节点的最大深度let deep = Math.abs(this.maxLevel - draggingNode.level) + 1this.maxLevel = 1if (type == 'inner') //放置目标节点之中return (deep + dropNode.level) <= 3else //目标节点之前或之后return (deep + dropNode.data.catLevel - 1) <= 3
},
countNodeLevel(node) { //求出被拖拽节点的最大深度,比如 1-node-3,深度为2if (node.childNodes != null && node.childNodes.length > 0) { //是否存在子节点for (let i = 0; i < node.childNodes.length; i++) { //迭代子节点let child = node.childNodes[i]if (child.level > this.maxLevel) //若子节点深度大于当前最大深度,则替换this.maxLevel = child.levelthis.countNodeLevel(child) //递归子节点求出最大深度}}
},
handleDrop(draggingNode, dropNode, dropType, ev) { //拖拽成功触发的函数//1. 获取当前节点最新的父节点idlet pCid = 0let siblings = nullif (dropType == 'inner') {pCid = dropNode.data.catIdsiblings = dropNode.childNodes}else {pCid = dropNode.parent.data.catId || 0siblings = dropNode.parent.childNodes}// 2. 被拖拽节点最新数据siblings.forEach((node, index) => {if (draggingNode.data.catId == node.data.catId) {let level = draggingNode.levelif (node.level != level) {level = node.levelthis.updateChildsLevel(node)}this.updateNodes.push({ catId: node.data.catId, sort: index, parentCid: pCid, catLevel: level })} else {this.updateNodes.push({ catId: node.data.catId, sort: index })}})this.pCid.push(pCid)
},
updateChildsLevel(node) { //拖拽后更新子节点node.childNodes.forEach(ele => {this.updateNodes.push({ catId: ele.data.catId, catLevel: ele.level })this.updateChildsLevel(ele)})
},
batchSave() { //批量拖拽保存this.$http({url: this.$http.adornUrl('/product/category/update/sort'),method: 'post',data: this.$http.adornData(this.updateNodes, false)}).then(({ data }) => {this.$message({type: 'success',message: '更新成功!'})this.getMenus()this.expandedKeys = this.pCidthis.updateNodes = []this.maxLevel = 1})
}
3)、批量删除
getCheckedNodes:获取被选中的节点
// 批量删除
batchDel() {let checkedNodes = this.$refs.menuTree.getCheckedNodes() // 获取选中节点let catIds = checkedNodes.map(node => node.catId) // 选中节点的idlet names = checkedNodes.map(node => node.name) // 选中节点的namelet parentCids = checkedNodes.map(node => node.parentCid) // 删除节点的父id,用来展开this.$confirm(`是否确认删除:【${names}】`, '提示', {confirmButtonText: '确认',cancelButtonText: '取消',type: 'warnning'}).then(() => {this.$http({url: this.$http.adornUrl('/product/category/delete'),method: 'post',data: this.$http.adornData(catIds, false)}).then(({ data }) => {this.$message({message: '删除成功',type: 'success'})this.getMenus()this.expandedKeys = parentCids});}).catch(() => {this.$message({message: '已取消',type: 'warnning'})})
}
2、品牌管理
- 添加品牌管理菜单
- 创建brand视图
将之前逆向工程生成的组件拿来
这里会判断是否拥有新增和删除的权限,将其移除或者return true
1)、显示状态
Table表格中有一个自定义模板,我们使用它来控制品牌的显示状态
Switch开关也拿来
使用Switch的Event来监听change
最终效果:
<el-table-columnprop="showStatus"header-align="center"align="center"label="显示状态"
><template slot-scope="scope"><el-switchv-model="scope.row.showStatus"active-color="#13ce66"inactive-color="#ff4949"@change="updateBrandStatus(scope.row)":active-value="1":inactive-value="0"></el-switch></template>
</el-table-column>
// 更新显示状态
updateBrandStatus(brand) {let { brandId, showStatus } = brandthis.$http({url: this.$http.adornUrl('/product/brand/update'),method: 'post',data: this.$http.adornData({ brandId, showStatus }, false)}).then(({ data }) => {this.$message({message: '已更新',type: 'success'})})
}
2)、文件上传
https://element.eleme.cn/#/zh-CN/component/upload
policy.js
import http from '@/utils/httpRequest.js'
export function policy() {return new Promise((resolve, reject) => {http({url: http.adornUrl('/thirdparty/oss/policy'),method: 'get'}).then(({ data }) => {resolve(data)})})
}
beforeUpload() {let _self = this;return policy().then(response => {console.log('响应的数据:', response);_self.dataObj.policy = response.data.policy_self.dataObj.signature = response.data.signature_self.dataObj.ossaccessKeyId = response.data.ossaccessKeyId_self.dataObj.key = response.data.dir + '/' + getUUID + '_${filename}'_self.dataObj.dir = response.data.dir_self.dataObj.host = response.data.hostconsole.log('响应数据:' + _self.dataObj);}).catch(err => {reject(false)})
}
跨域
跨域错误
在这里开启跨域访问
七、第三方服务模块
此模块用来提供第三方服务
1. 创建
引入common模块
<dependency><groupId>com.qhit.shuang</groupId><artifactId>shuang-common</artifactId><version>1.0.0</version>
</dependency>
引入依赖管理
<dependencyManagement><dependencies><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-dependencies</artifactId><version>${spring-cloud.version}</version><type>pom</type><scope>import</scope></dependency><dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-alibaba-dependencies</artifactId><version>2.1.2.RELEASE</version><type>pom</type><scope>import</scope></dependency></dependencies>
</dependencyManagement>
2. 文件上传
SpringCloud Alibaba-OSS
1)、介绍
上传文件的方式:
- 用户上传到应用服务器,由应用服务器携带凭证发给OSS
- 用户直接携带凭证上传到OSS
- 用户向应用服务器请求上传Policy,应用服务器返回上传Policy,用户上传文件到OSS
第一种方式会给服务器带来很大的压力,第二种方式存在安全隐患,因此我们选择第三种
服务端签名后直传:https://help.aliyun.com/document_detail/91868.htm?spm=a2c4g.11186623.0.0.16075d3f6zYO9b#concept-ahk-rfz-2fb
2)、使用
- 引入gav坐标
<!-- https://mvnrepository.com/artifact/com.alibaba.cloud/spring-cloud-starter-alicloud-oss --> <dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-starter-alicloud-oss</artifactId><version>2.1.0.RELEASE</version> </dependency>
- 配置AccessKey
spring:cloud:alicloud:access-key: your-aksecret-key: your-skoss:endpoint: oss-cn-hangzhou.aliyuncs.com #地域节点,此为示例
3. 新增品牌
1)、前端校验
ElementUI表单校验:https://element.eleme.cn/#/zh-CN/component/form
Form 组件提供了表单验证的功能,只需要通过 rules 属性传入约定的验证规则,并将 Form-Item 的 prop 属性设置为需校验的字段名即可。校验规则参见 async-validator
还可以自定义校验规则:
2)、后端校验
前端校验方便用户的同时,也减轻了服务器压力
但当恶意访问者绕过浏览器,通过Postman等类似工具进行访问时,前端校验未必有用,此时我们需要添加后端校验
我们此次使用JSR303
错误码
自定义错误码以便快速精确定位错误
放在公共模块以便所有模块使用
BizCodeEnume
4. 属性分组
后端统一异常处理
ExceptionControllerAdvice.java
bug
找不到python问题
**问题描述:**在github上clone下的项目执行npm install时报python环境错误
确保windows已安装node.js/vue/vue-cli
一、cmd下运行npm install -globabl -production windows-build-tools一键安装
- python(v2.7 ,3.x不支持);
- visual C++ Build Tools,或者 (vs2015以上(包含15))
- .net framework 4.5.1
二、在控制台输入:npm install -g node-gyp安装node-gyp
三、安装后检查:node-gyp list
最后到项目下执行npm install…成功。。。
后记:
如果还是提示“python找不到或者环境不对”
npm config set python C:\Users\Administrator\.windows-build-tools\python27\python.exe
跨域问题
跨域:指的是浏览器不能执行其他网站的脚本。它是由浏览器的同源策略造成的,是浏览器对JavaScript施加的安全限制。
同源策略:是指协议,域名,端口都要相同,其中有一个不同都会产生跨域。
解决方案一:使用Nginx部署为同一域
解决方案二:配置当前请求允许跨域
- 添加响应头
- Access-Control-Allow-Origin:支持哪些来源的请求跨域
- Accss-Control-Allow-Methods:支持哪些方法跨域
- Access-Control-Allow-Credentials:跨域请求默认不包含cookie,设置true包含
- Access-Control-Expose-Headers:跨域请求暴漏的字段
- CORS请求时,XMLHttpRequest对下国内的getResponseHeader()方法只能拿到6个基本字段:Cache-Control、Content-Language、Content-Type、Expires、Last-Modified、Pragma,如果想要拿到其他字段,就必须在Access-Control-Expose-Headers里面指定。
- Access-Control-Max-Age:表迷宫该响应的有效时间为多少秒。有效时间内,浏览器无需为同一请求再次发起预见请求。请注意,浏览器自身维护了一个最大有效时间,如果该首部字段的值超过了最大有效时间,将失效。
爽易购商城--后台管理相关推荐
- 前后端分离vue2+node易购商城后台管理系统
继续学习vue 之前写了个全栈后台管理系统,功能上大体已经满足了后台管理的全部内容.利用空余时间又重新写了一个,虽然页面上精简了很多,但是基本上都是自己写的,而且加入了自己的理解,尤其是vuex那一块 ...
- Axure高保真企业商城后台管理系统web端公司商城后台管理原型连锁门店管理系统交互组件点餐平台商家管理端后台库存管理财务管理系统管理接单管理
作品介绍:Axure高保真企业商城后台管理系统&web端公司商城后台管理原型&连锁门店管理系统交互组件&点餐平台商家管理端后台&库存管理&财务管理&系统 ...
- 1.电子商城后台管理平台项目概况
一.项目介绍 随着信息化的发展,电商也随着互联网的发展日益状态.为了整理之前所学,这里将做一个电子商城后台管理系统. 二.项目需求 电子商城后台管理平台包含账号管理(保存用户信息).用户登录.退出登录 ...
- 商城后台管理React+Springboot
# 商城后台管理React+SSM+小程序 代码下载:README.md · NANLI/商城后台管理React+Springboot - Gitee.com #### 介绍 前端技术:React.A ...
- HTML5期末大作业:仿苏宁易购商城网站设计——仿苏宁易购官网商城(1页) HTML+CSS+JavaScript web网页大作业
HTML5期末大作业:仿苏宁易购商城网站设计--仿苏宁易购官网商城(1页) HTML+CSS+JavaScript web网页大作业 常见网页设计作业题材有 个人. 美食. 公司. 学校. 旅游. 电 ...
- 网页设计作业 仿苏宁易购商城网站设计——仿苏宁易购官网商城(1页) HTML+CSS+JavaScript web网页大作业
HTML5期末大作业:仿苏宁易购商城网站设计--仿苏宁易购官网商城(1页) HTML+CSS+JavaScript web网页大作业 常见网页设计作业题材有 个人. 美食. 公司. 学校. 旅游. 电 ...
- php商城后台管理,商城后台管理系统
摘要:html> 商城后台管理系统商城后台管理系统 /*documentElement.clientHeight*/ .header{width:100%;height: 50px;line-h ...
- 酷鲨商城后台管理界面
代码 <!DOCTYPE html> <html> <head><meta charset="UTF-8"><!-- impo ...
- 美多商城后台管理之登录、浏览器的同源策略
登录 后台管理中我们首先需要完成登录功能,我们可以通过改写美多表单登录来完成相应的功能. 在后台登录中,由于我们前端服务和后端服务的域名不一样,所以我们首先解决跨域问题. 登后的状态保持我们采用jwt ...
最新文章
- AI让交通管理省时、省心、省力
- Ruby中的require_relative和require有什么区别?
- 设计模式 命令模式 之 管理智能家电
- 代码中设置excel自定义格式为[红色]的处理方法
- 敏捷软件开发实践-Sprint Status Track
- SAP Marketing Cloud的技术架构
- dos下操作mysql数据库常用命令
- MySQL8.0连接url
- 组合数学:容斥原理(HDU1976)
- Application Architecture Guide 2.0 - CH 19 - Mobile Applications(2)
- 乐橙tp6接入硬盘_乐橙“智能养殖”新概念,全套监管最佳组合方案曝光!
- 电路方案分析(一)智能手机FM发射器原理图及方案分析
- Delphi D10.X中实现安卓中文语音合成(中文朗读)就这么简单
- uniapp,vue学习笔记
- 【网站】八大极品桌面壁纸网站,惊艳
- git 将多条提交合并为一条
- 【词法分析和语法分析】编译原理实验一(hit)2022-lab1
- instant-ngp
- 首席新媒体运营黎想教程:海报裂变活动怎么做?4个必备技巧
- 使用 yarn 安装 marked
热门文章
- 冠珠瓷砖打造民族文化品牌,让中国陶成为中国潮
- 智慧公交精华主题汇总(更新至20220902)
- Linux xampp apache启动失败
- go html桌面,go语言使用go-sciter创建桌面应用(一) 简单的通过html,css写ui
- 江西哪所高校计算机最强,江西最好考的2所大学!计算机、财务专业省排名第三,力压一本!...
- Excel合并多个单元格内容
- IDEA报错:Command line is too long Shorten command line for xxx or also for JUnit default configuration
- swiper插件的基础使用
- 项目协作管理工具_5种管理工作流程和在线协作的工具
- 一种海量数据安全分类分级架构的实现