隐藏页面特效

个人博客项目笔记_08

bug修正

文章归档:

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

1. 文章图片上传

1.1 接口说明

接口url:/upload

请求方式:POST

请求参数:

参数名称 参数类型 说明
image file 上传的文件名称

返回数据:

{ "success":true, "code":200, "msg":"success", "data":"https://static.cherr.com/aa.png" }
<dependency> <groupId>com.qiniu</groupId> <artifactId>qiniu-java-sdk</artifactId> <version>[7.13.0, 7.13.99]</version> </dependency>

1.2 Controller

String fileName = UUID.randomUUID().toString() + "." + StringUtils.substringAfterLast(originalFilename, ".");

这行代码的作用是生成一个唯一的文件名,用于保存上传的文件。

  1. UUID.randomUUID().toString(): 这个方法调用生成一个随机的 UUID(Universally Unique Identifier),并将其转换为字符串形式。UUID 是一种用于唯一标识信息的标准化方法,通常由 32 个十六进制数字组成,例如:"550e8400-e29b-41d4-a716-446655440000"。使用 toString() 方法将其转换为字符串。
  2. "." + StringUtils.substringAfterLast(originalFilename, "."): 这部分代码是获取上传文件的扩展名,并将其与随机生成的 UUID 字符串拼接起来。StringUtils.substringAfterLast(originalFilename, ".") 方法从原始文件名中获取最后一个点 (.) 后面的字符串,即文件的扩展名。然后再在扩展名前面添加一个点,用于连接随机生成的 UUID。

通过这两个步骤,就可以生成一个形如 "random_uuid.png" 的唯一文件名,其这样可以确保每个上传的文件都有一个唯一的文件名,避免文件名冲突。

