300字范文,内容丰富有趣,生活中的好帮手!
300字范文 > springboot+vue练手小项目[前台搭建+后台编写](非常详细)

springboot+vue练手小项目[前台搭建+后台编写](非常详细)

时间:2019-08-29 01:41:31

相关推荐

springboot+vue练手小项目[前台搭建+后台编写](非常详细)

[ springboot+vue练手小项目 ]

技术栈:springboot+vue3+element-plus +Mybaties-plus+hutool

+mysql8项目介绍:最近刚学了springboot+vue,就想着做一个小的前后端分离的练手项目,简单的后台管理页面,有基本的登陆注册+增删改查,后面具体的模块等需要的时候的再进行完善,这只是一个练手项目,如果大家运行不出来或者有疑问,欢迎交流。我是个菜鸟,也不太会写文章,若有不足欢迎指正。

1.环境搭建

1.安装node环境,npm,cli,这里不再赘述

2.在指定文件夹使用cmd指令创建项目:vue create springboot-vue-demo

3.选择Manually select features

4.选择路由和vuex,这里未选择了eslint语法检测[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

5.选择3.x版本[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传![(img-H4bjGfpT-1647170194103)(C:UserserhangAppDataRoamingTypora ypora-user-imagesimage-0309152419903.png)]](https://img-/01313a7a07824b64820fb1c22a09aa4f.png)

6.输入y (路由信息为history,)[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传![(img-K8XKVnNm-1647170194104)(C:UserserhangAppDataRoamingTypora ypora-user-imagesimage-0309152546319.png)]](https://img-/616317c8beea4a0fa731a390d18c8dbc.png)

7.选择In package.json

8.是否保存配置

9.创建,启动项目

10.启动成功,浏览器输入8080端口进行访问

11.在idea打开项目,配置vue启动

选择npm,在npm中Script选项中输入serve

之后就可以点击启动键,快捷启动项目了

安装vue插件

2.项目基本布局

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-menuactive-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-buttonsize="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')

3.后台编写

在项目名称右键new一个Moudule为springboot

在项目目录下新建vue文件夹 将原来vue的工程文件拷贝进去

重新配置serve,因为项目结构改变,要重新选择vue的package.json

修改项目的maven为自己的本地maven仓库

pom文件

<?xml version="1.0" encoding="UTF-8"?><project xmlns="/POM/4.0.0" xmlns:xsi="/2001/XMLSchema-instance"xsi:schemaLocation="/POM/4.0.0 /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: 9090spring:datasource:druid:url: jdbc:mysql://localhost:3306/springboot-vueusername: rootpassword: 123456driver-class-name: com.mysql.cj.jdbc.DriverinitialSize: 10maxActive: 20maxWait: 60000minIdle: 1timeBetweenEvictionRunsMillis: 60000minEvictableIdleTimeMillis: 300000testWhileIdle: truetestOnBorrow: truetestOnReturn: falsepoolPreparedStatements: truemaxOpenPreparedStatements: 20validationQuery: SELECT 1validation-query-timeout: 500filters: stat,wallstat-view-servlet:enabled: trueurl-pattern: /druid/*reset-enable: truelogin-username: adminlogin-password: 10197538mybatis:mapper-locations: classpath:mapper/*.xmltype-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.mon;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 避免缓存出现问题(该属性会在旧插件移除后一同移除)*/@Beanpublic MybatisPlusInterceptor mybatisPlusInterceptor() {MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));return interceptor;}}

创建Result包包装返回类型工具类,新建Result

package com.mon;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")@Datapublic 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.mon.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@ResourceUserMapper userMapper;// 定义post接口@PostMapping// 新增 RequestBody注解把前台传来的数据转换成java对象实体public Result<?> save(@RequestBody User user){//使用userMapper的insert方法新增user对象userMapper.insert(user);return Result.success();}}

4.前台业务完善

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})}})}},

5.前后台数据交互

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

解决跨域问题,vue文件夹下新建vue.config.js文件,重启项目(这里将端口设置为9876)

// 跨域配置

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.实现了添加功能,前台点击确认,数据库有数据。接下来要实现前台的数据渲染

导入hutool工具类,引入依赖

cn.hutool hutool-all 5.7.3

在UserController中新增findpage方法

// 定义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);}

将查到的数据在渲染到前端tableData变量中

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)})},

6.crud

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进行更新@PutMappingpublic 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-buttonsize="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 = pageSizethis.load();},handleCurrentChange(currentPage) {this.currentPage = currentPagethis.load();}

7.登陆注册

因为之前实在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 = [{//默认路由地址为Layoutpath: '/',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: "登陆成功"})//登陆成功后将用户信息存到sessionStoragesessionStorage.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();}

8.项目路由

我们发现默认打开的是用户界面,因此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 = [{//默认路由地址为Layoutpath: '/',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 => {//获取返回结果的datalet 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 debugreturn 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对象 muser: sessionStorage.getItem("user")?JSON.parse(sessionStorage.getItem("user")):""}}}</script><style scoped></style>

我们新建Person.vue

运行项目

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。