菜单指的是权限菜单,也就是一堆权限字符串
需要展示菜单列表,不需要分页。可以针对菜单名进行模糊查询。也可以针对菜单的状态进行查询。菜单要按照父菜单id和orderNum进行排序
| 请求方式 | 请求路径 | 是否需求token头 |
| system/menu/list | 是 |
请求参数是query格式的:
- {
- status : 状态
-
- menuName: 菜单名
- }
响应格式:
- {
- "code":200,
- "data":[
- {
- "component":"组件路径",
- "icon":"build",
- "id":"2023",
- "isFrame":1,
- "menuName":"菜单名称",
- "menuType":"C",
- "orderNum":0,
- "parentId":"0",
- "path":"write",
- "perms":"权限字符串",
- "remark":"备注信息",
- "status":"0",
- "visible":"0"
- },
- {
- "icon":"system",
- "id":"1",
- "isFrame":1,
- "menuName":"菜单名称",
- "menuType":"M",
- "orderNum":1,
- "parentId":"0",
- "path":"system",
- "perms":"权限字符串",
- "remark":"备注信息",
- "status":"0",
- "visible":"0"
- }
- ],
- "msg":"操作成功"
- }
第一步: 在keke-framework工程的Vo目录新建MenuVo类,写入如下,用于把指定字段返回给前端
- package com.keke.domain.vo;
- import lombok.AllArgsConstructor;
- import lombok.Data;
- import lombok.NoArgsConstructor;
-
- @Data
- @NoArgsConstructor
- @AllArgsConstructor
- public class AdminMenuVo {
- //菜单ID
- private Long id;
- //菜单名称
- private String menuName;
- //父菜单ID
- private Long parentId;
- //显示顺序
- private Integer orderNum;
- //路由地址
- private String path;
- //组件路径
- private String component;
- //是否为外链(0是 1否)
- private Integer isFrame;
- //菜单类型(M目录 C菜单 F按钮)
- private String menuType;
- //菜单状态(0显示 1隐藏)
- private String visible;
- //菜单状态(0正常 1停用)
- private String status;
- //权限标识
- private String perms;
- //菜单图标
- private String icon;
- //备注
- private String remark;
- }
第二步: 在keke-admin工程的controller目录新建MenuController类,写入如下,是查询菜单列表的访问接口
- package com.keke.controller;
-
-
- import com.keke.domain.ResponseResult;
- import com.keke.domain.entity.Menu;
- import com.keke.service.MenuService;
- import org.springframework.beans.factory.annotation.Autowired;
- import org.springframework.web.bind.annotation.GetMapping;
- import org.springframework.web.bind.annotation.RequestMapping;
- import org.springframework.web.bind.annotation.RestController;
-
- @RestController
- @RequestMapping("/system/menu")
- public class MenuController {
-
- @Autowired
- private MenuService menuService;
-
-
- //查询菜单列表
- @GetMapping("/list")
- public ResponseResult selectAllMenu(Menu menu){
- List
adminMenuVos = menuService.selectAllMenu(menu); - return ResponseResult.okResult(adminMenuVos);
- }
- }
第三步:把keke-framework工程的MenuService接口修改为如下,增加了查询菜单列表的接口
- package com.keke.service;
-
- import com.baomidou.mybatisplus.extension.service.IService;
- import com.keke.domain.ResponseResult;
- import com.keke.domain.entity.Menu;
-
- import java.util.List;
-
-
- /**
- * 菜单权限表(Menu)表服务接口
- *
- * @author makejava
- * @since 2023-10-18 20:55:48
- */
- public interface MenuService extends IService
-
-
- //查询用户权限信息
- List
selectPermsByUserId(Long userId); -
- //查询用户的路由信息,也就是权限菜单
- List
-
- List
selectAllMenu(Menu menu); -
- }
第四步: 把keke-framework工程的MenuServiceImpl类修改为如下,增加了查询菜单列表的具体代码实现
- package com.keke.service.impl;
-
- import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
- import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
- import com.keke.constants.SystemConstants;
- import com.keke.domain.ResponseResult;
- import com.keke.domain.entity.Menu;
- import com.keke.domain.vo.AdminMenuVo;
- import com.keke.mapper.MenuMapper;
- import com.keke.service.MenuService;
- import com.keke.utils.BeanCopyUtils;
- import com.keke.utils.SecurityUtils;
- import org.springframework.stereotype.Service;
- import org.springframework.util.StringUtils;
-
- import java.util.List;
- import java.util.function.Function;
- import java.util.stream.Collectors;
-
- /**
- * 菜单权限表(Menu)表服务实现类
- *
- * @author makejava
- * @since 2023-10-18 20:55:48
- */
- @Service("menuService")
- public class MenuServiceImpl extends ServiceImpl
implements MenuService { -
-
-
- //根据用户id查询权限关键字
- @Override
- public List
selectPermsByUserId(Long userId) { - //如果用户id为1代表管理员,roles 中只需要有admin,
- // permissions中需要有所有菜单类型为C(菜单)或者F(按钮)的,状态为正常的,未被删除的权限
- if(SecurityUtils.isAdmin()) {
- LambdaQueryWrapper
- lambdaQueryWrapper.in(Menu::getMenuType, SystemConstants.MENU, SystemConstants.BUTTON);
- lambdaQueryWrapper.eq(Menu::getStatus, SystemConstants.STATUS_NORMAL);
- //由于我们的逻辑删除字段已经配置了,所以无需封装lambdaQueryWrapper
- List
- //我们需要的是String类型的集合,这里我们要进行数据的处理,这里采用流的方式
- List
permissions = menuList.stream() - .map(new Function
- @Override
- public String apply(Menu menu) {
- String perms = menu.getPerms();
- return perms;
- }
- })
- .collect(Collectors.toList());
- return permissions;
- }
- //否则返回这个用户所具有的权限
- //这里我们需要进行连表查询,因为我们的用户先和角色关联,然后角色才跟权限关联
- MenuMapper menuMapper = getBaseMapper();
- //我们期望menuMapper中有一个方法可以直接帮我们去实现这个复杂的逻辑,这里直接返回
- return menuMapper.selectPermsByUserId(userId);
- }
-
- @Override
- public List
- MenuMapper menuMapper = getBaseMapper();
- List
- //如果是管理员,返回所有
- if(SecurityUtils.isAdmin()){
- menus = menuMapper.selectAllRoutersMenu();
- }else {
- //如果不是管理员,返回对应用户的菜单
- menus = menuMapper.selectRoutersMenuTreeByUserId(userId);
- }
- //因为上面的查询都是从数据库进行查询,所以无法封装children,这里构建Tree
-
- List
- return menuTree;
- }
-
- @Override
- public ResponseResult selectAllMenu(Menu menu) {
- //可以针对菜单名进行模糊查询。也可以针对菜单的状态进行查询
- LambdaQueryWrapper
- lambdaQueryWrapper.like(StringUtils.hasText(menu.getMenuName()),Menu::getMenuName,menu.getMenuName());
- lambdaQueryWrapper.eq(StringUtils.hasText(menu.getStatus()),Menu::getStatus,menu.getStatus());
- //排序 parent_id和order_num
- lambdaQueryWrapper.orderByAsc(Menu::getParentId,Menu::getOrderNum);
- List
- List
adminMenuVos = BeanCopyUtils.copyBeanList(menus, AdminMenuVo.class); - return adminMenuVos;
- }
-
-
-
-
-
-
- /**
- * 构建MenuTree
- * 思路先找第一层级的菜单,就是找到id于parentId的对应关系,然后把parentId设置为Id的children
- * @param menus
- * @return
- */
- private List
- //转化流处理
- List
menuTree = menus.stream() - //过滤掉除一级菜单之外的菜单
- .filter(menu -> menu.getParentId().equals(parentId))
- //然后将获取其子菜单设置到children字段,并返回
- .map(m -> m.setChildren(gerChildren(m, menus)))
- .collect(Collectors.toList());
- return menuTree;
- }
-
- //获取当前菜单的子菜单
- private List
gerChildren(Menu menu, List menus) { - //流处理,遍历每一个流对象,筛选出流对象的parentId=menu的id,即过滤
- List
children = menus.stream() - .filter(m -> m.getParentId().equals(menu.getId()))
- //这里其实不必要写,这一步的逻辑是如果有三级,
- //可以把流对象中再过筛选出子菜单设置给对应的children并返回
- .map(m -> m.setChildren(gerChildren(m,menus)))
- .collect(Collectors.toList());
- return children;
- }
-
- }
运行前端工程,打开redis,打开菜单管理


新增权限菜单
| 请求方式 | 请求路径 | 是否需求token头 |
| POST | system/menu | 是 |
请求体参数:
Menu类对应的json格式
响应格式:
- {
- "code":200,
- "msg":"操作成功"
- }
第一步: 把keke-framework工程的Menu类修改为如下,注意有四个字段使用了mybatisplus的字段自增
- package com.keke.domain.entity;
-
- import java.util.Date;
- import java.util.List;
-
- import com.baomidou.mybatisplus.annotation.FieldFill;
- import com.baomidou.mybatisplus.annotation.TableField;
- import lombok.AllArgsConstructor;
- import lombok.Data;
- import lombok.NoArgsConstructor;
- import com.baomidou.mybatisplus.annotation.TableName;
- import lombok.experimental.Accessors;
-
- /**
- * 菜单权限表(Menu)表实体类
- *
- * @author makejava
- * @since 2023-10-18 20:55:24
- */
- @SuppressWarnings("serial")
- @Data
- @NoArgsConstructor
- @AllArgsConstructor
- @Accessors(chain = true)
- @TableName("sys_menu")
- public class Menu {
- //菜单ID
- private Long id;
- //菜单名称
- private String menuName;
- //父菜单ID
- private Long parentId;
- //显示顺序
- private Integer orderNum;
- //路由地址
- private String path;
- //组件路径
- private String component;
- //是否为外链(0是 1否)
- private Integer isFrame;
- //菜单类型(M目录 C菜单 F按钮)
- private String menuType;
- //菜单状态(0显示 1隐藏)
- private String visible;
- //菜单状态(0正常 1停用)
- private String status;
- //权限标识
- private String perms;
- //菜单图标
- private String icon;
- //创建者
- @TableField(fill = FieldFill.INSERT)
- private Long createBy;
- //创建时间
- @TableField(fill = FieldFill.INSERT)
- private Date createTime;
- //更新者
- @TableField(fill = FieldFill.INSERT_UPDATE)
- private Long updateBy;
- //更新时间
- @TableField(fill = FieldFill.INSERT_UPDATE)
- private Date updateTime;
- //备注
- private String remark;
-
- private String delFlag;
-
- //由于数据库没有children字段,所以我们要添加@TableField(exist = false)注解
- // 让mybatis在查表时不查询这个字段
- @TableField(exist = false)
- private List
children; - }
第二步: 把huanf-framework工程的MenuController类修改为如下,增加了新增菜单的具体代码实现
- package com.keke.controller;
-
-
- import com.keke.domain.ResponseResult;
- import com.keke.domain.entity.Menu;
- import com.keke.service.MenuService;
- import org.springframework.beans.factory.annotation.Autowired;
- import org.springframework.web.bind.annotation.*;
-
- @RestController
- @RequestMapping("/system/menu")
- public class MenuController {
-
- @Autowired
- private MenuService menuService;
-
-
- //查询菜单列表
- @GetMapping("/list")
- public ResponseResult selectAllMenu(Menu menu){
- return menuService.selectAllMenu(menu);
- }
-
- //新增菜单
- @PostMapping
- public ResponseResult add(@RequestBody Menu menu) {
- menuService.save(menu);
- return ResponseResult.okResult();
- }
-
- }
启动工程,打开前端工程,redis
测试在 '系统管理' 页面,点击 '新增',能否可以添加"测试目录"类型的菜单


能够修改菜单,但是修改的时候不能把父菜单设置为当前菜单,如果设置了需要给出相应的提示。并且修改失败。
修改菜单包含两个接口,一个是点击修改回显出菜单的详情信息,一个是点击确定后菜单修改成功
| 请求方式 | 请求路径 | 是否需求token头 |
|---|---|---|
| Get | system/menu/{id} | 是 |
请求参数PathVariable格式:
id: 菜单id
响应格式:
- {
- "code":200,
- "data":{
- "icon":"table",
- "id":"2017",
- "menuName":"内容管理",
- "menuType":"M",
- "orderNum":"4",
- "parentId":"0",
- "path":"content",
- "remark":"",
- "status":"0",
- "visible":"0"
- },
- "msg":"操作成功"
- }
controller层新增
- package com.keke.controller;
-
-
- import com.keke.domain.ResponseResult;
- import com.keke.domain.entity.Menu;
- import com.keke.service.MenuService;
- import org.springframework.beans.factory.annotation.Autowired;
- import org.springframework.web.bind.annotation.*;
-
- @RestController
- @RequestMapping("/system/menu")
- public class MenuController {
-
- @Autowired
- private MenuService menuService;
-
-
- //查询菜单列表
- @GetMapping("/list")
- public ResponseResult selectAllMenu(Menu menu){
- return menuService.selectAllMenu(menu);
- }
-
- //新增菜单
- @PostMapping
- public ResponseResult add(@RequestBody Menu menu) {
- menuService.save(menu);
- return ResponseResult.okResult();
- }
-
- @GetMapping("/{menuId}")
- public ResponseResult getInfoById(@PathVariable("menuId") Long menuId){
- Menu menu = menuService.getById(menuId);
- return ResponseResult.okResult(menu);
- }
-
- }
点击修改按钮后,回显出菜单的详情信息

| 请求方式 | 请求路径 | 是否需求token头 |
|---|---|---|
| PUT | system/menu | 是 |
请求体参数:
Menu类对应的json格式
响应格式:
- {
- "code":200,
- "msg":"操作成功"
- }
如果把父菜单设置为当前菜单:
- {
- "code":500,
- "msg":"修改菜单'写博文'失败,上级菜单不能选择自己"
- }
第一步:Controller层新增
- package com.keke.controller;
-
-
- import com.keke.domain.ResponseResult;
- import com.keke.domain.entity.Menu;
- import com.keke.service.MenuService;
- import org.springframework.beans.factory.annotation.Autowired;
- import org.springframework.web.bind.annotation.*;
-
- @RestController
- @RequestMapping("/system/menu")
- public class MenuController {
-
- @Autowired
- private MenuService menuService;
-
-
- //查询菜单列表
- @GetMapping("/list")
- public ResponseResult selectAllMenu(Menu menu){
- return menuService.selectAllMenu(menu);
- }
-
- //新增菜单
- @PostMapping
- public ResponseResult add(@RequestBody Menu menu) {
- menuService.save(menu);
- return ResponseResult.okResult();
- }
-
- @GetMapping("/{menuId}")
- public ResponseResult getInfoById(@PathVariable("menuId") Long menuId){
- Menu menu = menuService.getById(menuId);
- return ResponseResult.okResult(menu);
- }
-
- @PutMapping
- public ResponseResult editMenu(@RequestBody Menu menu){
- return menuService.editMenu(menu);
- }
-
- }
第二步:domain/entity的Menu实体类修改四个字段,设置为mp自动填充
- package com.keke.domain.entity;
-
- import java.util.Date;
- import java.util.List;
-
- import com.baomidou.mybatisplus.annotation.FieldFill;
- import com.baomidou.mybatisplus.annotation.TableField;
- import lombok.AllArgsConstructor;
- import lombok.Data;
- import lombok.NoArgsConstructor;
- import com.baomidou.mybatisplus.annotation.TableName;
- import lombok.experimental.Accessors;
-
- /**
- * 菜单权限表(Menu)表实体类
- *
- * @author makejava
- * @since 2023-10-18 20:55:24
- */
- @SuppressWarnings("serial")
- @Data
- @NoArgsConstructor
- @AllArgsConstructor
- @Accessors(chain = true)
- @TableName("sys_menu")
- public class Menu {
- //菜单ID
- private Long id;
- //菜单名称
- private String menuName;
- //父菜单ID
- private Long parentId;
- //显示顺序
- private Integer orderNum;
- //路由地址
- private String path;
- //组件路径
- private String component;
- //是否为外链(0是 1否)
- private Integer isFrame;
- //菜单类型(M目录 C菜单 F按钮)
- private String menuType;
- //菜单状态(0显示 1隐藏)
- private String visible;
- //菜单状态(0正常 1停用)
- private String status;
- //权限标识
- private String perms;
- //菜单图标
- private String icon;
- //创建者
- @TableField(fill = FieldFill.INSERT)
- private Long createBy;
- //创建时间
- @TableField(fill = FieldFill.INSERT)
- private Date createTime;
- //更新者
- @TableField(fill = FieldFill.INSERT_UPDATE)
- private Long updateBy;
- //更新时间
- @TableField(fill = FieldFill.INSERT_UPDATE)
- private Date updateTime;
- //备注
- private String remark;
-
- private String delFlag;
-
- //由于数据库没有children字段,所以我们要添加@TableField(exist = false)注解
- // 让mybatis在查表时不查询这个字段
- @TableField(exist = false)
- private List
children; - }
第三步:service层新增
- package com.keke.service;
-
- import com.baomidou.mybatisplus.extension.service.IService;
- import com.keke.domain.ResponseResult;
- import com.keke.domain.entity.Menu;
-
- import java.util.List;
-
-
- /**
- * 菜单权限表(Menu)表服务接口
- *
- * @author makejava
- * @since 2023-10-18 20:55:48
- */
- public interface MenuService extends IService
{ -
-
- //查询用户权限信息
- List
selectPermsByUserId(Long userId); -
- //查询用户的路由信息,也就是权限菜单
- List
selectRouterMenuTreeByUserId(Long userId); -
- ResponseResult selectAllMenu(Menu menu);
-
- ResponseResult editMenu(Menu menu);
-
- }
第四步:impl层新增
- package com.keke.service.impl;
-
- import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
- import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
- import com.keke.constants.SystemConstants;
- import com.keke.domain.ResponseResult;
- import com.keke.domain.entity.Menu;
- import com.keke.domain.vo.AdminMenuVo;
- import com.keke.mapper.MenuMapper;
- import com.keke.service.MenuService;
- import com.keke.utils.BeanCopyUtils;
- import com.keke.utils.SecurityUtils;
- import org.springframework.beans.factory.annotation.Autowired;
- import org.springframework.stereotype.Service;
- import org.springframework.util.StringUtils;
-
- import java.util.List;
- import java.util.function.Function;
- import java.util.stream.Collectors;
-
- /**
- * 菜单权限表(Menu)表服务实现类
- *
- * @author makejava
- * @since 2023-10-18 20:55:48
- */
- @Service("menuService")
- public class MenuServiceImpl extends ServiceImpl
implements MenuService { -
- @Autowired
- private MenuService menuService;
-
- //根据用户id查询权限关键字
- @Override
- public List
selectPermsByUserId(Long userId) { - //如果用户id为1代表管理员,roles 中只需要有admin,
- // permissions中需要有所有菜单类型为C(菜单)或者F(按钮)的,状态为正常的,未被删除的权限
- if(SecurityUtils.isAdmin()) {
- LambdaQueryWrapper
lambdaQueryWrapper = new LambdaQueryWrapper<>(); - lambdaQueryWrapper.in(Menu::getMenuType, SystemConstants.MENU, SystemConstants.BUTTON);
- lambdaQueryWrapper.eq(Menu::getStatus, SystemConstants.STATUS_NORMAL);
- //由于我们的逻辑删除字段已经配置了,所以无需封装lambdaQueryWrapper
- List
menuList = list(lambdaQueryWrapper); - //我们需要的是String类型的集合,这里我们要进行数据的处理,这里采用流的方式
- List
permissions = menuList.stream() - .map(new Function
() { - @Override
- public String apply(Menu menu) {
- String perms = menu.getPerms();
- return perms;
- }
- })
- .collect(Collectors.toList());
- return permissions;
- }
- //否则返回这个用户所具有的权限
- //这里我们需要进行连表查询,因为我们的用户先和角色关联,然后角色才跟权限关联
- MenuMapper menuMapper = getBaseMapper();
- //我们期望menuMapper中有一个方法可以直接帮我们去实现这个复杂的逻辑,这里直接返回
- return menuMapper.selectPermsByUserId(userId);
- }
-
- @Override
- public List
selectRouterMenuTreeByUserId(Long userId) { - MenuMapper menuMapper = getBaseMapper();
- List
menus = null; - //如果是管理员,返回所有
- if(SecurityUtils.isAdmin()){
- menus = menuMapper.selectAllRoutersMenu();
- }else {
- //如果不是管理员,返回对应用户的菜单
- menus = menuMapper.selectRoutersMenuTreeByUserId(userId);
- }
- //因为上面的查询都是从数据库进行查询,所以无法封装children,这里构建Tree
-
- List
menuTree = buildMenuTree(menus,0L); - return menuTree;
- }
-
- @Override
- public ResponseResult selectAllMenu(Menu menu) {
- //可以针对菜单名进行模糊查询。也可以针对菜单的状态进行查询
- LambdaQueryWrapper
lambdaQueryWrapper = new LambdaQueryWrapper<>(); - lambdaQueryWrapper.like(StringUtils.hasText(menu.getMenuName()),Menu::getMenuName,menu.getMenuName());
- lambdaQueryWrapper.eq(StringUtils.hasText(menu.getStatus()),Menu::getStatus,menu.getStatus());
- //排序 parent_id和order_num
- lambdaQueryWrapper.orderByAsc(Menu::getParentId,Menu::getOrderNum);
- List
menus = list(lambdaQueryWrapper); - List
adminMenuVos = BeanCopyUtils.copyBeanList(menus, AdminMenuVo.class); - return ResponseResult.okResult(adminMenuVos);
- }
-
- @Override
- public ResponseResult editMenu(Menu menu) {
- if(menu.getParentId().equals(menu.getId())){
- return ResponseResult.okResult(500,"修改菜单" + "'" + menu.getMenuName() + "'" + "失败,上级菜单不能选择自己");
- }
- updateById(menu);
- return ResponseResult.okResult();
- }
-
-
- /**
- * 构建MenuTree
- * 思路先找第一层级的菜单,就是找到id于parentId的对应关系,然后把parentId设置为Id的children
- * @param menus
- * @return
- */
- private List
buildMenuTree(List menus,Long parentId) { - //转化流处理
- List
menuTree = menus.stream() - //过滤掉除一级菜单之外的菜单
- .filter(menu -> menu.getParentId().equals(parentId))
- //然后将获取其子菜单设置到children字段,并返回
- .map(m -> m.setChildren(gerChildren(m, menus)))
- .collect(Collectors.toList());
- return menuTree;
- }
-
- //获取当前菜单的子菜单
- private List
gerChildren(Menu menu, List menus) { - //流处理,遍历每一个流对象,筛选出流对象的parentId=menu的id,即过滤
- List
children = menus.stream() - .filter(m -> m.getParentId().equals(menu.getId()))
- //这里其实不必要写,这一步的逻辑是如果有三级,
- //可以把流对象中再过筛选出子菜单设置给对应的children并返回
- .map(m -> m.setChildren(gerChildren(m,menus)))
- .collect(Collectors.toList());
- return children;
- }
-
- }


