当前位置: 首页 > news >正文

wordpress 菜单 导航代码seo推广沧州公司电话

wordpress 菜单 导航代码,seo推广沧州公司电话,百盛联合建设集团网站,做酒店的网站2019独角兽企业重金招聘Python工程师标准>>> 一般,页面上会分为很多部分,而不同的部分更新的频率是不一样的。如果对整个页面采用统一的缓存策略则不太合适, 而且很多系统的页面左上角都有一个该死的“Welcome XXX”。这种特定于…

2019独角兽企业重金招聘Python工程师标准>>> hot3.png


一般,页面上会分为很多部分,而不同的部分更新的频率是不一样的。如果对整个页面采用统一的缓存策略则不太合适,

而且很多系统的页面左上角都有一个该死的“Welcome XXX”。这种特定于用户的信息我们是不能缓存的。对于这些情况我们就需要使用片段缓存了。对页面不同的部分(片段)施加不同的缓存策略,而要使用片段缓存,首先就得对页面进行切分。土一点的办法可以用iframe,用iframe将页面划分为一块块的,不过我总觉得iframe是个邪恶的东西。好点的办法可以用Ajax单独的请求这个片段的内容然后再填充,看起来挺美好的。不过使用Ajax也有一些限制:

1、如果页面上有许多片段,使用太多的这种技术,会有很多请求发送到服务器,HTTP对同一个域名有连接的限制,这样会降低并发连接的效率。

2、如果说第一个不是什么问题,那么还有一点可能对用户体验不友好。比如有一个片段可能响应慢点,造成页面闪烁。不过如果前面两点都可以克服,这个方案还是可以的。可恶的是我们的客户(此处省略500字),说他们的大多数用户处于一个禁用JavaScript的环境里。好吧,这个方案也不能使用了。如是我们进行了一系列其他关于片段缓存的尝试:

我们的系统使用的是Spring+Hibernate+Oracle技术,模板引擎使用的是Apache Velocity。假设下面的片段是我们要缓存的内容:

 

<ul>
#foreach($book in $books)
<li><a href="/book/books/$book.id">$book.name</a>---<a href="/book/books/edit/$book.id">Edit</a> -- <a href="/book/books/delete/$book.id">Delete</a></li>
#end
</ul>


显示一个图书列表。对这个页面改动最小的办法是加上一个标签,被这个标签包围的片段就是缓存的:


#cache
<ul>
#foreach($book in $books)
<li><a href="/book/books/$book.id">$book.name</a>---<a href="/book/books/edit/$book.id">Edit</a> -- <a href="/book/books/delete/$book.id">Delete</a></li>
#end
</ul>
#end


由于一个页面可能有很多片段,不同的片段肯定要用不同的cache key,所以这个标签应该还能传入一个cache key。当呈现这个页面,到解析这个标签的时候我们就用这个cache key去缓存中取,如果取到了我们就直接将缓存的东西输出,

而不再需要解析这个图书列表了。

有了这个想法,我们就需要找到如何让Velocity解析我们的标签的方案。很好,Velocity是支持自定义标签的:

public class Cache extends Directive {@Overridepublic String getName() {return "cache";}@Overridepublic int getType() {return BLOCK;}@Overridepublic boolean render(InternalContextAdapter context, Writer writer,Node node) throws IOException, ResourceNotFoundException,ParseErrorException, MethodInvocationException {Node keyNode = node.jjtGetChild(0);String cacheKey = (String) keyNode.value(context);String cacheHtml = cacheHtml = (String) CacheManager.getInstance().get(cacheKey);if (StringUtils.isEmpty(cacheHtml)) {Node bodyNode = node.jjtGetChild(1);Writer tempWriter = new StringWriter();bodyNode.render(context, tempWriter);cacheHtml = tempWriter.toString();CacheManager.getInstance().set(cacheKey, cacheHtml);}writer.write(cacheHtml);return true;}
}


关于Velocity的自定义标签的使用我会在后面稍作解释。

最主要的逻辑在render方法里,我们先根据cache key去缓存里取,如果没取到再使用代码render,然后render的结果放到缓存中。很典型的缓存使用场景是不。再来看看控制器端得代码:

@Controller
@RequestMapping("/books")
public class BookController {private BookDAO bookDAO;@Autowiredpublic BookController(BookDAO bookDAO) {this.bookDAO = bookDAO;}@RequestMapping(value = { "", "index.html" }, method = RequestMethod.GET)public ModelAndView index() {return new ModelAndView("list", "books", bookDAO.findAll());}
}

控制器很简单,调用DAO,将所有图书列出来即可。正在我们高兴这么棘手的问题被解决的时候,问题来了:

