前端中间件Midway的使用

  • 一、 关于midway
    • 1. 解决什么痛点
    • 2. 期望达到什么效果
  • 二、创建应用并使用
    • 1. 创建midway应用
    • 2. 认识Midway
      • 2.1 目录结构
      • 2.2 Controller
      • 2.3 路由
      • 2.4 获取请求参数
      • 2.5 Web中间件
      • 2.6 组件使用
      • 2.7 服务(service)
  • 三、写到最后

一、 关于midway

Midway 是阿里巴巴 - 淘宝前端架构团队,基于渐进式理念研发的 Node.js 框架,通过自研的依赖注入容器,搭配各种上层模块,组合出适用于不同场景的解决方案。
Midway 基于 TypeScript 开发,结合了面向对象(OOP + Class + IoC)与函数式(FP + Function + Hooks)两种编程范式,并在此之上支持了 Web / 全栈 / 微服务 / RPC / Socket / Serverless 等多种场景,致力于为用户提供简单、易用、可靠的 Node.js 服务端研发体验。

1. 解决什么痛点

以往的开发中,前端直接项目中直接调取后台服务接口,就会从在过度依赖后台数据,或者只能请求服务后再到渲染层进行数据加工大大影响开发效率,或者存在多个部门协同开发,接口数据格式达不到统一,前端数据处理任务量加重等沟通问题。

2. 期望达到什么效果

在项目/产品开发中存在某种中间件进行服务接口的二次加工或者转发以达到前端所需的统一数据结构。比如如下分工:
数据:负责数据开发,对外提供服务数据接口
后端:负责业务逻辑开发,对外提供服务业务逻辑接口
中间层:根据前端需要,调用多端不同的服务接口并进行拼接、加工数据,对前端提供加工后接口
前端:负责数据渲染

二、创建应用并使用

1. 创建midway应用

$npm init midway
选择 koa-v3 项目进行初始化创建,项目名可以自定,比如 weather-sample。
现在可以启动应用来体验下。
$ npm run dev

则创建了一个类似下面结构的文件

.
├── src ## midway 项目源码
│ └── controller ## Web Controller 目录
│ └── home.controller.ts
├── test
├── package.json
└── tsconfig.json

整个项目包括了一些最基本的文件和目录。
• src 整个 Midway 项目的源码目录,你之后所有的开发源码都将存放于此
• test 项目的测试目录,之后所有的代码测试文件都在这里
• package.json Node.js 项目基础的包管理配置文件
• tsconfig.json TypeScript 编译配置文件

2. 认识Midway

2.1 目录结构

• controller Web Controller 目录
• middleware 中间件目录
• filter 过滤器目录
• aspect 拦截器
• service 服务逻辑目录
• entity 或 model 数据库实体目录
• config 业务的配置目录
• util 工具类存放的目录
• decorator 自定义装饰器目录
• interface.ts 业务的 ts 定义文件

2.2 Controller

控制器常用于对用户的请求参数做一些校验,转换,调用复杂的业务逻辑,拿到相应的业务结果后进行数据组装,然后返回。
在 Midway 中,控制器 也承载了路由的能力,每个控制器可以提供多个路由,不同的路由可以执行不同的操作。

import { Controller, Get } from '@midwayjs/decorator';

@Controller('/')
export class WeatherController {
  // 这里是装饰器,定义一个路由
  @Get('/weather')
  async getWeatherInfo(): Promise<string> {
    // 这里是 http 的返回,可以直接返回字符串,数字,JSON,Buffer 等
    return 'Hello Weather!';
  }
}

@Controller 装饰器告诉框架,这是一个 Web 控制器类型的类,而 @Get 装饰器告诉框架,被修饰的 home 方法,将被暴露为 / 这个路由,可以由 GET 请求来访问
通过访问 /weather 接口返回数据了;整个方法返回了一个字符串,在浏览器中你会收到 text/plain 的响应类型,以及一个 200 的状态码。

2.3 路由

上面创建了一个 GET 路由。一般情况下,我们会有其他的 HTTP Method,Midway 提供了更多的路由方法装饰器。
例如:

import { Controller, Get, Post } from '@midwayjs/decorator';

@Controller('/')
export class HomeController {

  @Get('/')
  async home() {
    return 'Hello Midwayjs!';
  }

  @Post('/update')
  async updateData() {
    return 'This is a post method'
  }
}

