项目github地址:github.com/pc859107393…

实时项目同步的地址是国内的码云:git.oschina.net/859107393/m…

我的简书首页是:www.jianshu.com/users/86b79…

上一期是:[手把手教程][第二季]java 后端博客系统文章系统——No9

行走的java全栈

工具

  • IDE为idea2017.1.5
  • JDK环境为1.8
  • gradle构建,版本:2.14.1
  • Mysql版本为5.5.27
  • Tomcat版本为7.0.52
  • 流程图绘制(xmind)
  • 建模分析软件PowerDesigner16.5
  • 数据库工具MySQLWorkBench,版本:6.3.7build

本期目标

完成EhCache接入

Ehcache资源引入

在我们工程目录下面的build.gradle文件中引入gradle资源。

// ehcache核心依赖
compile group: 'net.sf.ehcache', name: 'ehcache', version: '2.10.3'// mybatis-ehcache依赖
compile group: 'org.mybatis.caches', name: 'mybatis-ehcache', version: '1.1.0'//shiro-ehcache依赖
compile group: 'org.apache.shiro', name: 'shiro-ehcache', version: '1.4.0'复制代码

开启Ehcache相关配置

本来按照道理来说,我们的Ehcache是二级缓存用来降低数据库压力,也就应该写入我们的spring-dao.xml中,但是Ehcache因为要和Shiro整合,我们顺带也就将其写入spring-web.xml中,如下:

    <!-- ================ Shiro start ================ --><bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager"><property name="realm" ref="AccoutRealm"/><!-- 二级缓存 --><property name="cacheManager" ref="shiroCacheManager"/></bean><!-- 項目自定义的Realm --><bean id="AccoutRealm" class="cn.acheng1314.shiro.ShiroRealm"><!-- 自定义密码加密算法  --><property name="credentialsMatcher" ref="passwordMatcher"/></bean><bean id="passwordMatcher" class="cn.acheng1314.shiro.MyCredentialsMatcher"/><!-- Shiro Filter --><bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean"><!-- 核心安全接口 --><property name="securityManager" ref="securityManager"/><!-- 登录页面 --><property name="loginUrl" value="/main/login"/><!-- 登陆成功页面 --><property name="successUrl" value="/endSupport/index"/><!-- 未授权页面 --><property name="unauthorizedUrl" value="/endSupport/unauthorized"/><!-- shiro 连接约束配置 --><property name="filterChainDefinitions"><value>/static/*/** = anon<!--前台可以匿名访问-->/front/*/** = anon/index.jsp = anon/static/uploadFiles/** = anon/endSupport/*/** = authc/druid/*/** = authc</value></property></bean><cache:annotation-driven cache-manager="cacheManager"/><bean id="ehCacheManager" class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean"><property name="configLocation" value="classpath:config/shiro-ehcache.xml"/><property name="shared" value="true"></property> <!-- 这里是关键!!!没有必错  --></bean><bean id="shiroCacheManager" class="org.apache.shiro.cache.ehcache.EhCacheManager"><property name="cacheManager" ref="ehCacheManager"/><!--配置文件--><!--<property name="cacheManagerConfigFile" value="classpath:ehcache-shiro.xml"/>--></bean><bean id="cacheManager" class="org.springframework.cache.ehcache.EhCacheCacheManager"p:cacheManager-ref="ehCacheManager"/><bean id="lifecycleBeanPostProcessor"class="org.apache.shiro.spring.LifecycleBeanPostProcessor"/><bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator"depends-on="lifecycleBeanPostProcessor"><property name="proxyTargetClass" value="true"/></bean><bean class="org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor"><property name="securityManager" ref="securityManager"/></bean><!--================ Shiro end ================ -->复制代码

上面的配置中,我们可以将Ehcache的配置完全的拆分出来,如下:

    <cache:annotation-driven cache-manager="cacheManager"/><bean id="ehCacheManager" class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean"><property name="configLocation" value="classpath:config/shiro-ehcache.xml"/><property name="shared" value="true"></property> <!-- 这里是关键!!!没有必错  --></bean><bean id="cacheManager" class="org.springframework.cache.ehcache.EhCacheCacheManager"p:cacheManager-ref="ehCacheManager"/>复制代码

在上面的配置中,我们开启了spring的cache,注入了‘org.springframework.cache.CacheManager’的子类作为我们的CacheManager。

CacheManager具体由EhCacheCacheManager实现。在EhCacheCacheManager中有以下的方法来实现CacheManager的注入。

    /*** Set the backing EhCache {@link net.sf.ehcache.CacheManager}.*/public void setCacheManager(net.sf.ehcache.CacheManager cacheManager) {this.cacheManager = cacheManager;}复制代码

