第四十七章 Spring之假如让你来写MVC——闪存管理器篇

Spring源码阅读目录

第一部分——IOC篇

第一章 Spring之最熟悉的陌生人——IOC
第二章 Spring之假如让你来写IOC容器——加载资源篇
第三章 Spring之假如让你来写IOC容器——解析配置文件篇
第四章 Spring之假如让你来写IOC容器——XML配置文件篇
第五章 Spring之假如让你来写IOC容器——BeanFactory和FactoryBean
第六章 Spring之假如让你来写IOC容器——Scope和属性填充
第七章 Spring之假如让你来写IOC容器——属性填充特别篇:SpEL表达式
第八章 Spring之假如让你来写IOC容器——拓展篇
第九章 Spring之源码阅读——环境搭建篇
第十章 Spring之源码阅读——IOC篇

第二部分——AOP篇

第十一章 Spring之不太熟的熟人——AOP
第十二章 Spring之不得不了解的内容——概念篇
第十三章 Spring之假如让你来写AOP——AOP联盟篇
第十四章 Spring之假如让你来写AOP——雏形篇
第十五章 Spring之假如让你来写AOP——Joinpoint(连接点)篇
第十六章 Spring之假如让你来写AOP——Pointcut(切点)篇
第十七章 Spring之假如让你来写AOP——Advice(通知)上篇
第十八章 Spring之假如让你来写AOP——Advice(通知)下篇
第十九章 Spring之假如让你来写AOP——番外篇:Spring早期设计
第二十章 Spring之假如让你来写AOP——Aspect(切面)篇
第二十一章 Spring之假如让你来写AOP——Weaver(织入器)篇
第二十二章 Spring之假如让你来写AOP——Target Object(目标对象)篇
第二十三章 Spring之假如让你来写AOP——融入IOC容器篇
第二十四章 Spring之源码阅读——AOP篇

第三部分——事务篇

第二十五章 Spring之曾经的老朋友——事务
第二十六章 Spring之假如让你来写事务——初稿篇
第二十七章 Spring之假如让你来写事务——铁三角篇
第二十八章 Spring之假如让你来写事务——属性篇
第二十九章 Spring之假如让你来写事务——状态篇
第三十章 Spring之假如让你来写事务——管理篇
第三十一章 Spring之假如让你来写事务——融入IOC容器篇
第三十二章 Spring之源码阅读——事务篇

第四部分——MVC篇

第三十三章 Spring之梦开始的地方——MVC
第三十四章 Spring之假如让你来写MVC——草图篇
第三十五章 Spring之假如让你来写MVC——映射器篇
第三十六章 Spring之假如让你来写MVC——拦截器篇
第三十七章 Spring之假如让你来写MVC——控制器篇
第三十八章 Spring之假如让你来写MVC——适配器篇
第三十九章 Spring之假如让你来写MVC——番外篇:类型转换
第四十章 Spring之假如让你来写MVC——ModelAndView篇
第四十一章 Spring之假如让你来写MVC——番外篇:数据绑定
第四十二章 Spring之假如让你来写MVC——视图篇
第四十三章 Spring之假如让你来写MVC——上传文件篇
第四十四章 Spring之假如让你来写MVC——异常处理器篇
第四十五章 Spring之假如让你来写MVC——国际化篇
第四十六章 Spring之假如让你来写MVC——主题解析器篇
第四十七章 Spring之假如让你来写MVC——闪存管理器篇
第四十八章 Spring之假如让你来写MVC——请求映射视图篇
第四十九章 Spring之假如让你来写MVC——番外篇:属性操作
第五十章 Spring之假如让你来写MVC——融入IOC容器篇
第五十一章 Spring之源码阅读——MVC篇


文章目录

  • Spring源码阅读目录
    • 第一部分——IOC篇
    • 第二部分——AOP篇
    • 第三部分——事务篇
    • 第四部分——MVC篇
  • 前言
  • 尝试动手写IOC容器
      • 第四十一版 闪存管理器
        • 闪存数据结构
        • 闪存管理器
        • 重定向视图
        • 修改`UrlBasedViewResolver`
        • 修改`DispatcherServlet`
        • 测试
  • 总结


