优秀的编程知识分享平台

网站首页 > 技术文章 正文

SpringBoot+SptingCloud全家桶微服务实战项目(三)之查询和缓存

nanyue 2024-10-01 13:05:14 技术文章 58 ℃

一.条件查询

需求:完成标签的条件查询和条件查询+分页

返回的数据类型

controller层我们进行组装查询条件

//条件查询
@PostMapping("/search")
public Result findSearch(@RequestBody Map map){
List<Label> page = labelService.findSearch(map);
return new Result(true,StaticCode.OK,"查询成功",page);
}
//条件查询+分页查询
@PostMapping("search/{page}/{size}")
public Result findSearchByPageAndSize(@PathVariable int page,@PathVariable int size,@RequestBody(required = false) Map map){
//首先进行条件的封装
Pageable pageable = PageRequest.of(page-1,size);
Page<Label> pageData = labelService.findSearchByPageAndSize(pageable,map);
PageResult<Label> pageResult = new PageResult<>(pageData.getTotalElements(), pageData.getContent());
return new Result(true,StaticCode.OK,"查询成功",pageResult);
}

注意:在条件查询+分页查询中我们自己定义的pageRequest

service层开发

注意:dao接口中一定要进行继承JpaSpecificationExecutor用来动态的拼接我们的参数

/**
* 条件查询
* @param map
* @return
*/
@Override
public List<Label> findSearch(Map map) {
//构建条件
return labelDao.findAll(getSpecification(map));
}
/**
* 条件查询+分页查询
* @param pageable
* @param map
* @return
*/
@Override
public Page<Label> findSearchByPageAndSize(Pageable pageable, Map map) {
return labelDao.findAll(getSpecification(map),pageable);
}
//构建查询条件
public Specification<Label> getSpecification(Map map){
return new Specification<Label>() {
//动态的拼接参数进行组装参数
/**
*
* @param root
* @param criteriaQuery
* @param criteriaBuilder
* @return
*/
@Override
public Predicate toPredicate(Root<Label> root, CriteriaQuery<?> criteriaQuery, CriteriaBuilder criteriaBuilder) {
//首先进行创建一个集合
List<Predicate> list = new ArrayList<>();
//判断map是否为空
if (map==null){
return null;
}
//构建第一个条件
//判断map中的labelname是否为空
if (!StringUtils.isEmpty(map.get("labelname"))){
Predicate p1 = criteriaBuilder.like(root.get("labelname").as(String.class), "%" + (String) map.get("labelname") + "%");
//添加到集合中
list.add(p1);
}
//构建第二个条件
//判断map中的state是否为空
if (!StringUtils.isEmpty(map.get("state"))){
Predicate p2 = criteriaBuilder.equal(root.get("state").as(String.class), (String) map.get("state") );
//添加到集合中
list.add(p2);
}
//构建第二个条件
//判断map中的recommend是否为空
if (!StringUtils.isEmpty(map.get("recommend"))){
Predicate p3 = criteriaBuilder.equal(root.get("recommend").as(String.class), (String) map.get("recommend") );
//添加到集合中
list.add(p3);
}
//判断list集合
if (list.size()<=0){
return null;
}
//通过and或者or拼接条件
Predicate[] restrictions = new Predicate[list.size()];
//将集合转化数组
// Predicate[] predicates = list.toArray(restrictions);
return criteriaBuilder.and(list.toArray(new Predicate[list.size()]));
}
};
}

测试:

分页查询

二.招聘微服务开发

需求:查询热门企业列表 推荐职位列表 最新职位列表

基础的CRUD代码我们通过代码生成器进行生成

我们通过方法命名法进行编写

1.热门企业

controller层

//热门企业查询
@GetMapping("/search/hotlist")
public Result findHotList(){
return new Result(true,StatusCode.OK,"查询成功",enterpriseService.findHotList());
}

service层

public List<Enterprise> findHotList() {
return enterpriseDao.findByIshot("1");
}

dao层

public interface EnterpriseDao extends JpaRepository<Enterprise,String>,JpaSpecificationExecutor<Enterprise>{
//方法命名法,通过ishost是一的查询出来
public List<Enterprise> findByIshot(String ishot);
}

2.推荐职位和最新职位

controller层

