(十六)VUE权限菜单之动态路由--基于SpringBoot+MySQL+Vue+ElementUI+Mybatis前后端分离面向小白管理系统搭建

任务十四 VUE权限菜单之菜单管理

任务十五 VUE权限菜单之角色管理

任务十六 VUE权限菜单之动态路由

在任务十四中完成了权限菜单的菜单管理,主要实现了一级、二级等菜单的添加。任务十五中完成了权限菜单的角色管理,主要实现了角色增删改查已经为角色分配权限菜单。这些基本内容完成之后,就需要做本次任务的内容,即根据登录用户的角色进行动态路由分配,通过本次任务,大家能够:
(1)理解用户认证、授权的概念;
(2)学会登录验证以及基于网页的HTML5浏览器存储localStorage,存储用户信息和用户授权菜单;
(3)掌握动态路由设计;
(4)学会登录login基本方法。
首先梳理一下整个逻辑;
(1)用户登录需要做两件事,一件事是验证用户的合法性,设置TOKEN,然后将信息进行浏览器存储;另一件事是得到这个合法用户的role(也就是角色标识,如ROLE_ADMIN),根据这个角色标识获取到角色ID,根据角色ID获取权限菜单。
(2)获取到权限菜单后,只是一个列表,在确保确实是menu表中的数据之外,还需要与menu表中数据进行匹配,对每一个menuid判断出它是一级菜单还是二级菜单;
(3)将权限菜单数据同样进行浏览器存储;
(4)用户验证合法、获取授权菜单后登录,进入主页面,原先固定的Aside组件需要根据动态存储的menus值重新设置。

涉及到的实体类

表结构为:
在这里插入图片描述
具体数据表的讲解请参考任务十五。
为了方便期间,如果只做这一个任务实现登录并能动态路由分配,把涉及到的实体类再罗列出,如果是跟着前面的任务在做,就不需要重复做了。

1. 用户实体类User

package com.example.demo.entity;

import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.sun.javafx.beans.IDProperty;
import lombok.Data;

import java.sql.Date;


@Data
//可以使用 @TableName 表名注解指定当前实体类对应的表名,比如下面 User 实体类对应表名为 sys_user
@TableName(value="sys_user")
public class User {
    //可以使用 @TableId 注解(标注在主键上)和 @TableField 注解(标注在其他成员属性上)来指定对应的字段名
    @TableId(value = "id",type = IdType.AUTO)
    private Integer id;
    private String username;
    private String password;
    private String email;
    private String phone;
    private String nickname;
    private String address;
    @TableField(value="created_time")//这样处理的主要目的是java对带有下划线的字段不识别,所以改为驼峰形式
    private Date createdTime;//如果需要年月日格式的可以使用Date类型,如果需要具体到时分秒就使用String类型
    private String avatar;
    private String role;
}

2. 菜单实体类Menu

package com.example.demo.entity;


import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;

import java.util.List;

@Data
//可以使用 @TableName 表名注解指定当前实体类对应的表名,比如下面 Menu 实体类对应表名为 sys_menu
@TableName(value="sys_menu")
public class Menu {

    //可以使用 @TableId 注解(标注在主键上)和 @TableField 注解(标注在其他成员属性上)来指定对应的字段名
    @TableId(value = "id",type = IdType.AUTO)
    private Integer id;
    private String name;
    private String path;
    private String icon;
    private String description;

    //在数据表中没有children这个字段,这个在做菜单的时候会用到,所以使用exist=false忽略
    @TableField(exist = false)
    private List<Menu> children;

    private Integer pid;
    @TableField(value="page_path")//这样处理的主要目的是java对带有下划线的字段不识别,所以改为驼峰形式
    private String pagePath;
}

3.角色实体类 Role

package com.example.demo.entity;

import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;

import java.sql.Date;

@Data
//可以使用 @TableName 表名注解指定当前实体类对应的表名,比如下面 Role 实体类对应表名为 sys_role
@TableName(value="sys_role")
public class Role {
    //可以使用 @TableId 注解(标注在主键上)和 @TableField 注解(标注在其他成员属性上)来指定对应的字段名
    @TableId(value = "id",type = IdType.AUTO)
    private Integer id;
    private String name;
    private String description;
    private String flag;
}

4. 角色菜单实体类RoleMenu

