solr教程

一:安装配置

下载完成之后,解压solr文件,解压tomcat

 1.1 在tomcat安装solr,并且建立solrCore

  1. 把solr5.5目录下的server/solr-webapp/webapp 重命名为solr,并且放置到tomcat/webapp的目录下。 
  2. 打开tomcat/webapp/solr/WEB-INF/web.xml
  3. 新建一个文件夹,不要中文目录,用来做solrHome,也就是solrCore的实例存放位置
  4. 在tomcat/webapp/solr/WEB-INF/web.xml中配置solr的地址
  5. 在tomcat/webapp/solr/WEB-INF/文件夹中,建立classes目录

  6. 把solr5.5/server/resource/log4j.properties 复制到上一步建立的classes目录中
  7. 把solr5.5/server/lib/ext/目录下的所有jar文件复制到tomcat/webapp/solr/WEB-INF/lib/中,这是一些日志用的jar包,不然启动报错。
  8. 这个时候,可以输入http://127.0.0.1:8080/solr/admin.html来访问到solr的控制界面了。
  9. 接下来就是创建solrCore。
  10. 目前solrHome目录是空的,我们创建一个空文件夹core1,这个就是我们的一个实例,然后把solr5.5/server/solr/configsets/sample_techproducts_configs/conf/ 这个文件复制到solrHome/core1中。
  11. 把solr5.5/server/solr/solr.xml复制到solrHome目录下。
  12. 在solr的管理控制台界面,添加一个core1
  13. 这下就创建成功了一个实例core1,yge 请注意我打码的部分,需要先执行第11步操作,否则的话,会无法创建solr core,也就是会有错误信息,这是solr的一个bug,但是至今没有修复。

1.2 安装ik中文分词器

  1. 准备好ik分词器的jar包,可以自己编译,也可以下载我生成的。然后把它复制到tomcat/webapp/solr/WEB-INF/lib里面。(千万不要复制到tomcat/lib中,这样会找不到lucene的类)
  2. 打开solrHome/core1/conf/managed-schema文件,在最下方,追加如下配置
  3.     <fieldType name="text_ik" class="solr.TextField">
            <analyzer type="index" useSmart="false"
                class="org.wltea.analyzer.lucene.IKAnalyzer" />
            <analyzer type="query" useSmart="true"
                class="org.wltea.analyzer.lucene.IKAnalyzer" />
        </fieldType>

  4. 启动tomcat,即可看到text_ik分词

1.3 插入的文档必须与域相匹配

域,我个人也称它为字段,它在solr中有特定的含义,就类似数据库中表的列一样,规范着写入的数据,我们先来做个例子。

可以看到,我这次插入的文档,有id,title当然,在solr中,每一条记录都必须有着一个唯一的id,它就类似数据库中的主键,不可重复。这条记录的插入是成功的。

但是,如果我把title改成title1,这就与定义的字段不一样了,就会报错,如下图所示

可以看到,这里提示,未知的字段 title1.

1.4 域的定义 field

先拿出一条配置来看一下

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

 认识一下这些属性

  name:域名

  type:域的类型,必须匹配类型,不然会报错

  indexed:是否要作索引

  stored:是否要存储

  required:是否必填,一般只有id才会设置

  multiValued:是否有多个值,如果设置为多值,里面的值就采用数组的方式来存储,比如商品图片地址(大图,中图,小图等)

1.5 配置动态域 dynamicField

同样的,也先拿出一条来看看

<dynamicField name="*_i"  type="string"    indexed="true"  stored="true" multiValued="true" />

何谓动态域呢?就是这个域的名称,是由表达式组成的,只要名称满足了这个 表达式,就可以用这个域

 同样的认识一下这些属性

  name:域的名称,该域的名称是通过一个表达式来指定的,只要符合这这个规则,就可以使用这个域。比如  aa_i,bb_i,13_i等等,只要满足这个表达式皆可

  type:对应的值类型,相应的值必须满足这个类型,不然就会报错

  indexed:是否要索引

  stored:是否要存储

  ...其它的属性与普通的域一至

1.6 主键域 uniqueKey

给出一条配置

 <uniqueKey>id</uniqueKey>

指定一个唯一的主键,每一个文档中,都应该有一个唯一的主键,这个值不要随便改

1.7 复制域 copyField

给出一条配置

<copyField source="cat" dest="text"/>

说明一下相应的属性

  source:源域

  dest:目标域