Midway 还提供了其他的装饰器, @Get 、 @Post 、 @Put() 、@Del() 、 @Patch() 、 @Options() 、 @Head() 和 @All() ,表示各自的 HTTP 请求方法。
@All 装饰器比较特殊,表示能接受以上所有类型的 HTTP Method。
你可以将多个路由绑定到同一个方法上。

@Get('/')
@Get('/main')
async home() {
  return 'Hello Midwayjs!';
}

返回内容类型将定义的内容放在 src/interface.ts 文件中
例如:

export interface User {
  id: number;
  name: string;
  age: number;
}

使用:下方粗下划线处

import { Controller, Get, Query } from "@midwayjs/decorator";

@Controller('/api/user')
export class UserController {
  @Get('/')
  async getUser(@Query('id') id: string): Promise<User> {
    // xxxx
  }
}

2.4 获取请求参数

请求的数据一般都是动态的,会在 HTTP 的不同位置来传递,比如常见的 Query,Body 等。

第一种 query
@Query 装饰器的有参数,可以传入一个指定的字符串 key,获取对应的值,赋值给入参,如果不传入,则默认返回整个 Query 对象。

// URL = /?id=1
async getUser(@Query('id') id: string) // id = 1
async getUser(@Query() queryData) // {"id": "1"}


如果通过api获取query中的参数
import { Controller, Get, Inject } from "@midwayjs/decorator";
import { Context } from '@midwayjs/koa';

@Controller('/user')
export class UserController {

  @Inject()
  ctx: Context;

  @Get('/')
  async getUser(): Promise<User> {
    const query = this.ctx.query;
    // {
    //   uid: '1',
    //   sex: 'male',
    // }
  }
}

注意:
当 Query String 中的 key 重复时,ctx.query 只取 key 第一次出现时的值,后面再出现的都会被忽略。
比如 GET /user?uid=1&uid=2 通过 ctx.query 拿到的值是 { uid: ‘1’ }。

第二种 body
为什么要用body’传递参数?
• 浏览器中会对 URL 的长度有所限制,如果需要传递的参数过多就会无法传递。
• 服务端经常会将访问的完整 URL 记录到日志文件中,有一些敏感数据通过 URL 传递会不安全。
注意:
框架内置了 bodyParser 中间件来对这两类格式的请求 body 解析成 object 挂载到 ctx.request.body 上。HTTP 协议中并不建议在通过 GET、HEAD 方法访问时传递 body,所以我们无法在 GET、HEAD 方法中按照此方法获取到内容。
框架对 bodyParser 设置了一些默认参数,配置好之后拥有以下特性:
• 当请求的 Content-Type 为 application/json,application/json-patch+json,application/vnd.api+json 和 application/csp-report 时,会按照 json 格式对请求 body 进行解析,并限制 body 最大长度为 1mb。
• 当请求的 Content-Type 为 application/x-www-form-urlencoded 时,会按照 form 格式对请求 body 进行解析,并限制 body 最大长度为 1mb。
• 如果解析成功,body 一定会是一个 Object(可能是一个数组)。

获取单个 body

// src/controller/user.ts
// POST /user/ HTTP/1.1
// Host: localhost:3000
// Content-Type: application/json; charset=UTF-8
//
// {"uid": "1", "name": "harry"}
import { Controller, Post, Body } from "@midwayjs/decorator";

@Controller('/user')
export class UserController {
  @Post('/')
  async updateUser(@Body('uid') uid: string): Promise<User> {
    // id 等价于 ctx.request.body.uid
  }
}

获取整个 body

// src/controller/user.ts
// POST /user/ HTTP/1.1
// Host: localhost:3000
// Content-Type: application/json; charset=UTF-8
//
// {"uid": "1", "name": "harry"}
import { Controller, Post, Body } from "@midwayjs/decorator";

@Controller('/user')
export class UserController {
  @Post('/')
  async updateUser(@Body() user: User): Promise<User> {
    // user 等价于 ctx.request.body 整个 body 对象
    // => output user
    // {
    //   uid: '1',
    //   name: 'harry',
    // }
  }
}

从 API 获取

// src/controller/user.ts
// POST /user/ HTTP/1.1
// Host: localhost:3000
// Content-Type: application/json; charset=UTF-8
//
// {"uid": "1", "name": "harry"}
import { Controller, Post, Inject } from "@midwayjs/decorator";
import { Context } from '@midwayjs/koa';

@Controller('/user')
export class UserController {