能够删除菜单,但是如果要删除的菜单有子菜单则提示:存在子菜单不允许删除 并且删除失败
| 请求方式 | 请求路径 | 是否需求token头 |
|---|---|---|
| DELETE | content/article/{menuId} | 是 |
请求参数PathVariable参数:
menuId:要删除菜单的id
响应格式:
- {
- "code":200,
- "msg":"操作成功"
- }
如果有子菜单
- {
- "code":500,
- "msg":"存在子菜单不允许删除"
- }
第一步:controller层新增
- package com.keke.controller;
-
-
- import com.keke.domain.ResponseResult;
- import com.keke.domain.entity.Menu;
- import com.keke.service.MenuService;
- import org.springframework.beans.factory.annotation.Autowired;
- import org.springframework.web.bind.annotation.*;
-
- @RestController
- @RequestMapping("/system/menu")
- public class MenuController {
-
- @Autowired
- private MenuService menuService;
-
-
- //查询菜单列表
- @GetMapping("/list")
- public ResponseResult selectAllMenu(Menu menu){
- return menuService.selectAllMenu(menu);
- }
-
- //新增菜单
- @PostMapping
- public ResponseResult add(@RequestBody Menu menu) {
- menuService.save(menu);
- return ResponseResult.okResult();
- }
-
- @GetMapping("/{menuId}")
- public ResponseResult getInfoById(@PathVariable("menuId") Long menuId){
- Menu menu = menuService.getById(menuId);
- return ResponseResult.okResult(menu);
- }
-
- @PutMapping
- public ResponseResult editMenu(@RequestBody Menu menu){
- return menuService.editMenu(menu);
- }
-
- @DeleteMapping("/{menuId}")
- public ResponseResult deleteMenu(@PathVariable("menuId") Long menuId){
- return menuService.deleteMenu(menuId);
- }
-
- }
第二步:service层新增
- package com.keke.service;
-
- import com.baomidou.mybatisplus.extension.service.IService;
- import com.keke.domain.ResponseResult;
- import com.keke.domain.entity.Menu;
-
- import java.util.List;
-
-
- /**
- * 菜单权限表(Menu)表服务接口
- *
- * @author makejava
- * @since 2023-10-18 20:55:48
- */
- public interface MenuService extends IService
{ -
-
- //查询用户权限信息
- List
selectPermsByUserId(Long userId); -
- //查询用户的路由信息,也就是权限菜单
- List
selectRouterMenuTreeByUserId(Long userId); -
- ResponseResult selectAllMenu(Menu menu);
-
- ResponseResult editMenu(Menu menu);
-
- ResponseResult deleteMenu(Long menuId);
- }
第三步:impl层新增
- package com.keke.service.impl;
-
- import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
- import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
- import com.keke.constants.SystemConstants;
- import com.keke.domain.ResponseResult;
- import com.keke.domain.entity.Menu;
- import com.keke.domain.vo.AdminMenuVo;
- import com.keke.mapper.MenuMapper;
- import com.keke.service.MenuService;
- import com.keke.utils.BeanCopyUtils;
- import com.keke.utils.SecurityUtils;
- import org.springframework.beans.factory.annotation.Autowired;
- import org.springframework.stereotype.Service;
- import org.springframework.util.StringUtils;
-
- import java.util.List;
- import java.util.function.Function;
- import java.util.stream.Collectors;
-
- /**
- * 菜单权限表(Menu)表服务实现类
- *
- * @author makejava
- * @since 2023-10-18 20:55:48
- */
- @Service("menuService")
- public class MenuServiceImpl extends ServiceImpl
implements MenuService { -
- @Autowired
- private MenuService menuService;
-
- //根据用户id查询权限关键字
- @Override
- public List
selectPermsByUserId(Long userId) { - //如果用户id为1代表管理员,roles 中只需要有admin,
- // permissions中需要有所有菜单类型为C(菜单)或者F(按钮)的,状态为正常的,未被删除的权限
- if(SecurityUtils.isAdmin()) {
- LambdaQueryWrapper
lambdaQueryWrapper = new LambdaQueryWrapper<>(); - lambdaQueryWrapper.in(Menu::getMenuType, SystemConstants.MENU, SystemConstants.BUTTON);
- lambdaQueryWrapper.eq(Menu::getStatus, SystemConstants.STATUS_NORMAL);
- //由于我们的逻辑删除字段已经配置了,所以无需封装lambdaQueryWrapper
- List
menuList = list(lambdaQueryWrapper); - //我们需要的是String类型的集合,这里我们要进行数据的处理,这里采用流的方式
- List
permissions = menuList.stream() - .map(new Function
() { - @Override
- public String apply(Menu menu) {
- String perms = menu.getPerms();
- return perms;
- }
- })
- .collect(Collectors.toList());
- return permissions;
- }
- //否则返回这个用户所具有的权限
- //这里我们需要进行连表查询,因为我们的用户先和角色关联,然后角色才跟权限关联
- MenuMapper menuMapper = getBaseMapper();
- //我们期望menuMapper中有一个方法可以直接帮我们去实现这个复杂的逻辑,这里直接返回
- return menuMapper.selectPermsByUserId(userId);
- }
-
- @Override
- public List
selectRouterMenuTreeByUserId(Long userId) { - MenuMapper menuMapper = getBaseMapper();
- List
menus = null; - //如果是管理员,返回所有
- if(SecurityUtils.isAdmin()){
- menus = menuMapper.selectAllRoutersMenu();
- }else {
- //如果不是管理员,返回对应用户的菜单
- menus = menuMapper.selectRoutersMenuTreeByUserId(userId);
- }
- //因为上面的查询都是从数据库进行查询,所以无法封装children,这里构建Tree
-
- List
menuTree = buildMenuTree(menus,0L); - return menuTree;
- }
-
- @Override
- public ResponseResult selectAllMenu(Menu menu) {
- //可以针对菜单名进行模糊查询。也可以针对菜单的状态进行查询
- LambdaQueryWrapper
lambdaQueryWrapper = new LambdaQueryWrapper<>(); - lambdaQueryWrapper.like(StringUtils.hasText(menu.getMenuName()),Menu::getMenuName,menu.getMenuName());
- lambdaQueryWrapper.eq(StringUtils.hasText(menu.getStatus()),Menu::getStatus,menu.getStatus());
- //排序 parent_id和order_num
- lambdaQueryWrapper.orderByAsc(Menu::getParentId,Menu::getOrderNum);
- List
menus = list(lambdaQueryWrapper); - List
adminMenuVos = BeanCopyUtils.copyBeanList(menus, AdminMenuVo.class); - return ResponseResult.okResult(adminMenuVos);
- }
-
- @Override
- public ResponseResult editMenu(Menu menu) {
- if(menu.getParentId().equals(menu.getId())){
- return ResponseResult.okResult(500,"修改菜单" + "'" + menu.getMenuName() + "'" + "失败,上级菜单不能选择自己");
- }
- updateById(menu);
- return ResponseResult.okResult();
- }
-
- @Override
- public ResponseResult deleteMenu(Long menuId) {
- Menu menu = menuService.getById(menuId);
- //如果该菜单有子菜单,那么就提示不能删除,逻辑就是查询菜单表中是否有父菜单id是当前菜单id
- LambdaQueryWrapper
lambdaQueryWrapper = new LambdaQueryWrapper<>(); - lambdaQueryWrapper.eq(Menu::getParentId,menuId);
- List
menus = list(lambdaQueryWrapper); - if(!menus.isEmpty()) {
- return ResponseResult.okResult(500, "存在子菜单不允许删除");
- }
- removeById(menuId);
- return ResponseResult.okResult();
- }
-
-
- /**
- * 构建MenuTree
- * 思路先找第一层级的菜单,就是找到id于parentId的对应关系,然后把parentId设置为Id的children
- * @param menus
- * @return
- */
- private List
buildMenuTree(List menus,Long parentId) { - //转化流处理
- List
menuTree = menus.stream() - //过滤掉除一级菜单之外的菜单
- .filter(menu -> menu.getParentId().equals(parentId))
- //然后将获取其子菜单设置到children字段,并返回
- .map(m -> m.setChildren(gerChildren(m, menus)))
- .collect(Collectors.toList());
- return menuTree;
- }
-
- //获取当前菜单的子菜单
- private List
gerChildren(Menu menu, List menus) { - //流处理,遍历每一个流对象,筛选出流对象的parentId=menu的id,即过滤
- List
children = menus.stream() - .filter(m -> m.getParentId().equals(menu.getId()))
- //这里其实不必要写,这一步的逻辑是如果有三级,
- //可以把流对象中再过筛选出子菜单设置给对应的children并返回
- .map(m -> m.setChildren(gerChildren(m,menus)))
- .collect(Collectors.toList());
- return children;
- }
- }




需要有角色列表分页查询的功能。
要求能够针对角色名称进行模糊查询。
要求能够针对状态进行查询。
要求按照role_sort进行升序排列。
| 请求方式 | 请求路径 | 是否需求token头 |
|---|---|---|
| GET | system/role/list | 是 |
Query格式请求参数:
- pageNum: 页码
-
- pageSize: 每页条数
-
- roleName:角色名称
-
- status:状态
响应格式:
- {
- "code":200,
- "data":{
- "rows":[
- {
- "id":"12",
- "roleKey":"link",
- "roleName":"友链审核员",
- "roleSort":"1",
- "status":"0"
- }
- ],
- "total":"1"
- },
- "msg":"操作成功"
- }
第一步:新建RoleController新增
- package com.keke.controller;
-
- import com.keke.domain.ResponseResult;
- import com.keke.domain.dto.ChangeRoleStatusDto;
- import com.keke.domain.entity.Role;
- import com.keke.service.RoleService;
- import org.springframework.beans.factory.annotation.Autowired;
- import org.springframework.web.bind.annotation.*;
-
- @RestController
- @RequestMapping("/system/role")
- public class RoleController {
-
- @Autowired
- private RoleService roleService;
-
- @GetMapping("/list")
- public ResponseResult selectPageRole(Role role,Integer pageNum,Integer pageSize){
- return roleService.selectPageRole(role,pageNum,pageSize);
- }
- }
第二步:service层新增
- package com.keke.service;
-
- import com.baomidou.mybatisplus.extension.service.IService;
- import com.keke.domain.ResponseResult;
- import com.keke.domain.dto.ChangeRoleStatusDto;
- import com.keke.domain.entity.Role;
-
- import java.util.List;
-
-
- /**
- * 角色信息表(Role)表服务接口
- *
- * @author makejava
- * @since 2023-10-18 21:04:06
- */
- public interface RoleService extends IService
{ -
- List
selectRoleKeyByUserId(Long userId); -
-
- ResponseResult selectPageRole(Role role, Integer pageNum, Integer pageSize);
- }
第三步:impl层新增
- package com.keke.service.impl;
-
- import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
- import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
- import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
- import com.keke.domain.ResponseResult;
- import com.keke.domain.dto.ChangeRoleStatusDto;
- import com.keke.domain.entity.Role;
- import com.keke.domain.vo.PageVo;
- import com.keke.mapper.RoleMapper;
- import com.keke.service.RoleService;
- import org.springframework.stereotype.Service;
- import org.springframework.util.StringUtils;
-
- import java.util.ArrayList;
- import java.util.List;
-
- /**
- * 角色信息表(Role)表服务实现类
- *
- * @author makejava
- * @since 2023-10-18 21:04:06
- */
- @Service("roleService")
- public class RoleServiceImpl extends ServiceImpl
implements RoleService { -
-
- //根据用户id查询角色信息
- @Override
- public List
selectRoleKeyByUserId(Long userId) { - //如果userId为1,那么角色权限字符串就只需要返回一个admin
- if(userId==1L){
- List
roles = new ArrayList<>(); - roles.add("admin");
- return roles;
- }
- //如果用户id不为1,那么需要根据userId连表查询对应的roleId,然后再去角色表中去查询
- //对应的角色权限字符串
- //这里我们期望RoleMapper中封装一个方法去帮我们实现这个复杂的操作
- RoleMapper roleMapper = getBaseMapper();
- return roleMapper.selectRoleKeyByUserId(userId);
- }
-
- @Override
- public ResponseResult selectPageRole(Role role, Integer pageNum, Integer pageSize) {
- LambdaQueryWrapper
lambdaQueryWrapper = new LambdaQueryWrapper<>(); - lambdaQueryWrapper.like(StringUtils.hasText(role.getRoleName()),Role::getRoleName,role.getRoleName());
- lambdaQueryWrapper.eq(StringUtils.hasText(role.getStatus()),Role::getStatus,role.getStatus());
- lambdaQueryWrapper.orderByAsc(Role::getRoleSort);
- Page
page = new Page<>(pageNum,pageSize); - page(page,lambdaQueryWrapper);
- PageVo pageVo = new PageVo(page.getRecords(),page.getTotal());
- return ResponseResult.okResult(pageVo);
- }
- }

要求能够修改角色的停启用状态
| 请求方式 | 请求路径 | 是否需求token头 |
|---|---|---|
| PUT | system/role/changeStatus | 是 |
请求体:
- {
- "roleId":"11",
- "status":"1"
- }
响应格式:
- {
- "code":200,
- "msg":"操作成功"
- }
第一步:controller层新增
- package com.keke.controller;
-
- import com.keke.domain.ResponseResult;
- import com.keke.domain.dto.ChangeRoleStatusDto;
- import com.keke.domain.entity.Role;
- import com.keke.service.RoleService;
- import org.springframework.beans.factory.annotation.Autowired;
- import org.springframework.web.bind.annotation.*;
-
- @RestController
- @RequestMapping("/system/role")
- public class RoleController {
-
- @Autowired
- private RoleService roleService;
-
- @GetMapping("/list")
- public ResponseResult selectPageRole(Role role,Integer pageNum,Integer pageSize){
- return roleService.selectPageRole(role,pageNum,pageSize);
- }
-
- @PutMapping("/changeStatus")
- public ResponseResult changeRoleStatus(@RequestBody ChangeRoleStatusDto changeRoleStatusDto){
- return roleService.changeRoleStatus(changeRoleStatusDto);
- }
- }
第二步:domain/dto新增
- package com.keke.domain.dto;
-
- import lombok.AllArgsConstructor;
- import lombok.Data;
- import lombok.NoArgsConstructor;
-
- @Data
- @AllArgsConstructor
- @NoArgsConstructor
- public class ChangeRoleStatusDto {
-
- private Long roleId;
- //角色状态(0正常 1停用)
- private String status;
-
- }
第三步:service层新增
- package com.keke.service;
-
- import com.baomidou.mybatisplus.extension.service.IService;
- import com.keke.domain.ResponseResult;
- import com.keke.domain.dto.ChangeRoleStatusDto;
- import com.keke.domain.entity.Role;
-
- import java.util.List;
-
-
- /**
- * 角色信息表(Role)表服务接口
- *
- * @author makejava
- * @since 2023-10-18 21:04:06
- */
- public interface RoleService extends IService
{ -
- List
selectRoleKeyByUserId(Long userId); -
-
- ResponseResult selectPageRole(Role role, Integer pageNum, Integer pageSize);
-
- ResponseResult changeRoleStatus(ChangeRoleStatusDto changeRoleStatusDto);
- }
第四步:impl层新增
- package com.keke.service.impl;
-
- import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
- import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
- import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
- import com.keke.domain.ResponseResult;
- import com.keke.domain.dto.ChangeRoleStatusDto;
- import com.keke.domain.entity.Role;
- import com.keke.domain.vo.PageVo;
- import com.keke.mapper.RoleMapper;
- import com.keke.service.RoleService;
- import org.springframework.stereotype.Service;
- import org.springframework.util.StringUtils;
-
- import java.util.ArrayList;
- import java.util.List;
-
- /**
- * 角色信息表(Role)表服务实现类
- *
- * @author makejava
- * @since 2023-10-18 21:04:06
- */
- @Service("roleService")
- public class RoleServiceImpl extends ServiceImpl
implements RoleService { -
-
- //根据用户id查询角色信息
- @Override
- public List
selectRoleKeyByUserId(Long userId) { - //如果userId为1,那么角色权限字符串就只需要返回一个admin
- if(userId==1L){
- List
roles = new ArrayList<>(); - roles.add("admin");
- return roles;
- }
- //如果用户id不为1,那么需要根据userId连表查询对应的roleId,然后再去角色表中去查询
- //对应的角色权限字符串
- //这里我们期望RoleMapper中封装一个方法去帮我们实现这个复杂的操作
- RoleMapper roleMapper = getBaseMapper();
- return roleMapper.selectRoleKeyByUserId(userId);
- }
-
- @Override
- public ResponseResult selectPageRole(Role role, Integer pageNum, Integer pageSize) {
- LambdaQueryWrapper
lambdaQueryWrapper = new LambdaQueryWrapper<>(); - lambdaQueryWrapper.like(StringUtils.hasText(role.getRoleName()),Role::getRoleName,role.getRoleName());
- lambdaQueryWrapper.eq(StringUtils.hasText(role.getStatus()),Role::getStatus,role.getStatus());
- lambdaQueryWrapper.orderByAsc(Role::getRoleSort);
- Page
page = new Page<>(pageNum,pageSize); - page(page,lambdaQueryWrapper);
- PageVo pageVo = new PageVo(page.getRecords(),page.getTotal());
- return ResponseResult.okResult(pageVo);
- }
-
- @Override
- public ResponseResult changeRoleStatus(ChangeRoleStatusDto changeRoleStatusDto) {
- Long roleId = changeRoleStatusDto.getRoleId();
- Role role = getById(roleId);
- role.setStatus(changeRoleStatusDto.getStatus());
- updateById(role);
- return ResponseResult.okResult();
- }
- }
把该用户启用



