上回书说到,只要把页面模板里的文档 ID 正确传入,即可完成单篇 PDF 导出的功能流转。如此一来,就需要搞清楚这个 ID 可以从哪里得到。
最自然的想法是,页面生成的时候,把 ID 直接写入到菜单项的链接 URL 里即可。即在 <li><a href=”{{urlfor “DocumentController.ExportDoc” “:key” .Model.Identify “:id” “” “output” “pdf”}}” target=”_blank”>文档导出为 PDF</a> </li> 中进行正确的填充。既然 :key 的对应值可以使用 .Model.Identify 表示,那是不是会有个 .Model.Id 之类的可以直接使用?实验以失败告终,说定义的变量不认识……
这下激起兴趣,想知道原本的 .Model.Identify 这样的变量是如何工作的。于是在源代码里搜寻,在 controllers/document.go 的 Read() 函数中发现了 c.Data[“Model”] = bookResult 这样的语句,恍然大悟,于是兴冲冲地寻找 bookResult 的数据结构定义,想看一眼 Identify 之外是不是还有 Id 这样的信息,再次失望。只好退而求其次,自己来输出了:c.Data[“DecumentId”] = id,此处的 id 是既有代码逻辑里已经获取到了的。相应地,上面的语句也更新为 <li><a href=”{{urlfor “DocumentController.ExportDoc” “:key” .Model.Identify “:id” .DocumentId “output” “pdf”}}” target=”_blank”>文档导出为 PDF</a> </li>。测试,发现了两个问题。一是这个 ID 的值是 0,这并不是个有效的文档 ID,二是这个 ID 在切换文档时并不会随之而更改。后一个问题显然比前一个还要严重,这意味着机制的失败,所以决定优先处理。
加入一些调试输出的代码,证实 Read() 方法在绝大部分情况下会被前端的文档查看请求触发(未被触发的情况后文再谈),但是,其中不少请求是以 Ajax 的方式发起的,它所请求的内容返回到客户端之后,并不会用于更新上文链接所在的区域。这的情况说明,导出单篇 PDF 的请求链接已经不可能由后端程序一次性写定,而是需要前端用 Javascript 代码进行胶合处理。也就是说,点击链接需要触发一个脚本处理器,在其中根据当前文档现场拼装目标 URL,然后提交请求到后端。
找来了公司的前端专家进行指导,终于学会了把 A 元素用 onclick 事件和脚本对接起来。现在聚焦了,在脚本里如何探测当前正在呈现的文档的 ID 呢?如果当初文档在后端生成的时候,把 ID 写到了某个地方就好了,当然,Ajax 更新文档显示的区域时,这个 ID 也要能跟着更新才对。找了一圈,并没有发现如此趁手的现成物料。
前端专家怒了,说直接用浏览器地址栏里的 URL 吧,反正 RESTful 风格的,也好解析。随随便便用 / 字符 split 了一下(其实还 reverse 了一下),就把 bookid 和 docid 给分离出来了。随手测试,果然好使,不但 ID 确实获取无误,而且还同时验证了老夫后端 Go 语言的代码重构是一把奏效,单篇文档的 PDF 文件顺利诞生!
尽管如此,不过似乎还是有些地方处理得不够好,咱们下回再说。