前言

    对于Spring一直都是既熟悉又陌生,说对它熟悉吧,平时用用没啥问题,但面试的时候被问的一脸懵逼,就很尴尬,都不好意思在简历上写着熟悉Spring了
在这里插入图片描述

    所以决定花点时间研究研究Spring的源码。主要参考的书籍是:《Spring源码深度解析(第2版)》、《Spring揭秘》、《Spring技术内幕:深入解析Spring架构与设计原理(第2版)》


     书接上回,在上篇 第四十六章 Spring之假如让你来写MVC——主题解析器篇 中,A君 已经完成了 主题解析器 部分的功能了。接下来看看 A君 会有什么骚操作吧

尝试动手写IOC容器

    出场人物:A君(苦逼的开发)、老大(项目经理)

    背景:老大 要求 A君在一周内开发个简单的 IOC容器

    前情提要:A君 已经完成了 主题解析器 部分的功能了 。。。

第四十一版 闪存管理器

    “A君,就快结束了,今天在完成一个组件吧。” 老大 说道

    “啊,还没玩啊,还有啥组件?” A君 都快崩溃了

    “哈哈哈,不多了,就剩两个组件了。” 老大 笑道

    “那今天是什么?” A君 问道

    “就是重定向和转发,转发过程中需要存储的数据,去渲染视图。” A君 问道

    “那要如何实现呢?” A君 疑惑道

    “其实也不难,保留在内存中就行了,等过期后在失效掉。不过,看了下代码,你之前似乎并未实现 重定向视图,这部分内容你也补充下吧!” 老大 解释道

    “好吧。” A君 无奈应到,只能默默回去干活了

闪存数据结构

    走出办公室后,A君 径直回到了自己的工位上,开始琢磨 闪存 的事情了。按照 老大 的说法,闪存 存在着过期时间,那就不能是简单的Map能解决的,除了过期时间,闪存 也可能存在着一个key,多个value的情况,如:复选框。同时也可以根据目标请求路径存储数据。基于上述这么多情况,自然就得定义个单独的类来进行处理了。A君 新增FlashMap类,代码如下:

/*** 闪存*/
public final class FlashMap extends HashMap<String, Object> implements Comparable<FlashMap> {private final MultiValueMap<String, String> targetRequestParams = new LinkedMultiValueMap<>(3);/*** 目标请求路径*/private String targetRequestPath;/*** 过期时间*/private long expirationTime = -1;public void startExpirationPeriod(int timeToLive) {this.expirationTime = System.currentTimeMillis() + timeToLive * 1000;}public FlashMap addTargetRequestParams(MultiValueMap<String, String> params) {if (params != null) {params.forEach((key, values) -> {for (String value : values) {addTargetRequestParam(key, value);}});}return this;}public FlashMap addTargetRequestParam(String name, String value) {if (StringUtils.hasText(name) && StringUtils.hasText(value)) {this.targetRequestParams.add(name, value);}return this;}public MultiValueMap<String, String> getTargetRequestParams() {return this.targetRequestParams;}public boolean isExpired() {return (this.expirationTime != -1 && System.currentTimeMillis() > this.expirationTime);}@Overridepublic int compareTo(FlashMap other) {int thisUrlPath = (this.targetRequestPath != null ? 1 : 0);int otherUrlPath = (other.targetRequestPath != null ? 1 : 0);if (thisUrlPath != otherUrlPath) {return otherUrlPath - thisUrlPath;} else {return other.targetRequestParams.size() - this.targetRequestParams.size();}}//省略其他代码。。。
}
闪存管理器

    闪存数据结构 定义好之后,接着就是如何管理它了,直接操作FlashMap对象也不是不行,但是毕竟还是太过麻烦了,也不好管理。与其如此,不如直接定义个管理者,让它进行统一操作。管理器也简单,就干两件事:增加、更新。A君 新增FlashMapManager接口,代码如下:

/*** 闪存管理器*/
public interface FlashMapManager {/*** 清除闪存** @param request* @param response* @return*/FlashMap retrieveAndUpdate(HttpServletRequest request, HttpServletResponse response);/*** 保存闪存** @param flashMap* @param request* @param response*/void saveOutputFlashMap(FlashMap flashMap, HttpServletRequest request, HttpServletResponse response);
}

