文档章节

Spring-Boot+thymeleaf3

E
 Ellision
发布于 2017/01/22 09:37
字数 1660
阅读 44
收藏 0

简介

这个Demo来源于Spring-Boot的GitHub

项目结构

这里写图片描述

代码

pom.xml

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
	<modelVersion>4.0.0</modelVersion>
	<groupId>demo</groupId>
	<artifactId>Spring-boot-thymeleaf3</artifactId>
	<packaging>war</packaging>
	<version>0.0.1-SNAPSHOT</version>
	<name>Spring-boot-thymeleaf3 Maven Webapp</name>
	<url>http://maven.apache.org</url>
	<parent>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-parent</artifactId>
		<version>1.4.1.RELEASE</version>
	</parent>
	<properties>
		<main.basedir>${basedir}/../..</main.basedir>
		<thymeleaf.version>3.0.2.RELEASE</thymeleaf.version>
		<thymeleaf-layout-dialect.version>2.1.1</thymeleaf-layout-dialect.version>
	</properties>
	<dependencies>
		<dependency>
			<groupId>junit</groupId>
			<artifactId>junit</artifactId>
			<version>4.12</version>
			<scope>test</scope>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-thymeleaf</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-test</artifactId>
			<version>1.4.2.RELEASE</version>
			<scope>test</scope>
		</dependency>
	</dependencies>
	<build>
		<finalName>Spring-boot-thymeleaf3</finalName>
		<plugins>
			<plugin>
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-maven-plugin</artifactId>
			</plugin>
			<plugin>
				<groupId>org.apache.maven.plugins</groupId>
				<artifactId>maven-compiler-plugin</artifactId>
				<configuration>
					<source>1.8</source>
					<target>1.8</target>
				</configuration>
			</plugin>
			<plugin>
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-maven-plugin</artifactId>
			</plugin>
		</plugins>
	</build>
</project>

配置文件

# Allow Thymeleaf templates to be reloaded at dev time
spring.thymeleaf.cache: false
spring.thymeleaf.mode: html

java代码

Message.java

/*
 * Copyright 2012-2016 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package sample.web.thymeleaf3;

import java.util.Calendar;

import org.hibernate.validator.constraints.NotEmpty;

/**
 * @author Rob Winch
 */
public class Message {

	private Long id;

	@NotEmpty(message = "Message is required.")
	private String text;

	@NotEmpty(message = "Summary is required.")
	private String summary;

	private Calendar created = Calendar.getInstance();

	public Long getId() {
		return this.id;
	}

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

	public Calendar getCreated() {
		return this.created;
	}

	public void setCreated(Calendar created) {
		this.created = created;
	}

	public String getText() {
		return this.text;
	}

	public void setText(String text) {
		this.text = text;
	}

	public String getSummary() {
		return this.summary;
	}

	public void setSummary(String summary) {
		this.summary = summary;
	}
}

MessageRepository.java

/*
 * Copyright 2012-2016 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package sample.web.thymeleaf3;

/**
 * @author Rob Winch
 */
public interface MessageRepository {

	Iterable<Message> findAll();

	Message save(Message message);

	Message findMessage(Long id);

	void deleteMessage(Long id);

}

InMemoryMessageRepository.java

/*
 * Copyright 2012-2016 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package sample.web.thymeleaf3;

import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.atomic.AtomicLong;

/**
 * @author Dave Syer
 */
public class InMemoryMessageRepository implements MessageRepository {

	private static AtomicLong counter = new AtomicLong();

	private final ConcurrentMap<Long, Message> messages = new ConcurrentHashMap<Long, Message>();

	@Override
	public Iterable<Message> findAll() {
		return this.messages.values();
	}

	@Override
	public Message save(Message message) {
		Long id = message.getId();
		if (id == null) {
			id = counter.incrementAndGet();
			message.setId(id);
		}
		this.messages.put(id, message);
		return message;
	}

	@Override
	public Message findMessage(Long id) {
		return this.messages.get(id);
	}

	@Override
	public void deleteMessage(Long id) {
		this.messages.remove(id);
	}

}

SampleWebThymeleaf3Application.java

SpringBoot启动类

/*
 * Copyright 2012-2016 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package sample.web.thymeleaf3;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.core.convert.converter.Converter;

@SpringBootApplication
public class SampleWebThymeleaf3Application {

	@Bean
	public MessageRepository messageRepository() {
		return new InMemoryMessageRepository();
	}

	@Bean
	public Converter<String, Message> messageConverter() {
		return new Converter<String, Message>() {
			@Override
			public Message convert(String id) {
				return messageRepository().findMessage(Long.valueOf(id));
			}
		};
	}

	public static void main(String[] args) throws Exception {
		SpringApplication.run(SampleWebThymeleaf3Application.class, args);
	}

}

MessageController.java

/*
 * Copyright 2012-2016 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package sample.web.thymeleaf3.mvc;

import javax.validation.Valid;

import sample.web.thymeleaf3.Message;
import sample.web.thymeleaf3.MessageRepository;

import org.springframework.stereotype.Controller;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.support.RedirectAttributes;

/**
 * @author Rob Winch
 * @author Doo-Hwan Kwak
 */
