【struts2】预定义拦截器

  1)预定义拦截器

  Struts2有默认的拦截器配置,也就是说,虽然我们没有主动去配置任何关于拦截器的东西,但是Struts2会使用默认引用的拦截器。由于Struts2的默认拦截器声明和引用都在这个Struts-default.xml里面,因此我们需要到这个文件的struts-default包里去看一下。定义如下:

  1         <interceptors>
  2             <interceptor name="alias" class="com.opensymphony.xwork2.interceptor.AliasInterceptor"/>
  3             <interceptor name="autowiring" class="com.opensymphony.xwork2.spring.interceptor.ActionAutowiringInterceptor"/>
  4             <interceptor name="chain" class="com.opensymphony.xwork2.interceptor.ChainingInterceptor"/>
  5             <interceptor name="conversionError" class="org.apache.struts2.interceptor.StrutsConversionErrorInterceptor"/>
  6             <interceptor name="cookie" class="org.apache.struts2.interceptor.CookieInterceptor"/>
  7             <interceptor name="cookieProvider" class="org.apache.struts2.interceptor.CookieProviderInterceptor"/>
  8             <interceptor name="clearSession" class="org.apache.struts2.interceptor.ClearSessionInterceptor" />
  9             <interceptor name="createSession" class="org.apache.struts2.interceptor.CreateSessionInterceptor" />
 10             <interceptor name="debugging" class="org.apache.struts2.interceptor.debugging.DebuggingInterceptor" />
 11             <interceptor name="execAndWait" class="org.apache.struts2.interceptor.ExecuteAndWaitInterceptor"/>
 12             <interceptor name="exception" class="com.opensymphony.xwork2.interceptor.ExceptionMappingInterceptor"/>
 13             <interceptor name="fileUpload" class="org.apache.struts2.interceptor.FileUploadInterceptor"/>
 14             <interceptor name="i18n" class="com.opensymphony.xwork2.interceptor.I18nInterceptor"/>
 15             <interceptor name="logger" class="com.opensymphony.xwork2.interceptor.LoggingInterceptor"/>
 16             <interceptor name="modelDriven" class="com.opensymphony.xwork2.interceptor.ModelDrivenInterceptor"/>
 17             <interceptor name="scopedModelDriven" class="com.opensymphony.xwork2.interceptor.ScopedModelDrivenInterceptor"/>
 18             <interceptor name="params" class="com.opensymphony.xwork2.interceptor.ParametersInterceptor"/>
 19             <interceptor name="actionMappingParams" class="org.apache.struts2.interceptor.ActionMappingParametersInteceptor"/>
 20             <interceptor name="prepare" class="com.opensymphony.xwork2.interceptor.PrepareInterceptor"/>
 21             <interceptor name="staticParams" class="com.opensymphony.xwork2.interceptor.StaticParametersInterceptor"/>
 22             <interceptor name="scope" class="org.apache.struts2.interceptor.ScopeInterceptor"/>
 23             <interceptor name="servletConfig" class="org.apache.struts2.interceptor.ServletConfigInterceptor"/>
 24             <interceptor name="timer" class="com.opensymphony.xwork2.interceptor.TimerInterceptor"/>
 25             <interceptor name="token" class="org.apache.struts2.interceptor.TokenInterceptor"/>
 26             <interceptor name="tokenSession" class="org.apache.struts2.interceptor.TokenSessionStoreInterceptor"/>
 27             <interceptor name="validation" class="org.apache.struts2.interceptor.validation.AnnotationValidationInterceptor"/>
 28             <interceptor name="workflow" class="com.opensymphony.xwork2.interceptor.DefaultWorkflowInterceptor"/>
 29             <interceptor name="store" class="org.apache.struts2.interceptor.MessageStoreInterceptor" />
 30             <interceptor name="checkbox" class="org.apache.struts2.interceptor.CheckboxInterceptor" />
 31             <interceptor name="profiling" class="org.apache.struts2.interceptor.ProfilingActivationInterceptor" />
 32             <interceptor name="roles" class="org.apache.struts2.interceptor.RolesInterceptor" />
 33             <interceptor name="annotationWorkflow" class="com.opensymphony.xwork2.interceptor.annotations.AnnotationWorkflowInterceptor" />
 34             <interceptor name="multiselect" class="org.apache.struts2.interceptor.MultiselectInterceptor" />
 35             <interceptor name="deprecation" class="org.apache.struts2.interceptor.DeprecationInterceptor" />
 36 
 37             <!-- Basic stack -->
 38             <interceptor-stack name="basicStack">
 39                 <interceptor-ref name="exception"/>
 40                 <interceptor-ref name="servletConfig"/>
 41                 <interceptor-ref name="prepare"/>
 42                 <interceptor-ref name="checkbox"/>
 43                 <interceptor-ref name="multiselect"/>
 44                 <interceptor-ref name="actionMappingParams"/>
 45                 <interceptor-ref name="params">
 46                     <param name="excludeParams">^class\..*,^dojo\..*,^struts\..*,^session\..*,^request\..*,^application\..*,^servlet(Request|Response)\..*,^parameters\..*,^action:.*,^method:.*</param>
 47                 </interceptor-ref>
 48                 <interceptor-ref name="conversionError"/>
 49                 <interceptor-ref name="deprecation"/>
 50             </interceptor-stack>
 51 
 52             <!-- Sample validation and workflow stack -->
 53             <interceptor-stack name="validationWorkflowStack">
 54                 <interceptor-ref name="basicStack"/>
 55                 <interceptor-ref name="validation"/>
 56                 <interceptor-ref name="workflow"/>
 57             </interceptor-stack>
 58 
 59             <!-- Sample file upload stack -->
 60             <interceptor-stack name="fileUploadStack">
 61                 <interceptor-ref name="fileUpload"/>
 62                 <interceptor-ref name="basicStack"/>
 63             </interceptor-stack>
 64 
 65             <!-- Sample model-driven stack  -->
 66             <interceptor-stack name="modelDrivenStack">
 67                 <interceptor-ref name="modelDriven"/>
 68                 <interceptor-ref name="basicStack"/>
 69             </interceptor-stack>
 70 
 71             <!-- Sample action chaining stack -->
 72             <interceptor-stack name="chainStack">
 73                 <interceptor-ref name="chain"/>
 74                 <interceptor-ref name="basicStack"/>
 75             </interceptor-stack>
 76 
 77             <!-- Sample i18n stack -->
 78             <interceptor-stack name="i18nStack">
 79                 <interceptor-ref name="i18n"/>
 80                 <interceptor-ref name="basicStack"/>
 81             </interceptor-stack>
 82 
 83             <!-- An example of the paramsPrepareParams trick. This stack
 84                  is exactly the same as the defaultStack, except that it
 85                  includes one extra interceptor before the prepare interceptor:
 86                  the params interceptor.
 87 
 88                  This is useful for when you wish to apply parameters directly
 89                  to an object that you wish to load externally (such as a DAO
 90                  or database or service layer), but can't load that object
 91                  until at least the ID parameter has been loaded. By loading
 92                  the parameters twice, you can retrieve the object in the
 93                  prepare() method, allowing the second params interceptor to
 94                  apply the values on the object. -->
 95             <interceptor-stack name="paramsPrepareParamsStack">
 96                 <interceptor-ref name="exception"/>
 97                 <interceptor-ref name="alias"/>
 98                 <interceptor-ref name="i18n"/>
 99                 <interceptor-ref name="checkbox"/>
