diff --git a/src/main/java/com/guwan/backend/entity/UserRead.java b/src/main/java/com/guwan/backend/entity/UserRead.java
new file mode 100644
index 0000000..b850186
--- /dev/null
+++ b/src/main/java/com/guwan/backend/entity/UserRead.java
@@ -0,0 +1,33 @@
+package com.guwan.backend.entity;
+
+import lombok.Data;
+
+import java.time.LocalDateTime;
+
+@Data
+public class UserRead {
+ /**
+ * 用户id
+ */
+ private Long userId;
+ /**
+ * 图书id
+ */
+ private Long bookId;
+ /**
+ * 用户上次阅读节位置
+ */
+ private Integer sectionId;
+
+ private Long thisReadingTime;
+
+ /**
+ * 该书累计阅读时间
+ */
+ private Long cumulativeReadingTime;
+ /**
+ * 上次阅读时间
+ */
+ private LocalDateTime lastReadTime;
+
+}
diff --git a/src/main/java/com/guwan/backend/mybatis/query/LambdaQueryWrapperX.java b/src/main/java/com/guwan/backend/mybatis/query/LambdaQueryWrapperX.java
new file mode 100644
index 0000000..22b4f6b
--- /dev/null
+++ b/src/main/java/com/guwan/backend/mybatis/query/LambdaQueryWrapperX.java
@@ -0,0 +1,135 @@
+package com.guwan.backend.mybatis.query;
+
+import cn.hutool.core.util.ArrayUtil;
+import cn.hutool.core.util.ObjectUtil;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.core.toolkit.support.SFunction;
+import org.apache.commons.lang3.ArrayUtils;
+import org.springframework.util.StringUtils;
+
+import java.util.Collection;
+
+/**
+ * 拓展 MyBatis Plus QueryWrapper 类,主要增加如下功能:
+ *
+ * 1. 拼接条件的方法,增加 xxxIfPresent 方法,用于判断值不存在的时候,不要拼接到条件中。
+ *
+ * @param 数据类型
+ */
+public class LambdaQueryWrapperX extends LambdaQueryWrapper {
+
+ public LambdaQueryWrapperX likeIfPresent(SFunction column, String val) {
+ if (StringUtils.hasText(val)) {
+ return (LambdaQueryWrapperX) super.like(column, val);
+ }
+ return this;
+ }
+
+ public LambdaQueryWrapperX inIfPresent(SFunction column, Collection> values) {
+ if (ObjectUtil.isAllNotEmpty(values) && !ArrayUtil.isEmpty(values)) {
+ return (LambdaQueryWrapperX) super.in(column, values);
+ }
+ return this;
+ }
+
+ public LambdaQueryWrapperX inIfPresent(SFunction column, Object... values) {
+ if (ObjectUtil.isAllNotEmpty(values) && !ArrayUtil.isEmpty(values)) {
+ return (LambdaQueryWrapperX) super.in(column, values);
+ }
+ return this;
+ }
+
+ public LambdaQueryWrapperX eqIfPresent(SFunction column, Object val) {
+ if (ObjectUtil.isNotEmpty(val)) {
+ return (LambdaQueryWrapperX) super.eq(column, val);
+ }
+ return this;
+ }
+
+ public LambdaQueryWrapperX neIfPresent(SFunction column, Object val) {
+ if (ObjectUtil.isNotEmpty(val)) {
+ return (LambdaQueryWrapperX) super.ne(column, val);
+ }
+ return this;
+ }
+
+ public LambdaQueryWrapperX gtIfPresent(SFunction column, Object val) {
+ if (val != null) {
+ return (LambdaQueryWrapperX) super.gt(column, val);
+ }
+ return this;
+ }
+
+ public LambdaQueryWrapperX geIfPresent(SFunction column, Object val) {
+ if (val != null) {
+ return (LambdaQueryWrapperX) super.ge(column, val);
+ }
+ return this;
+ }
+
+ public LambdaQueryWrapperX ltIfPresent(SFunction column, Object val) {
+ if (val != null) {
+ return (LambdaQueryWrapperX) super.lt(column, val);
+ }
+ return this;
+ }
+
+ public LambdaQueryWrapperX leIfPresent(SFunction column, Object val) {
+ if (val != null) {
+ return (LambdaQueryWrapperX) super.le(column, val);
+ }
+ return this;
+ }
+
+ public LambdaQueryWrapperX betweenIfPresent(SFunction column, Object val1, Object val2) {
+ if (val1 != null && val2 != null) {
+ return (LambdaQueryWrapperX) super.between(column, val1, val2);
+ }
+ if (val1 != null) {
+ return (LambdaQueryWrapperX) ge(column, val1);
+ }
+ if (val2 != null) {
+ return (LambdaQueryWrapperX) le(column, val2);
+ }
+ return this;
+ }
+
+ public LambdaQueryWrapperX betweenIfPresent(SFunction column, Object[] values) {
+ Object val1 = ArrayUtils.get(values, 0);
+ Object val2 = ArrayUtils.get(values, 1);
+ return betweenIfPresent(column, val1, val2);
+ }
+
+ // ========== 重写父类方法,方便链式调用 ==========
+
+ @Override
+ public LambdaQueryWrapperX eq(boolean condition, SFunction column, Object val) {
+ super.eq(condition, column, val);
+ return this;
+ }
+
+ @Override
+ public LambdaQueryWrapperX eq(SFunction column, Object val) {
+ super.eq(column, val);
+ return this;
+ }
+
+ @Override
+ public LambdaQueryWrapperX orderByDesc(SFunction column) {
+ super.orderByDesc(true, column);
+ return this;
+ }
+
+ @Override
+ public LambdaQueryWrapperX last(String lastSql) {
+ super.last(lastSql);
+ return this;
+ }
+
+ @Override
+ public LambdaQueryWrapperX in(SFunction column, Collection> coll) {
+ super.in(column, coll);
+ return this;
+ }
+
+}
diff --git a/src/main/java/com/guwan/backend/service/impl/UserServiceImpl.java b/src/main/java/com/guwan/backend/service/impl/UserServiceImpl.java
index cb015a7..ddb1a44 100644
--- a/src/main/java/com/guwan/backend/service/impl/UserServiceImpl.java
+++ b/src/main/java/com/guwan/backend/service/impl/UserServiceImpl.java
@@ -7,6 +7,7 @@ import com.guwan.backend.dto.user.RegisterDTO;
import com.guwan.backend.dto.user.UserDTO;
import com.guwan.backend.entity.User;
import com.guwan.backend.mapper.UserMapper;
+import com.guwan.backend.mybatis.query.LambdaQueryWrapperX;
import com.guwan.backend.service.EmailService;
import com.guwan.backend.service.UserService;
import com.guwan.backend.util.JwtUtil;
@@ -92,7 +93,7 @@ public class UserServiceImpl implements UserService {
System.out.println("request = " + request);
if (request.getActiveTab().equals("account")) {
- user = userMapper.selectOne(new LambdaQueryWrapper().eq(User::getUsername, request.getUsername()));
+ user = userMapper.selectOne(new LambdaQueryWrapperX().eqIfPresent(User::getUsername, request.getUsername()));
if (user == null || !passwordEncoder.matches(request.getPassword(), user.getPassword())) {
throw new IllegalArgumentException("用户名或密码错误");
}