瀏覽代碼

热词管理功能

zxy 2 年之前
父節點
當前提交
19d04fed48

+ 7 - 0
spring-cloud/server-basic/pom.xml

@@ -111,6 +111,13 @@
 			<version>1.0.2</version>
 		</dependency>
 
+		<!-- 分词组件 -->
+		<dependency>
+			<groupId>com.janeluo</groupId>
+			<artifactId>ikanalyzer</artifactId>
+			<version>2012_u6</version>
+		</dependency>
+
 	</dependencies>
 
 	<build>

+ 85 - 0
spring-cloud/server-basic/src/main/java/com/jd/controller/ParticipleController.java

@@ -0,0 +1,85 @@
+package com.jd.controller;
+
+import cn.hutool.core.date.DateUtil;
+import cn.hutool.core.thread.ThreadUtil;
+import com.jd.entity.Participle;
+import com.jd.service.ParticipleService;
+import com.jd.util.SendUtil;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.web.bind.annotation.*;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+
+import javax.annotation.Resource;
+import java.util.Map;
+
+
+@Slf4j
+@RestController()
+@RequestMapping("/api/participle")
+@Api(tags = "分词表")
+public class ParticipleController {
+
+    @Resource
+    private ParticipleService participleService;
+
+    @GetMapping("/list")
+    @ApiOperation(value = "1、分页查询")
+    public Map<String, Object> queryPageBean(Integer page, Integer limit, Participle participle) {
+        Page pageBean = new Page(page, limit);
+        participleService.queryPage(pageBean, participle);
+        return SendUtil.layuiTable(pageBean.getTotal(), pageBean.getRecords());
+    }
+
+    @PostMapping("/addBean")
+    @ApiOperation(value = "2、新增")
+    public Map<String, Object> addBean(Participle participle) {
+        participle.setCreateTime(DateUtil.now());
+        //分词处理
+        participleService.participleHandel(participle);
+        Boolean result = participleService.save(participle);
+        if (result) {
+            //另开线程同步分词数据
+            ThreadUtil.execAsync(() -> {
+                participleService.participleSync();
+            });
+        }
+        return SendUtil.send(true, null, result);
+    }
+
+    @PostMapping("/updateBean")
+    @ApiOperation(value = "3、修改")
+    public Map<String, Object> updateBean(Participle participle) {
+        participle.setUpdateTime(DateUtil.now());
+        //分词处理
+        participleService.participleHandel(participle);
+        Boolean result = participleService.updateById(participle);
+        if (result) {
+            //另开线程同步分词数据
+            ThreadUtil.execAsync(() -> {
+                participleService.participleSync();
+            });
+        }
+        return SendUtil.send(true, null, result);
+    }
+
+    @PostMapping("/deleteById")
+    @ApiOperation(value = "4、删除")
+    public Map<String, Object> deleteById(Long id) {
+        Boolean result = participleService.removeById(id);
+        if (result) {
+            //另开线程同步分词数据
+            ThreadUtil.execAsync(() -> {
+                participleService.participleSync();
+            });
+        }
+        return SendUtil.send(true, null, result);
+    }
+
+    @GetMapping("/find/{id}")
+    @ApiOperation(value = "5、根据id查询")
+    public Map<String, Object> findById(@PathVariable("id") Integer id) {
+        return SendUtil.send(true, null, participleService.getById(id));
+    }
+}

+ 41 - 0
spring-cloud/server-basic/src/main/java/com/jd/entity/Participle.java

@@ -0,0 +1,41 @@
+package com.jd.entity;
+
+import java.io.Serializable;
+import java.util.Date;
+
+
+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 io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+
+@Data
+@ApiModel("分词表")
+@TableName("t_participle")
+public class Participle implements Serializable {
+	private static final long serialVersionUID = 1L;
+
+    @TableId(value = "id", type = IdType.AUTO)
+    private Integer id;
+
+    @ApiModelProperty("分词内容")
+    @TableField("participle_content")
+    private String participleContent;
+
+    @ApiModelProperty("分词后内容")
+    @TableField("participle_after_content")
+    private String participleAfterContent;
+
+    @ApiModelProperty("创建时间")
+    @TableField("create_time")
+    private String createTime;
+
+    @ApiModelProperty("修改时间")
+    @TableField("update_time")
+    private String updateTime;
+
+}