100                 <interceptor-ref name="multiselect"/>
101                 <interceptor-ref name="params">
102                     <param name="excludeParams">^class\..*,^dojo\..*,^struts\..*,^session\..*,^request\..*,^application\..*,^servlet(Request|Response)\..*,^parameters\..*,^action:.*,^method:.*</param>
103                 </interceptor-ref>
104                 <interceptor-ref name="servletConfig"/>
105                 <interceptor-ref name="prepare"/>
106                 <interceptor-ref name="chain"/>
107                 <interceptor-ref name="modelDriven"/>
108                 <interceptor-ref name="fileUpload"/>
109                 <interceptor-ref name="staticParams"/>
110                 <interceptor-ref name="actionMappingParams"/>
111                 <interceptor-ref name="params">
112                     <param name="excludeParams">^class\..*,^dojo\..*,^struts\..*,^session\..*,^request\..*,^application\..*,^servlet(Request|Response)\..*,^parameters\..*,^action:.*,^method:.*</param>
113                 </interceptor-ref>
114                 <interceptor-ref name="conversionError"/>
115                 <interceptor-ref name="validation">
116                     <param name="excludeMethods">input,back,cancel,browse</param>
117                 </interceptor-ref>
118                 <interceptor-ref name="workflow">
119                     <param name="excludeMethods">input,back,cancel,browse</param>
120                 </interceptor-ref>
121             </interceptor-stack>
122 
123             <!-- A complete stack with all the common interceptors in place.
124                  Generally, this stack should be the one you use, though it
125                  may do more than you need. Also, the ordering can be
126                  switched around (ex: if you wish to have your servlet-related
127                  objects applied before prepare() is called, you'd need to move
128                  servletConfig interceptor up.
129 
130                  This stack also excludes from the normal validation and workflow
131                  the method names input, back, and cancel. These typically are
132                  associated with requests that should not be validated.
133                  -->
134             <interceptor-stack name="defaultStack">
135                 <interceptor-ref name="exception"/>
136                 <interceptor-ref name="alias"/>
137                 <interceptor-ref name="servletConfig"/>
138                 <interceptor-ref name="i18n"/>
139                 <interceptor-ref name="prepare"/>
140                 <interceptor-ref name="chain"/>
141                 <interceptor-ref name="scopedModelDriven"/>
142                 <interceptor-ref name="modelDriven"/>
143                 <interceptor-ref name="fileUpload"/>
144                 <interceptor-ref name="checkbox"/>
145                 <interceptor-ref name="multiselect"/>
146                 <interceptor-ref name="staticParams"/>
147                 <interceptor-ref name="actionMappingParams"/>
148                 <interceptor-ref name="params">
149                     <param name="excludeParams">^class\..*,^dojo\..*,^struts\..*,^session\..*,^request\..*,^application\..*,^servlet(Request|Response)\..*,^parameters\..*,^action:.*,^method:.*</param>
150                 </interceptor-ref>
151                 <interceptor-ref name="conversionError"/>
152                 <interceptor-ref name="validation">
153                     <param name="excludeMethods">input,back,cancel,browse</param>
154                 </interceptor-ref>
155                 <interceptor-ref name="workflow">
156                     <param name="excludeMethods">input,back,cancel,browse</param>
157                 </interceptor-ref>
158                 <interceptor-ref name="debugging"/>
159                 <interceptor-ref name="deprecation"/>
160             </interceptor-stack>
161 
162             <!-- The completeStack is here for backwards compatibility for
163                  applications that still refer to the defaultStack by the
164                  old name -->
165             <interceptor-stack name="completeStack">
166                 <interceptor-ref name="defaultStack"/>
167             </interceptor-stack>
168 
169             <!-- Sample execute and wait stack.
170                  Note: execAndWait should always be the *last* interceptor. -->
171             <interceptor-stack name="executeAndWaitStack">
172                 <interceptor-ref name="execAndWait">
173                     <param name="excludeMethods">input,back,cancel</param>
174                 </interceptor-ref>
175                 <interceptor-ref name="defaultStack"/>
176                 <interceptor-ref name="execAndWait">
177                     <param name="excludeMethods">input,back,cancel</param>
178                 </interceptor-ref>
179             </interceptor-stack>
180 
181        </interceptors>
182 
183         <default-interceptor-ref name="defaultStack"/>
View Code
  • params拦截器

  这个拦截器是必不可少的,因为就是由它偷偷的把请求参数设置到相应的Action的属性去的,并自动进行类型转换。

  • staticParams拦截器

  将struts.xml配置文件里定义的Action参数,设置到对应的Action实例中,Action参数使用<param>标签,是<action>标签的子元素。struts.xml的示例如下:

<action name="helloworldAction" class="cn.javass.action.action.HelloWorldAction">  <param name="account">test</param>  
</action> 

  这要求Action中一定要有一个account的属性,并有相应的getter/setter方法。运行的时候,Action的account属性在初始化过后,会接到这里的赋值“test”。

  注意:params拦截器和staticParams拦截器都会为Action的属性赋值,如果碰到了都要赋同一个值呢,比如request里面有account参数,而struts.xml中也有account参数,最终的值是谁?其实是Action初始化过后,就会把struts.xml中配置的数据设置到Action实例中相应的属性上去。然后,把用户请求的数据设置到Action实例中相应的属性上去。很明显最后的值是用户请求中account的数据。

  • timer拦截器

  该拦截器可以记录ActionInvocation余下部分执行的时间,并做为日志信息记录下来,便于寻找性能瓶颈。也就是说,该拦截器可以记录Action运行的时间。

  • logger拦截器

  在日志信息中输出要执行的Action信息 ,这样,在调试的时候,就能很快的定位到这个对应的Action了。

  2)拦截器配置说明

  • <interceptor>元素用来定义一个拦截器,这里仅仅是一个定义,还没有任何一个Action来引用它。里面的name属性作为唯一标志,而class属性就是这个拦截器的实现类。拦截器的实现类都应该是com.opensymphony.xwork2.interceptor.Interceptor这个接口的实现类。
  • <interceptor-stack>定义了一个拦截器栈,这个栈中可以引用其他已经定义好的拦截器。拦截器栈简化了动作类Action在引用拦截器时的操作。

    因为大多数动作类Action在引用拦截器的时候都不会仅仅引用一个拦截器,而是引用一组拦截器,而多个动作类Action大概又会引用同一组拦截器,这时候,为了引用的方便,可以把多个拦截器组合成一个拦截器栈。Action在引用的时候,只需要引用这个拦截器栈就可以了,而不是引用每一个拦截器。下面看一下struts-2.1.dtd对于<action>元素的定义:

