当前位置: 首页 > news >正文

个人博客项目_09

1. 归档文章列表

1.1 接口说明

接口url:/articles

请求方式:POST

请求参数:

参数名称参数类型说明
yearstring
monthstring

返回数据:

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

1.2 文章列表参数

新增参数:

​ private String year;

​ private String month;

月份特殊处理:6月——>06月

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

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;private String year;private String month;public String getMonth(){if (this.month != null && this.month.length() == 1){return "0"+this.month;}return this.month;}
}

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

ArticleMapper:

listArticle():根据给定的条件查询文章,并且支持分页功能:

  • page: 这是一个分页对象,用于指定查询的页码和每页显示的数据量。
  • categoryId: 要查询的文章所属的分类 ID。
  • tagId: 要查询的文章关联的标签 ID。
  • year: 要查询的文章的发布年份。
  • month: 要查询的文章的发布月份。

这个方法会返回一个分页后的文章列表。

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

**ArticleServiceImpl:**重写方法listArticlesPage()

IPage<Article> 是 MyBatis-Plus 框架中用于分页查询结果的接口。它表示了一个分页后的文章列表,包括了查询结果的分页信息和实际的文章数据列表。

在这个接口中,可以通过以下方法获取分页信息和文章列表:

  • getRecords(): 获取当前页的文章列表。
  • getTotal(): 获取符合查询条件的总文章数。
  • getCurrent(): 获取当前页码。
  • getPages(): 获取总页数。
  • getSize(): 获取当前页的文章数量。
  • hasNext(): 是否有下一页。
  • hasPrevious(): 是否有上一页。
  @Overridepublic List<ArticleVo> listArticlesPage(PageParams pageParams) {//创建了一个用于分页查询的 Page 对象Page<Article> page = new Page<>(pageParams.getPage(),pageParams.getPageSize());IPage<Article> articleIPage = this.articleMapper.listArticle(//调用 listArticle 方法来查询文章page,pageParams.getCategoryId(),pageParams.getTagId(),pageParams.getYear(),pageParams.getMonth());List<Article> records = articleIPage.getRecords();List<ArticleVo> articleVoList = copyList(records,true,false,true);return articleVoList;}

ArticleMapper.xml:

	<resultMap id="articleMap" type="com.cherriesovo.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><select id="listArticle"  resultMap="articleMap">select * from ms_article<where>1 = 1<if test="categoryId != null">and  category_id = #{categoryId}</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><if test="tagId != null">and id in (select article_id from ms_article_tag where tag_id=#{tagId})</if></where>order by weight desc,create_date desc</select>

1.4 测试

2. 统一缓存处理(优化)

内存的访问速度 远远大于 磁盘的访问速度 (1000倍起)

使用AOP开始优化

切点:

package com.cherriesovo.blog.common.cache;import java.lang.annotation.*;@Target({ElementType.METHOD})	//表明这个 Cache 注解只能用于方法上
@Retention(RetentionPolicy.RUNTIME)	//表示 Cache 注解的生命周期为运行时
@Documented	//Cache 注解应该被 javadoc 工具记录
public @interface Cache {long expire() default 1 * 60 * 1000;    //缓存的过期时间,单位为毫秒,默认值为 1 分钟String name() default "";       //缓存标识,用于区分不同的缓存数据。默认为空字符串}

Method method = pjp.getSignature().getDeclaringType().getMethod(methodName, parameterTypes);

通过反射获取切点方法对应的 Method 对象。

  • pjp.getSignature().getDeclaringType(): 首先通过 pjp.getSignature() 获取切点方法的签名信息,然后调用 getDeclaringType() 方法获取声明该方法的类的 Class 对象。
  • getMethod(methodName, parameterTypes): 在获取到声明该方法的类的 Class 对象后,调用 getMethod() 方法获取指定方法名和参数类型的 Method 对象。这个方法需要传入两个参数,第一个是方法名 methodName,第二个是参数类型数组 parameterTypes

这行代码的作用是获取切点方法对应的 Method 对象,可以通过该对象进行一些反射操作,比如调用方法、获取方法的修饰符等。

package com.cherriesovo.blog.common.cache;import com.alibaba.fastjson.JSON;
import com.cherriesovo.blog.vo.Result;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.lang3.StringUtils;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.annotation.AliasFor;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;import java.lang.reflect.Method;
import java.time.Duration;
//AOP定义一个切面,切面定义了切点和通知的关系
@Aspect
@Component
@Slf4j
public class CacheAspect {@Autowiredprivate RedisTemplate<String, String> redisTemplate;//切点,匹配带有 @Cache 注解的方法@Pointcut("@annotation(com.cherriesovo.blog.common.cache.Cache)")public void pt(){}	//切点的实际定义,名称为 pt。它没有参数和实现,因为它只是用来定义切点,而不执行任何实际的逻辑。//通知,通知关联了切点@Around("pt()")public Object around(ProceedingJoinPoint pjp){try {Signature signature = pjp.getSignature();	//获取了切点方法的签名信息//获取了切点方法所属类的简单类名String className = pjp.getTarget().getClass().getSimpleName();//获取了切点方法的方法名String methodName = signature.getName();//定义了一个数组用于存储切点方法的参数类型。pjp.getArgs() 返回的是切点方法的参数列表,通过遍历参数列表,可以逐个获取参数的类型,并存储到 parameterTypes 数组中。Class[] parameterTypes = new Class[pjp.getArgs().length];Object[] args = pjp.getArgs();	//获取了切点方法的参数值列表//将切点方法的参数值转换为字符串,并且将参数的类型存储到 parameterTypes 数组中。String params = "";	//参数for(int i=0; i<args.length; i++) {if(args[i] != null) {params += JSON.toJSONString(args[i]);	//将参数值追加到 params 字符串后面parameterTypes[i] = args[i].getClass();}else {parameterTypes[i] = null;}}if (StringUtils.isNotEmpty(params)) {//加密 以防出现key过长以及字符转义获取不到的情况params = DigestUtils.md5Hex(params);}Method method = pjp.getSignature().getDeclaringType().getMethod(methodName, parameterTypes);//获取方法上的Cache注解Cache annotation = method.getAnnotation(Cache.class);//从注解中获取缓存过期时间long expire = annotation.expire();//从注解中获取缓存名称String name = annotation.name();//先从redis获取数据String redisKey = name + "::" + className+"::"+methodName+"::"+params;	//唯一标识缓存中的数据//通过 Redis 模板的 opsForValue() 方法获取了一个操作字符串的操作对象,并调用了 get(redisKey) 方法,尝试从 Redis 中			根据 redisKey 获取对应的缓存数据。String redisValue = redisTemplate.opsForValue().get(redisKey);if (StringUtils.isNotEmpty(redisValue)){log.info("走了缓存~~~,{},{}",className,methodName);//将获取到的 JSON 格式的字符串 redisValue 解析为 Result 类型的对象返回return JSON.parseObject(redisValue, Result.class);}//在缓存未命中时,执行方法的实际逻辑并将结果存入 Redis 缓存中Object proceed = pjp.proceed();redisTemplate.opsForValue().set(redisKey,JSON.toJSONString(proceed), Duration.ofMillis(expire));log.info("存入缓存~~~ {},{}",className,methodName);return proceed;} catch (Throwable throwable) {throwable.printStackTrace();}return Result.fail(-999,"系统错误");}}

使用(对最热文章进行缓存处理):

在想要添加缓存的接口上添加:@Cache(expire = 5 * 60 * 1000,name = “hot_article”)

   @PostMapping("hot")@Cache(expire = 5 * 60 * 1000,name = "hot_article")	//指定了缓存的过期时间 5 分钟public Result hotArticle(){int limit = 5;return articleService.hotArticle(limit);}

相关文章:

个人博客项目_09

1. 归档文章列表 1.1 接口说明 接口url&#xff1a;/articles 请求方式&#xff1a;POST 请求参数&#xff1a; 参数名称参数类型说明yearstring年monthstring月 返回数据&#xff1a; {"success": true, "code": 200, "msg": "succ…...

【2024年MathorCup数模竞赛】C题赛题与解题思路

2024年MathorCup数模竞赛C题 题目 物流网络分拣中心货量预测及人员排班背景求解问题 解题思路问题一问题二问题三问题四 本次竞赛的C题是对物流网络分拣中心的货量预测及人员排班问题进行规划。整个问题可以分为两个部分&#xff0c;一是对时间序列进行预测&#xff0c;二是对人…...

蓝桥杯省赛冲刺(3)广度优先搜索

广度优先搜索&#xff08;Breadth-First Search, BFS&#xff09;是一种在图或树等非线性数据结构中遍历节点的算法&#xff0c;它从起始节点开始&#xff0c;按层级逐步向外扩展&#xff0c;即先访问离起始节点最近的节点&#xff0c;再访问这些节点的邻居&#xff0c;然后是邻…...

网页内容生成图片,这18般武艺你会几种呢?

前言 关于【SSD系列】&#xff1a; 前端一些有意思的内容&#xff0c;旨在3-10分钟里&#xff0c; 500-1000字&#xff0c;有所获&#xff0c;又不为所累。 网页截图&#xff0c;windows内置了快捷命令和软件&#xff0c;chrome开发者工具也能一键截图&#xff0c;html2canva…...

pytest的时候输出一个F后面跟很多绿色的点解读

使用pytest来测试pyramid和kotti项目&#xff0c;在kotti项目测试的时候&#xff0c;输出一个F后面跟很多绿色的点&#xff0c;是什么意思呢&#xff1f; 原来在使用pytest进行测试时&#xff0c;输出中的“F”代表一个失败的测试&#xff08;Failed&#xff09;&#xff0c;而…...

算法打卡day33

今日任务&#xff1a; 1&#xff09;509. 斐波那契数 2&#xff09;70. 爬楼梯 3&#xff09;746.使用最小花费爬楼梯 509. 斐波那契数 题目链接&#xff1a;509. 斐波那契数 - 力扣&#xff08;LeetCode&#xff09; 斐波那契数&#xff0c;通常用 F(n) 表示&#xff0c;形成…...

《疯狂java讲义》Java AWT图形化编程中文显示

《疯狂java讲义》第六版第十一章AWT中文没有办法显示问题解决 VM Options设置为-Dfile.encodinggbk 需要增加变量 或者这边直接设置gbk 此外如果用swing 就不会产生这个问题了。...

Python3 标准库,API文档链接

一、标准库 即当你安装python3 后就自己携带的一些已经提供好的工具模块&#xff0c;工具类&#xff0c;可以专门用来某一类相关问题&#xff0c;达到辅助日常工作或者个人想法的一些成品库 类似的 C ,Java 等等也都有自己的标准库和使用文档 常见的一些&#xff1a; os 模块…...

【Web】CTFSHOW-ThinkPHP5-6反序列化刷题记录(全)

目录 web611 web612 web613-622 web623 web624-626 纯记录exp&#xff0c;链子不作赘述 web611 具体分析&#xff1a; ThinkPHP-Vuln/ThinkPHP5/ThinkPHP5.1.X反序列化利用链.md at master Mochazz/ThinkPHP-Vuln GitHub 题目直接给了反序列化入口 exp: <?ph…...

AR智能眼镜方案_MTK平台安卓主板芯片|光学解决方案

AR眼镜作为一种引人注目的创新产品&#xff0c;其芯片、显示屏和光学方案是决定整机成本和性能的关键因素。在这篇文章中&#xff0c;我们将探讨AR眼镜的关键技术&#xff0c;并介绍一种高性能的AR眼镜方案&#xff0c;旨在为用户带来卓越的体验。 AR眼镜的芯片选型至关重要。一…...

Android网络抓包--Charles

一、Android抓包方式 对Https降级进行抓包&#xff0c;降级成Http使用抓包工具对Https进行抓包 二、常用的抓包工具 wireshark&#xff1a;侧重于TCP、UDP传输层&#xff0c;HTTP/HTTPS也能抓包&#xff0c;但不能解密HTTPS报文。比较复杂fiddler&#xff1a;支持HTTP/HTTPS…...

【LeetCode热题100】238. 除自身以外数组的乘积(数组)

一.题目要求 给你一个整数数组 nums&#xff0c;返回 数组 answer &#xff0c;其中 answer[i] 等于 nums 中除 nums[i] 之外其余各元素的乘积 。 题目数据 保证 数组 nums之中任意元素的全部前缀元素和后缀的乘积都在 32 位 整数范围内。 请 **不要使用除法&#xff0c;**且在…...

《哈迪斯》自带的Lua解释器是哪个版本?

玩过《哈迪斯》&#xff08;英文名&#xff1a;Hades&#xff09;吗&#xff1f;最近在研究怎么给这款游戏做MOD&#xff0c;想把它的振动体验升级到更高品质的RichTap。N站下载了一些别人做的MOD&#xff0c;发现很多都基于相同的格式&#xff0c;均是对游戏.sjon文件或.lua文…...

Java内存泄漏内存溢出

1.定义 OOM内存溢出是指应用程序尝试使用更多内存资源&#xff0c;而系统无足够的内存&#xff0c;导致程序崩溃。 内存泄漏是指应用程序中分配的内存未能被正确释放&#xff0c;导致系统中的可用内存逐渐减少。 2.内存泄漏的原因 可能包括对象引用未被释放、缓存未被清理等。 …...

【springboot】项目启动时打印全部接口方法

方法&#xff1a;在你springboot项目的基础上&#xff0c;创建下面的类&#xff1a; package com.llq.wahaha.listener;import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.ApplicationContext; import org.springframework…...

单例19c RMAN数据迁移方案

一、环境说明 源库 目标库 IP 192.168.37.200 192.168.37.202 系统版本 RedHat 7.9 RedHat 7.9 数据库版本 19.3.0.0.0 19.3.0.0.0 SID beg beg hostname beg rman 数据量 1353M 说明:源库已经创建数据库实例&#xff0c;并且存在用户kk和他创建的表空间…...

05—面向对象(上)

一、面向对象编程 1、类和对象 &#xff08;1&#xff09;什么是类 类是一类具有相同特性的事物的抽象描述&#xff0c;是一组相关属性和行为的集合。 属性&#xff1a;就是该事物的状态信息。行为&#xff1a;就是在你这个程序中&#xff0c;该状态信息要做什么操作&#x…...

【LeetCode热题100】【链表】两数相加

题目链接&#xff1a;2. 两数相加 - 力扣&#xff08;LeetCode&#xff09; 基本思路同&#xff1a;【leetcode】大数相加-CSDN博客 数值的位置已经倒过来了&#xff0c;用一个进位记录进位&#xff0c;用一个数记录和&#xff0c;链表到空了就当成0 class Solution { publi…...

Linux命令学习—linux 的硬件管理

1.1、linux 的硬件管理 1.1.1、计算机的硬件管理 在 linux 下&#xff0c;计算机所有设备是以文件的形势存在的。 在 linux 下查看硬件信息 ①、lspci 列出所有的 PCI 设备 ②、fdisk -l 查看存储设备信息 ③、查看/proc 目录下相应的文件来查看一些设备信息 cat /proc/cp…...

通讯录项目(用c语言实现)

一.什么是通讯录 通讯录是一种用于存储联系人信息的工具或应用程序。它是一种电子化的地址簿&#xff0c;用于记录和管理个人、机构或组织的联系方式&#xff0c;如姓名、电话号码、电子邮件地址和邮寄地址等。通讯录的目的是方便用户在需要时查找和联系他人。 通讯录通常以列…...

(LeetCode 每日一题) 3442. 奇偶频次间的最大差值 I (哈希、字符串)

题目&#xff1a;3442. 奇偶频次间的最大差值 I 思路 &#xff1a;哈希&#xff0c;时间复杂度0(n)。 用哈希表来记录每个字符串中字符的分布情况&#xff0c;哈希表这里用数组即可实现。 C版本&#xff1a; class Solution { public:int maxDifference(string s) {int a[26]…...

RocketMQ延迟消息机制

两种延迟消息 RocketMQ中提供了两种延迟消息机制 指定固定的延迟级别 通过在Message中设定一个MessageDelayLevel参数&#xff0c;对应18个预设的延迟级别指定时间点的延迟级别 通过在Message中设定一个DeliverTimeMS指定一个Long类型表示的具体时间点。到了时间点后&#xf…...

docker详细操作--未完待续

docker介绍 docker官网: Docker&#xff1a;加速容器应用程序开发 harbor官网&#xff1a;Harbor - Harbor 中文 使用docker加速器: Docker镜像极速下载服务 - 毫秒镜像 是什么 Docker 是一种开源的容器化平台&#xff0c;用于将应用程序及其依赖项&#xff08;如库、运行时环…...

页面渲染流程与性能优化

页面渲染流程与性能优化详解&#xff08;完整版&#xff09; 一、现代浏览器渲染流程&#xff08;详细说明&#xff09; 1. 构建DOM树 浏览器接收到HTML文档后&#xff0c;会逐步解析并构建DOM&#xff08;Document Object Model&#xff09;树。具体过程如下&#xff1a; (…...

深入解析C++中的extern关键字:跨文件共享变量与函数的终极指南

&#x1f680; C extern 关键字深度解析&#xff1a;跨文件编程的终极指南 &#x1f4c5; 更新时间&#xff1a;2025年6月5日 &#x1f3f7;️ 标签&#xff1a;C | extern关键字 | 多文件编程 | 链接与声明 | 现代C 文章目录 前言&#x1f525;一、extern 是什么&#xff1f;&…...

Java线上CPU飙高问题排查全指南

一、引言 在Java应用的线上运行环境中&#xff0c;CPU飙高是一个常见且棘手的性能问题。当系统出现CPU飙高时&#xff0c;通常会导致应用响应缓慢&#xff0c;甚至服务不可用&#xff0c;严重影响用户体验和业务运行。因此&#xff0c;掌握一套科学有效的CPU飙高问题排查方法&…...

【Redis】笔记|第8节|大厂高并发缓存架构实战与优化

缓存架构 代码结构 代码详情 功能点&#xff1a; 多级缓存&#xff0c;先查本地缓存&#xff0c;再查Redis&#xff0c;最后才查数据库热点数据重建逻辑使用分布式锁&#xff0c;二次查询更新缓存采用读写锁提升性能采用Redis的发布订阅机制通知所有实例更新本地缓存适用读多…...

C# 表达式和运算符(求值顺序)

求值顺序 表达式可以由许多嵌套的子表达式构成。子表达式的求值顺序可以使表达式的最终值发生 变化。 例如&#xff0c;已知表达式3*52&#xff0c;依照子表达式的求值顺序&#xff0c;有两种可能的结果&#xff0c;如图9-3所示。 如果乘法先执行&#xff0c;结果是17。如果5…...

算法打卡第18天

从中序与后序遍历序列构造二叉树 (力扣106题) 给定两个整数数组 inorder 和 postorder &#xff0c;其中 inorder 是二叉树的中序遍历&#xff0c; postorder 是同一棵树的后序遍历&#xff0c;请你构造并返回这颗 二叉树 。 示例 1: 输入&#xff1a;inorder [9,3,15,20,7…...

电脑桌面太单调,用Python写一个桌面小宠物应用。

下面是一个使用Python创建的简单桌面小宠物应用。这个小宠物会在桌面上游荡&#xff0c;可以响应鼠标点击&#xff0c;并且有简单的动画效果。 import tkinter as tk import random import time from PIL import Image, ImageTk import os import sysclass DesktopPet:def __i…...