文章目录
- 项目框架的搭建
- 1.1 后台框架:
- 1.2 前端框架:
- 跨域处理:
- rules读表单字段进行验证
- ref
- 挂在路由导航守卫:
- 侧边导航栏
- 获取用户列表
- 分页的后台写法:
- 分页前台的写法
- 删除用户的数据
- 更新数据
- 增添用户的信息
- 查询数据
项目框架的搭建
1.1 后台框架:
后台框架用springBoot来做,前端框架用Vue
springBoot用idea开发
项目结构是:
- application.yml
# mysql
spring:
datasource:
#MySQL配置
driverClassName: com.mysql.jdbc.Driver
url: jdbc:mysql://localhost:3306/spot_vue?useUnicode=true&characterEncoding=UTF-8&useSSL=false&serverTimezone=UTC
username: root
password: tiger
mybatis:
mapper-locations: classpath:mapper/*.xml //mapper映射文件
type-aliases-package: com.example.demo.model
server:
port: 9000 //启用的端口,因为vue需要用到8080所以需要修改一下
- 设置跨域请求的方法:
package com.tjk.spotplay_vue.util;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
@Configuration /* (表示该类是全局配置类--配置跨域请求)*/
public class WebConfig extends WebMvcConfigurerAdapter {
/*@CrossOrigin (用来进行跨域请求的)*/
@Override
public void addCorsMappings(CorsRegistry registry) {
/**
* 1.域访问路径
* 2.请求来源
* 3.方法
* 4.最大响应时间
* 5.允许携带
*/
registry.addMapping("/**")
.allowedOrigins("http://localhost:8080", "null")//设置响应响应源
.allowedMethods("POST", "GET", "PUT", "OPTIONS", "DELETE")//设置响应的方法
.maxAge(3600)//设置最大响应实践
.allowCredentials(true);//设置是否可以带数据
}
}
MapperScan:(后面跟dao包)
扫描dao层的接口,将所有的接口变成实现类
@Repository
它用于将数据访问层 (DAO 层 ) 的类标识为 Spring Bean。
@RestController:
注解相当于@ResponseBody + @Controller合在一起的作用。
RequestMapping:
这个注解会将 HTTP 请求映射到 MVC 和 REST 控制器的处理方法上。是用来标记访问路径的
- pom.xml
<?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.4.0</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.tjk</groupId>
<artifactId>spotplay_vue</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>spotplay_vue</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<!-- springboot和mybatis-->
<dependency>
<groupId>org.mybatis.generator</groupId>
<artifactId>mybatis-generator-core</artifactId>
<version>1.3.5</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<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.1.4</version>
</dependency>
<!-- <dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>-->
<!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.8</version>
</dependency>
<!-- https://mvnrepository.com/artifact/com.alibaba/fastjson -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.28</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
1.2 前端框架:
前端框架用vue来实现
用 vue的官方ui来进行项目的初始化管理:
cmd 中切换到要存放vue项目的目录下,输入 vue ui
配置vue的初始化组件
项目结构:
- main.js
注意:所有的js和css引入从main.js引入则全局均可使用
import Vue from 'vue'
import App from './App.vue'
import router from './router'
import './plugins/element.js'
import './assets/css/global.css' // 添加全局样式
import './assets/font/iconfont.css'//引入iconfont
import axios from 'axios'//导入axios进行跨域请求
Vue.prototype.$http=axios //挂载axios在http上进行跨域操作
//设置访问根路径
axios.defaults.baseURL='http://localhost:9000'
Vue.config.productionTip = false
new Vue({
router,
render: h => h(App)
}).$mount('#app')
跨域处理:
在main.js中引入axios
import axios from 'axios'//导入axios进行跨域请求 Vue.prototype.$http=axios //挂载axios在http上进行跨域操作 //设置访问根路径 axios.defaults.baseURL='http://localhost:9000' 这里是后端项目的请求端口
rules读表单字段进行验证
ref
ref是为了给dom元素进行注册
挂在路由导航守卫:
vue-router
提供的导航守卫主要用来通过跳转或取消的方式守卫导航。(在路由跳转时触发)
我们主要介绍的是可以验证用户登录状态的全局前置守卫,当一个导航触发时,全局前置守卫按照创建顺序调用。守卫是异步解析执行,此时导航在所有守卫 resolve 完之前一直处于等待中。
-
to: 即将要进入的目标路由对象
-
from: 当前导航正要离开的路由
-
next: Function: 一定要调用该方法来 resolve 这个钩子。执行效果依赖 next 方法的调用参数。
-
next(): 进行管道中的下一个钩子。如果全部钩子执行完了,则导航的状态就是 confirmed (确认的)。
-
next(false): 中断当前的导航。如果浏览器的 URL 改变了 (可能是用户手动或者浏览器后退按钮),那么 URL 地址会重置到 from 路由对应的地址。
-
next(’/’) 或者 next({ path: ‘/’ }): 跳转到一个不同的地址。当前的导航被中断,然后进行一个新的导航
-
next(error): (2.4.0+) 如果传入 next 的参数是一个 Error 实例,则导航会被终止且该错误会被传递给 router.onError() 注册过的回调。
注意:一定要确保要调用 next 方法,否则钩子就不会被 resolved。
// //挂在路由导航守卫
router.beforeEach((to,form,next)=>{
//to将要访问
//form从那访问
//next接着干next(url)重定向到url next()空的话继续访问 to的路径
if(to.path=='/login'){
return next ();
}
//获取user
const userflag=window.sessionStorage.getItem("user"); //取出当前用户
if(!userflag){
return next('/login'); //无值,返回登录页
}
next();
});
:router="true"
:是否使用 vue-router 的模式,启用该模式会在激活导航时以 index 作为 path 进行路由跳转
侧边导航栏
- 前端 element
<template>
<!-- 引入container布局 -->
<el-container class="home-container">
<el-header class="el-header">
<div>
<img src="..\assets\logotjk.jpg" alt="" >
<span >个人运动平台</span>
</div>
<el-button type="info" @click="login_out">安全退出</el-button>
</el-header>
<!-- 主体 -->
<el-container >
<!-- 侧边栏 -->
<el-aside class="el-aside " :width="isCollapse?'64px':'200px'" >
<div class="toggle-button" @click="toggleCollapase()">|||</div>
<el-menu default-active="2" class="el-menu-vertical-demo celanbuqi" style="border-right:none ;" background-color="#545c64" text-color="#fff" active-text-color="#409eff"
unique-oppened :collapse="isCollapse" :collapse-transition="false" :router="true" :default-active="activePath">
<!-- //collapse控制是否折叠
是否使用 vue-router 的模式,
启用该模式会在激活导航时以
index 作为 path 进行路由跳转-->
<!-- 一级菜单 -->
<el-submenu :index="item.path" v-for="item in menuList" :key="item.id" style="background-color: rgb(110, 107, 107);">
<template slot="title">
<i :class="icon_page[item.id]"></i>
<span>{{item.title}}</span>
</template>
<!-- 二级菜单 -->
<el-menu-item :index="it.path" v-for="it in item.slist" :key="it.id" @click="saveNavState(it.path)">
<template slot="title">
<i :class="icon_page[it.id]"></i>
<span>{{it.title}}</span>
</template>
</el-menu-item>
</el-submenu>
</el-menu>
</el-col>
</el-row>
</el-aside>
<!-- 主体内容-->
<el-container>
<el-main>
<router-view></router-view>
</el-main>
</el-container>
</el-container>
</el-container>
</template>
<script>
export default{
data(){
return {
//菜单列表
menuList:[],
isCollapse:false,//伸缩
icon_page:{
'100':'el-icon-user',
'101':'el-icon-user-solid',
'102':'el-icon-s-custom',
'103':'el-icon-medal-1',
'104':'el-icon-s-goods',
'200':'el-icon-thumb',
'201':'el-icon-odometer',
'202':'el-icon-fork-spoon',
'203':'el-icon-cold-drink'
},
activePath:'/welcome',//默认路径
}
},
//相当于onload事件
created(){
//查询menuList
this.getMenuList();
this.activePath=sessionStorage.getItem("activePath");//取出session里的activePath 动态修改activePath
},
methods:{
login_out(){
window.sessionStorage.clear();//清除session数据 安全退出
this.$router.push("/login");//跳转到login界面上
},
//获取导航菜单
async getMenuList(){
const {data:res} =await this.$http.get("menus");
console.log(res);
if(res.flag!=200){
return this.$message.error("获取列表失败!!!");
}else{
this.menuList=res.data;//在菜单栏中注如数据
}
},
// 控制伸缩
toggleCollapase(){
this.isCollapse=!this.isCollapse;
},
//保存路径
saveNavState(path){
window.sessionStorage.setItem("activePath",path);//放入session中
this.activePath=path;
}
}
}
</script>
<style>
.home-container{
height: 100%;
}
.el-header{
background-color: #373d41;
display: flex;
justify-content: space-between;/* 左右贴边*/
padding-left: 0%;/* 左边界*/
align-items: center; /*水平*/
color: #fff;
font-size: 20px;
}
/* 主体样式 */
.el-main {
background-color: #f9f9fa;
color: #333;
text-align: center;
line-height: 20px;
}
/* 侧边样式 */
.el-aside {
background-color: #545c64;
color: rgb(212, 192, 192);
text-align: center;
line-height: 200px;
}
img{
width: 90x;
height: 55px;
}
/* |||的样式 */
.toggle-button{
background-color:#4A5064;
font-size: 10px;
line-height: 24px;
color:#fff;
text-align: center;
letter-spacing: 0.2em;
cursor: pointer;/* 显示鼠标指针为:小手*/
}
/*el-emun 让对齐 */
.celanbuqi{
border-right:none;
}
</style>
向后端进行请求获取菜单列表
后台 java的:
@RequestMapping("/menus")
public String getAllMenus() {
HashMap<String,Object> res =new HashMap<>();
int status=404;//错误404 成功200
List<MainMenuSelf> menus=mainmenuSelfMapper.getMenus();
//System.out.println(menus);
if(menus!=null){
res.put("data",menus);
res.put("flag",200);
}else {
res.put("flag",404);
}
String s=JSON.toJSONString(res);
System.out.println("=========="+s);
return s;
}
}
获取用户列表
后台
@Autowired
private EasyuserSelfMapper userdao;
@RequestMapping("/allUser")
public String getUserList(@RequestBody QueryInfo queryInfo){
//获取用户数
int number=userdao.getUserCounts(queryInfo.getQuery());
int pageStart= (queryInfo.getPageNum()-1)*queryInfo.getPageSize();
//获取所有的用户
List<Easyuser> easyusers= userdao.getAllUser(queryInfo.getQuery(),pageStart,queryInfo.getPageSize());
System.out.println(easyusers+"--------------------");
HashMap<String,Object> res= new HashMap<String,Object>();
res.put("number",number);
res.put("data",easyusers);
String res_String= JSON.toJSONString(res);
return res_String;
}
分页的后台写法:
int number=userdao.getUserCounts(queryInfo.getQuery());
int pageStart= (queryInfo.getPageNum()-1)*queryInfo.getPageSize();
//获取所有的用户
List<Easyuser> easyusers=userdao.getAllUser(queryInfo.getQuery(),pageStart,queryInfo.getPageSize());
PageNumber:为当前页码
PageSize:每页的最大数据
则:起始页=(当前页-1)*每页的数量
分页计算公式:
limit start pageSize;
start:就是当前页的起始索引,pageSize就是每页的条数
currentPage:就是当前页
公式:start=(currentPage-1)*pageSize
数据库:
<select id="getAllUser" resultType="com.tjk.spotplay_vue.bean.Easyuser">
SELECT * FROM easyUser
<if test="username !=null ">
WHERE username like '%${username}%'
</if>
LIMIT #{pageStart},#{pageSize}
</select>
前台:elementUI
<el-table :data="userList" border stripe >
<el-table-column type="index"></el-table-column><!---索引列-->
<el-table-column label="用户名" prop="username" ></el-table-column>
<el-table-column label="邮箱" prop="email"> </el-table-column>
<el-table-column label="密码" prop="password"> </el-table-column>
<el-table-column label="角色" prop="role"> </el-table-column>
<el-table-column label="状态" prop="state">
<!-- scope.row 就是当前行的信息 -->
<template slot-scope="scope">
<!--每一行的数据都子啊scope域中 scpoe.row.对象名-->
<el-switch v-model="scope.row.state" @change="userStateChanged(scope.row)" ></el-switch>
</template>
</el-table-column>
<!---作用域插槽-->
<el-table-column label="操作">
<template slot-scope="scope">
<!-- 修改 -->
<el-button type="primary" icon="el-icon-edit" size="mini" @click="editUserInfor(scope.row)"></el-button>
<!-- 删除 -->
<el-button type="danger" icon="el-icon-delete" size="mini" @click="deleteUserInfor(scope.row.id)"></el-button>
<!-- 权限 -->
<el-tooltip effect="dark" content="分配权限" placement="top-start" :enterable="false">
<el-button type="warning" icon="el-icon-setting" size="mini"></el-button>
</el-tooltip>
</template>
</el-table-column>
</el-table>
table中的列表的按照一列一列进行拼凑的,table中 :data=“userList” 是将数据进行绑定,然后对应的列的prop=”属性名“即可对数据进行遍历显示
slot-scope="scope" 列中的scpoe是对整行数据的获取,所有的数据均在其中,scope.row.属性名 scope.row是整行数据
switch v-model="数据":
对switch插件进行数据绑定,可以用boolean类型
async getUserList(){
const {data:res}= await this.$http.post("/allUser",this.queryInfo);
//对接口返回的数据进行解析
this.userList=res.data;
this.total=res.number;
console.log(res);
},
分页前台的写法
<div>
<el-pagination
@size-change="handleSizeChange" //每页多少条数据
@current-change="handleCurrentChange" //查询的页数
:current-page="queryInfo.pageNum"
:page-sizes="[1, 2, 5, 100]"
:page-size="queryInfo.pageSize"
layout="total, sizes, prev, pager, next, jumper"
:total="total">
</el-pagination>
</div>
data(){
return({
queryInfo:{
query:"",//查询信息
pageNum:1,//查询页
pageSize:5,//每页的最大值
},})}
//最大数
handleSizeChange(newSize){
this.queryInfo.pageSize=newSize;
this.getUserList();
},
//修改当前页的数据
handleCurrentChange(newPage){
this.queryInfo.pageNum=newPage;
this.getUserList();
},
//pageNumber的触发动作
async userStateChanged(userInfo){
console.log(userInfo);
const{data:res}=await this.$http.put(`updateUserStatus?id=${userInfo.id}&state=${userInfo.state}`);
if(res!="success"){
userInfo.id=!userInfo.id;
return this.$message.error("操作失败");
}else{
this.$message.success("操作成功");
}
},
删除用户的数据
后台:
数据库:
<delete id="deleteUserInfor" parameterType="java.lang.Integer">
delete from easyuser where id=#{id}
</delete>
//删除用户的信息
@RequestMapping("/deleteUserInfor")
public String deleteUserInfor(@RequestParam("id") Integer id){
System.out.println("id:"+id);
int i= userdao.deleteUserInfor(id);
return i>0?"success":"error";
}
前台:
<!-- 删除 -->
<el-button type="danger" icon="el-icon-delete" size="mini" @click="deleteUserInfor(scope.row.id)"></el-button>
js代码:
//根据主键删除用户信息
async deleteUserInfor(id){
const flag = await this.$confirm("此操作将删除该用户,是否继续???","提示",{
confirmButtonText:"确定",
canceButtonText:"取消",
type:"warning"
}).catch(err=>err);
if(flag!='confirm') return this.$message.info("已取消删除");
else{
const {data:res}= await this.$http.delete("deleteUserInfor?id="+id);
if(res!="success"){
return this.$message.error("删除失败");
}else{
this.$message.success("删除成功");
this.getUserList();
}
}
},
更新数据
后台:
数据库:
<update id="editUserInfor" parameterType="com.tjk.spotplay_vue.bean.Easyuser">
UPDATE easyuser SET username = #{username} , password = #{password} ,
email = #{email} WHERE id = #{id}
</update>
//编辑用户的提交信息
@RequestMapping("/editUserInfor")
public String editUserInfor(@RequestBody Easyuser easyuser){
System.out.println("----------"+easyuser);
int i=userdao.editUserInfor(easyuser);
return i>0?"success":"error";
}
<!--修改对话框-->
<!--新增用户区域-->、
<el-dialog title="修改用户信息" :visible.sync="editDialogVisible" width="50%" @close="editDialogClosed" >
<el-form :model="editForm" :rules="editFormRules" ref="editFormRef" label-width="70px">
<!--用户名-->
<el-form-item label="用户名" prop="username">
<el-input v-model="editForm.username" disabled></el-input>
</el-form-item>
<!--密码-->
<el-form-item label="密码" prop="password">
<el-input v-model="editForm.password"></el-input>
</el-form-item>
<!--邮箱-->
<el-form-item label="邮箱" prop="email">
<el-input v-model="editForm.email"></el-input>
</el-form-item>
</el-form>
<!-- 内容底部区域 -->
<span slot="footer" class="dialog-footer">
<el-button @click="editUserPage">取 消</el-button>
<el-button type="primary" @click="editUser">确 定</el-button>
</span>
</el-dialog>
</div>
//编辑用户表单数据
data(){
return ({
//编辑用户表单数据
editForm:{
username:'',
password:'',
email:'',
role:'',
state:''
},
editDialogVisible:false,//编辑用户界面的状态 true是显示 false是不显示})
}
//修改表单验证
editFormRules: {
password:[
{ required: true, message: "请输入密码", trigger: "blur" },
{ min: 6, max: 8, message: "长度在 6 到 8 个字符", trigger: "blur" }
],
email:[
{ required: true, message: "请输入邮箱", trigger: "blur" },
{ min: 5, max: 15, message: "请输入正确邮箱地址", trigger: "blur" }
],
},
//点击编辑按钮,将用户的信息传递给编辑框中
editUserInfor(userInfo){
//将原本的用户信息传递给编辑框
console.log(userInfo);
this.editForm=userInfo;
this.editDialogVisible=!this.editDialogVisible;
},
//编辑框的显示
editUserPage(){
this.editDialogVisible=!this.editDialogVisible;
},
//编辑框的关闭
editDialogClosed(){
this.$refs.editFormRef.resetFields();//清除界面中的所有数据
},
//点击编辑按钮的确定
editUser(){
this.$refs.editFormRef.validate(async vaild=>{
console.log(vaild);//vaild是框中的数据都符合规则以后返回true就可以进行下面的操作
if(!vaild){
return ;
}
else{
const {data:res}= await this.$http.post("/editUserInfor",this.editForm);
if(res!="success"){
return this.$message.error("操作失败");
}else{
this.$message.success("操作成功");
this.editUserPage();//关闭界面
this.getUserList();//重新渲染用户列表
}
}
});
}
}
增添用户的信息
后台:
<insert id="addUserInfor" parameterType="com.tjk.spotplay_vue.bean.Easyuser">
INSERT INTO easyuser (username,password,email,role,state)
VALUE
(#{username},#{password},#{email},#{role},#{state})
</insert>
//添加用户信息
@RequestMapping("/addUserInfor")
public String addUserInfor(@RequestBody Easyuser easyuser){
easyuser.setRole("普通用户");
easyuser.setState(false);
int i= userdao.addUserInfor(easyuser);
return i>0?"success":"error";
}
前台界面:
<!--新增用户区域-->、
<el-dialog title="添加用户" :visible.sync="addDialogVisible" width="50%" @close="addDialogClosed" >
<el-form :model="addForm" :rules="addFormRules" ref="addFormRef" label-width="70px">
<!--用户名-->
<el-form-item label="用户名" prop="username">
<el-input v-model="addForm.username"></el-input>
</el-form-item>
<!--密码-->
<el-form-item label="密码" prop="password">
<el-input v-model="addForm.password"></el-input>
</el-form-item>
<!--邮箱-->
<el-form-item label="邮箱" prop="email">
<el-input v-model="addForm.email"></el-input>
</el-form-item>
</el-form>
<!-- 内容底部区域 -->
<span slot="footer" class="dialog-footer">
<el-button @click="addUserPage">取 消</el-button>
<el-button type="primary" @click="addUser">确 定</el-button>
</span>
</el-dialog>
data(){
return({
//添加表单数据
addForm:{
username:'',
password:'',
email:''
},
addDialogVisible:false,//添加用户界面的状态 true是显示 false是不显示
//添加表单验证
addFormRules: {
username: [
{ required: true, message: '请输入用户名', trigger: 'blur' },
{ min: 6, max: 8, message: '长度在 6 到 8 个字符', trigger: 'blur' }
],
password:[
{ required: true, message: "请输入密码", trigger: "blur" },
{ min: 6, max: 8, message: "长度在 6 到 8 个字符", trigger: "blur" }
],
email:[
{ required: true, message: "请输入邮箱", trigger: "blur" },
{ min: 5, max: 15, message: "请输入正确邮箱地址", trigger: "blur" }
],
},})}
//添加用户界面动作
addUserPage(){
this.addDialogVisible=!this.addDialogVisible;
},
//界面上的小错号
addDialogClosed(){
this.$refs.addFormRef.resetFields();//清除界面中的所有数据
},
//点击确定后向后台发送请求
addUser(){
this.$refs.addFormRef.validate(async vaild=>{
console.log(vaild);//vaild是框中的数据都符合规则以后返回true就可以进行下面的操作
if(!vaild){
return ;
}
else{
const {data:res}= await this.$http.post("/addUserInfor",this.addForm);
if(res!="success"){
return this.$message.error("操作失败");
}else{
this.$message.success("操作成功");
this.addUserPage();//关闭界面
this.getUserList();//重新渲染用户列表
}
}
});
},
查询数据
<!-- 搜索添加 clearable为了可以删除搜索框的内容 -->
<el-input placeholder="请输入搜索内容" :span="10" v-model="queryInfo.query" clearable @clear="getUserList">
<el-button slot="append" icon="el-icon-search" @click="getUserList"></el-button>
</el-input>