脱敏的百度百科的定义:是指对某些敏感信息通过脱敏规则进行数据的变形,实现敏感隐私数据的可靠保护。在涉及客户安全数据或者一些商业性敏感数据的情况下,在不违反系统规则条件下,对真实数据进行改造并提供测试使用,如身份证号、手机号、卡号、客户号等个人信息都需要进行数据脱敏。

近日笔者更新了EasyPoi的4.3版本,主要功能是实现了数据脱敏,方便大家日常的脱敏需求。

脱敏的百度百科的定义:是指对某些敏感信息通过脱敏规则进行数据的变形,实现敏感隐私数据的可靠保护。在涉及客户安全数据或者一些商业性敏感数据的情况下,在不违反系统规则条件下,对真实数据进行改造并提供测试使用,如身份证号、手机号、卡号、客户号等个人信息都需要进行数据脱敏。

这块如果严格按照定义,实现身份证等数据的变形,笔者还没实现,因为这个设计脱敏规则对应,需要用户指定规则,我们内部的脱敏系统还是有些逻辑在的,这里就不细说了,这次主要实现的是加*号【后期再加自定义吧,毕竟常见的都是星号】,方便导出数据的时候隐藏非必须字段。

 Java用poi完成Excel导出数据脱敏(java使用poi导出excel) Java poi 数据脱敏 第1张

维护数据

主要功能

实现的功能主要分为三种:

  • 1. 隐去收尾,适合固定长度,比如:手机号,身份证
  • 2. 隐去部分,不固定长度,比如:姓名,地址
  • 3. 隐去特定部分,特别表示保留,比如:邮箱

简单地实现的效果为

  • 13112345678 --> 131****1234
  • 张三 -->张*
  • 罗纳尔迪尼奥 --> 罗纳***奥
  • wuyun@163.com -> w****@16com.com

 Java用poi完成Excel导出数据脱敏(java使用poi导出excel) Java poi 数据脱敏 第2张

脱敏效果

实现方法

1.注解

注解还是通过@Excel 的属性来实现的 ,在@Excel 这个地方加入了desensitizationRule属性,可以在desensitizationRule属性配置对应的格式遍可以得到对应的结果

  1. /**
  2. *数据脱敏规则
  3. *规则1:采用保留头和尾的方式,中间数据加星号
  4. *如:身份证6_4则保留370101********1234
  5. *手机号3_4则保留131****1234
  6. *规则2:采用确定隐藏字段的进行隐藏,优先保留头
  7. *如:姓名1,3表示最大隐藏3位,最小一位
  8. *李-->*
  9. *李三-->李*
  10. *张全蛋-->张*蛋
  11. *李张全蛋-->李**蛋
  12. *尼古拉斯.李张全蛋->尼古拉***张全蛋
  13. *规则3:特殊符号后保留
  14. *如:邮箱1~@表示只保留第一位和@之后的字段
  15. *afterturn@wupaas.com->a********@wupaas.com
  16. *复杂版本请使用接口
  17. *{@linkcn.afterturn.easypoi.handler.inter.IExcelDataHandler}
  18. */
  19. publicStringdesensitizationRule()default"";

可以根据注释看到,3个简单规则的使用方法,还是比较清晰的,主要是:

  • 用下划线分隔的保留头尾的第一种格式
  • 该格式首和尾都可以是0,表示不保留
  • 用逗号分隔的隐藏部分数据的第二种格式
  • 保留规则以对称为主
  • 用~号来区分的,保留特殊字符后的格式的
  • 如果存在多个特殊字符,只保留最后一位的数据

