博客文档续更
十、 博客前台模块-异常处理
目前我们的项目在认证出错或者权限不足的时候响应回来的Json,默认是使用Security官方提供的响应的格式,但是这种响应的格式肯定是不符合我们项目的接口规范的。所以需要自定义异常处理
我们需要去实现AuthenticationEntryPoint(官方提供的认证失败处理器)类、AccessDeniedHandler(官方提供的授权失败处理器)类,然后配置给Security

由于我们前台和后台的异常处理是一样的,所以我们在framework包下创建异常处理类
1. 认证的异常处理
在keke-framework工程的src/main/java/com.keke目录新建handler.security.AuthenticationEntryPointImpl类,写入如下
package com.keke.handler.security;import com.alibaba.fastjson.JSON;
import com.keke.domain.ResponseResult;
import com.keke.enums.AppHttpCodeEnum;
import com.keke.utils.WebUtils;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.InsufficientAuthenticationException;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.AuthenticationEntryPoint;
import org.springframework.stereotype.Component;import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;@Component
public class AuthenticationEntryPointImpl implements AuthenticationEntryPoint {@Overridepublic void commence(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, AuthenticationException authException) throws IOException, ServletException {authException.printStackTrace();ResponseResult result = null;//BadCredentialsException 这个是我们测试输入错误账号密码出现的异常if(authException instanceof BadCredentialsException){result = ResponseResult.errorResult(AppHttpCodeEnum.LOGIN_ERROR.getCode(),authException.getMessage());} else if (authException instanceof InsufficientAuthenticationException) {//InsufficientAuthenticationException 这个是我们测试不携带token出现的异常result = ResponseResult.errorResult(AppHttpCodeEnum.NEED_LOGIN);}else {result = ResponseResult.errorResult(AppHttpCodeEnum.SYSTEM_ERROR,"认证或者授权失败");}//响应给前端WebUtils.renderString(httpServletResponse, JSON.toJSONString(result));}
}
 
2. 授权的异常处理
在keke-framework工程的src/main/java/com.keke目录新建handler.security.AccessDeniedHandlerImpl类,写入如下
package com.keke.handler.security;import com.alibaba.fastjson.JSON;
import com.keke.domain.ResponseResult;
import com.keke.enums.AppHttpCodeEnum;
import com.keke.utils.WebUtils;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.web.access.AccessDeniedHandler;
import org.springframework.stereotype.Component;import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;@Component
public class AccessDeniedHandlerImpl implements AccessDeniedHandler {@Overridepublic void handle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, AccessDeniedException accessDeniedException) throws IOException, ServletException {accessDeniedException.printStackTrace();ResponseResult result = ResponseResult.errorResult(AppHttpCodeEnum.NO_OPERATOR_AUTH);//响应给前端WebUtils.renderString(httpServletResponse, JSON.toJSONString(result));}
}
 
3. 认证授权异常处理配置到框架
把keke-blog工程的SecurityConfig类修改为如下
package com.keke.config;import com.keke.filter.JwtAuthenticationTokenFilter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.AuthenticationEntryPoint;
import org.springframework.security.web.access.AccessDeniedHandler;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;@Configuration
//WebSecurityConfigurerAdapter是Security官方提供的类
public class SecurityConfig extends WebSecurityConfigurerAdapter {//注入我们在keke-blog工程写的JwtAuthenticationTokenFilter过滤器@Autowiredprivate JwtAuthenticationTokenFilter jwtAuthenticationTokenFilter;@AutowiredAuthenticationEntryPoint authenticationEntryPoint;@AutowiredAccessDeniedHandler accessDeniedHandler;@Override@Beanpublic AuthenticationManager authenticationManagerBean() throws Exception {return super.authenticationManagerBean();}@Bean//把官方的PasswordEncoder密码加密方式替换成BCryptPasswordEncoderpublic PasswordEncoder passwordEncoder(){return new BCryptPasswordEncoder();}@Overrideprotected void configure(HttpSecurity http) throws Exception {http//关闭csrf.csrf().disable()//不通过Session获取SecurityContext.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and().authorizeRequests()// 对于登录接口 允许匿名访问.antMatchers("/login").anonymous()//为方便测试认证过滤器,我们把查询友链的接口设置为需要登录才能访问。然后我们去访问的时候就能测试登录认证功能了.antMatchers("/link/getAllLink").authenticated()// 除上面外的所有请求全部不需要认证即可访问.anyRequest().permitAll();//配置我们自己写的认证和授权的异常处理http.exceptionHandling().authenticationEntryPoint(authenticationEntryPoint).accessDeniedHandler(accessDeniedHandler);http.logout().disable();//将自定义filter加入security过滤器链中http.addFilterBefore(jwtAuthenticationTokenFilter, UsernamePasswordAuthenticationFilter.class);//允许跨域http.cors();}} 
4. 测试自定义异常处理
第一步:打开redis,启动工程
第二步:向login接口发送用户名或者密码错误的post请求

第三步:向link/getAllLink接口发送不携带token的get请求

5. 统一异常处理
实际我们在开发过程中可能需要做很多的判断校验,如果出现了非法情况我们是期望响应对应的提示的。但是如果我们每次都自己手动去处理就会非常麻烦。我们可以选择直接抛出异常的方式,然后对异常进行统一处理。把异常中的信息封装成ResponseResult响应给前端
5.1 自定义异常
在keke-framework工程的src/main/java/com.keke目录新建exception.SystemException类,写入如下
package com.keke.exception;import com.keke.enums.AppHttpCodeEnum;//统一异常处理
public class SystemException extends RuntimeException{private int code;private String msg;public int getCode() {return code;}public String getMsg() {return msg;}//定义一个构造方法,接收的参数是枚举类型,AppHttpCodeEnum是我们在huanf-framework工程定义的枚举类public SystemException(AppHttpCodeEnum httpCodeEnum) {super(httpCodeEnum.getMsg());//把某个枚举类里面的code和msg赋值给异常对象this.code = httpCodeEnum.getCode();this.msg = httpCodeEnum.getMsg();}
} 
5.2 全局异常处理
在keke-framework的com.keke包下新建handler.exception.GlobalExceptionHandler 写入如下,登录和其他地方出现的异常都会被这里捕获,然后响应返回
package com.keke.handler.exception;import com.keke.domain.ResponseResult;
import com.keke.enums.AppHttpCodeEnum;
import com.keke.exception.SystemException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;//@ControllerAdvice //对controller层的增强
//@ResponseBody//或者用下面一个注解代替上面的两个注解
@RestControllerAdvice
//使用Lombok提供的Slf4j注解,实现日志功能
@Slf4j
//全局异常处理。最终都会在这个类进行处理异常
public class GlobalExceptionHandler {//SystemException是我们写的类。用户登录的异常交给这里处理@ExceptionHandler(SystemException.class)public ResponseResult systemExceptionHandler(SystemException e){//打印异常信息,方便我们追溯问题的原因。{}是占位符,具体值由e决定log.error("出现了异常! {}",e);//从异常对象中获取提示信息封装,然后返回。ResponseResult是我们写的类return ResponseResult.errorResult(e.getCode(),e.getMsg());}//其它异常交给这里处理@ExceptionHandler(Exception.class)public ResponseResult exceptionHandler(Exception e){//打印异常信息,方便我们追溯问题的原因。{}是占位符,具体值由e决定log.error("出现了异常! {}",e);//从异常对象中获取提示信息封装,然后返回。ResponseResult、AppHttpCodeEnum是我们写的类return ResponseResult.errorResult(AppHttpCodeEnum.SYSTEM_ERROR.getCode(),e.getMessage());//枚举值是500}
} 
5.3 Controller层逻辑
package com.keke.controller;import com.keke.domain.ResponseResult;
import com.keke.domain.entity.User;
import com.keke.enums.AppHttpCodeEnum;
import com.keke.exception.SystemException;
import com.keke.service.BlogLoginService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;@RestController
public class BlogLoginController {@Autowiredprivate BlogLoginService blogLoginService;@PostMapping("/login")public ResponseResult login(@RequestBody User user){if(!StringUtils.hasText(user.getUserName())){//提示必须要传用户名throw new SystemException(AppHttpCodeEnum.REQUIRE_USERNAME);}return blogLoginService.login(user);}
}
 
5.3 测试
向login接口发送一个没有用户名只有密码的post,响应如下

可以看到,响应回来的信息是正确的
5.4 总结
首相前端发送请求,controller层先判断是否携带用户名,如果没有携带,抛出SystemException异常,并把响应的枚举信息传给异常对象,然后全局异常类中的systemExceptionHandler处理器处理就会捕获到该异常,然后在这个位置去封装响应体返回
其他异常则是由exceptionHandler处理
这就是异常统一处理
十一、博客前台模块-退出登录
1. 接口分析
|   请求方式  |   请求地址  |   请求头  | 
|   POST  |   /logout  |   需要token请求头  | 
响应格式
{"code": 200,"msg": "操作成功"
} 
2. 思路分析
获取token解析出userId
删除redis中的用户信息
3. 代码实现
第一步: 把keke-blog工程的BlogLoginController类修改为如下,新增了退出登录的接口
package com.keke.controller;import com.keke.domain.ResponseResult;
import com.keke.domain.entity.User;
import com.keke.enums.AppHttpCodeEnum;
import com.keke.exception.SystemException;
import com.keke.service.BlogLoginService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;@RestController
public class BlogLoginController {@Autowiredprivate BlogLoginService blogLoginService;@PostMapping("/login")public ResponseResult login(@RequestBody User user){if(!StringUtils.hasText(user.getUserName())){//提示必须要传用户名throw new SystemException(AppHttpCodeEnum.REQUIRE_USERNAME);}return blogLoginService.login(user);}@PostMapping("/logout")public ResponseResult logout(){return blogLoginService.logout();}
}
 
 
第二步: 把keke-framework工程的BlogLoginService接口修改为如下,新增了退出登录的方法
package com.keke.service;import com.keke.domain.ResponseResult;
import com.keke.domain.entity.User;public interface BlogLoginService {ResponseResult login(User user);ResponseResult logout();}
 
第三步: 把keke-framework工程的BlogLoginServiceImpl类修改为如下,新增了退出登录的核心代码
package com.keke.service.impl;import com.keke.domain.ResponseResult;
import com.keke.domain.entity.LoginUser;
import com.keke.domain.entity.User;
import com.keke.domain.vo.BlogLoginUserVo;
import com.keke.domain.vo.UserInfoVo;
import com.keke.service.BlogLoginService;
import com.keke.utils.BeanCopyUtils;
import com.keke.utils.JwtUtil;
import com.keke.utils.RedisCache;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Service;
import java.util.Objects;@Service
public class BlogLoginServiceImpl implements BlogLoginService {@Autowiredprivate AuthenticationManager authenticationManager;@Autowiredprivate RedisCache redisCache;@Overridepublic ResponseResult login(User user) {UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(user.getUserName(),user.getPassword());Authentication authenticate = authenticationManager.authenticate(authenticationToken);//authenticationManager会默认调用UserDetailsService从内存中进行用户认证,我们实际需求是从数据库,因此我们要重新创建一个UserDetailsService的实现类//判断是否认证通过if(Objects.isNull(authenticate)){throw new RuntimeException("用户名或者密码错误");}//获取Userid,生成tokenLoginUser loginUser = (LoginUser) authenticate.getPrincipal();String userId = loginUser.getUser().getId().toString();String jwt = JwtUtil.createJWT(userId);//把用户信息存入redisredisCache.setCacheObject("bloglogin:" + userId,loginUser);//把token和userInfo封装返回,因为响应回去的data有这两个属性,所以要封装VoUserInfoVo userInfoVo = BeanCopyUtils.copyBean(loginUser.getUser(), UserInfoVo.class);BlogLoginUserVo blogLoginUserVo = new BlogLoginUserVo(jwt,userInfoVo);return ResponseResult.okResult(blogLoginUserVo);}@Overridepublic ResponseResult logout() {//获取token解析获取userIdAuthentication authentication = SecurityContextHolder.getContext().getAuthentication();LoginUser loginUser = (LoginUser) authentication.getPrincipal();Long userId = loginUser.getUser().getId();//删除redis中的信息(根据key删除)redisCache.deleteObject("bloglogin:" + userId);return ResponseResult.okResult();}
}
 
第四步: 把keke-blog工程的SecurityConfig类修改为如下,增加了需要有登录状态才能执行退出登录,否则就报'401 需要登录后操作'
package com.keke.config;import com.keke.filter.JwtAuthenticationTokenFilter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.AuthenticationEntryPoint;
import org.springframework.security.web.access.AccessDeniedHandler;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;@Configuration
//WebSecurityConfigurerAdapter是Security官方提供的类
public class SecurityConfig extends WebSecurityConfigurerAdapter {//注入我们在keke-blog工程写的JwtAuthenticationTokenFilter过滤器@Autowiredprivate JwtAuthenticationTokenFilter jwtAuthenticationTokenFilter;@AutowiredAuthenticationEntryPoint authenticationEntryPoint;@AutowiredAccessDeniedHandler accessDeniedHandler;@Override@Beanpublic AuthenticationManager authenticationManagerBean() throws Exception {return super.authenticationManagerBean();}@Bean//把官方的PasswordEncoder密码加密方式替换成BCryptPasswordEncoderpublic PasswordEncoder passwordEncoder(){return new BCryptPasswordEncoder();}@Overrideprotected void configure(HttpSecurity http) throws Exception {http//关闭csrf.csrf().disable()//不通过Session获取SecurityContext.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and().authorizeRequests()// 对于登录接口 允许匿名访问.antMatchers("/login").anonymous()
//这里新增必须要是登录状态才能访问退出登录的接口,即是认证过的状态.antMatchers("/logout").authenticated()//为方便测试认证过滤器,我们把查询友链的接口设置为需要登录才能访问。然后我们去访问的时候就能测试登录认证功能了.antMatchers("/link/getAllLink").authenticated()// 除上面外的所有请求全部不需要认证即可访问.anyRequest().permitAll();//配置我们自己写的认证和授权的异常处理http.exceptionHandling().authenticationEntryPoint(authenticationEntryPoint).accessDeniedHandler(accessDeniedHandler);http.logout().disable();//将自定义filter加入security过滤器链中http.addFilterBefore(jwtAuthenticationTokenFilter, UsernamePasswordAuthenticationFilter.class);//允许跨域http.cors();}} 
4. 测试
首先测试logout是否真的实现了退出登录的效果,即删除了token在redis中的缓存,使得携带原token的请求失效
第一步,先登录 JSON格式的body可复制如下代码,登录成功
{"userName":"sg","password":"1234"
} 

第二步,拿着登录成功的token,去访问getAllLink接口,访问成功,到这里一切正常

第三步:携带该token向logout接口发送post请求,为什么要携带token呢,因为我们之前在SecurityConfig中配置过了,必须是已认证的状态,已认证的状态意味着必须是请求头携带token

postman结果如下,操作成功意味着退出登录成功

第四步:拿token再次访问getAllLink接口,发现已经不能访问

并且我们可以看到redis中也没有缓存的信息了

十二、博客前台模块-评论列表
1. 评论表的字段


2. 接口分析
|   请求方式  |   请求地址  |   请求头  | 
|   GET  |   /comment/commentList  |   不需要token请求头(未登录也能看到评论信息)  | 
请求格式为query格式,参数如下
articleId:文章id
pageNum:页码
pageSize:每页条数 
响应格式如下
{"code": 200,"data": {"rows": [{"articleId": "1","children": [{"articleId": "1","content": "评论内容(子评论)","createBy": "1","createTime": "2022-01-30 10:06:21","id": "20","rootId": "1","toCommentId": "1","toCommentUserId": "1","toCommentUserName": "这条评论(子评论)回复的是哪个人","username": "发这条评论(子评论)的人"}],"content": "评论内容(根评论)","createBy": "1","createTime": "2022-01-29 07:59:22","id": "1","rootId": "-1","toCommentId": "-1","toCommentUserId": "-1","username": "发这条评论(根评论)的人"}],"total": "15"},"msg": "操作成功"
} 
3. 准备代码
第一步:实体类Comment创建在keke-framework的com.keke.domain.entity下
package com.keke.domain.entity;import java.util.Date;
import java.io.Serializable;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import com.baomidou.mybatisplus.annotation.TableName;/*** 评论表(Comment)表实体类** @author makejava* @since 2023-10-12 20:20:14*/
@SuppressWarnings("serial")
@Data
@NoArgsConstructor
@AllArgsConstructor
@TableName("ke_comment")
public class Comment {private Long id;//评论类型(0代表文章评论,1代表友链评论)private String type;//文章idprivate Long articleId;//根评论idprivate Long rootId;//评论内容private String content;//所回复的目标评论的useridprivate Long toCommentUserId;//回复目标评论idprivate Long toCommentId;private Long createBy;private Date createTime;private Long updateBy;private Date updateTime;//删除标志(0代表未删除,1代表已删除)private Integer delFlag;}
 
第二步:创建CommentMapper
package com.keke.mapper;import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.keke.domain.entity.Comment;/*** 评论表(Comment)表数据库访问层** @author makejava* @since 2023-10-12 20:20:41*/
public interface CommentMapper extends BaseMapper<Comment> {}
 
第三步:创建CommentService
package com.keke.service;import com.baomidou.mybatisplus.extension.service.IService;
import com.keke.domain.entity.Comment;/*** 评论表(Comment)表服务接口** @author makejava* @since 2023-10-12 20:20:41*/
public interface CommentService extends IService<Comment> {}
 
第四步:创建CommentServiceImpl
package com.keke.service.impl;import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.keke.domain.entity.Comment;
import com.keke.mapper.CommentMapper;
import com.keke.service.CommentService;
import org.springframework.stereotype.Service;/*** 评论表(Comment)表服务实现类** @author makejava* @since 2023-10-12 20:20:41*/
@Service("commentService")
public class CommentServiceImpl extends ServiceImpl<CommentMapper, Comment> implements CommentService {}
 
4. 代码实现-不考虑子评论
相关文章:
博客文档续更
十、 博客前台模块-异常处理 目前我们的项目在认证出错或者权限不足的时候响应回来的Json,默认是使用Security官方提供的响应的格式,但是这种响应的格式肯定是不符合我们项目的接口规范的。所以需要自定义异常处理 我们需要去实现AuthenticationEntryP…...
OCR让点读笔如虎添翼
点读笔是一种智能学习工具,它可以通过识别文字来提供相应的语音或图像反馈。在实现文字识别功能时,点读笔通常会借助OCR(Optical Character Recognition,光学字符识别)技术。下面将详细介绍点读笔如何利用OCR技术实现文…...
棱镜七彩参编!开源领域4项团体标准正式发布
近日,中电标2023年第27号团体标准公告正式发布,《T/CESA 1270.2-2023 信息技术 开源治理 第 2 部分:企业治理评估模型》、《T/CESA 1270.3-2023 信息技术 开源治理 第 3 部分:社区治理框架》、《T/CESA 1270.5-2023 信息技术 开源…...
轻量级Composition
MEF,全称Managed Extensibility Framework(托管可扩展框架)。MEF是专门致力于解决扩展性问题的框架。MEF 位于 ComponentModel.Composition 程序集中,添加 System.ComponentModel.Composition 和 System.ComponentModel.Compositi…...
Vxlan网络和flannel记录
Vxlan 大二层网络,在三层网络中构建逻辑的2层网络 数据包经过vxlan隧道 用vni标识不同的vxlan网络(类似于vlan的vid) 通过vtep来封装和解封装,通过UDP传输 Flannel 分配子网和IP地址:Flannel为每个容器或虚拟机分配唯一…...
【已解决】微信小程序-苹果手机日期解析异常
在开发微信小程序时,使用了 uView 的 CountDown倒计时 组件和 uni.$u.timeFrom Api,后台传递了一个时间字符串,前台计算时间戳的差值,来显示还有多久开始,这个功能在模拟器和我自己手机(iphon13)…...
Avalonia如何更改全局背景色
1.项目下载地址:https://gitee.com/confusedkitten/avalonia-demo 2.UI库Semi.Avalonia,项目地址 https://github.com/irihitech/Semi.Avalonia 3.ColorView,使用Semi.Avalonia.ColorPicker,Nuget获取就行 4.样式预览 以下是…...
万界星空科技低代码平台云MES系统功能场景
1、 工艺管理 生产工艺规程、岗位操作法、工艺卡片的编制。 生产过程的工艺条件、产品质量指标以及原材料消耗的执行检查、相关数据的统计分析。 2、 工序管理 对人、机、料、法控制,规定产品质量标准及有关完成方法的各项规程,并明确各道工序的管理负责…...
运维大数据平台的建设与实践探索
随着企业数字化转型的推进,运维管理面临着前所未有的挑战和机遇。为应对日益复杂且严峻的挑战,数字免疫系统和智能运维等概念应运而生。数字免疫系统和智能运维作为新兴技术,正引领着运维管理的新趋势。数字免疫系统和智能运维都借助大数据运…...
【Java 进阶篇】创建 HTML 注册页面
在这篇博客中,我们将介绍如何创建一个简单的 HTML 注册页面。HTML(Hypertext Markup Language)是一种标记语言,用于构建网页的结构和内容。创建一个注册页面是网页开发的常见任务之一,它允许用户提供个人信息并注册成为…...
【JVM系列】- 启航·JVM概论学习
启航JVM概论 😄生命不息,写作不止 🔥 继续踏上学习之路,学之分享笔记 👊 总有一天我也能像各位大佬一样 🏆 博客首页 怒放吧德德 To记录领地 🌝分享学习心得,欢迎指正,…...
Windows技巧
Windows应用 Windows应用无限延长Windows10 自动更新时间管理员身份打开cmd输入以下代码设置暂停更新时间 Windows应用 无限延长Windows10 自动更新时间 管理员身份打开cmd 输入以下代码 这里设置的是3000天,需要恢复更新可以将其设置为1天 reg add “HKEY_LOCA…...
Git 应用小记
常用命令 git reset 3种模式 --soft:将HEAD引用指向给定提交,索引(暂存区)和工作目录的内容不变 --mixed(默认,可不写):将HEAD引用指向给定提交,索引(暂存区…...
APT攻击与零日漏洞
APT攻击 当谈到网络安全时,APT(高级持续性威胁)攻击是最为复杂和难以检测的攻击类型之一。APT攻击通常涉及到高度的技术和策略性,而且它们的目标是深入地渗透和长时间地隐藏在目标网络中。 1. 什么是APT攻击? 高级持续…...
leetCode 1143.最长公共子序列 动态规划 + 滚动数组
1143. 最长公共子序列 - 力扣(LeetCode) 给定两个字符串 text1 和 text2,返回这两个字符串的最长 公共子序列 的长度。如果不存在 公共子序列 ,返回 0 。 一个字符串的 子序列 是指这样一个新的字符串:它是由原字符串…...
【C++ Miscellany】继承体系非尾端类设计为抽象类
部分赋值问题 用软件来处理两种动物:蜥蜴和鸡 class Animal { public:Animal& operator (const Animal& rhs);... };class Lizard: public Animal { public:Lizard& operator (const Lizard& rhs);... };class Chicken: public Animal {Chicken…...
Leetcode236. 二叉树的最近公共祖先
给定一个二叉树, 找到该树中两个指定节点的最近公共祖先。 百度百科中最近公共祖先的定义为:“对于有根树 T 的两个节点 p、q,最近公共祖先表示为一个节点 x,满足 x 是 p、q 的祖先且 x 的深度尽可能大(一个节点也可以是它自己的祖…...
Swift SwiftUI CoreData 过滤数据 2
预览 Code import SwiftUI import CoreDatastruct HomeSearchView: View {Environment(\.dismiss) var dismissState private var search_value ""FetchRequest(entity: Bill.entity(),sortDescriptors: [NSSortDescriptor(keyPath: \Bill.c_at, ascending: false)…...
解决maven骨架加载慢问题(亲测解决)
1、下载archetype-catalog.xml 网站 : https://repo.maven.apache.org/maven2/ 2、放在这个文件夹下面 3、setting–>build–>Runner : -DarchetypeCataloglocal...
Android---java内存模型与线程
Java 内存模型翻译自 Java Memory Model,简称 JMM。它所描述的是多线程并发、CPU 缓存等方面的内容。 在每一个线程中,都会有一块内部的工作内存,这块内存保存了主内存共享数据的拷贝副本。但在 Java 线程中并不存在所谓的工作内存࿰…...
浅谈 React Hooks
React Hooks 是 React 16.8 引入的一组 API,用于在函数组件中使用 state 和其他 React 特性(例如生命周期方法、context 等)。Hooks 通过简洁的函数接口,解决了状态与 UI 的高度解耦,通过函数式编程范式实现更灵活 Rea…...
uni-app学习笔记二十二---使用vite.config.js全局导入常用依赖
在前面的练习中,每个页面需要使用ref,onShow等生命周期钩子函数时都需要像下面这样导入 import {onMounted, ref} from "vue" 如果不想每个页面都导入,需要使用node.js命令npm安装unplugin-auto-import npm install unplugin-au…...
【Redis技术进阶之路】「原理分析系列开篇」分析客户端和服务端网络诵信交互实现(服务端执行命令请求的过程 - 初始化服务器)
服务端执行命令请求的过程 【专栏简介】【技术大纲】【专栏目标】【目标人群】1. Redis爱好者与社区成员2. 后端开发和系统架构师3. 计算机专业的本科生及研究生 初始化服务器1. 初始化服务器状态结构初始化RedisServer变量 2. 加载相关系统配置和用户配置参数定制化配置参数案…...
将对透视变换后的图像使用Otsu进行阈值化,来分离黑色和白色像素。这句话中的Otsu是什么意思?
Otsu 是一种自动阈值化方法,用于将图像分割为前景和背景。它通过最小化图像的类内方差或等价地最大化类间方差来选择最佳阈值。这种方法特别适用于图像的二值化处理,能够自动确定一个阈值,将图像中的像素分为黑色和白色两类。 Otsu 方法的原…...
高等数学(下)题型笔记(八)空间解析几何与向量代数
目录 0 前言 1 向量的点乘 1.1 基本公式 1.2 例题 2 向量的叉乘 2.1 基础知识 2.2 例题 3 空间平面方程 3.1 基础知识 3.2 例题 4 空间直线方程 4.1 基础知识 4.2 例题 5 旋转曲面及其方程 5.1 基础知识 5.2 例题 6 空间曲面的法线与切平面 6.1 基础知识 6.2…...
如何将联系人从 iPhone 转移到 Android
从 iPhone 换到 Android 手机时,你可能需要保留重要的数据,例如通讯录。好在,将通讯录从 iPhone 转移到 Android 手机非常简单,你可以从本文中学习 6 种可靠的方法,确保随时保持连接,不错过任何信息。 第 1…...
Ascend NPU上适配Step-Audio模型
1 概述 1.1 简述 Step-Audio 是业界首个集语音理解与生成控制一体化的产品级开源实时语音对话系统,支持多语言对话(如 中文,英文,日语),语音情感(如 开心,悲伤)&#x…...
C++ 求圆面积的程序(Program to find area of a circle)
给定半径r,求圆的面积。圆的面积应精确到小数点后5位。 例子: 输入:r 5 输出:78.53982 解释:由于面积 PI * r * r 3.14159265358979323846 * 5 * 5 78.53982,因为我们只保留小数点后 5 位数字。 输…...
3-11单元格区域边界定位(End属性)学习笔记
返回一个Range 对象,只读。该对象代表包含源区域的区域上端下端左端右端的最后一个单元格。等同于按键 End 向上键(End(xlUp))、End向下键(End(xlDown))、End向左键(End(xlToLeft)End向右键(End(xlToRight)) 注意:它移动的位置必须是相连的有内容的单元格…...
Go 语言并发编程基础:无缓冲与有缓冲通道
在上一章节中,我们了解了 Channel 的基本用法。本章将重点分析 Go 中通道的两种类型 —— 无缓冲通道与有缓冲通道,它们在并发编程中各具特点和应用场景。 一、通道的基本分类 类型定义形式特点无缓冲通道make(chan T)发送和接收都必须准备好࿰…...
