使用RESTful风格,故需要额外注意DispatcherServlet的url-pattern和applicationContext.xml中的配置。

<mvc:default-servlet-handler/>

【1】applicationContext.xml配置

applicationContext.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:tx="http://www.springframework.org/schema/tx"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd
http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">

<context:component-scan base-package="com" />

<mvc:annotation-driven />

<mvc:default-servlet-handler/>

<!-- 配置freemarker -->
<bean id="freemarkerConfigurer"
class="org.springframework.web.servlet.view.freemarker.FreeMarkerConfigurer">
<property name="templateLoaderPath" value="/WEB-INF/views/" />
<!--<property name="freemarkerSettings" ref="freemarkerConfiguration"/> -->
<property name="freemarkerSettings">
<props>
<!-- 禁用freemarker缓存 -->
<prop key="template_update_delay">0</prop>
<prop key="default_encoding">UTF-8</prop>
<prop key="url_escaping_charset">UTF-8</prop>
<prop key="locale">zh_CN</prop>
<prop key="localized_lookup">false</prop>
<prop key="datetime_format">yyyy-MM-dd HH:mm:ss</prop>
<prop key="date_format">yyyy-MM-dd</prop>
<prop key="time_format">HH:mm:ss</prop>
<prop key="boolean_format">true,false</prop>
<prop key="number_format">#.##</prop> //设置数字格式化,不被逗号隔开
</props>
</property>
<!--这里设置需要配置的变量-->
<property name="freemarkerVariables">
<map>
<entry key="xml_escape" value-ref="fmXmlEscape" />
</map>
</property>
</bean>
<!--这里配置xml转译工具类-->
<bean id="fmXmlEscape" class="freemarker.template.utility.XmlEscape" />

<!-- 如果属性配置在properties文件中,可使用如下代码(上面的freemarkerSettings可配置在properties文件中) -->
<!-- <bean id="freemarkerConfiguration" class="org.springframework.beans.factory.config.PropertiesFactoryBean">
<property name="location" value="classpath:freemarker.properties" />
</bean>
-->

<!-- freemarker配置视图解析器 -->
<bean id="viewResolver" class="org.springframework.web.servlet.view.freemarker.FreeMarkerViewResolver">
<!-- 禁用SpringMVC缓存 -->
<property name="cache" value="false" />
<property name="viewClass" value="org.springframework.web.servlet.view.freemarker.FreeMarkerView"/>
<!-- 扫描路径內所有以ftl結尾的文件 viewNames 和suffix 只能存在一个 -->
<!-- <property name="viewNames"> -->
<!-- <array> -->
<!-- <value>*.ftl</value> -->
<!-- </array> -->
<!-- </property> -->
<property name="suffix" value=".ftl" />
<property name="contentType" value="text/html;charset=UTF-8"/>
<property name="requestContextAttribute" value="request" />
<property name="exposeSpringMacroHelpers" value="true" />
<property name="exposeRequestAttributes" value="true" />
<property name="exposeSessionAttributes" value="true" />
</bean>

</beans>

【2】web.xml配置

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
version="3.0">

<filter>
<filter-name>encoding</filter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilter
</filter-class>
<init-param>
<param-name>encoding</param-name>
<param-value>UTF-8</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>encoding</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>

<servlet>
<servlet-name>hh-mvc</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet
</servlet-class>
<init-param>
<param-name>namespace</param-name>
<param-value>hh-mvc</param-value>
</init-param>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath*:applicationContext.xml</param-value>
</init-param>
<init-param>
<param-name>publishContext</param-name>
<param-value>true</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>hh-mvc</servlet-name>
<!-- 注意这里 -->
<url-pattern>/</url-pattern>
</servlet-mapping>

<welcome-file-list>
<welcome-file>index.jsp</welcome-file>
</welcome-file-list>
</web-app>

【3】测试实例

① 后台代码

package com.web.controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;

@RequestMapping("/data")
@Controller
public class DataController {

@RequestMapping("/hello")
public ModelAndView hello(){
ModelAndView mv = new ModelAndView();
mv.addObject("msg", "hello world !");
mv.setViewName("hello");
return mv;
}
}

② FTL模板

<#assign base=request.contextPath/>
<!DOCTYPE html>
<html>
<head>
<base id="base" href="${base}">
<meta charset="UTF-8">
<title>hello ftl</title>
<script type="text/javascript">
var base = document.getElementById("base").href;
console.log(base);
</script>
</head>
<body>
${msg}
</body>
</html>

【4】XmlEscape

对给定的模板片段执行XML转义,此转换的实例最初作为共享变量​​xml_escape​​​可见。即,其他地方使用​​xml_escape​​变量来引用该实例。

其源码如下:

package freemarker.template.utility;

import java.io.IOException;
import java.io.Writer;
import java.util.Map;

import freemarker.template.TemplateTransformModel;

/**
* Performs an XML escaping of a given template fragment. Specifically,
* <tt><</tt> <tt>></tt> <tt>"</tt> <tt>'</tt> and <tt>&</tt> are all turned into entity references.
*
* <p>An instance of this transform is initially visible as shared
* variable called <tt>xml_escape</tt>.</p>
*/
public class XmlEscape implements TemplateTransformModel {

private static final char[] LT = "<".toCharArray();
private static final char[] GT = ">".toCharArray();
private static final char[] AMP = "&".toCharArray();
private static final char[] QUOT = """.toCharArray();
private static final char[] APOS = "&apos;".toCharArray();

public Writer getWriter(final Writer out, Map args)
{
return new Writer()
{
public void write(int c)
throws
IOException
{
switch(c)
{
case '<': out.write(LT, 0, 4); break;
case '>': out.write(GT, 0, 4); break;
case '&': out.write(AMP, 0, 5); break;
case '"': out.write(QUOT, 0, 6); break;
case '\'': out.write(APOS, 0, 6); break;
default: out.write(c);
}
}

public void write(char cbuf[], int off, int len)
throws
IOException
{
int lastoff = off;
int lastpos = off + len;
for (int i = off; i < lastpos; i++)
{
switch (cbuf[i])
{
case '<': out.write(cbuf, lastoff, i - lastoff); out.write(LT, 0, 4); lastoff = i + 1; break;
case '>': out.write(cbuf, lastoff, i - lastoff); out.write(GT, 0, 4); lastoff = i + 1; break;
case '&': out.write(cbuf, lastoff, i - lastoff); out.write(AMP, 0, 5); lastoff = i + 1; break;
case '"': out.write(cbuf, lastoff, i - lastoff); out.write(QUOT, 0, 6); lastoff = i + 1; break;
case '\'': out.write(cbuf, lastoff, i - lastoff); out.write(APOS, 0, 6); lastoff = i + 1; break;
}
}
int remaining = lastpos - lastoff;
if(remaining > 0)
{
out.write(cbuf, lastoff, remaining);
}
}
public void flush() throws IOException {
out.flush();
}

public void close() {
}
};
}
}