可以通过http://start.spring.io/网站直接构建springboot基础框架.
pom文件常见依赖
在springboot开发中,groupId都是org.springframework.boot
依赖artifactId | 说明 |
---|---|
spring-boot-starter | 核心 POM,包含自动配置支持、日志库和对 YAML 配置文件的支持。 |
spring-boot-starter-amqp | 通过 spring-rabbit 支持 AMQP。 |
spring-boot-starter-aop | 包含 spring-aop 和 AspectJ 来支持面向切面编程(AOP)。 |
spring-boot-starter-batch | 支持 Spring Batch,包含 HSQLDB。 |
spring-boot-starter-data-jpa | 包含 spring-data-jpa、spring-orm 和 Hibernate 来支持 JPA。 |
spring-boot-starter-data-mongodb | 包含 spring-data-mongodb 来支持 MongoDB。 |
spring-boot-starter-data-rest | 通过 spring-data-rest-webmvc 支持以 REST 方式暴露 Spring Data 仓库。 |
spring-boot-starter-jdbc | 支持使用 JDBC 访问数据库。 |
spring-boot-starter-security | 包含 spring-security。 |
spring-boot-starter-test | 包含常用的测试所需的依赖,如 JUnit、Hamcrest、Mockito 和 spring-test 等。 |
spring-boot-starter-velocity | 支持使用 Velocity 作为模板引擎。 |
spring-boot-starter-web | 支持 Web 应用开发,包含 Tomcat 和 spring-mvc。 |
spring-boot-starter-websocket | 支持使用 Tomcat 开发 WebSocket 应用。 |
spring-boot-starter-ws | 支持 Spring Web Services。 |
spring-boot-starter-actuator | 添加适用于生产环境的功能,如性能指标和监测等功能。 |
spring-boot-starter-remote-shell | 添加远程 SSH 支持。 |
spring-boot-starter-jetty | 使用 Jetty 而不是默认的 Tomcat 作为应用服务器。 |
spring-boot-starter-log4j | 添加 Log4j 的支持。 |
spring-boot-starter-logging | 使用 Spring Boot 默认的日志框架 Logback。 |
spring-boot-starter-tomcat | 使用 Spring Boot 默认的 Tomcat 作为应用服务器。 |
kotlin开发pom.xml示例文件
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0modelVersion>
<groupId>com.tingfenggroupId>
<artifactId>springboottestartifactId>
<version>1.0-SNAPSHOTversion>
<parent>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-parentartifactId>
<version>1.5.8.RELEASEversion>
<relativePath/>
parent>
<properties>
<kotlin.compiler.incremental>truekotlin.compiler.incremental>
<project.build.sourceEncoding>UTF-8project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8project.reporting.outputEncoding>
<java.version>1.8java.version>
<kotlin.version>1.1.51kotlin.version>
<mysql.version>5.1.38mysql.version>
<druid.version>1.1.3druid.version>
properties>
<dependencies>
<dependency>
<groupId>com.alibabagroupId>
<artifactId>druid-spring-boot-starterartifactId>
<version>${druid.version}version>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-data-jpaartifactId>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-webartifactId>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-testartifactId>
<scope>testscope>
dependency>
<dependency>
<groupId>org.jetbrains.kotlingroupId>
<artifactId>kotlin-stdlib-jre8artifactId>
<version>${kotlin.version}version>
dependency>
<dependency>
<groupId>org.jetbrains.kotlingroupId>
<artifactId>kotlin-reflectartifactId>
<version>${kotlin.version}version>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-testartifactId>
<scope>testscope>
dependency>
<dependency>
<groupId>mysqlgroupId>
<artifactId>mysql-connector-javaartifactId>
<version>${mysql.version}version>
dependency>
dependencies>
<build>
<sourceDirectory>${project.basedir}/src/main/javasourceDirectory>
<testSourceDirectory>${project.basedir}/src/test/javatestSourceDirectory>
<plugins>
<plugin>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-maven-pluginartifactId>
plugin>
<plugin>
<artifactId>kotlin-maven-pluginartifactId>
<groupId>org.jetbrains.kotlingroupId>
<version>${kotlin.version}version>
<configuration>
<compilerPlugins>
<plugin>springplugin>
compilerPlugins>
<jvmTarget>1.8jvmTarget>
configuration>
<executions>
<execution>
<id>compileid>
<phase>compilephase>
<goals>
<goal>compilegoal>
goals>
execution>
<execution>
<id>test-compileid>
<phase>test-compilephase>
<goals>
<goal>test-compilegoal>
goals>
execution>
executions>
<dependencies>
<dependency>
<groupId>org.jetbrains.kotlingroupId>
<artifactId>kotlin-maven-allopenartifactId>
<version>${kotlin.version}version>
dependency>
dependencies>
plugin>
plugins>
build>
project>
devtools
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-devtoolsartifactId>
<scope>providedscope>
<optional>trueoptional>
dependency>
通过项目主程序入口启动即可,改动以后重新编译就好。
springloaded
Pom.xml中直接在spring-boot插件中添加依赖即可:
<plugin>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-maven-pluginartifactId>
<dependencies>
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>springloadedartifactId>
<version>1.2.6.RELEASEversion>
dependency>
dependencies>
<configuration>
<mainClass>cn.springboot.MainspringbootmainClass>
configuration>
plugin>
运行:
$ mvn clean spring-boot:run
改动后,编译即可实现热部署
这两种方式其实都是spring官网为了spring项目所推出的jar包,加之springBoot框架内嵌服务器的优势,
使得改动后的项目部署变得非常简单;当我使用以后这两种方法以后,
发现真正实现热部署的只是后者,前者只是实现了热启动而已,从控制台日志就可以看出来。
说明
项目使用maven管理:
第一种方式配置文件改动后不能触发热启动
第二种方式配置文件改动后不能触发热部署,会提示一下错误
2017-05-24 11:54:53.276 ERROR 12063 — [Loader@18b4aac2] org.springsource.loaded.ReloadableType
优先级从高到低顺序如下,命令行优先级最高.
1. 命令行参数。
通过 System.getProperties() 获取的 Java 系统参数。
2. 操作系统环境变量。
从 java:comp/env 得到的 JNDI 属性。
3. 通过 RandomValuePropertySource 生成的“random.*”属性。
4. 应用 Jar 文件之外的属性文件。
5. 应用 Jar 文件内部的属性文件。
6. 在应用配置 Java 类(包含“@Configuration”注解的 Java 类)中通过“@PropertySource”注解声明的属性文件。
7. 通过“SpringApplication.setDefaultProperties”声明的默认属性。
Spring Boot 的这个配置优先级看似复杂,其实是很合理的。
比如命令行参数的优先级被设置为最高。
这样的好处是可以在测试或生产环境中快速地修改配置参数值,而不需要重新打包和部署应用。
SpringApplication 类默认会把以“–”开头的命令行参数转化成应用中可以使用的配置参数,
如 “–name=Alex” 会设置配置参数 “name” 的值为 “Alex”。
如果不需要这个功能,可以通过 “SpringApplication.setAddCommandLineProperties(false)” 禁用解析命令行参数。
RandomValuePropertySource 可以用来生成测试所需要的各种不同类型的随机值,从而免去了在代码中生成的麻烦。RandomValuePropertySource 可以生成数字和字符串。数字的类型包含 int 和 long,可以限定数字的大小范围。
以“random.”作为前缀的配置属性名称由 RandomValuePropertySource 来生成,如代码
//使用 RandomValuePropertySource 生成的配置属性
user.id=${random.value}
user.count=${random.int}
user.max=${random.long}
user.number=${random.int(100)}
user.range=${random.int[100, 1000]}
当应用程序需要部署到不同运行环境时,一些配置细节通常会有所不同,最简单的比如日志,
生产日志会将日志级别设置为WARN或更高级别,并将日志写入日志文件,
而开发的时候需要日志级别为DEBUG,日志输出到控制台即可。
Spring Boot的Profile就给我们提供了解决方案,命令带上参数就搞定。
在Spring Boot中多环境配置文件名需要满足application-{profile}.properties
的格式,其中{profile}
对应你的环境标识,比如:
- application-dev.properties:开发环境
- application-prod.properties:生产环境
想要使用对应的环境,只需要在application.properties中使用spring.profiles.active属性来设置,
值对应上面提到的{profile},这里就是指dev、prod这2个。
当然你也可以用命令行启动的时候带上参数:
java - jar xxx.jar --spring.profiles.active=dev
除了可以用profile的配置文件来分区配置我们的环境变量,在代码里,
我们还可以直接用@Profile注解来进行配置,例如数据库配置,这里我们先定义一个接口:
分别定义俩个实现类来实现它
//测试数据库
@Component
@Profile("testdb")
public class TestDBConnector implements DBConnector{
@Override
public void configure(){
System.out.println("testdb");
}
}
//生产数据库
@Component
@Profile("devdb")
public class DevDBConnector implements DBConnector{
@Override
public void configure(){
System.out.println("devdb");
}
}
通过在配置文件激活具体使用哪个实现类
spring.profiles.active=testdb
然后通过注入DBConnector(注入接口,spring自动选择实现类),就可以用了.
除了spring.profiles.active来激活一个或者多个profile之外,还可以用spring.profiles.include来叠加profile
spring.profiles.active:testdb
spring.profiles.include:proddb,prodmq
属性文件是最常见的管理配置属性的方式。
Spring Boot 提供的 SpringApplication 类会搜索并加载 application.properties 文件来获取配置属性值。
SpringApplication 类会在下面位置搜索该文件。
1. 当前目录的“/config”子目录。
2. 当前目录。
3. classpath 中的“/config”包。
4. classpath
上面的顺序也表示了该位置上包含的属性文件的优先级。
优先级按照从高到低的顺序排列。
可以通过“spring.config.name”配置属性来指定不同的属性文件名称。
也可以通过“spring.config.location”来添加额外的属性文件的搜索路径。
如果应用中包含多个 profile,可以为每个 profile 定义各自的属性文件,按照“application-{profile}”来命名。
对于配置属性,可以在代码中通过“@Value”来使用,如代码所示。
//通过“@Value”来使用配置属性
@RestController
@EnableAutoConfiguration
public class Application {
@Value("${name}")
private String name;
@RequestMapping("/")
String home() {
return String.format("Hello %s!", name);
}
}
//变量 name 的值来自配置属性中的“name”属性。
相对于属性文件来说,YAML 是一个更好的配置文件格式。YAML 在 Ruby on Rails 中得到了很好的应用。
SpringApplication 类也提供了对 YAML 配置文件的支持,只需要添加对 SnakeYAML 的依赖即可。
application.yml 文件的示例。
spring:
profiles: development
db:
url: jdbc:hsqldb:file:testdb
username: sa
password:
spring:
profiles: test
db:
url: jdbc:mysql://localhost/test
username: test
password: test
通过“@ConfigurationProperties(prefix=”db”)”注解,配置属性中以“db”为前缀的属性值会被自动绑
定到 Java 类中同名的域上,如 url 域的值会对应属性“db.url”的值。
只需要在应用的配置类中添加“@EnableConfigurationProperties”注解就可以启用该自动绑定功能。
//使用 YAML 文件的 Java 类
@Component
@ConfigurationProperties(prefix="db")
public class DBSettings {
private String url;
private String username;
private String password;
}
如果你使用的是1.5以前的版本,那么可以通过locations指定properties文件的位置.
但是1.5版本后就没有这个属性了,添加@Configuration和@PropertySource(“classpath:test.properties”)后才可以读取。
@configrationProperties(prefix="db",locations="classpath:xxxx.properties")
yaml配置文件示例
spring:
# 环境 dev|test|pro
profiles:
active: dev
datasource:
type: com.alibaba.druid.pool.DruidDataSource
driver-class-name: com.mysql.jdbc.Driver
url: jdbc:mysql://127.0.0.1:3306/springboot
username: root
password: root
http:
multipart:
max-file-size: 100MB
max-request-size: 100MB
enabled: true
resources: # 指定静态资源的路径
static-locations: classpath:/static/
#cache-period,静态资源的缓存失效时间,此时间会在http response的时候
#写入http response的head中让让浏览器按照此时间来缓存,秒,其优先级高于html网页中的设置的meta;
cache-period: 600
redis:
open: false # 是否开启redis缓存 true开启 false关闭
database: 0
host: redis.open.renren.io
port: 16379
password: # 密码(默认为空)
timeout: 6000 # 连接超时时长(毫秒)
pool:
max-active: 1000 # 连接池最大连接数(使用负值表示没有限制)
max-wait: -1 # 连接池最大阻塞等待时间(使用负值表示没有限制)
max-idle: 10 # 连接池中的最大空闲连接
min-idle: 5 # 连接池中的最小空闲连接
devtools:
restart:
#热部署生效
enabled: true
#设置重启的目录
#additional-paths: src/main/java
#classpath目录下的WEB-INF文件夹内容修改不重启
exclude: static/**,
jpa:
hibernate:
# 第一次简表create 后面用update
#ddl-auto: create
ddl-auto: update
show-sql: true
show-sql: true
#base-package: com.tingfeng.dao
#repository-impl-postfix: impl
#entity-manager-factory-ref: entityManagerFactory
#transaction-manager-ref: transactionManager
server:
port: 8080
connection-timeout: 5000
context-path: /spring
tomcat:
uri-encoding: UTF-8
max-threads: 1000
min-spare-threads: 30
girl:
cupSize: B
age: 18
可以配置application-dev.yml / application-pro.yml /application-test.yml用于不同的环境.
其中默认配置的 /** 映射到 /static (或/public、/resources、/META-INF/resources)
其中默认配置的 /webjars/** 映射到 classpath:/META-INF/resources/webjars/
PS:上面的 static、public、resources 等目录都在 classpath: 下面(如 src/main/resources/static)。
读取优先级顺序为:META/resources > resources > static > public
自定义目录
以增加 /myres/* 映射到 classpath:/myres/* 为例的代码处理为:
实现类继承 WebMvcConfigurerAdapter 并重写方法 addResourceHandlers
package org.springboot.sample.config;
import org.springboot.sample.interceptor.MyInterceptor1;
import org.springboot.sample.interceptor.MyInterceptor2;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
@Configuration
public class MyWebAppConfigurer
extends WebMvcConfigurerAdapter {
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
//可以针对具体的资源来设置不同的缓存时间
//cache-period
registry.addResourceHandler("/myres/**").addResourceLocations("classpath:/myres/");
super.addResourceHandlers(registry);
}
}
访问myres 文件夹中的fengjing.jpg 图片的地址为 http://localhost:8080/myres/fengjing.jpg
这样使用代码的方式自定义目录映射,并不影响Spring Boot的默认映射,可以同时使用。
如果我们将/myres/* 修改为 /* 与默认的相同时,则会覆盖系统的配置,可以多次使用 addResourceLocations 添加目录,优先级先添加的高于后添加的。
registry.addResourceHandler("/**").addResourceLocations("classpath:/myres/").addResourceLocations("classpath:/static/");
其中 addResourceLocations 的参数是动参,可以这样写 addResourceLocations(“classpath:/img1/”, “classpath:/img2/”, “classpath:/img3/”);
registry.addResourceHandler("/myimgs/**").addResourceLocations("file:H:/myimgs/");
# 默认值为 /**
spring.mvc.static-path-pattern=
# 默认值为 classpath:/META-INF/resources/,classpath:/resources/,classpath:/static/,classpath:/public/
spring.resources.static-locations=这里设置要指向的路径,多个使用英文逗号隔开,
使用 spring.mvc.static-path-pattern 可以重新定义pattern,如修改为 /myres/** ,则访问static 等目录下的fengjing.jpg文件应该为 http://localhost:8080/myres/fengjing.jpg ,修改之前为 http://localhost:8080/fengjing.jpg
使用 spring.resources.static-locations 可以重新定义 pattern 所指向的路径,支持 classpath: 和 file: (上面已经做过说明) 注意 spring.mvc.static-path-pattern 只可以定义一个,目前不支持多个逗号分割的方式。
上面几个例子中也已经说明了怎么访问静态资源,其实在页面中使用不管是jsp还是freemarker,并没有什么特殊之处,也我们平时开发web项目一样即可。
下面是我的index.jsp:
<body>
<img alt="读取默认配置中的图片" src="${pageContext.request.contextPath }/pic.jpg">
<br/>
<img alt="读取自定义配置myres中的图片" src="${pageContext.request.contextPath }/myres/fengjing.jpg">
body>
WebJars 就是将js, css 等资源文件放到 classpath:/META-INF/resources/webjars/ 中,然后打包成jar 发布到maven仓库中。
简单应用
以jQuery为例,文件存放结构为:
META-INF/resources/webjars/jquery/2.1.4/jquery.js
META-INF/resources/webjars/jquery/2.1.4/jquery.min.js
META-INF/resources/webjars/jquery/2.1.4/jquery.min.map
META-INF/resources/webjars/jquery/2.1.4/webjars-requirejs.js
Spring Boot 默认将 /webjars/** 映射到 classpath:/META-INF/resources/webjars/ ,结合我们上面讲到的访问资源的规则,便可以得知我们在JSP页面中引入jquery.js的方法为:
<script type="text/javascript" src="${pageContext.request.contextPath }/webjars/jquery/2.1.4/jquery.js">script>
想实现这样,我们只需要在pom.xml 文件中添加jquery的webjars 依赖即可,如下:
<dependency>
<groupId>org.webjarsgroupId>
<artifactId>jqueryartifactId>
<version>2.1.4version>
dependency>
首先在pom.xml 中添加依赖:
<dependency>
<groupId>org.webjarsgroupId>
<artifactId>webjars-locatorartifactId>
dependency>
然后增加一个WebJarsController:
package org.springboot.sample.controller;
import javax.servlet.http.HttpServletRequest;
import org.springframework.core.io.ClassPathResource;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.servlet.HandlerMapping;
import org.webjars.WebJarAssetLocator;
/**
* 处理WebJars,自动读取版本号
*/
@Controller
public class WebJarsController {
private final WebJarAssetLocator assetLocator = new WebJarAssetLocator();
@ResponseBody
@RequestMapping("/webjarslocator/{webjar}/**")
public ResponseEntity
最后在页面中使用的方式:
<script type="text/javascript" src="${pageContext.request.contextPath }/webjarslocator/jquery/jquery.js">script>
Spring 默认提供了静态资源版本映射的支持。
当我们的资源内容发生改变时,由于浏览器缓存,用户本地的资源还是旧资源,为了防止这种情况发生导致的问题。我们可能会选择在资源文件后面加上参数“版本号”或其他方式。
使用版本号参数,如:
<script type="text/javascript" src="${pageContext.request.contextPath }/js/common.js?v=1.0.1">script>
使用这种方式,当我们文件修改后,手工修改版本号来达到URL文件不被浏览器缓存的目的。同样也存在很多文件都需要修改的问题。或者有的人会增加时间戳的方式,这样我认为是最不可取的,每次浏览器都要请求为服务器增加了不必要的压力。
然而Spring在解决这种问题方面,提供了2种解决方式。
spring.resources.chain.strategy.content.enabled=true
spring.resources.chain.strategy.content.paths=/**
所有 /** 请求的静态资源都会被处理。
创建 ResourceUrlProviderController 文件
package org.springboot.sample.config;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.servlet.resource.ResourceUrlProvider;
/**
* 处理静态资源URL
*/
@ControllerAdvice
public class ResourceUrlProviderController {
@Autowired
private ResourceUrlProvider resourceUrlProvider;
@ModelAttribute("urls")
public ResourceUrlProvider urls() {
return this.resourceUrlProvider;
}
}
在页面中使用的写法
<script type="text/javascript" src="${pageContext.request.contextPath }${urls.getForLookupPath('/js/common.js') }">script>
当我们访问页面后,HTML中实际生成的代码为:
<script type="text/javascript" src="/myspringboot/js/common-c6b7da8fffc9be141b48c073e39c7340.js">script>
其中 /myspringboot 为我这个项目的 contextPath
spring.resources.chain.strategy.fixed.enabled=true
spring.resources.chain.strategy.fixed.paths=/js/**,/v1.0.0/**
spring.resources.chain.strategy.fixed.version=v1.0.0
这样配置后,以上面 common.js 为例,实际页面中生成的HTML代码为:
<script type="text/javascript" src="/myspringboot/v1.0.0/js/common.js">script>
当请求的地址为版本号方式时,会在url中判断是否存在/v1.0.0 ,如果存在,则先从URL中把 /v1.0.0 去掉,然后再去映射目录查找对应文件,找到就返回。
静态资源配置摘录自:http://blog.csdn.net/catoop/article/details/50501706
<configuration>
<include resource="org/springframework/boot/logging/logback/base.xml" />
<logger name="org.springframework.web" level="INFO"/>
<logger name="org.springboot.sample" level="TRACE" />
<springProfile name="dev,test">
<logger name="org.springframework.web" level="INFO"/>
<logger name="org.springboot.sample" level="INFO" />
<logger name="io.renren" level="DEBUG" />
springProfile>
<springProfile name="pro">
<logger name="org.springframework.web" level="ERROR"/>
<logger name="org.springboot.sample" level="ERROR" />
<logger name="io.renren" level="ERROR" />
springProfile>
configuration>
Spring MVC 中使用 HttpMessageConverter 接口来在 HTTP 请求和响应之间进行消息格式的转换。
默认情况下已经通过 Jackson 支持 JSON 和通过 JAXB 支持 XML 格式。
可以通过创建自定义 HttpMessageConverters 的方式来添加其他的消息格式转换实现。
默认情况下,Spring Boot 可以对 “/static”、“/public”、“/resources” 或 “/META-INF/resources” 目录下的静态文件提供支持。
同时 Spring Boot 还支持 Webjars。路径“/webjars/**”下的内容会由 webjar 格式的 Jar 包来提供。
与开发和测试环境不同的是,当应用部署到生产环境时,需要各种运维相关的功能的支持,包括性能指标、运行信息和应用管理等。
所有这些功能都有很多技术和开源库可以实现。Spring Boot 对这些运维相关的功能进行了整合,形成了一个功能完备和可定制的功能集,称之为 Actuator。
只需要在 POM 文件中增加对 “org.springframe.boot:spring-boot-starter-actuator” 的依赖就可以添加 Actuator。
Actuator 在添加之后,会自动暴露一些 HTTP 服务来提供这些信息。这些 HTTP 服务的说明如表 。
名称 | 说明 | 是否包含敏感信息 |
---|---|---|
autoconfig | 显示 Spring Boot 自动配置的信息。 | 是 |
beans | 显示应用中包含的 Spring bean 的信息。 | 是 |
configprops | 显示应用中的配置参数的实际值。 | 是 |
dump | 生成一个 thread dump。 | 是 |
env | 显示从 ConfigurableEnvironment 得到的环境配置信息。 | 是 |
health | 显示应用的健康状态信息。 | 否 |
info | 显示应用的基本信息。 | 否 |
metrics | 显示应用的性能指标。 | 是 |
mappings | 显示 Spring MVC 应用中通过“ | |
@RequestMapping”添加的路径映射。 | 是 | |
shutdown | 关闭应用。 | 是 |
trace | 显示应用相关的跟踪(trace)信息。 | 是 |
对于表中的每个服务,通过访问名称对应的 URL 就可以获取到相关的信息。
如访问“/info”就可以获取到 info 服务对应的信息。
服务是否包含敏感信息说明了该服务暴露出来的信息是否包含一些比较敏感的信息,从而确定是否需要添加相应的访问控制,而不是对所有人都公开。
所有的这些服务都是可以配置的,比如通过改变名称来改变相应的 URL。
Spring Boot 默认提供了对应用本身、关系数据库连接、MongoDB、Redis 和 Rabbit MQ 的健康状态的检测功能。
当应用中添加了 DataSource 类型的 bean 时,Spring Boot 会自动在 health 服务中暴露数据库连接的信息。
应用也可以提供自己的健康状态信息,如代码所示。
//自定义 health 服务
@Component
public class AppHealthIndicator implements HealthIndicator {
@Override
public Health health() {
return Health.up().build();
}
}
``
应用只需要实现 org.springframework.boot.actuate.health.HealthIndicator 接口,并返回一个 org.springframework.boot.actuate.health.Health 对象,
就可以通过 health 服务来获取所暴露的信息。
```json
//health 服务返回的结果
{"status":"UP","app":{"status":"UP"},"db":{"status":"UP","database":"HSQL Database Engine","hello":1}}
"se-preview-section-delimiter">
info 服务所暴露的信息是完全由应用来确定的。
应用中任何以“info.”开头的配置参数会被自动的由 info 服务来暴露。
只需要往 application.properties 中添加以“info.”开头的参数即可,如代码所示。
info.app_name=My First Spring Boot Application
info.app_version=1.0.0
<div class="se-preview-section-delimiter">div>
当访问“/info”时,访问的 JSON 数据如代码所示。
//Info 服务返回的结果
{"app_name":"My First Spring Boot Application","app_version":"1.0.0"}
"se-preview-section-delimiter">
当访问 metrics 服务时,可以看到 Spring Boot 通过 SystemPublicMetrics 默认提供的一些系统的性能参数值.
包括内存、CPU、Java 类加载和线程等的基本信息。
应用可以记录其他所需要的信息。Spring Boot 默认提供了两种类型的性能指标记录方式:gauge 和 counter。
gauge 用来记录单个绝对数值,counter 用来记录增量或减量值。
比如在一个 Web 应用中,可以用 counter 来记录当前在线的用户数量。
当用户登录时,把 counter 的值加 1;当用户退出时,把 counter 的值减 1。
//自定义的 metrics 服务
@RestController
public class GreetingsController {
@Autowired
private CounterService counterService;
@RequestMapping("/greet")
public String greet() {
counterService.increment("myapp.greet.count");
return "Hello!";
}
}
"se-preview-section-delimiter">
在代码中添加了对 Spring Boot 提供的 CounterService 的依赖。
当 greet 方法被调用时,会把名称为“myapp.greet.count”的计数器的值加 1。
也就是当用户每次访问“/greet”时,该计算器就会被加 1。除了 CounterService 之外,还可以使用 GaugeService 来记录绝对值。
添加 Actuator 后所暴露的 HTTP 服务只能提供只读的信息。
如果需要对应用在运行时进行管理,则需要用到 JMX。
Spring Boot 默认提供了 JMX 管理的支持。只需要通过 JDK 自带的 JConsole 连接到应用的 JMX 服务器,就可以看到在域“org.springframework.boot”中 mbean。
可以通过 Spring 提供的 @ManagedResource、@ManagedAttribute 和 @ManagedOperation 注解来创建应用自己的 mbean。
Spring Boot Maven plugin能够将Spring Boot应用打包为可执行的jar或war文件,然后以通常的方式运行Spring Boot应用。
Spring Boot Maven plugin的最新版本为2017.6.8发布的1.5.4.RELEASE,要求Java 8, Maven 3.2及以后。
Spring Boot Maven plugin的5个Goals
- spring-boot:repackage,默认goal。在mvn package之后,再次打包可执行的jar/war,同时保留mvn package生成的jar/war为.origin
- spring-boot:run,运行Spring Boot应用
- spring-boot:start,在mvn integration-test阶段,进行Spring Boot应用生命周期的管理
- spring-boot:stop,在mvn integration-test阶段,进行Spring Boot应用生命周期的管理
- spring-boot:build-info,生成Actuator使用的构建信息文件build-info.properties
mvn package spring-boot:repackage
Spring Boot Maven plugin的最主要goal就是repackage,其在Maven的package生命周期阶段,
能够将mvn package生成的软件包,再次打包为可执行的软件包,并将mvn package生成的软件包重命名为*.original。
基于上述配置,对一个生成Jar软件包的项目执行如下命令。
mvn package spring-boot:repackage
<div class="se-preview-section-delimiter">div>
可以看到生成的两个jar文件,一个是.jar,另一个是.jar.original。
在执行上述命令的过程中,Maven首先在package阶段打包生成*.jar文件;
然后执行spring-boot:repackage重新打包,查找Manifest文件中配置的Main-Class属性,如下所示:
Manifest-Version: 1.0
Implementation-Title: gs-consuming-rest
Implementation-Version: 0.1.0
Archiver-Version: Plexus Archiver
Built-By: exihaxi
Implementation-Vendor-Id: org.springframework
Spring-Boot-Version: 1.5.3.RELEASE
Implementation-Vendor: Pivotal Software, Inc.
Main-Class: org.springframework.boot.loader.JarLauncher
Start-Class: com.ericsson.ramltest.MyApplication
Spring-Boot-Classes: BOOT-INF/classes/
Spring-Boot-Lib: BOOT-INF/lib/
Created-By: Apache Maven 3.5.0
Build-Jdk: 1.8.0_131
<div class="se-preview-section-delimiter">div>
注意,其中的Main-Class属性值为org.springframework.boot.loader.JarLauncher;
Start-Class属性值为com.ericsson.ramltest.MyApplication。
其中com.ericsson.ramltest.MyApplication类中定义了main()方法,是程序的入口。
通常,Spring Boot Maven plugin会在打包过程中自动为Manifest文件设置Main-Class属性,
事实上该属性还可以受Spring Boot Maven plugin的配置属性layout控制的,示例如下。
<plugin>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-maven-pluginartifactId>
<version>1.5.4.RELEASEversion>
<configuration>
<mainClass>${start-class}mainClass>
<layout>ZIPlayout>
configuration>
<executions>
<execution>
<goals>
<goal>repackagegoal>
goals>
execution>
executions>
plugin>
<div class="se-preview-section-delimiter">div>
注意,这里的layout属性值为ZIP。
layout属性的值可以如下
JAR,即通常的可执行jar
Main-Class: org.springframework.boot.loader.JarLauncher
WAR,即通常的可执行war,需要的servlet容器依赖位于WEB-INF/lib-provided
ZIP,即DIR,类似于JAR
Main-Class: org.springframework.boot.loader.PropertiesLauncher
MODULE,将所有的依赖库打包(scope为provided的除外),但是不打包Spring Boot的任何Launcher。
NONE,将所有的依赖库打包,但是不打包Spring Boot的任何Launcher。
如果省略Main-Class,只写layout,那么会自动使用默认的Main-Class。
4.integration-test(集成测试)阶段中的Spring Boot Maven plugin的start/stop
<properties>
<it.skip>falseit.skip>
properties>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.pluginsgroupId>
<artifactId>maven-failsafe-pluginartifactId>
<configuration>
<skip>${it.skip}skip>
configuration>
plugin>
<plugin>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-maven-pluginartifactId>
<version>1.5.4.RELEASEversion>
<executions>
<execution>
<id>pre-integration-testid>
<goals>
<goal>startgoal>
goals>
<configuration>
<skip>${it.skip}skip>
configuration>
execution>
<execution>
<id>post-integration-testid>
<goals>
<goal>stopgoal>
goals>
<configuration>
<skip>${it.skip}skip>
configuration>
execution>
executions>
plugin>
plugins>
build>
<div class="se-preview-section-delimiter">div>
注意,it.skip变量用作是否跳过integration-test的标志位。
maven-failsafe-plugin用作integration-test的主要执行目标。
spring-boot-maven-plugin用以为integration-test提供支持。
执行integration-test的Maven命令如下:
mvn verify
或者
mvn verify -Dit.skip=false
<div class="se-preview-section-delimiter">div>
## jar方式运行
<div class="se-preview-section-delimiter">div>
```shell
java -jar xx.jar --server.port=8080
可以看出,命令行中连续的两个减号–就是对application.properties中的属性值进行赋值的标识。
~/.spring-boot-devtools.properties
所以java -jar xx.jar --server.port=9090等价于在application.properties中添加属性server.port=9090。
实际上,Spring Boot应用程序有多种设置途径,Spring Boot能从多重属性源获得属性,
包括如下几种:
1. 根目录下的开发工具全局设置属性(当开发工具激活时为)。
SpringApplication.setDefaultProperties`指定).
2. 测试中的@TestPropertySource注解。
3. 测试中的@SpringBootTest#properties注解特性。
4. 命令行参数
5. SPRING_APPLICATION_JSON中的属性(环境变量或系统属性中的内联JSON嵌入)。
6. ServletConfig初始化参数。
7. ServletContext初始化参数。
8. java:comp/env里的JNDI属性
9. JVM系统属性
10. 操作系统环境变量
11. 随机生成的带random.* 前缀的属性(在设置其他属性时,可以应用他们,比如${random.long})
12. 应用程序以外的application.properties或者appliaction.yml文件
13. 打包在应用程序内的application.properties或者appliaction.yml文件
14. 通过@PropertySource标注的属性源
15. 默认属性(通过
这里列表按组优先级排序,也就是说,任何在高优先级属性源里设置的属性都会覆盖
低优先级的相同属性,列如我们上面提到的命令行属性就覆盖了application.properties的属性。
默认会将源代码和依赖的代码打包到一个jar文件中。
<plugin>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-maven-pluginartifactId>
<configuration>
<fork>truefork>
configuration>
plugin>
使用maven命令 : mvn package spring-boot:repackage
将会得到源代码包,和源代码与依赖的运行jar包。
使用maven命令:mvn package 打包。
maven配置文件如下:
<plugin>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-maven-pluginartifactId>
<configuration>
<fork>truefork>
<layout>ZIPlayout>
<executable>trueexecutable>
<includes>
<include>
<groupId>nothinggroupId>
<artifactId>nothingartifactId>
include>
includes>
configuration>
plugin>
然后使用命令:
java -Dloader.path="lib/" -jar ./har-merchant-manage.jar
运行,通过置顶lib依赖目录的方式运行。
在jar文件构建之后,我可以看到PropertiesLauncher被用于检查META-INF / MENIFEST中的Main-Class属性
现在,我可以运行该jar如下(在Windows中):
java -D loader.path = file:///C:/My/External/Dir,MyApp-0.0.1-SNAPSHOT.jar -jar MyApp-0.0.1-SNAPSHOT.jar
请注意,应用程序jar文件包含在loader.path中。
现在加载了C:\My\External\Dir\config中的application.properties文件。
对于非jar(扩展)文件(例如,静态html文件)也可以由jar访问,因为它位于加载器路径中。
其中java命令 -DXXX用于设置XXX属性值,说明:
-D<名称>=<值>
设置系统属性
import org.springframework.boot.SpringApplication
import org.springframework.boot.autoconfigure.SpringBootApplication
import org.springframework.boot.autoconfigure.domain.EntityScan
import org.springframework.context.annotation.ComponentScan
import org.springframework.data.jpa.repository.config.EnableJpaRepositories
import org.springframework.transaction.annotation.EnableTransactionManagement
fun main(args: Array){
SpringApplication.run(AppMain::class.java, *args)
}
@ComponentScan(basePackages= arrayOf("com.tingfeng"))
@EnableJpaRepositories(basePackages= arrayOf("com.tingfeng.dao"))//dao层对应的包路径,使用jpa时需要配置
@EntityScan(basePackages = arrayOf("com.tingfeng.entity"))//entity对应的包路径,使用jpa时需要配置
@SpringBootApplication
@EnableTransactionManagement
class AppMain {
}
baseDao只是一个接口,不需要实现类.
import com.tingfeng.Entity.BaseEntity
import org.springframework.data.jpa.repository.JpaRepository
import org.springframework.data.jpa.repository.JpaSpecificationExecutor
import org.springframework.data.repository.NoRepositoryBean
@NoRepositoryBean
interface BaseDao.io .Serializable>
: JpaRepository, JpaSpecificationExecutor
其余的Dao接口继承BaseDao接口,即可以直接使用JPA功能.
spring jpa会自动构建Dao接口的实现类.
import com.tingfeng.Entity.Account
import org.springframework.stereotype.Repository
@Repository
interface AccountDao:BaseDao, Long> {
fun findByName(name:String):List
}
Entity的配置类似Hibernate中Entity
import javax.persistence.Entity
import javax.persistence.GeneratedValue
import javax.persistence.Id
import javax.persistence.Table
@Entity
@Table(name="account")
data class Account(@Id @GeneratedValue var id:Long?,
var name:String?,
var money:Double?
) :BaseEntity() {
constructor(): this(null,null,null){}
}
@Configuration
@EnableWebMvc
@ComponentScan(
basePackages = Constants.MVC_PACKAGE_PATH,
useDefaultFilters = false,
includeFilters = {@ComponentScan.Filter(type = FilterType.ANNOTATION, value = {Controller.class})}
)
public class MvcConfig extends WebMvcConfigurerAdapter {
private static final String VIEW_PREFIX = "/";// 视图前缀
private static final String VIEW_SUFFIX = ".jsp";// 视图后缀
private static final String VIEW_CONTENT_TYPE = "text/html;charset=UTF-8";//视图的内容类型。
//可以配置消息的格式Message Converters
@Override
public void configureMessageConverters(List> converters) {
Jackson2ObjectMapperBuilder builder = new Jackson2ObjectMapperBuilder()
.indentOutput(true)
.dateFormat(new SimpleDateFormat("yyyy-MM-dd"))
.modulesToInstall(new ParameterNamesModule());
converters.add(new MappingJackson2HttpMessageConverter(builder.build()));
converters.add(new MappingJackson2XmlHttpMessageConverter(builder.xml().build()));
}
/**
* 可以配置路径的匹配规则
*/
@Override
public void configurePathMatch(PathMatchConfigurer configurer) {
configurer
.setUseSuffixPatternMatch(true)
.setUseTrailingSlashMatch(false)
.setUseRegisteredSuffixPatternMatch(true)
.setPathMatcher(antPathMatcher())
.setUrlPathHelper(urlPathHelper());
}
@Bean
public UrlPathHelper urlPathHelper() {
//...
}
@Bean
public PathMatcher antPathMatcher() {
//...
}
//等同于 ,
@Override
public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
configurer.enable();
//configurer.enable("myCustomDefaultServlet");
}
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/resources/**").addResourceLocations("/public-resources/");
}
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new LoginInterceptor()).addPathPatterns("/**").excludePathPatterns("token/login");
super.addInterceptors(registry);
}
/**
* 配置 视图解析器
* @return
*/
@Bean
public ViewResolver viewResolver(){
InternalResourceViewResolver resolver = new InternalResourceViewResolver();
resolver.setCache(true);
resolver.setPrefix(VIEW_PREFIX);
resolver.setSuffix(VIEW_SUFFIX);
resolver.setExposeContextBeansAsAttributes(true);
resolver.setContentType(VIEW_CONTENT_TYPE);
return resolver;
}
/**
* 配置静态资源处理
* @param configurer
*/
@Override
public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
configurer.enable();
}
也可以继承WebMvcConfigurationSupport类来配置。
两个类都是来自包org.springframework.web.servlet.config.annotation
两个类都可以实现配置mvc。两者都可以配置视图解析器以及静态资源等
说明:
WebMvcConfigurationSupport 与WebMvcConfigurerAdapter 都可以配MVC,
WebMvcConfigurationSupport 支持的自定义的配置更多更全,WebMvcConfigurerAdapter有的WebMvcConfigurationSupport 都有
添加的拦截器Interceptor必须继承HandlerInterceptor
public class LoginInterceptor implements HandlerInterceptor
spring-boot中的main类中的@EnableWebMvc注解等于扩展了WebMvcConfigurationSupport但
是没有重写任何方法。
配置的方式区别如下:
在WebMvcConfigurationSupport(@EnableWebMvc)和@EnableAutoConfiguration这
两种方式都有一些默认的设定 ,而WebMvcConfigurationAdapter则是一个abstract class
@EnableWebMvc
开启MVC配置,相当于
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc.xsd">
<mvc:annotation-driven/>
beans>
分别使用ConverterRegistry和FormatterRegistry
使用注册工厂
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.convert.converter.Converter;
import org.springframework.core.convert.converter.ConverterRegistry;
import javax.annotation.PostConstruct;
import java.util.Arrays;
import java.util.List;
@Configuration
public class MyConverterRegistry {
@Autowired
private ConverterRegistry converterRegistry;
@PostConstruct
public void init() {
converterRegistry.addConverter(new StringToListConvert());
}
private static class StringToListConvert implements Converter<String, List<String>> {
@Override
public List convert(String source) {
if (source == null) {
return Arrays.asList();
} else {
String[] split = source.split(",");
return Arrays.asList(split);
}
}
}
}
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.format.Formatter;
import org.springframework.format.FormatterRegistry;
import javax.annotation.PostConstruct;
import java.text.ParseException;
import java.util.List;
import java.util.Locale;
@Configuration
public class MyFormatterRegistry {
@Autowired
private FormatterRegistry formatterRegistry;
@PostConstruct
public void init() {
formatterRegistry.addFormatter(new StringDateFormatter());
}
public static class StringDateFormatter implements Formatter<List> {
//解析接口,根据Locale信息解析字符串到T类型的对象;
@Override
public List parse(String text, Locale locale) throws ParseException {
return null;
}
//格式化显示接口,将T类型的对象根据Locale信息以某种格式进行打印显示(即返回字符串形式);
@Override
public String print(List object, Locale locale) {
return "我是格式化的日期";
}
}
}
WebMvcConfigurerAdapter
import com.lf.web.convert.StringToListConvert;
import com.lf.web.formatter.StringDateFormatter;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.format.FormatterRegistry;
import org.springframework.web.servlet.ViewResolver;
import org.springframework.web.servlet.config.annotation.DefaultServletHandlerConfigurer;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.ViewResolverRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
import org.springframework.web.servlet.view.InternalResourceViewResolver;
@Configuration
@EnableWebMvc
@ComponentScan//组件扫描
public class WebConfig extends WebMvcConfigurerAdapter {
@Override
public void addFormatters(FormatterRegistry registry) {
super.addFormatters(registry);
registry.addFormatter(new StringDateFormatter());
registry.addConverter(new StringToListConvert());
}
}
xml的配置方式
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc.xsd">
<mvc:annotation-driven conversion-service="conversionService"/>
<bean id="conversionService" class="org.springframework.format.support.FormattingConversionServiceFactoryBean">
<property name="converters">
<set>
<bean class="com.web.convert.StringToListConvert"/>
set>
property>
<property name="formatters">
<set>
<bean class="com.web.formatter.StringDateFormatter"/>
set>
property>
<property name="formatterRegistrars">
<set>
<bean class="com.web.formatter.StringDateFormatter"/>
set>
property>
bean>
beans>
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.ViewResolver;
import org.springframework.web.servlet.view.JstlView;
import org.springframework.web.servlet.view.UrlBasedViewResolver;
import org.springframework.web.servlet.view.tiles2.TilesConfigurer;
import org.springframework.web.servlet.view.tiles2.TilesView;
@Configuration
public class ViewConfiguration {
@Bean
public ViewResolver urlBasedViewResolver() {
UrlBasedViewResolver viewResolver;
viewResolver = new UrlBasedViewResolver();
viewResolver.setOrder(2);
viewResolver.setPrefix(/WEB-INF/);
viewResolver.setSuffix(.jsp);
viewResolver.setViewClass(JstlView.class);
// for debug envirment
viewResolver.setCache(false);
return viewResolver;
}
@Bean
public ViewResolver tilesViewResolver() {
UrlBasedViewResolver urlBasedViewResolver = new UrlBasedViewResolver();
urlBasedViewResolver.setOrder(1);
urlBasedViewResolver.setViewClass(TilesView.class);
//urlBasedViewResolver.
return urlBasedViewResolver;
}
@Bean
public TilesConfigurer tilesConfigurer() {
TilesConfigurer tilesConfigurer = new TilesConfigurer();
tilesConfigurer.setDefinitions(new String[] { classpath:tiles.xml });
return tilesConfigurer;
}
}
实现WebApplicationInitializer 的作用类似于web.xml中对spring做的配置作用。
import javax.servlet.MultipartConfigElement;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.ServletRegistration.Dynamic;
import org.springframework.web.WebApplicationInitializer;
import org.springframework.web.context.support.AnnotationConfigWebApplicationContext;
import org.springframework.web.servlet.DispatcherServlet;
/**
* 服务器启动入口类
*/
public class WebApplicationStartup implements WebApplicationInitializer {
private static final String SERVLET_NAME = Spring-mvc;
private static final long MAX_FILE_UPLOAD_SIZE = 1024 * 1024 * 5; // 5 Mb
private static final int FILE_SIZE_THRESHOLD = 1024 * 1024; // After 1Mb
private static final long MAX_REQUEST_SIZE = -1L; // No request size limit
/**
* 服务器启动调用此方法,在这里可以做配置 作用与web.xml中配置spring的一些
础属性相同
*/
@Override
public void onStartup(ServletContext servletContext) throws ServletException {
// 注册springMvc的servlet
this.addServlet(servletContext);
// 注册过滤器
// servletContext.addFilter(arg0, arg1)
// 注册监听器
// servletContext.addListener(arg0);
}
/**
* 注册Spring servlet
*
* @param servletContext
*/
private void addServlet(ServletContext servletContext) {
// 构建一个application context
AnnotationConfigWebApplicationContext webContext = createWebContext(SpringMVC.class, ViewConfiguration.class);
// 注册spring mvc 的 servlet
Dynamic dynamic = servletContext.addServlet(SERVLET_NAME, new DispatcherServlet(webContext));
// 添加springMVC 允许访问的Controller后缀
dynamic.addMapping(*.html, *.ajax, *.css, *.js, *.gif, *.jpg, *.png);
// 全部通过请用 “/”
// dynamic.addMapping(/);
dynamic.setLoadOnStartup(1);
dynamic.setMultipartConfig(new MultipartConfigElement(null, MAX_FILE_UPLOAD_SIZE, MAX_REQUEST_SIZE, FILE_SIZE_THRESHOLD));
}
/**
* 通过自定义的配置类来实例化一个Web Application Context
*
* @param annotatedClasses
* @return
*/
private AnnotationConfigWebApplicationContext createWebContext(Class... annotatedClasses) {
AnnotationConfigWebApplicationContext webContext = new AnnotationConfigWebApplicationContext();
webContext.register(annotatedClasses);
return webContext;
}
}
通过在类上加入注解@Configuration,spring会自动扫描此类,并读取相关的配置。
类中的方法用@Bean注释,并指定其名称,返回bean的实例,等同于xml文件中的bena单例配置。
可以有多个@Configuration注解的类,多个@Bean注释的方法。
@Configuration
public class ShiroConfig {
@Bean("sessionManager")
public SessionManager sessionManager(){
DefaultWebSessionManager sessionManager = new DefaultWebSessionManager();
sessionManager.setSessionValidationSchedulerEnabled(true);
sessionManager.setSessionIdCookieEnabled(true);
return sessionManager;
}
@Bean("securityManager")
public SecurityManager securityManager(OAuth2Realm oAuth2Realm, SessionManager sessionManager) {
DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
securityManager.setRealm(oAuth2Realm);
securityManager.setSessionManager(sessionManager);
return securityManager;
}
@Bean("shiroFilter")
public ShiroFilterFactoryBean shirFilter(SecurityManager securityManager) {
ShiroFilterFactoryBean shiroFilter = new ShiroFilterFactoryBean();
shiroFilter.setSecurityManager(securityManager);
//oauth过滤
Map filters = new HashMap<>();
filters.put("oauth2", new OAuth2Filter());
shiroFilter.setFilters(filters);
Map filterMap = new LinkedHashMap<>();
filterMap.put("/webjars/**", "anon");
filterMap.put("/druid/**", "anon");
filterMap.put("/app/**", "anon");
filterMap.put("/sys/login", "anon");
filterMap.put("/**/*.css", "anon");
filterMap.put("/**/*.js", "anon");
filterMap.put("/**/*.html", "anon");
filterMap.put("/fonts/**", "anon");
filterMap.put("/plugins/**", "anon");
filterMap.put("/swagger/**", "anon");
filterMap.put("/favicon.ico", "anon");
filterMap.put("/captcha.jpg", "anon");
filterMap.put("/", "anon");
//filterMap.put("/**", "oauth2");
filterMap.put("/**", "anon");
shiroFilter.setFilterChainDefinitionMap(filterMap);
return shiroFilter;
}
@Bean("lifecycleBeanPostProcessor")
public LifecycleBeanPostProcessor lifecycleBeanPostProcessor() {
return new LifecycleBeanPostProcessor();
}
@Bean
public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator() {
DefaultAdvisorAutoProxyCreator proxyCreator = new DefaultAdvisorAutoProxyCreator();
proxyCreator.setProxyTargetClass(true);
return proxyCreator;
}
@Bean
public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager) {
AuthorizationAttributeSourceAdvisor advisor = new AuthorizationAttributeSourceAdvisor();
advisor.setSecurityManager(securityManager);
return advisor;
}
对于在Resource下的普通资源文件,如果采用war方式,那么可以采用传统的
读取classpath下的资源文件的方式来读取。
但是如果打成jar微服务包的形式,那么资源文件放在jar包中,读取的时候只能使用读取
jar包中的读取方式才能够获取到文件。
/**
* 读取流
* @param inStream
* @return 字节数组
* @throws Exception
*/
public static byte[] readStream(InputStream inStream) throws Exception {
ByteArrayOutputStream outSteam = new ByteArrayOutputStream();
try {
byte[] buffer = new byte[1024];
int len = -1;
while ((len = inStream.read(buffer)) != -1) {
outSteam.write(buffer, 0, len);
}
}finally {
if(null != outSteam) {
outSteam.close();
}
if(null != inStream) {
inStream.close();
}
}
return outSteam.toByteArray();
}
//将Resource目录下的文件读取成为Input,支持读取jar包中的资源文件
public static InputStream getResourcesFileInputStream(String fileRelativePath){
//获取容器资源解析器
ResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
try {
//获取所有匹配的文件
Resource[] resources = resolver.getResources(fileRelativePath);
Resource resource = null;
if(resources != null && resources.length > 0){
resource = resources[0];
}
//获得文件流,因为在jar文件中,不能直接通过文件资源路径拿到文件,但是可以在jar包中拿到文件流
InputStream stream = resource.getInputStream();
return stream;
} catch (IOException e) {
logger.warn("读取文件流失败!" + e);
}
return null;
}
/**
* 现采用普通的方式读取,不行的话就获取整个容器(jar包)中的资源文件
* @param filePath 文件在Resource目录下的路径和文件名信息
* @return
*/
public static String getResourceFileContent(String filePath, String charEncoding) throws Exception {
String url = Thread.currentThread().getContextClassLoader().getResource(filePath).getFile();
//String url = org.springframework.util.ResourceUtils.getURL("classpath:" + filePath).getFile();
//InputStream inputStream = ClassLoader.getSystemResourceAsStream(filePath);
File file = new File(url);
InputStream inputStream = null;
if(file.exists() && file.canRead()){
inputStream = new FileInputStream(file);
}else{
inputStream = getResourcesFileInputStream(filePath);
}
byte[] bytes = readStream(inputStream);
String content = new String(bytes,charEncoding);
return content;
}
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-cacheartifactId>
dependency>
<dependency>
<groupId>net.sf.ehcachegroupId>
<artifactId>ehcacheartifactId>
dependency>
加入ehcache的依赖和boot-starter-cache依赖后会,需要手动启用缓存,
启用后会自动使用ehcache为默认缓存。
单独配置config
@Configuration
@EnableCaching
public class CachingConfig {
@Bean
public CacheManager cacheManager() {
SimpleCacheManager cacheManager = new SimpleCacheManager();
cacheManager.setCaches(Arrays.asList(new ConcurrentMapCache("sampleCache")));
return cacheManager;
}
}
等效xml配置:
<beans>
<cache:annotation-driven/>
<bean id="cacheManager" class="org.springframework.cache.support.SimpleCacheManager">
<property name="caches">
<set>
<bean class="org.springframework.cache.concurrent.ConcurrentMapCacheFactoryBean">
<property name="name" value="sampleCache"/>
bean>
set>
property>
bean>
beans>
或者直接在SpringBootApplication上注解@EnableCaching
@SpringBootApplication
@EnableCaching
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="http://ehcache.org/ehcache.xsd">
<diskStore path="java.io.tmpdir"/>
<defaultCache
maxElementsInMemory="1000"
eternal="false"
timeToIdleSeconds="60"
timeToLiveSeconds="60"
overflowToDisk="false"/>
<cache name="myCache"
maxElementsOnDisk="20000"
maxElementsInMemory="2000"
eternal="true"
overflowToDisk="true"
diskPersistent="true"/>
<cache name="users"
maxEntriesLocalHeap="200"
timeToLiveSeconds="30">
cache>
ehcache>
@RestController
@RequestMapping("/cache")
@CacheConfig(cacheNames= arrayOf("users")) //如果不配置cacheconfig,那么在cacheable中必须指定value
class CacheController{
@RequestMapping("cached")
@Cacheable(key="'cache_d'",condition ="true")
fun cacheDefault():String{
return getDateString()
}
@RequestMapping("cachem")
@Cacheable(value = "myCache",key="'cache_m'",condition ="true")
fun cachem():String{
return getDateString()
}
fun getDateString():String{
return SimpleDateFormat("yyyy-mm-dd HH:mm:ss.sss").format( Date())
}
}
Spring boot 配置详解
https://www.cnblogs.com/zheting/p/6707036.html
Spring boot入门
https://www.ibm.com/developerworks/cn/java/j-lo-spring-boot/
Spring boot静态资源
https://blog.csdn.net/catoop/article/details/50501706
/**
* 读取流
* @param inStream
* @return 字节数组
* @throws Exception
*/
public static byte[] readStream(InputStream inStream) throws Exception {
ByteArrayOutputStream outSteam = new ByteArrayOutputStream();
try {
byte[] buffer = new byte[1024];
int len = -1;
while ((len = inStream.read(buffer)) != -1) {
outSteam.write(buffer, 0, len);
}
}finally {
if(null != outSteam) {
outSteam.close();
}
if(null != inStream) {
inStream.close();
}
}
return outSteam.toByteArray();
}
//将Resource目录下的文件读取成为Input,支持读取jar包中的资源文件
public static InputStream getResourcesFileInputStream(String fileRelativePath){
//获取容器资源解析器
ResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
try {
//获取所有匹配的文件
Resource[] resources = resolver.getResources(fileRelativePath);
Resource resource = null;
if(resources != null && resources.length > 0){
resource = resources[0];
}
//获得文件流,因为在jar文件中,不能直接通过文件资源路径拿到文件,但是可以在jar包中拿到文件流
InputStream stream = resource.getInputStream();
return stream;
} catch (IOException e) {
logger.warn("读取文件流失败!" + e);
}
return null;
}
/**
* 现采用普通的方式读取,不行的话就获取整个容器(jar包)中的资源文件
* @param filePath 文件在Resource目录下的路径和文件名信息
* @return
*/
public static String getResourceFileContent(String filePath, String charEncoding) throws Exception {
String url = Thread.currentThread().getContextClassLoader().getResource(filePath).getFile();
//String url = org.springframework.util.ResourceUtils.getURL("classpath:" + filePath).getFile();
//InputStream inputStream = ClassLoader.getSystemResourceAsStream(filePath);
File file = new File(url);
InputStream inputStream = null;
if(file.exists() && file.canRead()){
inputStream = new FileInputStream(file);
}else{
inputStream = getResourcesFileInputStream(filePath);
}
byte[] bytes = readStream(inputStream);
String content = new String(bytes,charEncoding);
return content;
}
原文链接:https://blog.csdn.net/huitoukest/article/details/80048541