最近在springmvc上集成velocity,磕磕絆絆,總算是有所收穫,在此記錄一下。
Velocity是一種易用的模板語言。Velocity將Java代碼從Web 頁面中分離出來,使用Web站點從長遠看更容易維護,並且提供了一種可行的JavaServer Pages替代解決方案。除了JSP,Velocity可能是用於Web應用的最流行的模板語言之一。很多web系統也都採用Velocity作爲視圖層技術,Spring對Velocity作爲視圖模板語言提供了很好的支持。
怎麼配置,來,一步步走:
1、首先,在Web.xml進行配置,DispatcherServlet配置的映射爲所有請求類型,這樣以後如果要集成其他如Freemaker等只需要加入其配置就可以了。
<servlet> <servlet-name>springmvc</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <init-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:spring-mvc.xml</param-value> </init-param> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>springmvc</servlet-name> <url-pattern>/</url-pattern> </servlet-mapping>
2、配置spring-mvc.xml
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xmlns:mvc="http://www.springframework.org/schema/mvc" xsi:schemaLocation="http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.1.xsd http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd"> <!-- 自動掃描且只掃描@Controller --> <context:component-scan base-package="com.per.action" use-default-filters="false"> <context:include-filter type="annotation" expression="org.springframework.stereotype.Controller" /> </context:component-scan> <mvc:annotation-driven /> <mvc:default-servlet-handler /> <!-- 定義JSP視圖解析器--> <bean id="jspViewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <property name="prefix" value="/WEB-INF/views/" /> <property name="suffix" value=".jsp" /> <property name="contentType" value="text/html;charset=UTF-8" /> </bean> <!-- velocity視圖解析器 --> <!-- velocity環境配置 --> <bean id="velocityConfig" class="org.springframework.web.servlet.view.velocity.VelocityConfigurer"> <!-- velocity配置文件路徑 --> <property name="configLocation" value="classpath:velocity.properties"/> <!-- velocity模板路徑 --> <property name="resourceLoaderPath" value="/WEB-INF/velocity/"/> </bean> <bean id="velocityViewResolver" class="org.springframework.web.servlet.view.velocity.VelocityViewResolver"> <property name="cache" value="false"/> <property name="prefix" value=""/> <property name="suffix" value=".vm"/> <property name="contentType" value="text/html;charset=UTF-8" /> <!-- 多ViewResovler配置 --> <property name="order" value="1" /> </bean> </beans>
注意,“order”屬性是必須加的,爲什麼呢,可以查看我前一篇內容
SpringMVC ViewResolver查找序列
velocity.properties配置文件,位置要與spring-mvc.xml中配置的一樣。
#encoding input.encoding=UTF-8 output.encoding=UTF-8 contentType=text/html;charset=UTF-8 #autoreload when vm changed file.resource.loader.cache=false file.resource.loader.modificationCheckInterval=1 velocimacro.library.autoreload=true runtime.log=velocity.log #runtime.log.logsystem.class=org.springframework.ui.velocity.CommonsLoggingLogSystem runtime.log.logsystem.class=org.apache.velocity.runtime.log.NullLogSystem #runtime.log.logsystem.class=org.springframework.ui.velocity.NullLogSystem runtime.log.error.stacktrace=false runtime.log.warn.stacktrace=false runtime.log.info.stacktrace=false runtime.log.invalid.reference=false
當然這裏面的jspViewResover和velocityViewResover是可以單獨運行的,合併也是可以運行的,不過我集成時,運行一個JSP,頁面是正常的,但日誌總是會提示“[Error]Resource Not Found :xxxx.vm”,查了資料都說這個可以ignore,可是怎麼設置呢,這個很頭疼,試着去掉velocity.jar包中日誌配置也不行,可日誌不能老讓報error啊,求解!
當然還有方法,就是打開ResourceBundleViewResover這個配置,設置view.properties,在裏面加入視圖的路徑配置,這樣就不會報異常了,也是可以正常運行的。可是新的問題來了,一個是頁面會有亂碼,到我寫這篇文字的時候也沒能解決,高人指點下啊;另外一個是你的controller的每個view路徑都要在view.properties中配置,這也比較麻煩,畢竟一個項目那麼多view呢。
修改後,加入ResourceBundleViewResover配置:
<!-- ResourceBundleViewResolver用於多個視圖集成,是通過解析資源文件來解析請求輸出文件的。 <property name="basename" value="views"></property>,即表示在/WEB-INF/classes路徑下有一個 views.properties文件 --> <bean class="org.springframework.web.servlet.view.ResourceBundleViewResolver"> <property name="basename" value="views"/> <property name="order" value="0" /> </bean> <!-- 定義JSP視圖解析器--> <bean id="jspViewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <property name="prefix" value="/WEB-INF/views/" /> <property name="suffix" value=".jsp" /> <property name="contentType" value="text/html;charset=UTF-8" /> </bean> <!-- velocity視圖解析器 --> <!-- velocity環境配置 --> <bean id="velocityConfig" class="org.springframework.web.servlet.view.velocity.VelocityConfigurer"> <!-- velocity配置文件路徑 --> <property name="configLocation" value="classpath:velocity.properties"/> <!-- velocity模板路徑 --> <property name="resourceLoaderPath" value="/WEB-INF/velocity/"/> </bean> <bean id="velocityViewResolver" class="org.springframework.web.servlet.view.velocity.VelocityViewResolver"> <property name="cache" value="false"/> <property name="prefix" value=""/> <property name="suffix" value=".vm"/> <property name="contentType" value="text/html;charset=UTF-8" /> <!-- 多ViewResovler配置 <property name="order" value="1" /> --> </bean>
view.properties配置文件
#welcome爲modelAndView.setViewName("welcome");中的welcome .(class)固定寫法 welcome.(class)=org.springframework.web.servlet.view.velocity.VelocityView #welcome.url 路徑 welcome.vm模板名稱 welcome.url=welcome.vm #IndexController路徑 velocity_main.(class)=org.springframework.web.servlet.view.velocity.VelocityView velocity_main.url=velocity_main.vm
無奈,看來,只有自己寫個ViewResover來處理多視圖了,google了一下,還真有人也是這麼做的,看來不只是我一個人這麼想啊,手懶了些,直接抄了http://blog.csdn.net/rommel1/article/details/7673325的代碼,好了,來看看配置吧:
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd "> <context:component-scan base-package="com.spring.action"/> <!-- org.springframework.web.servlet.view.ResourceBundleViewResolver 用於多個視圖集成時,ResourceBundleViewResolver是通過解析資源文件來解析請求輸出文件的。 <property name="basename" value="views"></property>,即表示在/WEB-INF/classes路徑下有一個 views.properties文件,本例中views.properties的內容爲 welcome.(class)=org.springframework.web.servlet.view.velocity.VelocityView welcome.url=welcome.vm freemarker.(class)=org.springframework.web.servlet.view.freemarker.FreeMarkerView freemarker.url=freemarker.ftl --> <bean class="org.springframework.web.servlet.view.ResourceBundleViewResolver"> <property name="basename" value="views"> </property> <!-- <property name="order" value="0"></property> --> </bean> <!-- FreeMarker環境配置 --> <bean id="freemarkerConfig" class="org.springframework.web.servlet.view.freemarker.FreeMarkerConfigurer"> <!-- freemarker模板位置 --> <property name="templateLoaderPath" value="/WEB-INF/freemarker/"/> </bean> <!-- velocity環境配置 --> <bean id="velocityConfig" class="org.springframework.web.servlet.view.velocity.VelocityConfigurer"> <!-- velocity配置文件路徑 --> <property name="configLocation" value="/WEB-INF/velocity.properties"/> <!-- velocity模板路徑 --> <property name="resourceLoaderPath" value="/WEB-INF/velocity/"/> </bean> <bean id="viewResolver" class="com.spring.action.MultiViewResover"> <property name="resolvers"> <map> <entry key="jsp"> <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <property name="viewClass" value="org.springframework.web.servlet.view.JstlView"/> <property name="prefix" value="/WEB-INF/jsp/"/> <property name="suffix" value=".jsp"/> </bean> </entry> <entry key="ftl"> <bean class="org.springframework.web.servlet.view.freemarker.FreeMarkerViewResolver"> <property name="cache" value="true"/> <property name="prefix" value="/"/> <property name="suffix" value=".ftl"/> </bean> </entry> <entry key="vm"> <bean class="org.springframework.web.servlet.view.velocity.VelocityViewResolver"> <property name="cache" value="true"/> <property name="prefix" value="/"/> <property name="suffix" value=".vm"/> </bean> </entry> </map> </property> </bean> </beans>
MultiViewResover代碼,這裏我默認的是使用jsp視圖解析,如果你沒有默認的可以去掉
public class MultiViewResover implements ViewResolver {
private Map<String, ViewResolver> resolvers;
@Override
public View resolveViewName(String viewName, Locale locale) throws Exception {
int n = viewName.lastIndexOf("."); // 獲取
// viewName(modelAndView中的名字)看其有沒有下劃線
String suffix = "";
// 沒有默認使用“jsp“方式 解析,有的話截取下劃線後面的字符串 這裏一般是jsp,ftl,vm與配置文件中的<entry
// key="ftl">的key匹配
if (n == (-1)) {
suffix = "jsp";
}
else {
suffix = viewName.substring(n + 1);
// 取下劃線前面的部分 那時真正的資源名.比如我們要使用hello.jsp 那viewName就應該是hello_jsp
viewName = viewName.substring(0, n);
}
// 根據下劃線後面的字符串去獲取託管的視圖解析類對象
ViewResolver resolver = resolvers.get(suffix);
if (resolver != null) {
return resolver.resolveViewName(viewName, locale);
}
else {
return null;
}
}
public Map<String, ViewResolver> getResolvers() {
return resolvers;
}
public void setResolvers(Map<String, ViewResolver> resolvers) {
this.resolvers = resolvers;
}
}
好了,第二步這個配置總算完成了,真累 啊,繼續看下面。
3、編寫controller代碼,注意,你的view名字中,要加上".vm",".jsp",".ftl"這些後綴哦,要不默認都使用jsp的解析器了
@Controller
public class IndexController{
@RequestMapping(value="/index")
public ModelAndView handleRequest(HttpServletRequest request,
HttpServletResponse response) throws Exception {
ModelAndView mav = new ModelAndView("velocity_main.vm");
Person p1 = new Person();
p1.setId(1);
p1.setName("胡楠");
p1.setPassword("123456");
p1.setAge(24);
p1.setBirthday(new Date());
List<Person> list = new ArrayList<Person>();
for(int i=0;i<10;i++){
Person p = new Person();
p.setId(1000+i);
p.setName("胡楠"+i);
p.setPassword("123456"+i);
p.setAge(24+i);
p.setBirthday(new Date());
list.add(p);
}
//集合
mav.addObject("persons", list);
//對象
mav.addObject("person",p1);
//request範圍數據
request.setAttribute("requestData", "hunan");
//session範圍數據
request.getSession().setAttribute("sessionData", "123456");
return mav;
}
@RequestMapping(value="/welcome")
public ModelAndView helloVm(){
ModelAndView modelAndView=new ModelAndView();
modelAndView.setViewName("welcome.vm");
modelAndView.addObject("message", "Hello,Velocity");
return modelAndView;
}
}
4、編寫velocity模板代碼,以下是velocity_main.vm代碼
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>Insert title here</title> </head> <body> 顯示對象的屬性<br> $person.id<br> $person.name<br> $person.password<br> $person.age<br> if語句<br> #if($person.id <2) id大於2 #else id小於2 #end #if($person.password=="123456") 密碼等於123456 #end <hr> foreach語句<br> #foreach($p in $persons) $p.id<br> $p.name<br> $!p.email<br> $dateTool.format("yyyy-MM-dd HH:mm:ss", $p.birthday)<br> #end <hr> request範圍數據<br> $requestData<br> session範圍數據<br> $sessionData<br> </body> </html>
呼~~寫完了終於,把tomcat發動起來,看一下效果吧。