数据库中状态正常
需要提供新增角色的功能。新增角色时能够直接设置角色所关联的菜单权限
首先应该获取权限菜单数,勾选,然后才能新增
分析下来,有两个接口需要实现
| 请求方式 | 请求路径 | 是否需求token头 |
|---|---|---|
| GET | /system/menu/treeselect | 是 |
无需请求参数
响应格式:
- {
- "code":200,
- "data":[
- {
- "children":[],
- "id":"2023",
- "label":"写博文",
- "parentId":"0"
- },
- {
- "children":[
- {
- "children":[
- {
- "children":[],
- "id":"1001",
- "label":"用户查询",
- "parentId":"100"
- },
- {
- "children":[],
- "id":"1007",
- "label":"重置密码",
- "parentId":"100"
- }
- ],
- "id":"100",
- "label":"用户管理",
- "parentId":"1"
- },
- {
- "children":[
- {
- "children":[],
- "id":"2024",
- "label":"友链新增",
- "parentId":"2022"
- },
- {
- "children":[],
- "id":"2025",
- "label":"友链修改",
- "parentId":"2022"
- },
- {
- "children":[],
- "id":"2026",
- "label":"友链删除",
- "parentId":"2022"
- },
- {
- "children":[],
- "id":"2027",
- "label":"友链查询",
- "parentId":"2022"
- }
- ],
- "id":"2022",
- "label":"友链管理",
- "parentId":"2017"
- },
- {
- "children":[],
- "id":"2021",
- "label":"标签管理",
- "parentId":"2017"
- }
- ],
- "id":"2017",
- "label":"内容管理",
- "parentId":"0"
- }
- ],
- "msg":"操作成功"
- }
第一步:keke-framework的domain/entity Role实体类修改如下,加上mp自填充,并且加上menuIds字段
- package com.keke.domain.entity;
-
- import java.util.Date;
- import java.io.Serializable;
- import java.util.List;
-
- import com.baomidou.mybatisplus.annotation.FieldFill;
- import com.baomidou.mybatisplus.annotation.TableField;
- import lombok.AllArgsConstructor;
- import lombok.Data;
- import lombok.NoArgsConstructor;
- import com.baomidou.mybatisplus.annotation.TableName;
-
- /**
- * 角色信息表(Role)表实体类
- *
- * @author makejava
- * @since 2023-10-18 21:03:52
- */
- @SuppressWarnings("serial")
- @Data
- @NoArgsConstructor
- @AllArgsConstructor
- @TableName("sys_role")
- public class Role {
- //角色ID
- private Long id;
- //角色名称
- private String roleName;
- //角色权限字符串
- private String roleKey;
- //显示顺序
- private Integer roleSort;
- //角色状态(0正常 1停用)
- private String status;
- //删除标志(0代表存在 1代表删除)
- private String delFlag;
- //创建者
- @TableField(fill = FieldFill.INSERT)
- private Long createBy;
- //创建时间
- @TableField(fill = FieldFill.INSERT)
- private Date createTime;
- //更新者
- @TableField(fill = FieldFill.INSERT_UPDATE)
- private Long updateBy;
- //更新时间
- @TableField(fill = FieldFill.INSERT_UPDATE)
- private Date updateTime;
- //备注
- private String remark;
- //角色关联的menuIds
- List
menuIds; - }
第二步:vo层创建MenuTreeVo
- package com.keke.domain.vo;
-
- import lombok.AllArgsConstructor;
- import lombok.Data;
- import lombok.NoArgsConstructor;
- import lombok.experimental.Accessors;
-
- import java.util.List;
-
-
- @Data
- @NoArgsConstructor
- @AllArgsConstructor
- @Accessors(chain = true)
- //新增角色-获取菜单下拉树列表
- public class MenuTreeVo {
- private static final long serialVersionUID = 1L;
- /** 节点ID */
- private Long id;
- /** 节点名称 */
- private String label;
-
- private Long parentId;
- /** 子节点 */
- private List
children; - }
第三步:entity层新增RoleMenu实体类
- package com.keke.domain.entity;
-
- import java.io.Serializable;
- import lombok.AllArgsConstructor;
- import lombok.Data;
- import lombok.NoArgsConstructor;
- import com.baomidou.mybatisplus.annotation.TableName;
-
- /**
- * 角色和菜单关联表(RoleMenu)表实体类
- *
- * @author makejava
- * @since 2023-10-23 17:00:27
- */
- @SuppressWarnings("serial")
- @Data
- @NoArgsConstructor
- @AllArgsConstructor
- @TableName("sys_role_menu")
- public class RoleMenu {
- //角色ID
- private Long roleId;
- //菜单ID
- private Long menuId;
-
- }
第四步:mapper层新增RoleMenuMapper
- package com.keke.mapper;
-
- import com.baomidou.mybatisplus.core.mapper.BaseMapper;
- import com.keke.domain.entity.RoleMenu;
-
-
- /**
- * 角色和菜单关联表(RoleMenu)表数据库访问层
- *
- * @author makejava
- * @since 2023-10-23 17:01:09
- */
- public interface RoleMenuMapper extends BaseMapper
{ -
- }
第五步:service层新增RoleMenuService
- package com.keke.service;
-
- import com.baomidou.mybatisplus.extension.service.IService;
- import com.keke.domain.entity.RoleMenu;
-
-
- /**
- * 角色和菜单关联表(RoleMenu)表服务接口
- *
- * @author makejava
- * @since 2023-10-23 17:01:09
- */
- public interface RoleMenuService extends IService
{ -
- }
第六步:impl层新增RoleMenuServiceImpl
- package com.keke.service.impl;
-
- import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
- import com.keke.domain.entity.RoleMenu;
- import com.keke.mapper.RoleMenuMapper;
- import com.keke.service.RoleMenuService;
- import org.springframework.stereotype.Service;
-
- /**
- * 角色和菜单关联表(RoleMenu)表服务实现类
- *
- * @author makejava
- * @since 2023-10-23 17:01:09
- */
- @Service("roleMenuService")
- public class RoleMenuServiceImpl extends ServiceImpl
implements RoleMenuService { -
- }
第七步:在keke-framework工程的utils目录新建SystemConverter类,写入如下,是一个获取菜单下拉树工具类
- package com.keke.utils;
-
- import com.keke.domain.entity.Menu;
- import com.keke.domain.vo.MenuTreeVo;
-
- import java.util.List;
- import java.util.Objects;
- import java.util.stream.Collectors;
-
- public class SystemConverter {
-
- private SystemConverter() {}
-
- public static List
buildMenuSelectTree(List menus) { - List
MenuTreeVos = menus.stream() - .map(m -> new MenuTreeVo(m.getId(), m.getMenuName(), m.getParentId(), null))
- .collect(Collectors.toList());
- List
options = MenuTreeVos.stream() - .filter(o -> o.getParentId().equals(0L))
- .map(o -> o.setChildren(getChildList(MenuTreeVos, o)))
- .collect(Collectors.toList());
- return options;
- }
-
-
- /**
- * 得到子节点列表
- */
- private static List
getChildList(List list, MenuTreeVo option) { - List
options = list.stream() - .filter(o -> Objects.equals(o.getParentId(), option.getId()))
- .map(o -> o.setChildren(getChildList(list, o)))
- .collect(Collectors.toList());
- return options;
- }
- }
第八步:keke-admin的MenuController中写接口
- package com.keke.controller;
-
-
- import com.keke.domain.ResponseResult;
- import com.keke.domain.entity.Menu;
- import com.keke.domain.vo.AdminMenuVo;
- import com.keke.domain.vo.MenuTreeVo;
- import com.keke.service.MenuService;
- import com.keke.utils.BeanCopyUtils;
- import com.keke.utils.SystemConverter;
- import org.springframework.beans.factory.annotation.Autowired;
- import org.springframework.web.bind.annotation.*;
-
- import java.util.List;
-
- @RestController
- @RequestMapping("/system/menu")
- public class MenuController {
-
- @Autowired
- private MenuService menuService;
-
-
- //查询菜单列表
- @GetMapping("/list")
- public ResponseResult selectAllMenu(Menu menu){
- List
adminMenuVos = menuService.selectAllMenu(menu); - return ResponseResult.okResult(adminMenuVos);
- }
-
- //新增菜单
- @PostMapping
- public ResponseResult add(@RequestBody Menu menu) {
- menuService.save(menu);
- return ResponseResult.okResult();
- }
-
- @GetMapping("/{menuId}")
- public ResponseResult getInfoById(@PathVariable("menuId") Long menuId){
- Menu menu = menuService.getById(menuId);
- return ResponseResult.okResult(menu);
- }
-
- @PutMapping
- public ResponseResult editMenu(@RequestBody Menu menu){
- return menuService.editMenu(menu);
- }
-
- @DeleteMapping("/{menuId}")
- public ResponseResult deleteMenu(@PathVariable("menuId") Long menuId){
- return menuService.deleteMenu(menuId);
- }
-
- @GetMapping("/treeselect")
- public ResponseResult treeSelect(){
- //复用之前的selectMenuList方法。方法需要参数,参数可以用来进行条件查询,而这个方法不需要条件,所以直接new Menu()传入
- //这样就可以获取所有的菜单了
- List
adminMenuVos = menuService.selectAllMenu(new Menu()); - List
menus = BeanCopyUtils.copyBeanList(adminMenuVos, Menu.class); - List
options = SystemConverter.buildMenuSelectTree(menus); - return ResponseResult.okResult(options);
- }
-
- }

| 请求方式 | 请求路径 | 是否需求token头 |
|---|---|---|
| POST | system/role | 是 |
请求体:
- {
- "roleName":"测试新增角色",
- "roleKey":"wds",
- "roleSort":0,
- "status":"0",
- "menuIds":[
- "1",
- "100"
- ],
- "remark":"我是角色备注"
- }
响应格式:
- {
- "code":200,
- "msg":"操作成功"
- }
第一步:domain/dto层新增
- package com.keke.domain.dto;
-
- import com.baomidou.mybatisplus.annotation.FieldFill;
- import com.baomidou.mybatisplus.annotation.TableField;
- import lombok.AllArgsConstructor;
- import lombok.Data;
- import lombok.NoArgsConstructor;
-
- import java.util.Date;
- import java.util.List;
-
- @Data
- @AllArgsConstructor
- @NoArgsConstructor
- public class AdminAddRoleDto {
- //角色名称
- private String roleName;
- //角色权限字符串
- private String roleKey;
- //显示顺序
- private Integer roleSort;
- //角色状态(0正常 1停用)
- private String status;
- //备注
- private String remark;
- //关联的menuId
- List
menuIds; - }
第二步:domain/entity层新增
- package com.keke.domain.entity;
-
- import java.io.Serializable;
- import lombok.AllArgsConstructor;
- import lombok.Data;
- import lombok.NoArgsConstructor;
- import com.baomidou.mybatisplus.annotation.TableName;
-
- /**
- * 角色和菜单关联表(RoleMenu)表实体类
- *
- * @author makejava
- * @since 2023-10-23 17:00:27
- */
- @SuppressWarnings("serial")
- @Data
- @NoArgsConstructor
- @AllArgsConstructor
- @TableName("sys_role_menu")
- public class RoleMenu {
- //角色ID
- private Long roleId;
- //菜单ID
- private Long menuId;
-
- }
第三步:mapper层新增RoleMenuMapper
- package com.keke.mapper;
-
- import com.baomidou.mybatisplus.core.mapper.BaseMapper;
- import com.keke.domain.entity.RoleMenu;
-
-
- /**
- * 角色和菜单关联表(RoleMenu)表数据库访问层
- *
- * @author makejava
- * @since 2023-10-23 17:01:09
- */
- public interface RoleMenuMapper extends BaseMapper
{ -
- }
第四步:service新增RoleMenuService
- package com.keke.service;
-
- import com.baomidou.mybatisplus.extension.service.IService;
- import com.keke.domain.entity.RoleMenu;
-
-
- /**
- * 角色和菜单关联表(RoleMenu)表服务接口
- *
- * @author makejava
- * @since 2023-10-23 17:01:09
- */
- public interface RoleMenuService extends IService
{ -
- }
第五步:impl层新增RoleMenuServiceImpl
- package com.keke.service.impl;
-
- import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
- import com.keke.domain.entity.RoleMenu;
- import com.keke.mapper.RoleMenuMapper;
- import com.keke.service.RoleMenuService;
- import org.springframework.stereotype.Service;
-
- /**
- * 角色和菜单关联表(RoleMenu)表服务实现类
- *
- * @author makejava
- * @since 2023-10-23 17:01:09
- */
- @Service("roleMenuService")
- public class RoleMenuServiceImpl extends ServiceImpl
implements RoleMenuService { -
- }
第六步:controller的RoleController新增
- package com.keke.controller;
-
- import com.keke.domain.ResponseResult;
- import com.keke.domain.dto.AdminAddRoleDto;
- import com.keke.domain.dto.ChangeRoleStatusDto;
- import com.keke.domain.entity.Role;
- import com.keke.service.RoleService;
- import org.springframework.beans.factory.annotation.Autowired;
- import org.springframework.web.bind.annotation.*;
-
- @RestController
- @RequestMapping("/system/role")
- public class RoleController {
-
- @Autowired
- private RoleService roleService;
-
- @GetMapping("/list")
- public ResponseResult selectPageRole(Role role,Integer pageNum,Integer pageSize){
- return roleService.selectPageRole(role,pageNum,pageSize);
- }
-
- @PutMapping("/changeStatus")
- public ResponseResult changeRoleStatus(@RequestBody ChangeRoleStatusDto changeRoleStatusDto){
- return roleService.changeRoleStatus(changeRoleStatusDto);
- }
-
- @PostMapping
- public ResponseResult addRole(@RequestBody AdminAddRoleDto adminAddRoleDto){
- return roleService.addRole(adminAddRoleDto);
- }
-
- }
第七步:service层的RoleService新增
- package com.keke.service;
-
- import com.baomidou.mybatisplus.extension.service.IService;
- import com.keke.domain.ResponseResult;
- import com.keke.domain.dto.AdminAddRoleDto;
- import com.keke.domain.dto.ChangeRoleStatusDto;
- import com.keke.domain.entity.Role;
-
- import java.util.List;
-
-
- /**
- * 角色信息表(Role)表服务接口
- *
- * @author makejava
- * @since 2023-10-18 21:04:06
- */
- public interface RoleService extends IService
{ -
- List
selectRoleKeyByUserId(Long userId); -
-
- ResponseResult selectPageRole(Role role, Integer pageNum, Integer pageSize);
-
- ResponseResult changeRoleStatus(ChangeRoleStatusDto changeRoleStatusDto);
-
- ResponseResult addRole(AdminAddRoleDto adminAddRoleDto);
-
- }
第八步:impl层的RoleServiceImpl新增,记得方法加上@Transactional注解
- package com.keke.service.impl;
-
- import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
- import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
- import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
- import com.keke.domain.ResponseResult;
- import com.keke.domain.dto.AdminAddRoleDto;
- import com.keke.domain.dto.ChangeRoleStatusDto;
- import com.keke.domain.entity.Role;
- import com.keke.domain.entity.RoleMenu;
- import com.keke.domain.vo.PageVo;
- import com.keke.mapper.RoleMapper;
- import com.keke.service.RoleMenuService;
- import com.keke.service.RoleService;
- import com.keke.utils.BeanCopyUtils;
- import org.springframework.beans.factory.annotation.Autowired;
- import org.springframework.stereotype.Service;
- import org.springframework.transaction.annotation.Transactional;
- import org.springframework.util.StringUtils;
-
- import java.util.ArrayList;
- import java.util.List;
- import java.util.function.Function;
- import java.util.stream.Collectors;
-
- /**
- * 角色信息表(Role)表服务实现类
- *
- * @author makejava
- * @since 2023-10-18 21:04:06
- */
- @Service("roleService")
- public class RoleServiceImpl extends ServiceImpl
implements RoleService { -
- @Autowired
- private RoleMenuService roleMenuService;
-
- //根据用户id查询角色信息
- @Override
- public List
selectRoleKeyByUserId(Long userId) { - //如果userId为1,那么角色权限字符串就只需要返回一个admin
- if(userId==1L){
- List
roles = new ArrayList<>(); - roles.add("admin");
- return roles;
- }
- //如果用户id不为1,那么需要根据userId连表查询对应的roleId,然后再去角色表中去查询
- //对应的角色权限字符串
- //这里我们期望RoleMapper中封装一个方法去帮我们实现这个复杂的操作
- RoleMapper roleMapper = getBaseMapper();
- return roleMapper.selectRoleKeyByUserId(userId);
- }
-
- @Override
- public ResponseResult selectPageRole(Role role, Integer pageNum, Integer pageSize) {
- LambdaQueryWrapper
lambdaQueryWrapper = new LambdaQueryWrapper<>(); - lambdaQueryWrapper.like(StringUtils.hasText(role.getRoleName()),Role::getRoleName,role.getRoleName());
- lambdaQueryWrapper.eq(StringUtils.hasText(role.getStatus()),Role::getStatus,role.getStatus());
- lambdaQueryWrapper.orderByAsc(Role::getRoleSort);
- Page
page = new Page<>(pageNum,pageSize); - page(page,lambdaQueryWrapper);
- PageVo pageVo = new PageVo(page.getRecords(),page.getTotal());
- return ResponseResult.okResult(pageVo);
- }
-
- @Override
- public ResponseResult changeRoleStatus(ChangeRoleStatusDto changeRoleStatusDto) {
- Long roleId = changeRoleStatusDto.getRoleId();
- Role role = getById(roleId);
- role.setStatus(changeRoleStatusDto.getStatus());
- updateById(role);
- return ResponseResult.okResult();
- }
-
- @Transactional
- @Override
- public ResponseResult addRole(AdminAddRoleDto adminAddRoleDto) {
- //Bean拷贝
- Role role = BeanCopyUtils.copyBean(adminAddRoleDto, Role.class);
- //拿到菜单权限id集合
- List
menuIds = adminAddRoleDto.getMenuIds(); - //流式处理转化,把每一个menuId都设置到该roleId下
- List
roleMenuList = menuIds.stream() - .map(new Function
() { - @Override
- public RoleMenu apply(Long menuId) {
- RoleMenu roleMenu = new RoleMenu();
- roleMenu.setRoleId(role.getId());
- roleMenu.setMenuId(menuId);
- return roleMenu;
- }
- }).collect(Collectors.toList());
- //mp批量保存到数据库中
- roleMenuService.saveBatch(roleMenuList);
- //封装返回
- return ResponseResult.okResult();
- }
- }
第九步:domain/entity的Role实体类修改四个字段为mp自动填充
- package com.keke.domain.entity;
-
- import java.util.Date;
- import java.io.Serializable;
-
- import com.baomidou.mybatisplus.annotation.FieldFill;
- import com.baomidou.mybatisplus.annotation.TableField;
- import lombok.AllArgsConstructor;
- import lombok.Data;
- import lombok.NoArgsConstructor;
- import com.baomidou.mybatisplus.annotation.TableName;
-
- /**
- * 角色信息表(Role)表实体类
- *
- * @author makejava
- * @since 2023-10-18 21:03:52
- */
- @SuppressWarnings("serial")
- @Data
- @NoArgsConstructor
- @AllArgsConstructor
- @TableName("sys_role")
- public class Role {
- //角色ID
- private Long id;
- //角色名称
- private String roleName;
- //角色权限字符串
- private String roleKey;
- //显示顺序
- private Integer roleSort;
- //角色状态(0正常 1停用)
- private String status;
- //删除标志(0代表存在 1代表删除)
- private String delFlag;
- //创建者
- @TableField(fill = FieldFill.INSERT)
- private Long createBy;
- //创建时间
- @TableField(fill = FieldFill.INSERT)
- private Date createTime;
- //更新者
- @TableField(fill = FieldFill.INSERT_UPDATE)
- private Long updateBy;
- //更新时间
- @TableField(fill = FieldFill.INSERT_UPDATE)
- private Date updateTime;
- //备注
- private String remark;
- }
需要提供修改角色的功能。修改角色时可以修改角色所关联的菜单权限
这里可以分析到修改角色有三个接口,一个点击是修改角色后,角色信息的回显接口,回显中有一个菜单权限树接口,另一个是修改角色的接口
| 请求路径 | 请求方式 | 是否需求token头 |
|---|---|---|
| system/role/{id} | Get | 是 |
请求参数PathVariable格式:
id: 角色id
响应格式:
- {
- "code":200,
- "data":{
- "id":"11",
- "remark":"嘎嘎嘎",
- "roleKey":"aggag",
- "roleName":"嘎嘎嘎",
- "roleSort":"5",
- "status":"0"
- },
- "msg":"操作成功"
- }
第一步:controller层
- package com.keke.controller;
-
- import com.keke.domain.ResponseResult;
- import com.keke.domain.dto.AdminAddRoleDto;
- import com.keke.domain.dto.ChangeRoleStatusDto;
- import com.keke.domain.entity.Role;
- import com.keke.service.RoleService;
- import org.springframework.beans.factory.annotation.Autowired;
- import org.springframework.web.bind.annotation.*;
-
- @RestController
- @RequestMapping("/system/role")
- public class RoleController {
-
- @Autowired
- private RoleService roleService;
-
- @GetMapping("/list")
- public ResponseResult selectPageRole(Role role,Integer pageNum,Integer pageSize){
- return roleService.selectPageRole(role,pageNum,pageSize);
- }
-
- @PutMapping("/changeStatus")
- public ResponseResult changeRoleStatus(@RequestBody ChangeRoleStatusDto changeRoleStatusDto){
- return roleService.changeRoleStatus(changeRoleStatusDto);
- }
-
- @PostMapping
- public ResponseResult addRole(@RequestBody AdminAddRoleDto adminAddRoleDto){
- return roleService.addRole(adminAddRoleDto);
- }
-
- @GetMapping("/{id}")
- public ResponseResult getRoleInfo(@PathVariable("id") Long id){
- return roleService.getRoleInfo(id);
- }
- }
第二步:domain/vo层新增
- package com.keke.domain.vo;
-
- import com.baomidou.mybatisplus.annotation.FieldFill;
- import com.baomidou.mybatisplus.annotation.TableField;
- import lombok.AllArgsConstructor;
- import lombok.Data;
- import lombok.NoArgsConstructor;
-
- import java.util.Date;
-
- @Data
- @AllArgsConstructor
- @NoArgsConstructor
- public class AdminRoleVo {
- //角色ID
- private Long id;
- //角色名称
- private String roleName;
- //角色权限字符串
- private String roleKey;
- //显示顺序
- private Integer roleSort;
- //角色状态(0正常 1停用)
- private String status;
- //备注
- private String remark;
- }
第三步:service层
- package com.keke.service;
-
- import com.baomidou.mybatisplus.extension.service.IService;
- import com.keke.domain.ResponseResult;
- import com.keke.domain.dto.AdminAddRoleDto;
- import com.keke.domain.dto.ChangeRoleStatusDto;
- import com.keke.domain.entity.Role;
-
- import java.util.List;
-
-
- /**
- * 角色信息表(Role)表服务接口
- *
- * @author makejava
- * @since 2023-10-18 21:04:06
- */
- public interface RoleService extends IService
{ -
- List
selectRoleKeyByUserId(Long userId); -
-
- ResponseResult selectPageRole(Role role, Integer pageNum, Integer pageSize);
-
- ResponseResult changeRoleStatus(ChangeRoleStatusDto changeRoleStatusDto);
-
- ResponseResult addRole(AdminAddRoleDto adminAddRoleDto);
-
- ResponseResult getRoleInfo(Long id);
- }
第四步:impl层新增
- package com.keke.service.impl;
-
- import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
- import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
- import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
- import com.keke.domain.ResponseResult;
- import com.keke.domain.dto.AdminAddRoleDto;
- import com.keke.domain.dto.ChangeRoleStatusDto;
- import com.keke.domain.entity.Role;
- import com.keke.domain.entity.RoleMenu;
- import com.keke.domain.vo.AdminRoleVo;
- import com.keke.domain.vo.PageVo;
- import com.keke.mapper.RoleMapper;
- import com.keke.service.RoleMenuService;
- import com.keke.service.RoleService;
- import com.keke.utils.BeanCopyUtils;
- import org.springframework.beans.factory.annotation.Autowired;
- import org.springframework.stereotype.Service;
- import org.springframework.transaction.annotation.Transactional;
- import org.springframework.util.StringUtils;
-
- import java.util.ArrayList;
- import java.util.List;
- import java.util.function.Function;
- import java.util.stream.Collectors;
-
- /**
- * 角色信息表(Role)表服务实现类
- *
- * @author makejava
- * @since 2023-10-18 21:04:06
- */
- @Service("roleService")
- public class RoleServiceImpl extends ServiceImpl
implements RoleService { -
- @Autowired
- private RoleMenuService roleMenuService;
-
- //根据用户id查询角色信息
- @Override
- public List
selectRoleKeyByUserId(Long userId) { - //如果userId为1,那么角色权限字符串就只需要返回一个admin
- if(userId==1L){
- List
roles = new ArrayList<>(); - roles.add("admin");
- return roles;
- }
- //如果用户id不为1,那么需要根据userId连表查询对应的roleId,然后再去角色表中去查询
- //对应的角色权限字符串
- //这里我们期望RoleMapper中封装一个方法去帮我们实现这个复杂的操作
- RoleMapper roleMapper = getBaseMapper();
- return roleMapper.selectRoleKeyByUserId(userId);
- }
-
- @Override
- public ResponseResult selectPageRole(Role role, Integer pageNum, Integer pageSize) {
- LambdaQueryWrapper
lambdaQueryWrapper = new LambdaQueryWrapper<>(); - lambdaQueryWrapper.like(StringUtils.hasText(role.getRoleName()),Role::getRoleName,role.getRoleName());
- lambdaQueryWrapper.eq(StringUtils.hasText(role.getStatus()),Role::getStatus,role.getStatus());
- lambdaQueryWrapper.orderByAsc(Role::getRoleSort);
- Page
page = new Page<>(pageNum,pageSize); - page(page,lambdaQueryWrapper);
- PageVo pageVo = new PageVo(page.getRecords(),page.getTotal());
- return ResponseResult.okResult(pageVo);
- }
-
- @Override
- public ResponseResult changeRoleStatus(ChangeRoleStatusDto changeRoleStatusDto) {
- Long roleId = changeRoleStatusDto.getRoleId();
- Role role = getById(roleId);
- role.setStatus(changeRoleStatusDto.getStatus());
- updateById(role);
- return ResponseResult.okResult();
- }
-
- @Transactional
- @Override
- public ResponseResult addRole(AdminAddRoleDto adminAddRoleDto) {
- //Bean拷贝
- Role role = BeanCopyUtils.copyBean(adminAddRoleDto, Role.class);
- //拿到菜单权限id集合
- List
menuIds = adminAddRoleDto.getMenuIds(); - //流式处理转化,把每一个menuId都设置到该roleId下
- List
roleMenuList = menuIds.stream() - .map(new Function
() { - @Override
- public RoleMenu apply(Long menuId) {
- RoleMenu roleMenu = new RoleMenu();
- roleMenu.setRoleId(role.getId());
- roleMenu.setMenuId(menuId);
- return roleMenu;
- }
- }).collect(Collectors.toList());
- //mp批量保存到数据库中
- roleMenuService.saveBatch(roleMenuList);
- //封装返回
- return ResponseResult.okResult();
- }
-
- @Override
- public ResponseResult getRoleInfo(Long id) {
- Role role = getById(id);
- AdminRoleVo adminRoleVo = BeanCopyUtils.copyBean(role, AdminRoleVo.class);
- return ResponseResult.okResult(adminRoleVo);
- }
- }
回显成功