<!ELEMENT action (param|result|interceptor-ref|exception-mapping)*>  

  action元素后面出现的interceptor-ref子元素后面用*来修饰,这说明一个action元素可以有不限个数的interceptor-ref子元素。那么在<action>元素中,如何使用<interceptor-ref>子元素呢?其实很简单,只需要在<action>元素中,配置需要的<interceptor-ref>子元素就可以了,<interceptor-ref>子元素里面配置需要使用的拦截器的名称,比如:

<action name="helloworldAction" class="cn.javass.action.action.HelloWorldAction">  <param name="account">test</param>  <result>/s2impl/welcome.jsp</result>  <interceptor-ref name="staticParams"/>  <interceptor-ref name="defaultStack"/>  
</action>  

  <interceptor-ref>子元素中的name,不仅仅可以是一个已经定义好的拦截器的名称,还可以是一个已经定义好的拦截器栈的名称。上面的示例,就引用了一个拦截器和一个拦截器栈。

  • <default-interceptor-ref>在包上声明包内所有的Action都使用的拦截器

  先看一下struts-2.1.dtd对于<package>元素的定义:

<!ELEMENT package (result-types?, interceptors?, default-interceptor-ref?, default-action-ref?, default-class-ref?, global-results?, global-exception-mappings?, action*)>  

  其实,在配置自己的package的时候所扩展的struts-default包里面,就已经定义了一个<default-interceptor-ref>,在Struts-default.xml中定义的struts-default包内,有如下定义:

<default-interceptor-ref name="defaultStack"/>  

  正是因为有这个定义,我们都没有主动去配置拦截器,但实际上,是有拦截器在运行并执行很重要的工作,只不过是使用的默认的拦截器,我们不知道罢了。

  3)拦截器的调用顺序

  在学习了预定义拦截器的配置使用之后,接下来看看<action>元素引用拦截器的调用顺序。在拿到一个动作类的声明<action>元素后,如何找到它引用的拦截器呢?

  1:首先,要找它自己有没有声明拦截器的引用,即<action>元素有没有<interceptor-ref>子元素,如果有,则不用继续再找,直接使用这些拦截器,如果没有,下一步。

  2:其次,找这个<action>所在的包有没有声明默认的拦截器引用,即<package>元素的<default-interceptor-ref>子元素, 如果有,则不用继续再找,直接使用这些拦截器,如果没有,下一步。

       3:最后,递归地寻找这个包的父包有没有声明默认的拦截器引用,直到找到有拦截器引用就为止。

       特别注意:这三个地方的定义是覆盖的关系,什么意思呢?就是如果<action>里面声明了拦截器引用,那么就以它的为准,其他的定义就无效了。也即是<action>里面的拦截器引用声明会覆盖<package>里面的缺省拦截器声明,而<package>里面的缺省拦截器声明又会覆盖父包的<package>里面的缺省拦截器声明,以此类推。

  4)全局拦截器的配置

