文章目录
spring boot 分层图解
安装idea
安装参考
idea插件使用一
idea插件使用二
项目热部署参考
配置阿里云镜像
<mirrors>
<mirror>
<id>nexus-aliyun</id>
<mirrorOf>central</mirrorOf>
<name>Nexus aliyun</name>
<url>http://maven.aliyun.com/nexus/content/groups/public</url>
</mirror>
</mirrors>
项目启动
1) 安装node.js(请自行安装)
安装参考一
安装参考二
2)切换到项目根目录
3)在项目根目录执行:
npm install -g cnpm --registry=https://registry.npm.taobao.org
//切换模块下载镜像地址
4)项目根目录执行cnpm install,下载该项目依赖模块
提示如果安装“360安全卫士”或“电脑管家”,一定要关闭,不然报错
5)添加mark-down编辑依赖
cnpm install mavon-editor --save
6)用于解析md文档依赖
cnpm install markdown-it --save
cnpm install github-markdown-css
7)启动服务:项目根目录执行npm run dev,会自动打开前端首页(后端项目要提前部署好)
前端项目结构
build | 项目构建(webpack)相关代码 |
---|---|
config | 配置目录,包括端口号等。我们初学可以使用默认的:8089,当然线上为 |
node_modules | npm 加载的项目依赖模块 |
src | 要开发的目录,基本上要做的事情都在这个目录里。里面包含了几个目录及文件:assets: 放置一些图片,如logo等。components: 公共组件。 router:路由。 App.vue: 项目入口文件,我们也可以直接将组件写这里,而不使用 components 目录。 main.js: 项目的核心文件。 |
static | 静态资源目录,如图片、字体等。 |
index.html | 首页入口文件,可以添加一些 meta 信息 |
package.json | 项目配置文件 |
README.md | 项目的说明文档,markdown 格式 |
项目前端模块中引入了vuex,存放vuex的系列文件:
vuex需要遵守的规则:
1、应用层级的状态应该集中到单个 store 对象中。
2、提交 mutation 是更改状态的唯一方法,并且这个过程是同步的。
3、异步逻辑都应该封装到 action 里面。
1)首先 index.js 入口文件
2)store.js - 引入vuex,设置state状态数据,引入getter、mutation和action
3)state.js 相当于数据库
里面定义了数据结构,一些数据的初始状态
4)getters.js 顾名思义 取用,不做修改
5)mutation-types.js 存放Vuex常用的变量
引入mutation-types.js 操作里面定义的常用变量
6)action.js - 提交mutation以达到委婉地修改state状态,可异步操作
store.js文件
import VUE from 'vue'
import VUEX from 'vuex'
VUE.use(VUEX)
const state = {
isPractice: false, //练习模式标志
flag: false, //菜单栏左右滑动标志
userInfo: null,
menu: [
// {
// index: '1',
// title: '考试管理',
// icon: 'icon-kechengbiao',
// content:[{item1:'考试查询',path:'selectExam'},{item2:'添加考试',path:'/addExam'}],
// },
// {
// index: '2',
// title: '题库管理',
// icon: 'icon-tiku',
// content:[{item2:'所有题库',path:'/selectAnswer'},{item3:'增加题库',path:'/addAnswer'},{path: '/addAnswerChildren'}],
// },
{
index: '1',
title: '成绩查询',
icon: 'icon-performance',
content:[{
item1:'学生成绩查询',path:'/allStudentsGrade'},{
path: '/grade'},{
item2: '成绩分段查询',path: '/selectExamToPart'},{
path: '/scorePart'},{
item2: '成绩分科排序',path: '/selectExamToPart2'},{
path: '/scorePart2'}],
},
{
index: '2',
title: '批改试卷',
icon: 'el-icon-edit',
content:[{
item1:'未批改的应用题',path:'/studentApplication'},{
item2: '已批改的应用题',path: '/studentApplication2'}],
},
{
index: '3',
title: '答疑解惑',
icon: 'el-icon-chat-dot-round',
content:[{
item1:'发布问题',path:'/publishProblem'},{
item2:'学生问题',path:'/solveProblem'}],
},
// {
// index: '6',
// title: '教师管理',
// icon: 'icon-Userselect',
// content:[{item1:'教师管理',path:'/teacherManage'},{item2: '添加教师',path: '/addTeacher'}],
// },
// {
// index: '7',
// title: '模块管理',
// icon: 'icon-module4mokuai',
// content:[{item1:'模块操作',path:'/module'}],
// }
],
}
const mutations = {
practice(state,status) {
state.isPractice = status
},
toggle(state) {
state.flag = !state.flag
},
changeUserInfo(state,info) {
state.userInfo = info
}
}
const getters = {
}
const actions = {
getUserInfo(context,info) {
context.commit('changeUserInfo',info)
},
getPractice(context,status) {
context.commit('practice',status)
}
}
export default new VUEX.Store({
state,
mutations,
getters,
actions,
// store
})
项目前端中index.html
项目中index.html和其他html差不多,但一般只定义一个空的根节点,在main.js里面定义的实例将挂载在根节点下,内容都通过vue组件来填充。
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1.0">
<title>锋芒频波测评系统</title>
<link rel="stylesheet" href="//at.alicdn.com/t/font_987928_pqv3jkd52jl.css">
<link rel="icon" type="image/x-icon" href="../static/img/图标1.png"/>
</head>
<body>
<div id="app"></div>
<!-- built files will be auto injected -->
</body>
</html>
main.js里面定义的实例
new Vue({
el: '#app',
router,
render: h => h(App),
components: {
App },
template: '<App/>'
})
App.vue
一个vue页面通常由三部分组成:模板(template)、js(script)、样式(style)
- template
其中模板只能包含一个父节点,<router-view/>
为<router-view/> <router-view/>
的简写,是子路由视图,后面的路由页面都显示在此处。 - script
vue通常用es6来写,用export default导出,其下面可以包含数据data,生命周期(mounted等),方法(methods)等 - style
样式通过style标签<style></style>
包裹,默认是影响全局的,如需定义作用域只在该组件下起作用,需在标签上加scoped,<style scoped></style>
<template>
<div id="app">
<router-view/>
</div>
</template>
<script>
export default {
name: 'App'
}
</script>
<style>
ul {
list-style: none;
}
a {
text-decoration: none;
}
* {
margin: 0;
padding: 0;
}
#app {
font-family: "Microsoft YaHei", "Helvetica", "Tahoma", "Geneva", "Arial", sans-serif;
background-color: #eee;
}
</style>
main.js
main.js主要是引入vue框架,根组件及路由设置,并且定义vue实例。
// The Vue build version to load with the `import` command
// (runtime-only or standalone) has been set in webpack.base.conf with an alias.
import Vue from 'vue'
import App from './App'
import router from './router'
import echarts from 'echarts'
import axios from 'axios'
import ElementUI from 'element-ui'
import 'element-ui/lib/theme-chalk/index.css'
import VueCookies from 'vue-cookies'
import mavonEditor from 'mavon-editor'
import 'mavon-editor/dist/css/index.css'
Vue.use(ElementUI)
Vue.use(VueCookies)
Vue.use(mavonEditor)
Vue.config.productionTip = false
Vue.prototype.bus = new Vue()
Vue.prototype.$echarts = echarts
Vue.prototype.$axios = axios
new Vue({
el: '#app',
router,
render: h => h(App),
components: {
App },
template: '<App/>'
})
代码中的router相当于router:router,为ES6写法,在对象中,如果键值对一样的话,可以简写为一个;
components: { App }引入根组件App.vue,App即App:App;
template:'<App/>'
是简写形式,等价于 <App></App>
。
router
router下的index.js文件中的routes定义了路径为’/'的路由,该路由对应的页面是HelloWorld组件。
import Vue from 'vue'
import Router from 'vue-router'
Vue.use(Router)
export default new Router({
routes: [
{
path: '/',
name: 'login', //登录界面
component: () => import('@/components/common/login')
},
{
path: '/changeUser',
name: 'changeUser',
component: () => import ('@/components/common/userManager')
},
{
path: '/index', //教师主页
component: () => import('@/components/admin/index'),
children: [
{
path: '/', //首页默认路由
component: () => import('@/components/common/hello')
},
{
path:'/grade', //学生成绩
component: () => import('@/components/charts/grade')
},
{
path: '/selectExamToPart', //学生分数段
component: () => import('@/components/teacher/selectExamToPart')
},
{
path: '/selectExamToPart2', //学生分科成绩
component: () => import('@/components/teacher/selectExamToPart2')
},
{
path: '/scorePart',
component: () => import('@/components/charts/scorePart')
},
{
path: '/scorePart2', //单科成绩排序
component: () => import('@/components/charts/scorePart2')
},
{
path: '/searchStudentApplication', //单科成绩排序
component: () => import('@/components/teacher/searchStudentApplication')
},
{
path: '/allStudentsGrade', //所有学生成绩统计
component: () => import('@/components/teacher/allStudentsGrade')
},
{
path: '/examDescription', //考试管理功能描述
component: () => import('@/components/teacher/examDescription')
},
{
path: '/selectExam', //查询所有考试
component: () => import('@/components/teacher/selectExam')
},
{
path: '/addExam', //添加考试
component: () => import('@/components/teacher/addExam')
},
{
path: '/answerDescription', //题库管理功能介绍
component: ()=> import('@/components/teacher/answerDescription')
},
{
path: '/selectAnswer', //查询所有题库
component: () => import('@/components/teacher/selectAnswer')
},
{
path: '/addAnswer', //增加题库主界面
component: () => import('@/components/teacher/addAnswer')
},
{
path: '/addAnswerChildren', //点击试卷跳转到添加题库页面
component: () => import('@/components/teacher/addAnswerChildren')
},
{
path: '/studentManage', //学生管理界面
component: () => import('@/components/teacher/studentManage')
},
{
path: '/studentApplication', //展示要批改的应用题
component: () => import('@/components/teacher/studentApplicationNoCorrect')
},
{
path: '/studentApplication2', //展示批改过的应用题
component: () => import('@/components/teacher/studentApplicationCorrect')
},
{
path: '/solveProblem', //展示问题
component: () => import('@/components/teacher/solveProblem')
},
{
path: '/publishProblem', //展示问题
component: () => import('@/components/teacher/publishProblem')
},
{
path: '/addStudent', //添加学生
component: () => import('@/components/teacher/addStudent')
},
{
path: '/teacherManage',
component: () => import('@/components/admin/tacherManage')
},
{
path: '/addTeacher',
component: () => import ('@/components/admin/addTeacher')
},
]
},
{
path: '/student',
component: () => import('@/components/student/index'),
children: [
{
path:"/",component: ()=> import('@/components/student/myExam')},
{
path: '/manager', component: () => import('@/components/student/manager')},
{
path: '/update_stuinfo', component: () => import('@/components/student/update_stuinfo')},
{
path: '/examMsg', component: () => import('@/components/student/examMsg')},
{
path: '/message', component: () => import('@/components/student/message')},
{
path: '/studentScore', component: () => import("@/components/student/answerScore")},
{
path: '/scoreTable', component: () => import("@/components/student/scoreTable")}
]
},
{
path: '/answer',component: () => import('@/components/student/answer')},
{
path: '/registerstudent', component: () => import('@/components/student/registerstudent')},
{
path: '*',
redirect: '/'
}
]
})
整个页面渲染过程
访问http://localhost:8088/显示的就是index.html页面,index.html原本只有一个根结点id=“app”。
main.js入口文件引入根组件App
前边我们已经提到,根组件App中,<router-view/>
是子路由视图,后面的路由页面都显示在此处,访问http://localhost:8088/,路由为‘/’,根据路由文件index.js,所以引入login组件。
login.vue
<!-- 用户登录界面 -->
<template>
<div id="login">
<div>
<img src="../../assets/img/top_logo.jpg" height="60" width="60"/>
</div>
<div class="bg"></div>
<el-row class="main-container">
<el-col :lg="8" :xs="16" :md="10" :span="10">
<div class="bottom">
<div class="container">
<p class="title">锋芒频波测评系统</p>
<el-form :label-position="labelPosition" label-width="80px" :model="formLabelAlign">
<el-form-item label="账号:">
<el-input v-model.number="formLabelAlign.username" placeholder="请输入账号"></el-input>
</el-form-item>
<el-form-item label="密码:">
<!-- <i class="el-icon-unlock"></i>-->
<el-input v-model="formLabelAlign.password" placeholder="请输入密码" type='password'></el-input>
</el-form-item>
<div>
<input class="myInput" type="text" v-model="formLabelAlign.verifyCode" placeholder="请输入验证码"/>
<!-- <el-input v-model="formLabelAlign.verifyCode" placeholder="请输入验证码" type='text' ></el-input>-->
<img alt="单击图片刷新!" style="margin-bottom: -13px;" src="/api/kaptcha"
onclick="this.src='/api/kaptcha?d='+new Date()*1">
</div>
<div class="submit">
<el-button type="primary" class="row-login" @click="login()">登录</el-button>
</div>
<!-- <el-button class="row-register" type="button" @click="register()">Or, Sign Up?</el-button>-->
</el-form>
</div>
</div>
</el-col>
</el-row>
<el-row class="footer">
<el-col>
<p class="msg2">©2020 锋芒工作室 All Rights Reserved</p>
</el-col>
</el-row>
</div>
</template>
<script>
import store from '@/vuex/store'
import {
mapState} from 'vuex'
export default {
store,
name: "login",
data() {
return {
role: 2,
labelPosition: 'left',
verfyCode_houtuan:'',
formLabelAlign: {
username: '',
password: '',
verifyCode:''
}
}
},
created(){
// this.$axios(`/api/getVerify`).then(res => {
// console.log(res.data)})
},
methods: {
getverfiyCode() {
//分页查询所有试卷信息
},
register() {
this.$router.push({
path: '/registerstudent'})
},
//用户登录请求后台处理
login() {
console.log("登录操作执行-------");
// console.log(this.formLabelAlign.verifyCode);
this.$axios({
url: `/api/getVerify`,
method: 'get',
async:false
}).then(res => {
// if (res.data.code==200){
//
// }
if (res.data === this.formLabelAlign.verifyCode) {
if (this.formLabelAlign.username === "" || this.formLabelAlign.password === ""){
this.$message({
showClose: true,
type: 'error',
message: '用户名或密码为空'
})
}else{
this.$axios({
url: `/api/login`,
method: 'post',
data: {
...this.formLabelAlign
}
}).then(res=>{
let resData = res.data.data
if(resData != null) {
switch(resData.role) {
case "0": //管理员
this.$cookies.set("cname", resData.adminName)
this.$cookies.set("cid", resData.adminId)
this.$cookies.set("role", 0)
this.$router.push({
path: '/index' }) //跳转到首页
break
case "1": //教师
this.$cookies.set("cname", resData.teacherName)
this.$cookies.set("cid", resData.teacherId)
this.$cookies.set("role", 1)
this.$router.push({
path: '/index' }) //跳转到教师用户
break
case "2": //学生
this.$cookies.set("cname", resData.studentName)
this.$cookies.set("cid", resData.studentId)
this.$cookies.set("role", 2)
this.$router.push({
path: '/student'})
break
}
}
if(resData == null) {
//错误提示
this.$message({
showClose: true,
type: 'error',
message: '用户名或者密码错误'
})
}
})
}
}else{
this.$message({
showClose: true,
type: 'error',
message: '验证码错误'
})
}
})
},
clickTag(key) {
this.role = key
}
},
computed: mapState(["userInfo"]),
mounted() {
}
}
</script>
<style lang="scss" scoped>
.myInput{
background-color: #FFF;
background-image: none;border-radius: 4px;border: 1px solid #DCDFE6;
-webkit-box-sizing: border-box;box-sizing: border-box;
color: #606266;
display: inline-block;
font-size: inherit;
height: 40px;
line-height: 40px;
outline: 0;
padding: 0 15px;
transition: border-color .2s cubic-bezier(.645,.045,.355,1);
}
.container {
margin-bottom: 32px;
}
.container .el-radio-group {
margin: 30px 0px;
}
#login {
font-size: 14px;
color: #000;
background-color: #fff;
}
#login .bg {
position: fixed;
top: 70px;
left: 0;
width: 100%;
overflow-y: auto;
height: 75%;
/*<!--background: url('../../assets/img/img2.jpg')center top / cover no-repeat;-->*/
background-color: #459ddd;
}
#login .main-container {
display: flex;
justify-content: center;
align-items: center;
margin-top: 75px;
}
#login .bottom {
display:flex;
justify-content: center;
background-color:white;
border-radius: 10px;
box-shadow: 0 4px 8px 0 rgba(0, 0, 0, 0.2), 0 6px 20px 0 rgba(0, 0, 0, 0.19);
min-height: 430px;
}
#login .bottom .title {
text-align: center;
font-size: 30px;
}
.bottom .container .title {
margin: 70px 0px;;
}
.bottom .submit .row-login {
width: 100%;
background-color: #459ddd;
border-color: #459ddd;
margin: 10px 0px 10px 0px;
padding: 15px 20px;
}
.bottom .submit {
display: flex;
justify-content: center;
}
.footer {
margin-top: 50px;
text-align: center;
}
.footer .msg2 {
font-size: 14px;
color: gray;
margin-top: 70px;
}
.bottom .options .register span:nth-child(1) {
color: #8C8C8C;
}
//学生注册
.bottom .row-register {
background-color: transparent;
border: none;
padding: 0;
margin:0;
font-size: 1.1em;
box-sizing: border-box;
border-bottom: 1px solid transparent;
cursor: pointer;
}
.bottom .row-register{
border-bottom: 1px solid #ffffff;
}
</style>
由于在config文件夹下index.js文件下创建"api",代替target里面的地址(后台请求),后面组件中我们掉接口时直接用api代替
关于矢量图图标的使用
引入JQuery依赖
cnpm install jquery --save