SpringBoot+Vue博客前后端分离项目 六 图片上传(七牛云)+分类 后端(springboot + mybatisplus+redis+mysql+jwt+缓存)

目录

1. 文章图片上传

1.1 接口说明

1.2 Controller

1.3 使用七牛云

1.4 测试

2. 导航-文章分类

2.1 查询所有的文章分类

2.1.1 接口说明

2.1.2 Controller

2.1.3 Service

2.2 查询所有的标签

2.2.1 接口说明

2.2.3 Controller

2.2.4 Service

测试

3. 分类文章列表

3.1 接口说明

3.2 Controller

3.3 Service

测试

4. 标签文章列表

4.1 接口说明

4.2 Controller

4.3 Service

4.4 修改原有的查询文章接口

4.5 测试

5. 归档文章列表

5.1 接口说明

5.2 文章列表参数

5.3 使用自定义sql 实现文章列表

5.4 测试


 

1. 文章图片上传

1.1 接口说明

接口url:/upload

请求方式:POST

请求参数:

参数名称

参数类型

说明

image

file

上传的文件名称

返回数据:

{
    "success": true,
    "code": 200,
    "msg": "success",
    "data": "http://rzeu8sn8o.hn-bkt.clouddn.com//d4d2e0f3-aeda-4104-8ba3-5a116bce506f.png"
}

文件上传到七牛云 导入依赖

<dependency>
  <groupId>com.qiniu</groupId>
  <artifactId>qiniu-java-sdk</artifactId>
  <version>[7.7.0, 7.7.99]</version>
</dependency>

1.2 Controller

package com.pjp.blog.controller;

import com.pjp.blog.utils.QiniuUtils;
import com.pjp.blog.vo.Result;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;

import java.util.UUID;

@RestController
@RequestMapping("upload")
public class UploadController {
    @Autowired
    private QiniuUtils qiniuUtils;

    @PostMapping
    public Result upload(@RequestParam("image") MultipartFile file) {
        //原始文件名称 比如 aa.png
        String originalFilename = file.getOriginalFilename();
        //唯一的文件名称
        String fileName = UUID.randomUUID().toString() + "." + StringUtils.substringAfterLast(originalFilename, ".");
        //文件上传到七牛云 云服务器 按量付费 速度快 把图片发放到离用户最近的服务器上
        //降低我们自身应用服务器的带宽消耗
        boolean upload = qiniuUtils.upload(file, fileName);
        if (upload) {
            return Result.success(qiniuUtils.url + "/"+fileName);
        }
        return Result.fail(20001, "上传失败");
    }
}

配置上传文件参数

#上传文件总的最大值
spring.servlet.multipart.max-request-size=20MB
#单个文件的最大值
spring.servlet.multipart.max-file-size=5MB

1.3 使用七牛云

用户访问图片资源时,图片一般占用的带宽比较大,如果很多人同时访问图片资源,就可能会造成应用服务器网络拥堵,解决办法是使用专门的图片云服务器(我们这里采用免费的七牛云) ,用户去图片服务器访问图片资源,降低应用服务器的带宽压力。

工具类

package com.pjp.blog.utils;

import com.alibaba.fastjson.JSON;
import com.qiniu.common.Zone;
import com.qiniu.http.Response;
import com.qiniu.storage.Configuration;
import com.qiniu.storage.Region;
import com.qiniu.storage.UploadManager;
import com.qiniu.storage.model.DefaultPutRet;
import com.qiniu.util.Auth;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;

@Component
public class QiniuUtils {
    public static final String url = "http://rzeu8sn8o.hn-bkt.clouddn.com/";

    @Value("${qiniu.accessKey}")
    private String accessKey;
    @Value("${qiniu.accessSecretKey}")
    private String accessSecretKey;

