velocity是一个基于java的模板引擎,通过特定的语法,可以获取到在java中定义的对象,从而实现页面与java代码的分离。由于JSP需要先转换为Servlet,然后编译为class执行,导致效率较低。在访问量较大时表现较差,velocity则可以作为JSP的替代。

velocity的介绍、语法等可以参考:https://www.jianshu.com/p/5913903324ff

这里是一个springmvc集成velocity的显示用户列表和修改用户信息的例子,备忘。

maven依赖

添加velocity的相关依赖。(注:spring相关的依赖未给出)

1
2
3
4
5
6
7
8
9
10
<dependency>
  <groupId>org.apache.velocity</groupId>
  <artifactId>velocity</artifactId>
  <version>1.7</version>
</dependency>
<dependency>
  <groupId>org.apache.velocity</groupId>
  <artifactId>velocity-tools</artifactId>
  <version>2.0</version>
</dependency>

注意:必须引入spring-context-support依赖,否则velocityConfig配置中configLocation和resourceLoaderPath属性找不到。

springmvc配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
<!-- 自动扫描controller包下的所有类,如果@Controller注入为bean -->
<context:component-scan base-package="com.tommy.velocity.controller"/>
<!-- 注解驱动 -->
<mvc:annotation-driven />
<!-- velocity环境配置 -->
<bean id="velocityConfig" class="org.springframework.web.servlet.view.velocity.VelocityConfigurer">
    <!-- velocity配置文件路径  或者直接用velocityProperties属性 -->
    <property name="configLocation" value="classpath:velocity.properties"/>
    <!-- velocity模板路径 -->
    <property name="resourceLoaderPath" value="/WEB-INF/view/"/>
</bean>
<!-- velocity视图解析器 -->
<bean id="velocityViewResolver" class="org.springframework.web.servlet.view.velocity.VelocityLayoutViewResolver">
    <property name="order" value="0"/>
    <property name="contentType" value="text/html;charset=UTF-8"/>
    <property name="cache" value="true"/>
    <property name="suffix" value=".vm"/>
    <property name="layoutUrl" value="layout/layout.vm"/>
    <property name="exposeSpringMacroHelpers" value="true"/>
    <!--是否使用spring对宏定义的支持-->
    <property name="exposeSessionAttributes" value="true"/>
    <!--是否开放request属性-->
    <property name="requestContextAttribute" value="request"/>
    <!--request属性引用名称-->
    <property name="dateToolAttribute" value="dateTool"/>
    <property name="numberToolAttribute" value="numberTool"/>
</bean>

velocity.properties:

1
2
3
4
5
6
7
8
9
10
#设置字符集
#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=false

web.xml配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
<context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>classpath:spring.xml</param-value>
</context-param>
<listener>
    <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<!-- 防止spring内存溢出监听器 -->
<listener>
    <listener-class>org.springframework.web.util.IntrospectorCleanupListener</listener-class>
</listener>

<filter>
    <filter-name>encodingFilter</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>
    <init-param>
        <param-name>forceEncoding</param-name>
        <param-value>true</param-value>
    </init-param>
</filter>

<filter-mapping>
    <filter-name>encodingFilter</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>

<servlet>
    <servlet-name>rest</servlet-name>
    <description>spring mvc servlet</description>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <init-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>
            /WEB-INF/spring-mvc.xml
        </param-value>
    </init-param>
    <load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
    <servlet-name>rest</servlet-name>
    <url-pattern>/*</url-pattern>
</servlet-mapping>

注意配置Spring的字符集过滤器,否则向后台提交数据时中文乱码。

模板文件

布局模板:

1
2
3
4
5
6
7
8
9
10
11
12
13
<html>
<head>
    <title>$!page_title</title>
    #parse("default/header.vm")
</head>
<body>

<div>
    $screen_content
</div>

</body>
</html>

header.vm:

1
2
3
4
5
6
<meta http-equiv="Content-Type" content="text/html;charset=UTF-8">
<meta http-equiv="Cache-Control" content="no-store"/>
<meta http-equiv="Pragma" content="no-cache"/>
<meta http-equiv="Expires" content="3600"/>
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no" name="viewport">

展示用户列表的模板:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
<html>
<head>
    <title>Spring MVC and Velocity</title>
</head>
<body>
<h1>Spring MVC and Velocity</h1>

    <table>
        <tr>
            <td>id</td>
            <td>姓名</td>
            <td>age</td>
            <td>操作</td>
        </tr>
        #foreach($user in $users)
            <tr>
                <td>$!{user.id}</td>
                <td>$!{user.name}</td>
                <td>$!{user.age}</td>
                <td><a href="/preEdit?userId=${user.id}">修改</a></td>
            </tr>
        #end
    </table>
</body>
</html>

修改的模板:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<html>
<head>
    <title>Spring MVC and Velocity</title>
</head>
<body>
<h1>Spring MVC and Velocity</h1>

<form action="/edit" method="post">
    <input type="hidden" name="id" value="${user.id}" />
    姓名:<input type="text" name="name" value="$!{user.name}" /><br>
    年龄:<input type="text" name="age" value="$!{user.age}" />
    <input type="submit" value="提交" />
</form>
</body>
</html>

controller

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
@Controller
public class HelloController {
    private final static Map<Integer,User> users = new HashMap<>(8);

    static {
        initData();
    }

    @RequestMapping(value = "/list")
    public String showList(ModelMap map) {
        map.put("users",users);
        return "/list";
    }

    @RequestMapping(value = "/preEdit")
    public String preEdit(ModelMap map, Integer userId) {
        User user = users.get(userId);
        map.put("user",user);
        return "/edit";
    }

    @RequestMapping(value = "/edit")
    public String edit(ModelMap map, User user) {
        users.put(user.getId(),user);
        return showList(map);
    }

    private static void initData() {
        for (int i=0;i<8;i++) {
            User user = new User();
            user.setId(i);
            user.setName("测试用户" + i);
            user.setAge((int) (Math.random()*100+10));
            users.put(i, user);
        }
    }
}

User:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
public class User {
    private int id;
    private String name;
    private int age;

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }
}

演示:
列表页面

修改一个用户名称

再次回到列表页面

本文示例代码:https://gitee.com/qincd/my-test-projects下的spring-velocity模块。

本文参考:springmvc集成 velocity,实现多视图整合(jsp,velocity)