Vue系列第五篇:Vue2(Element UI) + Go(gin框架) + nginx开发登录页面及其校验登录功能

news2024/11/24 6:19:05

   本篇使用Vue2开发前端,Go语言开发服务端,使用nginx代理部署实现登录页面及其校验功能。

目录

1.部署结构

2.Vue2前端

2.1代码结构

2.1源码

3.Go后台服务

3.2代码结构

3.2 源码

3.3单测效果

4.nginx

5.运行效果

6.问题总结


1.部署结构

 

2.Vue2前端

2.1代码结构

2.1源码

index.html

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width,initial-scale=1.0">
    <title>demo</title>
  </head>
  <body>
    <div id="myapp"></div>
    <!-- built files will be auto injected -->
  </body>
</html>

src/App.vue

<template>
<div>
<router-view></router-view>
</div>
</template>

src/assets/css/reset.css

/* http://meyerweb.com/eric/tools/css/reset/ 
   v2.0 | 20110126
   License: none (public domain)
*/

html, body, div, span, applet, object, iframe,
h1, h2, h3, h4, h5, h6, p, blockquote, pre,
a, abbr, acronym, address, big, cite, code,
del, dfn, em, img, ins, kbd, q, s, samp,
small, strike, strong, sub, sup, tt, var,
b, u, i, center,
dl, dt, dd, ol, ul, li,
fieldset, form, label, legend,
table, caption, tbody, tfoot, thead, tr, th, td,
article, aside, canvas, details, embed, 
figure, figcaption, footer, header, hgroup, 
menu, nav, output, ruby, section, summary,
time, mark, audio, video {
    margin: 0;
    padding: 0;
    border: 0;
    font-size: 100%;
    font: inherit;
    vertical-align: baseline;
}
/* HTML5 display-role reset for older browsers */
article, aside, details, figcaption, figure, 
footer, header, hgroup, menu, nav, section {
    display: block;
}
body {
    line-height: 1;
}
ol, ul {
    list-style: none;
}
blockquote, q {
    quotes: none;
}
blockquote:before, blockquote:after,
q:before, q:after {
    content: '';
    content: none;
}
table {
    border-collapse: collapse;
    border-spacing: 0;
}

src/components/Home.vue

<template>
<div id="YYYYYYYYYYY" class="hello">
<button @click="goLogin">登录</button>
<el-button type="primary">你好</el-button>
<el-button type="info">你好</el-button>
<el-button type="danger">你好</el-button>
<el-button type="success">你好</el-button>
<el-tag> fsfsd dsd dsfv</el-tag>
<i class="fa fa-user"></i>
<i class="fa fa-users"></i>
</div>
</template>

<style lang="scss">
    .hello {
        background: yello;
        .el-button {
            color: red;
        }
    }
@import url('../assets/css/reset.css')
</style>


<script>
export default {
  methods: {
    goLogin () {
      this.$router.push('/login')
    }
  }
}
</script>

src/components/Login.vue

<template>
  <div class="login">
    <el-card class="box-card">
        <div slot="header" class="clearfix">
            <span>业务后台管理系统</span>
        </div>

        <el-form label-width="100px" :model="form" ref="form" :rules='rules'>
            <el-form-item label="用户名" prop='username'>
                <el-input v-model="form.username"></el-input>
            </el-form-item>
            <el-form-item label="密码" prop='password'>
                <el-input type='password' v-model="form.password"></el-input>
            </el-form-item>
            <el-form-item>
                <el-button type='primary' @click="login('form')">登录</el-button>
            </el-form-item>
        </el-form>
    </el-card>
  </div>
</template>

/*
原生AJAX和Axios在使用上存在一定的区别。Axios可以支持多种方式,包括浏览器环境、node环境,而AJAX则只能在浏览器环境中使用。
Axios还支持多种请求方式,包括GET、POST、PUT、DELETE等;而AJAX只能支持GET和POST方式发送请求。此外,Axios还可以拦截请求和响应。
*/

<script>

//登录验证的封装
import {nameRule, passRule} from '../utils/validate.js'

import {setToken} from '@/utils/dealtoken.js'

