若依框架:前端项目结构与初始页面渲染流程

news2024/9/28 5:32:34

目录

main.js入口文件

前端页面初始化

package.json配置文件

vue-cli:.env模式和环境变量配置

vue-cli三大核心构件

 CLI 服务与npm scripts

vue-cli-service命令与.env模式配置文件

.env模式和环境变量配置

vue.config.js:项目启动-自动打开默认浏览器的两种配置方式  

方式1:vue-cli-service命令参数--open   

方式2:vue.config.js配置文件-devServer

vue.config.js配置文件与vue-cli

方式1:CommonJS模块导出

方式2:defineConfig 帮手函数

vue-router全局导航守卫配置

Vue-Router

Vue-Router:内置组件

router-view组件与初始页面渲染流程解析

vue-Router路由的配置信息

Vue-Router全局导航守卫配置

全局前置导航守卫的注册/配置

全局前置导航守卫的控制逻辑图解


        若依前后端环境在本地部署完毕之后,成功启动前端Vue项目之后,会自动打开默认浏览器,并看到如下的初始登录页面,展示一个登录表单+验证码图像。

若依-前端项目初始页面

main.js入口文件

        如果打开前端项目的main.js入口文件查看,会看到内部做了一些Scss全局变量导入、全局样式index.scss引入、自定义指令导入directive.js、自定义插件导入plugins.js、文件下载download等全局方法挂载、分页组件\富文本组件\图片上传组件等自定义组件的全局注册(Vue.component)、element-ui第三方UI组件库注册,以及Vue实例创建等诸多项初始化工作。 

        这是一个比较大的话题,可能需要花费不少时间去研究这些实现细节。在之后的篇章中将一点点去进行剖析。

前端页面初始化

        以上谈到的关于main.js中的所做的初始化工作,是比较直观的。当然,若依的Vue前端项目也执行了一些较为隐蔽的、不易发觉的初始化工作,这些内容,即:后者是此刻我比较关心的、也是接下来要基于个人的粗浅理解、着重进行谈论的内容。

        主要涉及的内容包括:vue.config.js文件配置.env模式和环境变量配置vue-router全局导航守卫配置vue-router路由配置简介。由于整个前端项目是一个比较系统性的工程,各部分相互穿插,因此,以上涉及的内容可能不会特别深入到某个细节的知识点,而只是和当前篇章《前端页面初始化》相关的内容,至于余下的,将在之后的篇章中逐步深入。

package.json配置文件

        当我拿到一个前端项目时,我会比较习惯性的先去查看整个目录结构,接着就是去看一看package.json配置文件,因为它至少可以告诉我们项目的环境依赖、启动/打包/测试等相关的npm脚本命令等基础信息。

        package.json文件内容如下。当然,初次见面,我们还是优先关注scripts节点下的内容,

