当前位置: 首页 > news >正文

代码实现特殊的字段的基本功能

在使用 tk.mybatis.mapper.common.Mapper 提供的通用 Mapper 接口时,如果你需要添加自定义的 SQL 查询方法,并且希望通过 XML 文件来定义这些方法,你不需要在 Mapper 接口中为这些自定义方法提供方法体,而是通过在 XML 文件中定义这些方法,并确保 Mapper 接口的命名空间和方法名与 XML 中的配置一致。

示例

假设你有一个 User 实体类,并且你想添加一个自定义方法来根据用户的邮箱查询用户。

实体类
public class User {private Integer id;private String name;private String email;// Getters and Setters
}
Mapper 接口

UserMapper 接口中,你只需要声明方法名,而不需要提供实现。方法名应该与 XML 文件中定义的 id 一致。

import tk.mybatis.mapper.common.Mapper;public interface UserMapper extends Mapper<User> {// 自定义方法声明,方法名与 XML 中的 id 对应User selectUserByEmail(String email);
}
UserMapper.xml

创建一个 UserMapper.xml 文件,并在其中定义自定义查询方法。

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapperPUBLIC "-//mybatis.org//DTD Mapper 3.0//EN""http://mybatis.org/dtd/mybatis-3-mapper.dtd"><mapper namespace="com.example.mapper.UserMapper"><!-- 自定义查询方法 --><select id="selectUserByEmail" parameterType="string" resultType="com.example.entity.User">SELECT * FROM users WHERE email = #{email}</select></mapper>

说明

  1. 命名空间

    • 在 XML 文件中,<mapper> 标签的 namespace 属性应该与 UserMapper 接口的全限定名一致。例如,如果 UserMapper 接口在 com.example.mapper 包中,那么 namespace 应该是 com.example.mapper.UserMapper
  2. 方法名与 id 一致

    • UserMapper 接口中的方法名 selectUserByEmail 应该与 XML 文件中 <select> 标签的 id 属性一致。
  3. 参数类型和返回类型

    • 在 XML 文件中,parameterType 指定了传入参数的类型,resultType 指定了返回结果的类型。确保这些类型与你的实体类和参数类型匹配。

使用

在你的服务层或控制器中,你可以通过注入 UserMapper 来使用这些方法:

@Autowired
private UserMapper userMapper;public User getUserByEmail(String email) {return userMapper.selectUserByEmail(email);
}

通过这种方式,你可以在继承通用 Mapper 接口的同时,使用 XML 文件来定义自定义的 SQL 查询方法。

在 MyBatis 中,XML 映射文件的路径需要与 MyBatis 的配置保持一致,以便 MyBatis 能够正确加载和解析这些文件。通常,XML 映射文件的放置路径和命名规则需要遵循以下几点建议:

1. 放置路径

  • 资源目录:通常,XML 映射文件会放置在 src/main/resources 目录下。这个目录是 Maven 项目默认的资源目录,MyBatis 会从这里加载资源文件。
  • 包结构:为了保持项目的组织性和可维护性,建议将 XML 文件放置在与对应 Mapper 接口相同的包结构下。例如,如果 UserMapper 接口在 com.example.mapper 包中,那么 UserMapper.xml 文件可以放置在 src/main/resources/com/example/mapper 目录下。

