简单介绍
springboot
首先什么是springboot?
springboot是spring的另外一款框架,设计目的是用来简化新的spring应用的搭建和开发时所需要的特定的配置,从而使开发过程不需要一次次无聊的复制那些一模一样的配置。
springboot内嵌tomcat,不需要部署war文件了,常常我们只需要将springboot项目打成jar包,然后通过: java -jar 项目名称
即可,例如我有一个名叫demo的项目现在打包成了demo.jar需要在服务器上运行,那么我只需要这样: java -jar demo.jar
springboot简化了maven的配置
而且springboot可以自动化配置,其实就将一些配置设置了有默认的配置。
ssm框架
ssm框架即Spring+SpringMVC+Mybatis
这里引用一下百度的介绍
Spring
Spring就像是整个项目中装配bean的大工厂,在配置文件中可以指定使用特定的参数去调用实体类的构造方法来实例化对象。也可以称之为项目中的粘合剂。
Spring的核心思想是IoC(控制反转),即不再需要程序员去显式地new
一个对象,而是让Spring框架帮你来完成这一切。SpringMVC
SpringMVC在项目中拦截用户请求,它的核心Servlet即DispatcherServlet承担中介或是前台这样的职责,将用户请求通过HandlerMapping去匹配Controller,Controller就是具体对应请求所执行的操作。SpringMVC相当于SSH框架中struts。mybatis
mybatis是对jdbc的封装,它让数据库底层操作变的透明。mybatis的操作都是围绕一个sqlSessionFactory实例展开的。mybatis通过配置文件关联到各实体类的Mapper文件,Mapper文件中配置了每个类对数据库所需进行的sql语句映射。在每次与数据库交互时,通过sqlSessionFactory拿到一个sqlSession,再执行sql命令。页面发送请求给控制器,控制器调用业务层处理逻辑,逻辑层向持久层发送请求,持久层与数据库交互,后将结果返回给业务层,业务层将处理逻辑发送给控制器,控制器再调用视图展现数据。
Druid
Druid是阿里巴巴开源平台的一款项目,就是一款Java语言的数据库连接池,而且性能优越拥有强大的监控和扩展功能。
通用Mapper
我们用Mybatis进行开发的时候肯定会遇到这样一种情况,有时候我的某个表只需要进行简单的增删改查,但是却需要些大量的xml,而且假如数据库结构发生改变的时候所有的实体类和sql都需要修改。(虽然一般不会改,改了可能会这样( ̄ε(# ̄)☆╰╮o( ̄皿 ̄///))这样大大的影响了我们的工作效率啊。为此就出现了通用mapper。
通用mapper是个什么鬼东西呢,怎么就这么棒呢,通用mapper就是为了解决单表增删该改查(没错你没看错只能解决单表,多表自己想办法( ̄_, ̄ )),基于mybatis插件,这时候开发人员不需要写sql,不需要在Dao中写方法,只要写好实体类就能支持相应的增删改查方法。是不是感觉很奈斯。
快速搭建一个springboot项目
快速搭建,哼哼哼,你猜有多快,你跟本想不到有多快︿( ̄︶ ̄)︿
使用spring脚手架
关于spring脚手架的使用,我们有两种方式
第一种是通过https://start.spring.io/ 这个地址直接搭建
打开后大概是这个样子
我们选择Maven Project因为我们的项目是用maven构建 ,语言选Java,Springboot版本默认就好。
然后在Group填写自己的项目组织所属,一般就是com,xxxx之类的啦(ーー゛),Artifact 我们填自己的项目名,比如demo。最后Search for dependencies 我们可以指定web,填一个web回车就好了。
完事后大概就是这个样子{% asset_img springboot脚手架2.png %}
然后我们点击Generate Project将项目下载下来。
我们得到一个demo.zip的文件,然后将它解压
然后我们看下文件结构
│ .gitignore
│ mvnw
│ mvnw.cmd
│ pom.xml
│
├─.mvn
│ └─wrapper
│ maven-wrapper.jar
│ maven-wrapper.properties
│
└─src
├─main
│ ├─java
│ │ └─com
│ │ └─ccsert
│ │ └─demo
│ │ DemoApplication.java
│ │
│ └─resources
│ │ application.properties
│ │
│ ├─static
│ └─templates
└─test
└─java
└─com
└─ccsert
└─demo
DemoApplicationTests.java这里只需要知道pom.xml是用来管理maven依赖的,以及DemoApplication是启动类就可以了
接下来我们将项目导入到idea中。
点击Import Project
选择那个解压好的项目点击ok
然后这里选择maven点击下一步
然后一直下一步,最后finis就好了
这样我们就完成了springboot的创建
还有一种创建方式是通过idea自带的脚手架 工具创建,这里不在进行说明了。
SpringBoot快速入门
既然项目搭建好了,那么我们可以开始写代码了。我们可以像写springMVC一样去使用springboot写web项目。
我们先创建一个controller的包,然后创建一个controller类,就叫HelloController吧,创建好以后是这个样子的
接下来国际惯例,hello world (*/ω\*)
package com.ccsert.demo.controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* @author ccsert
* @version V1.0
* @Description: TODO
* @date
*/
@RestController //RestController==@ResponseBody+@Controller
public class HelloController {
@RequestMapping("/hello")
public String hello(){
return "hello SpringBoot";
}
}
然后我们将项目运行起来,在DemoApplication直接点击绿色小箭头运行,就跟运行main方法一样,好吧就是运行main方法
我们从控制台看到tomcat的端口是8080,所以我们在浏览器输入http://localhost:8080/hello 就能直接访问你的项目了
这样一来我们很轻松的就完成了一个基础的springboot web项目。是不是很简单?
SpringBoot集成
在上面我们已经完成了一个基础的项目,现在我们需要集成整合SSM以及druid连接池还有通用Mapper,在后面我会很详细的给大家讲解集成过程。
SpringBoot集成Druid
springboot简化了maven 的配置我们只要引入druid的maven库即可,不需要关心maven之间的依赖,springboot会自行帮我们处理好
我们直接引入druid的地址 将其引入pom.xml
<!-- Druid连接池 -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.5</version>
</dependency>
<!-- mysql -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>6.0.6</version>
</dependency>
我们使用yaml的配置,所以将原本是application.properority的文件改名为application.yml
然后进行配置,记得先建立一个demo的数据库
spring:
datasource:
type: com.alibaba.druid.pool.DruidDataSource
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://127.0.0.1:3306/demo?useUnicode=true&characterEncoding=UTF8&serverTimezone=UTC
platform: mysql
username: root
password: 123456
initialSize: 3
minIdle: 3
maxActive: 30
maxWait: 15000
timeBetweenEvictionRunsMillis: 120000
minEvictableIdleTimeMillis: 300000
validationQuery: SELECT 1 FROM DUAL
testWhileIdle: true
testOnBorrow: false
testOnReturn: false
poolPreparedStatements: true
maxPoolPreparedStatementPerConnectionSize: 20
filters: stat,wall,log4j
connectionProperties: druid.stat.mergeSql=true;druid.stat.slowSqlMillis=5000
druidRegistrationUrl: /druid/*
resetEnable: true
loginUsername: admin
loginPassword: admin
我原本准备在yml里面写些注释的,但是后来启动会报错,就去掉了注释,关于德鲁伊配置的参数大家可以去看看相关的文档。
这里注意一下我使用的druid版本不是最新版本,最新版本的配置与旧版本的filters: stat,wall,log4j 不太一样,这个版本是当前使用人数最多的版本。
yml配置好以后我们还要对druid进行相关的配置
先在demo包下建一个config包,然后在config创建DruidConfig类,在此之前因为我们会需要写getset方法我们引入一下Lombok
<!-- lombok -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.4</version>
<scope>provided</scope>
</dependency>
下面的是配置类的Java代码
package com.ccsert.demo.config;
import com.alibaba.druid.pool.DruidDataSource;
import com.alibaba.druid.support.http.StatViewServlet;
import lombok.Getter;
import lombok.Setter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.web.servlet.ServletRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Primary;
import org.springframework.stereotype.Component;
import java.sql.SQLException;
@Component
@ConfigurationProperties(prefix = "spring.datasource")
@Getter@Setter
public class DruidConfig {
private final Logger logger = LoggerFactory.getLogger(DruidConfig.class);
private String driverClassName;
private String url;
private String username;
private String password;
private int initialSize;
private int minIdle;
private int maxActive;
private long maxWait;
private long timeBetweenEvictionRunsMillis;
private long minEvictableIdleTimeMillis;
private String validationQuery;
private boolean testWhileIdle;
private boolean testOnBorrow;
private boolean testOnReturn;
private boolean poolPreparedStatements;
private int maxPoolPreparedStatementPerConnectionSize;
private long removeAbandonedTimeoutMillis;
private boolean removeAbandoned;
private boolean logAbandoned;
private boolean logDifferentThread;
private String filters;
private String connectionProperties;
private boolean useGlobalDataSourceStat;
//Druid 监控 Servlet 配置参数
private String druidRegistrationUrl;
private boolean resetEnable;
private String loginUsername;
private String loginPassword;
// Filters 配置参数
private String filtersUrlPatterns;
private String exclusions;
private int sessionStatMaxCount;
private boolean sessionStatEnable;
private String principalSessionName;
private boolean profileEnable;
@Bean(initMethod = "init", destroyMethod = "close")
@Primary
public DruidDataSource dataSource() {
DruidDataSource dataSource = new DruidDataSource();
dataSource.setDriverClassName(driverClassName);
dataSource.setUrl(url);
dataSource.setUsername(username);
dataSource.setPassword(password);
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);
dataSource.setRemoveAbandonedTimeoutMillis(removeAbandonedTimeoutMillis);
dataSource.setRemoveAbandoned(removeAbandoned);
dataSource.setLogDifferentThread(logDifferentThread);
try {
dataSource.setFilters(filters);
}
catch(SQLException e) {
e.printStackTrace();
logger.error("Druid URL过滤设置失败", e);
}
dataSource.setConnectionProperties(connectionProperties);
dataSource.setUseGlobalDataSourceStat(useGlobalDataSourceStat);
return dataSource;
}
@Bean
public ServletRegistrationBean druidServlet() {
ServletRegistrationBean servletBean = new ServletRegistrationBean(new StatViewServlet(), druidRegistrationUrl);
servletBean.addInitParameter("resetEnable", String.valueOf(resetEnable));
servletBean.addInitParameter("loginUsername", loginUsername);
servletBean.addInitParameter("loginPassword", loginPassword);
return servletBean;
}
}
紧接着我们让druid支持事务,在config包下创建一个TransactionConfig类
在此之前因为需要用到mybatis的注解,我们先将mybatis的依赖引入
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>1.3.1</version>
</dependency>
然后下面是Java代码
package com.ccsert.demo.config;
import com.alibaba.druid.pool.DruidDataSource;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.context.annotation.Configuration;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;
import org.springframework.transaction.annotation.TransactionManagementConfigurer;
/**
* @author ccsert
* @version V1.0
* @Description: TODO
* @date
*/
@Configuration
@EnableTransactionManagement
@AutoConfigureAfter({DruidConfig.class})
@MapperScan(basePackages = {"Mybatis 的 DAO 接口所在的包路径"})
public class TransactionConfig implements TransactionManagementConfigurer {
@Autowired
private DruidDataSource mDataSource;
@Override
public PlatformTransactionManager annotationDrivenTransactionManager() {
return new DataSourceTransactionManager(mDataSource);
}
}
最后我们配置一下druid的监控界面
在上面的DruidConfig类中加入一个方法
@Bean
public ServletRegistrationBean druidServlet() {
ServletRegistrationBean servletBean = new ServletRegistrationBean(new StatViewServlet(), druidRegistrationUrl);
servletBean.addInitParameter("resetEnable", String.valueOf(resetEnable));
servletBean.addInitParameter("loginUsername", loginUsername);
servletBean.addInitParameter("loginPassword", loginPassword);
return servletBean;
}
这样就配置完毕了
然后我们开始集成mybatis,这个时候先不要着急访问druid的监控界面,也不要着急启动项目,因为我们还没有mapper
接口。
SpringBoot集成mybatis
我们这里使用xml写sql所以在刚才的yml配置里加上一条配置用于扫描mapper.xml的映射文件。
mybatis:
mapper-locations: classpath:mappers/**/*Mapper.xml
type-aliases-package: com.ccsert.demo.*.model
然后在resources下建一个文件夹名字为mappers
其实这样已经差不多可以使用了,这里我们先不着急使用
先集成一下通用mapper
SpringBoot集成通用mapper
先引入通用mapper
<!-- 通用mapper -->
<dependency>
<groupId>tk.mybatis</groupId>
<artifactId>mapper-spring-boot-starter</artifactId>
<version>2.0.2</version>
</dependency>
然后我们在config包下建立一个MyBatisConfig 类用于配置通用mapper
package com.ccsert.demo.config;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import tk.mybatis.mapper.common.Mapper;
import tk.mybatis.spring.mapper.MapperScannerConfigurer;
import java.util.Properties;
/**
* @author ccsert
* @version V1.0
* @Description: TODO
* @date
*/
@Slf4j
@Configuration
public class MyBatisConfig {
@Bean
public MapperScannerConfigurer mapperScannerConfigurer(){
log.info("加载MyBatisConfig.....");
MapperScannerConfigurer mapperScannerConfigurer = new MapperScannerConfigurer();
mapperScannerConfigurer.setSqlSessionFactoryBeanName("sqlSessionFactory");
mapperScannerConfigurer.setBasePackage("com.ccsert.demo.login.dao");
Properties properties = new Properties();
properties.setProperty("mappers", Mapper.class.getName());
properties.setProperty("notEmpty", "false");
properties.setProperty("IDENTITY", "MYSQL");
properties.setProperty("ORDER","BEFORE");
mapperScannerConfigurer.setProperties(properties);
return mapperScannerConfigurer;
}
}
好了结束了,就这么点点东西
我们直接开始使用测试一下
SpringBoot Smm使用
在demo新建一个login包吧
然后在login包中建立dao,controller,service,model四个包,弄完以后大概就是这样
然后我们先建立一个简单的用户表,并新增些数据
/*
Navicat MySQL Data Transfer
Source Server : 本地
Source Server Version : 50624
Source Host : 127.0.0.1:3306
Source Database : demo
Target Server Type : MYSQL
Target Server Version : 50624
File Encoding : 65001
Date: 2019-02-11 14:43:32
*/
SET FOREIGN_KEY_CHECKS=0;
-- ----------------------------
-- Table structure for user_info
-- ----------------------------
DROP TABLE IF EXISTS `user_info`;
CREATE TABLE `user_info` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`user_name` varchar(255) DEFAULT NULL,
`password` varchar(255) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8;
-- ----------------------------
-- Records of user_info
-- ----------------------------
INSERT INTO `user_info` VALUES ('1', 'ccsert', '123456');
INSERT INTO `user_info` VALUES ('2', 'root', '654321');
INSERT INTO `user_info` VALUES ('3', 'admin', '8848');
INSERT INTO `user_info` VALUES ('4', '来个中文名', '111aaa');
然后我们从实体类开始写
然后在model下建立一个实体类UserInfo,这里注意一下,我踩过几次坑了,这里必须使用驼峰命名法,因为我们的表名是带 _ 的所以因该从这里我们命名应当是UserInfo ,我们的通用mapper是根据实体类名去找表的。
package com.ccsert.demo.login.model;
import lombok.Getter;
import lombok.Setter;
/**
* @author ccsert
* @version V1.0
* @Description: TODO
* @date
*/
@Getter@Setter
public class UserInfo {
private Integer Id;
private String UserName;
private String Password;
}
接着是dao下建立一个UserInfoMapper接口,并继承通用mapper类
package com.ccsert.demo.login.dao;
import com.ccsert.demo.login.model.UserInfo;
import tk.mybatis.mapper.common.BaseMapper;
/**
* @author ccsert
* @version V1.0
* @Description: TODO
* @date
*/
public interface UserInfoMapper extends BaseMapper<UserInfo> {
}
然后在service包下建立UserInfoService接口
在接口里写一个查询所有的方法
package com.ccsert.demo.login.service;
import com.ccsert.demo.login.model.UserInfo;
import java.util.List;
public interface UserInfoService {
List<UserInfo> selectAll();
}
接着在service包下建立一个impl的包
然后在包内建一个UserInfoService的实现类UserInfoServiceImpl
package com.ccsert.demo.login.service.impl;
import com.ccsert.demo.login.dao.UserInfoMapper;
import com.ccsert.demo.login.model.UserInfo;
import com.ccsert.demo.login.service.UserInfoService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
/**
* @author ccsert
* @version V1.0
* @Description: TODO
* @date
*/
@Service
public class UserInfoServiceImpl implements UserInfoService {
@Autowired
private UserInfoMapper userInfoMapper;
@Override
public List<UserInfo> selectAll() {
List<UserInfo> userInfos = userInfoMapper.selectAll();
return userInfos;
}
}
最后是controller包下建立一个UserInfoController
package com.ccsert.demo.login.controller;
import com.ccsert.demo.login.model.UserInfo;
import com.ccsert.demo.login.service.UserInfoService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
/**
* @author ccsert
* @version V1.0
* @Description: TODO
* @date
*/
@RestController
@RequestMapping("/user")
public class UserInfoController {
@Autowired
private UserInfoService userInfoService;
@RequestMapping("getall")
public List<UserInfo> selectAll(){
List<UserInfo> userInfos = userInfoService.selectAll();
return userInfos;
}
}
最后我们还要在启动类上加一个mapper扫描的注解
@MapperScan("com.ccsert.demo.login.dao")
导包时请注意,导入import tk.mybatis.spring.annotation.MapperScan;这个包
记得在事务配置上改为自己dao接口的路径
@MapperScan(basePackages = {"com.ccsert.demo.login.dao"})
我们运行一下,按照我写代码的方式,多半是要报错的。
org.springframework.context.ApplicationContextException: Unable to start web server; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'org.springframework.boot.autoconfigure.web.servlet.ServletWebServerFactoryConfiguration$EmbeddedTomcat': Initialization of bean failed; nested exception is org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'org.springframework.transaction.annotation.ProxyTransactionManagementConfiguration': Unsatisfied dependency expressed through method 'setConfigurers' parameter 0; nested exception is org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'transactionConfig': Unsatisfied dependency expressed through field 'mDataSource'; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'dataSource' defined in class path resource [com/ccsert/demo/config/DruidConfig.class]: Bean instantiation via factory method failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [com.alibaba.druid.pool.DruidDataSource]: Factory method 'dataSource' threw exception; nested exception is java.lang.NoClassDefFoundError: org/apache/log4j/Logger
果然是报错了(ノへ ̄、)
不过这个错看起来很好解决,末尾说找不到log4j,讲道理导入log4j的依赖就完事了
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>1.7.12</version>
</dependency>
导入后重新启动项目是会又警告的,虽然开发运行没有影响但是在生产打包为jar可能会报错,这是因为springboot默认的日志是logback,而logback和log4j发生冲突了。
我们把logback排除掉即可。
然而真相并不是这样,其实是druid的锅,既然都已经给了更好的logback,我们就直接用就好哪里还要换一个又屏蔽一个的?( ̄_, ̄ )
我们只要在yml的配置文件中去掉 filters: stat,wall,log4j 的log4j就完事了
上面的那个log4j我就放出来看看而已不用加进去。嘿嘿嘿~~
我们最后在yml配置里加一个日志的配置
logging:
file: logs/mass.log
level:
org.springframework: info
com.ccsert: DEBUG
然后就能打印sql了。
然后再次运行,果断运行成功,其实前面的报错都是我装的,我早就考虑到这些问题了。(其实我压根不知道,还找了半天的错)
输入http://localhost:8080/user/getall访问
我们访问一下druid的监控
http://localhost:8080/druid/index.html
然后我们点击sql监控
我们可以看到我们之前所执行的sql都会被druid监控
总算搞完了,后面有时间会继续集成使用的组件。
这里感谢简书一位朋友的支持,其中有些代码摘抄于这位朋友的文章
附上原文链接https://www.jianshu.com/p/9dc6f4418a06