{
  "name": "ruoyi",
  "version": "3.8.4",
  "description": "若依管理系统",
  "author": "若依",
  "license": "MIT",
  "scripts": {
    "dev": "vue-cli-service serve",
    "build:prod": "vue-cli-service build",
    "build:stage": "vue-cli-service build --mode staging",
    "preview": "node build/index.js --preview",
    "lint": "eslint --ext .js,.vue src"
  },
  "husky": {
    "hooks": {
      "pre-commit": "lint-staged"
    }
  },
  "lint-staged": {
    "src/**/*.{js,vue}": [
      "eslint --fix",
      "git add"
    ]
  },
  "keywords": [
    "vue",
    "admin",
    "dashboard",
    "element-ui",
    "boilerplate",
    "admin-template",
    "management-system"
  ],
  "repository": {
    "type": "git",
    "url": "https://gitee.com/y_project/RuoYi-Vue.git"
  },
  "dependencies": {
    "@riophae/vue-treeselect": "0.4.0",
    "axios": "0.24.0",
    "clipboard": "2.0.8",
    "core-js": "3.25.3",
    "echarts": "5.4.0",
    "element-ui": "2.15.10",
    "file-saver": "2.0.5",
    "fuse.js": "6.4.3",
    "highlight.js": "9.18.5",
    "js-beautify": "1.13.0",
    "js-cookie": "3.0.1",
    "jsencrypt": "3.0.0-rc.1",
    "nprogress": "0.2.0",
    "quill": "1.3.7",
    "screenfull": "5.0.2",
    "sortablejs": "1.10.2",
    "vue": "2.6.12",
    "vue-count-to": "1.0.13",
    "vue-cropper": "0.5.5",
    "vue-meta": "2.4.0",
    "vue-router": "3.4.9",
    "vuedraggable": "2.24.3",
    "vuex": "3.6.0"
  },
  "devDependencies": {
    "@vue/cli-plugin-babel": "4.4.6",
    "@vue/cli-plugin-eslint": "4.4.6",
    "@vue/cli-service": "4.4.6",
    "babel-eslint": "10.1.0",
    "babel-plugin-dynamic-import-node": "2.3.3",
    "chalk": "4.1.0",
    "compression-webpack-plugin": "5.0.2",
    "connect": "3.6.6",
    "eslint": "7.15.0",
    "eslint-plugin-vue": "7.2.0",
    "lint-staged": "10.5.3",
    "runjs": "4.4.2",
    "sass": "1.32.13",
    "sass-loader": "10.1.1",
    "script-ext-html-webpack-plugin": "2.1.5",
    "svg-sprite-loader": "5.1.1",
    "vue-template-compiler": "2.6.12"
  },
  "engines": {
    "node": ">=8.9",
    "npm": ">= 3.0.0"
  },
  "browserslist": [
    "> 1%",
    "last 2 versions"
  ]
}

         从中可以了解到如下内容,

# 项目开发环境下的启动命令

npm run dev

# 项目生产环境下的打包命令

npm run build:prod

# 项目Staging 模式下的打包命令

npm run build:stage

# 项目的打包预览命令-【即:先执行打包命令,然后在本地开启一个端口号,执行项目部署操作,通过localhost主机+端口号,可以看到项目打包之后的页面展示效果】

npm run preview

# ESlint自动修复错误的命令-【执行此命令后,在执行npm run dev启动项目,可防止ESLint检查报错】

npm run lint

打包预览命令执行后控制台信息
打包预览命令执行后-页面预览效果

vue-cli:.env模式和环境变量配置

        以上,解析package.json文件,我们可以拿到项目在开发环境下的启动命令:`npm run dev`。那么,这个脚本命令是如何做到开发环境、生产环境的区分呢?

        这就到聊到vue-cli脚手架中.env配置文件相关的内容了。按照传统惯例,我们要先使用如下命令进行本地的全局安装,才能进行后续的使用环节。

npm install -g @vue/cli
# OR
yarn global add @vue/cli

vue-cli三大核心构件

        先来基于我自己的理解来聊一下vue-cli吧。

CLI-命令行界面构件

        vue-cli,俗称“Vue脚手架”,通常,我们创建一个vue项目,很少会自己基于webpackwebpack-server去手动搭建项目框架,而是会使用如下命令获得一个vue项目模板。

vue create project_name

        其实,这个命令就是vue-cli的CLI核心构件提供的终端里的 vue 命令,用于快速创建一个Vue项目模板。

vue-cli官网介绍

CLI服务-命令行界面服务构件

node_modules文件夹

        基于vue-cli命令创建的vue项目,一般都会在项目的根目录下有一个node_modules文件夹,用来存放当前项目相关的所有依赖项或者说是第三方JavaScript开发库。我们注意到,若依的前端项目下就有node_modules文件夹。

        其实,这个文件夹下还包括了@vue/cli-service插件依赖项,这个插件就是保证package.json文件中scripts节点下一些npm run XXX命令正常运行的关键。我们来看一下vue-cli官网的介绍,

         细致看package.json中定义的一些命令,键值对的值,如前3个都包含vue-cli-service相关的命令,这些命令可以说都是依赖于@vue/cli-service插件才能生效的。

