疫情防控交流社区平台——3.1 开发社区核心功能

🌕开发社区核心功能

1.过滤敏感词

在这里插入图片描述

比如我们平时浏览网站的时候,网站会对内容进行过滤 —— 暴力、色情等进行过滤,进行打码或者隐藏;这些就是过滤敏感词!

技术角度:对字符串进行过滤,输入的内容就是一个大的字符串;调用某些API去判断字符串里有没敏感词
可以用JDK自带的方法string的replace()方法;
在网站中,敏感词很多(几十上百个),替换太麻烦,所以实际过程中,
我们会采用前缀树,这一种数据结构自己来实现一个敏感词过滤的算法!

前缀树过滤敏感词的算法逻辑
特点:

  • 除了根节点外的每一个节点,只包含一个字符,根节点为空;
  • 从根节点开始,到某一个节点c,它会途径a和b,那么途径的字符按顺序连起来就是过滤的字符
  • 每个节点的所有子节点包含的字符不相同
    工作流程图
    在这里插入图片描述
    在这里插入图片描述

1.1 定义前缀树

  • 先定义好敏感词,敏感词可以写在数据库里,也可以写在文件里;
    在这里插入图片描述
  • 然后定义一个工具类用来描述定义前缀树,因为后续其他功能点也会用到敏感词过滤,比如评论,帖子等等;
1.1.1 SensitiveFilter
@Component
public class SensitiveFilter {

    //定义一个内部类,不允许外界访问
    //这就是前缀树的算法逻辑
    private class TireNode{
        //1.关键词结束标识 —— 也就是图解中打了x的底部元素
        private boolean isKeywordEnd = false;
        //2.子节点(key是下级字符,value是下级节点)
        private Map<Character,TireNode> subNodes = new HashMap<>();

        //get、setter方法
        public boolean isKeywordEnd() {
            return isKeywordEnd;
        }
        public void setKeywordEnd(boolean keywordEnd) {
            isKeywordEnd = keywordEnd;
        }

        //3.添加子节点的方法
        public void addSubNode(Character c,TireNode node){
            subNodes.put(c, node);
        }
        //4.获取子节点
        public TireNode getSubNode(Character c){
            return subNodes.get(c);
        }
    }
}

1.2 根据敏感词,初始化前缀树

其实就是在上述代码中的内部上面添加了代码,具体如下;

SensitiveFilter

@Component
public class SensitiveFilter {

    private static final Logger logger = LoggerFactory.getLogger(SensitiveFilter.class);

    //敏感词的替换符
    private static final String REPLACEMENT = "***";
    //根节点初始化
    private TireNode rootNode = new TireNode();

    @PostConstruct //表示这是一个初始化方法;
    public void init(){
        try (
                InputStream is = this.getClass().getClassLoader().getResourceAsStream("sensitive-words.txt");
                //这是一个字节流,从字节流读文字不太方便,所以转为字符流
                BufferedReader reader = new BufferedReader(new InputStreamReader(is));//缓冲流
         ) {
            String keywords; //每次读取的词都存到变量keywords里
            while ((keywords = reader.readLine()) != null){
                //添加到前缀树
				this.addKeyword(keywords);
            }
        }catch (IOException e){
            logger.error("加载敏感词文件失败!" + e.getMessage());
        }
    }

    //方法定义:将一个敏感词添加到前缀树当中去
    private void addKeyword(String keyword){
        TireNode tempNode = rootNode;
        //tempNode临时节点,相当于一个指针,默认先等于根节点,然后根据单词拆解每个字符不断地指向下一个字符,不断构造树的下一级;
        for (int i=0;i<keyword.length();i++){
            char c = keyword.charAt(i);  //得到一个字符
            TireNode subNode = tempNode.getSubNode(c); //
            if (subNode == null){
                //初始化子节点
                subNode = new TireNode();
                tempNode.addSubNode(c,subNode);
            }

            //指针指向子节点,进入下一轮循环
            tempNode = subNode;

            //设置结束标识
            if (i == keyword.length()-1){
                tempNode.setKeywordEnd(true);
            }
        }
    }
 

    //定义一个内部类,不允许外界访问
    //这就是前缀树的算法逻辑
    private class TireNode{
        //1.关键词结束标识 —— 也就是图解中打了x的底部元素
        private boolean isKeywordEnd = false;
        //2.子节点(key是下级字符,value是下级节点)
        private Map<Character,TireNode> subNodes = new HashMap<>();