具体实现代码如下:

  1. /**
  2. *特定字符分隔,添加星号
  3. *@paramstart
  4. *@parammark
  5. *@paramvalue
  6. *@return
  7. */
  8. privatestaticStringmarkSpilt(intstart,Stringmark,Stringvalue){
  9. if(value==null){
  10. returnnull;
  11. }
  12. intend=value.lastIndexOf(mark);
  13. if(end<=start){
  14. returnvalue;
  15. }
  16. returnStringUtils.left(value,start).concat(StringUtils.leftPad(StringUtils.right(value,value.length()-end),value.length()-start,"*"));
  17. }
  18. /**
  19. *部分数据截取,优先对称截取
  20. *@paramstart
  21. *@paramend
  22. *@paramvalue
  23. *@return
  24. */
  25. privatestaticStringsubMaxString(intstart,intend,Stringvalue){
  26. if(value==null){
  27. returnnull;
  28. }
  29. if(start>end){
  30. thrownewIllegalArgumentException("startmustlessend");
  31. }
  32. intlen=value.length();
  33. if(len<=start){
  34. returnStringUtils.leftPad("",len,"*");
  35. }elseif(len>start&&len<=end){
  36. if(len==1){
  37. returnvalue;
  38. }
  39. if(len==2){
  40. returnStringUtils.left(value,1).concat("*");
  41. }
  42. returnStringUtils.left(value,1).concat(StringUtils.leftPad(StringUtils.right(value,1),StringUtils.length(value)-1,"*"));
  43. }else{
  44. start=(int)Math.ceil((len-end+0.0D)/2);
  45. end=len-start-end;
  46. end=end==0?1:end;
  47. returnStringUtils.left(value,start).concat(StringUtils.leftPad(StringUtils.right(value,end),len-start,"*"));
  48. }
  49. }
  50. /**
  51. *收尾截取数据
  52. *@paramstart
  53. *@paramend
  54. *@paramvalue
  55. *@return
  56. */
  57. privatestaticStringsubStartEndString(intstart,intend,Stringvalue){
  58. if(value==null){
  59. returnnull;
  60. }
  61. if(value.length()<=start+end){
  62. returnvalue;
  63. }
  64. returnStringUtils.left(value,start).concat(StringUtils.leftPad(StringUtils.right(value,end),StringUtils.length(value)-start,"*"));
  65. }

注解demo

使用起来也比较简单,通过简单的注解配置,就可以实现

  1. @Excel(name="姓名",desensitizationRule="1,6")
  2. privateStringname;
  3. @Excel(name="身份证",desensitizationRule="6_4")
  4. privateStringcard;
  5. @Excel(name="手机号",desensitizationRule="3_4")
  6. privateStringphone;
  7. @Excel(name="邮箱",desensitizationRule="3~@")
  8. privateStringemail;
  9. //---------------下面是生成excel的代码-------
  10. //都是测试数据,就简单生成了部分
  11. List<DesensitizationEntity>list=newArrayList<>();
  12. for(inti=0;i<20;i++){
  13. DesensitizationEntityentity=newDesensitizationEntity();
  14. entity.setCard("37010119900101123"+i%10);
  15. entity.setName("张三");
  16. entity.setPhone("1311234567"+i%10);
  17. entity.setEmail(i%10+"ttttt@afterturn.com");
  18. list.add(entity);
  19. }
  20. Datestart=newDate();
  21. ExportParamsparams=newExportParams("脱敏测试","脱敏测试",ExcelType.XSSF);
  22. Workbookworkbook=ExcelExportUtil.exportExcel(params,DesensitizationEntity.class,list);
  23. System.out.println(newDate().getTime()-start.getTime());
  24. Filesavefile=newFile("D:/home/excel/");
  25. if(!savefile.exists()){
  26. savefile.mkdirs();
  27. }
  28. FileOutputStreamfos=newFileOutputStream("D:/home/excel/ExcelDesensitizationTest.xlsx");
  29. workbook.write(fos);
  30. fos.close();

生成的效果如下,可以看到几个场景都有所覆盖,基本上常用的字段也就

 Java用poi完成Excel导出数据脱敏(java使用poi导出excel) Java poi 数据脱敏 第3张

PS: 因为变种注解和注解可以通用,所以大家在使用变种注解的时候也可以使用这种方式来脱敏数据。

这里就不举例子了,只需要new ExcelExportEntity的之后调用setDesensitizationRule(rule),把对应的规则设置就好,规则和上面保持一致。

2. 模板

 Java用poi完成Excel导出数据脱敏(java使用poi导出excel) Java poi 数据脱敏 第4张

模板脱敏

目前从群里反应和问题数量看,模板已经是最常用的方式了,虽然我一致推荐注解,但明显模板比注解简单的,对代码的侵入一些,我自己写的特殊标签,也日益丰富了。