@vue/cli-service插件驱动的命令

 CLI插件-命令行界面插件构件

           有关CLI插件,我们最常见的就是ESLint,当前还有一些其它的插件,但是无论如何,这些插件都是以@vue/cli-plugin开头的,我们可以在package.json文件中的devDependencies节点下看到若依前端框架中涉及到的CLI插件,分别是:babel和ESLint插件。

           至于这些插件有什么用?插件可以修改 webpack 的内部配置,也可以向 vue-cli-service 注入命令。

CLI插件

 CLI 服务与npm scripts

        我们还是回归到“.env模式和环境变量配置”这个核心问题上,但是,关于环境区分,我们最直观的区分形式,是以npm scritps脚本命令的方式去进行区分的。那么,这其中的原理是什么呢?

        我们还要继续聊一聊vue-cli三大核心构件之——CLI服务相关的内容。

        以上内容中,我们谈到,在任何Vue项目根目录下的node_modules下,会自动安装一个叫做“@vue/cli-service”的第三方依赖,这个依赖项提供了名为 vue-cli-service 的命令,开发者可以在 npm scripts 中以 vue-cli-service、或者从终端中以 ./node_modules/.bin/vue-cli-service 访问这个命令

         而在执行这个vue-cli-service命令时,还可以附加一些参数,例如:上图中的build:satge中就包含了一个mode参数,用于区分项目中预先配置好的环境变量

        以vue-cli-service serve启动项目的命令为例,详细的参数信息如下,

用法:vue-cli-service serve [options] [entry]

选项:

  --open    在服务器启动时打开浏览器
  --copy    在服务器启动时将 URL 复制到剪切版
  --mode    指定环境模式 (默认值:development)
  --host    指定 host (默认值:0.0.0.0)
  --port    指定 port (默认值:8080)
  --https   使用 https (默认值:false)

        而vue-cli-service命令在执行时,会基于内部的webpack-dev-server,启动一个开发服务器并附带开箱即用的模块热重载 (Hot-Module-Replacement)。除了通过命令行参数,你也可以使用 vue.config.js 里的 devServer 字段配置开发服务器,当然,这是下一部分我们要讨论的内容。

        再以vue-cli-service build打包项目的命令为例,详细的参数信息如下,

用法:vue-cli-service build [options] [entry|pattern]

选项:

  --mode        指定环境模式 (默认值:production)
  --dest        指定输出目录 (默认值:dist)
  --modern      面向现代浏览器带自动回退地构建应用
  --target      app | lib | wc | wc-async (默认值:app)
  --name        库或 Web Components 模式下的名字 (默认值:package.json 中的 "name" 字段或入口文件名)
  --no-clean    在构建项目之前不清除目标目录的内容
  --report      生成 report.html 以帮助分析包内容
  --report-json 生成 report.json 以帮助分析包内容
  --watch       监听文件变化

        vue-cli-service build 会在 dist/ 目录产生一个可用于生产环境的包,带有 JS/CSS/HTML 的压缩,和为更好的缓存而做的自动的 vendor chunk splitting。它的 chunk manifest 会内联在 HTML 里。类似于vue-cli-service serve项目启动命令,项目打包的相关配置也可以在vue.config.js文件之中进行指定。

vue-cli-service命令与.env模式配置文件

        注意到上述与项目启动、打包相关的 vue-cli-service命令,都含有一个'--mode'参数,这个参数其实就是用来指定环境模式的,其中:vue-cli-service serve命令的--mode参数默认是开发环境,对应的值是:development,通常是在项目开发过程中使用的;当然,也还有生产环境production,通常是在项目打包/线上环境使用的。

        具体的使用,例如:

         上图的命令,默认等价于,

  "scripts": {

    "dev": "vue-cli-service serve --mode development",

    "build:prod": "vue-cli-service build --mode production",

    "build:stage": "vue-cli-service build --mode staging",

    "preview": "node build/index.js --preview",

    "lint": "eslint --ext .js,.vue src"

  },

