基于SpringBoot的哈士奇博客项目(五)

4、后台管理

4.15、菜单列表

4.15.1、需求分析

需要展示菜单列表,不需要分页。

可以针对菜单名进行模糊查询,也可以针对菜单的状态进行查询。

菜单要按照父菜单id和orderNum进行排序。

4.15.2、接口设计

请求方式请求路径是否需求token头
GETsystem/menu/list

请求参数:

status  : 状态
menuName: 菜单名

响应格式:

{
    "code":200,
    "data":[
        {
            "component":"content/article/write/index",
            "icon":"build",
            "id":"2023",
            "isFrame":1,
            "menuName":"写博文",
            "menuType":"C",
            "orderNum":0,
            "parentId":"0",
            "path":"write",
            "perms":"content:article:writer",
            "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"
        },
        ...
    ]
}

4.15.3、代码实现

MenuDTO

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@AllArgsConstructor
@NoArgsConstructor
public class MenuDTO {

    private String status;
    private String menuName;
}

MenuVO

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.time.LocalDateTime;

@Data
@AllArgsConstructor
@NoArgsConstructor
public class MenuVO {

    /**
     * 菜单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 LocalDateTime createTime;

    /**
     * 备注
     */
    private String remark;
}

MenuController

import com.hashiqi.domain.ResponseResult;
import com.hashiqi.domain.dto.MenuDTO;
import com.hashiqi.service.MenuService;
import io.swagger.annotations.ApiOperation;
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")
    @ApiOperation(value = "获取符合条件的所有菜单")
    public ResponseResult menuList(MenuDTO menuDTO) {
        return menuService.menuList(menuDTO);
    }
}

MenuService

// 获取符合条件的所有菜单
ResponseResult menuList(MenuDTO menuDTO);

MenuServiceImpl

/**
* 获取符合条件的所有菜单
* @param menuDTO 条件查询对象
* @return 符合条件的所有菜单
*/
@Override
public ResponseResult menuList(MenuDTO menuDTO) {
    // 获取符合条件的菜单列表
    List<Menu> menus = this.list(new LambdaQueryWrapper<Menu>()
                                 .like(StringUtils.hasText(menuDTO.getMenuName()), Menu::getMenuName, menuDTO.getMenuName())
                                 .eq(StringUtils.hasText(menuDTO.getStatus()), Menu::getStatus, menuDTO.getStatus()));
    // 将符合条件的菜单列表Menu转成MenuVO,并返回
    return ResponseResult.okResult(BeanCopyUtils.copyBeanList(menus, MenuVO.class));
}

4.16、新增菜单

4.16.1、需求分析

可以新增菜单

4.16.2、接口设计

请求方式请求路径是否需求token头
POSTcontent/article

请求体参数:Menu类对应的json格式

响应格式:

{
    "code":200,
    "msg":"操作成功"
}

4.16.3、代码实现

MenuController

4.17、修改菜单

4.17.1、需求分析

能够修改菜单,但是修改的时候不能把父菜单设置为当前菜单,如果设置了需要给出相应的提示。并且修改失败。

4.17.2、接口设计

4.17.2.1、根据id查询菜单数据
请求方式请求路径是否需求token头
Getsystem/menu/{id}

请求参数:菜单id

响应格式:

{
    "code":200,
    "data":{
        "icon":"table",
        "id":"2017",
        "menuName":"内容管理",
        "menuType":"M",
        "orderNum":"4",
        "parentId":"0",
        "path":"content",
        "remark":"",
        "status":"0",
        "visible":"0"
    },
    "msg":"操作成功"
}

4.17.2.2、更新菜单
请求方式请求路径是否需求token头
PUTsystem/menu

请求体参数:menu类对应的json格式

操作成功,响应格式:

{
    "code":200,
    "msg":"操作成功"
}

操作失败,提示信息。

4.17.3、代码实现

4.17.3.1、根据id查询菜单数据接口实现

QueryMenuVO

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@AllArgsConstructor
@NoArgsConstructor
public class QueryMenuVO {

    /**
     * 菜单ID
     */
    private Long id;

    /**
     * 菜单名称
     */
    private String menuName;

    /**
     * 父菜单ID
     */
    private Long parentId;

    /**
     * 显示顺序
     */
    private Integer orderNum;

    /**
     * 路由地址
     */
    private String path;

    /**
     * 菜单类型(M目录 C菜单 F按钮)
     */
    private String menuType;

    /**
     * 菜单状态(0显示 1隐藏)
     */
    private String visible;

    /**
     * 菜单状态(0正常 1停用)
     */
    private String status;

    /**
     * 菜单图标
     */
    private String icon;

    /**
     * 备注
     */
    private String remark;
}

MenuController

@GetMapping("/{id}")
@ApiOperation(value = "根据id查询菜单数据")
public ResponseResult getMenuById(@PathVariable("id") Long id) {
    return menuService.getMenuById(id);
}

MenuService

// 根据id查询菜单数据
ResponseResult getMenuById(Long id);

MenuServiceImpl

/**
 * 根据id查询菜单数据
 * @param id 菜单id
 * @return 菜单数据
 */