复制域,将源域的内容复制到目标域中

注意:目标域必须是允许多值的,如下,nultiValued必须为true,因为可能多个源域对应一个目标域,所以它需要以数组来存储

<field name="text" type="string" indexed="true" stored="true" multiValued="true"/>

1.8 域的类型 fieldType

同样的给出一段配置,这段稍微有点复杂

    <fieldType name="text_general" class="solr.TextField" positionIncrementGap="100">
      <analyzer type="index">
        <tokenizer class="solr.StandardTokenizerFactory"/>
        <filter class="solr.StopFilterFactory" ignoreCase="true" words="stopwords.txt" />
        <!-- in this example, we will only use synonyms at query time
        <filter class="solr.SynonymFilterFactory" synonyms="index_synonyms.txt" ignoreCase="true" expand="false"/>
        -->
        <filter class="solr.LowerCaseFilterFactory"/>
      </analyzer>
      <analyzer type="query">
        <tokenizer class="solr.StandardTokenizerFactory"/>
        <filter class="solr.StopFilterFactory" ignoreCase="true" words="stopwords.txt" />
        <filter class="solr.SynonymFilterFactory" synonyms="synonyms.txt" ignoreCase="true" expand="true"/>
        <filter class="solr.LowerCaseFilterFactory"/>
      </analyzer>
    </fieldType>

给出相应属性的说明

  name:域的名称

  class:指定solr的类型

  analyzer:分词器的配置

    type: index(索引分词器),query(查询分词器)

    tokenizer:配置分词器

    filter:过滤器

1.9 业务字段的实际配置

经过上面的学习,差不多了解了一些常用的配置,如今我们用field来配置实际的业务字段,有属性如下

当然,中文分词还是要用的,因为我们在前面的  1.2  章节中,已经配置了一个fieldType的中文分词,所以我们现在一律用中文分词的域类型

主键的id就不需要配置了,默认已经把id配置为主键了,默认的配置如下

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

商品名称(需要分词,需要存储)

<field name="name" type="text_ik" indexed="true" stored="true"  /> 

商品分类(不需要分词,需要存储)

<field name="catalog" type="int" indexed="false" stored="true"  /> 

商品分类名称(需要分词,需要存储)

<field name="catalog_name" type="text_ik" indexed="true" stored="true"  /> 

商品价格(不分词,需要存储)

<field name="price" type="double" indexed="false" stored="true"  /> 

商品描述(需要分词,不需要存储)

<field name="description" type="text_ik" indexed="true" stored="false"  /> 

商品图片(不需要分词,需要存储)

<field name="picture" type="string" indexed="false" stored="true"  /> 

复制域的应用

前面我们了解了复制域,但是却不知道它的应用场景,现在我们结合实际情况来讲一下复制域

用户在搜索框搜索的时候,有可能输入的是商品名称,也有可能输入的是商品描述,也有可能输入的是一个商品类型,那么这些值的搜索,肯定在后台是对应一个域的,那么既然如此,我们就可以把这些域合并成一个,这样在后台只需要单独的对这一个域进行搜索就可以了

先定义一个目标域

<field name="keywords" type="text_ik" indexed="true" stored="false"  multiValued="true"/> 

复制域,把商品名称,商品描述,商品类型名称复制到上面的这个域中

<copyField source="name" dest="keywords"/>
<copyField source="catalog_name" dest="keywords"/>
<copyField source="description" dest="keywords"/>

1.10 dataimport 导入数据库数据

