> 文章列表 > 基于Ant DesignPro Vue实现通过SpringBoot后台加载自定义菜单- 前后端分离

基于Ant DesignPro Vue实现通过SpringBoot后台加载自定义菜单- 前后端分离

基于Ant DesignPro Vue实现通过SpringBoot后台加载自定义菜单- 前后端分离

基于Ant DesignPro Vue实现通过SpringBoot后台加载自定义菜单- 前后端分离

本文想基于Ant DesignPro Vue构建的前端+SpringBoot实现的后端接口服务,实现前后端分离开发和独立运行,业务场景是登录认证,认证成功后返回该用户相应权限范围内可见的菜单。

Ant Design Pro相关系列文章:
一、AntDesign Pro安装过程
二、基于Ant DesignPro实现通过SpringBoot后台加载自定义菜单-前端部分
三、基于Ant DesignPro实现通过SpringBoot后台加载自定义菜单-SpringBoot后端部分
四、搭建Vue版Ant Design Pro后台管理系统
五、基于Ant DesignPro Vue实现通过SpringBoot后台加载自定义菜单- 前后端分离

目录

  • 基于Ant DesignPro Vue实现通过SpringBoot后台加载自定义菜单- 前后端分离
  • 一、通过Ant DesignPro Vue构建前端
  • 二、Ant DesignPro Vue前端对接后台服务接口
    • 1、去掉Mock
    • 2、vue.config.js 中配置api代理
    • 3、修改菜单加载是从后台服务接口请求
  • 三、创建Ant DesignPro后台服务SpringBoot项目
    • 1. File->New->Project
    • 2.编辑pom.xml,添加需要的依赖
    • 3.编辑application.properties
    • 4.创建依赖的实体类
      • 4.1 登录请求实体类UserLoginDto.java
      • 4.2 向前端画面传输的用户信息实体类 UserVo.java
      • 4.3 菜单实体类MenuVo.java
      • 4.4 菜单项实体类MenuMetaVo.java
    • 5.创建登录认证(/api/auth/)接口响应处理类
    • 6.创建用户(/api/user/)接口响应处理类
    • 7.创建Account(/api/account)接口响应处理类
  • 四、验证
    • 1.启动服务端
    • 2.启动前端
    • 3.访问前端画面

一、通过Ant DesignPro Vue构建前端

参见 搭建Vue版Ant Design Pro后台管理系统

二、Ant DesignPro Vue前端对接后台服务接口

1、去掉Mock

编辑src/main.js,把mock注释
基于Ant DesignPro Vue实现通过SpringBoot后台加载自定义菜单- 前后端分离

2、vue.config.js 中配置api代理

基于Ant DesignPro Vue实现通过SpringBoot后台加载自定义菜单- 前后端分离

说明:
上面target配置属性是指后台服务接口URL,默认格式为:target指定的Ulr/api/请求接口

基于Ant DesignPro Vue实现通过SpringBoot后台加载自定义菜单- 前后端分离

3、修改菜单加载是从后台服务接口请求

基于Ant DesignPro Vue实现通过SpringBoot后台加载自定义菜单- 前后端分离

三、创建Ant DesignPro后台服务SpringBoot项目

1. File->New->Project

基于Ant DesignPro Vue实现通过SpringBoot后台加载自定义菜单- 前后端分离基于Ant DesignPro Vue实现通过SpringBoot后台加载自定义菜单- 前后端分离
基于Ant DesignPro Vue实现通过SpringBoot后台加载自定义菜单- 前后端分离
基于Ant DesignPro Vue实现通过SpringBoot后台加载自定义菜单- 前后端分离

2.编辑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.5.5</version><relativePath/></parent><groupId>cn.chinaelink.im</groupId><artifactId>mcvboot</artifactId><version>0.0.1-SNAPSHOT</version><name>mcboot</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.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency><!-- 热部署加入的引用,1.spring-boot-devtools--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-devtools</artifactId></dependency><!--json需要的依赖 --><dependency><groupId>net.sf.json-lib</groupId><artifactId>json-lib-ext-spring</artifactId><version>1.0.2</version></dependency><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><optional>true</optional></dependency><!--重点:模板引擎,用于显示网页需要的依赖,如果不需要将静态页面放入当前工程,则不需要解注下面依赖--><!-- 如果要在当前工程中加入静态页面,首先需要解注下面依赖,并在src/main/resources/目录下创建static和templates目录--><!--<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-thymeleaf</artifactId></dependency>--></dependencies><build><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId><configuration><includeSystemScope>true</includeSystemScope></configuration></plugin></plugins></build>
</project>

