赞
踩
目录
4.8.3.1.1 @EnableAutoConfiguration
4.8.3.1.3 @SpringBootConfiguration
4.8.3.1.4 @SpringBootApplication
众所周知 Spring 应用需要进行大量的配置,各种 XML 配置和注解配置让人眼花缭乱,且极容易出错,因此 Spring 一度被称为“配置地狱”。
为了简化 Spring 应用的搭建和开发过程,出现了一套全新的开源的框架,它就是 Spring Boot。
Spring Boot 具有 Spring 一切优秀特性,Spring 能做的事,Spring Boot 都可以做,而且使用更加简单,功能更加丰富,性能更加稳定而健壮。
Spring Boot 提供了大量开箱即用(out-of-the-box)的依赖模块,例如 spring-boot-starter-redis、spring-boot-starter-data-mongodb 和 spring-boot-starter-data-elasticsearch 等。这些依赖模块为 Spring Boot 应用提供了大量的自动配置,使得 Spring Boot 应用只需要非常少量的配置甚至零配置,便可以运行起来,让开发人员从 Spring 的“配置地狱”中解放出来,有更多的精力专注于业务逻辑的开发。
因此,我们也称springboot为脚手架。
SpringBoot官方参考文献【Spring Boot Reference Guide】
Spring Boot 主要特征是:
创建一个空项目
添加父工程坐标
- <parent>
- <groupId>org.springframework.boot</groupId>
- <artifactId>spring-boot-starter-parent</artifactId>
- <version>2.0.6.RELEASE</version>
- </parent>
添加web启动器
- <dependencies>
- <dependency>
- <groupId>org.springframework.boot</groupId>
- <artifactId>spring-boot-starter-web</artifactId>
- </dependency>
- </dependencies>
为了让SpringBoot帮我们完成各种自动配置,我们必须引入SpringBoot提供的自动配置依赖,我们称为启动器
。因为我们是web项目,这里我们引入web启动器:
需要注意的是,我们并没有在这里指定版本信息。因为SpringBoot的父工程已经对版本进行了管理了。
SpringbootDemoApplication
- //@SpringBootApplication
- @EnableAutoConfiguration
- @ComponentScan
- public class SpringbootDemoApplication {
- public static void main(String[] args) {
- SpringApplication.run(SpringbootDemoApplication.class);
- }
- }
DemoController
- @RestController
- @EnableAutoConfiguration //开启自动配置
- public class DemoController {
- @RequestMapping("/first")
- public String first(){
- return "this is my first spring boot project!";
- }
-
- public static void main(String[] args) {
- SpringApplication.run(DemoController.class,args);
- }
-
- }
输入网址
开启spring应用程序的自动配置,SpringBoot基于所添加的依赖和自定义的bean,试图去猜测并配置想要的配置。比如引入spring-boot-starter-web
,而这个启动器中帮我们添加了tomcat
、SpringMVC
的依赖。此时自动配置就知道是要开发一个web应用,所以自动完成了web及SpringMVC的默认配置了!
配置组件扫描的指令。提供了类似与<context:component-scan>
标签的作用
通过basePackageClasses或者basePackages属性来指定要扫描的包。如果没有指定这些属性,那么将从声明这个注解的类所在的包开始,扫描包及子包
而@ComponentScan注解声明的类就是main函数所在的启动类,因此扫描的包是该类所在包及其子包。一般启动类会放在一个比较浅的包目录中。
这个注解的作用就是声明当前类是一个配置类,然后Spring会自动扫描到添加了@Configuration
的类,并且读取其中的配置信息。而@SpringBootConfiguration
是来声明当前类是SpringBoot应用的配置类,项目中只能有一个。所以一般我们无需自己添加。
上面一堆太复杂,于是@SpringBootApplication整合了上面所有注解,以后只需要写一个@SpringBootApplication就可以
@SpringBootApplication其实是一个组合注解,这里重点的注解有3个:
@RestController 是@controller和@ResponseBody 的结合
@Controller 将当前修饰的类注入SpringBoot IOC容器,使得从该类所在的项目跑起来的过程中,这个类就被实例化。
@ResponseBody表示方法的返回值直接以指定的格式写入Http response body中,而不是解析为跳转路径
如果要求方法返回的是json格式数据,而不是跳转页面,可以直接在类上标注@RestController,而不用在每个方法中标注@ResponseBody,简化了开发过程。
- @RestController
- public class TestController {
- @RequestMapping("/first")
- public String test(){
- return "test";
- }
- }
- @Configuration //配置类 bean.xml
- @PropertySource("classpath:jdbc.properties") //加载属性文件
- public class DataSourceAutoConfiguration {
- //使用value注解传递参数
- @Value("${jdbc.url}")
- String url;
- @Value("${jdbc.driverClassName}")
- String driverClassName;
- @Value("${jdbc.username}")
- String username;
- @Value("${jdbc.password}")
- String password;
-
- //方法返回的对象放到IOC中
- @Bean //<bean id="DataSource" class="......">
- public DataSource dataSource() {
- DruidDataSource dataSource = new DruidDataSource();
- dataSource.setUrl(url);
- dataSource.setDriverClassName(driverClassName);
- dataSource.setUsername(username);
- dataSource.setPassword(password);
- return dataSource;
- }
@Configuration
:声明JdbcConfiguration
是一个配置类。
@PropertySource
:指定属性文件的路径是:classpath:jdbc.properties
通过
@Value
为属性注入值。通过@Bean将
dataSource()
方法声明为一个注册Bean的方法,Spring会自动调用该方法,将方法的返回值加入Spring容器中。相当于以前的bean标签
可以在任意位置通过@Autowired
注入DataSource
传统方式属性注入使用的是@Value注解。这种方式虽然可行,但是不够强大,因为它只能注入基本类型值。
在SpringBoot中,提供了一种新的属性注入方式,支持各种java基本数据类型及复杂类型的注入。
1、新建JdbcProperties
,用来进行属性注入
- @ConfigurationProperties(prefix = "jdbc")
- public class JdbcProperties {
- private String url;
- private String driverClassName;
- private String username;
- private String password;
- // ... 略
- // getters 和 setters
- }
在类上通过@ConfigurationProperties注解声明当前类为属性读取类
prefix="jdbc"
读取属性文件中,前缀为jdbc的值。在类上定义各个属性,名称必须与属性文件中
jdbc.
后面部分一致,并且必须具有getter和setter方法需要注意的是,这里我们并没有指定属性文件的地址,SpringBoot默认会读取文件名为application.properties的资源文件
application.properties
-
- # SpringBoot
- spring.datasource.driverClassName=com.mysql.jdbc.Driver
-
- spring.datasource.url=jdbc:mysql:///mydb
- spring.datasource.username=root
- spring.datasource.password=123456
- #HikariCP 连接池 springboot默认连接池
- spring.datasource.hikari.idle-timeout=60000
- spring.datasource.hikari.maximum-pool-size=30
- spring.datasource.hikari.minimum-idle=10
-
- #
- #logging.level.org.springframework=debug
-
- # mybatis
- # 别名
- mybatis.type-aliases-package=com.bl.model
- # mapper文件路径
- # mybatis.mapper-locations=classpath:mapper/*.xml
- # mybatis全局配置文件路径
- # mybatis.config-location=classpath:mybatis-config.xml
2、在JdbcConfiguration中使用这个属性,有三种方式
@Autowired注入
- @Configuration
- @EnableConfigurationProperties(JdbcProperties.class)
- public class JdbcConfiguration {
-
- @Autowired
- private JdbcProperties jdbcProperties;
-
- @Bean
- public DataSource dataSource() {
- DruidDataSource dataSource = new DruidDataSource();
- dataSource.setUrl(jdbcProperties.getUrl());
- dataSource.setDriverClassName(jdbcProperties.getDriverClassName());
- dataSource.setUsername(jdbcProperties.getUsername());
- dataSource.setPassword(jdbcProperties.getPassword());
- return dataSource;
- }
-
- }
构造函数注入
- @Configuration
- @EnableConfigurationProperties(JdbcProperties.class)
- public class JdbcConfiguration {
-
- private JdbcProperties jdbcProperties;
-
- public JdbcConfiguration(JdbcProperties jdbcProperties){
- this.jdbcProperties = jdbcProperties;
- }
-
- @Bean
- public DataSource dataSource() {
- // 略
- }
-
- }
@Bean方法的形参注入
- @Configuration
- @EnableConfigurationProperties(JdbcProperties.class)
- public class JdbcConfiguration {
-
- @Autowired
- DataSourceProperties dataSourceProperties;
- //方法返回的对象放到IOC中
- @Bean //<bean id="DataSource" class="......">
- public DataSource dataSource() {
- DruidDataSource dataSource = new DruidDataSource();
- dataSource.setUrl(dataSourceProperties.getUrl());
- dataSource.setDriverClassName(dataSourceProperties.getDriverClassName());
- dataSource.setUsername(dataSourceProperties.getUsername());
- dataSource.setPassword(dataSourceProperties.getPassword());
- return dataSource;
- }
- }
当只有一个类使用属性。如果一段属性只有一个Bean需要使用,我们无需将其注入到一个类(JdbcProperties)中。而是直接在需要的地方声明即可:
- @Configuration
- public class JdbcConfiguration {
-
- @Bean
- // 声明要注入的属性前缀,SpringBoot会自动把相关属性通过set方法注入到DataSource中
- @ConfigurationProperties(prefix = "jdbc")
- public DataSource dataSource() {
- DruidDataSource dataSource = new DruidDataSource();
- return dataSource;
- }
- }
直接把
@ConfigurationProperties(prefix = "jdbc")
声明在需要使用的@Bean
的方法上,然后SpringBoot就会自动调用这个Bean(此处是DataSource)的set方法,然后完成注入。使用的前提是:该类必须有对应属性的set方法!
如图所示手动搭建项目
父工程坐标
- <parent>
- <groupId>org.springframework.boot</groupId>
- <artifactId>spring-boot-starter-parent</artifactId>
- <version>2.0.6.RELEASE</version>
- </parent>
web启动器
- <dependencies>
- <dependency>
- <groupId>org.springframework.boot</groupId>
- <artifactId>spring-boot-starter-web</artifactId>
- </dependency>
- </dependencies>
创建启动类Appstarter
- @SpringBootApplication
- public class Appstarter {
- public static void main(String[] args) {
- SpringApplication.run(Appstarter.class,args);
- }
- }
注意启动类的位置,要和最后的包同层(要放在一个比较浅的包目录中)
TestController
- @RestController
- public class TestController {
- @RequestMapping("/first")
- public String test1(){
- return "first";
- }
- }
添加全局配置文件application.properties
- # 此时可以创建空的文件,后续整合其他模块会在全局配置文件中逐步添加配置信息
- # 映射端口
- # server.port=8080
访问静态资源
项目是一个jar工程,没有webapp,我们的静态资源该放哪里呢?
只要静态资源放在这些目录中任何一个,SpringMVC都会帮我们处理。
习惯性将静态资源放在classpath:/static/
目录下
添加拦截器
拦截器不是一个普通属性,而是一个类,所以就要用到java配置方式了
如果想要保持Spring Boot 的一些默认MVC特征,同时又想自定义一些MVC配置(包括:拦截器,格式化器, 视图控制器、消息转换器 等等),你应该让一个类实现
WebMvcConfigurer
,并且添加@Configuration
注解,但是千万不要加@EnableWebMvc
注解。如果你想要自定义HandlerMapping
、HandlerAdapter
、ExceptionResolver
等组件,你可以创建一个WebMvcRegistrationsAdapter
实例 来提供以上组件。如果你想要完全自定义SpringMVC,不保留SpringBoot提供的一切特征,你可以自己定义类并且添加
@Configuration
注解和@EnableWebMvc
注解
通过实现WebMvcConfigurer
并添加@Configuration
注解来实现自定义部分SpringMvc配置。
定义一个拦截器MyInterceptor
- @Component //创建对象
- public class MyInterceptor implements HandlerInterceptor {
- @Override
- public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
- System.out.println("核心业务之前执行");
- return true; //true:表示放行 false:不放行,一直卡这
- }
-
- @Override
- public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
- System.out.println("核心业务之后执行");}
-
- @Override
- public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
- System.out.println("核心业务完成之后执行");
- }
- }
定义配置类,注册拦截器
- @Configuration //配置类 替代以前的xml文件
- public class MyMVCConfig implements WebMvcConfigurer {
- //配置原来的xml里面的规则
- @Autowired
- MyInterceptor myInterceptor;
-
- @Override
- public void addInterceptors(InterceptorRegistry registry) {
- //添加自定义拦截器
- registry.addInterceptor(myInterceptor)
- .addPathPatterns("/**") //定义规则 /**:拦截所有资源 /*:只拦截一层 如/user/findall 只拦截user,不拦截findall
- .excludePathPatterns("/first"); //不拦截哪些资源
-
- }
- }
[hi·ka·'lē] (日语): 光
HikariCP应该是目前速度最快的连接池,同时也是springboot默认的连接池,所以不需要引入依赖,直接简单配置即可
application.properties
- # 连接四大参数
- spring.datasource.url=jdbc:mysql://localhost:3306/dms
- spring.datasource.username=root
- spring.datasource.password=root
- # 可省略,SpringBoot自动推断
- spring.datasource.driverClassName=com.mysql.jdbc.Driver
-
- spring.datasource.hikari.idle-timeout=60000
- spring.datasource.hikari.maximum-pool-size=30
- spring.datasource.hikari.minimum-idle=10
引入Druid官方提供的启动器
- <!-- Druid连接池 -->
- <dependency>
- <groupId>com.alibaba</groupId>
- <artifactId>druid-spring-boot-starter</artifactId>
- <version>1.1.6</version>
- </dependency>
application.properties
- #初始化连接数
- spring.datasource.druid.initial-size=1
- #最小空闲连接
- spring.datasource.druid.min-idle=1
- #最大活动连接
- spring.datasource.druid.max-active=20
- #获取连接时测试是否可用
- spring.datasource.druid.test-on-borrow=true
- #监控页面启动
- spring.datasource.druid.stat-view-servlet.allow=true
类别 | Druid | HikariCP |
获取和关闭Connection速度 | 较慢 | 较快 |
lru cache | 支持 | 不支持 |
ps chace | 支持 | 不支持 |
Filter扩展 | 支持 | 不支持 |
连接泄露诊断 | logAbandoned | 不支持 |
SQL注入检查 | 支持 | 不支持 |
配置加密 | 支持 | 不支持 |
代码量 | 较多 | 较少 |
总的来说
性能方面:HikariCP因为细节方面优化力度较大,性能方面强于Druid
功能丰富程度方面:Druid功能更全面除了具有连接池的基本功能以外,还支持sql级监控,支持扩展,防止SQL注入等功能。
使用热度:Druid在国内使用较多,国内有很多生产实践。HikariCP是spring boot 2.0以后默认连接池,在国外使用较多。
如果要求速度,建议使用HikariCP,如果对速度要求不是很严格,但对各个方面功能要求综合性,建议使用Druid。
SpringBoot官方并没有提供Mybatis的启动器,不过Mybatis官方自己实现了:
- <!--mybatis -->
- <dependency>
- <groupId>org.mybatis.spring.boot</groupId>
- <artifactId>mybatis-spring-boot-starter</artifactId>
- <version>1.3.2</version>
- </dependency>
基本没什么可配置的
application.properties
- # mybatis
- # 别名
- mybatis.type-aliases-package=com.bl.model
- # mapper文件路径
- # mybatis.mapper-locations=classpath:mapper/*.xml
- # mybatis全局配置文件路径
- # mybatis.config-location=classpath:mybatis-config.xml
注意,这里没有配置mapper接口扫描包,因此我们需要给每一个Mapper接口添加@Mapper
注解,才能被识别。
- @Mapper
- public interface UserMapper {
- }
由于mapper里很多代码都是重复的,因此把重复的代码提取出来,便有了通用mapper
通用 Mapper 是一个可以实现任意 MyBatis 通用方法的框架,项目提供了常规的增删改查操作
我们可以仅仅继承通用mapper,就可以使用父类的简单的增删改查方法。
相当于认个干爹,这样,干爹有什么,儿子就有什么,很方便
通用mapper启动器
- <!-- 通用mapper -->
- <dependency>
- <groupId>tk.mybatis</groupId>
- <artifactId>mapper-spring-boot-starter</artifactId>
- <version>2.0.2</version>
- </dependency>
创建UserMapper继承通用mapper
- @org.apache.ibatis.annotations.Mapper //扫描持久层,认个爹,基础的增删改查都有了
- public interface UserMapper extends Mapper<User> {
-
- }
-
-
-
- @Mapper
- public interface UserMapper extends tk.mybatis.mapper.common.Mapper<User>{
-
- }
UserServiceImpl
- @Service
- // @Transactional全局事务
- public class UserServiceImpl implements UserService {
- @Autowired
- UserMapper userMapper;
- @Override
- // Transactional() 某个方法添加事务
- public User findById(Integer id) {
- //父亲给我的方法,不用自己写
- return userMapper.selectByPrimaryKey(id);
- }
- }
model层
- @Table(name="user") //指定哪张表
- @Data
- public class User implements Serializable {
- @Id //指定主键
- private Integer id;
- private String name;
- private String password;
- }
我们在这里会发现,自己明明没有定义mapper层的具体方法,为什么有个selectByPrimaryKey?
如果点击进入Mapper<User>里,就会发现里面定义了基础的增删改查方法,我们只需要直接用就行
UserController
- @RestController
- public class UserController {
- @Autowired
- UserService userService;
- @RequestMapping("findById/{id}")
- public User findById(Integer id){
- User user = userService.findById(id);
- System.out.println(user);
- return user;
- }
- }
注意
若出现id为0的问题
可能是model层的id类型为int,将int修改为integer类型
model 类里面 id 必须用integer 类型,int 类型会出错。
Integer 改用 包装类的时候必须要用包装类解决:自增主键类型int型改为Integer
引入jdbc或者web的启动器,就已经引入事务相关的依赖及默认配置了,所以不需要再单独引入事务启动器
事务的注解@Transactional
在某个方法上添加@Transactional表示该方法添加事务
在类上添加@Transactional表示该类添加全局事务
- @Service
- // @Transactional全局事务
- public class UserServiceImpl implements UserService {
- @Autowired
- UserMapper userMapper;
- @Override
- // Transactional() 某个方法添加事务
- public User findById(Integer id) {
- //父亲给我的方法,不用自己写
- return userMapper.selectByPrimaryKey(id);
- }
- }
Spring Boot Test分为如下三类:
单元测试:一般面向方法,编写一般业务代码时。涉及到的注解有@Test。
切片测试:一般面向难于测试的边界功能,介于单元测试和功能测试之间。涉及到的注解有@RunWith @WebMvcTest等。
功能测试:一般面向某个完整的业务功能,同时也可以使用切面测试中的mock能力,推荐使用。涉及到的注解有@RunWith @SpringBootTest等。
-
- public class JavaTest {
- @Test
- public void test() {
- }
- }
- @RunWith(SpringRunner.class)
- @SpringBootTest
- public class springboottest {
- @Autowired
- myTest mytest;
-
- @Test
- public void test1() {
- mytest.test();
- }
- }
Springboot的@RunWith(SpringRunner.class)
注解的意义在于Test测试类要使用注入的类,比如@Autowired注入的类,
有了@RunWith(SpringRunner.class)这些类才能实例化到spring容器中,自动注入才能生效,
否则会抛出NullPointerExecption
前后端分离,为什么后端还要做静态页面相关工作?
想象一个场景,优惠券,除了金额数据不一样,其他的页面布局都一样,如果每种优惠券都手动书写静态页面太麻烦
所以前端可以制作一个静态页面模板,后端将金额数据填充到模板中,之后模板引擎渲染页面,最后动态生成不同金额的优惠券,效率极大的提高。
因此虽然前后端分离,但是后端还会做一些静态页面相关工作
SpringBoot并不推荐使用jsp,但是支持一些模板引擎技术
Thymeleaf 是一个和FreeMarker 类似的模板引擎,里面有标签,可以做页面渲染,生成页面;
Thymeleaf 是spring推荐的官方模板引擎
Thymeleaf 可以完全替代 JSP 。相较于其他的模板引擎,它有如下四个特点:
简单看一下Thymeleaf 配置类
- ConfigurationProperties(prefix = "spring.thymeleaf")
- public class ThymeleafProperties{
- private static final charset DEFAULT_ENCODING = standardCharsets.UTF_8;
- //视图解析器里 添加前缀和后缀
- //和jsp中视图解析器处理类似
- public static final string DEFAULT_PREFIX = "classpath: /templates/";
- public static final string DEFAULT_SUFFIX = ".html":;
添加启动器
- <dependency>
- <groupId>org.springframework.boot</groupId>
- <artifactId>spring-boot-starter-thymeleaf</artifactId>
- </dependency>
SpringBoot会自动为Thymeleaf注册一个视图解析器
与解析JSP的InternalViewResolver类似,Thymeleaf也会根据前缀和后缀来确定模板文件的位置
controller方法
- //@RestController//之前是因为页面不跳转,所以才添加的@RestController
- @Controller //用需要添加@ResponseBody
- public class UserController {
- @Autowired
- UserService userService;
-
- @ResponseBody //添加注释,不会页面跳转,而是静态显示
- @RequestMapping("findById/{id}")
- public String findById(Integer id, Model model){
- User user = userService.findById(id);
- return user;
- }
-
- @RequestMapping("findAll")
- public String findALL(Model model){
- List<User> user = userService.findAll();
- model.addAttribute("user",user);
- return "user"; //由于thymeleaf有视图解析 会访问/templates/user.html
- }
- }
静态页面
模板默认放在classpath下的templates文件夹,我们新建一个html文件放入其中
- <!DOCTYPE html>
- <!--thymeleaf名称空间必须引入-->
- <html xmlns:th="http://www.thymeleaf.org">
- <head>
- <meta charset="UTF-8">
- <title>首页</title>
- <style type="text/css">
- table {border-collapse: collapse; font-size: 14px; width: 80%; margin: auto}
- table, th, td {border: 1px solid darkslategray;padding: 10px}
- </style>
- </head>
- <body>
- <div style="text-align: center">
- <hr/>
- <table class="list">
- <tr>
- <th>id</th>
- <th>姓名</th>
- <th>性别</th>
- <th>年龄</th>
- <th>地址</th>
- <th>qq</th>
- <th>email</th>
- </tr>
- <tr th:each="user : ${user}">
- <td th:text="${user.id}">test</td>
- <td th:text="${user.name}">test</td>
- <td th:text="${user.gender}">test</td>
- <td th:text="${user.age}">test</td>
- <td th:text="${user.address}">test</td>
- <td th:text="${user.qq}">test</td>
- <td th:text="${user.email}">test</td>
- </tr>
- </table>
- </div>
- </body>
- </html>
语法:
${}
:这个类似与el表达式,但其实是ognl的语法,比el表达式更加强大
th-
指令:th-
是利用了Html5中的自定义属性来实现的。如果不支持H5,可以用data-th-
来代替
th:each
:类似于c:foreach
遍历集合,但是语法更加简洁
th:text
:声明标签中的文本
例如
<td th-text='${user.id}'>test</td>
,如果user.id有值,会覆盖默认的test如果没有值,则会显示td中默认的test。这正是thymeleaf能够动静结合的原
因,模板解析失败不影响页面的显示效果,因为会显示默认值!
运行结果
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。