solr默认是没有开启dataimport这个功能的,所以我们要经过一点配置来开启它

  1. 首先找到solr5.5/dist/solr-dataimporthandler-5.5.2.jar,把这个文件复制到tomcat/webapp/solr/WEB-INF/lib/下,并且找到相应数据库的驱动包,也同样放到该目录。我这里用的是mysql的驱动包。
  2. 找到solr5.5/example/example-DIH/solr/db/conf/db-data-config.xml,把其复制到solrHome/core1/conf/下,并改名为data-config.xml.
  3. 找到solrHome/core1/conf/solrconfig.xml,并打开,在里面添加一段内容,如下
  4.   <requestHandler name="/dataimport" class="solr.DataImportHandler">
          <lst name="defaults">
                <str name="config">data-config.xml</str>
          </lst>
      </requestHandler>

  5. 打开并编辑data-config.xml,完整的配置文件如下
  6.  <dataConfig>
        <!-- 这是mysql的配置,学会jdbc的都应该看得懂 -->
        <dataSource driver="com.mysql.jdbc.Driver" url="jdbc:mysql://localhost:3306/solr/useUnicode=true&characterEncoding=utf-8" user="root" password="密码"/>
        <document>
            <!-- name属性,就代表着一个文档,可以随便命名 -->
            <!-- query是一条sql,代表在数据库查找出来的数据 -->
            <entity name="product" query="select * from products">
                <!-- 每一个field映射着数据库中列与文档中的域,column是数据库列,name是solr的域(必须是在managed-schema文件中配置过的域才行) -->
                <field column="pid" name="id"/>
                <field column="name" name="product_name"/>
                <field column="catalog" name="product_catalog"/>
                <field column="catalog_name" name="product_catalog_name"/>
                <field column="price" name="product_price"/>
                <field column="description" name="product_description"/>
                <field column="picture" name="product_picture"/>
            </entity>
        </document>
    </dataConfig>

  7. 重启tomcat,然后会看到如下页面
  8. 点击蓝色的按钮,则开始导入,导入过程依据数量量的大小,需要的时间也不同,可以点击右边的Refresh status来刷新状态,可以查看当前导入了多少条。
  9. 导入成功如下

二:solrj的使用

上面一章节已经讲完了solr的安装与配置,现在说一下使用solrj来维护solr的索引及操作,solrj就是一个java的客户端,是一个jar包的使用

首先引入MAVEN的依赖,solrj的版本号要对应solr的版本号

        <dependency>
            <groupId>org.apache.solr</groupId>
            <artifactId>solr-solrj</artifactId>
            <version>5.5.2</version>
        </dependency>

2.1 增加及修改

首先说明,在solr中,增加与修改都是一回事,当这个id不存在时,则是添加,当这个id存在时,则是修改

代码很好理解,直接给出

    private String serverUrl = "http://192.168.1.4:8080/solr/core1";
    /**
     * 增加与修改<br>
     * 增加与修改其实是一回事,只要id不存在,则增加,如果id存在,则是修改
     * @throws IOException 
     * @throws SolrServerException 
     */
    @Test
    public void upadteIndex() throws SolrServerException, IOException{
        //已废弃的方法
        //HttpSolrServer server = new HttpSolrServer("http://192.168.1.4:8080/solr/core1");
        //创建
        HttpSolrClient client = new  HttpSolrClient(serverUrl);
        SolrInputDocument doc = new SolrInputDocument();
        
        doc.addField("id", "zxj1");
        doc.addField("product_name", "javaWEB技术");
        doc.addField("product_catalog", "1");
        doc.addField("product_catalog_name", "书籍");
        doc.addField("product_price", "11");
        doc.addField("product_description", "这是一本好书");
        doc.addField("product_picture", "图片地址");
        
        client.add(doc);
        client.commit();
        
        client.close();
    }

2.2 删除索引

删除的代码也直接给出,看代码里面的注释就可以了

    /**
     * 删除索引
     * @throws Exception
     */
    @Test
    public void deleteIndex()throws Exception{
        HttpSolrClient client = new  HttpSolrClient(serverUrl);
        
        //1.删除一个
        client.deleteById("zxj1");
        
        //2.删除多个
        List<String> ids = new ArrayList<>();
        ids.add("1");
        ids.add("2");
        client.deleteById(ids);
        
        //3.根据查询条件删除数据,这里的条件只能有一个,不能以逗号相隔
        client.deleteByQuery("id:zxj1");
        
        //4.删除全部,删除不可恢复
        client.deleteByQuery("*:*");
        
        //一定要记得提交,否则不起作用
        client.commit();
        client.close();
    }

2.3 查询

查询稍微复杂一点,但是与solr管理界面的条件一致

  • q - 查询字符串,如果查询所有*:* (id:1)
  • fq - (filter query)过虑查询,过滤条件,基于查询出来的结果
  • fl - 指定返回那些字段内容,用逗号或空格分隔多个。
  • start - 分页开始
  • rows - 分页查询数据
  • sort - 排序,格式:sort=<field name>+<desc|asc>[,<field name>+<desc|asc>]… 。示例:(score desc, price asc)表示先 “score” 降序, 再 “price” 升序,默认是相关性降序。
  • wt - (writer type)指定输出格式,可以有 xml, json, php, phps。
  • fl表示索引显示那些field( *表示所有field,如果想查询指定字段用逗号或空格隔开(如:Name,SKU,ShortDescription或Name SKU ShortDescription【注:字段是严格区分大小写的】))
  • q.op 表示q 中 查询语句的 各条件的逻辑操作 AND(与) OR(或)
  • hl 是否高亮 ,如hl=true
  • hl.fl 高亮field ,hl.fl=Name,SKU
  • hl.snippets :默认是1,这里设置为3个片段
  • hl.simple.pre 高亮前面的格式
  • hl.simple.post 高亮后面的格式
  • facet 是否启动统计
  • facet.field 统计field