.env模式和环境变量配置

         进一步思考,这里的production、development是如何生效的呢?其实,仔细观察,会发现,若依前端项目根目录下,还包含了三个以.env开头的文件,例如:.env.development.env.production.env.staging,而上述命令中的--mode参数后面的值,就是与文件名中.env.xxx中的xxx部分相对应的,例如:执行npm run dev,以vue-cli-service serve --mode development命令启动项目时,在项目中的任何地方,待用process.env去查询环境变量时,匹配的就是.env.development文件中定义的信息。

         例如,.env.development开发环境变量配置文件中定义的信息如下,那么在开发环境下,就可以通过process.env.VUE_APP_TITLE的方式,拿到页面标题的内容,其它的以此类推。

# 页面标题
VUE_APP_TITLE = 若依管理系统

# 开发环境配置
ENV = 'development'

# 若依管理系统/开发环境
VUE_APP_BASE_API = '/dev-api'

# 路由懒加载
VUE_CLI_BABEL_TRANSPILE_MODULES = true

        .env文件中的信息称之为“环境变量”,通常地,配置一个.env.xxx文件的操作,也叫作:配置环境变量。但是,环境变量的名称定义并不是随意可写的,而是要遵循一定的规范。如下图所示,

         但是,请注意:不要在你的应用程序中存储任何机密信息(例如私有 API 密钥)!环境变量会随着构建打包嵌入到输出代码,意味着任何人都有机会能够看到它。

        请注意,只有 NODE_ENVBASE_URL 和以 VUE_APP_ 开头的变量将通过 webpack.DefinePlugin 静态地嵌入到客户端侧的代码中。这意味着,只有遵循此规范的环境变量在一个Vue前端应用中才能生效。

补充:环境文件加载优先级

vue.config.js:项目启动-自动打开默认浏览器的两种配置方式  

         接下来,我们终于可以执行'npm run dev'命令,间接驱动“vue-cli-service serve --mode development”命令,来启动若依前端项目了。

        等待若干秒时长,项目被启动,并自动打开如下页面。

若依前端-起始页

         此刻我们当然应该高兴,因为这意味着若依的前后端项目我们至少已经在本地初步地部署成功了。但是,随之而来的是困惑:Vue项目是如何做到项目启动成功之后,自动打开默认浏览器,展示初始页面的呢?

方式1:vue-cli-service命令参数--open   

        还记得之前,我们在讨论vue-cli-service serve命令时,它包含着一个open参数吗?

vue-cli-service serve

         好的,兄弟,我们来配置一下试一试,如下图所示,经过实际验证,是可以生效的。

方式2:vue.config.js配置文件-devServer

        另一点内容,我们在谈论 vue-cli-service serve命令时,也提到,它的配置参数,也可以在vue.config.js配置文件中,对devServer字段进行配置,也是可行的。

       当然,若依前端项目默认就是这样配置的。

vue.config.js配置文件与vue-cli

         此刻,相比深入了解vue.config.js的具体配置项,我想你一定更想了解,这里的vue.config.js配置文件是如何生效的?

        如果你了解过Java后端框架SpringBoot,那么,可以清晰地认定:项目启动时,会自动去加载resources目录下的application.yml配置文件。一样的道理,vue.config.js配置文件就是Vue前端项目的配置文件,在项目启动时会自动被加载、解析。

        那么,它是如何生效的呢?还记得@vue/cli-service依赖项吗,这个项目根目录下的vue.config.js配置文件,在启动时,就是被@vue/cli-service依赖项自动加载的。当然,也可以在package.json文件中,新建一个vue结点,进行同类型的配置。但是,通常的我们更推荐在vue.config.js文件中进行配置。

vue.config.js配置文件加载原理

        那么,标准的vue.config.js配置文件该如何书写呢?

        一般有两种书写方式,

方式1:CommonJS模块导出

        示例文件内容如下,

// vue.config.js

/**
 * @type {import('@vue/cli-service').ProjectOptions}
 */
module.exports = {
  // 选项...
}

方式2:defineConfig 帮手函数

         示例文件内容如下,

// vue.config.js
const { defineConfig } = require('@vue/cli-service')

module.exports = defineConfig({
  // 选项
})

        详细的配置项,可以查看Vue-cli官网-配置参考。

