springboot2.0.1(目前最新版本)整合redis叢集和多索引庫solr,同時將redis叢集作mybatis的二級快取

WoddenFish發表於2018-05-10

springboot2.0.1版本相對之前的版本來說有較大的改動,所以在配置的時候不太一樣。

《《《《原始碼下載直通車》》》》

1.pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>

	<groupId>cn.fx2</groupId>
	<artifactId>fx2Back</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<packaging>war</packaging>

	<name>fx2Back</name>
	<description>後臺管理系統</description>

	<parent>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-parent</artifactId>
		<version>2.0.1.RELEASE</version>
		<relativePath /> <!-- lookup parent from repository -->
	</parent>

	<properties>
		<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
		<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
		<java.version>1.8</java.version>
	</properties>

	<dependencies>
		<!-- 分頁外掛 -->
		<dependency>
			<groupId>com.github.pagehelper</groupId>
			<artifactId>pagehelper-spring-boot-starter</artifactId>
			<version>1.2.3</version>
		</dependency>
		<!--熱部署 -->
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-devtools</artifactId>
			<optional>true</optional>
		</dependency>
		<!-- 引入freeMarker的依賴包. -->
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-freemarker</artifactId>
		</dependency>
		<!-- Spring-Mybatis -->
		<dependency>
			<groupId>org.mybatis.spring.boot</groupId>
			<artifactId>mybatis-spring-boot-starter</artifactId>
			<version>1.3.2</version>
		</dependency>
		<!-- MySQL -->
		<dependency>
			<groupId>mysql</groupId>
			<artifactId>mysql-connector-java</artifactId>
			<scope>runtime</scope>
		</dependency>
		<!-- Redis配置 -->
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-data-redis</artifactId>
		</dependency>
		<dependency>
			<groupId>redis.clients</groupId>
			<artifactId>jedis</artifactId>
		</dependency>
		<!--solr -->
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-data-solr</artifactId>
		</dependency>
		<!--逆向工程 -->
		<dependency>
			<groupId>org.mybatis.generator</groupId>
			<artifactId>mybatis-generator-core</artifactId>
			<version>1.3.5</version>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
		</dependency>

		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-tomcat</artifactId>
			<scope>provided</scope>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-test</artifactId>
			<scope>test</scope>
		</dependency>
	</dependencies>

	<build>
		<plugins>
			<plugin>
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-maven-plugin</artifactId>
			</plugin>
		</plugins>
	</build>


</project>

2.application.yml

server:
  #服務埠號
  port: 8080
  debug: true
#spring配置
spring:
  #資料來源配置
  datasource:
    driver-class-name: com.mysql.jdbc.Driver
    url: jdbc:mysql://localhost:3306/manager
    username: root
    password: 123456
  #freemaker配置
  freemarker:
    allow-request-override: false
    cache: true
    check-template-location: true
    charset: UTF-8
    content-type: text/html
    expose-request-attributes: false
    expose-session-attributes: false
    expose-spring-macro-helpers: false
  #solr配置
  data: 
    solr:
      host: http://localhost:9080/solr
  #redis叢集配置
  redis:
    # Redis伺服器連線密碼(預設為空) 
    password: *****
    jedis:
      pool:
       # 連線池最大連線數(使用負值表示沒有限制)
        max-active: 5000
       # 連線池最大阻塞等待時間(使用負值表示沒有限制)   
        max-wait: -1
       # 連線池中的最大空閒連線
        max-idle: 30
       # 連線池中的最小空閒連線 
        min-idle: 5
    # 連線超時時間(毫秒)
    timeout: 50000
    commandTimeout: 50000
    #叢集
    cluster:
      nodes: 192.168.0.159:7001,192.168.0.159:7002,192.168.0.159:7003,192.168.0.159:7004,192.168.0.159:7005,192.168.0.159:7006