@Override
public ResponseResult getMenuById(Long id) {
    // 根据id查询菜单数据
    Menu menu = this.getById(id);
    // 将Menu转成QueryMenuVO,并返回
    return ResponseResult.okResult(BeanCopyUtils.copyBean(menu, QueryMenuVO.class));
}

4.17.3.2、更新菜单接口实现

MenuController

@PutMapping
@ApiOperation(value = "更新菜单")
public ResponseResult updateMenuById(@RequestBody Menu menu) {
    return ResponseResult.okResult(menuService.updateById(menu));
}

4.18、删除菜单

4.18.1、需求分析

能够删除菜单,但是如果要删除的菜单有子菜单则提示:存在子菜单不允许删除 并且删除失败。

4.18.2、接口设计

请求方式请求路径是否需求token头
DELETEcontent/article/{menuId}

请求参数:要删除的菜单id

操作成功,响应格式:

{
    "code":200,
    "msg":"操作成功"
}

操作失败,提示信息。

4.18.3、代码实现

MenuController

@DeleteMapping("/{menuId}")
@ApiOperation(value = "根据菜单id删除菜单信息")
public ResponseResult deleteMenuById(@PathVariable("menuId") Long id) {
    return ResponseResult.okResult(menuService.removeById(id));
}

4.19、角色列表

4.19.1、需求分析

需要有角色列表分页查询的功能。

要求能够针对角色名称进行模糊查询,对状态查询。

要求按照role_sort进行升序排列。

4.19.2、接口设计

请求方式请求路径是否需求token头
GETsystem/role/list

请求参数:

pageNum: 页码
pageSize: 每页条数
roleName:角色名称
status:状态

响应格式:

{
    "code":200,
    "data":{
        "rows":[
            {
                "id":"12",
                "roleKey":"link",
                "roleName":"审核员",
                "roleSort":"1",
                "status":"0"
            }
        ],
        "total":"1"
    },
    "msg":"操作成功"
}

4.19.3、代码实现

RoleDTO

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@AllArgsConstructor
@NoArgsConstructor
public class RoleDTO {

    private String roleName;
    private String status;
}

RoleVO

@Data
@AllArgsConstructor
@NoArgsConstructor
public class RoleVO {

    private Long id;
    private String roleKey;
    private String roleName;
    private Integer roleSort;
    private String status;
    private Date createTime;
}

RoleController

@GetMapping("/list")
@ApiOperation(value = "根据条件分页查询角色列表")
public ResponseResult pageRoleList(
        Integer pageNum,
        Integer pageSize,
        RoleDTO roleDTO) {
    return roleService.pageRoleList(pageNum, pageSize, roleDTO);
}

RoleService

// 根据条件分页查询角色列表
ResponseResult pageRoleList(Integer pageNum, Integer pageSize, RoleDTO roleDTO);

RoleServiceImpl

/**
 * 根据条件分页查询角色列表
 * @param pageNum 当前页
 * @param pageSize 页大小
 * @param roleDTO 条件参数对象
 * @return 角色分页列表
 */
@Override
public ResponseResult pageRoleList(Integer pageNum, Integer pageSize, RoleDTO roleDTO) {
    // 获取符合条件的角色分页列表
    Page<Role> page = this.page(
            new Page<>(pageNum, pageSize),
            new LambdaQueryWrapper<Role>()
                    .like(StringUtils.hasText(roleDTO.getRoleName()), Role::getRoleName, roleDTO.getRoleName())
                    .eq(StringUtils.hasText(roleDTO.getStatus()), Role::getStatus, roleDTO.getStatus()));
    // 将Role转成RoleVO
    List<RoleVO> roleVOs = BeanCopyUtils.copyBeanList(page.getRecords(), RoleVO.class);
    return ResponseResult.okResult(new PageVO(roleVOs, page.getTotal()));
}

4.20、改变角色状态

4.20.1、需求

能够修改角色的停启用状态。

4.20.2、接口设计

请求方式请求路径是否需求token头
PUTsystem/role/changeStatus

请求体:

{
    "roleId":"11",
    "status":"1"
}

响应格式:

{
    "code":200,
    "msg":"操作成功"
}

4.20.3、代码实现

RoleController

@PutMapping("/changeStatus")
@ApiOperation(value = "修改角色的停启用状态")
public ResponseResult updateStatus(@RequestBody UpdateRoleStatusDTO updateRoleStatusDTO) {
    // 首先,通过角色id获取角色
    Role role = roleService.getById(updateRoleStatusDTO.getRoleId());
    System.err.println(role);
    // 接着进行更新操作
    roleService.update(new LambdaUpdateWrapper<Role>()
                       .eq(Role::getId, role.getId())
                       .set(Role::getStatus, updateRoleStatusDTO.getStatus()));
    return ResponseResult.okResult();
}

4.21、新增角色

4.21.1、需求分析

需要提供新增角色的功能,新增角色时能够直接设置角色所关联的菜单权限。

4.21.2、接口设计

4.21.2.1、获取菜单树接口
请求方式请求路径是否需求token头
GET/system/menu/treeselect

请求参数:无

响应格式:

{
    "code":200,
    "data":[
        {
            "children":[],
            "id":"2023",
            "label":"写博文",
            "parentId":"0"
        },
        ...
    ],
    "msg":"操作成功"
}