vue-router全局导航守卫配置

        基本了解Vue项目的package.json、.env模式和环境变量区分、vue.config.js配置文件、vue-cli与项目基本启动/打包/规范化命令等内容之后,新的问题来了:若依的Vue前端项目启动之后,为什么是下面这个登录页面,这个路由控制是如何实现的呢?

起始页

        结合若依的前端项目框架,这就要谈到Vue-Router路由控制相关全局导航守卫相关的内容了 。

Vue-Router

        Vue-Router的介绍,借用Vue Router官网的截图,总结为一句话就是:Vue Router为Vue前端项目提供了路由配置、路由跳转/导航控制相关的功能。

什么是Vue-Router?

         如果你了解过后端项目的开发流程,那么这里的Vue Router,也可以理解为类似于Java后端Controller控制器的页面重定向、请求拦截等一类操作。

        Vue-Router官方网站提供了如下两种安装Vue Router依赖库的方式,

# npm安装命令
npm install vue-router@4

# yarn安装命令
yarn add vue-router@4

Vue-Router:内置组件

        Vue-Router提供了两个强大的内置组件:<router-link/>、<router-view/>,其中:

        ①<router-link/>:类似于HTML中的<a></a>标签,但是,相比a标签,<router-link/>可以不重新加载页面的情况下更改 URL,处理 URL 的生成以及编码。

        ②<router-view/>router-view 将显示与 url 对应的组件。你可以把它放在任何地方,以适应你的布局。

router-view组件与初始页面渲染流程解析

        我们可以查看若依前端项目中App.vue组件,在<template></template>内部,就包含了<router-view/>组件,

<template>
  <div id="app">
    <router-view />
    <theme-picker />
  </div>
</template>

        这里的<router-view/>组件就是用于显示默认路由"/"或者""对应的组件的,我们可以通过vue-devTools开发工具查看页面组件的组织结构,注意到:在id为app的组件根节点下,<App/>父组件下的<router-viewer/>组件对应的就是Login.vue登录页面组件,因此,在执行npm run dev(vue-cli-service serve --mode development)项目启动之后,通过@vue/cli-service加载vue.config.js文件,解析到devServer.open=true,自动打开浏览器;然后通过路由匹配,将<App/>组价内部的<router-view/>组件替换为默认路由对应的Login.vue登录组件

vue-Router路由的配置信息

        接下来,我们可能会疑惑,这里的vue-Router路由的配置信息在哪里呢?或者说,Vue-Router的配置信息是如何生效的呢?

        通常地,Vue项目在创建之后,如果选择了vue-Router依赖项,那么,就会自动在项目根目录下创建一个router文件夹,里面包含了一个index.js文件,这个index.js文件,就是用来对Vue-Router的路由规则进行配置的

        我们查看若依前端项目的这个文件,会发现最终该文件基于ES6的export的语法规则,导出了一个Router对象,而这个Router类是预先调用Vue.use()方法注册完成的。

import Vue from 'vue'
import Router from 'vue-router'

Vue.use(Router)


...

export default new Router({
  mode: 'history', // 去掉url中的#
  scrollBehavior: () => ({ y: 0 }),
  routes: constantRoutes
})

        注意到,这里的Router的routes参数就是关键,该参数的内容如下,

// 公共路由
export const constantRoutes = [
  {
    path: '/redirect',
    component: Layout,
    hidden: true,
    children: [
      {
        path: '/redirect/:path(.*)',
        component: () => import('@/views/redirect')
      }
    ]
  },
  {
    path: '/login',
    component: () => import('@/views/login'),
    hidden: true
  },
  {
    path: '/register',
    component: () => import('@/views/register'),
    hidden: true
  },
  {
    path: '/404',
    component: () => import('@/views/error/404'),
    hidden: true
  },
  {
    path: '/401',
    component: () => import('@/views/error/401'),
    hidden: true
  },
  {
    path: '',
    component: Layout,
    redirect: 'index',
    children: [
      {
        path: 'index',
        component: () => import('@/views/index'),
        name: 'Index',
        meta: { title: '首页', icon: 'dashboard', affix: true }
      }
    ]
  },
  {
    path: '/user',
    component: Layout,
    hidden: true,
    redirect: 'noredirect',
    children: [
      {
        path: 'profile',
        component: () => import('@/views/system/user/profile/index'),
        name: 'Profile',
        meta: { title: '个人中心', icon: 'user' }
      }
    ]
  }
]

        仔细观察,我们找到了默认路由路径""对应的组件,竟然是:Index.vue主页组件,但是,实际上显示的是Login.vue登录组件,这又是如何实现的呢?