    public boolean upload(MultipartFile file, String fileName) {

        //构造一个带指定 Region 对象的配置类
        Configuration cfg = new Configuration(Zone.zone2());
        //...其他参数参考类注释
        UploadManager uploadManager = new UploadManager(cfg);
        //...生成上传凭证,然后准备上传
        String bucket = "pjpblog";
        //默认不指定key的情况下,以文件内容的hash值作为文件名
        try {
            byte[] uploadBytes = file.getBytes();
            Auth auth = Auth.create(accessKey, accessSecretKey);
            String upToken = auth.uploadToken(bucket);
            Response response = uploadManager.put(uploadBytes, fileName, upToken);
            //解析上传成功的结果
            DefaultPutRet putRet = JSON.parseObject(response.bodyString(), DefaultPutRet.class);
            return true;
        } catch (Exception ex) {
            ex.printStackTrace();
        }
        return false;
    }
}

配置自己七牛云的密钥

qiniu.accessKey=
qiniu.accessSecretKey=

1.4 测试

2. 导航-文章分类

2.1 查询所有的文章分类

2.1.1 接口说明

接口url:/categorys/detail

请求方式:GET

请求参数:

返回数据:

{
    "success": true, 
    "code": 200, 
    "msg": "success", 
    "data": [
        {
            "id": 1, 
            "avatar": "/static/category/front.png", 
            "categoryName": "前端", 
            "description": "前端是什么,大前端"
        }, 
        {
            "id": 2, 
            "avatar": "/static/category/back.png", 
            "categoryName": "后端", 
            "description": "后端最牛叉"
        }, 
        {
            "id": 3, 
            "avatar": "/static/category/lift.jpg", 
            "categoryName": "生活", 
            "description": "生活趣事"
        }, 
        {
            "id": 4, 
            "avatar": "/static/category/database.png", 
            "categoryName": "数据库", 
            "description": "没数据库,啥也不管用"
        }, 
        {
            "id": 5, 
            "avatar": "/static/category/language.png", 
            "categoryName": "编程语言", 
            "description": "好多语言,该学哪个?"
        }
    ]
}
@Data
public class CategoryVo {

    private Long id;

    private String avatar;

    private String categoryName;

    private String description;
}
2.1.2 Controller
package com.pjp.blog.controller;

import com.pjp.blog.service.CategoryService;
import com.pjp.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("categorys")
public class CategoryController {

    @GetMapping("detail")
    public Result categoriesDetail(){
        return categoryService.findAllDetail();
    }
}

2.1.3 Service
/**
 * 查询所有分类及详细信息
 * @return
 */
Result findAllDetail();

 @Override
    public Result findAllDetail() {
        List<Category> categories = categoryMapper.selectList(new LambdaQueryWrapper<>());
        return Result.success(copyList(categories));
    }

2.2 查询所有的标签

2.2.1 接口说明

接口url:/tags/detail

请求方式:GET

请求参数:

参数名称

参数类型

说明

返回数据:

{
    "success": true,
    "code": 200,
    "msg": "success",
    "data": [
        {
            "id": 5,
            "tagName": "springboot",
            "avatar": "/static/tag/java.png"
        },
        {
            "id": 6,
            "tagName": "spring",
            "avatar": "/static/tag/java.png"
        },
        {
            "id": 7,
            "tagName": "springmvc",
            "avatar": "/static/tag/java.png"
        },
        {
            "id": 8,
            "tagName": "css",
            "avatar": "/static/tag/css.png"
        }
    ]
}
@Data
public class TagVo {

    private Long id;

    private String tagName;

    private String avatar;
}
2.2.3 Controller
@GetMapping("detail")
    public Result findAllDetail(){
        return tagService.findAllDetail();
    }
2.2.4 Service
/**
 * 所有标签及详细信息
 *
 * @return
 */
Result findAllDetail();

 @Override
    public Result findAllDetail() {
        LambdaQueryWrapper<Tag> queryWrapper = new LambdaQueryWrapper<>();
        List<Tag> tags = this.tagMapper.selectList(queryWrapper);
        return Result.success(copyList(tags));
    }
测试

3. 分类文章列表

3.1 接口说明

接口url:/category/detail/{id}

请求方式:GET

请求参数:

参数名称

参数类型

说明

id

分类id

路径参数

返回数据:

{
    "success": true, 
    "code": 200, 
    "msg": "success", 
    "data": 
        {
            "id": 1, 
            "avatar": "/static/category/front.png", 
            "categoryName": "前端", 
            "description": "前端是什么,大前端"
        }
}
@Data
public class PageParams {

    private int page = 1;

    private int pageSize = 10;

    private Long categoryId;

    private Long tagId;
}

3.2 Controller

@GetMapping("detail/{id}")
    public Result categoriesDetailById(@PathVariable("id") Long id){
        return categoryService.categoriesDetailById(id);
    }

3.3 Service

CategoryService

/**
 * 根据id查询具体分类信息
 *
 * @param id
 * @return
 */
Result categoriesDetailById(long id);
@Override
public Result categoriesDetailById(long id) {
Category category = categoryMapper.selectById(id);
return Result.success(copy(category));
}

ArticleServiceImpl

@Override
public Result listArticle(PageParams pageParams) {
Page<Article> page = new Page<>(pageParams.getPage(), pageParams.getPageSize());
//        LambdaQueryWrapper可以使用lambda表达式构建SQL查询语句
LambdaQueryWrapper<Article> queryWrapper = new LambdaQueryWrapper<>();
//查询文章的参数 加上分类id,判断不为空 加上分类条件
if (pageParams.getCategoryId() != null) {
    queryWrapper.eq(Article::getCategoryId, pageParams.getCategoryId());
}
//        按时间进行排序
//        queryWrapper.orderByDesc(“属性”)——根据属性降序排序
//        queryWrapper.orderByDesc(Article::getCreateDate);
//        是否置顶排序
//        queryWrapper.orderByDesc(Article::getWeight);
queryWrapper.orderByDesc(Article::getWeight, Article::getCreateDate);
Page<Article> articlePage = articleMapper.selectPage(page, queryWrapper);
//        getRecords();查询到的数据
List<Article> records = articlePage.getRecords();
//      数据不能直接返回,和前端进行数据交互
List<ArticleVo> articleVoList = copyList(records, true, true);
return Result.success(articleVoList);
}

测试

4. 标签文章列表

4.1 接口说明

接口url:/tags/detail/{id}

请求方式:GET

请求参数:

参数名称

参数类型

说明

id

标签id

路径参数

返回数据:

{
    "success": true, 
    "code": 200, 
    "msg": "success", 
    "data": 
        {
            "id": 5, 
            "tagName": "springboot", 
            "avatar": "/static/tag/java.png"
        }
}

4.2 Controller

@RestController
@RequestMapping("tags")
public class TagsController {
    @Autowired
    private TagService tagService;

    @GetMapping("detail/{id}")
    public Result findDetailById(@PathVariable("id") Long id) {
        return tagService.findDetailById(id);
    }
}

4.3 Service

/**
 * 根据id查询标签详细信息
 *
 * @param id
 * @return
 */
Result findDetailById(Long id);

  @Override
    public Result findDetailById(Long id) {
        Tag tag = this.tagMapper.selectById(id);
        return Result.success(tag);
    }

4.4 修改原有的查询文章接口

@Override
public Result listArticle(PageParams pageParams) {
Page<Article> page = new Page<>(pageParams.getPage(), pageParams.getPageSize());
//        LambdaQueryWrapper可以使用lambda表达式构建SQL查询语句
LambdaQueryWrapper<Article> queryWrapper = new LambdaQueryWrapper<>();
//查询文章的参数 加上分类id,判断不为空 加上分类条件
if (pageParams.getCategoryId() != null) {
    queryWrapper.eq(Article::getCategoryId, pageParams.getCategoryId());
}
List<Long> articleIdList = new ArrayList<>();
if (pageParams.getTagId() != null) {
    //加入标签 条件查询
    //article表中 并没有tag字段 去articleTag表中查 一篇文章有多个标签
    LambdaQueryWrapper<ArticleTag> lambdaQueryWrapper = new LambdaQueryWrapper<>();
    lambdaQueryWrapper.eq(ArticleTag::getTagId, pageParams.getTagId());
    List<ArticleTag> articleTags = articleTagMapper.selectList(lambdaQueryWrapper);
    for (ArticleTag articleTag : articleTags) {
        articleIdList.add(articleTag.getArticleId());
    }
    if (articleIdList.size() > 0) {
        // and id in(1,2,3)
        queryWrapper.in(Article::getId,articleIdList);
    }
}
//        按时间进行排序
//        queryWrapper.orderByDesc(“属性”)——根据属性降序排序
//        queryWrapper.orderByDesc(Article::getCreateDate);
//        是否置顶排序
//        queryWrapper.orderByDesc(Article::getWeight);
queryWrapper.orderByDesc(Article::getWeight, Article::getCreateDate);
Page<Article> articlePage = articleMapper.selectPage(page, queryWrapper);
//        getRecords();查询到的数据
List<Article> records = articlePage.getRecords();
//      数据不能直接返回,和前端进行数据交互
List<ArticleVo> articleVoList = copyList(records, true, true);
return Result.success(articleVoList);
}