3.编辑application.properties

#配置管理服务端口号,默认为8080
server.port=8080
#服务访问路径
server.servlet.context-path=/# 输出的log文件名
logging.file.name=mc
# 输出的文件的路径
logging.file.path=./logs/mcv/
# 限制日志文件的大小
logging.file.max-size=10MB
# 日志的保存天数
logging.file.max-history=7# 输出级别
logging.level.root=warn
logging.level.cn.com.hxyl.filebs=debug# xml配置文件
logging.config=classpath:logback-spring.xml#关闭缓存
#如果不需要将静态页面放入当前工程,则不需要解注下面依赖
#如果要在当前工程中加入静态页面,首先需要解注下面依赖,并将静态页面文件放入src/main/resources/static/目录下
#spring.thymeleaf.cache=false
#spring.thymeleaf.prefix=classpath:/static/
server.tomcat.threads.max=100
server.tomcat.threads.min-spare=30#开启项目热部署
spring.devtools.restart.enabled=true

4.创建依赖的实体类

基于Ant DesignPro Vue实现通过SpringBoot后台加载自定义菜单- 前后端分离

4.1 登录请求实体类UserLoginDto.java

package cn.chinaelink.im.mcvboot.dto;import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;@AllArgsConstructor
@NoArgsConstructor
@Data
public class UserLoginDto {// 用户名private String username;// 密码private String password;// 手机号private String mobile;// 验证码private String captcha;
}

4.2 向前端画面传输的用户信息实体类 UserVo.java

package cn.chinaelink.im.mcvboot.vo;import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;@AllArgsConstructor
@NoArgsConstructor
@Data
public class UserVo {private String id;private String name;private String username;private String password;private String avatar;private int status;private String telephone;private String lastLoginIp;private long lastLoginTime;private String creatorId;private long createTime;private int deleted;private String roleId;private String lang;private String token;
}

4.3 菜单实体类MenuVo.java

package cn.chinaelink.im.mcvboot.vo.menu;import lombok.Data;@Data
public class MenuVo {private String name;private int id;private int parentId;private String component;private String redirect;private String path;private MenuMetaVo meta;
}

4.4 菜单项实体类MenuMetaVo.java

package cn.chinaelink.im.mcvboot.vo.menu;import lombok.Data;@Data
public class MenuMetaVo {private String title;private String icon;private String target;private boolean show;
}

5.创建登录认证(/api/auth/)接口响应处理类

所以有接口实现都是参见src/mock/services/目录的相应的模拟接口js的结果定义的

基于Ant DesignPro Vue实现通过SpringBoot后台加载自定义菜单- 前后端分离

AuthController类

import cn.chinaelink.im.mcvboot.dto.UserLoginDto;
import cn.chinaelink.im.mcvboot.vo.UserVo;
import lombok.extern.slf4j.Slf4j;
import net.sf.json.JSONObject;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;import java.util.Optional;
import java.util.Random;
import java.util.UUID;@Controller
@Slf4j
@RequestMapping("/api/auth")
public class AuthController {@PostMapping("/login")@ResponseBodypublic String login(@RequestBody UserLoginDto userLoginDto) {JSONObject resJson = new JSONObject();if (Optional.ofNullable(userLoginDto.getUsername()).isPresent() &&("ant.design".equals(userLoginDto.getPassword()) ||"admin".equals(userLoginDto.getUsername()))) {UserVo userVo = getAdminUserVo();resJson.put("result",JSONObject.fromObject(userVo).toString());resJson.put("message","认证成功");resJson.put("code",200);resJson.put("_status", 200);resJson.put("token",userVo.getToken());return resJson.toString();} else if(Optional.ofNullable(userLoginDto.getMobile()).isPresent()){UserVo userVo =  getAdminUserVo();resJson.put("result",JSONObject.fromObject(userVo).toString());resJson.put("message","认证成功");resJson.put("code",200);resJson.put("_status", 200);resJson.put("token",userVo.getToken());return resJson.toString();}JSONObject result = new JSONObject();result.put("isLogin", true);resJson.put("result",result);resJson.put("message","错误的用户名和密码,请确认后重试!");resJson.put("code",401);resJson.put("_status", 401);return resJson.toString();}@PostMapping("/2step-code")@ResponseBodypublic JSONObject twoFactor() {JSONObject resJson = new JSONObject();JSONObject dataJson = new JSONObject();dataJson.put("stepCode",new Random().nextInt(1));resJson.put("result", dataJson);return resJson;}@PostMapping("/logout")@ResponseBodypublic JSONObject logout() {JSONObject data = new JSONObject();data.put("result", new JSONObject());data.put("message", "");return data;}private UserVo getAdminUserVo() {UserVo userVo = new UserVo();userVo.setId(UUID.randomUUID().toString());userVo.setName("超级管理员");userVo.setUsername("admin");userVo.setAvatar("https://gw.alipayobjects.com/zos/rmsportal/jZUIxmJycoymBprLOUbT.png");userVo.setStatus(1);userVo.setLastLoginTime(System.currentTimeMillis());userVo.setCreatorId("admin");userVo.setCreateTime(System.currentTimeMillis());userVo.setRoleId("admin");userVo.setLang("zh-CN");userVo.setToken("4291d7da9005377ec9aec4a71ea837f");return userVo;}
}