  @Inject()
  ctx: Context;

  @Post('/')
  async getUser(): Promise<User> {
    const body = this.ctx.request.body;
    // {
    //   uid: '1',
    //   name: 'harry',
    // }
  }
}

此外装饰器还可以组合使用,获取 query 和 body 参数

@Post('/')
async updateUser(@Body() user: User, @Query('pageIdx') pageIdx: number): Promise<User> {
  // user 从 body 获取
  // pageIdx 从 query 获取
}

第三种 Params
如果路由上使用 :xxx 的格式来声明路由,那么参数可以通过 ctx.params 获取到。
示例:从装饰器获取

// src/controller/user.ts
// GET /user/1
import { Controller, Get, Param } from "@midwayjs/decorator";

@Controller('/user')
export class UserController {
  @Get('/:uid')
  async getUser(@Param('uid') uid: string): Promise<User> {
    // xxxx
  }
}

示例:从 API 获取

// src/controller/user.ts
// GET /user/1
import { Controller, Get, Inject } from "@midwayjs/decorator";
import { Context } from '@midwayjs/koa';

@Controller('/user')
export class UserController {

  @Inject()
  ctx: Context;

  @Get('/:uid')
  async getUser(): Promise<User> {
    const params = this.ctx.params;
    // {
    //   uid: '1',
    // }
  }
}

2.5 Web中间件

Web 中间件是在控制器调用 之前 和 之后(部分)调用的函数。 中间件函数可以访问请求和响应对象。

import { IMiddleware } from '@midwayjs/core';
import { Middleware } from '@midwayjs/decorator';
import { NextFunction, Context } from '@midwayjs/koa';

@Middleware()
export class ReportMiddleware implements IMiddleware<Context, NextFunction> {

  resolve() {
    return async (ctx: Context, next: NextFunction) => {
      // 控制器前执行的逻辑
      const startTime = Date.now();
      // 执行下一个 Web 中间件,最后执行到控制器
      // 这里可以拿到下一个中间件或者控制器的返回值
      const result = await next();
      // 控制器之后执行的逻辑
      console.log(Date.now() - startTime);
      // 返回给上一个中间件的结果
      return result;
    };
  }

  static getName(): string {
    return 'report';
  }
}

例如:

export class ErrorMiddleware implements IWebMiddleware {
    resolve() {
        return async (ctx: Context, next: IMidwayWebNext) => {
            try {
                await next()
            } catch (err: any) {
                const errorInter = RestCode.INTERNAL_SERVER_ERROR;
                console.info('错误信息' + err.name, err.message, err.status);
                const status = err.status || errorInter;
                // 生产环境时 500 错误的详细错误内容不返回给客户端,因为可能包含敏感信息
                const errorMsg = status === errorInter && ctx.app.config.env === 'prod' ?
                    'Internal Server Error' :
                    err.message;

                ctx.body = {
                    code: err.name === 'ValidationError' ? RestCode.VALIDATE_ERROR : status,
                    error: errorMsg.replaceAll('\"',''),
                }

                if (status === 422) {
                    ctx.body.detail = err.errors;
                }
                ctx.status = 200
            }
            };
    }
}


全局使用中间件
所有的路由都会执行的中间件,比如 cookie、session 等等

// src/configuration.ts
import { App, Configuration } from '@midwayjs/decorator';
import * as koa from '@midwayjs/koa';
import { ReportMiddleware } from './middleware/user.middleware';

@Configuration({
  imports: [koa]
  // ...
})
export class AutoConfiguration {

  @App()
  app: koa.Application;

  async onReady() {
    this.app.useMiddleware([ReportMiddleware1, ReportMiddleware2]);
  }
}

路由使用中间件
单个/部分路由会执行的中间件,比如某个路由的前置校验,数据处理等等

import { Controller } from '@midwayjs/decorator';
import { ReportMiddleware } from '../middleware/report.middlweare';

@Controller('/', { middleware: [ ReportMiddleware ] })
export class HomeController {

}

忽略和匹配路由
在中间件执行时,我们可以添加路由忽略的逻辑。

ignore(ctx: Context): boolean {
    // 下面的路由将忽略此中间件
    return ctx.path === '/'
      || ctx.path === '/api/auth'
      || ctx.path === '/api/login';
  }