#mybatis配置
mybatis:
  mapper-locations: classpath:mybatis/mapper/*.xml,mybatis/mapper/customize/*.xml
  config-location: classpath:mybatis/mybatis-config.xml

3.mybatis-config.xml

<?xml version="1.0" encoding="UTF-8"?>  
<!DOCTYPE configuration  
  PUBLIC "-//mybatis.org//DTD Config 3.0//EN"  
  "http://mybatis.org/dtd/mybatis-3-config.dtd">  
<configuration>  
    <settings>  
        <setting name="cacheEnabled" value="true"/>  
    </settings>
</configuration> 

4.mapper.xml

<?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="cn.fx2.mapper.BannerMapper">
<cache type="cn.fx2.utils.MybatisRedisCache"></cache>

  <select>省略</select>
</mapper>

5.入口類Application.java

import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cache.annotation.EnableCaching;

@SpringBootApplication
@MapperScan({"cn.gdq.mapper.customize","cn.gdq.mapper"})
@EnableCaching
public class Application {

	public static void main(String[] args) {
		SpringApplication.run(Application.class, args);
	}
}

6.redis叢集配置類

import java.net.UnknownHostException;
import java.util.HashSet;
import java.util.Set;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;

import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;

import redis.clients.jedis.HostAndPort;
import redis.clients.jedis.JedisCluster;
import redis.clients.jedis.JedisPoolConfig;

/**
 * Title: RedisProperties 
 * @author: gdq
 * @date 2018年5月7日
 * @version V1.0 Description: redis叢集實體類
 */
@Configuration
@ConditionalOnClass({ JedisCluster.class })
public class RedisConfig {
	@Value("${spring.redis.cluster.nodes}")  
    private String clusterNodes;  
    @Value("${spring.redis.timeout}")  
    private int timeout;  
    @Value("${spring.redis.jedis.pool.max-idle}")  
    private int maxIdle;  
    @Value("${spring.redis.jedis.pool.max-wait}")  
    private long maxWaitMillis;  
    @Value("${spring.redis.commandTimeout}")  
    private int commandTimeout;
    @Value("${spring.redis.password}")
    private String password;
	
	@Bean
	public JedisCluster getJedisCluster() {
		String[] cNodes = clusterNodes.split(",");
		Set<HostAndPort> nodes = new HashSet<HostAndPort>();
		// 分割出叢集節點
		for (String node : cNodes) {
			String[] hp = node.split(":");
			nodes.add(new HostAndPort(hp[0], Integer.parseInt(hp[1])));
		}
		JedisPoolConfig jedisPoolConfig = new JedisPoolConfig();
		jedisPoolConfig.setMaxIdle(maxIdle);
		jedisPoolConfig.setMaxWaitMillis(maxWaitMillis);
		/*GenericObjectPoolConfig jedisPoolConfig=new GenericObjectPoolConfig();
		jedisPoolConfig.setMaxIdle(maxIdle);
		jedisPoolConfig.setMaxWaitMillis(maxWaitMillis);*/
		// 建立叢集物件
		// JedisCluster jedisCluster = new JedisCluster(nodes,commandTimeout);
		JedisCluster jedisCluster = new JedisCluster(nodes,commandTimeout,timeout,maxIdle,password,jedisPoolConfig);
		//JedisCluster jedisCluster=new JedisCluster(nodes,commandTimeout,jedisPoolConfig);
		return jedisCluster;
	}

	/**
	 * 設定資料存入 redis 的序列化方式 </br>
	 * redisTemplate 序列化預設使用的jdkSerializeable, 儲存二進位制位元組碼, 導致key會出現亂碼,所以自定義 序列化類
	 *
	 * @param redisConnectionFactory
	 */
	@Bean
	public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory)
			throws UnknownHostException {
		RedisTemplate<Object, Object> redisTemplate = new RedisTemplate<>();
		redisTemplate.setConnectionFactory(redisConnectionFactory);
		Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
		ObjectMapper objectMapper = new ObjectMapper();
		objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
		objectMapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
		jackson2JsonRedisSerializer.setObjectMapper(objectMapper);

		redisTemplate.setValueSerializer(jackson2JsonRedisSerializer);
		redisTemplate.setKeySerializer(new StringRedisSerializer());

		redisTemplate.afterPropertiesSet();

		return redisTemplate;
	}
}

7.redis作mybatis二級快取工具類

