个人博客项目笔记_02
1. 统一异常处理
不管是controller层还是service,dao层,都有可能报异常,如果是预料中的异常,可以直接捕获处理,如果是意料之外的异常,需要统一进行处理,进行记录,并给用户提示相对比较友好的信息。
package com.cherriesovo.blog.handler;
import com.cherriesovo.blog.vo.Result;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
//对加了@Controller注解的方法进行拦截处理 AOP的实现
@ControllerAdvice
public class AllExceptionHandler {
//进行异常处理,处理Exception.class的异常
@ExceptionHandler(Exception.class)
@ResponseBody //返回json数据
public Result doException(Exception ex){
ex.printStackTrace();
return Result.fail(-999,"系统异常");
}
}
2. 首页-最热文章
2.1 接口说明
接口url:/articles/hot
请求方式:POST
请求参数:
参数名称 | 参数类型 | 说明 |
---|---|---|
返回数据:
{
"success": true,
"code": 200,
"msg": "success",
"data": [
{
"id": 1,
"title": "springboot介绍以及入门案例",
},
{
"id": 9,
"title": "Vue.js 是什么",
},
{
"id": 10,
"title": "Element相关",
}
]
}
2.2 Controller
ArticleController:
@PostMapping("hot")
public Result hotArticle(){
int limit = 5;
return articleService.hotArticle(limit);
}
2.3 Service
LambdaQueryWrapper<Article>
和QueryWrapper<Article>
都是 MyBatis-Plus 提供的用于构建查询条件的包装器,它们之间的主要区别在于构建查询条件的方式不同。
- LambdaQueryWrapper
:
LambdaQueryWrapper
是基于 Lambda 表达式的方式构建查询条件的,可以使用 Lambda 表达式直接引用实体类的属性。- 通过 Lambda 表达式引用属性,可以避免硬编码字段名称,使代码更加清晰易懂。
- 由于使用了 Lambda 表达式,编译器可以在编译时进行类型检查,避免一些常见的拼写错误或属性不存在的问题。
- QueryWrapper
:
QueryWrapper
是传统的方式构建查询条件的,需要通过字符串指定字段名,比较符号等。- 在构建查询条件时,需要手动输入属性的名称,容易出现拼写错误或者属性不存在的问题。
- 不具备 Lambda 表达式的类型检查和编译时安全性。
因此,如果项目采用了 Java 8 及以上的版本,推荐使用
LambdaQueryWrapper
,它更加直观、类型安全,并且代码更加清晰易读。而如果项目不支持 Lambda 表达式或者需要与旧的代码兼容,可以继续使用QueryWrapper
。
queryWrapper.orderByDesc(Article::getViewCounts)详解:
这行代码使用了
LambdaQueryWrapper
的orderByDesc
方法,用于指定查询结果按照指定字段进行降序排序。具体解释如下:
queryWrapper
:这是一个LambdaQueryWrapper<Article>
对象,用于构建查询条件和排序规则。orderByDesc
:这是LambdaQueryWrapper
提供的方法之一,用于指定按照指定字段进行降序排序。Article::getViewCounts
:这是一个 Java 8 的方法引用,指定了排序的字段。Article
是实体类,getViewCounts
是该实体类中的一个方法或属性,通常表示文章的浏览量。综上所述,这行代码的作用是对查询结果按照文章的浏览量字段进行降序排序。
public interface ArticleService {
//首页最热文章
Result hotArticle(int limit);
}
@Service
public class ArticleServiceImpl implements ArticleService {
//之前代码已省略。。。
@Override
public Result hotArticle(int limit) {
LambdaQueryWrapper<Article> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.orderByDesc(Article::getViewCounts); //根据浏览量倒序
queryWrapper.select(Article::getId,Article::getTitle);
queryWrapper.last("limit " + limit);
//上述三条语句等同于:select id,title from article order by view_counts desc limit 5
List<Article> articles = articleMapper.selectList(queryWrapper);
return Result.success(copyList(articles,false,false,false));
}
}
2.4 测试
3. 首页-最新文章
3.1 接口说明
接口url:/articles/new
请求方式:POST
请求参数:
参数名称 | 参数类型 | 说明 |
---|---|---|
返回数据:
{
"success": true,
"code": 200,
"msg": "success",
"data": [
{
"id": 1,
"title": "springboot介绍以及入门案例",
},
{
"id": 9,
"title": "Vue.js 是什么",
},
{
"id": 10,
"title": "Element相关",
}
]
}
3.1 Controller
ArticleController:
/*
* 最新文章
* */
@PostMapping("new")
public Result newArticles(){
int limit = 5;
return articleService.newArticles(limit);
}
3.2 Service
public interface ArticleService {
//最新文章
Result newArticles(int limit);
}
@Service
public class ArticleServiceImpl implements ArticleService {
//之前代码已省略。。。
@Override
public Result newArticles(int limit) {
LambdaQueryWrapper<Article> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.orderByDesc(Article::getCreateDate);
queryWrapper.select(Article::getId,Article::getTitle);
queryWrapper.last("limit "+limit);
//select id,title from article order by create_date desc limit 5
List<Article> articles = articleMapper.selectList(queryWrapper);
return Result.success(copyList(articles,false,false,false));
}
}
4. 首页-文章归档
4.1接口说明
接口url:/articles/listArchives
请求方式:POST
请求参数:
参数名称 | 参数类型 | 说明 |
---|---|---|
返回数据:
{
"success": true,
"code": 200,
"msg": "success",
"data": [
{
"year": "2021",
"month": "6",
"count": 2
}
]
}
4.1 Controller
ArticleController:
//json数据进行交互
@RestController
@RequestMapping("articles")
public class ArticleController {
/*
* 文章归档
* */
@PostMapping("listArchives")
public Result listArchives(){
return articleService.listArchives();
}
}
4.2 Service
public interface ArticleService {
//文章归档
Result listArchives();
}
@Service
public class ArticleServiceImpl implements ArticleService {
@Override
public Result listArchives() {
List<Archives> archivesList = articleMapper.listArchives();
return Result.success(archivesList);
}
}
4.3 Dao
package com.cherriesovo.blog.dao.dos;
import lombok.Data;
// 档案类
@Data
public class Archives {
private Integer year;
private Integer month;
private Integer count; //文章数量
}
package com.cherriesovo.blog.dao.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.cherriesovo.blog.dao.dos.Archives;
import com.cherriesovo.blog.dao.pojo.Article;
import java.util.List;
public interface ArticleMapper extends BaseMapper<Article> {
List<Archives> listArchives();
}
<?xml version="1.0" encoding="UTF-8" ?>
<!--MyBatis配置文件-->
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.cherriesovo.blog.dao.mapper.ArticleMapper">
<!--List<Archives> listArchives();-->
<select id="listArchives" resultType="com.cherriesovo.blog.dao.dos.Archives">
select year(from_unixtime(create_date/1000)) as year,month(from_unixtime(create_date/1000)) as month,count(*) as count from ms_article group by year,month
</select>
</mapper>
//使用FROM_UNIXTIME函数将时间戳转换为日期时间格式,并从中提取年份,然后使用YEAR函数提取年份部分。create_date/1000是为了将毫秒级时间戳转换为秒级时间戳,因为大多数数据库中的FROM_UNIXTIME函数接受的是秒级时间戳。
select year(from_unixtime(create_date/1000)) as year,month(from_unixtime(create_date/1000)) as month,count(*) as count from ms_article group by year,month