@Controller
@RequestMapping("/")
public class MessageController {

	private final MessageRepository messageRepository;

	public MessageController(MessageRepository messageRepository) {
		this.messageRepository = messageRepository;
	}

	@GetMapping
	public ModelAndView list() {
		Iterable<Message> messages = this.messageRepository.findAll();
		return new ModelAndView("messages/list", "messages", messages);
	}

	@GetMapping("{id}")
	public ModelAndView view(@PathVariable("id") Message message) {
		return new ModelAndView("messages/view", "message", message);
	}

	@GetMapping(params = "form")
	public String createForm(@ModelAttribute Message message) {
		return "messages/form";
	}

	@PostMapping
	public ModelAndView create(@Valid Message message, BindingResult result,
			RedirectAttributes redirect) {
		if (result.hasErrors()) {
			return new ModelAndView("messages/form", "formErrors", result.getAllErrors());
		}
		message = this.messageRepository.save(message);
		redirect.addFlashAttribute("globalMessage", "Successfully created a new message");
		return new ModelAndView("redirect:/{message.id}", "message.id", message.getId());
	}

	@RequestMapping("foo")
	public String foo() {
		throw new RuntimeException("Expected exception in controller");
	}

	@GetMapping(value = "delete/{id}")
	public ModelAndView delete(@PathVariable("id") Long id) {
		this.messageRepository.deleteMessage(id);
		Iterable<Message> messages = this.messageRepository.findAll();
		return new ModelAndView("messages/list", "messages", messages);
	}

	@GetMapping(value = "modify/{id}")
	public ModelAndView modifyForm(@PathVariable("id") Message message) {
		return new ModelAndView("messages/form", "message", message);
	}

}

前端模板

layout.html

样式框架

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org"
	xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout">
<head>
<title>Layout</title>
<link rel="stylesheet" th:href="@{/css/bootstrap.min.css}"
	href="../../css/bootstrap.min.css" />
</head>
<body>
	<div class="container">
		<div class="navbar">
			<div class="navbar-inner">
				<a class="brand"
					href="https://github.com/ultraq/thymeleaf-layout-dialect">
					Thymeleaf - Layout </a>
				<ul class="nav">
					<li><a th:href="@{/}" href="messages.html"> Messages </a></li>
				</ul>
			</div>
		</div>
		<h1 layout:fragment="header">Layout</h1>
		<div layout:fragment="content">Fake content</div>
	</div>
</body>
</html>

form.htmil

增加、删除页

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org"
	xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout"
	layout:decorate="layout">
<head>
<title>Messages : Create</title>
</head>
<body>
	<h1 layout:fragment="header">Messages : Create</h1>
	<div layout:fragment="content" class="container">
		<form id="messageForm" th:action="@{/(form)}" th:object="${message}" action="#" method="post">
			<div th:if="${#fields.hasErrors('*')}" class="alert alert-error">
				<p th:each="error : ${#fields.errors('*')}" th:text="${error}">Validation error</p>
			</div>
			<div class="pull-right">
				<a th:href="@{/}" href="messages.html"> Messages </a>
			</div>
			<input type="hidden" th:field="*{id}" th:class="${#fields.hasErrors('id')} ? 'field-error'" /> 
			<label for="summary">Summary</label>
			<input type="text" th:field="*{summary}" th:class="${#fields.hasErrors('summary')} ? 'field-error'" />
			<label for="text">Message</label>
			<textarea th:field="*{text}" th:class="${#fields.hasErrors('text')} ? 'field-error'"></textarea>
			<div class="form-actions">
				<input type="submit" value="Save" />
			</div>
		</form>
	</div>
</body>
</html>

list.html

列表页

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org"
	xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout"
	layout:decorate="layout">
<head>
<title>Messages : View all</title>
</head>
<body>
	<h1 layout:fragment="header">Messages : View all</h1>
	<div layout:fragment="content" class="container">
		<div class="pull-right">
			<a href="form.html" th:href="@{/(form)}">Create Message</a>
		</div>
		<table class="table table-bordered table-striped">
			<thead>
				<tr>
					<td>ID</td>
					<td>Created</td>
					<td>Summary</td>
				</tr>
			</thead>
			<tbody>
				<tr th:if="${messages.empty}">
					<td colspan="3">No messages</td>
				</tr>
				<tr th:each="message : ${messages}">
					<td th:text="${message.id}">1</td>
					<td th:text="${#calendars.format(message.created)}">July 11,
						2012 2:17:16 PM CDT</td>
					<td><a href="view.html" th:href="@{'/' + ${message.id}}"
						th:text="${message.summary}"> The summary </a></td>
				</tr>
			</tbody>
		</table>
	</div>
</body>
</html>

view.html

详情页

<html xmlns:th="http://www.thymeleaf.org"
	xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout"
	layout:decorate="layout">