6.创建用户(/api/user/)接口响应处理类

package cn.chinaelink.im.mcvboot.controller.api;import cn.chinaelink.im.mcvboot.vo.menu.MenuMetaVo;
import cn.chinaelink.im.mcvboot.vo.menu.MenuVo;
import lombok.extern.slf4j.Slf4j;
import net.sf.json.JSONArray;
import net.sf.json.JSONObject;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;import java.util.ArrayList;
import java.util.List;@Controller
@Slf4j
@RequestMapping("/api/user")
public class UserController {@RequestMapping("/info")@ResponseBodypublic JSONObject info(){JSONObject userInfoJson = new JSONObject();userInfoJson.put("id", "4291d7da9005377ec9aec4a71ea837f");userInfoJson.put("name", "天野远子");userInfoJson.put("username", "admin");userInfoJson.put("password", "");userInfoJson.put("avatar", "/avatar2.jpg'");userInfoJson.put("status", 1);userInfoJson.put("telephone", "");userInfoJson.put("lastLoginIp", "27.154.74.117");userInfoJson.put("lastLoginTime", 1534837621348L);userInfoJson.put("creatorId", "admin'");userInfoJson.put("createTime", 1497160610259L);userInfoJson.put("merchantCode", "TLif2btpzg079h15bk'");userInfoJson.put("deleted", 0);userInfoJson.put("roleId", "admin'");JSONObject roleObj = new JSONObject();roleObj.put("id","admin");roleObj.put("name","管理员");roleObj.put("describe","拥有所有权限");roleObj.put("status", 1);roleObj.put("creatorId","system");roleObj.put("createTime",1497160610259L);roleObj.put("deleted", 0);JSONArray permissionArray = new JSONArray();JSONObject permission1 = new JSONObject();permission1.put("roleId","admin");permission1.put("permissionId","dashboard");permission1.put("permissionName","仪表盘");permission1.put("actions","[{\\"action\\":\\"add\\",\\"defaultCheck\\":false,\\"describe\\":\\"新增\\"},{\\"action\\":\\"query\\",\\"defaultCheck\\":false,\\"describe\\":\\"查询\\"},{\\"action\\":\\"get\\",\\"defaultCheck\\":false,\\"describe\\":\\"详情\\"},{\\"action\\":\\"update\\",\\"defaultCheck\\":false,\\"describe\\":\\"修改\\"},{\\"action\\":\\"delete\\",\\"defaultCheck\\":false,\\"describe\\":\\"删除\\"}]");JSONArray actionEntitySet = new JSONArray();JSONObject actionEntity1 = new JSONObject();actionEntity1.put("action", "add");actionEntity1.put("describe", "新增");actionEntity1.put("defaultCheck", false);actionEntitySet.add(actionEntity1);JSONObject actionEntity2 = new JSONObject();actionEntity2.put("action", "query");actionEntity2.put("describe", "查询");actionEntity2.put("defaultCheck", false);actionEntitySet.add(actionEntity2);JSONObject actionEntity3 = new JSONObject();actionEntity3.put("action", "get");actionEntity3.put("describe", "详情");actionEntity3.put("defaultCheck", false);actionEntitySet.add(actionEntity3);JSONObject actionEntity4 = new JSONObject();actionEntity4.put("action", "update");actionEntity4.put("describe", "修改");actionEntity4.put("defaultCheck", false);actionEntitySet.add(actionEntity4);JSONObject actionEntity5 = new JSONObject();actionEntity5.put("action", "delete");actionEntity5.put("describe", "删除");actionEntity5.put("defaultCheck", false);actionEntitySet.add(actionEntity5);permission1.put("actionEntitySet", actionEntitySet);permission1.put("actionList", null);permission1.put("dataAccess", null);permissionArray.add(permission1);JSONObject permission2 = new JSONObject();permission2.put("roleId","admin");permission2.put("permissionId","exception");permission2.put("permissionName","异常页面权限");permission2.put("actions","[{\\"action\\":\\"add\\",\\"defaultCheck\\":false,\\"describe\\":\\"新增\\"},{\\"action\\":\\"query\\",\\"defaultCheck\\":false,\\"describe\\":\\"查询\\"},{\\"action\\":\\"get\\",\\"defaultCheck\\":false,\\"describe\\":\\"详情\\"},{\\"action\\":\\"update\\",\\"defaultCheck\\":false,\\"describe\\":\\"修改\\"},{\\"action\\":\\"delete\\",\\"defaultCheck\\":false,\\"describe\\":\\"删除\\"}]");JSONArray actionEntitySet2 = new JSONArray();JSONObject actionEntity21 = new JSONObject();actionEntity21.put("action", "add");actionEntity21.put("describe", "新增");actionEntity21.put("defaultCheck", false);actionEntitySet2.add(actionEntity21);JSONObject actionEntity22 = new JSONObject();actionEntity22.put("action", "query");actionEntity22.put("describe", "查询");actionEntity22.put("defaultCheck", false);actionEntitySet2.add(actionEntity22);JSONObject actionEntity23 = new JSONObject();actionEntity23.put("action", "get");actionEntity23.put("describe", "详情");actionEntity23.put("defaultCheck", false);actionEntitySet2.add(actionEntity23);JSONObject actionEntity24 = new JSONObject();actionEntity24.put("action", "update");actionEntity24.put("describe", "修改");actionEntity24.put("defaultCheck", false);actionEntitySet2.add(actionEntity24);JSONObject actionEntity25 = new JSONObject();actionEntity25.put("action", "delete");actionEntity25.put("describe", "删除");actionEntity25.put("defaultCheck", false);actionEntitySet2.add(actionEntity25);permission2.put("actionEntitySet", actionEntitySet2);permission2.put("actionList", null);permission2.put("dataAccess", null);permissionArray.add(permission2);roleObj.put("permissions", permissionArray);userInfoJson.put("role", roleObj);JSONObject body = new JSONObject();body.put("result", userInfoJson);return body;}@RequestMapping("/nav")@ResponseBodypublic JSONObject getUserMenus(){List<MenuVo> dataArray = new ArrayList<>();MenuVo menu1 = new MenuVo();menu1.setId(1);menu1.setParentId(0);menu1.setName("dashboard");menu1.setComponent("RouteView");menu1.setRedirect("/dashboard/workplace");MenuMetaVo meta1 = new MenuMetaVo();meta1.setTitle("menu.dashboard");meta1.setIcon("dashboard");meta1.setShow(true);menu1.setMeta(meta1);dataArray.add(menu1);MenuVo menu2 = new MenuVo();menu2.setId(7);menu2.setParentId(1);menu2.setName("workplace");menu2.setComponent("Workplace");MenuMetaVo meta2 = new MenuMetaVo();meta2.setTitle("menu.dashboard.monitor");meta2.setShow(true);menu2.setMeta(meta2);dataArray.add(menu2);MenuVo menu3 = new MenuVo();menu3.setId(3);menu3.setParentId(1);menu3.setName("monitor");menu3.setPath("https://www.baidu.com/");MenuMetaVo meta3 = new MenuMetaVo();meta3.setTitle("menu.dashboard.workplace");meta3.setTarget("_blank");meta3.setShow(true);menu3.setMeta(meta3);dataArray.add(menu3);MenuVo menu4 = new MenuVo();menu4.setId(2);menu4.setParentId(1);menu4.setName("Analysis");menu4.setComponent("Analysis");menu4.setPath("/dashboard/analysis");MenuMetaVo meta4 = new MenuMetaVo();meta4.setTitle("menu.dashboard.analysis");meta4.setShow(true);menu4.setMeta(meta4);dataArray.add(menu4);// FormMenuVo menu5 = new MenuVo();menu5.setId(10);menu5.setParentId(0);menu5.setName("form");menu5.setComponent("RouteView");menu5.setRedirect("/form/base-form");MenuMetaVo meta5 = new MenuMetaVo();meta5.setTitle("menu.form");meta5.setIcon("form");menu5.setMeta(meta5);dataArray.add(menu5);MenuVo menu6 = new MenuVo();menu6.setId(6);menu6.setParentId(10);menu6.setName("basic-form");menu6.setComponent("BasicForm");MenuMetaVo meta6 = new MenuMetaVo();meta6.setTitle("menu.form.basic-form");menu6.setMeta(meta6);dataArray.add(menu6);MenuVo menu7 = new MenuVo();menu7.setId(5);menu7.setParentId(10);menu7.setName("step-form");menu7.setComponent("StepForm");MenuMetaVo meta7 = new MenuMetaVo();meta7.setTitle("menu.form.step-form");menu7.setMeta(meta7);dataArray.add(menu7);MenuVo menu8 = new MenuVo();menu8.setId(4);menu8.setParentId(10);menu8.setName("advanced-form");menu8.setComponent("AdvanceForm");MenuMetaVo meta8 = new MenuMetaVo();meta8.setTitle("menu.form.advanced-form");menu8.setMeta(meta8);dataArray.add(menu8);// ListMenuVo menu9 = new MenuVo();menu9.setId(10010);menu9.setParentId(0);menu9.setName("list");menu9.setComponent("RouteView");menu9.setRedirect("/list/table-list");MenuMetaVo meta9 = new MenuMetaVo();meta9.setTitle("menu.list");meta9.setIcon("table");meta9.setShow(true);menu9.setMeta(meta9);dataArray.add(menu9);MenuVo menu10 = new MenuVo();menu10.setId(10011);menu10.setParentId(10010);menu10.setName("table-list");menu10.setComponent("TableList");menu10.setPath("/list/table-list/:pageNo([1-9]\\\\d*)?");MenuMetaVo meta10 = new MenuMetaVo();meta10.setTitle("menu.list.table-list");meta10.setShow(true);menu10.setMeta(meta10);dataArray.add(menu10);MenuVo menu11 = new MenuVo();menu11.setId(10012);menu11.setParentId(10010);menu11.setName("basic-list");menu11.setComponent("StandardList");MenuMetaVo meta11 = new MenuMetaVo();meta11.setTitle("menu.list.basic-list");meta11.setShow(true);menu11.setMeta(meta11);dataArray.add(menu11);JSONObject body = new JSONObject();body.put("result", dataArray);return body;}
}

7.创建Account(/api/account)接口响应处理类

package cn.chinaelink.im.mcvboot.controller.api;import lombok.extern.slf4j.Slf4j;
import net.sf.json.JSONObject;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;import java.util.Random;@Controller
@Slf4j
@RequestMapping("/api/account")
public class AccountController {@RequestMapping("/sms")@ResponseBodypublic String smsCaptcha() {Random random = new Random();int num = random.nextInt(89999) + 10000;JSONObject data = new JSONObject();data.put("captcha", num);JSONObject response = new JSONObject();response.put("result", data);return response.toString();}
}

四、验证

1.启动服务端

基于Ant DesignPro Vue实现通过SpringBoot后台加载自定义菜单- 前后端分离

启动成功后可以通过浏览器访问http://127.0.0.1:8080/

2.启动前端

在命令行进入前端代码所在目录后,执行下面的命令

D:\\work\\JavaTeam\\workspace\\IdeaProjects\\antDesignPro\\antdvPromc> yarn run serve

基于Ant DesignPro Vue实现通过SpringBoot后台加载自定义菜单- 前后端分离

3.访问前端画面

基于Ant DesignPro Vue实现通过SpringBoot后台加载自定义菜单- 前后端分离
基于Ant DesignPro Vue实现通过SpringBoot后台加载自定义菜单- 前后端分离

说明:
通过访问,前端已正常通过http://192.168.0.100:8080这个后端服务接口登录认证成功,并成功的获取到后台返回的菜单(只返回了两项一级菜单)

摄像头大全