1. “:” 指定字段查指定值,如返回所有值*:*
2. “?” 表示单个任意字符的通配
3. “*” 表示多个任意字符的通配(不能在检索的项开始使用*或者?符号)
4. “~” 表示模糊检索,如检索拼写类似于”roam”的项这样写:roam~将找到形如foam和roams的单词;roam~0.8,检索返回相似度在0.8以上的记录。
5. 邻近检索,如检索相隔10个单词的”apache”和”jakarta”,”jakarta apache”~10
6. “^” 控制相关度检索,如检索jakarta apache,同时希望去让”jakarta”的相关度更加好,那么在其后加上”^”符号和增量值,即jakarta^4 apache
7. 布尔操作符AND、||
8. 布尔操作符OR、&&
9. 布尔操作符NOT、!、- (排除操作符不能单独与项使用构成查询)
10. “+” 存在操作符,要求符号”+”后的项必须在文档相应的域中存在
11. ( ) 用于构成子查询
12. [] 包含范围检索,如检索某时间段记录,包含头尾,date:[200707 TO 200710]

给出基本的代码看一下,仅仅作为一个基本的查询,高级的查询,各位要自己结合文档

package zxj.solrj;

import java.util.List;
import java.util.Map;

import org.apache.solr.client.solrj.SolrQuery;
import org.apache.solr.client.solrj.impl.HttpSolrClient;
import org.apache.solr.client.solrj.response.QueryResponse;
import org.apache.solr.common.SolrDocument;
import org.apache.solr.common.SolrDocumentList;
import org.junit.Test;

/**
 * 搜索
 * @author Administrator
 *
 */
public class IndexSearch {

    private String serverUrl = "http://192.168.1.4:8080/solr/core1";
    @Test
    public void search()throws Exception{
        HttpSolrClient client = new  HttpSolrClient(serverUrl);
        
        //创建查询对象
        SolrQuery query = new SolrQuery();
        //q 查询字符串,如果查询所有*:*
        query.set("q", "product_name:小黄人");
        //fq 过滤条件,过滤是基于查询结果中的过滤
        query.set("fq", "product_catalog_name:幽默杂货");
        //sort 排序,请注意,如果一个字段没有被索引,那么它是无法排序的
//        query.set("sort", "product_price desc");
        //start row 分页信息,与mysql的limit的两个参数一致效果
        query.setStart(0);
        query.setRows(10);
        //fl 查询哪些结果出来,不写的话,就查询全部,所以我这里就不写了
//        query.set("fl", "");
        //df 默认搜索的域
        query.set("df", "product_keywords");
        
        //======高亮设置===
        //开启高亮
        query.setHighlight(true);
        //高亮域
        query.addHighlightField("product_name");
        //前缀
        query.setHighlightSimplePre("<span style='color:red'>");
        //后缀
        query.setHighlightSimplePost("</span>");
        
        
        //执行搜索
        QueryResponse queryResponse = client.query(query);
        //搜索结果
        SolrDocumentList results = queryResponse.getResults();
        //查询出来的数量
        long numFound = results.getNumFound();
        System.out.println("总查询出:" + numFound + "条记录");
        
        //遍历搜索记录
        //获取高亮信息
        Map<String, Map<String, List<String>>> highlighting = queryResponse.getHighlighting();
        for (SolrDocument solrDocument : results) {
            System.out.println("商品id:" + solrDocument.get("id"));
            System.out.println("商品名称 :" + solrDocument.get("product_name"));
            System.out.println("商品分类:" + solrDocument.get("product_catalog"));
            System.out.println("商品分类名称:" + solrDocument.get("product_catalog_name"));
            System.out.println("商品价格:" + solrDocument.get("product_price"));
            System.out.println("商品描述:" + solrDocument.get("product_description"));
            System.out.println("商品图片:" + solrDocument.get("product_picture"));

            //输出高亮 
            Map<String, List<String>> map = highlighting.get(solrDocument.get("id"));
            List<String> list = map.get("product_name");
            if(list != null && list.size() > 0){
                System.out.println(list.get(0));
            }
        }
        
        client.close();
    }
}