+ 19 - 0
spring-cloud/server-basic/src/main/java/com/jd/mapper/ParticipleMapper.java

@@ -0,0 +1,19 @@
+package com.jd.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.jd.entity.Participle;
+import org.apache.ibatis.annotations.Param;
+import org.apache.ibatis.annotations.Select;
+
+public interface ParticipleMapper extends BaseMapper<Participle> {
+
+    @Select("<script>" +
+            "SELECT * FROM t_participle WHERE 1 = 1" +
+            "<if test=\"@org.apache.commons.lang3.StringUtils@isNotBlank(participle.participleContent)\">" +
+            " and participle_content LIKE CONCAT('%',#{participle.participleContent},'%') " +
+            "</if>" +
+            "</script>")
+    IPage<Participle> queryPage(Page page, @Param("participle") Participle participle);
+}

+ 17 - 0
spring-cloud/server-basic/src/main/java/com/jd/service/ParticipleService.java

@@ -0,0 +1,17 @@
+package com.jd.service;
+
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.baomidou.mybatisplus.extension.service.IService;
+import com.jd.entity.Participle;
+
+public interface ParticipleService extends IService< Participle> {
+
+    IPage<Participle> queryPage(Page page, Participle participle);
+
+    //分词处理
+    Participle participleHandel(Participle participle);
+
+    //分词同步
+    void participleSync();
+}

+ 85 - 0
spring-cloud/server-basic/src/main/java/com/jd/service/impl/ParticipleServiceImpl.java

@@ -0,0 +1,85 @@
+package com.jd.service.impl;
+
+import cn.hutool.core.map.MapUtil;
+import cn.hutool.http.HttpRequest;
+import cn.hutool.json.JSONArray;
+import cn.hutool.json.JSONUtil;
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.core.toolkit.Wrappers;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.jd.entity.Participle;
+import com.jd.mapper.ParticipleMapper;
+import com.jd.service.ParticipleService;
+import com.jd.util.ParticipleUtil;
+import org.springframework.stereotype.Service;
+
+import java.util.Arrays;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+
+@Service
+public class ParticipleServiceImpl extends ServiceImpl<ParticipleMapper, Participle> implements ParticipleService {
+
+    private String PARTICIPLE_URL = "http://23.37.100.50:8123/word/update";
+
+    @Override
+    public IPage<Participle> queryPage(Page page, Participle participle) {
+        return baseMapper.queryPage(page, participle);
+    }
+
+    @Override
+    public Participle participleHandel(Participle participle) {
+        //分词处理
+        try {
+            participle.setParticipleAfterContent(
+                    Arrays.stream(ParticipleUtil.parse(participle.getParticipleContent(), false)
+                            .split("\\|"))
+                            //排除长度大于2的热词
+                            .filter(t -> t.length() <= 2)
+                            .collect(Collectors.joining("|"))
+            );
+        } catch (Exception e) {
+            log.error("分词失败");
+            e.printStackTrace();
+        }
+        return participle;
+    }
+
+    /**
+     * 同步分词数据
+     */
+    @Override
+    public void participleSync() {
+        //先查询出数据库所有的分词数据
+        List<Participle> participleList = baseMapper.selectList(Wrappers.lambdaQuery());
+        //映射分词数据并拼接成字符串
+        String participleStr = participleList.stream().map(t -> t.getParticipleAfterContent()).collect(Collectors.joining("|"));
+        //分割所有单词并去重
+        List<String> participles = Arrays.stream(participleStr.split("\\|"))
+                .distinct()
+                //排除长度大于2的热词
+                .filter(t -> t.length() <= 2)
+                .collect(Collectors.toList());
+        //转成JsonArray
+        JSONArray jsonArray = JSONUtil.createArray();
+        participles.stream().forEach(jsonArray::put);
+        log.debug("分词数据:" + jsonArray);
+        //封装请求参数
+        Map<Object, Object> params = MapUtil.builder()
+                .put("words", jsonArray.toString())
+                .map();
+        //调接口同步分词
+        try {
+            String result = HttpRequest.post(PARTICIPLE_URL)
+                    .body(JSONUtil.parse(params).toString(), "application/json")
+                    .execute()
+                    .body();
+            log.debug("分词同步响应体:" + result);
+        } catch (Exception e) {
+            log.error("分词同步失败!错误信息:" + e.getMessage());
+            e.printStackTrace();
+        }
+    }
+}

