一位阿里 Java 工程师的技术小站。作者黄小斜,专注 Java 相关技术:SSM、SpringBoot、MySQL、分布式、中间件、集群、Linux、网络、多线程,偶尔讲点 Docker、ELK,同时也分享技术干货和学习经验,致力于 Java 全栈开发!(关注公众号后回复”Java“即可领取 Java 基础、进阶、项目和架构师等免费学习资料,更有数据库、分布式、微服务等热门技术学习视频,内容丰富,兼顾原理和实践,另外也将赠送作者原创的 Java 学习指南、Java 程序员面试指南等干货资源)
SpringBoot 详解(一)- 快速入门
SpringBoot 详解系列文章:
SpringBoot 详解(一)- 快速入门
SpringBoot 详解(二)-Spring Boot 的核心
SpringBoot 详解(三)-Spring Boot 的 web 开发
SpringBoot 详解(四)- 优雅地处理日志
一、Spring Boot
久闻 Spring Boot 大名,这两天终于得空,学习了一把,发觉 Spring Boot 确实好用,那 Spring Boot 到底是什么,又是怎么好用呢?
什么是 Spring Boot
目前 ssm 框架还是比较常用的,其中的 ss 指的无非就是 Spring 和 SpringMVC,我们可以简单的认为 “Spring Boot ≥ Spring + SpringMVC”,没错,用了 Spring Boot 中涵盖了 Spring 和 SpringMVC 等大量常用开发配置,而且 Spring Boot 的配置极其简单,可以让你不用或者只需要很少的 Spring 配置就可以让你的项目快速运行起来。
Spring Boot 的优缺点
优点
- 快速构建项目
- 对主流开发框架的无配置集成
- 项目可独立运行,无须外部依赖 Servlet 容器(Spring Boot 默认自带了一个 Tomcat)
- 提供运行时的应用监控
- 极大地提高了开发、部署效率
- 与云计算的天然集成
缺点
- 坑有些多, 文档略少
二、快速入门
1、Spring 的 Java 配置方式
上面已经提到了,使用 Spring Boot,可以让你不用或者只需要很少的 Spring 配置就可以让你的项目快速运行起来,说的就是使用代码注解来取代 xml 配置。其实从 Spring3.x 开始就已经提供了 java 配置方式,使用 java 配置方式可以更好的理解你配置的 Bean,而如今的 Spring4.x 更是推荐 java 配置方式,java 配置方式可以完全替代 xml 配置,下面就先来看看两个最基本的注释:
1)@Configuration 和 @Bean
Spring 的 java 配置方式是通过 @Configuration 和 @Bean 这两个注释实现的:
- @Configuration 作用于类上,相当于一个 xml 配置文件
- @Bean 作用于方法上,相当于 xml 配置中的
2)小示例
该示例将通过 java 配置方式配置 Spring,实现 Spring IOC 功能。
这是一个简单的模拟从数据库获取 User 数据的 Dao 类(注意,它并没有使用任何注解,也就是说 UserDao 目前并没有交给 Spring 容器管理)。
<pre>public class UserDao {
public List<String> queryUserList() {
List<String> list = new ArrayList<>(); for (int i = 0; i < 10; i++) {
list.add(“User ” + i);
} return list;
}
}
</pre>
这是一个最最常见的 Service,通过注入 UserDao,使用 UserDao 的方法获取用户数据。
<pre>@Service
public class UserService {
@Autowired
UserDao userDao;
public void getUserList() {
List<String> list = userDao.queryUserList(); for (int i = 0; i < list.size(); i++) {
System.out.println(list.get(i));
}
}
}
</pre>
从这里开始就跟以往的 Spring 开发不一样了,这个类使用了 2 个新的注解,其中 @Configuration 表明该相当于 Spring 的一个 xml 配置文件,@Bean 将一开始的 UserDao 配置给 Spring 管理.
<pre>@Configuration// 通过注解来表明该类是一个 Spring 的配置,相当于一个 xml 文件
public class SpringConfig {
@Bean// 这里要注意, 方法名 ”getUserDao” 将作为 UserDao 在容器中的 id
public UserDao getUserDao() { return new UserDao();
}
}
</pre>
接下来就是获取 Spring 容器, 从容器中拿到 UserService, 并调用其获取用户数据的方法, 代码如下:
<pre>public class Test {
public static void main(String[] args) {
AnnotationConfigApplicationContext acac = new AnnotationConfigApplicationContext(SpringConfig.class);
UserService userService = (UserService) acac.getBean(“userService”);
userService.getUserList();
}
}
</pre>
像普通的 java 程序一样,直接运行 Test 类中的 main 方法即可在控制台看到用户数据输出了。
细心的你应该发现了, 以往获取 Spring 容器使用到的类要么是 ClassPathXmlApplicationContext 或是 FileSystemXmlApplicationContext, 但 Spring Boot 使用的却是 AnnotationConfigApplicationContext, 原因也好理解, 因为我们 Spring Boot 使用的是 java 配置的方式, 而以往使用的是 Spring 的 xml 配置方式.
2、第一个 Web 应用
通过上面的示例, 我们已经知道了 java 配置方式是怎么回事了, 那接下来便正式开始使用 Spring Boot 来开发我们的第一个 web 应用了.
1)pom.xml 配置
设置 spring boot 的 parent
<pre><parent>
<groupId>org.springframework.boot</groupId>
spring-boot-starter-parent
<version>1.5.2.RELEASE</version>
</parent>
</pre>
说明:Spring boot 的项目必须要将 parent 设置为 spring boot 的 parent,该 parent 包含了大量默认的配置,大大简化了我们的开发。
导入 spring boot 的 web 支持
<pre><dependency>
<groupId>org.springframework.boot</groupId>
spring-boot-starter-web
</dependency>
</pre>
添加 Spring boot 的插件
<pre><plugin>
<groupId>org.springframework.boot</groupId>
spring-boot-maven-plugin
</plugin>
</pre>
通过上面简单的 3 步配置,Spring Boot 就配置完毕了, 相比以往的 Spring、SpringMVC 配置是不是要简洁的多呢?
2)小示例
<pre>@SpringBootApplication// Spring Boot 项目的核心注解,主要目的是开启自动配置
@Controller// 标明这是一个 SpringMVC 的 Controller 控制器
public class HelloApplication {
@RequestMapping(“/hello”)
@ResponseBody
public String hello() { return “hello world”;
}
// 在 main 方法中启动一个应用,即:这个应用的入口
public static void main(String[] args) {
SpringApplication.run(HelloApplication.class, args);
}
}
</pre>
一般 Spring Boot 的 Web 应用都有一个 xxxApplication 类,并使用 @SpringBootApplication 注解标记,作为该 web 应用的加载入口。此外,还需要在 main 方法中 (可以是任意一个类) 使用 SpringApplication.run(xxxApplication.class, args)来启动该 web 应用。
运行 HelloApplication 中的 main()方法,启动该 web 应用后,在地址栏输入 ”http://localhost:8080/hello”,就可以看到输出结果了。
3)运行报错
如果你项目中没有其他配置,那在运行这个简单的项目时一般是不会报错的,但如果很不幸你第一次运行就报错的话,也不用着急,大部分问题百度即可,本人在启动项目过程中遇到就 ”Cannot determine embedded database driver class for database type NONE” 这样的错误,这样就记录一下,报错截图如下:
原因是:springboot 启动时会自动注入数据源和配置 jpa。
解决方法:在 @SpringBootApplication 中排除其注入
@SpringBootApplication(exclude={DataSourceAutoConfiguration.class,HibernateJpaAutoConfiguration.class})
所以,上面的代码修改如下即可:
<pre>@SpringBootApplication(exclude={DataSourceAutoConfiguration.class,HibernateJpaAutoConfiguration.class})
@Controller
public class HelloApplication {
…
}
</pre>
三、疑问
到这里是不是已经大概感觉到了 Spring Boot 的高效和简洁了呢?配置就是如此简单,功能就是如此强大,但通过上面一系列的讲解,你是不是也产生一些疑惑呢,比如:
- Spring Boot 的 WEB 应用默认端口就是 8080,那这个端口要怎么修改呢?
- 为什么会出现 ”Cannot determine embedded database driver class for database type NONE” 这样的错误?(或者说为什么 springboot 启动时会自动注入数据源和配置 jpa)
- 为什么 @SpringBootApplication(exclude={DataSourceAutoConfiguration.class,HibernateJpaAutoConfiguration.class})就可以解决 ”Cannot determine embedded database driver class for database type NONE” 这样的错误呢?
- 既然 Spring Boot 的 WEB 应用默认使用的是自带的 Tomcat,那要怎么部署到外部的 Servlet 容器呢?
- …
不急,后续文章将会对这些问题一一解释清楚。
SpringBoot 详解(二)-Spring Boot 的核心
SpringBoot 详解系列文章:
SpringBoot 详解(一)- 快速入门
SpringBoot 详解(二)-Spring Boot 的核心
SpringBoot 详解(三)-Spring Boot 的 web 开发
SpringBoot 详解(四)- 优雅地处理日志
Spring Boot 的核心
在上篇中我们成功运行了一个简单的 web 应用,其中有一个注解被轻易的带过了,但它在 Spring Boot 中是最重要的注解,没有之一,它就是 @SpringBootApplication,本篇将对它与 Spring Boot 的配置进行深入的介绍。
1、@SpringBootApplication
前面已经说过了,一般 Spring Boot 的 Web 应用都有一个 xxxApplication 类,并使用 @SpringBootApplication 注解标记,作为该 web 应用的加载入口。那这个 @SpringBootApplication 注解到底是何方神圣?通过查看它的源码,可以发现它是一个组合注解:
@SpringBootApplication 这个 Spring Boot 核心注解是由其它三个重要的注解组合,分别是:@SpringBootConfiguration、@EnableAutoConfiguration 和 @ComponentScan。
1)@SpringBootConfiguration
@SpringBootConfiguration 是 Spring Boot 项目的配置注解,这也是一个组合注解。
通过上图代码,结合前面所讲的知识,不难猜测出 @SpringBootConfiguration 与 @Configuration 存在着某种关系,可以认为 @SpringBootConfiguration 就相当于 @Configuration,在 Spring Boot 项目中推荐使用 @SpringBootConfiguration 替代 @Configuration,不过因为注释长度问题,往往 @Configuration 较为常用。
2)@EnableAutoConfiguration
@EnableAutoConfiguration 注解用于启用自动配置,该注解会使 Spring Boot 根据项目中依赖的 jar 包自动配置项目的配置项。
例如:上篇中,我们在编写第一个 WEB 应用时,就在 pom.xml 中引入了 spring-boot-starter-web 的依赖,所以项目中就会引入 SpringMVC 的依赖,就会自动配置 tomcat 和 SpringMVC。
还有后面使用事务时,会引入 spring-boot-starter-jdbc 的依赖,让 Spring Boot 自动配置 DataSourceTransactionManager 或 JpaTransactionManager,等等。。
3)@ComponentScan
@ComponentScan 是组件扫描注解,不配置默认扫描 @SpringBootApplication 所在类的同级目录以及它的子目录(这很重要, 后面很应用到这个特性)。当然你也可以自己指定要扫描的包目录,例如:
<pre>@ComponentScan(basePackages = “com.lqr.demo1”)
</pre>
2、取消部分自动配置
上面说了,Spring Boot 根据项目中依赖的 jar 包自动配置项目的配置项, 而 Spring Boot 支持的自动配置非常之多, 如下图所示(只是其中的一部分):
当自动配置的东西一多了,就容易出问题,上篇中最后出现的 ”Cannot determine embedded database driver class for database type NONE” 错误,就是因为 springboot 启动时会自动注入数据源和配置 jpa,所以我们就需要取消 Spring Boot 的部分自动配置。至于取消自动配置的方式也相当简单,就是对 @SpringBootApplication 注解的 exclude 进行赋值即可,如:
<pre>@SpringBootApplication(exclude={DataSourceAutoConfiguration.class,HibernateJpaAutoConfiguration.class})
@Controller
public class HelloApplication {
…
}
</pre>
其他的取消自动配置以此类推。
3、自定义 Banner
这个知识点其实对开发意义不太,但不妨了解下(可以装个逼~~)。在 Spring Boot 项目启动时,控制台会输出一个 ”spring>>>” 的 banner 文字图案,如:
这个 banner 是可以自定义的,自定义的方法很简单:只需要把想输出的文字保存在 banner.txt 文件中,然后把这个 banner.txt 放到 resources 目录下即可:
运行项目,然后控制台就可以输出 banner.txt 中的文字了。
Text to ASCII Art Generator (TAAG)这个网站可以得到文字图案。
4、Starter pom
Spring Boot 为我们提供了简化企业级开发绝大多数场景的 start pom(类似于组件),只要使用了对应的 starter pom,Spring Boot 就会为我们提供自动配置的 Bean。
这里官方给出的 starter,以下是 ” 好心人 ” 对这些 Starter pom 做的翻译:
怎么使用?直接在 pom.xml 中引入依赖即可(不懂请参考上篇中“第一个 Web 应用”中 pom.xml 配置的第二部分,或请自行百度)。
5、使用 Xml 配置文件
常规开发中,java 配置方式已经可以完全取代 xml 配置方式了,但有时我们并不想使用 java 配置,而是继续沿用之前的 xml 配置方式,或者出于其他原因,一定要在 xml 中进行配置,那该怎么办呢,很简单,使用 @ImportResource 注解即可:
<pre>@ImportResource(value = {“classpath:xxx1.xml”,”classpath:xxx2.xml”})
</pre>
6、全局配置文件
Spring Boot 项目使用一个全局的配置文件 application.properties 或者是 application.yml,在 resources 目录下或者类路径下的 /config 下,一般我们放到 resources 下。
我们知道 Spring Boot 会根据在 pom.xml 中依赖的 jar 包进行自动配置,当我们要对这些 jar 包对应的框架进行配置又该怎么办呢,没错,可以在全局配置文件(application.properties 或者是 application.yml)中进行配置,如 tomcat 的端口配置等。
1)全局配置文件的基本使用(application.properties)
这部分使用 application.properties 中的书写方式来介绍。
①tomcat 端口配置
<pre>server.port=8888
</pre>
②修改 Spring MVC 拦截路径规则
默认 Spring MVC 拦截路径规则是 /,如果要修改成 *.html 的话,可以在全局配置文件中进行如下设置:
<pre>server.servlet-path=*.html
</pre>
③视图解析器配置
一样的,Spring Boot 也可以通过全局配置文件对视图解析器进行配置:
<pre>spring.mvc.view.prefix=/WEB-INF/views/
spring.mvc.view.suffix=.jsp
</pre>
④日志输出
Spring Boot 对各种日志框架都做了支持,我们可以通过配置来修改默认的日志的配置:
<pre># 设置日志级别 logging.level.org.springframework=DEBUG
</pre>
2)全局配置文件的进阶使用(application.yml)
这部分使用 application.yml 中的书写方式来介绍。
properties 与 yml 文件在形式上有所差别,yml 文件的书写方式比较简洁,类似 eclipse 中 package 的 flag 呈现方式(而 properties 文件则像 Hierarchical 方式)。如上面 properties 文件中的属性配置使用 yml 文件来写:
<pre>server:
port: 8080
context-path: /
spring:
mvc:
view:
prefix: /WEB-INF/views/
suffix: .jsp
logging:
level: debug
</pre>
yml 文件在书写时,需要注意一个地方:冒号与值中间是存在空格的!
①自定义属性
全局配置文件并不只是配置 Spring Boot 中已经存在的属性,我们也可以自定义属性(别忘了,它本身就是一个 properties 文件),代码需要使用 @Value(“${xxx}”)注解来获取这些属性,如:
②属性引用属性
属性引用属性也简单,使用 ${xxx}就可以引用配置文件中的属性了。
<pre>lqr: 666
content: “${lqr} is six six six”
</pre>
③属性转对象
这个就比较有看点了,以上面的 ”server.port: 8080″ 为例,我们可以认为是 Server 这个类中有一个 port 属性,其值为 8080。可以使用 @ConfigurationProperties(prefix = “ 属性名前缀 ”)这个注解作为配置文件中属性转对象属性的桥梁,具体如图所示:
Spring Boot 的全局配置很强大,同时它可以配置的属性也很多,以上只列出几个常用的属性配置,如需查看完整的全局属性配置,请到 spring-boot 官方配置文档查看。好了,本篇到此结束,主要介绍了 Spring Boot 中几个核心注解与自动配置,同时解决上篇中的几个问题,从下篇开始,将针对 Spring Boot 的 web 开发进行介绍。
SpringBoot 详解(三)-Spring Boot 的 web 开发
SpringBoot 详解系列文章:
SpringBoot 详解(一)快速入门
SpringBoot 详解(二)-Spring Boot 的核心
SpringBoot 详解(三)-Spring Boot 的 web 开发
一、web 基础配置
1、访问静态资源
1)进入规则为 / 时
如果进入 SpringMVC 的规则为 / 时,Spring Boot 的默认静态资源的路径为:
<pre>spring.resources.static-locations=classpath:/META-INF/resources/,classpath:/resources/,classpath:/static/,classpath:/public/
</pre>
也就是说,在默认的 Spring MVC 进入规则下,classpath 下的 META-INF/resources 目录、resources 目录、static 目录和 public 目录中的静态资料是可以直接通过 “http: // xxx.com/ 静态资源 ” 的方式访问到的。如:
2)进入规则为 *.xxx 或者 不指定静态文件路径时
如果进入 SpringMVC 的规则为.xxx 时(如:.html),则上述目录下的静态资源将无法直接访问,需要将静态资源放置到 webapp 下的 static 目录中即可通过 “http://xxx.com/static/ 静态资源 ” 访问。此外,默认不配置 SpringMVC 的规则下也可以如此访问,也就是说这种访问静态资源的方式是通用的。如图所示:
2、自定义拦截器
增加一个拦截器,需要通过继承 WebMvcConfigurerAdapter 然后重写父类中的方法进行扩展。
<pre>@Configuration
public class MySpringMvcConfig extends WebMvcConfigurerAdapter {
@Override
public void addInterceptors(InterceptorRegistry registry) {
HandlerInterceptor handlerInterceptor = new HandlerInterceptor() {
@Override
public boolean preHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o) throws Exception {
System.out.println(“ 自定义拦截器。。。”);
return true;
}
@Override
public void postHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, ModelAndView modelAndView) throws Exception {
}
@Override
public void afterCompletion(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) throws Exception {
}
};
// 添加拦截器并设置拦截规则
registry.addInterceptor(handlerInterceptor).addPathPatterns(“/**”);
}
}
</pre>
3、自定义消息转化器
自定义消息转化器有两种实现方式,一种是 @Bean 方式,另一种是自定义拦截器。
1)@Bean 方式
只需要在 @Configuration 的类中添加消息转化器的 @bean 加入到 Spring 容器,就会被 Spring Boot 自动加入到容器中。
<pre>// spring boot 默认就有消息转化器,其编码格式为 utf-8
@Bean
public StringHttpMessageConverter stringHttpMessageConverter() {
StringHttpMessageConverter stringHttpMessageConverter = new StringHttpMessageConverter(Charset.forName(“UTF-8”));
return stringHttpMessageConverter;
}
</pre>
2)自定义拦截器方式
WebMvcConfigurerAdapter 的功能很强大,除了可以配置拦截器外,还可以配置消息转换器。
<pre>@Configuration
public class MySpringMvcConfig extends WebMvcConfigurerAdapter {
@Override
public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
StringHttpMessageConverter stringHttpMessageConverter = new StringHttpMessageConverter(Charset.forName(“UTF-8”));
converters.add(stringHttpMessageConverter);
}
}
</pre>
4、读取外部的配置文件
<pre>@Configuration
@PropertySource(value = { “classpath:jdbc.properties”, “classpath:base.properties”}, ignoreResourceNotFound = true)
public class 任意类 {
}
</pre>
5、Druid DataSource 的配置
Druid 提供了一个高效、功能强大、可扩展性好的数据库连接池,常用于替换 DBCP 和 C3P0。但在 Spring Boot 上配置比较“恶心”,这里就简单的贴出个人参照网上的配置代码,不必深究。
1)引入依赖
<pre><dependency>
<groupId>com.alibaba</groupId>
druid
<version>1.0.11</version>
</dependency>
</pre>
2)jdbc.properties
项目中一般会创建一个 jdbc.properties 文件来记录数据库的连接信息。
<pre>#MySQL
jdbc.url=jdbc:mysql://127.0.0.1:3306/dbxxx?useUnicode=true&characterEncoding=utf-8
jdbc.username=root
jdbc.password=123456
Druid
jdbc.initialSize=0
jdbc.minIdle=0
jdbc.maxActive=150
</pre>
3)配置 Druid 数据源
建议将配置 Druid 数据源的操作放在 @SpringBootApplication 注解的类中。
<pre>@SpringBootApplication
@Configuration
@PropertySource(value = {“classpath:jdbc.properties”})
public class MyWebApplication{
@Value(“${jdbc.url}”)
public String jdbcUrl;
@Value(“${jdbc.username}”)
public String jdbcUsername;
@Value(“${jdbc.password}”)
public String jdbcPassword;
@Value(“${jdbc.initialSize}”)
public int jdbcInitialSize;
@Value(“${jdbc.minIdle}”)
public int jdbcMinIdle;
@Value(“${jdbc.maxActive}”)
public int jdbcMaxActive;
@Bean
public ServletRegistrationBean druidServletRegistrationBean() {
ServletRegistrationBean servletRegistrationBean = new ServletRegistrationBean();
servletRegistrationBean.setServlet(new StatViewServlet());
servletRegistrationBean.addUrlMappings(“/druid/*”);
return servletRegistrationBean;
}
@Bean
public FilterRegistrationBean duridFilterRegistrationBean() {
FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean();
filterRegistrationBean.setFilter(new WebStatFilter());
HashMap<String, String> initParams = new HashMap<>();
// 设置忽略请求
initParams.put(“exclusions”, “.js,.gif,.jpg,.bmp,.png,.css,.ico,/druid/“);
filterRegistrationBean.setInitParameters(initParams);
filterRegistrationBean.addUrlPatterns(“/*”);
return filterRegistrationBean;
}
@Bean(initMethod = “init”, destroyMethod = “close”)
public DruidDataSource druidDataSource() {
DruidDataSource druidDataSource = new DruidDataSource();
druidDataSource.setUrl(jdbcUrl);
druidDataSource.setUsername(jdbcUsername);
druidDataSource.setPassword(jdbcPassword);
druidDataSource.setInitialSize(jdbcInitialSize);
druidDataSource.setMinIdle(jdbcMinIdle);
druidDataSource.setMaxActive(jdbcMaxActive);
return druidDataSource;
}
}
</pre>
之后就可以通过 @AutoWried 注解得到数据源 (druidDataSource) 了。
6、数据库框架集成
1)jpa 集成
Jpa 在使用上跟 Hibernate 很像,因为它们之前的关系非同一般,有兴趣可以看看《Hibernate 与 Jpa 的关系,终于弄懂》这篇文章。Spring Boot 对 jpa 的支持也是很好的,配置起来非常简单。
在 pom.xml 中引用 jpa 及数据库驱动(如:mysql)依赖
<pre><dependency>
<groupId>org.springframework.boot</groupId>
spring-boot-starter-data-jpa
</dependency>
<dependency>
<groupId>mysql</groupId>
mysql-connector-java
</dependency>
</pre>
在 application.yml 文件中配置
<pre>spring:
datasource:
driver-class-name: com.mysql.jdbc.Driver
url: jdbc:mysql://127.0.0.1/dbgirl
username: root
password: 123456
jpa:
hibernate:
ddl-auto: update #第一次加载 hibernate 时根据 model 类会自动建立起表的结构(前提是先建立好数据库),以后加载 hibernate 时根据 model 类自动更新表结构,即使表结构改变了但表中的行仍然存在不会删除以前的行。要注意的是当部署到服务器后,表结构是不会被马上建立起来的,是要等 应用第一次运行起来后才会。
show-sql: true
</pre>
2)MyBatis 集成
Mybatis 和 Spring Boot 的整合有两种方式:
第一种:使用 mybatis 官方提供的 Spring Boot 整合包实现,地址:spring-boot-starter
第二种:使用 mybatis-spring 整合的方式,也就是我们传统的方式
这里推荐并使用第二种方式,因为可以很方便的控制 Mybatis 的各种配置。这里假设你已经配置过数据源了(数据源可以是 druid、dbcp、c3p0…)。
首先,需要在 pom.xml 文件中引用 mybatis 依赖
<pre><dependency>
<groupId>org.mybatis</groupId>
mybatis
<version>3.3.0</version>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
mybatis-spring
<version>1.2.2</version>
</dependency>
</pre>
然后,创建一个 Mybatis 的配置类:
<pre>@Configuration
public class MybatisConfig {
@Autowired
DruidDataSource druidDataSource;
@Bean
@ConditionalOnMissingBean// 当 Spring 容器中没有 SqlSessionFactoryBean 时才创建
public SqlSessionFactoryBean sqlSessionFactoryBean() {
SqlSessionFactoryBean sqlSessionFactory = new SqlSessionFactoryBean();
// 设置数据源
sqlSessionFactory.setDataSource(druidDataSource);
// 设置别名扫描包
sqlSessionFactory.setTypeAliasesPackage(“com.lqr.demo3.bean”);
// 设置 Mybatis 的配置文件位置
PathMatchingResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
Resource mybatisConfigXml = resolver.getResource(“classpath:mybatis-config.xml”);
sqlSessionFactory.setConfigLocation(mybatisConfigXml);
return sqlSessionFactory;
}
}
</pre>
最后,创建 Mapper 接口的扫描类 MapperScannerConfig:
<pre>@Configuration
@AutoConfigureAfter(MybatisConfig.class)// Mybatis 的扫描配置必须在 SqlSessionFactory 被创建之后
public class MapperScanConfig {
@Bean
public MapperScannerConfigurer mapperScannerConfigurer() {
MapperScannerConfigurer mapperScannerConfigurer = new MapperScannerConfigurer();
mapperScannerConfigurer.setBasePackage(“com.lqr.demo3.mapper”);
return mapperScannerConfigurer;
}
}
</pre>
7、设置事务管理
Spring Boot 中推荐使用 @Transactional 注解来申明事务。
<pre><dependency>
<groupId>org.springframework.boot</groupId>
spring-boot-starter-jdbc
</dependency>
</pre>
当引入 jdbc 依赖之后,Spring Boot 会自动默认分别注入 DataSourceTransactionManager 或 JpaTransactionManager,所以我们不需要任何额外配置就可以用 @Transactional 注解进行事务的使用。
<pre>@Service
@Transactional
public class GirlService {
@Transactional
public void insertGirl() {
Girl girlA = new Girl();
girlA.setCupSize(“A”);
girlA.setAge(18);
girlRespository.save(girlA);
}
}
</pre>
@Transactional 不仅可以注解在方法,也可以注解在类上。当注解在类上时,意味着此类所有 public 方法都会开启事务。如果类级别和方法级别同时使用了 @Transactional 注解,则使用在类级别的注解会重载方法级别的注解。
8、开启 jsp 支持
Spring boot 默认内嵌的 tomcat 是不支持 jsp 页面的,如果项目中使用到了 jsp,需要导入如下依赖才能正常访问。
<pre><dependency>
<groupId>org.apache.tomcat.embed</groupId>
tomcat-embed-jasper
<scope>provided</scope>
</dependency>
</pre>
二、Web 编码进阶
这部分可能跟 Spring Boot 的关系并不是很大(或者说,并非 Spring Boot 特有),但很值得我们在编码方面作为参考。
1、Spring MVC 中新的注解
1)@RestController
现在的 Web 项目已经越来越趋向于将后端与前端分别开发了,如果贵公司的项目就是使用 json 来进行前后端交互,且使用 Spring MVC 来开发的话,就一定会用到下面这 2 个注解:
<pre>@Controller
@ResponseBody
public class GirlController {
...
}
</pre>
而在 Spring MVC4 之后,我们可以使用 @RestController 注解来开发基于 Spring MVC4 的 REST 风格的 JSON 服务。
通俗的说就是 @RestController = @Controller + @ResponseBody。
@Controller 和 @RestController 的区别:
如果只是使用 @RestController 注解 Controller,则 Controller 中的方法无法返回 jsp 页面,配置的视图解析器 InternalResourceViewResolver 不起作用,返回的内容就是 Return 里的内容。例如:本来应该到 success.jsp 页面的,则其显示 success.
2)http 组合注解
Spring4.3 中引进了{@GetMapping、@PostMapping、@PutMapping、@DeleteMapping、@PatchMapping},来帮助简化常用的 HTTP 方法的映射,并更好地表达被注解方法的语义。
<pre>@GetMapping =>
@RequestMapping(value = "/xxx",method = RequestMethod.GET)
@PostMapping =>
@RequestMapping(value = "/xxx",method = RequestMethod.POST)
@PutMapping =>
@RequestMapping(value = "/xxx",method = RequestMethod.PUT)
@DeleteMapping =>
@RequestMapping(value = "/xxx",method = RequestMethod.DELETE)
…
</pre>
2、数据校验
Web 开发中,对从前端传过来的数据做数据校验已经是家常便饭的事了,但如果校验的数据很多,那么,一方面在开发上就需要做很多 if 判断,另一方面则是代码上显得不再简洁。其实,使用 @Valid + BindingResult 就可以优雅地解决这样的问题。使用示例如下:
1)@Valid + BindingResult
首先,使用一个 Java Bean 来接收前端提交的数据。在这个 Java Bean 之前加上 @Valid,在这个 Java Bean 之后加上 BindingResult(BindingResult 参数必须紧跟在 @Valid 参数之后。)
<pre>/**
- 添加一个女生
*/
@PostMapping(value = “/girls”)
public Result<Girl> girlAdd(@Valid Girl girl, BindingResult bindingResult) {
if (bindingResult.hasErrors()) {
return ResultUtils.error(-1, bindingResult.getFieldError().getDefaultMessage());
}
return ResultUtils.success(girlRespository.save(girl));
}
</pre>
2)设置校验规则
然后,需要在 @Valid 注解的 Java Bean 中,使用各种 ” 规则注解 ” 对其中的属性进行校验规则的设定。示例如下:
<pre>public class Girl {
private Integer id;
@NotBlank(message = “ 这个字段必传 ”)
private String cupSize;
@Min(value = 18, message = “ 未成年少女禁止入内 ”)
private Integer age;
@NotNull(message = “ 金额必传 ”)
private Double money;
…
}
</pre>
示例中,” 规则注解 ” 的 message 值可以在 Controller 中通过 bindingResult.getFieldError().getDefaultMessage()获取。
这类用于数据校验的注解还有很多,有兴趣的可以好好研究一下:
注解 | 类型 | 说明 |
---|---|---|
@AssertFalse | Boolean,boolean | 验证注解的元素值是 false |
@AssertTrue | Boolean,boolean | 验证注解的元素值是 true |
@NotNull | 任意类型 | 验证注解的元素值不是 null |
@Null | 任意类型 | 验证注解的元素值是 null |
@Min(value= 值) | BigDecimal,BigInteger, byte,short, int, long,等任何 Number 或 CharSequence(存储的是数字)子类型 | 验证注解的元素值大于等于 @Min 指定的 value 值 |
@Max(value= 值) | 和 @Min 要求一样 | 验证注解的元素值小于等于 @Max 指定的 value 值 |
@DecimalMin(value= 值) | 和 @Min 要求一样 | 验证注解的元素值大于等于 @ DecimalMin 指定的 value 值 |
@DecimalMax(value= 值) | 和 @Min 要求一样 | 验证注解的元素值小于等于 @ DecimalMax 指定的 value 值 |
@Digits(integer= 整数位数, fraction= 小数位数) | 和 @Min 要求一样 | 验证注解的元素值的整数位数和小数位数上限 |
@Size(min= 下限, max= 上限) | 字符串、Collection、Map、数组等 | 验证注解的元素值的在 min 和 max(包含)指定区间之内,如字符长度、集合大小 |
@Past | java.util.Date,java.util.Calendar;Joda Time 类库的日期类型 | 验证注解的元素值(日期类型)比当前时间早 |
@Future | 与 @Past 要求一样 | 验证注解的元素值(日期类型)比当前时间晚 |
@NotBlank | CharSequence 子类型 | 验证注解的元素值不为空(不为 null、去除首位空格后长度为 0),不同于 @NotEmpty,@NotBlank 只应用于字符串且在比较时会去除字符串的首位空格 |
@Length(min= 下限, max= 上限) | CharSequence 子类型 | 验证注解的元素值长度在 min 和 max 区间内 |
@NotEmpty | CharSequence 子类型、Collection、Map、数组 | 验证注解的元素值不为 null 且不为空(字符串长度不为 0、集合大小不为 0) |
@Range(min= 最小值, max= 最大值) | BigDecimal,BigInteger,CharSequence, byte, short, int, long 等原子类型和包装类型 | 验证注解的元素值在最小值和最大值之间 |
@Email(regexp= 正则表达式,flag= 标志的模式) | CharSequence 子类型(如 String) | 验证注解的元素值是 Email,也可以通过 regexp 和 flag 指定自定义的 email 格式 |
@Pattern(regexp= 正则表达式,flag= 标志的模式) | String,任何 CharSequence 的子类型 | 验证注解的元素值与指定的正则表达式匹配 |
@Valid | 任何非原子类型 | 指定递归验证关联的对象;如用户对象中有个地址对象属性,如果想在验证用户对象时一起验证地址对象的话,在地址对象上加 @Valid 注解即可级联验证 |
3、面积切面编程(AOP 配置)
AOP 是 Spring 中一大核心,若在 SpringBoot 中要使用 AOP 只需两步:
1)引入 AOP 的 starter 依赖
<pre><dependency>
<groupId>org.springframework.boot</groupId>
spring-boot-starter-aop
</dependency>
</pre>
2)编写切面类
<pre>@Aspect
@Component
public class HttpAspect {
private final static Logger logger = LoggerFactory.getLogger(HttpAspect.class);
@Pointcut(“execution(public com.lqr.controller.GirlController.(..))”)
public void log() {
}
@Before(“log()”)
public void deBefore(JoinPoint joinPoint) {
ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
HttpServletRequest request = attributes.getRequest();
// url
logger.info(“url={}”, request.getRequestURL());
// method
logger.info(“method={}”, request.getMethod());
// ip
logger.info(“ip={}”, request.getRemoteAddr());
// 类方法
logger.info(“class_method={}”, joinPoint.getSignature().getDeclaringTypeName() + “.” + joinPoint.getSignature().getName());
// 参数
logger.info(“args={}”, joinPoint.getArgs());
}
@After(“log()”)
public void doAfter() {
logger.info(“doAfter…”);
}
@AfterReturning(returning = “object”, pointcut = “log()”)
public void doAfterReturning(Object object) {
if (object != null)
logger.info(“response={}”, object.toString());
}
}
</pre>
4、统一异常处理(配置通知 Advice)
1)自定义异常
这里之所以继承 RuntimeException,是为了方便事务回滚。而自定义异常的好处在于:一方面可以使代码语义化,另一方面使得我们编码更加方便。
<pre>public class GirlException extends RuntimeException {
private Integer code;
public GirlException(ResultEnum resultEnum) {
super(resultEnum.getMsg());
this.code = resultEnum.getCode();
}
public Integer getCode() {
return code;
}
public void setCode(Integer code) {
this.code = code;
}
}
</pre>
2)配置全局异常捕获器
使用全局异常捕获器,一方面可以捕获到整个项目中的 Exception 及其子类(包含 RuntimeException 等),另一方面可以对异常进行统一处理并返回统一的数据格式,为前端提供友好的数据交互。
<pre>@ControllerAdvice
public class ExceptionHandle {
private final Logger logger = LoggerFactory.getLogger(ExceptionHandle.class);
@ExceptionHandler(value = Exception.class)
@ResponseBody
public Result handle(Exception e) {
if (e instanceof GirlException) {
GirlException girlException = (GirlException) e;
return ResultUtils.error(girlException.getCode(), girlException.getMessage());
} else {
logger.error(“【系统异常】{}”, e);
return ResultUtils.error(-1, “ 未知错误 ”);
}
}
}
</pre>
三、开发与生产
1、热部署
Web 开发中,没有热部署怎么能行呢?所以,下面就介绍下 Spring Boot 的热部署配置。
1)在 pom.xml 中配置热部署需要的依赖与插件
<pre><dependencies>
…
<!–spring boot 热部署 –>
<dependency>
<groupId>org.springframework.boot</groupId>
spring-boot-devtools
<optional>true</optional>
</dependency>
</dependencies>
<build>
<plugins>
<!–spring boot 热部署 –>
<plugin>
<groupId>org.springframework.boot</groupId>
spring-boot-maven-plugin
<configuration>
<fork>true</fork>
</configuration>
</plugin>
</plugins>
...
</build>
</pre>
2)开启自动编译
打开 Idea 的 Settings 界面,找到 ”Build,Execution,Depolyment”,在 Compiler 中将 ”Build project automatically” 打钩。
3)修改 pom.xml 的维护(Maintenance)登记项
使用快捷键 “ctrl+shift+alt+/” 打开 pom.xml 的维护(Maintenance)菜单,找到登记(registry)项,单击打开。
4)允许应用程序运行时自动编译
在登记(registry)中找到 ”compiler.automake.allow.when.app.running” 这一项打钩,关闭。最后重启项目即可!!!
2、发布到独立的 tomcat 中运行
尽管 Spring Boot 项目会内置一个 tomcat,仅只需通过一个简单的指令便可启动项目,但在生产环境下,我们还是习惯将项目发布到第三外的 servlet 容器中,下面将介绍如果将一个 Spring Boot 项目团部署到第三方 tomcat 中运行。
1)修改工程的打包方式为 war
2)将 spring-boot-starter-tomcat 的范围设置为 provided
spring-boot-starter-tomcat 是 Spring Boot 默认就会配置的,即上面说到的内嵌 tomcat,将其设置为 provided 是在打包时会将该包 (依赖) 排除,因为要放到独立的 tomcat 中运行,Spring Boot 内嵌的 Tomcat 是不需要用到的。
<pre><!–spring boot tomcat(默认可以不用配置,但当需要把当前 web 应用布置到外部 servlet 容器时就需要配置,并将 scope 配置为 provided)–>
<dependency>
<groupId>org.springframework.boot</groupId>
spring-boot-starter-tomcat
<scope>provided</scope>
</dependency>
</pre>
3)修改代码,设置启动配置
需要继承 SpringBootServletInitializer,并重写 configure()方法,将 Spring Boot 的入口类设置进去。
<pre>// 若要部署到外部 servlet 容器, 需要继承 SpringBootServletInitializer 并重写 configure()
@SpringBootApplication
@Configuration
public class MyWebApplication extends SpringBootServletInitializer
{
@Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder builder) {
// 设置启动类, 用于独立 tomcat 运行的入口
return builder.sources(MyWebApplication.class);
}
}
</pre>
4)打 war 包并部署到 tomcat
微信公众号【黄小斜】大厂程序员,互联网行业新知,终身学习践行者。关注后回复「Java」、「Python」、「C++」、「大数据」、「机器学习」、「算法」、「AI」、「Android」、「前端」、「iOS」、「考研」、「BAT」、「校招」、「笔试」、「面试」、「面经」、「计算机基础」、「LeetCode」等关键字可以获取对应的免费学习资料。