A. 如何在service层加入redis缓存
//放入缓存注解
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
@Inherited
public@interfaceCacheable{//放入
Stringkey();//缓存key
StringfieldKey();//field值
intexpireTime()default3600;
}
//从缓存中销毁注解
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public@interfaceCacheEvict{//销毁
Stringkey();
String[]fieldKey();
intexpireTime()default3600;
}
Aspect类
//环绕切入
@Around(value="@annotation(com.xx.cache.annotation.Cacheable)")
publicObjectcache(ProceedingJoinPointpjp){
Objectresult=null;
Methodmethod=getMethod(pjp);
Cacheablecacheable=method.getAnnotation(Cacheable.class);
StringfieldKey=cacheable.fieldKey();
if(cacheable.fieldKey().indexOf("#")==0){//动态变量存入方式
fieldKey=parseKey(cacheable.fieldKey(),method,pjp.getArgs());
}
if(useCache){//判断是否开启缓存开启缓存从缓存获取result
//获取方法的返回类型,让缓存可以返回正确的类型
ClassreturnType=((MethodSignature)pjp.getSignature()).getReturnType();
//使用redis的hash进行存取,易于管理
//result=JedisUtils.hget(cacheable.key(),fieldKey,method.getReturnType());
result=JedisUtils.hget(cacheable.key(),fieldKey,returnType);
if(result==null){
try{
result=pjp.proceed();
//Assert.notNull(fieldKey);
JedisUtils.hset(cacheable.key(),fieldKey,result);
logger.debug("The"+cacheable.key()+"addtoredis,thefieldKeyis"+fieldKey);
}catch(Throwablee){
e.printStackTrace();
}
}
returnresult;
}
try{
returnpjp.proceed();
}catch(Throwablethrowable){
throwable.printStackTrace();
returnnull;
}
}
//环绕切入
@Around(value="@annotation(com.xx.cache.annotation.CacheEvict)")
publicObjectevict(ProceedingJoinPointpjp){
//和cache类似,使用Jedis.hdel()删除缓存即可
if(useCache){//判断是否开启缓存
Methodmethod=getMethod(pjp);
CacheEvictcacheEvict=method.getAnnotation(CacheEvict.class);
String[]fieldKeys=cacheEvict.fieldKey();
intdeleteSuccessFlag=0;
for(StringfieldKey:fieldKeys){
if(fieldKey.indexOf("#")==0){//动态变量存入方式
Stringt=fieldKey;
fieldKey=parseKey(fieldKey,method,pjp.getArgs());
if(fieldKey==null){
logger.error("cacheevictfieldkey{}connotbenull,thatmaybecausedataconnotsync",t);
t=null;
}
}
deleteSuccessFlag+=JedisUtils.hdel(cacheEvict.key(),fieldKey==null?"":fieldKey);
logger.debug("Thereferencefieldkey:"+fieldKey+"for"+cacheEvict.key()+"hasbeendeletefromredis");
}
logger.debug("Delete"+deleteSuccessFlag+""+cacheEvict.key()+"fromredis");
}
try{
returnpjp.proceed();
}catch(Throwablee){
e.printStackTrace();
returnnull;
}
}
/**
*获取缓存的key
*key定义在注解上,支持SPEL表达式
*
*@paramkey
*@parammethod
*@paramargs
*@return
*/
privateStringparseKey(Stringkey,Methodmethod,Object[]args){
//获取被拦截方法参数名列表(使用Spring支持类库)
=();
String[]paraNameArr=u.getParameterNames(method);
//使用SPEL进行key的解析
ExpressionParserparser=newSpelExpressionParser();
//SPEL上下文
=newStandardEvaluationContext();
//把方法参数放入SPEL上下文中
for(inti=0;i<paraNameArr.length;i++){
context.setVariable(paraNameArr[i],args[i]);
}
returnparser.parseExpression(key).getValue(context,String.class);
}
使用,在service调用前使用:
@Cacheable(key="biz_member",fieldKey="#id")publicMemberget(Stringid){returnsuper.get(id);}@CacheEvict(key="member",fieldKey={"#member.id","#member.account"})publicSerializablesave(Membermember){return.insert(member);}@CacheEvict(key="member",fieldKey={"#member.id","#member.account"})publicvoiddelete(Membermember){.delete(member);}
B. 自定义微信分享链接(使用JS-SDK) + 实现预览pdf
可参考:微信JS-SDK说明文档 >
此时可能出现白名单错误(忘截图了),需要在微信公众号中设置错误中的IP
注意:access_token和ticket都需要缓存
4. 获取签名 signature
将以上内容以键值对形式拼接,类似如下
本地引入sha1算法(需网上查找)
将上述拼接的字符串以参数的形式传递到sha1中得到 signature
signature = sha1(拼接完的字符串)
验证 signature 是否正确 >
将appId,nonceStr,timestamp和signature返回给前端
官网上是这样描述的:
这时候调用 updateAppMessageShareData , updateTimelineShareData 的时候就可以生效了,具体原理不清楚。。
注意:imgUrl配置有严格的要求
尺寸120 x 120,大小不超过10K,不支持GIF格式。必须采用https协议(最好写完整url),不支持base64。由于我使用的是vue,在webpack打包时图片小于10k的是会自动打包成base64导致无法正常显示余册图片,因此在webpack.base.config.js中修改默认配置
由于在网页中直接查看pdf的路径是无法在微信中查看(安卓)和分享(ios),因此使用pdf插件进行优化 --- pdf.js 。其原理是绘制成canvas,最终在真机上放大时可能出现模糊的问题闷毁信。
创建之后控制台会报错出现跨域问题,因为pdf.js不支持跨域访问。此时可以将错误跨域信息在上一步你引入的文件中查找,然后将其判断语句注释掉即可解决这个问题。最后会发现pdf出现在这个容器中(忘截图了),蚂轮也实现了微信中预览和分享的功能。