mybatis-plus加密字段模糊查询

本文介绍了如何在Mybatis-Plus项目中处理加密字段的模糊查询需求,通过IKAnalyzer进行分词并结合数据库操作,避免全表扫描,提高了查询效率。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

目录

前言

设计思路

添加依赖

代码

分词工具类

分词实体类

分词扩展配置

Service类

分词service

角色service 

目录结构

测试

添加

查询

​编辑

结束语


前言

在前面的文章中,实现了数据库中表字段的加解密,mybatis-plus数据库字段信息加解密-优快云博客,提高了数据的安全性,正当我们松了一口气的时候,这时候产品带来了一个新的需求,说老板需要对这些加密的字段进行模糊查询,一听到这个需求的时候是不是一脸懵逼,对一个加密的字段模糊查询,这是得多久的老血栓才能提出来的要求,不过想想还没有干巴巴的口袋,咬咬牙必须给它实现了。

设计思路

方式一:我们就将当前表信息全部加载到内存中,将加密字段进行解密后,然后在进行模糊匹配。这个针对表中的数据量少的情况下比较好,但是数据量多的话,那么就不适应了。

方式二:新建一张表,将原文信息保存到该表中,加密字段保存在原表中,模糊查询的时候,查询的是新建的表中原文的字段,不过这样就失去了加密字段的意义,不可取。

方式三:新建一张分词表,将加密字段的分词加密信息保存到表中,模糊查询的时候查询该表,获取加密字段数据所在的id集合,然后根据id集合去查询原表。

添加依赖

<!--ik分词器-->
<dependency>
   <groupId>com.janeluo</groupId>
   <artifactId>ikanalyzer</artifactId>
   <version>2012_u6</version>
   <exclusions>
      <exclusion>
         <groupId>org.apache.lucene</groupId>
         <artifactId>lucene-core</artifactId>
      </exclusion>
      <exclusion>
         <groupId>org.apache.lucene</groupId>
         <artifactId>lucene-queryparser</artifactId>
      </exclusion>
      <exclusion>
         <groupId>org.apache.lucene</groupId>
         <artifactId>lucene-analyzers-common</artifactId>
      </exclusion>
   </exclusions>
</dependency>

代码

分词工具类

import cn.hutool.core.collection.ListUtil;
import cn.hutool.core.util.StrUtil;
import org.wltea.analyzer.core.IKSegmenter;
import org.wltea.analyzer.core.Lexeme;

import java.io.StringReader;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;

/**
 * @Description: 分词工具类
 * @Author ly
 * @Date 2023/11/222:23
 */
