Springboot+Vue实现像浏览器一样搜索下拉框的高频词推荐或历史搜索记录

最近在做法院的案件检索系统,需求中有一个需要做搜索下拉框可以提供历史高频搜索记录,并且可以根据输入自动匹配,就是像浏览器的搜索栏一样的效果。

效果图:

Springboot+Vue实现像浏览器一样搜索下拉框的高频词推荐或历史搜索记录_第1张图片
Springboot+Vue实现像浏览器一样搜索下拉框的高频词推荐或历史搜索记录_第2张图片
如图所示,根据输入的关键字自动匹配高频搜索记录,并按照搜索次数进行排序。

实现过程:

1.前段Vue部分:

<el-row style="padding-top: 10px;">
      <el-col style="width: 85%;">
        <el-autocomplete
          popper-class="my-autocomplete"
          class="inline-input"
          v-model="keywords"
          :fetch-suggestions="querySearch"
          placeholder="请输入内容"
          @select="handleSelect"
          style="width: 100%;margin: 0px;padding: 0px;"
          id="1">
          <template slot-scope="{ item }">
            <div>
              <div class="val">{{ item.value }}div>
              <div class="addr">{{ item.num }}div>

            div>

          template>
        el-autocomplete>
      el-col>
      <el-col style="width: 15%; padding-left: 5px">
        <el-button type="primary" icon="el-icon-search" @click="searchAl">搜索el-button>
      el-col>
    el-row>

采用element-ui中的el-autocomplete组件,这个组件就是带搜索建议的输入框, v-model="keywords"用来接收输入的值, :fetch-suggestions="querySearch"用来提供搜索建议,template用来自定义下拉框的模板。

对应的css代码:

.val {
    width: 95%;
    /*background-color: red ;*/
    text-overflow: ellipsis;
    overflow: hidden;
    white-space: nowrap;
    float: left;

  }

  .addr {
    font-size: 12px;
    color: #b4b4b4;
    float: right;

  }

这是template中的样式,其他的样式都用style写在html中了。

对应的js代码:

export default{
		data() {
            return {
                restaurants: [],
                keywords: '',
            };
        },
        methods:{
        		querySearch(queryString, cb) {
                var restaurants = this.restaurants;
                var results = queryString ? restaurants.filter(this.createFilter(queryString)) : restaurants;
                // 调用 callback 返回建议列表的数据
                cb(results);
            },
            createFilter(queryString) {
                return (restaurant) => {
                    return (restaurant.value.toLowerCase().indexOf(queryString.toLowerCase()) === 0);
                };
            },
            handleSelect(item) {
                console.log(item);
            },
            loadAll() {
                this.$axios.get('/bd/read').then(res => {
                    console.log(res.data)
                    this.restaurants = res.data

                })
            },
        
        },
        mounted() {
      
            this.loadAll();
        },
}

上面代码初始化的时候会返回restaurants和keywords,都是为空的,restaurants需要通过loadAll函数从后端获取数据,并将值赋值给restaurants,mounted()函数会在页面加载时就会执行,把loadAll放在这个函数中,就可以打开页面时restaurants就可以获取到数据了。当点击输入框时会触发querySearch函数,通过过滤后调用 callback 返回建议列表的数据。

那么词频是怎么计算的呢?词频的数据格式如下:

[{"value":"土地","num":7},{"value":"行政","num":4},{"value":"案件","num":3}]

简单来说就是当点击搜索按钮时,对应的num增加,然后再更新到后台持久保存。
还有一点就是如何对数据根据num排序,代码如下:

//搜索高词频统计
            searchSuggest() {
                if (this.keywords != '' && this.keywords != null) {
                    var l = this.restaurants.length
                    if (l > 0) {
                        var b = false;
                        for (let a = 0; a < l; a++) {
                            var i = this.restaurants[a].value == this.keywords;
                            if (i) {
                                this.restaurants[a].num += 1;
                                b = true;
                            }
                        }
                        if (!b) {
                            console.log(this.keywords)
                            this.restaurants.push({"value": this.keywords, "num": 1});
                        }
                        var str = JSON.stringify(this.restaurants);
                        // str = "%5B"+str.substring(1,str.length-1)+"%5D"
                        console.log(str);
                        var parm = qs.stringify({
                            data:str,
                        });
                        this.$axios.post("/bd/save",parm).then(res=>{
                            if(res.data==1){
                                console.log("成功");
                            }
                        })

                        // console.log(str);
                        var objectArraySort = function (keyName) {
                            return function (objectN, objectM) {
                                var valueN = objectN[keyName]
                                var valueM = objectM[keyName]
                                if (valueN < valueM) return 1
                                else if (valueN > valueM) return -1
                                else return 0
                            }
                        }
                        this.restaurants.sort(objectArraySort("num"));


                    }
                }
            },

上面代码的逻辑如下:当搜索输入栏不为空,并且已经获得高频词数据(l>0),这时如果搜索栏的词在高频词库中,那么将它的num加一,如果不在高频词库中,将该词和num=1加入到高频词库中。通过push方法加入到列表的末尾。

var str = JSON.stringify(this.restaurants);                   
console.log(str);
 var parm = qs.stringify({
     data:str,
 });
 this.$axios.post("/bd/save",parm).then(res=>{
     if(res.data==1){
         console.log("成功");
     }
 })

上面这段代码就是通过post方法将数据传送到后端服务器保存起来。注意post传参数的方法。尤其是传送列表数据。

var objectArraySort = function (keyName) {
          return function (objectN, objectM) {
               var valueN = objectN[keyName]
               var valueM = objectM[keyName]
               if (valueN < valueM) return 1
               else if (valueN > valueM) return -1
               else return 0
           }
       }
 this.restaurants.sort(objectArraySort("num"));

上面这段代码用来根据列表中每个对象字典中的num数值进行从大到小的排序,这样搜索建议栏就可以按照词频进行显示了。

当点击搜索按钮时,不止是实现搜索功能,还要调用searchSuggest方法,把搜索词保存。

searchAl() { 
                var q = this.keywords
                if (q == '') {
                    alert("搜索内容不能为空")
                    this.tableLoading = false;
                    return;
                }
                this.searchSuggest();
                this.$router.push({path: '/anli', query: {}})//实现页面跳转到搜索结果页面的。
            },

2.后端springboot代码:

package com.nju.software.search.Controller;

import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.*;

import java.io.*;
import java.util.List;

@Controller
public class SearchController {

    @ResponseBody
    @RequestMapping("/save")
    public String saveSearch( String data){
        BufferedWriter writer = null;
        File file = new File("./data.json");
        //如果文件不存在,则新建一个
        if(!file.exists()){
            try {
                file.createNewFile();
            }catch (IOException e) {
                e.printStackTrace();
            }
        }
        //写入
        try {
            writer = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(file,false), "UTF-8"));
            writer.write(String.valueOf(data));
        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            try {
                if(writer != null){
                    writer.close();
                    System.out.println("文件写入成功!");
                    return "1";
                }
            } catch (IOException e) {
                e.printStackTrace();

            }
        }
        System.out.println("文件写入失败!");
        return "0";

    }

    @ResponseBody
    @RequestMapping("/read")
    public String read(){
        try {
            BufferedReader in = new BufferedReader(new FileReader("./data.json"));
            String str;
            while ((str = in.readLine()) != null) {
//                System.out.println(str);
                return str;
            }
        } catch (IOException e) {

        }
        return "";


    }
}

后端代码为了简单,没有使用数据库,而是将数据以json文件存储在本地,主要两个方法,一个保存数据,一个读取数据,过于简单,不做详细解释了。

你可能感兴趣的:(vue)