2017-09-20 21:40:41 hadoopxsy 阅读数 3191
  • 微信支付开发-微信公众号开发12-微信开发php

    微信公众平台开发之微信支付开发是子恒老师《微信公众平台开发》视频教程的第12部。详细讲解了用php进行微信支付的开发。内容包含获取支付密钥,微信公众号支付开发,扫码支付,微信刷卡支付,异步处理支付结果等等。欢迎反馈,微信/QQ:68183131

    27764 人正在学习 去看看 秦子恒

众所周知,在我们pc端的浏览器上,当后台改动css,或者js等代码的时候,需要浏览器清除缓存,页面才能重新加载,显示最新的样式或内容;

但是,如果我们的在手机端呢?比如说,我们开发一个微信服务号来实现一个微商场。突然有一天,客户要求升级或者改动一部分样式,这时我们在后台很rasy的搞定了,

但是会发现,微信页面根本样式就没变,搞了一下午原来是缓存的问题!但是发现怎么清理缓存啊!而且大部分用户根本就不知道“缓存”这回事:经过测试和努力找到了一下解决方案:

1、取消关注该微信公众号,重新关注即可(这很影响用户体验)

2、清理微信内存,关闭微信,再重新登录(太折腾)

3、给引入网页的css文件,或超链接  加参数时间戳:time=${time}   (终极解决方案)

例如:

<link rel="stylesheet" href="<%=basePath %>css/public.css?time=${time}">

当后台修改public.css文件内容时,微信服务号会重新加载最新的时间戳内容。这里的${time}  是从后台传过来的System.currentTimeMillis()值


同理,超链接也是如此!


这样做会使每次都重新加载内容会使反映时间加长,不过那也是在用户量访问大的时候!毕竟功能的展现啊!!!


2019-10-11 17:15:17 weixin_42233038 阅读数 34
  • 微信支付开发-微信公众号开发12-微信开发php

    微信公众平台开发之微信支付开发是子恒老师《微信公众平台开发》视频教程的第12部。详细讲解了用php进行微信支付的开发。内容包含获取支付密钥,微信公众号支付开发,扫码支付,微信刷卡支付,异步处理支付结果等等。欢迎反馈,微信/QQ:68183131

    27764 人正在学习 去看看 秦子恒

微信网页缓存清理

吐槽:微信这个缓存是真的坑人,开发的时候每次修改后发布测试都有缓存,可能其他人没我这么频繁,我每次修改了都要清理一次缓存才行。然而很多方式试了都没效果,但最终找到了一个很有效果的,不废话了,直接开始。

打开微信

我 -> 设置 -> 通用 -> 微信存储空间
在这里插入图片描述

结束了,点到这个界面它统计完已使用空间就行了。不要问我为什么,能清除缓存就行了。

2017-11-28 16:06:24 cx091 阅读数 1129
  • 微信支付开发-微信公众号开发12-微信开发php

    微信公众平台开发之微信支付开发是子恒老师《微信公众平台开发》视频教程的第12部。详细讲解了用php进行微信支付的开发。内容包含获取支付密钥,微信公众号支付开发,扫码支付,微信刷卡支付,异步处理支付结果等等。欢迎反馈,微信/QQ:68183131

    27764 人正在学习 去看看 秦子恒

两个问题:微信ios返回为静态返回,防止微信做缓存


这几天在做微信开发遇到一些问题,后续应该还会有博客发出,希望可以帮助大家


1.微信ios返回为静态返回的问题

微信ios的静态返回操作有:点击微信上边的返回按钮,按住屏幕→滑动操作
网上有很多说可以用window.addEventListener监听popstate我去,我就想问大哥,你是用的脑测蛮?能不能行心里没有一点B数?本人亲测不行!
真正可用的代码是(忘了是哪位老兄的了,先感谢一下):

$(function() {
            var isPageHide = false;
            window.addEventListener('pageshow', function() {
                if(isPageHide) {
                    window.location.reload();//自己重新刷新,这一步相当于模拟了跳转
                }
            });
            window.addEventListener('pagehide', function() {
                isPageHide = true;
            });
        })

2.防止微信做缓存

网上说了很多方法(我这里说的是前端的方法):
1.手动给文件名加备注如index_2017.html,index_2017.js用于代码更新
2.给微信一个假的h5缓存地址,还真可以骗到,个人觉得这个方法还是挺有用的
代码如下:

<html manifest="demo.appcache">
2017-09-18 15:26:24 yesfeel 阅读数 2497
  • 微信支付开发-微信公众号开发12-微信开发php

    微信公众平台开发之微信支付开发是子恒老师《微信公众平台开发》视频教程的第12部。详细讲解了用php进行微信支付的开发。内容包含获取支付密钥,微信公众号支付开发,扫码支付,微信刷卡支付,异步处理支付结果等等。欢迎反馈,微信/QQ:68183131

    27764 人正在学习 去看看 秦子恒

      做微信开发的小伙伴们肯定都遇到过这样的问题,页面上传后总有用户反映使用不正常,各种奇葩问题,查实后皆由微信缓存问题所导致。

试过以下手动刷新方法,但并不能保证完全有效:

  1. 强制关闭微信进程,重新打开登录
  2. 打开页面后,点击右上角“...”刷新页面
  3. 清理微信缓存,设置->通用->清理微信存储空间
  4. 使用腾讯提供的X5浏览器工具,微信中打开 debugx5.qq.com ->代理->最下方选中“Cookie”和“文件缓存”->清除

这样可以解决大概80%的问题,依旧会遇到顽固缓存,而且使用体验也不好。


下面放大招!

通过服务器配置来解决缓存问题,示例是Apache的相关配置。

1) 首先确保mod_expires模块有效

2) 在http.conf中加上如下配置:

<IfModule mod_expires.c>
    ExpiresActive On
    ExpiresDefault "access plus 12 hours"
    ExpiresByType text/html "modification plus 1 seconds"
    ExpiresByType text/plain "modification plus 1 seconds"
    ExpiresByType text/css  "modification plus 1 seconds"
    ExpiresByType application/x-javascript "modification plus 1 seconds"
    ExpiresByType image/gif "access plus 1 days"
    ExpiresByType image/png "access plus 1 days"
    ExpiresByType image/jpg "access plus 1 days"
    ExpiresByType image/jpeg "access plus 1 days"
    ExpiresByType image/x-icon "access plus 1 days"
    ExpiresByType video/x-flv  "access plus 10 days"
    ExpiresByType application/x-shockwave-flash "access plus 10 days"
</IfModule>

access 表示过期时间从访问的时间开始计算

modification 表示过期时间按照文件的最后修改时间开始计算(可用于配置静态文件,动态页面无效)

详细配置可参考官方说明



2018-08-06 10:17:19 jiepan9178 阅读数 2440
  • 微信支付开发-微信公众号开发12-微信开发php

    微信公众平台开发之微信支付开发是子恒老师《微信公众平台开发》视频教程的第12部。详细讲解了用php进行微信支付的开发。内容包含获取支付密钥,微信公众号支付开发,扫码支付,微信刷卡支付,异步处理支付结果等等。欢迎反馈,微信/QQ:68183131

    27764 人正在学习 去看看 秦子恒

通过微信授权拿到的token有一个7200秒的有效期,并且获取token的次数也有一定限制,所以token不能“随用随取”,通过网络资源获取,解决方案有①储存在数据库中,每次使用时都查询一次数据库,②定义静态全局变量(单例模式),开启线程监控变量是否“过期”,③结合数据库做缓存,开启定时任务,每7200秒从微信服务器中获取一次token并保存到自己的数据库中

各方法的优缺:

①:简单粗暴,对数据库的操作过多,适合访问量小,调用微信API次数少的项目

②:(单例模式)全局变量在服务器重启时会清除,不使用数据库的方式,变量设置不当可能会混淆(微信有两个token,一个用于(粉丝)用户授权,一个用于开发者授权)

③:灵活,易结合到各类开发中,spring也对各种缓存方案有很好的支持

以下为方法③的实现方式之一(未开启定期任务,缓存方案使用ehcache)

 基本配置

ehcache.xml配置