| 请求方式 | 请求路径 | 是否需求token头 |
|---|---|---|
| Get | /system/menu/roleMenuTreeselect/{id} | 是 |
请求参数PathVariable格式:
id: 角色id
响应格式:
字段介绍
menus:菜单树
checkedKeys:角色所关联的菜单权限id列表
- {
- "code":200,
- "data":{
- "menus":[
- {
- "children":[],
- "id":"2023",
- "label":"写博文",
- "parentId":"0"
- },
- {
- "children":[
- {
- "children":[
- {
- "children":[],
- "id":"1001",
- "label":"用户查询",
- "parentId":"100"
- },
- {
- "children":[],
- "id":"1002",
- "label":"用户新增",
- "parentId":"100"
- },
- {
- "children":[],
- "id":"1003",
- "label":"用户修改",
- "parentId":"100"
- },
- {
- "children":[],
- "id":"1004",
- "label":"用户删除",
- "parentId":"100"
- },
- {
- "children":[],
- "id":"1005",
- "label":"用户导出",
- "parentId":"100"
- },
- {
- "children":[],
- "id":"1006",
- "label":"用户导入",
- "parentId":"100"
- },
- {
- "children":[],
- "id":"1007",
- "label":"重置密码",
- "parentId":"100"
- }
- ],
- "id":"100",
- "label":"用户管理",
- "parentId":"1"
- },
- {
- "children":[
- {
- "children":[],
- "id":"1008",
- "label":"角色查询",
- "parentId":"101"
- },
- {
- "children":[],
- "id":"1009",
- "label":"角色新增",
- "parentId":"101"
- },
- {
- "children":[],
- "id":"1010",
- "label":"角色修改",
- "parentId":"101"
- },
- {
- "children":[],
- "id":"1011",
- "label":"角色删除",
- "parentId":"101"
- },
- {
- "children":[],
- "id":"1012",
- "label":"角色导出",
- "parentId":"101"
- }
- ],
- "id":"101",
- "label":"角色管理",
- "parentId":"1"
- },
- {
- "children":[
- {
- "children":[],
- "id":"1013",
- "label":"菜单查询",
- "parentId":"102"
- },
- {
- "children":[],
- "id":"1014",
- "label":"菜单新增",
- "parentId":"102"
- },
- {
- "children":[],
- "id":"1015",
- "label":"菜单修改",
- "parentId":"102"
- },
- {
- "children":[],
- "id":"1016",
- "label":"菜单删除",
- "parentId":"102"
- }
- ],
- "id":"102",
- "label":"菜单管理",
- "parentId":"1"
- }
- ],
- "id":"1",
- "label":"系统管理",
- "parentId":"0"
- },
- {
- "children":[
- {
- "children":[],
- "id":"2019",
- "label":"文章管理",
- "parentId":"2017"
- },
- {
- "children":[
- {
- "children":[],
- "id":"2028",
- "label":"导出分类",
- "parentId":"2018"
- }
- ],
- "id":"2018",
- "label":"分类管理",
- "parentId":"2017"
- },
- {
- "children":[
- {
- "children":[],
- "id":"2024",
- "label":"友链新增",
- "parentId":"2022"
- },
- {
- "children":[],
- "id":"2025",
- "label":"友链修改",
- "parentId":"2022"
- },
- {
- "children":[],
- "id":"2026",
- "label":"友链删除",
- "parentId":"2022"
- },
- {
- "children":[],
- "id":"2027",
- "label":"友链查询",
- "parentId":"2022"
- }
- ],
- "id":"2022",
- "label":"友链管理",
- "parentId":"2017"
- },
- {
- "children":[],
- "id":"2021",
- "label":"标签管理",
- "parentId":"2017"
- }
- ],
- "id":"2017",
- "label":"内容管理",
- "parentId":"0"
- }
- ],
- "checkedKeys":[
- "1001"
- ]
- },
- "msg":"操作成功"
- }
第一步:vo层新建RoleMenuTreeSelectVo,用于响应返回
- package com.keke.domain.vo;
-
- import lombok.AllArgsConstructor;
- import lombok.Data;
- import lombok.NoArgsConstructor;
-
- import java.util.List;
-
- @Data
- @AllArgsConstructor
- @NoArgsConstructor
- public class RoleMenuTreeSelectVo {
-
- private List
menus; -
- private List
checkedKeys; - }
第二步: 把keke-framework工程的MenuService接口修改为如下,增加了 '根据角色id查询对应角色菜单列表树' 的接口
- package com.keke.service;
-
- import com.baomidou.mybatisplus.extension.service.IService;
- import com.keke.domain.ResponseResult;
- import com.keke.domain.entity.Menu;
- import com.keke.domain.vo.AdminMenuVo;
-
- import java.util.List;
-
-
- /**
- * 菜单权限表(Menu)表服务接口
- *
- * @author makejava
- * @since 2023-10-18 20:55:48
- */
- public interface MenuService extends IService
{ -
-
- //查询用户权限信息
- List
selectPermsByUserId(Long userId); -
- //查询用户的路由信息,也就是权限菜单
- List
selectRouterMenuTreeByUserId(Long userId); -
- List
selectAllMenu(Menu menu); -
- ResponseResult editMenu(Menu menu);
-
- ResponseResult deleteMenu(Long menuId);
-
-
- List
selectMenuListByRoleId(Long roleId); - }
第三步:MenuServiceImpl
- package com.keke.service.impl;
-
- import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
- import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
- import com.keke.constants.SystemConstants;
- import com.keke.domain.ResponseResult;
- import com.keke.domain.entity.Menu;
- import com.keke.domain.vo.AdminMenuVo;
- import com.keke.mapper.MenuMapper;
- import com.keke.service.MenuService;
- import com.keke.utils.BeanCopyUtils;
- import com.keke.utils.SecurityUtils;
- import org.springframework.beans.factory.annotation.Autowired;
- import org.springframework.stereotype.Service;
- import org.springframework.util.StringUtils;
-
- import java.util.List;
- import java.util.function.Function;
- import java.util.stream.Collectors;
-
- /**
- * 菜单权限表(Menu)表服务实现类
- *
- * @author makejava
- * @since 2023-10-18 20:55:48
- */
- @Service("menuService")
- public class MenuServiceImpl extends ServiceImpl
implements MenuService { -
- @Autowired
- private MenuService menuService;
-
- //根据用户id查询权限关键字
- @Override
- public List
selectPermsByUserId(Long userId) { - //如果用户id为1代表管理员,roles 中只需要有admin,
- // permissions中需要有所有菜单类型为C(菜单)或者F(按钮)的,状态为正常的,未被删除的权限
- if(SecurityUtils.isAdmin()) {
- LambdaQueryWrapper
lambdaQueryWrapper = new LambdaQueryWrapper<>(); - lambdaQueryWrapper.in(Menu::getMenuType, SystemConstants.MENU, SystemConstants.BUTTON);
- lambdaQueryWrapper.eq(Menu::getStatus, SystemConstants.STATUS_NORMAL);
- //由于我们的逻辑删除字段已经配置了,所以无需封装lambdaQueryWrapper
- List
menuList = list(lambdaQueryWrapper); - //我们需要的是String类型的集合,这里我们要进行数据的处理,这里采用流的方式
- List
permissions = menuList.stream() - .map(new Function
() { - @Override
- public String apply(Menu menu) {
- String perms = menu.getPerms();
- return perms;
- }
- })
- .collect(Collectors.toList());
- return permissions;
- }
- //否则返回这个用户所具有的权限
- //这里我们需要进行连表查询,因为我们的用户先和角色关联,然后角色才跟权限关联
- MenuMapper menuMapper = getBaseMapper();
- //我们期望menuMapper中有一个方法可以直接帮我们去实现这个复杂的逻辑,这里直接返回
- return menuMapper.selectPermsByUserId(userId);
- }
-
- @Override
- public List
selectRouterMenuTreeByUserId(Long userId) { - MenuMapper menuMapper = getBaseMapper();
- List
menus = null; - //如果是管理员,返回所有
- if(SecurityUtils.isAdmin()){
- menus = menuMapper.selectAllRoutersMenu();
- }else {
- //如果不是管理员,返回对应用户的菜单
- menus = menuMapper.selectRoutersMenuTreeByUserId(userId);
- }
- //因为上面的查询都是从数据库进行查询,所以无法封装children,这里构建Tree
-
- List
menuTree = buildMenuTree(menus,0L); - return menuTree;
- }
-
- @Override
- public List
selectAllMenu(Menu menu) { - //可以针对菜单名进行模糊查询。也可以针对菜单的状态进行查询
- LambdaQueryWrapper
lambdaQueryWrapper = new LambdaQueryWrapper<>(); - lambdaQueryWrapper.like(StringUtils.hasText(menu.getMenuName()),Menu::getMenuName,menu.getMenuName());
- lambdaQueryWrapper.eq(StringUtils.hasText(menu.getStatus()),Menu::getStatus,menu.getStatus());
- //排序 parent_id和order_num
- lambdaQueryWrapper.orderByAsc(Menu::getParentId,Menu::getOrderNum);
- List
menus = list(lambdaQueryWrapper); - List
adminMenuVos = BeanCopyUtils.copyBeanList(menus, AdminMenuVo.class); - return adminMenuVos;
- }
-
- @Override
- public ResponseResult editMenu(Menu menu) {
- if(menu.getParentId().equals(menu.getId())){
- return ResponseResult.okResult(500,"修改菜单" + "'" + menu.getMenuName() + "'" + "失败,上级菜单不能选择自己");
- }
- updateById(menu);
- return ResponseResult.okResult();
- }
-
- @Override
- public ResponseResult deleteMenu(Long menuId) {
- Menu menu = menuService.getById(menuId);
- //如果该菜单有子菜单,那么就提示不能删除,逻辑就是查询菜单表中是否有父菜单id是当前菜单id
- LambdaQueryWrapper
lambdaQueryWrapper = new LambdaQueryWrapper<>(); - lambdaQueryWrapper.eq(Menu::getParentId,menuId);
- List
menus = list(lambdaQueryWrapper); - if(!menus.isEmpty()) {
- return ResponseResult.okResult(500, "存在子菜单不允许删除");
- }
- removeById(menuId);
- return ResponseResult.okResult();
- }
-
- @Override
- public List
selectMenuListByRoleId(Long roleId) { - return getBaseMapper().selectMenuListByRoleId(roleId);
- }
-
-
- /**
- * 构建MenuTree
- * 思路先找第一层级的菜单,就是找到id于parentId的对应关系,然后把parentId设置为Id的children
- * @param menus
- * @return
- */
- private List
buildMenuTree(List menus,Long parentId) { - //转化流处理
- List
menuTree = menus.stream() - //过滤掉除一级菜单之外的菜单
- .filter(menu -> menu.getParentId().equals(parentId))
- //然后将获取其子菜单设置到children字段,并返回
- .map(m -> m.setChildren(gerChildren(m, menus)))
- .collect(Collectors.toList());
- return menuTree;
- }
-
- //获取当前菜单的子菜单
- private List
gerChildren(Menu menu, List menus) { - //流处理,遍历每一个流对象,筛选出流对象的parentId=menu的id,即过滤
- List
children = menus.stream() - .filter(m -> m.getParentId().equals(menu.getId()))
- //这里其实不必要写,这一步的逻辑是如果有三级,
- //可以把流对象中再过筛选出子菜单设置给对应的children并返回
- .map(m -> m.setChildren(gerChildren(m,menus)))
- .collect(Collectors.toList());
- return children;
- }
-
- }
第四步:MenuMapper新增
- package com.keke.mapper;
-
- import com.baomidou.mybatisplus.core.mapper.BaseMapper;
- import com.keke.domain.entity.Menu;
- import org.apache.ibatis.annotations.Mapper;
-
- import java.util.List;
-
-
- /**
- * 菜单权限表(Menu)表数据库访问层
- *
- * @author makejava
- * @since 2023-10-18 20:55:48
- */
- @Mapper
- public interface MenuMapper extends BaseMapper
{ -
- //Mapper的实现类对应xml映射文件
- List
selectPermsByUserId(Long userId); -
- List
selectAllRoutersMenu(); -
- List
selectRoutersMenuTreeByUserId(Long userId); -
- List
selectMenuListByRoleId(Long roleId); - }
第五步: 把keke-framework工程的resources/mapper目录的MenuMapper.xml修改为如下,增加了 '根据角色id查询对应角色菜单列表树' 的具体实现代码
- "1.0" encoding="UTF-8" ?>
- mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
- <mapper namespace="com.keke.mapper.MenuMapper">
- <select id="selectPermsByUserId" resultType="java.lang.String">
- -- 这里的逻辑是先用userId连表查询roleId,再用roleId连表查询menuId,再根据menuId
- -- 查询对应的用户权限
- select
- DISTINCT m.`perms`
- from `sys_user_role` ur
- left join `sys_role_menu` rm on ur.`role_id`=rm.`role_id`
- left join `sys_menu` m on m.`id`=rm.`menu_id`
- where
- ur.`user_id`=#{userId} and
- m.`menu_type` in ('C','F') and
- m.`status`=0 and
- m.`del_flag`=0
- select>
- <select id="selectAllRoutersMenu" resultType="com.keke.domain.entity.Menu">
- -- 这里与上面的sql差不多,只是menu_type有差别,还有查询的字段个数
- SELECT
- DISTINCT m.id, m.parent_id, m.menu_name, m.path, m.component, m.visible, m.status,
- IFNULL(m.perms,'') AS perms, m.is_frame, m.menu_type, m.icon, m.order_num, m.create_time
- FROM
- `sys_menu` m
- WHERE
- -- 查询所有的,所以不需要加userId的条件
- m.`menu_type` IN ('C','M') AND
- m.`status` = 0 AND
- m.`del_flag` = 0
- ORDER BY
- m.parent_id,m.order_num
- select>
-
- <select id="selectRoutersMenuTreeByUserId" resultType="com.keke.domain.entity.Menu">
- -- 这里与上面的sql差不多
- SELECT
- DISTINCT m.id, m.parent_id, m.menu_name, m.path, m.component, m.visible, m.status,
- IFNULL(m.perms,'') AS perms, m.is_frame, m.menu_type, m.icon, m.order_num, m.create_time
- FROM
- `sys_user_role` ur
- LEFT JOIN `sys_role_menu` rm ON ur.`role_id` = rm.`role_id`
- LEFT JOIN `sys_menu` m ON m.`id` = rm.`menu_id`
- WHERE
- ur.`user_id` = #{userId} AND
- m.`menu_type` IN ('C','M') AND
- m.`status` = 0 AND
- m.`del_flag` = 0
- ORDER BY
- m.parent_id,m.order_num
- select>
-
- <select id="selectMenuListByRoleId" resultType="java.lang.Long">
- select m.id
- from sys_menu m
- left join sys_role_menu rm on m.id = rm.menu_id
- where rm.role_id = #{roleId}
-
-
- order by m.parent_id, m.order_num
- select>
-
- mapper>
第六步:MenuController
- package com.keke.controller;
-
-
- import com.keke.domain.ResponseResult;
- import com.keke.domain.entity.Menu;
- import com.keke.domain.vo.AdminMenuVo;
- import com.keke.domain.vo.MenuTreeVo;
- import com.keke.domain.vo.RoleMenuTreeSelectVo;
- import com.keke.service.MenuService;
- import com.keke.utils.BeanCopyUtils;
- import com.keke.utils.SystemConverter;
- import org.springframework.beans.factory.annotation.Autowired;
- import org.springframework.security.core.parameters.P;
- import org.springframework.web.bind.annotation.*;
-
- import java.util.List;
-
- @RestController
- @RequestMapping("/system/menu")
- public class MenuController {
-
- @Autowired
- private MenuService menuService;
-
-
- //查询菜单列表
- @GetMapping("/list")
- public ResponseResult selectAllMenu(Menu menu){
- List
adminMenuVos = menuService.selectAllMenu(menu); - return ResponseResult.okResult(adminMenuVos);
- }
-
- //新增菜单
- @PostMapping
- public ResponseResult add(@RequestBody Menu menu) {
- menuService.save(menu);
- return ResponseResult.okResult();
- }
-
- @GetMapping("/{menuId}")
- public ResponseResult getInfoById(@PathVariable("menuId") Long menuId){
- Menu menu = menuService.getById(menuId);
- return ResponseResult.okResult(menu);
- }
-
- @GetMapping("/roleMenuTreeselect/{id}")
- public ResponseResult selectMenuListByRoleId(@PathVariable("id") Long roleId){
- List
adminMenuVos = menuService.selectAllMenu(new Menu()); - List
menus = BeanCopyUtils.copyBeanList(adminMenuVos, Menu.class); - List
checkedKeys = menuService.selectMenuListByRoleId(roleId); - List
menuTreeVos = SystemConverter.buildMenuSelectTree(menus); - RoleMenuTreeSelectVo roleMenuTreeSelectVo = new RoleMenuTreeSelectVo(menuTreeVos,checkedKeys);
- return ResponseResult.okResult(roleMenuTreeSelectVo);
-
- }
-
- @PutMapping
- public ResponseResult editMenu(@RequestBody Menu menu){
- return menuService.editMenu(menu);
- }
-
- @DeleteMapping("/{menuId}")
- public ResponseResult deleteMenu(@PathVariable("menuId") Long menuId){
- return menuService.deleteMenu(menuId);
- }
-
- @GetMapping("/treeselect")
- public ResponseResult treeSelect(){
- //复用之前的selectMenuList方法。方法需要参数,参数可以用来进行条件查询,而这个方法不需要条件,所以直接new Menu()传入
- //这样就可以获取所有的菜单了
- List
adminMenuVos = menuService.selectAllMenu(new Menu()); - List
menus = BeanCopyUtils.copyBeanList(adminMenuVos, Menu.class); - List
options = SystemConverter.buildMenuSelectTree(menus); - return ResponseResult.okResult(options);
- }
-
- }


