赞
踩
1.安装node环境,npm,cli,这里不再赘述
2.在指定文件夹使用cmd指令创建项目:vue create springboot-vue-demo
3.选择Manually select features
4.选择路由和vuex,这里未选择了eslint语法检测[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传
5.选择3.x版本[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传
6.输入y (路由信息为history,)[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传
7.选择In package.json
8.是否保存配置
9.创建,启动项目
10.启动成功,浏览器输入8080端口进行访问
11.在idea打开项目,配置vue启动
选择npm,在npm中Script选项中输入serve
之后就可以点击启动键,快捷启动项目了
安装vue插件
1.引入Element-plus(基于vue3.x版本)
在idea终端输入指令引入Element-ui依赖
项目中引入Element-ui,main.js文件中引入Element-plus
2.删除HelloWorld组件,删除App.vue的多余部分
在components中创建Header组件 在App.js中引入
创建css文件夹,创建global.css文件,在main.js中引入全局css样式
在components中创建Aside(侧边栏),app.vue引入组件
Aside中引入emement导航栏样式
Home中引入四个区域 功能 搜索 表格 分页作为主体区域
3.项目目录
4.代码
global.css
*{
margin: 0;
padding: 0;
box-sizing: border-box;
}
Aside.vue
<template> <el-row class="tac"> <el-col :span="24"> <el-menu active-text-color="#ffd04b" background-color="#545c64" class="el-menu-vertical-demo" default-active="2" style="width: 200px;min-height:100vh" text-color="#fff" > <el-sub-menu index="1"> <template #title> <el-icon><location /></el-icon> <span>选项1</span> </template> <el-menu-item index="1-1"> <el-icon><setting /></el-icon> <span>选项1-1</span> </el-menu-item> </el-sub-menu> <el-sub-menu index="2"> <template #title> <el-icon><location /></el-icon> <span>选项2</span> </template> <el-menu-item index="2-1"> <el-icon><setting /></el-icon> <span>选项2-1</span> </el-menu-item> </el-sub-menu> <el-menu-item index="3"> <el-icon><icon-menu /></el-icon> <span>3</span> </el-menu-item> </el-menu> </el-col> </el-row> </template> <script> export default { name: "Aside" } </script> <style scoped> </style>
Header.vue
<template> <div style="height: 50px;line-height: 50px;border-bottom: 1px solid #ccc;display: flex"> <div style="width: 200px;font-weight: bold;padding-left: 20px;color: blue">后天管理</div> <div style="flex: 1"></div> <div style="width: 100px;margin-right: 20px;margin-top: 20px"> <el-dropdown> <span class="el-dropdown-link"> 张三 <el-icon class="el-icon--right"> <arrow-down/> </el-icon> </span> <template #dropdown> <el-dropdown-menu> <el-dropdown-item>个人信息</el-dropdown-item> <el-dropdown-item>退出系统</el-dropdown-item> </el-dropdown-menu> </template> </el-dropdown> </div> </div> </template> <script> export default { name: "Header" } </script> <style scoped> </style>
router/index.js
import { createRouter, createWebHistory } from 'vue-router' import HomeView from '../views/HomeView.vue' const routes = [ { path: '/', name: 'home', component: HomeView }, ] const router = createRouter({ history: createWebHistory(process.env.BASE_URL), routes }) export default router
store/index.js
import { createStore } from 'vuex'
export default createStore({
state: {
},
getters: {
},
mutations: {
},
actions: {
},
modules: {
}
})
HomeView.vue
<template> <div class="home" style="padding: 10px"> <!-- 功能区域--> <div style="margin: 10px 0"> <el-button type="primary">新增</el-button> <el-button type="primary">导入</el-button> <el-button type="primary">导出</el-button> </div> <!-- 搜索区域--> <div style="margin: 10px 0"> <el-input v-model="search" style="width: 20%;" placeholder="请输入关键字"></el-input> <el-button type="primary" style="margin-left: 5px">查询</el-button> </div> <!-- 表格区域--> <el-table :data="tableData" border stripe style="width: 100%"> <el-table-column prop="id" label="ID" sortable/> <el-table-column prop="username" label="用户名"/> <el-table-column prop="nickName" label="昵称"/> <el-table-column prop="age" label="年龄"/> <el-table-column prop="sex" label="性别"/> <el-table-column label="操作"> <template #default="scope"> <el-button size="small" @click="handleEdit(scope.$index, scope.row)" >编辑 </el-button> <el-popconfirm title="确定删除吗?"> <template #reference> <el-button size="small" type="danger" @click="handleDelete(scope.$index, scope.row)" >删除 </el-button> </template> </el-popconfirm> </template> </el-table-column> </el-table> <!-- 分页--> <div style="margin: 10px 0"> <el-pagination :currentPage="currentPage" :page-sizes="[5,10,20]" :page-size="pageSize" :small="small" :disabled="disabled" :background="background" layout="total, sizes, prev, pager, next, jumper" :total="total" @size-change="handleSizeChange" @current-change="handleCurrentChange" > </el-pagination> </div> </div> </template> <script> export default { name: 'HomeView', components: {}, data() { return { form:{}, dialogVisible: false, serch: '', currentPage: 1, pageSize:"10", total: 0, tableData: [ { id: '1', name: 'Tom', nickName: '189号', age: 18, sex: "男", }, { id: '1', name: 'Tom', nickName: '189号', age: 18, sex: "男", }, { id: '1', name: 'Tom', nickName: '189号', age: 18, sex: "男", }, { id: '1', name: 'Tom', nickName: '189号', age: 18, sex: "男", }, ] } }, methods: { handleEdit() { }, handleDelete() { }, handleSizeChange(){}, handleCurrentChange(){} } } </script>
App.vue
<template> <nav> <!--头部--> <Header></Header> <!--主题--> <div style="display: flex"> <!-- 侧边栏--> <Aside></Aside> <!--内容区域--> <router-view style="flex: 1;"></router-view> </div> </nav>1 </template> <script> import Header from "@/components/Header"; import Aside from "@/components/Aside"; export default { name: "App", components: { Header, Aside } } </script>
main.js
import { createApp } from 'vue'
import App from './App.vue'
import router from './router'
import store from './store'
import ElementPlus from 'element-plus'
import 'element-plus/dist/index.css'
import '@/assets/css/global.css'
import zhCn from 'element-plus/es/locale/lang/zh-cn'
createApp(App).use(store).use(router).use(ElementPlus, {locale: zhCn,}).mount('#app')
在项目名称右键new一个Moudule为springboot
在项目目录下新建vue文件夹 将原来vue的工程文件拷贝进去
重新配置serve,因为项目结构改变,要重新选择vue的package.json
修改项目的maven为自己的本地maven仓库
pom文件
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.6.4</version> <relativePath/> <!-- lookup parent from repository --> </parent> <groupId>com.example</groupId> <artifactId>lesson08</artifactId> <version>0.0.1-SNAPSHOT</version> <name>lesson08</name> <description>Demo project for Spring Boot</description> <properties> <java.version>1.8</java.version> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.mybatis.spring.boot</groupId> <artifactId>mybatis-spring-boot-starter</artifactId> <version>2.2.2</version> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <scope>runtime</scope> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> <dependency> <groupId>com.alibaba</groupId> <artifactId>druid-spring-boot-starter</artifactId> <version>1.1.21</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-actuator</artifactId> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> </project>
检验是否配置成功
如果报错则将vue文件夹的node_modules文件夹删除 再vue项目执行命令npm install
新的目录结构
springboot的resource目录下application.property文件修改为application.yml
输入配置(我这是mysql8版本 配置了druid数据库连接池)
server: port: 9090 spring: datasource: druid: url: jdbc:mysql://localhost:3306/springboot-vue username: root password: 123456 driver-class-name: com.mysql.cj.jdbc.Driver initialSize: 10 maxActive: 20 maxWait: 60000 minIdle: 1 timeBetweenEvictionRunsMillis: 60000 minEvictableIdleTimeMillis: 300000 testWhileIdle: true testOnBorrow: true testOnReturn: false poolPreparedStatements: true maxOpenPreparedStatements: 20 validationQuery: SELECT 1 validation-query-timeout: 500 filters: stat,wall stat-view-servlet: enabled: true url-pattern: /druid/* reset-enable: true login-username: admin login-password: 10197538 mybatis: mapper-locations: classpath:mapper/*.xml type-aliases-package: com.syb.po
启动mysql服务
再navicat里新建数据库
新建user表
点击启动,启动成功则配置完成
引入mybaties-plus pom文件添加依赖
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.4.3.1</version>
</dependency>
导入分页插件包
com.example.spring目录下创建mapper包
com.example.springboot包创建common包,创建MybatiesPlusCongif类
package com.example.springboot.common; import com.baomidou.mybatisplus.annotation.DbType; import com.baomidou.mybatisplus.autoconfigure.ConfigurationCustomizer; import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor; import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor; import org.mybatis.spring.annotation.MapperScan; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @Configuration @MapperScan("com.example.springboot.mapper") public class MybatisPlusConfig { /** * 新的分页插件,一缓和二缓遵循mybatis的规则,需要设置 MybatisConfiguration#useDeprecatedExecutor = false 避免缓存出现问题(该属性会在旧插件移除后一同移除) */ @Bean public MybatisPlusInterceptor mybatisPlusInterceptor() { MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor(); interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL)); return interceptor; } }
创建Result包包装返回类型工具类,新建Result
package com.example.springboot.common; public class Result<T> { private String code; private String msg; private T data; public String getCode() { return code; } public void setCode(String code) { this.code = code; } public String getMsg() { return msg; } public void setMsg(String msg) { this.msg = msg; } public T getData() { return data; } public void setData(T data) { this.data = data; } public Result() { } public Result(T data) { this.data = data; } public static Result success(){ Result result = new Result<>(); result.setCode("0"); result.setMsg("成功"); return result; } public static <T> Result<T> success(T data){ Result<T> result = new Result<>(data); result.setCode("0"); result.setMsg("成功"); return result; } public static Result error(String code,String msg){ Result result = new Result(); result.setCode(code); result.setMsg(msg); return result; } }
com.example.spring目录下新建controller包,新建UserController类
com.example.spring目录下新建entity包,新建User类
package com.example.springboot.entity; import com.baomidou.mybatisplus.annotation.IdType; import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableName; import lombok.Data; //数据库表名 @TableName("user") @Data public class User { // 设置ID自增长 @TableId(type = IdType.AUTO) private Integer id; private String username; private String password; private Integer age; private String sex; // private String address }
定义UserMapper接口,继承BaseMapper,传入的泛型为User
再UserConroller中使用@Resource注解引入UserMapper(这里为了简化没有创建service)
UserMapper:
package com.example.springboot.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.example.springboot.entity.User;
public interface UserMapper extends BaseMapper<User>
{
}
UserConroller:
package com.example.springboot.controller; import com.example.springboot.common.Result; import com.example.springboot.entity.User; import com.example.springboot.mapper.UserMapper; import org.springframework.web.bind.annotation.PatchMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import javax.annotation.Resource; //定义是返回json的controller @RestController //定义统一的路由 @RequestMapping("/user") public class UserController { //引入UserMaooer @Resource UserMapper userMapper; // 定义post接口 @PostMapping // 新增 RequestBody注解把前台传来的数据转换成java对象实体 public Result<?> save(@RequestBody User user) { //使用userMapper的insert方法新增user对象 userMapper.insert(user); return Result.success(); } }
1.在新增按钮中绑定add方法添加用户数据,点击后有弹窗提示
引入elementui Dialog 对话框组件,引入表单组件
点击新增按钮后弹出对话框,点击确认后使用axios将数据存入后台
add() { //打开弹窗 this.dialogVisible = true; //清空 this.form = {} }, //点击确认后保存到后台 save() { //使用axios进行数据交互 //两个参数,url和请求参数 /* 注意这样写会有跨域问题 request.post("/user",this.form).then(res => { console.log(res) }) request.post("http://localhost:9090/user",this.form).then(res => { console.log(res) }) */ //如果id存在 执行更新操作 否则执行新增操作 if (this.form.id) {//更新 request.put("/user", this.form).then(res => { console.log(res) //根据状态码判断 0为成功 这里用了elmentui 的提示框 if (res.code === '0') { this.$message({ type: "success", message: "更新成功" }) } else { this.$message({ type: "error", message: res.msg }) } }) } },
1.封装axios接口
安装axios依赖,在vue目录下执行npm i axios -S
在vue项目scr目录下新建utils文件夹,新建request.js文件,在request.js里引入axios,request.js用来请求数据
//引入axios包 import axios from 'axios' //创建request对象 const request = axios.create({ baseURL: '/api', // 注意!! 这里是全局统一加上了 '/api' 前缀,也就是说所有接口都会加上'/api'前缀在,页面里面写接口的时候就不要加 '/api'了,否则会出现2个'/api',类似 '/api/api/user'这样的报错,切记!!! timeout: 5000 }) // request 拦截器 // 可以自请求发送前对请求做一些处理 // 比如统一加token,对请求参数统一加密 request.interceptors.request.use(config => { //设置请求头 config.headers['Content-Type'] = 'application/json;charset=utf-8'; // config.headers['token'] = user.token; // 设置请求头 return config }, error => { return Promise.reject(error) }); // response 拦截器 // 可以在接口响应后统一处理结果 request.interceptors.response.use( response => { //获取返回结果的data let res = response.data; // 如果是返回的文件 if (response.config.responseType === 'blob') { return res } // 兼容服务端返回的字符串数据 if (typeof res === 'string') { res = res ? JSON.parse(res) : res } return res; }, error => { console.log('err' + error) // for debug return Promise.reject(error) } ) export default request
// 跨域配置
module.exports = {
devServer: { //记住,别写错了devServer//设置本地默认端口 选填
port: 9876,
proxy: { //设置代理,必须填
'/api': { //设置拦截器 拦截器格式 斜杠+拦截器名字,名字可以自己定
target: 'http://localhost:9090', //代理的目标地址
changeOrigin: true, //是否设置同源,输入是的
pathRewrite: { //路径重写
'^/api': '' //选择忽略拦截器里面的内容 把api解析为空字符串
}
}
}
}
}
HomeView.vue中的save方法使用request.post方法访问后台的接口
save(){
request.post("/user",this.form).then(res => {
console.log(res)
}
2.实现了添加功能,前台点击确认,数据库有数据。接下来要实现前台的数据渲染
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.7.3</version>
</dependency>
// 定义get接口 @GetMapping /** * @pageNum 当前页 默认为1 * @pageSize 分页大小 默认为10 * @search 查询关键字 默认为空字符串 */ public Result<?> findPage(@RequestParam(defaultValue = "1") Integer pageNum, @RequestParam(defaultValue = "10") Integer pageSize, @RequestParam(defaultValue = "") String search) { //Page是MybatiesPlus提供的类 //分页对象 Wrappers 条件构造器, 通过搜索框绑定的search值,在用户列表中拆模糊查询 LambdaQueryWrapper<User> wrapper = Wrappers.<User>lambdaQuery(); //当search为空时查询全部 if (StrUtil.isNotBlank(search)){ wrapper.like(User::getNickName,search); } Page<User> userPage = userMapper.selectPage(new Page<>(pageNum, pageSize), wrapper); return Result.success(userPage); }
HomeView.vue中定义load方法,加载后台数据。在生命周期created(页面加载完成后) 调用load方法,即可在前端拿到后台的数据。
在load().then()内将拿到对象的具体data赋值给tableData,即可将后台数据渲染至前端页面
HomeView.vue
//生命周期函数 created() { //调用load() this.load() }, methods: { load() { //传入三个参数 get请求不能传对象 request.get("/user", { params: { pageNum: this.currentPage, pageSize: this.pageSize, search: this.search } }).then(res => { this.tableData = res.data.records; //实现前端显示总条数 this.total = res.data.total; // console.log(res) }) },
1.查询
给查询按钮点击事件绑定load方法,点击按钮即可查询
<el-input v-model="search" @input="onInput" style="width: 20%;" clearable placeholder="请输入关键字" />
<el-button type="primary" @click="load" style="margin-left: 5px">查询</el-button>
//注意我这里遇到了el-input输入框无法实时刷新的问题,在网上寻找后发现这应该是element-ui的一个bug,解决方案是:在el-input标签绑定@input事件 @input="onInput"
定义事件
onInput(){
this.$forceUpdate();
}
2.编辑功能
点击编辑按钮,出现弹窗,并且弹窗里有原本的数据
为了避免点击取消后数据依然会有变化,这里选择深拷贝
现在在弹窗点击确定时,后台会报错,因为之前post只有一个新增方法,数据的主键ID重复,所以会报错,这里我们需要改写之前的save方法,并在UserController新增一个update方法
编辑按钮绑定handleEdit方法
<el-button size="small" @click="handleEdit(scope.row)">编辑</el-button>
handleEdit(row) {
this.form = JSON.parse(JSON.stringify(row));
this.dialogVisible = true
},
改写save方法
save() { //使用axios进行数据交互 //两个参数,url和请求参数 /* 注意这样写会有跨域问题 request.post("/user",this.form).then(res => { console.log(res) }) request.post("http://localhost:9090/user",this.form).then(res => { console.log(res) }) */ //如果id存在 执行更新操作 否则执行新增操作 if (this.form.id) {//更新 request.put("/user", this.form).then(res => { console.log(res) //根据状态码判断 0为成功 这里用了elmentui 的提示框 if (res.code === '0') { this.$message({ type: "success", message: "更新成功" }) } else { this.$message({ type: "error", message: res.msg }) } this.load()//刷新表格数据 this.dialogVisible = false //关闭弹窗 }) } else {//新增 request.post("/user", this.form).then(res => { console.log(res) if (res.code === '0'){ this.$message({ type: "success", message:"新增成功" }) }else { this.$message({ type: "error", message:res.msg }) } this.load()//刷新表格数据 this.dialogVisible = false //关闭弹窗 }) } },
UserController添加update方法
// 一般put进行更新
@PutMapping
public Result<?> update(@RequestBody User user)
{
userMapper.updateById(user);
return Result.success();
}
3.删除:
确认删除按钮,confirm事件绑定handleDelete方法,根据主键id删除
<el-popconfirm title="确定删除吗?" @confirm="handleDelete(scope.row.id)">
<template #reference>
<el-button
size="small"
type="danger"
>删除</el-button>
</template>
</el-popconfirm>
拿到id后,在后台写一个删除接口
UserController
//占位符方式传入参数id 必须用@PathVariable接收
@DeleteMapping("/{id}")
public Result<?> delete(@PathVariable Long id)
{
userMapper.deleteById(id);
return Result.success();
}
分页功能:
HomeView中有两个方法:
handleSizeChange(),改变当前每页个数触发和handleCurrentChange(),改变当前页数触发
handleSizeChange(pageSize) {
this.pageSize = pageSize
this.load();
},
handleCurrentChange(currentPage) {
this.currentPage = currentPage
this.load();
}
因为之前实在App.vue作为页面的框架,所有的页面都是在App.vue里,App在main.js作为根节点,因此应该将App.vue作为访问所有界面的结点,根据具体的路由进行页面展示
重构App.vue
<template>
<div>
<router-view></router-view>
</div>
</template>
<script>
export default {
name: "App",
components: {}
}
</script>
在src目录下新建目录Layout,新建Layout.vue作为框架页面
<template> <div> <!--头部--> <Header></Header> <!--主题--> <div style="display: flex"> <!-- 侧边栏--> <Aside></Aside> <!--内容区域--> <router-view style="flex: 1;"></router-view> </div> </div> </template> <script> import Header from "@/components/Header"; import Aside from "@/components/Aside"; export default { name: "Layout", components:{ Header, Aside } } </script> <style scoped> </style>
修改HomeView.vue为Home.vue
配置路由
router/index.js
import { createRouter, createWebHistory } from 'vue-router' import Layout from '../Layout/Layout.vue' import Login from '../views/Login.vue' const routes = [ { //默认路由地址为Layout path: '/', name: 'Layout', component: Layout, //重定向设置路由跳转,当访问'/'时自动跳转到'/home' redirect:"/home", //嵌套子路由 主体区域展示 children:[ { path:"home", name:"Home", component:() => import("@/views/Home") } ] }, { path: '/login', name: 'Login', component: () => import("@/views/Login") }, ] const router = createRouter({ history: createWebHistory(process.env.BASE_URL), routes }) export default router
编写登陆页面
vies/Login.vue
<template> <div style="width: 100%;height: 100vh;overflow:hidden ;background-color: darkcyan;"> <div style="width: 400px;margin: 150px auto"> <div style="color:#cccccc; padding: 30px 0; font-size: 30px;text-align: center">欢迎登陆</div> <el-form ref="formRef" :model="form" size="normal" :rules="rules"> <el-form-item prop="username"> <el-input placeholder="请输入用户名" v-model="form.username"></el-input> </el-form-item> <el-form-item prop="password"> <el-input placeholder="请输入密码" v-model="form.password" style=""></el-input> </el-form-item> <el-form-item> <el-button style="width: 100%;" @click="login" type="primary">登录</el-button> </el-form-item> <el-form-item> <el-button style="width: 100%;" @click="toRegister" type="primary">注册</el-button> </el-form-item> </el-form> </div> </div> </template> <script> import request from "@/utils/request"; export default { name: "Login", components: {}, data() { return { form: {}, rules: { username: [ { required: true, message: '请输入用户名', trigger: 'blur', }, ], password: [ { required: true, message: '请输入密码', trigger: 'blur', }, ], } } }, methods: { toRegister(){ this.$router.push("/login") }, login() { //满足校验规则才传给后台数据 this.$refs['formRef'].validate((valid) => { if (valid) { //将登录信息传给后台 request.post("/user/login", this.form).then(res => { if (res.code === '0') { this.$message({ type: "success", message: "登陆成功" }) //登陆成功后将用户信息存到sessionStorage sessionStorage.setItem("user",JSON.stringify(res.data)) this.$router.push("/") //登录成功后进行页面跳转 跳转到主页 } else { this.$message({ type: "error", message: res.msg }) } }) } }) } } } </script> <style scoped> </style>
UserCOntroller添加登录接口
//登录接口
@PostMapping("/login")
public Result<?> login(@RequestBody User user)
{
User res = userMapper.selectOne(Wrappers.<User>lambdaQuery().eq(User::getUsername,user.getUsername()).eq(User::getPassword,user.getPassword()));
//判断查询是否存在
if (res == null){
return Result.error("-1","用户名或密码错误");
}
return Result.success(res);
}
登陆后点击退出系统,重新返回登录界面
在Header.vue的添加路由跳转
<el-dropdown-menu>
<el-dropdown-item>个人信息</el-dropdown-item>
<el-dropdown-item @click="$router.push('/login')">退出系统</el-dropdown-item>
</el-dropdown-menu>
注册界面
在views目录下新建Register.vue
<template> <div style="width: 100%;height: 100vh;overflow:hidden ;background-color: darkcyan;"> <div style="width: 400px;margin: 150px auto"> <div style="color:#cccccc; padding: 30px 0; font-size: 30px;text-align: center">欢迎注册</div> <el-form ref="formRef" :model="form" size="normal" :rules="rules"> <el-form-item prop="username"> <el-input placeholder="请输入用户名" v-model="form.username"></el-input> </el-form-item> <el-form-item prop="password"> <el-input placeholder="请输入密码" v-model="form.password" style=""></el-input> </el-form-item> <el-form-item prop="confirm"> <el-input placeholder="确认密码" v-model="form.confirm" style=""></el-input> </el-form-item> <el-form-item> <el-button style="width: 100%;" @click="register" type="primary">注册</el-button> </el-form-item> <el-form-item> <el-button style="width: 100%;" @click="toLogin" type="primary">已有帐号</el-button> </el-form-item> </el-form> </div> </div> </template> <script> import request from "@/utils/request"; export default { name: "Register", components: {}, data() { return { form: {}, //表单校验规则 rules: { username: [ { required: true, message: '请输入用户名', trigger: 'blur', }, ], password: [ { required: true, message: '请输入密码', trigger: 'blur', }, ], confirm: [ { required: true, message: '请确认密码', trigger: 'blur', }, ], } } }, methods: { toLogin(){ this.$router.push("/login") }, register() { //判断两次密码是否一致 if (this.form.password !== this.form.confirm) { this.$message({ type: "error", message: "2次密码输入不一致!" }) return } //满足校验规则才传给后台数据 this.$refs['formRef'].validate((valid) => { if (valid) { //将登录信息传给后台 request.post("/user/register", this.form).then(res => { if (res.code === '0') { this.$message({ type: "success", message: "注册成功" }) this.$router.push("/login") //Register成功后进行页面跳转 跳转到登录 } else { this.$message({ type: "error", message: res.msg }) } }) } }) } } } </script> <style scoped> </style>
router/index.js新增路由
{
path: '/register',
name: 'Register',
component: () => import("@/views/Register")
},
UserController新增注册接口
//注册接口 @PostMapping("/register") public Result<?> register(@RequestBody User user) { //注册之前先验证是否有重名 User res = userMapper.selectOne(Wrappers.<User>lambdaQuery().eq(User::getUsername,user.getUsername())); //判断查询是否存在 if (res != null){ return Result.error("-1","用户名重复!"); } //默认密码 if(user.getPassword() == null){ user.setPassword("123456"); } userMapper.insert(user); return Result.success(); }
我们发现默认打开的是用户界面,因此Home.vue命名不太合适
更名为User.vue,同时将router/index.js中的home都改为user
在Aside.vue的el-menu标签里写入router,可以直接根据el-menu-item的index进行路由跳转
为了实现效果,在views下新建Book.vue,同时写入路由
<template>
<div>
我是book
</div>
</template>
<script>
export default {
name: "book"
}
</script>
<style scoped>
</style>
import { createRouter, createWebHistory } from 'vue-router' import Layout from '../Layout/Layout.vue' import Login from '../views/Login.vue' const routes = [ { //默认路由地址为Layout path: '/', name: 'Layout', component: Layout, //重定向设置路由跳转,当访问'/'时自动跳转到'/home' redirect:"/user", //嵌套子路由 主体区域展示 children:[ { path:"user", name:"User", component:() => import("@/views/User") }, { path:"book", name:"Book", component:() => import("@/views/Book") }, ] }, { path: '/login', name: 'Login', component: () => import("@/views/Login") }, { path: '/register', name: 'Register', component: () => import("@/views/Register") }, ] const router = createRouter({ history: createWebHistory(process.env.BASE_URL), routes }) export default router
点击菜单栏可以发现实现了路由的跳转
这里有一个bug,每次重新进入项目都会自动进去user,无论我们有没有登录。因此我们可以在request.js里设置拦截器,登陆成功则将用户信息存储在sessionStorage中命名为user变量,若sessionStoragem没有用户信息,则重启项目强制跳转到登陆界面
request.js
//引入axios包 import axios from 'axios' import router from "@/router"; //创建request对象 const request = axios.create({ baseURL: '/api', // 注意!! 这里是全局统一加上了 '/api' 前缀,也就是说所有接口都会加上'/api'前缀在,页面里面写接口的时候就不要加 '/api'了,否则会出现2个'/api',类似 '/api/api/user'这样的报错,切记!!! timeout: 5000 }) // request 拦截器 // 可以自请求发送前对请求做一些处理 // 比如统一加token,对请求参数统一加密 request.interceptors.request.use(config => { config.headers['Content-Type'] = 'application/json;charset=utf-8'; // config.headers['token'] = user.token; // 设置请求头 //取出sessionStorage里面的缓存的用户信息 let userJson = sessionStorage.getItem("user"); if (!userJson){ //如果没有该用户信息则跳转到登陆页面 router.push("login") } return config }, error => { return Promise.reject(error) }); // response 拦截器 // 可以在接口响应后统一处理结果 request.interceptors.response.use( response => { //获取返回结果的data let res = response.data; // 如果是返回的文件 if (response.config.responseType === 'blob') { return res } // 兼容服务端返回的字符串数据 if (typeof res === 'string') { res = res ? JSON.parse(res) : res } return res; }, error => { console.log('err' + error) // for debug return Promise.reject(error) } ) export default request
可以看到,登陆成功后,sessionStorage存储了用户信息
有了sessionStorage对象,我们可以页面右上角的用户实时更新为用户名
在Header.vue添加数据user:JSON.parse(sessionStorage.getItem(“user”))(这里是将JSON字符串转化为JSON对象),
<template> <div style="height: 50px;line-height: 50px;border-bottom: 1px solid #ccc;display: flex"> <div style="width: 200px;font-weight: bold;padding-left: 20px;color: blue">后台管理</div> <div style="flex: 1"></div> <div style="width: 100px;margin-right: 20px;margin-top: 20px"> <el-dropdown> <span class="el-dropdown-link"> <!--绑定user的username属性--> 管理员:{{ user.username }} <el-icon class="el-icon--right"> <arrow-down/> </el-icon> </span> <template #dropdown> <el-dropdown-menu> <el-dropdown-item @click="$router.push('/person')">个人信息</el-dropdown-item> <el-dropdown-item @click="$router.push('/login')">退出系统</el-dropdown-item> </el-dropdown-menu> </template> </el-dropdown> </div> </div> </template> <script> export default { name: "Header", data() { return { //注意这里是将JSON字符串转化为JSON对象 m user: sessionStorage.getItem("user")?JSON.parse(sessionStorage.getItem("user")):"" } } } </script> <style scoped> </style>
我们新建Person.vue
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。