<head>
<title>Messages : View</title>
</head>
<body>
	<h1 layout:fragment="header">Messages : Create</h1>
	<div layout:fragment="content" class="container">
		<div class="alert alert-success" th:if="${globalMessage}"
			th:text="${globalMessage}">Some Success message</div>
		<div class="pull-right">
			<a th:href="@{/}" href="list.html"> Messages </a>
		</div>
		<dl>
			<dt>ID</dt>
			<dd id="id" th:text="${message.id}">123</dd>
			<dt>Date</dt>
			<dd id="created" th:text="${#calendars.format(message.created)}">
				July 11, 2012 2:17:16 PM CDT</dd>
			<dt>Summary</dt>
			<dd id="summary" th:text="${message.summary}">A short summary...
			</dd>
			<dt>Message</dt>
			<dd id="text" th:text="${message.text}">A detailed message that
				is longer than the summary.</dd>
		</dl>
		<div class="pull-left">
			<a href="messages" th:href="@{'/delete/' + ${message.id}}">
				delete </a> | <a href="form.html"
				th:href="@{'/modify/' + ${message.id}}"> modify </a>
		</div>
	</div>
</body>
</html>

测试

运行SampleWebThymeleaf3Application.java

这里写图片描述

使用浏览器登录http://localhost:8080/ 若出现以下页面,则运行成功

这里写图片描述

© 著作权归作者所有

E
粉丝 0
博文 4
码字总数 5401
作品 0
福州
程序员
私信 提问
Spring Cloud Greenwich.RC1 发布

Spring Cloud Greenwich 首个 RC 版发布了,这个里程碑版本与 Spring Boot 2.1.1.RELEASE 兼容,各个项目都进行了更新,以实现与 Java 11 的兼容性。可点此查看在该版本中,分配给这个版本的...

局长
2018/12/17
1K
1
Spring Cloud Greenwich.M3 版本发布

Spring Cloud Function 的第三个 Milestone 3 已发布,该版本的各个模块现可在 Spring Milestone 存储库中使用。 主要更改 此版本与 Spring Boot 2.1.0.RELEASE 兼容,并已对 Java 11 兼容性...

淡漠悠然
2018/11/22
5.5K
0
Spring Boot的启动器Starter详解

Spring Boot的启动器Starter详解 Spring Boot应用启动器基本的一共有44种,具体如下: 1)spring-boot-starter 这是Spring Boot的核心启动器,包含了自动配置、日志和YAML。 2)spring-boot...

anlve
2018/02/22
157
0
Spring Cloud Finchley SR4 正式发布

Spring Cloud Finchley 的 Service Release 4 (SR4) 版本已发布,本次更新主要是对其包含的一些模块进行了升级,查看发布说明以了解更多信息,可从 Maven 中央仓库获取源码。Spring Cloud Fi...

xplanet
06/15
2.3K
1
spring-boot-plus 1.1.0 发布,集成 Spring Boot Admin 管理和监控应用

spring-boot-plus1.1.0.发布 集成Spring Boot Admin管理和监控应用 Spring Boot Admin用来管理和监控Spring Boot应用程序 应用程序向我们的Spring Boot Admin Client注册(通过HTTP)或使用S...

geekidea
08/01
4.1K
9

没有更多内容

加载失败,请刷新页面

加载更多

OpenStack 简介和几种安装方式总结

OpenStack :是一个由NASA和Rackspace合作研发并发起的,以Apache许可证授权的自由软件和开放源代码项目。项目目标是提供实施简单、可大规模扩展、丰富、标准统一的云计算管理平台。OpenSta...

小海bug
昨天
5
0
DDD(五)

1、引言 之前学习了解了DDD中实体这一概念,那么接下来需要了解的就是值对象、唯一标识。值对象,值就是数字1、2、3,字符串“1”,“2”,“3”,值时对象的特征,对象是一个事物的具体描述...

MrYuZixian
昨天
6
0
数据库中间件MyCat

什么是MyCat? 查看官网的介绍是这样说的 一个彻底开源的,面向企业应用开发的大数据库集群 支持事务、ACID、可以替代MySQL的加强版数据库 一个可以视为MySQL集群的企业级数据库,用来替代昂贵...

沉浮_
昨天
6
0
解决Mac下VSCode打开zsh乱码

1.乱码问题 iTerm2终端使用Zsh,并且配置Zsh主题,该主题主题需要安装字体来支持箭头效果,在iTerm2中设置这个字体,但是VSCode里这个箭头还是显示乱码。 iTerm2展示如下: VSCode展示如下: 2...

HelloDeveloper
昨天
7
0
常用物流快递单号查询接口种类及对接方法

目前快递查询接口有两种方式可以对接,一是和顺丰、圆通、中通、天天、韵达、德邦这些快递公司一一对接接口,二是和快递鸟这样第三方集成接口一次性对接多家常用快递。第一种耗费时间长,但是...

程序的小猿
昨天
10
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部