所以最后我们通过实现具体的EhCacheManagerFactoryBean来引入cache的设置。当然在EhCacheManagerFactoryBean中我们可以找到对应的方法如:configLocation和shared。我们通过配置configLocation引入了shiro-ehcache.xml这个配置文件。

接着,我们在Shiro中引入Ehcache。配置如下:

<bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager"><property name="realm" ref="AccoutRealm"/><!-- 二级缓存 --><property name="cacheManager" ref="shiroCacheManager"/>
</bean>
<bean id="shiroCacheManager" class="org.apache.shiro.cache.ehcache.EhCacheManager"><property name="cacheManager" ref="ehCacheManager"/><!--配置文件--><!--<property name="cacheManagerConfigFile" value="classpath:ehcache-shiro.xml"/>-->
</bean>复制代码

从上面不难看出我们把Ehcache注入到了Shiro的securityManager中,同时我们的shiroCacheManager具体是由ehCacheManager来实现。

当然最上面的代码中出掉Ehcache相关的,剩下的就是Shiro的相关设置了。

Ehcache配置文件

我们从上面可以看到Ehcache配置文件是在config目录下的shiro-ehcache.xml文件,具体内容如下:

<ehcache updateCheck="false" name="shiroCache"><diskStore path="java.io.tmpdir"/><defaultCachemaxElementsInMemory="10000"eternal="false"timeToIdleSeconds="120"timeToLiveSeconds="120"overflowToDisk="false"diskPersistent="false"diskExpiryThreadIntervalSeconds="120"/><!--updateCheck="false" 不检查更新当前使用的Ehcache的版本eternal:缓存中对象是否为永久的,如果是,超时设置将被忽略,对象从不过期。maxElementsInMemory:缓存中允许创建的最大对象数overflowToDisk:内存不足时,是否启用磁盘缓存。timeToIdleSeconds:缓存数据的钝化时间,也就是在一个元素消亡之前,两次访问时间的最大时间间隔值,这只能在元素不是永久驻留时有效,如果该值是 0 就意味着元素可以停顿无穷长的时间。timeToLiveSeconds:缓存数据的生存时间,也就是一个元素从构建到消亡的最大时间间隔值,这只能在元素不是永久驻留时有效,如果该值是0就意味着元素可以停顿无穷长的时间。memoryStoreEvictionPolicy:缓存满了之后的淘汰算法。1 FIFO,先进先出2 LFU,最少被使用,缓存的元素有一个hit属性,hit值最小的将会被清出缓存。3 LRU,最近最少使用的,缓存的元素有一个时间戳,当缓存容量满了,而又需要腾出地方来缓存新的元素的时候,那么现有缓存元素中时间戳离当前时间最远的元素将被清出缓存。-->
</ehcache>复制代码

启用缓存

在上面我们已经把缓存相关的东西已经设置完成了,现在我们是需要对dao层启用缓存。这个时候我们需要怎么做呢?两种方法!

方法一:在mapper配置文件中直接粗暴的启用设置

我们直接编辑mapper配置文件加入以下内容:

<cache type="org.mybatis.caches.ehcache.LoggingEhcache"><property name="timeToIdleSeconds" value="3600"/><property name="timeToLiveSeconds" value="3600"/><property name="maxEntriesLocalHeap" value="1000"/><property name="maxEntriesLocalDisk" value="10000000"/><property name="memoryStoreEvictionPolicy" value="LRU"/>
</cache>复制代码

对于我们不想启用缓存的方法,直接在末尾加上‘ useCache="false" ’,如:

<select id="findAllPublish" resultType="cn.acheng1314.domain.PostCustom" useCache="false">···省略方法详细sql···
</select>复制代码

方法二:在service层的方法处注解

我们先看看以前不加缓存的service方法是怎么样子的。

