从零开始的VUE项目-02(创建后台ASP.NET Web API项目和连接数据库)
今天我们来创建后台和数据库1,创建ASP.NET Web API项目生成完毕,项目结构:运行看一下2,数据库建表我们对数据库的操作就在Controllers里的文件里,想一想这一篇原来是要做读取数据库数据生成菜单和登录登出的,所以要开始创建数据库了,菜单一张表,用户一张表,先做这两张表吧菜单表的数据用户表的数据3,后台构建在Controllers文件夹里新建MenuController.cs文件(
代码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
发现页面还是登录页面,成功了。
那这一篇就到这里了,既然框已经搭好了,那就应该往里填东西了,下一篇准备从数据库读取数据,然后在弹窗上展示表格和进行增删改查操作,基本像是这样
好,再见。
更多推荐
所有评论(0)