注意:没有索引的域,是不能用作排序的

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/26350.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

DevOps - (3)使用SOPS 和Terraform来加密/解密敏感信息文件

一&#xff1a;背景 每个人都想将自己的敏感数据以加密格式存储在一个安全的地方。例如我们的数据库的账号密码&#xff0c;不能以纯文本的方式来记录。让我们利用Mozilla SOPS以一种安全的方式实现它。SOPS支持将文件加密为二进制文件&#xff0c;除此之外&#xff0c;它还具…

LNMT架构之LNMT与nginx动静分离

LNMT架构之LNMT与nginx动静分离 目录 一、实验前提环境配置 &#xff08;一&#xff09;关闭防火墙&#xff0c;安装本地yum &#xff08;二&#xff09;部署tomcat &#xff08;三&#xff09;部署Mariadb &#xff08;四&#xff09;部署nginx 二、动静分离 步骤一&a…

RISC-V IDE MRS使用笔记(八):实现局域网下的远程调试功能

RISC-V IDE MRS使用笔记(八)&#xff1a;实现局域网下的远程调试功能 1.原理介绍 MRS调试时上位机与硬件的通信基于gdb客户端与服务端的连接。调试时&#xff0c;首先启动openocd以挂载gdbserver的服务到指定端口上。通信建立后&#xff0c;监听到界面操作后以gdb指令的形式发…

Springboot +spring security,OAuth2 四种授权模式概念

一.简介 这篇文章来讲下Spring Security OAuth2 四种授权模式。 二.什么是OAuth2 OAuth 2.0 是一种用于授权的开放标准&#xff0c;允许用户授权第三方应用程序访问他们的资源&#xff0c;例如照片、视频或其他个人信息。OAuth 2.0 提供了一些不同的授权模式&#xff0c;包括…

测试替身Test Doubles的5类型(Mockito)

测试替身Test Doubles的5类型(Mockito) 我们有一个名为 BankAccount 的类。 数据库用于存储和检索银行帐户信息。 我们想测试 BankAccount 中的逻辑&#xff0c;而不必担心它使用的底层数据库.由此类实现——它将 SQL 查询发送到数据库并返回其中包含的值。 测试替身Test Dou…

Django实现接口自动化平台(五)httprunner(4.x)介绍【持续更新中】

上一章&#xff1a; Django实现接口自动化平台&#xff08;四&#xff09;解决跨域问题【持续更新中】_做测试的喵酱的博客-CSDN博客 下一章&#xff1a; 一、httpruner介绍 1.1 背景&#xff1a; 之所以学习httpruner的用法&#xff0c;是要把httpruner嵌入我们的自动化平…

自动缩放Kubernetes上的Kinesis Data Streams应用程序

想要学习如何在Kubernetes上自动缩放您的Kinesis Data Streams消费者应用程序&#xff0c;以便节省成本并提高资源效率吗&#xff1f;本文提供了一个逐步指南&#xff0c;教您如何实现这一目标。 通过利用Kubernetes对Kinesis消费者应用程序进行自动缩放&#xff0c;您可以从其…

2023年陕西彬州第八届半程马拉松赛153pb完赛

1、赛事背景 2023年6月3日&#xff0c;我参加了2023陕西彬州第八届半程马拉松赛&#xff0c;最终153完赛&#xff0c;PB了5分钟。起跑时间早上7点30分&#xff0c;毕竟6月天气也开始热了。天气预报显示当天还是小到中雨&#xff0c;上次铜川宜君半马也是雨天跑的&#xff0c;阴…

lecory 波形二进制文件头(.trc)定义

1.文件头&#xff0c;从0字节开始 byte[] lecroy_trc_header new byte[]{0x23,0x39,0x30,0x30,0x32,0x30,0x30,0x30,0x31,0x34,0x34,0x57,0x41,0x56,0x45,0x44,0x45,0x53,0x43,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x4C,0x45,0x43,0x52,0x4F,0x59,0x5F,0x32,0x5F,0x33,0x…

研发工程师玩转Kubernetes——使用Ingress进行路由