public class AnalyzerUtil {
    /**
     * ik 字符串用该方法
     *
     * @param str    str
     * @param length length
     * @return List<String>
     */
    public static List<String> ikSegmentationList(String str, Integer length) {
        List<String> list = new LinkedList<>();
        try {
            if (StrUtil.isEmpty(str)) {
                return ListUtil.empty();
            }
            StringReader stringReader = new StringReader(str);
            IKSegmenter ik = new IKSegmenter(stringReader, false);
            Lexeme le;
            while ((le = ik.next()) != null) {
                String lexemeText = le.getLexemeText();
                if (lexemeText.length() >= length) {
                    list.add(lexemeText);
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return list;
    }

    /**
     * 部分分词(分割数字类型的字段,如手机号)
     *
     * @param str    str
     * @param length length
     * @return List<String>
     */
    public static List<String> partSegmentationList(String str, Integer length) {
        List<String> list = new ArrayList<>();
        if (StrUtil.isEmpty(str)) {
            return ListUtil.empty();
        }
        int strLength = str.length();
        for (int startIndex = 0; startIndex <= strLength - length; startIndex++) {
            String substring = str.substring(startIndex, startIndex + length);
            list.add(substring);
        }
        return list;
    }

分词实体类

import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.lyy.demo3.handler.TypeHandler;
import lombok.Data;

/**
 * @Description: 分词实体类
 * @Author ly
 * @Date 2023/10/1721:48
 */
@Data
@TableName(value = "word_part_mapping",autoResultMap = true)
public class WordPartMapping {

    @TableId(value = "id", type = IdType.AUTO)
    private Long id;

    /**
     * 表名
     */
    private String tableName;

    /**
     * 分词对应的数据id
     */
    private Long fieldId;

    /**
     * 分词加密字段
     */
    @TableField(typeHandler = TypeHandler.class)
    private String analyzerEncrypt;

    /**
     * 字段名
     */
    private String fieldName;

}

分词扩展配置

在resource目录下添加IKAnalyzer.cfg.xml、ext_dict、ext-stopwords文件

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE properties SYSTEM "http://java.sun.com/dtd/properties.dtd">
<properties>
    <comment>IKAnalyzer扩展配置</comment>
    <!--用户的扩展字典 -->
    <entry key="ext_dict">extend.dic</entry>
    <!--用户扩展停止词字典 -->
    <entry key="ext_stopwords">stopword.dic</entry>
</properties>

Service类

分词service
import cn.hutool.core.collection.CollUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.lyy.demo3.entity.WordPartMapping;
import com.lyy.demo3.mapper.WordPartMappingMapper;
import com.lyy.demo3.service.WordPartMappingService;
import com.lyy.demo3.utils.AesUtil;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * @Description: TODO(这里用一句话描述这个类的作用)
 * @Author ly
 * @Date 2023/11/2 22:35
 */
@Service
public class WordPartMappingServiceImpl extends ServiceImpl<WordPartMappingMapper, WordPartMapping> implements WordPartMappingService {

    @Autowired
    private WordPartMappingMapper wordPartMappingMapper;

    @Override
    public boolean saveBatchWords(List<WordPartMapping> wordPartMappings) {
        return saveBatch(wordPartMappings);
    }

    @Override
    public List<Long> findFieldId(String searchLike) {
        QueryWrapper<WordPartMapping> wrapper = new QueryWrapper<>();
        ArrayList<String> list = new ArrayList<>();
        wrapper.eq("table_name","roles");
        if(StringUtils.isNotBlank(searchLike)){
            String encrypt = AesUtil.encrypt(searchLike);
            wrapper.eq("field_name","username").eq("analyzer_encrypt",encrypt);
            list.add(searchLike);
        }
        if(1 < list.size()){
            wrapper.groupBy("field_id").having("COUNT(field_id) >=" + list.size());
        }
        List<WordPartMapping> selectList = wordPartMappingMapper.selectList(wrapper);
        List<Long> fieldIds = new ArrayList<>();
        if(CollUtil.isNotEmpty(selectList)){
            fieldIds = selectList.stream().map(
                    WordPartMapping::getFieldId
            ).distinct().collect(Collectors.toList());
        }
        return fieldIds;
    }
}
角色service 
import cn.hutool.core.collection.CollUtil;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.lyy.demo3.entity.Roles;
import com.lyy.demo3.entity.WordPartMapping;
import com.lyy.demo3.mapper.RolesMapper;
import com.lyy.demo3.service.RolesService;
import com.lyy.demo3.service.WordPartMappingService;
import com.lyy.demo3.utils.AnalyzerUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

/**
 * @Description: TODO(这里用一句话描述这个类的作用)
 * @Author ly
 * @Date 2023/10/1721:54
 */
@Service
public class RolesServiceImpl extends ServiceImpl<RolesMapper, Roles> implements RolesService {

    @Autowired
    private RolesMapper rolesMapper;

    @Autowired
    private WordPartMappingService wordPartMappingService;


    @Override
    public List<Roles> queryLike(String username) {
        List<Long> fieldId = wordPartMappingService.findFieldId(username);
        return rolesMapper.selectBatchIds(fieldId);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public int addRoles(Roles roles) {
        int insert = rolesMapper.insert(roles);
        // 将模糊查询的数据保存到分词表中
        List<String> nameSp = AnalyzerUtil.ikSegmentationList(roles.getUsername(), 2);
        ArrayList<WordPartMapping> words = new ArrayList<>();
        if(CollUtil.isNotEmpty(nameSp)){
            for(String name : nameSp){
                WordPartMapping partMapping = new WordPartMapping();
                partMapping.setTableName("roles");
                partMapping.setFieldId(roles.getId());
                partMapping.setFieldName("username");
                partMapping.setAnalyzerEncrypt(name);
                words.add(partMapping);
            }
        }
        wordPartMappingService.saveBatchWords(words);
        return insert;
    }

目录结构

测试

添加

 

查询

结束语

现在模糊查询加密字段实现了,后面看看怎么实现数据的脱敏展示吧。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值