Vue-Router全局导航守卫配置

         我们讲到:默认路由路径""对应的组件,竟然是:Index.vue主页组件,但是,实际上显示的是Login.vue登录组件,这种逻辑其实是通过Vue-Router的全局导航守卫实现的。

        全局导航守卫,就类似于Java后端的Filter过滤器,例如:在用户还未登陆时,可以将一些未携带Token信息的HTTP请求在请求链中提前过滤掉,实现某种主页访问的权限控制。

标题

 

        这里基于Vue-Router的全局导航守卫,是一样的实现思路。由于全局导航守卫在任意的导航路由被触发时,都会先去执行导航守卫中预定义的逻辑,因此,也可以实现类似于后端基于过滤器的首页访问控制的效果。

全局前置导航守卫的注册/配置

        可以使用 router.beforeEach 注册一个全局前置守卫:

const router = createRouter({ ... })

router.beforeEach((to, from) => {
  // ...
  // 返回 false 以取消导航
  return false
})

        至于若依前端项目中的全局导航守卫配置,是在项目根目录下的permission.js文件中实现的,具体代码如下,

import router from './router'
import store from './store'
import { Message } from 'element-ui'
import NProgress from 'nprogress'
import 'nprogress/nprogress.css'
import { getToken } from '@/utils/auth'
import { isRelogin } from '@/utils/request'

NProgress.configure({ showSpinner: false })

//路由白名单-用户未登录时可以随意访问的路由
const whiteList = ['/login', '/auth-redirect', '/bind', '/register']

/**
 * 全局前置守卫-router.beforeEach
 *  判断用户是否有权限进入主页-获取存储在Cookie中的token值
 *    有token-进入主页
 *    无token-进入登录页重新登录
 */
router.beforeEach((to, from, next) => {
  console.log(to)
  console.log(from)
  console.log(next)
  debugger;
  NProgress.start()
  //从Cookie中获取Token-判断用户是否已经登录
  if (getToken()) {
    //如果已经登录
    to.meta.title && store.dispatch('settings/setTitle', to.meta.title)
    /* has token*/
    if (to.path === '/login') {
      next({ path: '/' })
      NProgress.done()
    } else {
      if (store.getters.roles.length === 0) {
        isRelogin.show = true
        // 判断当前用户是否已拉取完user_info信息
        store.dispatch('GetInfo').then(() => {
          isRelogin.show = false
          store.dispatch('GenerateRoutes').then(accessRoutes => {
            // 根据roles权限生成可访问的路由表
            router.addRoutes(accessRoutes) // 动态添加可访问路由表
            next({ ...to, replace: true }) // hack方法 确保addRoutes已完成
          })
        }).catch(err => {
            store.dispatch('LogOut').then(() => {
              Message.error(err)
              next({ path: '/' })
            })
          })
      } else {
        next()
      }
    }
  } else {
    // 没有token-用户未登录
    if (whiteList.indexOf(to.path) !== -1) {
      // 如果在免登录白名单,直接进入目标路由对应的页面
      next()
    } else {
      //如果不在登录白名单中时,自动跳转到Login登录组件进行登录
      next(`/login?redirect=${to.fullPath}`) // 否则全部重定向到登录页
      NProgress.done()
    }
  }
})

//全局后置钩子-不会接受 next 函数也不会改变导航本身
router.afterEach(() => {
  NProgress.done()
})

全局前置导航守卫的控制逻辑图解

        下图为全局前置导航守卫的作用机制,

        PS:有关获取Token成功之后,进行路由表动态生成的逻辑,在之后的篇章中再进行梳理。

 

若依前端项目-页面初始化时-前置导航守卫实现逻辑

         在下一篇章中,将介绍Login.vue登录组件的初始化流程以及验证码图片的实现逻辑。

        

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