2. 配置 MyBatis

  • mybatis-config.xml:在 MyBatis 的全局配置文件 mybatis-config.xml 中,通常不需要显式指定每个 XML 文件的路径,因为 MyBatis 会根据 Mapper 接口的全限定名和包扫描机制自动查找对应的 XML 文件。

  • 包扫描:如果你使用的是 Spring 或 Spring Boot,可以通过配置来指定 Mapper 接口所在的包,MyBatis 会自动扫描这些包下的接口,并查找对应的 XML 文件。例如,在 Spring Boot 中,你可以在 application.ymlapplication.properties 中配置:

    mybatis:mapper-locations: classpath:com/example/mapper/*.xmltype-aliases-package: com.example.entity
    

    或者在 application.properties 中:

    mybatis.mapper-locations=classpath:com/example/mapper/*.xml
    mybatis.type-aliases-package=com.example.entity
    

3. 命名规范

  • 文件名:XML 文件的名称通常与对应的 Mapper 接口名称相同,例如 UserMapper.xml 对应 UserMapper 接口。
  • 一致性:确保 XML 文件的 namespace 属性与 Mapper 接口的全限定名一致,以便 MyBatis 能够正确地将接口方法与 XML 中的 SQL 语句关联起来。

示例

假设你的项目结构如下:

src/
├── main/
│   ├── java/
│   │   └── com/
│   │       └── example/
│   │           ├── entity/
│   │           │   └── User.java
│   │           └── mapper/
│   │               └── UserMapper.java
│   └── resources/
│       └── com/
│           └── example/
│               └── mapper/
│                   └── UserMapper.xml

在这个结构中,UserMapper.xml 文件位于 src/main/resources/com/example/mapper 目录下,与 UserMapper 接口的包结构一致。

通过这种方式,你可以确保 MyBatis 能够正确加载和解析 XML 映射文件,并与对应的 Mapper 接口关联起来。

实现物理删除的替代方案时,通常不建议直接从数据库中删除记录,而是通过设置一个状态字段(如 is_deleteddeleted)来标记记录是否被“删除”。这种方式称为逻辑删除。以下是如何使用 MyBatis 和通用 Mapper 框架来实现逻辑删除的步骤:

1. 数据库设计

假设你有一个 users 表,其中包含一个 is_deleted 字段,用于标记记录是否被删除。

CREATE TABLE users (id INT PRIMARY KEY AUTO_INCREMENT,name VARCHAR(255) NOT NULL,email VARCHAR(255) NOT NULL,is_deleted TINYINT(1) DEFAULT 0 -- 0表示未删除,1表示已删除
);

2. 实体类

在实体类中添加 isDeleted 字段,并确保它与数据库中的字段对应。

public class User {private Integer id;private String name;private String email;private Boolean isDeleted; // 通常使用Boolean类型,便于逻辑处理// Getters and Setterspublic Integer getId() {return id;}public void setId(Integer id) {this.id = id;}public String getName() {return name;}public void setName(String name) {this.name = name;}public String getEmail() {return email;}public void setEmail(String email) {this.email = email;}public Boolean getIsDeleted() {return isDeleted;}public void setIsDeleted(Boolean isDeleted) {this.isDeleted = isDeleted;}
}

3. Mapper 接口

使用通用 Mapper 接口 Mapper<T>,并通过自定义方法实现逻辑删除。

import tk.mybatis.mapper.common.Mapper;public interface UserMapper extends Mapper<User> {// 自定义方法:逻辑删除用户int logicalDeleteUserById(@Param("id") Integer id);
}

4. UserMapper.xml

在 XML 文件中定义 logicalDeleteUserById 方法的 SQL 语句。

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapperPUBLIC "-//mybatis.org//DTD Mapper 3.0//EN""http://mybatis.org/dtd/mybatis-3-mapper.dtd"><mapper namespace="com.example.mapper.UserMapper"><!-- 逻辑删除用户 --><update id="logicalDeleteUserById" parameterType="int">UPDATE usersSET is_deleted = 1WHERE id = #{id} AND is_deleted = 0</update></mapper>

5. Service 层实现

在 Service 层调用 UserMapperlogicalDeleteUserById 方法。

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;@Service
public class UserService {@Autowiredprivate UserMapper userMapper;public boolean deleteUserById(Integer id) {int rowsAffected = userMapper.logicalDeleteUserById(id);return rowsAffected > 0; // 如果影响的行数大于0,表示删除成功}
}

6. 使用示例

在控制器或其他地方调用 UserServicedeleteUserById 方法。

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;@RestController
@RequestMapping("/users")
public class UserController {@Autowiredprivate UserService userService;@DeleteMapping("/{id}")public String deleteUser(@PathVariable Integer id) {boolean success = userService.deleteUserById(id);return success ? "User deleted successfully" : "Failed to delete user";}
}

说明

  • 逻辑删除:通过更新 is_deleted 字段为 1 来标记记录为已删除。
  • 防止重复删除:在 SQL 语句中添加 AND is_deleted = 0 条件,防止重复删除已标记为删除的记录。
  • 通用 Mapper:虽然通用 Mapper 提供了许多基本操作,但某些特定操作(如逻辑删除)需要自定义 SQL。

通过这种方式,你可以在不直接删除数据库记录的情况下,实现记录的“删除”功能,同时保留数据以便后续可能的恢复或审计。

在实现逻辑删除的情况下,查询操作需要排除那些被标记为“已删除”的记录。为了实现这一点,你可以在查询语句中添加一个条件,过滤掉 is_deleted = 1 的记录。

以下是一些常见的查询场景及其实现方式:

1. 查询所有未删除的用户

如果你需要查询所有未被标记为删除的用户,可以在 UserMapper 接口中定义一个自定义查询方法,或者直接使用注解或 XML 配置。

使用 XML 配置
<mapper namespace="com.example.mapper.UserMapper"><!-- 查询所有未删除的用户 --><select id="selectAllActiveUsers" resultType="com.example.model.User">SELECT * FROM users WHERE is_deleted = 0</select></mapper>
使用注解(如果喜欢简洁的代码)
import org.apache.ibatis.annotations.Select;
import tk.mybatis.mapper.common.Mapper;public interface UserMapper extends Mapper<User> {@Select("SELECT * FROM users WHERE is_deleted = 0")List<User> selectAllActiveUsers();
}

2. 根据 ID 查询未删除的用户

如果你需要根据用户的 ID 查询一个未被标记为删除的用户,可以这样做:

使用 XML 配置
<mapper namespace="com.example.mapper.UserMapper"><!-- 根据 ID 查询未删除的用户 --><select id="selectActiveUserById" parameterType="int" resultType="com.example.model.User">SELECT * FROM users WHERE id = #{id} AND is_deleted = 0</select></mapper>
使用注解
import org.apache.ibatis.annotations.Select;
import tk.mybatis.mapper.common.Mapper;public interface UserMapper extends Mapper<User> {@Select("SELECT * FROM users WHERE id = #{id} AND is_deleted = 0")User selectActiveUserById(@Param("id") Integer id);
}

3. 在 Service 层使用

在 Service 层中,你可以调用这些方法来获取未删除的用户。

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;@Service
public class UserService {@Autowiredprivate UserMapper userMapper;public List<User> getAllActiveUsers() {return userMapper.selectAllActiveUsers();}public User getActiveUserById(Integer id) {return userMapper.selectActiveUserById(id);}
}

4. 注意事项

  • 性能考虑:在大数据量的情况下,频繁查询未删除的记录可能会导致性能问题。可以考虑在数据库中为 is_deleted 字段创建索引,以提高查询性能。
  • 通用 Mapper 的限制:虽然通用 Mapper 提供了许多便捷的方法,但在涉及逻辑删除的复杂查询时,可能需要自定义 SQL。
  • 数据一致性:确保所有涉及用户数据的查询都包含 is_deleted = 0 的条件,以避免返回已删除的数据。

通过这种方式,你可以在应用中有效地管理逻辑删除,同时保持数据的完整性和可查询性。

解方法可以查出所有未被移除的数据,也能查出单条未被移除的数据,具体取决于方法的设计和实现。以下是详细说明:


1. 查询所有未被移除的数据

通过注解方式实现查询所有未被移除的数据,可以定义一个方法,并在注解中编写对应的 SQL 查询语句。

示例代码
import org.apache.ibatis.annotations.Select;
import java.util.List;public interface UserMapper {// 查询所有未被移除的用户@Select("SELECT * FROM users WHERE is_deleted = 0")List<User> selectAllActiveUsers();
}
  • 方法说明

    • selectAllActiveUsers 方法通过注解 @Select 指定了 SQL 查询语句。
    • 查询条件 WHERE is_deleted = 0 确保只返回未被移除的数据。
    • 返回值类型为 List<User>,表示返回多个用户记录。
  • 调用方式

    • 在 Service 层调用 selectAllActiveUsers() 方法,即可获取所有未被移除的用户列表。

2. 查询单条未被移除的数据

如果需要查询单条未被移除的数据,可以在注解中添加条件,例如根据用户的 ID 进行查询。

示例代码
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select;public interface UserMapper {// 根据 ID 查询未被移除的用户@Select("SELECT * FROM users WHERE id = #{id} AND is_deleted = 0")User selectActiveUserById(@Param("id") Integer id);
}
  • 方法说明

    • selectActiveUserById 方法通过注解 @Select 指定了 SQL 查询语句。
    • 查询条件 WHERE id = #{id} AND is_deleted = 0 确保只返回指定 ID 且未被移除的用户。
    • 返回值类型为 User,表示返回单个用户记录。
  • 调用方式

    • 在 Service 层调用 selectActiveUserById(id) 方法,并传入用户 ID,即可获取对应的未被移除的用户。

3. 注解方法的灵活性

  • 查询所有数据:通过不指定具体条件(除了 is_deleted = 0),可以返回所有符合条件的记录。
  • 查询单条数据:通过添加具体的条件(如 id = #{id}),可以返回单条符合条件的记录。

4. 示例对比

功能注解方法示例返回类型
查询所有未被移除的数据@Select("SELECT * FROM users WHERE is_deleted = 0") List<User> selectAllActiveUsers();List<User>
查询单条未被移除的数据@Select("SELECT * FROM users WHERE id = #{id} AND is_deleted = 0") User selectActiveUserById(@Param("id") Integer id);User

5. 注意事项

  • SQL 注入风险:使用注解时,确保参数通过 #{} 占位符传递,避免直接拼接 SQL 字符串,防止 SQL 注入攻击。
  • 性能优化:对于大数据量的查询,建议为 is_deleted 字段创建索引,以提高查询性能。
  • 代码可读性:如果查询逻辑较为复杂,建议使用 XML 配置文件编写 SQL,以便更好地维护和管理。

总结

  • 注解方法可以同时支持查询所有未被移除的数据和单条未被移除的数据,具体取决于方法的实现。
  • 通过在注解中编写不同的 SQL 查询语句,可以灵活地实现各种查询需求。
  • 在实际应用中,根据业务需求选择合适的方式(注解或 XML)来实现查询逻辑。

在实现查询所有未被移除(逻辑删除)数据的 impl(实现类)时,你可以通过以下步骤来完成。假设你使用的是 MyBatis 框架,并且已经有了一个 UserMapper 接口,以下是实现查询所有未被移除用户的具体方法。

1. 定义 UserMapper 接口

首先,确保你的 UserMapper 接口中定义了查询所有未被移除用户的方法。你可以使用注解或 XML 配置来定义这个方法。

使用注解
import org.apache.ibatis.annotations.Select;
import java.util.List;public interface UserMapper {// 查询所有未被移除的用户@Select("SELECT * FROM users WHERE is_deleted = 0")List<User> selectAllActiveUsers();
}

2. 实现 UserMapper 的方法(通常不需要单独实现类,因为 MyBatis 会自动生成代理)

在 MyBatis 中,你通常不需要手动实现 Mapper 接口,因为 MyBatis 会通过动态代理自动生成实现类。不过,如果你使用的是 Spring 框架,并且希望在 Service 层中调用这个方法,你可以按照以下方式编写 Service 层代码。

3. 创建 UserService

在 Service 层中,你可以注入 UserMapper,并调用其方法来获取所有未被移除的用户。

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;@Service
public class UserService {@Autowiredprivate UserMapper userMapper;public List<User> getAllActiveUsers() {return userMapper.selectAllActiveUsers();}
}

4. 详细步骤说明

  1. 定义接口方法

    • UserMapper 接口中定义 selectAllActiveUsers 方法,并使用 @Select 注解指定 SQL 查询语句。
    • 查询条件 WHERE is_deleted = 0 确保只返回未被移除的用户。
  2. 自动生成实现类

    • MyBatis 会根据 UserMapper 接口自动生成实现类,因此你不需要手动编写实现代码。
  3. 在 Service 层调用

    • UserService 中注入 UserMapper,并调用 selectAllActiveUsers 方法来获取所有未被移除的用户。

5. 使用 XML 配置(可选)

如果你更喜欢使用 XML 配置而不是注解,可以在 UserMapper.xml 文件中定义查询语句:

<mapper namespace="com.example.mapper.UserMapper"><!-- 查询所有未被移除的用户 --><select id="selectAllActiveUsers" resultType="com.example.model.User">SELECT * FROM users WHERE is_deleted = 0</select></mapper>

6. 注意事项

  • 接口与实现

    • 在 MyBatis 中,Mapper 接口通常不需要手动实现,MyBatis 会根据接口定义自动生成实现。
  • 注解与 XML

    • 可以选择使用注解或 XML 配置来定义 SQL 查询,根据项目需求和团队习惯选择合适的方式。
  • 数据一致性

    • 确保所有涉及用户数据的查询都包含 is_deleted = 0 的条件,以避免返回已删除的数据。

7. 示例代码结构

// UserMapper.java
public interface UserMapper {@Select("SELECT * FROM users WHERE is_deleted = 0")List<User> selectAllActiveUsers();
}
// UserService.java
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;@Service
public class UserService {@Autowiredprivate UserMapper userMapper;public List<User> getAllActiveUsers() {return userMapper.selectAllActiveUsers();}
}

8. 总结

  • 注解与 XML:你可以选择使用注解或 XML 配置来定义 SQL 查询,MyBatis 会自动处理接口的实现。
  • Service 层调用:在 Service 层中调用 UserMapper 的方法,获取未被移除的用户列表。
  • 性能优化:对于大数据量查询,建议为 is_deleted 字段创建索引,以提高查询性能。

通过这种方式,你可以在应用中有效地管理逻辑删除,同时保持数据的完整性和可查询性。Service 层提供了业务逻辑的封装,使得调用更加方便和清晰

在实现批量逻辑移除(即将多个记录标记为已删除)的功能时,可以通过 MyBatis 的批量操作来完成。以下是使用 MyBatis 和 Spring 框架实现批量逻辑移除的步骤和示例代码。

1. 定义 UserMapper 接口

首先,在 UserMapper 接口中定义一个方法,用于批量更新用户的 is_deleted 字段。

import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Update;
import java.util.List;public interface UserMapper {// 批量逻辑移除用户@Update({"<script>","UPDATE users","SET is_deleted = 1","WHERE id IN","<foreach item='id' collection='ids' open='(' separator=',' close=')'>","#{id}","</foreach>","</script>"})int batchDeleteUsers(@Param("ids") List<Integer> ids);
}

2. 说明

  • @Update 注解:使用 MyBatis 的 @Update 注解来定义批量更新操作。
  • <script> 标签:用于在注解中编写动态 SQL。
  • <foreach> 标签:用于遍历 ids 集合,生成 IN 子句。
  • @Param 注解:用于指定方法参数的名称,以便在 SQL 中引用。

3. 创建 UserService

在 Service 层中,注入 UserMapper,并调用其方法来执行批量逻辑移除。

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;@Service
public class UserService {@Autowiredprivate UserMapper userMapper;/*** 批量逻辑移除用户** @param ids 要移除的用户ID列表* @return 受影响的行数*/public int batchDeleteUsers(List<Integer> ids) {if (ids == null || ids.isEmpty()) {return 0;}return userMapper.batchDeleteUsers(ids);}
}