同理,也可以添加匹配的路由,只有匹配到的路由才会执行该中间件。ignore 和 match 同时只有一个会生效。

 match(ctx: Context): boolean {
    // 下面的匹配到的路由会执行此中间件
    if (ctx.path === '/api/index') {
      return true;
    }
  }

2.6 组件使用

参数校验
Midway 提供了 Validate 组件。 配合 @Validate 和 @Rule 装饰器,用来快速定义校验的规则,帮助用户减少这些重复的代码。
注意:从 v3 开始,@Rule 和 @Validate 装饰器从 @midwayjs/validate 中导出。
1、 安装依赖:$ npm i @midwayjs/validate@3 –save
2、 开启组件:
在 configuration.ts 中增加组件。
import * as validate from ‘@midwayjs/validate’;
import { join } from ‘path’;
@Configuration({
imports: [ validate],
importConfigs: [join(__dirname, ‘./config’)],
})

}
3、 定义检查规则:
为了方便后续处理,我们将 user 放到一个 src/dto 目录中。
例如:
// src/dto/user.ts
import { Rule, RuleType } from ‘@midwayjs/validate’;

export class UserDTO {
@Rule(RuleType.number().required())
id: number;

@Rule(RuleType.string().required())
firstName: string;

@Rule(RuleType.string().max(10))
lastName: string;

@Rule(RuleType.number().max(60))
age: number;
}
4、 应用:
定义完类型之后,就可以直接在业务代码中使用了,开启校验能力还需要 @Validate 装饰器。
// src/controller/home.ts
import { Controller, Get, Provide } from ‘@midwayjs/decorator’;
import { UserDTO } from ‘./dto/user’;
@Controller(‘/api/user’)
export class HomeController {
@Post(‘/’)
async updateUser(@Body() user: UserDTO ) {
// user.id
}
}
Swagger-ui
基于最新的 OpenAPI 3.0.3 实现了新版的 Swagger 组件。
1、 安装依赖:
npm install @midwayjs/swagger@3 --save
npm install swagger-ui-dist --save-dev
2、 开启组件:
import { Configuration } from ‘@midwayjs/decorator’;
import * as swagger from ‘@midwayjs/swagger’;
@Configuration({
imports: [
{
component: swagger,
enabledEnvironment: [‘local’] //只在 local 环境下启用
}]})
export class MainConfiguration {
}
然后启动项目,访问地址:
• UI: http://127.0.0.1:7001/swagger-ui/index.html
• JSON: http://127.0.0.1:7001/swagger-ui/index.json

2.7 服务(service)

在业务中,只有控制器(Controller)的代码是不够的,一般来说会有一些业务逻辑被抽象到一个特定的逻辑单元中,我们一般称为服务(Service)。
在这里插入图片描述
提供这个抽象有以下几个好处:
• 保持 Controller 中的逻辑更加简洁。
• 保持业务逻辑的独立性,抽象出来的 Service 可以被多个 Controller 重复调用。
• 将逻辑和展现分离,更容易编写测试用例。
创建服务
一般会存放到 src/service 目录中。我们来添加一个 user 服务。

import { Provide, App, Inject } from '@midwayjs/decorator';
import { Application } from 'egg';
import { HttpService } from '@midwayjs/axios';
var fs = require('fs');
var path = require('path');
@Provide() //抛出服务
export class UserService {
  @App()
  app: Application;

  @Inject() //依赖注入
  httpService: HttpService;

 async getUser(options: any) {
    const url = 'https://172.30.154.46:9998/samp/v1/auth/login';
    const { data } = await this.httpService.post(url, options);
    return data;
  }
}

使用服务

在 Controller 处,我们需要来调用这个服务。传统的代码写法,我们需要初始化这个 Class(new),然后将实例放在需要调用的地方。在 Midway 中,你不需要这么做,只需要编写我们提供的 “依赖注入” 的代码写法。

import { Inject, Controller, Get, Provide, Query } from '@midwayjs/decorator';
import { UserService } from '../service/user';

@Controller('/api/user')
export class APIController {

  @Inject()//引入服务
  userService: UserService;

  @Get('/')
  async getUser(@Query('id') uid) {
    const user = await this.userService.getUser(uid);
    return {success: true, message: 'OK', data: user};
  }
}

三、写到最后