package com.example.demo.entity;


import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;

@Data
//可以使用 @TableName 表名注解指定当前实体类对应的表名,比如下面 RoleMenu 实体类对应表名为 sys_role_menu
@TableName(value="sys_role_menu")
public class RoleMenu {
    private Integer roleId;
    private Integer menuId;
}

5. 登录用户类UserDTO

package com.example.demo.controller.dto;

import com.example.demo.entity.Menu;
import lombok.Data;

import java.util.List;


//UserDTO用来接受前端登录时传递的用户名和密码
@Data
public class UserDTO {
    private String username;
    private String password;
    private String nickname;
    private String avatar;
    private String token;
    //把当前登录用户的角色以及他的菜单项带出来
    private String role;
    private List<Menu> menus;
}

一、后端登录接口

1. 修改userService类中的login方法

基于任务十三 JWT+SpringSecurity实现基于Token的登录修改userService类中login方法。主要修改的思路:用户登录后,根据用户获取到角色标识。然后根据角色标识获取到角色id,由角色id获取菜单列表。获取菜单列表的时候注意一级菜单和二级菜单。

package com.example.demo.service;

import cn.hutool.core.bean.BeanUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.example.demo.common.Constants;
import com.example.demo.controller.dto.UserDTO;
import com.example.demo.entity.Menu;
import com.example.demo.entity.User;
import com.example.demo.exception.ServiceException;
import com.example.demo.mapper.RoleMapper;
import com.example.demo.mapper.RoleMenuMapper;
import com.example.demo.mapper.UserMapper;
import com.example.demo.utils.TokenUtils;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;

@Service
public class UserService extends ServiceImpl<UserMapper,User>{
    private UserMapper userMapper;
    @Resource
    private RoleMenuMapper roleMenuMapper;
    @Resource
    private RoleMapper roleMapper;
    @Resource
    private MenuService menuService;
   
    public Boolean saveUser(User user) {       
       return  saveOrUpdate(user);
    }

    public UserDTO login(UserDTO userDTO) {
        QueryWrapper<User> queryWrapper=new QueryWrapper<>();
        queryWrapper.eq("username",userDTO.getUsername());
        queryWrapper.eq("password",userDTO.getPassword());
        User one;
        try{
            one=getOne(queryWrapper);
        }catch (Exception e){
            throw new ServiceException(Constants.CODE_500,"系统错误");//这里假设查询了多于1条记录,就让他报系统错误
        }
        if(one!=null){  //以下是登录判断业务
            BeanUtil.copyProperties(one,userDTO,true);
            //设置token
            String token=TokenUtils.genToken(one.getId().toString(),one.getPassword().toString());
            userDTO.setToken(token);
            String role=one.getRole();//查询出用户的角色标识,比如ROLE_ADMIN
            //设置用户的菜单列表
            List<Menu> roleMenus=getRoleMenus(role);
            userDTO.setMenus(roleMenus);
            return userDTO;
        }else {
            throw new ServiceException(Constants.CODE_600,"用户名或密码错误");
        }
    }

    /**
     * 获取当前用户的菜单列表

     */
    private List<Menu> getRoleMenus(String roleFlag){
        //根据角色标识获取角色Id
        Integer roleId=roleMapper.selectByflag(roleFlag);
        //当前角色Id的所有菜单id集合
        List<Integer> menuIds=roleMenuMapper.selectByRoleId(roleId);
        //查出系统所有菜单
        List<Menu> menus=menuService.findMenus("");
        //筛选当前用户菜单
        List<Menu> roleMenus=new ArrayList<>();
        for(Menu menu:menus){
            if(menuIds.contains(menu.getId())){
                roleMenus.add(menu);
            }
            List<Menu> children=menu.getChildren();
            //removeIf移除children里面不在menuIds集合中的元素
            children.removeIf(child->!menuIds.contains(child.getId()));
        }
        return roleMenus;
    }
}

其中涉及到的方法在任务十四和任务十五中均有,如果前面没有做的童鞋,可以在前面的任务中找到。
roleMapper.selectByflag(roleFlag);在任务十五有详细讲解,完整代码为:

package com.example.demo.mapper;

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.example.demo.entity.Role;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select;