4. 详细步骤说明

  1. 定义接口方法

    • UserMapper 接口中定义 batchDeleteUsers 方法,并使用 @Update 注解指定批量更新的 SQL 语句。
    • 使用 <foreach> 标签生成 IN 子句,以便在 SQL 中包含多个用户 ID。
  2. 自动生成实现类

    • MyBatis 会根据 UserMapper 接口自动生成实现类,因此你不需要手动编写实现代码。
  3. 在 Service 层调用

    • UserService 中注入 UserMapper,并调用 batchDeleteUsers 方法来执行批量逻辑移除。
    • 添加参数检查,确保在 ids 列表为空或为 null 时不执行更新操作。

5. 示例代码结构

// UserMapper.java
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Update;
import java.util.List;public interface UserMapper {@Update({"<script>","UPDATE users","SET is_deleted = 1","WHERE id IN","<foreach item='id' collection='ids' open='(' separator=',' close=')'>","#{id}","</foreach>","</script>"})int batchDeleteUsers(@Param("ids") List<Integer> ids);
}
// UserService.java
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;@Service
public class UserService {@Autowiredprivate UserMapper userMapper;public int batchDeleteUsers(List<Integer> ids) {if (ids == null || ids.isEmpty()) {return 0;}return userMapper.batchDeleteUsers(ids);}
}