export default {
  data () {
    return {
        form: {
            username: "",
            password: ""
        },
        rules: {
            username: [{validator: nameRule, required: true, trigger: "blur"}],
            password: [{validator: passRule, required: true, trigger: "blur"}]
        }
    }
  },
  methods: {
    login(form) {
        this.$refs[form].validate((valid) => {
            if (valid) {
                console.log(this.form)
                //this.$router.push('/home')
                //解决axios post请求 404  OPTIONS问题
                const posthead = {
                    headers: {
                    'Content-Type': 'text/plain;charset=utf-8',
                    },
                    //withCredentials: 'same-origin'
                }
                this.axios.post('http://localhost:8282/login', JSON.stringify(this.form), posthead).then(res => {
                    console.log(res)
                    if (res.status === 200) {
                        //localStorage.setItem('username', res.data.username)
                        setToken('username', res.data.username)
                        this.$message({message: res.data, type: 'success'})
                        this.$router.push('/home')
                        console.log("post mid")
                    }
                })
            } else {
                console.error(this.form)
            }
        })
    }
  }
}
</script>

<style lang='scss'>
    .login {
        width: 100%;
        height: 100%;
        position: absolute;
        background: #409EFF;
        .box-card {
            width: 450px;
            margin: 200px auto;
            .el-card_header {
                font-size: 34px;
            }
            .el-button {
                width: 100%;
            }
        }
    }
</style>

src/main.js

import Vue from 'vue'
import App from './App'
import 'font-awesome/css/font-awesome.min.css'
import axios from 'axios'
import router from './router'

// 挂载到原型就可以全局使用
Vue.prototype.axios = axios

import ElementUI from 'element-ui'
import 'element-ui/lib/theme-chalk/index.css'
Vue.use(ElementUI)


new Vue({
  router,
  render: h => h(App)
}).$mount('#myapp')

src/router/index.js

import Vue from 'vue'
import Home from '@/components/Home'
import VueRouter from 'vue-router'

Vue.use(VueRouter)

const routes = [
  { path: '/', redirect: '/login', component: () => import('@/components/Login') },
  { path: '/login', name: 'Login', component: () => import('@/components/Login') },
  { path: '/home', component: Home },
  { path: '*', component: Home }
]


export default new VueRouter({
  mode: 'history',
  routes: routes
})


src/utils/validate.js

// Token的封装 Token存放在localStorage
export function setToken(tokenkey, token) {
    return localStorage.setItem(tokenkey, token)
}

export function getToken(tokenkey) {
    return localStorage.getItem(tokenkey)
}

export function removeToken(tokenkey) {
    return localStorage.removeItem(tokenkey)
}

src/utils/dealtoken.js

//用户名匹配
export function nameRule (rule, value, callback) {
    let reg = /(^[a-zA-Z0-9]{4,10}$)/;
    if (value === "") {
        callback(new Error("请输入用户名"));
    } else if (!reg.test(value)) {
        callback(new Error("请输入4-10用户名"));
    } else {
        callback();
    }
}