pycharm如何设置python文件模板

pycharm如何设置python文件模板设置文件模板预定义变量设置自定义模板变量设置文件模板 打开设置界面 进入编辑器->文件和代码模板 此处我只写了文件头注释模板&#xff0c;也可以加一些默认代码&#xff0c;比如&#xff1a; python if __name__ "__main__":…

NC65在单据添加按钮跳转到固定单据,且进行数据初始化

实现功能 下面两个是按钮 下面红框里面的内容是上面单据带过来的 上面就是本地代码实现的功能 具体实现代码 提前约定 为了方便称呼&#xff0c;这里把第一张图称为上游单据&#xff0c;第二张图为下游单据 所有代码AggVo都要替换成你自己的 配置文件 上游单据拓展配置文…

2023年天津美术学院专升本专业课线上考试安排准备及设备操作说明

天津美术学院2023年高职升本招生专业考试考生须知及操作说明一、考试时间安排二、考前准备 (一)纸张及其他材料(二)考试设备及网络 1.考生须提前准备好至少两部智能手机&#xff0c;为确保网络考试顺利进行&#xff0c;建议考生使用最近3年上市的主流品牌手机&#xff08;如iPh…

太强了!这么设计中间件完美解决了百万并发的问题!

V-xin&#xff1a;ruyuan0330 获得600页原创精品文章汇总PDF 目录 一、大部分人对Java并发仍停留在理论阶段二、中间件系统的内核机制&#xff1a;双缓冲机制三、百万并发的技术挑战四、内存数据写入的锁机制以及串行化问题五、片机制 分段加锁机制 六、缓冲区写满时的双缓冲…

c++ - 第19节 - c++11

1.C11简介 c11简介&#xff1a;在2003年C标准委员会曾经提交了一份技术勘误表(简称TC1)&#xff0c;使得C03这个名字已经取代了C98称为C11之前的最新C标准名称。不过由于C03(TC1)主要是对C98标准中的漏洞进行修复&#xff0c;语言的核心部分则没有改动&#xff0c;因此人们习惯…

Pycharm打开Project(工程)时停留在preparing workspace时间过长,导致打开很慢的解决方法...

Pycharm打开Project(工程)时停留在preparing workspace时间过长,导致打开很慢的解决方法… 昊虹君用Pycharm进行Python的开发&#xff0c;一直用得好好的&#xff0c;也没作过什么异常操作&#xff0c;但是从上星期开始&#xff0c;打开Project(工程)时停留在preparing worksp…

【王道操作系统】2.1.1 进程的定义、特征、组成、组织

进程的定义、特征、组成、组织 文章目录进程的定义、特征、组成、组织1.进程的定义2.进程的特征3.进程的组成4.进程的组织1.进程的定义 程序的概念&#xff1a; 进程的概念&#xff1a; 进程和程序的区别和联系&#xff1a; 区别&#xff1a; 进程是动态的&#xff0c;程序是静…

Linux系统下crond任务调度指令的常见用法

Linux系统下crond任务调度指令的常见用法 任务调度 任务调度是指系统在某个时间执行的特定的命令或程序。任务调度分类:1)系统工作:有些重要的工作必须周而复始地执行。如病毒扫描等;2)个别用户工作:个别用户可能希望执行某些程序&#xff0c;比如对mysql数据库的备份。 基本语…

【攻防世界】网鼎杯2018 Web fakebook

学web总是能让我学到新的知识&#xff0c;很开心&#xff0c;很有趣&#xff0c;很好玩 打开题目 一个登录按钮&#xff0c;一个注册按钮&#xff0c;其余没有什么发现&#xff0c;对于web来说&#xff0c;常规先测试一下robots.txt文件 果然又发现&#xff0c;有一个bak文件…

opencv-python常用函数解析及参数介绍(二)——图像填充与图像融合

1.图像填充 函数及参数介绍 在opencv中使用cv2.copyMakeBorder可以进行图像的边界填充&#xff0c;需要的参数为(img, top_size, bottom_size, left_size, right_size, borderType&#xff09;&#xff0c;即&#xff08;图片&#xff0c;上侧填充值&#xff0c;下侧填充值&a…