<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:noNamespaceSchemaLocation="http://ehcache.org/ehcache.xsd">

    <defaultCache
            eternal="false"
            maxElementsInMemory="1000"
            overflowToDisk="false"
            diskPersistent="false"
            timeToIdleSeconds="0"
            timeToLiveSeconds="600"
            memoryStoreEvictionPolicy="LRU" />

    <cache
            name="TokenCache"
            eternal="false"
            maxElementsInMemory="100"
            overflowToDisk="false"
            diskPersistent="false"
            timeToIdleSeconds="7200"
            timeToLiveSeconds="7200"
            memoryStoreEvictionPolicy="LRU" />

    <!-- eternal:true表示对象永不过期,此时会忽略timeToIdleSeconds和timeToLiveSeconds属性,默认为false -->
    <!-- maxEntriesLocalHeap:堆内存中最大缓存对象数,0没有限制 -->
    <!-- timeToIdleSeconds: 设定允许对象处于空闲状态的最长时间,以秒为单位。当对象自从最近一次被访问后,
    如果处于空闲状态的时间超过了timeToIdleSeconds属性值,这个对象就会过期,EHCache将把它从缓存中清空。
    只有当eternal属性为false,该属性才有效。如果该属性值为0,则表示对象可以无限期地处于空闲状态 -->
</ehcache>

spring boot配置

#端口
server.port=8080
#数据源
spring.datasource.name=test
spring.datasource.url=jdbc:mysql://127.0.0.1:3306/test?useUnicode=true&characterEncoding=utf-8&useSSL=true&zeroDateTimeBehavior=convertToNull
spring.datasource.username=root
spring.datasource.password=123456
spring.datasource.type=com.alibaba.druid.pool.DruidDataSource
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
##连接池属性配置
spring.datasource.initialSize=5  
spring.datasource.minIdle=5  
spring.datasource.maxActive=20  
spring.datasource.maxWait=60000  
spring.datasource.timeBetweenEvictionRunsMillis=60000  
spring.datasource.minEvictableIdleTimeMillis=300000  
spring.datasource.validationQuery=SELECT 1 FROM DUAL  
spring.datasource.testWhileIdle=true  
spring.datasource.testOnBorrow=false  
spring.datasource.testOnReturn=false  
spring.datasource.poolPreparedStatements=true  
spring.datasource.maxPoolPreparedStatementPerConnectionSize=20  
spring.datasource.filters=stat,wall,log4j  
spring.datasource.connectionProperties=druid.stat.mergeSql=true;druid.stat.slowSqlMillis=5000 
#mybatis.config
mybatis.mapper-locations=classpath:mapping/*xml
mybatis.type-aliases-package=cn.vision.springbootdemo.model

#分页插件
pagehelper.helper-dialect=mysql
pagehelper.reasonable=true
pagehelper.support-methods-arguments=true
pagehelper.params=count=countSql

#日志
logging.level.cn.vision.weixindemo.mapper = debug

# spring 设置缓存方案为ehcache
spring.cache.type=ehcache
spring.cache.ehcache.config=classpath:cache/ehcache.xml

 微信工具类———微信post、get请求工具类

package cn.vision.weixindemo.utils.base;

import com.alibaba.fastjson.JSONObject;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.ParseException;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import org.springframework.stereotype.Component;

import java.io.IOException;

@Component
public class BaseRequest {
    /**
     * get请求
     * @param url
     * @return
     * @throws ParseException
     * @throws IOException
     *
     * @author vision
     */
    public static JSONObject doGet(String url) throws ParseException, IOException {
        CloseableHttpClient client = HttpClients.createDefault();
        HttpGet httpGet = new HttpGet(url);
        JSONObject jsonObject = null;
        HttpResponse httpResponse = client.execute(httpGet);
        HttpEntity entity = httpResponse.getEntity();
        if(entity != null){
            String result = EntityUtils.toString(entity,"UTF-8");
            jsonObject = JSONObject.parseObject(result);
        }

        //        释放连接
        httpGet.releaseConnection();
        client.close();
        return jsonObject;
    }
    /**
     * POST请求
     * @param url
     * @param outStr
     * @return
     * @throws ParseException
     * @throws IOException
     */
    public static JSONObject doPost(String url, String outStr) throws ParseException, IOException{
        CloseableHttpClient client = HttpClients.createDefault();
        HttpPost httpost = new HttpPost(url);

        httpost.setEntity(new StringEntity(outStr,"UTF-8"));
        HttpResponse response = client.execute(httpost);
        String result = EntityUtils.toString(response.getEntity(),"UTF-8");
//        释放连接
        httpost.releaseConnection();
        client.close();
        return JSONObject.parseObject(result);
    }
}

