Spring Boot 学习
一、入门
1.介绍
使用Spring Boot 可以更轻松地创建独立的、生产级的基于 Spring 的Java应用程序,这些应用程序可以使用 java -jar或更传统的 war 部署来部署
Spring Boot 2.0.2.RELEASE 需要 Java 8(或 9)和 Spring Framework 5.0.6.RELEASE
参考:官方文档
2.Spring Boot的特点
- 项目搭建更迅速便捷,可无需配置的自动整合主流第三方框架
- 遵循习惯优于配置的原则,大多数时候使用默认配置即可
- 内嵌servlet容器(Servlet、Jetty、Undertow),降低了对环境的要求,可用命令直接执行项目
- 提供了starter POM,能够非常方便的进行包管理
- 没有代码生成,也不需要 XML 配置
- 应用监控
- Spring cloud
3. Spring Boot 搭建
项目结构图pom.xml主要内容如下
<!--继承父启动器-->
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.0.2.RELEASE</version>
</parent>
<!-- Additional lines to be added here... -->
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
在项目根目录下创建Application启动入口
@SpringBootApplication
@EnableAutoConfiguration
@ImportResource({"classpath:applicationContext.xml"}) //根据具体情况配置
public class JackDawsonApplication {
public static void main(String[] args) {
SpringApplication.run(JackDawsonApplication.class, args);
}
}
一个controller文件
import org.springframework.boot.*;
import org.springframework.boot.autoconfigure.*;
import org.springframework.web.bind.annotation.*;
@RestController
public class ExampleController {
@RequestMapping("/")
String home() {
return "Hello World!";
}
}
配置bean
package com.jack.jackdawson.config;
@Configuration
public class BeanConfig implements EnvironmentAware{
private Environment env;
@Override
public void setEnvironment(@NonNull Environment env) { this.env = env}
@Bean(name = "myBeanA")
// @Qualifier("myBean")
public A getA(){
A a = new A();
a.setName(env.getProperty("a.name"))
return a;
}
@Bean(name = "myBeanAback")
// @Qualifier("myBeanAback")
public A getA(){
A a = new A();
a.setName(env.getProperty("a.name.back"))
return a;
}
}
4.基本注解
Spring boot的注解
- @SpringBootApplication:申明让spring boot自动给程序进行必要的配置,包含了@ComponentScan、@Configuration和@EnableAutoConfiguration注解。其中@ComponentScan让spring Boot扫描到Configuration类并把它加入到程序上下文
- @EnableAutoConfiguration 自动配置
- @AutoConfigureBefore、@AutoConfigureAfter、@AutoConfigureOrder 制定类加载顺序在参数类之前、之后或自定义顺序,可以用于定制配置文件加载顺序
- @ConfigurationProperties 定义bean时,bean会根据该注解内的参数去application.properties文件内匹配对应的变量自动注入
Spring 5.0中的注解
- @Configuration 等同于spring的XML配置文件;使用Java代码可以检查类型安全
- @Bean 注册Bean到Spring IoC的注解
- @ComponentScan 组件扫描,可自动发现和装配一些Bean
- @Conditional 根据参数中设置的条件装载不同的bean,该注解的参数是一个实现了Condition接口的类
- @Import 是引入带有@Configuration的java类
- @ImportResource 引入Spring的xml配置文件
- @PropertySource 将properties配置文件中的值存储到Spring的 Environment中
- @Autowired 装配bean,按类型装配
- @Controller:注解在类上,表示这是一个控制层bean
- @Service: 注解在类上,表示这是一个业务层bean
- @Repository: 注解在类上,表示这是一个数据访问层bean
- @Component: 注解在类上,表示通用bean
Spring web mvc 注解
- @RequestMapping,@RestController,@RequestParam,@ModelAttribute,@SessionAttributes ,@RequestBody,@ResponseBody
Java 注解
- @Resource 装配bean,按名称装配
- @PostConstruct 注解在方法上,构造函数执行后执行
- @PreDestroy 注解在方法上,在Bean销毁前执行
二、使用
1.mysql数据库配置
配置mysql数据源,jdbc方式
添加pom依赖
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
application.properties配置,SpringBoot能够自动识别到以下这些mysql配置
spring.datasource.url=jdbc:mysql://127.0.0.1:3306/test
spring.datasource.username=root
spring.datasource.password=123456
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
#spring.datasource.max-idle=10
#spring.datasource.max-wait=10000
#spring.datasource.min-idle=5
#spring.datasource.initial-size=5
在代码中直接使用jdbcTemplate
@Autowired
private JdbcTemplate jdbcTemplate;
多数据源配置
可以新建一个db.properties文件,里面定义各个数据库的连接配置,然后通过注册bean的方式手动定义各个datasource
db.properties文件如下
datasource.url=jdbc:mysql://localhost:3306/test
datasource.username=root
datasource.password=123456
datasource.back.url=jdbc:mysql://localhost:3306/jack
datasource.back.username=root
datasource.back.password=123456
DataSourceConfig配置文件如下
@Configuration
@PropertySource("classpath:config/db.properties")
@ComponentScan(value = "com.jack.jackdawson")
public class DataSourceConfig {
@Autowired
private Environment env;
@Bean(name = "myDataSource1")
public DataSource getDataSource1(){
DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setUrl(env.getProperty("spring.datasource.url"));
dataSource.setUsername(env.getProperty("spring.datasource.username"));
dataSource.setPassword(env.getProperty("spring.datasource.password"));
return dataSource;
}
@Bean(name = "myDataSource2")
public DataSource getMyDataSource2(){
DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setUrl(env.getProperty("spring.datasource.back.url"));
dataSource.setUsername(env.getProperty("spring.datasource.back.username"));
dataSource.setPassword(env.getProperty("spring.datasource.back.password"));
return dataSource;
}
}
2.JPA
参考博客
2.1 特点
JPA顾名思义就是Java Persistence API的意思
- 标准化:JPA 是Java EE 标准之一,任何符合 JPA 标准的框架都遵循同样的架构,基于JPA开发的企业应用能够经过少量的修改就能够在不同的JPA框架下运行。
- 支持大数据集、事务、并发等容器级事务
- 简单方便:在JPA框架下创建实体和创建Java 类一样简单,只需要使用 @Entity进行注释,JPA的框架和接口也都非常简单,没有太多特别的规则和设计模式的要求,可以很容易的和其它框架或者容器集成。
- 查询能力:JPA的查询语言是面向对象而非面向数据库的,它以面向对象的自然语法构造查询语句,可以看成是Hibernate HQL的等价物。JPA定义了独特的JPQL
2.2 常用注解
@Entity 声明为实体类
@Table 声明表名
@Id 标识表的主键
@GeneratedValue 指定主键生成策略
@Column 指定持久属性栏属性
@Basic 表示一个简单的属性到数据库表的字段的映射
@ManyToMany、@ManyToOne、@OneToMany、@OneToOne 定义连接表之间的关系
2.3 配置
# pom依赖配置
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
# yml格式的application.properties
spring:
datasource:
url: jdbc:mysql://localhost:3306/mytest
type: com.alibaba.druid.pool.DruidDataSource
username: root
password: root
driver-class-name: com.mysql.jdbc.Driver
jpa:
hibernate:
ddl-auto: update //自动更新
show-sql: true //日志中显示sql语句
定义实体类以及数据访问接口
@Entity
@Table(name = "person") //如果未指定则和类名一致
@Data
public class Person {
@Id
@GeneratedValue
private Long id;
@Column(name = "name", nullable = true, length = 20)
private String name;
@Column(name = "agee", nullable = true, length = 4)
private int age;
}
public interface PersonDAO extends JpaRepository<Person, Long> {
}
然后在业务代码中直接引用PersonDAO 的对象即可,提供了各种操作Person对象的方法,如果需要自己定义复杂的sql语句,可以在PersonDAO 接口中进行声明
@Query(nativeQuery = true, value = "SELECT * FROM persion WHERE name = :name1 OR name = :name2 ")
List<Persion> findTwoName(@Param("name1") String name1, @Param("name2") String name2);
如果需要可以在application.properties中配置spring.jpa.hibernate.ddt-auto等参数,控制项目启动后是否需要自动连接数据库将表建好或更新,参考
3.过滤器与拦截器等web配置
Spring boot 已经可以完全抛弃web.xml
TomcatStarter 中的 org.springframework.boot.context.embedded.ServletContextInitializer 是 springboot 初始化 servlet,filter,listener 的关键
使用WebMvcConfigurerAdapter抽象类来处理SpringMVC相关的配置
下面的WebAppRootContext配置类分别实现了这两个接口,并在里面定义了filter和interceptor
@Configuration
@ComponentScan
@EnableAutoConfiguration
@PropertySource("classpath:config/web.properties")
public class WebAppRootContext implements ServletContextInitializer, WebMvcConfigurer, EnvironmentAware {
private Environment env;
@Resource
private RequestMappingHandlerAdapter handlerAdapter;
@Override
public void setEnvironment(@NonNull Environment environment) {
this.env = environment;
}
//这里可以设置initParam
@Override
public void onStartup(ServletContext servletContext) throws ServletException {
String casServerName = env.getProperty("cas_server_name");
servletContext.addListener(WebAppRootListener.class);
servletContext.setInitParameter("cas_server_name", casServerName);
}
@Bean
public FilterRegistrationBean getAuthenticationFilter() {
AuthenticationFilter authenticationFilter = new AuthenticationFilter();
authenticationFilter.setCasServerLoginUrl("***");
authenticationFilter.setServerName("localhost:8080");
authenticationFilter.setIgnoreInitConfiguration(true);
FilterRegistrationBean<AuthenticationFilter> casFilterBean = new FilterRegistrationBean<>();
casFilterBean.setUrlPatterns(Collections.singletonList("/*"));
casFilterBean.setFilter(authenticationFilter);
return casFilterBean;
}
@Bean
public FilterRegistrationBean getTicketValidationFilter() {
Cas20ProxyReceivingTicketValidationFilter ticketValidationFilter = new Cas20ProxyReceivingTicketValidationFilter();
FilterRegistrationBean<Cas20ProxyReceivingTicketValidationFilter> ticketFilterBean = new FilterRegistrationBean<>();
ticketFilterBean.setFilter(ticketValidationFilter);
ticketFilterBean.setUrlPatterns(Collections.singletonList("/*"));
Map<String, String> initParameters = new HashMap<>();
initParameters.put("casServerUrlPrefix", "***");
initParameters.put("serverName", "http://localhost:9080");
ticketFilterBean.setInitParameters(initParameters);
ticketFilterBean.setOrder(1);
return ticketFilterBean;
}
/*
* 这里需要把拦截器注册一下,否则里面依赖的bean无法使用
*/
@Bean
public LoginRequiredInterceptor getLoginRequiredInterceptor() {
return new LoginRequiredInterceptor();
}
@Bean
public PrivilegeInterceptor getPrivilegeInterceptor() {
return new PrivilegeInterceptor();
}
@Override
public void addInterceptors(InterceptorRegistry registry) {
//登录拦截的管理器
registry.addInterceptor(getLoginRequiredInterceptor()) //拦截的对象会进入这个类中进行判断
.addPathPatterns("/**") //所有路径都被拦截
.excludePathPatterns("/","/login*","/logout*", "/noPrivilege*", "/error*", "/assets"); //添加不拦截路径
registry.addInterceptor(getPrivilegeInterceptor())
.addPathPatterns("/**")
.excludePathPatterns("/","/login*","/logout*", "/noPrivilege*", "/error*", "/assets");
}
//后面设置controller层默认参数会用到
@PostConstruct
public void initEditableValidation() {
ConfigurableWebBindingInitializer initializer = (ConfigurableWebBindingInitializer)handlerAdapter.getWebBindingInitializer();
if(initializer.getConversionService()!=null) {
GenericConversionService genericConversionService = (GenericConversionService)initializer.getConversionService();
genericConversionService.addConverter(new StringToDateConverter());
genericConversionService.addConverter(new StringToIntConverter());
genericConversionService.addConverter(new StringToLongConverter());
}
}
}
4.前端模板配置
velocity
使用阿里巴巴提供的velocity-starter,参考文档
pom配置
<dependency>
<groupId>com.alibaba.boot</groupId>
<artifactId>velocity-spring-boot-starter</artifactId>
<version>1.0.4.RELEASE</version>
</dependency>
application.properties配置
spring.velocity.resource-loader-path = classpath:/templates
spring.velocity.prefix = /view/
spring.velocity.suffix = .vm
velocimacro.library = global_library.vm
#velocimacro.permissions.allow.inline = true
#velocimacro.permissions.allow.inline.to.replace.global = false
#velocimacro.context.localscope = false
#velocimacro.library.autoreload = false
spring.velocity.layout-url = /template/layout.vm
spring.velocity.layout-enabled = true
thymeleaf
Thymeleaf 是一种模板语言,和velocity类似
- 静态资源(css、js、图片等)默认放在resources/static下面。如果要修改默认存放目录,可以通过设置属性 spring.mvc.static-path-pattern来实现。
- 模板文件默认放在 templates目录下
pom配置
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-themeleaf</artifactId>
</dependency>
application.properties配置
#thymelea模板配置
spring.thymeleaf.prefix=classpath:/templates/
spring.thymeleaf.suffix=.html
spring.thymeleaf.mode=HTML5
spring.thymeleaf.encoding=UTF-8
#热部署文件,页面不产生缓存,及时更新
spring.thymeleaf.cache=false
spring.resources.chain.strategy.content.enabled=true
spring.resources.chain.strategy.content.paths=/**
thymeleaf入门
thymeleaf官方文档
velocity -> thymeleaf迁移参考
5.log4j2 配置
Spring Boot 2.0 默认情况下是使用logback作为日志系统,如果需要使用log4j2需要进行以下配置,这里需要使用log42而不是log4j,从 spring boot 1.4开始Spring Boot就支持log4j2,写法和log4j类似,只是有些标签的名字不同
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<exclusions>
<exclusion><!--剔除原来默认的logging-->
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-logging</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-log4j2</artifactId>
</dependency>
如下时一个log4j2.xml文件,将该文件放到resources目录下,SpringBoot项目会自动识别到该配置文件进行配置,当然了如果不添加log4j.xml文件,springboot会提示你没有对应文件,并使用默认的配置文件,这个时候日志级别可以在application.properties中配置
<?xml version="1.0" encoding="UTF-8"?>
<Configuration>
<Appenders>
<Console name="Console" target="SYSTEM_OUT" follow="true">
<PatternLayout>
<pattern>[%-5p] %d %c - %m%n</pattern>
</PatternLayout>
</Console>
<!--添加一个文本追加器,文件位于根目录下,名为log.log-->
<File name="File" fileName="log.log">
<PatternLayout>
<pattern>[%-5p] %d %c - %m%n</pattern>
</PatternLayout>
</File>
</Appenders>
<Loggers>
<Logger name="com.jack-dawson" level="debug" >
<!-- AppenderRef 可以控制文件输出对象-->
<AppenderRef ref="File" />
</Logger>
<Logger name="org.spring" level="debug">
<AppenderRef ref="File" />
</Logger>
<!--根记录全部输出到控制台上-->
<Root level="debug">
<AppenderRef ref="Console" />
</Root>
</Loggers>
</Configuration>
三、拓展
Spring Boot为什么没有web.xml了
使用spring-boot-devtools实现热部署及热更新
过滤器Filter和拦截器Interceptor区别
处理前端模型数据ModelAndView
Maven常用插件
四、问题
1.@Environment 注解失效,获取到的对象是null
原来使用@Autowired方式获取Environment对象,改成实现EnvironmentAware接口
2.bean初始化顺序问题
在用@Configuration注解标记为配置文件的类中使用@Resource等方式去获取bean实例可能会发生错误,改为@bean方式获取即可
3.controller层接收的参数类型是int,如果请求中未设置对应值会报错
项目初始化bean完成后通过ConfigurableWebBindingInitializer类添加自定义的参数转换器
4.前端模板文件必须放在resources目录下
5.velocity配置指定layout-enabled=true时tools.xml的配置会失效
[velocity-spring-boot-starter](https://github.com/alibaba/velocity-spring-boot-project/blob/master/README_CN.md)
6.application.properties中无法通过${}方式获取pom的变量
Spring Boot已经将maven-resources-plugins默认的${}方式改为了@@方式,如@name@
7.Spring boot集成rose框架后启动时初始化失败
rose框架在初始化时会创建SpringContext对象,和SpringBoot创建的SpringContext对象发生冲突
8.Spring boot继承rose框架,把项目打成jar包后启动失败,提示FileNotFoundException
rose框架内会去项目依赖的jar包中寻找是否有需要初始化的bean,比如用@DAO注解标记的类,但是将项目打成jar包后,无法加载到项目jar内的jar包
9.继承velocity后controller层返回的vm模板名称被当成普通字符串处理
@RestController -> @Controller,如果方法需要返回json用@ResponseBody标记,同时指定@RequestMapping(value = "/pets/{petId}", method = RequestMethod.GET, produces="application/json") 中的produces为json