【数据结构与算法】KMP算法

文章目录前言一 .KMP的来历二.KMP解决的问题1.引入2.定义的引入1.字符串前缀2.字符串后缀3.最长相等前后缀3.核心思想三.next/prefix1.next的含义定义规律2.next的求取1.准备工作2.思路和图解4.应用前言 在C语言的strcmp的实现过程中&#xff0c;所涉及的算法较为简单&#xff…

Golang - 字符串操作汇总

Golang 字符串操作汇总1 string初始化2 遍历string3 byte & Rune3.1 初始化3.2 byte和rune区别1 string初始化 func newString() {//1. 字符串初始化// 方式一&#xff1a;使用简写声明&#xff0c;带有字符串的变量,支持特殊字符str : "one hello \n world"fmt…

三个月后,快手To B怎么样了?

未来&#xff0c;如何独立作战和走出快手的TOC“客户资源圈”&#xff0c;或将成为快手TOB新的十字路口。 作者|斗斗 编辑|皮爷 出品|产业家 人口红利终结&#xff0c;流量红利终结&#xff0c;超常规的高速增长终结。TOC模式的路越来越难走了。 快手与抖音作为短视频…

光耦特性以及计算

光耦特性 光耦器件电路图 这是我们常用的。光耦器件以及它的连接方式。 左侧R1是我们主要考虑的。 电流最小值是要让LED能够保持发光状态&#xff0c;最大值的话。1.不能让LED烧坏了。2. LED的负极端是单片机的。 这里主要是看引脚灌入电流的最大值。 电气规格 我们看看说…

手机数据包抓包详解

今天继续给大家介绍渗透测试相关知识&#xff0c;本文主要内容是手机数据包抓包详解。 免责声明&#xff1a; 本文所介绍的内容仅做学习交流使用&#xff0c;严禁利用文中技术进行非法行为&#xff0c;否则造成一切严重后果自负&#xff01; 再次强调&#xff1a;严禁对未授权设…

并发编程——6.共享模型之不可变

目录6.共享模型之不可变6.1.日期转换的问题6.1.1.问题提出6.1.2.解决思路——同步锁6.1.3.解决思路——不可变6.2.不可变设计6.3.享元模式6.3.1.简介6.3.2.体现6.3.3.DIY6.4.final 原理6.5.无状态本文笔记整理来自黑马视频https://www.bilibili.com/video/BV16J411h7Rd/?p197&…

Unity脚本(二)

视频教程&#xff1a;https://www.bilibili.com/video/BV12s411g7gU/?share_sourcecopy_web Transform 对象的位置、旋转和缩放 场景中的每个对象都有一个Transform&#xff0c;用于存储和操作对象的位置、旋转和缩放。 每个Transform都可以有一个父级&#xff0c;能够分…

C语言强制类型转换

强制类型转换是把变量从一种类型转换为另一种数据类型。例如&#xff0c;如果您想存储一个 long 类型的值到一个简单的整型中&#xff0c;您需要把 long 类型强制转换为 int 类型。您可以使用强制类型转换运算符来把值显式地从一种类型转换为另一种类型&#xff0c;如下所示&am…

gitlab-ci.yml关键字(五)tags 、only 、when

tags 使用Tags用于选择Runner的标签列表 我们在创建Runner 时可以给该Runner打上特定的标签&#xff0c;那后续流水线中的job如果需要使用特定标签的Runner执行时&#xff0c;就需要使用tags来标记 比如这里有两个标签的Runner 也可以对当前的runner进行一些配置上的设置 …

2022总结:我是怎样从一个混子到如今小有所成

前言 &#x1f340;作者简介&#xff1a;被吉师散养、喜欢前端、学过后端、练过CTF、玩过DOS、不喜欢java的不知名学生。 &#x1f341;个人主页&#xff1a;红中 &#x1f342;抽根烟&#xff0c;吹个牛b(不是 入门 如果硬要问我是在什么时候入门的&#xff0c;那就要说到高一…