数据库表-对应Entity
产品表 my_products
product_name | product_id(主键) | create_time(上架时间) | product_info |
---|---|---|---|
电脑 | 1 | 2021-08-27 17:28:57.076 | (bytes) |
手机 | 2 | 2021-08-27 17:28:57.076 | (bytes) |
导管 | 3 | 2021-08-27 17:28:57.076 | (bytes) |
关联表 my_tag_relation
tag_id | id(主键) | product_id |
---|---|---|
1 | 1 | 1 |
2 | 2 | 3 |
1 | 3 | 2 |
标签表 my_tag
tag_id(主键) | tag_name | type |
---|---|---|
1 | 电子产品 | 1 |
2 | 其他产品 | 1 |
3 | 食品 | 1 |
需求
产品表分页;
可以按createTime时间过滤筛选
可以按商品名称productName模糊查询筛选
可以按商品名称productId模糊查询筛选
可以按标签名称筛选
分页查询实现
按标签过滤,原本是表关联查询后过滤,这个jpa分页看起来无法联表写条件,我没有找到写法;
那就把这个转换成简单的条件。在tagRelationRepository中查询出符合标签条件的distinct(product_id).
public List<String> findProductIdsByTagNames(List<String> tagNames) {
//要查询的标签名称
Set<String> tagSet = new HashSet<>();
tagSet.addAll(tagNames);
String inFilterValues = createInFilterValues(tagSet);
String sql = "SELECT distinct(r.product_id) from my_tag_relation r LEFT JOIN my_tag t on r.tag_id=t.id where t.tag in (" + inFilterValues + ");";
List<String> productIds= jdbcTemplate.queryForList(sql, String.class);
return productIds;
}
//拼接sql 'tag1','tag2'
public String createInFilterValues(Set<String> tagSet) {
StringBuilder sb = new StringBuilder();
for (String tag : tagSet) {
sb.append("'").append(tag).append("',");
}
sb.deleteCharAt(sb.length() - 1);
return sb.toString();
}
再将这个product_ids给jpa分页的in条件。
需Service层实现
@Service
public class ProductService{
@Autowired
ProductRepository productRepository;
/**
* 分页查询、按多种条件过滤
*/
public Map<String, Object> pageByParams(ProductListParams params) {
Map<String, Object> res = new HashMap<>();
String startTime = params.getStartTime();
String endTime = params.getEndTime();
Sort sort = new Sort(new Sort.Order(Sort.Direction.DESC, "createTime"));
PageRequest pageRequest = new PageRequest(params.getPage() - 1, params.getLimit(), sort);
Specification specification = new Specification() {
@Override
public Predicate toPredicate(Root root, CriteriaQuery query, CriteriaBuilder cb) {
//增加筛选条件 productInfo is not null
Predicate predicate = cb.conjunction();
predicate.getExpressions().add(cb.isNotNull(root.get("productInfo").as(byte[].class)));
//标签过滤 转换为productId in ()
if (params.getTagNames() != null && params.getProductIds() != null) {
predicate.getExpressions().add(root.get("productId").as(String.class).in(params.getProductIds()));
}
//名称过滤
if (params.getProductIdFilter() != null && params.getProductIdFilter().length() > 0) {
predicate.getExpressions().add(cb.like(root.get("productId").as(String.class), "%" + params.getProductIdFilter() + "%"));
}
if (params.getProductNameFilter() != null && params.getProductNameFilter().length() > 0) {
predicate.getExpressions().add(cb.like(root.get("productName").as(String.class), "%" + params.getProductNameFilter() + "%"));
}
//起始日期
if (startTime != null && !startTime.trim().equals("")) {
predicate.getExpressions().add(cb.greaterThanOrEqualTo(root.get("createTime").as(String.class), startTime));
}
//结束日期
if (endTime != null && !endTime.trim().equals("")) {
predicate.getExpressions().add(cb.lessThanOrEqualTo(root.get("createTime").as(String.class), endTime));
}
return predicate;
}
};
Page<RasterLayerEntity> page = rasterLayerRepository.findAll(specification, pageRequest);
Stream<RasterLayerEntity> rasterLayerEntityStream = page.get();
List<RasterLayerEntity> entities = rasterLayerEntityStream.collect(Collectors.toList());
setBatchEntityTagNames(entities);
res.put("totalElements", page.getTotalElements());
res.put("totalPages", page.getTotalPages());
res.put("values", entities);
return res;
}
}
自己写分页(虽然麻烦,但是也能很好解决问题,可控性强)
使用jdbcTemplate执行sql
条件自己写sql,联表条件使用联表查询
分页使用offset limit.有自增主键则使用主键,id > 80 limit 10,速度更快
Entity映射需要自己实现,写一个RowMapper