可用看到回显出了对应角色的权限信息
| 请求方式 | 请求路径 | 是否需求token头 |
|---|---|---|
| PUT | system/role | 是 |
请求体:
- {
- "id":"13",
- "remark":"我是角色备注",
- "roleKey":"wds",
- "roleName":"测试新增角色",
- "roleSort":0,
- "status":"0",
- "menuIds":[
- "1",
- "100",
- "1001"
- ]
- }
响应体
- {
- "code":200,
- "msg":"操作成功"
- }
第一步:domain/dto层新增
- package com.keke.domain.dto;
-
- import com.baomidou.mybatisplus.annotation.FieldFill;
- import com.baomidou.mybatisplus.annotation.TableField;
- import lombok.AllArgsConstructor;
- import lombok.Data;
- import lombok.NoArgsConstructor;
-
- import java.util.Date;
- import java.util.List;
-
- @Data
- @AllArgsConstructor
- @NoArgsConstructor
- public class EditRoleDto {
- //角色ID
- private Long id;
- //角色名称
- private String roleName;
- //角色权限字符串
- private String roleKey;
- //显示顺序
- private Integer roleSort;
- //角色状态(0正常 1停用)
- private String status;
- //备注
- private String remark;
- //权限id
- private List
menuIds; - }
第二步:controller层新增EditRole接口
- package com.keke.controller;
-
- import com.keke.domain.ResponseResult;
- import com.keke.domain.dto.AdminAddRoleDto;
- import com.keke.domain.dto.ChangeRoleStatusDto;
- import com.keke.domain.dto.EditRoleDto;
- import com.keke.domain.entity.Role;
- import com.keke.service.RoleService;
- import org.springframework.beans.factory.annotation.Autowired;
- import org.springframework.web.bind.annotation.*;
-
- @RestController
- @RequestMapping("/system/role")
- public class RoleController {
-
- @Autowired
- private RoleService roleService;
-
- @GetMapping("/list")
- public ResponseResult selectPageRole(Role role,Integer pageNum,Integer pageSize){
- return roleService.selectPageRole(role,pageNum,pageSize);
- }
-
- @PutMapping("/changeStatus")
- public ResponseResult changeRoleStatus(@RequestBody ChangeRoleStatusDto changeRoleStatusDto){
- return roleService.changeRoleStatus(changeRoleStatusDto);
- }
-
- @PostMapping
- public ResponseResult addRole(@RequestBody AdminAddRoleDto adminAddRoleDto){
- return roleService.addRole(adminAddRoleDto);
- }
-
- @GetMapping("/{id}")
- public ResponseResult getRoleInfo(@PathVariable("id") Long id){
- return roleService.getRoleInfo(id);
- }
-
- @PutMapping
- public ResponseResult editRole(@RequestBody EditRoleDto editRoleDto){
- return roleService.editRole(editRoleDto);
- }
- }
第二步:service新增
- package com.keke.service;
-
- import com.baomidou.mybatisplus.extension.service.IService;
- import com.keke.domain.ResponseResult;
- import com.keke.domain.dto.AdminAddRoleDto;
- import com.keke.domain.dto.ChangeRoleStatusDto;
- import com.keke.domain.dto.EditRoleDto;
- import com.keke.domain.entity.Role;
-
- import java.util.List;
-
-
- /**
- * 角色信息表(Role)表服务接口
- *
- * @author makejava
- * @since 2023-10-18 21:04:06
- */
- public interface RoleService extends IService
{ -
- List
selectRoleKeyByUserId(Long userId); -
-
- ResponseResult selectPageRole(Role role, Integer pageNum, Integer pageSize);
-
- ResponseResult changeRoleStatus(ChangeRoleStatusDto changeRoleStatusDto);
-
- ResponseResult addRole(AdminAddRoleDto adminAddRoleDto);
-
- ResponseResult getRoleInfo(Long id);
-
- ResponseResult editRole(EditRoleDto editRoleDto);
- }
第三步:impl新增,逻辑和添加用户一样
- package com.keke.service.impl;
-
- import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
- import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
- import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
- import com.keke.domain.ResponseResult;
- import com.keke.domain.dto.AdminAddRoleDto;
- import com.keke.domain.dto.ChangeRoleStatusDto;
- import com.keke.domain.dto.EditRoleDto;
- import com.keke.domain.entity.Role;
- import com.keke.domain.entity.RoleMenu;
- import com.keke.domain.vo.AdminRoleVo;
- import com.keke.domain.vo.PageVo;
- import com.keke.mapper.RoleMapper;
- import com.keke.service.RoleMenuService;
- import com.keke.service.RoleService;
- import com.keke.utils.BeanCopyUtils;
- import org.springframework.beans.factory.annotation.Autowired;
- import org.springframework.stereotype.Service;
- import org.springframework.transaction.annotation.Transactional;
- import org.springframework.util.StringUtils;
-
- import java.util.ArrayList;
- import java.util.List;
- import java.util.function.Function;
- import java.util.stream.Collectors;
-
- /**
- * 角色信息表(Role)表服务实现类
- *
- * @author makejava
- * @since 2023-10-18 21:04:06
- */
- @Service("roleService")
- public class RoleServiceImpl extends ServiceImpl
implements RoleService { -
- @Autowired
- private RoleMenuService roleMenuService;
-
- //根据用户id查询角色信息
- @Override
- public List
selectRoleKeyByUserId(Long userId) { - //如果userId为1,那么角色权限字符串就只需要返回一个admin
- if(userId==1L){
- List
roles = new ArrayList<>(); - roles.add("admin");
- return roles;
- }
- //如果用户id不为1,那么需要根据userId连表查询对应的roleId,然后再去角色表中去查询
- //对应的角色权限字符串
- //这里我们期望RoleMapper中封装一个方法去帮我们实现这个复杂的操作
- RoleMapper roleMapper = getBaseMapper();
- return roleMapper.selectRoleKeyByUserId(userId);
- }
-
- @Override
- public ResponseResult selectPageRole(Role role, Integer pageNum, Integer pageSize) {
- LambdaQueryWrapper
lambdaQueryWrapper = new LambdaQueryWrapper<>(); - lambdaQueryWrapper.like(StringUtils.hasText(role.getRoleName()),Role::getRoleName,role.getRoleName());
- lambdaQueryWrapper.eq(StringUtils.hasText(role.getStatus()),Role::getStatus,role.getStatus());
- lambdaQueryWrapper.orderByAsc(Role::getRoleSort);
- Page
page = new Page<>(pageNum,pageSize); - page(page,lambdaQueryWrapper);
- PageVo pageVo = new PageVo(page.getRecords(),page.getTotal());
- return ResponseResult.okResult(pageVo);
- }
-
- @Override
- public ResponseResult changeRoleStatus(ChangeRoleStatusDto changeRoleStatusDto) {
- Long roleId = changeRoleStatusDto.getRoleId();
- Role role = getById(roleId);
- role.setStatus(changeRoleStatusDto.getStatus());
- updateById(role);
- return ResponseResult.okResult();
- }
-
- @Transactional
- @Override
- public ResponseResult addRole(AdminAddRoleDto adminAddRoleDto) {
- //Bean拷贝
- Role role = BeanCopyUtils.copyBean(adminAddRoleDto, Role.class);
- //拿到菜单权限id集合
- List
menuIds = adminAddRoleDto.getMenuIds(); - //流式处理转化,把每一个menuId都设置到该roleId下
- List
roleMenuList = menuIds.stream() - .map(new Function
() { - @Override
- public RoleMenu apply(Long menuId) {
- RoleMenu roleMenu = new RoleMenu();
- roleMenu.setRoleId(role.getId());
- roleMenu.setMenuId(menuId);
- return roleMenu;
- }
- }).collect(Collectors.toList());
- //mp批量保存到数据库中
- roleMenuService.saveBatch(roleMenuList);
- //封装返回
- return ResponseResult.okResult();
- }
-
- @Override
- public ResponseResult getRoleInfo(Long id) {
- Role role = getById(id);
- AdminRoleVo adminRoleVo = BeanCopyUtils.copyBean(role, AdminRoleVo.class);
- return ResponseResult.okResult(adminRoleVo);
- }
-
- @Override
- public ResponseResult editRole(EditRoleDto editRoleDto) {
- Role role = BeanCopyUtils.copyBean(editRoleDto, Role.class);
- List
menuIds = editRoleDto.getMenuIds(); - List
roleMenuList = menuIds.stream() - .map(new Function
() { - @Override
- public RoleMenu apply(Long menuId) {
- RoleMenu roleMenu = new RoleMenu();
- roleMenu.setRoleId(role.getId());
- roleMenu.setMenuId(menuId);
- return roleMenu;
- }
- }).collect(Collectors.toList());
- roleMenuService.saveBatch(roleMenuList);
- return ResponseResult.okResult();
- }
- }
可用新增角色,并且赋予其相应的菜单权限

删除固定的某个角色(逻辑删除)
| 请求方式 | 请求路径 | 是否需求token头 |
|---|---|---|
| DELETE | system/role/{id} | 是 |
请求参数PathVariable格式:
id:要删除的角色id
响应格式:
- {
- "code":200,
- "msg":"操作成功"
- }
controller层新增接口,逻辑较少直接写
- package com.keke.controller;
-
- import com.keke.domain.ResponseResult;
- import com.keke.domain.dto.AdminAddRoleDto;
- import com.keke.domain.dto.ChangeRoleStatusDto;
- import com.keke.domain.dto.EditRoleDto;
- import com.keke.domain.entity.Role;
- import com.keke.service.RoleService;
- import org.springframework.beans.factory.annotation.Autowired;
- import org.springframework.web.bind.annotation.*;
-
- @RestController
- @RequestMapping("/system/role")
- public class RoleController {
-
- @Autowired
- private RoleService roleService;
-
- @GetMapping("/list")
- public ResponseResult selectPageRole(Role role,Integer pageNum,Integer pageSize){
- return roleService.selectPageRole(role,pageNum,pageSize);
- }
-
- @PutMapping("/changeStatus")
- public ResponseResult changeRoleStatus(@RequestBody ChangeRoleStatusDto changeRoleStatusDto){
- return roleService.changeRoleStatus(changeRoleStatusDto);
- }
-
- @PostMapping
- public ResponseResult addRole(@RequestBody AdminAddRoleDto adminAddRoleDto){
- return roleService.addRole(adminAddRoleDto);
- }
-
- @GetMapping("/{id}")
- public ResponseResult getRoleInfo(@PathVariable("id") Long id){
- return roleService.getRoleInfo(id);
- }
-
- @PutMapping
- public ResponseResult editRole(@RequestBody EditRoleDto editRoleDto){
- return roleService.editRole(editRoleDto);
- }
-
- @DeleteMapping("/{id}")
- public ResponseResult deleteRoleById(@PathVariable("id") Long id){
- roleService.removeById(id);
- return ResponseResult.okResult();
- }
- }


只是逻辑删除