        //get、setter方法
        public boolean isKeywordEnd() {
            return isKeywordEnd;
        }

        public void setKeywordEnd(boolean keywordEnd) {
            isKeywordEnd = keywordEnd;
        }

        //3.添加子节点的方法
        public void addSubNode(Character c,TireNode node){
            subNodes.put(c, node);
        }
        //4.获取子节点
        public TireNode getSubNode(Character c){
            return subNodes.get(c);
        }

    }

}

1.3 编写过滤敏感词的方法

SensitiveFilter

@Component
public class SensitiveFilter {

    private static final Logger logger = LoggerFactory.getLogger(SensitiveFilter.class);

    //敏感词的替换符
    private static final String REPLACEMENT = "***";
    //根节点初始化
    private TireNode rootNode = new TireNode();

    //2.
    @PostConstruct //表示这是一个初始化方法;
    public void init(){
        try (
                InputStream is = this.getClass().getClassLoader().getResourceAsStream("sensitive-words.txt");
                //这是一个字节流,从字节流读文字不太方便,所以转为字符流
                BufferedReader reader = new BufferedReader(new InputStreamReader(is));//缓冲流
         ) {
            String keywords; //每次读取的词都存到变量keywords里
            while ((keywords = reader.readLine()) != null){
                //添加到前缀树
				this.addKeyword(keywords);
            }
        }catch (IOException e){
            logger.error("加载敏感词文件失败!" + e.getMessage());
        }
    }

    //2.1 方法定义:将一个敏感词添加到前缀树当中去
    private void addKeyword(String keyword){
        TireNode tempNode = rootNode;
        //tempNode临时节点,相当于一个指针,默认先等于根节点,然后根据单词拆解每个字符不断地指向下一个字符,不断构造树的下一级;
        for (int i=0;i<keyword.length();i++){
            char c = keyword.charAt(i);  //得到一个字符
            TireNode subNode = tempNode.getSubNode(c); //
            if (subNode == null){
                //初始化子节点
                subNode = new TireNode();
                tempNode.addSubNode(c,subNode);
            }

            //指针指向子节点,进入下一轮循环
            tempNode = subNode;

            //设置结束标识
            if (i == keyword.length()-1){
                tempNode.setKeywordEnd(true);
            }
        }
    }

    /*
    * 过滤敏感词
    *
    * @param:text —— 待过滤的文本
    * @return: 过滤后的文本
    * */
    public String filter(String text){
        //非空判断
        if (StringUtils.isBlank(text)){
            return null;
        }

        //指针1(图解中的指向前缀树结构的指针)
        TireNode tempNode = rootNode;
        //指针2(图解中最上面开始的指向指针)
        int begin = 0;
        //指针3(图解中最下面用于扫描徘徊的指针)
        int position = 0;
        //结果封装(对扫描字符进行逐个封装,最后成为合法的字符串)
        StringBuilder stringBuilder = new StringBuilder();

        while (position < text.length()){
            char c = text.charAt(position);

            //跳过符号 (防止在敏感词中加入特殊符号来逃避过滤)
            if (isSymbol(c)){
                //若指针1属于根节点,将此符号计入结果,让指针2向下走一步
                if (tempNode == rootNode){
                    stringBuilder.append(c);
                    begin++;
                }
                //无论符号在开头或中间,指针3都向下走一步
                position++;
                continue;
            }

            //检查下级节点
            tempNode = tempNode.getSubNode(c);
            if (tempNode == null){
                //tempNode == null 节点为空,表示当前节点没有下级节点
                //即以begin开头的字符串不是敏感词
                stringBuilder.append(text.charAt(begin));
                //进入下一个位置
                position = ++begin;
                //指针1重新指向根节点,进行下一轮判断
                tempNode = rootNode;
            }else if (tempNode.isKeywordEnd){
                //发现了敏感词,将begin到position的字符串替换掉
                stringBuilder.append(REPLACEMENT);
                //让指针进3入下一个位置
                begin = ++ position;
                //指针1重新指向根节点,进行下一轮判断
                tempNode = rootNode;
            }else {
                //检查下一个字符
                position++;
            }
        }
        //将最后一批字符计入结果
        stringBuilder.append(text.substring(begin));

        return stringBuilder.toString();
    }