6. 注意事项

  • 参数检查

    • 在调用 batchDeleteUsers 方法之前,确保 ids 列表不为空或 null,以避免不必要的数据库操作。
  • 事务管理

    • 如果批量逻辑移除是事务的一部分,确保在 Service 层或更高层管理事务,以保证数据一致性。
  • SQL 注入

    • 使用 MyBatis 的动态 SQL 功能(如 <foreach>)可以有效防止 SQL 注入。
  • 性能考虑

    • 对于非常大的 ids 列表,考虑分批处理,以避免 SQL 语句过长或数据库性能问题。

通过这种方式,你可以在应用中实现批量逻辑移除功能,同时保持代码的清晰和可维护性。

在 MyBatis 中,<script><foreach> 是用于动态 SQL 生成的重要标签,它们在处理批量操作时非常有用。以下是它们的作用和参数说明:

1. <script> 标签

  • 作用

    • <script> 标签用于在 MyBatis 的注解(如 @Select@Insert@Update@Delete)中编写动态 SQL。
    • 它允许你在注解中使用复杂的 SQL 逻辑,如条件判断、循环、动态列选择等。
  • 使用场景

    • 当你需要动态生成 SQL 语句时,比如根据输入参数的不同生成不同的 SQL。
    • 在批量操作中,用于生成包含多个值的 IN 子句。

2. <foreach> 标签

  • 作用

    • <foreach> 标签用于遍历集合(如 ListSet、数组等),并生成重复的 SQL 片段。
    • 通常用于生成 IN 子句、批量插入语句等。
  • 常用属性

    • collection:指定要遍历的集合。在注解中,通常使用 @Param 注解的参数名。
    • item:指定集合中每个元素的变量名,在 SQL 片段中通过这个变量名引用当前元素。
    • index:可选,指定当前元素的索引变量名。
    • open:可选,指定生成的 SQL 片段的起始字符(如 ()。
    • separator:可选,指定每个元素之间的分隔符(如 ,)。
    • close:可选,指定生成的 SQL 片段的结束字符(如 ))。

示例说明

@Update({"<script>","UPDATE users","SET is_deleted = 1","WHERE id IN","<foreach item='id' collection='ids' open='(' separator=',' close=')'>","#{id}","</foreach>","</script>"
})
int batchDeleteUsers(@Param("ids") List<Integer> ids);
  • <script>

    • 包裹整个动态 SQL 语句,使其能够在注解中使用。
  • <foreach>

    • collection='ids':指定要遍历的集合是方法参数 ids
    • item='id':指定集合中每个元素的变量名为 id
    • open='(':生成的 SQL 片段以 ( 开头。
    • separator=',':每个元素之间用 , 分隔。
    • close=')':生成的 SQL 片段以 ) 结尾。
  • #{id}

    • 在 SQL 中引用当前遍历到的元素。

