2017-08-25 11:05

@JFinal 今天刚发现这个问题,
如果使用FstSerializer,虽然无法与hincrBy()混合使用,但是序列化与反序列化时保存了"类型信息",存一个Integer,使用hgetAll()时类型一定是Integer
如果使用MyFstSerializer,虽然可以与hincrBy()混合使用,若存一个Integer,但是序列化时:keyToBytes(String.valueOf(value))存放的是String,自然hgetAll()返回的也是String
又看了一下Jedis的方法,方法签名为: public String hmset(final String key, final Map hash),也即Jedis存放的值全部当作String,无类型区分
总结:cache使用FstSerializer就是"封装"了使用Jedis存取数据时的"类型转换",缺点是无法与hincrBy()等方法混合使用,现在使用MyFstSerializer等于将cache封装的"类型转换"暴露出来,由应用程序处理,有利也有弊

2017-08-22 14:57

源代码修改如下:
public class MyFstSerializer implements ISerializer {
public static final ISerializer me = new MyFstSerializer();
private ISerializer subject = FstSerializer.me;

private static final Set NOT_SERIALIZER_SET = new HashSet() {
private static final long serialVersionUID = 2303504492407898281L;
{
add(Integer.class);
add(Integer.TYPE);
add(Long.class);
add(Long.TYPE);
add(Float.class);
add(Float.TYPE);
add(Double.class);
add(Double.TYPE);
}
};

@Override
public byte[] keyToBytes(String key) {
return FstSerializer.me.keyToBytes(key);
}

@Override
public String keyFromBytes(byte[] bytes) {
return subject.keyFromBytes(bytes);
}

@Override
public byte[] fieldToBytes(Object field) {
return valueToBytes(field);
}

@Override
public Object fieldFromBytes(byte[] bytes) {
return valueFromBytes(bytes);
}

@Override
public byte[] valueToBytes(Object value) {
if (NOT_SERIALIZER_SET.contains(value.getClass())) {
return keyToBytes(String.valueOf(value));
}
return subject.valueToBytes(value);
}

/**
* 反序列化,利用FstSerializer解析,出错则利用keyFromBytes解析
* @param bytes
* @return
*/
@Override
public Object valueFromBytes(byte[] bytes) {
try {
return subject.valueFromBytes(bytes);
} catch (Exception e) {
return keyFromBytes(bytes);
}
}
}
修改:
1.使用了NOT_SERIALIZER_SET,仿照RestInterceptor,方便修改
2.将ISerializer设置为一变量,方便修改

2017-08-22 14:53

1.上面源码有错误,错误在于valueFromBytes()直接使用FstSerializer进行反序列化,但是如果使用keyToBytes()序列化的value,反序列化使用valueFromBytes报错

2017-08-14 18:40

@JFinal 站长,我找到了新的解决方法了 : )
http://www.jfinal.com/share/389

2017-08-10 16:46

@小木学堂 学到了,多谢~~

2017-08-09 15:51

@JFinal 那用hmset就没有办法存放hash的value是integer的情况,如果一个record中有的value是integer,有的value不是integer,那就需要hmset存放所有域,然后用hdel删除value是integer的域,然后再使用hincrBy存放integer的域,这样需要三个操作,有没有简便一点的方法?

2017-07-01 18:12

上面哪个问题算是解决了,但是解决方式非常丑,我是直接修改了InterceptorManager源码,因为InterceptorManager的构造器是private的,没法继承
另:我是用的idea,在自己的项目中建了与框架中InterceptorManager相同的包名,相同的类名,编译可以通过,没有报类冲突,运行时直接使用了项目中的InterceptorManager类
备注:至于站长说的继承InterceptorStack,还没有研究,有时间再说(可能不会有时间了~~),以后若有优雅的方法再行整理
以下是修改后的InterceptorManager源码,
/**
* 修改此方法实现多重拦截
* 但是遇到循环拦截会无穷递归(一定不要循环拦截)
* @param interceptorClasses
* @return
*/
public Interceptor[] createInterceptor(
Class[] interceptorClasses) {
if (interceptorClasses == null || interceptorClasses.length == 0) {
return NULL_INTERS;
}

// 使用List存放在action之前的拦截器,因为可能有多重拦截,长度不确定
List interceptorList = new ArrayList<>();
try {
for (Class interceptorClass : interceptorClasses) {
// 获取interceptorClass及其上的拦截器实例
List singleList = getMultipleInter(
interceptorClass);
interceptorList.addAll(singleList);
}
// 去重
deDuplicates(interceptorList);
return interceptorList.toArray(new Interceptor[] {});
} catch (Exception e) {
throw new RuntimeException(e);
}

// 框架源码
// Interceptor[] result = new Interceptor[interceptorClasses.length];
// try {
// for (int i = 0; i < result.length; i++) {
// result[i] = singletonMap.get(interceptorClasses[i]);
// if (result[i] == null) {
// result[i] = (Interceptor) interceptorClasses[i]
// .newInstance();
// // result[i] = Enhancer.enhance(result[i]);
// singletonMap.put(interceptorClasses[i], result[i]);
// }
// }
// return result;
// } catch (Exception e) {
// throw new RuntimeException(e);
// }
}

/**
* 获取interceptorClass实例及其上的多重拦截器
* 1.多重拦截器只能定义在Class上
* 2.一个递归函数
*
* @param interceptorClass
* @return
*/
private List getMultipleInter(
Class interceptorClass) {
// 返回最终结果
List interList = new ArrayList<>();

//
List multiInterList = null;

// 获取定义在interceptorClass上的@Before
Before before = interceptorClass.getAnnotation(Before.class);
// 判断是否有多重拦截器
if (before != null) {
// 判断是否有缓存
multiInterList = multipleMap.get(interceptorClass);
if (multiInterList == null) {
// 无缓存
// 有多重拦截器则需获取interceptorClass上的多重拦截器实例
multiInterList = new ArrayList<>();
Class[] multiClasses = before.value();
for (Class multiClass : multiClasses) {
multiInterList.addAll(getMultipleInter(multiClass));
}
// 添加缓存(mutipleMap是自定义的)
multipleMap.put(interceptorClass, multiInterList);
}
}

// 由于定义在interceptorClass上的拦截器需在interceptorClass之前add到interList中
// 获取interceptorClass实例
Interceptor now = singletonMap.get(interceptorClass);
if (now == null) {
try {
now = interceptorClass.newInstance();
// 添加缓存
singletonMap.put(interceptorClass, now);
} catch (InstantiationException | IllegalAccessException e) {
e.printStackTrace();
}
}
// ArrayList.addAll()参数不能为null
if (multiInterList != null) {
interList.addAll(multiInterList);
}
interList.add(now);

// 去重
deDuplicates(interList);
return interList;
}

/**
* 去掉interList中重复值
* @param interList
*/
private void deDuplicates(List interList) {
// 双重循环去重
for (int i = interList.size() - 1; i >= 0; i--) {
for (int j = 0; j < i; j++) {
if (interList.get(i) == interList.get(j)) {
interList.remove(i);
}
}
}
// 使用set去重
// Set interSet = new LinkedHashSet<>(interList);
// interList.clear();
// interList.addAll(interSet);
}

2017-07-01 16:44

@EATI001 不是做类似全局拦截器那样的功能,而是对拦截器进行拦截

2017-06-30 16:41

查了以下代码,如果修改InterceptorManager中的createInterceptor()和一些其他方法可以实现上述功能,但是InterceptorManager的构造器是private的,不能继承