//推荐职位
@GetMapping("/search/recommend")
public Result recommend(){
return new Result(true,StatusCode.OK,"查询成功",recruitService.findCommend());
}
//最新职位
@GetMapping("/search/newlist")
public Result newList(){
return new Result(true,StatusCode.OK,"查询成功",recruitService.findNewList());
}

service层:

public List<Recruit> findCommend() {
return recruitDao.findTop4ByStateOrderByCreatetimeDesc("2");
}
public List<Recruit> findNewList() {
return recruitDao.findTop12ByStateNotOrderByCreatetimeDesc("0");
}

dao层

public interface RecruitDao extends JpaRepository<Recruit,String>,JpaSpecificationExecutor<Recruit>{
//推荐职位
public List<Recruit> findTop4ByStateOrderByCreatetimeDesc(String state);
//最新的职位
public List<Recruit> findTop12ByStateNotOrderByCreatetimeDesc(String state);
}

测试:

三.问答微服务开发

需求分析:

通过点击每个标题,下面的列表展示三个页签,最新回答,热门回答,等待回答

注意:我们通过原生的sql可以查询,也可以通过JPQL进行查询 还要添加一个中间表, Pl表 一个标签可以有多个问题一个问题也可以有多个标签,

原生的采用这样方式:

 @Query(nativeQuery = true, value = "select * from tb_problem p where p.id in(select problemid from tb_pl p1 WHERE p1.labelid = ?1)")

JPQl方式查询

controller层

/**
* 热门问答列表
*/
@GetMapping("/hotlist/{labelid}/{page}/{size}")
public Result findHotList(@PathVariable String labelid,@PathVariable int page,@PathVariable int size){
Pageable pageable = PageRequest.of(page-1,size);
Page<Problem> pageData = problemService.findHostList(labelid,pageable);
return new Result(true,StatusCode.OK,"查询成功",new PageResult<Problem>(pageData.getTotalElements(), pageData.getContent()));
}
/**
* 最新问答
*/
@GetMapping("/newlist/{labelid}/{page}/{size}")
public Result findNewList(@PathVariable String labelid,@PathVariable int page,@PathVariable int size){
Pageable pageable = PageRequest.of(page-1,size);
Page<Problem> pageData = problemService.findNewList(labelid,pageable);
return new Result(true,StatusCode.OK,"查询成功",new PageResult<Problem>(pageData.getTotalElements(), pageData.getContent()));
}
/**
* 等待回答列表
*/
@GetMapping("/waitlist/{labelid}/{page}/{size}")
public Result findWaitList(@PathVariable String labelid,@PathVariable int page,@PathVariable int size){
Pageable pageable = PageRequest.of(page-1,size);
Page<Problem> pageData = problemService.findWaitList(labelid,pageable);
return new Result(true,StatusCode.OK,"查询成功",new PageResult<Problem>(pageData.getTotalElements(), pageData.getContent()));
}

dao层

public interface ProblemDao extends JpaRepository<Problem,String>,JpaSpecificationExecutor<Problem>{
/**
* 根据标签id查询最新问题列表
*/
@Query("select p from Problem p where p.id in(select problemid from Pl where labelid = ?1) order by p.createtime desc ")
Page<Problem> newList(String labelId, Pageable pageable);
/**
* 根据标签id查询热门问题
* @param labelId
* @param pageable
* @return
*/
@Query("select p from Problem p where p.id in(select problemid from Pl where labelid = ?1) order by p.reply desc")
Page<Problem> hotList(String labelId, Pageable pageable);
/**
* 根据标签id查询等待回答列表
* @param labelId
* @param pageable
* @return
*/
@Query("select p from Problem p where p.id in(select problemid from Pl where labelid = ?1) and p.reply = 0 order by p.createtime desc ")
Page<Problem> waitList(String labelId, Pageable pageable);
}

四.文章微服务开发

需求分析: 文章审核 通过修改state的状态为1

点赞数 : 每次点赞,让数据库中thumbmp加一

Controller 层:

/**
* 文章的审核
* @param articleId
* @return
*/
@PutMapping("/examine/{articleId}")
public Result examine(@PathVariable String articleId){
articleService.examine(articleId);
return new Result(true,StatusCode.OK,"审核成功");
}
/**
* 文章的点赞
*/
@PutMapping("/thumbup/{articleId}")
public Result thumbup(@PathVariable String articleId){
articleService.thumbup(articleId);
return new Result(true,StatusCode.OK,"点赞成功");
}