总结

  • <script>:用于在注解中编写动态 SQL。
  • <foreach>:用于遍历集合,生成重复的 SQL 片段,常用于生成 IN 子句。

通过这种方式,你可以灵活地生成复杂的 SQL 语句,以适应不同的输入参数和业务需求。

为了实现分页功能,我们需要在 Mapper 接口、Service 层和 Controller 层中进行相应的实现。以下是一个基于 MyBatisSpring Boot 的示例,假设我们有一个 tb_reservation 表。

数据库表结构假设

假设 tb_reservation 表结构如下:

CREATE TABLE tb_reservation (id INT PRIMARY KEY AUTO_INCREMENT,name VARCHAR(100),reservation_date DATE
);

Mapper 接口

首先,我们需要在 Mapper 接口中定义一个分页查询的方法。

public interface ReservationMapper {List<Reservation> selectReservationsWithPagination(@Param("offset") int offset, @Param("limit") int limit);int countReservations();
}

对应的 XML 映射文件(如果使用 XML 映射):

<mapper namespace="com.example.mapper.ReservationMapper"><select id="selectReservationsWithPagination" resultType="com.example.model.Reservation">SELECT * FROM tb_reservation ORDER BY id LIMIT #{limit} OFFSET #{offset}</select><select id="countReservations" resultType="int">SELECT COUNT(*) FROM tb_reservation</select>
</mapper>

Service 层

Service 层中,我们实现分页逻辑,包括计算总页数。

@Service
public class ReservationService {@Autowiredprivate ReservationMapper reservationMapper;public Page<Reservation> getReservations(int page, int size) {int offset = (page - 1) * size;List<Reservation> reservations = reservationMapper.selectReservationsWithPagination(offset, size);int total = reservationMapper.countReservations();int totalPages = (int) Math.ceil((double) total / size);return new Page<>(reservations, totalPages);}// 自定义Page类,用于封装分页结果public static class Page<T> {private List<T> content;private int totalPages;public Page(List<T> content, int totalPages) {this.content = content;this.totalPages = totalPages;}// Getters and Setterspublic List<T> getContent() {return content;}public void setContent(List<T> content) {this.content = content;}public int getTotalPages() {return totalPages;}public void setTotalPages(int totalPages) {this.totalPages = totalPages;}}
}

Controller 层

Controller 层中,我们实现一个接口来处理分页请求。

@RestController
@RequestMapping("/reservations")
public class ReservationController {@Autowiredprivate ReservationService reservationService;@GetMappingpublic ResponseEntity<ReservationService.Page<Reservation>> getReservations(@RequestParam(defaultValue = "1") int page,@RequestParam(defaultValue = "10") int size) {if (page < 1) {page = 1;}if (size < 1) {size = 10;}ReservationService.Page<Reservation> reservationPage = reservationService.getReservations(page, size);return ResponseEntity.ok(reservationPage);}
}

模型类

确保你有一个 Reservation 模型类来映射数据库表:

public class Reservation {private Integer id;private String name;private Date reservationDate;// Getters and Setterspublic Integer getId() {return id;}public void setId(Integer id) {this.id = id;}public String getName() {return name;}public void setName(String name) {this.name = name;}public Date getReservationDate() {return reservationDate;}public void setReservationDate(Date reservationDate) {this.reservationDate = reservationDate;}
}

说明

  1. 分页逻辑Mapper 接口提供了两个方法,一个用于获取分页数据,另一个用于计算总记录数。Service 层根据这些数据计算总页数,并返回一个 Page 对象。
  2. 分页参数Controller 层通过请求参数接收分页参数 pagesize,并进行基本的参数验证。
  3. 响应格式Controller 返回一个包含分页数据和总页数的响应。

通过这种方式,你可以实现一个简单的分页功能,并允许用户通过请求参数进行页面跳转和显示。根据实际需求,你可以进一步扩展和优化这个实现。

在 MyBatis 中,如果你不想使用 XML 映射文件,而是想直接在 Mapper 接口中通过注解来定义 SQL 查询,你可以使用 @Select 注解。下面是如何将你的 XML 映射转换为使用 @Select 注解的示例:

使用 @Select 注解的 Mapper 接口

package com.example.mapper;import com.example.model.Reservation;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select;
import java.util.List;public interface ReservationMapper {/*** 分页查询预订记录** @param offset 偏移量,从0开始* @param limit 每页记录数* @return 预订记录列表*/@Select("SELECT * FROM tb_reservation ORDER BY id LIMIT #{limit} OFFSET #{offset}")List<Reservation> selectReservationsWithPagination(@Param("offset") int offset, @Param("limit") int limit);/*** 查询预订记录总数** @return 预订记录总数*/@Select("SELECT COUNT(*) FROM tb_reservation")int countReservations();
}

说明

  1. @Select 注解

    • 使用 @Select 注解直接在接口方法上定义 SQL 查询。
    • 注解中的 SQL 字符串可以直接引用方法参数,通过 #{} 语法进行参数绑定。
  2. @Param 注解

    • 当方法有多个参数时,使用 @Param 注解为每个参数指定一个名称,以便在 SQL 字符串中引用。
    • 如果方法只有一个参数,并且参数名与 SQL 中的占位符名一致,可以省略 @Param 注解。
  3. 返回类型

    • selectReservationsWithPagination 方法返回一个 List<Reservation>,其中 Reservation 是与数据库表 tb_reservation 对应的实体类。
    • countReservations 方法返回一个 int,表示预订记录的总数。

通过这种方式,你可以在 Mapper 接口中直接定义 SQL 查询,而不需要额外的 XML 映射文件。这种方法适用于简单的查询,对于更复杂的查询或动态 SQL,可能需要结合其他 MyBatis 注解(如 @InsertProvider@UpdateProvider@DeleteProvider)或使用 XML 映射文件来提高灵活性。