需要用户分页列表接口。
可以根据用户名模糊搜索。
可以进行手机号的搜索。
可以进行状态的查询。
| 请求方式 | 请求路径 | 是否需求token头 |
|---|---|---|
| GET | system/user/list | 是 |
请求参数query格式:
- pageNum: 页码
-
- pageSize: 每页条数
-
- userName:用户名
-
- phonenumber:手机号
-
- status:状态
响应格式:
- {
- "code":200,
- "data":{
- "rows":[
- {
- "avatar":"http://r7yxkqloa.bkt.clouddn.com/2022/03/05/75fd15587811443a9a9a771f24da458d.png",
- "createTime":"2022-01-05 17:01:56",
- "email":"23412332@qq.com",
- "id":"1",
- "nickName":"sg3334",
- "phonenumber":"18888888888",
- "sex":"1",
- "status":"0",
- "updateBy":"1",
- "updateTime":"2022-03-13 21:36:22",
- "userName":"sg"
- }
- ],
- "total":"1"
- },
- "msg":"操作成功"
- }
第一步:keke-admin的controller层新建UserController
- package com.keke.controller;
-
- import com.keke.domain.ResponseResult;
- import com.keke.domain.entity.User;
- import com.keke.service.UserService;
- import org.springframework.beans.factory.annotation.Autowired;
- import org.springframework.web.bind.annotation.GetMapping;
- import org.springframework.web.bind.annotation.RequestMapping;
- import org.springframework.web.bind.annotation.RestController;
-
- @RestController
- @RequestMapping("/system/user")
- public class UserController {
-
- @Autowired
- private UserService userService;
-
- @GetMapping("/list")
- public ResponseResult selectPageUser(User user, Integer pageNum, Integer pageSize){
- return userService.selectPageUser(user,pageNum,pageSize);
- }
- }
第二步:service层
- package com.keke.service;
-
- import com.baomidou.mybatisplus.extension.service.IService;
- import com.keke.domain.ResponseResult;
- import com.keke.domain.dto.RegisterUserDto;
- import com.keke.domain.dto.UserInfoDto;
- import com.keke.domain.entity.User;
- import org.springframework.stereotype.Service;
-
-
- /**
- * 用户表(User)表服务接口
- *
- * @author makejava
- * @since 2023-10-13 09:08:38
- */
-
- public interface UserService extends IService
{ -
- ResponseResult userInfo();
-
- ResponseResult updateUserInfo(UserInfoDto userInfoDto);
-
- ResponseResult register(RegisterUserDto registerUserDto);
-
- //后台接口分页查询用户
- ResponseResult selectPageUser(User user, Integer pageNum, Integer pageSize);
- }
第三步:impl层
- package com.keke.service.impl;
-
- import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
- import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
- import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
- import com.keke.domain.ResponseResult;
- import com.keke.domain.dto.RegisterUserDto;
- import com.keke.domain.dto.UserInfoDto;
- import com.keke.domain.entity.User;
- import com.keke.domain.vo.PageVo;
- import com.keke.domain.vo.UserInfoVo;
- import com.keke.enums.AppHttpCodeEnum;
- import com.keke.handler.exception.exception.SystemException;
- import com.keke.mapper.UserMapper;
- import com.keke.service.UserService;
- import com.keke.utils.BeanCopyUtils;
- import com.keke.utils.SecurityUtils;
- import org.springframework.beans.factory.annotation.Autowired;
- import org.springframework.security.crypto.password.PasswordEncoder;
- import org.springframework.stereotype.Service;
- import org.springframework.util.StringUtils;
-
- /**
- * 用户表(User)表服务实现类
- *
- * @author makejava
- * @since 2023-10-13 10:12:51
- */
- @Service("userService")
- public class UserServiceImpl extends ServiceImpl
implements UserService { -
- @Autowired
- private PasswordEncoder passwordEncoder;
-
- @Override
- public ResponseResult userInfo() {
- Long userId = SecurityUtils.getUserId();
- User user = getById(userId);
- UserInfoVo userInfoVo = BeanCopyUtils.copyBean(user, UserInfoVo.class);
- return ResponseResult.okResult(userInfoVo);
- }
-
- @Override
- public ResponseResult updateUserInfo(UserInfoDto userInfoDto) {
- User user = BeanCopyUtils.copyBean(userInfoDto, User.class);
- updateById(user);
- return ResponseResult.okResult();
- }
-
- @Override
- public ResponseResult register(RegisterUserDto registerUserDto) {
- //对前端传过来的用户名进行非空判断,例如null、"",就抛出异常
- if(!StringUtils.hasText(registerUserDto.getUserName())){
- //SystemException是我们写的异常类、AppHttpCodeEnum是我们写的枚举类
- throw new SystemException(AppHttpCodeEnum.USERNAME_NOT_NULL);
- }
- //密码
- if(!StringUtils.hasText(registerUserDto.getPassword())){
- throw new SystemException(AppHttpCodeEnum.PASSWORD_NOT_NULL);
- }
- //邮箱
- if(!StringUtils.hasText(registerUserDto.getEmail())){
- throw new SystemException(AppHttpCodeEnum.EMAIL_NOT_NULL);
- }
- //昵称
- if(!StringUtils.hasText(registerUserDto.getNickName())){
- throw new SystemException(AppHttpCodeEnum.NICKNAME_NOT_NULL);
- }
-
- //判断用户传给我们的用户名是否在数据库已经存在。userNameExist方法是下面定义的
- if(userNameExist(registerUserDto.getUserName())){
- //SystemException是我们写的异常类、AppHttpCodeEnum是我们写的枚举类
- throw new SystemException(AppHttpCodeEnum.USERNAME_EXIST);
- }
- //判断用户传给我们的昵称是否在数据库已经存在。NickNameExist方法是下面定义的
- if(nickNameExist(registerUserDto.getNickName())){
- //SystemException是我们写的异常类、AppHttpCodeEnum是我们写的枚举类
- throw new SystemException(AppHttpCodeEnum.NICKNAME_EXIST);
- }
- //判断用户传给我们的邮箱是否在数据库已经存在。NickNameExist方法是下面定义的
- if(emailExist(registerUserDto.getEmail())){
- //SystemException是我们写的异常类、AppHttpCodeEnum是我们写的枚举类
- throw new SystemException(AppHttpCodeEnum.EMAIL_EXIST);
- }
-
- //经过上面的判断,可以确保用户传给我们的用户名和昵称是数据库不存在的,且相关字段都不为空。就可以存入数据库
- //注意用户传给我们的密码是明文,对于密码我们要转成密文之后再存入数据库。注意加密要和解密用同一套算法
- //keke-blog工程的securityConfig类里面有解密算法,当时我们写了一个passwordEncoder方法,并且注入到了spring容器
-
- //解密
- String encodePassword = passwordEncoder.encode(registerUserDto.getPassword());
- //封装成user存数据库中
- User user = BeanCopyUtils.copyBean(registerUserDto, User.class);
- //设置密码为加密的密码
- user.setPassword(encodePassword);
- //存入数据库中
- save(user);
- //封装返回
- return ResponseResult.okResult();
- }
-
- @Override
- public ResponseResult selectPageUser(User user, Integer pageNum, Integer pageSize) {
- LambdaQueryWrapper
lambdaQueryWrapper = new LambdaQueryWrapper<>(); - //可以根据用户名模糊搜索
- lambdaQueryWrapper.like(StringUtils.hasText(user.getUserName()),User::getUserName,user.getUserName());
- //可以进行手机号的搜索
- lambdaQueryWrapper.eq(StringUtils.hasText(user.getPhonenumber()),User::getPhonenumber,user.getPhonenumber());
- //可以根据状态进行搜索
- lambdaQueryWrapper.eq(StringUtils.hasText(user.getStatus()),User::getStatus,user.getStatus());
- //mp分页器
- Page
page = new Page<>(pageNum,pageSize); - page(page,lambdaQueryWrapper);
- //封装vo
- PageVo pageVo = new PageVo(page.getRecords(),page.getTotal());
- //响应返回
- return ResponseResult.okResult(pageVo);
- }
-
-
- //'判断用户传给我们的用户名是否在数据库已经存在' 的方法
- public boolean userNameExist(String userName){
- LambdaQueryWrapper
lambdaQueryWrapper = new LambdaQueryWrapper<>(); - //查询数据库中有用户名相同的数据没有
- lambdaQueryWrapper.eq(User::getUserName,userName);
- //如果查出来有,就说明存在,返回true
- int count = count(lambdaQueryWrapper);
- return count>0;
- }
-
- //'判断用户传给我们的昵称是否在数据库已经存在' 的方法
- public boolean nickNameExist(String nickName){
- LambdaQueryWrapper
lambdaQueryWrapper = new LambdaQueryWrapper<>(); - //查询数据库中有用户名相同的数据没有
- lambdaQueryWrapper.eq(User::getNickName,nickName);
- //如果查出来有,就说明存在,返回true
- int count = count(lambdaQueryWrapper);
- return count>0;
- }
-
-
- //'判断用户传给我们的邮箱是否在数据库已经存在' 的方法
- public boolean emailExist(String email){
- LambdaQueryWrapper
lambdaQueryWrapper = new LambdaQueryWrapper<>(); - //查询数据库中有用户名相同的数据没有
- lambdaQueryWrapper.eq(User::getEmail,email);
- //如果查出来有,就说明存在,返回true
- int count = count(lambdaQueryWrapper);
- return count>0;
- }
-
- }


需要新增用户功能。新增用户时可以直接关联角色。
注意:新增用户时注意密码加密存储。
用户名不能为空,否则提示:必需填写用户名
用户名必须之前未存在,否则提示:用户名已存在
手机号必须之前未存在,否则提示:手机号已存在
邮箱必须之前未存在,否则提示:邮箱已存在
注意:查询的是所有状态正常的角色
| 请求方式 | 请求路径 | 是否需求token头 |
|---|---|---|
| GET | /system/role/listAllRole | 是 |
响应格式:
- {
- "code":200,
- "data":[
- {
- "createBy":"0",
- "createTime":"2021-11-12 18:46:19",
- "delFlag":"0",
- "id":"1",
- "remark":"超级管理员",
- "roleKey":"admin",
- "roleName":"超级管理员",
- "roleSort":"1",
- "status":"0",
- "updateBy":"0"
- },
- {
- "createBy":"0",
- "createTime":"2021-11-12 18:46:19",
- "delFlag":"0",
- "id":"2",
- "remark":"普通角色",
- "roleKey":"common",
- "roleName":"普通角色",
- "roleSort":"2",
- "status":"0",
- "updateBy":"0",
- "updateTime":"2022-01-02 06:32:58"
- },
- {
- "createTime":"2022-01-06 22:07:40",
- "delFlag":"0",
- "id":"11",
- "remark":"嘎嘎嘎",
- "roleKey":"aggag",
- "roleName":"嘎嘎嘎",
- "roleSort":"5",
- "status":"0",
- "updateBy":"1",
- "updateTime":"2022-09-12 10:00:25"
- },
- {
- "createTime":"2022-01-16 14:49:30",
- "delFlag":"0",
- "id":"12",
- "roleKey":"link",
- "roleName":"友链审核员",
- "roleSort":"1",
- "status":"0",
- "updateTime":"2022-01-16 16:05:09"
- }
- ],
- "msg":"操作成功"
- }
第一步:在keke-admin的controller层的RoleController新增查询状态正常角色的接口
- package com.keke.controller;
-
- import com.keke.domain.ResponseResult;
- import com.keke.domain.dto.AdminAddRoleDto;
- import com.keke.domain.dto.ChangeRoleStatusDto;
- import com.keke.domain.dto.EditRoleDto;
- import com.keke.domain.entity.Role;
- import com.keke.service.RoleService;
- import org.springframework.beans.factory.annotation.Autowired;
- import org.springframework.web.bind.annotation.*;
-
- @RestController
- @RequestMapping("/system/role")
- public class RoleController {
-
- @Autowired
- private RoleService roleService;
-
- @GetMapping("/list")
- public ResponseResult selectPageRole(Role role,Integer pageNum,Integer pageSize){
- return roleService.selectPageRole(role,pageNum,pageSize);
- }
-
- @PutMapping("/changeStatus")
- public ResponseResult changeRoleStatus(@RequestBody ChangeRoleStatusDto changeRoleStatusDto){
- return roleService.changeRoleStatus(changeRoleStatusDto);
- }
-
- @PostMapping
- public ResponseResult addRole(@RequestBody AdminAddRoleDto adminAddRoleDto){
- return roleService.addRole(adminAddRoleDto);
- }
-
- @GetMapping("/{id}")
- public ResponseResult getRoleInfo(@PathVariable("id") Long id){
- return roleService.getRoleInfo(id);
- }
-
- @PutMapping
- public ResponseResult editRole(@RequestBody EditRoleDto editRoleDto){
- return roleService.editRole(editRoleDto);
- }
-
- @DeleteMapping("/{id}")
- public ResponseResult deleteRoleById(@PathVariable("id") Long id){
- roleService.removeById(id);
- return ResponseResult.okResult();
- }
-
- @GetMapping("/listAllRole")
- public ResponseResult listAllRole(){
- return roleService.listAllRole();
- }
- }
第二步:service层新增
- package com.keke.service;
-
- import com.baomidou.mybatisplus.extension.service.IService;
- import com.keke.domain.ResponseResult;
- import com.keke.domain.dto.AdminAddRoleDto;
- import com.keke.domain.dto.ChangeRoleStatusDto;
- import com.keke.domain.dto.EditRoleDto;
- import com.keke.domain.entity.Role;
-
- import java.util.List;
-
-
- /**
- * 角色信息表(Role)表服务接口
- *
- * @author makejava
- * @since 2023-10-18 21:04:06
- */
- public interface RoleService extends IService
{ -
- List
selectRoleKeyByUserId(Long userId); -
-
- ResponseResult selectPageRole(Role role, Integer pageNum, Integer pageSize);
-
- ResponseResult changeRoleStatus(ChangeRoleStatusDto changeRoleStatusDto);
-
- ResponseResult addRole(AdminAddRoleDto adminAddRoleDto);
-
- ResponseResult getRoleInfo(Long id);
-
- ResponseResult editRole(EditRoleDto editRoleDto);
-
- ResponseResult listAllRole();
-
- }
第三步:impl层新增
- package com.keke.service.impl;
-
- import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
- import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
- import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
- import com.keke.constants.SystemConstants;
- import com.keke.domain.ResponseResult;
- import com.keke.domain.dto.AdminAddRoleDto;
- import com.keke.domain.dto.ChangeRoleStatusDto;
- import com.keke.domain.dto.EditRoleDto;
- import com.keke.domain.entity.Role;
- import com.keke.domain.entity.RoleMenu;
- import com.keke.domain.vo.AdminRoleVo;
- import com.keke.domain.vo.PageVo;
- import com.keke.mapper.RoleMapper;
- import com.keke.service.RoleMenuService;
- import com.keke.service.RoleService;
- import com.keke.utils.BeanCopyUtils;
- import org.springframework.beans.factory.annotation.Autowired;
- import org.springframework.stereotype.Service;
- import org.springframework.transaction.annotation.Transactional;
- import org.springframework.util.StringUtils;
-
- import java.util.ArrayList;
- import java.util.List;
- import java.util.function.Function;
- import java.util.stream.Collectors;
-
- /**
- * 角色信息表(Role)表服务实现类
- *
- * @author makejava
- * @since 2023-10-18 21:04:06
- */
- @Service("roleService")
- public class RoleServiceImpl extends ServiceImpl
implements RoleService { -
- @Autowired
- private RoleMenuService roleMenuService;
-
- //根据用户id查询角色信息
- @Override
- public List
selectRoleKeyByUserId(Long userId) { - //如果userId为1,那么角色权限字符串就只需要返回一个admin
- if(userId==1L){
- List
roles = new ArrayList<>(); - roles.add("admin");
- return roles;
- }
- //如果用户id不为1,那么需要根据userId连表查询对应的roleId,然后再去角色表中去查询
- //对应的角色权限字符串
- //这里我们期望RoleMapper中封装一个方法去帮我们实现这个复杂的操作
- RoleMapper roleMapper = getBaseMapper();
- return roleMapper.selectRoleKeyByUserId(userId);
- }
-
- @Override
- public ResponseResult selectPageRole(Role role, Integer pageNum, Integer pageSize) {
- LambdaQueryWrapper
lambdaQueryWrapper = new LambdaQueryWrapper<>(); - lambdaQueryWrapper.like(StringUtils.hasText(role.getRoleName()),Role::getRoleName,role.getRoleName());
- lambdaQueryWrapper.eq(StringUtils.hasText(role.getStatus()),Role::getStatus,role.getStatus());
- lambdaQueryWrapper.orderByAsc(Role::getRoleSort);
- Page
page = new Page<>(pageNum,pageSize); - page(page,lambdaQueryWrapper);
- PageVo pageVo = new PageVo(page.getRecords(),page.getTotal());
- return ResponseResult.okResult(pageVo);
- }
-
- @Override
- public ResponseResult changeRoleStatus(ChangeRoleStatusDto changeRoleStatusDto) {
- Long roleId = changeRoleStatusDto.getRoleId();
- Role role = getById(roleId);
- role.setStatus(changeRoleStatusDto.getStatus());
- updateById(role);
- return ResponseResult.okResult();
- }
-
- @Transactional
- @Override
- public ResponseResult addRole(AdminAddRoleDto adminAddRoleDto) {
- //Bean拷贝
- Role role = BeanCopyUtils.copyBean(adminAddRoleDto, Role.class);
- //拿到菜单权限id集合
- List
menuIds = adminAddRoleDto.getMenuIds(); - //流式处理转化,把每一个menuId都设置到该roleId下
- List
roleMenuList = menuIds.stream() - .map(new Function
() { - @Override
- public RoleMenu apply(Long menuId) {
- RoleMenu roleMenu = new RoleMenu();
- roleMenu.setRoleId(role.getId());
- roleMenu.setMenuId(menuId);
- return roleMenu;
- }
- }).collect(Collectors.toList());
- //mp批量保存到数据库中
- roleMenuService.saveBatch(roleMenuList);
- //封装返回
- return ResponseResult.okResult();
- }
-
- @Override
- public ResponseResult getRoleInfo(Long id) {
- Role role = getById(id);
- AdminRoleVo adminRoleVo = BeanCopyUtils.copyBean(role, AdminRoleVo.class);
- return ResponseResult.okResult(adminRoleVo);
- }
-
- @Override
- public ResponseResult editRole(EditRoleDto editRoleDto) {
- Role role = BeanCopyUtils.copyBean(editRoleDto, Role.class);
- List
menuIds = editRoleDto.getMenuIds(); - List
roleMenuList = menuIds.stream() - .map(new Function
() { - @Override
- public RoleMenu apply(Long menuId) {
- RoleMenu roleMenu = new RoleMenu();
- roleMenu.setRoleId(role.getId());
- roleMenu.setMenuId(menuId);
- return roleMenu;
- }
- }).collect(Collectors.toList());
- roleMenuService.saveBatch(roleMenuList);
- return ResponseResult.okResult();
- }
-
- @Override
- public ResponseResult listAllRole() {
- LambdaQueryWrapper
lambdaQueryWrapper = new LambdaQueryWrapper<>(); - lambdaQueryWrapper.eq(Role::getStatus, SystemConstants.STATUS_NORMAL);
- List
roleList = list(lambdaQueryWrapper); - return ResponseResult.okResult(roleList);
- }
- }

