背景
公司线上业务有报错,截图找不到了。总之,就是有些生僻字,用pinyin4这个工具包是找不到的,然后抛出空指针。
时间线
- 生僻字无法转换拼音,说起来也是非常无语的。第一反应是升级工具包吧,拼音翻译的工具包升级应该也就是为了规避生僻字吧,于是吧maven升级了一下。但是发现..并没有用。
- 没用那就看看文档喽,对比了好多转换拼音的工具包。emm 找到链接后补充吧,总之是经过多方对比,发现jpinyin很好。
还有一点就是对于无法找到拼音的汉字,会直接返回本字体,起码不会报错。于是更改了工具包,重新引入。又外挂了本项目路径下的字典,添加了日志中发现的特别的字。
- 代码提交后,组长觉得有问题.. 因为他看了 jpinyin和pinyin4的github,发现jpinyin的star数过低..认为风险很大..说两个都查才是最好的.. 怪我,我没有把对比的方案写出来(不过写出来好像也没啥用。
- 后来想想还是算了,我又改回了原有的pinyin4,更改了原来的代码,实在找不到再用jpinyin找一下. okok. 再原有逻辑下,又添加了外挂字典。不是很懂为啥要这么复杂..
请记住外挂了字典,接下来戏剧开始了..
static { MultiPinyinConfig.multiPinyinPath= Objects.requireNonNull(ChineseToSpellManagerImpl.class.getClassLoader().getResource("userPinyin.txt")).getPath(); }
- 发到测试环境,没有翻译成功,没有找到对应的拼音。直接更新的是原有汉字。考虑没有读取到外挂文件。
- 我们的项目用的是dropwized,这个框架,蛮特别的,可以看下此文章介绍。
我们的项目是部署在docker容器中的,目前的流程是dropwized会打包jar,然后docker拉取镜像,然后进行部署启动。再此过程中,找不到文件是很很正常的,因为容器中并没有文件路径。于是参考了下文章去想办法在容器中添加目录,挂载文件。
- 找到了运维,他是一次次的加路径改项目,最后找到了文件,也可以按照我的想法执行,但是发现致命的问题。
- 项目应用过多,若用docker挂载,需要在每个应用配置文件添加,日后还会私有化部署,这个很不友好。
- 现在公司还没有文件管理器,但凡要是加一个字在字典中,那就每个文件都加吧..
- 基于以上的问题,又想到可以在jar包里面直接读取,不通过docker,在jar中读取文件,然后写到一个虚拟路径文件中,最后把路径交给工具包解析。于是就有了下面的代码
static { MultiPinyinConfig.multiPinyinPath = System.getProperty("user.dir") + "/config/userPinyin.txt"; String line; BufferedReader br = new BufferedReader( new InputStreamReader( Objects.requireNonNull(ChineseToSpellManagerImpl.class.getClassLoader() .getResourceAsStream("userPinyin.txt")))); try (PrintWriter pw = new PrintWriter(new FileOutputStream(MultiPinyinConfig.multiPinyinPath))) { while ((line = br.readLine()) != null) { pw.println(line); } } catch (IOException e) { log.error("ChineseToSpellManager read file error.{}.", e.getMessage(), e); } finally { try { br.close(); } catch (IOException e) { log.error("ChineseToSpellManager BufferedReader error.{}.", e.getMessage(), e); } } }
本地测试通过,再次提交测试环境。然后maven打包过不去了.. 刚开始是认为自己pom文件写的不规范,怎么也找不到原因。
本地打包,还是不行,然后按照提示找用了findbug命令。
这个findbug工具包是指在项目打包的时候,会检测是潜在的风险点。
使用指令后,打包弹窗如下:
最后发现: 项目再打包时候,会运行static加载类文件。。因为字符的转换,没有写标准的字符。。😭😭😭
static { MultiPinyinConfig.multiPinyinPath = System.getProperty("user.dir") + "/config/userPinyin.txt"; String line; BufferedReader br = new BufferedReader( new InputStreamReader( Objects.requireNonNull(ChineseToSpellManagerImpl.class.getClassLoader().getResourceAsStream("userPinyin.txt")), StandardCharsets.UTF_8)); try (PrintWriter pw = new PrintWriter(new OutputStreamWriter(new FileOutputStream(MultiPinyinConfig.multiPinyinPath),StandardCharsets.UTF_8))) { while ((line = br.readLine()) != null) { pw.println(line); } } catch (IOException e) { log.error("ChineseToSpellManager read file error.{}.", e.getMessage(), e); } finally { try { br.close(); } catch (IOException e) { log.error("ChineseToSpellManager BufferedReader error.{}.", e.getMessage(), e); } } }
- 最后再次发版。再次发版读拼音!测试发现,还是找不到路径,根本就写到容器中的文件。 行,很行了。
- 最后服了,不挂文件了,自己弄了一个枚举做字典,然后查枚举中拼音汉字,读吧..
//生僻字字典,可自行在枚举中添加 //目前数量少,量大可考虑添加缓存中 private static final Map<Character,String> initMap = ChinesePinEnum.readPinYinMap();
思考
- 不管多简单的事,也要输出各种文档对比,不然会被质疑。
- 要心平气和的面对每一次失败,发散思维方式,不要转牛角尖。docker挂在上,过于执着了,还好有个身边有人提醒换了方向。
- 代码是最诚实的。👌
本地石墨写的地址:
https://shimo.im/docs/NJkbEgYPm2c75bqR/ 《中文转换拼音》,可复制链接后用石墨文档 App 或小程序打开