SpringBoot+vue練手項目 博客系統 項目使用技術 : springboot + mybatisplus+redis+mysql 1. 工程搭建 前端的工程地址: 鏈接:https://pan.baidu.com/s/1cg_11ctsbbq_WM9BnpcOaQ 提取碼:nrun npm ...
SpringBoot+vue練手項目---博客系統
項目使用技術 :
springboot + mybatisplus+redis+mysql
1. 工程搭建
前端的工程地址:
鏈接:https://pan.baidu.com/s/1cg_11ctsbbq_WM9BnpcOaQ
提取碼:nrun
npm install
npm run build
npm run dev
1.1 新建maven工程
pom.xml(blog-parent)
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.jihu</groupId>
<artifactId>blog-parent</artifactId>
<version>1.0-SNAPSHOT</version>
<modules>
<module>blog-api</module>
</modules>
<!--聲明pom代表他是一個父工程-->
<packaging>pom</packaging>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.5.0</version>
<relativePath/>
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
</properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.76</version>
</dependency>
<dependency>
<groupId>commons-collections</groupId>
<artifactId>commons-collections</artifactId>
<version>3.2.2</version>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.4.3</version>
</dependency>
<!-- https://mvnrepository.com/artifact/joda-time/joda-time -->
<dependency>
<groupId>joda-time</groupId>
<artifactId>joda-time</artifactId>
<version>2.10.10</version>
</dependency>
</dependencies>
</dependencyManagement>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
pom.xml(blog-api)
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>blog-parent</artifactId>
<groupId>com.jihu</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>blog-api</artifactId>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
<!-- 排除 預設使用的logback -->
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-logging</artifactId>
</exclusion>
</exclusions>
</dependency>
<!-- log4j2 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-log4j2</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-mail</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.76</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
</dependency>
<dependency>
<groupId>commons-collections</groupId>
<artifactId>commons-collections</artifactId>
<version>3.2.2</version>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.4.3</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
<!-- https://mvnrepository.com/artifact/joda-time/joda-time -->
<dependency>
<groupId>joda-time</groupId>
<artifactId>joda-time</artifactId>
<version>2.10.10</version>
</dependency>
</dependencies>
</project>
1.2 application.yml
server:
port: 8888
spring:
application:
name: mszlu_blog
#資料庫的配置
datasource:
url: jdbc:mysql://localhost:3306/blog?useUnicode=true&characterEncoding=UTF-8&serverTimeZone=UTC
username: root
password: 123456
driver-class-name: com.mysql.cj.jdbc.Driver
#mybatis-plus
mybatis-plus:
configuration:
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl #列印日誌 如sql語句
global-config:
db-config:
table-prefix: ms_ #標識表的首碼為ms_
#指定mapper文件的位置
mybatis-plus:
config-location: classpath:mapper/*.xml
1.3 配置 分頁 和跨域
分頁
package com.jihu.blog.config;
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
//掃包,將此包下的介面生成代理實現類,並且註冊到spring容器中
@MapperScan("com.jihu.blog.mapper")
public class MybatisPlusConfig {
//分頁插件
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor(){
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
interceptor.addInnerInterceptor(new PaginationInnerInterceptor());
return interceptor;
}
}
跨域
package com.jihu.blog.config;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration
public class WebMVCConfig implements WebMvcConfigurer {
//實現跨域請求
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
.allowedOriginPatterns("*")
.allowedMethods("GET","HEAD","POST","PUT","DELETE","OPTIONS")
.allowCredentials(true)
.maxAge(3600)
.allowedHeaders("*");
}
}
1.4啟動類
package com.jihu.blog;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class BlogApp {
public static void main(String[] args) {
SpringApplication.run(BlogApp.class,args);
}
}
2.首頁-文章列表
2.1 介面說明
介面url:/articles
請求方式:POST
請求參數:
參數名稱 | 參數類型 | 說明 |
---|---|---|
page | int | 當前頁數 |
pageSize | int | 每頁顯示的數量 |
返回數據:
{
"success": true,
"code": 200,
"msg": "success",
"data": [
{
"id": 1,
"title": "springboot介紹以及入門案例",
"summary": "通過Spring Boot實現的服務,只需要依靠一個Java類,把它打包成jar,並通過`java -jar`命令就可以運行起來。\r\n\r\n這一切相較於傳統Spring應用來說,已經變得非常的輕便、簡單。",
"commentCounts": 2,
"viewCounts": 54,
"weight": 1,
"createDate": "2609-06-26 15:58",
"author": "12",
"body": null,
"tags": [
{
"id": 5,
"avatar": null,
"tagName": "444"
},
{
"id": 7,
"avatar": null,
"tagName": "22"
},
{
"id": 8,
"avatar": null,
"tagName": "11"
}
],
"categorys": null
},
{
"id": 9,
"title": "Vue.js 是什麼",
"summary": "Vue (讀音 /vjuː/,類似於 view) 是一套用於構建用戶界面的漸進式框架。",
"commentCounts": 0,
"viewCounts": 3,
"weight": 0,
"createDate": "2609-06-27 11:25",
"author": "12",
"body": null,
"tags": [
{
"id": 7,
"avatar": null,
"tagName": "22"
}
],
"categorys": null
},
{
"id": 10,
"title": "Element相關",
"summary": "本節將介紹如何在項目中使用 Element。",
"commentCounts": 0,
"viewCounts": 3,
"weight": 0,
"createDate": "2609-06-27 11:25",
"author": "12",
"body": null,
"tags": [
{
"id": 5,
"avatar": null,
"tagName": "444"
},
{
"id": 6,
"avatar": null,
"tagName": "33"
},
{
"id": 7,
"avatar": null,
"tagName": "22"
},
{
"id": 8,
"avatar": null,
"tagName": "11"
}
],
"categorys": null
}
]
}
2.2 編碼
2.2.1 表結構
文章表
CREATE TABLE `blog`.`ms_article` (
`id` bigint(0) NOT NULL AUTO_INCREMENT,
`comment_counts` int(0) NULL DEFAULT NULL COMMENT '評論數量',
`create_date` bigint(0) NULL DEFAULT NULL COMMENT '創建時間',
`summary` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '簡介',
`title` varchar(64) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '標題',
`view_counts` int(0) NULL DEFAULT NULL COMMENT '瀏覽數量',
`weight` int(0) NOT NULL COMMENT '是否置頂',
`author_id` bigint(0) NULL DEFAULT NULL COMMENT '作者id',
`body_id` bigint(0) NULL DEFAULT NULL COMMENT '內容id',
`category_id` int(0) NULL DEFAULT NULL COMMENT '類別id',
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 25 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;
標簽表
id,文章id,標簽id,通過文章id可以間接查到標簽id
CREATE TABLE `blog`.`ms_tag` (
`id` bigint(0) NOT NULL AUTO_INCREMENT,
`article_id` bigint(0) NOT NULL,
`tag_id` bigint(0) NOT NULL,
PRIMARY KEY (`id`) USING BTREE,
INDEX `article_id`(`article_id`) USING BTREE,
INDEX `tag_id`(`tag_id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;
用戶表
CREATE TABLE `blog`.`ms_sys_user` (
`id` bigint(0) NOT NULL AUTO_INCREMENT,
`account` varchar(64) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '賬號',
`admin` bit(1) NULL DEFAULT NULL COMMENT '是否管理員',
`avatar` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '頭像',
`create_date` bigint(0) NULL DEFAULT NULL COMMENT '註冊時間',
`deleted` bit(1) NULL DEFAULT NULL COMMENT '是否刪除',
`email` varchar(128) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '郵箱',
`last_login` bigint(0) NULL DEFAULT NULL COMMENT '最後登錄時間',
`mobile_phone_number` varchar(20) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '手機號',
`nickname` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '昵稱',
`password` varchar(64) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '密碼',
`salt` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '加密鹽',
`status` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '狀態',
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 16 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;
2.2.2 entity層
Article 文章實體類
package com.jihu.blog.dao.pojo;
import lombok.Data;
@Data
public class Article {
public static final int Article_TOP = 1;
public static final int Article_Common = 0;
private Long id;
private String title;
private String summary;
private int commentCounts;
private int viewCounts;
/**
* 作者id
*/
private Long authorId;
/**
* 內容id
*/
private Long bodyId;
/**
*類別id
*/
private Long categoryId;
/**
* 置頂
*/
private int weight = Article_Common;
/**
* 創建時間
*/
private Long createDate;
}
SysUser 用戶實體類
package com.jihu.blog.dao.pojo;
import lombok.Data;
@Data
public class SysUser {
private Long id;
private String account;
private Integer admin;
private String avatar;
private Long createDate;
private Integer deleted;
private String email;
private Long lastLogin;
private String mobilePhoneNumber;
private String nickname;
private String password;
private String salt;
private String status;
}
Tag 標簽實體類
package com.jihu.blog.dao.pojo;
import lombok.Data;
@Data
public class Tag {
private Long id;
private String avatar;
private String tagName;
}
2.2.3 Controller層
ArticleController
package com.jihu.blog.controller;
import com.jihu.blog.service.ArticleService;
import com.jihu.blog.vo.Result;
import com.jihu.blog.vo.params.PageParams;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("articles")
public class ArticleController {
@Autowired
private ArticleService articleService;
//首頁 文章列表
@PostMapping
public Result listArticle(@RequestBody PageParams pageParams){
//ArticleVo 頁面接收的數據
return articleService.listArticle(pageParams);
}
}
2.2.4 Service層
ArticleService
package com.jihu.blog.service;
import com.jihu.blog.vo.Result;
import com.jihu.blog.vo.params.PageParams;
public interface ArticleService {
Result listArticle(PageParams pageParams);
}
ArticleServiceImpl
package com.jihu.blog.service.impl;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.jihu.blog.dao.mapper.ArticleMapper;
import com.jihu.blog.dao.mapper.TagMapper;
import com.jihu.blog.dao.pojo.Article;
import com.jihu.blog.service.ArticleService;
import com.jihu.blog.service.SysUserService;
import com.jihu.blog.service.TagService;
import com.jihu.blog.vo.ArticleVo;
import com.jihu.blog.vo.Result;
import com.jihu.blog.vo.params.PageParams;
import org.joda.time.DateTime;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.ArrayList;
import java.util.List;
@Service
public class ArticleServiceImpl implements ArticleService {
@Autowired
private ArticleMapper articleMapper;
@Autowired
private TagService tagService;
@Autowired
private SysUserService sysUserService;
@Override
public Result listArticle(PageParams pageParams) {
Page<Article> page = new Page<>(pageParams.getPage(), pageParams.getPageSize());
LambdaQueryWrapper<Article> queryWrapper = new LambdaQueryWrapper<>();
//是否置頂進行排序
queryWrapper.orderByDesc(Article::getWeight,Article::getCreateDate);
Page<Article> articlePage = articleMapper.selectPage(page, queryWrapper);
List<Article> records = articlePage.getRecords();
//能直接返回嗎 肯定不行 所以需要進行如下轉換
List<ArticleVo> articleVoList = copyList(records,true,true);
return Result.success(articleVoList);
}
private List<ArticleVo> copyList(List<Article> records,boolean isTag,boolean isAuthor) {
List<ArticleVo> articleVoList = new ArrayList<>();
for (Article record : records) {
articleVoList.add(copy(record,isTag,isAuthor));
}
return articleVoList;
}
private ArticleVo copy(Article article,boolean isTag,boolean isAuthor){
ArticleVo articleVo = new ArticleVo();
BeanUtils.copyProperties(article,articleVo);
articleVo.setCreateDate(new DateTime(article.getCreateDate()).toString("yyyy-MM-dd HH:mm"));
//並不是所有的介面,都需要標簽,作者信息
if (isTag){
Long articleId = article.getId();
articleVo.setTags(tagService.findTagsByrticleId(articleId));
}
if (isAuthor){
Long authorId = article.getAuthorId();
articleVo.setAuthor(sysUserService.findUserById(authorId).getNickname());
}
return articleVo;
}
}
SysUserService
package com.jihu.blog.service;
import com.jihu.blog.dao.pojo.SysUser;
public interface SysUserService {
SysUser findUserById(Long id);
}
SysUserServiceImpl
package com.jihu.blog.service.impl;
import com.jihu.blog.dao.mapper.SysUserMapper;
import com.jihu.blog.dao.pojo.SysUser;
import com.jihu.blog.service.SysUserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
public class SysUserServiceImpl implements SysUserService {
@Autowired
private SysUserMapper sysUserMapper;
@Override
public SysUser findUserById(Long id) {
SysUser sysUser = sysUserMapper.selectById(id);
//防止空指針出現 加一個判斷
if (sysUser == null){
sysUser = new SysUser();
sysUser.setNickname("馬神之路");
}
return sysUser;
}
}
TagService
package com.jihu.blog.service;
import com.jihu.blog.vo.TagVo;
import java.util.List;
public interface TagService {
List<TagVo> findTagsByrticleId(Long articleId);
}
TagServiceImpl
package com.jihu.blog.service.impl;
import com.jihu.blog.dao.mapper.TagMapper;
import com.jihu.blog.dao.pojo.Tag;
import com.jihu.blog.service.TagService;
import com.jihu.blog.vo.TagVo;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.ArrayList;
import java.util.List;
@Service
public class TagServiceImpl implements TagService {
@Autowired
private TagMapper tagMapper;
@Override
public List<TagVo> findTagsByrticleId(Long articleId) {
//mybatisplus 無法進行多表查詢
List<Tag> tags = tagMapper.findTagsByrticleId(articleId);
return copyList(tags);
}
private List<TagVo> copyList(List<Tag> tags) {
List<TagVo> tagVoList = new ArrayList<>();
for (Tag tag : tags) {
tagVoList.add(copy(tag));
}
return tagVoList;
}
private TagVo copy(Tag tag) {
TagVo tagVo = new TagVo();
BeanUtils.copyProperties(tag,tagVo);
return tagVo;
}
}
2.2.5 Mapper層
ArticleMapper
package com.jihu.blog.dao.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.jihu.blog.dao.pojo.Article;
//BaseMapper mybatisplus中提供的可以讓我們很方便的查詢這張表
public interface ArticleMapper extends BaseMapper<Article> {
}
SysUserMapper
package com.jihu.blog.dao.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.jihu.blog.dao.pojo.SysUser;
public interface SysUserMapper extends BaseMapper<SysUser> {
}
TagMapper
package com.jihu.blog.dao.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.jihu.blog.dao.pojo.Tag;
import java.util.List;
public interface TagMapper extends BaseMapper<Tag> {
/**
* 根據文章id 查詢標簽列表
* @param articleId
* @return
*/
List<Tag> findTagsByrticleId(Long articleId);
}
TagMapper.xml
<?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.jihu.blog.dao.mapper.TagMapper">
<sql id="all">
id,avatar,tag_name as tagName
</sql>
<!-- List<Tag> findTagsByArticleId(Long articleId);
在這個文件中,id代表方法名,parameterType表示輸入變數的名字,resultType表示泛型的類型-->
<select id="findTagsByrticleId" parameterType="long" resultType="com.jihu.blog.dao.pojo.Tag">
select id,avatar,tag_name as tagName from ms_tag
where id in
(select tag_id from ms_article_tag where article_id=#{articleId})
</select>
</mapper>
2.2.6 Vo層
Result(統一最後的結果)
package com.jihu.blog.vo;
import lombok.AllArgsConstructor;
import lombok.Data;
@Data
@AllArgsConstructor
public class Result {
private boolean success;
private int code ;
private String msg;
private Object data;
public static Result success(Object data) {
return new Result(true, 200, "success", data);
}
public static Result fail(int code,String msg) {
return new Result(false, code, msg, null);
}
}
ArticleVo 建立與前端交互的Vo文件
package com.jihu.blog.vo;
import lombok.Data;
import java.util.List;
//建立與前端交互的Vo文件
@Data
public class ArticleVo {
private Long id;
private String title;
private String summary;
private int commentCounts;
private int viewCounts;
private int weight;
/**
* 創建時間
*/
private String createDate;
private String author;
// private ArticleBodyVo body;
private List<TagVo> tags;
// private List<CategoryVo> categorys;
}
新建TagVo
package com.jihu.blog.vo;
import lombok.Data;
@Data
public class TagVo {
private Long id;
private String tagName;
}
新建PageParams
package com.jihu.blog.vo.params;
import lombok.Data;
@Data
public class PageParams {
private int Page =1; //當前頁數
private int PageSize =10; //每頁顯示的數量
}
2.2.7 測試:
3.首頁- 最熱標簽
3.1介面說明
介面url:/tags/hot
請求方式:GET
請求參數:無
id: 標簽名稱 ,我們期望點擊標簽關於文章的所有列表都顯示出來
返回數據:
{
"success": true,
"code": 200,
"msg": "success",
"data": [
{
"id":1,
"tagName":"4444"
}
]
}
3.2編碼
3.2.1Controller層
package com.jihu.blog.controller;
import com.jihu.blog.service.TagService;
import com.jihu.blog.vo.Result;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("tags")
public class TagsController {
@Autowired
private TagService tagService;
@GetMapping("hot")
public Result hot(){
int limit = 6;
return tagService.hots(limit);
}
}
3.2.2 Service層
建立service介面
TagService
package com.jihu.blog.service;
import com.jihu.blog.vo.Result;
import com.jihu.blog.vo.TagVo;
import java.util.List;
public interface TagService {
Result hots(int limit);
}
建立serviceimpl實現類
TagServiceImpl
@Service
public class TagServiceImpl implements TagService {
@Autowired
private TagMapper tagMapper;
@Override
public Result hots(int limit) {
/*
1.標簽所擁有的文章數量最多 即為最熱標簽
2. 查詢 根據tag_id 分組 計數,從大到小 排列 取前 limit個
*/
List<Long> tagIds = tagMapper.findHotsIds(limit);
//判斷一下是否為空
if (tagIds == null){
return Result.success(Collections.emptyList());
}
//需求的是 tagId 和 tagName tag對象
//需要的是這樣的一個sql語句 select * from tag where id in (1,2,3...)
List<Tag> tagList = tagMapper.findTagdByTagIds(tagIds);
return Result.success(tagList);
}
}
3.2.3 Mapper層
TagMapper
package com.jihu.blog.dao.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.jihu.blog.dao.pojo.Tag;
import java.util.List;
public interface TagMapper extends BaseMapper<Tag> {
/**
* 查詢最熱的標簽 前limit條
* @param limit
* @return
*/
List<Long> findHotsIds(int limit);
/*
根據最熱標簽查詢 最熱文章名字
*/
List<Tag> findTagdByTagIds(List<Long> tagIds);
}
TagMapper
<?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.jihu.blog.dao.mapper.TagMapper">
<sql id="all">
id,avatar,tag_name as tagName
</sql>
<select id="findHotsIds" parameterType="int" resultType="java.lang.Long">
SELECT tag_id from ms_article_tag GROUP BY tag_id ORDER BY count(*) DESC limit #{limit}
</select>
<select id="findTagdByTagIds" parameterType="list" resultType="com.jihu.blog.dao.pojo.Tag">
select id,tag_name as tagName from ms_tag
where id in
<foreach collection="collection" item="tagId" separator="," open="(" close=")">
#{tagId}
</foreach>
</select>
</mapper>
3.2.4 測試
4.統一異常處理
不管是controller層還是service,dao層,都有可能報異常,如果是預料中的異常,可以直接捕獲處理,如果是意料之外的異常,需要統一進行處理,進行記錄,並給用戶提示相對比較友好的信息。
AllExceptionHandler
package com.jihu.blog.handler;
import com.jihu.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,"系統異常");
}
}
5.首頁-最熱文章
5.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相關",
}
]
}
5.2 Controller層
ArticleController
@RestController
@RequestMapping("articles")
public class ArticleController {
@Autowired
private ArticleService articleService;
//首頁 最熱文章
@PostMapping("hot")
public Result hotArticle(){
int limit = 5; //取前5條
return articleService.hotArticle(limit);
}
}
5.3 Service層
ArticleService
package com.jihu.blog.service;
import com.jihu.blog.vo.Result;
import com.jihu.blog.vo.params.PageParams;
public interface ArticleService {
Result listArticle(PageParams pageParams);
Result hotArticle(int limit);
}
ArticleServiceImpl
@Service
public class ArticleServiceImpl implements ArticleService {
@Autowired
private ArticleMapper articleMapper;
/**
* 最熱文章查詢
* @param limit
* @return
*/
@Override
public Result hotArticle(int limit) {
LambdaQueryWrapper<Article> lambdaQueryWrapper = new LambdaQueryWrapper<>();
lambdaQueryWrapper.orderByDesc(Article::getViewCounts);
lambdaQueryWrapper.select(Article::getId,Article::getTitle);
lambdaQueryWrapper.last("limit "+ limit);
//SELECT id, title from ms_article ORDER BY view_counts DESC limit 5
List<Article> articles = articleMapper.selectList(lambdaQueryWrapper);
return Result.success(copyList(articles,false,false));
}
}
5.4測試
6.首頁-最新文章
和最熱文章非常類似,一個是根據瀏覽量來選擇,一個是根據最新創建時間來選擇
6.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相關",
}
]
}
6.2 Controller層
在com.jihu.blog.controller.ArticleController中添加
//首頁 最新文章
@PostMapping("new")
public Result newArticle(){
int limit = 5; //取前5條
return articleService.newArticle(limit);
}
6.3ArticleService
Result newArticle(int limit);
6.4ArticleServiceImpl
/**
* 最新文章查詢
* @param limit
* @return
*/
@Override
public Result newArticle(int limit) {
LambdaQueryWrapper<Article> lambdaQueryWrapper = new LambdaQueryWrapper<>();
lambdaQueryWrapper.orderByDesc(Article::getCreateDate);
lambdaQueryWrapper.select(Article::getId,Article::getTitle);
lambdaQueryWrapper.last("limit "+limit);
//SELECT id, title from ms_article ORDER BY create_data DESC limit 5
List<Article> articles = articleMapper.selectList(lambdaQueryWrapper);
return Result.success(copyList(articles,false,false));
}
6.5測試
7.首頁-文章歸檔
每一篇文章根據創建時間某年某月發表多少篇文章
7.1介面說明
介面url:/articles/listArchives
請求方式:POST
請求參數:無
返回數據:
{
"success": true,
"code": 200,
"msg": "success",
"data": [
{
"year": "2021",
"month": "6",
"count": 2
}
]
}
7.2 Controller層
com.jihu.blog.controller.ArticleController
//首頁 文章歸檔
@PostMapping("listArchives")
public Result listArchives(){
return articleService.listArchives();
}
7.3 ArticleService
Result listArchives();
7.4 ArticleServiceImpl
//文章歸檔
@Override
public Result listArchives() {
List<Archives> archivesList = articleMapper.listArchives();
return Result.success(archivesList);
}
7.5 ArticleMapper
package com.jihu.blog.dao.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.jihu.blog.dao.dos.Archives;
import com.jihu.blog.dao.pojo.Article;
import com.jihu.blog.vo.Result;
import java.util.List;
//BaseMapper mybatisplus中提供的可以讓我們很方便的查詢這張表
public interface ArticleMapper extends BaseMapper<Article> {
List<Archives> listArchives();
}
7.6 ArticleMapper.xml
<?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.jihu.blog.dao.mapper.ArticleMapper">
<!--
select YEAR(create_date) as year,YEAR(create_date) as month ,count(*) as count from ms_article GROUP BY year,MONTH 這樣查詢不行
-->
<!--create_date 為bigint 13位,直接year()不行,需要先轉date型後year()。-->
<select id="listArchives" resultType="com.jihu.blog.dao.dos.Archives" >
select year(FROM_UNIXTIME(create_date/1000)) year,month(FROM_UNIXTIME(create_date/1000)) month, count(*)
count from ms_article group by year,month;
</select>
</mapper>