实现分页模糊查询通常需要结合数据库查询(通过 MyBatis Mapper)、业务逻辑(通过 Service 层)以及 API 接口(通过 Controller 层)。以下是一个基于 Spring Boot 和 MyBatis 的示例,假设我们有一个 User 实体类,并且需要对其 name 字段进行分页模糊查询。

1. 数据库表结构

假设我们有一个 users 表:

CREATE TABLE users (id INT PRIMARY KEY AUTO_INCREMENT,name VARCHAR(255) NOT NULL
);

2. MyBatis Mapper

UserMapper.java
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select;
import java.util.List;public interface UserMapper {@Select("<script>" +"SELECT * FROM users " +"WHERE name LIKE CONCAT('%', #{name}, '%') " +"LIMIT #{limit} OFFSET #{offset}" +"</script>")List<User> findUsersByName(@Param("name") String name, @Param("limit") int limit, @Param("offset") int offset);@Select("<script>" +"SELECT COUNT(*) FROM users " +"WHERE name LIKE CONCAT('%', #{name}, '%')" +"</script>")int countUsersByName(@Param("name") String name);
}

3. Service 层

UserService.java
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;@Service
public class UserService {@Autowiredprivate UserMapper userMapper;public List<User> findUsersByName(String name, int page, int size) {int offset = (page - 1) * size;return userMapper.findUsersByName(name, size, offset);}public int countUsersByName(String name) {return userMapper.countUsersByName(name);}
}

4. Controller 层

UserController.java
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.HashMap;
import java.util.List;
import java.util.Map;@RestController
@RequestMapping("/users")
public class UserController {@Autowiredprivate UserService userService;@GetMapping("/search")public Map<String, Object> searchUsers(@RequestParam String name,@RequestParam(defaultValue = "1") int page,@RequestParam(defaultValue = "10") int size) {List<User> users = userService.findUsersByName(name, page, size);int total = userService.countUsersByName(name);int totalPages = (int) Math.ceil((double) total / size);Map<String, Object> response = new HashMap<>();response.put("data", users);response.put("total", total);response.put("totalPages", totalPages);response.put("currentPage", page);response.put("size", size);return response;}
}

5. User 实体类

User.java
public class User {private Integer id;private String name;// Getters and Setterspublic Integer getId() {return id;}public void setId(Integer id) {this.id = id;}public String getName() {return name;}public void setName(String name) {this.name = name;}
}

说明

  1. Mapper 层

    • findUsersByName 方法用于根据名称进行模糊查询,并支持分页。
    • countUsersByName 方法用于获取符合条件的记录总数。
  2. Service 层

    • findUsersByName 方法计算偏移量(offset)并调用 Mapper 层的方法。
    • countUsersByName 方法用于获取记录总数。
  3. Controller 层

    • searchUsers 方法接收查询参数(namepagesize),调用 Service 层的方法,并返回分页结果。
  4. 分页逻辑

    • 使用 LIMITOFFSET 实现分页。
    • 计算总页数 totalPages,并返回给前端。

注意事项

  • 确保数据库连接配置正确,并且 MyBatis 已正确集成到项目中。
  • 根据实际情况调整实体类字段和数据库表结构。
  • 考虑异常处理和输入验证,以提高代码的健壮性。

通过这种方式,你可以实现一个简单的分页模糊查询功能,并通过 RESTful API 提供给前端使用。

实现一个能够处理 Excel 表格导入和导出的工具类、服务层(Service)以及控制器层(Controller)需要涉及多个组件和库。下面是一个简化的实现思路,主要使用 Apache POI 库来处理 Excel 文件。

依赖

首先,确保在你的项目中引入了 Apache POI 的依赖。在 Maven 项目中,你可以在 pom.xml 中添加以下依赖:

<dependency><groupId>org.apache.poi</groupId><artifactId>poi</artifactId><version>5.2.3</version> <!-- 请使用最新版本 -->
</dependency>
<dependency><groupId>org.apache.poi</groupId><artifactId>poi-ooxml</artifactId><version>5.2.3</version>
</dependency>

ExcelUtil 工具类