@Service("weichatService")
public class WeichatServiceImpl {@Autowiredprivate SiteConfigDao siteConfigDao;@Autowiredprivate WeChatDao weChatDao;public static String updateMenuUrl = "https://api.weixin.qq.com/cgi-bin/menu/create?access_token=";/*** 同步微信菜单到微信公众号上面** @return*/public String synWeichatMenu() {try {WeiChatMenuBean menuBean = creatWeMenuList();if (null == menuBean) return GsonUtils.toJsonObjStr(null, ResponseCode.FAILED, "菜单内容不能为空!");String menuJson = GsonUtils.toJson(menuBean);LogPrintUtil.getInstance(this.getClass()).logOutLittle(menuJson);WeiChatResPM pm = null; //微信响应的应答String responseStr = HttpClientUtil.doJsonPost(String.format("%s%s", updateMenuUrl, getAccessToken()), menuJson);LogPrintUtil.getInstance(this.getClass()).logOutLittle(responseStr);pm = GsonUtils.fromJson(responseStr, WeiChatResPM.class);if (pm.getErrcode() == 0) return GsonUtils.toJsonObjStr(null, ResponseCode.OK, "同步微信菜单成功!");else throw new Exception(pm.getErrmsg());} catch (Exception e) {e.printStackTrace();return GsonUtils.toJsonObjStr(null, ResponseCode.FAILED, "同步失败!原因:" + e.getMessage());}}public String getAccessToken() throws Exception {MyWeiConfig weiConfig = getWeiConfig();return WeiChatUtils.getSingleton(weiConfig.getAppid(), weiConfig.getAppsecret()).getWeAccessToken();}/*** 获取微信设置,包装了微信的appid,secret和token** @return*/public MyWeiConfig getWeiConfig() {String weiChatAppid = "", weichatAppsecret = "", token = "";MyWeiConfig apiConfig;try {List<HashMap<String, String>> siteInfo = getAllSiteInfo();LogPrintUtil.getInstance(this.getClass()).logOutLittle(siteInfo.toString());for (HashMap<String, String> map : siteInfo) {Set<Map.Entry<String, String>> sets = map.entrySet();      //获取HashMap键值对for (Map.Entry<String, String> set : sets) {             //遍历HashMap键值对String mKey = set.getValue();if (mKey.contains(MySiteMap.WECHAT_APPID)) {weiChatAppid = map.get("option_value");} else if (mKey.contains(MySiteMap.WECHAT_APPSECRET))weichatAppsecret = map.get("option_value");else if (mKey.contains(MySiteMap.WECHAT_TOKEN))token = map.get("option_value");}}apiConfig = new MyWeiConfig(weiChatAppid, weichatAppsecret, token);return apiConfig;} catch (Exception e) {e.printStackTrace();}return null;}/*** 保存微信设置,内部遍历** @param weiConfig 微信的设置信息* @throws Exception*/public void saveConfig(MyWeiConfig weiConfig) throws Exception {if (weiConfig != null && !StringUtils.isEmpty(weiConfig.getAppid(), weiConfig.getAppsecret(), weiConfig.getToken())) {String[] key = {MySiteMap.WECHAT_APPID, MySiteMap.WECHAT_APPSECRET, MySiteMap.WECHAT_TOKEN};String[] value = {weiConfig.getAppid(), weiConfig.getAppsecret(), weiConfig.getToken()};for (int i = 0; i < key.length; i++)siteConfigDao.updateOneByKey(key[i], value[i]);} else {throw new Exception("微信相关设置不能为空!");}}public MyWeChatMenu findOneById(Integer id) {return weChatDao.findOneById(id);}······
}复制代码

如果我们加上对应的cache注解后是什么样子呢?这里就不得不提spring-cache!

因为我们项目本身核心框架是spring,也就是依赖spring的相关框架都有对应的spring实现。也就是说这时候,我们在Ehcache下面找不到对应注解的时候我们打开spring-cache包后,可以找到注解了。这时候我们直接拿spring-cache会有什么效果呢?

其实这时候我们完全可以参考别人的写法,毕竟比人已经很完善了,我就不再一一搞出来了。

当然简单概括的说说主要是用了三个关键字:@Cacheable、@CachePut、@CacheEvict。详细介绍请查阅下面的介绍。

关于注解缓存的简单介绍:blog.csdn.net/wabiaozia/a…

关于注解缓存的深度介绍:blog.csdn.net/wabiaozia/a…

缓存集成完毕后,我们可以在服务器上看到对应的缓存资源如下:

缓存文件

如果你认可我所做的事情,并且认为我做的事对你有一定的帮助,希望你也能打赏我一杯咖啡,谢谢。

支付宝捐赠

[java手把手教程][第二季]java后端博客系统文章系统——No10相关推荐

  1. 一文搭建Vuepress博客/文档系统:搭建,导出,SEO,自动编译和部署,域名,HTTPS,备案等

    本文纯原创,搭建后的博客/文档网站可以参考: Java 全栈知识体系.如需转载请说明原处. 文章内容目录 文章内容目录 第一部分 - 博客/文档系统的搭建 博客/文档搭建前言 有哪些选择 我做了哪些尝 ...

  2. java毕业设计博客管理系统Mybatis+系统+数据库+调试部署

