Appearance
dataviewjs
// === 配置区 ===
const coverField = "banner_img"; // 封面图属性名
const cardWidth = "220px"; // 卡片宽度
// 1. 获取当前页面的出链
const outlinks = dv.current().file.outlinks;
const currentFile = app.vault.getAbstractFileByPath(dv.current().file.path);
if (currentFile && outlinks.length > 0) {
const fileContent = await app.vault.read(currentFile);
// 2. 排序:按链接在正文中的出现位置
// 不能拿 link.display 去找:[别名]() 的 display 是"别名",正文里根本没有「[[别名」,
// indexOf 会返回 -1,这张卡就被过滤掉了。这里改成用"链接目标"匹配,
// 并要求后面紧跟 | # ^ ] 之一,避免 [笔记]() 误命中 [笔记2]()。
const escapeRe = (s) => s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
const linkPosition = (content, link) => {
const base = link.path.split("/").pop().replace(/\.md$/, "");
const targets = [link.path, link.path.replace(/\.md$/, ""), base].filter(Boolean);
let pos = -1;
for (const t of new Set(targets)) {
const re = new RegExp(`\\[\\[\\s*${escapeRe(t)}\\s*(?=[|#^\\]])`);
const m = re.exec(content);
if (m && (pos === -1 || m.index < pos)) pos = m.index;
}
return pos;
};
const selfPath = dv.current().file.path;
const seenPaths = new Set();
const sortedLinks = [];
for (const link of outlinks) {
// 先解析成真实文件路径:[名称]()、[路径/名称]()、[别名]()、[名称#标题]() 都会落到同一篇
const dest = app.metadataCache.getFirstLinkpathDest(link.path, selfPath);
const path = dest ? dest.path : link.path;
if (!path || path === selfPath) continue; // 跳过 [#本页小标题]() 这类自链接
if (seenPaths.has(path)) continue; // 同一篇被链接多次,只出一张卡
seenPaths.add(path);
sortedLinks.push({ link, path, index: linkPosition(fileContent, link) });
}
// 找不到出现位置的排到最后:宁可多显示一张,也别让它莫名消失
sortedLinks.sort((a, b) => {
const x = a.index === -1 ? Number.MAX_SAFE_INTEGER : a.index;
const y = b.index === -1 ? Number.MAX_SAFE_INTEGER : b.index;
return x - y;
});
// 3. 创建网格容器
// 【关键】不能写 dv.el("div", ""):空字符串会走 Dataview 的 renderValue,
// 在容器里塞一个没有内容的 <span>。它也是网格项,会独占第一行第一列,
// 于是整排卡片右移一格、最后一张掉到第二行,左上角留出一块空白。
const container = dv.el("div");
container.empty(); // 双保险:清掉任何非卡片子节点
container.style.display = "grid";
container.style.gridTemplateColumns = `repeat(auto-fill, minmax(${cardWidth}, 1fr))`;
container.style.gap = "16px";
container.style.marginLeft = "0";
container.style.paddingLeft = "0";
container.style.width = "100%";
// 4. 遍历生成卡片
for (const { link, path } of sortedLinks) {
const page = dv.page(path);
if (!page) continue;
// 处理封面图
const cover = page[coverField];
let imgSrc = "";
if (cover) {
if (cover.startsWith("[[")) {
const imgName = cover.replace(/\[\[|\]\]/g, '');
const imgFile = app.metadataCache.getFirstLinkpathDest(imgName, page.file.path);
if (imgFile) imgSrc = app.vault.getResourcePath(imgFile);
} else {
imgSrc = cover;
}
}
// 创建卡片外壳
const card = container.createEl("a", { href: page.file.path, cls: "internal-link" });
card.style.textDecoration = "none";
card.style.color = "inherit";
const cardInner = card.createEl("div");
cardInner.style.background = "var(--background-secondary)";
cardInner.style.borderRadius = "8px";
cardInner.style.overflow = "hidden";
cardInner.style.boxShadow = "0 2px 4px rgba(0,0,0,0.1)";
cardInner.style.transition = "transform 0.2s";
// 封面图区域
if (imgSrc) {
const img = cardInner.createEl("img");
img.src = imgSrc;
img.style.width = "100%";
img.style.height = "140px";
img.style.objectFit = "cover";
img.style.display = "block";
} else {
const noCover = cardInner.createEl("div");
noCover.style.height = "140px";
noCover.style.display = "flex";
noCover.style.alignItems = "center";
noCover.style.justifyContent = "center";
noCover.style.background = "var(--background-modifier-border)";
noCover.style.color = "var(--text-muted)";
noCover.textContent = "无封面";
}
// 文字信息区域
const textDiv = cardInner.createEl("div");
textDiv.style.padding = "12px";
// 标题:优先用链接里写的别名([别名]()),没写别名就用文件名。
// link.display 只有 [别名]() 这种写法才有值,[文件]() 时是 undefined。
const linkAlias = (link.display || "").trim();
const titleDiv = textDiv.createEl("div");
titleDiv.textContent = linkAlias || page.file.name;
titleDiv.title = page.file.name; // 悬停显示真实文件名,别名太抽象也能对回去
titleDiv.style.fontWeight = "bold";
titleDiv.style.marginBottom = "4px";
titleDiv.style.whiteSpace = "nowrap";
titleDiv.style.overflow = "hidden";
titleDiv.style.textOverflow = "ellipsis";
const folderDiv = textDiv.createEl("div");
// 优化显示:只显示最后一级文件夹,避免太长
const folderName = page.file.folder;
folderDiv.textContent = folderName ? folderName.split('/').pop() : "根目录";
folderDiv.style.fontSize = "12px";
folderDiv.style.color = "var(--text-muted)";
}
} else if (outlinks.length === 0) {
dv.paragraph("当前笔记没有出链");
}章节篇放弃维护,只维护这个总版本 面试煎熬成蛋_Java面试速刷_第三版
简历: - Java面试准备 2026版本
面试煎熬成蛋
- Java面试准备 - 面试煎熬成蛋
- 面试突击 面试突击_常见面试题 (只记录题目)
面试记录
面试要求
年限要求,同时问一下自己是否确实具备了这些能力。
6年Java开发工程师,属于中高级到资深的过渡阶段,应该在以下几个层面有扎实积累:
技术基本功
- Java核心:JVM内存模型、GC调优、类加载机制、并发编程(JUC包、锁机制、线程池调优)
- 框架深度:Spring Boot/Cloud 源码级理解,不只是会用,要能排查框架层面的问题
- 数据库:MySQL索引原理、执行计划分析、分库分表方案、慢SQL优化;熟悉至少一种NoSQL(Redis/MongoDB)
- 中间件:消息队列(Kafka/RocketMQ)的使用场景与可靠性保障、分布式缓存、配置中心、注册中心
架构与设计
- 能独立完成中等复杂度系统的技术方案设计
- 理解DDD、微服务拆分原则、服务治理(限流、熔断、降级)
- 分布式事务方案选型(TCC、Saga、最终一致性)
技术基本功
- Java核心:JVM内存模型、GC调优、类加载机制、并发编程(JUC包、锁机制、线程池调优)
- 框架深度:Spring Boot/Cloud 源码级理解,不只是会用,要能排查框架层面的问题
- 数据库:MySQL索引原理、执行计划分析、分库分表方案、慢SQL优化;熟悉至少一种NoSQL(Redis/MongoDB)
- 中间件:消息队列(Kafka/RocketMQ)的使用场景与可靠性保障、分布式缓存、配置中心、注册中心
架构与设计
- 能独立完成中等复杂度系统的技术方案设计
- 理解DDD、微服务拆分原则、服务治理(限流、熔断、降级)
- 分布式事务方案选型(TCC、Saga、最终一致性)
- 性能瓶颈定位能力:链路追踪、火焰图、线程dump分析
工程能力
- CI/CD流程设计、容器化部署(Docker/K8s基础)
- 代码质量意识:单测覆盖、Code Review、重构能力
- 线上问题排查:OOM、CPU飙高、死锁、Full GC等生产问题的系统化排查思路
- 技术选型能力:能权衡方案的trade-off,不盲目追新
软技能
- 能带2-3人的小团队或mentor初中级工程师
- 需求评审时能识别技术风险并提前暴露
- 跨团队协作沟通、技术文档输出
容易被忽视但区分度高的点
- 源码阅读习惯:遇到问题能翻源码定位,而不是只靠搜索引擎
- 全链路思维:从用户请求到数据落盘,每一跳的瓶颈和风险点都能说清
- 成本意识:方案设计考虑资源开销、运维复杂度,不过度设计
简单说,6年应该从"能写好代码"进化到"能设计好系统、能兜住线上问题、能带人"。如果你想针对某个方向深入聊,比如架构设计、面试准备、或者技术成长路径,可以继续问。
大模型方面最近的要求
- 1、参与AI 智能体相关能力建设,包括大模型调用、Agent 任务编排、工具调用、知识库、工作流等功能开发
- 2、负责与大模型服务、知识库、MCP、第三方API 等系统集成。