[bs-118], [bs-119]: add UI builder features
* MessageSource created automatically (location spring.messages.basename:messages) * Thymeleaf configured automatically to look for templates in classpath:/templates * Added static resource handlers for classpath:/static and classpath:/ [Fixes #49832165] [bs-118] Support for thymeleaf templatespull/1/merge
parent
ceea71fc38
commit
53078c320e
@ -0,0 +1,64 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<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/xsd/maven-4.0.0.xsd">
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
<parent>
|
||||||
|
<groupId>org.springframework.bootstrap</groupId>
|
||||||
|
<artifactId>spring-bootstrap-samples</artifactId>
|
||||||
|
<version>0.5.0.BUILD-SNAPSHOT</version>
|
||||||
|
</parent>
|
||||||
|
<artifactId>spring-bootstrap-ui-sample</artifactId>
|
||||||
|
<packaging>war</packaging>
|
||||||
|
<properties>
|
||||||
|
<m2eclipse.wtp.contextRoot>/</m2eclipse.wtp.contextRoot>
|
||||||
|
<start-class>org.springframework.bootstrap.sample.ui.UiBootstrapApplication</start-class>
|
||||||
|
</properties>
|
||||||
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>${project.groupId}</groupId>
|
||||||
|
<artifactId>spring-bootstrap</artifactId>
|
||||||
|
<version>${project.version}</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework</groupId>
|
||||||
|
<artifactId>spring-webmvc</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.thymeleaf</groupId>
|
||||||
|
<artifactId>thymeleaf-spring3</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>nz.net.ultraq.web.thymeleaf</groupId>
|
||||||
|
<artifactId>thymeleaf-layout-dialect</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.apache.tomcat.embed</groupId>
|
||||||
|
<artifactId>tomcat-embed-core</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.apache.tomcat.embed</groupId>
|
||||||
|
<artifactId>tomcat-embed-logging-juli</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.hibernate</groupId>
|
||||||
|
<artifactId>hibernate-validator</artifactId>
|
||||||
|
<version>4.3.1.Final</version>
|
||||||
|
<!-- FIXME: make this optional -->
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.slf4j</groupId>
|
||||||
|
<artifactId>slf4j-jdk14</artifactId>
|
||||||
|
<scope>runtime</scope>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
<build>
|
||||||
|
<plugins>
|
||||||
|
<plugin>
|
||||||
|
<artifactId>maven-dependency-plugin</artifactId>
|
||||||
|
</plugin>
|
||||||
|
<plugin>
|
||||||
|
<artifactId>maven-assembly-plugin</artifactId>
|
||||||
|
</plugin>
|
||||||
|
</plugins>
|
||||||
|
</build>
|
||||||
|
</project>
|
@ -0,0 +1,52 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2012-2013 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 org.springframework.bootstrap.sample.ui;
|
||||||
|
|
||||||
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
import java.util.concurrent.ConcurrentMap;
|
||||||
|
import java.util.concurrent.atomic.AtomicLong;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Dave Syer
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class InMemoryMessageRespository implements MessageRepository {
|
||||||
|
|
||||||
|
private static AtomicLong counter = new AtomicLong();
|
||||||
|
private 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);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,67 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2012 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 org.springframework.bootstrap.sample.ui;
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,28 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2012 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 org.springframework.bootstrap.sample.ui;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author Rob Winch
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public interface MessageRepository {
|
||||||
|
|
||||||
|
Iterable<Message> findAll();
|
||||||
|
|
||||||
|
Message save(Message message);
|
||||||
|
|
||||||
|
Message findMessage(Long id);
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,34 @@
|
|||||||
|
package org.springframework.bootstrap.sample.ui;
|
||||||
|
|
||||||
|
import org.springframework.bootstrap.SpringApplication;
|
||||||
|
import org.springframework.bootstrap.context.annotation.EnableAutoConfiguration;
|
||||||
|
import org.springframework.context.annotation.Bean;
|
||||||
|
import org.springframework.context.annotation.ComponentScan;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
import org.springframework.core.convert.converter.Converter;
|
||||||
|
|
||||||
|
@Configuration
|
||||||
|
@EnableAutoConfiguration
|
||||||
|
@ComponentScan
|
||||||
|
public class UiBootstrapApplication {
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public MessageRepository messageRepository() {
|
||||||
|
return new InMemoryMessageRespository();
|
||||||
|
}
|
||||||
|
|
||||||
|
@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(UiBootstrapApplication.class, args);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,82 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2012 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 org.springframework.bootstrap.sample.ui.mvc;
|
||||||
|
|
||||||
|
import javax.validation.Valid;
|
||||||
|
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.bootstrap.sample.ui.Message;
|
||||||
|
import org.springframework.bootstrap.sample.ui.MessageRepository;
|
||||||
|
import org.springframework.stereotype.Controller;
|
||||||
|
import org.springframework.validation.BindingResult;
|
||||||
|
import org.springframework.web.bind.annotation.ModelAttribute;
|
||||||
|
import org.springframework.web.bind.annotation.PathVariable;
|
||||||
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RequestMethod;
|
||||||
|
import org.springframework.web.servlet.ModelAndView;
|
||||||
|
import org.springframework.web.servlet.mvc.support.RedirectAttributes;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author Rob Winch
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
@Controller
|
||||||
|
@RequestMapping("/")
|
||||||
|
public class MessageController {
|
||||||
|
private MessageRepository messageRepository;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
public MessageController(MessageRepository messageRepository) {
|
||||||
|
this.messageRepository = messageRepository;
|
||||||
|
}
|
||||||
|
|
||||||
|
@RequestMapping
|
||||||
|
public ModelAndView list() {
|
||||||
|
Iterable<Message> messages = messageRepository.findAll();
|
||||||
|
return new ModelAndView("messages/list", "messages", messages);
|
||||||
|
}
|
||||||
|
|
||||||
|
@RequestMapping("{id}")
|
||||||
|
public ModelAndView view(@PathVariable("id")
|
||||||
|
Message message) {
|
||||||
|
return new ModelAndView("messages/view", "message", message);
|
||||||
|
}
|
||||||
|
|
||||||
|
@RequestMapping(params = "form", method = RequestMethod.GET)
|
||||||
|
public String createForm(@ModelAttribute
|
||||||
|
Message message) {
|
||||||
|
return "messages/form";
|
||||||
|
}
|
||||||
|
|
||||||
|
@RequestMapping(method = RequestMethod.POST)
|
||||||
|
public ModelAndView create(@Valid
|
||||||
|
Message message, BindingResult result, RedirectAttributes redirect) {
|
||||||
|
if (result.hasErrors()) {
|
||||||
|
return new ModelAndView("messages/form", "formErrors",
|
||||||
|
result.getAllErrors());
|
||||||
|
}
|
||||||
|
message = messageRepository.save(message);
|
||||||
|
redirect.addFlashAttribute("globalMessage",
|
||||||
|
"Successfully created a new message");
|
||||||
|
return new ModelAndView("redirect:/{message.id}",
|
||||||
|
"message.id", message.getId());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,32 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html xmlns:th="http://www.thymeleaf.org" xmlns:layout="http://www.ultraq.net.nz/web/thymeleaf/layout">
|
||||||
|
<head>
|
||||||
|
<title>Layout</title>
|
||||||
|
<link rel="stylesheet"
|
||||||
|
th:href="@{/resources/css/bootstrap.min.css}"
|
||||||
|
href="../../resources/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>
|
@ -0,0 +1,43 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html xmlns:th="http://www.thymeleaf.org"
|
||||||
|
xmlns:layout="http://www.ultraq.net.nz/web/thymeleaf/layout"
|
||||||
|
layout:decorator="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>
|
||||||
|
<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="Create"/>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
@ -0,0 +1,45 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html xmlns:th="http://www.thymeleaf.org"
|
||||||
|
xmlns:layout="http://www.ultraq.net.nz/web/thymeleaf/layout"
|
||||||
|
layout:decorator="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>
|
@ -0,0 +1,42 @@
|
|||||||
|
<html xmlns:th="http://www.thymeleaf.org"
|
||||||
|
xmlns:layout="http://www.ultraq.net.nz/web/thymeleaf/layout"
|
||||||
|
layout:decorator="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>
|
||||||
|
</body>
|
||||||
|
</html>
|
@ -0,0 +1,98 @@
|
|||||||
|
package org.springframework.bootstrap.sample.ui;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.net.URI;
|
||||||
|
import java.util.concurrent.Callable;
|
||||||
|
import java.util.concurrent.Executors;
|
||||||
|
import java.util.concurrent.Future;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
|
import org.junit.AfterClass;
|
||||||
|
import org.junit.BeforeClass;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.springframework.bootstrap.SpringApplication;
|
||||||
|
import org.springframework.context.ConfigurableApplicationContext;
|
||||||
|
import org.springframework.http.HttpStatus;
|
||||||
|
import org.springframework.http.ResponseEntity;
|
||||||
|
import org.springframework.http.client.ClientHttpResponse;
|
||||||
|
import org.springframework.util.LinkedMultiValueMap;
|
||||||
|
import org.springframework.util.MultiValueMap;
|
||||||
|
import org.springframework.web.client.DefaultResponseErrorHandler;
|
||||||
|
import org.springframework.web.client.RestTemplate;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
import static org.junit.Assert.assertFalse;
|
||||||
|
import static org.junit.Assert.assertTrue;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Basic integration tests for demo application.
|
||||||
|
*
|
||||||
|
* @author Dave Syer
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class UiBootstrapApplicationTests {
|
||||||
|
|
||||||
|
private static ConfigurableApplicationContext context;
|
||||||
|
|
||||||
|
@BeforeClass
|
||||||
|
public static void start() throws Exception {
|
||||||
|
Future<ConfigurableApplicationContext> future = Executors
|
||||||
|
.newSingleThreadExecutor().submit(
|
||||||
|
new Callable<ConfigurableApplicationContext>() {
|
||||||
|
@Override
|
||||||
|
public ConfigurableApplicationContext call() throws Exception {
|
||||||
|
return (ConfigurableApplicationContext) SpringApplication
|
||||||
|
.run(UiBootstrapApplication.class);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
context = future.get(30, TimeUnit.SECONDS);
|
||||||
|
}
|
||||||
|
|
||||||
|
@AfterClass
|
||||||
|
public static void stop() {
|
||||||
|
if (context != null) {
|
||||||
|
context.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testHome() throws Exception {
|
||||||
|
ResponseEntity<String> entity = getRestTemplate().getForEntity(
|
||||||
|
"http://localhost:8080", String.class);
|
||||||
|
assertEquals(HttpStatus.OK, entity.getStatusCode());
|
||||||
|
assertTrue("Wrong body (title doesn't match):\n" + entity.getBody(), entity
|
||||||
|
.getBody().contains("<title>Messages"));
|
||||||
|
assertFalse("Wrong body (found layout:fragment):\n" + entity.getBody(), entity
|
||||||
|
.getBody().contains("layout:fragment"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testCreate() throws Exception {
|
||||||
|
MultiValueMap<String, String> map = new LinkedMultiValueMap<String, String>();
|
||||||
|
map.set("text", "FOO text");
|
||||||
|
map.set("summary", "FOO");
|
||||||
|
URI location = getRestTemplate().postForLocation("http://localhost:8080", map);
|
||||||
|
assertTrue("Wrong location:\n" + location,
|
||||||
|
location.toString().contains("localhost:8080"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testCss() throws Exception {
|
||||||
|
ResponseEntity<String> entity = getRestTemplate().getForEntity(
|
||||||
|
"http://localhost:8080/css/bootstrap.min.css", String.class);
|
||||||
|
assertEquals(HttpStatus.OK, entity.getStatusCode());
|
||||||
|
assertTrue("Wrong body:\n" + entity.getBody(), entity.getBody().contains("body"));
|
||||||
|
}
|
||||||
|
|
||||||
|
private RestTemplate getRestTemplate() {
|
||||||
|
RestTemplate restTemplate = new RestTemplate();
|
||||||
|
restTemplate.setErrorHandler(new DefaultResponseErrorHandler() {
|
||||||
|
@Override
|
||||||
|
public void handleError(ClientHttpResponse response) throws IOException {
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return restTemplate;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,7 @@
|
|||||||
|
handlers = java.util.logging.ConsoleHandler
|
||||||
|
.level = INFO
|
||||||
|
|
||||||
|
java.util.logging.ConsoleHandler.level = FINE
|
||||||
|
sun.net.www.protocol.http.HttpURLConnection.level = ALL
|
||||||
|
org.springframework.bootstrap.context.annotation.level = ALL
|
||||||
|
org.thymeleaf.level = ALL
|
@ -0,0 +1,46 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2012-2013 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 org.springframework.bootstrap.autoconfigure;
|
||||||
|
|
||||||
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
|
import org.springframework.bootstrap.context.annotation.ConditionalOnMissingBean;
|
||||||
|
import org.springframework.bootstrap.context.annotation.EnableAutoConfiguration;
|
||||||
|
import org.springframework.context.MessageSource;
|
||||||
|
import org.springframework.context.annotation.Bean;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
import org.springframework.context.support.ResourceBundleMessageSource;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@link EnableAutoConfiguration Auto-configuration} for {@link MessageSource}.
|
||||||
|
*
|
||||||
|
* @author Dave Syer
|
||||||
|
*/
|
||||||
|
@Configuration
|
||||||
|
@ConditionalOnMissingBean(MessageSource.class)
|
||||||
|
public class MessageSourceAutoConfiguration {
|
||||||
|
|
||||||
|
@Value("${spring.messages.basename:messages}")
|
||||||
|
private String basename;
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public MessageSource messageSource() {
|
||||||
|
ResourceBundleMessageSource messageSource = new ResourceBundleMessageSource();
|
||||||
|
messageSource.setBasename(this.basename);
|
||||||
|
return messageSource;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,155 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2012-2013 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 org.springframework.bootstrap.autoconfigure.thymeleaf;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.Collections;
|
||||||
|
|
||||||
|
import javax.servlet.Servlet;
|
||||||
|
|
||||||
|
import nz.net.ultraq.web.thymeleaf.LayoutDialect;
|
||||||
|
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
|
import org.springframework.bootstrap.context.annotation.ConditionalOnClass;
|
||||||
|
import org.springframework.bootstrap.context.annotation.ConditionalOnMissingBean;
|
||||||
|
import org.springframework.bootstrap.context.annotation.ConditionalOnMissingClass;
|
||||||
|
import org.springframework.bootstrap.context.annotation.EnableAutoConfiguration;
|
||||||
|
import org.springframework.context.annotation.Bean;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
import org.springframework.core.io.DefaultResourceLoader;
|
||||||
|
import org.springframework.core.io.ResourceLoader;
|
||||||
|
import org.thymeleaf.TemplateProcessingParameters;
|
||||||
|
import org.thymeleaf.resourceresolver.IResourceResolver;
|
||||||
|
import org.thymeleaf.spring3.SpringTemplateEngine;
|
||||||
|
import org.thymeleaf.spring3.view.ThymeleafViewResolver;
|
||||||
|
import org.thymeleaf.templateresolver.ITemplateResolver;
|
||||||
|
import org.thymeleaf.templateresolver.TemplateResolver;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@link EnableAutoConfiguration Auto-configuration} for Thymeleaf templating.
|
||||||
|
*
|
||||||
|
* @author Dave Syer
|
||||||
|
*/
|
||||||
|
@Configuration
|
||||||
|
@ConditionalOnClass(SpringTemplateEngine.class)
|
||||||
|
public class ThymeleafAutoConfiguration {
|
||||||
|
|
||||||
|
@Configuration
|
||||||
|
@ConditionalOnMissingBean(name = "defaultTemplateResolver")
|
||||||
|
protected static class DefaultTemplateResolverConfiguration {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private ResourceLoader resourceLoader = new DefaultResourceLoader();
|
||||||
|
|
||||||
|
@Value("${spring.template.prefix:classpath:/templates/}")
|
||||||
|
private String prefix = "classpath:/templates/";
|
||||||
|
|
||||||
|
@Value("${spring.template.suffix:.html}")
|
||||||
|
private String suffix = ".html";
|
||||||
|
|
||||||
|
@Value("${spring.template.mode:HTML5}")
|
||||||
|
private String templateMode = "HTML5";
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public ITemplateResolver defaultTemplateResolver() {
|
||||||
|
TemplateResolver resolver = new TemplateResolver();
|
||||||
|
resolver.setResourceResolver(new IResourceResolver() {
|
||||||
|
@Override
|
||||||
|
public InputStream getResourceAsStream(
|
||||||
|
TemplateProcessingParameters templateProcessingParameters,
|
||||||
|
String resourceName) {
|
||||||
|
try {
|
||||||
|
return DefaultTemplateResolverConfiguration.this.resourceLoader
|
||||||
|
.getResource(resourceName).getInputStream();
|
||||||
|
} catch (IOException e) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getName() {
|
||||||
|
return "SPRING";
|
||||||
|
}
|
||||||
|
});
|
||||||
|
resolver.setPrefix(this.prefix);
|
||||||
|
resolver.setSuffix(this.suffix);
|
||||||
|
resolver.setTemplateMode(this.templateMode);
|
||||||
|
return resolver;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Configuration
|
||||||
|
@ConditionalOnMissingClass("nz.net.ultraq.web.thymeleaf.LayoutDialect")
|
||||||
|
@ConditionalOnMissingBean(SpringTemplateEngine.class)
|
||||||
|
protected static class ThymeleafDefaultConfiguration {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private Collection<ITemplateResolver> templateResolvers = Collections.emptySet();
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public SpringTemplateEngine templateEngine() {
|
||||||
|
SpringTemplateEngine engine = new SpringTemplateEngine();
|
||||||
|
for (ITemplateResolver templateResolver : this.templateResolvers) {
|
||||||
|
engine.addTemplateResolver(templateResolver);
|
||||||
|
}
|
||||||
|
return engine;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Configuration
|
||||||
|
@ConditionalOnClass({ LayoutDialect.class })
|
||||||
|
@ConditionalOnMissingBean(SpringTemplateEngine.class)
|
||||||
|
protected static class ThymeleafWebLayoutConfiguration {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private Collection<ITemplateResolver> templateResolvers = Collections.emptySet();
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public SpringTemplateEngine templateEngine() {
|
||||||
|
SpringTemplateEngine engine = new SpringTemplateEngine();
|
||||||
|
for (ITemplateResolver templateResolver : this.templateResolvers) {
|
||||||
|
engine.addTemplateResolver(templateResolver);
|
||||||
|
}
|
||||||
|
engine.addDialect(new LayoutDialect());
|
||||||
|
return engine;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Configuration
|
||||||
|
@ConditionalOnClass({ Servlet.class })
|
||||||
|
protected static class ThymeleafViewResolverConfiguration {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private SpringTemplateEngine templateEngine;
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
@ConditionalOnMissingBean(name = "thymeleafViewResolver")
|
||||||
|
public ThymeleafViewResolver thymeleafViewResolver() {
|
||||||
|
ThymeleafViewResolver resolver = new ThymeleafViewResolver();
|
||||||
|
resolver.setTemplateEngine(this.templateEngine);
|
||||||
|
return resolver;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,43 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2012-2013 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 org.springframework.bootstrap.context.annotation;
|
||||||
|
|
||||||
|
import java.lang.annotation.Documented;
|
||||||
|
import java.lang.annotation.ElementType;
|
||||||
|
import java.lang.annotation.Retention;
|
||||||
|
import java.lang.annotation.RetentionPolicy;
|
||||||
|
import java.lang.annotation.Target;
|
||||||
|
|
||||||
|
import org.springframework.context.annotation.Conditional;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@link Conditional} that only matches when the specified classes are on the classpath.
|
||||||
|
*
|
||||||
|
* @author Dave Syer
|
||||||
|
*/
|
||||||
|
@Target({ ElementType.TYPE, ElementType.METHOD })
|
||||||
|
@Retention(RetentionPolicy.RUNTIME)
|
||||||
|
@Documented
|
||||||
|
@Conditional(OnMissingClassCondition.class)
|
||||||
|
public @interface ConditionalOnMissingClass {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The classes names that must be absent.
|
||||||
|
* @return the class names that must be absent.
|
||||||
|
*/
|
||||||
|
public String[] value() default {};
|
||||||
|
}
|
@ -0,0 +1,38 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2012-2013 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 org.springframework.bootstrap.context.annotation;
|
||||||
|
|
||||||
|
import java.lang.annotation.Documented;
|
||||||
|
import java.lang.annotation.ElementType;
|
||||||
|
import java.lang.annotation.Retention;
|
||||||
|
import java.lang.annotation.RetentionPolicy;
|
||||||
|
import java.lang.annotation.Target;
|
||||||
|
|
||||||
|
import org.springframework.context.annotation.Conditional;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@link Conditional} that only matches when the application context is a not a web
|
||||||
|
* application context.
|
||||||
|
*
|
||||||
|
* @author Dave Syer
|
||||||
|
*/
|
||||||
|
@Target({ ElementType.TYPE, ElementType.METHOD })
|
||||||
|
@Retention(RetentionPolicy.RUNTIME)
|
||||||
|
@Documented
|
||||||
|
@Conditional(OnNotWebApplicationCondition.class)
|
||||||
|
public @interface ConditionalOnNotWebApplication {
|
||||||
|
}
|
@ -0,0 +1,38 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2012-2013 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 org.springframework.bootstrap.context.annotation;
|
||||||
|
|
||||||
|
import java.lang.annotation.Documented;
|
||||||
|
import java.lang.annotation.ElementType;
|
||||||
|
import java.lang.annotation.Retention;
|
||||||
|
import java.lang.annotation.RetentionPolicy;
|
||||||
|
import java.lang.annotation.Target;
|
||||||
|
|
||||||
|
import org.springframework.context.annotation.Conditional;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@link Conditional} that only matches when the application context is a web application
|
||||||
|
* context.
|
||||||
|
*
|
||||||
|
* @author Dave Syer
|
||||||
|
*/
|
||||||
|
@Target({ ElementType.TYPE, ElementType.METHOD })
|
||||||
|
@Retention(RetentionPolicy.RUNTIME)
|
||||||
|
@Documented
|
||||||
|
@Conditional(OnWebApplicationCondition.class)
|
||||||
|
public @interface ConditionalOnWebApplication {
|
||||||
|
}
|
@ -0,0 +1,75 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2012-2013 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 org.springframework.bootstrap.context.annotation;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.apache.commons.logging.Log;
|
||||||
|
import org.apache.commons.logging.LogFactory;
|
||||||
|
import org.springframework.context.annotation.Condition;
|
||||||
|
import org.springframework.context.annotation.ConditionContext;
|
||||||
|
import org.springframework.core.type.AnnotatedTypeMetadata;
|
||||||
|
import org.springframework.util.Assert;
|
||||||
|
import org.springframework.util.ClassUtils;
|
||||||
|
import org.springframework.util.MultiValueMap;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@link Condition} that checks for the specific classes.
|
||||||
|
*
|
||||||
|
* @author Dave Syer
|
||||||
|
* @see ConditionalOnMissingClass
|
||||||
|
*/
|
||||||
|
class OnMissingClassCondition implements Condition {
|
||||||
|
|
||||||
|
private static Log logger = LogFactory.getLog(OnMissingClassCondition.class);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
|
||||||
|
MultiValueMap<String, Object> attributes = metadata.getAllAnnotationAttributes(
|
||||||
|
ConditionalOnMissingClass.class.getName(), true);
|
||||||
|
if (attributes != null) {
|
||||||
|
List<String> classNames = new ArrayList<String>();
|
||||||
|
collectClassNames(classNames, attributes.get("value"));
|
||||||
|
Assert.isTrue(classNames.size() > 0,
|
||||||
|
"@ConditionalOnMissingClass annotations must specify at least one class value");
|
||||||
|
for (String className : classNames) {
|
||||||
|
if (logger.isDebugEnabled()) {
|
||||||
|
logger.debug("Checking for class: " + className);
|
||||||
|
}
|
||||||
|
if (ClassUtils.isPresent(className, context.getClassLoader())) {
|
||||||
|
if (logger.isDebugEnabled()) {
|
||||||
|
logger.debug("Found class: " + className
|
||||||
|
+ " (search terminated with matches=false)");
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void collectClassNames(List<String> classNames, List<Object> values) {
|
||||||
|
for (Object value : values) {
|
||||||
|
for (Object valueItem : (Object[]) value) {
|
||||||
|
classNames.add(valueItem instanceof Class<?> ? ((Class<?>) valueItem)
|
||||||
|
.getName() : valueItem.toString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,56 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2012-2013 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 org.springframework.bootstrap.context.annotation;
|
||||||
|
|
||||||
|
import org.apache.commons.logging.Log;
|
||||||
|
import org.apache.commons.logging.LogFactory;
|
||||||
|
import org.springframework.context.annotation.Condition;
|
||||||
|
import org.springframework.context.annotation.ConditionContext;
|
||||||
|
import org.springframework.core.type.AnnotatedTypeMetadata;
|
||||||
|
import org.springframework.util.ClassUtils;
|
||||||
|
import org.springframework.util.StringUtils;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@link Condition} that checks for a web application context and returns false if one is
|
||||||
|
* found.
|
||||||
|
*
|
||||||
|
* @author Dave Syer
|
||||||
|
* @see ConditionalOnNotWebApplication
|
||||||
|
*/
|
||||||
|
class OnNotWebApplicationCondition implements Condition {
|
||||||
|
|
||||||
|
private static Log logger = LogFactory.getLog(OnNotWebApplicationCondition.class);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
|
||||||
|
if (!ClassUtils.isPresent(
|
||||||
|
"org.springframework.web.context.support.GenericWebApplicationContext",
|
||||||
|
null)) {
|
||||||
|
if (logger.isDebugEnabled()) {
|
||||||
|
logger.debug("Web application classes not found");
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
boolean result = !StringUtils.arrayToCommaDelimitedString(
|
||||||
|
context.getBeanFactory().getRegisteredScopeNames()).contains("session");
|
||||||
|
if (logger.isDebugEnabled()) {
|
||||||
|
logger.debug("Web application context found: " + !result);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,57 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2012-2013 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 org.springframework.bootstrap.context.annotation;
|
||||||
|
|
||||||
|
import org.apache.commons.logging.Log;
|
||||||
|
import org.apache.commons.logging.LogFactory;
|
||||||
|
import org.springframework.context.annotation.Condition;
|
||||||
|
import org.springframework.context.annotation.ConditionContext;
|
||||||
|
import org.springframework.core.type.AnnotatedTypeMetadata;
|
||||||
|
import org.springframework.util.ClassUtils;
|
||||||
|
import org.springframework.util.StringUtils;
|
||||||
|
import org.springframework.web.context.support.StandardServletEnvironment;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@link Condition} that checks for a web application context.
|
||||||
|
*
|
||||||
|
* @author Dave Syer
|
||||||
|
* @see ConditionalOnWebApplication
|
||||||
|
*/
|
||||||
|
class OnWebApplicationCondition implements Condition {
|
||||||
|
|
||||||
|
private static Log logger = LogFactory.getLog(OnWebApplicationCondition.class);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
|
||||||
|
if (!ClassUtils.isPresent(
|
||||||
|
"org.springframework.web.context.support.GenericWebApplicationContext",
|
||||||
|
null)) {
|
||||||
|
if (logger.isDebugEnabled()) {
|
||||||
|
logger.debug("Web application classes not found");
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
boolean result = StringUtils.arrayToCommaDelimitedString(
|
||||||
|
context.getBeanFactory().getRegisteredScopeNames()).contains("session")
|
||||||
|
|| context.getEnvironment() instanceof StandardServletEnvironment;
|
||||||
|
if (logger.isDebugEnabled()) {
|
||||||
|
logger.debug("Web application context found: " + result);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -1,13 +1,16 @@
|
|||||||
org.springframework.bootstrap.context.annotation.EnableAutoConfiguration=\
|
org.springframework.bootstrap.context.annotation.EnableAutoConfiguration=\
|
||||||
org.springframework.bootstrap.autoconfigure.PropertyPlaceholderAutoConfiguration,\
|
org.springframework.bootstrap.autoconfigure.PropertyPlaceholderAutoConfiguration,\
|
||||||
|
org.springframework.bootstrap.autoconfigure.MessageSourceAutoConfiguration,\
|
||||||
org.springframework.bootstrap.autoconfigure.data.JpaRepositoriesAutoConfiguration,\
|
org.springframework.bootstrap.autoconfigure.data.JpaRepositoriesAutoConfiguration,\
|
||||||
org.springframework.bootstrap.autoconfigure.jdbc.EmbeddedDatabaseAutoConfiguration,\
|
org.springframework.bootstrap.autoconfigure.jdbc.EmbeddedDatabaseAutoConfiguration,\
|
||||||
org.springframework.bootstrap.autoconfigure.batch.BatchAutoConfiguration,\
|
org.springframework.bootstrap.autoconfigure.batch.BatchAutoConfiguration,\
|
||||||
org.springframework.bootstrap.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration,\
|
org.springframework.bootstrap.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration,\
|
||||||
|
org.springframework.bootstrap.autoconfigure.thymeleaf.ThymeleafAutoConfiguration,\
|
||||||
org.springframework.bootstrap.autoconfigure.web.EmbeddedContainerCustomizerConfiguration,\
|
org.springframework.bootstrap.autoconfigure.web.EmbeddedContainerCustomizerConfiguration,\
|
||||||
org.springframework.bootstrap.autoconfigure.web.EmbeddedJettyAutoConfiguration,\
|
org.springframework.bootstrap.autoconfigure.web.EmbeddedJettyAutoConfiguration,\
|
||||||
org.springframework.bootstrap.autoconfigure.web.EmbeddedTomcatAutoConfiguration,\
|
org.springframework.bootstrap.autoconfigure.web.EmbeddedTomcatAutoConfiguration,\
|
||||||
org.springframework.bootstrap.autoconfigure.web.WebMvcAutoConfiguration
|
org.springframework.bootstrap.autoconfigure.web.WebMvcAutoConfiguration
|
||||||
org.springframework.context.ApplicationContextInitializer=\
|
org.springframework.context.ApplicationContextInitializer=\
|
||||||
org.springframework.bootstrap.context.initializer.ConfigFileApplicationContextInitializer,\
|
org.springframework.bootstrap.context.initializer.ConfigFileApplicationContextInitializer,\
|
||||||
|
org.springframework.bootstrap.context.initializer.LoggingInitializer,\
|
||||||
org.springframework.bootstrap.context.initializer.EnvironmentDelegateApplicationContextInitializer
|
org.springframework.bootstrap.context.initializer.EnvironmentDelegateApplicationContextInitializer
|
@ -0,0 +1,60 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2012-2013 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 org.springframework.bootstrap.autoconfigure;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Locale;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
|
||||||
|
import org.springframework.core.env.MapPropertySource;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Dave Syer
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class MessageSourceAutoConfigurationTests {
|
||||||
|
|
||||||
|
private AnnotationConfigApplicationContext context;
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testDefaultMessageSource() throws Exception {
|
||||||
|
this.context = new AnnotationConfigApplicationContext();
|
||||||
|
this.context.register(MessageSourceAutoConfiguration.class,
|
||||||
|
PropertyPlaceholderAutoConfiguration.class);
|
||||||
|
this.context.refresh();
|
||||||
|
assertEquals("Foo message",
|
||||||
|
this.context.getMessage("foo", null, "Foo message", Locale.UK));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testMessageSourceCreated() throws Exception {
|
||||||
|
this.context = new AnnotationConfigApplicationContext();
|
||||||
|
this.context.register(MessageSourceAutoConfiguration.class,
|
||||||
|
PropertyPlaceholderAutoConfiguration.class);
|
||||||
|
Map<String, Object> map = new HashMap<String, Object>();
|
||||||
|
map.put("spring.messages.basename", "test/messages");
|
||||||
|
this.context.getEnvironment().getPropertySources()
|
||||||
|
.addFirst(new MapPropertySource("test", map));
|
||||||
|
this.context.refresh();
|
||||||
|
assertEquals("bar",
|
||||||
|
this.context.getMessage("foo", null, "Foo message", Locale.UK));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,84 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2012-2013 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 org.springframework.bootstrap.autoconfigure.thymeleaf;
|
||||||
|
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Locale;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.springframework.bootstrap.autoconfigure.PropertyPlaceholderAutoConfiguration;
|
||||||
|
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
|
||||||
|
import org.springframework.core.env.MapPropertySource;
|
||||||
|
import org.springframework.mock.web.MockHttpServletRequest;
|
||||||
|
import org.springframework.mock.web.MockHttpServletResponse;
|
||||||
|
import org.springframework.mock.web.MockServletContext;
|
||||||
|
import org.springframework.web.context.support.AnnotationConfigWebApplicationContext;
|
||||||
|
import org.springframework.web.servlet.support.RequestContext;
|
||||||
|
import org.thymeleaf.TemplateEngine;
|
||||||
|
import org.thymeleaf.context.Context;
|
||||||
|
import org.thymeleaf.spring3.view.ThymeleafView;
|
||||||
|
import org.thymeleaf.spring3.view.ThymeleafViewResolver;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
import static org.junit.Assert.assertTrue;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Dave Syer
|
||||||
|
*/
|
||||||
|
public class ThymeleafAutoConfigurationTests {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void createFromConfigClass() throws Exception {
|
||||||
|
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
|
||||||
|
context.register(ThymeleafAutoConfiguration.class,
|
||||||
|
PropertyPlaceholderAutoConfiguration.class);
|
||||||
|
Map<String, Object> map = new HashMap<String, Object>();
|
||||||
|
map.put("spring.template.mode", "XHTML");
|
||||||
|
map.put("spring.template.suffix", "");
|
||||||
|
context.getEnvironment().getPropertySources()
|
||||||
|
.addFirst(new MapPropertySource("test", map));
|
||||||
|
context.refresh();
|
||||||
|
TemplateEngine engine = context.getBean(TemplateEngine.class);
|
||||||
|
Context attrs = new Context(Locale.UK, Collections.singletonMap("foo", "bar"));
|
||||||
|
String result = engine.process("template.txt", attrs);
|
||||||
|
assertEquals("<html>bar</html>", result);
|
||||||
|
context.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void createLayoutFromConfigClass() throws Exception {
|
||||||
|
AnnotationConfigWebApplicationContext context = new AnnotationConfigWebApplicationContext();
|
||||||
|
context.register(ThymeleafAutoConfiguration.class,
|
||||||
|
PropertyPlaceholderAutoConfiguration.class);
|
||||||
|
MockServletContext servletContext = new MockServletContext();
|
||||||
|
context.setServletContext(servletContext);
|
||||||
|
context.refresh();
|
||||||
|
ThymeleafView view = (ThymeleafView) context.getBean(ThymeleafViewResolver.class)
|
||||||
|
.resolveViewName("view", Locale.UK);
|
||||||
|
MockHttpServletResponse response = new MockHttpServletResponse();
|
||||||
|
MockHttpServletRequest request = new MockHttpServletRequest();
|
||||||
|
request.setAttribute(RequestContext.WEB_APPLICATION_CONTEXT_ATTRIBUTE, context);
|
||||||
|
view.render(Collections.singletonMap("foo", "bar"), request, response);
|
||||||
|
String result = response.getContentAsString();
|
||||||
|
assertTrue("Wrong result: " + result, result.contains("<title>Content</title>"));
|
||||||
|
assertTrue("Wrong result: " + result, result.contains("<span>bar</span>"));
|
||||||
|
context.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1 @@
|
|||||||
|
body: {background: red}
|
@ -0,0 +1,14 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html xmlns:th="http://www.thymeleaf.org" xmlns:layout="http://www.ultraq.net.nz/web/thymeleaf/layout">
|
||||||
|
<head>
|
||||||
|
<title layout:fragment="title">Layout</title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class="container">
|
||||||
|
<h1 layout:fragment="title">Layout</h1>
|
||||||
|
<div layout:fragment="content">
|
||||||
|
Fake content
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
@ -0,0 +1 @@
|
|||||||
|
<html th:text="${foo}">foo</html>
|
@ -0,0 +1,13 @@
|
|||||||
|
<?xml version="1.0" encoding="ISO-8859-1" ?>
|
||||||
|
<!DOCTYPE tiles-definitions PUBLIC
|
||||||
|
"-//Apache Software Foundation//DTD Tiles Configuration 2.1//EN"
|
||||||
|
"http://tiles.apache.org/dtds/tiles-config_2_1.dtd">
|
||||||
|
<tiles-definitions>
|
||||||
|
<definition name="*" template="layout">
|
||||||
|
<put-attribute name="content" value="content/{1}" />
|
||||||
|
<put-attribute name="title" value="title/{1}" />
|
||||||
|
</definition>
|
||||||
|
|
||||||
|
<definition name="content/*" template="{1} :: content" />
|
||||||
|
<definition name="title/*" template="{1} :: title" />
|
||||||
|
</tiles-definitions>
|
@ -0,0 +1,10 @@
|
|||||||
|
<html xmlns:th="http://www.thymeleaf.org" xmlns:layout="http://www.ultraq.net.nz/web/thymeleaf/layout" layout:decorator="layout">
|
||||||
|
<head>
|
||||||
|
<title layout:fragment="title">Content</title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div layout:fragment="content">
|
||||||
|
<span th:text="${foo}">foo</span>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
@ -0,0 +1 @@
|
|||||||
|
foo=bar
|
Loading…
Reference in New Issue