public interface RoleMapper extends BaseMapper<Role> {
    //根据角色唯一标识flag查找角色id
    @Select("select id from sys_role where flag=#{flag}")
    Integer selectByflag(@Param("flag") String role);
}

roleMenuMapper.selectByRoleId(roleId);在任务十五有详细讲解,完整代码为:

package com.example.demo.mapper;

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.example.demo.entity.RoleMenu;
import org.apache.ibatis.annotations.Delete;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select;

import java.util.List;

public interface RoleMenuMapper  extends BaseMapper<RoleMenu> {
    //根据角色id删除角色菜单数据
    @Delete("delete from sys_role_menu where role_id=#{roleId}")
    int deleteByRoleId(@Param("roleId") Integer roleId);

    //根据角色id查找菜单id
    @Select("select menu_Id from sys_role_menu where role_id=#{roleId}")
    List<Integer> selectByRoleId(@Param("roleId") Integer roleId);
}

menuService.findMenus(“”);在任务十四有详细讲解,完整代码为:

package com.example.demo.service;

import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
importcom.example.demo.entity.Menu;;
import com.example.demo.mapper.MenuMapper;
import org.springframework.stereotype.Service;

import java.util.List;
import java.util.stream.Collectors;

@Service
public class MenuService extends ServiceImpl<MenuMapper, Menu> {
    public List<Menu> findMenus(String name) {
        QueryWrapper<Menu> queryWrapper=new QueryWrapper<>();
        if(StrUtil.isNotBlank(name)){
            queryWrapper.like("name",name);
        }
        List<Menu> list = list(queryWrapper);
        // 找出pid为null的一级菜单
        List<Menu> parentNodes=list.stream().filter(menu -> menu.getPid()==null).collect(Collectors.toList());
        //找出一级菜单为null的二级菜单放到Children中
        for(Menu menu:parentNodes){
            menu.setChildren(list.stream().filter(m->menu.getId().equals(m.getPid())).collect(Collectors.toList()));
        }
        System.out.println(parentNodes);
        return parentNodes;
    }
}

二、前端登录页面

login.vue完整代码

这个页面与任务十三登录页面没有太多大的改动,因为那里已经实现了基于Token的认证,并且保存了用户信息。
继续添加一个把菜单添加到浏览器的接口即可。
完整代码如下:

<template>
 <div class="login_container">
    <div class="login_box">
      <div style="margin:20px 0; text-align:center; font-size:24px"><b>登录</b></div>
      <!-- 用户名-->
      <el-form ref="LoginFormRef" :model="loginForm" :rules="LoginFormRules" >
        <el-form-item prop="username">
          <el-input size="medium" style="margin:10px 0px;width: 300px;margin-left:25px" v-model="loginForm.username" prefix-icon="el-icon-user"></el-input>
        </el-form-item>
      <!-- 密码-->
         <el-form-item prop="password">
           <el-input size="medium" style="margin:10px 0px;width: 300px;margin-left:25px" show-password v-model="loginForm.password" prefix-icon="el-icon-lock" type="password"></el-input>
        </el-form-item>
        <div style="margin:10px 0; text-align:center">
          <el-button type="primary" size="small" @click="login" >登录</el-button>
          <el-button type="warning" size="small" @click="resetLoginForm">重置</el-button>
        </div> 
      </el-form> 
    </div>
  </div>
</template>

<script>
import {setRoutes} from "@/router";
import {resetRouter} from "@/router";
  export default {
    name: "Login",
    data() {
      return {
        loginForm: {
          username:'',
          password:''
        },
        LoginFormRules:{
          username:[
            { required: true, message: '请输入用户名', trigger: 'blur' },
          ],
          password:[
            { required: true, message: '请输入密码', trigger: 'blur' },
          ]
        }
      }
    },
    methods:{
      login(){
        this.$refs['LoginFormRef'].validate(async (valid) => {
          if (valid) {
            this.request.post("http://localhost:8084/user/login",this.loginForm).then(res=>{
              if(res.code=='200'){
                localStorage.setItem("user",JSON.stringify(res.data));//存储用户信息到浏览器
                localStorage.setItem("menus",JSON.stringify(res.data.menus));//存储用户权限菜单信息到浏览器
                //动态设置当前用户的路由
                setRoutes()
                this.$router.push("/home");
                this.$message.success("登录成功");
              }else{
                this.$message.error(res.msg);
              }
            })
          }
          
        })
      },
      resetLoginForm(){
        this.$refs.LoginFormRef.resetFields()
      }
    }    
  }