脱敏的标签取自:desensitizationRule 的两个单词的头两个字符 deru,用来表示这个数据需要脱敏。使用方法也比较简单deru:1_3,即deru:后面跟具体的规则,规则使用方式和上面介绍的 保持一致,这里就不重复赘述了,下面给大家看下例子:

  1. /**
  2. *这个包含两个规则
  3. *1.deru:代表这个数据需要脱敏
  4. *2.dict:代表这个需要调用字典接口转移
  5. **/
  6. deru:1_1;dict:mtype;t.supMaterialList.mtype

脱敏在标签处理级别中属于最低级,所有标签处理后,才会处理这个标签,和他的书写顺序无关,比如上面的例子他写着第一个,也是先处理了字典之后才处理标签。

核心代码如下:

  1. /**
  2. *根据模板解析函数获取值
  3. *@paramfunStr
  4. *@parammap
  5. *@return
  6. */
  7. privateObjectgetValByHandler(StringfunStr,Map<String,Object>map,Cellcell)throwsException{
  8. //step2.判断是否含有解析函数
  9. if(isHasSymbol(funStr,NUMBER_SYMBOL)){
  10. funStr=funStr.replaceFirst(NUMBER_SYMBOL,"");
  11. }
  12. booleanisStyleBySelf=false;
  13. if(isHasSymbol(funStr,STYLE_SELF)){
  14. isStyleBySelf=true;
  15. funStr=funStr.replaceFirst(STYLE_SELF,"");
  16. }
  17. booleanisDict=false;
  18. Stringdict=null;
  19. if(isHasSymbol(funStr,DICT_HANDLER)){
  20. isDict=true;
  21. dict=funStr.substring(funStr.indexOf(DICT_HANDLER)+5).split(";")[0];
  22. funStr=funStr.replaceFirst(DICT_HANDLER,"");
  23. funStr=funStr.replaceFirst(dict+";","");
  24. }
  25. booleanisI18n=false;
  26. if(isHasSymbol(funStr,I18N_HANDLER)){
  27. isI18n=true;
  28. funStr=funStr.replaceFirst(I18N_HANDLER,"");
  29. }
  30. //这里判断是否包含注解规则,如果有注解规则就把注解规则挑出来,然后删除掉规则
  31. booleanisDern=false;
  32. Stringdern=null;
  33. if(isHasSymbol(funStr,DESENSITIZATION_RULE)){
  34. isDern=true;
  35. dern=funStr.substring(funStr.indexOf(DESENSITIZATION_RULE)+5).split(";")[0];
  36. funStr=funStr.replaceFirst(DESENSITIZATION_RULE,"");
  37. funStr=funStr.replaceFirst(dern+";","");
  38. }
  39. if(isHasSymbol(funStr,MERGE)){
  40. StringmergeStr=PoiPublicUtil.getElStr(funStr,MERGE);
  41. funStr=funStr.replace(mergeStr,"");
  42. mergeStr=mergeStr.replaceFirst(MERGE,"");
  43. try{
  44. intcolSpan=(int)Double.parseDouble(PoiPublicUtil.getRealValue(mergeStr,map).toString());
  45. PoiMergeCellUtil.addMergedRegion(cell.getSheet(),cell.getRowIndex(),
  46. cell.getRowIndex(),cell.getColumnIndex(),cell.getColumnIndex()+colSpan-1);
  47. }catch(Exceptione){
  48. LOGGER.error(e.getMessage(),e);
  49. }
  50. }
  51. Objectobj=funStr.indexOf(START_STR)==-1?eval(funStr,map):PoiPublicUtil.getRealValue(funStr,map);
  52. if(isDict){
  53. obj=dictHandler.toName(dict,null,funStr,obj);
  54. }
  55. if(isI18n){
  56. obj=i18nHandler.getLocaleName(obj.toString());
  57. }
  58. //这里就是调用脱敏规则,和注解是一个工具类,所以规则一致
  59. if(isDern){
  60. obj=PoiDataDesensitizationUtil.desensitization(dern,obj);
  61. }
  62. returnobj;
  63. }

给大家看下模板跑出来的效果:

 Java用poi完成Excel导出数据脱敏(java使用poi导出excel) Java poi 数据脱敏 第5张

最后结果

 Java用poi完成Excel导出数据脱敏(java使用poi导出excel) Java poi 数据脱敏 第6张

转载请说明出处
知优网 » Java用poi完成Excel导出数据脱敏(java使用poi导出excel)

发表评论

您需要后才能发表评论