我们的缓存是为了什么?总不是为了节约Velocity解析的时间吧。我想大家应该都知道,最主要的还是为了节约这次bookDAO.findAll()查询数据库的时间。但是回过头看看我们的方案。不管我们的cache命没命中,这个bookDAO.findAll()都会执行一次,因为控制器的执行是在视图render之前发生的。我们唯一节省的是Velocity解析的时间,杯具。

找到了问题的答案,寻找解决办法就容易了。我们要做的就是在缓存没有命中的时候才执行查询,那么这个数据查询就必须放到cache标签内部做。但是我们的cache标签可不是为了一个片段啊,有很多片段,而各种片段取数据的方式却不同。

嗯,你还记得接口么?还记得计算机里所有的问题都可以通过中间层解决的这个名言么?按照这个思路我们如此设计cache标签:

#cache("book_list",$dataProvider)<ul>#foreach($book in $books)<li><a href="/book/books/$book.id">$book.name</a>---<a href="/book/books/edit/$book.id">Edit</a> -- <a href="/book/books/delete/$book.id">Delete</a></li>#end</ul>#end

我们传入一个dataProvider对象进来,而这个dataProvider是控制器里传入进来的,一个专门用来取数据的:

public class BookController {private DataProvider dataProvider;@Autowiredpublic BookController(BookDataProvider dataProvider) {this.dataProvider = dataProvider;}@RequestMapping(value = { "", "index.html" }, method = RequestMethod.GET)public ModelAndView index() {return new ModelAndView("list", "dataProvider", dataProvider);}
}

控制器还是一如既往的简单,我们再来看看cache标签的实现:

public class Cache extends Directive {@Overridepublic String getName() {return "cache";}@Overridepublic int getType() {return BLOCK;}@Overridepublic boolean render(InternalContextAdapter context, Writer writer, Node node)throws IOException, ResourceNotFoundException, ParseErrorException, MethodInvocationException {Node keyNode = node.jjtGetChild(0);String cacheKey = (String) keyNode.value(context);String cacheHtml = cacheHtml = (String) CacheManager.getInstance().get(cacheKey);if (StringUtils.isEmpty(cacheHtml)) {Node dataProviderNode = node.jjtGetChild(1);DataProvider dataProvider = (DataProvider) dataProviderNode.value(context);Map<String, Object> map = dataProvider.load();for (String key map.keySet()) {context.put(key, map.get(key));}Node bodyNode = node.jjtGetChild(3);Writer tempWriter = new StringWriter();bodyNode.render(context, tempWriter);cacheHtml = tempWriter.toString();CacheManager.getInstance().set(cacheKey, cacheHtml);}writer.write(cacheHtml);return true;}
}

我们在标签内部取到外部传入的dataProvider,它实现了一个接口DataProvider,然后在标签内部进行数据的查询。

然后将查询的数据put到velocity的context中,然后再次render,将render的结果放到缓存。这下好了,控制器里只需要向视图传递一个可以取数据的对象就可以了,cache标签内部会进行判断。DataProvider和BookDataProvider的代码:

public interface DataProvider {Map<String, Object> load();
}@Service
public class BooksDataProvider implements DataProvider {private BookDAO bookDAO;@Autowiredpublic BooksDataProvider(BookDAO bookDAO) {this.bookDAO = bookDAO;}public Map<String, Object> load() {Map<String, Object> result = new HashMap<String, Object>();result.put("books", bookDAO.findAll());return result;}
}

现在我们要改造的就是对于每个不同的缓存片段写一个DataProvider的实现,而实际上这个实现原来已经有了:

就是原来控制器内那部分代码。比如BooksDataProvider实际上就是原来BookController内的代码。通过这种方式,我们基本上就将一个页面划分为很多用cache包围的小片段了,只要划分出来了那么你就可以对不同

的片段采用不同的缓存策略。代码的结构还算清晰。

下面我稍微介绍一下Velocity自定义标签的使用

Velocity自定义标签

每个自定义标签都从Directive派生下来,我们要覆盖几个方法。

1、getName,返回一个字符串,这个就是你在velocity模板里使用的那个标签的名字:#cache。

2、标签的类型,像我们的cache这种#cache…#end的叫块级标签,那么返回的就是一个BLOCK(常量1)。还有一个类型是LINE(2),那就没有那个#end了。

3、render方法,这是最主要的,你可以覆盖一些行为。

取外部传入的参数

