百木园-与人分享,
就是让自己快乐。

SpringBoot+vue 练手项目-- 个人博客系统

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

<!--



-->
<!--

Top

-->


收藏


关注


评论


来源:https://www.cnblogs.com/yin-jihu/p/16100034.html
本站部分图文来源于网络,如有侵权请联系删除。

未经允许不得转载:百木园 » SpringBoot+vue 练手项目-- 个人博客系统

相关推荐

  • 暂无文章