Midway 框架是在内部已经使用使用 5 年以上的 Node.js 框架,有着长期投入和持续维护的团队做后盾,已经在每年的大促场景经过考验,稳定性无须担心,并且有着丰富的组件和扩展能力,例如数据库,缓存,定时任务,进程模型,部署以及 Web,Socket 甚至 Serverless 等新场景的支持。一体化调用方案可以方便快捷和前端页面协同开发和良好的 TypeScript 定义支持。
所以在项目中应用Midway, 能够为应用提供更优雅的架构。

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

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

相关文章

基于深度学习的高精度安全背心检测识别系统(PyTorch+Pyside6+YOLOv5模型)

摘要&#xff1a;基于深度学习的高精度安全背心检测识别系统可用于日常生活中或野外来检测与定位安全背心目标&#xff0c;利用深度学习算法可实现图片、视频、摄像头等方式的安全背心目标检测识别&#xff0c;另外支持结果可视化与图片或视频检测结果的导出。本系统采用YOLOv5…

微服务: 01-rabbitmq的应用场景及安装(docker)

目录 1. rabbitmq前言简介: 1.1 RabbitMQ的几个重要作用&#xff1a; -> 1.1.1 解耦&#xff1a; -> 1.1.2 异步通信&#xff1a; -> 1.1.3 流量削峰&#xff1a; -> 1.1.4 消息传递的可靠性和持久性&#xff1a; 2. rabbitmq的安装(docker版) -> 2.1 …

SpringMVC 学习整理

文章目录 一、SpringMVC 简介1.1 什么是MVC1.2 什么是Spring MVC1.3 Spring MVC的特点 二、SpringMVC 快速入门三、RequestMapping注解说明四、SpringMVC获取请求参数4.1 通过ServletAPI获取请求参数4.2 通过控制器方法的形参获取请求参数4.3 通过RequestParam接收请求参数4.4 …

Rust语言从入门到入坑——(2)Rust在windows上搭建开发环境

文章目录 0 引入1、搭建 Visual Studio Code 开发环境1.1、安装 Rust 编译工具1.2 、VS Code安装 2、官网在线3、总结4、引用 0 引入 开始搭建一个适合在windows上运行的Rust环境。 Rust支持的程序语言很多&#xff1a;可详见官网介绍 1、搭建 Visual Studio Code 开发环境 …

[架构之路-211]- 需求- 软架构前的需求理解:ADMEMS标准化、有序化、结构化、层次化需求矩阵 =》需求框架

目录 前言&#xff1a; 一、什么是ADMES: 首先&#xff0c;需求是分层次的&#xff1a; 其次&#xff0c;需求是有结构的&#xff0c;有维度的 再次&#xff0c;不同层次需求、不同维度需求之间可以相互转化&#xff08;难点、经验积累&#xff09; 最终&#xff0c;标准…

【雕爷学编程】Arduino动手做(114)---US-015高分辨超声波模块

37款传感器与执行器的提法&#xff0c;在网络上广泛流传&#xff0c;其实Arduino能够兼容的传感器模块肯定是不止这37种的。鉴于本人手头积累了一些传感器和执行器模块&#xff0c;依照实践出真知&#xff08;一定要动手做&#xff09;的理念&#xff0c;以学习和交流为目的&am…

Floyd 判圈算法(Floyd Cycle Detection Algorithm)

Floyd 判圈算法(Floyd Cycle Detection Algorithm) 前言 Floyd判圈算法属于对指针操作的算法&#xff0c;它一般需要且仅需要两个指针&#xff0c;通过设定不同的指针移动速度&#xff0c;来判定链表或有限状态机中是否存在环。人为规定移动较快的指针称为快速指针(fast poin…

给初级测试工程师的一些避坑建议

我遇到的大多数开发人员都不怎么热衷于测试。有些会去做测试&#xff0c;但大多数都不测试&#xff0c;不愿意测试&#xff0c;或者勉而为之。我喜欢测试&#xff0c;并且比起编写新的代码&#xff0c;愉快地花更多的时间在测试中。我认为&#xff0c;正是因为专注于测试&#…

【Turfjs的java版本JTS】前面讲了Turfjs可以实现几何计算,空间计算的功能,如果后端要做这项功能也有类似的类库,JTS

JTS Java Topology Suite 几何计算&#xff1a; 1. 前端js就用这个 Turfjs的类库。参考网站&#xff1a; 计算两线段相交点 | Turf.js中文网 2. 后端java语言就可以用 JTS这个类库&#xff0c;参考网站&#xff1a; JTS参考网站&#xff1a; 1. https://github.com/locatio…

Windows11 安装 CUDA/cuDNN+Pytorch