    //方法:判断是否为符号
    private boolean isSymbol(Character c){
        //0x2E80 ~ 0x9FFF 是东亚文字范围
        return !CharUtils.isAsciiAlphanumeric(c) && (c<0x2E80 || c>0x9FFF);
    }

    //1.定义一个内部类,不允许外界访问
    //这就是前缀树的算法逻辑
    private class TireNode{
        //1.1 关键词结束标识 —— 也就是图解中打了x的底部元素
        private boolean isKeywordEnd = false;
        //1.2 子节点(key是下级字符,value是下级节点)
        private Map<Character,TireNode> subNodes = new HashMap<>();

        //get、setter方法
        public boolean isKeywordEnd() {
            return isKeywordEnd;
        }

        public void setKeywordEnd(boolean keywordEnd) {
            isKeywordEnd = keywordEnd;
        }

        //1.3 添加子节点的方法
        public void addSubNode(Character c,TireNode node){
            subNodes.put(c, node);
        }
        //1.4 获取子节点
        public TireNode getSubNode(Character c){
            return subNodes.get(c);
        }

    }

}

1.4 SensitiveTests测试类测试

SensitiveTests

@RunWith(SpringRunner.class)
@SpringBootTest
@ContextConfiguration(classes = CommunityApplication.class)
public class SensitiveTests {

    @Autowired
    private SensitiveFilter sensitiveFilter;

    @Test
    public void testSensitiveFilter(){
        String text = "加入来吃饭啊!加入来睡觉啊!加入也能放假哦!";
        text = sensitiveFilter.filter(text);
        System.out.println(text);

        String text1 = "加入来❤吃❤饭啊!加入来睡❤觉啊!加入也能❤放❤假❤哦!";
        text = sensitiveFilter.filter(text);
        System.out.println(text);
    }
}

结果:
在这里插入图片描述

目 录 摘 要 I ABSTRACT II 第一章 绪论 1 1.1 选题的背景 1 1.2 国内外状况 2 1.3 问题的提出 3 1.4 主要研究内容 3 1.5 论文的组织结构 3 第二章 相关理论及技术介绍 5 2.1 开发平台 5 2.1.1 MyEclipse 5 2.1.2 NetBeans 5 2.2 相关技术 5 2.2.1 XML 5 2.2.2 Dom4j 6 2.2.3 SOAP 6 2.2.4 WebService 7 2.2.5 WSDL 7 2.2.6 Velocity 8 2.2.7 Swing 8 2.2.8 Java反射 9 2.3 本章小结 9 第三章 服务开发平台的总体框架 10 3.1 前台可视化IDE的设计 11 3.2 后台的总体设计 12 3.2.1 后台RuntimeContainer容器管理模块设计概述 13 3.2.2 后台UDDI注册中心模块设计概述 14 3.2.3 后台SP Agent Builder代码生成模块设计概述 16 3.3 本章小结 20 第四章 服务生成工具SP Agent Builder的设计与实现 21 4.1 三层XML schema设计与解析模块的设计与实现 21 4.1.1 功能层XML schema的设计 21 4.1.2 表示层XML schema 的设计 24 4.1.3 传输层XML schema 的设计 24 4.1.4 三层XML文件解析的设计与实现 26 4.2 数据转换模块的设计与实现 28 4.2.1 目标数据格式介绍 28 4.2.2 对象与目标数据格式之间的转换 31 4.3 传输代理模块的设计与实现 35 4.3.1 网络传输协议 36 4.3.2 传输代理的运作流程 38 4.4 代码生成器模块的设计与实现 39 4.4.1 模板的设计 39 4.4.2 代码生成的运作流程 40 4.5 可视化编辑器模块的设计与实现 41 4.5.1 可视化编辑器的设计 41 4.5.2 可视化编辑器的运作流程 42 4.5 本章小结 42 第五章 系统实现 44 4.1 创建服务 44 4.2 编辑服务 48 4.3 删除服务 50 4.4 本章小结 51 第六章 结论 52 致 谢 53 参考文献 54 毕业设计小结 56 附录A XML数据类型和Java数据类型之间的映射规则 57 附录B 功能层XML schema的设计 58 附录C 表示层XML schema的设计 60 附录D 传输层XML schema的设计 61 附录E TXT文本的格式介绍 63
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

11_1

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值