接下来就是抽象类了,哪些可以提取出来呢?A君 开动脑瓜开始思考:清理要怎么清理?保存要怎么保存?

  • 清理:首当其冲的自然是过期数据了,这个不用怀疑。还有就是每个url需要保留多少数据?对于一次请求来说,请求结束也意味着这些数据已经失效,其生命周期很短,这就意味着 闪存 不可能存储很多数据。那就定一个规则:每次都拉出一个倒霉鬼进行清理,目标url为空的优先,参数多的优先谁叫他占内存呢(笑)?

  • 保存:这就更简单了,获取已有数据和现有数据合并即可了

思绪整理完毕后,A君 新增AbstractFlashMapManager类,代码如下:

public abstract class AbstractFlashMapManager implements FlashMapManager {private static final Object DEFAULT_FLASH_MAPS_MUTEX = new Object();/*** 180s*/private int flashMapTimeout = 180;private UrlPathHelper urlPathHelper = UrlPathHelper.defaultInstance;@Overridepublic final FlashMap retrieveAndUpdate(HttpServletRequest request, HttpServletResponse response) {List<FlashMap> allFlashMaps = retrieveFlashMaps(request);if (CollectionUtils.isEmpty(allFlashMaps)) {return null;}/***获取过期数据*/List<FlashMap> mapsToRemove = getExpiredFlashMaps(allFlashMaps);/*** targetPath、参数多的会优先被清理*/FlashMap match = getMatchingFlashMap(allFlashMaps, request);if (match != null) {mapsToRemove.add(match);}if (!mapsToRemove.isEmpty()) {Object mutex = getFlashMapsMutex(request);if (mutex != null) {synchronized (mutex) {//清除数据allFlashMaps = retrieveFlashMaps(request);if (allFlashMaps != null) {allFlashMaps.removeAll(mapsToRemove);updateFlashMaps(allFlashMaps, request, response);}}} else {allFlashMaps.removeAll(mapsToRemove);updateFlashMaps(allFlashMaps, request, response);}}return match;}@Overridepublic final void saveOutputFlashMap(FlashMap flashMap, HttpServletRequest request, HttpServletResponse response) {if (CollectionUtils.isEmpty(flashMap)) {return;}/*** 修正地址*/String path = decodeAndNormalizePath(flashMap.getTargetRequestPath(), request);flashMap.setTargetRequestPath(path);//设置开始时间flashMap.startExpirationPeriod(getFlashMapTimeout());/*** 获取对象锁*/Object mutex = getFlashMapsMutex(request);if (mutex != null) {synchronized (mutex) {/*** 获取老数据*/List<FlashMap> allFlashMaps = retrieveFlashMaps(request);allFlashMaps = (allFlashMaps != null ? allFlashMaps : new CopyOnWriteArrayList<>());/*** 添加并更新数据*/allFlashMaps.add(flashMap);updateFlashMaps(allFlashMaps, request, response);}} else {List<FlashMap> allFlashMaps = retrieveFlashMaps(request);allFlashMaps = (allFlashMaps != null ? allFlashMaps : new ArrayList<>(1));allFlashMaps.add(flashMap);updateFlashMaps(allFlashMaps, request, response);}}protected abstract List<FlashMap> retrieveFlashMaps(HttpServletRequest request);protected abstract void updateFlashMaps(List<FlashMap> flashMaps, HttpServletRequest request, HttpServletResponse response);//省略其他代码。。。
}

抽象类已经把大部分逻辑提取出来了,剩下的部分就是从哪里获取数据?从哪里更新数据?这个有可能是Cookie,也有可能是Session。老样子,这里还是以Session为例,这个很简单,直接从Session中的获取值就行了。A君 新增SessionFlashMapManager类,代码如下:

public class SessionFlashMapManager extends AbstractFlashMapManager {private static final String FLASH_MAPS_SESSION_ATTRIBUTE = SessionFlashMapManager.class.getName() + ".FLASH_MAPS";@Overrideprotected List<FlashMap> retrieveFlashMaps(HttpServletRequest request) {HttpSession session = request.getSession(false);return (session != null ? (List<FlashMap>) session.getAttribute(FLASH_MAPS_SESSION_ATTRIBUTE) : null);}@Overrideprotected void updateFlashMaps(List<FlashMap> flashMaps, HttpServletRequest request, HttpServletResponse response) {WebUtils.setSessionAttribute(request, FLASH_MAPS_SESSION_ATTRIBUTE, (!flashMaps.isEmpty() ? flashMaps : null));}@Overrideprotected Object getFlashMapsMutex(HttpServletRequest request) {return WebUtils.getSessionMutex(request.getSession());}
}
重定向视图