import javax.annotation.PostConstruct;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import redis.clients.jedis.JedisCluster;

/**
 * Title: JedisUtils 
 * @author: gdq
 * @date 2018年5月10日
 * @version V1.0 Description: redis做mybatis二級快取工具類
 */
@Component
public class JedisUtils {
	
	@Autowired
	public JedisCluster jedisCluster;
	
	private static String PREFIX="FX2_CACHE";
	
	private static JedisUtils jedisUtils;
	
	@PostConstruct
	public void init() {
		jedisUtils=this;
		jedisUtils.jedisCluster=this.jedisCluster;
	}
	
	public static void set(Object key, Object value) {
		try {
			jedisUtils.jedisCluster.hset(SerializingUtils.serialize(PREFIX),SerializingUtils.serialize(key), SerializingUtils.serialize(value));
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	public static Object get(Object key) {
		try {
			byte[] keyBytes = SerializingUtils.serialize(key);
			byte[] prefixBytes = SerializingUtils.serialize(PREFIX);
			if (jedisUtils.jedisCluster.hexists(prefixBytes, keyBytes)) {
				return SerializingUtils.deserialize(jedisUtils.jedisCluster.hget(prefixBytes,keyBytes));
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
		return null;
	}

	public static void del(Object key) {
		try {
			byte[] prefixBytes = SerializingUtils.serialize(PREFIX);
			jedisUtils.jedisCluster.hdel(prefixBytes,SerializingUtils.serialize(key));
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	public static void clear() {
		byte[] prefixBytes = SerializingUtils.serialize(PREFIX);
		jedisUtils.jedisCluster.del(prefixBytes);
	}

	public static int getSize() {
		return jedisUtils.jedisCluster.dbSize().intValue();
	}
}

8.二級快取實現cache類

import java.util.concurrent.locks.ReadWriteLock;  

import org.apache.ibatis.cache.Cache;  
import org.apache.ibatis.cache.CacheException;  
  
import cn.fx2.utils.JedisUtils;
/**
 * Title:      MybatisRedisCache
 * @author:    gdq
 * @date       2018年5月10日
 * @version    V1.0
 * Description: 二級快取實現
 */
/** 
 * Cache為快取介面,給快取供應商的SPI(Service Provider Interface) 
 * Cache介面的實現類必須有一個具有String型別引數的構造方法,該引數作為實現類物件的id,對其進行唯一標識 
 */  
public class MybatisRedisCache implements Cache {  
  
    private String id;  
  
    public MybatisRedisCache(String id) {  
        this.id = id;  
    }  
  
    /** 
     * 清空快取 
     */  
    @Override  
    public void clear() {  
        JedisUtils.clear();  
    }  
  
    /** 
     * 獲取快取物件的唯一標識 
     */  
    @Override  
    public String getId() {  
        return this.id;  
    }  
  
    /** 
     * 從快取物件中獲取key對應的value 
     */  
    @Override  
    public Object getObject(Object key) {  
        return JedisUtils.get(key);  
    }  
  
    /** 
     * 獲取讀寫鎖 可選的方法,從3.2.6起這個方法不再被框架核心呼叫 任何需要的鎖,都必須由快取供應商提供 
     */  
    @Override  
    public ReadWriteLock getReadWriteLock() {  
  
        return null;  
    }  
  
    /** 
     * 獲取快取物件中儲存的鍵/值對的數量 可選的方法,沒有被框架核心呼叫 
     */  
    @Override  
    public int getSize() {  
        return JedisUtils.getSize();  
    }  
  
    /** 
     * 儲存key/value到快取物件中 key可以是任何物件 
     */  
    @Override  
    public void putObject(Object key, Object value) {  
        JedisUtils.set(key, value);  
    }  
  
    /** 
     * 可選的方法,沒有被核心框架呼叫,移除key對應的value 
     */  
    @Override  
    public Object removeObject(Object key) {  
  
        return null;  
    }  
  
    /** 
     * 重新equals方法 
     */  
    @Override  
    public boolean equals(Object o) {  
        if (getId() == null)  
            throw new CacheException("Cache instances require an ID.");  
        if (this == o)  
            return true;  
        if (!(o instanceof Cache))  
            return false;  
  
        Cache otherCache = (Cache) o;  
        return getId().equals(otherCache.getId());  
    }  
  
    /** 
     * 重新hashCode方法 
     */  
    @Override  
    public int hashCode() {  
        if (getId() == null)  
            throw new CacheException("Cache instances require an ID.");  
        return getId().hashCode();  
    }  
  
}

9.序列化redis的鍵值對工具類(將object型別資料轉換為位元組存入redis)

import java.io.ByteArrayInputStream;  
import java.io.ByteArrayOutputStream;  
import java.io.IOException;  
import java.io.ObjectInputStream;  
import java.io.ObjectOutputStream;  
/**
 * Title:      SerializingUtils
 * @author:    gdq
 * @date       2018年5月10日
 * @version    V1.0
 * Description: redis序列化
 */
public class SerializingUtils {  
      
    public static byte[] serialize(Object obj) {  
        ByteArrayOutputStream bos = null;  
        ObjectOutputStream out = null;  
        try {  
            bos = new ByteArrayOutputStream();  
            out = new ObjectOutputStream(bos);  
            out.writeObject(obj);  
            out.flush();  
        }  
        catch (IOException e) {  
            e.printStackTrace();  
        }finally {  
            try {  
                if(out!=null)out.close();  
            }catch (IOException e) {  
                e.printStackTrace();  
            }  
        }  
        return bos.toByteArray();  
    }  
      
    public static Object deserialize(byte[] data) {  
        ObjectInputStream in = null;  
        Object obj = null;  
        try {  
            ByteArrayInputStream byteIn = new ByteArrayInputStream(data);  
            in = new ObjectInputStream(byteIn);  
            obj = in.readObject();  
        }catch (Exception e) {  
            e.printStackTrace();  
        }finally {  
            try {  
                if(in!=null)in.close();  
            }catch (IOException e) {  
                e.printStackTrace();  
            }  
        }  
        return obj;  
    }  
      
}

10.測試:

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

import org.apache.solr.client.solrj.SolrClient;
import org.apache.solr.client.solrj.SolrQuery;
import org.apache.solr.client.solrj.SolrServerException;
import org.apache.solr.client.solrj.response.QueryResponse;
import org.apache.solr.common.SolrDocument;
import org.apache.solr.common.SolrDocumentList;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import cn.fx2.mapper.BannerMapper;
import cn.fx2.pojo.Banner;
import cn.fx2.service.BannerService;
import redis.clients.jedis.JedisCluster;

/**
 * Title: BannerServiceImpl
 * 
 * @author: gdq
 * @date 2018年5月5日
 * @version V1.0 Description: 測試
 */
@Service
public class BannerServiceImpl implements BannerService {

	@Autowired
	private BannerMapper bannerMapper;

	@Autowired
	private JedisCluster jedisCluster;

	@Autowired
	private SolrClient solrClient;

	/**
	 * Title: getBanners
	 * @author: gdq
	 * @date 2018年5月5日
	 * @version V1.0 Description: 測試
	 */
	@Override
	public List<Banner> getBanners() {
		jedisCluster.set("test", "778797");
		// 組織查詢條件
		SolrQuery query = new SolrQuery();
		// 設定查詢關鍵字
		query.setQuery("紅燒肉");
		// 設定分頁條件
		query.setStart(0);
		query.setRows(10);
		List<String> books = new ArrayList<>();
		// 設定查詢的域
		query.set("df", "book_name");
		// 組裝查詢結果
		QueryResponse response = null;
		try {
			response = solrClient.query("collection1", query);//solr多索引庫操作只需要變換第一個引數(索引庫名字)即可
		} catch (SolrServerException e) {
			e.printStackTrace();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		SolrDocumentList results = response.getResults();
		for (SolrDocument doc : results) {

			books.add((String) doc.get("dataName"));
		}
		for (String book : books) {
			System.err.println(book);
		}
		return bannerMapper.selectByExample(null);
	}

}

有問題可以聯絡我qgeniu@foxmail.com


相關文章