一、修改登录接口
1.将登录地址修改成本地 http://localhost:8001
在config下的dev.env.js下
2.实现模拟登录
进行登录调用2个方法,login登录操作方法和info登录之后获取用户的方法。
(1)login返回token值 (2)info返回 roles name avatar
3.根据前端需要编写后端代码
创建一个新的controller
编写内容
/**登录接口*/
@PostMapping("login")
public R login(){
return R.ok().data("token", "admin");
}
/**获取登录用户信息*/
@GetMapping("info")
public R info(){
return R.ok().data("roles", "admin").data("name", "admin").data("avatar", "https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fnimg.ws.126.net%2F%3Furl%3Dhttp%253A%252F%252Fdingyue.ws.126.net%252F2021%252F0820%252F0142054dp00qy3hyz0019d200u0015dg00u0015d.png%26thumbnail%3D650x2147483647%26quality%3D80%26type%3Djpg&refer=http%3A%2F%2Fnimg.ws.126.net&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=jpeg?sec=1634440222&t=bfa361b71f6a6a988859a0c3dfda7a2c");
}
4.重启前端 nmp run dev
出现跨域问题
1.出现跨域的原因
通过一个地址去访问另一个地址,这个过程中有3个地方有任意一处不一样则会出现跨域问题
访问协议 | http | https |
ip地址 | 192.168.1.1 | 172.11.11.1 |
端口号 | 9528 | 8001 |
以我们的前后端地址为例
前端:
后端:
前后端端口明显不一样!!!!
2.跨域的解决方式
1.在controller中加上@CrossOrigin注解进行解决
2.使用网关解决(后边讲到)
登录成功
如果图片不出来,打开控制台看到报错403,百度了一下好像该图片设置了防盗。去其他地方找图片即可,一般带了水印都是没有设置防盗的
二.前端框架开发过程
1.框架使用过程
1.添加路由
2.点击某个路由,显示对应的界面
3.在api文件夹下边创建一个js文件,定义接口参数,地址
4.在创建的vue页面引入js文件,调用方法实现
2.讲师列表前端实现
1.添加路由
在router下的js文件中constantRouterMap标题内添加一段代码
{
path: '/teacher',
component: Layout,
redirect: '/teacher/table',
name: '讲师管理',
meta: { title: '讲师管理', icon: 'example' },
children: [
{
path: 'table',
name: '讲师列表',
component: () => import('@/views/table/index'),
meta: { title: '讲师列表', icon: 'table' }
},
{
path: 'save',
name: '添加讲师',
component: () => import('@/views/tree/index'),
meta: { title: '添加讲师', icon: 'tree' }
}
]
},
2.创建路由相对于的页面
在view文件夹下边新建edu文件夹在里边在创建teacher文件夹,在teacher文件夹里边创建一个list.vue跟save.vue文件
最后修改路由里边的路径
3.编写测试跳转内容分别在list.vue跟save.vue文件中编写测试内容
<template>
<div class="app-app-container">
讲师列表
</div>
</template>
4.在api文件下创建一个teacher.js文件
import request from '@/utils/request'
export default{
getTeacherList(current,limit,teacherQuery){
//1 讲师列表(条件查询待分页)
return request({
// url: '/teacher/pageTeacherCondition/'+current+"/"+limit, //第一种写法
url: `/teacher/pageTeacherCondition/${current}/${limit}`,
method: 'post',
//teacherQuery条件对象,后端使用@RequestBody获取数据
//data表示把对象转换成json进行传递到接口里边
data: teacherQuery
})
}
}
5.在讲师列表页面list.vue页面调用定义方法接口,得到返回数据
<template>
<div class="app-app-container">
讲师列表
</div>
</template>
<script>
//引用teacher.js文件
import teacher from "@/api/teacher.js"
export default {
//核心代码位置
// data:{
// },
data(){ //定义变量跟初始值
return{
list:null,//查询之后接口返回集合
page:1, //当前页
limit:10, //每页显示的数据
total:0,//总记录数
teacherQuery:{} //条件封装对象
}
},
created(){//在页面渲染之前执行,一般调用methods里边的方法
//调用
this.getList()
},
methods:{//创建具体方法,调用teacher.js定义的方法
//讲师列表方法
getList(){
teacher.getTeacherList(this.page,this.limit,this.teacherQuery)
.then(response=>{//请求成功
//response请求回来的数据
console.log(response)
})
.catch(error=>{//请求失败
console.log(error)
})
}
}
}
</script>
后端代码,可能与前边的不一样导致数据出不来。已该代码为准
//4.条件查询带分页方法
@ApiOperation("条件查询带分页方法")
@PostMapping("pageTeacherCondition/{current}/{limit}")
public R pageTeacherCondition(@PathVariable Long current,@PathVariable Long limit,
@RequestBody(required = false) TeacherQuery teacherQuery){
String name = teacherQuery.getName();
Integer level = teacherQuery.getLevel();
String begin = teacherQuery.getBegin();
String end = teacherQuery.getEnd();
Page<EduTeacher> pageList = new Page<>(current, limit);
QueryWrapper<EduTeacher> wrapper = new QueryWrapper<>();
//判断条件值是否为空,如果不为空,拼接条件
//判断是否有传入教师名
if (!StringUtils.isEmpty(name)){
//构建条件
wrapper.like("name",name);//参数1:数据库字段名; 参数2:模糊查询的值
}
//判断是否传入教师头衔
if (level!=null){
//构造条件
wrapper.eq("level",level);
}
if (!StringUtils.isEmpty(begin)){
//构造条件
wrapper.ge("gmt_create",begin);//ge:大于等于
}
if (!StringUtils.isEmpty(begin)){
//构造条件
wrapper.le("gmt_modified",end);//le:小于等于
}
IPage<EduTeacher> teacherPageList = eduTeacherService.page(pageList,wrapper);
List<EduTeacher> records = teacherPageList.getRecords();
long total = teacherPageList.getTotal();
Map<String,Object> data = new HashMap<>();
data.put("tatol", total);
data.put("rows", records);
return R.ok().data(data);
}
请求得到数据
6.把请求接口的数据在页面中进行展示,使用组件element-ui实现
在list.vue下的<template>标签及<div>标签内粘贴
<!-- 表 格 -->
<el-table
v-loading="listLoading"
:data="list"
element-loading-text="数据加载中" border
fit
highlight-current-row>
<el-table-column label=" 序 号 " width="70" align="center">
<template slot-scope="scope">
{{ (page - 1) * limit + scope.$index + 1 }}
</template>
</el-table-column>
<el-table-column prop="name" label="名称" width="80" />
<el-table-column label="头衔" width="80">
<template slot-scope="scope">
{{ scope.row.level===1?'普通讲师' : scope.row.level===2?'高级讲师':'超级讲师' }}
</template>
</el-table-column>
<el-table-column prop="intro" label="资历" />
<el-table-column prop="gmtCreate" label="添加时间" width="160"/>
<el-table-column prop="sort" label="排序" width="60" />
<el-table-column label="操作" width="200" align="center">
<template slot-scope="scope">
<router-link :to="'/edu/teacher/edit/'+scope.row.id">
<el-button type="primary" size="mini" icon="el-icon-edit">修改</el-button>
</router-link>
<el-button type="danger" size="mini" icon="el-icon-delete" @click="removeDataById(scope.row.id)">删除</el-button>
</template>
</el-table-column>
</el-table>
效果
7.分页组件
<!-- 分 页 -->
<el-pagination
:current-page="page"
:page-size="limit"
:total="total"
style="padding: 30px 0; text-align: center;" layout="total, prev, pager, next, jumper" @current-change="getList"
/>
8、顶部查询表单
注意:
element-ui的 date-picker组件默认绑定的时间值是默认世界标准时间,和中国时间差8小时设置 value-format="yyyy-MM-dd HH:mm:ss" 改变绑定的值
<!--查询表单-->
<el-form :inline="true" class="demo-form-inline">
<el-form-item>
<el-input v-model="teacherQuery.name" placeholder="讲师名"/>
</el-form-item>
<el-form-item>
<el-select v-model="teacherQuery.level" clearable placeholder="讲师头衔">
<el-option :value="1" label="普通讲师"/>
<el-option :value="2" label="高级讲师"/>
<el-option :value="3" label="超级讲师"/>
</el-select>
</el-form-item>
<el-form-item label="添加时间">
<el-date-picker
v-model="teacherQuery.begin" type="datetime"
placeholder="选择开始时间"
value-format="yyyy-MM-dd HH:mm:ss"
default-time="00:00:00"
/>
</el-form-item>
<el-form-item>
<el-date-picker
v-model="teacherQuery.end" type="datetime"
placeholder="选择截止时间"
value-format="yyyy-MM-dd HH:mm:ss"
default-time="00:00:00"
/>
</el-form-item>
<el-button type="primary" icon="el-icon-search" @click="getList()">查询</el-button>
<el-button type="default" @click="resetData()">清空</el-button>
</el-form>
9、清空查询条件
resetData() {//清空的方法
//表单查询条件清空
this.teacherQuery = {}
//查询所有讲师数据
this.getList()
}
3.讲师删除功能
1.在每条记录后边添加一个删除按钮
上边的代码已添加
2.在按钮上绑定事件
3.在绑定事件方法上传递需要删除的讲师id值
4.在api文件teacher.js文件中定义删除的接口地址
deteleTeacherId(id){
//2 删除讲师方法
return request({
url: `/teacher/${id}`,
method: 'delete'
})
}
5.定义methods方法添加删除讲师方法
使用MessageBox 弹框组件增加用户体验
//删除讲师方法
removeDataById(id){
this.$confirm('此操作将永久删除该记录, 是否继续?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
})
.then(() => { //弹窗之后的执行方法
return teacher.deteleTeacherId(id)})
.then(() => { //执行deteleTeacherId(id)方法成功之后
//调用获取全部数据接口 刷新页面数据
this.getList()
//提示信息
this.$message({
type: 'success',
message: '删除成功!'})
})
.catch((response) => { // 失 败
if (response === 'cancel') {
this.$message({
type: 'info',
message: '已取消删除'})
} else {
this.$message({
type: 'error',
message: '删除失败'})
}
})
}
展示效果
4.讲师添加功能
1.定义api
src/api/edu/teacher.js
save(eduTeacher) {
return request({
url: `teacher/addTeacher`,
method: 'post',
data: eduTeacher
})
}
2.初始化组件
src/views/edu/teacher/save.vue
html部分
<template>
<div class="app-app-container">
添加讲师
<el-form label-width="120px">
<el-form-item label="讲师名称">
<el-input v-model="teacher.name"/>
</el-form-item>
<el-form-item label="讲师排序">
<el-input-number v-model="teacher.sort" controls-position="right" min="0"/>
</el-form-item>
<el-form-item label="讲师头衔">
<el-select v-model="teacher.level" clearable placeholder="请选择">
<!--
数据类型一定要和取出的json中的一致,否则没法回填
因此,这里value使用动态绑定的值,保证其数据类型是number
-->
<el-option :value="1" label="普通讲师"/>
<el-option :value="2" label="高级讲师"/>
<el-option :value="3" label="超级讲师"/>
</el-select>
</el-form-item>
<el-form-item label="讲师资历">
<el-input v-model="teacher.career"/>
</el-form-item>
<el-form-item label="讲师简介">
<el-input v-model="teacher.intro" :rows="10" type="textarea"/>
</el-form-item>
<!-- 讲师头像:TODO -->
<el-form-item>
<el-button :disabled="saveBtnDisabled" type="primary" @click="saveOrUpdate">保存</el-button>
</el-form-item>
</el-form>
</div>
</template>
js部分
<script>
export default {
data(){
return {
teacher: {
name: '',
sort: 0,
level: 1,
career: '',
intro: '',
avatar: ''
},
saveBtnDisabled: false // 保存按钮是否禁用,
}
},
created(){
},
methods:{
}
}
</script>
查看效果
3.在页面实现调用
saveOrUpdate(){
//添加讲师方法
this.saveTeacher()
},
//添加讲师方法
saveTeacher(){
teacherApi.addTeacher(this.teacher)
.then(response=>{//添加成功
//提示信息
this.$message({
type: 'success',
message: '添加成功!'
});
//回到列表页面 路由跳转
this.$router.push({path:'/teacher/table'})
})
}
5.讲师修改功能
1.在每条记录后边添加一个修改按钮
2.点击修改按钮 进入表单页面 进行数据回显
调用后端
该接口
3.通过路由跳转进入数据回显页面,在路由index.js页面添加路由
4.在表单页面实现数据回显
在teacher.js中定义根据id查询接口
getTeacherInfo(id) {
//根据id获取讲师信息
return request({
url: `teacher/getById/${id}`,
method: 'get'
})
}
5.在页面编写接口实现数据回显
6.调用根据id查询教师方法(较麻烦)
因为修改跟添加都是在同一个页面,需要区别是添加还是修改,只有修改的时候会调用数据回显接口
判断路径里边是否含有id值,有的话即是修改,没有就算添加
console.log('created')
//判断路由是否有id值
if (this.$route.params && this.$route.params.id) {
//从路径获取id值
const id = this.$route.params.id
//调用根据id获取讲师信息方法
this.getInfo(id)
7.在teacher.js中定义修改接口
updateTeacherInfo(teacher) {
//根据id修改讲师信息
return request({
url: `teacher/updateById`,
method: 'post',
data: teacher
})
}
8.在页面定义调用修改方法
//添加讲师方法
saveTeacher(){
teacherApi.addTeacher(this.teacher)
.then(response=>{//添加成功
//提示信息
this.$message({
type: 'success',
message: '添加成功!'
});
//回到列表页面 路由跳转
this.$router.push({path:'/teacher/table'})
})
}
saveOrUpdate(){
//判断是修改还是添加
//根据teacher是否有id
if(this.teacher.id){
//修改讲师方法
this.updateTeacher()
}else{
//添加讲师方法
this.saveTeacher()
}
},
//修改讲师的方法
updateTeacher(){
teacherApi.updateTeacherInfo(this.teacher)
.then(response=>{
//提示信息
this.$message({
type: 'success',
message: '修改成功!'
});
//回到列表页面 路由跳转
this.$router.push({path:'/teacher/table'})
})
},
5.路由切换问题及演示和解决
点击修改讲师的时候出现 该页面,但是在此点击添加讲师列表也是该页面。正常应该是添加讲师的页面。
1.在save.vue中添加判断代码
并没有清空,无法达到我们想要的效果
2.为什么该代码没有实现我们的需求
多次路由跳转到同一个页面,页面中的created方法只会执行第一次,后边在进行跳转的时候不会在执行
3.使用vue监听
在save.vue中将created中的判断方法抽取出来
保存去页面查看效果