微信工具类————token工具类(API函数SpringContextHolder类

package cn.vision.weixindemo.utils.Token;

import cn.vision.weixindemo.config.WeiXinConfig;
import cn.vision.weixindemo.model.AccessToken;
import cn.vision.weixindemo.service.TokenService;
import cn.vision.weixindemo.utils.base.API.WeiXin_API;
import cn.vision.weixindemo.utils.base.BaseRequest;
import cn.vision.weixindemo.utils.spring.SpringContextHolder;
import com.alibaba.fastjson.JSONObject;
import org.apache.http.ParseException;

import java.io.IOException;
import java.util.Date;

public class TokenUtils {

    private TokenService tokenService = SpringContextHolder.getBean(TokenService.class);
    /**
     * 获取accessToken
     *
     * @return
     * @throws ParseException
     * @throws IOException
     */
    public AccessToken getAccessToken() throws ParseException, IOException {
       AccessToken accessToken = tokenService.selectByPrimaryKey(1);
        System.out.println("CreateTime: "+accessToken.getCreatedate().getTime()+"NOW: "+new Date().getTime() +"\n"+ Long.parseLong(accessToken.getExpiresin()));
       if(accessToken == null || accessToken.getCreatedate().getTime() + Long.parseLong(accessToken.getExpiresin()) *1000 < new Date().getTime()){
           String url = WeiXin_API.API_GET_ACCESS_TOKEN.replace("APPID", WeiXinConfig.APPID).replace("APPSECRET", WeiXinConfig.APPSECRET);
           JSONObject jsonObject = BaseRequest.doGet(url);
           System.out.println(jsonObject.toString());
           if(jsonObject.getString("errorcode") == null){
               accessToken = new AccessToken();
               accessToken.setId(1);
               accessToken.setAccessToken(jsonObject.getString("access_token"));
               accessToken.setExpiresin(jsonObject.getString("expires_in"));
               accessToken.setCreatedate(new Date());
           }
           if(accessToken == null){
               tokenService.insert(accessToken);
            }
           tokenService.updateByPrimaryKey(accessToken);
       }
       return accessToken;
    }
}

 Spring Boot启动类中开启缓存注解@EnableCaching

package cn.vision.weixindemo;

import com.alibaba.druid.spring.boot.autoconfigure.DruidDataSourceAutoConfigure;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cache.annotation.EnableCaching;

@SpringBootApplication(exclude={DruidDataSourceAutoConfigure.class})
@EnableCaching
@MapperScan("cn.vision.weixindemo.mapper")
public class WeixindemoApplication {

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

数据库表结构

数据模型

package cn.vision.weixindemo.model;

import java.util.Date;

public class AccessToken {
    private Integer id;

    private String accessToken;

    private String expiresin;

    private Date createdate;

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getAccessToken() {
        return accessToken;
    }

    public void setAccessToken(String accessToken) {
        this.accessToken = accessToken == null ? null : accessToken.trim();
    }

    public String getExpiresin() {
        return expiresin;
    }

    public void setExpiresin(String expiresin) {
        this.expiresin = expiresin == null ? null : expiresin.trim();
    }

    public Date getCreatedate() {
        return createdate;
    }

    public void setCreatedate(Date createdate) {
        this.createdate = createdate;
    }
}

 mapper

package cn.vision.weixindemo.mapper;

import cn.vision.weixindemo.model.AccessToken;

public interface AccessTokenMapper {

    int deleteByPrimaryKey(Integer id);

    int insert(AccessToken record);

    int insertSelective(AccessToken record);

    AccessToken selectByPrimaryKey(Integer id);

    int updateByPrimaryKeySelective(AccessToken record);

    int updateByPrimaryKey(AccessToken record);
}

mappering

<?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.vision.weixindemo.mapper.AccessTokenMapper" >
  <resultMap id="BaseResultMap" type="cn.vision.weixindemo.model.AccessToken" >
    <id column="Id" property="id" jdbcType="INTEGER" />
    <result column="Access_Token" property="accessToken" jdbcType="VARCHAR" />
    <result column="expiresIn" property="expiresin" jdbcType="VARCHAR" />
    <result column="createDate" property="createdate" jdbcType="TIMESTAMP" />
  </resultMap>
  <sql id="Base_Column_List" >
    Id, Access_Token, expiresIn, createDate
  </sql>
  <select id="selectByPrimaryKey" resultMap="BaseResultMap" parameterType="java.lang.Integer" >
    select 
    <include refid="Base_Column_List" />
    from weixin_token
    where Id = #{id,jdbcType=INTEGER}
  </select>
  <delete id="deleteByPrimaryKey" parameterType="java.lang.Integer" >
    delete from weixin_token
    where Id = #{id,jdbcType=INTEGER}
  </delete>
  <insert id="insert" parameterType="cn.vision.weixindemo.model.AccessToken" >
    insert into weixin_token (Id, Access_Token, expiresIn, 
      createDate)
    values (#{id,jdbcType=INTEGER}, #{accessToken,jdbcType=VARCHAR}, #{expiresin,jdbcType=VARCHAR}, 
      #{createdate,jdbcType=TIMESTAMP})
  </insert>
  <insert id="insertSelective" parameterType="cn.vision.weixindemo.model.AccessToken" >
    insert into weixin_token
    <trim prefix="(" suffix=")" suffixOverrides="," >
      <if test="id != null" >
        Id,
      </if>
      <if test="accessToken != null" >
        Access_Token,
      </if>
      <if test="expiresin != null" >
        expiresIn,
      </if>
      <if test="createdate != null" >
        createDate,
      </if>
    </trim>
    <trim prefix="values (" suffix=")" suffixOverrides="," >
      <if test="id != null" >
        #{id,jdbcType=INTEGER},
      </if>
      <if test="accessToken != null" >
        #{accessToken,jdbcType=VARCHAR},
      </if>
      <if test="expiresin != null" >
        #{expiresin,jdbcType=VARCHAR},
      </if>
      <if test="createdate != null" >
        #{createdate,jdbcType=TIMESTAMP},
      </if>
    </trim>
  </insert>
  <update id="updateByPrimaryKeySelective" parameterType="cn.vision.weixindemo.model.AccessToken" >
    update weixin_token
    <set >
      <if test="accessToken != null" >
        Access_Token = #{accessToken,jdbcType=VARCHAR},
      </if>
      <if test="expiresin != null" >
        expiresIn = #{expiresin,jdbcType=VARCHAR},
      </if>
      <if test="createdate != null" >
        createDate = #{createdate,jdbcType=TIMESTAMP},
      </if>
    </set>
    where Id = #{id,jdbcType=INTEGER}
  </update>
  <update id="updateByPrimaryKey" parameterType="cn.vision.weixindemo.model.AccessToken" >
    update weixin_token
    set Access_Token = #{accessToken,jdbcType=VARCHAR},
      expiresIn = #{expiresin,jdbcType=VARCHAR},
      createDate = #{createdate,jdbcType=TIMESTAMP}
    where Id = #{id,jdbcType=INTEGER}
  </update>
</mapper>

service

package cn.vision.weixindemo.service;

import cn.vision.weixindemo.model.AccessToken;
import org.springframework.stereotype.Service;


public interface TokenService {
    int deleteByPrimaryKey(Integer id);

    int insert(AccessToken record);

    int insertSelective(AccessToken record);

    AccessToken selectByPrimaryKey(Integer id);

    int updateByPrimaryKeySelective(AccessToken record);

    int updateByPrimaryKey(AccessToken record);
}

serviceImpl

package cn.vision.weixindemo.service;

import cn.vision.weixindemo.mapper.AccessTokenMapper;
import cn.vision.weixindemo.model.AccessToken;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheConfig;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.CachePut;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;

@Service
@CacheConfig(cacheNames = "TokenCache")
public class TokenServiceImpl implements TokenService{

    @Autowired
    private AccessTokenMapper tokenMapper;

    @Override
    @CacheEvict(key = "#p0")
    public int deleteByPrimaryKey(Integer id) {
        return tokenMapper.deleteByPrimaryKey(id);
    }

    @Override
    @CachePut(key = "#p0")
    public int insert(AccessToken record) {
        return tokenMapper.insert(record);
    }

    @Override
    @CachePut(key = "#p0")
    public int insertSelective(AccessToken record) {
        return tokenMapper.insertSelective(record);
    }

    @Override
    @Cacheable(key = "#p0")
    public AccessToken selectByPrimaryKey(Integer id) {
        return tokenMapper.selectByPrimaryKey(id);
    }

    @Override
    @Cacheable(key = "#p0")
    public int updateByPrimaryKeySelective(AccessToken record) {
        return tokenMapper.updateByPrimaryKeySelective(record);
    }

    @Override
    @Cacheable(key = "#p0")
    public int updateByPrimaryKey(AccessToken record) {
        return tokenMapper.updateByPrimaryKey(record);
    }
}

测试用Controller

package cn.vision.weixindemo.controller;

import cn.vision.weixindemo.service.TokenService;
import cn.vision.weixindemo.utils.Token.TokenUtils;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;

import java.io.IOException;

@Controller
@RequestMapping("/test")
public class TestController {

    @Autowired
    TokenService tokenService;
    @RequestMapping("/testCache.do")
    public String TestCache(Model model) throws IOException {
        tokenService.selectByPrimaryKey(1);
        model.addAttribute("token",new TokenUtils().getAccessToken());
        return "test";
    }
}

测试用html

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>缓存测试</title>
</head>
<body>
<!--/*@thymesVar id="token" type="cn.vision.weixindemo.model.AccessToken"*/-->
<h1 th:text="${token.getAccessToken()}">
</h1>
</body>
</html>

运行截图

 

 注解说明:

  • @CacheConfig:主要用于配置该类中会用到的一些共用的缓存配置。在这里@CacheConfig(cacheNames = "users"):配置了该数据访问对象中返回的内容将存储于名为users的缓存对象中,我们也可以不使用该注解,直接通过@Cacheable自己配置缓存集的名字来定义。

  • @Cacheable:配置了findByName函数的返回值将被加入缓存。同时在查询时,会先从缓存中获取,若不存在才再发起对数据库的访问。该注解主要有下面几个参数:

    • valuecacheNames:两个等同的参数(cacheNames为Spring 4新增,作为value的别名),用于指定缓存存储的集合名。由于Spring 4中新增了@CacheConfig,因此在Spring 3中原本必须有的value属性,也成为非必需项了
    • key:缓存对象存储在Map集合中的key值,非必需,缺省按照函数的所有参数组合作为key值,若自己配置需使用SpEL表达式,比如:@Cacheable(key = "#p0"):使用函数第一个参数作为缓存的key值,更多关于SpEL表达式的详细内容可参考官方文档
    • condition:缓存对象的条件,非必需,也需使用SpEL表达式,只有满足表达式条件的内容才会被缓存,比如:@Cacheable(key = "#p0", condition = "#p0.length() < 3"),表示只有当第一个参数的长度小于3的时候才会被缓存,若做此配置上面的AAA用户就不会被缓存,读者可自行实验尝试。
    • unless:另外一个缓存条件参数,非必需,需使用SpEL表达式。它不同于condition参数的地方在于它的判断时机,该条件是在函数被调用之后才做判断的,所以它可以通过对result进行判断。
    • keyGenerator:用于指定key生成器,非必需。若需要指定一个自定义的key生成器,我们需要去实现org.springframework.cache.interceptor.KeyGenerator接口,并使用该参数来指定。需要注意的是:该参数与key是互斥的
    • cacheManager:用于指定使用哪个缓存管理器,非必需。只有当有多个时才需要使用
    • cacheResolver:用于指定使用那个缓存解析器,非必需。需通过org.springframework.cache.interceptor.CacheResolver接口来实现自己的缓存解析器,并用该参数指定。

     

除了这里用到的两个注解之外,还有下面几个核心注解:

  • @CachePut:配置于函数上,能够根据参数定义条件来进行缓存,它与@Cacheable不同的是,它每次都会真是调用函数,所以主要用于数据新增和修改操作上。它的参数与@Cacheable类似,具体功能可参考上面对@Cacheable参数的解析
  • @CacheEvict:配置于函数上,通常用在删除方法上,用来从缓存中移除相应数据。除了同@Cacheable一样的参数之外,它还有下面两个参数:
    • allEntries:非必需,默认为false。当为true时,会移除所有数据
    • beforeInvocation:非必需,默认为false,会在调用方法之后移除数据。当为true时,会在调用方法之前移除数据。
没有更多推荐了,返回首页