import org.apache.poi.ss.usermodel.*;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;import java.io.*;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;public class ExcelUtil {public static <T> List<T> importExcel(InputStream is, Class<T> clazz, ExcelRowMapper<T> mapper) throws Exception {List<T> result = new ArrayList<>();try (Workbook workbook = new XSSFWorkbook(is)) {Sheet sheet = workbook.getSheetAt(0); // 假设只处理第一个工作表Iterator<Row> rowIterator = sheet.iterator();boolean isFirstRow = true; // 跳过标题行while (rowIterator.hasNext()) {Row row = rowIterator.next();if (isFirstRow) {isFirstRow = false;continue;}result.add(mapper.mapRow(row));}}return result;}public static <T> void exportExcel(List<T> dataList, String[] headers, OutputStream os, ExcelRowWriter<T> writer) throws Exception {try (Workbook workbook = new XSSFWorkbook()) {Sheet sheet = workbook.createSheet("Data");// 创建标题行Row headerRow = sheet.createRow(0);for (int i = 0; i < headers.length; i++) {Cell cell = headerRow.createCell(i);cell.setCellValue(headers[i]);}// 填充数据for (int i = 0; i < dataList.size(); i++) {Row row = sheet.createRow(i + 1);writer.writeRow(dataList.get(i), row);}workbook.write(os);}}@FunctionalInterfacepublic interface ExcelRowMapper<T> {T mapRow(Row row) throws Exception;}@FunctionalInterfacepublic interface ExcelRowWriter<T> {void writeRow(T data, Row row) throws Exception;}
}

Service 层

假设我们有一个简单的用户实体类 User

import org.apache.poi.ss.usermodel.Row;import java.util.List;public class UserService {public List<User> importUsers(InputStream is) throws Exception {return ExcelUtil.importExcel(is, User.class, row -> {// 简单示例,假设Excel列顺序是 id, name, emaillong id = (long) row.getCell(0).getNumericCellValue();String name = row.getCell(1).getStringCellValue();String email = row.getCell(2).getStringCellValue();return new User(id, name, email);});}public void exportUsers(List<User> users, OutputStream os) throws Exception {ExcelUtil.exportExcel(users, new String[]{"ID", "Name", "Email"}, os, (user, row) -> {row.createCell(0).setCellValue(user.getId());row.createCell(1).setCellValue(user.getName());row.createCell(2).setCellValue(user.getEmail());});}
}

Controller 层

使用 Spring Boot 框架来处理 HTTP 请求。

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;import javax.servlet.http.HttpServletResponse;
import java.io.OutputStream;
import java.util.List;@RestController
@RequestMapping("/users")
public class UserController {@Autowiredprivate UserService userService;@PostMapping("/import")public ResponseEntity<String> importUsers(@RequestParam("file") MultipartFile file) {try {List<User> users = userService.importUsers(file.getInputStream());// 处理导入后的用户数据,比如保存到数据库return ResponseEntity.ok("Import successful");} catch (Exception e) {return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body("Import failed: " + e.getMessage());}}@GetMapping("/export")public void exportUsers(HttpServletResponse response) {try {List<User> users = // 获取用户数据,比如从数据库中查询response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");response.setHeader(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=users.xlsx");OutputStream os = response.getOutputStream();userService.exportUsers(users, os);os.flush();} catch (Exception e) {// 处理异常}}
}

注意事项

  1. 错误处理:实际应用中需要更详细的错误处理。
  2. 性能优化:对于大数据量的导入导出,可能需要考虑流式处理和分页。
  3. 安全性:确保上传的文件是安全的,避免文件上传漏洞。
  4. 数据库交互:示例中没有展示如何与数据库交互,实际应用中需要在导入时将数据保存到数据库,在导出时从数据库读取数据。
  5. 依赖注入UserServiceUserController 示例中使用了 Spring 的依赖注入特性。

这种设计模式使得代码模块化,便于维护和扩展

当然可以!下面是一个假设的 ExcelUtil 工具类的简单示例代码,并附上详细的注释,解释每一行代码的作用。这个工具类通常用于读取或写入 Excel 文件。

import org.apache.poi.ss.usermodel.*;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;public class ExcelUtil {/*** 读取Excel文件,并将数据存储到List中** @param filePath Excel文件的路径* @return 包含Excel数据的List,每一行是一个List<String>* @throws IOException 如果文件读取失败*/public static List<List<String>> readExcel(String filePath) throws IOException {List<List<String>> data = new ArrayList<>();// 打开Excel文件的输入流try (FileInputStream fis = new FileInputStream(new File(filePath));Workbook workbook = new XSSFWorkbook(fis)) {// 获取第一个工作表Sheet sheet = workbook.getSheetAt(0);// 遍历工作表中的每一行Iterator<Row> rowIterator = sheet.iterator();while (rowIterator.hasNext()) {Row row = rowIterator.next();List<String> rowData = new ArrayList<>();// 遍历行中的每一个单元格Iterator<Cell> cellIterator = row.cellIterator();while (cellIterator.hasNext()) {Cell cell = cellIterator.next();// 根据单元格类型获取单元格的值switch (cell.getCellType()) {case STRING:rowData.add(cell.getStringCellValue());break;case NUMERIC:// 如果是数字类型,可以选择转换为字符串rowData.add(String.valueOf(cell.getNumericCellValue()));break;case BOOLEAN:rowData.add(String.valueOf(cell.getBooleanCellValue()));break;case FORMULA:// 可以选择计算公式结果或公式本身rowData.add(cell.getCellFormula());break;default:rowData.add("");break;}}// 将行数据添加到总数据列表中data.add(rowData);}}return data;}/*** 将数据写入Excel文件** @param filePath Excel文件的路径* @param data 包含要写入的数据的List,每一行是一个List<String>* @throws IOException 如果文件写入失败*/public static void writeExcel(String filePath, List<List<String>> data) throws IOException {try (Workbook workbook = new XSSFWorkbook();FileOutputStream fos = new FileOutputStream(new File(filePath))) {// 创建一个新的工作表Sheet sheet = workbook.createSheet("Sheet1");// 遍历数据列表,将每一行写入工作表for (int i = 0; i < data.size(); i++) {Row row = sheet.createRow(i);List<String> rowData = data.get(i);// 遍历行数据,将每个单元格写入行for (int j = 0; j < rowData.size(); j++) {Cell cell = row.createCell(j);cell.setCellValue(rowData.get(j));}}// 将工作簿写入文件workbook.write(fos);}}
}

代码解释

  1. 导入必要的库

    • org.apache.poi.ss.usermodel.*org.apache.poi.xssf.usermodel.XSSFWorkbook 用于处理 Excel 文件。
    • java.io.* 用于文件输入输出操作。
  2. readExcel 方法

    • 打开 Excel 文件并读取其内容。
    • 使用 FileInputStreamXSSFWorkbook 读取 Excel 文件。
    • 遍历工作表中的每一行和每一个单元格,根据单元格类型获取其值,并将其存储到 List<List<String>> 中。
  3. writeExcel 方法

    • 将数据写入 Excel 文件。
    • 创建一个新的 XSSFWorkbookSheet
    • 遍历数据列表,将每一行写入工作表,并将每个单元格写入行。
    • 使用 FileOutputStream 将工作簿写入文件。

希望这些注释能帮助你理解 ExcelUtil 工具类的代码!

ExcelUtil工具类

package com.zmxr.until;import org.apache.poi.ss.usermodel.*;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;import java.io.*;
import java.lang.reflect.Field;
import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;public class ExcelUntil<T> {private static final DateTimeFormatter DATE_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd");private static final DateTimeFormatter DATETIME_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");/*** 从Excel文件导入数据到List中** @param file     Excel文件* @param clazz    实体类类型* @param dateFormat 日期格式(如果需要解析日期)* @return 实体类对象的List* @throws Exception 异常*/public List<T> importFromExcel(File file, Class<T> clazz, String dateFormat) throws Exception {List<T> list = new ArrayList<>();try (InputStream is = new FileInputStream(file);Workbook workbook = new XSSFWorkbook(is)) {Sheet sheet = workbook.getSheetAt(0);Iterator<Row> rowIterator = sheet.iterator();Row headerRow = rowIterator.next(); // 跳过标题行while (rowIterator.hasNext()) {Row row = rowIterator.next();T obj = clazz.getDeclaredConstructor().newInstance();Field[] fields = clazz.getDeclaredFields();for (int i = 0; i < fields.length; i++) {fields[i].setAccessible(true);Cell cell = row.getCell(i);if (cell != null) {Object value = null;switch (cell.getCellType()) {case STRING:String cellValue = cell.getStringCellValue();if (fields[i].getType() == LocalDate.class) {value = LocalDate.parse(cellValue, DATE_FORMATTER);} else if (fields[i].getType() == LocalDateTime.class) {value = LocalDateTime.parse(cellValue, DATETIME_FORMATTER);} else {value = cellValue;}break;case NUMERIC:if (DateUtil.isCellDateFormatted(cell)) {Date date = cell.getDateCellValue();//如果需要,将Date转换为LocalDateTime(假设特定时间,例如午夜)value = date.toInstant().atZone(java.time.ZoneId.systemDefault()).toLocalDate().atStartOfDay(); // 转换示例// 或者,如果您有时间信息,请使用更精确的转换} else {value = cell.getNumericCellValue();}break;case BOOLEAN:value = cell.getBooleanCellValue();break;// 其他类型可以根据需要添加}fields[i].set(obj, value);}}list.add(obj);}}return list;}/*** 将List数据导出到Excel文件** @param list     数据列表* @param clazz    实体类类型* @param file     输出的Excel文件* @throws Exception 异常*/public void exportToExcel(List<T> list, Class<T> clazz, File file) throws Exception {try (Workbook workbook = new XSSFWorkbook();OutputStream os = new FileOutputStream(file)) {Sheet sheet = workbook.createSheet("Data");// 创建标题行Row headerRow = sheet.createRow(0);Field[] fields = clazz.getDeclaredFields();for (int i = 0; i < fields.length; i++) {fields[i].setAccessible(true);headerRow.createCell(i).setCellValue(fields[i].getName());}// 填充数据行int rowIdx = 1;for (T obj : list) {Row row = sheet.createRow(rowIdx++);for (int i = 0; i < fields.length; i++) {Object value = fields[i].get(obj);Cell cell = row.createCell(i);if (value instanceof Date) {SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");cell.setCellValue(sdf.format(value));} else {cell.setCellValue(value != null ? value.toString() : "");}}}workbook.write(os);}}}

根据需要添加
}
fields[i].set(obj, value);
}
}
list.add(obj);
}
}
return list;
}

/*** 将List数据导出到Excel文件** @param list     数据列表* @param clazz    实体类类型* @param file     输出的Excel文件* @throws Exception 异常*/
public void exportToExcel(List<T> list, Class<T> clazz, File file) throws Exception {try (Workbook workbook = new XSSFWorkbook();OutputStream os = new FileOutputStream(file)) {Sheet sheet = workbook.createSheet("Data");// 创建标题行Row headerRow = sheet.createRow(0);Field[] fields = clazz.getDeclaredFields();for (int i = 0; i < fields.length; i++) {fields[i].setAccessible(true);headerRow.createCell(i).setCellValue(fields[i].getName());}// 填充数据行int rowIdx = 1;for (T obj : list) {Row row = sheet.createRow(rowIdx++);for (int i = 0; i < fields.length; i++) {Object value = fields[i].get(obj);Cell cell = row.createCell(i);if (value instanceof Date) {SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");cell.setCellValue(sdf.format(value));} else {cell.setCellValue(value != null ? value.toString() : "");}}}workbook.write(os);}
}

}


http://www.dtcms.com/a/265065.html

相关文章:

  • 用Rust编写的开源支付解决方案——Hyperswitch
  • springboot集成达梦数据库,取消MySQL数据库,解决问题和冲突
  • nohup java -jar 命令启动jar包,项目仍然会挂掉或者停止运行的解决方案
  • C++——手撕智能指针、单例模式、线程池、String
  • Vue + RuoYi 前后端分离入门手册
  • [深度学习环境踩坑记录]ubuntu22.04安装RTX3060驱动,黑屏、桌面只有壁纸和鼠标,一顿折腾
  • javaWeb02-Tomcat
  • java.sql.SQLSyntaxErrorException: Unknown column ‘user_name‘ in ‘field list‘
  • YOLOv11剪枝与量化(一)模型压缩的必要性
  • Qt写入excel
  • 整流电路Multisim电路仿真实验汇总——硬件工程师笔记
  • Rust实现FasterR-CNN目标检测全流程
  • 教程:国内如何免费用Claude4+GPT4o生成高质量科研绘图
  • vue动态绑定样式
  • Kalibr解毒填坑(一):相机标定失败
  • 408第三季part1 - 操作系统 - 文件基本概念
  • 基于STM32的土豆种植自动化灌溉系统设计与实现
  • java依赖注入方法
  • 【C语言】知识总结·文件操作
  • Redis在项目中的使用
  • 在移动端使用 Tailwind CSS (uniapp)
  • 在项目架构时,如何选择打包构建工具?
  • Nginx、Spring Cloud Gateway 与 Higress 的应用场景及核心区别
  • Linux基本命令篇 —— alias命令
  • AI专业化应用加速落地,安全治理挑战同步凸显
  • 车载软件架构 -- SOA服务分层设计原则
  • 数学建模_非线性规划
  • 时钟(6.25-26)
  • pppoe宽带连接-系列命令调用
  • 使用Process Monitor定位benchstat工具执行过程