</script>

<style scoped>
  .login_container{
    background-color: #2b4b6b;
    height: 100%;
  }

  .login_box{
    width: 350px;
    height: 300px;
    background-color: #fff;
    border-radius: 3px;
    position: absolute;
    left: 50%;
    top: 50%;
    transform: translate(-50%,-50%)
  }
</style>>

在这里插入图片描述
特别注意:这里调用了 setRoutes(),进行动态设置当前用户的路由

三、动态路由index.js

1. 修改router里的index.js

在这里插入图片描述
完整代码如下:

import Vue from 'vue'
import VueRouter from 'vue-router'
import Login from '../views/Login.vue'

Vue.use(VueRouter)

const routes = [ 
  {
    path: '/login',
    name: 'Login',
    component: Login
  }
]

const router = new VueRouter({
  mode: 'history',
  base: process.env.BASE_URL,
  routes
})

// 提供一个重置路由的方法
export const resetRouter=()=>{
  router.matcher=new VueRouter({
    mode: 'history',
    base: process.env.BASE_URL,
    routes
  })
}
//刷新页面会重置路由
export const setRoutes=()=>{
  const storeMenus=localStorage.getItem("menus");
  if(storeMenus){
    //拼装动态路由
    const manageRoute={ path: '/', name:'Manage', component: () => import('../views/Manage.vue'),redirect: '/login', children: []}
    const menus=JSON.parse(storeMenus)
    menus.forEach(item=>{
      if(item.path){//当且仅当path不为空的时候才去设置路由
        let itemMenu={ path: item.path.replace("/",""),name: item.name,component: () => import('../views/'+item.pagePath+'.vue')}
        manageRoute.children.push(itemMenu)
      }else if(item.children.length){
        item.children.forEach(item=>{
          if(item.path){
            let itemMenu={ path: item.path.replace("/",""),name: item.name,component: () => import('../views/'+item.pagePath+'.vue')}
            manageRoute.children.push(itemMenu)
          }
        })
      }
    })  
    //获取当前的路由对象名称数组
    const currentRouteNames=router.getRoutes().map(v=>v.name)
    if(!currentRouteNames.includes('Manage')){
      //动态加载到想在的路由对象
    router.addRoute(manageRoute)
    }    
  }
}
export default router

2. 修改Aside组件

任务十VUE侧边菜单栏导航 中我们修改过VUE侧边菜单栏导航,但那时候还是固定的。现在根据动态路由生成侧边菜单栏。
完整代码如下:

<template>
  <el-menu :default-openeds="opens" style="min-height:100%; overflow-x:hidden"
    background-color=rgb(48,65,86)
    text-color=#ccc
    active-text-color=red
    router=""
    >
    <div style="height:60px; line-height:60px; text-align:center">
    <img src="../assets/logo.png" style="width:20px;position:relative;top:5px;margin-right:5px"/>
    <b style="color:white">后台管理系统</b>
    </div>
    <div v-for="item in menus" :key="item.id">
      <div v-if="item.path">
          <el-menu-item :index="item.path">               
              <i :class="item.icon"></i>
              <span slot="title">{{item.name}}</span>                 
          </el-menu-item>
      </div>
      <div v-else>
         <el-submenu :index="item.id+'' ">
          <template slot="title">
            <i :class="item.icon"></i>
            <span slot="title">{{item.name}}</span>
          </template>
          <div v-for="subItem in item.children" :key="subItem.id">
             <el-menu-item :index="subItem.path">
              <i :class="subItem.icon"></i>
              <span slot="title">{{subItem.name}}</span>
            </el-menu-item>
          </div>
        </el-submenu>
      </div>
    </div>    
  </el-menu>
</template>

<script>
export default {
  name: "Aside",
  props:{

  },
  data(){
    return{
      menus:localStorage.getItem("menus")?JSON.parse(localStorage.getItem("menus")):[],  
      opens:localStorage.getItem("menus")?JSON.parse(localStorage.getItem("menus")).map(v=>v.id+''):[],
    }
  },
  methods:{
    showmst(){
      console(this.opens)
    }
  }
}
</script>