<package name="helloworld"  extends="struts-default">  <interceptors>  <interceptor-stack name="myStack">  <interceptor-ref name="timer"/>  <interceptor-ref name="defaultStack"/>  </interceptor-stack>  </interceptors>  <default-interceptor-ref name="myStack"/>  <action name="helloworldAction" class="cn.javass.hello.struts2impl.action.HelloWorldAction"> <result name="toWelcome">/${folder}/welcome.jsp</result> <result name="input">/${folder}/login.jsp</result>   </action>  </package>  

  参考资料:http://www.iteye.com/topic/1124526

转载于:https://www.cnblogs.com/ningvsban/p/3735639.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/473362.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

使用注意力机制建模 - 标准化日期格式

文章目录1. 概述2. 数据3. 模型4. 训练5. 测试参考 基于深度学习的自然语言处理本文使用attention机制的模型&#xff0c;将各种格式的日期转化成标准格式的日期 1. 概述 LSTM、GRU 减少了梯度消失的问题&#xff0c;但是对于复杂依赖结构的长句子&#xff0c;梯度消失仍然存…

牛客 数学实验(模拟)

文章目录1. 题目2. 解题1. 题目 链接&#xff1a;https://ac.nowcoder.com/acm/contest/10166/A 来源&#xff1a;牛客网 牛牛在做数学实验。 老师给了牛牛一个数字n&#xff0c;牛牛需要不断地将所有数位上的值做乘法运算&#xff0c;直至最后数字不发生变化为止。 请你帮牛…

css动画之波纹

样式定义&#xff1a; #ContactAbout { height: auto; position: relative; overflow: hidden; } #sectioncontact { display: block; width: 100%; position: relative; height: 700px; z-index: 10; }#sectioncontact .map { width: 370px; height: 280px; position: absolut…

牛客 奇怪的排序问题(单调栈/遍历)

文章目录1. 题目2. 解题1. 题目 链接&#xff1a;https://ac.nowcoder.com/acm/contest/10166/B 来源&#xff1a;牛客网 操场上有n个人排成一队&#xff0c;这n个人身高互不相同&#xff0c;可将他们的身高视为一个1到n的排列。 这时需要把队伍变成升序&#xff0c;也就是从…

Python 中,matplotlib绘图无法显示中文的问题

在python中&#xff0c;默认情况下是无法显示中文的&#xff0c;如下代码&#xff1a; import matplotlib.pyplot as plt# 定义文本框和箭头格式 decisionNode dict(boxstyle "sawtooth", fc "0.8") leafNode dict(boxstyle "round4", fc …

牛客 XOR和(找规律)

文章目录1. 题目2. 解题1. 题目 链接&#xff1a;https://ac.nowcoder.com/acm/contest/10166/C 来源&#xff1a;牛客网 牛牛最近学会了异或操作&#xff0c;于是他发现了一个函数 f(x)x⊕(x−1)f(x)x\oplus (x-1)f(x)x⊕(x−1)&#xff0c;现在牛牛给你一个数 n&#xff0c…

天池 在线编程 数组划分III(计数)

文章目录1. 题目2. 解题1. 题目 https://tianchi.aliyun.com/oj/231188302809557697/235445278655844965 给你一个整数数组和一个整数K&#xff0c;请你判断数组是否可以划分为若干大小为k序列&#xff0c;并满足以下条件&#xff1a; 数组中的每一个数恰恰出现在一个序列中…

详解nohup和 区别

一、nohup nohup 命令运行由 Command参数和任何相关的 Arg参数指定的命令&#xff0c;忽略所有挂断&#xff08;SIGHUP&#xff09;信号。在注销后使用 nohup 命令运行后台中的程序。要运行后台中的 nohup 命令&#xff0c;添加 & &#xff08; 表示“and”的符号&#xf…

天池 在线编程 最小振幅(排序)

文章目录1. 题目2. 解题1. 题目 https://tianchi.aliyun.com/oj/231188302809557697/235445278655844966 给定一个由N个整数组成的数组A&#xff0c;一次移动&#xff0c;我们可以选择此数组中的任何元素并将其替换为任何值。 数组的振幅是数组A中的最大值和最小值之间的差。…

Python把两张图片拼接为一张图片并保存

这里主要用Python扩展库pillow中Image对象的paste()方法把两张图片拼接起来 from os import listdir from PIL import Imagedef pinjie():# 获取当前文件夹中所有JPG图像im_list [Image.open(fn) for fn in listdir() if fn.endswith(.jpg)]# 图片转化为相同的尺寸ims []for…