    java毕业设计博客管理系统Mybatis+系统+数据库+调试部署 java毕业设计博客管理系统Mybatis+系统+数据库+调试部署 本源码技术栈: 项目架构:B/S架构 开发语言:Java语言 开 ...

  3. JAVA计算机毕业设计大学生个人博客网站Mybatis+系统+数据库+调试部署

    JAVA计算机毕业设计大学生个人博客网站Mybatis+系统+数据库+调试部署 JAVA计算机毕业设计大学生个人博客网站Mybatis+系统+数据库+调试部署 本源码技术栈: 项目架构:B/S架构 开 ...

  4. java毕业设计大学生个人博客网站Mybatis+系统+数据库+调试部署

    java毕业设计大学生个人博客网站Mybatis+系统+数据库+调试部署 java毕业设计大学生个人博客网站Mybatis+系统+数据库+调试部署 本源码技术栈: 项目架构:B/S架构 开发语言:Ja ...

  5. java毕业设计个人博客网站Mybatis+系统+数据库+调试部署

    java毕业设计个人博客网站Mybatis+系统+数据库+调试部署 java毕业设计个人博客网站Mybatis+系统+数据库+调试部署 本源码技术栈: 项目架构:B/S架构 开发语言:Java语言 开 ...

  6. java培训教程分享:Java中怎样将数据对象序列化和反序列化?

    本期为大家介绍的java培训教程是关于"Java中怎样将数据对象序列化和反序列化?"的内容,相信大家都知道,程序在运行过程中,可能需要将一些数据永久地保存到磁盘上,而数据在Java ...

  7. java培训教程分享:Java编写软件代码自动提示功能

    本期的java培训教程分享主要是介绍的java编写软件代码的一个自动提示功能,很多零基础和初学java的同学们对这一块还不是很了解,Eclipse for android 实现代码自动提示智能提示功能 ...

  8. java培训教程分享:Java中用户如何自定义异常?

    我们在学习java技术的时候应该有了解过,在java中是定义了很多的异常类的,虽然这些大量异常类可以帮助我们描述编程时出现的大部分异常情况,但是在程序开发中有时可能需要描述程序中特有的异常情况,例如在 ...

  9. java 使用webmagic 爬虫框架爬取博客园数据

    java 使用webmagic 爬虫框架爬取博客园数据存入数据库 学习记录   webmagic简介: WebMagic是一个简单灵活的Java爬虫框架.你可以快速开发出一个高效.易维护的爬虫. ht ...

最新文章

  1. 西数硬盘固件刷新工具_鲁大师Q2季度硬盘排行:三星、西数上榜产品最多
  2. python标准库导入语句有哪些_如何将python标准库缺失的进行导入?
  3. HTML制作搞笑照片,40张创意搞笑的照片PS效果
  4. 直播 | 清华大学郑楚杰:知识增强对话生成中的差异感知知识选择
  5. 04.search_template
  6. 【C++学习笔记四】运算符重载
  7. hadoop安装以及Java API操作hdfs
  8. 64 SD配置-交货凭证配置-在交货时定义项目类别确定
  9. 基于Verilog-HDL实现会呼吸的流水灯
  10. [译]使用深度学习方法实现面部表情包识别
  11. 绿色应用成主流,国内千款主流应用75%已达绿标
  12. (day 40 - 双指针+库函数) 剑指 Offer 58 - I. 翻转单词顺序
  13. torch.nn.functional.cosine_similarity使用详解
  14. Java学习十四,JDBC,反射
  15. 这是一篇来源于阿里内部技术论坛的文章
  16. 【读书笔记】清单革命
  17. python下载歌曲教程视频_实现python批量下载网易云音乐的免费音乐
  18. 面试自我介绍的两个通用模板
  19. 【软件测试】简历中的项目经历可以怎么写?
  20. LQB04 定时器代码使用01,定时闪烁灯和定时框架。

热门文章

  1. graphic头文件函数_graphics.h头文件详解
  2. mac最好用的markdown_Markdown 语法简明教程 amp; Markdown 编辑器推荐
  3. java php mysql_系统学习javaweb13----MYSQL学习(使用PHP、SQL)1
  4. java多线程 门闩_Java线程与并发编程实践----同步器(倒计时门闩,同步屏障)...
  5. php 获取手机品牌,三到五年内,这家品牌要冲刺手机市场第一梯队
  6. oracle开发数据库试题,Oracle_开发数据库试题.doc
  7. Elasticsearch介绍Kibana分词器增删改操作
  8. 如何进行图片的平移,滚卷?
  9. 第十六届全国大学生智能汽车竞赛华东赛区 承办情况汇报
  10. 交叉熵损失函数公式_交叉熵损失函数对其参数求导