<style scoped>
</style>

理解 的重点就是根据已存储的menus动态部署侧栏。

四、vue全局状态管理

对于一些全局变量或者方法,可以进行全局设置,然后在任何时候都可以直接使用。比如常用的登出logout方法等。
具体方法为:

1.安装vuex

npm install vuex --save

安装完成后注意观察一个vuex的版本。
vuex分3.x版本和4.x版本,分别对应vue2.0与3.0。
这里用的是VUE2.0,所以需要vuex是3.x版本。具体安装方法也可以到网上查找。
在这里插入图片描述

2. 在src下新建文件夹store,并在文件夹中新建文件index.js

在这里插入图片描述
index.js完整代码如下:

import Vue from 'vue'
import Vuex from 'vuex'
import router from '@/router'

Vue.use(Vuex)

const store=new Vuex.Store({
    state:{
        currntPathName:''
    },
    mutations:{
        logout(){
            localStorage.removeItem("user")
            localStorage.removeItem("menus")
            router.push("/login")
        }
    }
})
export default store

3. 在main.js中引用,并添加到组件中

新增代码段如下:

import store from './store/index'
 
new Vue({
    router,
    store,//定义成全局变量
    render: h => h(App)
}).$mount('#app')

在这里插入图片描述

4.引用

比如在任务十五中当判断给管理员重新分配了权限,就需要重新登录,这时候先登出,就调用store中的logout方法。
在这里插入图片描述

五、运行项目

1. 登录

在这里插入图片描述

2.菜单管理-新增一级菜单

在这里插入图片描述

3.菜单管理-新增两个子菜单

在这里插入图片描述

4.角色管理

为管理员角色分配菜单
在这里插入图片描述
因为是给管理员重新分配权限菜单,所以点击“确定”后需要重新登录。

5.新增一个Test1.vue组件

在这里插入图片描述
代码为:

<template>
    <div>
        <h1>测试一个新路由</h1>
    </div>
</template>

6.保存重新运行登录

在这里插入图片描述

任务总结

本次任务完成后,整个项目将根据不同用户部署不同菜单,实现动态路由,而且,只要有新的页面生成,只要添加到菜单中即可,就可以实现动态访问。
通过本次任务,大家能够:
(1)理解动态路由的概念;
(2)VUE对整个框架的管理机制有所了解;
(3)学会VUE 状态管理定义与使用。
下一个任务将使用Echart做一个简单Home页面。

  • 8
    点赞
  • 42
    收藏
    觉得还不错? 一键收藏
  • 12
    评论
