如果您使用的是 Spring MyBatis,您可以使用 2 个 MyBatis 查询和有用的 Spring Page 和 Pageable 接口手动实现分页。
您创建更高级别的DAO 接口,例如UploadDao
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
public interface UploadDao {
Page<Upload> search(UploadSearch uploadSearch, Pageable pageable);
}
... 其中Upload 映射到upload 表,UploadSearch 是一个参数 POJO,例如
@Data // lombok
public class UploadSearch {
private Long userId;
private Long projectId;
...
}
UploadDao 的实现(注入一个 MyBatis UploadMapper 映射器)如下:
public class DefaultUploadDao implements UploadDao {
@Autowired
private UploadMapper uploadMapper;
public Page<Upload> searchUploads(UploadSearch uploadSearch, Pageable pageable) {
List<Upload> content = uploadMapper.searchUploads(uploadSearch, pageable);
Long total = uploadMapper.countUploads(uploadSearch);
return new PageImpl<>(content, pageable, total);
}
}
DAO 实现调用UploadMapper 的2 个方法。它们是:
-
UploadMapper.searchUploads - 根据搜索参数 (UploadSearch) 和 Pageable 参数(包含偏移量/限制等)返回一页结果。
-
UploadMapper.countUploads - 返回总计数,再次基于搜索参数 UploadSearch。注意 - 这里不需要Pageable 参数,因为我们只是确定搜索参数过滤到的总行数,而不关心页码/偏移量等。
注入的UploadMapper接口看起来像...
@Mapper
public interface UploadMapper {
List<Upload> searchUploads(
@Param("search") UploadSearch search,
@Param("pageable") Pageable pageable);
long countUploads(
@Param("search") UploadSearch search);
}
... 以及包含动态 SQL 的映射器 XML 文件,例如upload_mapper.xml 包含...
<mapper namespace="com.yourproduct.UploadMapper">
<select id="searchUploads" resultType="com.yourproduct.Upload">
select u.*
from upload u
<include refid="queryAndCountWhereStatement"/>
<if test="pageable.sort.sorted">
<trim prefix="order by">
<foreach item="order" index="i" collection="pageable.sort" separator=", ">
<if test="order.property == 'id'">id ${order.direction}</if>
<if test="order.property == 'projectId'">project_id ${order.direction}</if>
</foreach>
</trim>
</if>
<if test="pageable.paged">
limit #{pageable.offset}, #{pageable.pageSize}
</if>
<!-- NOTE: PostgreSQL has a slightly different syntax to MySQL i.e.
limit #{pageable.pageSize} offset #{pageable.offset}
-->
</select>
<select id="countUploads" resultType="long">
select count(1)
from upload u
<include refid="queryAndCountWhereStatement"/>
</select>
<sql id="queryAndCountWhereStatement">
<where>
<if test="search != null">
<if test="search.userId != null"> and u.user_id = #{search.userId}</if>
<if test="search.productId != null"> and u.product_id = #{search.productId}</if>
...
</if>
</where>
</sql>
</mapper>
注意 - <sql> 块(连同 <include refid=" ... " >)在这里非常有用,可确保您的 count 和 select 查询对齐。此外,在排序时,我们使用条件,例如<if test="order.property == 'projectId'">project_id ${order.direction}</if> 映射到列(并停止 SQL 注入)。 ${order.direction} 是安全的,因为 Spring Direction 类是 enum。
UploadDao 然后可以从例如注入和使用。一个 Spring 控制器:
@RestController("/upload")
public UploadController {
@Autowired
private UploadDao uploadDao; // Likely you'll have a service instead (which injects DAO) - here for brevity
@GetMapping
public Page<Upload>search (@RequestBody UploadSearch search, Pageable pageable) {
return uploadDao.search(search, pageable);
}
}