那么在标签内部如何取得外部传入的参数呢?其实它的行为和xml path的操作方式差不多。在render方法的参数里有一个Node,这个就是标签自身。我们可以通过node.jjtGetChild(index)来取得各种参数。以0开始,如果是BLOCK类型的标签,那么最后一个就是标签包围的内容了(比如我们的cache标签)。然后我们可以通过node的value取到参数的值。取值的时候还将context传入进去了,这说明这个值是可计算的。比如现在有这么一个需求,我们的图书列表是分页的,但是只缓存第一页,后面的不缓存。那我们就期望能传入

一个表达式,让cache标签自己计算一把,如果这个表达式为true则缓存,否则不缓存:

#cache("book_list",$pageIndex==1,$dataProvider)
。。。。。
#end

那么在cache标签内部呢:

Node needCacheNode = node.jjtGetChild(1);Boolean needCache = (Boolean) needCacheNode.value(context);String cacheHtml = StringUtils.EMPTY;if (needCache) {cacheHtml = (String) CacheManager.getInstance().get(cacheKey);}

这样就可以计算出$pageIndex==1这个表达式的结果(当然,$pageIndex这个变量是需要传入进来的)。

好了,编写好自定义标签的代码我们可以使用了。而并不是我们写好这代码往那儿一丢就可以使用了,还需要一个配置环节:

<bean class="org.springframework.web.servlet.view.velocity.VelocityConfigurer"><property name="resourceLoaderPath" value="/WEB-INF/templates/"/><property name="velocityProperties"><props><prop key="userdirective">com.yuyijq.web.Cache</prop></props></property></bean>

好了,这么一个利用Velocity的片段缓存就完成了。但是这种方式也存在一些问题,给我们带来了一些bug。

1、有的时候我们会在片段里set一些变量,然后在这个片段外使用。但是现在使用了cache之后,cache之后的是HTML

文本,这些变量全部消失了,那么片段外也取不到这些变量的值了。那我们就需要仔细搜查Velocity模板,将这些变量的使用全部移动到片段内部。如果是一开始就设计了这个片段缓存还好,我们可以注意这个问题。但问题是现在是项目的中途提出的,系统中velocity模板成千上万,我们每缓存一个片段就要仔细检查一番,而且Velocity模板没有测试(当然可以写测试,但很麻烦)。这个过程全部靠人肉,所以出bug的几率会很高。

2、还是一样,改动比较大,不仅模板,后面的控制器也需要修改。不过貌似也没什么更好的方法,要使用片段缓存貌似改动是避免不了的。

转载于:https://my.oschina.net/fangshaowei/blog/150447

http://www.lbrq.cn/news/2552905.html

相关文章:

  • 个人 可以备案做分类信息网站吗重庆网站网络推广
  • 网站建设 我们是专业的网络营销平台
  • 企业网站设计策划大数据技术主要学什么
  • 银川网站建设一条龙谷歌google中文登录入口
  • 视频网站发展好应该怎么做百度指数有三个功能模块
  • 自己电脑做网站服务器广域网访问西安网站关键词优化推荐
  • 提供商城网站制作最新国际消息
  • 佛山网站建设no.1怎么做电商平台
  • cad如何做图纸模板下载网站kol合作推广
  • 商城网站建设费用郑州网站推广公司排名
  • 网站建设项目描述范文直播引流推广方法
  • 用手机自创游戏郑州seo实战培训
  • 做网站需要做h5吗网站seo排名公司
  • 泰州专业制作网站南京seo排名
  • 网站被host重定向处理怎么做网站平台
  • 用来查数据的网站怎么建设网站优化公司认准乐云seo
  • php网站打开一片空白1688网站
  • 做视频类网站需要哪些许可证百度经验首页官网
  • php和ASP网站那个好市场营销公司排名
  • wordpress 秒拍seo北京网站推广
  • 电商美工的工作内容是什么seo优化公司
  • 报名网站开发多钱全国疫情排行榜
  • wordpress单页主题营销无锡seo关键词排名
  • 找个免费的网站这么难吗海外seo
  • 外贸网站建设加推广宁波seo运营推广平台排名
  • 腾飞网站建设站长之家网站排行榜
  • 租车网站建设方案google官网浏览器
  • 宣传片拍摄实施方案新的seo网站优化排名 网站
  • 网站设计机构成都黑帽seo
  • 洛阳市住房和城乡建设委员会网站6免费网站推广工具
  • SpringMVC全局异常处理+拦截器使用+参数校验
  • SpringMVC的高级特性
  • anaconda searchanaconda show | conda 检索包资源安装指定版本包指定源安装命令package
  • 【neo4j】跨版本升级数据库
  • 另外几种语言挑战100万行字符串文本排序
  • 机器学习之逻辑回归(Logistic Regression)