+ 29 - 0
spring-cloud/server-basic/src/main/java/com/jd/util/ParticipleUtil.java

@@ -0,0 +1,29 @@
+package com.jd.util;
+
+import org.wltea.analyzer.core.IKSegmenter;
+import org.wltea.analyzer.core.Lexeme;
+
+import java.io.IOException;
+import java.io.StringReader;
+
+public class ParticipleUtil {
+
+    public static String parse(String content, boolean useSmart) throws IOException {
+        StringReader sr = new StringReader(content);
+        // 参数2为是否使用智能分词
+        // true:使用智能分词
+        // false:使用最细粒度分词
+        IKSegmenter ikSegmenter = new IKSegmenter(sr, useSmart);
+        Lexeme word = null;
+        String w = null;
+        StringBuffer sb = new StringBuffer();
+        while((word = ikSegmenter.next()) != null){
+            w = word.getLexemeText();
+            if(sb.length() > 0){
+                sb.append("|");
+            }
+            sb.append(w);
+        }
+        return sb.toString();
+    }
+}

+ 15 - 0
spring-cloud/server-basic/src/main/resources/mapper/ParticipleMapper.xml

@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+
+<mapper namespace="com.jd.mapper.ParticipleMapper">
+
+	<!-- 可根据自己的需求,是否要使用 -->
+   <resultMap type="com.jd.entity.Participle" id="participleMap">
+        <result property="id" column="id"/>
+        <result property="participleContent" column="participle_content"/>
+        <result property="participleAfterContent" column="participle_after_content"/>
+        <result property="createTime" column="create_time"/>
+        <result property="updateTime" column="update_time"/>
+    </resultMap>
+
+</mapper>

+ 246 - 0
spring-cloud/server-page/src/main/resources/static/page/js/basic/participleManage.js