| 请求方式 | 请求路径 | 是否需求token头 |
|---|---|---|
| POST | system/user | 是 |
请求体:
- {
- "userName":"wqeree",
- "nickName":"测试新增用户",
- "password":"1234343",
- "phonenumber":"18889778907",
- "email":"233@sq.com",
- "sex":"0",
- "status":"0",
- "roleIds":[
- "2"
- ]
- }
响应格式:
- {
- "code":200,
- "msg":"操作成功"
- }
第一步:keke-framework的domain/entity新增
- package com.keke.domain.entity;
-
- import java.io.Serializable;
- import lombok.AllArgsConstructor;
- import lombok.Data;
- import lombok.NoArgsConstructor;
- import com.baomidou.mybatisplus.annotation.TableName;
-
- /**
- * 用户和角色关联表(UserRole)表实体类
- *
- * @author makejava
- * @since 2023-10-23 21:17:14
- */
- @SuppressWarnings("serial")
- @Data
- @NoArgsConstructor
- @AllArgsConstructor
- @TableName("sys_user_role")
- public class UserRole {
- //用户ID
- private Long userId;
- //角色ID
- private Long roleId;
- }
第二步:keke-framework的service新增
- package com.keke.service;
-
- import com.baomidou.mybatisplus.extension.service.IService;
-
-
- /**
- * 用户和角色关联表(UserRole)表服务接口
- *
- * @author makejava
- * @since 2023-10-23 21:17:32
- */
- public interface UserRoleService extends IService
{ -
- }
第三步:keke-framework的service/impl新增
- package com.keke.service.impl;
-
- import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
- import com.keke.domain.entity.UserRole;
- import com.keke.mapper.UserRoleMapper;
- import com.keke.service.UserRoleService;
- import org.springframework.stereotype.Service;
-
- /**
- * 用户和角色关联表(UserRole)表服务实现类
- *
- * @author makejava
- * @since 2023-10-23 21:17:32
- */
- @Service("userRoleService")
- public class UserRoleServiceImpl extends ServiceImpl
implements UserRoleService { -
- }
第四步:keke-framework的mapper新增
- package com.keke.mapper;
-
- import com.baomidou.mybatisplus.core.mapper.BaseMapper;
- import com.keke.domain.entity.User;
- import org.apache.ibatis.annotations.Mapper;
-
-
- /**
- * 用户表(User)表数据库访问层
- *
- * @author makejava
- * @since 2023-10-11 20:26:26
- */
- @Mapper
- public interface UserMapper extends BaseMapper
{ -
- }
第五步:keke-framework的domain/dto新增
- package com.keke.domain.dto;
-
- import lombok.AllArgsConstructor;
- import lombok.Data;
- import lombok.NoArgsConstructor;
-
- import java.util.List;
-
-
- @Data
- @AllArgsConstructor
- @NoArgsConstructor
- public class AdminAddUserDto {
- //用户名
- private String userName;
- //昵称
- private String nickName;
- //密码
- private String password;
- //账号状态(0正常 1停用)
- private String status;
- //邮箱
- private String email;
- //手机号
- private String phonenumber;
- //用户性别(0男,1女,2未知)
- private String sex;
- //roleId
- List
roleIds; - }
第六步:keke-admin的controller层UserController新增
- package com.keke.controller;
-
- import com.keke.domain.ResponseResult;
- import com.keke.domain.dto.AdminAddUserDto;
- import com.keke.domain.entity.User;
- import com.keke.service.UserService;
- import org.springframework.beans.factory.annotation.Autowired;
- import org.springframework.web.bind.annotation.*;
-
- @RestController
- @RequestMapping("/system/user")
- public class UserController {
-
- @Autowired
- private UserService userService;
-
- @GetMapping("/list")
- public ResponseResult selectPageUser(User user, Integer pageNum, Integer pageSize){
- return userService.selectPageUser(user,pageNum,pageSize);
- }
-
- @PostMapping
- public ResponseResult addUser(@RequestBody AdminAddUserDto adminAddUserDto){
- return userService.addUser(adminAddUserDto);
- }
-
-
- }
第七步:service层UserService新增
- package com.keke.service;
-
- import com.baomidou.mybatisplus.extension.service.IService;
- import com.keke.domain.ResponseResult;
- import com.keke.domain.dto.AdminAddUserDto;
- import com.keke.domain.dto.RegisterUserDto;
- import com.keke.domain.dto.UserInfoDto;
- import com.keke.domain.entity.User;
- import org.springframework.stereotype.Service;
-
-
- /**
- * 用户表(User)表服务接口
- *
- * @author makejava
- * @since 2023-10-13 09:08:38
- */
-
- public interface UserService extends IService
{ -
- ResponseResult userInfo();
-
- ResponseResult updateUserInfo(UserInfoDto userInfoDto);
-
- ResponseResult register(RegisterUserDto registerUserDto);
-
- //后台接口分页查询用户
- ResponseResult selectPageUser(User user, Integer pageNum, Integer pageSize);
-
- ResponseResult addUser(AdminAddUserDto adminAddUserDto);
- }
第八步:impl层实现方法
- package com.keke.service.impl;
-
- import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
- import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
- import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
- import com.keke.domain.ResponseResult;
- import com.keke.domain.dto.AdminAddUserDto;
- import com.keke.domain.dto.RegisterUserDto;
- import com.keke.domain.dto.UserInfoDto;
- import com.keke.domain.entity.User;
- import com.keke.domain.entity.UserRole;
- import com.keke.domain.vo.PageVo;
- import com.keke.domain.vo.UserInfoVo;
- import com.keke.enums.AppHttpCodeEnum;
- import com.keke.handler.exception.exception.SystemException;
- import com.keke.mapper.UserMapper;
- import com.keke.service.UserRoleService;
- import com.keke.service.UserService;
- import com.keke.utils.BeanCopyUtils;
- import com.keke.utils.SecurityUtils;
- import org.springframework.beans.factory.annotation.Autowired;
- import org.springframework.security.crypto.password.PasswordEncoder;
- import org.springframework.stereotype.Service;
- import org.springframework.util.StringUtils;
-
- import java.util.List;
- import java.util.function.Function;
- import java.util.stream.Collectors;
-
- /**
- * 用户表(User)表服务实现类
- *
- * @author makejava
- * @since 2023-10-13 10:12:51
- */
- @Service("userService")
- public class UserServiceImpl extends ServiceImpl
implements UserService { -
- @Autowired
- private PasswordEncoder passwordEncoder;
-
- @Autowired
- private UserRoleService userRoleService;
-
- @Override
- public ResponseResult userInfo() {
- Long userId = SecurityUtils.getUserId();
- User user = getById(userId);
- UserInfoVo userInfoVo = BeanCopyUtils.copyBean(user, UserInfoVo.class);
- return ResponseResult.okResult(userInfoVo);
- }
-
- @Override
- public ResponseResult updateUserInfo(UserInfoDto userInfoDto) {
- User user = BeanCopyUtils.copyBean(userInfoDto, User.class);
- updateById(user);
- return ResponseResult.okResult();
- }
-
- @Override
- public ResponseResult register(RegisterUserDto registerUserDto) {
- //对前端传过来的用户名进行非空判断,例如null、"",就抛出异常
- if(!StringUtils.hasText(registerUserDto.getUserName())){
- //SystemException是我们写的异常类、AppHttpCodeEnum是我们写的枚举类
- throw new SystemException(AppHttpCodeEnum.USERNAME_NOT_NULL);
- }
- //密码
- if(!StringUtils.hasText(registerUserDto.getPassword())){
- throw new SystemException(AppHttpCodeEnum.PASSWORD_NOT_NULL);
- }
- //邮箱
- if(!StringUtils.hasText(registerUserDto.getEmail())){
- throw new SystemException(AppHttpCodeEnum.EMAIL_NOT_NULL);
- }
- //昵称
- if(!StringUtils.hasText(registerUserDto.getNickName())){
- throw new SystemException(AppHttpCodeEnum.NICKNAME_NOT_NULL);
- }
-
- //判断用户传给我们的用户名是否在数据库已经存在。userNameExist方法是下面定义的
- if(userNameExist(registerUserDto.getUserName())){
- //SystemException是我们写的异常类、AppHttpCodeEnum是我们写的枚举类
- throw new SystemException(AppHttpCodeEnum.USERNAME_EXIST);
- }
- //判断用户传给我们的昵称是否在数据库已经存在。NickNameExist方法是下面定义的
- if(nickNameExist(registerUserDto.getNickName())){
- //SystemException是我们写的异常类、AppHttpCodeEnum是我们写的枚举类
- throw new SystemException(AppHttpCodeEnum.NICKNAME_EXIST);
- }
- //判断用户传给我们的邮箱是否在数据库已经存在。NickNameExist方法是下面定义的
- if(emailExist(registerUserDto.getEmail())){
- //SystemException是我们写的异常类、AppHttpCodeEnum是我们写的枚举类
- throw new SystemException(AppHttpCodeEnum.EMAIL_EXIST);
- }
-
- //经过上面的判断,可以确保用户传给我们的用户名和昵称是数据库不存在的,且相关字段都不为空。就可以存入数据库
- //注意用户传给我们的密码是明文,对于密码我们要转成密文之后再存入数据库。注意加密要和解密用同一套算法
- //keke-blog工程的securityConfig类里面有解密算法,当时我们写了一个passwordEncoder方法,并且注入到了spring容器
-
- //解密
- String encodePassword = passwordEncoder.encode(registerUserDto.getPassword());
- //封装成user存数据库中
- User user = BeanCopyUtils.copyBean(registerUserDto, User.class);
- //设置密码为加密的密码
- user.setPassword(encodePassword);
- //存入数据库中
- save(user);
- //封装返回
- return ResponseResult.okResult();
- }
-
- @Override
- public ResponseResult selectPageUser(User user, Integer pageNum, Integer pageSize) {
- LambdaQueryWrapper
lambdaQueryWrapper = new LambdaQueryWrapper<>(); - //可以根据用户名模糊搜索
- lambdaQueryWrapper.like(StringUtils.hasText(user.getUserName()),User::getUserName,user.getUserName());
- //可以进行手机号的搜索
- lambdaQueryWrapper.eq(StringUtils.hasText(user.getPhonenumber()),User::getPhonenumber,user.getPhonenumber());
- //可以根据状态进行搜索
- lambdaQueryWrapper.eq(StringUtils.hasText(user.getStatus()),User::getStatus,user.getStatus());
- //mp分页器
- Page
page = new Page<>(pageNum,pageSize); - page(page,lambdaQueryWrapper);
- //封装vo
- PageVo pageVo = new PageVo(page.getRecords(),page.getTotal());
- //响应返回
- return ResponseResult.okResult(pageVo);
- }
-
- @Override
- public ResponseResult addUser(AdminAddUserDto adminAddUserDto) {
- User user = BeanCopyUtils.copyBean(adminAddUserDto, User.class);
- List
roleIds = adminAddUserDto.getRoleIds(); - List
userRoleList = roleIds.stream() - .map(new Function
() { - @Override
- public UserRole apply(Long roleId) {
- UserRole userRole = new UserRole();
- userRole.setUserId(user.getId());
- userRole.setRoleId(roleId);
- return userRole;
- }
- }).collect(Collectors.toList());
- userRoleService.saveBatch(userRoleList);
- return ResponseResult.okResult();
- }
-
-
- //'判断用户传给我们的用户名是否在数据库已经存在' 的方法
- public boolean userNameExist(String userName){
- LambdaQueryWrapper
lambdaQueryWrapper = new LambdaQueryWrapper<>(); - //查询数据库中有用户名相同的数据没有
- lambdaQueryWrapper.eq(User::getUserName,userName);
- //如果查出来有,就说明存在,返回true
- int count = count(lambdaQueryWrapper);
- return count>0;
- }
-
- //'判断用户传给我们的昵称是否在数据库已经存在' 的方法
- public boolean nickNameExist(String nickName){
- LambdaQueryWrapper
lambdaQueryWrapper = new LambdaQueryWrapper<>(); - //查询数据库中有用户名相同的数据没有
- lambdaQueryWrapper.eq(User::getNickName,nickName);
- //如果查出来有,就说明存在,返回true
- int count = count(lambdaQueryWrapper);
- return count>0;
- }
-
-
- //'判断用户传给我们的邮箱是否在数据库已经存在' 的方法
- public boolean emailExist(String email){
- LambdaQueryWrapper
lambdaQueryWrapper = new LambdaQueryWrapper<>(); - //查询数据库中有用户名相同的数据没有
- lambdaQueryWrapper.eq(User::getEmail,email);
- //如果查出来有,就说明存在,返回true
- int count = count(lambdaQueryWrapper);
- return count>0;
- }
-
- }




需要分页查询分类列表。
能根据分类名称进行模糊查询。
能根据状态进行查询。
| 请求方式 | 请求路径 | 是否需求token头 |
|---|---|---|
| GET | content/category/list | 是 |
Query格式请求参数:
- pageNum: 页码
-
- pageSize: 每页条数
-
- name:分类名
-
- status: 状态
响应格式:
- {
- "code":200,
- "data":{
- "rows":[
- {
- "description":"wsd",
- "id":"1",
- "name":"java",
- "status":"0"
- },
- {
- "description":"wsd",
- "id":"2",
- "name":"PHP",
- "status":"0"
- }
- ],
- "total":"2"
- },
- "msg":"操作成功"
- }
第一步:keke-admin controller层
- package com.keke.controller;
-
-
- import com.alibaba.excel.EasyExcel;
- import com.alibaba.fastjson.JSON;
- import com.keke.domain.ResponseResult;
- import com.keke.domain.entity.Category;
- import com.keke.domain.vo.ExcelCategoryVo;
- import com.keke.enums.AppHttpCodeEnum;
- import com.keke.service.CategoryService;
- import com.keke.utils.BeanCopyUtils;
- import com.keke.utils.WebUtils;
- import io.swagger.annotations.Api;
- import org.springframework.beans.factory.annotation.Autowired;
- import org.springframework.security.access.prepost.PreAuthorize;
- import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
- import org.springframework.web.bind.annotation.GetMapping;
- import org.springframework.web.bind.annotation.RequestMapping;
- import org.springframework.web.bind.annotation.RestController;
-
- import javax.servlet.http.HttpServletResponse;
- import java.io.UnsupportedEncodingException;
- import java.util.List;
-
- @RestController
- @RequestMapping("/content/category")
- @Api(tags = "后台标签相关接口")
- public class CategoryController {
-
- @Autowired
- private CategoryService categoryService;
-
- @GetMapping("/listAllCategory")
- public ResponseResult listAllCategory(){
- return categoryService.listAllCategory();
- }
-
- //权限控制,ps是PermissionService类的bean名称
- @PreAuthorize("@ps.hasPermission('content:category:export')")
- @GetMapping("/export")
- public void export(HttpServletResponse response){
-
- try {
- //设置下载文件的请求头
- WebUtils.setDownLoadHeader("分类.xlsx",response);
- //获取需要导出的数据
- List
categoryList = categoryService.list(); - List
excelCategoryVos = BeanCopyUtils.copyBeanList(categoryList, ExcelCategoryVo.class); - //把数据写入Excel中
- EasyExcel.write(response.getOutputStream(), ExcelCategoryVo.class).autoCloseStream(Boolean.FALSE).sheet("分类导出")
- .doWrite(excelCategoryVos);
- } catch (Exception e) {
- //如果出现异常,就返回失败的json数据给前端
- ResponseResult result = ResponseResult.errorResult(AppHttpCodeEnum.SYSTEM_ERROR);
- //WebUtils是我们在keke-framework工程写的类,里面的renderString方法是将json字符串写入到请求体,然后返回给前端
- WebUtils.renderString(response, JSON.toJSONString(result));
- }
- }
-
-
- @GetMapping("/list")
- public ResponseResult selectPageCategory(Category category,Integer pageNum,Integer pageSize){
- return categoryService.selectPageCategory(category,pageNum,pageSize);
- }
- }
第二步:keke-framework service层
- package com.keke.service;
-
- import com.baomidou.mybatisplus.extension.service.IService;
- import com.keke.domain.ResponseResult;
- import com.keke.domain.entity.Category;
- import org.springframework.web.bind.annotation.RequestMapping;
-
-
- /**
- * 分类表(Category)表服务接口
- *
- * @author makejava
- * @since 2023-10-10 20:42:22
- */
- public interface CategoryService extends IService
{ -
- ResponseResult getCategoryList();
-
- //后台接口,查询所有文章分类
- ResponseResult listAllCategory();
-
- ResponseResult selectPageCategory(Category category, Integer pageNum, Integer pageSize);
- }
第三步:keke-framework impl层 实现selectPageCategory
- package com.keke.service.impl;
-
- import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
- import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
- import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
- import com.keke.constants.SystemConstants;
- import com.keke.domain.ResponseResult;
- import com.keke.domain.entity.Article;
- import com.keke.domain.entity.Category;
- import com.keke.domain.vo.AdminCategoryVo;
- import com.keke.domain.vo.CategoryVo;
- import com.keke.domain.vo.PageVo;
- import com.keke.mapper.CategoryMapper;
- import com.keke.service.ArticleService;
- import com.keke.service.CategoryService;
- import com.keke.utils.BeanCopyUtils;
- import org.springframework.beans.factory.annotation.Autowired;
- import org.springframework.stereotype.Service;
- import org.springframework.util.StringUtils;
- import org.springframework.web.bind.annotation.RequestMapping;
-
- import java.util.List;
- import java.util.Set;
- import java.util.function.Function;
- import java.util.stream.Collectors;
-
- /**
- * 分类表(Category)表服务实现类
- *
- * @author makejava
- * @since 2023-10-10 20:42:22
- */
- @Service("categoryService")
- public class CategoryServiceImpl extends ServiceImpl
implements CategoryService { -
- @Autowired
- private ArticleService articleService;
-
- @Override
- public ResponseResult getCategoryList() {
- //查询文章表,状态已发布的文章,但是在CategoryService下,查询文章表,就要注入ArticleService
- LambdaQueryWrapper
articleWrapper = new LambdaQueryWrapper<>(); - articleWrapper.eq(Article::getStatus, SystemConstants.ARTICLE_STATUS_NORMAL);
- List
articleList = articleService.list(articleWrapper); - //获取文章的分类id,并去重
- Set
categoryIds = articleList.stream() - .map(article -> article.getCategoryId())
- //toSet可以去除重复的id
- .collect(Collectors.toSet());
- //查询分类表
- List
categories = listByIds(categoryIds); - //分类表中只获取正常状态非禁用的分类,用stream流过滤
- categories = categories.stream()
- .filter(category -> SystemConstants.STATUS_NORMAL.equals(category.getStatus()))
- .collect(Collectors.toList());
- //封装Vo
- List
categoryVos = BeanCopyUtils.copyBeanList(categories, CategoryVo.class); - //封装到响应体中,因为有数据,所以要调用有参okResult(),把参数传进去
- return ResponseResult.okResult(categoryVos);
- }
-
- @Override
- public ResponseResult listAllCategory() {
- LambdaQueryWrapper
lambdaQueryWrapper = new LambdaQueryWrapper<>(); - lambdaQueryWrapper.eq(Category::getStatus,SystemConstants.STATUS_NORMAL);
- List
categoryList = list(lambdaQueryWrapper); - List
adminCategoryVos = BeanCopyUtils.copyBeanList(categoryList, AdminCategoryVo.class); - return ResponseResult.okResult(adminCategoryVos);
- }
-
- @Override
- public ResponseResult selectPageCategory(Category category, Integer pageNum, Integer pageSize) {
- LambdaQueryWrapper
lambdaQueryWrapper = new LambdaQueryWrapper<>(); - //根据分类名进行模糊查询
- lambdaQueryWrapper.like(StringUtils.hasText(category.getName()),Category::getName,category.getName());
- lambdaQueryWrapper.eq(StringUtils.hasText(category.getStatus()),Category::getStatus,category.getStatus());
- //构造分页器
- Page
page = new Page<>(pageNum,pageSize); - page(page,lambdaQueryWrapper);
- //封装Vo
- PageVo pageVo = new PageVo(page.getRecords(),page.getTotal());
- return ResponseResult.okResult(pageVo);
- }
- }