//密码匹配
export function passRule (rule, value, callback) {
    let pass = /^\S*(?=\S{6,12})(?=\S*\d)(?=\S*[A-Z])(?=\S*[a-z])(?=\S*[!@#$%^&*? ])\S*$/;
    if (value === "") {
        callback(new Error("请输入密码"));
    } else if (!pass.test(value)) {
        callback(new Error("请输入6-12位密码需要包含大小写和数字及特殊字符"));
    } else {
        callback();
    }
}

plugins/element.js

import Vue from 'vue'
import { Button, Tag } from 'element-ui'

Vue.use(Button)
Vue.use(Tag)

3.Go后台服务

3.2代码结构

3.2 源码

controller/login.go

package controller

import (
    "encoding/json"
    "fmt"
    "io/ioutil"
    "net/http"
    "path/filepath"

    "github.com/gin-gonic/gin"
)

// post  http://127.0.0.1:8181/login
// axios.post 和 post json处理
func LoginPost(ctx *gin.Context) {
    version := ctx.DefaultQuery("version", "V1.0.0.1")

    //前端使用axios直接传递form时,axios会默认使用json,必须使用下面方式获取json数据,解析后再使用
    data, _ := ioutil.ReadAll(ctx.Request.Body)
    type UserInfo struct {
        Username string
        Password string
    }
    var u UserInfo
    err := json.Unmarshal(data, &u)
    if err != nil {
        fmt.Println(err)
    }
    username := u.Username
    password := u.Password

    fmt.Println("login info:: ", version, username, password)

    /*
        ctx.Header("Access-Control-Allow-Origin", "*")

            ctx.Header("Access-Control-Allow-Headers", "Content-Type,AccessToken,X-CSRF-Token, Authorization, Token")
            ctx.Header("Access-Control-Allow-Credentials", "true")
            ctx.Header("Access-Control-Allow-Methods", "POST, GET, OPTIONS, PUT, DELETE")
            ctx.Header("content-type", "application/json;charset=UTF-8")

            ctx.Writer.Header().Set("Access-Control-Max-Age", "86400")
            ctx.Writer.Header().Set("Access-Control-Allow-Methods", "*")
            ctx.Writer.Header().Set("Access-Control-Allow-Headers", "*")
            ctx.Writer.Header().Set("Access-Control-Expose-Headers", "*")
            ctx.Writer.Header().Set("Access-Control-Allow-Credentials", "true")
    */

    if username == "123456" && password == "1234abcdE@" {
        ctx.String(http.StatusOK, "登录成功")
    } else {
        ctx.String(http.StatusNotFound, "用户名或密码错误")
    }
}

// http://127.0.0.1:8181/formlogin
// form表单提交处理 application/x-www-form-urlencoded
func FormLoginPost(ctx *gin.Context) {

    //第一种
    username := ctx.PostForm("username")
    password := ctx.PostForm("password")

    //第二种
    /*
        username := ctx.DefaultPostForm("username", "somebody")
        password := ctx.DefaultPostForm("password", "***")
    */

    //第三种
    /*
        username, ok := ctx.GetPostForm("username")
        if !ok {
            username = "取不到的话"
        }
        password, ok := ctx.GetPostForm("password")
        if !ok {
            password = "***"
        }
    */

    fmt.Println("FormLoginPost :: ", username, password)
    /*
        ctx.HTML(http.StatusOK, "home.html", gin.H{
            "Name":     username,
            "Password": password,
        })
    */
    ctx.JSON(http.StatusOK, gin.H{
        "Name":     username,
        "Password": password,
    })

    if username == "123456" && password == "1234abcdE@" {
        ctx.String(http.StatusOK, "登录成功")
    } else {
        ctx.String(http.StatusNotFound, "用户名或密码错误")
    }
}

// form表单提交文件上传处理 multipart/form-data
func UploadFile(ctx *gin.Context) {
    file, _ := ctx.FormFile("uploadfile")
    fmt.Println(file.Filename)
    file_path := "upload/" + filepath.Base(file.Filename)
    fmt.Println(file_path)
    ctx.SaveUploadedFile(file, file_path)
    ctx.String(http.StatusOK, "上传成功")
}

server.go

package main

import (
    "main/controller"
    "net/http"

    "github.com/gin-contrib/cors"
    "github.com/gin-gonic/gin"
)

/*
// 错误: server.go:4:2: package main/controller is not in GOROOT (/home/tiger/go/go/src/main/controller)
go mod init main

//错误: server.go:7:2: no required module provides package github.com/gin-gonic/gin; to add it:
go get github.com/gin-gonic/gin

//处理跨域框架
go get github.com/gin-contrib/cors
*/

/*
当客户端(尤其是基于 Web 的客户端)想要访问 API 时,服务器会决定允许哪些客户端发送请求。这是通过使用称为 CORS 来完成的,它代表跨源资源共享。
跨域资源共享 (CORS) 是一种机制,允许从提供第一个资源的域之外的另一个域请求网页上的受限资源。
*/

func CrosHandler() gin.HandlerFunc {
    return func(context *gin.Context) {
        context.Writer.Header().Set("Access-Control-Allow-Origin", "*")
        context.Header("Access-Control-Allow-Origin", "*") // 设置允许访问所有域
        context.Header("Access-Control-Allow-Methods", "POST,GET,OPTIONS,PUT,DELETE,UPDATE")
        context.Header("Access-Control-Allow-Headers", "Authorization, Content-Length, X-CSRF-Token, Token,session,X_Requested_With,Accept, Origin, Host, Connection, Accept-Encoding, Accept-Language,DNT, X-CustomHeader, Keep-Alive, User-Agent, X-Requested-With, If-Modified-Since, Cache-Control, Content-Type, Pragma,token,openid,opentoken")
        context.Header("Access-Control-Expose-Headers", "Content-Length, Access-Control-Allow-Origin, Access-Control-Allow-Headers,Cache-Control,Content-Language,Content-Type,Expires,Last-Modified,Pragma,FooBar")
        context.Header("Access-Control-Max-Age", "172800")
        context.Header("Access-Control-Allow-Credentials", "true")
        context.Set("content-type", "application/json") //设置返回格式是json
        //处理请求
        context.Next()
    }
}

// http://127.0.0.1:8181/ping
// http://127.0.0.1:8181/index
func main() {
    r := gin.Default()

    // 设置全局跨域访问
    //r.Use(CrosHandler())

    //cors处理跨域
    r.Use(cors.Default())

    // 返回一个json数据
    r.GET("/ping", func(c *gin.Context) {
        c.JSON(200, gin.H{
            "message": "pong",
            "num":     888,
        })
    })

    // 返回一个html页面
    r.LoadHTMLGlob("templates/*")
    r.GET("/index", func(c *gin.Context) {
        c.HTML(http.StatusOK, "index.html", nil)
    })

    r.POST("/login", controller.LoginPost)
    r.POST("/formlogin", controller.FormLoginPost)
    r.POST("/upload", controller.UploadFile)

    //r.Run()  // <===> r.Run(":8080")  监听并在 0.0.0.0:8080 上启动服务
    r.Run(":8181")
}

templates/home.html

欢迎进入首页

templates/index.html

<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8"/>
        <title>欢迎进入首页</title>
    </head>
    <body>
        <h3>登录测试</h3>
        <hr/>

        <form action="http://localhost:8282/formlogin" method="post">
            <table border=0 title="测试">
                <tr>
                    <td>用户名:</td>
                    <td><input type="text" name="username"></td>
                </tr>
                <tr>
                    <td>密码:</td>
                    <td><input type="password" name="password"></td>
                </tr>
                <tr>
                    <td colspan=2>
                        <input type="reset" />
                        <input type="submit" value="登录" />
                    </td>
                </tr>
            </table>
        </form>
        <br>
        <h3>文件上传测试</h3>
        <hr/>
        <form action="http://localhost:8282/upload" method="post" enctype="multipart/form-data">
            <input type="file" name="uploadfile"/>
            <input type="submit" value="upload">
        </form>
    </body>
</html>

3.3单测效果

http://127.0.0.1:8181/ping


http://127.0.0.1:8181/index

 

上传文件:

8282端口nginx代理测试:

4.nginx

#user nobody;

worker_processes 1;

#error_log logs/error.log;

#error_log logs/error.log notice;

#error_log logs/error.log info;

#pid logs/nginx.pid;


 

events {

worker_connections 1024;

}

#location [ = | ~ | ~* | ^~ ] uri { }

# ~区分大小写的正则匹配;

# ~*不区分大小写的正则匹配;

# ^~常规字符串匹配;

http {

include mime.types;

default_type application/octet-stream;

#log_format main '$remote_addr - $remote_user [$time_local] "$request" '

# '$status $body_bytes_sent "$http_referer" '

# '"$http_user_agent" "$http_x_forwarded_for"';

#access_log logs/access.log main;

sendfile on;

#tcp_nopush on;

#keepalive_timeout 0;

keepalive_timeout 65;

fastcgi_intercept_errors on;

#gzip on;

limit_conn_zone $binary_remote_addr zone=addr:10m;

#代理静态页面

server {

listen 80;

server_name www.liudehua.com;

#charset koi8-r;

#access_log logs/host.access.log main;

location / {

root /home/tiger/nginx-1.22.1/nginx/html/dist;

index index.html;

try_files $uri $uri/ /index.html;

}

#404配置

#error_page 404 /404.html;

#location /404.html {

# alias /home/tiger/nginx-1.22.1/nginx/html/dist;

# index index.html index.htm;

#}

#error_page 404 /404.html;

# redirect server error pages to the static page /50x.html

#

error_page 500 502 503 504 /50x.html;

location = /50x.html {

root html;

}

# proxy the PHP scripts to Apache listening on 127.0.0.1:80

#

#location ~ \.php$ {

# proxy_pass http://127.0.0.1;

#}

# pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000

#

#location ~ \.php$ {

# root html;

# fastcgi_pass 127.0.0.1:9000;

# fastcgi_index index.php;

# fastcgi_param SCRIPT_FILENAME /scripts$fastcgi_script_name;

# include fastcgi_params;

#}

# deny access to .htaccess files, if Apache's document root

# concurs with nginx's one

#

#location ~ /\.ht {

# deny all;

#}

}

#代理真正的后台服务

server {

listen 8282;

location / {

proxy_pass http://127.0.0.1:8181/;

}

}


 

# another virtual host using mix of IP-, name-, and port-based configuration

#

#server {

# listen 8000;

# listen somename:8080;

# server_name somename alias another.alias;

# location / {

# root html;

# index index.html index.htm;

# }

#}


 

# HTTPS server

#

#server {

# listen 443 ssl;

# server_name localhost;

# ssl_certificate cert.pem;

# ssl_certificate_key cert.key;

# ssl_session_cache shared:SSL:1m;

# ssl_session_timeout 5m;

# ssl_ciphers HIGH:!aNULL:!MD5;

# ssl_prefer_server_ciphers on;

# location / {

# root html;

# index index.html index.htm;

# }

#}

}

部署前端程序:

 启动nginx:

5.运行效果

http://www.liudehua.com/

 可以看到nginx反向代理:

 

 postman测试:

不代理测试:8181端口

 代理测试:8282端口

6.问题总结

6.1 跨域访问错误:前后台一块解决
6.2 form表单请求,axios.post请求Go解析处理
6.2 vue中的正则表达式
vscode安装插件any-rule插件
ctrl + shift + p 输入密码,选择正则表达式

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

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

相关文章

【雕爷学编程】Arduino动手做(93)--- 0.96寸OLED液晶屏模块2

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

pytorch学习——多层感知机

一.感知机 感知机——神经网络基本单元&#xff0c;最简单的深度网络称为多层感知机。多层感知机由多层神经元组成&#xff0c;每一层与它上一层相连&#xff0c;从中接收输入&#xff0c; 同时每一层也与它的下一层相连&#xff0c;影响当前层的神经元。 解释&#xff1a;如果…

分布式I/O,IT和OT融合少不了它

长期以来信息技术IT和操作运营技术OT是相互隔离的&#xff0c;随着大数据分析和边缘计算业务的对现场级实时数据的采集需求&#xff0c;IT和OT有了逐渐融合的趋势。IT与OT融合&#xff0c;它赋予工厂的管理者监控运行和过程的能力大为增强&#xff0c;甚至可以预测到可能发生的…

Vue2到3 全套学习内容(持续更新)

Vue 初次上手 1. Vue 概念 概念: Vue 是一个用于 构建用户界面 的 渐进式 框架 ①构建用户界面&#xff1a;基于数据动态渲染出用户看到的页面 ②渐进式&#xff1a;循序渐进 Vue的两种使用方式: ①Vue 核心包开发 场景: 局部 模块改造 ②Vue核心包&Vue插件工程化开发…

Echarts 地图点击板块高亮,再次点击还是高亮,在地图外点击返回,则不高亮。

需求就是&#xff1a;点击广东省板块&#xff0c;广东省高亮&#xff0c;再次点击广东省还是高亮&#xff0c;如果再点击内蒙古&#xff0c;则内蒙古高亮&#xff0c;广东不高亮。 点击返回全国&#xff0c;则都不高亮。 1、返回全国 //返回全国 backQG(){ this.clickCity 全…

多租户分缓存处理

多租户redis缓存分租户处理 那么数据库方面已经做到了拦截&#xff0c;但是缓存还是没有分租户&#xff0c;还是通通一个文件夹里&#xff0c; 想实现上图效果&#xff0c;global文件夹里存的是公共缓存。 首先&#xff0c;那么就要规定一个俗称&#xff0c;缓存名字带有globa…

安全学习DAY08_算法加密

算法加密 漏洞分析、漏洞勘测、漏洞探针、挖漏洞时要用到的技术知识 存储密码加密-应用对象传输加密编码-发送回显数据传输格式-统一格式代码特性混淆-开发语言 传输数据 – 加密型&编码型 安全测试时&#xff0c;通常会进行数据的修改增加提交测试 数据在传输的时候进行…

Kotlin基础(八):泛型

前言 本文主要讲解kotlin泛型&#xff0c;主要包括泛型基础&#xff0c;类型变异&#xff0c;类型投射&#xff0c;星号投射&#xff0c;泛型函数&#xff0c;泛型约束&#xff0c;泛型在Android中的使用。 Kotlin文章列表 Kotlin文章列表: 点击此处跳转查看 目录 1.1 泛型基…

protobuf入门实践1

protobuf入门实践1 下载和安装 protobuf&#xff1a;https://github.com/google/protobuf 解压压缩包&#xff1a;unzip protobuf-master.zip 2、进入解压后的文件夹&#xff1a;cd protobuf-master 3、安装所需工具&#xff1a;sudo apt-get install autoconf automake libt…

企业计算机服务器数据库中了360后缀勒索病毒怎么解决,数据恢复

近日&#xff0c;一家中型企业的服务器数据库遭到了一起严重的网络安全事件&#xff0c;导致企业的运营暂时陷入混乱。据了解&#xff0c;该企业的技术人员在服务器数据库中发现了一种名为“360后缀”勒索病毒&#xff0c;该勒索病毒通过对企业重要文件进行加密&#xff0c;数据…

node.js 爬虫图片下载

主程序文件 app.js 运行主程序前需要先安装使用到的模块&#xff1a; npm install superagent --save axios要安装指定版,安装最新版会报错&#xff1a;npm install axios0.19.2 --save const {default: axios} require(axios); const fs require(fs); const superagent r…

[每日习题]位运算——二进制插入 求最大连续bit数——牛客习题

hello&#xff0c;大家好这里是bang___bang_,今天记录2道关于位运算的牛客习题&#xff0c;二进制插入和求最大连续bit数&#xff0c;题目简单不难。 目录 1️⃣二进制插入 2️⃣求最大连续bit数 1️⃣二进制插入 二进制插入__牛客网 (nowcoder.com) 描述&#xff1a; 给定…

umi 创建的项目中,如何配置多个环境变量

创建env.js 在config.js中配置 在页面中使用 env.js和config.js的目录顺序 package.json中的配置

CountDownLatch和CyclicBarrier学习

CountDownLatch和CyclicBarrier都有一个计数器 CountDownLatch countDownLatch new CountDownLatch(4); CyclicBarrier cyclicBarrier new CyclicBarrier(4) CountDownLatch 是在 countDownLatch.countDown()执行后 4-1 等到4减到0后&#xff0c;就可以继续执行程序&#x…

QT控件通过qss设置子控件的对齐方式、大小自适应等

一些复杂控件&#xff0c;是有子控件的&#xff0c;每个子控件&#xff0c;都可以通过qss的双冒号选择器来选中&#xff0c;进行独特的样式定义。很多控件都有子控件&#xff0c;太多了&#xff0c;后面单独写一篇文章来介绍各个控件的子控件。这里就随便来几个例子 例如下拉列…

【AI换脸】roop在Kaggle上的使用样例

【AI换脸】roop在Kaggle上的使用样例 roop-kaggle前言换脸效果样例 GIF项目描述 roop-kaggle 【AI换脸】roop在Kaggle上的使用样例只需一张脸的图片&#xff0c;即可完成视频内的换脸点我进入Kaggle Notebook样例 前言 因为roop项目的Python环境依赖等问题的处理对于部分朋友…

环境监测系统网关,让景区变成智能化

景区环境监测系统采用先进的物联网网关&#xff0c;实现对各监测单元数据的采集、存储、传输和管理&#xff0c;主要对景点的气象要素、空气质量、水文变化、地质信息、雷电危害等进行监测&#xff0c;是一个集气象预警、在线监控等多种功能于一体的现代化综合系统。 系统介绍…

基于vue+uniapp微信小程序公司企业后勤服务(设备)系统

本系统分为用户和管理员两个角色&#xff0c;其中用户可以注册登陆系统&#xff0c;查看公司公告&#xff0c;查看设备&#xff0c;设备入库&#xff0c;查看通讯录&#xff0c;会议室预约&#xff0c;申请出入&#xff0c;申请请假等功能。管理员可以对员工信息&#xff0c;会…

【Linux】Centos的一些快捷操作

Centos的一些快捷操作 一个窗口多个终端GVIM 一个窗口多个文件 一个窗口多个终端 GVIM 一个窗口多个文件

2023十大最牛编程语言排行榜以及各语言的优缺点

文章目录 ⭐️ 2023年7月十大编程语言排行榜⭐️ 十大值得学习编程语言概要&#x1f31f; Python&#x1f31f; C/C&#x1f31f; Java&#x1f31f; C#&#x1f31f; JavaScript&#x1f31f; Swift&#x1f31f; Ruby&#x1f31f; GO&#xff08;Golang&#xff09;&#x1…