1. Spring Boot + Spring MVC + Spring Core + MyBatis + Druid整合案例
1. 在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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.example</groupId>
<artifactId>springboot-demo01</artifactId>
<version>1.0.0-SNAPSHOT</version>
<name>springboot-demo01</name>
<!-- 继承spring boot的父工程 -->
<!-- spring boot父工程直接约束了常用依赖的版本 -->
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.9.RELEASE</version>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- 引入mybatis-spring-boot-starter依赖,用于mybatis与spring boot整合 -->
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>1.3.1</version>
</dependency>
<!-- 引入mysql驱动依赖 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<!-- 引入spring-boot-starter-data-jpa依赖 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<!-- 引入阿里的druid连接池依赖 -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.6</version>
</dependency>
</dependencies>
<!-- 引入一个spring boot插件,可以支持我们打包程序 -->
<!-- 打包时是需要将所有依赖的第三方jar包都打进来的,spring boot这个插件可以支持 -->
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
2. 在application.properties配置文件中配置druid连接池
# 驱动配置
spring.datasource.type=com.alibaba.druid.pool.DruidDataSource
spring.datasource.url=jdbc:mysql://127.0.0.1:3306/oa?useUnicode=true&characterEncoding=utf-8
spring.datasource.username=root
spring.datasource.password=root
spring.datasource.driverClassName=com.mysql.jdbc.Driver
# 连接池的配置信息
# 连接池初始大小
spring.datasource.initialSize=5
# 连接池最小空闲连接数量
spring.datasource.minIdle=5
# 连接池最大活跃连接数量
spring.datasource.maxActive=20
spring.datasource.maxWait=60000
spring.datasource.timeBetweenEvictionRunsMillis=60000
spring.datasource.minEvictableIdleTimeMillis=300000
spring.datasource.validationQuery=SELECT 1 FROM DUAL
spring.datasource.testWhileIdle=true
spring.datasource.testOnBorrow=false
spring.datasource.testOnReturn=false
spring.datasource.poolPreparedStatements=true
spring.datasource.maxPoolPreparedStatementPerConnectionSize=20
spring.datasource.filters=stat,wall,log4j
spring.datasource.connectionProperties=druid.stat.mergeSql=true;druid.stat.slowSqlMillis=5000
3. 编写Druid连接池配置管理类
package com.example.springboot.config;
// 使用@Configuration标注,表示这是一个配置管理类
@Configuration
public class DruidDBConfig {
// 因为spring boot是默认开启了资源过滤的
// 所以这里的配置,都会自动从application.properties配置文件中加载出来,设置到这个@Configuration类中
@Value("${spring.datasource.url}")
private String dbUrl;
@Value("${spring.datasource.username}")
private String username;
@Value("${spring.datasource.password}")
private String password;
@Value("${spring.datasource.driverClassName}")
private String driverClassName;
@Value("${spring.datasource.initialSize}")
private int initialSize;
@Value("${spring.datasource.minIdle}")
private int minIdle;
@Value("${spring.datasource.maxActive}")
private int maxActive;
@Value("${spring.datasource.maxWait}")
private int maxWait;
@Value("${spring.datasource.timeBetweenEvictionRunsMillis}")
private int timeBetweenEvictionRunsMillis;
@Value("${spring.datasource.minEvictableIdleTimeMillis}")
private int minEvictableIdleTimeMillis;
@Value("${spring.datasource.validationQuery}")
private String validationQuery;
@Value("${spring.datasource.testWhileIdle}")
private boolean testWhileIdle;
@Value("${spring.datasource.testOnBorrow}")
private boolean testOnBorrow;
@Value("${spring.datasource.testOnReturn}")
private boolean testOnReturn;
@Value("${spring.datasource.poolPreparedStatements}")
private boolean poolPreparedStatements;
@Value("${spring.datasource.maxPoolPreparedStatementPerConnectionSize}")
private int maxPoolPreparedStatementPerConnectionSize;
@Value("${spring.datasource.filters}")
private String filters;
@Value("{spring.datasource.connectionProperties}")
private String connectionProperties;
// 在这个配置类中,直接基于配置信息,创建出了一个bean
// 这个bean就是一个DataSource
// 这个DataSource bean就会被纳入spring容器的管理范围之内
@Bean
@Primary
public DataSource dataSource() {
// 这里就是用外部加载进来的配置信息,创建出来一个Druid连接池
DruidDataSource datasource = new DruidDataSource();
datasource.setUrl(this.dbUrl);
datasource.setUsername(username);
datasource.setPassword(password);
datasource.setDriverClassName(driverClassName);
//configuration
datasource.setInitialSize(initialSize);
datasource.setMinIdle(minIdle);
datasource.setMaxActive(maxActive);
datasource.setMaxWait(maxWait);
datasource.setTimeBetweenEvictionRunsMillis(timeBetweenEvictionRunsMillis);
datasource.setMinEvictableIdleTimeMillis(minEvictableIdleTimeMillis);
datasource.setValidationQuery(validationQuery);
datasource.setTestWhileIdle(testWhileIdle);
datasource.setTestOnBorrow(testOnBorrow);
datasource.setTestOnReturn(testOnReturn);
datasource.setPoolPreparedStatements(poolPreparedStatements);
datasource.setMaxPoolPreparedStatementPerConnectionSize(maxPoolPreparedStatementPerConnectionSize);
try {
datasource.setFilters(filters);
} catch (SQLException e) {
e.printStackTrace();
}
datasource.setConnectionProperties(connectionProperties);
return (DataSource) datasource;
}
}
编写这个类之后,还需要在Application类中导入这个配置管理类
@SpringBootApplication
// 使用@Import就可以将其他的配置管理类导入进来
@Import(DruidDBConfig.class)
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
4. 编写Domain类
package com.example.springboot.domain;
public class User {
private Long id;
private String name;
private Integer age;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
}
5. 编写Mapper类
package com.example.springboot.mapper;
@Mapper
public interface UserMapper {
@Select("SELECT * FROM user")
List<User> listUsers();
@Select("SELECT * FROM user WHERE user_id = #{userId}")
User getUserById(@Param("userId") Long userId);
@Insert("INSERT INTO user(name, age) VALUES(#{name}, #{age})")
void saveUser(User user);
@Update("UPDATE user SET name=#{name}, age=#{age} WHERE user_id=#{userId}")
void updateUser(User user);
@Delete("DELETE FROM user WHERE user_id=#{userId}")
void removeUser(@Param("userId") Long userId);
}
6. 编写Dao
package com.example.springboot.dao;
public interface UserDao {
List<User> listUsers();
User getUserById(Long userId);
void saveUser(User user);
void updateUser(User user);
void removeUser(Long userId);
}
package com.example.springboot.dao.impl;
@Repository
public class UserDaoImpl implements UserDao{
@Autowired
private UserMapper userMapper;
@Override
public List<User> listUsers() {
return userMapper.listUsers();
}
@Override
public User getUserById(Long userId) {
return userMapper.getUserById(userId);
}
@Override
public void saveUser(User user) {
userMapper.saveUser(user);
}
@Override
public void updateUser(User user) {
userMapper.updateUser(user);
}
@Override
public void removeUser(Long userId) {
userMapper.removeUser(userId);
}
}
7. 编写Service
package com.example.springboot.service;
public interface UserService {
List<User> listUsers();
User getUserById(Long userId);
void saveUser(User user);
void updateUser(User user);
void removeUser(Long userId);
}
package com.example.springboot.service.impl;
@Service
public class UserServiceImpl implements UserService{
@Autowired
private UserDao userDao;
@Override
public List<User> listUsers() {
return userDao.listUsers();
}
@Override
public User getUserById(Long userId) {
return userDao.getUserById(userId);
}
@Override
public void saveUser(User user) {
userDao.saveUser(user);
}
@Override
public void updateUser(User user) {
userDao.updateUser(user);
}
@Override
public void removeUser(Long userId) {
userDao.removeUser(userId);
}
}
8. 编写controller
package com.example.springboot.controller;
// 这里直接在类级别给一个/user的映射,就是代表用户管理的请求都会到这里来
@RequestMapping(value="/user")
public class UserController {
@Autowired
private UserService userService;
// GET请求代表着是查询数据
@RequestMapping(value="/", method=RequestMethod.GET)
public List<User> listUsers() {
return userService.listUsers();
}
// GET请求+{id}代表的是查询某个用户
@RequestMapping(value="/{userId}", method=RequestMethod.GET)
public User getUser(@PathVariable("userId") Long userId) {
return userService.getUserById(userId);
}
// POST请求代表着是新增数据
@RequestMapping(value="/", method=RequestMethod.POST)
public String saveUser(User user) {
userService.saveUser(user);
return "success";
}
// PUT请求代表的是更新
@RequestMapping(value="/{userId}", method=RequestMethod.PUT)
public String updateUser(@PathVariable("userId") Long userId, User user) {
user.setId(userId);
userService.updateUser(user);
return "success";
}
// DELETE请求代表的是删除
@RequestMapping(value="/{userId}", method=RequestMethod.DELETE)
public String deleteUser(@PathVariable("userId") Long userId) {
userService.removeUser(userId);
return "success";
}
}
9. 启动程序
启动程序,然后浏览器访问:http://localhost:8080/employee/1
此时会在浏览器中看到,将id=1的员工信息查询了出来,显示到了浏览器中
curl命令的使用,通过curl命令,可以替代浏览器去进行RESTful接口的一个测试,git命令行里面,就可以直接使用curl命令
curl -XPOST URL -d "param1=value1¶m2=value2"
curl -XGET URL
curl -XDELETE URL
curl -XPUT URL
curl -XPUT URL -H 'Content-Type:application/json' -d'
{
"param1":"value1",
"param2":"value2"
}
10. 测试
在spring boot做restful接口的时候,PUT请求和DELETE请求是有问题的,因为spring mvc对RESTful接口的支持会有一点问题
所以在做开发的时候,一般对于PUT,POST,请求,他们的请求参数,都不是用表单直接提交的,一般要求是用ajax走content-type是application/json的类型,通过json类型发送请求参数过来
2. 梳理一下此时的几个框架整合的思路
(1)系统启动的时候,首先会去扫描DruidDBConfig类,这就可以将外部的druid连接池配置加载进来,同时初始化出来一个druid连接池的DataSource bean
(2)mybatis-spring-boot-starter接着开始干活儿,发现了一个DataSource bean,就会将其注入SqlSessionFactory,再创建SqlSessionTemplate,接着扫描Mapper接口,将SqlSessionTemplate注入每个Mapper,然后将Mapper放入spring容器中来管理
(3)spring boot的@ComponantScan注解开始干活儿,自动扫描所有的bean,依次初始化实例以及注入依赖,EmployeeServiceImpl(将EmployeeMapper注入其中),EmployeeCongtroller(将EmployeeServiceImpl注入其中)
(4)此时浏览器发送请求,会先由controlller处理,接着调用service,再调用mapper。mapper底层会基于druid连接池访问到数据库,进行数据操作
至此,最常规的几个框架整合和使用,就完成了。
3. Demo中涉及的知识
1. spring-boot-starter-parent的作用
(1)默认的编译级别是 JDK 1.6
(2)指定了 UTF-8 为 source coding
(3)有一个
(4)开启了资源过滤器,支持对应资源文件中占位符的替换
(5)指定了多个插件:exec、surefire、git commit id、shade,用来支持运行、测试、版本控制、打包
2. 不直接继承spring-boot-starter-parent
如果要继承自己的 parent 工程,而不是直接继承 spring-boot-starter-parent,那么可以考虑使用 import 方式,将 spring-boot-start-parent 中的 dependency management 引入进来。但是这样的话,就没法用到 plugin management 了。
<dependencyManagement>
<dependencies>
<dependency>
<!-- Import dependency management from Spring Boot -->
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>1.5.9.RELEASE</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
3. 自己指定JDK版本
<properties>
<java.version>1.8</java.version>
</properties>
4. 使用spring boot的打包插件
spring-boot-starter-parent 指定了 pluginManagement,配置好了一系列的插件,其中一个就是用于打成可执行 jar 包的 shade 插件。如果我们要使用的话,需要自己手动声明这个插件,然后通过 mvn pakcage 命令就可以将工程打包成可以执行的 jar 包了。
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
5. spring-boot-starter-*
spring-boot 提供了一些列的 starter 类依赖,跟流行的常用项目进行整合,比如mybatis、redis、mongodb、elasticsearch,等等。我们只要声明对应的 spring-boot-starter-*,就可以直接使用对应版本的依赖,多个依赖的版本都是兼容的。可能就是通过 application.properties,注解,少量的配置,就可以快速整合进来一个技术开始使用。
6. 基于spring boot进行开发需要遵守的约定规则
一般建议基于 spring boot 来开发的时候,按照 spring boot 约定的规则来设置我们的包结构、代码布局,比如下面这样,这样 spring boot 在按照约定搜索各种注解的时候,一般不会出现什么问题。
com
+- example
+- springboot
+- Application.java
|
+- domain
| +- User.java
+- dao
| +- UserDao.java
|
+- service
| +- UserService.java
|
+- controller
+- UserController.java
用于启动的类一般会按照下面这样来写
@Configuration
@EnableAutoConfiguration
@ComponentScan
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
7. Configuration类
spring boot 的一个核心思想,就是尽量消除掉各种复杂的 xml 配置文件,所以一般建议如果要进行一些配置,可以采用 Configuration 类,在 Java 类中做一些配置。
而且通常比较好的实践是,就将用来放 main 方法的 Application 类,作为 Configuration 类,所以一般会给 Application 类加@Configuration 注解。
如果不想将所有的配置都放在 Application 类中,也可以使用 @Import 注解将其他的 Configuration 类引入进来,或者是依靠@ComponentScan 注解自动扫描其他的 Configuration 类。
即使一定要使用一个 xml 配置文件,建议是用 @ImportResource 来导入一个 xml 配置文件。
8. Auto Configuration
(1)什么是Auto Configuration
Auto Configuration是spring boot中非常核心的一个功能,因为spring boot的一个核心思想,就是尽可能减少我们要配置的东西,尽量才有约定规则自动完成一些配置。这个Auto Configuration功能,就会根据我们引入的依赖,来推测我们做什么事情,然后自动给我们完成需要的一些配置。举个例子,如果依赖了HSQLDB,那么spring boot会基于HSQLDB自动配置和创建一个内存数据库。
(2)如何启用Auto Configuration
我们给@Configuration类,增加了@EnableAutoConfiguration注解之后,就会开启Auto Configuration功能,而且一般推荐使用使用@EnableAutoConfiguration开启Auto Configuration功能。
9. 与Spring核心框架进行整合使用
spring boot 可以无缝与 spring 框架进行整合使用,一般就是在 Application 类上加 @ComponentScan 注解,启用自动扫描所有的 spring bean,同时搭配好 @Autowired 注解来进行自动装配。只要按照上面的那个约定,将 Application 类放在最顶层的包结构中,那么使用了 @ComponentScan 之后,就可以自动扫描和搜索到所有的 spring bean,包括了:@Component、@Contorller、@Service、@Repository
10. @SpringBootApplication
大多数的spring boot项目,都会在main类上标注:@Configuration、@EnableAutoConfiguration、@ComponantScan,因为这个实在是太过于常见了,所以spring boot提供了一个@SpringBootApplication注解,这个注解就相当于是上面3个注解的综合。所以实际上在开发的时候,一般就会在main类上加一个@SpringBootApplication注解
11. 启动spring boot程序
spring boot的另外一个核心思想,就是尽量简化各种应用的开发。
比如最常见的web应用程序,如果使用传统的方式来开发,需要安装和配置tomcat/jetty服务器,然后还需要将web程序打包后放入tomcat中才可以运行。或者是需要将eclipse等ide工具配置支持tomcat,才能在eclipse中直接启动web程序。
而在spring boot中,直接基于了内置的tomcat/jetty容器,可以在写好代码之后,一键启动web程序,然后就可以在浏览器中访问了。对于本地开发、测试以及debug个调试,都是非常的方便的
(1)在IDE中启动spring boot程序
直接运行main方法即可,默认会绑定在8080端口上
(2)在命令行执行jar包来启动spring boot程序
使用mvn package将应用程序打成一个可以执行的jar包之后,就可以在命令行使用jar -jar命令来启动了,scp命令,自行百度,拷贝到线上的服务器
$ java -jar target/myproject-0.0.1-SNAPSHOT.jar
同样在启动spring boot应用程序时可以传递一些参数
$ java -Xdebug -Xrunjdwp:server=y,transport=dt_socket,address=8082,suspend=n \
-jar target/springboot-demo-1.0.0.jar
(3)在命令行直接启动spring boot程序
也可以使用spring-boot插件的run goal来直接在命令行基于代码启动spring boot程序,几乎很少用
$ mvn spring-boot:run