一、继续做base模块
下面来点JPA的高级操作
1、标签查找
标签分页,请求路径没问题,传进来的东西是一个Label类,模糊查找labelname和精准查找state,那就要转换一下了
controller
@PostMapping("search")
public Result findSearch(@RequestBody Label label){
System.out.println(label);
List<Label> list = labelService.findSearch(label);
return new Result(true,StatusCode.OK,"查询成功",list);
}
service
public List<Label> findSearch(Label label) {
/*
返回一个List集合,这个是模糊查找嘛,就labelname和state是有可能查找的,就这两个查找
*/
return labelDao.findAll(new Specification<Label>() {
@Override
public Predicate toPredicate(Root<Label> root, CriteriaQuery<?> criteriaQuery, CriteriaBuilder criteriaBuilder) {
//new一个list集合,用来存放所有条件,因为直接and不行,有if条件在
List<Predicate> list = new ArrayList<>();
//当labelname不为空的时候
if (label.getLabelname()!=null&&!"".equals(label.getLabelname())){
Path<Object> labelname = root.get("labelname");
Predicate predicate1 = criteriaBuilder.like(labelname.as(String.class), "%" + label.getLabelname() + "%");//where labelname like xxx
list.add(predicate1);
}
//当state不为空的时候
if (label.getState()!=null&&!"".equals(label.getState())){
Path<Object> state = root.get("state");
// Predicate predicate2 = criteriaBuilder.like(state.as(String.class), "%" + label.getState() + "%");//where state like xxx
Predicate predicate2 = criteriaBuilder.equal(state, label.getState());
list.add(predicate2);
}
//因为不知道Predicate长度,但是list不用知道长度,把list转换成数组就行
Predicate[] parr = new Predicate[list.size()];
parr = list.toArray(parr);
//and()参数 Predicate[]
return criteriaBuilder.and(parr);//where state like xxx and labelname like xxx
}
});
}
2、标签+分页查找
先看需求
这个返回的data类型,第一个是总数据量,第二个才是那一页的的数据
controller:
@PostMapping("search/{page}/{size}")
public Result findSearchPage(@RequestBody Label label,@PathVariable("page") int page,@PathVariable("size") int size){
Page<Label> pageData = labelService.findSearchPage(label,page,size);
//返回的data为PageResult类,其第一个是总数量,第二个是数据
return new Result(true,StatusCode.OK,"查询成功",new PageResult<Label>((int) pageData.getTotalElements(),pageData.getContent()));
}
public Page<Label> findSearchPage(Label label, int page, int size) {
Specification<Label> specification = new Specification<Label>() {
@Override
public Predicate toPredicate(Root<Label> root, CriteriaQuery<?> criteriaQuery, CriteriaBuilder criteriaBuilder) {
//new一个list集合,用来存放所有条件,因为直接and不行,有if条件在
List<Predicate> list = new ArrayList<>();
//当labelname不为空的时候
if (label.getLabelname()!=null&&!"".equals(label.getLabelname())){
Path<Object> labelname = root.get("labelname");
Predicate predicate1 = criteriaBuilder.like(labelname.as(String.class), "%" + label.getLabelname() + "%");//where labelname like xxx
list.add(predicate1);
}
//当state不为空的时候
if (label.getState()!=null&&!"".equals(label.getState())){
Path<Object> state = root.get("state");
// Predicate predicate2 = criteriaBuilder.like(state.as(String.class), "%" + label.getState() + "%");//where state like xxx
Predicate predicate2 = criteriaBuilder.equal(state, label.getState());
list.add(predicate2);
}
//因为不知道Predicate长度,但是list不用知道长度,把list转换成数组就行
Predicate[] parr = new Predicate[list.size()];
parr = list.toArray(parr);
//and()参数 Predicate[]
return criteriaBuilder.and(parr);//where state like xxx and labelname like xxx
}
};
Pageable pageable = PageRequest.of(page-1,size);//因为查询是从0开始的
return labelDao.findAll(specification,pageable);
}
controller用PageResult<T>
接受,这个在tensquare_commom模板中已经写好了,所以,准确的说这也是个POJO
二、招聘模块
普通的增删改查都很简单,我们主要来看特殊一点的
1、使用代码生成器(偷懒)
由于数据库表之前都做了,搭建基本的包什么的都是很简单的,用IT黑马
给的代码生成器自动生成
然后对其拉入到tensquare目录下,对其进行简单的修改
1)修改父文件pom
2)修改招聘模块pom文件
这两个直接抄base模块的就可以
3)改下Application
就是原本是
改成RecruitApplication而已,这样Application就不混乱了
4)改yml文件
修改端口号,还有url不要useUnicode=true&
server:
port: 9002
spring:
application:
name: tensquare-recruit #指定服务名
datasource:
driverClassName: com.mysql.jdbc.Driver
url: jdbc:mysql://192.168.12.128:3306/tensquare_recruit?characterEncoding=UTF8
username: root
password: root
jpa:
database: MySQL
show-sql: true
其自动生成了我们之前敲的东西(不亏是教育机构)
5)可以的话改下controller请求和@RequestBody的参数
这个设及的东西太多,慢慢改。。都是体力活
改成@GETMapping这些
然后是@RequestBody都是Map,但我还是喜欢直接用类来做,这样一改,底层就要全部改了,工作量太大了。。。但是不改也不是不能用
6)表的BUG
那个表啊,好起不起,有个列为condition
,而数据库列名的关键字为连接里面的表
https://blog.csdn.net/findmyself_for_world/article/details/43225555
解决办法:
https://blog.csdn.net/lose_alan/article/details/105510504
2、业务说明与数据库说明
先看下完成的模板
要的是推荐职位、最新职位、热门企业这3个部分
先说下数据库,当初建表的时候没说,现在说
分为两个表,企业表和招聘表
是否热门企业就ishot的变化,推荐职位就是state为2的状态,最新职位就直接按时间推算就行
3、查询热门企业
就一个很简单的东西,就查ishot是不是为1就行了,应该忘了。。
dao:
public interface EnterpriseDao extends JpaRepository<Enterprise,String>,JpaSpecificationExecutor<Enterprise>{
public List<Enterprise> findByIshot(String ishot);
}
service
public List<Enterprise> findByIshot(String ishot){
return enterpriseDao.findByIshot(ishot);
}
controller
@GetMapping("search/hotlist")
public Result hotlist(){
List<Enterprise> enterprises = enterpriseService.findByIshot("1");
return new Result(true,StatusCode.OK,"查询成功",enterprises);
}
4、推荐职位与最新职位
推荐职位:state为2等于推荐,找前6个即可,并且根据时间顺序排序
最新职位:state不为0(不关闭),前6个,并且根据时间顺序排序,
public interface RecruitDao extends JpaRepository<Recruit,String>,JpaSpecificationExecutor<Recruit>{
//推荐职位
public List<Recruit> findTop6ByStateOrderByCreatetimeDesc(String state);
//最新职位
public List<Recruit> findTop6ByStateNotOrderByCreatetimeDesc(String state);
}
service
public List<Recruit> findTop6ByStateOrderByCreatetimeDesc(){
return recruitDao.findTop6ByStateOrderByCreatetimeDesc("2");
}
public List<Recruit> findTop6ByStateNotOrderByCreatetimeDesc(){
return recruitDao.findTop6ByStateNotOrderByCreatetimeDesc("0");
}
controller
@GetMapping("search/recommend")
public Result findTop6ByStateOrderByCreatetimeDesc(){
List<Recruit> recruits = recruitService.findTop6ByStateOrderByCreatetimeDesc();
return new Result(true,StatusCode.OK,"查询成功",recruits);
}
@GetMapping("search/newlist")
public Result findTop6ByStateNotOrderByCreatetimeDesc(){
List<Recruit> recruits = recruitService.findTop6ByStateNotOrderByCreatetimeDesc();
return new Result(true,StatusCode.OK,"查询成功",recruits);
}
三、问答模块
1、关系说明
问答长这样
一个问题可以对应多个标签(php,js),一个标签可以有多个问题,多对多关系,建立中间表。
一个问题对应多个回答,1对多
这个触发器和跨数据库连接表的,还没做,也不会做。。。
2、代码生成
然后也是用代码生成器,改端口9003,改父与子的pom文件
3、最新、热门、等待回答列表
3个表的传入传出参数都一样,对应表一起来看
最新问题就按照最新回复时间排序,热门就根据reply顺序排序,等待回答就reply为0的,注意这里要用多表连接了,因为要根据连接标签号ID查找列表(就是tb_problem连接tb_pl表啦,问题ID与标签号连接)
热门回答:回复数从高到低
最新回答:最新回复时间
等待回答:回复数为0
1)dao用sql语句
public interface ProblemDao extends JpaRepository<Problem,String>,JpaSpecificationExecutor<Problem>{
@Query(value ="SELECT * FROM `tb_problem` as `p`,`tb_pl` as `pl` where p.id = pl.problemid and pl.labelid = ? ORDER BY replytime DESC",nativeQuery=true)
public Page<Problem> newList(String id, Pageable pageable);
@Query(value ="SELECT * FROM `tb_problem` as `p`,`tb_pl` as `pl` where p.id = pl.problemid and pl.labelid = ? ORDER BY reply DESC",nativeQuery=true)
public Page<Problem> hotList(String id,Pageable pageable);
@Query(value ="SELECT * FROM `tb_problem` as `p`,`tb_pl` as `pl` where p.id = pl.problemid and pl.labelid = ? and p.reply = 0 ORDER BY replytime DESC",nativeQuery=true)
public Page<Problem> waitList(String id,Pageable pageable);
}
2)service
public Page<Problem> newList(String id,int page,int size){
return problemDao.newList(id, PageRequest.of(page-1, size));
}
public Page<Problem> hotList(String id,int page,int size){
return problemDao.hotList(id, PageRequest.of(page-1, size));
}
public Page<Problem> waitList(String id,int page,int size){
return problemDao.waitList(id, PageRequest.of(page-1, size));
}
3)controller
@GetMapping("newlist/{labelid}/{page}/{size}")
public Result newList(@PathVariable("labelid") String labelid,@PathVariable int page,@PathVariable int size){
Page<Problem> problems = problemService.newList(labelid, page, size);
return new Result(true,StatusCode.OK,"查找成功",new PageResult(problems.getTotalElements(),problems.getContent()));
}
@GetMapping("hotlist/{labelid}/{page}/{size}")
public Result hotList(@PathVariable("labelid") String labelid,@PathVariable int page,@PathVariable int size){
Page<Problem> problems = problemService.hotList(labelid, page, size);
return new Result(true,StatusCode.OK,"查找成功",new PageResult(problems.getTotalElements(),problems.getContent()));
}
@GetMapping("waitlist/{labelid}/{page}/{size}")
public Result waitList(@PathVariable("labelid") String labelid,@PathVariable int page,@PathVariable int size){
Page<Problem> problems = problemService.waitList(labelid, page, size);
return new Result(true,StatusCode.OK,"查找成功",new PageResult( problems.getTotalElements(),problems.getContent()));
}
四、文章模块
继续代码生成
1、文章审核与点赞
都比较简单,但是注意要用事务性@Transactional
注解,否则会出错
1)dao
@Transactional
public interface ArticleDao extends JpaRepository<Article,String>,JpaSpecificationExecutor<Article>{
@Modifying
@Query(value = "update tb_article set state = 1 where id = ?",nativeQuery = true)
public void examine(String id);
@Modifying
@Query(value = "update tb_article set thumbup = thumbup + 1 where id = ?",nativeQuery = true)
public void thumbup(String id);
}
2)service和controller
public void examine(String id){
articleDao.examine(id);
}
public void thumbup(String id){
articleDao.thumbup(id);
}
@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,"点赞成功");
}
五、redis
redis都知道了,就是缓冲的东西,已经查过的东西不要丢,放在redis缓冲中,再次查找就从redis中找数据,减少数据库压力
1、安装
在docker容器中安装,我们已经安装了,就直接启用就行
docker run -di --name=tensquare_redis -p 6379:6379 redis
- redis端口号为6379
2、使用步骤
1)导包
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
2)改yml
spring:
redis:
host: 192.168.12.128:6379
3)将数据缓冲(查找ID例子)
执行一次查找一次,将改方法加入redis缓冲中
service:
@Service
public class ArticleService {
@Autowired
private ArticleDao articleDao;
@Autowired
private IdWorker idWorker;
//自动导入RedisTemplate,主要就是靠这个类
@Autowired
private RedisTemplate redisTemplate;
public Article findById(String id) {
//先从缓冲中查询当前对象
Article article = (Article)redisTemplate.opsForValue().get("article_" + id);
//如果没有取到的话
if (article==null){
//那就从数据库中查询
article = articleDao.findById(id).get();
//然后把值存入到缓冲中
redisTemplate.opsForValue().set("article_"+id,article);
}
return article;
}
4)删除缓冲
值得一提的是,如果你update或者delete的时候,redis中的缓冲不会自动删除,所以要在更新和删除语句中使用删除缓冲语句
public void update(Article article) {
redisTemplate.delete("article_"+article.getId());
articleDao.save(article);
}
public void deleteById(String id) {
redisTemplate.delete("article_"+id);
articleDao.deleteById(id);
}
5)基本语法
stringRedisTemplate.opsForValue().set("test", "100",60*10,TimeUnit.SECONDS);//向redis里存入数据和设置缓存时间
stringRedisTemplate.opsForValue().get("test")//根据key获取缓存中的val
stringRedisTemplate.boundValueOps("test").increment(-1);//val做-1操作
stringRedisTemplate.boundValueOps("test").increment(1);//val +1
stringRedisTemplate.getExpire("test")//根据key获取过期时间
stringRedisTemplate.getExpire("test",TimeUnit.SECONDS)//根据key获取过期时间并换算成指定单位
stringRedisTemplate.delete("test");//根据key删除缓存
stringRedisTemplate.hasKey("546545");//检查key是否存在,返回boolean值
stringRedisTemplate.expire("red_123",1000 , TimeUnit.MILLISECONDS);//设置过期时间
stringRedisTemplate.opsForSet().add("red_123", "1","2","3");//向指定key中存放set集合
stringRedisTemplate.opsForSet().isMember("red_123", "1")//根据key查看集合中是否存在指定数据
stringRedisTemplate.opsForSet().members("red_123");//根据key获取set集合
6)总结
导包改yml,导入RedisTemplate ,RedisTemplate查找,如果没有就设值
其实最主要就只是redisTemplate.opsForValue().get(下标);
来查找值,和redisTemplate.opsForValue().set(下标,值);
来设置缓冲下标与对应值
但建议还是弄个redis工具类,把东西都写好,这样就不用一个一个写这么麻烦了