package com.cherriesovo.blog.controller; import com.cherriesovo.blog.utils.QiniuUtils; import com.cherriesovo.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){ //原始文件名称 比如:1.png String originalFilename = file.getOriginalFilename(); //唯一的文件名称 String fileName = UUID.randomUUID().toString() + "." + StringUtils.substringAfterLast(originalFilename, "."); //上传文件到哪里?七牛云 云服务器按量付费,速度快,把图片发到离用户最近的服务器 //降低我们自身应用服务器的带宽消耗 boolean upload = qiniuUtils.upload(file, fileName); if (upload){ //QiniuUtils.url 是一个用于存储七牛云存储的 URL 地址的变量 return Result.success(QiniuUtils.url + fileName); } return Result.fail(20001,"上传失败"); } }

1.3 使用七牛云

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

需要自行修改的配置:

//七牛云url或者自己的url(这里使用七牛云的url) public static final String url = "http://sbf25hzn6.hb-bkt.clouddn.com/"; //AK @Value("") private String accessKey; //SK @Value("") private String accessSecretKey; //对象空间名称 String bucket = "cherriesovo-blog";
package com.cherriesovo.blog.utils; import com.alibaba.fastjson.JSON; 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 { //七牛云url或者自己的url public static final String url = "http://sbf25hzn6.hb-bkt.clouddn.com/"; //AK @Value("") private String accessKey; //SK @Value("") private String accessSecretKey; //将文件上传到七牛云存储中 //MultipartFile 是 Spring Framework 提供的一个接口,用于表示 HTTP 请求中的文件。在这段代码中,MultipartFile 类型的参数 file 用于接收客户端上传的文件。 public boolean upload(MultipartFile file,String fileName){ //创建一个配置类对象 cfg,并指定了上传的区域为华北 Configuration cfg = new Configuration(Region.huabei()); //创建一个上传管理器对象 uploadManager,用于执行文件上传操作 UploadManager uploadManager = new UploadManager(cfg); //...生成上传凭证,然后准备上传,(对象空间名称) String bucket = "cherriesovo-blog"; //默认不指定key的情况下,以文件内容的hash值作为文件名 try { byte[] uploadBytes = file.getBytes();//使用 MultipartFile 对象的 getBytes() 方法获取上传文件的字节数组 Auth auth = Auth.create(accessKey, accessSecretKey);//创建一个认证对象 String upToken = auth.uploadToken(bucket);//用认证对象的 uploadToken 方法生成上传凭证 upToken Response response = uploadManager.put(uploadBytes, fileName, upToken);//执行文件上传 //解析上传成功的结果,将上传结果的 JSON 字符串解析为 DefaultPutRet 类对象 putRet DefaultPutRet putRet = JSON.parseObject(response.bodyString(), DefaultPutRet.class); return true; //返回 true 表示上传成功 } catch (Exception ex) { ex.printStackTrace(); } return false; } }

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": "好多语言,该学哪个?" } ] }
package com.cherriesovo.blog.vo; import lombok.Data; @Data public class CategoryVo { private Long id; private String avatar; private String categoryName; private String description; }

2.1.2 Controller

@RestController @RequestMapping("categorys") public class CategoryController { @GetMapping("detail") public Result categoriesDetail(){ return categoryService.findAllDetail(); } }

2.1.3 Service

CategoryService:

Result findAllDetail();

CategoryServiceImpl:

@Override public Result findAll() { LambdaQueryWrapper<Category> queryWrapper = new LambdaQueryWrapper<>(); queryWrapper.select(Category::getId,Category::getCategoryName); //SELECT id, category_name FROM category; List<Category> categories = categoryMapper.selectList(queryWrapper); return Result.success(copyList(categories)); } @Override public Result findAllDetail() { //SELECT * FROM category; 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": "11", "avatar": "/static/tag/css.png" } ] }

2.2.3 Controller

package com.cherriesovo.blog.vo; import lombok.Data; @Data public class TagVo { private Long id; private String tagName; private String avatar; }
@RestController @RequestMapping("tags") public class TagsController { @GetMapping("detail") public Result findAllDetail(){ return tagsService.findAllDetail(); } }

2.2.4 Service

TagsService:

Result findAllDetail();//查询所有的标签

TagsServiceImpl:

@Override public Result findAll() { LambdaQueryWrapper<Tag> queryWrapper = new LambdaQueryWrapper<>(); queryWrapper.select(Tag::getId,Tag::getTagName); List<Tag> tags = this.tagMapper.selectList(queryWrapper); return Result.success(copyList(tags)); } @Override public Result findAllDetail() { LambdaQueryWrapper<Tag> queryWrapper = new LambdaQueryWrapper<>(); //select * from tag 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": "前端是什么,大前端" } }

3.2 Controller

CategoryController:

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

3.3 Service

CategoryService:

Result categoriesDetailById(Long id);

CategoryServiceImpl:

@Override public Result categoriesDetailById(Long id) { Category category = categoryMapper.selectById(id); CategoryVo categoryVo = copy(category); return Result.success(categoryVo); }

ArticleServiceImpl:

新增如下代码:

​ //查询文章的参数 加上分类id,判断不为空 加上分类条件
​ if (pageParams.getCategoryId() != null) {
​ queryWrapper.eq(Article::getCategoryId,pageParams.getCategoryId());
​ }

@Override public List<ArticleVo> listArticlesPage(PageParams pageParams) { // 分页查询article数据库表 Page<Article> page = new Page<>(pageParams.getPage(),pageParams.getPageSize()); LambdaQueryWrapper<Article> queryWrapper = new LambdaQueryWrapper<>(); //查询文章的参数 加上分类id,判断不为空 加上分类条件,SELECT * FROM article WHERE category_id = ? if (pageParams.getCategoryId() != null) { queryWrapper.eq(Article::getCategoryId,pageParams.getCategoryId()); } //是否置顶排序,SELECT * FROM article ORDER BY weight DESC, create_date DESC queryWrapper.orderByDesc(Article::getWeight,Article::getCreateDate); //SELECT * FROM article WHERE category_id = ? ORDER BY weight DESC, create_date DESC Page<Article> articlePage = articleMapper.selectPage(page,queryWrapper); List<Article> records = articlePage.getRecords(); List<ArticleVo> articleVoList = copyList(records,true,false,true); return articleVoList; }
package com.cherriesovo.blog.vo.params; import lombok.Data; @Data public class PageParams { private int page = 1; private int pageSize = 10; private Long categoryId; private Long tagId; }

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

TagsController:

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

4.3 Service

TagService:

Result findDetailById(Long id);

TagServiceImpl:

@Override public Result findDetailById(Long id) { //select * from tag where id = ? Tag tag = tagMapper.selectById(id); TagVo copy = copy(tag); return Result.success(copy); }

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

ArticleServiceImpl:

新增如下代码:

核心逻辑:

  1. 创建一个列表articleIdList用于存放某个标签对应的文章id;
  2. 通过tag_id在article_tag表中查询所有数据;
  3. 通过循环遍历操作将第二步查出来的数据中的article_id存放到articleIdList列表;
  4. SELECT *FROM article WHERE id IN articleIdList
List<Long> articleIdList = new ArrayList<>(); //用于存储文章ID if (pageParams.getTagId() != null){ /* * 加入标签条件查询 * article表中没有tag字段 一篇文章有多个标签 * article_tag表中 article_id与tag_id是一对多的关系 * */ LambdaQueryWrapper<ArticleTag> articleTagLambdaQueryWrapper = new LambdaQueryWrapper<>(); articleTagLambdaQueryWrapper.eq(ArticleTag::getTagId,pageParams.getTagId()); //SELECT * FROM article_tag WHERE tag_id = ? List<ArticleTag> articleTags = articleTagMapper.selectList(articleTagLambdaQueryWrapper); for (ArticleTag articleTag : articleTags) { articleIdList.add(articleTag.getArticleId()); } if (articleIdList.size() > 0){ //SELECT *FROM article WHERE id IN (articleId1, articleId2, articleId3, ...) queryWrapper.in(Article::getId,articleIdList); } }
@Override public List<ArticleVo> listArticlesPage(PageParams pageParams) { // 分页查询article数据库表 Page<Article> page = new Page<>(pageParams.getPage(),pageParams.getPageSize()); 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字段 一篇文章有多个标签 * article_tag表中 article_id与tag_id是一对多的关系 * */ LambdaQueryWrapper<ArticleTag> articleTagLambdaQueryWrapper = new LambdaQueryWrapper<>(); articleTagLambdaQueryWrapper.eq(ArticleTag::getTagId,pageParams.getTagId()); List<ArticleTag> articleTags = articleTagMapper.selectList(articleTagLambdaQueryWrapper); for (ArticleTag articleTag : articleTags) { articleIdList.add(articleTag.getArticleId()); } if (articleIdList.size() > 0){ queryWrapper.in(Article::getId,articleIdList); } } //是否置顶排序 queryWrapper.orderByDesc(Article::getWeight,Article::getCreateDate); Page<Article> articlePage = articleMapper.selectPage(page,queryWrapper); List<Article> records = articlePage.getRecords(); List<ArticleVo> articleVoList = copyList(records,true,false,true); return articleVoList; }

4.5 测试

posted @   CherriesOvO  阅读(28)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 【.NET】调用本地 Deepseek 模型
· CSnakes vs Python.NET:高效嵌入与灵活互通的跨语言方案对比
· Plotly.NET 一个为 .NET 打造的强大开源交互式图表库
· DeepSeek “源神”启动!「GitHub 热点速览」
· 上周热点回顾(2.17-2.23)
历史上的今天:
2022-04-12 操作系统学习笔记_05
2021-04-12 全国疫情数据可视化展示(详细介绍,含完整源码)
点击右上角即可分享
微信分享提示