compass实现搜索、订单载入功能、velocity模版静态化、OSCache优化性能、SSI实现
2012-08-07 15:19
513 查看
一、compass实现搜索
1、配置
1.1、加入如下jar包。
1.2、将compass与spring集成,让compass使用spring的事务,配置文件如下:
bean.xml文件中加入如下内容
Article实体内容如下
建立ArticleSearchServiceBean.java
建立ArticleResultCallback.java
ArticleSearchAction内加入如下内容
二、订单载入(锁定,防止多人同时操作)
order实体内加入
/* 锁定该订单的员工,如果该值不为null,即订单被锁定 */
private String employee;
OrderServiceBean内加入
action内加入
jsp内判断
三、Velocity 模版静态化
1、Velocity配置
如下代码加入到系统初始化代码块中
引入Velocity1.6 jar 包
2、实例
WebRoot-WEB-INF-VM目录下建立mailContent.vm
文件内容如下
三、Velocity脚本语法摘要
1. 变量
(1)变量的定义:
#set($name = "hello") 说明:velocity中变量是弱类型的。
当使用#set 指令时,括在双引号中的字面字符串将解析和重新解释,如下所示:
#set($directoryRoot = "www" )
#set($templateName = "index.vm" )
#set($template = "$directoryRoot/$templateName" )
$template
输出将会是:www/index.vm
注:在velocity中使用$2.5这样的货币标识是没有问题得的,因为velocity中的变量总是以一个大写或者小写的字母开始的。
(2)变量规范的写法
${name} ,也可以写成:$name。提倡用前面的写法。
例如:你希望通过一个变量$vice来动态的组织一个字符串。
Jack is a $vicemaniac.
本来变量是$vice现在却变成了$vicemaniac,这样Veloctiy就不知道您到底要什么了。所以,应该使用规范的格式书写 : Jack is a ${vice}maniac
现在Velocity知道变量是$vice而不是$vicemaniac。
注意:当引用属性的时候不能加{}
(3)变量的赋值:
$name="hello"
赋值的左边必须是一个变量或者是属性引用。右边可以是下面六种类型之一:
变量引用,字面字符串,属性引用,方法引用,字面数字,数组列表。
下面的例子演示了上述的每种类型:
#set( $monkey = $bill ) ## variable reference
#set( $monkey.Friend = "monica" ) ## string
#set( $monkey.Blame = $whitehouse.Leak ) ## property reference
#set( $monkey.Plan = $spindoctor.weave($web) ) ## method reference
#set( $monkey.Number = 123 ) ##number
#set( $monkey.Say = ["Not", $my, "fault"] ) ## ArrayList
注意:①如果上述例子中的右值是null, 则左值不会被赋值,也就是说会保留以前的值。
②velocity模板中未被定义的变量将被认为是一个字符串。例如:
#set($foo = "gibbous")
$moon = $foo
输出结果为:
$moon = gibbous
③velocity模板中不会将reference解释为对象的实例变量。例如:$foo.Name将被解释为Foo对象的getName()方法,而不是Foo对象的Name实例变量。例如:
$foo.getBar() 等同于$foo.Bar ;
$data.getUser("jon") 等同于$data.User("jon") ;
data.getRequest().getServerName() 等同于
$data.Request.ServerName等同于${data.Request.ServerName}
2. 循环
#foreach ($element in $list)
This is $element.
$velocityCount
#end
例子:
#set( $list = ["pine", "oak", "maple"])
#foreach ($element in $list)
$velocityCount
This is $element.<br>
#end
输出的结果为:
1 This is pine.
2 This is oak.
3 This is maple.
每次循环$list中的一个值都会赋给$element变量。
$list可以是一个Vector、Hashtable或者Array。分配给$element的值是一个java对象,并且可以通过变量被引用。例如:如果$element t是一个java的Product类,并且这个产品的名字可以通过调用他的getName()方法得到。
#foreach ( $key in $list.keySet())
Key: $key -> Value: $list.get($key) <br>
#end
提示:velocity中大小写敏感。
Velocity还特别提供了得到循环次数的方法,$velocityCount变量的名字是Velocity默认的名字。
例子:
First example:
#foreach ( $foo in [1..5] )
$foo
#end
Second example:
#foreach ( $bar in [2..-2] )
$bar
#end
Third example:
#set ( $arr = [0..1] )
#foreach ( $i in $arr )
$i
#end
上面三个例子的输出结果为:
First example:
1 2 3 4 5
Second example:
2 1 0 -1 -2
Third example:
0 1
3. 条件语句
#if (condition)
#elseif (condition)
#else
#end
4. 语句的嵌套
#foreach ($element in $list)
## inner foreach 内循环
#foreach ($element in $list)
This is $element. $velocityCount <br>inner<br>
#end
## inner foreach 内循环结束
## outer foreach
This is $element.
$velocityCount <br>outer<br>
#end
语句中也可以嵌套其他的语句,如#if…#else…#end等。
5. 注释
(1)单行注释:
## This is a single line comment.
(2)多行注释:
#*
Thus begins a multi-line comment. Online visitors won’t
see this text because the Velocity Templating Engine will
ignore it.
*#
(3)文档格式:
#**
This is a VTL comment block and
may be used to store such information
as the document author and versioning
information:
@version 1.1
@author xiao
*#
6. 关系和逻辑操作符
Velocity 也具有逻辑AND, OR 和 NOT 操作符。
如
## example for AND
#if($foo && $bar)
<strong> This AND that</strong>
#end
例子中#if() 指令仅在$foo 和$bar 斗为真的时候才为真。如果$foo 为假,则表达式也为假;并且 $bar 将不被求值。如果 $foo 为真,Velocity 模板引擎将继续检查$bar的值,如果 $bar 为真,则整个表达式为真。并且输出This AND that 。如果 $bar 为假,将没有输出因为整个表达式为假。
7.Velocity 中的宏
Velocity中的宏我们可以理解为函数。
①宏的定义
#macro(宏的名称 $参数1 $参数2 …)
语句体(即函数体)
#end
②宏的调用
#宏的名称($参数1 $参数2 …)
说明:参数之间用空格隔开。
8.#stop
停止执行模板引擎并返回,把它应用于debug是很有帮助的。
9.#include与#parse
#include和#parse的作用都是引入本地文件, 为了安全的原因,被引入的本地文件只能在TEMPLATE_ROOT目录下。
区别:
(1) 与#include不同的是,#parse只能指定单个对象。而#include可以有多个
如果您需要引入多个文件,可以用逗号分隔就行:
#include ("one.gif", "two.txt", "three.htm" )
在括号内可以是文件名,但是更多的时候是使用变量的:
#include ( “greetings.txt”, $seasonalstock )
(2) #include被引入文件的内容将不会通过模板引擎解析;
而#parse引入的文件内容Velocity将解析其中的velocity语法并移交给模板,意思就是说相当与把引入的文件copy到文件中。
#parse是可以递归调用的,例如:如果dofoo.vm包含如下行:
Count down.<br>
#set ($count = 8)
#parse ("parsefoo.vm")
<br>All done with dofoo.vm!
那么在parsefoo.vm模板中,你可以包含如下VTL:
$count
#set($count = $count - 1)
#if ( $count > 0 )<br>
#parse( "parsefoo.vm" )
#else
<br>All done with parsefoo.vm!
#end的显示结果为:
Count down.
8
7
6
5
4
3
2
1
0
All done with parsefoo.vm!
All done with dofoo.vm!
注意:在vm中使用#parse来嵌套另外一个vm时的变量共享问题。如:
->a.vm 里嵌套 b.vm;
->a.vm 里定义了变量 $param;
->b.vm 里可以直接使用$param,无任何限制。
但需要特别注意的是,如果b.vm里同时定义有变量$param,则b.vm里将使用b.vm里定义的值。
10.转义字符'\'的使用
如果reference被定义,两个’\’意味着输出一个’\’,如果未被定义,刚按原样输出。如:
#set($email = "foo" )
$email
\$email
\\$email
\\\$email
输出:
foo
$email
\foo
\$email
如果$email 未定义
$email
\$email
\\$email
\\\$email
输出:
$email
\$email
\\$email
\\$email
11.内置对象
Velocity内置了一些对象,在vm模版里可以直接调用,列举如下:
$request、$response、$session,另外,模板内还可以使用 $msg内的消息工具访问 Struts 的国际化资源,达到简便实现国际化的方法。
12. 数组访问
对数组的访问在Velocity中存在问题,因为Velocity只能访问对象的方法,而数组又是一个特殊的Array,所以虽然数组可以进行循环列举,但却不能定位访问特定位置的元素,如 strs[2],数组对固定位置元素的访问调用了Array的反射方法get(Object array, int index),而Velocity没能提供这样的访问,所以数组要么改成List等其他类容器的方式来包装,要么就通过公用Util类的方式来提供,传入数组对象和要访问的位置参数,从而达到返回所需值的目的。
四、OSCache缓存
1、hibernate与OSCache对比
hibernate 二级缓存仅仅针对实体进行缓存。
oscache 针对整体或者局部进行缓存。速度更快,更全面。
http://java.net/downloads/oscache/ 下载路径
2、配置
第一步:把上述两个jar文件放置在WEB-INF/lib目录下.
第二步:把oscache安装目录下的/etc/oscache.properties 文件放入 /WEB-INF/classes目录.开发阶段,我们可以把该文件放置在src目录.
下载路径:http://www.opensymphony.com/oscache/
oscache.jar
\lib\commons-logging.jar
3、实例
使用OSCache作页面局部缓存
我们使用Oscache的标签<oscache></oscache>来进行页面的局部缓存.使用方法如下:
<%@taglib uri="http://www.opensymphony.com/oscache" prefix=“oscache"%>
<oscache:cache>
<%=new Date() %>
</oscache:cache>
缓存的key将以请求的URI+查询字串组成,如果你访问/oscache/index.jsp?name=ttt和/oscache/index.jsp?name=ppp将得到两份缓存。缓存默认存放在application范围,缓存时间默认为3600秒,即1小时.
<oscache:cache key=“name”>
name=${param.name}
</oscache:cache>
这时候缓存将以name为key,不再是请求的URI+查询字串组成,所以如果你访问/oscache/index.jsp?name=ttt和/oscache/index.jsp?name=ppp将得到一份缓存。
<oscache:cache key="name" scope="session">
name=${param.name}
</oscache:cache>
缓存范围设置为session,这时候缓存保存在用户的session中,如果用户的把浏览器关闭,再重新打开一个新浏览器,原来缓存的内容将不存在。
<oscache:cache key="name" time="10">
name=${param.name}
</oscache:cache>
上面设置了缓存的时间为10秒,超过10秒后,缓存的内容将失掉。
<oscache:cache key="name" time="60" refresh="${param.refresh}">
name=${param.name}
</oscache:cache>
refresh为true将会导致缓存的内容过期而被清除,简单地说,该属性为true用于清除缓存。
人为管理缓存<flush />标签:
<oscache:flush scope="application" />
清除application范围内的所有缓存
<oscache:flush scope="session" key="foobar" />
清除session范围内的key为foobar的缓存。
<oscache:flush scope="application" group="currencyData" />
清除application范围内组名为currencyData内的所有缓存。
在局部缓存,显示动态人名的时候。可以这么做。
你好<SCRIPT Languge=JavaScript src="welcome.js"></SCRIPT>,欢迎访问。
welcome.js代码如下。
使用OSCache作页面全局缓存
页面全局缓存将使用Filter实现:
这个filter应该放在最上面,这样才会第一个通过它,如果存在缓存,就不需要访问后面,直接返回
缓存的key将以请求的URI+查询字串组成,如果你访问/oscache/index.jsp?name=ttt和/oscache/index.jsp?name=ppp将得到两份缓存。缓存是在初次访问页面时进行的,后续的请求将会返回缓存中的内容。缓存中存放的内容为页面返回给用户的html源代码。
oscache.properties文件设置如下:
cache.memory=true
指定是否使用内存缓存,默认值为true,即使用内存缓存。
cache.capacity
指定缓存的容量,默认的容量是无限的。我们可以为它设置缓存数量,如:
cache.capacity=100000
如果我们要使用硬盘缓存,可以这样设置:
cache.memory=false
cache.path=d:\\cache (指定,缓存保存的路径,注意:路径应采用双\符)
cache.persistence.class=com.opensymphony.oscache.plugins.diskpersistence.DiskPersistenceListener
cache.persistence.class用于设置持久化类。
五、SSI技术
1、SSI技术说明
<!--#include virtual="/global/foot.jsp"-->
类似jsp中<jsp:include page="/global/foot.jsp"/>
1.1、SSI技术不受运行环境影像,在java,dotnet,cgi等都可以ssi技术。
1.2、sii效率比jsp效率快。
2、SSI技术配置
tomcat 下使用ssi
1、把server/lib/servlets-ssi.renametojar的名称改名为servlets-ssi.jar (tomcat5.5有此步骤,tomcat6则没有此步骤)
2、设置conf/context.xml文件,在<Context>节点添加privileged="true"
3、在conf/web.xml中开启ssi,tomcat提供了两种开启ssi方式。一种是servlet,另一种是filter.
这里我们使用Servlet开启ssi。在web.xml中找到<servlet-name>ssi</servlet-name>,把对该Servlet的注释去掉。
使用SSI filter的话删除在SSI filter和filter-mapping周围的注释
然后根据shtml文件的编码格式指定inputEncoding和outputEncoding属性值。
<servlet>
<servlet-name>ssi</servlet-name>
<servlet-class>org.apache.catalina.ssi.SSIServlet</servlet-class>
这里省略了一些代码
<init-param>
<param-name>inputEncoding</param-name>
<param-value>UTF-8</param-value>
</init-param>
<init-param>
<param-name>outputEncoding</param-name>
<param-value>UTF-8</param-value>
</init-param>
<load-on-startup>4</load-on-startup>
</servlet>
当打开了上面servlet的注释之后,我们别忘了也要<servlet-mapping>的注释去掉,如:
<servlet-mapping>
<servlet-name>ssi</servlet-name>
<url-pattern>*.shtml</url-pattern>
</servlet-mapping>
3、SSI范例
3.1、include示范
<!--#include virtual="/global/foot.jsp"-->
<!--#include file="foot.jsp"-->
参数:
file 指定包含文件相对于本文档的位置
virtual 指定相对于服务器文档根目录的位置 如 /global/foot.html 表示
注意:文件名称必须带有扩展名。
示例:
<!--#flastmod file="foot.html"-->将当前目录下foot.html文件的最近更新日期插入到当前页面
<!--#fsize file="foot.html"-->将当前目录下news.html的文件大小入到当前页面
main.shtml内容
head.jsp内容:
<%@ page language="java" pageEncoding="UTF-8"%>
这是头部
foot.html内容:
这是尾部
3.2、SSI指令-- #flastmod 和 #fsize
#flastmod 和 #fsize 示范
作用:
#flastmod 文件最近更新日期
#fsize 文件的长度
语法:
<!--#flastmod file="文件名称"-->
<!--#fsize file="文件名称"-->
3.3、SSI指令-- #echo
#echo 示范
作用:将环境变量插入到页面中。
语法:
<!--#echo var="变量名称"-->
示例:
本文档名称:<!--#echo var="DOCUMENT_NAME"--> <br>
你的IP地址:<!--#echo var="REMOTE_ADDR"--> <br>
显示当前文档的虚拟路径:<!--#echo var="DOCUMENT_URI" -->
QUERY_STRING_UNESCAPED:显示未经转义处理的由客户端发送的查询字串,其中所有的特殊字符前面都有转义符"\"。
例如:<!--#echo var="QUERY_STRING_UNESCAPED" -->
请求完整路径为: <!--#echo var="DOCUMENT_URI" -->?<!--#echo var="QUERY_STRING_UNESCAPED" -->
<!--#config timefmt=“%Y-%m-%d %a %H:%M:%S”--> %a表示星期几 ,这句是格式化下面输出的时间格式
现在时间:<!--#echo var="DATE_LOCAL"--> <br>
echo命令还可以显示以下环境变量:
SERVER_SOFTWARE:显示服务器软件的名称和版本。例如:
<!--#echo var="SERVER_SOFTWARE" --><br>
SERVER_NAME: 显示服务器的主机名称,DNS别名或IP地址。例如:
<!--#echo var="SERVER_NAME" --><br>
SERVER_PROTOCOL:显示客户端请求所使用的协议名称和版本,如HTTP/1.0。例如:
<!--#echo var="SERVER_PROTOCOL" --><br>
SERVER_PORT:显示服务器的响应端口。例如:
<!--#echo var="SERVER_PORT" --><br>
REQUEST_METHOD:显示客户端的文档请求方法,包括GET, HEAD, 和POST。例如:
<!--#echo var="REQUEST_METHOD" --><br>
REMOTE_HOST:显示发出请求信息的客户端主机名称。
<!--#echo var="REMOTE_HOST" --><br>
REMOTE_ADDR:显示发出请求信息的客户端IP地址。
<!--#echo var="REMOTE_ADDR" --><br>
AUTH_TYPE:显示用户身份的验证方法。
<!--#echo var="AUTH_TYPE" --><br>
REMOTE_USER:显示访问受保护页面的用户所使用的帐号名称。
<!--#echo var="REMOTE_USER" -->
3.4、SSI指令-- #set指令
#set
作用:可给变量赋值,以用于后面的if语句。
语法:
<!--#set var="变量名" value="变量值"-->
示例:
<!--#set var=“varname" value=“lihuoming"-->
3.5、SSI指令-- #if指令
#if
作用:创建可以改变数据的页面,这些数据根据使用if语句时计算的要求予以显示。
语法:
<!--#if expr="$变量名=\"变量值A\""-->
显示内容
<!--#elif expr="$变量名=\"变量值B\""-->
显示内容
<!--#else-->
显示内容
<!--#endif"-->
示例:
<!--#set var="varname" value="b"-->
<!--#if expr="$varname=\"a\""-->
A。
<!--#elif expr="$varname=\"b\"" -->
B。
<!--#else-->
other
<!--#endif"-->
注意:用于前面指令中的反斜杠,是用来代换内部的引号,以便它们不会被解释为结束表达式。不可省略。
一般来说ssi大多使用include指令。
1、配置
1.1、加入如下jar包。
1.2、将compass与spring集成,让compass使用spring的事务,配置文件如下:
bean.xml文件中加入如下内容
<bean id="compass" class="org.compass.spring.LocalCompassBean"> <!-- 指定映射类方式 --> <property name="classMappings"> <list> <value>com.nbchina.bean.article.Article</value> <value>com.nbchina.bean.article.ArticleClass</value> </list> </property> <property name="compassSettings"> <props> <prop key="compass.engine.connection">file://e:/index</prop> <prop key="compass.engine.highlighter.default.formatter.simple.pre"><![CDATA[<font color='red'>]]></prop> <prop key="compass.engine.highlighter.default.formatter.simple.post"><![CDATA[</font>]]></prop> <prop key="compass.transaction.factory">org.compass.spring.transaction.SpringSyncTransactionFactory</prop> </props> </property> <property name="transactionManager" ref="transactionManager" /> </bean> <!-- CompassGps为CompassGpsDevice提供Compass对象,他们一起为程序提供索引的实时更新 --> <bean id="compassGps" class="org.compass.gps.impl.SingleCompassGps" init-method="start" destroy-method="stop"> <property name="compass" ref="compass" /> <property name="gpsDevices"> <list> <bean class="org.compass.spring.device.SpringSyncTransactionGpsDeviceWrapper"> <property name="gpsDevice"> <!-- 为gpsDevice属性注入针对JPA的GPS驱动 --> <bean class="org.compass.gps.device.jpa.JpaGpsDevice"> <property name="name" value="jpaDevice" /> <property name="entityManagerFactory" ref="entityManagerFactory" /> <property name="injectEntityLifecycleListener" value="true"/> </bean> </property> </bean> </list> </property> </bean>
Article实体内容如下
@Entity @Searchable //通过这个注解,指明该类跟lucene中的document映射 public class Article { @Id @GeneratedValue(strategy=GenerationType.AUTO) @SearchableId private Integer id; @ManyToOne(cascade=CascadeType.REFRESH,optional=false) @JoinColumn(name="acid") @SearchableComponent private ArticleClass ac; //@SearchableComponent代表还要跟其他类关联 //boost=2数字越大级别越高,代表标题检索到的排序在前。默认为1. //index=Index.NO代表不参与索引 //store=Store.YES代表储存 //name="titleName" 有些字段和关联的其他表字段相同,那么可以重命名。 @Column(length=80,nullable=false) @SearchableProperty(boost=2,store=Store.YES, name="titleName") private String title; @Column(length=255) private String titleIntact; @Column(length=10) private String titleFontColor; @Column(length=255) private String linkURL; @Column(length=255) private String keyword; @Column(length=255) @SearchableProperty(index=Index.NO,store=Store.YES) private String intro; @Column(nullable=false) private Integer hits = 1; @Temporal(TemporalType.DATE) @Column(nullable=false) @SearchableProperty(index=Index.NO,store=Store.YES,format="yyyy-MM-dd") private Date updateTime = new Date(); @Column(nullable=false) private Boolean onTop = false; @Column(nullable=false) private Boolean elite = false; @Column(nullable=false) private Boolean hot = false; @Column(nullable=false) private Integer status = 0; @Column(nullable=false) private Integer deleted = 0; @Column(length=80) private String editor = "admin"; @Column(length=80) private String author = "佚名"; @Column(length=80) private String copyFrom; @Lob @Column(nullable=false) @SearchableProperty(store=Store.YES) private String content; @Column(nullable=true) private Integer includeImage = 0; @Lob private String uploadFiles; @Column(length=255) private String includeImageURL; @Column(length=255) private String voiceURL; }
@Entity @Searchable(root=false) public class ArticleClass implements Serializable{ //@Searchable(root=false)代表不是搜索的根类,是Article的配角,关联的类而已。 @Id @GeneratedValue(strategy=GenerationType.AUTO) @SearchableProperty(index=Index.NO, store=Store.YES) private Integer id; @Column(length=36,nullable=false) @SearchableProperty(index=Index.NO, store=Store.YES) private String name; @Column(length=200) private String note; @Column(nullable=false) private Boolean visible=true; @Column(nullable=false) private Integer orderId=0; @Column(length=255) private String imageURL; @Column(length=10) private String level; @OneToMany(cascade={CascadeType.REFRESH,CascadeType.REMOVE},mappedBy="parent") private Set<ArticleClass> childs = new HashSet<ArticleClass>(); @ManyToOne(cascade=CascadeType.REFRESH) @JoinColumn(name="parentid") private ArticleClass parent; @OneToMany(mappedBy="ac", cascade=CascadeType.REMOVE) @SearchableReference //表示引用article private Set<Article> articles = new HashSet<Article>(); }
建立ArticleSearchServiceBean.java
@Service @Transactional public class ArticleSearchServiceBean extends CompassDaoSupport implements ArticleSearchService { @Resource public void setSessionFactory(Compass compass){ super.setCompass(compass); } public QueryResult<Article> search(String key, int startIndex, int maxResult) { return this.getCompassTemplate().execute(new ArticleResultCallback(key, startIndex, maxResult)); } }
建立ArticleResultCallback.java
public class ArticleResultCallback implements CompassCallback<QueryResult<Article>> { private String key; private int startIndex; private int maxResult; public ProductResultCallback(String key, int startIndex, int maxResult) { this.key = key; this.startIndex = startIndex; this.maxResult = maxResult; } public QueryResult<Article> doInCompass(CompassSession session) throws CompassException { List<Article> articles = new ArrayList<Article>(); CompassHits hits = session.find(key); int lastIndex = startIndex + maxResult - 1; if(lastIndex>(hits.length()-1)) lastIndex = hits.length()-1; for(int i=startIndex; i<=lastIndex; i++){ Article article = (Article) hits.data(i); if(hits.highlighter(i).fragment("title")!=null){//处理高亮显示 article.setTitle(hits.highlighter(i).fragment("title")); } articles.add(article); } QueryResult<Article> qr = new QueryResult<Article>(); qr.setResultlist(articles); qr.setTotalrecord(hits.length());//设置查询到的总记录数 return qr; } }
ArticleSearchAction内加入如下内容
QueryResult<Article> qr = articleSearchService.search("关键字", pageView.getFirstResult(), pageView.getMaxresult()); pageView.setQueryResult(qr);
二、订单载入(锁定,防止多人同时操作)
order实体内加入
/* 锁定该订单的员工,如果该值不为null,即订单被锁定 */
private String employee;
OrderServiceBean内加入
public Order getLockOrder(String orderid, String employee){ em.createQuery("update Order o set o.employee=?1 where o.orderid=?2 and o.employee is null") .setParameter(1, employee).setParameter(2, orderid).executeUpdate(); em.flush(); return this.find(orderid); } public void unLock(String orderid){ em.createQuery("update Order o set o.employee=?1 where o.orderid=?2") .setParameter(1, null).setParameter(2, orderid).executeUpdate(); }
action内加入
if(!order.getEmployee().equals(username)){ request.setAttribute("message", "该订单已被"+ order.getEmployee() + "锁定"); return mapping.findForward("message"); }
jsp内判断
<c:if test="${empty entry.employee || entry.employee==employee.username}"><a href="">载入订单</a></c:if> <c:if test="${!empty entry.employee && entry.employee!=employee.username}">被${entry.employee}锁定</c:if>
三、Velocity 模版静态化
1、Velocity配置
如下代码加入到系统初始化代码块中
try{ Properties prop = new Properties(); prop.put("runtime.log", config.getServletContext().getRealPath("/WEB-INF/Log/velocity.log")); prop.put("file.resource.loader.path", config.getServletContext().getRealPath("/WEB-INF/VM")); prop.put("input.encoding", "UTF-8"); prop.put("output.encoding", "UTF-8"); Velocity.init(prop); System.out.println("Velocity Initialized"); }catch( Exception e ){ System.out.println("VSelocity error"); e.printStackTrace(); }
引入Velocity1.6 jar 包
2、实例
WebRoot-WEB-INF-VM目录下建立mailContent.vm
文件内容如下
<html> <head> <title>测试</title> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> </head> 尊敬的客户:${userName} </body> </html>使用代码如下
Template template = Velocity.getTemplate("mailContent.vm","UTF-8"); VelocityContext context = new VelocityContext(); context.put("userName", "测试名"); StringWriter writer = new StringWriter(); template.merge(context, writer); writer.flush(); String mailContent = writer.toString(); EmailSender.send(entry.getEmail(), "测试", mailContent, "text/html");
三、Velocity脚本语法摘要
1. 变量
(1)变量的定义:
#set($name = "hello") 说明:velocity中变量是弱类型的。
当使用#set 指令时,括在双引号中的字面字符串将解析和重新解释,如下所示:
#set($directoryRoot = "www" )
#set($templateName = "index.vm" )
#set($template = "$directoryRoot/$templateName" )
$template
输出将会是:www/index.vm
注:在velocity中使用$2.5这样的货币标识是没有问题得的,因为velocity中的变量总是以一个大写或者小写的字母开始的。
(2)变量规范的写法
${name} ,也可以写成:$name。提倡用前面的写法。
例如:你希望通过一个变量$vice来动态的组织一个字符串。
Jack is a $vicemaniac.
本来变量是$vice现在却变成了$vicemaniac,这样Veloctiy就不知道您到底要什么了。所以,应该使用规范的格式书写 : Jack is a ${vice}maniac
现在Velocity知道变量是$vice而不是$vicemaniac。
注意:当引用属性的时候不能加{}
(3)变量的赋值:
$name="hello"
赋值的左边必须是一个变量或者是属性引用。右边可以是下面六种类型之一:
变量引用,字面字符串,属性引用,方法引用,字面数字,数组列表。
下面的例子演示了上述的每种类型:
#set( $monkey = $bill ) ## variable reference
#set( $monkey.Friend = "monica" ) ## string
#set( $monkey.Blame = $whitehouse.Leak ) ## property reference
#set( $monkey.Plan = $spindoctor.weave($web) ) ## method reference
#set( $monkey.Number = 123 ) ##number
#set( $monkey.Say = ["Not", $my, "fault"] ) ## ArrayList
注意:①如果上述例子中的右值是null, 则左值不会被赋值,也就是说会保留以前的值。
②velocity模板中未被定义的变量将被认为是一个字符串。例如:
#set($foo = "gibbous")
$moon = $foo
输出结果为:
$moon = gibbous
③velocity模板中不会将reference解释为对象的实例变量。例如:$foo.Name将被解释为Foo对象的getName()方法,而不是Foo对象的Name实例变量。例如:
$foo.getBar() 等同于$foo.Bar ;
$data.getUser("jon") 等同于$data.User("jon") ;
data.getRequest().getServerName() 等同于
$data.Request.ServerName等同于${data.Request.ServerName}
2. 循环
#foreach ($element in $list)
This is $element.
$velocityCount
#end
例子:
#set( $list = ["pine", "oak", "maple"])
#foreach ($element in $list)
$velocityCount
This is $element.<br>
#end
输出的结果为:
1 This is pine.
2 This is oak.
3 This is maple.
每次循环$list中的一个值都会赋给$element变量。
$list可以是一个Vector、Hashtable或者Array。分配给$element的值是一个java对象,并且可以通过变量被引用。例如:如果$element t是一个java的Product类,并且这个产品的名字可以通过调用他的getName()方法得到。
#foreach ( $key in $list.keySet())
Key: $key -> Value: $list.get($key) <br>
#end
提示:velocity中大小写敏感。
Velocity还特别提供了得到循环次数的方法,$velocityCount变量的名字是Velocity默认的名字。
例子:
First example:
#foreach ( $foo in [1..5] )
$foo
#end
Second example:
#foreach ( $bar in [2..-2] )
$bar
#end
Third example:
#set ( $arr = [0..1] )
#foreach ( $i in $arr )
$i
#end
上面三个例子的输出结果为:
First example:
1 2 3 4 5
Second example:
2 1 0 -1 -2
Third example:
0 1
3. 条件语句
#if (condition)
#elseif (condition)
#else
#end
4. 语句的嵌套
#foreach ($element in $list)
## inner foreach 内循环
#foreach ($element in $list)
This is $element. $velocityCount <br>inner<br>
#end
## inner foreach 内循环结束
## outer foreach
This is $element.
$velocityCount <br>outer<br>
#end
语句中也可以嵌套其他的语句,如#if…#else…#end等。
5. 注释
(1)单行注释:
## This is a single line comment.
(2)多行注释:
#*
Thus begins a multi-line comment. Online visitors won’t
see this text because the Velocity Templating Engine will
ignore it.
*#
(3)文档格式:
#**
This is a VTL comment block and
may be used to store such information
as the document author and versioning
information:
@version 1.1
@author xiao
*#
6. 关系和逻辑操作符
Velocity 也具有逻辑AND, OR 和 NOT 操作符。
如
## example for AND
#if($foo && $bar)
<strong> This AND that</strong>
#end
例子中#if() 指令仅在$foo 和$bar 斗为真的时候才为真。如果$foo 为假,则表达式也为假;并且 $bar 将不被求值。如果 $foo 为真,Velocity 模板引擎将继续检查$bar的值,如果 $bar 为真,则整个表达式为真。并且输出This AND that 。如果 $bar 为假,将没有输出因为整个表达式为假。
7.Velocity 中的宏
Velocity中的宏我们可以理解为函数。
①宏的定义
#macro(宏的名称 $参数1 $参数2 …)
语句体(即函数体)
#end
②宏的调用
#宏的名称($参数1 $参数2 …)
说明:参数之间用空格隔开。
8.#stop
停止执行模板引擎并返回,把它应用于debug是很有帮助的。
9.#include与#parse
#include和#parse的作用都是引入本地文件, 为了安全的原因,被引入的本地文件只能在TEMPLATE_ROOT目录下。
区别:
(1) 与#include不同的是,#parse只能指定单个对象。而#include可以有多个
如果您需要引入多个文件,可以用逗号分隔就行:
#include ("one.gif", "two.txt", "three.htm" )
在括号内可以是文件名,但是更多的时候是使用变量的:
#include ( “greetings.txt”, $seasonalstock )
(2) #include被引入文件的内容将不会通过模板引擎解析;
而#parse引入的文件内容Velocity将解析其中的velocity语法并移交给模板,意思就是说相当与把引入的文件copy到文件中。
#parse是可以递归调用的,例如:如果dofoo.vm包含如下行:
Count down.<br>
#set ($count = 8)
#parse ("parsefoo.vm")
<br>All done with dofoo.vm!
那么在parsefoo.vm模板中,你可以包含如下VTL:
$count
#set($count = $count - 1)
#if ( $count > 0 )<br>
#parse( "parsefoo.vm" )
#else
<br>All done with parsefoo.vm!
#end的显示结果为:
Count down.
8
7
6
5
4
3
2
1
0
All done with parsefoo.vm!
All done with dofoo.vm!
注意:在vm中使用#parse来嵌套另外一个vm时的变量共享问题。如:
->a.vm 里嵌套 b.vm;
->a.vm 里定义了变量 $param;
->b.vm 里可以直接使用$param,无任何限制。
但需要特别注意的是,如果b.vm里同时定义有变量$param,则b.vm里将使用b.vm里定义的值。
10.转义字符'\'的使用
如果reference被定义,两个’\’意味着输出一个’\’,如果未被定义,刚按原样输出。如:
#set($email = "foo" )
输出:
foo
\foo
如果$email 未定义
输出:
11.内置对象
Velocity内置了一些对象,在vm模版里可以直接调用,列举如下:
$request、$response、$session,另外,模板内还可以使用 $msg内的消息工具访问 Struts 的国际化资源,达到简便实现国际化的方法。
12. 数组访问
对数组的访问在Velocity中存在问题,因为Velocity只能访问对象的方法,而数组又是一个特殊的Array,所以虽然数组可以进行循环列举,但却不能定位访问特定位置的元素,如 strs[2],数组对固定位置元素的访问调用了Array的反射方法get(Object array, int index),而Velocity没能提供这样的访问,所以数组要么改成List等其他类容器的方式来包装,要么就通过公用Util类的方式来提供,传入数组对象和要访问的位置参数,从而达到返回所需值的目的。
四、OSCache缓存
1、hibernate与OSCache对比
hibernate 二级缓存仅仅针对实体进行缓存。
oscache 针对整体或者局部进行缓存。速度更快,更全面。
http://java.net/downloads/oscache/ 下载路径
2、配置
第一步:把上述两个jar文件放置在WEB-INF/lib目录下.
第二步:把oscache安装目录下的/etc/oscache.properties 文件放入 /WEB-INF/classes目录.开发阶段,我们可以把该文件放置在src目录.
下载路径:http://www.opensymphony.com/oscache/
oscache.jar
\lib\commons-logging.jar
3、实例
使用OSCache作页面局部缓存
我们使用Oscache的标签<oscache></oscache>来进行页面的局部缓存.使用方法如下:
<%@taglib uri="http://www.opensymphony.com/oscache" prefix=“oscache"%>
<oscache:cache>
<%=new Date() %>
</oscache:cache>
缓存的key将以请求的URI+查询字串组成,如果你访问/oscache/index.jsp?name=ttt和/oscache/index.jsp?name=ppp将得到两份缓存。缓存默认存放在application范围,缓存时间默认为3600秒,即1小时.
<oscache:cache key=“name”>
name=${param.name}
</oscache:cache>
这时候缓存将以name为key,不再是请求的URI+查询字串组成,所以如果你访问/oscache/index.jsp?name=ttt和/oscache/index.jsp?name=ppp将得到一份缓存。
<oscache:cache key="name" scope="session">
name=${param.name}
</oscache:cache>
缓存范围设置为session,这时候缓存保存在用户的session中,如果用户的把浏览器关闭,再重新打开一个新浏览器,原来缓存的内容将不存在。
<oscache:cache key="name" time="10">
name=${param.name}
</oscache:cache>
上面设置了缓存的时间为10秒,超过10秒后,缓存的内容将失掉。
<oscache:cache key="name" time="60" refresh="${param.refresh}">
name=${param.name}
</oscache:cache>
refresh为true将会导致缓存的内容过期而被清除,简单地说,该属性为true用于清除缓存。
人为管理缓存<flush />标签:
<oscache:flush scope="application" />
清除application范围内的所有缓存
<oscache:flush scope="session" key="foobar" />
清除session范围内的key为foobar的缓存。
<oscache:flush scope="application" group="currencyData" />
清除application范围内组名为currencyData内的所有缓存。
在局部缓存,显示动态人名的时候。可以这么做。
你好<SCRIPT Languge=JavaScript src="welcome.js"></SCRIPT>,欢迎访问。
welcome.js代码如下。
function readCookieByName(name){ var nameOfCookie = name + "="; var x = 0; while ( x <= document.cookie.length ){ var y = (x+nameOfCookie.length); if ( document.cookie.substring( x, y ) == nameOfCookie ) { if ( (endOfCookie=document.cookie.indexOf( ";", y )) == -1 ) endOfCookie = document.cookie.length; return document.cookie.substring( y, endOfCookie ); } x = document.cookie.indexOf( " ", x ) + 1; if ( x == 0 ) break; } return ""; } function readWelcomeMsg(){ try{ var msg = readCookieByName("realName"); if(msg!=""){ return decodeURI(msg); }else{ msg = readCookieByName("userName"); if(msg!="") return msg; } } catch(e){ ; } return ""; } document.write(readWelcomeMsg());
使用OSCache作页面全局缓存
页面全局缓存将使用Filter实现:
<filter> <filter-name>CacheFilter</filter-name> <filter-class>com.opensymphony.oscache.web.filter.CacheFilter</filter-class> <init-param> <param-name>time</param-name> <param-value>7200</param-value> </init-param> <init-param> <param-name>scope</param-name> <param-value>application</param-value> </init-param> </filter> <filter-mapping> <filter-name>CacheFilter</filter-name> <url-pattern>*.jsp</url-pattern> </filter-mapping>
这个filter应该放在最上面,这样才会第一个通过它,如果存在缓存,就不需要访问后面,直接返回
缓存的key将以请求的URI+查询字串组成,如果你访问/oscache/index.jsp?name=ttt和/oscache/index.jsp?name=ppp将得到两份缓存。缓存是在初次访问页面时进行的,后续的请求将会返回缓存中的内容。缓存中存放的内容为页面返回给用户的html源代码。
oscache.properties文件设置如下:
cache.memory=true
指定是否使用内存缓存,默认值为true,即使用内存缓存。
cache.capacity
指定缓存的容量,默认的容量是无限的。我们可以为它设置缓存数量,如:
cache.capacity=100000
如果我们要使用硬盘缓存,可以这样设置:
cache.memory=false
cache.path=d:\\cache (指定,缓存保存的路径,注意:路径应采用双\符)
cache.persistence.class=com.opensymphony.oscache.plugins.diskpersistence.DiskPersistenceListener
cache.persistence.class用于设置持久化类。
五、SSI技术
1、SSI技术说明
<!--#include virtual="/global/foot.jsp"-->
类似jsp中<jsp:include page="/global/foot.jsp"/>
1.1、SSI技术不受运行环境影像,在java,dotnet,cgi等都可以ssi技术。
1.2、sii效率比jsp效率快。
2、SSI技术配置
tomcat 下使用ssi
1、把server/lib/servlets-ssi.renametojar的名称改名为servlets-ssi.jar (tomcat5.5有此步骤,tomcat6则没有此步骤)
2、设置conf/context.xml文件,在<Context>节点添加privileged="true"
3、在conf/web.xml中开启ssi,tomcat提供了两种开启ssi方式。一种是servlet,另一种是filter.
这里我们使用Servlet开启ssi。在web.xml中找到<servlet-name>ssi</servlet-name>,把对该Servlet的注释去掉。
使用SSI filter的话删除在SSI filter和filter-mapping周围的注释
然后根据shtml文件的编码格式指定inputEncoding和outputEncoding属性值。
<servlet>
<servlet-name>ssi</servlet-name>
<servlet-class>org.apache.catalina.ssi.SSIServlet</servlet-class>
这里省略了一些代码
<init-param>
<param-name>inputEncoding</param-name>
<param-value>UTF-8</param-value>
</init-param>
<init-param>
<param-name>outputEncoding</param-name>
<param-value>UTF-8</param-value>
</init-param>
<load-on-startup>4</load-on-startup>
</servlet>
当打开了上面servlet的注释之后,我们别忘了也要<servlet-mapping>的注释去掉,如:
<servlet-mapping>
<servlet-name>ssi</servlet-name>
<url-pattern>*.shtml</url-pattern>
</servlet-mapping>
3、SSI范例
3.1、include示范
<!--#include virtual="/global/foot.jsp"-->
<!--#include file="foot.jsp"-->
参数:
file 指定包含文件相对于本文档的位置
virtual 指定相对于服务器文档根目录的位置 如 /global/foot.html 表示
注意:文件名称必须带有扩展名。
示例:
<!--#flastmod file="foot.html"-->将当前目录下foot.html文件的最近更新日期插入到当前页面
<!--#fsize file="foot.html"-->将当前目录下news.html的文件大小入到当前页面
main.shtml内容
<html xmlns="http://www.w3.org/1999/xhtml"><HEAD> <TITLE>测试</TITLE> <META http-equiv="Content-Type" content="text/html; charset=UTF-8"> </HEAD> <BODY> <!--#include file="head.jsp" --> <br>中部<br> <!--#include file="foot.html" --> </BODY></html>
head.jsp内容:
<%@ page language="java" pageEncoding="UTF-8"%>
这是头部
foot.html内容:
这是尾部
3.2、SSI指令-- #flastmod 和 #fsize
#flastmod 和 #fsize 示范
作用:
#flastmod 文件最近更新日期
#fsize 文件的长度
语法:
<!--#flastmod file="文件名称"-->
<!--#fsize file="文件名称"-->
3.3、SSI指令-- #echo
#echo 示范
作用:将环境变量插入到页面中。
语法:
<!--#echo var="变量名称"-->
示例:
本文档名称:<!--#echo var="DOCUMENT_NAME"--> <br>
你的IP地址:<!--#echo var="REMOTE_ADDR"--> <br>
显示当前文档的虚拟路径:<!--#echo var="DOCUMENT_URI" -->
QUERY_STRING_UNESCAPED:显示未经转义处理的由客户端发送的查询字串,其中所有的特殊字符前面都有转义符"\"。
例如:<!--#echo var="QUERY_STRING_UNESCAPED" -->
请求完整路径为: <!--#echo var="DOCUMENT_URI" -->?<!--#echo var="QUERY_STRING_UNESCAPED" -->
<!--#config timefmt=“%Y-%m-%d %a %H:%M:%S”--> %a表示星期几 ,这句是格式化下面输出的时间格式
现在时间:<!--#echo var="DATE_LOCAL"--> <br>
echo命令还可以显示以下环境变量:
SERVER_SOFTWARE:显示服务器软件的名称和版本。例如:
<!--#echo var="SERVER_SOFTWARE" --><br>
SERVER_NAME: 显示服务器的主机名称,DNS别名或IP地址。例如:
<!--#echo var="SERVER_NAME" --><br>
SERVER_PROTOCOL:显示客户端请求所使用的协议名称和版本,如HTTP/1.0。例如:
<!--#echo var="SERVER_PROTOCOL" --><br>
SERVER_PORT:显示服务器的响应端口。例如:
<!--#echo var="SERVER_PORT" --><br>
REQUEST_METHOD:显示客户端的文档请求方法,包括GET, HEAD, 和POST。例如:
<!--#echo var="REQUEST_METHOD" --><br>
REMOTE_HOST:显示发出请求信息的客户端主机名称。
<!--#echo var="REMOTE_HOST" --><br>
REMOTE_ADDR:显示发出请求信息的客户端IP地址。
<!--#echo var="REMOTE_ADDR" --><br>
AUTH_TYPE:显示用户身份的验证方法。
<!--#echo var="AUTH_TYPE" --><br>
REMOTE_USER:显示访问受保护页面的用户所使用的帐号名称。
<!--#echo var="REMOTE_USER" -->
3.4、SSI指令-- #set指令
#set
作用:可给变量赋值,以用于后面的if语句。
语法:
<!--#set var="变量名" value="变量值"-->
示例:
<!--#set var=“varname" value=“lihuoming"-->
3.5、SSI指令-- #if指令
#if
作用:创建可以改变数据的页面,这些数据根据使用if语句时计算的要求予以显示。
语法:
<!--#if expr="$变量名=\"变量值A\""-->
显示内容
<!--#elif expr="$变量名=\"变量值B\""-->
显示内容
<!--#else-->
显示内容
<!--#endif"-->
示例:
<!--#set var="varname" value="b"-->
<!--#if expr="$varname=\"a\""-->
A。
<!--#elif expr="$varname=\"b\"" -->
B。
<!--#else-->
other
<!--#endif"-->
注意:用于前面指令中的反斜杠,是用来代换内部的引号,以便它们不会被解释为结束表达式。不可省略。
一般来说ssi大多使用include指令。
相关文章推荐
- compass实现搜索、订单载入功能、velocity模版静态化、OSCache优化性能、SSI实现
- compass实现搜索、订单载入功能、velocity模版静态化、OSCache优化性能、SSI实现
- 网站性能优化,使用velocity实现页面静态化,实现实时更新静态页面
- 性能优化:用FreeMarker实现页面静态化
- 数据库性能优化的五种方案(mycat,基于阿里coba开源的数据库中间件,很容易实现分库分表、主从切换功能。另一个当当网开源的一个库 sharding-jdbc)
- SpringMVC(17):使用springmvc+spring+jdbc 优化订单管理系统的示例(新增用户的功能实现)
- SpringMVC(22):使用springmvc+spring+jdbc 优化订单管理系统的示例(ID修改供应商明细的功能实现)
- SpringMVC(24):使用springmvc+spring+jdbc 优化订单管理系统的示例(多文件上传功能的实现)
- 各种系统性能优化技术,采用vilocity实现商品页面静态化
- SpringMVC(16):使用springmvc+spring+jdbc 优化订单管理系统的示例(多条件查询供应商列表功能实现)
- With递归循环实现like功能(性能优化)
- SpringMVC(14):使用springmvc+spring+jdbc 优化订单管理系统的示例(多条件查询用户列表功能实现)
- 搜索功能优化,性能优化比较,dom,dom4j,json
- SpringMVC(18):使用springmvc+spring+jdbc 优化订单管理系统的示例(供应商新增的功能实现)
- SpringMVC(21):使用springmvc+spring+jdbc 优化订单管理系统的示例(ID查看供应商信息明细-REST的功能实现)
- Android 实现ListView的A-Z字母排序和过滤搜索功能,实现汉字转成拼音
- 在SQL Server 2005中用存储过程实现搜索功能
- 【微信开发笔记】常见的长按保存图片功能的实现方式及清晰度优化方式
- 静态页面用JS实现搜索功能
- 百度地图实现普通地图、定位、周边搜索功能