【wiki知识库】07.用户管理后端SpringBoot部分

目录

一、今日目标

二、??SpringBoot部分类的添加

[2.1 使用逆向工程新增User模块](#2.1 使用逆向工程新增User模块)

[2.2 UserQueryParam添加](#2.2 UserQueryParam添加)

[2.3 UserSaveParam添加](#2.3 UserSaveParam添加)

[2.4 UserResetPasswordParam添加](#2.4 UserResetPasswordParam添加)

[2.5 UserQueryVo添加](#2.5 UserQueryVo添加)

[2.6 SnowFlake工具类](#2.6 SnowFlake工具类)

三、??后端新增接口?

[3.1 /user/list接口添加](#3.1 /user/list接口添加)

[3.2 /user/save接口添加](#3.2 /user/save接口添加)

[3.3 /user/delete接口添加](#3.3 /user/delete接口添加)

[3.4 /user/reset-password接口添加](#3.4 /user/reset-password接口添加)


一、今日目标

上一篇文章我把前端部分的代码给大家了,这篇文章就来实现上一篇文章没有完成的接口。

二、??SpringBoot部分类的添加

2.1 使用逆向工程新增User模块

这一块的代码和之前的相同,我们找到逆向工程的工具类后,把类的部分改为user即可。

2.2 UserQueryParam添加

这个类看名字也知道是用来用户查询的,要继承之前的分页类。

复制代码
@Data
public class UserQueryParam extends PageParam {
    private String loginName;
}

2.3 UserSaveParam添加

这个类是用来作为用户新增参数接收用的。这个类作为用户信息保存的参数类,在这个类中对于属性的值做了一些限制。用户名、昵称和密码不能为空,同时密码要匹配正则表达式,这个正则表达式限制了密码由数字和字母组成,并且长度在6-32位,如果上边有条件不满足,那么就会抛出message中的错误。

复制代码
@Data
public class UserSaveParam {
    private Long id;

    @NotNull(message = "【用户名】不能为空")
    private String loginName;

    @NotNull(message = "【昵称】不能为空")
    private String name;

    @NotNull(message = "【密码】不能为空")
    @Pattern(regexp = "^(?![0-9]+$)(?![a-zA-Z]+$)[0-9A-Za-z]{6,32}$", message = "【密码】至少包含 数字和英文,长度6-32")
    private String password;

}

2.4 UserResetPasswordParam添加

这个类用于重置用户密码,传入账号的id还有用户的新密码。同样也做了密码的安全性校验。

复制代码
@Data
public class UserResetPasswordParam {
    private Long id;

    @NotNull(message = "【密码】不能为空")
    @Pattern(regexp = "^(?![0-9]+$)(?![a-zA-Z]+$)[0-9A-Za-z]{6,32}$", message = "【密码】至少包含 数字和英文,长度6-32")
    private String password;
}

2.5 UserQueryVo添加

这个类作为用户查询结果返回。

复制代码
@Data
@NoArgsConstructor
@AllArgsConstructor
public class UserQueryVo {
    private Long id;

    private String loginName;

    private String name;

    private String password;

}

2.6 SnowFlake工具类

这个工具类的作用就是生成一个不会重复的id值,想要了解具体内容的小伙伴可以搜索一下雪花算法。现在我先不过多介绍,可能之后会补上这一部分。现在只要记住这个类可以帮你生成一个不会重复的id值就可以了。

复制代码
/**
 * Twitter的分布式自增ID雪花算法
 **/
@Component
public class SnowFlake {

    /**
     * 起始的时间戳
     */
    private final static long START_STMP = 1609459200000L; // 2021-01-01 00:00:00

    /**
     * 每一部分占用的位数
     */
    private final static long SEQUENCE_BIT = 12; //序列号占用的位数
    private final static long MACHINE_BIT = 5;   //机器标识占用的位数
    private final static long DATACENTER_BIT = 5;//数据中心占用的位数

    /**
     * 每一部分的最大值
     */
    private final static long MAX_DATACENTER_NUM = -1L ^ (-1L << DATACENTER_BIT);
    private final static long MAX_MACHINE_NUM = -1L ^ (-1L << MACHINE_BIT);
    private final static long MAX_SEQUENCE = -1L ^ (-1L << SEQUENCE_BIT);

    /**
     * 每一部分向左的位移
     */
    private final static long MACHINE_LEFT = SEQUENCE_BIT;
    private final static long DATACENTER_LEFT = SEQUENCE_BIT + MACHINE_BIT;
    private final static long TIMESTMP_LEFT = DATACENTER_LEFT + DATACENTER_BIT;

    private long datacenterId = 1;  //数据中心
    private long machineId = 1;     //机器标识
    private long sequence = 0L; //序列号
    private long lastStmp = -1L;//上一次时间戳

    public SnowFlake() {
    }

    public SnowFlake(long datacenterId, long machineId) {
        if (datacenterId > MAX_DATACENTER_NUM || datacenterId < 0) {
            throw new IllegalArgumentException("datacenterId can't be greater than MAX_DATACENTER_NUM or less than 0");
        }
        if (machineId > MAX_MACHINE_NUM || machineId < 0) {
            throw new IllegalArgumentException("machineId can't be greater than MAX_MACHINE_NUM or less than 0");
        }
        this.datacenterId = datacenterId;
        this.machineId = machineId;
    }

    /**
     * 产生下一个ID
     *
     * @return
     */
    public synchronized long nextId() {
        long currStmp = getNewstmp();
        if (currStmp < lastStmp) {
            throw new RuntimeException("Clock moved backwards.  Refusing to generate id");
        }

        if (currStmp == lastStmp) {
            //相同毫秒内,序列号自增
            sequence = (sequence + 1) & MAX_SEQUENCE;
            //同一毫秒的序列数已经达到最大
            if (sequence == 0L) {
                currStmp = getNextMill();
            }
        } else {
            //不同毫秒内,序列号置为0
            sequence = 0L;
        }

        lastStmp = currStmp;

        return (currStmp - START_STMP) << TIMESTMP_LEFT //时间戳部分
                | datacenterId << DATACENTER_LEFT       //数据中心部分
                | machineId << MACHINE_LEFT             //机器标识部分
                | sequence;                             //序列号部分
    }

    private long getNextMill() {
        long mill = getNewstmp();
        while (mill <= lastStmp) {
            mill = getNewstmp();
        }
        return mill;
    }

    private long getNewstmp() {
        return System.currentTimeMillis();
    }
}

上边的代码都没有什么难度,下面就开始实现用户管理的逻辑部分。

三、??后端新增接口

在UserController类中需要小小的修改一下。

复制代码
@RestController
@RequestMapping("/user")
public class UserController {
  @Autowired
  private UserService userService;
}

3.1 /user/list接口添加

其实这样的代码已经写了不少了,这样的list查询并没有什么难度,

复制代码
@RequestMapping("/list")
  public CommonResp list(@Validated UserQueryParam userQueryParam){
    PageVo<UserQueryVo> list = userService.list(userQueryParam);
    return new CommonResp(true,"查找成功", list);
  }

UserServiceImpl中的list接口。

复制代码
 public PageVo<UserQueryVo> list(UserQueryParam userQueryParam) {
        // 构建一个表达式来筛选用户
        LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(StringUtils.isNotBlank(userQueryParam.getLoginName()),
                User::getLoginName,userQueryParam.getLoginName());
        // 创建分页查询的对象
        Page<User> page = new Page<>(userQueryParam.getPage(),userQueryParam.getSize());
        // 接收分页查询的结果
        Page<User> resultPage = userMapper.selectPage(page, queryWrapper);
        // 这个对象用于返回给前端
        PageVo<UserQueryVo> pageVo = new PageVo<>();
        // 将分页查询的结果转换一下 User-》UserQueryVo
        List<UserQueryVo> users = CopyUtil.copyList(resultPage.getRecords(),UserQueryVo.class);
        pageVo.setList(users);
        pageVo.setTotal(resultPage.getTotal());
        return pageVo;
    }

3.2 /user/save接口添加

值得注意的是,在数据库当中,用户的密码我们不在进行明文存储了,我们存储的都是加密后的代码,这里仅仅使用了简单的md5加密算法,实际的加密码算法有很多种类型。

复制代码
@PostMapping("/save")
  public CommonResp save(@Valid @RequestBody UserSaveParam userSaveParam) {
    userSaveParam.setPassword(DigestUtils.md5DigestAsHex(userSaveParam.getPassword().getBytes()));
    boolean save = userService.save(userSaveParam);
    String message = Boolean.TRUE.equals(save) ? "添加成功":"添加失败";
    return new CommonResp<>(save,message,null);
  }

UserServiceImpl中的save接口。

复制代码
 public boolean save(UserSaveParam userSaveParam) {
        User user = CopyUtil.copy(userSaveParam, User.class);
        if (ObjectUtils.isEmpty(userSaveParam.getId())) {
            User userDB = selectByLoginName(userSaveParam.getLoginName());
            if (ObjectUtils.isEmpty(userDB)) {
                // 新增
                user.setId(snowFlake.nextId());
                userMapper.insert(user);
            } else {
                // 用户名已存在
                throw new RuntimeException("用户存在");
            }
        } else {
            // 更新
            user.setLoginName(null);
            user.setPassword(null);
            userMapper.updateById(user);
        }
        return true;
    }

 private User selectByLoginName(String loginName) {
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("login_name", loginName);
        return userMapper.selectOne(queryWrapper);
    }

3.3 /user/delete接口添加

这一部分就更简单了。

复制代码
  @DeleteMapping("/delete/{id}")
  public CommonResp delete(@PathVariable Long id) {
    boolean res = userService.removeById(id);
    String message = Boolean.TRUE.equals(res) ? "删除成功":"删除失败";
    return new CommonResp<>(res,message,null);
  }

3.4 /user/reset-password接口添加

复制代码
  @PostMapping("/reset-password")
  public CommonResp resetPassword(@Valid @RequestBody UserResetPasswordParam req) {
    req.setPassword(DigestUtils.md5DigestAsHex(req.getPassword().getBytes()));
    userService.resetPassword(req);
    return new CommonResp(true,"密码重置成功",null);
  }

UserServiceImpl中的resetPassword接口。

复制代码
    public void resetPassword(UserResetPasswordParam req) {
        User user = CopyUtil.copy(req, User.class);
        userMapper.updateById(user);
    }
相关推荐
fanzhonghong6 分钟前
javaWeb开发之Maven高级
java·开发语言·spring boot·spring cloud·私服
aircrushin12 分钟前
给宝宝办了个宴,朋友用trae做的工具帮了大忙
前端·后端
码上小翔哥18 分钟前
Jackson 配置深度解析
java·后端
程序员Sunday21 分钟前
爆肝万字!这应该是全网最全的 Codex 实战教程了
前端·后端·ai编程
aircrushin22 分钟前
朋友用trae搭建的工具,解决了旅行拍照共享的大事儿
前端·后端
星栈23 分钟前
把业务逻辑写成纯函数之后,我再也不想写 Service 层了
后端·开源
未秃头的程序猿23 分钟前
如何用 AI 写出符合规范的 Java 代码?我总结了 7 条有效建议
java·后端·ai编程
阿聪谈架构24 分钟前
第10章:Agent 记忆系统 —— 让 AI 真正"记住"你
人工智能·后端
木雷坞26 分钟前
我把 AI Coding Agent 的 MCP 工具链放进容器里跑了一遍
后端
BING_Algorithm33 分钟前
开发常用Linux命令
linux·后端