我已将Solr 6.2.1配置为SolrCloud。后来我配置了基本身份验证。 我将使用Solrj 6.2配置Spring数据solr 2.0.4.RELEASE,这是我的代码:
@Configuration
@EnableSolrRepositories(basePackages = { "ir.saeed.server.solr" }, multicoreSupport = true)
public class SearchContext {
@Value("${solr.host}")
private String host;
@Value("${solr.port}")
private Integer port;
@Value("${solr.username}")
private String username;
@Value("${solr.password}")
private String password;
@Value("${zkHost}")
private String zkHost;
@Value("${solr.coreName}")
private String collectionName;
@Bean
public SolrTemplate solrTemplate() {
return new SolrTemplate(solrClientFactory());
}
@Bean
public BasicCredentialsProvider credentialsProvider() {
BasicCredentialsProvider provider = new BasicCredentialsProvider();
provider.setCredentials(AuthScope.ANY, new UsernamePasswordCredentials(username, password));
return provider;
}
@Bean
public SolrClientFactory solrClientFactory() {
return new HttpSolrClientFactory(solrClient(), "", credentialsProvider().getCredentials(AuthScope.ANY), "BASIC");
}
@Bean
public SolrClient solrClient() {
return new CloudSolrClient.Builder().withZkHost(zkHost).build();
}
}
但是,当我运行我的Web应用程序时,会发生此异常:
10:51:48,110 org.springframework.data.solr.UncategorizedSolrException: nested exception is java.lang.NullPointerException
10:51:48,111 at org.springframework.data.solr.core.SolrTemplate.execute(SolrTemplate.java:172)
10:51:48,111 at org.springframework.data.solr.core.SolrTemplate.executeSolrQuery(SolrTemplate.java:509)
10:51:48,111 at org.springframework.data.solr.core.SolrTemplate.query(SolrTemplate.java:504)
10:51:48,111 at org.springframework.data.solr.core.SolrTemplate.doQueryForPage(SolrTemplate.java:338)
10:51:48,111 at org.springframework.data.solr.core.SolrTemplate.queryForPage(SolrTemplate.java:350)
我该如何解决这个问题? 我认为我的配置不正确
答案 0 :(得分:0)
您的代码无法正常工作有几个原因,但主要是因为spring-data-solr缺少功能。
首先,spring-data-solr版本2.0.4不支持Solr 5(云)功能。
因此,这就是您在方法NullPointerException
org.springframework.data.solr.server.support.SolrClientUtils#cloneLBHttpSolrClient
的原因
我试图看看你公开的场景是否适用于spring-data-solr的最新SNAPSHOT(2.1.0-SNAPSHOT)以及SolrContext
spring配置类的一些修改:
@Configuration
@EnableSolrRepositories(basePackages = {"com.acme.solr"})
// notice that the multicoresupport is left false
// see org.springframework.data.solr.repository.config.SolrRepositoryConfigExtension#postProcess(org.springframework.beans.factory.support.BeanDefinitionBuilder, org.springframework.data.repository.config.AnnotationRepositoryConfigurationSource) for details
public class SolrContext {
@Bean
public Credentials credentials(@Value("${solr.username}") String username, @Value("${solr.password}") String
password) {
return new UsernamePasswordCredentials(username, password);
}
@Bean
public BasicCredentialsProvider credentialsProvider(Credentials credentials) {
BasicCredentialsProvider provider = new BasicCredentialsProvider();
provider.setCredentials(AuthScope.ANY, credentials);
return provider;
}
@Bean
public SolrClientFactory solrClientFactory(SolrClient solrClient, Credentials credentials) {
return new HttpSolrClientFactory(solrClient, "", credentials, "BASIC");
}
// create a solrtemplate bean, so that it is used in
// org.springframework.data.solr.repository.support.SolrRepositoryFactoryBean#doCreateRepositoryFactory method
// for using org.springframework.data.solr.repository.support.SolrRepositoryFactory#SolrRepositoryFactory(org.springframework.data.solr.core.SolrOperations) constructor
@Bean
public SolrTemplate solrTemplate(SolrClientFactory solrClientFactory){
return new SolrTemplate(solrClientFactory);
}
@Bean
public CloudSolrClient solrClient(@Value("${zkHost}") String zkHost) {
CloudSolrClient solrClient = new CloudSolrClient.Builder().withZkHost(zkHost).build();
solrClient.setDefaultCollection("gettingstarted");
return solrClient;
}
}
执行solr请求时(在solr上启用基本身份验证时),我仍然收到401身份验证问题。
在vanilla solrj应用程序中,这是您进行身份验证请求的方式:
CloudSolrClient solr = new CloudSolrClient.Builder()
.withZkHost("localhost:9983")
.build();
SolrQuery query = new SolrQuery();
query.setQuery("*:*");
SolrRequest<QueryResponse> req = new QueryRequest(query);
req.setBasicAuthCredentials("solr", "SolrRocks");
QueryResponse rsp = req.process(solr, "gettingstarted");
System.out.println("numFound: " + rsp.getResults().getNumFound());
当查看spring-data-solr的代码中是否使用了方法SolrRequest#setBasicAuthCredentials(String, String)
时,我没有注意到这个方法的使用。因此,很有可能,即使在spring-data-solr的SNAPSHOT版本中,这个功能还没有实现。
我在spring-data-solr项目上创建了一个feature request来添加对此功能的支持。
答案 1 :(得分:0)
我为那些有同样问题的人找到了解决方法 扩展您自己的HttpSolrClientFactory。 LBHttpSolrClient httpClient未正确设置导致的问题。正确的设置应该类似于以下块 if(solrClient instanceof LBHttpSolrClient){...}
<强> AuthHttpSolrClientFactory.java 强>
@SuppressWarnings(&#34;弃用&#34) 公共类AuthHttpSolrClientFactory扩展了HttpSolrClientFactory {
public AuthHttpSolrClientFactory(SolrClient solrClient, String core, Credentials credentials, String authPolicy) {
super(solrClient, core, credentials, authPolicy);
Assert.notNull(solrClient, "solrClient must not be null");
if (authPolicy != null) {
Assert.hasText(authPolicy);
}
appendBasicAuthentication(credentials, authPolicy, this.getSolrClient());
}
private void appendBasicAuthentication(Credentials credentials, String authPolicy, SolrClient solrClient) {
if( credentials != null) {
if (solrClient instanceof HttpSolrClient) {
HttpSolrClient httpSolrClient = (HttpSolrClient) solrClient;
if (assertHttpClientInstance(httpSolrClient.getHttpClient())) {
AbstractHttpClient httpClient = (AbstractHttpClient) httpSolrClient.getHttpClient();
httpClient.getCredentialsProvider().setCredentials(new AuthScope(AuthScope.ANY), credentials);
httpClient.getParams().setParameter(AuthPNames.TARGET_AUTH_PREF, Arrays.asList(authPolicy));
}
}
else if (solrClient instanceof LBHttpSolrClient) {
LBHttpSolrClient lbhttpSolrClient = (LBHttpSolrClient) solrClient;
if (assertHttpClientInstance(lbhttpSolrClient.getHttpClient())) {
AbstractHttpClient httpClient = (AbstractHttpClient) lbhttpSolrClient.getHttpClient();
httpClient.getCredentialsProvider().setCredentials(new AuthScope(AuthScope.ANY), credentials);
httpClient.getParams().setParameter(AuthPNames.TARGET_AUTH_PREF, Arrays.asList(authPolicy));
}
}
}
}
private boolean assertHttpClientInstance(HttpClient httpClient) {
Assert.isInstanceOf(AbstractHttpClient.class, httpClient,
"HttpClient has to be derivate of AbstractHttpClient in order to allow authentication.");
return true;
}
}
<强>豆-solr.xml 强>
<solr:solr-client id="solrClient" url="${solr.host}" />
<bean id="credentials" class="org.apache.http.auth.UsernamePasswordCredentials">
<constructor-arg type="java.lang.String" value="${solr.credentials}"/>
</bean>
<bean id="solrClientFactory" class="com.example.solr.AuthHttpSolrClientFactory" scope="singleton">
<constructor-arg ref="solrClient" />
<constructor-arg name="core">
<null />
</constructor-arg>
<constructor-arg ref="credentials" />
<constructor-arg type="java.lang.String" value="BASIC"/>
</bean>
<bean id="solrTemplate" class="org.springframework.data.solr.core.SolrTemplate" scope="singleton">
<constructor-arg ref="solrClientFactory" />
<constructor-arg name="requestMethod">
<value type="org.springframework.data.solr.core.RequestMethod">POST</value>
</constructor-arg>
</bean>
答案 2 :(得分:0)
是,您的配置似乎不正确。我遇到了像你一样的问题
我想使用6.6.0版的apache solr和2.0.8版的spring数据solr(由spring boot starter购买)。原来,spring data solr的版本不支持apache solr version> 5,因为当您跟踪
时在org.springframework.data.solr.core.SolrTemplate.execute(SolrTemplate.java:172)上,很明显,当solrTemplate打算创建createClientForCore时,它将从我们已配置的cloudSolrClient中克隆>
问题出在字符串zkHost =(String)readField(solrClient,“ zkHost”); *由于在apache solr版本> 5中,它将返回null,因为zkHost存储在“ clusterStateProvider”中,而不与“ cloudSolrClient”处于同一级别
已解决: 如果要继续使用spring data solr版本2,则需要降级apache solr版本
答案 3 :(得分:0)
在使用 Solr 7.7 和 spring-boot-starter-data-solr 2.1.14(使用 spring-data-solr-4.0.17.RELEASE)时遇到了同样的问题
尝试了几种方法,包括创建自定义 HttpSolrClientFactory。它有效,但实际上对 Solr 进行了 2 次调用,第一个返回 401 未经授权。
我解决了扩展 CloudSolrClient 的问题(尝试按照 Basic Auth with SolrJ 中的描述进行正确的身份验证)
它只调用一次 Solr 并使用基本身份验证
public class BasicAuthCloudSolrClient extends CloudSolrClient {
private final Credentials credentials;
/**
* Create a new client object that connects to Zookeeper using BASIC Authentication and is always aware
* of the SolrCloud state. If there is a fully redundant Zookeeper quorum and
* SolrCloud has enough replicas for every shard in a collection, there is no
* single point of failure. Updates will be sent to shard leaders by default.
*
* @param builder a {@link BasicAuthCloudSolrClient.Builder} with the options used to create the client.
*/
protected BasicAuthCloudSolrClient(Builder builder) {
super(builder);
this.credentials = builder.credentials;
}
@Override
public QueryResponse query(String collection, SolrParams params, SolrRequest.METHOD method)
throws
SolrServerException, IOException {
QueryRequest request = new QueryRequest(params, method);
request.setBasicAuthCredentials(credentials.getUserPrincipal().getName(),
credentials.getPassword());
return request.process(this, collection);
}
/**
* Constructs {@link BasicAuthCloudSolrClient} instances from provided configuration.
*/
public static class Builder extends CloudSolrClient.Builder {
protected Credentials credentials;
/**
* @deprecated use other constructors instead. This constructor will be changing visibility in an upcoming release.
*/
@Deprecated
public Builder() {
}
/**
* Provide a series of ZK hosts which will be used when configuring {@link CloudSolrClient} instances.
*
* @param zkHosts a List of at least one ZooKeeper host and port (e.g. "zookeeper1:2181")
* @param credentials a credentials to connect to Solr.
*/
public Builder(List<String> zkHosts, Credentials credentials) {
super(zkHosts, empty());
this.credentials = credentials;
}
/**
* Create a {@link CloudSolrClient} based on the provided configuration.
*/
public BasicAuthCloudSolrClient build() {
if (Objects.isNull(credentials)) {
throw new IllegalArgumentException(
"Credentials must be provided to initialize BasicAuthCloudSolrClient");
}
if (stateProvider == null) {
if (!zkHosts.isEmpty()) {
stateProvider = new ZkClientClusterStateProvider(zkHosts, zkChroot);
} else if (!this.solrUrls.isEmpty()) {
try {
stateProvider = new HttpClusterStateProvider(solrUrls, httpClient);
} catch (Exception e) {
throw new RuntimeException(
"Couldn't initialize a HttpClusterStateProvider (is/are the "
+ "Solr server(s), " + solrUrls + ", down?)", e);
}
} else {
throw new IllegalArgumentException("Both zkHosts and solrUrl cannot be null.");
}
}
return new BasicAuthCloudSolrClient(this);
}
@Override
public BasicAuthCloudSolrClient.Builder getThis() {
return this;
}
}
配置如下:
@Bean
public Credentials solrCredentials(@Value("${solr.username}") String username, @Value("${solr.password}") String
password) {
return new UsernamePasswordCredentials(username, password);
}
@Bean
public SolrClientFactory solrClientFactory(SolrClient solrClient,
Credentials solrCredentials) {
return new HttpSolrClientFactory(solrClient, solrCredentials, AuthSchemes.BASIC);
}
@Bean
public SolrTemplate solrTemplate(SolrClientFactory solrClientFactory){
return new SolrTemplate(solrClientFactory);
}
@Bean
public SolrClient solrClient(Credentials solrCredentials) {
if (isNotEmpty(properties.getZkHosts())) {
BasicAuthCloudSolrClient solrClient =
new BasicAuthCloudSolrClient.Builder(properties.getZkHosts(), solrCredentials).build();
solrClient.setDefaultCollection(properties.getCollection());
return solrClient;
} else {
throw new IllegalStateException("ZkHosts is required for application startup.");
}
}