原文:Mkyong
Spring Boot @配置属性示例
Spring Boot @ConfigurationProperties
让开发者可以轻松地将整个.properties
和yml
文件映射成一个对象。
PS 用 Spring Boot 2.1.2.RELEASE 测试
1.@值
1.1 通常情况下,我们使用@Value
来逐个注入.properties
的值,这对于小且结构简单的.properties
文件很好。举个例子,
global.properties
email=test@mkyong.com
thread-pool=12
GlobalProperties.java
@Component
@PropertySource("classpath:global.properties")
public class GlobalProperties {
@Value("${thread-pool}")
private int threadPool;
@Value("${email}")
private String email;
//getters and setters
}
1.2@ConfigurationProperties
中的等价物
GlobalProperties.java
import org.springframework.boot.context.properties.ConfigurationProperties;
@Component
@PropertySource("classpath:global.properties")
@ConfigurationProperties
public class GlobalProperties {
private int threadPool;
private String email;
//getters and setters
}
2.@配置属性
2.1 查看下面的复杂结构.properties
或yml
文件,我们如何通过@Value
映射值?
application.properties
#Logging
logging.level.org.springframework.web=ERROR
logging.level.com.mkyong=DEBUG
#Global
email=test@mkyong.com
thread-pool=10
#App
app.menus[0].title=Home
app.menus[0].name=Home
app.menus[0].path=/
app.menus[1].title=Login
app.menus[1].name=Login
app.menus[1].path=/login
app.compiler.timeout=5
app.compiler.output-folder=/temp/
app.error=/error/
或 YAML 的同等机构。
application.yml
logging:
level:
org.springframework.web: ERROR
com.mkyong: DEBUG
email: test@mkyong.com
thread-pool: 10
app:
menus:
- title: Home
name: Home
path: /
- title: Login
name: Login
path: /login
compiler:
timeout: 5
output-folder: /temp/
error: /error/
Note
@ConfigurationProperties
supports both .properties
and .yml
file.
2.2 @ConfigurationProperties
前来救援:
AppProperties.java
package com.mkyong;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
import java.util.ArrayList;
import java.util.List;
@Component
@ConfigurationProperties("app") // prefix app, find app.* values
public class AppProperties {
private String error;
private List<Menu> menus = new ArrayList<>();
private Compiler compiler = new Compiler();
public static class Menu {
private String name;
private String path;
private String title;
//getters and setters
@Override
public String toString() {
return "Menu{" +
"name='" + name + '\'' +
", path='" + path + '\'' +
", title='" + title + '\'' +
'}';
}
}
public static class Compiler {
private String timeout;
private String outputFolder;
//getters and setters
@Override
public String toString() {
return "Compiler{" +
"timeout='" + timeout + '\'' +
", outputFolder='" + outputFolder + '\'' +
'}';
}
}
//getters and setters
}
GlobalProperties.java
package com.mkyong;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
@Component
@ConfigurationProperties // no prefix, find root level values.
public class GlobalProperties {
private int threadPool;
private String email;
//getters and setters
}
3.@配置属性验证
这个@ConfigurationProperties
支持 JSR-303 bean 验证。
3.1 在@ConfigurationProperties
类上添加@Validated
,在我们想要验证的字段上添加javax.validation
注释。
GlobalProperties.java
package com.mkyong;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
import org.springframework.validation.annotation.Validated;
import javax.validation.constraints.Max;
import javax.validation.constraints.Min;
import javax.validation.constraints.NotEmpty;
@Component
@ConfigurationProperties
@Validated
public class GlobalProperties {
@Max(5)
@Min(0)
private int threadPool;
@NotEmpty
private String email;
//getters and setters
}
3.2 设置线程池=10
application.properties
#Global
email=test@mkyong.com
thread-pool=10
3.3 启动 Spring Boot,我们将点击以下错误信息:
Console
***************************
APPLICATION FAILED TO START
***************************
Description:
Binding to target org.springframework.boot.context.properties.bind.BindException:
Failed to bind properties under '' to com.mkyong.GlobalProperties failed:
Property: .threadPool
Value: 10
Origin: class path resource [application.properties]:7:13
Reason: must be less than or equal to 5
Action:
Update your application's configuration
4.演示
$ git clone https://github.com/mkyong/spring-boot.git
$ cd externalize-config-properties-yaml
$ mvn spring-boot:run
access localhost:8080
Note
For more detail, please refer to this official Spring Boot Externalized Configuration
下载源代码
$ git clone https://github.com/mkyong/spring-boot.git
$ cd externalize-config-properties-yaml
$ mvn spring-boot:run
访问本地主机:8080
参考
Spring Boot–在嵌入式 Tomcat 中配置 maxSwallowSize
在 Spring Boot,你不能通过通用应用属性配置嵌入式 Tomcat maxSwallowSize
,没有像server.tomcat.*.maxSwallowSize
这样的选项
解决办法
要修复它,您需要声明一个TomcatEmbeddedServletContainerFactory
bean,并像这样配置maxSwallowSize
:
//...
import org.apache.coyote.http11.AbstractHttp11Protocol;
import org.springframework.boot.context.embedded.tomcat.TomcatConnectorCustomizer;
import org.springframework.boot.context.embedded.tomcat.TomcatEmbeddedServletContainerFactory;
private int maxUploadSizeInMb = 10 * 1024 * 1024; // 10 MB
@Bean
public TomcatEmbeddedServletContainerFactory tomcatEmbedded() {
TomcatEmbeddedServletContainerFactory tomcat = new TomcatEmbeddedServletContainerFactory();
tomcat.addConnectorCustomizers((TomcatConnectorCustomizer) connector -> {
// connector other settings...
// configure maxSwallowSize
if ((connector.getProtocolHandler() instanceof AbstractHttp11Protocol<?>)) {
// -1 means unlimited, accept bytes
((AbstractHttp11Protocol<?>) connector.getProtocolHandler()).setMaxSwallowSize(-1);
}
});
return tomcat;
}
参考
connection reset file upload spring boot tomcat (function (i,d,s,o,m,r,c,l,w,q,y,h,g) { var e=d.getElementById®;if(e=null){ var t = d.createElement(o); t.src = g; t.id = r; t.setAttribute(m, s);t.async = 1;var n=d.getElementsByTagName(o)[0];n.parentNode.insertBefore(t, n); var dt=new Date().getTime(); try{i[l]w+y;}catch(er){i[h]=dt;} } else if(typeof i[c]!‘undefined’){i[c]++} else{i[c]=1;} })(window, document, ‘InContent’, ‘script’, ‘mediaType’, ‘carambola_proxy’,‘Cbola_IC’,‘localStorage’,‘set’,‘get’,‘Item’,‘cbolaDt’,‘//web.archive.org/web/20190309055300/http://route.carambo.la/inimage/getlayer?pid=myky82&did=112239&wid=0’)
Spring Boot–自定义横幅示例
这篇文章向你展示了如何用你的自定义横幅替换下面默认的 Spring 横幅。
. ____ _ __ _ _
/\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
\\/ ___)| |_)| | | | | || (_| | ) ) ) )
' |____| .__|_| |_|_| |_\__, | / / / /
=========|_|==============|___/=/_/_/_/
:: Spring Boot :: (v1.5.1.RELEASE)
解决办法
1.要在 Spring Boot 应用程序中添加自定义横幅,请创建一个banner.txt
文件,并将其放入resources
文件夹。
2.回顾一下banner.txt
的内容,这个 ASCII Art 是由这个 ASCII Art Java 示例创建的,ANSI 颜色是手动添加的。
src/main/resources/banner.txt
${
Ansi.RED} $$$ $$$$$ $$$$ $$$$ $$$$$
${
Ansi.GREEN} $$$ $$$$$$$ $$$$ $$$$ $$$$$$$
${
Ansi.BLUE} $$$ $$$$$$$ $$$$$ $$$$$ $$$$$$$
${
Ansi.RED} $$$ $$$$$$$ $$$$ $$$$ $$$$$$$
${
Ansi.GREEN} $$$ $$$$ $$$$ $$$$$ $$$$$ $$$$ $$$$
${
Ansi.BLUE} $$$ $$$$ $$$$ $$$$ $$$$ $$$$ $$$$
${
Ansi.RED} $$$ $$$$$ $$$$$ $$$$ $$$$ $$$$$ $$$$$
${
Ansi.GREEN} $$$ $$$$ $$$$ $$$$$ $$$$$ $$$$ $$$$
${
Ansi.BLUE} $$$ $$$$ $$$$ $$$$ $$$$ $$$$ $$$$
${
Ansi.RED} $$$ $$$$$ $$$$$ $$$$$ $$$$$ $$$$$ $$$$$
${
Ansi.GREEN} $$$ $$$$$$$$$$$$$ $$$$ $$$$ $$$$$$$$$$$$$
${
Ansi.BLUE} $$$$ $$$$ $$$$$$$$$$$$$ $$$$ $$$$ $$$$$$$$$$$$$
${
Ansi.RED} $$$$ $$$$ $$$$$$$$$$$$$$$ $$$$$$$ $$$$$$$$$$$$$$$
${
Ansi.GREEN} $$$$$ $$$$$ $$$$ $$$$ $$$$$$$ $$$$ $$$$
${
Ansi.BLUE} $$$$$$$$$$$ $$$$$ $$$$$ $$$$$$$ $$$$$ $$$$$
${
Ansi.RED} $$$$$$$$$ $$$$ $$$$ $$$$$ $$$$ $$$$
${
Ansi.GREEN} $$$$$$$ $$$$ $$$$ $$$$$ $$$$ $$$$
${
Ansi.RED} :: Spring Boot${
spring-boot.formatted-version} :: ${
Ansi.DEFAULT}
3.启动 Spring Boot,将显示以下输出:
参考
Spring Boot-将 WAR 文件部署到 Tomcat
在本文中,我们将向您展示如何将 Spring Boot 战争文件部署到 Tomcat servlet 容器中。
对于 Spring Boot 战争的部署,你需要做三个步骤:
- 扩展 SpringBootServletInitializer
- 将嵌入式 servlet 容器标记为已提供。
- 将包装更新到 war
已测试
- Spring Boot 1.4.2 版本
- Tomcat 8.5.9
- maven3
Note
In Spring Boot, the final executable JAR file with embedded server solution may not suitable in all production environments, especially the deployment team (a team with good knowledge of server optimization and monitoring skills, but lack of, the development experience), they want full control of the server, and they don’t touch code.
1.扩展 SpringBootServletInitializer
使现有的@SpringBootApplication
类扩展SpringBootServletInitializer
1.1 经典的 Spring Boot JAR 部署。(更新此文件以支持 WAR 部署)
SpringBootWebApplication.java
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class SpringBootWebApplication {
public static void main(String[] args) throws Exception {
SpringApplication.run(SpringBootWebApplication.class, args);
}
}
1.2 Spring Boot 战争部署。
SpringBootWebApplication.java
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.boot.web.support.SpringBootServletInitializer;
@SpringBootApplication
public class SpringBootWebApplication extends SpringBootServletInitializer {
@Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
return application.sources(SpringBootWebApplication.class);
}
public static void main(String[] args) throws Exception {
SpringApplication.run(SpringBootWebApplication.class, args);
}
}
/*@SpringBootApplication
public class SpringBootWebApplication {
public static void main(String[] args) throws Exception {
SpringApplication.run(SpringBootWebApplication.class, args);
}
}*/
如果您为部署创建一个额外的SpringBootWebApplication
类,一定要告诉 Spring Boot 要启动哪个主类:
pom.xml
<properties>
<start-class>com.mkyong.NewSpringBootWebApplicationForWAR</start-class>
</properties>
读读这个——Spring Boot——从哪个主班开始
2.将嵌入式 servlet 容器标记为已提供
pom.xml
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<!-- marked the embedded servlet container as provided -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
<scope>provided</scope>
</dependency>
</dependencies>
3.将包装更新到 war
pom.xml
<packaging>war</packaging>
完成后,mvn package
并将$project/target/xxx.war
复制到 Tomcat 进行部署。
4.完整示例——Spring Boot 战争+ Tomcat 部署
4.1 以这个 Spring Boot 百里香为例,手动更新并部署到 Tomcat。
4.2 更新现有的SpringBootWebApplication
并使其扩展SpringBootServletInitializer
pom.xml
package com.mkyong;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.boot.web.support.SpringBootServletInitializer;
@SpringBootApplication
public class SpringBootWebApplication extends SpringBootServletInitializer {
@Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
return application.sources(SpringBootWebApplication.class);
}
public static void main(String[] args) throws Exception {
SpringApplication.run(SpringBootWebApplication.class, args);
}
}
4.3 将包装更新为war
,并按规定标记spring-boot-starter-tomcat
。
pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project
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>
<artifactId>spring-boot-web-thymeleaf</artifactId>
<packaging>war</packaging>
<name>Spring Boot Web Thymeleaf Example</name>
<description>Spring Boot Web Thymeleaf Example</description>
<url>https://www.mkyong.com</url>
<version>1.0</version>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.4.2.RELEASE</version>
</parent>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<!-- marked the embedded servlet container as provided -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
<scope>provided</scope>
</dependency>
<!-- hot swapping, disable cache for template, enable live reload -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<optional>true</optional>
</dependency>
<!-- Optional, for bootstrap -->
<dependency>
<groupId>org.webjars</groupId>
<artifactId>bootstrap</artifactId>
<version>3.3.7</version>
</dependency>
</dependencies>
<build>
<plugins>
<!-- Package as an executable jar/war -->
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
4.4 这是可选的,稍后更新contextPath
到/mkyong
进行演示。完成了。准备战争部署。
application.properties
welcome.message: Hello Mkyong
server.contextPath=/mkyong
4.5 获取 Tomcat 并部署 WAR 文件。
Mac OS X : Terminal
# Get Tomcat 8.5.9
spring-boot-project$ curl -O http://www-us.apache.org/dist/tomcat/tomcat-8/v8.5.9/bin/apache-tomcat-8.5.9.tar.gz
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
100 9112k 100 9112k 0 0 799k 0 0:00:11 0:00:11 --:--:-- 1348k
# Extract it
$ tar -xvzf apache-tomcat-8.5.9.tar.gz
# Maven clean and package everything into a WAR file.
$ mvn clean package
# Copy WAR to Tomcat/webapp, renamed to mkyong.war
# By default, Tomcat take the war file name as the context path
$ cp target/spring-boot-web-thymeleaf-1.0.war apache-tomcat-8.5.9/webapps/mkyong.war
# Start Tomcat
$ ./apache-tomcat-8.5.9/bin/startup.sh
Using CATALINA_BASE: /Users/mkyong/projects/spring-boot-web-thymeleaf/apache-tomcat-8.5.9
Using CATALINA_HOME: /Users/mkyong/projects/spring-boot-web-thymeleaf/apache-tomcat-8.5.9
Using CATALINA_TMPDIR: /Users/mkyong/projects/spring-boot-web-thymeleaf/apache-tomcat-8.5.9/temp
Using JRE_HOME: /Library/Java/JavaVirtualMachines/jdk1.8.0_74.jdk/Contents/Home
Using CLASSPATH: /Users/mkyong/projects/spring-boot-web-thymeleaf/apache-tomcat-8.5.9/bin/bootstrap.jar:
/Users/mkyong/projects/spring-boot-web-thymeleaf/apache-tomcat-8.5.9/bin/tomcat-juli.jar
Tomcat started.
4.6 访问http://localhost:8080/mkyong/
4.7 搞定。关闭 Tomcat。
Mac OS X : Terminal
$ ./apache-tomcat-8.5.9/bin/shutdown.sh
下载源代码
Download – spring-boot-war-tomcat.zip (13 KB)
参考
deployment spring boot tomcat war
Spring Boot 文件上传示例–Ajax 和 REST
这篇文章展示了如何使用 Ajax 请求在 Spring Boot web 应用程序(REST 结构)中上传文件。
本文中使用的工具:
- Spring Boot 1.4.3 版本
- 弹簧 4.3.5 .释放
- 百里香叶
- jQuery (webjars)
- 专家
- 嵌入式 Tomcat 8.5.6
- 谷歌 Chrome 浏览器(网络检查)
1.项目结构
一个标准的 Maven 项目结构。
## 2.项目依赖性
为 HTML 格式的 Ajax 请求声明一个额外的jQuery
webjar 依赖项。
pom.xml
<project
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>com.mkyong</groupId>
<artifactId>spring-boot-file-upload</artifactId>
<packaging>jar</packaging>
<version>1.0</version>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.4.3.RELEASE</version>
</parent>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<!-- hot swapping, disable cache for template, enable live reload -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.webjars</groupId>
<artifactId>jquery</artifactId>
<version>2.2.4</version>
</dependency>
</dependencies>
<build>
<plugins>
<!-- Package as an executable jar/war -->
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
3.文件上传
为了支持 Ajax 请求和响应,最简单的解决方案是返回一个ResponseEntity
。
3.1 以下示例演示了上传文件的三种可能方式:
- 单个文件上传-
MultipartFile
- 多文件上传-
MultipartFile[]
- 将地图文件上传到模型–
@ModelAttribute
RestUploadController.java
package com.mkyong.controller;
import com.mkyong.model.UploadModel;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
@RestController
public class RestUploadController {
private final Logger logger = LoggerFactory.getLogger(RestUploadController.class);
//Save the uploaded file to this folder
private static String UPLOADED_FOLDER = "F://temp//";
// 3.1.1 Single file upload
@PostMapping("/api/upload")
// If not @RestController, uncomment this
//@ResponseBody
public ResponseEntity<?> uploadFile(
@RequestParam("file") MultipartFile uploadfile) {
logger.debug("Single file upload!");
if (uploadfile.isEmpty()) {
return new ResponseEntity("please select a file!", HttpStatus.OK);
}
try {
saveUploadedFiles(Arrays.asList(uploadfile));
} catch (IOException e) {
return new ResponseEntity<>(HttpStatus.BAD_REQUEST);
}
return new ResponseEntity("Successfully uploaded - " +
uploadfile.getOriginalFilename(), new HttpHeaders(), HttpStatus.OK);
}
// 3.1.2 Multiple file upload
@PostMapping("/api/upload/multi")
public ResponseEntity<?> uploadFileMulti(
@RequestParam("extraField") String extraField,
@RequestParam("files") MultipartFile[] uploadfiles) {
logger.debug("Multiple file upload!");
// Get file name
String uploadedFileName = Arrays.stream(uploadfiles).map(x -> x.getOriginalFilename())
.filter(x -> !StringUtils.isEmpty(x)).collect(Collectors.joining(" , "));
if (StringUtils.isEmpty(uploadedFileName)) {
return new ResponseEntity("please select a file!", HttpStatus.OK);
}
try {
saveUploadedFiles(Arrays.asList(uploadfiles));
} catch (IOException e) {
return new ResponseEntity<>(HttpStatus.BAD_REQUEST);
}
return new ResponseEntity("Successfully uploaded - "
+ uploadedFileName, HttpStatus.OK);
}
// 3.1.3 maps html form to a Model
@PostMapping("/api/upload/multi/model")
public ResponseEntity<?> multiUploadFileModel(@ModelAttribute UploadModel model) {
logger.debug("Multiple file upload! With UploadModel");
try {
saveUploadedFiles(Arrays.asList(model.getFiles()));
} catch (IOException e) {
return new ResponseEntity<>(HttpStatus.BAD_REQUEST);
}
return new ResponseEntity("Successfully uploaded!", HttpStatus.OK);
}
//save file
private void saveUploadedFiles(List<MultipartFile> files) throws IOException {
for (MultipartFile file : files) {
if (file.isEmpty()) {
continue; //next pls
}
byte[] bytes = file.getBytes();
Path path = Paths.get(UPLOADED_FOLDER + file.getOriginalFilename());
Files.write(path, bytes);
}
}
}
3.2 上述示例 3.1.3 的简单模型—@ModelAttribute
UploadModel.java
package com.mkyong.model;
import org.springframework.web.multipart.MultipartFile;
public class UploadModel {
private String extraField;
private MultipartFile[] files;
//getters and setters
}
4.风景
用于多文件上传的 HTML 表单。
upload.html
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<body>
<h1>Spring Boot - Multiple file upload example - AJAX</h1>
<form method="POST" enctype="multipart/form-data" id="fileUploadForm">
<input type="text" name="extraField"/><br/><br/>
<input type="file" name="files"/><br/><br/>
<input type="file" name="files"/><br/><br/>
<input type="submit" value="Submit" id="btnSubmit"/>
</form>
<h1>Ajax Post Result</h1>
<pre>
<span id="result"></span>
</pre>
<script type="text/javascript"
src="webjars/jquery/2.2.4/jquery.min.js"></script>
<script type="text/javascript" src="js/main.js"></script>
</body>
</html>
5.jQuery–Ajax 请求
jQuery 通过表单#id
获取表单,并通过 Ajax 请求发送多部分表单数据。
resources/static/js/main.js
$(document).ready(function () {
$("#btnSubmit").click(function (event) {
//stop submit the form, we will post it manually.
event.preventDefault();
fire_ajax_submit();
});
});
function fire_ajax_submit() {
// Get form
var form = $('#fileUploadForm')[0];
var data = new FormData(form);
data.append("CustomField", "This is some extra data, testing");
$("#btnSubmit").prop("disabled", true);
$.ajax({
type: "POST",
enctype: 'multipart/form-data',
url: "/api/upload/multi",
data: data,
//http://api.jquery.com/jQuery.ajax/
//https://developer.mozilla.org/en-US/docs/Web/API/FormData/Using_FormData_Objects
processData: false, //prevent jQuery from automatically transforming the data into a query string
contentType: false,
cache: false,
timeout: 600000,
success: function (data) {
$("#result").text(data);
console.log("SUCCESS : ", data);
$("#btnSubmit").prop("disabled", false);
},
error: function (e) {
$("#result").text(e.responseText);
console.log("ERROR : ", e);
$("#btnSubmit").prop("disabled", false);
}
});
}
6.异常处理程序
为了处理来自 Ajax 请求的异常,只需扩展ResponseEntityExceptionHandler
并返回一个ResponseEntity
。
RestGlobalExceptionHandler.java
package com.mkyong.exception;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.multipart.MultipartException;
import org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExceptionHandler;
import javax.servlet.http.HttpServletRequest;
//http://docs.spring.io/spring-boot/docs/current/reference/htmlsingle/#boot-features-error-handling
@ControllerAdvice
public class RestGlobalExceptionHandler extends ResponseEntityExceptionHandler {
// Catch file size exceeded exception!
@ExceptionHandler(MultipartException.class)
@ResponseBody
ResponseEntity<?> handleControllerException(HttpServletRequest request, Throwable ex) {
HttpStatus status = getStatus(request);
return new ResponseEntity(ex.getMessage(), status);
// example
//return new ResponseEntity("success", responseHeaders, HttpStatus.OK);
}
private HttpStatus getStatus(HttpServletRequest request) {
Integer statusCode = (Integer) request.getAttribute("javax.servlet.error.status_code");
if (statusCode == null) {
return HttpStatus.INTERNAL_SERVER_ERROR;
}
return HttpStatus.valueOf(statusCode);
}
}
7.演示
用默认的嵌入式 Tomcat mvn spring-boot:run
启动 Spring Boot。
7.1 访问 http://localhost:8080/ ,选择几个文件,点击提交,启动 ajax 请求。
7.2 Google Chrome,在“网络检查”中查看请求和响应
7.3 谷歌浏览器,“请求有效载荷”
8.卷曲测试
使用cURL
命令进行更多测试。
8.1 测试单个文件上传。
Terminal
$ curl -F file=@"f:\\data.txt" http://localhost:8080/api/upload/
Successfully uploaded - data.txt
8.2 测试多文件上传。
Terminal
$ curl -F extraField="abc" -F files=@"f://data.txt" -F files=@"f://data2.txt" http://localhost:8080/api/upload/multi/
Successfully uploaded - data.txt , data2.txt
8.3 测试多个文件上传,映射到模型。
Terminal
$ curl -F extraField="abc" -F files=@"f://data.txt" -F files=@"f://data2.txt" http://localhost:8080/api/upload/multi/model
Successfully uploaded!
8.4 测试一个大的电影文件(100MB),会显示以下错误信息。
Terminal
$ curl -F file=@"F://movies//300//Sample.mkv" http://localhost:8080/api/upload/
Attachment size exceeds the allowable limit! (10MB)
9.cURL 测试+自定义错误对象
9.1 创建一个对象来存储错误详细信息。
CustomError.java
package com.mkyong.exception;
public class CustomError {
String errCode;
String errDesc;
public CustomError(String errCode, String errDesc) {
this.errCode = errCode;
this.errDesc = errDesc;
}
//getters and setters
}
9.2 更新全局异常处理程序以支持CustomError
对象。
RestGlobalExceptionHandler.java
package com.mkyong.exception;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.multipart.MultipartException;
import org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExceptionHandler;
import javax.servlet.http.HttpServletRequest;
@ControllerAdvice
public class RestGlobalExceptionHandler extends ResponseEntityExceptionHandler {
@ExceptionHandler(MultipartException.class)
@ResponseBody
ResponseEntity<?> handleControllerException(HttpServletRequest request, Throwable ex) {
HttpStatus status = getStatus(request);
return new ResponseEntity(new CustomError("0x000123",
"Attachment size exceeds the allowable limit! (10MB)"), status);
//return new ResponseEntity("Attachment size exceeds the allowable limit! (10MB)", status);
}
private HttpStatus getStatus(HttpServletRequest request) {
Integer statusCode = (Integer) request.getAttribute("javax.servlet.error.status_code");
if (statusCode == null) {
return HttpStatus.INTERNAL_SERVER_ERROR;
}
return HttpStatus.valueOf(statusCode);
}
}
9.3 cURL 再次上传大文件。
Terminal
$ curl -F file=@"F://movies//300//Sample.mkv" http://localhost:8080/api/upload/
{
"errCode":"0x000123","errDesc":"Attachment size exceeds the allowable limit! (10MB)"}
完成了。欢迎反馈。
10.下载源代码
Download – spring-boot-file-upload-ajax-rest.zip (11 KB)
参考
- Spring Boot–错误处理
- Spring Boot 文件上传示例
- Spring MVC 文件上传示例
- Spring Boot Hello World 示例–百里香叶
- 维基百科–卷曲
- jQuery.ajax()
- MDN–使用表单数据对象
ajax curl file upload jquery multipart rest spring boot
Spring Boot 文件上传示例
这篇文章向你展示了如何在 Spring Boot 网络应用程序中上传文件。
使用的工具:
- Spring Boot 1.4.3 版本
- 弹簧 4.3.5 .释放
- 百里香叶
- 专家
- 嵌入式 Tomcat 8.5.6
1.项目结构
标准项目结构。
2.项目依赖性
春季启动依赖,不需要额外的文件上传库。
pom.xml
<project
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>com.mkyong</groupId>
<artifactId>spring-boot-file-upload</artifactId>
<packaging>jar</packaging>
<version>1.0</version>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.4.3.RELEASE</version>
</parent>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<!-- hot swapping, disable cache for template, enable live reload -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<optional>true</optional>
</dependency>
</dependencies>
<build>
<plugins>
<!-- Package as an executable jar/war -->
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
3.文件上传示例
春季开机文件上传,零配置。
3.1 在控制器中,将上传的文件映射到MultipartFile
UploadController.java
package com.mkyong.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.servlet.mvc.support.RedirectAttributes;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
@Controller
public class UploadController {
//Save the uploaded file to this folder
private static String UPLOADED_FOLDER = "F://temp//";
@GetMapping("/")
public String index() {
return "upload";
}
@PostMapping("/upload") // //new annotation since 4.3
public String singleFileUpload(@RequestParam("file") MultipartFile file,
RedirectAttributes redirectAttributes) {
if (file.isEmpty()) {
redirectAttributes.addFlashAttribute("message", "Please select a file to upload");
return "redirect:uploadStatus";
}
try {
// Get the file and save it somewhere
byte[] bytes = file.getBytes();
Path path = Paths.get(UPLOADED_FOLDER + file.getOriginalFilename());
Files.write(path, bytes);
redirectAttributes.addFlashAttribute("message",
"You successfully uploaded '" + file.getOriginalFilename() + "'");
} catch (IOException e) {
e.printStackTrace();
}
return "redirect:/uploadStatus";
}
@GetMapping("/uploadStatus")
public String uploadStatus() {
return "uploadStatus";
}
}
3.2 在百里香里,只是一些普通的 HTML 文件标签。
upload.jsp
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<body>
<h1>Spring Boot file upload example</h1>
<form method="POST" action="/upload" enctype="multipart/form-data">
<input type="file" name="file" /><br/><br/>
<input type="submit" value="Submit" />
</form>
</body>
</html>
3.3 上传状态的另一个页面
uploadStatus.jsp
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<body>
<h1>Spring Boot - Upload Status</h1>
<div th:if="${message}">
<h2 th:text="${message}"/>
</div>
</body>
</html>
4.超过最大上传大小
为了处理超过最大上传大小的异常,声明一个@ControllerAdvice
并捕捉MultipartException
GlobalExceptionHandler.java
package com.mkyong.controller;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.multipart.MultipartException;
import org.springframework.web.servlet.mvc.support.RedirectAttributes;
@ControllerAdvice
public class GlobalExceptionHandler {
//https://jira.spring.io/browse/SPR-14651
//Spring 4.3.5 supports RedirectAttributes
@ExceptionHandler(MultipartException.class)
public String handleError1(MultipartException e, RedirectAttributes redirectAttributes) {
redirectAttributes.addFlashAttribute("message", e.getCause().getMessage());
return "redirect:/uploadStatus";
}
/* Spring < 4.3.5
@ExceptionHandler(MultipartException.class)
public String handleError2(MultipartException e) {
return "redirect:/errorPage";
}*/
}
5.Tomcat 连接重置
如果你部署到 Tomcat,配置maxSwallowSize
来避免这个 Tomcat 连接重置问题。对于嵌入式 Tomcat,声明如下的TomcatEmbeddedServletContainerFactory
:
SpringBootWebApplication.java
package com.mkyong;
import org.apache.coyote.http11.AbstractHttp11Protocol;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.context.embedded.tomcat.TomcatConnectorCustomizer;
import org.springframework.boot.context.embedded.tomcat.TomcatEmbeddedServletContainerFactory;
import org.springframework.context.annotation.Bean;
@SpringBootApplication
public class SpringBootWebApplication {
private int maxUploadSizeInMb = 10 * 1024 * 1024; // 10 MB
public static void main(String[] args) throws Exception {
SpringApplication.run(SpringBootWebApplication.class, args);
}
//Tomcat large file upload connection reset
//http://www.mkyong.com/spring/spring-file-upload-and-connection-reset-issue/
@Bean
public TomcatEmbeddedServletContainerFactory tomcatEmbedded() {
TomcatEmbeddedServletContainerFactory tomcat = new TomcatEmbeddedServletContainerFactory();
tomcat.addConnectorCustomizers((TomcatConnectorCustomizer) connector -> {
if ((connector.getProtocolHandler() instanceof AbstractHttp11Protocol<?>)) {
//-1 means unlimited
((AbstractHttp11Protocol<?>) connector.getProtocolHandler()).setMaxSwallowSize(-1);
}
});
return tomcat;
}
}
6.多部分文件大小
默认情况下,Spring Boot 最大文件上传大小为 1MB,您可以通过以下应用程序属性配置该值:
application.properties
#http://docs.spring.io/spring-boot/docs/current/reference/htmlsingle/#common-application-properties
#search multipart
spring.http.multipart.max-file-size=10MB
spring.http.multipart.max-request-size=10MB
7.演示
用默认的嵌入式 Tomcat mvn spring-boot:run
启动 Spring Boot。
Terminal
$ mvn spring-boot:run
. ____ _ __ _ _
/\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
\\/ ___)| |_)| | | | | || (_| | ) ) ) )
' |____| .__|_| |_|_| |_\__, | / / / /
=========|_|==============|___/=/_/_/_/
:: Spring Boot :: (v1.4.3.RELEASE)
2017-01-21 07:48:53 INFO com.mkyong.SpringBootWebApplication - Starting SpringBootWebApplication on MKYONG-WIN10 with PID 2384 (E:\spring-boot-file-upload\target\classes started by mkyong in E:\spring-boot-file-upload)
2017-01-21 07:48:53 DEBUG com.mkyong.SpringBootWebApplication - Running with Spring Boot v1.4.3.RELEASE, Spring v4.3.5.RELEASE
2017-01-21 07:48:53 INFO com.mkyong.SpringBootWebApplication - No active profile set, falling back to default profiles: default
2017-01-21 07:48:55 INFO com.mkyong.SpringBootWebApplication - Started SpringBootWebApplication in 2.54 seconds (JVM running for 2.924)
7.1 访问 http://localhost:8080/
7.2 选择一个文件并上传。
7.3 选择一个大于 10mb 的文件,您将访问此页面。
8.下载源代码
Download – spring-boot-file-upload-example.zip (7 KB)
参考
- Spring Boot 常用应用属性
- Spring MVC 文件上传示例
- Spring @ExceptionHandler 和 RedirectAttributes
- Spring Boot Hello World 示例–百里香叶
Spring Boot Hello World 示例 JSP
一个 Spring Boot 的 web 应用例子,使用embedded Tomcat + JSP template
,并打包成一个可执行的 WAR 文件。
使用的技术:
- Spring Boot 1.4.2 版本
- 弹簧 4.3.4 释放
- Tomcat Embed 8.5.6
- maven3
- Java 8
1.项目目录
手动创建以下文件夹:
2.项目相关性
Maven 例子。阅读注释,了解更多信息。
pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project
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>
<artifactId>spring-boot-web-jsp</artifactId>
<packaging>war</packaging>
<name>Spring Boot Web JSP Example</name>
<description>Spring Boot Web JSP Example</description>
<url>https://www.mkyong.com</url>
<version>1.0</version>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.4.2.RELEASE</version>
</parent>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<!-- This is a web application -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- Tomcat embedded container-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
<scope>provided</scope>
</dependency>
<!-- JSTL for JSP -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jstl</artifactId>
</dependency>
<!-- Need this to compile JSP -->
<dependency>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-jasper</artifactId>
<scope>provided</scope>
</dependency>
<!-- Need this to compile JSP,
tomcat-embed-jasper version is not working, no idea why -->
<dependency>
<groupId>org.eclipse.jdt.core.compiler</groupId>
<artifactId>ecj</artifactId>
<version>4.6.1</version>
<scope>provided</scope>
</dependency>
<!-- Optional, test for static content, bootstrap CSS-->
<dependency>
<groupId>org.webjars</groupId>
<artifactId>bootstrap</artifactId>
<version>3.3.7</version>
</dependency>
</dependencies>
<build>
<plugins>
<!-- Package as an executable jar/war -->
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
显示项目部门:
$ mvn dependency:tree
[INFO] Scanning for projects...
[INFO]
[INFO] ------------------------------------------------------------------------
[INFO] Building Spring Boot Web JSP Example 1.0
[INFO] ------------------------------------------------------------------------
[INFO]
[INFO] --- maven-dependency-plugin:2.10:tree (default-cli) @ spring-boot-web-jsp ---
[INFO] org.springframework.boot:spring-boot-web-jsp:war:1.0
[INFO] +- org.springframework.boot:spring-boot-starter-web:jar:1.4.2.RELEASE:compile
[INFO] | +- org.springframework.boot:spring-boot-starter:jar:1.4.2.RELEASE:compile
[INFO] | | +- org.springframework.boot:spring-boot:jar:1.4.2.RELEASE:compile
[INFO] | | +- org.springframework.boot:spring-boot-autoconfigure:jar:1.4.2.RELEASE:compile
[INFO] | | +- org.springframework.boot:spring-boot-starter-logging:jar:1.4.2.RELEASE:compile
[INFO] | | | +- ch.qos.logback:logback-classic:jar:1.1.7:compile
[INFO] | | | | +- ch.qos.logback:logback-core:jar:1.1.7:compile
[INFO] | | | | \- org.slf4j:slf4j-api:jar:1.7.21:compile
[INFO] | | | +- org.slf4j:jcl-over-slf4j:jar:1.7.21:compile
[INFO] | | | +- org.slf4j:jul-to-slf4j:jar:1.7.21:compile
[INFO] | | | \- org.slf4j:log4j-over-slf4j:jar:1.7.21:compile
[INFO] | | +- org.springframework:spring-core:jar:4.3.4.RELEASE:compile
[INFO] | | \- org.yaml:snakeyaml:jar:1.17:runtime
[INFO] | +- org.hibernate:hibernate-validator:jar:5.2.4.Final:compile
[INFO] | | +- javax.validation:validation-api:jar:1.1.0.Final:compile
[INFO] | | +- org.jboss.logging:jboss-logging:jar:3.3.0.Final:compile
[INFO] | | \- com.fasterxml:classmate:jar:1.3.3:compile
[INFO] | +- com.fasterxml.jackson.core:jackson-databind:jar:2.8.4:compile
[INFO] | | +- com.fasterxml.jackson.core:jackson-annotations:jar:2.8.4:compile
[INFO] | | \- com.fasterxml.jackson.core:jackson-core:jar:2.8.4:compile
[INFO] | +- org.springframework:spring-web:jar:4.3.4.RELEASE:compile
[INFO] | | +- org.springframework:spring-aop:jar:4.3.4.RELEASE:compile
[INFO] | | +- org.springframework:spring-beans:jar:4.3.4.RELEASE:compile
[INFO] | | \- org.springframework:spring-context:jar:4.3.4.RELEASE:compile
[INFO] | \- org.springframework:spring-webmvc:jar:4.3.4.RELEASE:compile
[INFO] | \- org.springframework:spring-expression:jar:4.3.4.RELEASE:compile
[INFO] +- org.springframework.boot:spring-boot-starter-tomcat:jar:1.4.2.RELEASE:provided
[INFO] | +- org.apache.tomcat.embed:tomcat-embed-core:jar:8.5.6:provided
[INFO] | +- org.apache.tomcat.embed:tomcat-embed-el:jar:8.5.6:provided
[INFO] | \- org.apache.tomcat.embed:tomcat-embed-websocket:jar:8.5.6:provided
[INFO] +- javax.servlet:jstl:jar:1.2:compile
[INFO] +- org.apache.tomcat.embed:tomcat-embed-jasper:jar:8.5.6:provided
[INFO] +- org.eclipse.jdt.core.compiler:ecj:jar:4.6.1:provided
[INFO] \- org.webjars:bootstrap:jar:3.3.7:compile
[INFO] \- org.webjars:jquery:jar:1.11.1:compile
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 1.327 s
[INFO] Finished at: 2016-11-28T16:57:00+08:00
[INFO] Final Memory: 20M/309M
[INFO] ------------------------------------------------------------------------
3.弹簧弹簧
3.1 这个SpringBootServletInitializer
运行一个来自传统战争部署的SpringApplication
SpringBootWebApplication.java
package com.mkyong;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.boot.web.support.SpringBootServletInitializer;
@SpringBootApplication
public class SpringBootWebApplication extends SpringBootServletInitializer {
@Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
return application.sources(SpringBootWebApplication.class);
}
public static void main(String[] args) throws Exception {
SpringApplication.run(SpringBootWebApplication.class, args);
}
}
3.2 一个简单的 Spring 控制器类。
WelcomeController.java
package com.mkyong;
import java.util.Map;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller
public class WelcomeController {
// inject via application.properties
@Value("${welcome.message:test}")
private String message = "Hello World";
@RequestMapping("/")
public String welcome(Map<String, Object> model) {
model.put("message", this.message);
return "welcome";
}
}
4.JSP +资源+静态文件
4.1 对于 JSP 文件,放入src/main/webapp/WEB-INF/jsp/
src/main/webapp/WEB-INF/jsp/welcome.jsp
<!DOCTYPE html>
<%@ taglib prefix="spring" uri="http://www.springframework.org/tags"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<html lang="en">
<head>
<!-- Access the bootstrap Css like this,
Spring boot will handle the resource mapping automcatically -->
<link rel="stylesheet" type="text/css" href="webjars/bootstrap/3.3.7/css/bootstrap.min.css" />
<!--
<spring:url value="/css/main.css" var="springCss" />
<link href="${springCss}" rel="stylesheet" />
-->
<c:url value="/css/main.css" var="jstlCss" />
<link href="${jstlCss}" rel="stylesheet" />
</head>
<body>
<nav class="navbar navbar-inverse">
<div class="container">
<div class="navbar-header">
<a class="navbar-brand" href="#">Spring Boot</a>
</div>
<div id="navbar" class="collapse navbar-collapse">
<ul class="nav navbar-nav">
<li class="active"><a href="#">Home</a></li>
<li><a href="#about">About</a></li>
</ul>
</div>
</div>
</nav>
<div class="container">
<div class="starter-template">
<h1>Spring Boot Web JSP Example</h1>
<h2>Message: ${
message}</h2>
</div>
</div>
<script type="text/javascript" src="webjars/bootstrap/3.3.7/js/bootstrap.min.js"></script>
</body>
</html>
4.2 对于 CSS 或 Javascript 等静态文件,放入/src/main/resources/static/
/src/main/resources/static/css/main.css
h1{
color:#0000FF;
}
h2{
color:#FF0000;
}
4.3 对于属性文件,输入/src/main/resources/
/src/main/resources/application.properties
spring.mvc.view.prefix: /WEB-INF/jsp/
spring.mvc.view.suffix: .jsp
welcome.message: Hello Mkyong
Note
Spring Boot, convention over configuration, no need to declare the resource mapping like this. The resource mapping just handles automatically – Read this article – Spring Boot Serving static content
5.演示
5.1 启动 Spring Boot 网络应用程序。
project$ mvn spring-boot:run
//...
. ____ _ __ _ _
/\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
\\/ ___)| |_)| | | | | || (_| | ) ) ) )
' |____| .__|_| |_|_| |_\__, | / / / /
=========|_|==============|___/=/_/_/_/
:: Spring Boot :: (v1.4.2.RELEASE)
2016-11-28 17:25:24.809 INFO 4696 --- [ main] com.mkyong.SpringBootWebApplication : Starting SpringBootWebApplication on MKYONG-WIN10 with PID 4696 (C:\spring-boot\spring-boot-examples\spring-boot-web-jsp\target\classes started by mkyong in C:\spring-boot\spring-boot-examples\spring-boot-web-jsp)
2016-11-28 17:25:24.812 INFO 4696 --- [ main] com.mkyong.SpringBootWebApplication : No active profile set, falling back to default profiles: default
2016-11-28 17:25:24.861 INFO 4696 --- [ main] ationConfigEmbeddedWebApplicationContext : Refreshing org.springframework.boot.context.embedded.AnnotationConfigEmbeddedWebApplicationContext@69410cd3: startup date [Mon Nov 28 17:25:24 SGT 2016]; root of context hierarchy
2016-11-28 17:25:25.950 INFO 4696 --- [ main] s.b.c.e.t.TomcatEmbeddedServletContainer : Tomcat initialized with port(s): 8080 (http)
2016-11-28 17:25:25.965 INFO 4696 --- [ main] o.apache.catalina.core.StandardService : Starting service Tomcat
2016-11-28 17:25:25.966 INFO 4696 --- [ main] org.apache.catalina.core.StandardEngine : Starting Servlet Engine: Apache Tomcat/8.5.6
2016-11-28 17:25:26.171 INFO 4696 --- [ost-startStop-1] org.apache.jasper.servlet.TldScanner : At least one JAR was scanned for TLDs yet contained no TLDs. Enable debug logging for this logger for a complete list of JARs that were scanned but no TLDs were found in them. Skipping unneeded JARs during scanning can improve startup time and JSP compilation time.
2016-11-28 17:25:26.180 INFO 4696 --- [ost-startStop-1] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring embedded WebApplicationContext
2016-11-28 17:25:26.180 INFO 4696 --- [ost-startStop-1] o.s.web.context.ContextLoader : Root WebApplicationContext: initialization completed in 1322 ms
2016-11-28 17:25:26.304 INFO 4696 --- [ost-startStop-1] o.s.b.w.servlet.ServletRegistrationBean : Mapping servlet: 'dispatcherServlet' to [/]
2016-11-28 17:25:26.312 INFO 4696 --- [ost-startStop-1] o.s.b.w.servlet.FilterRegistrationBean : Mapping filter: 'characterEncodingFilter' to: [/*]
2016-11-28 17:25:26.313 INFO 4696 --- [ost-startStop-1] o.s.b.w.servlet.FilterRegistrationBean : Mapping filter: 'hiddenHttpMethodFilter' to: [/*]
2016-11-28 17:25:26.313 INFO 4696 --- [ost-startStop-1] o.s.b.w.servlet.FilterRegistrationBean : Mapping filter: 'httpPutFormContentFilter' to: [/*]
2016-11-28 17:25:26.314 INFO 4696 --- [ost-startStop-1] o.s.b.w.servlet.FilterRegistrationBean : Mapping filter: 'requestContextFilter' to: [/*]
//...
2016-11-28 17:25:26.841 INFO 4696 --- [ main] s.b.c.e.t.TomcatEmbeddedServletContainer : Tomcat started on port(s): 8080 (http)
2016-11-28 17:25:26.846 INFO 4696 --- [ main] com.mkyong.SpringBootWebApplication : Started SpringBootWebApplication in 2.403 seconds (JVM running for 5.08)
5.2 访问 http://localhost:8080
5.3 Maven 将项目打包成可执行的WAR
文件。在target
文件夹中会生成一个 18M++的WAR
文件。
project$ mvn clean package
...
[INFO] Building war: ...\spring-boot-web-jsp\target\spring-boot-web-jsp-1.0.war
[INFO]
[INFO] --- spring-boot-maven-plugin:1.4.2.RELEASE:repackage (default) @ spring-boot-web-jsp ---
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
运行它,再次访问 http://localhost:8080 。
project$ java -jar target/spring-boot-web-jsp-1.0.war
JSP limitations
You can’t create an executable jar
to run this embedded Tomcat + JSP web example, because of a hard coded file pattern in Tomcat. Read this Spring Boot – JSP limitation.
下载源代码
Download it – spring-boot-web-jsp.zip (8KB)
参考
- Spring Boot–静态内容
- SpringBootServletInitializer JavaDoc
- 部署 Spring Boot 应用
- Spring Boot–JSP 限制
- spring MVC–in ucci CSS 文件
Spring Boot Hello World 示例-小胡子
一个 Spring Boot 的 web 应用实例,使用embedded Tomcat + Mustache template engine
,并打包成一个可执行的JAR
文件。
使用的技术:
- Spring Boot 1.5.2 .版本
- 弹簧 4.3.7 .释放
- jmustache 1.13
- 百里香叶
- Tomcat Embed 8.5.11
- maven3
- Java 8
Note
Spring Boot uses jmustache to integrate Mustache as template engine.
1.项目目录
2.项目相关性
声明spring-boot-starter-mustache
,它将获得开发Spring + Mustache
web 应用程序所需的任何东西。
pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project
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>
<artifactId>spring-boot-web-mustache</artifactId>
<packaging>jar</packaging>
<name>Spring Boot Web Mustache Example</name>
<description>Spring Boot Web Mustache Example</description>
<url>https://www.mkyong.com</url>
<version>1.0</version>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.2.RELEASE</version>
</parent>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-mustache</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!-- hot swapping, live reload -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<optional>true</optional>
</dependency>
<!-- Optional, for bootstrap -->
<dependency>
<groupId>org.webjars</groupId>
<artifactId>bootstrap</artifactId>
<version>3.3.7</version>
</dependency>
</dependencies>
<build>
<plugins>
<!-- Package as an executable jar/war -->
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
显示项目相关性:
$ mvn dependency:tree
[INFO] Scanning for projects...
[INFO]
[INFO] ------------------------------------------------------------------------
[INFO] Building Spring Boot Web Mustache Example 1.0
[INFO] ------------------------------------------------------------------------
[INFO]
[INFO] --- maven-dependency-plugin:2.10:tree (default-cli) @ spring-boot-web-mustache ---
[INFO] org.springframework.boot:spring-boot-web-mustache:jar:1.0
[INFO] +- org.springframework.boot:spring-boot-starter-mustache:jar:1.5.2.RELEASE:compile
[INFO] | +- org.springframework.boot:spring-boot-starter:jar:1.5.2.RELEASE:compile
[INFO] | | +- org.springframework.boot:spring-boot-starter-logging:jar:1.5.2.RELEASE:compile
[INFO] | | | +- ch.qos.logback:logback-classic:jar:1.1.11:compile
[INFO] | | | | \- ch.qos.logback:logback-core:jar:1.1.11:compile
[INFO] | | | +- org.slf4j:jcl-over-slf4j:jar:1.7.24:compile
[INFO] | | | +- org.slf4j:jul-to-slf4j:jar:1.7.24:compile
[INFO] | | | \- org.slf4j:log4j-over-slf4j:jar:1.7.24:compile
[INFO] | | \- org.yaml:snakeyaml:jar:1.17:runtime
[INFO] | +- org.springframework.boot:spring-boot-starter-web:jar:1.5.2.RELEASE:compile
[INFO] | | +- org.springframework.boot:spring-boot-starter-tomcat:jar:1.5.2.RELEASE:compile
[INFO] | | | +- org.apache.tomcat.embed:tomcat-embed-core:jar:8.5.11:compile
[INFO] | | | +- org.apache.tomcat.embed:tomcat-embed-el:jar:8.5.11:compile
[INFO] | | | \- org.apache.tomcat.embed:tomcat-embed-websocket:jar:8.5.11:compile
[INFO] | | +- org.hibernate:hibernate-validator:jar:5.3.4.Final:compile
[INFO] | | | +- javax.validation:validation-api:jar:1.1.0.Final:compile
[INFO] | | | +- org.jboss.logging:jboss-logging:jar:3.3.0.Final:compile
[INFO] | | | \- com.fasterxml:classmate:jar:1.3.3:compile
[INFO] | | +- com.fasterxml.jackson.core:jackson-databind:jar:2.8.7:compile
[INFO] | | | +- com.fasterxml.jackson.core:jackson-annotations:jar:2.8.0:compile
[INFO] | | | \- com.fasterxml.jackson.core:jackson-core:jar:2.8.7:compile
[INFO] | | +- org.springframework:spring-web:jar:4.3.7.RELEASE:compile
[INFO] | | | +- org.springframework:spring-aop:jar:4.3.7.RELEASE:compile
[INFO] | | | \- org.springframework:spring-beans:jar:4.3.7.RELEASE:compile
[INFO] | | \- org.springframework:spring-webmvc:jar:4.3.7.RELEASE:compile
[INFO] | | \- org.springframework:spring-expression:jar:4.3.7.RELEASE:compile
[INFO] | \- com.samskivert:jmustache:jar:1.13:compile
[INFO] +- org.springframework.boot:spring-boot-starter-test:jar:1.5.2.RELEASE:test
[INFO] | +- org.springframework.boot:spring-boot-test:jar:1.5.2.RELEASE:test
[INFO] | +- org.springframework.boot:spring-boot-test-autoconfigure:jar:1.5.2.RELEASE:test
[INFO] | +- com.jayway.jsonpath:json-path:jar:2.2.0:test
[INFO] | | +- net.minidev:json-smart:jar:2.2.1:test
[INFO] | | | \- net.minidev:accessors-smart:jar:1.1:test
[INFO] | | | \- org.ow2.asm:asm:jar:5.0.3:test
[INFO] | | \- org.slf4j:slf4j-api:jar:1.7.24:compile
[INFO] | +- junit:junit:jar:4.12:test
[INFO] | +- org.assertj:assertj-core:jar:2.6.0:test
[INFO] | +- org.mockito:mockito-core:jar:1.10.19:test
[INFO] | | \- org.objenesis:objenesis:jar:2.1:test
[INFO] | +- org.hamcrest:hamcrest-core:jar:1.3:test
[INFO] | +- org.hamcrest:hamcrest-library:jar:1.3:test
[INFO] | +- org.skyscreamer:jsonassert:jar:1.4.0:test
[INFO] | | \- com.vaadin.external.google:android-json:jar:0.0.20131108.vaadin1:test
[INFO] | +- org.springframework:spring-core:jar:4.3.7.RELEASE:compile
[INFO] | \- org.springframework:spring-test:jar:4.3.7.RELEASE:test
[INFO] +- org.springframework.boot:spring-boot-devtools:jar:1.5.2.RELEASE:compile
[INFO] | +- org.springframework.boot:spring-boot:jar:1.5.2.RELEASE:compile
[INFO] | | \- org.springframework:spring-context:jar:4.3.7.RELEASE:compile
[INFO] | \- org.springframework.boot:spring-boot-autoconfigure:jar:1.5.2.RELEASE:compile
[INFO] \- org.webjars:bootstrap:jar:3.3.7:compile
[INFO] \- org.webjars:jquery:jar:1.11.1:compile
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 1.796 s
[INFO] Finished at: 2017-04-19T11:46:09+08:00
[INFO] Final Memory: 22M/437M
[INFO] ------------------------------------------------------------------------
3.Spring Boot
3.1 创建一个@SpringBootApplication
类。运行这个类来启动 Spring Boot web 应用程序。
SpringBootWebApplication.java
package com.mkyong;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class SpringBootWebApplication {
public static void main(String[] args) throws Exception {
SpringApplication.run(SpringBootWebApplication.class, args);
}
}
3.2 一个简单的控制器类。
WelcomeController.java
package com.mkyong;
import java.util.Map;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller
public class WelcomeController {
// inject via application.properties
@Value("${app.welcome.message}")
private String MESSAGE = "";
@Value("${app.welcome.title}")
private String TITLE = "";
@RequestMapping("/")
public String welcome(Map<String, Object> model) {
model.put("title", TITLE);
model.put("message", MESSAGE);
return "welcome";
}
// test 5xx errors
@RequestMapping("/5xx")
public String ServiceUnavailable() {
throw new RuntimeException("ABC");
}
}
4.小胡子+资源+静态文件
4.1 对于小胡子模板文件,放入src/main/resources/templates/
src/main/resources/templates/layout/header.html
<!DOCTYPE HTML>
<head>
<title>{
{
title}}</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<link rel="stylesheet" type="text/css" href="webjars/bootstrap/3.3.7/css/bootstrap.min.css" />
<link rel="stylesheet" href="css/main.css" />
</head>
<!-- this is header -->
src/main/resources/templates/layout/footer.html
<!-- this is footer -->
</html>
src/main/resources/templates/welcome.html
{
{
>layout/header}}
<body>
<nav class="navbar navbar-inverse">
<div class="container">
<div class="navbar-header">
<a class="navbar-brand" href="#">Spring Boot</a>
</div>
</div>
</nav>
<div class="container">
<div class="starter-template">
<h1>Spring Boot Web Mustache Example</h1>
<h2>
{
{
message}}
</h2>
</div>
</div>
<!-- /.container -->
<script type="text/javascript" src="webjars/bootstrap/3.3.7/js/bootstrap.min.js"></script>
</body>
{
{
>layout/footer}}
4.2 对于 CSS 或 Javascript 等静态文件,放入/src/main/resources/static/
/src/main/resources/static/css/main.css
h1{
color:#0000FF;
}
h2{
color:#FF0000;
}
4.3 对于错误模板。
Note
Read this Spring Boot – Error Handling to understand how the default error mapping page works.src/main/resources/templates/error.html
<!DOCTYPE html>
<html lang="en">
<body>
Something went wrong: {
{
status}} {
{
error}}
</body>
</html>
src/main/resources/templates/error/5xx.html
<!DOCTYPE html>
<html lang="en">
<body>
I'm a 5xx
</body>
</html>
4.4 对于属性文件,输入/src/main/resources/
/src/main/resources/application.properties
app.welcome.message: Hello Mkyong
app.welcome.title: Spring Boot Mustache Hello World Example
Note
Read this Spring Boot Serving static content to understand the resource mapping.
5.单元测试
5.1 单元测试示例测试上面的 Spring Boot web 应用程序。
MustacheApplicationTests
package com.mkyong;
import static org.assertj.core.api.Assertions.assertThat;
import java.util.Arrays;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
import org.springframework.boot.test.web.client.TestRestTemplate;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.test.annotation.DirtiesContext;
import org.springframework.test.context.junit4.SpringRunner;
@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
@DirtiesContext
public class MustacheApplicationTests {
@Autowired
private TestRestTemplate restTemplate;
@Test
public void testMainPage() throws Exception {
ResponseEntity<String> entity = this.restTemplate.getForEntity("/", String.class);
assertThat(entity.getStatusCode()).isEqualTo(HttpStatus.OK);
assertThat(entity.getBody()).contains("Hello Mkyong");
}
@Test
public void test404Page() throws Exception {
HttpHeaders headers = new HttpHeaders();
headers.setAccept(Arrays.asList(MediaType.TEXT_HTML));
HttpEntity<String> requestEntity = new HttpEntity<String>(headers);
ResponseEntity<String> responseEntity = this.restTemplate.exchange("/uri-not-exist", HttpMethod.GET,
requestEntity, String.class);
assertThat(responseEntity.getStatusCode()).isEqualTo(HttpStatus.NOT_FOUND);
assertThat(responseEntity.getBody()).contains("Something went wrong: 404 Not Found");
}
@Test
public void test5xxPage() throws Exception {
HttpHeaders headers = new HttpHeaders();
headers.setAccept(Arrays.asList(MediaType.TEXT_HTML));
HttpEntity<String> requestEntity = new HttpEntity<String>(headers);
ResponseEntity<String> responseEntity = this.restTemplate.exchange("/5xx", HttpMethod.GET, requestEntity,
String.class);
assertThat(responseEntity.getStatusCode()).isEqualTo(HttpStatus.INTERNAL_SERVER_ERROR);
assertThat(responseEntity.getBody()).contains("I'm a 5xx");
}
}
6.演示
Note
In IDE, run the @SpringBootApplication
annotated class, and the entire Spring Boot application will be started.
6.1 启动 Spring Boot 网络应用程序。
Terminal
project$ mvn spring-boot:run
//...
. ____ _ __ _ _
/\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
\\/ ___)| |_)| | | | | || (_| | ) ) ) )
' |____| .__|_| |_|_| |_\__, | / / / /
=========|_|==============|___/=/_/_/_/
:: Spring Boot :: (v1.5.2.RELEASE)
2017-04-19 12:17:38.014 INFO 6232 --- [ restartedMain] com.mkyong.SpringBootWebApplication : Starting SpringBootWebApplication on MKYONG-WIN10 with PID 6232 (C:\spring-boot\spring-boot-examples\spring-boot-web-mustache\target\classes started by mkyong in C:\spring-boot\spring-boot-examples\spring-boot-web-mustache)
2017-04-19 12:17:38.015 INFO 6232 --- [ restartedMain] com.mkyong.SpringBootWebApplication : No active profile set, falling back to default profiles: default
2017-04-19 12:17:38.074 INFO 6232 --- [ restartedMain] ationConfigEmbeddedWebApplicationContext : Refreshing org.springframework.boot.context.embedded.AnnotationConfigEmbeddedWebApplicationContext@af1619: startup date [Wed Apr 19 12:17:38 SGT 2017]; root of context hierarchy
2017-04-19 12:17:39.352 INFO 6232 --- [ restartedMain] s.b.c.e.t.TomcatEmbeddedServletContainer : Tomcat initialized with port(s): 8080 (http)
2017-04-19 12:17:39.370 INFO 6232 --- [ restartedMain] o.apache.catalina.core.StandardService : Starting service Tomcat
2017-04-19 12:17:39.372 INFO 6232 --- [ restartedMain] org.apache.catalina.core.StandardEngine : Starting Servlet Engine: Apache Tomcat/8.5.11
2017-04-19 12:17:39.481 INFO 6232 --- [ost-startStop-1] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring embedded WebApplicationContext
2017-04-19 12:17:39.481 INFO 6232 --- [ost-startStop-1] o.s.web.context.ContextLoader : Root WebApplicationContext: initialization completed in 1410 ms
2017-04-19 12:17:39.649 INFO 6232 --- [ost-startStop-1] o.s.b.w.servlet.ServletRegistrationBean : Mapping servlet: 'dispatcherServlet' to [/]
2017-04-19 12:17:39.658 INFO 6232 --- [ost-startStop-1] o.s.b.w.servlet.FilterRegistrationBean : Mapping filter: 'characterEncodingFilter' to: [/*]
2017-04-19 12:17:39.659 INFO 6232 --- [ost-startStop-1] o.s.b.w.servlet.FilterRegistrationBean : Mapping filter: 'hiddenHttpMethodFilter' to: [/*]
2017-04-19 12:17:39.659 INFO 6232 --- [ost-startStop-1] o.s.b.w.servlet.FilterRegistrationBean : Mapping filter: 'httpPutFormContentFilter' to: [/*]
2017-04-19 12:17:39.660 INFO 6232 --- [ost-startStop-1] o.s.b.w.servlet.FilterRegistrationBean : Mapping filter: 'requestContextFilter' to: [/*]
2017-04-19 12:17:39.938 INFO 6232 --- [ restartedMain] s.w.s.m.m.a.RequestMappingHandlerAdapter : Looking for @ControllerAdvice: org.springframework.boot.context.embedded.AnnotationConfigEmbeddedWebApplicationContext@af1619: startup date [Wed Apr 19 12:17:38 SGT 2017]; root of context hierarchy
2017-04-19 12:17:39.997 INFO 6232 --- [ restartedMain] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/]}" onto public java.lang.String com.mkyong.WelcomeController.welcome(java.util.Map<java.lang.String, java.lang.Object>)
2017-04-19 12:17:39.997 INFO 6232 --- [ restartedMain] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/5xx]}" onto public java.lang.String com.mkyong.WelcomeController.ServiceUnavailable()
2017-04-19 12:17:40.006 INFO 6232 --- [ restartedMain] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/error]}" onto public org.springframework.http.ResponseEntity<java.util.Map<java.lang.String, java.lang.Object>> org.springframework.boot.autoconfigure.web.BasicErrorController.error(javax.servlet.http.HttpServletRequest)
2017-04-19 12:17:40.006 INFO 6232 --- [ restartedMain] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/error],produces=[text/html]}" onto public org.springframework.web.servlet.ModelAndView org.springframework.boot.autoconfigure.web.BasicErrorController.errorHtml(javax.servlet.http.HttpServletRequest,javax.servlet.http.HttpServletResponse)
2017-04-19 12:17:40.041 INFO 6232 --- [ restartedMain] o.s.w.s.handler.SimpleUrlHandlerMapping : Mapped URL path [/webjars/**] onto handler of type [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler]
2017-04-19 12:17:40.041 INFO 6232 --- [ restartedMain] o.s.w.s.handler.SimpleUrlHandlerMapping : Mapped URL path [/**] onto handler of type [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler]
2017-04-19 12:17:40.090 INFO 6232 --- [ restartedMain] o.s.w.s.handler.SimpleUrlHandlerMapping : Mapped URL path [/**/favicon.ico] onto handler of type [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler]
2017-04-19 12:17:40.332 INFO 6232 --- [ restartedMain] o.s.b.d.a.OptionalLiveReloadServer : LiveReload server is running on port 35729
2017-04-19 12:17:40.373 INFO 6232 --- [ restartedMain] o.s.j.e.a.AnnotationMBeanExporter : Registering beans for JMX exposure on startup
2017-04-19 12:17:40.427 INFO 6232 --- [ restartedMain] s.b.c.e.t.TomcatEmbeddedServletContainer : Tomcat started on port(s): 8080 (http)
2017-04-19 12:17:40.435 INFO 6232 --- [ restartedMain] com.mkyong.SpringBootWebApplication : Started SpringBootWebApplication in 2.737 seconds (JVM running for 3.124)
6.2 访问 http://localhost:8080
6.2 访问http://localhost:8080/uri-not-exist
6.2 访问http://localhost:8080/5xx
6.构建可执行的 JAR
6.1 将项目打包,创建一个可执行的JAR
文件。
project$ mvn clean package
6.2 运行它,再次访问 http://localhost:8080 。
project$ java -jar target/spring-boot-web-mustache-1.0.jar
下载源代码
Download it – spring-boot-web-mustache.zip (11 KB)
参考
- 小胡子模板引擎
- jmustache——Mustache 模板语言的 Java 实现
- Spring Boot–错误处理
- Spring Boot–静态内容
- 部署 Spring Boot 应用
- spring MVC–in ucci CSS 文件
- Spring Boot——开发者工具
- 使用 Spring MVC 提供 Web 内容
- Spring Boot Hello World 示例–JSP
Spring Boot Hello World 示例-百里香叶
在本文中,我们将向您展示如何开发一个 Spring Boot web 应用程序,使用百里香叶视图,嵌入式 Tomcat,并将其打包为一个可执行的JAR
文件。
使用的技术:
- Spring Boot 2.1.2 .版本
- 弹簧 5.1.4 释放
- 百里香叶
- Tomcat embed 9.0.14
- JUnit 4.12
- maven3
- Java 8
1.项目目录
2.专家
放上spring-boot-starter-web
和spring-boot-starter-thymeleaf
,它将获得我们开发 Spring MVC + Thymeleaf web 应用程序所需的任何东西,包括嵌入式 Tomcat 服务器。
pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project
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>
<artifactId>web-thymeleaf</artifactId>
<packaging>jar</packaging>
<name>Spring Boot Web Thymeleaf Example</name>
<description>Spring Boot Web Thymeleaf Example</description>
<version>1.0</version>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.2.RELEASE</version>
</parent>
<properties>
<java.version>1.8</java.version>
<bootstrap.version>4.2.1</bootstrap.version>
</properties>
<dependencies>
<!-- web mvc -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- thymeleaf -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<!-- test -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!-- hot swapping, disable cache for template, enable live reload -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<optional>true</optional>
</dependency>
<!-- Optional, for bootstrap -->
<dependency>
<groupId>org.webjars</groupId>
<artifactId>bootstrap</artifactId>
<version>${
bootstrap.version}</version>
</dependency>
</dependencies>
<build>
<plugins>
<!-- Package as an executable jar/war -->
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<addResources>true</addResources>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.22.0</version>
</plugin>
</plugins>
</build>
</project>
显示项目依赖关系。
$ mvn dependency:tree
[INFO] org.springframework.boot:web-thymeleaf:jar:1.0
[INFO] +- org.springframework.boot:spring-boot-starter-web:jar:2.1.2.RELEASE:compile
[INFO] | +- org.springframework.boot:spring-boot-starter:jar:2.1.2.RELEASE:compile
[INFO] | | +- org.springframework.boot:spring-boot-starter-logging:jar:2.1.2.RELEASE:compile
[INFO] | | | +- ch.qos.logback:logback-classic:jar:1.2.3:compile
[INFO] | | | | \- ch.qos.logback:logback-core:jar:1.2.3:compile
[INFO] | | | +- org.apache.logging.log4j:log4j-to-slf4j:jar:2.11.1:compile
[INFO] | | | | \- org.apache.logging.log4j:log4j-api:jar:2.11.1:compile
[INFO] | | | \- org.slf4j:jul-to-slf4j:jar:1.7.25:compile
[INFO] | | +- javax.annotation:javax.annotation-api:jar:1.3.2:compile
[INFO] | | \- org.yaml:snakeyaml:jar:1.23:runtime
[INFO] | +- org.springframework.boot:spring-boot-starter-json:jar:2.1.2.RELEASE:compile
[INFO] | | +- com.fasterxml.jackson.core:jackson-databind:jar:2.9.8:compile
[INFO] | | | +- com.fasterxml.jackson.core:jackson-annotations:jar:2.9.0:compile
[INFO] | | | \- com.fasterxml.jackson.core:jackson-core:jar:2.9.8:compile
[INFO] | | +- com.fasterxml.jackson.datatype:jackson-datatype-jdk8:jar:2.9.8:compile
[INFO] | | +- com.fasterxml.jackson.datatype:jackson-datatype-jsr310:jar:2.9.8:compile
[INFO] | | \- com.fasterxml.jackson.module:jackson-module-parameter-names:jar:2.9.8:compile
[INFO] | +- org.springframework.boot:spring-boot-starter-tomcat:jar:2.1.2.RELEASE:compile
[INFO] | | +- org.apache.tomcat.embed:tomcat-embed-core:jar:9.0.14:compile
[INFO] | | +- org.apache.tomcat.embed:tomcat-embed-el:jar:9.0.14:compile
[INFO] | | \- org.apache.tomcat.embed:tomcat-embed-websocket:jar:9.0.14:compile
[INFO] | +- org.hibernate.validator:hibernate-validator:jar:6.0.14.Final:compile
[INFO] | | +- javax.validation:validation-api:jar:2.0.1.Final:compile
[INFO] | | +- org.jboss.logging:jboss-logging:jar:3.3.2.Final:compile
[INFO] | | \- com.fasterxml:classmate:jar:1.4.0:compile
[INFO] | +- org.springframework:spring-web:jar:5.1.4.RELEASE:compile
[INFO] | | \- org.springframework:spring-beans:jar:5.1.4.RELEASE:compile
[INFO] | \- org.springframework:spring-webmvc:jar:5.1.4.RELEASE:compile
[INFO] | +- org.springframework:spring-aop:jar:5.1.4.RELEASE:compile
[INFO] | +- org.springframework:spring-context:jar:5.1.4.RELEASE:compile
[INFO] | \- org.springframework:spring-expression:jar:5.1.4.RELEASE:compile
[INFO] +- org.springframework.boot:spring-boot-starter-thymeleaf:jar:2.1.2.RELEASE:compile
[INFO] | +- org.thymeleaf:thymeleaf-spring5:jar:3.0.11.RELEASE:compile
[INFO] | | +- org.thymeleaf:thymeleaf:jar:3.0.11.RELEASE:compile
[INFO] | | | +- org.attoparser:attoparser:jar:2.0.5.RELEASE:compile
[INFO] | | | \- org.unbescape:unbescape:jar:1.1.6.RELEASE:compile
[INFO] | | \- org.slf4j:slf4j-api:jar:1.7.25:compile
[INFO] | \- org.thymeleaf.extras:thymeleaf-extras-java8time:jar:3.0.2.RELEASE:compile
[INFO] +- org.springframework.boot:spring-boot-starter-test:jar:2.1.2.RELEASE:test
[INFO] | +- org.springframework.boot:spring-boot-test:jar:2.1.2.RELEASE:test
[INFO] | +- org.springframework.boot:spring-boot-test-autoconfigure:jar:2.1.2.RELEASE:test
[INFO] | +- com.jayway.jsonpath:json-path:jar:2.4.0:test
[INFO] | | \- net.minidev:json-smart:jar:2.3:test
[INFO] | | \- net.minidev:accessors-smart:jar:1.2:test
[INFO] | | \- org.ow2.asm:asm:jar:5.0.4:test
[INFO] | +- junit:junit:jar:4.12:test
[INFO] | +- org.assertj:assertj-core:jar:3.11.1:test
[INFO] | +- org.mockito:mockito-core:jar:2.23.4:test
[INFO] | | +- net.bytebuddy:byte-buddy:jar:1.9.7:test
[INFO] | | +- net.bytebuddy:byte-buddy-agent:jar:1.9.7:test
[INFO] | | \- org.objenesis:objenesis:jar:2.6:test
[INFO] | +- org.hamcrest:hamcrest-core:jar:1.3:test
[INFO] | +- org.hamcrest:hamcrest-library:jar:1.3:test
[INFO] | +- org.skyscreamer:jsonassert:jar:1.5.0:test
[INFO] | | \- com.vaadin.external.google:android-json:jar:0.0.20131108.vaadin1:test
[INFO] | +- org.springframework:spring-core:jar:5.1.4.RELEASE:compile
[INFO] | | \- org.springframework:spring-jcl:jar:5.1.4.RELEASE:compile
[INFO] | +- org.springframework:spring-test:jar:5.1.4.RELEASE:test
[INFO] | \- org.xmlunit:xmlunit-core:jar:2.6.2:test
[INFO] | \- javax.xml.bind:jaxb-api:jar:2.3.1:test
[INFO] | \- javax.activation:javax.activation-api:jar:1.2.0:test
[INFO] +- org.springframework.boot:spring-boot-devtools:jar:2.1.2.RELEASE:compile (optional)
[INFO] | +- org.springframework.boot:spring-boot:jar:2.1.2.RELEASE:compile
[INFO] | \- org.springframework.boot:spring-boot-autoconfigure:jar:2.1.2.RELEASE:compile
[INFO] \- org.webjars:bootstrap:jar:4.2.1:compile
[INFO] +- org.webjars:jquery:jar:3.0.0:compile
[INFO] \- org.webjars:popper.js:jar:1.14.3:compile
3.开发者工具
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<optional>true</optional>
</dependency>
这个spring-boot-devtools
有助于禁用高速缓存并启用热插拔,这样开发人员将总是看到最后的更改。有利于发展。阅读此–Spring Boot–开发者工具尝试修改百里香模板或属性文件,刷新浏览器以查看更改是否立即生效。
- 对于 Eclipse IDE 来说,它与
spring-boot-devtools
集成得很好。 - 对于 Intellij IDEA,需要额外的步骤,阅读此重新加载静态文件不工作
4.Spring Boot + MVC
4.1 简单的控制器。
WelcomeController.java
package com.mkyong.controller;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import java.util.Arrays;
import java.util.List;
@Controller
public class WelcomeController {
// inject via application.properties
@Value("${welcome.message}")
private String message;
private List<String> tasks = Arrays.asList("a", "b", "c", "d", "e", "f", "g");
@GetMapping("/")
public String main(Model model) {
model.addAttribute("message", message);
model.addAttribute("tasks", tasks);
return "welcome"; //view
}
// /hello?name=kotlin
@GetMapping("/hello")
public String mainWithParam(
@RequestParam(name = "name", required = false, defaultValue = "")
String name, Model model) {
model.addAttribute("message", name);
return "welcome"; //view
}
}
4.2 创建一个类并用@SpringBootApplication
标注。在 IDE 中,运行此类来启动整个 web 应用程序。
StartWebApplication.java
package com.mkyong;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class StartWebApplication {
public static void main(String[] args) {
SpringApplication.run(StartWebApplication.class, args);
}
}
5.百里香+静态文件
Note
Read this Spring Boot Serving static content to understand the resource mapping.
5.1 对于百里香模板文件,放入src/main/resources/templates/
src/main/resources/templates/welcome.html
<!DOCTYPE HTML>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<title>Spring Boot Thymeleaf Hello World Example</title>
<link rel="stylesheet" th:href="@{webjars/bootstrap/4.2.1/css/bootstrap.min.css}"/>
<link rel="stylesheet" th:href="@{/css/main.css}"/>
</head>
<body>
<nav class="navbar navbar-expand-md navbar-dark bg-dark fixed-top">
<a class="navbar-brand" href="#">Mkyong.com</a>
</nav>
<main role="main" class="container">
<div class="starter-template">
<h1>Spring Boot Web Thymeleaf Example</h1>
<h2>
<span th:text="'Hello, ' + ${message}"></span>
</h2>
</div>
<ol>
<li th:each="task : ${tasks}" th:text="${task}"></li>
</ol>
</main>
<!-- /.container -->
<script type="text/javascript" th:src="@{webjars/bootstrap/4.2.1/js/bootstrap.min.js}"></script>
</body>
</html>
5.2 Spring Boot 通用应用属性
src/main/resources/application.properties
welcome.message: Mkyong
spring.thymeleaf.cache=false
5.3 对于 CSS 或 JS 等静态文件,放入src/main/resources/static/
src/main/resources/static/css/main.css
body {
padding-top: 5rem;
}
.starter-template {
padding: 3rem 1.5rem;
text-align: center;
}
h1{
color:#0000FF;
}
h2{
color:#FF0000;
}
6.单元测试
MockMvc
测试 Spring MVC 控制器。
WelcomeControllerTest.java
package com.mkyong;
import com.mkyong.controller.WelcomeController;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.MvcResult;
import org.springframework.test.web.servlet.ResultActions;
import org.springframework.web.servlet.ModelAndView;
import java.util.Arrays;
import java.util.List;
import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.is;
import static org.hamcrest.core.IsEqual.equalTo;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;
@RunWith(SpringRunner.class)
@WebMvcTest(controllers = WelcomeController.class)
public class WelcomeControllerTest {
@Autowired
private MockMvc mockMvc;
List<String> expectedList = Arrays.asList("a", "b", "c", "d", "e", "f", "g");
@Test
public void main() throws Exception {
ResultActions resultActions = mockMvc.perform(get("/"))
.andExpect(status().isOk())
.andExpect(view().name("welcome"))
.andExpect(model().attribute("message", equalTo("Mkyong")))
.andExpect(model().attribute("tasks", is(expectedList)))
.andExpect(content().string(containsString("Hello, Mkyong")));
MvcResult mvcResult = resultActions.andReturn();
ModelAndView mv = mvcResult.getModelAndView();
//
}
// Get request with Param
@Test
public void hello() throws Exception {
mockMvc.perform(get("/hello").param("name", "I Love Kotlin!"))
.andExpect(status().isOk())
.andExpect(view().name("welcome"))
.andExpect(model().attribute("message", equalTo("I Love Kotlin!")))
.andExpect(content().string(containsString("Hello, I Love Kotlin!")));
}
}
7.演示
$ mvn spring-boot:run
: Tomcat initialized with port(s): 8080 (http)
: Starting service [Tomcat]
: Starting Servlet engine: [Apache Tomcat/9.0.14]
: Tomcat started on port(s): 8080 (http) with context path ''
Started StartWebApplication in 1.858 seconds (JVM running for 2.222)
URL = http://localhost:8080
URL =http://localhost:8080/hello?name=abc
8.创建可执行的 JAR
对于部署,只需普通的 Maven 包来创建一个可执行的 JAR 文件。
$ mvn clean package
$ java -jar target\web-thymeleaf-1.0.jar
下载源代码
$ git clone https://github.com/mkyong/spring-boot.git
$ cd web-thymeleaf
$ mvn spring-boot:run