4、后台管理
4.15、菜单列表
4.15.1、需求分析
需要展示菜单列表,不需要分页。
可以针对菜单名进行模糊查询,也可以针对菜单的状态进行查询。
菜单要按照父菜单id和orderNum进行排序。
4.15.2、接口设计
请求方式 | 请求路径 | 是否需求token头 |
---|---|---|
GET | system/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头 |
---|---|---|
POST | content/article | 是 |
请求体参数:Menu类对应的json格式
响应格式:
{ "code":200, "msg":"操作成功" }
4.16.3、代码实现
MenuController
4.17、修改菜单
4.17.1、需求分析
能够修改菜单,但是修改的时候不能把父菜单设置为当前菜单,如果设置了需要给出相应的提示。并且修改失败。
4.17.2、接口设计
4.17.2.1、根据id查询菜单数据
请求方式 | 请求路径 | 是否需求token头 |
---|---|---|
Get | system/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头 |
---|---|---|
PUT | system/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头 |
---|---|---|
DELETE | content/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头 |
---|---|---|
GET | system/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头 |
---|---|---|
PUT | system/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头 |
---|---|---|
POST | system/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头 |
---|---|---|
Get | system/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头 |
---|---|---|
PUT | system/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头 |
---|---|---|
DELETE | system/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头 |
---|---|---|
GET | system/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头 |
---|---|---|
POST | system/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头 |
---|---|---|
Get | content/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));
}