【资源说明】 1、基于springboot+vue前后端分离的小型电商系统源码+项目说明.zip 2、该资源包括项目的全部源码,下载可以直接使用! 3、本项目适合作为计算机、数学、电子信息等专业的课程设计、期末大作业和毕设项目,作为参考资料学习借鉴。 4、本资源作为“参考资料”如果需要实现其他功能,需要能看懂代码,并且热爱钻研,自行调试。 基于springboot+vue前后端分离的小型电商系统源码+项目说明.zip # lite_shop微商铺 基于springboot + vue前后端分离的完整小型电商系统 ## 项目介绍 lite_shop是一套小型电商系统,该项目为B2C模式电商系统,包括前台商城系统和后台管理系统,基于springboot + vue打造。后台管理系统包含会员管理、商品管理、订单管理、运营管理、系统管理、统计报表、后台用户管理、权限管理、系统设置等模块。前台管理系统包含首页、商品推荐、商品搜索、专题推荐、用户下单、支付等一套完整电商流程。 ![11644241501_.pic.jpg](https://s2.loli.net/2022/02/07/KQeqcARCNtpTB65.jpg) ![21644241502_.pic.jpg](https://s2.loli.net/2022/02/07/8lxZvDRi2HJW4PC.jpg) ![后台截图1.png](https://i.loli.net/2020/09/20/YPAkIb32zMHXvFr.png) ![后台截图2.png](https://i.loli.net/2020/09/20/IRp7HblznxMUvoB.png) 前台商城系统 敬请期待...... ## 项目架构 ![lite_shop架构.jpg](https://i.loli.net/2020/09/20/73PWtHj2cUqh1XL.png) ## 技术栈 后端技术 | 技术 | 说明 | 版本 | | :--------------------: | :----------------- | :----: | | SpringBoot | web容器+MVC框架 | 2.3.0 | | SpringSecurity | 身份认证与授权 | 5.2.4 | | Mybati-Plus | orm框架 | 3.2.0 | | mybatis-plus-generator | 持久层代码生成器 | 3.2.0 | | Redis | 分布式缓存 | 4.0.10 | | MySQL | 数据库 | 5.7.28 | | jjwt | JWT支持 | 0.9.0 | | 七牛云 | 对象存储 | 7.2.0 | | hutool | 工具包 | 5.3.8 | | elasticsearch | 分布式全文搜索引擎 | 7.6.2 | | RabbitMQ | 消息队列 | 3.9.0 | 前端技术 | 技术 | 说明 | 版本 | | :----------------: | :---------------: | :----: | | Vue | 前端框架 | 2.6.10 | | Vue-router | 前端路由框架 | 3.1.2 | | Vuex | 全局状态管理框架 | 3.1.1 | | Axios | 前端HTTP框架 | 0.19.0 | | Ant Design of Vue | 后台管理UI框架 | 1.6.2 | | Vant | 前台商城VUE组件库 | 2.0 | ## 功能介绍 #### 管理后台: ###### 会员管理: - 会员列表 - 收货地址 - 会员收藏 - 会员足迹 - 意见反馈 ###### 商品管理: -
摘 要 在如今这个人才需求量大的时代,各方企业为了永葆企业的活力与生机,在不断开 拓进取的同时,又广泛纳用人才,为企业的长久发展奠定了基础。于是,各个企业与部 门机构,都不可避免地会接触到人力资源管理的问题。 Hrm 是一款人力资源管理系统,其主要功能模块有员工个人信息修改、请假、员工 的薪资管理、考勤管理、社保管理。其中考勤管理实现了员工考勤状态的修改与员工考 勤月报表的导出,以及通过员工考勤记录的导入来实现员工考勤状态的判断。社保管理, 主要实现了员工社保的计算以及明细的修改。薪资管理,实现了员工工资的调整,以及 员工月工资报表的导出。 本项目采用了前后端分离的技术,前端是基于 Vue+ElementUI+Axios 开发的,后端 则是基于 Spring Boot+MyBatis Plus+ Jwt+Mysql。本项目实现了权限菜单管理,通过员 工的权限动态渲染菜单,并动态生成路由。通过 Jwt token 来判断当前登录的员工以及 员工的登录状态。 关键词:人力资源管理系统Spring BootVue权限管 人力资源管理是企业运营中必不可少的一环,它关系到企业的前途与发展。尤其对 于中小微企业来说,对企业的发展有着举足轻重的作用。随着近年来,政府对创业项目 的大力扶持,我国创业型企业蓬勃发展。据统计,2019 年,我国创业企业数量已达 1810 万余家,占全国企业数的 97%,截止 2020 年,我国创业企业数量达到了 2030 万,同比 增长 10%。虽然我国创业企业的基数在不断增大,但是能够长久存活的企业却少之又少。 在创业初期,随着企业初具规模,大多数创业者开始将主要精力集中在市场调研和 开发产品上,而忽略了团队的内部管理。据调查,中国企业的平均寿命是 7.02 年,但 70%的企业存活不超过 5 年,究其原因有很多,其中最重要的一点就是,人力资源管理 未能有效推动企业向前发展
好的,下面是一个简单的示例: ### 后端部分 #### 1. 创建Spring Boot项目 使用Spring Initializr创建一个基于Maven的Spring Boot项目,勾选Web、MyBatisMySQL、Lombok等依赖。 #### 2. 配置数据库连接 在`application.properties`文件中配置数据库连接信息: ``` spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver spring.datasource.url=jdbc:mysql://localhost:3306/mydb?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=Asia/Shanghai spring.datasource.username=root spring.datasource.password=123456 ``` #### 3. 创建数据库表 创建一个名为`user`的表,包含`id`、`username`、`password`三个字段。 #### 4. 创建实体类和Mapper 创建一个名为`User`的实体类,对应数据库中的`user`表。同时,创建一个名为`UserMapper`的Mapper接口,用于操作数据库中的`user`表。 #### 5. 创建Controller 创建一个名为`UserController`的Controller类,用于处理用户相关的请求。 ```java @RestController @RequestMapping("/user") public class UserController { @Autowired private UserService userService; @PostMapping("/register") public Result register(@RequestBody User user) { userService.register(user); return Result.success(); } @PostMapping("/login") public Result login(@RequestBody User user) { User result = userService.login(user.getUsername(), user.getPassword()); if (result != null) { return Result.success(result); } else { return Result.error("用户名或密码错误"); } } } ``` #### 6. 创建Service 创建一个名为`UserService`的Service接口,包含用户注册和登录的方法。 ```java public interface UserService { void register(User user); User login(String username, String password); } ``` 创建一个名为`UserServiceImpl`的Service实现类,实现`UserService`接口中的方法。 ```java @Service public class UserServiceImpl implements UserService { @Autowired private UserMapper userMapper; @Override public void register(User user) { userMapper.insert(user); } @Override public User login(String username, String password) { return userMapper.selectByUsernameAndPassword(username, password); } } ``` #### 7. 创建返回结果类 创建一个名为`Result`的类,用于封装接口的返回结果。 ```java @Data @NoArgsConstructor @AllArgsConstructor public class Result { private int code; private String msg; private Object data; public static Result success() { return new Result(200, "success", null); } public static Result success(Object data) { return new Result(200, "success", data); } public static Result error(String msg) { return new Result(500, msg, null); } } ``` ### 前端部分 #### 1. 创建Vue项目 使用Vue CLI创建一个基于Vue.js的项目。 #### 2. 安装Axios 使用npm安装Axios。 ``` npm install axios --save ``` #### 3. 创建登录和注册组件 创建一个名为`Login`的组件,包含用户名和密码输入框、登录按钮和注册链接。 ```html <template> <div class="login"> <h2>登录</h2> <form> <div class="form-group"> <label>用户名:</label> <input type="text" class="form-control" v-model="username"> </div> <div class="form-group"> <label>密码:</label> <input type="password" class="form-control" v-model="password"> </div> <button type="button" class="btn btn-primary" @click="login">登录</button> </form> <div class="register-link"> <a href="javascript:void(0)" @click="goRegister">没有账号?去注册</a> </div> </div> </template> <script> import axios from 'axios' export default { data () { return { username: '', password: '' } }, methods: { login () { axios.post('/user/login', { username: this.username, password: this.password }).then(res => { if (res.data.code === 200) { alert('登录成功') } else { alert(res.data.msg) } }).catch(err => { console.error(err) }) }, goRegister () { this.$router.push('/register') } } } </script> ``` 创建一个名为`Register`的组件,包含用户名、密码和确认密码输入框、注册按钮和登录链接。 ```html <template> <div class="register"> <h2>注册</h2> <form> <div class="form-group"> <label>用户名:</label> <input type="text" class="form-control" v-model="username"> </div> <div class="form-group"> <label>密码:</label> <input type="password" class="form-control" v-model="password"> </div> <div class="form-group"> <label>确认密码:</label> <input type="password" class="form-control" v-model="confirmPassword"> </div> <button type="button" class="btn btn-primary" @click="register">注册</button> </form> <div class="login-link"> <a href="javascript:void(0)" @click="goLogin">已有账号?去登录</a> </div> </div> </template> <script> import axios from 'axios' export default { data () { return { username: '', password: '', confirmPassword: '' } }, methods: { register () { if (this.password !== this.confirmPassword) { alert('两次输入密码不一致') return } axios.post('/user/register', { username: this.username, password: this.password }).then(res => { if (res.data.code === 200) { alert('注册成功,请登录') this.$router.push('/login') } else { alert(res.data.msg) } }).catch(err => { console.error(err) }) }, goLogin () { this.$router.push('/login') } } } </script> ``` #### 4. 配置路由 在`router/index.js`文件中配置路由。 ```javascript import Vue from 'vue' import Router from 'vue-router' import Login from '@/components/Login' import Register from '@/components/Register' Vue.use(Router) export default new Router({ routes: [ { path: '/', redirect: '/login' }, { path: '/login', component: Login }, { path: '/register', component: Register } ] }) ``` #### 5. 运行项目 启动Spring Boot项目和Vue项目后,访问`http://localhost:8080`即可看到登录页面。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 12
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值