• Solr搜索引擎的搭建与应用


     

    一、什么是Solr?

             Solr是一个高性能,采用Java开发,基于Lucene的全文搜索服务器。同时对其进行了扩展,提供了比Lucene更为丰富的查询语言,同时实现了可配置、可扩展并对查询性能进行了优化,并且提供了一个完善的功能管理界面,是一款非常优秀的全文搜索引擎

             个人理解, Solr是一个索引库,将数据库数据做成索引保存文件,从而大大提高搜索效率。

    二、Solr的应用场景

             Solr主要解决大数据量全文搜索问题,广泛应用于各大电商平台,例如:淘宝、京东等等。

             个人在工作中使用过的两个典型场景:

      1、约1.8亿的数据(占硬盘380多G),单条件模糊查询用时不到两秒

      2、网站数据1000万左右,日搜索请求量小200万,搜索响应速度两秒内

    三、Solr安装配置

      1. Solr运行环境要求

        需要安装jdk,要求jdk的版本为1.7.0以上版本。

        Tomcat要求7以上版本

        操作系统:linux、windows都可以

      2. 安装文件下载

        链接: https://pan.baidu.com/s/1LednAPNO0Jc5Zav8-WjklQ     提取码: 7mh4

      3. 安装JDK

                  JDK安装教程: https://www.cnblogs.com/vcing/p/13173512.html

      4. 安装Tomcat

                  Tomcat安装及配置教程:https://www.cnblogs.com/vcing/p/13173531.html

      5.搭建Solr

        a) 复制solr-4.7.2目录example/solr到D:Java目录下

          

        b) 复制solr-4.7.2目录dist/solr-4.7.2.war 到Tomcat的webapps/solr.war(solr-4.7.2.war重命名为solr.war)

        c) 复制solr-4.7.2目录example/lib/ext下的所有jar到Tomcat的lib下,同时将example/resources下的log4j.properties文件也复制到Tomcat的lib下

        d)在Tomcat/conf/Catalina/localhost下创建solr.xml文件,内容如下:

    <?xml version="1.0" encoding="utf-8"?>

    <Context docBase="webapps/solr.war" debug="0" crossContext="true">

      <Environment name="solr/home" type="java.lang.String" value="D:/Java/solr" override="true"/>

    </Context>

        e) 将Solr路径Tomcat7.0webappssolrWEB-INFweb.xml,

         <env-entry>

           <env-entry-name>solr/home</env-entry-name>

           <env-entry-value>D:/Java/solr</env-entry-value>

           <env-entry-type>java.lang.String</env-entry-type>

        </env-entry>

              

        f)  重新启动Tomcat服务器,在浏览器输入http://localhost:8080/solr 查看服务,出现如下界面就安装成功了.

           

    四、Solr控制面板介绍

      1.      Documents

          索引库的维护功能。可对索引进行增删改

        添加文档

          直接 Submit Document  就可以添加文档

          

          

        1) 在solr中,一条记录就是一个文档。

        2) 文档可以使用json数据格式描述:key就是域名(字段名),value就是值。在solr所有文档中,必须有一个id域。类似关系型数据库表中的主键。必须有,且不能重复。

        3) 域必须先定义后使用。必须在schema.xml中定义

       更新文档

         更新文档的原理:先删除后添加。保持ID相同,做添加操作,即更新文档。

        

         

      删除文档

    1. 根据字段删除,删除指定ID文档:<delete><id>change.me</id></delete><commit/>

         

    1. 根据查询条件删除:

        基础查询语法:

               *:*:匹配所有文档;

                  域名:关键字

        删除指定ID文档:<delete><query>id:1</query></delete><commit/>

        删除所有文档:<delete><query>*:*</query></delete><commit/>

       2.url请求删除

         ID删除:http://localhost:8080/solr/collection1/update/?stream.body=<delete><id>12345<id></delete>&commit=true

         搜索条件删除:http://localhost:8080/solr/collection1/update/?stream.body=<delete><query>*:*</query></delete>&commit=true

                http://localhost:8080/solr/collection1/update/?stream.body=<delete><query>orgingid:12345</query></delete>&commit=true

         多搜索条件删除:http://localhost:8080/solr/collection1/update/?stream.body=<delete><query>orderColumn:拟在建项目+AND+firstArea:海外</query></delete>&commit=tru

     2.      Query

        查询索引库

         

        q:查询条件

        fq:过滤条件,查询语句和查询语法完全相同。可设置多个过滤条件

        sort:排序条件

        start,rows:分页条件。start:起始记录,rows每页显示的记录数。

        fl:返回结果中域的列表。默认显示所有域

        df:默认搜索域

        hl:高亮显示

        hl.fl:高亮显示的域

        hl.simple.pre:高亮前缀

        hl.simple.post:高亮后缀

      3. Analysis

        在Field Value输入你好啊solr ,Analyse FieldName/FieldType中选择text_en,然后点击左侧Analyze Value按钮,就能看到分词结果。Solr自带的数据类型,对中文分词效果不太好

        效果图如下:

         

         

          域(字段)列表:所有的域都是定义在schema.xml配置文件中。在solr中,域必须是先定义后使用。如果想修改域的定义及自定义域需要修改schema.xml。

          

    五、Solr分词器安装

       安装IK分词器

        A. 分词器介绍

        一个分词器就是一个数据类型,分词器的安装是非必要的。Solr自带的数据类型,对中文分词效果不太好,根据自己使用需求,可以安装其他分词器。以IK分词器为例,介绍下分词安装步骤

        B. 资源下载

          官网下载地址:http://code.google.com/p/ik-analyzer/downloads/detail?name=IK%20Analyzer%202012FF_hf1.zip&can=2&q=

          当然 Solr安装文件 中已有,可以直接使用

        C. 安装配置

          1、复制ik分词解压包中的三个文件::IKAnalyzer.cfg.xml、IKAnalyzer2012FF_u1.jar、stopword.dic 到Tomcat7webappssolrWEB-INFlib文件夹下面

         2、修改D:Javasolrcollection1conf文件夹下的schema.xml.在<types></types>中增加如下内容:

    <!--配置IK分词器—name是名称 下面可以选择分词器-->
        <fieldType name="text_ik" class="solr.TextField">
            <!--索引时候的分词器-->
              <analyzer type="index" isMaxWordLength="false" class="org.wltea.analyzer.lucene.IKAnalyzer"/>
            <!--查询时候的分词器-->
            <analyzer type="query" isMaxWordLength="true" class="org.wltea.analyzer.lucene.IKAnalyzer"/>
        </fieldType>

        3、重启Tomcat,在浏览器中输入http://localhost:8080/solr ,在页面左侧菜单中选择Core为collection1,点击Analysis(漏斗形状)菜单,在右侧页面Filed Value文本框中输入要测试分词的中文串.

        4、在Field Value下方,Analyse FieldName/FieldType中选择text_ik,然后点击左侧Analyze Value按钮,就能看到分词结果。

          效果图如下:

          

    六、solr的配置文件及其含义

        详见:https://www.cnblogs.com/vcing/p/13196342.html

    七、solr连接数据库

      安装配置

        1、将sqljdbc4.jar复制到D:JavaTomcat7.0webappssolrWEB-INFlib

        2、在D:Javasolrcollection1conf下新建data-config.xml文件(名字任意,路径也可以任意)

           

        3、在D:Javasolrcollection1confsolrconfig.xml,文件里配置data-confing.xml路径

    <requestHandler name="/dataimport" class="org.apache.solr.handler.dataimport.DataImportHandler">  
        <lst name="defaults">  
              <str name="config">D:/Java/solr/collection1/conf/db/data-config.xml</str>  
        </lst>  
    </requestHandler>

        4、将solr4.72文件夹下的dist, contrib文件夹复制到D:JavaTomcat7.0

        5、在D:Javasolrcollection1confsolrconfig.xml,文件里配置dist, contrib这两个文件夹的路径(solrconfig.xml已存在这些路径,如果以你放置的路径不一样,修改一下就可以了)

    <lib dir="D:/Java/Tomcat7.0/contrib/extraction/lib" regex=".*.jar" />
      <lib dir="D:/Java/Tomcat7.0/dist/" regex="solr-cell-d.*.jar" />
     
      <lib dir="D:/Java/Tomcat7.0/contrib/clustering/lib/" regex=".*.jar" />
      <lib dir="D:/Java/Tomcat7.0/dist/" regex="solr-clustering-d.*.jar" />
     
      <lib dir="D:/Java/Tomcat7.0/contrib/langid/lib/" regex=".*.jar" />
      <lib dir="D:/Java/Tomcat7.0/dist/" regex="solr-langid-d.*.jar" />
     
      <lib dir="D:/Java/Tomcat7.0/contrib/velocity/lib" regex=".*.jar" />
      <lib dir="D:/Java/Tomcat7.0/dist/" regex="solr-velocity-d.*.jar" />
     
       <lib dir="D:/Java/Tomcat7.0/dist/" regex="solr-dataimporthandler-d.*.jar" />

         6、将dist文件夹下的这两个文件复制到与数据库驱动同一个文件夹下,以上配置的路径我是用绝对路径配置的,也可以用相对路径,

         7、配置连接数据库。首先是配置data-confing.xml文件,data-confing.xml文件就是连接数据库的配置文件(刚才新建的),将如下代码粘贴到该文件中

    <?xml version="1.0" encoding="UTF-8"?>  
    <dataConfig>
        <dataSource driver="com.microsoft.sqlserver.jdbc.SQLServerDriver" url="jdbc:sqlserver://127.0.0.1;DatabaseName=test" user="sa" password="123456"/>
        <document name="Info">
            <entity name="zpxx"  transformer="ClobTransformer" pk="id"
                  query="select id,name from test"        
              deltaImportQuery="select id,name from test"    
              deltaQuery="SELECT id FROM test where adddate >='${dataimporter.last_index_time}'">             
                        <field column="id"      name="id"      />  
                        <field column="name"      name="name"      />  
             </entity>
        </document>
        </dataConfig>

       配置文件讲解分析

          a).这个显而易见,就是连接数据库的字符串了

      <dataSource driver="com.microsoft.sqlserver.jdbc.SQLServerDriver"  url="jdbc:sqlserver://127.0.0.1;DatabaseName=test" user="sa" password="123456"/>

           b).这个就是从哪张表里取数据了的sql语句了   

             query是获取全部数据的SQL(solr从sql中获取那些数据)
             deltaImportQuery是获取增量数据时使用的SQL(数据库新增数据是,追加到solr的数据)
             deltaQuery是获取pk的SQL(数据库新增数据是,追加到solr的数据时的条件,根据id ,条件是最后一次获取的时间,${dataimporter.last_index_time,最后获取的时间})

    <document name="Info">
            <entity name="zpxx"  transformer="ClobTransformer" pk="id"
                  query="select id,name from test"        
              deltaImportQuery="select id,name from test"    
              deltaQuery="SELECT id FROM test where adddate >='${dataimporter.last_index_time}'">             
                        <field column="id"      name="id"      />  
                        <field column="name"      name="name"      />  
             </entity>
        </document>

         c).这个就是数据库与solr的映射关系了,在上一节schema.xml中定义的field子节点对应,那么根据本届内容field就要这么定义

    <field column="id"      name="id"      />  

     <field column="name"      name="name"      /> 

    <field name="id" type="string" indexed="true" stored="true" required="true" multiValued="false" /> 
     <field name="solrname" type=" string " indexed="true" stored="true" omitNorms="true"/>

         其他的field就可以删掉了(初学者不要删,容易出问题),也可以多定义一些备用,这样table表中id下的数据就存储在了solr中id的位置,name就存储在solrname下了

        这个不要删,这是solr自已自己内部的字段,删掉会报错,这样solr就配置完成

    <field name="_version_" type="long" indexed="true" stored="true"/>
       
       <!-- points to the root document of a block of nested documents. Required for nested
          document support, may be removed otherwise
       -->
       <field name="_root_" type="string" indexed="true" stored="false"/>

        d). 多表、多库

        <entity> …..  </entity> 每一个 entiy就是一张表,有几张表就写几个,这里就要注意一个问题了,单核的solr是把所有的数据存储在在一个文件中,上文中结束的时候说道, schema.xml这个文件可以设置主键(一定要有主键),默认是id, data-confing.xml,文件定义每张表时也指定了主键,没写默认id,多张表示就要注意id的唯一行了,平时我们总是喜欢使用自增id,所以多张表的id肯定会重复,主键的重复solr是不会报错了,但是遵循相同主键后一条覆盖前一条,所以多张表时,就要考虑主键唯一的问题了,如果使用guid的形式那就没问题了,(solr从数据库获取数据是按<entity> …..  </entity>的顺序逐个表去取数据了),那如果非要主键重复存储怎么办,也可以,使用多核模式

            多表实例:

    <?xml version="1.0" encoding="UTF-8"?>  
    <dataConfig>
        <dataSource driver="com.microsoft.sqlserver.jdbc.SQLServerDriver" url="jdbc:sqlserver://127.0.0.1;DatabaseName="test" user="sa" password="123456"/>
        <document name="Info">
                
            <entity name="zpxx"  transformer="ClobTransformer"
                     query="select id, name from test"        
                     deltaImportQuery="select id, name from test"    
                     deltaQuery="SELECT id FROM table where adddate >= '${dataimporter.last_index_time}'">             
                        <field column="id"      name=“id"      />  
                        <field column="name"      name=“name"      />  
             </entity>
     
          
            <entity name="zpxx2"  transformer="ClobTransformer"
                     query="select id, name from test2"        
                     deltaImportQuery="select id, name from test2"    
                     deltaQuery="SELECT id FROM table2 where adddate >='${dataimporter.last_index_time}'">             
                        <field column="id"      name=“id"      />  
                        <field column="name"      name=“name"      />  
             </entity>
        </document>
        </dataConfig>

         现在再说一说多数据库的问题了,一个配置文件可以配置多个数据源。增加一个dataSource元素就可以增加一个数据源了。name属性可以区分不同的数据源。如果配置了多于一个的数据源,那么要注意将name配置成唯一的。

           多数据库实例:

    <dataSource type="JdbcDataSource" name="ds-1" driver="com.mysql.jdbc.Driver" url="jdbc:mysql://db1-host/dbname" user="db_username" password="db_password"/>
     
    <dataSource type="JdbcDataSource" name="ds-2" driver="com.mysql.jdbc.Driver" url="jdbc:mysql://db2-host/dbname" user="db_username" password="db_password"/>
     
     
     
     然后这样使用
        
    ..
     
    <entity name="one" dataSource="ds-1" ...>
     
       ..
     
    </entity>
     
    <entity name="two" dataSource="ds-2" ...>
     
       ..
     
    </entity>
     
    ..

        如果存在多表链接怎么办,这个也可以解决, <entity> 中可以嵌套<entity>达到链接效果

           例:

    <entity name="item" query="select id name from item">                    
          <entity name="feature" query="select description  from feature where item_id='${item.ID}'"/>            
         <entity name="item_category" query="select phone from  item_category where  category _id='${item.ID}'">
          </entity>
    </entity>

        这个相当于 select a.id ,a.name ,b. description ,c. phone from item as a left join feature as b on a.id=b. item_id left join item_category as c on a.id=c. category _id
            这个链接也是有限制的:
                 子Entity的query必须引用父Entity的pk
                 子Entity的parentDeltaQuery必须引用自己的pk
                 子Entity的parentDeltaQuery必须返回父Entity的pk
                 deltaImportQuery引用的必须是自己的pk

        说了这么多我们来简单的配置一个,现在有一张表tableA,有如下字段id ,name,address,phone,class,addtime 我想把这张表的数据存储到solr, 怎配置,首先在schema.xml fields 节点配置索引字段,(name可以随便起,type是类型,上文字提到过solr的类型,这里为了省事就都用string)

    <field name="id" type="string" indexed="true" stored="true" required="true" multiValued="false" /> 
       <field name="solrname" type=" string " indexed="true" stored="true" omitNorms="true"/>
    <field name=" address " type="string" indexed="true" stored="true" required="true" multiValued="false" /> 
       <field name="phone" type=" string " indexed="true" stored="true" omitNorms="true"/>
       <field name="class" type=" string " indexed="true" stored="true" omitNorms="true"/>
       <field name="addtime" type=" date" indexed="true" stored="true" omitNorms="true"/>

     

        上文中还提到过 copyfeild与DynamicField,这个可用可不用,怎样用上文已经解释了,solr中会自带一些定义,想删就删,不删也没事,然后我们配置data-confing.xml,如下,

    <dataSource driver="com.microsoft.sqlserver.jdbc.SQLServerDriver" url="jdbc:sqlserver://127.0.0.1;DatabaseName=test" user="sa" password="123456"/>
        <document name="Info">
            <entity name=" test "  transformer="ClobTransformer" pk="id"
              query="select id, name ,address,phone,class,addtime from tableA"        
              deltaImportQuery=" select id, name ,address,phone,class,addtime from tableA"    
              deltaQuery="SELECT id FROM tableA where addtime > '${dataimporter.last_index_time}'">          
                <field column="id"      name="id"      />  
                 <field column="name"      name="solrname"      />  
                 <field column="address "      name=“address "      />  
                 <field column="phone "      name="phone "      /> 
                 <field column="class "      name="class "      />  
                 <field column="addtime "      name="addtime "      /> 
             </entity>
        </document>
        </dataConfig>

     

     

     

         好了,这样就配置完成了,下面该开始执行了,执行有两种方式

             先说第一种,浏览器执行方式:

         终止跑索引                 

          http://localhost:8080//solr/collection1/dataimport?command=abort

          开始索引                    

          http://localhost:8080//solr/collection1/dataimport?command=full-import

          增量索引                     

          http://localhost:8080//solr/collection1/dataimport?command=delta-import

             直接在浏览器中输入 http://localhost:8080//solr/collection1/dataimport?command=full-import就可以了

             我们看看效果

           

         这种方式我们看不到执行过程,执行时间

            Solr还提供了图形化的执行方式,如下:

        

          Full Import工作原理
              执行本Entity的Query,获取所有数据;
              针对每个行数据Row,获取pk,组装子Entity的Query;
              执行子Entity的Query,获取子Entity的数据。

             Delta Import工作原理
              查找子Entity,直到没有为止;
              执行Entity的deltaQuery,获取变化数据的pk;
              合并子Entity parentDeltaQuery得到的pk;
              针对每一个pk Row,组装父Entity的parentDeltaQuery;
              执行parentDeltaQuery,获取父Entity的pk;
              执行deltaImportQuery,获取自身的数据;
              如果没有deltaImportQuery,就组装Query

         强调一下,修改了Solr或TomCat配置文件 ,需重启tomcat

    八、solr定时增量索引与安全

          solr增量索引的方式,就是一个Http请求,但是这样的请求显然不能满足要求,我们需要的是一个自动的增量索引,solr官方提供了一个定时器实例,来完成增量索引。

      1、下载 apache-solr-dataimportscheduler-1.0.jar,

      下载地址:http://solr-dataimport-scheduler.googlecode.com/files/apache-solr-dataimportscheduler-1.0.jar

      当然,Solr安装文件 中有,可以直接使用

      2、安装配置

       1) 将apache-solr-dataimportscheduler-1.0.jar

        复制到D:JavaTomcat7.0webappssolrWEB-INFlib

       2) 修改D:JavaTomcat7.0webappssolrWEB-INF下的web.xml文件, 在servlet节点前面增加

    <listener>
         <listener-class>
           org.apache.solr.handler.dataimport.scheduler.ApplicationListener
         </listener-class>
      </listener>

      3) 将apache-solr-dataimportscheduler-.jar 中 dataimport.properties 取出,放入D:Javasolrconf,没有conf新建一个

      4) 重启tomcat即可

      5) dataimport.properties 配置项说明

    #################################################

    #                                               #

    #       dataimport scheduler properties         #

    #                                               #

    #################################################

    #  to sync or not to sync

    #  1 - active; anything else - inactive

    syncEnabled=1

    #  which cores to schedule

    #  in a multi-core environment you can decide which cores you want syncronized

    #  leave empty or comment it out if using single-core deployment

    syncCores=game,resource

    #  solr server name or IP address

    #  [defaults to localhost if empty]

    server=localhost

    #  solr server port

    #  [defaults to 80 if empty]

    port=8080

    #  application name/context

    #  [defaults to current ServletContextListener's context (app) name]

    webapp=solr

    #  URL params [mandatory]

    #  remainder of URL

    params=/select?qt=/dataimport&command=delta-import&clean=false&commit=true

    #  schedule interval

    #  number of minutes between two runs

    #  [defaults to 30 if empty]

    interval=1

    #  重做索引的时间间隔,单位分钟,默认7200,即1天;

    #  为空,为0,或者注释掉:表示永不重做索引

    reBuildIndexInterval=2

    #  重做索引的参数

    reBuildIndexParams=/select?qt=/dataimport&command=full-import&clean=true&commit=true

    #  重做索引时间间隔的计时开始时间,第一次真正执行的时间=reBuildIndexBeginTime+reBuildIndexInterval*60*1000;

    #  两种格式:2012-04-11 03:10:00 或者  03:10:00,后一种会自动补全日期部分为服务启动时的日期

    reBuildIndexBeginTime=03:10:00

        以上是原文,#后面的是注释,我们来翻译一下

    #################################################

    #                                               #

    #       dataimport scheduler properties         #

    #                                               #

    #################################################

    syncEnabled=1

    #要定时的增量索引的核心,多核逗号隔开 collection1, collection2

    syncCores= collection1

    # 这个就不用说了,服务器地址

    server=192.168.0.9

    port=8080

    webapp=solr

    # 增量索引执行的命令

    params=/dataimport?command=delta-import&clean=false&commit=true

    #多长时间执行一次,默认单位分钟

    interval=30

    #下面的,是有人更改了该文件,新加的定时重建索引,原包是不带定时重建索引的,只有增量索引,官方的包是不支持下面三句话的,不需要可以删掉

    reBuildIndexInterval=7200

    reBuildIndexParams=/dataimport?command=full-import&clean=true&commit=true

    reBuildIndexBeginTime=03:10:00

      3、solr安全性的问题

        了解solr后,大家都知道了,solr是通过Http请求去执行所有操作的,那问题就来了,如果别人知道了你的solr服务器的地址就很危险了,solr的新增和删除也都是通过http请求来完成的,地址暴漏后,

      你的数据就容易受到攻击了.我这里的解决办法是,设置tomcat的访问权限,只有固定ip可以访问,这样别人就访问不了你的solr了

      修改C:Program FilesApache Software FoundationTomcat 7.0confserver.xml,加入ip限制即可

      全局设置,对Tomcat下所有应用生效
         server.xml中添加下面一行,重启服务器即可:

         <Valve className="org.apache.catalina.valves.RemoteAddrValve" allow="192.168.1.*"  deny=""/> 

        此行放在</Host>之前。

          例:

        1).只允许192.168.1.10访问:

          <Valve className="org.apache.catalina.valves.RemoteAddrValve"allow="192.168.1.10" deny=""/>

        2).只允许192.168.1.*网段访问:

          <Valve className="org.apache.catalina.valves.RemoteAddrValve" allow="192.168.1.*" deny=""/>

        3).只允许192.168.1.10、192.168.1.30访 问:

          <Valve className="org.apache.catalina.valves.RemoteAddrValve" allow="192.168.1.10,192.168.1.30" deny=""/>

        4).根据主机名进行限制:

          <Valve className="org.apache.catalina.valves.RemoteHostValve" allow="abc.com" deny=""/>

    九、solr在程序中应用

      1、Java-SolrJ管理索引库

        solr提供的一个客户端,就是一个jar包,把jar包添加到工程中整合solr服务。

         

        1) 第一步:创建java工程

        2) 第二步:导入jar包

           

           

           

           

           

           

       3)第三步:创建java类进行测试

      添加文档

       代码演示:(不发源码,自己手敲熟悉一遍)

    1. 创建一个连接solr服务的客户端对象SolrServer对象。
    2. 创建一个文档对象
    3. 向文档对象中添加域
    4. 提交文档到索引库

        

      更新文档

        更新文档同添加文档,ID保持一致即可,这里就做代码演示了

      删除文档

        代码演示:(不发源码,自己手敲熟悉一遍)

         

       查询

         

      2、C#-Solr管理索引库

        两种方式:

       手写请求,通过solr 命令进行增删改查

        代码演示

        

         

         

         

         

      使用SolrNet.dll 实现增删改查

        参考资料:https://www.cnblogs.com/vcing/p/13196312.html

    十、相关扩展

        本篇笔记整理主要参考前辈 "一枚信蜂"的博客笔记,修复了他笔记中一些配置问题,想了解更多请参照:https://www.cnblogs.com/wenxinghaha/

  • 相关阅读:
    论文--文章编号
    论文---参考文献格式
    第3章 Java语言基础----static
    第3章 Java语言基础----成员变量与局部变量
    第3章 Java语言基础----声明成员变量,对变量进行赋值
    第2章 熟悉Eclipse开发工具----加减乘除,和差积商的英文写法
    第1章 初识java----输出多行的语句写法
    No PostCSS Config found解决办法
    react-cnode
    qs.parse()、qs.stringify()使用方法
  • 原文地址:https://www.cnblogs.com/vcing/p/13196298.html
Copyright © 2020-2023  润新知