依据微服务理念&#xff0c;我们希望每个独立的功能由一个服务支持。比如有两个接口&#xff1a;http://www.xxx.com/plus和http://www.xxx.com/minus&#xff0c;前者由一个叫plus-service的服务支持&#xff0c;后者由一个叫minus-service的服务支持。这样就需要一个路由层&a…

Revit问题:创建牛腿柱和快速生成圈梁

一、Revit中如何用体量创建牛腿柱 牛腿&#xff1a;悬臂体系的挂梁与悬臂间必然出现搁置构造&#xff0c;通常就将悬臂端和挂梁端的局部构造&#xff0c;又称梁托。牛腿的作用是衔接悬臂梁与挂梁&#xff0c; 并传递来自挂梁的荷载。牛腿柱可以用于桥梁、厂房的搭建&#xff0c…

西南财经大学李玉周:数智化技术广泛使用推动管理会计加快落地

近日&#xff0c;由用友主办的「智能会计 价值财务」2023企业数智化财务创新峰会收官站圆满举办。来自知名院校的专家学者、央国企等大型企业财务领路人相约成都&#xff0c;一同见证“智能会计”新时代的到来&#xff0c;并肩探讨“价值财务”新主张。 为更好传递智能会计对企…

【接口测试】JMeter接口关联测试

‍‍1 前言 我们来学习接口管理测试&#xff0c;这就要使用到JMeter提供的JSON提取器和正则表达式提取器了&#xff0c;下面我们来看看是如何使用的吧。 2 JSON提取器 1、添加JSON提取器 在线程组右键 > 添加 > 后置处理器 > JSON提取器 2、JSON提取器参数说明 N…

chatgpt赋能python:Python如何删除行:从入门到精通

Python如何删除行&#xff1a;从入门到精通 在Python编程中&#xff0c;删除行是必不可少的操作之一。无论是清除不必要的数据&#xff0c;还是在数据集中删除重复行&#xff0c;或者在文本文件中删除某些行&#xff0c;删除行都是一项极其重要的任务。 什么是Python语言&…

Shell脚本攻略:文本三剑客之sed

目录 一、理论 1.sed 二、实验 1.sed命令的寻址打印 2.显示奇偶 3.查找替换 4.后向引用 一、理论 1.sed (1) 概念 sed 英文全称为stream editor流式编辑器&#xff0c;sed 对输入流&#xff08;文件或来自管道的输入&#xff09;执行基本文本转换单通过流&#xff0c;…

Matlab进阶绘图第22期—不等宽柱状图

不等宽柱状图是一种特殊的柱状图。 与常规柱状图相比&#xff0c;不等宽柱状图可以通过柱高与柱宽分别表达两个维度的数据&#xff0c;因此在多个领域得到应用。 在《Matlab论文插图绘制模板第91期》中&#xff0c;虽有介绍过利用Matlab自带bar函数绘制不等宽柱状图的方法&am…

高完整性系统(7)Formal Verification and Validation

文章目录 Specification Process 规格化过程State Invariants案例check ... expect Alloy是一种用于构建和检查抽象模型的语言和工具。当Alloy说所有断言都成立时&#xff0c;这意味着你的模型或规格在给定范围内已成功通过了所有的断言检查。换句话说&#xff0c;对于你所定义…

C#实例:多功能Windows窗体应用程序Helloworld_WinForm

有了创建一个Windows窗体应用程序的经验&#xff0c;就可以开始尝试运用更多的控件实现更多丰富的功能界面。以下分享我基于项目Helloworld_WinForm使用常用C#Windows窗体控件实现一些小功能。 每一节标题为所用到的控件&#xff0c;全文以实际制作过程为序编制。 目录 WinFor…

来了解一下白盒测试,黑盒测试,灰盒测试吧(超详解~)

根据被测对象的不同&#xff0c;软件测试可以分为白盒测试、黑盒测试、灰盒测试三种方式。那么&#xff0c;这三种测试方式具体是如何运行的&#xff1f;各有什么特点&#xff1f;下面&#xff0c;跟着静姐一起了解一下吧&#xff01; 01、白盒测试 WHITE BOX ●概念&#x…

PACS影像解决方案

现代医学影像技术的迅猛发展&#xff0c;使得PACS系统已逐渐成为各级医院实现信息化建设的重要组成部分。医学影像技术的进步也提升了医学影像的清晰度&#xff0c;推动二维PACS向三维升级转变。这一切都使得医学影像数据量激增&#xff0c;加之医疗行业法规的数据保存要求&…