4.5 测试

5. 归档文章列表

5.1 接口说明

接口url:/articles

请求方式:POST

请求参数:

参数名称

参数类型

说明

year

string

month

string

返回数据:

{
    "success": true, 
    "code": 200, 
    "msg": "success", 
    "data": [文章列表,数据同之前的文章列表接口]
        
}

5.2 文章列表参数

在之前的PageParams加上属性 year ,month 并重写getMonth方法

@Data
public class PageParams {

    private int page = 1;

    private int pageSize = 10;

    private Long categoryId;

    private Long tagId;

    private String year;

    private String month;

    public String getMonth(){
        if (this.month != null && this.month.length() == 1){
            return "0"+this.month;
        }
        return this.month;
    }
}

5.3 使用自定义sql 实现文章列表

@Override
public Result listArticle(PageParams pageParams) {
Page<Article> page = new Page<>(pageParams.getPage(), pageParams.getPageSize());
IPage<Article> articleIPage = this.articleMapper.listArticle(page,
                                                             pageParams.getCategoryId(),
                                                             pageParams.getTagId(),
                                                             pageParams.getYear(),
                                                             pageParams.getMonth());
//getRecords();是用来获取当前页的数据,即查询的记录
return Result.success(copyList(articleIPage.getRecords(), true, true, true, true));
}

ArticleMapper

public interface ArticleMapper extends BaseMapper<Article> {
    /**
     * 文章归档
     * @return
     */
    List<Archives> listArchives();

    IPage<Article> listArticle(Page<Article> page,
                               Long categoryId,
                               Long tagId,
                               String year,
                               String month);
}

ArticleMapper.xml

<resultMap id="articleMap" type="com.pjp.blog.dao.pojo.Article">
  <id column="id" property="id"/>
  <result column="author_id" property="authorId"/>
  <result column="comment_counts" property="commentCounts"/>
  <result column="create_date" property="createDate"/>
  <result column="summary" property="summary"/>
  <result column="title" property="title"/>
  <result column="view_counts" property="viewCounts"/>
  <result column="weight" property="weight"/>
  <result column="body_id" property="bodyId"/>
  <result column="category_id" property="categoryId"/>
</resultMap>
<!-- IPage<Article> listArticle(Page<Article> page,
Long categoryId,
Long tagId,
String year,
String month);-->
<select id="listArticle" resultMap="articleMap">
  select * from ms_article
  <where>
    1 = 1
    <!--test元素的作用是判断所指定的表达式是否成立,如果成立,则执行下面的SQL语句。-->
    <if test="categoryId != null">
      and category_id=#{categoryId}
    </if>
    <if test="tagId != null">
      and id in (select article_id from ms_article_tag where tag_id=#{tagId})
    </if>
    <if test="year != null and year.length>0 and month != null and month.length>0">
      and (FROM_UNIXTIME(create_date/1000,'%Y') =#{year} and FROM_UNIXTIME(create_date/1000,'%m')=#{month})
    </if>
  </where>
  order by weight,create_date desc
</select>

5.4 测试

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

PJP__00

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值