    闪存管理器 是定义好了,可是在哪里用呢?A君 不经一阵挠头。总不能在DispatcherServlet中弄吧。又思索了一阵,A君 忽然发现,不论 重定向 还是 转发,其实都是在返回值里边定义,转发 还好说,直接通过分发器就行了,接着就是 重定向 了,不如定一个 视图 来进行处理。实现是解决了,但是还有个问题:这个 视图 要干什么?A君 又想了下,所谓 重定向 无非就是uri的定义罢了。重定向 到哪里?要不要带参数?要带哪些参数?这个就是 重定向视图 要处理的重点了。好啦,一切都敲定了。A君 新增RedirectView类,代码如下:

/*** 重定向视图*/
public class RedirectView extends AbstractUrlBasedView implements SmartView {/*** 是否是绝对路径*/private boolean contextRelative = false;/*** 是否兼容 HTTP/1.0*/private boolean http10Compatible = true;/*** 暴露模型属性*/private boolean exposeModelAttributes = true;/*** URL 编码*/private String encodingScheme;/*** 响应码*/private HttpStatus statusCode;/*** 是否将当前请求的查询参数传递到目标 URL*/private boolean propagateQueryParams = false;/*** 主机名*/private String[] hosts;@Overrideprotected void renderMergedOutputModel(Map<String, Object> model, HttpServletRequest request,HttpServletResponse response) throws IOException {String targetUrl = createTargetUrl(model, request);targetUrl = updateTargetUrl(targetUrl, model, request, response);//保存到闪存中RequestContextUtils.saveOutputFlashMap(targetUrl, request, response);// 重定向sendRedirect(request, response, targetUrl, this.http10Compatible);}/*** 构建重定向url** @param model* @param request* @return* @throws UnsupportedEncodingException*/protected final String createTargetUrl(Map<String, Object> model, HttpServletRequest request)throws UnsupportedEncodingException {StringBuilder targetUrl = new StringBuilder();if (this.contextRelative && getUrl().startsWith("/")) {targetUrl.append(getContextPath(request));}targetUrl.append(getUrl());String enc = this.encodingScheme;/*** 编码为空,使用请求编码*/if (enc == null) {enc = request.getCharacterEncoding();}/*** 请求编码还是为空,使用默认编码*/if (enc == null) {enc = WebUtils.DEFAULT_CHARACTER_ENCODING;}/*** 是否追加参数*/if (isPropagateQueryProperties()) {appendCurrentQueryParams(targetUrl, request);}/*** 是否暴露模型数据*/if (this.exposeModelAttributes) {appendQueryProperties(targetUrl, model, enc);}return targetUrl.toString();}//省略其他方法。。。
}

这个类基本上就是在构建url,拼接参数

修改UrlBasedViewResolver

    之前在写UrlBasedViewResolver时候,A君 并没有支持 重定向转发,这回就可以加上了。改动的点也比较简单,在渲染的时候,做个判断就行了。A君 修改createView方法,改动如下:

	@Overrideprotected View createView(String viewName, Locale locale) throws Exception {/*** 是否能够处理*/if (!canHandle(viewName, locale)) {return null;}/*** 重定向*/if (viewName.startsWith(REDIRECT_URL_PREFIX)) {String redirectUrl = viewName.substring(REDIRECT_URL_PREFIX.length());RedirectView view = new RedirectView(redirectUrl,isRedirectContextRelative(), isRedirectHttp10Compatible());String[] hosts = getRedirectHosts();if (hosts != null) {view.setHosts(hosts);}return applyLifecycleMethods(REDIRECT_URL_PREFIX, view);}/*** 转发*/if (viewName.startsWith(FORWARD_URL_PREFIX)) {String forwardUrl = viewName.substring(FORWARD_URL_PREFIX.length());InternalResourceView view = new InternalResourceView(forwardUrl);return applyLifecycleMethods(FORWARD_URL_PREFIX, view);}return super.createView(viewName, locale);}
修改DispatcherServlet