需要新增分类功能
| 请求方式 | 请求路径 | 是否需求token头 |
|---|---|---|
| POST | /content/category | 是 |
请求体:
- {
- "name":"威威",
- "description":"是的",
- "status":"0"
- }
响应格式:
- {
- "code":200,
- "msg":"操作成功"
- }
第一步:新增dto,接受前端传来的参数
- package com.keke.domain.dto;
-
- import lombok.AllArgsConstructor;
- import lombok.Data;
- import lombok.NoArgsConstructor;
-
- import java.util.Date;
-
- @Data
- @AllArgsConstructor
- @NoArgsConstructor
- public class AdminCategoryDto {
- //分类名
- private String name;
- //描述
- private String description;
- //状态0:正常,1禁用
- private String status;
- }
第二步:entity层Category修改mp自填充
- package com.keke.domain.entity;
-
- import java.util.Date;
- import java.io.Serializable;
-
- import com.baomidou.mybatisplus.annotation.FieldFill;
- import com.baomidou.mybatisplus.annotation.TableField;
- import com.baomidou.mybatisplus.annotation.TableId;
- import com.baomidou.mybatisplus.annotation.TableName;
- import lombok.AllArgsConstructor;
- import lombok.Data;
- import lombok.NoArgsConstructor;
-
- /**
- * 分类表(Category)表实体类
- *
- * @author makejava
- * @since 2023-10-10 20:42:21
- */
- @SuppressWarnings("serial")
- @Data
- @NoArgsConstructor
- @AllArgsConstructor
- @TableName("ke_category")
- public class Category {
- @TableId
- private Long id;
- //分类名
- private String name;
- //父分类id,如果没有父分类为-1
- private Long pid;
- //描述
- private String description;
- //状态0:正常,1禁用
- private String status;
-
- //创建者
- @TableField(fill = FieldFill.INSERT)
- private Long createBy;
- //创建时间
- @TableField(fill = FieldFill.INSERT)
- private Date createTime;
- //更新者
- @TableField(fill = FieldFill.INSERT_UPDATE)
- private Long updateBy;
- //更新时间
- @TableField(fill = FieldFill.INSERT_UPDATE)
- private Date updateTime;
-
- //删除标志(0代表未删除,1代表已删除)
- private Integer delFlag;
-
- }
第三步: keke-admin的Controller层
- package com.keke.controller;
-
-
- import com.alibaba.excel.EasyExcel;
- import com.alibaba.fastjson.JSON;
- import com.keke.domain.ResponseResult;
- import com.keke.domain.dto.AdminCategoryDto;
- import com.keke.domain.entity.Category;
- import com.keke.domain.vo.ExcelCategoryVo;
- import com.keke.enums.AppHttpCodeEnum;
- import com.keke.service.CategoryService;
- import com.keke.utils.BeanCopyUtils;
- import com.keke.utils.WebUtils;
- import io.swagger.annotations.Api;
- import org.springframework.beans.factory.annotation.Autowired;
- import org.springframework.security.access.prepost.PreAuthorize;
- import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
- import org.springframework.web.bind.annotation.*;
-
- import javax.servlet.http.HttpServletResponse;
- import java.io.UnsupportedEncodingException;
- import java.util.List;
-
- @RestController
- @RequestMapping("/content/category")
- @Api(tags = "后台标签相关接口")
- public class CategoryController {
-
- @Autowired
- private CategoryService categoryService;
-
- @GetMapping("/listAllCategory")
- public ResponseResult listAllCategory(){
- return categoryService.listAllCategory();
- }
-
- //权限控制,ps是PermissionService类的bean名称
- @PreAuthorize("@ps.hasPermission('content:category:export')")
- @GetMapping("/export")
- public void export(HttpServletResponse response){
-
- try {
- //设置下载文件的请求头
- WebUtils.setDownLoadHeader("分类.xlsx",response);
- //获取需要导出的数据
- List
categoryList = categoryService.list(); - List
excelCategoryVos = BeanCopyUtils.copyBeanList(categoryList, ExcelCategoryVo.class); - //把数据写入Excel中
- EasyExcel.write(response.getOutputStream(), ExcelCategoryVo.class).autoCloseStream(Boolean.FALSE).sheet("分类导出")
- .doWrite(excelCategoryVos);
- } catch (Exception e) {
- //如果出现异常,就返回失败的json数据给前端
- ResponseResult result = ResponseResult.errorResult(AppHttpCodeEnum.SYSTEM_ERROR);
- //WebUtils是我们在keke-framework工程写的类,里面的renderString方法是将json字符串写入到请求体,然后返回给前端
- WebUtils.renderString(response, JSON.toJSONString(result));
- }
- }
-
-
- @GetMapping("/list")
- public ResponseResult selectPageCategory(Category category,Integer pageNum,Integer pageSize){
- return categoryService.selectPageCategory(category,pageNum,pageSize);
- }
-
- @PostMapping
- public ResponseResult addCategory(@RequestBody AdminCategoryDto adminCategoryDto){
- return categoryService.addCategory(adminCategoryDto);
- }
-
- }
第四步:keke-framework的service层
- package com.keke.service;
-
- import com.baomidou.mybatisplus.extension.service.IService;
- import com.keke.domain.ResponseResult;
- import com.keke.domain.dto.AdminCategoryDto;
- import com.keke.domain.entity.Category;
- import org.springframework.web.bind.annotation.RequestMapping;
-
-
- /**
- * 分类表(Category)表服务接口
- *
- * @author makejava
- * @since 2023-10-10 20:42:22
- */
- public interface CategoryService extends IService
{ -
- ResponseResult getCategoryList();
-
- //后台接口,查询所有文章分类
- ResponseResult listAllCategory();
-
- ResponseResult selectPageCategory(Category category, Integer pageNum, Integer pageSize);
-
- ResponseResult addCategory(AdminCategoryDto adminCategoryDto);
-
- }
第五步:keke-framework的impl层
- package com.keke.service.impl;
-
- import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
- import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
- import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
- import com.keke.constants.SystemConstants;
- import com.keke.domain.ResponseResult;
- import com.keke.domain.dto.AdminCategoryDto;
- import com.keke.domain.entity.Article;
- import com.keke.domain.entity.Category;
- import com.keke.domain.vo.AdminCategoryVo;
- import com.keke.domain.vo.CategoryVo;
- import com.keke.domain.vo.PageVo;
- import com.keke.mapper.CategoryMapper;
- import com.keke.service.ArticleService;
- import com.keke.service.CategoryService;
- import com.keke.utils.BeanCopyUtils;
- import org.springframework.beans.factory.annotation.Autowired;
- import org.springframework.stereotype.Service;
- import org.springframework.util.StringUtils;
- import org.springframework.web.bind.annotation.RequestMapping;
-
- import java.util.List;
- import java.util.Set;
- import java.util.function.Function;
- import java.util.stream.Collectors;
-
- /**
- * 分类表(Category)表服务实现类
- *
- * @author makejava
- * @since 2023-10-10 20:42:22
- */
- @Service("categoryService")
- public class CategoryServiceImpl extends ServiceImpl
implements CategoryService { -
- @Autowired
- private ArticleService articleService;
-
- @Override
- public ResponseResult getCategoryList() {
- //查询文章表,状态已发布的文章,但是在CategoryService下,查询文章表,就要注入ArticleService
- LambdaQueryWrapper
articleWrapper = new LambdaQueryWrapper<>(); - articleWrapper.eq(Article::getStatus, SystemConstants.ARTICLE_STATUS_NORMAL);
- List
articleList = articleService.list(articleWrapper); - //获取文章的分类id,并去重
- Set
categoryIds = articleList.stream() - .map(article -> article.getCategoryId())
- //toSet可以去除重复的id
- .collect(Collectors.toSet());
- //查询分类表
- List
categories = listByIds(categoryIds); - //分类表中只获取正常状态非禁用的分类,用stream流过滤
- categories = categories.stream()
- .filter(category -> SystemConstants.STATUS_NORMAL.equals(category.getStatus()))
- .collect(Collectors.toList());
- //封装Vo
- List
categoryVos = BeanCopyUtils.copyBeanList(categories, CategoryVo.class); - //封装到响应体中,因为有数据,所以要调用有参okResult(),把参数传进去
- return ResponseResult.okResult(categoryVos);
- }
-
- @Override
- public ResponseResult listAllCategory() {
- LambdaQueryWrapper
lambdaQueryWrapper = new LambdaQueryWrapper<>(); - lambdaQueryWrapper.eq(Category::getStatus,SystemConstants.STATUS_NORMAL);
- List
categoryList = list(lambdaQueryWrapper); - List
adminCategoryVos = BeanCopyUtils.copyBeanList(categoryList, AdminCategoryVo.class); - return ResponseResult.okResult(adminCategoryVos);
- }
-
- @Override
- public ResponseResult selectPageCategory(Category category, Integer pageNum, Integer pageSize) {
- LambdaQueryWrapper
lambdaQueryWrapper = new LambdaQueryWrapper<>(); - //根据分类名进行模糊查询
- lambdaQueryWrapper.like(StringUtils.hasText(category.getName()),Category::getName,category.getName());
- lambdaQueryWrapper.eq(StringUtils.hasText(category.getStatus()),Category::getStatus,category.getStatus());
- //构造分页器
- Page
page = new Page<>(pageNum,pageSize); - page(page,lambdaQueryWrapper);
- //封装Vo
- PageVo pageVo = new PageVo(page.getRecords(),page.getTotal());
- return ResponseResult.okResult(pageVo);
- }
-
- @Override
- public ResponseResult addCategory(AdminCategoryDto adminCategoryDto) {
- Category category = BeanCopyUtils.copyBean(adminCategoryDto, Category.class);
- save(category);
- return ResponseResult.okResult();
- }
- }


需要提供修改分类的功能
分析:点击修改按钮,需要回显出分类的相关信息
点击确定按钮,修改成功
所以这里需要实现两个接口
根据id查询分类
| 请求方式 | 请求路径 | 是否需求token头 |
|---|---|---|
| Get | content/category/{id} | 是 |
逻辑较少,直接在Controller层写逻辑
- package com.keke.controller;
-
-
- import com.alibaba.excel.EasyExcel;
- import com.alibaba.fastjson.JSON;
- import com.keke.domain.ResponseResult;
- import com.keke.domain.dto.AdminCategoryDto;
- import com.keke.domain.entity.Category;
- import com.keke.domain.vo.ExcelCategoryVo;
- import com.keke.enums.AppHttpCodeEnum;
- import com.keke.service.CategoryService;
- import com.keke.utils.BeanCopyUtils;
- import com.keke.utils.WebUtils;
- import io.swagger.annotations.Api;
- import org.springframework.beans.factory.annotation.Autowired;
- import org.springframework.security.access.prepost.PreAuthorize;
- import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
- import org.springframework.web.bind.annotation.*;
-
- import javax.servlet.http.HttpServletResponse;
- import java.io.UnsupportedEncodingException;
- import java.util.List;
-
- @RestController
- @RequestMapping("/content/category")
- @Api(tags = "后台标签相关接口")
- public class CategoryController {
-
- @Autowired
- private CategoryService categoryService;
-
- @GetMapping("/listAllCategory")
- public ResponseResult listAllCategory(){
- return categoryService.listAllCategory();
- }
-
- //权限控制,ps是PermissionService类的bean名称
- @PreAuthorize("@ps.hasPermission('content:category:export')")
- @GetMapping("/export")
- public void export(HttpServletResponse response){
-
- try {
- //设置下载文件的请求头
- WebUtils.setDownLoadHeader("分类.xlsx",response);
- //获取需要导出的数据
- List
categoryList = categoryService.list(); - List
excelCategoryVos = BeanCopyUtils.copyBeanList(categoryList, ExcelCategoryVo.class); - //把数据写入Excel中
- EasyExcel.write(response.getOutputStream(), ExcelCategoryVo.class).autoCloseStream(Boolean.FALSE).sheet("分类导出")
- .doWrite(excelCategoryVos);
- } catch (Exception e) {
- //如果出现异常,就返回失败的json数据给前端
- ResponseResult result = ResponseResult.errorResult(AppHttpCodeEnum.SYSTEM_ERROR);
- //WebUtils是我们在keke-framework工程写的类,里面的renderString方法是将json字符串写入到请求体,然后返回给前端
- WebUtils.renderString(response, JSON.toJSONString(result));
- }
- }
-
-
- @GetMapping("/list")
- public ResponseResult selectPageCategory(Category category,Integer pageNum,Integer pageSize){
- return categoryService.selectPageCategory(category,pageNum,pageSize);
- }
-
- @PostMapping
- public ResponseResult addCategory(@RequestBody AdminCategoryDto adminCategoryDto){
- return categoryService.addCategory(adminCategoryDto);
- }
-
- @GetMapping("/{id}")
- public ResponseResult getInfoById(@PathVariable("id") Long id){
- Category category = categoryService.getById(id);
- return ResponseResult.okResult(category);
- }
-
- }


成功回显出分类信息
| 请求方式 | 请求路径 | 是否需求token头 |
|---|---|---|
| PUT | /content/category | 是 |
请求体:
- {
- "description":"是的",
- "id":"3",
- "name":"威威2",
- "status":"0"
- }
响应格式:
- {
- "code":200,
- "msg":"操作成功"
- }
逻辑较少,直接在controller层实现
-
- @PutMapping
- public ResponseResult editCategory(@RequestBody Category category){
- categoryService.updateById(category);
- return ResponseResult.okResult();
- }



删除某个分类(逻辑删除)
| 请求方式 | 请求路径 | 是否需求token头 |
|---|---|---|
| DELETE | /content/category/{id} | 是 |
请求参数PathVariable格式:
id:要删除的分类id
响应格式:
- {
- "code":200,
- "msg":"操作成功"
- }
逻辑较少,直接在controller层实现
- @DeleteMapping("/{id}")
- public ResponseResult deleteCategory(@PathVariable("/id") Long id){
- categoryService.removeById(id);
- return ResponseResult.okResult();
- }

需要分页查询友链列表。
能根据友链名称进行模糊查询。
能根据状态进行查询。
| 请求方式 | 请求路径 | 是否需求token头 |
|---|---|---|
| GET | /content/link/list | 是 |
Query格式请求参数:
- pageNum: 页码
-
- pageSize: 每页条数
-
- name:友链名
-
- status:状态
响应格式:
- {
- "code":200,
- "data":{
- "rows":[
- {
- "address":"https://www.baidu.com",
- "description":"sda",
- "id":"1",
- "logo":"图片URL",
- "name":"sda",
- "status":"0"
- }
- ],
- "total":"1"
- },
- "msg":"操作成功"
- }
第一步:keke-admin的controller层新建LinkController
- package com.keke.controller;
-
- import com.keke.domain.ResponseResult;
- import com.keke.domain.entity.Link;
- import com.keke.service.LinkService;
- import org.springframework.beans.factory.annotation.Autowired;
- import org.springframework.web.bind.annotation.GetMapping;
- import org.springframework.web.bind.annotation.RequestMapping;
- import org.springframework.web.bind.annotation.RestController;
-
- @RestController
- @RequestMapping("/system/link")
- public class LinkController {
-
- @Autowired
- private LinkService linkService;
-
- @GetMapping("/list")
- public ResponseResult selectPageLink(Link link, Integer pageNum, Integer pageSize){
- return linkService.selectPageLink(link,pageNum,pageSize);
- }
- }
第二步:keke-framework的service层新增方法
- package com.keke.service;
-
- import com.keke.domain.ResponseResult;
- import com.keke.domain.entity.Link;
- import com.baomidou.mybatisplus.extension.service.IService;
-
- /**
- * 友链(Link)表服务接口
- *
- * @author makejava
- * @since 2023-10-11 15:46:23
- */
- public interface LinkService extends IService {
-
- ResponseResult getAllLink();
-
- ResponseResult selectPageLink(Link link, Integer pageNum, Integer pageSize);
- }
第三步:keke-framework的impl层实现方法
- package com.keke.service.impl;
-
-
- import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
- import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
- import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
- import com.keke.constants.SystemConstants;
- import com.keke.domain.ResponseResult;
- import com.keke.domain.entity.Link;
- import com.keke.domain.vo.LinkVo;
- import com.keke.domain.vo.PageVo;
- import com.keke.mapper.LinkMapper;
- import com.keke.service.LinkService;
- import com.keke.utils.BeanCopyUtils;
- import org.springframework.stereotype.Service;
- import org.springframework.util.StringUtils;
-
- import java.util.List;
-
- /**
- * 友链(Link)表服务实现类
- *
- * @author makejava
- * @since 2023-10-11 16:53:47
- */
- @Service("linkService")
- public class LinkServiceImpl extends ServiceImpl
implements LinkService { -
- @Override
- public ResponseResult getAllLink() {
- //查询所有审核通过的
- LambdaQueryWrapper lambdaQueryWrapper = new LambdaQueryWrapper<>();
- lambdaQueryWrapper.eq(Link::getStatus, SystemConstants.Link_STATUS_NORMAL);
- List links = list(lambdaQueryWrapper);
- //转换Vo
- List
linkVos = BeanCopyUtils.copyBeanList(links, LinkVo.class); - //封装响应体
- return ResponseResult.okResult(linkVos);
- }
-
- @Override
- public ResponseResult selectPageLink(Link link, Integer pageNum, Integer pageSize) {
- LambdaQueryWrapper lambdaQueryWrapper = new LambdaQueryWrapper<>();
- //根据友链名进行模糊查询
- lambdaQueryWrapper.like(StringUtils.hasText(link.getName()),Link::getName,link.getName());
- //根据状态进行查询
- lambdaQueryWrapper.eq(StringUtils.hasText(link.getStatus()),Link::getStatus,link.getStatus());
- //构造分页器
- Page page = new Page<>(pageNum,pageSize);
- page(page,lambdaQueryWrapper);
- //封装Vo
- PageVo pageVo = new PageVo(page.getRecords(),page.getTotal());
- //封装响应体返回
- return ResponseResult.okResult(pageVo);
- }
- }

需要新增友链功能
| 请求方式 | 请求路径 | 是否需求token头 |
|---|---|---|
| POST | /content/link | 是 |
请求体:
- {
- "name":"sda",
- "description":"weqw",
- "address":"wewe",
- "logo":"weqe",
- "status":"2"
- }
响应格式:
- {
- "code":200,
- "msg":"操作成功"
- }
第一步:修改entity层Link实体类,修改四字段为mp自动填充
- package com.keke.domain.entity;
-
- import java.util.Date;
- import java.io.Serializable;
-
- import com.baomidou.mybatisplus.annotation.FieldFill;
- import com.baomidou.mybatisplus.annotation.TableField;
- import lombok.AllArgsConstructor;
- import lombok.Data;
- import lombok.NoArgsConstructor;
- import com.baomidou.mybatisplus.annotation.TableName;
-
- /**
- * 友链(Link)表实体类
- *
- * @author makejava
- * @since 2023-10-11 15:45:54
- */
- @SuppressWarnings("serial")
- @Data
- @NoArgsConstructor
- @AllArgsConstructor
- @TableName("ke_link")
- public class Link {
-
- private Long id;
-
- private String name;
-
- private String logo;
-
- private String description;
- //网站地址
- private String address;
- //审核状态 (0代表审核通过,1代表审核未通过,2代表未审核)
- private String status;
-
- //创建者
- @TableField(fill = FieldFill.INSERT)
- private Long createBy;
- //创建时间
- @TableField(fill = FieldFill.INSERT)
- private Date createTime;
- //更新者
- @TableField(fill = FieldFill.INSERT_UPDATE)
- private Long updateBy;
- //更新时间
- @TableField(fill = FieldFill.INSERT_UPDATE)
- private Date updateTime;
-
- //删除标志(0代表未删除,1代表已删除)
- private Integer delFlag;
-
- }
第二步:keke-admin的controller层新增添加友链的接口
- package com.keke.controller;
-
- import com.keke.domain.ResponseResult;
- import com.keke.domain.entity.Link;
- import com.keke.service.LinkService;
- import org.springframework.beans.factory.annotation.Autowired;
- import org.springframework.web.bind.annotation.*;
-
- @RestController
- @RequestMapping("/content/link")
- public class LinkController {
-
- @Autowired
- private LinkService linkService;
-
- //分页查询友链
- @GetMapping("/list")
- public ResponseResult selectPageLink(Link link, Integer pageNum, Integer pageSize){
- return linkService.selectPageLink(link,pageNum,pageSize);
- }
-
- //新增友链
- @PostMapping
- public ResponseResult addLink(@RequestBody Link link){
- linkService.save(link);
- return ResponseResult.okResult();
- }
- }


需要提供修改友链的功能
根据id查询友链
| 请求方式 | 请求路径 | 是否需求token头 |
|---|---|---|
| Get | content/link/{id} | 是 |
请求PathVariable格式参数:
id: 友链id
响应格式:
- {
- "code":200,
- "data":{
- "address":"wewe",
- "description":"weqw",
- "id":"4",
- "logo":"weqe",
- "name":"sda",
- "status":"2"
- },
- "msg":"操作成功"
- }
逻辑较少,直接在controller层写
- //回显友链信息
- @GetMapping("/{id}")
- public ResponseResult getInfoById(@PathVariable("id") Long id){
- Link link = linkService.getById(id);
- return ResponseResult.okResult(link);
- }

| 请求方式 | 请求路径 | 是否需求token头 |
|---|---|---|
| PUT | /content/link | 是 |
请求头:
- {
- "address":"https://www.qq.com",
- "description":"dada2",
- "id":"2",
- "logo":"https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fn1.itc.cn%2Fimg8%2Fwb%2Frecom%2F2016%2F05%2F10%2F146286696706220328.PNG&refer=http%3A%2F%2Fn1.itc.cn&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=jpeg?sec=1646205529&t=f942665181eb9b0685db7a6f59d59975",
- "name":"sda",
- "status":"0"
- }
响应体:
- {
- "code":200,
- "msg":"操作成功"
- }
- //修改友链
- @PutMapping
- public ResponseResult editLink(@RequestBody Link link){
- linkService.updateById(link);
- return ResponseResult.okResult();
- }
我们把刚才新增的友链LOG修改成猴子图标


删除某个友链(逻辑删除)
| 请求方式 | 请求路径 | 是否需求token头 |
|---|---|---|
| DELETE | /content/link/{id} | 是 |
请求参数PathVariable格式:
id:要删除的友链id
响应格式:
- {
- "code":200,
- "msg":"操作成功"
- }
- package com.keke.controller;
-
- import com.keke.domain.ResponseResult;
- import com.keke.domain.entity.Link;
- import com.keke.service.LinkService;
- import org.springframework.beans.factory.annotation.Autowired;
- import org.springframework.web.bind.annotation.*;
-
- @RestController
- @RequestMapping("/content/link")
- public class LinkController {
-
- @Autowired
- private LinkService linkService;
-
- //分页查询友链
- @GetMapping("/list")
- public ResponseResult selectPageLink(Link link, Integer pageNum, Integer pageSize){
- return linkService.selectPageLink(link,pageNum,pageSize);
- }
-
- //新增友链
- @PostMapping
- public ResponseResult addLink(@RequestBody Link link){
- linkService.save(link);
- return ResponseResult.okResult();
- }
-
- //回显友链信息
- @GetMapping("/{id}")
- public ResponseResult getInfoById(@PathVariable("id") Long id){
- Link link = linkService.getById(id);
- return ResponseResult.okResult(link);
- }
-
- //修改友链
- @PutMapping
- public ResponseResult editLink(@RequestBody Link link){
- linkService.updateById(link);
- return ResponseResult.okResult();
- }
-
- //根据id删除友链
- @DeleteMapping("/{id}")
- public ResponseResult deleteLink(@PathVariable("id") Long id){
- linkService.removeById(id);
- return ResponseResult.okResult();
- }
- }



至此,KekeBlog的后台模块开发全部结束