@@ -0,0 +1,246 @@
+let form, table, upload;
+layui.config({
+    base: 'js/encryption/'
+}).use(['layer', 'form', 'jquery', 'table', 'upload', 'ajax'], function () {
+    layer = layui.layer;
+    upload = layui.upload;
+    table = layui.table;
+    form = layui.form;
+    $ = layui.jquery;
+    ly = layui.ajax;
+
+    // 主要表格
+    table.render({
+        elem: '#participleTable',
+        url: PAGE_BASIC + '/api/participle/list',
+        toolbar: '#participleTable_toolbar', //开启头部工具栏,并为其绑定左侧模板
+        page: true,
+        cols: [
+            [{
+                type: 'numbers',
+                title: '序号'
+            }, {
+                field: 'participleContent',
+                title: '热词内容',
+            },  {
+                field: 'createTime',
+                title: '创建时间'
+            }, {
+                fixed: 'right',
+                title: '操作',
+                toolbar: '#participleTable_bar',
+                width: 250
+            }]
+        ]
+    });
+
+    //头工具栏事件(主要表格)
+    table.on('toolbar(participleTable)', function (obj) {
+        // var checkStatus = table.checkStatus(obj.config.id);
+        switch (obj.event) {
+            case 'add': //新增
+                $(".main").addClass("layui-hide").removeClass("layui-show");
+                $(".add").addClass("layui-show").removeClass("layui-hide");
+                $('#submit').attr('submitType', 'insert');
+                $(".add .header_title span").html("新增");
+                $('#participleInfo')[0].reset();
+                break;
+        }
+    });
+
+    //监听行工具事件(主要表格)
+    table.on('tool(participleTable)', function (obj) {
+        let data = obj.data;
+        //console.log(obj)
+        if (obj.event === 'del') {
+            layer.confirm('是否确认删除', function (index) {
+                deleteExplainArea(data.id);
+                layer.close(index);
+            });
+        } else if (obj.event === 'edit') {
+            $(".main").addClass("layui-hide").removeClass("layui-show");
+            $(".add").addClass("layui-show").removeClass("layui-hide");
+            $(".add .header_title span").html("编辑");
+            $('#submit').attr('submitType', 'update');
+            $('#participleInfo')[0].reset();
+            // 数据初始化
+            echoExplainAreaInfo(data.id);
+        }
+    });
+
+    // 验证表单
+    form.verify({
+        participleContent: function (value, item) {
+            if (!value.trim()) {
+                return '分词内容不能为空';
+            }
+        }
+    });
+
+    // 监听提交按钮
+    form.on('submit(submit)', function (data) {
+        let submitType = data.elem.getAttribute("submitType");
+        // 新增
+        if (submitType == 'insert') {
+            addExplainArea();
+            return false;
+        } else if (submitType == 'update') {
+            updateExplainArea();
+            return false;
+        }
+    });
+
+    // 查询
+    $(".search_btn").click(function () {
+        let queryValue = $.trim($("#queryValue").val());
+        table.reload('participleTable', {
+            where: {
+                "participleContent": queryValue
+            },
+            page: {
+                curr: 1 //重新从第 1 页开始
+            }
+        }); //只重载数据
+    });
+
+    //基础数据搜索回车事件
+    $('#queryValue').bind('keypress', function (event) {
+        if (event.keyCode == "13") {
+            $(".search_btn").click();
+        }
+    });
+
+    // 返回
+    $(".back").click(function () {
+        $(".main").addClass("layui-show").removeClass("layui-hide");
+        $(".add").addClass("layui-hide").removeClass("layui-show");
+        $('.show-content').empty()
+    });
+
+    /**
+     * 回显讲解区域
+     * @param id
+     */
+    function echoExplainAreaInfo(id) {
+        let index = layer.load(2);
+        ly.ajax({
+            type: 'GET',
+            url: PAGE_BASIC + '/api/participle/find/' + id,
+            dataType: 'json',
+            success: function (json) {
+                if (json.result) {
+                    let data = json.data
+                    $('#id').val(data.id)
+                    $('#participleContent').val(data.participleContent)
+                    form.render();
+                } else {
+                    layer.msg("数据获取失败");
+                }
+                layer.close(index);
+            },
+            error: function (msg) {
+                layer.close(index);
+            }
+        });
+    }
+
+});
+
+/**
+ * 新增智能讲解
+ */
+function addExplainArea() {
+    let postData = form.val('participleInfo');
+    console.log(postData)
+    let index = layer.load(2);
+    ly.ajax({
+        type: 'POST',
+        url: PAGE_BASIC + '/api/participle/addBean',
+        dataType: 'json',
+        data: postData,
+        success: function (json) {
+            if (json.result) {
+                layer.msg("新增成功");
+                $(".main").addClass("layui-show").removeClass("layui-hide");
+                $(".add").addClass("layui-hide").removeClass("layui-show");
+                $('.show-content').empty()
+                reloadTable();
+            } else {
+                layer.msg("新增失败");
+            }
+            layer.close(index);
+        },
+        error: function (msg) {
+            layer.close(index);
+        }
+    });
+}
+
+/**
+ * 编辑讲解区域
+ */
+function updateExplainArea() {
+    let postData = form.val('participleInfo');
+    let index = layer.load(2);
+    ly.ajax({
+        type: 'POST',
+        url: PAGE_BASIC + '/api/participle/updateBean',
+        dataType: 'json',
+        data: postData,
+        success: function (json) {
+            if (json.result) {
+                layer.msg("编辑成功");
+                $(".main").addClass("layui-show").removeClass("layui-hide");
+                $(".add").addClass("layui-hide").removeClass("layui-show");
+                $('.show-content').empty()
+                reloadTable();
+            } else {
+                layer.msg("编辑失败");
+            }
+            layer.close(index);
+        },
+        error: function (msg) {
+            layer.close(index);
+        }
+    });
+}
+
+/**
+ * 删除讲解区域
+ * @param id
+ */
+function deleteExplainArea(id) {
+    let index = layer.load(2);
+    ly.ajax({
+        type: 'POST',
+        url: PAGE_BASIC + '/api/participle/deleteById',
+        dataType: 'json',
+        data: {
+            "id": id,
+        },
+        success: function (json) {
+            if (json.result) {
+                layer.msg("删除成功");
+                reloadTable();
+            } else {
+                layer.msg("删除失败");
+            }
+            layer.close(index);
+        },
+        error: function (msg) {
+            layer.close(index);
+        }
+    });
+}
+
+/**
+ * 重载数据表格
+ */
+function reloadTable() {
+    table.reload('participleTable', {
+        page: {
+            curr: 1 //重新从第 1 页开始
+        }
+    }); //只重载数据
+}
+

+ 103 - 0
spring-cloud/server-page/src/main/resources/static/page/participleManage.html