    现在组件基本准备好了,既然是组件,那么DispatcherServlet就当之无愧了。首先需要的是初始化该组件,A君 新增initFlashMapManager方法,代码如下:

    protected void initStrategies() {/***1.初始化文件上传*/initMultipartResolver();/*** 2.初始化国际化*/initLocaleResolver();/*** 3.初始化主题*/initThemeResolver();/*** 4.初始化url处理器*/initHandlerMappings();/*** 5.初始化适配器*/initHandlerAdapters();/*** 6.初始化异常处理*/initHandlerExceptionResolvers();/*** 初始化视图*/initViewResolvers();/*** 初始化闪存管理器*/initFlashMapManager();}private void initFlashMapManager() {this.flashMapManager = new SessionFlashMapManager();}

还有一个问题:谁去清理 闪存?谁去创建 闪存 对象?当下 A君doService方法进行修改,改动如下:

    protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception {Map<String, Object> attributesSnapshot = null;if (WebUtils.isIncludeRequest(request)) {//清理includeattributesSnapshot = new HashMap<>();Enumeration<?> attrNames = request.getAttributeNames();while (attrNames.hasMoreElements()) {String attrName = (String) attrNames.nextElement();if (this.cleanupAfterInclude || attrName.startsWith(DEFAULT_STRATEGIES_PREFIX)) {attributesSnapshot.put(attrName, request.getAttribute(attrName));}}}//设置国际化处理器request.setAttribute(LOCALE_RESOLVER_ATTRIBUTE, this.localeResolver);//设置主题处理器request.setAttribute(THEME_RESOLVER_ATTRIBUTE, this.themeResolver);/*** 存在闪存管理器*/if (this.flashMapManager != null) {FlashMap inputFlashMap = this.flashMapManager.retrieveAndUpdate(request, response);if (inputFlashMap != null) {/*** 已存在,转成不可修改的*/request.setAttribute(INPUT_FLASH_MAP_ATTRIBUTE, Collections.unmodifiableMap(inputFlashMap));}//不存在,建立新的缓存request.setAttribute(OUTPUT_FLASH_MAP_ATTRIBUTE, new FlashMap());request.setAttribute(FLASH_MAP_MANAGER_ATTRIBUTE, this.flashMapManager);}doDispatch(request, response);}

就新增了对于 闪存 的处理,并无太多东西

测试

    好了,现在一切都完成了,又可以开始愉快地测试了。这次测试主要就集中在 控制器 上,其他地方基本就不用改动。A君 新增HelloController代码:

@Controller
public class HelloController {// 首页视图@RequestMapping("/index")public String home(Model model) {// 将 Flash 属性添加到重定向的请求中model.addAttribute("message", "Form submitted successfully!");return "redirect:hello";}@RequestMapping("/hello")public String hello(String message, Model model) {model.addAttribute("message", message);return "hello";}
}

添加一个hello.jsp,代码如下:


<%@page isELIgnored="false"%>
<html>
<body>
<h2>This message is: ${requestScope.message}</h2>
</body>
</html>

然后就可以添加测试代码,如下:

	@Testpublic void v41() throws LifecycleException {System.out.println("############# 第四十一版: 闪存管理器篇 #############");Tomcat tomcat = new Tomcat();//设置端口tomcat.setPort(8082);//设置静态资源路径String webApp = new File("src/main/resources/v41").getAbsolutePath();Context context = tomcat.addWebapp("/test/", webApp);tomcat.start();//挂起tomcat.getServer().await();}

测试结果如下:

在这里插入图片描述

可以看到,经过 重定向 后,url后边也拼上参数。OK,现在 A君 也可以下班了

在这里插入图片描述


总结

    正所谓树欲静而风不止,欲知后事如何,请看下回分解(✪ω✪)

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

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

相关文章

Python 脚本-扫描当前目录和所有子目录并显示它们的大小。

目录 1.Python 代码实现 2.Python 代码解释&#xff08;部分&#xff09; 1. 模块导入 2. ANSI 颜色编码 3. format_size 函数 4.get_directory_size 函数 5. scan_directory 函数 6. display_progress 函数 7. main 函数 3.运行脚本 3.1 基本用法 3.2 使用详…

基于微信小程序高校订餐系统的设计与开发ssm+论文源码调试讲解

第4章 系统设计 一个成功设计的系统在内容上必定是丰富的&#xff0c;在系统外观或系统功能上必定是对用户友好的。所以为了提升系统的价值&#xff0c;吸引更多的访问者访问系统&#xff0c;以及让来访用户可以花费更多时间停留在系统上&#xff0c;则表明该系统设计得比较专…

C语言基本知识

基础 存储类 auto&#xff1a;用完即丢。其实就是局部变量。 static&#xff1a;本文件的全局变量。 extern&#xff1a;只声明&#xff0c;不定义&#xff0c;引用外部变量。 register&#xff1a;放在寄存器而不是内存。 //auto {auto int month; // 等于int mount; …

使用批处理文件清除系统垃圾

第一步&#xff1a;打开记事本&#xff0c;里面的命令如下 echo off echo 正在清理临时文件&#xff0c;请稍候...:: 清理系统临时文件 echo 清理系统临时文件... del /q /f /s "%TEMP%\*.*" del /q /f /s "%WINDIR%\Temp\*.*" rd /s /q "%WINDIR%\T…

更新布局元素的属性

每个布局元素都有一组可以通过编程来更新的属性.布局元素有很多种不同的类型,如图例,图形,文本,地图整饰等等. 操作方法: 1.打开目标活动地图文档 2.打开python窗口 3.导入arcpy模块 import arcpy.mapping as mapping 4.引用当前活动地图文档,把该引用赋值给变量 mxd map…

计算最接近的数

计算最接近的数 真题目录: 点击去查看 E B卷 100分题型 题目描述 给定一个数组X和正整数K&#xff0c;请找出使表达式&#xff1a; X[i] - X[i 1] - … - X[i K - 1] 结果最接近于数组中位数的下标 i &#xff0c;如果有多个 i 满足条件&#xff0c;请返回最大的 i. 其中&…

Linux——信号量和(环形队列消费者模型)

Linux——线程条件变量&#xff08;同步&#xff09;-CSDN博客 文章目录 目录 文章目录 前言 一、信号量是什么&#xff1f; 二、信号量 1、主要类型 2、操作 3、应用场景 三、信号量函数 1、sem_init 函数 2、sem_wait 函数 3、sem_post 函数 4、sem_destroy 函数 ​​​​​​…

简识JVM私有内存区域栈、数据结构

前记&#xff1a;JVM稀有内存区域栈包含&#xff1a;虚拟机栈、本地方法栈、程序计数器&#xff1b; 在JVM&#xff08;Java虚拟机&#xff09;中&#xff0c;私有内存区域栈主要指的是虚拟机栈&#xff08;VM Stack&#xff09;和本地方法栈&#xff08;Native Method Stack&…

垂直供排水抢险车:守护城市,抗击洪涝|深圳鼎跃

我国面积幅员辽阔&#xff0c;其灾害种类多样&#xff0c;而洪涝灾害是其中最常见的灾害&#xff0c;其容易受强降雨的影响&#xff0c;严重影响人民群众的日常生活。而在洪水肆虐的场景中&#xff0c;快速、高效地排涝和供水是防止次生灾害、保护人民生命财产安全的关键环节。…

Social LSTM:Human Trajectory Prediction in Crowded Spaces | 文献翻译

概要 行人遵循不同轨迹以避免障碍物和容纳同行者。任何在这种场景中巡航的自动驾驶车辆都需要能够遇见行人的未来位置并相应地调整其路线以避免碰撞。轨迹预测问题能够被看作一个顺序生成任务&#xff0c;其中我们对基于行人过去的位置预测其未来的轨迹感兴趣。根据最近RNN&am…

React+AntDesign实现类似Chatgpt交互界面

以下是一个基于React和Ant Design搭建的简单ChatGPT风格前端交互界面代码框架示例&#xff0c;该示例实现了基本的用户输入、发送请求以及展示回复的功能。假设后端有一个模拟接口来处理请求并返回回复。 1. 项目初始化&#xff1a; 确保你已经安装了Node.js和npm。通过以下命…

与“神”对话:Swift 语言在 2025 中的云霓之望

0. 引子 夜深人静&#xff0c;是一片极度沉醉的黑&#xff0c;这便于我与深沉的 macbook 悄悄隐秘于其中。一股异香袭来&#xff0c;恍惚着&#xff0c;撸码中身心极度疲惫、头脑昏沉的我仿佛感觉到了一束淡淡的微光轻洒在窗边。 我的对面若隐若现逐渐浮现出一个熟悉的身影。他…

iOS 网络请求: Alamofire 结合 ObjectMapper 实现自动解析

引言 在 iOS 开发中&#xff0c;网络请求是常见且致其重要的功能之一。从获取资料到上传数据&#xff0c;出色的网络请求框架能夠大大提升开发效率。 Alamofire 是一个极具人气的 Swift 网络请求框架&#xff0c;提供了便据的 API 以完成网络请求和响应处理。它支持多种请求类…

【0397】Postgres内核 checkpoint process ⑦ 获取 delaying checkpoint VXIDs(delayChkpt)

1. Top-level transactions 顶级事务(Top-level transactions)通过由 PGPROC 字段 backendId 和 lxid 组成的 VirtualTransactionIDs 来标识。对于已准备的事务,LocalTransactionId 是一个普通的 XID。这些在短期内保证唯一,但在数据库重启或 XID 滚转后会被重新使用;因此…

68,[8] BUUCTF WEB [RoarCTF 2019]Simple Upload(未写完)

<?php // 声明命名空间&#xff0c;遵循 PSR-4 自动加载规范&#xff0c;命名空间为 Home\Controller namespace Home\Controller;// 导入 Think\Controller 类&#xff0c;以便扩展该类 use Think\Controller;// 定义 IndexController 类&#xff0c;继承自 Think\Control…

IntelliJ IDEA 2023.3 中配置 Spring Boot 项目的热加载

IntelliJ IDEA 2023.3 中配置 Spring Boot 项目的热加载 在 IntelliJ IDEA 2023.3 中配置 Spring Boot 项目的热加载&#xff0c;可以让你在不重启应用的情况下看到代码修改的效果。以下是详细的配置步骤&#xff1a; 添加 spring-boot-devtools 依赖 在 pom.xml 文件中添加 …

使用HTML5 Canvas 实现呼吸粒子球动画效果的原理

在网页开发领域&#xff0c;动画效果能够极大地提升用户体验&#xff0c;让页面变得更加生动有趣。今天&#xff0c;我们深入剖析一个基于 HTML5 Canvas 的 3D 粒子动画 —— 呼吸粒子球。通过详细解读其代码实现&#xff0c;我们将全面了解如何运用 HTML5 的强大功能构建出如此…

【C++】引用(上)

1、引用的基本使用 作用&#xff1a;给变量起别名 语法&#xff1a;数据类型&#xff08;该数据类型要与原名的数据类型一致&#xff09; &别名原名&#xff1b; 示例&#xff1a; #include<iostream> using namespace std; int main() {int a 10;int& …

JDBC实验测试

一、语言和环境 实现语言&#xff1a;Java。 环境要求&#xff1a;IDEA2023.3、JDK 17 、MySQL8.0、Navicat 16 for MySQL。 二、技术要求 该系统采用 SWING 技术配合 JDBC 使用 JAVA 编程语言完成桌面应用开发。 三、功能要求 某电商公司为了方便客服查看用户的订单信…

外包公司名单一览表(成都)

大家好&#xff0c;我是苍何。 之前写了一篇武汉的外包公司名单&#xff0c;评论区做了个简单统计&#xff0c;很多人说&#xff0c;在外包的日子很煎熬&#xff0c;不再想去了。 有小伙伴留言说有些外包会强制离职&#xff0c;不行就转岗&#xff0c;让人极度没有安全感。 这…