由於業務需要使用文件級別的緩存,特此採用protostuff加上基本的TXT文件操作,來實現基於文件的緩存。
實現以下功能:
文件級別緩存的對象工具類
1、傳入一個對象和緩存時間還有緩存名稱對這個對象進行緩存
2、傳入一個緩存名稱查詢是否存在這個名稱的緩存
3、傳入一個緩存名稱和該類的類型對象獲取對應的緩存
4、傳入一個緩存名稱刪除該名稱的緩存
模塊一:protostuff序列化使用類
package tool;
import io.protostuff.LinkedBuffer;
import io.protostuff.ProtostuffIOUtil;
import io.protostuff.runtime.RuntimeSchema;
/**
* Created by yy on 2017/9/28.
* 用與序列化以及反序列化對象的類
* 1、傳入一個對象,返回該對象序列化後的字節數組
* 2、傳入字節數組和類的類型對象,獲取這個數據的反序列對象
*/
public class Serialization {
/**
* 傳入一個對象,返回這個對象的序列化後的字節數組
* @param object 需要實例化的對象
* @param <T> 傳入對象的類型
* @return 返回對應的字節數組
* @throws Exception 序列化失敗繼續拋出異常
*/
public static <T> byte[] sequence(T object) throws Exception{
//安全判斷,要是傳入的對象爲空返回對應的也是空
if(object==null){
return null;
}
//獲取對應的類
Class<T> objectClass = (Class<T>) object.getClass();
//使用LinkedBuffer分配一塊默認大小的buffer空間;
LinkedBuffer linkedBuffer = LinkedBuffer.allocate(LinkedBuffer.DEFAULT_BUFFER_SIZE);
try {
//生成對應的圖,返回對應的字節數組
//使用ProtoStuff-runtime生成模式,以便在運行時通過反射進行緩存和使用。
RuntimeSchema<T> runtimeSchema = RuntimeSchema.createFrom(objectClass);
return ProtostuffIOUtil.toByteArray(object, runtimeSchema, linkedBuffer);
} catch (Exception e) {
//繼續拋出異常
throw new RuntimeException("對象序列化失敗!",e);
} finally {
//關閉Buffer空間
linkedBuffer.clear();
}
}
/**
* 根據穿進來的字節數組和具體的類的類型對象,獲取對應反序列的結果對象
* @param info 序列化完成的字節數組對象
* @param classInfo 類的類型對象
* @param <T> 具體要轉換的類類型
* @return 序列化成功返回序列化前的對象,要是傳入的數據爲空返回空對象
* @throws Exception 拋出反序列化的異常
*/
public static <T> T reverse(byte[] info,Class<T> classInfo)throws Exception{
//安全判斷
if(info.length==0||classInfo==null){
return null;
}
//根據傳進來的數據反序列具體對象
try{
RuntimeSchema<T> runtimeSchema = RuntimeSchema.createFrom(classInfo);
T object =runtimeSchema.newMessage();
ProtostuffIOUtil.mergeFrom(info,object,runtimeSchema);
return object;
}catch(Exception e){
throw new RuntimeException("反序列對象失敗!",e);
}
}
}
模塊二:MD5加密(用於文件名生成)
package tool;
import java.security.MessageDigest;
/**
* md5的生成類
* Created by yy on 2017/10/11.
*/
public class MD5maker {
public static String make(String value){
String md5str = "";
try {
MessageDigest md = MessageDigest.getInstance("MD5");
byte[] input = value.getBytes();
byte[] buff = md.digest(input);
md5str = bytesToHex(buff);
} catch (Exception e) {
e.printStackTrace();
}
return md5str;
}
/**
* 換成16進制
* @param bytes
* @return
*/
private static String bytesToHex(byte[] bytes) {
StringBuffer md5str = new StringBuffer();
int digital;
for (int i = 0; i < bytes.length; i++) {
digital = bytes[i];
if (digital < 0) {
digital += 256;
}
if (digital < 16) {
md5str.append("0");
}
md5str.append(Integer.toHexString(digital));
}
return md5str.toString().toUpperCase();
}
}
模塊三:緩存工具類
package tool;
import org.apache.commons.lang3.StringEscapeUtils;
import java.io.*;
/**
* Created by yy on 2017/9/29.
* 文件級別緩存的對象工具類
* 1、傳入一個對象和緩存時間還有緩存名稱對這個對象進行緩存
* 2、傳入一個名稱查詢是否存在這個名稱的緩存
* 3、傳入一個名稱和該類的類型對象獲取對應的緩存
* 4、傳入一個緩存名稱刪除該名稱的緩存
*/
public class CacheBF {
/**
* 根據穿進來的名稱和實體緩存對象到文件中
* @param name 鍵名
* @param object 需要保存的實體
* @param time 過期時間秒
* @param <T> 傳入的實體類型
* @return 保存成功返回true,失敗返回false
*/
public static <T> boolean cache(String name,T object,int time) throws Exception{
File file=CacheBF.getCacheFile(name);//獲取緩存文件
FileWriter fw=new FileWriter(file);
BufferedWriter bw = new BufferedWriter(fw);
//設置過期時間
bw.write((System.currentTimeMillis()+(time*1000))+"");
bw.newLine();
//設置緩存信息
bw.write(StringEscapeUtils.escapeJava(new String(Serialization.sequence(object))));//添加轉義
bw.close();
fw.close();
return true;
}
/**
* 根據傳進來的文件名,和類的類型獲取緩存的實體類
* @param name 緩存名稱
* @param objectClass 需要取得的實體類型
* @param <T> 旋迴對應實例
* @return
* @throws Exception
*/
public static <T> T get(String name,Class<T> objectClass)throws Exception{
T vo=null;
File file=new File(CacheBF.getCacheFileName(name));//獲取緩存文件
if (file.exists()){//判斷文件是否存在
FileReader fr=new FileReader(file);
BufferedReader br=new BufferedReader(fr);
Long now =System.currentTimeMillis();
Long time=Long.parseLong(br.readLine());//判斷文件緩存是否過期
String object=StringEscapeUtils.unescapeJava(br.readLine());//返回程序,反轉義字符
br.close();
fr.close();
if (time>now){
vo= Serialization.reverse(object.getBytes(),objectClass);
}else{
file.delete();//過期刪除文件,刪除前關閉輸出流
}
}
return vo;
}
/**
* 傳入一個緩存名稱,查詢是否存在此緩存
* @param name 緩存名稱
* @return 存在並且不過期返回true,否則返回false
* @throws Exception
*/
public static boolean check(String name)throws Exception{
boolean back=false;
File file=new File(CacheBF.getCacheFileName(name));//獲取緩存文件
if (file.exists()){
FileReader fr=new FileReader(file);
BufferedReader br=new BufferedReader(fr);
Long now=System.currentTimeMillis();
Long time=Long.parseLong(br.readLine());//判斷文件緩存是否過期
br.close();
fr.close();
if (time>now){
back=true;
}else{
file.delete();//過期刪除文件
}
}
return back;
}
/**
* 刪除穿進來的緩存名稱的文件
* @param name 需要刪除的緩存的名稱
* @throws Exception
*/
public static void delete(String name)throws Exception{
File file=new File(CacheBF.getCacheFileName(name));
if (file.exists()){
file.delete();
}
}
/**
* 根據緩存的名稱獲取需要操作的文件對象
* 1、判斷父類目錄cache是否存在,不存在則創建
* 2、判斷當前文件是否存在,存在刪除後創建,不存在直接創建
* 3、文件名MD5加密
* @param name 需要得到的緩存的名稱
* @return
* @throws Exception
*/
private static File getCacheFile(String name)throws Exception{
File file=new File(CacheBF.getCacheFileName(name));//獲取操作對象
//判斷父目錄是否存在
if (!file.getParentFile().exists()){
file.getParentFile().mkdir();
}
//判斷當前文件是否存在
if (!file.exists()){
file.createNewFile();
}else {
file.delete();
file.createNewFile();
}
return file;
}
/**
* 傳入緩存名獲取緩存的文件名
* @param name 緩存名
* @return
*/
private static String getCacheFileName(String name){
name=MD5maker.make(name)+".txt";//獲取文件名
StringBuffer fileName=new StringBuffer(System.getProperty("user.dir"))
.append(File.separator).append("src")
.append(File.separator).append("main")
.append(File.separator).append("webapp")
.append(File.separator).append("WEB-INF")
.append(File.separator).append("cache")
.append(File.separator).append(name);//獲取文件路徑
return fileName.toString();
}
}
模塊四:測試
import tool.CacheBF;
import tool.Serialization;
import java.io.File;
/**
* Created by yy on 2017/10/11.
* 文件緩存測試
*/
public class test {
public static void main(String args[]) {
Data data= new Data();
data.setInfo("hello");
data.setName("world");
try {
CacheBF.cache("123",data,100);
System.out.println("緩存是否存在:"+CacheBF.check("123"));
Data da=CacheBF.get("123",Data.class);
System.out.println(da);
CacheBF.delete("123");
System.out.println("緩存是否存在:"+CacheBF.check("123"));
Data dd=CacheBF.get("123",Data.class);
System.out.println(dd);
}catch (Exception e){
e.printStackTrace();
}
}
}
//測試使用
class Data{
private String name;
private String info;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getInfo() {
return info;
}
public void setInfo(String info) {
this.info = info;
}
@Override
public String toString() {
return "Data{" +
"name='" + name + '\'' +
", info='" + info + '\'' +
'}';
}
}
模塊五:測試輸出
緩存是否存在:true
Data{name='world', info='hello'}
緩存是否存在:false
null
模塊六:文件內容(A8AE104615CB4E966DDB435F3E575A02.txt)
1508081000098
\n\u0005world\u0012\u0005hello