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.DruidDataSourcespring.datasource.url=jdbc:mysql://127.0.0.1:3306/oa?useUnicode=true&characterEncoding=utf-8spring.datasource.username=rootspring.datasource.password=rootspring.datasource.driverClassName=com.mysql.jdbc.Driver# 连接池的配置信息# 连接池初始大小spring.datasource.initialSize=5# 连接池最小空闲连接数量spring.datasource.minIdle=5# 连接池最大活跃连接数量spring.datasource.maxActive=20spring.datasource.maxWait=60000spring.datasource.timeBetweenEvictionRunsMillis=60000spring.datasource.minEvictableIdleTimeMillis=300000spring.datasource.validationQuery=SELECT 1 FROM DUALspring.datasource.testWhileIdle=truespring.datasource.testOnBorrow=falsespring.datasource.testOnReturn=falsespring.datasource.poolPreparedStatements=truespring.datasource.maxPoolPreparedStatementPerConnectionSize=20spring.datasource.filters=stat,wall,log4jspring.datasource.connectionProperties=druid.stat.mergeSql=true;druid.stat.slowSqlMillis=5000
3. 编写Druid连接池配置管理类
package com.example.springboot.config;// 使用@Configuration标注,表示这是一个配置管理类@Configurationpublic 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@Primarypublic DataSource dataSource() {// 这里就是用外部加载进来的配置信息,创建出来一个Druid连接池DruidDataSource datasource = new DruidDataSource();datasource.setUrl(this.dbUrl);datasource.setUsername(username);datasource.setPassword(password);datasource.setDriverClassName(driverClassName);//configurationdatasource.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
