乐趣区

走进JavaWeb技术世界16极简配置的SpringBoot

一位阿里 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 的优缺点

优点

  1. 快速构建项目
  2. 对主流开发框架的无配置集成
  3. 项目可独立运行,无须外部依赖 Servlet 容器(Spring Boot 默认自带了一个 Tomcat)
  4. 提供运行时的应用监控
  5. 极大地提高了开发、部署效率
  6. 与云计算的天然集成

缺点

  1. 坑有些多, 文档略少

二、快速入门

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 的高效和简洁了呢?配置就是如此简单,功能就是如此强大,但通过上面一系列的讲解,你是不是也产生一些疑惑呢,比如:

  1. Spring Boot 的 WEB 应用默认端口就是 8080,那这个端口要怎么修改呢?
  2. 为什么会出现 ”Cannot determine embedded database driver class for database type NONE” 这样的错误?(或者说为什么 springboot 启动时会自动注入数据源和配置 jpa)
  3. 为什么 @SpringBootApplication(exclude={DataSourceAutoConfiguration.class,HibernateJpaAutoConfiguration.class})就可以解决 ”Cannot determine embedded database driver class for database type NONE” 这样的错误呢?
  4. 既然 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」等关键字可以获取对应的免费学习资料。

                     

退出移动版