本篇实现主页面功能,包括主页面排版布局,学生管理模块实现,后台接口实现等功能。
目录
1.运行效果
1.1登录页面
1.2主页面
1.3学生管理 - 信息列表
1.4学生管理 - 信息管理
1.5学生管理 - 作业列表
1.6学生管理 - 作业管理
2.前端代码
2.1 代码结构
2.2 代码实现
3.后端代码
3.1 代码结构
3.2 代码实现
4.其他
4.1 vscode快速编写正则表达式
文章来源地址https://uudwc.com/A/Mxqmn
1.运行效果
1.1登录页面
文章来源:https://uudwc.com/A/Mxqmn
1.2主页面
1.3学生管理 - 信息列表
1.4学生管理 - 信息管理
1.5学生管理 - 作业列表
1.6学生管理 - 作业管理
2.前端代码
2.1 代码结构
2.2 代码实现
src/api/api.js
//业务服务调用接口封装
import service from '../service.js'
//npm i qs -D
import qs from 'qs'
//登录接口
export function login(data) {
return service({
method: 'post',
url: '/login',
data
})
}
//学生信息查询接口
export function students(params) {
return service({
method: 'get',
url: '/api/students',
params
})
}
//删除学生信息
export function delstudentsbyid(id) {
return service({
method: 'get',
//此处应用模板字符串传参
url: `/api/students/del?id=${id}`
})
}
export function delstudentsbyreqid(id) {
return service({
method: 'get',
//此处应用模板字符串传参
url: `/api/students/del/${id}`
})
}
export function addStudent(data) {
//data = qs.stringify(data)
return service({
method: 'post',
url: '/api/info',
data
})
}
export function updateStudent(data) {
return service({
method: 'post',
url: '/api/updateinfo',
data
})
}
export function getInfo() {
return service({
method: 'get',
url: '/api/getinfo'
})
}
export function delinfo(id) {
return service({
method: 'get',
//此处应用模板字符串传参
url: `/api/info/del/id=${id}`
})
}
src/components/common/students/InfoList.vue
<!-- 信息列表页面 -->
<template>
<div class="infoList">
<!-- 新增表单 -->
<el-form :inline="true" :model="form" class="demo-form-inline" size="small">
<el-form-item>
<el-button type="primary" @click="add('form')">新增</el-button>
</el-form-item>
</el-form>
<el-table
:data="tableData"
border
style="width: 100%">
<el-table-column
prop="name"
label="姓名"
align="center">
</el-table-column>
<el-table-column
prop="age"
label="年龄"
align="center">
</el-table-column>
<el-table-column
prop="sex"
label="性别"
align="center">
</el-table-column>
<el-table-column
prop="father"
label="父亲"
align="center">
</el-table-column>
<el-table-column
prop="mother"
label="母亲"
align="center">
</el-table-column>
<el-table-column
prop="time"
label="入校时间"
align="center">
</el-table-column>
<el-table-column
prop="address"
label="家庭住址"
align="center">
</el-table-column>
<el-table-column
prop="phone"
label="联系方式"
align="center">
</el-table-column>
<!-- scope.row表示点击的当前行,包含当前行的所有数据 -->
<el-table-column
label="操作" align="center">
<template slot-scope="scope">
<el-button type="danger" size="mini" icon="el-icon-edit"
@click="edit(scope.row)">
</el-button>
<el-button type="danger" size="mini" icon="el-icon-delete"
@click="del(scope.row)">
</el-button>
</template>
</el-table-column>
</el-table>
<el-dialog :title="state ? '添加学生信息' : '修改学生信息'" :visible.sync="dialogFormVisible" width="500px">
<el-form :model="form" :rules="rules" ref="form">
<el-form-item label="姓名" :label-width="formLabelWidth" prop="name">
<el-input v-model="form.name" autocomplete="off"></el-input>
</el-form-item>
<el-form-item label="年龄" :label-width="formLabelWidth" prop="age">
<el-input v-model="form.age" autocomplete="off"></el-input>
</el-form-item>
<el-form-item label="性别" :label-width="formLabelWidth" prop="sex">
<el-radio v-model="form.sex" label="1">男</el-radio>
<el-radio v-model="form.sex" label="2">女</el-radio>
</el-form-item>
<el-form-item label="父亲" :label-width="formLabelWidth" prop="father">
<el-input v-model="form.father" autocomplete="off"></el-input>
</el-form-item>
<el-form-item label="母亲" :label-width="formLabelWidth" prop="mother">
<el-input v-model="form.mother" autocomplete="off"></el-input>
</el-form-item>
<el-form-item label="入校时间" :label-width="formLabelWidth" prop="time">
<el-date-picker
v-model="form.time"
format="yyyy 年 MM 月 dd 日"
type="date"
placeholder="选择日期">
</el-date-picker>
</el-form-item>
<el-form-item label="家庭住址" :label-width="formLabelWidth" prop="address">
<el-input v-model="form.address" autocomplete="off"></el-input>
</el-form-item>
<el-form-item label="联系方式" :label-width="formLabelWidth" prop="phone">
<el-input v-model="form.phone" autocomplete="off"></el-input>
</el-form-item>
</el-form>
<span slot="footer" class="dialog-footer">
<el-button @click="closeForm('form')">取消</el-button>
<el-button type="primary" @click="sure('form')">确认</el-button>
</span>
</el-dialog>
</div>
</template>
<script>
import { addStudent, getInfo, updateStudent, delinfo } from '@/api/api.js'
export default {
data() {
return {
tableData: [],
dialogFormVisible: false,
form: {
name: '',
age: '',
sex: '1',
father: '',
mother: '',
time: '',
address: '',
phone: ''
},
formLabelWidth: "80px",
rules: {
name: [{required: true, message: '请输入姓名'}],
age: [{required: true, message: '请输入年龄'}],
sex: [{required: true, message: '请选择性别'}],
time: [{required: true, message: '请选择入校时间'}],
address: [{required: true, message: '请输入家庭住址'}],
phone: [{required: true, message: '请输入联系方式'}]
},
total: 0,
state: true
}
},
created() {
this.getData()
},
methods: {
getData() {
getInfo().then((res) => {
if (res.data.status === 200) {
this.tableData = res.data.data
this.total = res.data.total
}
})
},
add(form) {
this.state = true
this.form = {
name: '',
age: '',
sex: '1',
father: '',
mother: '',
time: '',
address: '',
phone: ''
}
//this.$refs[form].resetFields()
this.dialogFormVisible = true
},
edit(row) {
this.state = false
//此处需要扩展赋值
this.form = {...row}
this.dialogFormVisible = true
},
del(row) {
this.$alert("确定要删除吗?", "提示", {
confirmButtonText: '确定',
callback: () => {
delinfo(row.id).then(res => {
if (res.data.status === 200) {
this.getData()
this.$message({message: res.data.msg, type: "success"})
}
})
}
})
delinfo
},
closeForm(form) {
//清调校验规则
this.$refs[form].resetFields()
this.dialogFormVisible = false
},
sure(form) {
this.$refs[form].validate(valid => {
if (valid) {
console.log(form, this.form)
if (this.state) {
addStudent(this.form).then((res) => {
console.log(res)
if (res.data.status === 200) {
this.getData()
this.dialogFormVisible = false
this.$refs[form].resetFields()
this.$message({message: res.data.msg, type: "success"})
}
})
}
else {
updateStudent(this.form).then((res) => {
console.log(res)
if (res.data.status === 200) {
this.getData()
this.dialogFormVisible = false
this.$refs[form].resetFields()
this.$message({message: res.data.msg, type: "success"})
}
})
}
}
})
}
}
}
</script>
<style lang="scss">
.infoList {
.demo-form-inline, .el-form-item {
text-align: left;
}
.el-pagination {
text-align: left;
margin-top: 20px;
}
}
</style>
src/components/common/students/InfoLists.vue
<!-- 信息管理页面 -->
<template>
<div class="infoList">
<!-- 新增表单 -->
<el-form :inline="true" :model="form" class="demo-form-inline" size="small">
<el-form-item>
<el-button type="primary" @click="add('form')">新增</el-button>
</el-form-item>
</el-form>
<el-table
:data="tableData"
border
style="width: 100%">
<el-table-column
prop="name"
label="姓名"
align="center">
</el-table-column>
<el-table-column
prop="age"
label="年龄"
align="center">
</el-table-column>
<el-table-column
prop="sex"
label="性别"
align="center">
</el-table-column>
<el-table-column
prop="father"
label="父亲"
align="center">
</el-table-column>
<el-table-column
prop="mother"
label="母亲"
align="center">
</el-table-column>
<el-table-column
prop="time"
label="入校时间"
align="center">
</el-table-column>
<el-table-column
prop="address"
label="家庭住址"
align="center">
</el-table-column>
<el-table-column
prop="phone"
label="联系方式"
align="center">
</el-table-column>
<!-- scope.row表示点击的当前行,包含当前行的所有数据 -->
<el-table-column
label="操作" align="center">
<template slot-scope="scope">
<el-button type="danger" size="mini" icon="el-icon-edit"
@click="edit(scope.row)">
</el-button>
<el-button type="danger" size="mini" icon="el-icon-delete"
@click="del(scope.row)">
</el-button>
</template>
</el-table-column>
</el-table>
<el-dialog :title="state ? '添加学生信息' : '修改学生信息'" :visible.sync="dialogFormVisible" width="500px">
<el-form :model="form" :rules="rules" ref="form">
<el-form-item label="姓名" :label-width="formLabelWidth" prop="name">
<el-input v-model="form.name" autocomplete="off"></el-input>
</el-form-item>
<el-form-item label="年龄" :label-width="formLabelWidth" prop="age">
<el-input v-model="form.age" autocomplete="off"></el-input>
</el-form-item>
<el-form-item label="性别" :label-width="formLabelWidth" prop="sex">
<el-radio v-model="form.sex" label="1">男</el-radio>
<el-radio v-model="form.sex" label="2">女</el-radio>
</el-form-item>
<el-form-item label="父亲" :label-width="formLabelWidth" prop="father">
<el-input v-model="form.father" autocomplete="off"></el-input>
</el-form-item>
<el-form-item label="母亲" :label-width="formLabelWidth" prop="mother">
<el-input v-model="form.mother" autocomplete="off"></el-input>
</el-form-item>
<el-form-item label="入校时间" :label-width="formLabelWidth" prop="time">
<el-date-picker
v-model="form.time"
format="yyyy 年 MM 月 dd 日"
type="date"
placeholder="选择日期">
</el-date-picker>
</el-form-item>
<el-form-item label="家庭住址" :label-width="formLabelWidth" prop="address">
<el-input v-model="form.address" autocomplete="off"></el-input>
</el-form-item>
<el-form-item label="联系方式" :label-width="formLabelWidth" prop="phone">
<el-input v-model="form.phone" autocomplete="off"></el-input>
</el-form-item>
</el-form>
<span slot="footer" class="dialog-footer">
<el-button @click="closeForm('form')">取消</el-button>
<el-button type="primary" @click="sure('form')">确认</el-button>
</span>
</el-dialog>
</div>
</template>
<script>
import { getData, changeInfo, delData } from '@/utils/table.js'
export default {
data() {
return {
tableData: [],
dialogFormVisible: false,
form: {
name: '',
age: '',
sex: '1',
father: '',
mother: '',
time: '',
address: '',
phone: ''
},
formLabelWidth: "80px",
rules: {
name: [{required: true, message: '请输入姓名'}],
age: [{required: true, message: '请输入年龄'}],
sex: [{required: true, message: '请选择性别'}],
time: [{required: true, message: '请选择入校时间'}],
address: [{required: true, message: '请输入家庭住址'}],
phone: [{required: true, message: '请输入联系方式'}]
},
total: 0,
state: true
}
},
created() {
getData(this, '/api/getinfo')
},
methods: {
add(form) {
this.state = true
this.form = {
name: '',
age: '',
sex: '1',
father: '',
mother: '',
time: '',
address: '',
phone: ''
}
//this.$refs[form].resetFields()
this.dialogFormVisible = true
},
edit(row) {
this.state = false
//此处需要扩展赋值
this.form = {...row}
this.dialogFormVisible = true
},
del(row) {
console.log("row.id", row.id)
delData(this, "/api/info/del/", row.id, getData, '/api/getinfo')
},
closeForm(form) {
//清调校验规则
this.$refs[form].resetFields()
this.dialogFormVisible = false
},
sure(form) {
this.$refs[form].validate(valid => {
if (valid) {
console.log(form, this.form)
let url = ""
this.state ? url = '/api/info' : url = '/api/updateinfo'
changeInfo(this, 'post', url, this.form, getData, '/api/getinfo')
}
})
}
}
}
</script>
<style lang="scss">
.infoList {
.demo-form-inline, .el-form-item {
text-align: left;
}
.el-pagination {
text-align: left;
margin-top: 20px;
}
}
</style>
src/components/common/students/StudentList.vue
<!-- 学生列表页面 -->
<template>
<div class="studentList">
<!-- 查询重置表单 -->
<el-form :inline="true" :model="formInline" class="demo-form-inline" size="small">
<el-form-item label="姓名">
<el-input v-model="formInline.name" placeholder="姓名查询"></el-input>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="onFind">查询</el-button>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="onReset">重置</el-button>
</el-form-item>
</el-form>
<!-- 学生列表 -->
<el-table
:data="compData"
border
style="width: 100%">
<el-table-column
prop="name"
label="姓名"
align="center">
</el-table-column>
<el-table-column
prop="age"
label="年龄"
align="center">
</el-table-column>
<el-table-column
prop="sex_text"
label="性别"
align="center">
</el-table-column>
<el-table-column
prop="number"
label="学号"
align="center">
</el-table-column>
<el-table-column
prop="class"
label="班级"
align="center">
</el-table-column>
<el-table-column
prop="state_text"
label="状态"
align="center">
</el-table-column>
<el-table-column
prop="address"
label="住址"
align="center">
</el-table-column>
<el-table-column
prop="phone"
label="电话"
align="center">
</el-table-column>
<!-- scope.row表示点击的当前行,包含当前行的所有数据 -->
<el-table-column
label="操作" align="center">
<template slot-scope="scope">
<el-button type="danger" size="mini" icon="el-icon-delete"
@click="del(scope.row)">
</el-button>
</template>
</el-table-column>
</el-table>
<el-pagination
@size-change="handleSizeChange"
@current-change="handleCurrentChange"
:current-page.sync="currentPage"
:page-sizes="[10, 20, 30, 50]"
:page-size="pageSize"
layout="total, sizes, prev, pager, next, jumper"
:total="total">
</el-pagination>
</div>
</template>
<script>
import { students, delstudentsbyreqid } from '@/api/api.js'
export default {
data() {
return {
tableData: [],
currentPage: 1,
pageSize: 10,
total: 0,
formInline: {
name: ''
}
}
},
computed: {
compData() {
return this.tableData.slice((this.currentPage - 1) * this.pageSize, this.currentPage * this.pageSize)
}
},
created() {
this.getData()
},
methods: {
onFind() {
console.log(this.formInline)
this.getData(this.formInline)
},
onReset() {
console.log(this.formInline)
this.formInline = {}
this.getData(this.formInline)
},
handleSizeChange(val) {
this.pageSize = val
this.currentPage = 1
},
handleCurrentChange(val) {
this.currentPage = val
},
getData(param) {
students(param).then((res) => {
console.log(res)
if (res.data.status === 200) {
this.total = res.data.total
this.tableData = res.data.data
this.tableData.forEach(item => {
//尽量不要修改原始数据,因为原始数据后面可能会用
item.sex === 1 ? item.sex_text = "男" : item.sex_text = "女"
item.state === 1 ? item.state_text = "已入学" : item.state === 2
? item.state_text = "未入学" : item.state_text = "休学中"
})
}
})
},
del(row) {
console.log(row, row.id, row.address)
delstudentsbyreqid(row.id).then((res) => {
console.log(res)
if (res.data.status === 200) {
this.$message({message: "删除数据成功", type: "success"})
//删除成功后再重新请求一次
this.getData()
}
})
},
onSubmit() {
console.log('submit!')
}
}
}
</script>
<style>
.studentList {
.demo-form-inline, .el-form-item {
text-align: left;
}
.el-pagination {
text-align: left;
margin-top: 20px;
}
}
</style>
src/components/common/students/WorkList.vue
<!-- 作业列表页面 -->
<template>
<div class="workList">
<el-table :data="tableData" v-loading="loading" border style="width: 100%">
<el-table-column
prop="id"
label="用户ID"
align="center">
</el-table-column>
<el-table-column
prop="userId"
label="所属班级"
align="center">
</el-table-column>
<el-table-column
prop="title"
label="作业名称"
align="center">
</el-table-column>
<el-table-column
prop="completed_text"
label="完成情况"
align="center">
</el-table-column>
</el-table>
<el-pagination
@size-change="handleSizeChange"
@current-change="handleCurrentChange"
:current-page="page"
:page-sizes="[10, 20, 30, 50]"
:page-size="size"
layout="total, sizes, prev, pager, next, jumper"
:total="total">
</el-pagination>
</div>
</template>
<script>
import { getTableData } from '@/utils/table.js'
export default {
data() {
return {
tableData: [],
total: 0,
page: 1,
size: 10,
loading: true
}
},
created() {
//采用后端分页方法
getTableData(this, '/api/works', {page: this.page, size: this.size}, ['completed'])
},
methods: {
handleSizeChange(val) {
this.size = val
this.page = 1
getTableData(this, '/api/works', {page: this.page, size: val}, ['completed'])
},
handleCurrentChange(val) {
this.page = val
getTableData(this, '/api/works', {page: val, size: this.size}, ['completed'])
},
}
}
</script>
<style lang="scss">
.workList {
.el-pagination {
text-align: left;
margin-top: 20px;
}
}
</style>
src/components/common/students/WorkMent.vue
<!-- 作业管理页面 -->
<template>
<div class="workMent">
<el-table :data="tableData" v-loading="loading" border style="width: 100%">
<el-table-column
prop="id"
label="用户ID"
align="center">
</el-table-column>
<el-table-column
prop="userId"
label="所属班级"
align="center">
</el-table-column>
<el-table-column
prop="title"
label="作业名称"
align="center">
</el-table-column>
<el-table-column
prop="completed_text"
label="完成情况"
align="center">
</el-table-column>
</el-table>
<!-- 通过传参调用分页子组件 模块化和组件化思想 total url由当前页面传递给子组件Page -->
<Page :total="total" :url="url" />
</div>
</template>
<script>
import Page from '../Pageing.vue'
export default {
//注册分页组件Page
components: {
Page
},
data() {
return {
tableData: [],
total: 0,
loading: true,
url: '/api/works'
}
}
}
</script>
<style lang="scss">
.workMent {
.el-pagination {
text-align: left;
margin-top: 20px;
}
}
</style>
src/components/common/Breadcrumb.vue
<template>
<div class="footer">
<!-- el-card包裹是为了好看而已 组件中属性名前面:表明该属性的值是动态获取的-->
<el-card>
<el-breadcrumb separator-class="el-icon-arrow-right">
<el-breadcrumb-item :to="{ path: '/' }">首页</el-breadcrumb-item>
<el-breadcrumb-item v-for="(item, index) in $route.matched" :key="index">
{{item.name}}
</el-breadcrumb-item>
</el-breadcrumb>
</el-card>
</div>
</template>
src/components/common/Footer.vue
<template>
<div class="footer">
<el-card>
welcome to 2023
</el-card>
</div>
</template>
<script>
export default {
data() {
return {}
}
}
</script>
<style lang='scss'>
</style>
src/components/common/Header.vue
<template>
<div class="header">
<el-header>
<div class="title">业务后台管理系统</div>
<div>{{name}}</div>
</el-header>
</div>
</template>
<script>
import { getToken } from '@/utils/dealtoken.js'
export default {
data() {
return {
name: ""
}
},
created() {
this.name = getToken('username')
}
}
</script>
<style lang='scss'>
.header {
.el-header {
background-color: #409eff;
color: #333;
text-align: center;
line-height: 60px;
display: flex;
justify-content: space-between;
.title {
width: 200px;
font-size: 24px;
}
}
}
</style>
src/components/common/Menu.vue
<template>
<div class="menu">
<el-aside width="200px">
<el-menu
router
default-active="2"
class="el-menu-vertical-demo"
background-color="#409eff"
text-color="#fff"
active-text-color="#ffd04b">
<template v-for="(item, index) in menus">
<el-submenu :index="index + ''" :key="index" v-if="!item.hidden">
<template slot="title">
<i :class="item.iconClass"></i>
<span>{{item.name}}</span>
</template>
<el-menu-item-group v-for="(child, index) in item.children" :key="index">
<el-menu-item :index="child.path">
<i :class="item.iconClass"></i>
{{child.name}}
</el-menu-item>
</el-menu-item-group>
</el-submenu>
</template>
</el-menu>
</el-aside>
</div>
</template>
<script>
export default {
data() {
return {
menus: []
}
},
created() {
console.log(this.$router.options.routes)
this.menus = [...this.$router.options.routes]
}
}
</script>
<style lang='scss'>
.menu {
.el-aside {
height: 100%;
.el-menu {
height: 100%;
.fa {
margin-right: 10px;
}
}
//解决左右
.el-submenu .el-menu-item {
min-width: 0;
}
}
}
</style>
src/components/common/Pageing.vue (封装的分页组件)
<!-- 分页管理组件封装 -->
<!-- 为了多个页面复用,将路由引入 :url="url" -->
<template>
<div class="pageMent">
<el-pagination
@size-change="handleSizeChange"
@current-change="handleCurrentChange"
:current-page="page"
:page-sizes="[10, 20, 30, 50]"
:page-size="size"
layout="total, sizes, prev, pager, next, jumper"
:total="total"
:url="url">
</el-pagination>
</div>
</template>
<script>
import { getTableData } from '@/utils/table.js'
export default {
//校验外部传入参数,props用来接收父组件传递进来的参数
props: {
"total": Number,
"url": String
},
data() {
return {
page: 1, //当前页
size: 10 //每页显示条数
}
},
created() {
//console.log("this", this)
//采用后端分页方法,this.$parent代表父页面
getTableData(this.$parent, this.url, {page: this.page, size: this.size}, ['completed'])
},
methods: {
handleSizeChange(val) {
this.size = val
this.page = 1
getTableData(this.$parent, this.url, {page: this.page, size: val}, ['completed'])
},
handleCurrentChange(val) {
this.page = val
getTableData(this.$parent, this.url, {page: val, size: this.size}, ['completed'])
},
}
}
</script>
<style lang="scss">
.pageMent {
.el-pagination {
text-align: left;
margin-top: 20px;
}
}
</style>
src/components/Home.vue
<template>
<div class="home">
<Header />
<el-container class="content">
<Menu />
<el-container>
<Bread />
<el-main>
<div class="cont">
<!-- 添加菜单路由出口 -->
<router-view>
</router-view>
</div>
</el-main>
<el-footer><Footer /></el-footer>
</el-container>
</el-container>
</div>
</template>
<script>
import Menu from "@/components/common/Menu"
import Footer from "./common/Footer.vue"
import Header from "./common/Header.vue"
import Bread from "./common/Breadcrumb.vue"
export default {
components: {
Header,
Footer,
Menu,
Bread
},
data() {
return {}
}
}
</script>
<style lang="scss">
.home {
width: 100%;
height: 100%;
.content {
position: absolute;
width: 100%;
top: 60px;
bottom: 0;
.cont {
margin: 20px 0;
}
}
}
//@import url('../assets/css/reset.css')
</style>
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 {login} from '@/api/api.js'
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)
login(this.form).then(res => {
if (res.data.status === 200) {
setToken('token', res.data.token)
setToken('username', res.data.Name)
this.$message({message: res.data.msg, type: 'success'})
this.$router.push('/home')
}
})
} else {
console.error(this.form)
}
})
}
}
}
</script>
<style lang='scss'>
.login {
width: 100%;
height: 100%;
position: absolute;
//background: #409EFF;
background: url('../assets/logo.png') center no-repeat;
.el-card {
background: #65768557;
}
.box-card {
width: 450px;
margin: 200px auto;
color: #fff;
.el-form .el-form-item_label {
color: #fff;
}
.el-card_header {
font-size: 34px;
}
.el-button {
width: 100%;
}
}
}
</style>
src/components/NotFound.vue
<template>
<div class="notfound">
<div class="big">页面不见了!</div>
<div>首页瞧瞧,点击<router-link to="/">这里</router-link>进入首页.</div>
</div>
</template>
<script>
export default {
data() {
return {};
},
};
</script>
<style lang='scss'>
.notfound {
width: 100%;
height: 100%;
position: absolute;
background: #409EFF;
background: url('../assets/404page.jpg') center no-repeat;
}
</style>
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', hidden: true, component: () => import('@/components/Login') },
{ path: '/login', name: 'Login', hidden: true, component: () => import('@/components/Login') },
{ path: '/home',
name: '学生管理',
iconClass: 'fa fa-users',
redirect: '/home/student',
component: Home,
children: [
{
path: '/home/student',
name: '学生列表',
iconClass: 'fa fa-list',
component: () => import('@/components/common/students/StudentList')
},
{
path: '/home/info',
name: '信息列表',
iconClass: 'fa fa-list-alt',
component: () => import('@/components/common/students/InfoList')
},
{
path: '/home/infoman',
name: '信息管理',
iconClass: 'fa fa-list-alt',
component: () => import('@/components/common/students/InfoLists')
},
{
path: '/home/work',
name: '作业列表',
iconClass: 'fa fa-list-ul',
component: () => import('@/components/common/students/WorkList')
},
{
path: '/home/works',
name: '作业管理',
iconClass: 'fa fa-th-list',
component: () => import('@/components/common/students/WorkMent')
}
]
},
{ path: '/data',
name: '数据分析',
iconClass: 'fa fa-bar-chart',
component: Home,
children: [
{
path: '/data/dataview',
name: '数据概览',
iconClass: 'fa fa-line-chart',
component: () => import('@/components/common/dataanalyse/DataView')
},
{
path: '/data/mapview',
name: '视图概览',
iconClass: 'fa fa-line-chart',
component: () => import('@/components/common/dataanalyse/MapView')
},
{
path: '/data/score',
name: '分数视图',
iconClass: 'fa fa-line-chart',
component: () => import('@/components/common/dataanalyse/ScoreMap')
},
{
path: '/data/travel',
name: '旅游视图',
iconClass: 'fa fa-line-chart',
component: () => import('@/components/common/dataanalyse/TravelMap')
}
]
},
{ path: '/users',
name: '用户中心',
iconClass: 'fa fa-user',
component: Home,
children: [
{
path: '/users/user',
name: '数据概览',
iconClass: 'fa fa-user',
component: () => import('@/components/common/users/User')
}]
},
{ path: '*', name: 'NotFound', hidden: true, component: () => import('@/components/NotFound') }
]
export default new VueRouter({
mode: 'history',
routes: routes
})
src/utils/dealtoken.js
// Token的封装 Token存放在localStorage
export function setToken(tokenkey, token) {
console.log(tokenkey, token)
return localStorage.setItem(tokenkey, token)
}
export function getToken(tokenkey) {
console.log(tokenkey)
return localStorage.getItem(tokenkey)
}
export function removeToken(tokenkey) {
return localStorage.removeItem(tokenkey)
}
src/utils/table.js
//表格操作封装
import { call } from "file-loader"
//获取表格数据
export function getData (root, url, params) {
root.service.get(url, {params: params || {}})
.then(res => {
if (res.data.status === 200) {
root.tableData = res.data.data
root.total = res.data.total
}
})
.catch(err => {
throw err
})
}
//新增或修改表格数据
export function changeInfo (root, method, url, form, callback, callurl) {
root.service[method](url, form)
.then(res => {
if (res.data.status === 200) {
callback(root, callurl)
root.dialogFormVisible = false
root.$refs['form'].resetFields()
root.$message({message: res.data.msg, type: "success"})
}
})
.catch(err => {
throw err
})
}
//删除方法封装
export function delData (root, url, id, callback, callurl) {
root.$alert("确定要删除吗?", "提示", {
confirmButtonText: '确定',
callback: () => {
root.service.get(url + id).then(res => {
if (res.data.status === 200) {
callback(root, callurl)
root.$message({message: res.data.msg, type: "success"})
}
})
}
})
.catch(err => {
throw err
})
}
//作业列表获取数据封装
export function getTableData (root, url, params, arr) {
root.service.get(url, {params: params || {}})
.then(res => {
if (res.data.status === 200) {
root.tableData = res.data.data
root.total = res.data.total
root.tableData.map(item => {
arr.map(aItem => [
item[aItem] ? item[aItem + '_text'] = '是' : item[aItem + '_text'] = '否'
])
})
root.loading = false
}
})
.catch(err => {
throw err
})
}
src/utils/validate.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();
}
}
src/App.vue
<template>
<div>
<router-view></router-view>
</div>
</template>
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'
import service from './service'
// 挂载到原型就可以全局使用
//Vue.prototype.axios = axios
Vue.prototype.service = service
//Vue.config.productionTip = false
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/service.js
import axios from "axios";
import { getToken } from "@/utils/dealtoken.js"
import { Promise } from 'core-js'
import { Message } from "element-ui";
// axios二次封装
const service = axios.create({
// baseURL还可以使用代理
baseURL: 'http://127.0.0.1:8181',
timeout: 3000
})
// 请求拦截器
service.interceptors.request.use((config) => {
//对请求做一些额外处理
config.headers['token'] = getToken('token')
config.headers['username'] = getToken('username')
return config
}, (error) => {
return Promise.reject(error)
})
// 响应拦截器
service.interceptors.response.use((response) => {
//对响应做一些处理
let {status, msg} = response.data
if (status != 200) {
Message({message: msg || 'error', type: 'warning'})
}
console.log(response, status, msg)
return response
}, (error) => {
return Promise.reject(error)
})
export default service
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>
3.后端代码
3.1 代码结构
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) {
fmt.Println("ctx", ctx)
fmt.Println("ctx.Request", ctx.Request)
version := ctx.DefaultQuery("version", "V1.0.0.1")
//前端使用axios直接传递form时,axios会默认使用json,必须使用下面方式获取json数据,解析后再使用
data, _ := ioutil.ReadAll(ctx.Request.Body)
fmt.Println("data", data)
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)
if username == "123456" && password == "1234abcdE@" {
ctx.JSON(http.StatusOK, gin.H{
"status": 200,
"Name": username,
"Password": password,
"msg": "登录成功",
"token": "abcd1234ABCD",
})
} else {
ctx.JSON(http.StatusOK, gin.H{
"status": -1,
"Name": username,
"Password": password,
"msg": "用户名或密码错误",
})
}
}
// http://127.0.0.1:8181/formlogin
// form表单提交处理 application/x-www-form-urlencoded 或者 application/form-data
func FormLoginPost(ctx *gin.Context) {
fmt.Println("ctx", ctx)
fmt.Println("ctx.Request", ctx.Request)
username := ctx.PostForm("username")
password := ctx.PostForm("password")
fmt.Println("FormLoginPost :: ", username, password)
if username == "123456" && password == "1234abcdE@" {
ctx.JSON(http.StatusOK, gin.H{
"status": 200,
"Name": username,
"Password": password,
"msg": "登录成功",
"token": "abcd1234ABCD",
})
} else {
ctx.JSON(http.StatusOK, gin.H{
"status": -1,
"Name": username,
"Password": password,
"msg": "用户名或密码错误",
})
}
}
// 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, "上传成功")
}
controller/student.go
package controller
import (
"encoding/json"
"fmt"
"io/ioutil"
"net/http"
"github.com/gin-gonic/gin"
)
/*
type User struct {
Name string `json:"name"`
Age int `json:"age"`
}
user := User{"Tom", 18}
jsonData, err := json.Marshal(user)
if err != nil {
c.AbortWithError(500, err)
}
c.Data(200, "application/json", jsonData)
*/
/*
在 Go 语言中,可以使用内置的 copy 函数来将数组转换为切片。
// 将 arr 转换为切片
arr := [3]int{1, 2, 3}
sl := make([]int, len(arr))
copy(sl, arr[:])
// 将切片转换为数组
var arr2 [3]int
copy(arr2[:], sl)
*/
var students = []map[string]interface{}{
{"id": 1, "name": "张三", "age": 10, "sex": 2, "time": "2023-08-05", "father": "爸爸", "mother": "妈妈", "number": 2, "class": 2, "state": 1, "address": "北京市 朝阳区", "phone": "18818812345"},
{"id": 2, "name": "李四", "age": 11, "sex": 1, "time": "2023-08-05", "father": "爸爸", "mother": "妈妈", "number": 2, "class": 2, "state": 2, "address": "天津市 朝阳区", "phone": "18818812345"},
{"id": 3, "name": "王五", "age": 12, "sex": 2, "time": "2023-08-05", "father": "爸爸", "mother": "妈妈", "number": 2, "class": 2, "state": 3, "address": "上海市 朝阳区", "phone": "18818812345"},
{"id": 4, "name": "赵六", "age": 9, "sex": 1, "time": "2023-08-05", "father": "爸爸", "mother": "妈妈", "number": 2, "class": 2, "state": 1, "address": "重庆市 朝阳区", "phone": "18818812345"},
{"id": 5, "name": "张三", "age": 10, "sex": 2, "time": "2023-08-05", "father": "爸爸", "mother": "妈妈", "number": 2, "class": 2, "state": 1, "address": "北京市 朝阳区", "phone": "18818812345"},
{"id": 6, "name": "李四", "age": 11, "sex": 1, "time": "2023-08-05", "father": "爸爸", "mother": "妈妈", "number": 2, "class": 2, "state": 2, "address": "天津市 朝阳区", "phone": "18818812345"},
{"id": 7, "name": "王五", "age": 12, "sex": 2, "time": "2023-08-05", "father": "爸爸", "mother": "妈妈", "number": 2, "class": 2, "state": 3, "address": "上海市 朝阳区", "phone": "18818812345"},
{"id": 8, "name": "赵六", "age": 9, "sex": 1, "time": "2023-08-05", "father": "爸爸", "mother": "妈妈", "number": 2, "class": 2, "state": 1, "address": "重庆市 朝阳区", "phone": "18818812345"},
{"id": 9, "name": "张三", "age": 10, "sex": 2, "time": "2023-08-05", "father": "爸爸", "mother": "妈妈", "number": 2, "class": 2, "state": 1, "address": "北京市 朝阳区", "phone": "18818812345"},
{"id": 10, "name": "李四", "age": 11, "sex": 1, "time": "2023-08-05", "father": "爸爸", "mother": "妈妈", "number": 2, "class": 2, "state": 2, "address": "天津市 朝阳区", "phone": "18818812345"},
{"id": 11, "name": "王五", "age": 12, "sex": 2, "time": "2023-08-05", "father": "爸爸", "mother": "妈妈", "number": 2, "class": 2, "state": 3, "address": "上海市 朝阳区", "phone": "18818812345"},
{"id": 12, "name": "赵六", "age": 9, "sex": 1, "time": "2023-08-05", "father": "爸爸", "mother": "妈妈", "number": 2, "class": 2, "state": 1, "address": "重庆市 朝阳区", "phone": "18818812345"},
{"id": 13, "name": "张三", "age": 10, "sex": 2, "time": "2023-08-05", "father": "爸爸", "mother": "妈妈", "number": 2, "class": 2, "state": 1, "address": "北京市 朝阳区", "phone": "18818812345"},
{"id": 14, "name": "李四", "age": 11, "sex": 1, "time": "2023-08-05", "father": "爸爸", "mother": "妈妈", "number": 2, "class": 2, "state": 2, "address": "天津市 朝阳区", "phone": "18818812345"},
{"id": 15, "name": "王五", "age": 12, "sex": 2, "time": "2023-08-05", "father": "爸爸", "mother": "妈妈", "number": 2, "class": 2, "state": 3, "address": "上海市 朝阳区", "phone": "18818812345"},
{"id": 16, "name": "赵六", "age": 9, "sex": 1, "time": "2023-08-05", "father": "爸爸", "mother": "妈妈", "number": 2, "class": 2, "state": 1, "address": "重庆市 朝阳区", "phone": "18818812345"},
{"id": 17, "name": "张三", "age": 10, "sex": 2, "time": "2023-08-05", "father": "爸爸", "mother": "妈妈", "number": 2, "class": 2, "state": 1, "address": "北京市 朝阳区", "phone": "18818812345"},
{"id": 18, "name": "李四", "age": 11, "sex": 1, "time": "2023-08-05", "father": "爸爸", "mother": "妈妈", "number": 2, "class": 2, "state": 2, "address": "天津市 朝阳区", "phone": "18818812345"},
{"id": 19, "name": "王五", "age": 12, "sex": 2, "time": "2023-08-05", "father": "爸爸", "mother": "妈妈", "number": 2, "class": 2, "state": 3, "address": "上海市 朝阳区", "phone": "18818812345"},
{"id": 20, "name": "赵六", "age": 9, "sex": 1, "time": "2023-08-05", "father": "爸爸", "mother": "妈妈", "number": 2, "class": 2, "state": 1, "address": "重庆市 朝阳区", "phone": "18818812345"},
{"id": 21, "name": "张三", "age": 10, "sex": 2, "time": "2023-08-05", "father": "爸爸", "mother": "妈妈", "number": 2, "class": 2, "state": 1, "address": "北京市 朝阳区", "phone": "18818812345"},
{"id": 22, "name": "李四", "age": 11, "sex": 1, "time": "2023-08-05", "father": "爸爸", "mother": "妈妈", "number": 2, "class": 2, "state": 2, "address": "天津市 朝阳区", "phone": "18818812345"},
{"id": 23, "name": "王五", "age": 12, "sex": 2, "time": "2023-08-05", "father": "爸爸", "mother": "妈妈", "number": 2, "class": 2, "state": 3, "address": "上海市 朝阳区", "phone": "18818812345"},
{"id": 24, "name": "赵六", "age": 9, "sex": 1, "time": "2023-08-05", "father": "爸爸", "mother": "妈妈", "number": 2, "class": 2, "state": 1, "address": "重庆市 朝阳区", "phone": "18818812345"},
{"id": 25, "name": "张三", "age": 10, "sex": 2, "time": "2023-08-05", "father": "爸爸", "mother": "妈妈", "number": 2, "class": 2, "state": 1, "address": "北京市 朝阳区", "phone": "18818812345"},
{"id": 26, "name": "李四", "age": 11, "sex": 1, "time": "2023-08-05", "father": "爸爸", "mother": "妈妈", "number": 2, "class": 2, "state": 2, "address": "天津市 朝阳区", "phone": "18818812345"},
{"id": 27, "name": "王五", "age": 12, "sex": 2, "time": "2023-08-05", "father": "爸爸", "mother": "妈妈", "number": 2, "class": 2, "state": 3, "address": "上海市 朝阳区", "phone": "18818812345"},
{"id": 28, "name": "赵六", "age": 9, "sex": 1, "time": "2023-08-05", "father": "爸爸", "mother": "妈妈", "number": 2, "class": 2, "state": 1, "address": "重庆市 朝阳区", "phone": "18818812345"},
{"id": 29, "name": "张三", "age": 10, "sex": 2, "time": "2023-08-05", "father": "爸爸", "mother": "妈妈", "number": 2, "class": 2, "state": 1, "address": "北京市 朝阳区", "phone": "18818812345"},
{"id": 30, "name": "李四", "age": 11, "sex": 1, "time": "2023-08-05", "father": "爸爸", "mother": "妈妈", "number": 2, "class": 2, "state": 2, "address": "天津市 朝阳区", "phone": "18818812345"},
{"id": 31, "name": "王五", "age": 12, "sex": 2, "time": "2023-08-05", "father": "爸爸", "mother": "妈妈", "number": 2, "class": 2, "state": 3, "address": "上海市 朝阳区", "phone": "18818812345"},
{"id": 32, "name": "赵六", "age": 9, "sex": 1, "time": "2023-08-05", "father": "爸爸", "mother": "妈妈", "number": 2, "class": 2, "state": 1, "address": "重庆市 朝阳区", "phone": "18818812345"},
{"id": 33, "name": "张三", "age": 10, "sex": 2, "time": "2023-08-05", "father": "爸爸", "mother": "妈妈", "number": 2, "class": 2, "state": 1, "address": "北京市 朝阳区", "phone": "18818812345"},
{"id": 34, "name": "李四", "age": 11, "sex": 1, "time": "2023-08-05", "father": "爸爸", "mother": "妈妈", "number": 2, "class": 2, "state": 2, "address": "天津市 朝阳区", "phone": "18818812345"},
{"id": 35, "name": "王五", "age": 12, "sex": 2, "time": "2023-08-05", "father": "爸爸", "mother": "妈妈", "number": 2, "class": 2, "state": 3, "address": "上海市 朝阳区", "phone": "18818812345"},
{"id": 36, "name": "赵六", "age": 9, "sex": 1, "time": "2023-08-05", "father": "爸爸", "mother": "妈妈", "number": 2, "class": 2, "state": 1, "address": "重庆市 朝阳区", "phone": "18818812345"},
{"id": 37, "name": "张三", "age": 10, "sex": 2, "time": "2023-08-05", "father": "爸爸", "mother": "妈妈", "number": 2, "class": 2, "state": 1, "address": "北京市 朝阳区", "phone": "18818812345"},
{"id": 38, "name": "李四", "age": 11, "sex": 1, "time": "2023-08-05", "father": "爸爸", "mother": "妈妈", "number": 2, "class": 2, "state": 2, "address": "天津市 朝阳区", "phone": "18818812345"},
{"id": 39, "name": "王五", "age": 12, "sex": 2, "time": "2023-08-05", "father": "爸爸", "mother": "妈妈", "number": 2, "class": 2, "state": 3, "address": "上海市 朝阳区", "phone": "18818812345"},
{"id": 40, "name": "赵六", "age": 9, "sex": 1, "time": "2023-08-05", "father": "爸爸", "mother": "妈妈", "number": 2, "class": 2, "state": 1, "address": "重庆市 朝阳区", "phone": "18818812345"},
{"id": 41, "name": "张三", "age": 10, "sex": 2, "time": "2023-08-05", "father": "爸爸", "mother": "妈妈", "number": 2, "class": 2, "state": 1, "address": "北京市 朝阳区", "phone": "18818812345"},
{"id": 42, "name": "李四", "age": 11, "sex": 1, "time": "2023-08-05", "father": "爸爸", "mother": "妈妈", "number": 2, "class": 2, "state": 2, "address": "天津市 朝阳区", "phone": "18818812345"},
{"id": 43, "name": "王五", "age": 12, "sex": 2, "time": "2023-08-05", "father": "爸爸", "mother": "妈妈", "number": 2, "class": 2, "state": 3, "address": "上海市 朝阳区", "phone": "18818812345"},
{"id": 44, "name": "赵六", "age": 9, "sex": 1, "time": "2023-08-05", "father": "爸爸", "mother": "妈妈", "number": 2, "class": 2, "state": 1, "address": "重庆市 朝阳区", "phone": "18818812345"},
{"id": 45, "name": "张三", "age": 10, "sex": 2, "time": "2023-08-05", "father": "爸爸", "mother": "妈妈", "number": 2, "class": 2, "state": 1, "address": "北京市 朝阳区", "phone": "18818812345"},
{"id": 46, "name": "李四", "age": 11, "sex": 1, "time": "2023-08-05", "father": "爸爸", "mother": "妈妈", "number": 2, "class": 2, "state": 2, "address": "天津市 朝阳区", "phone": "18818812345"},
{"id": 47, "name": "王五", "age": 12, "sex": 2, "time": "2023-08-05", "father": "爸爸", "mother": "妈妈", "number": 2, "class": 2, "state": 3, "address": "上海市 朝阳区", "phone": "18818812345"},
{"id": 48, "name": "赵六", "age": 9, "sex": 1, "time": "2023-08-05", "father": "爸爸", "mother": "妈妈", "number": 2, "class": 2, "state": 1, "address": "重庆市 朝阳区", "phone": "18818812345"},
{"id": 47, "name": "张三", "age": 10, "sex": 2, "time": "2023-08-05", "father": "爸爸", "mother": "妈妈", "number": 2, "class": 2, "state": 1, "address": "北京市 朝阳区", "phone": "18818812345"},
{"id": 50, "name": "李四", "age": 11, "sex": 1, "time": "2023-08-05", "father": "爸爸", "mother": "妈妈", "number": 2, "class": 2, "state": 2, "address": "天津市 朝阳区", "phone": "18818812345"},
{"id": 51, "name": "王五", "age": 12, "sex": 2, "time": "2023-08-05", "father": "爸爸", "mother": "妈妈", "number": 2, "class": 2, "state": 3, "address": "上海市 朝阳区", "phone": "18818812345"},
{"id": 52, "name": "赵六", "age": 9, "sex": 1, "time": "2023-08-05", "father": "爸爸", "mother": "妈妈", "number": 2, "class": 2, "state": 1, "address": "重庆市 朝阳区", "phone": "18818812345"},
}
// get http://127.0.0.1:8181/api/students
func GetStudentList(ctx *gin.Context) {
name := ctx.Query("name")
fmt.Println("name :: ", name)
//sex: 1 -> 男 2 -> 女
//state: 1:已入学 2:未入学 3:休学中
selstudents := []map[string]interface{}{}
if len(name) != 0 {
for index, value := range students {
if value["name"] == name {
selstudents = append(selstudents, students[index])
}
}
} else {
for index, _ := range students {
selstudents = append(selstudents, students[index])
}
}
/*
selstudents := list.New()
if len(name) != 0 {
for _, value := range students {
if value["name"] == name {
selstudents.PushBack(value)
}
}
} else {
for _, value := range students {
selstudents.PushBack(value)
}
}
selstudents.Len()
*/
ctx.JSON(http.StatusOK, gin.H{
"status": 200,
"msg": "获取学生信息成功",
"data": selstudents,
"total": len(selstudents),
})
}
// GET请求 http://127.0.0.1:8181/api/students/del?id=1
func DelStudent(ctx *gin.Context) {
id := ctx.Query("id")
fmt.Println("del student id :: ", id)
ctx.JSON(http.StatusOK, gin.H{
"status": 200,
"msg": "删除学生信息成功",
"id": id,
})
}
// GET请求 http://127.0.0.1:8181/api/students/del/1
func DelStudentByReq(ctx *gin.Context) {
// 使用Param获取URL参数
id := ctx.Param("id")
// 返回请求参数
ctx.JSON(200, gin.H{
"status": 200,
"msg": "删除学生信息成功",
"id": id,
})
}
type UserInfo struct {
Name string //`json:"name"`
Age string //`json:"age"`
Sex string //`json:"sex"`
Father string //`json:"father"`
Mother string //`json:"mother"`
Time string //`json:"time"`
Address string //`json:"address"`
Phone string //`json:"phone"`
}
func AddStudent(ctx *gin.Context) {
data, _ := ioutil.ReadAll(ctx.Request.Body)
var u UserInfo
err := json.Unmarshal(data, &u)
if err != nil {
fmt.Println(err)
}
fmt.Println("AddStudent :: ", u.Name, u.Age, u.Sex, u.Father, u.Mother, u.Time, u.Address, u.Phone)
ctx.JSON(http.StatusOK, gin.H{
"status": 200,
"name": u.Name,
"msg": "增加成功",
})
}
// get http://127.0.0.1:8181/api/getinfo
func GetInfo(ctx *gin.Context) {
name := ctx.Query("name")
fmt.Println("name :: ", name)
//sex: 1 -> 男 2 -> 女
//state: 1:已入学 2:未入学 3:休学中
selstudents := []map[string]interface{}{}
if len(name) != 0 {
for index, value := range students {
if value["name"] == name {
selstudents = append(selstudents, students[index])
}
}
} else {
for index, _ := range students {
selstudents = append(selstudents, students[index])
}
}
ctx.JSON(http.StatusOK, gin.H{
"status": 200,
"msg": "获取学生信息成功",
"data": selstudents,
"total": len(selstudents),
})
}
func UpdateStudent(ctx *gin.Context) {
data, _ := ioutil.ReadAll(ctx.Request.Body)
var u UserInfo
err := json.Unmarshal(data, &u)
if err != nil {
fmt.Println(err)
}
fmt.Println("UpdateStudent :: ", u.Name, u.Age, u.Sex, u.Father, u.Mother, u.Time, u.Address, u.Phone)
ctx.JSON(http.StatusOK, gin.H{
"status": 200,
"name": u.Name,
"msg": "修改成功",
})
}
// GET请求 http://127.0.0.1:8181/api/info/del/1
func DelIfo(ctx *gin.Context) {
// 使用Param获取URL参数
id := ctx.Param("id")
// 返回请求参数
ctx.JSON(200, gin.H{
"status": 200,
"msg": "删除信息成功",
"id": id,
})
}
var works = []map[string]interface{}{
{"id": 1, "userId": 110, "title": "JS", "completed": true},
{"id": 2, "userId": 111, "title": "C++", "completed": false},
{"id": 3, "userId": 112, "title": "Java", "completed": true},
{"id": 4, "userId": 113, "title": "Golang", "completed": false},
{"id": 1, "userId": 110, "title": "JS", "completed": true},
{"id": 2, "userId": 111, "title": "C++", "completed": false},
{"id": 3, "userId": 112, "title": "Java", "completed": true},
{"id": 4, "userId": 113, "title": "Golang", "completed": false},
{"id": 1, "userId": 110, "title": "JS", "completed": true},
{"id": 2, "userId": 111, "title": "C++", "completed": false},
{"id": 3, "userId": 112, "title": "Java", "completed": true},
{"id": 4, "userId": 113, "title": "Golang", "completed": false},
{"id": 1, "userId": 110, "title": "JS", "completed": true},
{"id": 2, "userId": 111, "title": "C++", "completed": false},
{"id": 3, "userId": 112, "title": "Java", "completed": true},
{"id": 4, "userId": 113, "title": "Golang", "completed": false},
{"id": 1, "userId": 110, "title": "JS", "completed": true},
{"id": 2, "userId": 111, "title": "C++", "completed": false},
{"id": 3, "userId": 112, "title": "Java", "completed": true},
{"id": 4, "userId": 113, "title": "Golang", "completed": false},
{"id": 1, "userId": 110, "title": "JS", "completed": true},
{"id": 2, "userId": 111, "title": "C++", "completed": false},
{"id": 3, "userId": 112, "title": "Java", "completed": true},
{"id": 4, "userId": 113, "title": "Golang", "completed": false},
{"id": 1, "userId": 110, "title": "JS", "completed": true},
{"id": 2, "userId": 111, "title": "C++", "completed": false},
{"id": 3, "userId": 112, "title": "Java", "completed": true},
{"id": 4, "userId": 113, "title": "Golang", "completed": false},
}
// get请求,支持分页查询
func Works(ctx *gin.Context) {
page := ctx.Query("page")
size := ctx.Query("size")
fmt.Println("Works :: ", page, size)
//数据分页处理
ctx.JSON(200, gin.H{
"status": 200,
"msg": "获取作业成功",
"data": works,
"total": len(works),
})
}
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处理跨域
corsConfig := cors.DefaultConfig()
corsConfig.AllowCredentials = true
corsConfig.AllowHeaders = []string{"content-type", "Origin", "token", "username"}
corsConfig.AllowOrigins = []string{"http://localhost:8080", "http://localhost:8081"}
corsConfig.AllowMethods = []string{"POST", "GET", "OPTIONS", "PUT", "DELETE", "UPDATE"}
r.Use(cors.New(corsConfig))
//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.GET("/api/students", controller.GetStudentList)
r.GET("/api/students/del", controller.DelStudent)
r.GET("/api/students/del/:id", controller.DelStudentByReq)
r.POST("/api/info", controller.AddStudent)
r.GET("/api/getinfo", controller.GetInfo)
r.POST("api/updateinfo", controller.UpdateStudent)
r.GET("/api/info/del/:id", controller.DelIfo)
r.GET("api/works", controller.Works)
//r.Run() // <===> r.Run(":8080") 监听并在 0.0.0.0:8080 上启动服务
r.Run(":8181")
}
4.其他
4.1 vscode快速编写正则表达式
安装any-rule插件
ctrl shift p 调出正则表达式选择