service层:

/**
* 审核
* @param articleId
*/
@Transactional
 public void examine(String articleId) {
articleDao.examine(articleId);
 }
?
/**
* 点赞数的实现
* @param articleId
*/
@Transactional
public void thumbup(String articleId) {
articleDao.updateThumbup(articleId);
}

dao层:

public interface ArticleDao extends JpaRepository<Article,String>,JpaSpecificationExecutor<Article>{
 /**
 * 文章的审核
 * 第一种方法:先查询,然后修改
 * 第二中通过注解@modify 注意必须添加事物处理
 * 第三种我们通过jpa的快照机制
 */
 @Modifying
 @Query("update Article a set a.state = '1' where a.id = ?1")
 public void examine(String id);
 /**
 * 文章点赞功能的实现
 */
 @Modifying
 @Query("update Article set thumbup=thumbup+1 where id =?1")
 public void updateThumbup(String id);
}

测试:可以成功的修改

注意:我们在通过第三个方法,利用jpa的一级缓存机制的时候先查询,然后进行设置stae的值为1 ,还有一定要添加事物控制,在service层

这样就可以了,事物会在提交的时候自动判断是否修改

2.缓存处理

通过reids缓存可以提高我们的查询效率,减少服务器的压力

docker上搭建redis服务

导入spring data redis的包

配置redis的host地址为我们的linux的地址

我们在文章的的service中,在通过id获得的时候添加判断,加入到缓存中

修改和删除时候,同时清除redis中的缓存

/**
* 根据ID查询实体
* @param id
* @return
*/
public Article findById(String id) {
//1.首先从缓存中获得
Article article = (Article) redisTemplate.opsForValue().get("article_"+id);
//2.判断是否为空,如果为空,我们从数据库中查询
if (article==null){
article = articleDao.findById(id).get();
//3.将数据库中查询的在放到缓存中
redisTemplate.opsForValue().set("article_"+id,article);
}
//4.最后返回article
return article;
}
/**
* 修改
* @param article
*/
public void update(Article article) {
//修改后清除缓存
redisTemplate.delete("article_"+article.getId());
articleDao.save(article);
}
/**
* 删除
* @param id
*/
public void deleteById(String id) {
//修改后清除缓存
redisTemplate.delete("article_"+id);
articleDao.deleteById(id);
}

五.缓存处理

上面我们介绍了redis的缓存,在这我们继续学习一种spring提供的缓存,springCache

核心就是将缓存的方法,作为key,查询的结果作为value,放到缓存中,当我们再次查询的时候就会,从缓存中获取.

常用注解:

@Cacheable-------使用这个注解的方法在执行后会缓存其返回结果。

@CacheEvict--------使用这个注解的方法在其执行前或执行后移除Spring Cache中的某些

元素。

需求:缓存根据id查询标签数据

1.在启动类上添加注解开启@EnabelCacheing

2.在方法上添加注解标签Cacheable 注意value属性是必须指定的,表示的是当前方法的返回值,会缓存到那个cache中

代码:

/**
* 根据ID查询实体
* @param id
* @return
*/
@Cacheable(value = "gethering",key = "#id")
public Gathering findById(String id) {
return gatheringDao.findById(id).get();
}
/**
* 修改
* @param gathering
*/
@CacheEvict(value = "gethering",key = "#gathering.id")
public void update(Gathering gathering) {
gatheringDao.save(gathering);
}
/**
* 删除
* @param id
*/
@CacheEvict(value = "gethering",key = "#id")
public void deleteById(String id) {
gatheringDao.deleteById(id);
}

六.总结

在项目中哪部分业务用到缓存?

1.在文章微服务模块,点赞的时候,我们将每次的点赞加一的数都保存到redis中,在每次修改和删除文章的时候进行删除缓存

2.活动微服务模块,我们通过springCache将获得信息缓存到spring中,每次直接从缓存中拿,减少数据库的访问压力

你说一下项目中是如何使用缓存的?

1.第一个通过redis实现缓存,将查询的结果存到缓存中

2.通过springCache进行缓存

说一下如何设置缓存过期时间?

redis中通过给定一个时间,然后描述它的单位,就ok了

最近发表
标签列表