代码svn地址 (用户名:liu,密码;123)
今天我们来创建后台和数据库

1,创建ASP.NET Web API项目

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
生成完毕,项目结构:
在这里插入图片描述
运行看一下在这里插入图片描述

2,数据库建表

我们对数据库的操作就在Controllers里的文件里,想一想这一篇原来是要做读取数据库数据生成菜单和登录登出的,所以要开始创建数据库了,菜单一张表,用户一张表,先做这两张表吧在这里插入图片描述
菜单表的数据
在这里插入图片描述
用户表的数据
在这里插入图片描述

3,后台构建

(后面已修改为使用sqlsugar连接数据库,详情见此篇
在Controllers文件夹里新建MenuController.cs文件(新建控制器),代码:

using Newtonsoft.Json;
using System;
using System.Data;
using System.Data.SqlClient;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Web.Http;
using MySql.Data.MySqlClient;
using System.Collections;
using System.Text;

namespace API.Controllers
{
    /// <summary>
    /// 菜单栏
    /// </summary>
    public class MenuController : ApiController
    {

        /// <summary>
        /// 获取菜单
        /// </summary>
        public String Get()
        {
            try
            {
                //数据库连接信息
                string sqlCconnStr = "server=localhost;port=3306;user=xxx;password=xxx; database=xxx;";
                //连接数据库 
                MySqlConnection sqlCon = new MySqlConnection(sqlCconnStr);
                //建立DataSet对象(相当于建立前台的虚拟数据库)
                DataSet ds = new DataSet();
                //建立DataTable对象(相当于建立前台的虚拟数据库中的数据表)
                DataTable dtable;
                //建立DataRowCollection对象(相当于表的行的集合)
                DataRowCollection coldrow;
                //建立DataRow对象(相当于表的列的集合)
                DataRow drow;
                //打开连接
                sqlCon.Open();
                //建立DataAdapter对象  
                string sltStr = "select * from Menu ";//查询的sql语句
                MySqlCommand sqlCmd = new MySqlCommand(sltStr, sqlCon);
                MySqlDataReader reader = sqlCmd.ExecuteReader();
                String jsonData = ToJson(reader);
                sqlCon.Close();
                if (jsonData.Trim().Equals("")) jsonData = "success";
                return jsonData;
            }
            catch (Exception ex)
            {
                return "fail";
            }

        }

        /// <summary>
        /// DataReader转换为Json串
        /// </summary>
        public static string ToJson(MySqlDataReader dataReader)
        {
            StringBuilder Builder = new StringBuilder();

            int rows = 0;
            while (dataReader.Read())
            {
                if (rows++ > 0) Builder.Append(",");

                // 行数据转Json
                Builder.Append("{");
                for (int i = 0; i < dataReader.FieldCount; i++)
                {
                    if (i > 0) Builder.Append(",");

                    // 列名称
                    string strKey = dataReader.GetName(i);
                    strKey = "\"" + strKey + "\"";

                    // 列数据
                    Type type = dataReader.GetFieldType(i);
                    string strValue = dataReader[i].ToString();
                    strValue = String.Format(strValue, type).Trim();
                    if (type == typeof(string) || type == typeof(DateTime)) strValue = "\"" + strValue + "\"";

                    Builder.Append(strKey + ":" + strValue);
                }
                Builder.Append("}");
            }
            dataReader.Close();

            if (rows > 1) return "[" + Builder.ToString() + "]";
            else return Builder.ToString();
        }


        /// <summary>
        /// Post请求
        /// </summary>
        public void Post([FromBody] string value)
        {
        }

        /// <summary>
        /// Put请求
        /// </summary>
        public void Put(int id, [FromBody] string value)
        {
        }

        /// <summary>
        /// Delete请求
        /// </summary>
        public void Delete(int id)
        {
        }
    }
}

报错了,有一些包没有安,让我们把它们安上在这里插入图片描述
运行程序,我们看一下API页面在这里插入图片描述
刚刚新创建Menu控制器文件里的方法可以看到了在这里插入图片描述
这几个就是所谓的后台接口了
后台就不多说了,我也不怎么会,现在返回的是字符串,要在前台转成数组,其实昨天也是按照数组来生成菜单的,后面会完善的(初步完善见此文章

4,前台调用后台接口

下面我们就要让vue前端来调用上面的接口:
我们先安装axios包

npm install axios

然后在src文件夹里新建api文件夹,在api文件夹里新建api.js文件
api.js内容如下:

import axios from "axios";

let base='https://localhost:44328'  //44328就是你后台的端口号

//获取菜单栏数据
export const getMenu = params => {
  return axios.get(base+`/api/Menu/Get`);
};

在这里插入图片描述
现在这个getMenu方法就是获取菜单栏的数据,让我们在Menu.vue里来调用它
先是引入这个方法

import {getMenu} from '../api/api'

然后在getMenuList方法里调用它,先看看(Console.log())得到的是什么东西

getMenu().then((res) => {
        console.log(res)
      })

然后又报错了,是跨域的问题在这里插入图片描述
跨域在后台改也可以在前台改,我们这次在后台改,
打开Web.config文件,加上这么几句代码

<httpProtocol>
      <customHeaders>
        <add name="Access-Control-Allow-Origin" value="*" />
        <add name="Access-Control-Allow-Headers" value="Content-Type" />
        <add name="Access-Control-Allow-Methods" value="GET, POST, PUT, DELETE, OPTIONS" />
      </customHeaders>
    </httpProtocol>

在这里插入图片描述
运行,看一下Console.log的结果在这里插入图片描述
好,就是我们需要的,把Menu.vue里的字符串用这个数据替换的,Menu.vue就变成这样

<template>
  <div>
    <el-menu class="el-menu-demo"
             @select="handleSelect"
             background-color="#1f5f9a"
             text-color="#fff"
             active-text-color="#ffd04b"
             mode="horizontal">
      <template v-for="item in NavigateItem">
        <el-submenu v-if="item.items.length"
                    :index="item.key"
                    :key="item.key">
          <template slot="title">
            <img :src="require('../assets/images/'+item.icon+'.png')"
                 :alt="item.title" />
            {{ item.title }}
          </template>
          <el-menu-item v-for="(items, key) in item.items"
                        :key="key"
                        :index="items.key">
            {{ items.title }}
          </el-menu-item>
        </el-submenu>
        <el-menu-item v-else
                      :index="item.key"
                      :key="item.key">
          {{ item.title }}
        </el-menu-item>
      </template>
    </el-menu>
  </div>
  </div>
</template>

<script>
import MapQuery from '../views/MapQuery.vue'
import ThematicMap from '../views/ThematicMap.vue'
import DataManagement from '../views/DataManagement.vue'
import BusinessLog from '../views/BusinessLog.vue'
import {getMenu} from '../api/api'
export default {
  data () {
    return {
      activeIndex: 1,
      menuList: [],
      NavigateItem: [],
    };
  },
  created () {
    this.getMenuList();
  },
  methods: {
    //菜单激活
    handleSelect (key) {
      switch (key) {
        case "1001":
          this.$layer.iframe({
            content: {
              content: MapQuery,
              parent: this,
            },
            area: ["550px", "570px"],
            title: "地图查询",
            maxmin: true,
            shade: false,
            shadeClose: false,
            resize: true,
            cancel: () => {
              //关闭事件
              this.$layer.close(this.layerid);
            },
          });
          break;
        case "1002":
          this.$layer.iframe({
            content: {
              content: ThematicMap,
              parent: this,
            },
            area: ["550px", "570px"],
            title: "专题图",
            maxmin: true,
            shade: false,
            shadeClose: false,
            resize: true,
            cancel: () => {
              //关闭事件
              this.$layer.close(this.layerid);
            },
          });
          break;
        case "2001":
          this.$layer.iframe({
            content: {
              content: DataManagement,
              parent: this,
            },
            area: ["550px", "570px"],
            title: "数据管理",
            maxmin: true,
            shade: false,
            shadeClose: false,
            resize: true,
            cancel: () => {
              //关闭事件
              this.$layer.close(this.layerid);
            },
          });
          break;
        case "3001":
          this.$layer.iframe({
            content: {
              content: BusinessLog,
              parent: this,
            },
            area: ["550px", "570px"],
            title: "业务日志",
            maxmin: true,
            shade: false,
            shadeClose: false,
            resize: true,
            cancel: () => {
              //关闭事件
              this.$layer.close(this.layerid);
            },
          });
          break;
        default:
          break;
      }

    },
    getMenuList () {
      getMenu().then((res) => {
        //这就是我们后台传过来的菜单栏信息,是一个字符串,下面我们来对它进行处理
      var jsonStr = res.data
      //将字符串转成数组
      var jsonObj = JSON.parse(jsonStr)
      var jsonArr = [];
      for (var i = 0; i < jsonObj.length; i++) {
        jsonArr[i] = jsonObj[i];
      }
      this.menuList = jsonArr;
      //将菜单的父菜单和子菜单分开
      this.menuList.forEach((item, index) => {
        if (item["P_id"] == -1) {
          this.NavigateItem.push({
            title: item["Name"],
            key: item["Id"],
            path: item["Url"],
            icon: item["Icon"],
            items: [],
          })
        }
        else {
          this.NavigateItem[item["P_id"] - 1].items.push({
            title: item["Name"],
            key: item["Id"],
            path: item["Url"],
            icon: item["Icon"],
          })
        }
      })
    
      })
    }
  },
};
</script>
<style scoped>
.el-row {
  width: 200px;
}
</style>

在这里插入图片描述
页面和原先是一样的了,但现在我们是从数据库读取数据生成的菜单栏

5,登录登出功能

登录那就要有一个登录的页面,过程无非是输入账号密码,然后和数据库的信息对比一下,如果符合就登录,不符合就提示。在components文件夹里新建一个Login.vue文件,内容如下:

<template>
  <div class="login-container">
    <el-form ref="form" :model="loginForm" label-width="80px" class="login-form">
      <h2 class="login-title">管理系统</h2>
      <el-form-item label="用户名">
        <el-input v-model="loginForm.username"></el-input>
      </el-form-item>
      <el-form-item label="密码">
        <el-input v-model="loginForm.password"></el-input>
      </el-form-item>

      <el-form-item>
        <el-button type="primary" @click="login">登录</el-button>
      </el-form-item>
    </el-form>
  </div>
</template>
 
<script>
import { getToken } from '../api/api'

export default {
  name: "login",
  data () {
    return {
      loginForm: {
        username: '',
        password: ''
      }
    };
  },

  methods: {
    login () {
      let _this = this;
      if (this.loginForm.username === '' || this.loginForm.password === '') {
        alert('账号或密码不能为空');
      } else {
        let params = {
          username: this.loginForm.username,
          password: this.loginForm.password
        }
        getToken(params).then(res => {
          if (res.data != "") {
            _this.userToken = 'Bearer ' + "12345qwer";
            // 将用户token保存到vuex中
            window.sessionStorage.setItem('data', _this.userToken)
            _this.$router.push('/home');
            this.$message({
              message: '登录成功',
              type: 'success',
            })
          }
          else {
            this.$message({
              message: '账号或密码错误',
              type: 'error',
            })
          }
        }).catch(error => {
           this.$message({
              message: '账号或密码错误',
              type: 'error',
            })
          console.log(error);
        });
      }
    }
  }
};
</script>
<style acoped>
.login-form {
  width: 350px;
  margin: 160px auto; /* 上下间距160px,左右自动居中*/
  background-color: rgb(255, 255, 255, 0.8); /* 透明背景色 */
  padding: 30px;
  border-radius: 20px; /* 圆角 */
}

/* 背景 */
.login-container {
  position: absolute;
  width: 100%;
  height: 100%;
  background: url("../assets/images/login.png");
}

/* 标题 */
.login-title {
  color: #303133;
  text-align: center;
}
</style> 

window.sessionStorage,我们在config文件夹的config.js文件里定义它

window.sessionStorage=''

我们用它来判断用户是否登录,后面会使用它。
还有getToken,这就是我们判断用户名密码是否正确的方法
这个方法我们要在后台写,在后台的Controllers文件夹里新建UserinfoController.cs文件(控制器类),内容如下:

using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Data;
using System.Data.SqlClient;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Web.Http;
using MySql.Data.MySqlClient;
using System.Collections;
using System.Text;
namespace API.Controllers
{
    public class UserinfoController : ApiController
    {
        /// <summary>
        /// 获取Token
        /// </summary>
        public String Get(string username, string password)
        {
            try
            {
                //数据库连接信息
                string sqlCconnStr = "server=localhost;port=3306;user=xxx;password=xxx; database=xxx;";
                //连接数据库 
                MySqlConnection sqlCon = new MySqlConnection(sqlCconnStr);
                //建立DataSet对象(相当于建立前台的虚拟数据库)
                DataSet ds = new DataSet();
                //打开连接
                sqlCon.Open();
                //建立DataAdapter对象  
                string sltStr = "select * from userinfo where UserName ='" + username + "' " + "and Password ='" + password + "'";//查询的sql语句
                MySqlCommand sqlCmd = new MySqlCommand(sltStr, sqlCon);
                MySqlDataReader reader = sqlCmd.ExecuteReader();
                String jsonData = ToJson(reader);
                sqlCon.Close();
                return jsonData;
            }
            catch (Exception ex)
            {
                return "fail";
            }

        }

        /// <summary>
        /// DataReader转换为Json串
        /// </summary>
        public static string ToJson(MySqlDataReader dataReader)
        {
            StringBuilder Builder = new StringBuilder();

            int rows = 0;
            while (dataReader.Read())
            {
                if (rows++ > 0) Builder.Append(",");

                // 行数据转Json
                Builder.Append("{");
                for (int i = 0; i < dataReader.FieldCount; i++)
                {
                    if (i > 0) Builder.Append(",");

                    // 列名称
                    string strKey = dataReader.GetName(i);
                    strKey = "\"" + strKey + "\"";

                    // 列数据
                    Type type = dataReader.GetFieldType(i);
                    string strValue = dataReader[i].ToString();
                    strValue = String.Format(strValue, type).Trim();
                    if (type == typeof(string) || type == typeof(DateTime)) strValue = "\"" + strValue + "\"";

                    Builder.Append(strKey + ":" + strValue);
                }
                Builder.Append("}");
            }
            dataReader.Close();

            if (rows > 1) return "[" + Builder.ToString() + "]";
            else return Builder.ToString();
        }

    }
}

像之前获取菜单数据的方法一样,让我们把它放到api.js里

//获取Token
export const getToken = params => {
  return axios.get(base+`/api/Userinfo/Get`,{ params: params });
};

我们需要让这个登录页称为默认页面,来到router文件夹的index.js文件里修改:

import Vue from 'vue'
import Router from 'vue-router'
import HelloWorld from '@/components/HelloWorld'
import Home from '@/components/Home'
import login from '@/components/Login'

Vue.use(Router)

const router= new Router({
  routes: [
    {
      path: '/',
      redirect: '/login'
    },
    { 
      path: '/login',
      name: 'login',
      component: login
    },
    {
      path: '/home',
      name: 'Home',
      component: Home
    },
  ],
  mode:"history" 
})

export default router;

刷新一下页面,默认变成登录页了在这里插入图片描述
输入用户名:liu 密码:12345(后面会加密的),就登陆进主页面了。
只有登录不太行啊,我们再加个登出
在components文件夹里新建LogoutPartial.vue文件,内容如下:

<template>
  <div>
    <el-button @click="out"
               class="out_bt">退出登录</el-button>
  </div>
</template>

<script>
export default {
  methods: {
    out () {
      this.$confirm('是否退出登录?', '提示', {
        confirmButtonText: '确定',
        cancelButtonText: '取消',
        type: 'waring'
      }).then(() => {
        //清空token
        window.sessionStorage.clear()
        //跳转到登录页
        this.$router.push('/login')
      }).catch(()=>{
          this.$message({
            typeA:'info',
            message:'已取消操作'
          })
      })
     
    }
  }
}
</script>

<style>
.out_bt {
  float: right;
}
</style>

这里也有window.sessionStorage
效果就是点击退出登录并确定后回到登录页面,让我们把这个登出放到Home.vue里,于是就变成了这样

<template>
  <div class="home">
    <header style="margin:0;height:85px;width:100%;position:fixed;z-index: 10;">
      <div style="position:relative">
      <Menu ref="Menu"></Menu>
      </div>
      <div style="right:0px">
        <LogoutPartial />
      </div>
    </header>
       <main style="position:relative;">
      <mapView></mapView>
    </main>
  </div>
</template>

<script>
import Menu from './Menu.vue'
import mapView from './Map.vue'
import LogoutPartial from './LogoutPartial.vue'
export default {
  components: {
    Menu,
    mapView,
    LogoutPartial
  },
}
</script>

<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped>
.home,main{
  height: 100%;
}

h1,
h2 {
  font-weight: normal;
}
ul {
  list-style-type: none;
  padding: 0;
}
li {
  display: inline-block;
  margin: 0 10px;
}
a {
  color: #42b983;
}
</style>

现在主页面就变成了这样在这里插入图片描述
点击退出登录。又回到登录页面了在这里插入图片描述
这时,我们把地址栏地址改成在这里插入图片描述
发现页面到主页面去了,可我们还没输用户名和密码啊,这可不是我们想要的
我们打开router文件夹的index.js文件,加上这一段代码

// 导航守卫
// 使用 router.beforeEach 注册一个全局前置守卫,判断用户是否登陆
router.beforeEach((to, from, next) => {
  if (to.path === '/login') {
    next();
  } else {
    let token = window.sessionStorage.data;
    if (!token|| token === '') {
      next('/login');
    } else {
      next();
    }
  }
});

我们前面的window.sessionStorage这里就用到了吧,用户登录,那window.sessionStorage.data就被赋值了,用户未登录或推出了,那window.sessionStorage就是空的了.
现在我们再退出,将地址栏改为http://localhost:8080/home
发现页面还是登录页面,成功了。
那这一篇就到这里了,既然框已经搭好了,那就应该往里填东西了,下一篇准备从数据库读取数据,然后在弹窗上展示表格和进行增删改查操作,基本像是这样在这里插入图片描述
好,再见。

Logo

前往低代码交流专区

更多推荐