@@ -0,0 +1,103 @@
+<!DOCTYPE html>
+<html>
+
+<head>
+    <meta charset="UTF-8">
+    <meta name="renderer" content="webkit">
+    <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
+    <meta name="viewport"
+          content="width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=no"/>
+    <title>分词管理</title>
+    <link rel="stylesheet" type="text/css" href="layui/css/layui.css"/>
+    <link rel="stylesheet" type="text/css" href="css/admin.css"/>
+    <link rel="stylesheet" type="text/css" href="css/common.css"/>
+    <link rel="stylesheet" type="text/css" href="css/animate.css"/>
+</head>
+<style>
+    .layui-form-item .layui-input-inline {
+        width: 60%;
+    }
+
+    .layui-textarea {
+        resize: none;
+        height: 100px;
+    }
+
+    .show-content * {
+        width: auto;
+        height: auto;
+        max-height: 100px;
+        margin: 5px;
+        line-height: 100px;
+    }
+</style>
+<body>
+<!-- 主要内容 -->
+<div class="main fadeIn animated">
+    <div class="header_title"><span>热词管理</span></div>
+    <div class="main_content">
+        <table class="layui-hide" id="participleTable" lay-filter="participleTable"></table>
+
+        <script type="text/html" id="participleTable_toolbar">
+            {{# if (sessionStorage.getItem("menuid-" + sessionStorage.MENU_ID + "-add")  == 'add') { }}
+            <div class="layui-btn-container">
+                <button class="layui-btn layui-btn-sm main_head_btn" lay-event="add"><span
+                        class="iconfont">&#xe607;</span>新增
+                </button>
+            </div>
+            {{# } }}
+        </script>
+
+        <script type="text/html" id="participleTable_bar">
+            {{# if (sessionStorage.getItem("menuid-" + sessionStorage.MENU_ID + "-update") == 'update') { }}
+            <a class="main_tab_btn" lay-event="edit" style="color: #64ADF9;"><span
+                    class="iconfont">&#xe637;</span>编辑</a>
+            {{# } }}
+            {{# if (sessionStorage.getItem("menuid-" + sessionStorage.MENU_ID + "-delete") == 'delete') { }}
+            <a class="main_tab_btn" lay-event="del" style="color: #FC7D8C;"><span class="iconfont">&#xe78d;</span>删除</a>
+            {{# } }}
+        </script>
+
+        <div class="search_box">
+            <div class="layui-input-inline">
+                <input type="text" name="queryValue" id="queryValue" autocomplete="off" class="layui-input"
+                       placeholder="请输入分词内容"/>
+            </div>
+            <button type="button" class="layui-btn layui-btn-sm search_btn">搜 索</button>
+        </div>
+    </div>
+</div>
+
+<!-- 新增 -->
+<div class="add layui-hide fadeIn animated">
+    <div class="header_title"><span>新增</span></div>
+    <div class="main_content">
+        <form class="layui-form" action="" id="participleInfo" lay-filter="participleInfo">
+            <input type="hidden" class="layui-hide" id="id" name="id" readonly=""/>
+            <div class="layui-form-item">
+                <label class="layui-form-label"><span class="font-red">*</span>分词内容:</label>
+                <div class="layui-input-inline">
+                            <textarea class="layui-textarea" id="participleContent" name="participleContent"
+                                      lay-verify="participleContent"
+                                      placeholder="请输入分词内容" autocomplete="off"></textarea>
+                </div>
+            </div>
+            <button type="submit" id="submit" class="layui-btn submit_btn" lay-submit="" lay-filter="submit"
+                    submitType="" style="margin-left: 50px;margin-top: 30px;">提交
+            </button>
+            <button type="button" class="layui-btn layui-btn-primary back back_btn" style="margin-top: 30px;">返回
+            </button>
+        </form>
+    </div>
+</div>
+
+<script src="layui/layui.js" type="text/javascript" charset="utf-8"></script>
+<script src="js/common.js" type="text/javascript" charset="utf-8"></script>
+<script src="js/constants.js" type="text/javascript" charset="utf-8"></script>
+<script src="js/js-util.js" type="text/javascript" charset="utf-8"></script>
+<script src="js/base64.js" type="text/javascript" charset="utf-8"></script>
+<script src="js/basic/participleManage.js" type="text/javascript" charset="utf-8"></script>
+
+</body>
+
+</html>