一、准备工作&#xff1a; 查看torch版本&#xff1a;进入python交互环境&#xff1a; >>>import torch >>>torch.__version__ 查看cuda版本&#xff1a;CMD窗口 nvcc --version 如果版本不一致&#xff0c;需要卸载再重装。 二、安装 Windows 安装 CU…

unity制作愤怒的小鸟

文章目录 一、 介绍SpringJoint2D 、line renderer制作发射绳基类bird脚本的基础功能给bird添加飞行拖尾效果pig类游戏胜利的小星星烟花界面摄像机跟随移动游戏失败的界面多种小鸟的制作&#xff1a;黄鸟、绿鸟、黑鸟地图选择关卡选择数据保存制作多个关卡场景异步加载游戏全局…

go 调试利器之pprof指标分析

文章目录 概要一、指标类型1.1、堆栈指标1.2、CPU指标分析1.3、http-pprof 二、go tool pprof2.1、可视化2.2、CPU火焰图 概要 Go语言原生支持对于程序运行时重要指标或特征进行分析。pprof是其中一种重要的工具&#xff0c;其不仅可以分析程序运行时的错误&#xff08;内存泄…

绕过激活锁 ,拯救一台旧手机iphone

一台旧的iphone忘了apple id账号和密码了&#xff0c;导致锁住了 某宝上解锁要花50&#xff0c; 不是舍不得花钱&#xff0c;作为一个搞技术的&#xff0c;实在觉得花钱有点丢人 经过一番探索 最终确定了有用的流程 并贴出来 亲测可用 最终实现了趟再床上就可以打卡 1、 刷机 …

【软件测试】性能测试服务端—排查指标问题(详细)

目录&#xff1a;导读 前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结&#xff08;尾部小惊喜&#xff09; 前言 软件性能测试的目…

node安装后的全局环境变量配置

安装node时&#xff0c;位置最好不要装在c盘&#xff0c;这里&#xff0c;我在D盘下创建了文件夹"node"&#xff0c;安装地址选择在该文件夹下 一直next&#xff0c;直到安装结束&#xff0c;打开"node"文件夹&#xff0c;安装完后&#xff0c;里面的配置…

未来10年,网络安全人才就业的黄金期

随着大数据、物联网、人工智能等新技术的发展&#xff0c;信息技术与经济社会各领域的融合也更加深入。网络攻击行为日趋复杂、黑客攻击行为组织性更强、针对手机无线终端的网络攻击日趋严重&#xff0c;近几年有关网络攻击和数据泄露的新闻层出不穷。因此&#xff0c;随着国家…

Nodejs一、初识

零、文章目录 Nodejs一、初识 1、初识 Node.js &#xff08;1&#xff09;回顾与思考 浏览器中的 JavaScript 的组成部分 为什么 JavaScript 可以在浏览器中被执行 为什么 JavaScript 可以操作 DOM 和 BOM 浏览器中的 JavaScript 运行环境 JavaScript 能否做后端开发&#…

MySQL - 第0节 - MySQL在Centos 7环境安装

目录 1.安装前说明 2.MySQL在Centos 7环境安装 2.1.卸载不要的环境 2.2.配置mysql官方yum源 2.3.检查yum源能否正常工作 2.4.安装mysql 2.5.检查mysql是否安装成功 2.6.启动mysqld数据库服务端 2.7.三种登录方法 2.7.1.登陆方法一 2.7.2.登陆方法二 2.7.3.登陆方法…

Pandas+Pyecharts | 中国高校及专业数据分析可视化

文章目录 &#x1f3f3;️‍&#x1f308; 1. 导入模块&#x1f3f3;️‍&#x1f308; 2. Pandas数据处理2.1 读取数据 &#x1f3f3;️‍&#x1f308; 3. Pyecharts数据可视化3.1 全国高校分布地图3.2 全国高校分布城市地图3.3 本科/专科占比3.4 985/211/双一流高校数量占比…

【考研复习】李春葆新编C语言习题与解析(错误答案订正)持续更新

新编C语言习题与解析 做习题时发现有些错误答案&#xff0c;写篇博客进行改正记录。不对地方欢迎指正&#xff5e; 第二章 C. 其中b的表达形式错误&#xff0c;若加上0x1e2b则正确。所以C错误。 D. e后为整数。指数命名规则&#xff1a;e前有数&#xff0c;后有整数。所以D错…
最新文章