4.21.2.2、新增角色接口
请求方式请求路径是否需求token头
POSTsystem/role

请求体:

{
    "roleName":"测试新增角色",
    "roleKey":"xxx",
    "roleSort":0,
    "status":"0",
    "menuIds":[
        "1",
        "100"
    ],
    "remark":"我是角色备注"
}

响应格式:

{
    "code":200,
    "msg":"操作成功"
}

4.21.3、代码实现

4.21.3.1、获取菜单树接口实现

TreeMenuVO

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.experimental.Accessors;

import java.util.List;

@Data
@AllArgsConstructor
@NoArgsConstructor
@Accessors(chain = true)
public class TreeMenuVO {

    private Long id;
    private String label;
    private Long parentId;
    private List<TreeMenuVO> children;
}

MenuController

@GetMapping("/treeselect")
@ApiOperation(value = "获取菜单树结构")
public ResponseResult treeSelectMenu() {
    return menuService.treeSelectMenu();
}

MenuService

// 获取菜单树结构
ResponseResult treeSelectMenu();

MenuServiceImpl

这里通过stream流和增强for循环进行两个链表的循环赋值对比发现,后者的效率会比前者高,所以这里使用了后者进行循环赋值。

/**
     * 获取菜单树结构
     * @return 菜单树结构
     */
    @Override
    public ResponseResult treeSelectMenu() {
        // 首先,获取所有符合条件的菜单,并转成treeMenuVO
        List<Menu> menus = this.list();
        List<TreeMenuVO> treeMenuVOs = BeanCopyUtils.copyBeanList(menus, TreeMenuVO.class);
        // list双循环,将menu中的menuName复制给treeMenuVOs中的label
//        List<TreeMenuVO> treeMenuVOs = treeMenuVOList.stream().map(
//                menuVO -> menus.stream().filter(menu -> menuVO.getId().equals(menu.getId()))
//                        .findFirst()
//                        .map(menu -> {
//                            menuVO.setLabel(menu.getMenuName());
//                            return menuVO;
//                        }).orElse(null)
//        ).collect(Collectors.toList()); // 1
        for (TreeMenuVO treeMenuVO : treeMenuVOs) {
            for (Menu menu : menus) {
                if (treeMenuVO.getId().equals(menu.getId())) {
                    treeMenuVO.setLabel(menu.getMenuName());
                }
            }
        }
        // 接着,通过顶级菜单id为0获取第一级菜单
        List<TreeMenuVO> parentMenuVOs = treeMenuVOs.stream().filter(treeMenuVO -> SystemConstants.ROUTER_ROOT.equals(treeMenuVO.getParentId()))
                .map(menuVO -> menuVO.setChildren(getChildrenVO(menuVO, treeMenuVOs))).collect(Collectors.toList());
        return ResponseResult.okResult(parentMenuVOs);
    }

    /***
     * 构建菜单树结构
     * @param parentMenuVO 父级菜单
     * @param treeMenuVOs 所有菜单
     * @return 父级菜单的子菜单
     */
    private List<TreeMenuVO> getChildrenVO(TreeMenuVO parentMenuVO, List<TreeMenuVO> treeMenuVOs) {
        return treeMenuVOs.stream().filter(menuVO -> parentMenuVO.getId().equals(menuVO.getParentId()))
                .map(menu -> menu.setChildren(getChildrenVO(menu, treeMenuVOs)))
                .collect(Collectors.toList());
    }

4.21.3.2、新增角色接口实现

AddRoleDTO

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.util.List;

@Data
@AllArgsConstructor
@NoArgsConstructor
public class AddRoleDTO {

    private String roleName;
    private String roleKey;
    private Integer roleSort;
    private String status;
    private List<Long> menuIds;
    private String remark;
}

RoleController

@PostMapping
@ApiOperation(value = "新增角色")
public ResponseResult addRole(@RequestBody AddRoleDTO addRoleDTO) {
    return roleService.addRole(addRoleDTO);
}

RoleService

// 新增角色
ResponseResult addRole(AddRoleDTO addRoleDTO);

RoleServiceImpl

/**
 * 新增角色
 * @param addRoleDTO 角色信息
 * @return 结果集
 */
@Override
@Transactional
public ResponseResult addRole(AddRoleDTO addRoleDTO) {
    // 先将AddRoleDTO转成Role
    Role role = BeanCopyUtils.copyBean(addRoleDTO, Role.class);
    // 接着将role存入数据库
    this.save(role);
    List<RoleMenu> roleMenus = new ArrayList<>();
    addRoleDTO.getMenuIds().forEach(menuId -> {
        RoleMenu roleMenu = new RoleMenu(role.getId(), menuId);
        roleMenus.add(roleMenu);
    });
    // 最后将roleMenus存入数据库
    roleMenuService.saveBatch(roleMenus);
    return ResponseResult.okResult();
}

4.22、修改角色

4.22.1、需求分析

需要提供修改角色的功能,修改角色时可以修改角色所关联的菜单权限

4.22.2、接口设计

4.22.2.1、角色信息回显接口
请求方式请求路径是否需求token头
Getsystem/role/{id}

请求参数:角色id

响应格式:

{
    "code":200,
    "data":{
        "id":"13",
        "remark":"s",
        "roleKey":"xxx",
        "roleName":"s",
        "roleSort":"0",
        "status":"0"
    },
    "msg":"操作成功"
}

4.22.2.2、加载对应角色菜单列表树接口
请求方式请求路径是否需求token头
Get/system/menu/roleMenuTreeselect/{id}

请求参数:角色id

响应格式:

{
    "code":200,
    "data":{
        "menus":[
            {
                "children":[],
                "id":"2023",
                "label":"写博文",
                "parentId":"0"
            },
            {
                "children":[
                    {
                        "children":[],
                        "id":"2019",
                        "label":"文章管理",
                        "parentId":"2017"
                    }
        ],
        "checkedKeys":[
            "1001"  
        ]
    },
    "msg":"操作成功"
}

解释:

menus:代表菜单树;

checkedKeys:代表角色所关联的菜单权限id列表。

4.22.2.3、更新角色信息接口
请求方式请求路径是否需求token头
PUTsystem/role

请求体:

{
    "id":"13",
    "remark":"s",
    "roleKey":"s",
    "roleName":"s",
    "roleSort":0,
    "status":"0",
    "menuIds":[
        "1",
        "100",
        "1001"
    ]
}

响应格式:

{
    "code":200,
    "msg":"操作成功"
}

4.22.3、代码实现

4.22.3.1、角色信息回显接口实现

RoleVO

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.util.Date;

@Data
@AllArgsConstructor
@NoArgsConstructor
public class RoleVO {

    private Long id;
    private String roleKey;
    private String roleName;
    private Integer roleSort;
    private String status;
    private String remark;
    private Date createTime;
}

RoleController

@GetMapping("/{id}")
@ApiOperation(value = "通过id获取角色信息")
public ResponseResult getRoleById(@PathVariable("id") Long id) {
    return ResponseResult.okResult(BeanCopyUtils.copyBean(roleService.getById(id), RoleVO.class));
}

4.22.3.2、加载对应角色菜单列表树接口实现

MenuController

@GetMapping("/roleMenuTreeselect/{id}")
@ApiOperation(value = "加载对应角色菜单列表树")
public ResponseResult roleMenuTreeSelectById(@PathVariable("id") Long id) {
    return menuService.roleMenuTreeSelectById(id);
}

MenuService

// 加载对应角色菜单列表树
ResponseResult roleMenuTreeSelectById(Long id);

MenuServiceImpl

/**
* 加载对应角色菜单列表树
* @param id 角色id
* @return 对应角色菜单列表树
*/
@Override
public ResponseResult roleMenuTreeSelectById(Long id) {
    // 通过角色id获取菜单集
    List<Menu> roleMenus = getBaseMapper().selectMenuTreeByRoleId(id);
    // 获取所有符合条件的菜单
    List<Menu> menus = this.list();
    // 将锁获取的菜单集遍历取出菜单id
    RoleMenuVO roleMenuVO = new RoleMenuVO(MenusToTreeMenuVOs(menus), roleMenus.stream().map(Menu::getId).collect(Collectors.toList()));
    // 将获取的menus集合转成TreeMenuVO
    return ResponseResult.okResult(roleMenuVO);
}

/**
* 将获取的菜单集合转成菜单树结构
* @param menus 原本的菜单集合
* @return 菜单树结构
*/
private List<TreeMenuVO> MenusToTreeMenuVOs(List<Menu> menus) {
    List<TreeMenuVO> treeMenuVOs = BeanCopyUtils.copyBeanList(menus, TreeMenuVO.class);
    // list双循环,将menu中的menuName复制给treeMenuVOs中的label
    //        List<TreeMenuVO> treeMenuVOs = treeMenuVOList.stream().map(
    //                menuVO -> menus.stream().filter(menu -> menuVO.getId().equals(menu.getId()))
    //                        .findFirst()
    //                        .map(menu -> {
    //                            menuVO.setLabel(menu.getMenuName());
    //                            return menuVO;
    //                        }).orElse(null)
    //        ).collect(Collectors.toList()); // 1
    for (TreeMenuVO treeMenuVO : treeMenuVOs) {
        for (Menu menu : menus) {
            if (treeMenuVO.getId().equals(menu.getId())) {
                treeMenuVO.setLabel(menu.getMenuName());
            }
        }
    }
    // 接着,通过顶级菜单id为0获取第一级菜单
    return treeMenuVOs.stream().filter(treeMenuVO -> SystemConstants.ROUTER_ROOT.equals(treeMenuVO.getParentId()))
        .map(menuVO -> menuVO.setChildren(getChildrenVO(menuVO, treeMenuVOs))).collect(Collectors.toList());
}

RoleMenuVO

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.util.List;

@Data
@AllArgsConstructor
@NoArgsConstructor
public class RoleMenuVO {

    private List<TreeMenuVO> menus;
    private List<Long> checkedKeys;
}

TreeMenuVO

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.experimental.Accessors;

import java.util.List;

@Data
@AllArgsConstructor
@NoArgsConstructor
@Accessors(chain = true)
public class TreeMenuVO {

    private Long id;
    private String label;
    private Long parentId;
    private List<TreeMenuVO> children;
}

4.22.3.3、更新角色信息接口实现

RoleController

@PutMapping
@ApiOperation(value = "通过id更新角色信息")
public ResponseResult updateRole(@RequestBody UpdateRoleDTO updateRoleDTO) {
    return roleService.updateRole(updateRoleDTO);
}

RoleService

// 通过id更新角色信息
ResponseResult updateRole(UpdateRoleDTO updateRoleDTO);

UpdateRoleDTO

import lombok.Data;

@Data
public class UpdateRoleDTO extends AddRoleDTO {

    private Long id;
}

RoleServiceImpl

/**
 * 通过id更新角色信息
 * @param updateRoleDTO 角色信息
 * @return 结果集
 */
@Override
@Transactional
public ResponseResult updateRole(UpdateRoleDTO updateRoleDTO) {
    // 先删除之前关联的菜单信息
    roleMenuService.remove(new LambdaQueryWrapper<RoleMenu>()
            .eq(RoleMenu::getRoleId, updateRoleDTO.getId()));
    // 添加新的关联菜单信息
    List<RoleMenu> roleMenus = new ArrayList<>();
    updateRoleDTO.getMenuIds().forEach(menuId -> {
        RoleMenu roleMenu = new RoleMenu(updateRoleDTO.getId(), menuId);
        roleMenus.add(roleMenu);
    });
    roleMenuService.saveBatch(roleMenus);
    // 最后更新角色信息
    // 将UpdateRoleDTO转成Role
    Role role = BeanCopyUtils.copyBean(updateRoleDTO, Role.class);
    this.updateById(role);
    return ResponseResult.okResult();
}

4.23、删除角色

4.23.1、需求分析

删除某个角色。

4.23.2、接口设计

请求方式请求路径是否需求token头
DELETEsystem/role/{id}

请求参数:要删除的角色id

响应格式:

{
    "code":200,
    "msg":"操作成功"
}

4.23.3、代码实现

RoleController

@DeleteMapping("/{id}")
@ApiOperation(value = "通过角色id删除角色信息")
public ResponseResult deleteRoleById(@PathVariable("id") Long id) {
    return roleService.deleteRoleById(id);
}

RoleService

// 通过角色id删除角色信息
ResponseResult deleteRoleById(Long id);

RoleServiceImpl

/**
 * 通过角色id删除角色信息
 * @param id 角色id
 * @return 结果集
 */
@Override
@Transactional
public ResponseResult deleteRoleById(Long id) {
    // TODO 判断是否有用户关联该角色
    // 先删除与之相关联的菜单信息
    roleMenuService.remove(new LambdaQueryWrapper<RoleMenu>()
            .eq(RoleMenu::getRoleId, id));
    // 再删除角色本身
    this.removeById(id);
    return ResponseResult.okResult();
}

4.24、用户列表

4.24.1、需求分析

需要用户分页列表接口。

可以根据用户名模糊、手机号、状态搜索。

4.24.2、接口设计

请求方式请求路径是否需求token头
GETsystem/user/list

请求参数:

pageNum: 页码
pageSize: 每页条数
userName:用户名
phonenumber:手机号
status:状态

响应格式:

{
    "code":200,
    "data":{
        "rows":[
            {
                "avatar":"http://xxx.clouddn.com/2022/03/05/75fd15587811443a9a9a771f24da458d.png",
                "createTime":"2023-10-01 17:01:56",
                "email":"222222222@qq.com",
                "id":"1",
                "nickName":"xxx",
                "phonenumber":"18888888888",
                "sex":"1",
                "status":"0",
                "updateBy":"1",
                "updateTime":"2023-10-01 21:36:22",
                "userName":"xxx"
            }
        ],
        "total":"1"
    },
    "msg":"操作成功"
}

4.24.3、代码实现

UserAdminVO

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.util.Date;

@Data
@AllArgsConstructor
@NoArgsConstructor
public class UserAdminVO {

    /**
     * 主键
     */
    private Long id;

    /**
     * 用户名
     */
    private String userName;

    /**
     * 昵称
     */
    private String nickName;

    /**
     * 账号状态(0正常 1停用)
     */
    private String status;

    /**
     * 邮箱
     */
    private String email;

    /**
     * 手机号
     */
    private String phonenumber;

    /**
     * 用户性别(0男,1女,2未知)
     */
    private String sex;

    /**
     * 头像
     */
    private String avatar;

    /**
     * 创建时间
     */
    private Date createTime;
}

QueryUserDTO

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@AllArgsConstructor
@NoArgsConstructor
public class QueryUserDTO {

    private String userName;
    private String phonenumber;
    private String status;
}

UserController

import com.hashiqi.domain.ResponseResult;
import com.hashiqi.domain.dto.QueryUserDTO;
import com.hashiqi.service.UserService;
import io.swagger.annotations.ApiOperation;
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")
    @ApiOperation(value = "获取用户分页列表")
    public ResponseResult pageUserList(
            Integer pageNum,
            Integer pageSize,
            QueryUserDTO queryUserDTO) {
        return userService.pageUserList(pageNum, pageSize, queryUserDTO);
    }
}

UserService

// 获取用户分页列表
ResponseResult pageUserList(Integer pageNum, Integer pageSize, QueryUserDTO queryUserDTO);

UserServiceImpl

/**
 * 获取用户分页列表
 * @param pageNum 当前页
 * @param pageSize 页大小
 * @param queryUserDTO 请求参数对象
 * @return 用户分页列表
 */
@Override
public ResponseResult pageUserList(Integer pageNum, Integer pageSize, QueryUserDTO queryUserDTO) {
    // 获取符合条件的用户分页列表
    Page<User> page = this.page(
            new Page<>(pageNum, pageSize),
            new LambdaUpdateWrapper<User>()
                    .like(StringUtils.hasText(queryUserDTO.getUserName()), User::getUserName, queryUserDTO.getUserName())
                    .like(StringUtils.hasText(queryUserDTO.getPhonenumber()), User::getPhonenumber, queryUserDTO.getPhonenumber())
                    .eq(StringUtils.hasText(queryUserDTO.getStatus()), User::getStatus, queryUserDTO.getStatus()));
    // User转换成UserAdminVO
    List<UserAdminVO> userAdminVOs = BeanCopyUtils.copyBeanList(page.getRecords(), UserAdminVO.class);
    return ResponseResult.okResult(new PageVO(userAdminVOs, page.getTotal()));
}

4.25、新增用户

4.25.1、需求分析

需要新增用户功能,可以直接管理角色。

新增用户注意加密处理存储。

用户名不能为空且不存在于数据库这种,否则提示:必须填写用户名/已有该用户名。

手机号、邮箱同理。

4.25.2、接口设计

4.25.2.1、查询角色列表接口

注意:查询的是所有状态正常的角色

请求方式请求路径是否需求token头
GET/system/role/listAllRole

响应格式:

{
    "code":200,
    "data":[
        {
            "createBy":"0",
            "createTime":"2023-10-02 18:46:19",
            "delFlag":"0",
            "id":"1",
            "remark":"超级管理员",
            "roleKey":"admin",
            "roleName":"超级管理员",
            "roleSort":"1",
            "status":"0",
            "updateBy":"0"
        },
        ...
    ],
    "msg":"操作成功"
}

4.25.2.2、新增用户
请求方式请求路径是否需求token头
POSTsystem/user

请求体:

{
    "userName":"wqeree",
    "nickName":"测试新增用户",
    "password":"1234343",
    "phonenumber":"18889778907",
    "email":"233@sq.com",
    "sex":"0",
    "status":"0",
    "roleIds":[
        "2"
    ]
}

响应格式:

{
    "code":200,
    "msg":"操作成功"
}

4.25.3、代码实现

4.25.3.1、查询角色列表接口实现

RoleController

@GetMapping("/listAllRole")
public ResponseResult listAllRole() {
    return ResponseResult.okResult(roleService.list(new LambdaQueryWrapper<Role>()
            .eq(Role::getStatus, SystemConstants.STATUS_NORMAL)));
}

4.25.3.2、新增用户接口实现

AddUserDTO

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.util.List;

@Data
@AllArgsConstructor
@NoArgsConstructor
public class AddUserDTO {

    private String userName;
    private String nickName;
    private String password;
    private String phonenumber;
    private String email;
    private String sex;
    private String status;
    private List<Long> roleIds;
}

UserController

@PostMapping
@ApiOperation(value = "后台新增用户")
public ResponseResult addUser(@RequestBody AddUserDTO addUserDTO) {
    return userService.addUser(addUserDTO);
}

UserService

// 后台新增用户
ResponseResult addUser(AddUserDTO addUserDTO);

UserServiceImpl

@Autowired
private UserRoleService userRoleService;

/**
 * 后台新增用户
 * @param addUserDTO 用户信息
 * @return 结果集
 */
@Override
@Transactional
public ResponseResult addUser(AddUserDTO addUserDTO) {
    // 先进行用户名、手机号、邮箱的判断
    String userName = addUserDTO.getUserName();
    String phonenumber = addUserDTO.getPhonenumber();
    String email = addUserDTO.getEmail();
    if (!StringUtils.hasText(userName)) {
        throw new SystemException(AppHttpCodeEnum.REQUIRE_USERNAME);
    }
    if (userNameExist(userName)) {
        throw new SystemException(AppHttpCodeEnum.USERNAME_EXIST);
    }
    if (phoneNumberExist(phonenumber)) {
        throw new SystemException(AppHttpCodeEnum.PHONENUMBER_EXIST);
    }
    if (emailExist(email)) {
        throw new SystemException(AppHttpCodeEnum.EMAIL_EXIST);
    }
    // 再将AddUserDTO转成User
    User user = BeanCopyUtils.copyBean(addUserDTO, User.class);
    // 对用户的密码进行加密处理
    String encodePassword = passwordEncoder.encode(user.getPassword());
    user.setPassword(encodePassword);
    // 最后将用户进行保存到数据库
    this.save(user);
    // 保存成功后,则会获取到用户的id,这时候进行用户和角色的关联操作
    List<UserRole> userRoles = new ArrayList<>();
    addUserDTO.getRoleIds().forEach(roleId -> {
        UserRole userRole = new UserRole(user.getId(), roleId);
        userRoles.add(userRole);
    });
    userRoleService.saveBatch(userRoles);
    return ResponseResult.okResult();
}

/**
 * 判断手机号是否已存在
 * @param phoneNumber 新增用户的手机号
 * @return true:存在;false:不存在
 */
private boolean phoneNumberExist(String phoneNumber) {
    return this.count(new LambdaQueryWrapper<User>().eq(User::getPhonenumber, phoneNumber)) > 0;
}

4.26、删除用户

4.26.1、需求分析

删除某个用户。

4.26.2、接口设计

不能删除当前操作的用户。

请求方式请求路径是否需求token头
DELETE/system/user/{id}

请求参数:要删除的用户id

响应格式:

{
    "code":200,
    "msg":"操作成功"
}

4.26.3、代码实现

UserController

@DeleteMapping("/{id}")
@ApiOperation(value = "删除某个用户")
public ResponseResult deleteUserById(@PathVariable("id") Long id) {
    return userService.deleteUserById(id);
}

UserService

// 删除某个用户
ResponseResult deleteUserById(Long id);

UserServiceImpl

/**
 * 删除某个用户
 * @param id 用户id
 * @return 结果集
 */
@Override
@Transactional
public ResponseResult deleteUserById(Long id) {
    // 首先,判断当前登录用户是不是要删除的用户
    if (SecurityUtils.getUserId().equals(id)) {
        throw new SystemException(AppHttpCodeEnum.LOGIN_USER_EXIST);
    }
    // 接着删除用户与角色的关联关系
    userRoleService.remove(new LambdaQueryWrapper<UserRole>()
            .eq(UserRole::getUserId, id));
    // 接着删除用户本身
    this.removeById(id);
    return ResponseResult.okResult();
}

4.27、修改用户

4.27.1、需求分析

需要提供修改用户的功能,修改用户时可以修改用户所关联的角色。

4.27.2、接口设计

4.27.2.1、根据id查询用户信息回显接口
请求方式请求路径是否需求token头
Get/system/user/{id}

请求参数:用户id

响应格式:

roleIds:用户所关联的角色id列表
roles:所有角色的列表
user:用户信息
{
    "code":200,
    "data":{
        "roleIds":[
            "11"
        ],
        "roles":[
            {
                "createBy":"0",
                "createTime":"2023-10-02 18:46:19",
                "delFlag":"0",
                "id":"1",
                "remark":"超级管理员",
                "roleKey":"admin",
                "roleName":"超级管理员",
                "roleSort":"1",
                "status":"0",
                "updateBy":"0"
            },
            ...
        ],
        "user":{
            "email":"sdasd@2132.com",
            "id":"14787164048663",
            "nickName":"xxx",
            "sex":"0",
            "status":"0",
            "userName":"xxx"
        }
    },
    "msg":"操作成功"
}

4.27.2.2、更新用户信息接口
请求方式请求路径是否需求token头
PUT/system/user

请求体:

{
    "email":"weq@2132.com",
    "id":"14787164048663",
    "nickName":"xxx",
    "sex":"1",
    "status":"0",
    "userName":"xxx",
    "roleIds":[
        "11"
    ]
}

响应格式:

{
    "code":200,
    "msg":"操作成功"
}

4.27.3、代码实现

4.27.3.1、根据id查询用户信息回显接口实现

AdminUserVO

import com.hashiqi.domain.entity.Role;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.util.List;

@Data
@AllArgsConstructor
@NoArgsConstructor
public class AdminUserVO {

    private List<Long> roleIds;
    private List<Role> roles;
    private UserAdminVO user;
}

UserController

@GetMapping("/{id}")
@ApiOperation(value = "根据id查询用户信息回显")
public ResponseResult getUserById(@PathVariable("id") Long id) {
    return userService.getUserById(id);
}

UserService

// 后台根据id查询用户信息回显
ResponseResult getUserById(Long id);

UserServiceImpl

 

/**
 * 后台根据id查询用户信息回显
 * @param id 用户id
 * @return 结果集
 */
@Override
public ResponseResult getUserById(Long id) {
    // 通过用户id查询用户信息
    User oldUser = this.getById(id);
    // 将User转成UserAdminVO
    UserAdminVO user = BeanCopyUtils.copyBean(oldUser, UserAdminVO.class);
    // 获取与该用户关联的所有角色列表id
    List<Long> roleIds = userRoleService.list(new LambdaQueryWrapper<UserRole>()
            .eq(UserRole::getUserId, id))
            .stream().map(UserRole::getRoleId)
            .collect(Collectors.toList());
    // 获取所有角色列表
    List<Role> roles = roleService.list();
    // 将这些获取的数据都进行封装
    AdminUserVO adminUserVO = new AdminUserVO(roleIds, roles, user);
    return ResponseResult.okResult(adminUserVO);
}

4.27.3.2、更新用户信息接口实现

UpdateUserDTO

import lombok.Data;

@Data
public class UpdateUserDTO extends AddUserDTO {

    private Long id;
}

UserController

@PutMapping
@ApiOperation(value = "更新用户信息")
public ResponseResult updateUser(@RequestBody UpdateUserDTO updateUserDTO) {
    return userService.updateUser(updateUserDTO);
}

UserService

// 更新用户信息
ResponseResult updateUser(UpdateUserDTO updateUserDTO);

UserServiceImpl

/**
 * 更新用户信息
 * @param updateUserDTO 要更新的用户信息
 * @return 结果集
 */
@Override
public ResponseResult updateUser(UpdateUserDTO updateUserDTO) {
    // 首先UpdateUserDTO转成User
    User user = BeanCopyUtils.copyBean(updateUserDTO, User.class);
    // 先删除之前用户与角色的关联关系
    userRoleService.remove(new LambdaQueryWrapper<UserRole>()
            .eq(UserRole::getUserId, user.getId()));
    // 重新添加与角色的关联关系
    List<UserRole> userRoles = new ArrayList<>();
    updateUserDTO.getRoleIds().forEach(roleId -> {
        UserRole userRole = new UserRole(user.getId(), roleId);
        userRoles.add(userRole);
    });
    userRoleService.saveBatch(userRoles);
    // 最后更新用户信息
    this.updateById(user);
    return ResponseResult.okResult();
}

4.28、新增分类

4.28.1、需求分析

新增分类功能

4.28.2、接口设计

请求方式请求路径是否需求token头
POST/content/category

请求体:

{
    "name":"威威",
    "description":"是的",
    "status":"0"
}

响应格式:

{
    "code":200,
    "msg":"操作成功"
}

4.28.3、代码实现

CategoryDTO

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@AllArgsConstructor
@NoArgsConstructor
public class CategoryDTO {

    private String name;
    private String status;

    private String description;
}

CategoryController

@PostMapping
@ApiOperation(value = "新增分类")
public ResponseResult addCategory(@RequestBody CategoryDTO categoryDTO) {
    return categoryService.addCategory(categoryDTO);
}

CategoryService

// 新增分类
ResponseResult addCategory(CategoryDTO categoryDTO);

CategoryServiceImpl

/**
 * 新增分类
 * @param categoryDTO 分类信息
 * @return 结果集
 */
@Override
public ResponseResult addCategory(CategoryDTO categoryDTO) {
    Category category = BeanCopyUtils.copyBean(categoryDTO, Category.class);
    this.save(category);
    return ResponseResult.okResult();
}

4.29、修改分类

4.29.1、需求分析

提供修改分类的功能

4.29.2、接口设计

4.29.2.1、根据id查询分类
请求方式请求路径是否需求token头
Getcontent/category/{id}

请求参数:分类id

响应格式:

{
    "code":200,
    "data":{
        "description":"xxx",
        "id":"4",
        "name":"ww",
        "status":"0"
    },
    "msg":"操作成功"
}

4.29.2.2、更新分类
请求方式请求路径是否需求token头
PUT/content/category

请求体:

{
    "description":"xxx",
    "id":"3",
    "name":"xxx",
    "status":"0"
}

响应格式:

{
    "code":200,
    "msg":"操作成功"
}

4.29.3、代码实现

4.29.3.1、根据id查询分类接口实现

CategoryVO

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@NoArgsConstructor
@AllArgsConstructor
public class CategoryVO {

    private Long id;
    private String name;
    private String description;
    private String status;
}

CategoryController

@GetMapping("/{id}")
@ApiOperation(value = "通过id查询单个分类")
public ResponseResult getCategory(@PathVariable("id") Long id) {
    return categoryService.getCategory(id);
}

CategoryService

// 通过id查询单个分类
ResponseResult getCategory(Long id);

CategoryServiceImpl

/**
 * 通过id查询单个分类
 * @param id 分类id
 * @return 分类信息
 */
@Override
public ResponseResult getCategory(Long id) {
    Category category = this.getById(id);
    CategoryVO categoryVO = BeanCopyUtils.copyBean(category, CategoryVO.class);
    return ResponseResult.okResult(categoryVO);
}

4.29.3.2、更新分类接口实现

CategoryDTO

将这个实体类进行修改,并也将CategoryVO进行修改。

@Data
@AllArgsConstructor
@NoArgsConstructor
public class CategoryDTO {

    private Long id;
    private String name;
    private String status;
    private String description;
}

CategoryVO

@Data
public class CategoryVO extends CategoryDTO {

}

CategoryController

@PutMapping
@ApiOperation(value = "更新分类信息")
public ResponseResult updateCategory(@RequestBody CategoryDTO categoryDTO) {
    return categoryService.updateCategory(categoryDTO);
}

CategoryService

// 更新分类信息
ResponseResult updateCategory(CategoryDTO categoryDTO);

CategoryServiceImpl

/**
 * 更新分类信息
 * @param categoryDTO 分类信息
 * @return 结果集
 */
@Override
public ResponseResult updateCategory(CategoryDTO categoryDTO) {
    Category category = BeanCopyUtils.copyBean(categoryDTO, Category.class);
    this.updateById(category);
    return ResponseResult.okResult();
}

4.30、删除分类

4.30.1、需求分析

删除某个分类。

4.30.2、接口设计

请求方式请求路径是否需求token头
DELETE/content/category/{id}

请求参数:要删除的分类id

响应格式:

{
    "code":200,
    "msg":"操作成功"
}

4.30.3、代码实现

CategoryController

@DeleteMapping("/{id}")
@ApiOperation(value = "删除分类信息")
public ResponseResult deleteCategory(@PathVariable("id") Long id) {
    return ResponseResult.okResult(categoryService.removeById(id));
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值