天池 在线编程 高效作业处理服务(01背包DP)

文章目录1. 题目2. 解题1. 题目 https://tianchi.aliyun.com/oj/231188302809557697/235445278655844967 Twitter正在测试一种名为Pigeon的新工作处理服务。 Pigeon可以用任务实际持续时间的两倍处理任务&#xff0c;并且每个任务都有一个权重。 此外&#xff0c;Pigeon在一…

LeetCode 1694. 重新格式化电话号码(模拟)

文章目录1. 题目2. 解题1. 题目 给你一个字符串形式的电话号码 number 。 number 由数字、空格 、和破折号 - 组成。 请你按下述方式重新格式化电话号码。 首先&#xff0c;删除 所有的空格和破折号。 其次&#xff0c;将数组从左到右 每 3 个一组 分块&#xff0c;直到 剩…

LeetCode 1695. 删除子数组的最大得分(前缀和+哈希+双指针)

文章目录1. 题目2. 解题1. 题目 给你一个正整数数组 nums &#xff0c;请你从中删除一个含有 若干不同元素 的子数组。 删除子数组的 得分 就是子数组各元素之 和 。 返回 只删除一个 子数组可获得的 最大得分 。 如果数组 b 是数组 a 的一个连续子序列&#xff0c;即如果它…

大型网站系统与Java中间件实践

大型网站系统与Java中间件实践&#xff08;贯通分布式高并发高数据高访问量网站架构与实现之权威著作&#xff0c;九大一线互联网公司CTO联合推荐&#xff09; 曾宪杰 著 ISBN 978-7-121-22761-5 2014年4月出版 定价&#xff1a;65.00元 340页 16开 编辑推荐 到底是本什么书…

LeetCode 1696. 跳跃游戏 VI(优先队列 / 单调队列)

文章目录1. 题目2. 解题2.1 贪心错误解2.2 优先队列/单调队列1. 题目 给你一个下标从 0 开始的整数数组 nums 和一个整数 k 。 一开始你在下标 0 处。每一步&#xff0c;你最多可以往前跳 k 步&#xff0c;但你不能跳出数组的边界。 也就是说&#xff0c;你可以从下标 i 跳到…

LeetCode 1697. 检查边长度限制的路径是否存在(排序+并查集)

文章目录1. 题目2. 解题1. 题目 给你一个 n 个点组成的无向图边集 edgeList &#xff0c;其中 edgeList[i] [ui, vi, disi] 表示点 ui 和点 vi 之间有一条长度为 disi 的边。请注意&#xff0c;两个点之间可能有 超过一条边 。 给你一个查询数组queries &#xff0c;其中 qu…

限制RICHTEXTBOX的输入的范围

附件&#xff1a;http://files.cnblogs.com/xe2011/WindowsFormsApplication_LimitRichTextBoxInput.rarusing System;using System.Collections.Generic;using System.ComponentModel;using System.Data;using System.Drawing;using System.Linq;using System.Text;using Syst…

NLP项目工作流程

文章目录1. 谷歌Colab设置2. 编写代码3. flask 微服务4. 打包到容器5. 容器托管参考 基于深度学习的自然语言处理使用这篇文章的数据(情感分类)进行学习。 1. 谷歌Colab设置 Colab 地址 新建笔记本 设置 选择 GPU/TPU 加速计算 测试 GPU 是否分配 import tensorflow…

牛客 牛牛浇树(差分)

文章目录1. 题目2. 解题1. 题目 链接&#xff1a;https://ac.nowcoder.com/acm/contest/10323/A 来源&#xff1a;牛客网 牛牛现在在花园养了n棵树&#xff0c;按顺序从第1棵到第n棵排列着。 牛牛每天会按照心情给其中某一个区间的树浇水。 例如如果某一天浇水的区间为[2,4]&…

再议 语法高亮插件的选择

之前一篇《为博客园选择一个小巧霸气的语法高亮插件》介绍了语法高亮插件的选择&#xff0c;当时只注重速度了。这些天在做深度定制的时候发现一个严重的问题&#xff0c;匹配精度不够。 什么是匹配精度呢&#xff1f;简单说就是没有把代码分块&#xff0c;是否分的足够细&…