1.项目介绍
1.1项目效果
博客首页
登录功能
注册功能
文章分类
文章归档
文章页面
发布文章 (集成富文本编译器)
1.2项目使用技术
前端:
- vue
- element-ui
后端:
- Springboot
- mybatis-plus
- redis
- mysql
- jwt
2.工程搭建
2.1新建springboot项目
2.2在maven中导入相关依赖
<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>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
<dependency>
<groupId>com.qiniu</groupId>
<artifactId>qiniu-java-sdk</artifactId>
<version>[7.7.0, 7.7.99]</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</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>
<!-- https://mvnrepository.com/artifact/com.alibaba/fastjson -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.76</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>
<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>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.4.3</version>
</dependency>
<dependency>
<groupId>joda-time</groupId>
<artifactId>joda-time</artifactId>
<version>2.10.10</version>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
</dependency>
<dependency>
<groupId>commons-codec</groupId>
<artifactId>commons-codec</artifactId>
<version>1.15</version>
</dependency>
<dependency>
<groupId>commons-collections</groupId>
<artifactId>commons-collections</artifactId>
<version>3.2.2</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<!-- https://mvnrepository.com/artifact/io.jsonwebtoken/jjwt -->
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
<version>0.9.1</version>
</dependency>
</dependencies>
2.3配置文件
mybatis-plus分页插件
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
@MapperScan("com.leggasai.dao.mapper")
public class MybatisPlusConfig {
//分页插件
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
interceptor.addInnerInterceptor(new PaginationInnerInterceptor());
return interceptor;
}
}
跨域配置文件
import com.leggasai.handler.LoginInterceptor;
import org.springframework.beans.factory.annotation.Autowired;
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("/**")
.allowedOrigins("http://localhost:8080")
.allowedMethods("GET","POST","PUT","OPTIONS","DELETE")
.allowCredentials(true)
.maxAge(3600);
}
}
springboot配置文件 application.yml
server:
port: 8888
spring:
datasource:
username: "mysql用户名"
password: "mysql密码"
url: jdbc:mysql://localhost:3306/blog?useSSL=false&useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai
driver-class-name: com.mysql.cj.jdbc.Driver
redis:
host: localhost
port: 6379
servlet:
multipart:
max-file-size: 2MB
max-request-size: 20MB
mybatis-plus:
configuration:
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
#mysql中表前缀为ms_
global-config:
db-config:
table-prefix: ms_
type-aliases-package: com.leggasai.dao.pojo
mapper-locations: classpath*:mapper/*.xml
2.4特殊类
异常类:用于统一处理异常
package com.leggasai.handler;
import com.leggasai.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 {
@ExceptionHandler(Exception.class)
@ResponseBody//返回json数据
public Result doException(Exception ex){
ex.printStackTrace();
return Result.fail(-999, "系统异常");
}
}
返回结果类:用于给前端返回数据
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@AllArgsConstructor
@NoArgsConstructor
//返回结果类
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);
}
}
异常码类:枚举类,用于显示不同的出错提示
package com.leggasai.vo;
public enum ErrorCode {
PARAMS_ERROR(10001,"参数有误"),
ACCOUNT_PWD_NOT_EXIST(10002,"用户名或密码不存在"),
TOKEN_ERROR(10003,"token不合法"),
ACCOUNT_EXISTED(10004,"账号已存在"),
NO_PERMISSION(70001,"无访问权限"),
SESSION_TIME_OUT(90001,"会话超时"),
NO_LOGIN(90002,"未登录"),
UPLOAD_ERROR(20001,"上传失败"),;
private int code;
private String msg;
ErrorCode(int code, String msg){
this.code = code;
this.msg = msg;
}
public int getCode() {
return code;
}
public void setCode(int code) {
this.code = code;
}
public String getMsg() {
return msg;
}
public void setMsg(String msg) {
this.msg = msg;
}
}
3.数据库搭建
在sqlyog(或navicat)中新建名为blog的数据库
3.1表一:ms_article文章表
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;
3.2表二:ms_article_body文章内容表
drop table if exists `ms_article_body`;
create table `ms_article_body` (
`id` bigint(0) not null auto_increment,
`content` longtext character set utf8 collate utf8_general_ci null,
`content_html` longtext character set utf8 collate utf8_general_ci null,
`article_id` bigint(0) not null,
primary key (`id`) using btree,
index `article_id`(`article_id`) using btree
) engine = innodb auto_increment = 1405916999854342147 character set = utf8 collate = utf8_general_ci row_format = dynamic;
3.3表三:ms_article_tag关联表
这个表是用于关联article表和tag表(文章标签表)
drop table if exists `ms_article_tag`;
create table `ms_article_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 = 1405916999787233282 character set = utf8 collate = utf8_general_ci row_format = dynamic;
3.4表四:ms_sys_user用户表
drop table if exists `ms_sys_user`;
create table `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 = 1404448588146192387 character set = utf8 collate = utf8_general_ci row_format = dynamic;
3.5表五: ms_tag文章标签表
drop table if exists `ms_tag`;
create table `ms_tag` (
`id` bigint(0) not null auto_increment,
`avatar` varchar(255) character set utf8mb4 collate utf8mb4_unicode_ci null default null,
`tag_name` varchar(255) character set utf8mb4 collate utf8mb4_unicode_ci null default null,
primary key (`id`) using btree
) engine = innodb auto_increment = 11 character set = utf8 collate = utf8_general_ci row_format = dynamic;
3.6表六:ms_comment评论表
drop table if exists `ms_comment`;
create table `ms_comment` (
`id` bigint(0) not null auto_increment,
`content` varchar(255) character set utf8mb4 collate utf8mb4_unicode_ci not null,
`create_date` bigint(0) not null,
`article_id` int(0) not null,
`author_id` bigint(0) not null,
`parent_id` bigint(0) not null,
`to_uid` bigint(0) not null,
`level` varchar(1) character set utf8 collate utf8_general_ci not null,
primary key (`id`) using btree,
index `article_id`(`article_id`) using btree
) engine = innodb auto_increment = 1405209691876790275 character set = utf8 collate = utf8_general_ci row_format = dynamic;
3.7表七: ms_category类别表
drop table if exists `ms_category`;
create table `ms_category` (
`id` bigint(0) not null auto_increment,
`avatar` varchar(255) character set utf8mb4 collate utf8mb4_unicode_ci null default null,
`category_name` varchar(255) character set utf8mb4 collate utf8mb4_unicode_ci null default null,
`description` varchar(255) character set utf8mb4 collate utf8mb4_unicode_ci null default null,
primary key (`id`) using btree
) engine = innodb auto_increment = 6 character set = utf8 collate = utf8_general_ci row_format = dynamic;
4.首页功能
4.1文章列表实现
效果图
4.1.1pojo类
1.建立pojo类——article
package com.leggasai.dao.pojo;
import lombok.Data;
@Data
public class Article {
public static final int Article_TOP=1;//是否指定,默认是
public static final int Article_Common=0;//默认评论数0
private Long id;//文章id
private String title;//文章标题
private String summary;//文章简介
private Integer commentCounts;//文章评论数
private Integer viewCounts;//文章阅读数
private Long authorId;//作者id
private Long bodyId;//文章内容id
private Long categoryId;//文章类别id
private Integer weight=Article_Common;//文章权重
private Long createDate;//文章创建时间
}
2.建立pojo类——sysUser用户类
package com.leggasai.dao.pojo;
import lombok.Data;
@Data
public class SysUser {
private Long id;//用户id
private String account;//用户账号
private String password;//用户密码
private Integer admin;//是否管理员
private String avatar;//用户头像地址
private Long createDate;//用户创建时间
private Integer deleted;//是否被删除
private String email;//用户邮箱
private Long lastLogin;//用户最后一次登录时间
private String nickname;//用户昵称
private String mobilePhoneNumber;//用户手机号
private String salt;//加密盐
private String status;//用户状态
}
3.建立pojo类——tag标签类
package com.leggasai.dao.pojo;
import lombok.Data;
@Data
public class Tag {
private Long id;//标签id
private String avatar;//标签图片地址
private String tagName;//标签名
}
4.建立vo类——articleVo:前端显示类往往和数据库中的类有差别
import java.util.List;
@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;
}
4.1.2controller类
ArticleController类:用于处理和article相关业务
import java.util.List;
@RestController
@RequestMapping("articles")
public class ArticleController {
@Autowired
private ArticleService articleService;
//Result是统一结果返回
@PostMapping
public Result articles(@RequestBody PageParams pageParams) {
//ArticleVo 页面接收的数据
List<ArticleVo> articles = articleService.listArticlesPage(pageParams);
return Result.success(articles);
}
}
4.1.3service类
ArticleService接口与ArticleServiceImpl实现类
import java.util.List;
public interface ArticleService {
List<ArticleVo> listArticlesPage(PageParams pageParams);
}
package com.leggasai.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.leggasai.common.aop.LogAnnotation;
import com.leggasai.dao.dos.Archives;
import com.leggasai.dao.mapper.ArticleBodyMapper;
import com.leggasai.dao.mapper.ArticleMapper;
import com.leggasai.dao.mapper.ArticleTagMapper;
import com.leggasai.dao.pojo.Article;
import com.leggasai.dao.pojo.ArticleBody;
import com.leggasai.dao.pojo.ArticleTag;
import com.leggasai.dao.pojo.SysUser;
import com.leggasai.service.*;
import com.leggasai.utils.UserThreadLocal;
import com.leggasai.vo.ArticleBodyVo;
import com.leggasai.vo.ArticleVo;
import com.leggasai.vo.Result;
import com.leggasai.vo.TagVo;
import com.leggasai.vo.params.ArticleParam;
import com.leggasai.vo.params.PageParams;
import net.sf.jsqlparser.expression.DateTimeLiteralExpression;
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.HashMap;
import java.util.List;
import java.util.Map;
@Service
public class ArticleServiceImpl implements ArticleService {
@Autowired
private ArticleMapper articleMapper;
@Autowired
private SysUserService sysUserService;
@Autowired
private TagsService tagsService;
public ArticleVo copy(Article article,boolean isAuthor,boolean isBody,boolean isTags){
ArticleVo articleVo = new ArticleVo();
BeanUtils.copyProperties(article, articleVo);
if (isAuthor) {
SysUser sysUser = sysUserService.findSysUserById(article.getAuthorId());
articleVo.setAuthor(sysUser.getNickname());
}
articleVo.setCreateDate(new DateTime(article.getCreateDate()).toString("yyyy-MM-dd HH:mm"));
if (isTags){
List<TagVo> tags = tagsService.findTagsByArticleId(article.getId());
articleVo.setTags(tags);
}
return articleVo;
}
private List<ArticleVo> copyList(List<Article> records,boolean isAuthor,boolean isBody,boolean isTags) {
List<ArticleVo> articleVoList = new ArrayList<>();
for (Article article : records) {
ArticleVo articleVo = copy(article,isAuthor,isBody,isTags);
articleVoList.add(articleVo);
}
return articleVoList;
}
@Override
public List<ArticleVo> listArticlesPage(PageParams pageParams) {
QueryWrapper<Article> queryWrapper = new QueryWrapper<>();
Page<Article> page = new Page<>(pageParams.getPage(),pageParams.getPageSize());
Page<Article> articlePage = articleMapper.selectPage(page, queryWrapper);
List<ArticleVo> articleVoList = copyList(articlePage.getRecords(),true,false,true);
return articleVoList;
}
}
sysUserService和sysUserServiceImpl
public interface UserService {
SysUser findUserById(Long userId);
}
package com.leggasai.service.impl;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.leggasai.dao.mapper.SysUserMapper;
import com.leggasai.dao.pojo.SysUser;
import com.leggasai.service.LoginService;
import com.leggasai.service.SysUserService;
import com.leggasai.vo.ErrorCode;
import com.leggasai.vo.LoginUserVo;
import com.leggasai.vo.Result;
import com.leggasai.vo.UserVo;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
@Service
public class UserServiceImpl implements UserService {
@Autowired
private SysUserMapper sysUserMapper;
@Override
public SysUser findUserById(Long userId) {
SysUser sysUser = sysUserMapper.selectById(userId);
if (sysUser == null) {
sysUser = new SysUser();
sysUser.setNickname("码神之路");
}
return sysUser;
}
}
tagService和tagServiceImpl
package com.leggasai.service;
import com.leggasai.vo.Result;
import com.leggasai.vo.TagVo;
import java.util.List;
public interface TagService {
List<TagVo> findTagsByArticleId(Long articleId);
}
package com.leggasai.service.impl;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.leggasai.dao.mapper.TagMapper;
import com.leggasai.dao.pojo.Tag;
import com.leggasai.service.TagService;
import com.leggasai.vo.Result;
import com.leggasai.vo.TagVo;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import java.lang.reflect.Array;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
@Service
public class TagServiceImpl implements TagService {
@Autowired
private TagMapper tagMapper;
@Override
public List<TagVo> findTagsByArticleId(Long articleId) {
//mybatis-plus无法进行多表查询
List<Tag> tags=tagMapper.findTagsByArticleId(articleId);
return copyList(tags);
}
public TagVo copy(Tag tag){
TagVo tagVo=new TagVo();
BeanUtils.copyProperties(tag,tagVo);
tagVo.setId(String.valueOf(tag.getId()));
return tagVo;
}
public List<TagVo> copyList(List<Tag> tagList){
List<TagVo> tagVoList = new ArrayList<>();
for (Tag tag : tagList) {
tagVoList.add(copy(tag));
}
return tagVoList;
}
}
4.1.4dao层
ArticleMapper接口
package com.leggasai.dao.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.leggasai.dao.dos.Archives;
import com.leggasai.dao.pojo.Article;
import org.apache.ibatis.annotations.Mapper;
import org.springframework.stereotype.Repository;
import java.util.List;
@Mapper
public interface ArticleMapper extends BaseMapper<Article> {
List<Archives> listArchives();
IPage<Article> listArticle(Page<Article> page,
Long categoryId,
Long tagId,
String year,
String month);
}
SysUserMapper接口
package com.leggasai.dao.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.leggasai.dao.pojo.SysUser;
import org.apache.ibatis.annotations.Mapper;
import org.springframework.stereotype.Repository;
@Mapper
public interface SysUserMapper extends BaseMapper<SysUser> {
}
TagMapper接口
package com.leggasai.dao.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.leggasai.dao.pojo.Tag;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import org.springframework.stereotype.Repository;
import java.util.List;
@Mapper
public interface TagMapper extends BaseMapper<Tag> {
/*
根据文章id查询标签列表
*/
List<Tag> findTagsByArticleId(Long articleId);
}
TagMapper.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!--中文错误改成UTF8即可-->
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.leggasai.dao.mapper.TagMapper">
<!-- List<Tag> findTagsByArticleId(Long articleId);-->
<select id="findTagsByArticleId" parameterType="long" resultType="com.leggasai.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>
4.2首页最热标签功能
4.2.1前端接口
接口url:/tags/hot
请求方式:GET
请求参数:无
返回数据:
{ "success": true, "code": 200, "msg": "success", "data": [ { "id":1, "tagName":"4444" } ] }
4.2.2controller类
@GetMapping("/hot")
public Result hot(){
int limit =6;
Result hots = tagService.hots(limit);
return hots;
}
4.2.3service层
Result hots(int limit);
@Override
public Result hots(int limit) {
/*
标签所拥有的文章数量做多,就是最热标签
*/
List<Long> tagIds=tagMapper.findHotsTagIds(limit);
if(CollectionUtils.isEmpty(tagIds)){
return Result.success(Collections.emptyList());
}
//需要的是tagId和tagName
List<Tag> tagList=tagMapper.findTagesByTagIds(tagIds);
//System.out.println("最热标签");
//System.out.println(tagList);
return Result.success(tagList);
}
4.2.4mapper层
<select id="findHotsTagIds" 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="findTagesByTagIds" parameterType="list" resultType="com.leggasai.dao.pojo.Tag">
select id,tag_name as tagName from ms_tag
where id in
<foreach collection="tagIds" item="tagId" separator="," open="(" close=")">
#{tagId}
</foreach>
</select>
4.3首页最热文章功能
后续可以用cache优化
4.3.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相关",
}
]
}
4.3.2controller层
@PostMapping("/hot")
public Result hotArticle(){
int limit =5;
return articleService.hotArticle(limit);
}
4.3.3service层
@Override
public Result hotArticle(int limit) {
LambdaQueryWrapper<Article> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.orderByDesc(Article::getViewCounts);
queryWrapper.select(Article::getId,Article::getTitle);
queryWrapper.last("limit "+limit);
//select id,title from article order by view_counts desc limit 5
List<Article> articles = articleMapper.selectList(queryWrapper);
return Result.success(copyList(articles,false,false));
}
4.4首页最新文章功能
后续可以用cache优化
4.4.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相关", } ] }
4.4.2controller层
@PostMapping("/new")
public Result newArticles(){
int limit =5;
return articleService.newArticles(limit);
}
4.4.3service层
@Override
public Result newArticles(int limit) {
LambdaQueryWrapper<Article> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.orderByDesc(Article::getCreateDate);
queryWrapper.select(Article::getId,Article::getTitle);
queryWrapper.last("limit "+limit);
//select id,title from article order by create_date desc limit 5
List<Article> articles = articleMapper.selectList(queryWrapper);
return Result.success(copyList(articles,false,false));
}
4.5首页文章归档功能
4.5.1前端接口
接口url:/articles/listArchives
请求方式:POST
请求参数:
返回数据:
{ "success": true, "code": 200, "msg": "success", "data": [ { "year": "2021", "month": "6", "count": 2 } ]
}
4.5.2controller层
@PostMapping("listArchives")
public Result listArchives(){
return articleService.listArchives();
}
4.5.3service层
@Override
public Result listArchives() {
List<Archives> archivesList=articleMapper.listArchives();
return Result.success(archivesList);
}
4.5.4mapper层
List<Archives> listArchives();
注意数据库中create_date是时间戳,需要使用FROM_UNIXTIME转化为xxxx年xx月的格式!
<select id="listArchives" resultType="com.leggasai.dao.dos.Archives">
select FROM_UNIXTIME(create_date/1000,'%Y') as year,FROM_UNIXTIME(create_date/1000,'%m') as month,COUNT(*) as COUNT
from ms_article group by year,month
</select>
Archives类
package com.leggasai.dao.dos;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Archives {
private Integer year;
private Integer month;
private Long count;
}
5.登录功能
5.1jwt技术
5.2退出功能
5.3注册功能
5.4登录拦截器
5.5ThreadLocal使用
未完待续~