springboot博客实战笔记02

一、评论功能:

注意要先登录之后才能进行评论,所有把评论加入到登录拦截器当中

@Overridepublic void addInterceptors(InterceptorRegistry registry) {//拦截test接口,后续实际遇到需要拦截的接口时,在配置为真正的拦截接口registry.addInterceptor(loginInterceptor).addPathPatterns("/test").addPathPatterns("/comments/create/change");}
  • 在登录拦截器LoginInterceptor里面存入了用户信息:
  //登录成功 放行//我希望再controller中 直接获取用户的信息  怎么获取UserThreadLocal.put(sysUser);
  • 后续在评论的实现类里面可以用gei方法获取到 用户信息 充当评论人
 //这里直接在线程里面找到登录时候保存的用户信息SysUser sysUser = UserThreadLocal.get();

1.根据文章id查询评论

    @Overridepublic Result commentsByArticleId(Long id) {/*** 1.根据文章id 查询评论列表 从comments表中查询-* 2.根据作者的id 查询作者的信息* 3.判断  如果 level = 1 要去查询它有没有子评论* 4.如果 有 根据评论id  进行查询(parent_id)*/LambdaQueryWrapper<Comment> queryWrapper = new LambdaQueryWrapper<>();queryWrapper.eq(Comment::getArticleId,id);queryWrapper.eq(Comment::getLevel,1);List<Comment> comments = commentMapper.selectList(queryWrapper);List<CommentVo> commentVoList = copyList(comments);return Result.success(commentVoList);}
private List<CommentVo> findCommentsByParentId(Long id) {LambdaQueryWrapper<Comment> queryWrapper = new LambdaQueryWrapper<>();queryWrapper.eq(Comment::getParentId,id);queryWrapper.eq(Comment::getLevel,2);List<Comment> comments = commentMapper.selectList(queryWrapper);return copyList(comments);}

将pojo —> vo的方法,这里有个小巧思,分为level大于1和等于1的情况,当level等于1时,说明可能是楼主,会有子评论

private List<CommentVo> copyList(List<Comment> comments) {List<CommentVo> commentVoList = new ArrayList<>();for (Comment comment : comments) {commentVoList.add(copy(comment));}return  commentVoList;}private CommentVo copy(Comment comment) {CommentVo commentVo = new CommentVo();BeanUtils.copyProperties(comment,commentVo);commentVo.setId(String.valueOf(comment.getId()));//作者信息Long authorId = comment.getAuthorId();UserVo userVo = this.sysUserService.findUserVoById(authorId);commentVo.setAuthor(userVo);//子评论Integer level = comment.getLevel();if( 1 == level){Long id = Long.valueOf(comment.getId());List<CommentVo> commentVoList = findCommentsByParentId(id);commentVo.setChildrens(commentVoList);}//to User 给谁评论if(level >1){Long toUid = comment.getToUid();UserVo toUserVo = this.sysUserService.findUserVoById(toUid);commentVo.setToUser(toUserVo);}return commentVo;}

精度损失问题

当数据库用的是分布式id的时候,前端会出现精度损失问题,导致找不到正确的id 此时需要在实体类中,添加相关注解,把id转为string,(分布式id 比较长,传到前端 会有精度损失,必须转为string类型,进行运输,就不会有问题了

    //防止前端精度损失 把id转为string@JsonSerialize(using = ToStringSerializer.class)private Long id;

二、发布文章

也需要登录过后才能发布文章,

 registry.addInterceptor(loginInterceptor).addPathPatterns("/test").addPathPatterns("/comments/create/change").addPathPatterns("/articles/publish");
 @Overridepublic Result publish(ArticleParam articleParam) {/*** 1.发布文章  目的 构建Article对象* 2.作者id 当前的登录用户* 3.标签 要将标签加入到 关联表中* 4.body 内容存储**/SysUser sysUser = UserThreadLocal.get();//登录的用户id就是作者id 而登录的用户 可以去线程中找Article article = new Article();article.setAuthorId(Long.valueOf(sysUser.getId()));article.setWeight(Article.Article_Common);article.setViewCounts(0);article.setTitle(articleParam.getTitle());article.setSummary(articleParam.getSummary());article.setCommentCounts(0);article.setCreateDate(System.currentTimeMillis());article.setCategoryId(Long.valueOf(articleParam.getCategory().getId()));//插入之后会生成一个文章idthis.articleMapper.insert(article);//tagList<TagVo> tags = articleParam.getTags();if(tags!=null){for (TagVo tag : tags) {Long articleId = Long.valueOf(article.getId());ArticleTag articleTag = new ArticleTag();articleTag.setTagId(Long.valueOf(tag.getId()));articleTag.setArticleId(articleId);articleTagMapper.insert(articleTag);}}//bodyArticleBody articleBody = new ArticleBody();articleBody.setArticleId(Long.valueOf(article.getId()));articleBody.setContent(articleParam.getBody().getContent());articleBody.setContentHtml(articleParam.getBody().getContentHtml());articleBodyMapper.insert(articleBody);article.setBodyId(Long.valueOf(articleBody.getId()));articleMapper.updateById(article);//方法1 articleVo
//        ArticleVo articleVo = new ArticleVo();
//        articleVo.setId(article.getId());
//        return Result.success(articleVo);//方法2Map<String,String> map = new HashMap<>();map.put("id",article.getId().toString());//返回字符串避免精度损失问题return Result.success(map);}

三、AOP日志

对于 IoC 的一种补充,面向切面编程,简化程序的一种方式
IoC 简化代码量,AOP 实现解耦合的
让代码变得松散,灵活,更方便扩展和维护
日志输出和业务计算混合在一起,耦合在一起,不方便维护
解耦合,把日志输出和业务计算的代码进行分离
最终程序运行的时候,结果还要合到一起

1.在需要记录日志的controller上添加注解

    @PostMapping//加上此注解 代表要对此接口记录日志@LogAnnotation(module="文章",operator="获取文章列表")public Result listArticle(@RequestBody PageParams pageParams){return articleService.listArticle(pageParams);}

2.创建aop包,并且创建annotation类

在这里插入图片描述

在这里插入图片描述

package com.mszlu.blog.common.aop;import java.lang.annotation.*;//Type 代表可以放在类上面 Method代表可以放在方法上面
//ElementType.Type ElementType.METHOD
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface LogAnnotation {String module() default "";String operator() default "";
}

3.开花AOP创建LogAspect类

package com.mszlu.blog.common.aop;import com.alibaba.fastjson.JSON;
import com.mszlu.blog.common.aop.LogAnnotation;
import com.mszlu.blog.utils.HttpContextUtils;
import com.mszlu.blog.utils.IpUtils;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;@Component//让spring识别到
@Aspect//切面 定义了通知和切点的关系
@Slf4j
public class LogAspect {@Pointcut("@annotation(com.mszlu.blog.common.aop.LogAnnotation)")public void pt(){}@Around("pt()")public Object log(ProceedingJoinPoint joinPoint) throws Throwable {long beginTime = System.currentTimeMillis();//执行方法Object result = joinPoint.proceed();//执行时长(毫秒)long time = System.currentTimeMillis() - beginTime;//保存日志recordLog(joinPoint, time);return result;}private void recordLog(ProceedingJoinPoint joinPoint, long time) {MethodSignature signature = (MethodSignature) joinPoint.getSignature();Method method = signature.getMethod();LogAnnotation logAnnotation = method.getAnnotation(LogAnnotation.class);log.info("=====================log start================================");log.info("module:{}",logAnnotation.module());log.info("operator:{}",logAnnotation.operator());//请求的方法名String className = joinPoint.getTarget().getClass().getName();String methodName = signature.getName();log.info("request method:{}",className + "." + methodName + "()");//        //请求的参数Object[] args = joinPoint.getArgs();String params = JSON.toJSONString(args[0]);log.info("params:{}",params);//获取request 设置IP地址HttpServletRequest request = HttpContextUtils.getHttpServletRequest();log.info("ip:{}", IpUtils.getIpAddr(request));log.info("excute time : {} ms",time);log.info("=====================log end================================");}}

四、上传图片


@RestController
@RequestMapping("upload")
public class UploadController {@Autowiredprivate QiniuUtils qiniuUtils;@PostMapping()public Result upload(@RequestParam("image")MultipartFile file){//原始文件名称 比如aa.pngString 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,"上传失败");}

我们用的平台是七牛云 首先先要导入依赖:

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

@Component
public class QiniuUtils {public static  final String url = "http://t0oltruo7.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(Region.huanan());//...其他参数参考类注释UploadManager uploadManager = new UploadManager(cfg);//...生成上传凭证,然后准备上传String bucket = "danb24";//默认不指定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;}
}

注意点

  • url就是你在七牛云创建的域名 “http://t0oltruo7.hn-bkt.clouddn.com/”;
  • accessKey和SecretKey在七牛云中获得 并且配置在在properties或者直接赋值(不推荐)
    qiniu.accessKey=NnneEoseKEAqkNNFuaMYWIBU7gn0xdVUbGuBjmGU
    qiniu.accessSecretKey=G5NBjBLd3OdttFet71AGxjbpahwduNpom_amLe1G
  • bucket 修改为自己的文件名
  • 也可以在配置文件中限制上传文件的值
    #上传文件总的最大值
    spring.servlet.multipart.max-request-size=20MB
    #单个文件的最大值
    spring.servlet.multipart.max-file-size=2MB

统一缓存处理(优化)

1.cache包下Cache

package com.mszlu.blog.common.cache;import java.lang.annotation.*;//
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Cache {long expire() default 1 * 60 * 1000;//缓存标识KeyString name() default "";}

2.cache包下CacheAspect

package com.mszlu.blog.common.cache;import com.alibaba.fastjson.JSON;
import com.mszlu.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.data.redis.core.RedisTemplate;
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;//切点@Pointcut("@annotation(com.mszlu.blog.common.cache.Cache)")public void pt(){}//环绕@Around("pt()")public Object around(ProceedingJoinPoint pjp){try {Signature signature = pjp.getSignature();//类名String className = pjp.getTarget().getClass().getSimpleName();//调用的方法名String methodName = signature.getName();Class[] parameterTypes = new Class[pjp.getArgs().length];Object[] args = pjp.getArgs();//参数String params = "";for(int i=0; i<args.length; i++) {if(args[i] != null) {params += JSON.toJSONString(args[i]);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;String redisValue = redisTemplate.opsForValue().get(redisKey);if (StringUtils.isNotEmpty(redisValue)){log.info("走了缓存~~~,{},{}",className,methodName);return JSON.parseObject(redisValue, Result.class);}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,"系统错误");}}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/news/918744.shtml
繁体地址,请注明出处:http://hk.pswp.cn/news/918744.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

ThinkPHP+Mysql 灵活用工小程序-技术深度解析与实践指南

一、模块设计分包商&#xff1a;税地注册公司&#xff0c;用于在当地申请有利的税收政策&#xff0c;是实际报税公司。 代理商&#xff1a;代理商可以邀请客户使用本平台&#xff0c;平台会给予代理商一定的服务费差价作为佣金。 客户&#xff1a;使用本平台进行工资发放的…

开源数据发现平台:Amundsen 第1部分:基础入门与本地环境设置

Amundsen 是一个数据发现和元数据引擎&#xff0c;旨在提高数据分析师、数据科学家和工程师与数据交互时的生产力。目前&#xff0c;它通过索引数据资源&#xff08;表格、仪表板、数据流等&#xff09;并基于使用模式&#xff08;例如&#xff0c;查询频率高的表格会优先于查询…

Linux编程--进程

1、基本概念&#xff1a;进程&#xff1a;是程序动态执行的过程&#xff0c;包括创建、调度、消亡程序&#xff1a;存放在外存中一段数据的集合虚拟地址&#xff1a;进程使用的逻辑地址&#xff0c;有操作系统管理&#xff0c;不直接对应物理内存物理地址&#xff1a;实际内存的…

【开源工具】基于硬件指纹的“一机一码”软件授权系统全实现(附完整源码)

🚨 紧急预警!你的软件正在被白嫖?这套Python软件加密授权方案让破解者当场崩溃 🌈 个人主页:创客白泽 - CSDN博客 🔥 系列专栏:🐍《Python开源项目实战》 💡 热爱不止于代码,热情源自每一个灵感闪现的夜晚。愿以开源之火,点亮前行之路。 🐋 希望大家多多支持…

机器学习算法篇(八)-------svm支持向量机

目录 ​​1. SVM 的核心原理&#xff08;必须掌握&#xff09;​​ ​​2. Python 中的实践重点​​ ​​(1) Scikit-learn 的 SVM 实现​​ ​​(2) 数据预处理​​ ​​(3) 模型评估与调优​​ ​​3. 学习侧重点优先级​​ ​​4. 经典案例实践方向​​ ​​5. 学习…

发票查验接口接收参数说明-PHP语言集成-财务管理

发票验真服务接口可实时联网核验发票真伪&#xff0c;查验一致时返回全票面信息。其支持核验增值税发票管理系统开具发票的真伪&#xff0c;且能进行发票批量查验&#xff0c;当日开具的发票当日即可查验。同时&#xff0c;结合发票识别接口可实现自动识别发票信息核验&#xf…

Uniapp物联网平台登录与温湿度监测系统

下面是一个完整的Uniapp物联网平台实现&#xff0c;包含登录功能和温湿度监测系统。这个解决方案采用现代化UI设计&#xff0c;模拟了物联网平台的核心功能。文章末尾提供源码下载。 系统功能说明 这个Uniapp物联网平台登录与温湿度监测系统包含以下核心功能&#xff1a; 1.…

【企业架构】TOGAF概念之四(终结)

导读&#xff1a;学习TOGAF&#xff08;The Open Group Architecture Framework&#xff0c;开放组架构框架&#xff09;相关概念的意义和价值&#xff0c;体现在它为企业架构&#xff08;Enterprise Architecture, EA&#xff09;实践提供了标准化方法论、跨领域协同框架、战略…

centos 怎么部署 vscode 网页版

安装编译工具 下载适用于 linux 版本的 rpm 格式文件 下載 Visual Studio Tools - 免費安裝 Windows、Mac、Linux 拷贝路径&#xff0c;下载文件 wget https://vscode.download.prss.microsoft.com/dbazure/download/stable/e3550cfac4b63ca4eafca7b601f0d2885817fd1f/code…

sql的关键字 limit 和offset

核心概念LIMIT (限制): 指定查询最多返回多少行记录。OFFSET (偏移): 指定在开始返回记录之前要跳过多少行记录。它定义了结果集的起始点。核心前提&#xff1a; 必须 使用 ORDER BY 子句来确保分页结果的顺序稳定和可预测。示例&#xff1a; 假设 employees 表有 100 条记录&a…

git config的配置全局或局部仓库的参数: local, global, system

git config的范围参数: local, global, system1. --local: 作用于当前仓库2. --global: 作用于当前用户的全局范围的 Git 仓库3. --system: 作用于系统范围内的 Git 仓库4. 注意事项参考链接1. --local: 作用于当前仓库 --local: 这个参数的作用范围是当前仓库。其配置的参数保…

应用系统连达梦数据库报“服务器模式不匹配”的根源与修复方案

近期遇到很多个应用系统连接达梦数据库报“服务器模式不匹配”的问题&#xff0c;省流直接说文章结论通常两种场景 初次连接达梦数据库时报服务器模式不匹配&#xff0c;可能是配置文件中LOGIN_MODE参数配置与数据库状态不一致导致连接失败应用系统正常运行负载大或者偶发报服务…

git:分支

分支命名可以使用斜杠(/)构建分层命名方案不能以减号(-)开头&#xff0c;分层的命名不能以点(.)开头不能使用连接两个点(.)不能包括空格或其他空白字符以及~ ^ : ? * [列出分支名称 git branch 列出本地版本库的分支git branch -r 列出远程跟踪分支git branch -a …

T05_卷积神经网络

全连接网络存的弊端 以MINST数字识别为例&#xff0c;创建一个4层全连接网络层&#xff0c;输入为28x28&#xff0c;中间三个隐藏层的节点数都是 256&#xff0c;输出节点数是10。通过summary()函数打印出模型每一层的参数量&#xff0c;计算总的参数量超过34万个网络参数&…

区块链在可信空间智能合约中的应用

区块链在可信数据空间的智能合约应用,通过去中心化信任机制、自动化执行、可验证计算等特性,正在重塑数据存储、共享、交易和治理的模式。以下是其核心应用方向、关键技术及落地案例的深度解析: 一、核心应用方向 1. 数据确权与授权管理 应用场景 个人数据主权:用户通过智…

pycharm配置python解释器教程

一个解释器对应一个环境&#xff0c;无论是conda环境或是Python环境。python环境的解释器的路径形如"D:\Python3.12\python.exe"&#xff0c;conda环境的解释器的路径形如"D:\anaconda3\envs\opencv\python.exe"。 如何在Pycharm中设置解释器 打开pycharm&…

C#教程之NPOI读写excel文件XLS,XLSX格式

NPOI 是开源的 POI 项目的.NET版&#xff0c;可以用来读写Excel&#xff0c;Word&#xff0c;PPT文件。仅需处理 XLS/XLSX 格式的文本和数字读写&#xff0c;最少需要加载 2 个核心 DLL&#xff1a;NPOI.dll包含所有格式的通用接口&#xff08;IWorkbook、ISheet、IRow、ICell …

Perforce P4 Git 连接器

Perforce P4 Git连接器将Git代码库与数字资产集中存储于Perforce P4&#xff08;前身为Helix Core&#xff09;&#xff0c;为所有数字资产&#xff08;源码二进制文件&#xff09;构建单一事实来源。 突破代码库与文件限制 当艺术家、开发者及工程师组成的大型团队仅使用Git时…

day10_寻找用户推荐人

一、题目给出一张customer表&#xff0c;里面有id&#xff08;客户id&#xff09;——主键&#xff0c;name&#xff08;客户姓名&#xff09;&#xff0c;referee_id&#xff08;推荐人客户id&#xff09;三个字段二、题目要求1、找出被id不是2的用户推荐的客户姓名2、没有被任…

python爬虫(三)----Selenium

目录 1. Selenium 1.1 Selenium是啥 1.2 安装chrom Driver 1.3 selenium 使用 1.4 selenium元素定位 1.5 访问元素信息 1.6 交互 2. Phantomjs、Chrom handless 1. Selenium 1.1 Selenium是啥 自动化Web浏览器操作 主要用于Web应用程序的测试 支持多操作系统、多浏览器…