SpringBoot+vue 練手項目-- 個人博客系統

来源:https://www.cnblogs.com/yin-jihu/archive/2022/04/04/16100034.html
-Advertisement-
Play Games

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 編碼

Spring基於註解的開發
每個註解的作用

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 測試:

image-20220404162338575

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 測試

image-20220404170243616

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,"系統異常");
    }

}

image-20220404171112342

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測試

image-20220404180253013

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測試

image-20220404181514531

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>

7.7測試

image-20220404184134240

收藏 關註 評論
您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 08-Functions, Parameters、 functions、 first class、 function signatures、 parameter、 pass by value、 p... ...
  • java是什麼? java是java面向對象程式設計語言和java平臺的總稱 java的開發平臺 javaSE:標準版 javaEE:企業版 javaME:嵌入式 JRE和JDK JRE:jre是java運行時環境,包含JVM和運行時所需要的核心類庫 JDK:jdk時java程式開發工具包,包含jr ...
  • 方法重載的規則,main方法也可以重載,JVM在調用main方法的時候傳入了一個空字元串數組 構成方法重載的規則: 1.首先必須是在同一個類中 2.函數名相同 3.形參列表不同(形參個數,類型,順序不同都可以構成方法重載) 只有返回值不同不能構成方法重載。 只有訪問修飾符不同也不能構成方法重載 ma ...
  • 有沒有小火伴是特別喜歡玩五子棋的,我記得我初中是特別喜歡的。於是,我今天就用Python給大家寫了一個黑白棋游戲。代碼放在下麵了。 01、繪製棋盤 Python學習交流Q群:906715085### import pygame, sys, random from pygame.locals impo ...
  • 多線程方式實現(1) 方式1:繼承Thread類。 * 步驟 * A:自定義類MyThread繼承Thread類。 * B:MyThread類裡面重寫run()? * 為什麼是run()方法呢? * C:創建對象 * D:啟動線程 */ package cn.itcast_02; /* * 該類要重 ...
  • Windows微信清理工具v.3.0.2 更新內容: 1、清理完成時可顯示刪除了哪些文件。 軟體截圖: 所有版本及源碼下載鏈接: 百度網盤:https://pan.baidu.com/s/1OSIpvZEOvd-lVZb_82BnKg 提取碼:ylzh (請下載v.3.0.2版本) 阿裡雲盤:htt ...
  • 假期就要好好利用,不然怎麼捲死同齡人,今天給大家分享替換字元串。 FlashText 演算法是由 Vikash Singh 於2017年發表的大規模關鍵詞替換演算法,這個演算法的時間複雜度僅由文本長度(N)決定,演算法時間複雜度為O(N) 而對於正則表達式的替換,演算法時間複雜度還需要考慮被替換的關鍵詞數量( ...
  • 說明 當前的版本為 MyBatis 3.5.9 MyBatis Plus 3.5.1 Spring Boot 2.6.4 Postgresql 42.3.3 與 Spring Boot 結合使用 MyBatis 以下說明Spring Boot下完全以註解方式進行的配置, 覆蓋大部分功能場景 項目依賴 ...
一周排行
    -Advertisement-
    Play Games
  • 示例項目結構 在 Visual Studio 中創建一個 WinForms 應用程式後,項目結構如下所示: MyWinFormsApp/ │ ├───Properties/ │ └───Settings.settings │ ├───bin/ │ ├───Debug/ │ └───Release/ ...
  • [STAThread] 特性用於需要與 COM 組件交互的應用程式,尤其是依賴單線程模型(如 Windows Forms 應用程式)的組件。在 STA 模式下,線程擁有自己的消息迴圈,這對於處理用戶界面和某些 COM 組件是必要的。 [STAThread] static void Main(stri ...
  • 在WinForm中使用全局異常捕獲處理 在WinForm應用程式中,全局異常捕獲是確保程式穩定性的關鍵。通過在Program類的Main方法中設置全局異常處理,可以有效地捕獲並處理未預見的異常,從而避免程式崩潰。 註冊全局異常事件 [STAThread] static void Main() { / ...
  • 前言 給大家推薦一款開源的 Winform 控制項庫,可以幫助我們開發更加美觀、漂亮的 WinForm 界面。 項目介紹 SunnyUI.NET 是一個基於 .NET Framework 4.0+、.NET 6、.NET 7 和 .NET 8 的 WinForm 開源控制項庫,同時也提供了工具類庫、擴展 ...
  • 說明 該文章是屬於OverallAuth2.0系列文章,每周更新一篇該系列文章(從0到1完成系統開發)。 該系統文章,我會儘量說的非常詳細,做到不管新手、老手都能看懂。 說明:OverallAuth2.0 是一個簡單、易懂、功能強大的許可權+可視化流程管理系統。 有興趣的朋友,請關註我吧(*^▽^*) ...
  • 一、下載安裝 1.下載git 必須先下載並安裝git,再TortoiseGit下載安裝 git安裝參考教程:https://blog.csdn.net/mukes/article/details/115693833 2.TortoiseGit下載與安裝 TortoiseGit,Git客戶端,32/6 ...
  • 前言 在項目開發過程中,理解數據結構和演算法如同掌握蓋房子的秘訣。演算法不僅能幫助我們編寫高效、優質的代碼,還能解決項目中遇到的各種難題。 給大家推薦一個支持C#的開源免費、新手友好的數據結構與演算法入門教程:Hello演算法。 項目介紹 《Hello Algo》是一本開源免費、新手友好的數據結構與演算法入門 ...
  • 1.生成單個Proto.bat內容 @rem Copyright 2016, Google Inc. @rem All rights reserved. @rem @rem Redistribution and use in source and binary forms, with or with ...
  • 一:背景 1. 講故事 前段時間有位朋友找到我,說他的窗體程式在客戶這邊出現了卡死,讓我幫忙看下怎麼回事?dump也生成了,既然有dump了那就上 windbg 分析吧。 二:WinDbg 分析 1. 為什麼會卡死 窗體程式的卡死,入口門檻很低,後續往下分析就不一定了,不管怎麼說先用 !clrsta ...
  • 前言 人工智慧時代,人臉識別技術已成為安全驗證、身份識別和用戶交互的關鍵工具。 給大家推薦一款.NET 開源提供了強大的人臉識別 API,工具不僅易於集成,還具備高效處理能力。 本文將介紹一款如何利用這些API,為我們的項目添加智能識別的亮點。 項目介紹 GitHub 上擁有 1.2k 星標的 C# ...