Spring Boot 是所有基于 Spring 开发的项目的起点。Spring Boot 的设计是为了让你尽可能快的跑起来 Spring 应用程序并且尽可能减少你的配置文件。简单来说就是SpringBoot其实不是什么新的框架,它默认配置了很多框架的使用方式,就像maven整合了所有的jar包,spring boot整合了所有的框架。
SpringBoot所具备的特征有:
可以创建独立的Spring应用程序,并且基于其Maven或Gradle插件,可以创建可执行的JARs和WARs;
内嵌Tomcat或Jetty等Servlet容器;
提供自动配置的“starter”项目对象模型(POMS)以简化Maven配置;
尽可能自动配置Spring容器;
提供准备好的特性,如指标、健康检查和外部化配置;
绝对没有代码生成,不需要XML配置。
maven环境搭建可以看这一篇文章(https://www.runoob.com/maven/maven-setup.html)
首先打开idea创建一个maven项目
1,maven-archetype-quickstart
默认的Archetype,基本内容包括:
一个包含junit依赖声明的pom.xml
src/main/java主代码目录及一个名为App的类
src/test/java测试代码目录及一个名为AppTest的测试用例
2,maven-archetype-webapp
一个最简单的Maven war项目模板,当需要快速创建一个Web应用的时候可以使用它。生成的项目内容包括:
一个packaging为war且带有junit依赖声明的pom.xml
src/main/webapp/目录
src/main/webapp/index.jsp文件
src/main/webapp/WEB-INF/web.xml文件
<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>
</dependencies>
spring-boot-starter-parent作用
在pom.xml中引入spring-boot-start-parent,它可以提供dependency management,也就是说依赖管理,引入以后在申明其它dependency的时候就不需要version了,后面可以看到。
spring-boot-starter-web作用
springweb 核心组件
@RestController//相当于声明Controller - 提共restful 风格
@EnableAutoConfiguration//自动配置,不需要写spring的配置文件
class HelloController {
@RequestMapping("/hello")//映射路径
@ResponseBody//响应体
public String hello() {
return "Hello World";
}
public static void main(String[] args) {
//启动程序
SpringApplication.run(HelloController.class, args);
}
}
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-freemarker</artifactId>
</dependency>
@Controller // 声明Rest风格的控制器,访问freeMarker不要用RestController
@RequestMapping("stu")
public class StudentController {
/**
* 返回 stu/list这里默认配置自动映射到 templages/stu/list
* */
@RequestMapping("list")
public String list(Model model){
model.addAttribute("username","gyf");
model.addAttribute("age",20);
List<Object> stuList = new ArrayList<>();
stuList.add(new Student(1001,"zhuangsan","男"));
stuList.add(new Student(1002,"lisi","男"));
model.addAttribute("stuList",stuList);
return "stu/list";// 找模板页面
}
}
在src/main/resources/创建一个templates文件夹,后缀为*.ftl
掌握如何取值和判断
欢迎《${username}》
<#if (age <= 18)>-小朋友
<#elseif (age > 30)>大叔
<#else >帅哥/美女
</#if>
登陆<br/>
学生列表<br/>
<table border="1">
<tr>
<td>ID</td>
<td>名字</td>
<td>性别</td>
</tr>
<#list stuList?sort_by("id")?reverse as stu>
<tr>
<td>${stu.id}</td>
<td>${stu.username}</td>
<td>${stu.gender}</td>
</tr>
</#list>
<dependency>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-jasper</artifactId>
</dependency>
spring.mvc.view.prefix=/WEB-INF/view/
spring.mvc.view.suffix=.jsp
@RequestMapping("list")
public String list(){
return "teacher/list";
}
public static void main(String[] args) {
SpringApplication.run(TeacherController.class,args);
}
<!-- JDBC -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<!-- 数据库驱动 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
#数据库配置
spring.datasource.url=jdbc:mysql://localhost:3306/day12
spring.datasource.username=root
spring.datasource.password=123456
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
@Service
public class UserServiceImpl implements UserService {
@Autowired// 自动注入
private JdbcTemplate jdbcTemplate;
public void register(String uname, String upass) {
jdbcTemplate.update("insert user(uname,upass) values (?,?)",uname,upass);
}
}
@RestController // 声明Rest风格的控制器
@RequestMapping("user")
public class UserController {
private UserService userService;
// 连接数据库
@RequestMapping("register")
public String register(String uname,String upass){
userService.register(uname,upass);
return "success";
}
// 扫描多个包{} 扫描单个包""
@ComponentScan(basePackages = "com.fz")
// 自动扫描
@EnableAutoConfiguration
public class App {
public static void main(String[] args) {
SpringApplication.run(App.class,args);
}
}
<!-- mybaties -->
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>1.1.1</version>
</dependency>
#数据库配置
spring.datasource.url=jdbc:mysql://localhost:3306/day12
spring.datasource.username=root
spring.datasource.password=123456
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
// 扫描多个包{} 扫描单个包""
@ComponentScan(basePackages = "com.fz")
// 锁定mapper文件
@MapperScan(basePackages = "com.fz.mapper")
// 自动扫描
@EnableAutoConfiguration
public class App {
public static void main(String[] args) {
SpringApplication.run(App.class,args);
}
}
public interface UserMapper {
// 注解方式
@Insert("insert user(uname,upass) values(#{uname},#{upass})")
public int save(@Param("uname") String uname,@Param("upass") String upass);
// @Param作用:参数要和数据库保持一致
@Select("select * from user where uname = #{uname}")
public User findByUserName(@Param("uname") String uname);String upass);
}
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="com.gyf.mapper.UserMapper" >
<insert id="save">
insert into t_user (username,password) VALUES(#{0},#{1})
</insert>
<select id="findByUsername" resultType="com.gyf.model.User" parameterType="string">
select * from t_user where username = #{username,jdbcType=VARCHAR}
</select>
</mapper>
<build>
<resources>
<resource>
<directory>src/main/java</directory>
<includes>
<include>**/*.xml
spring.datasource.test1.driverClassName=com.mysql.jdbc.Driver
spring.datasource.test1.url=jdbc:mysql://localhost:3306/springboottest1?useUnicode=true&characterEncoding=utf-8
spring.datasource.test1.username=root
spring.datasource.test1.password=root
spring.datasource.test2.driverClassName=com.mysql.jdbc.Driver
spring.datasource.test2.url=jdbc:mysql://localhost:3306/springboottest2?useUnicode=true&characterEncoding=utf-8
spring.datasource.test2.username=root
spring.datasource.test2.password=root
@Configuration//注解到springboot容器中
@MapperScan(basePackages="com.fz.test1.mapper",sqlSessionFactoryRef="test1SqlSessionFactory")
public class DataSource01 {
/**
* @return 返回test1数据库的数据源
*/
@Bean(name="test1DataSource")
@Primary//主数据源 一个应用只能有一个主数据源
@ConfigurationProperties(prefix="spring.datasource.test1")
public DataSource dateSource(){
return DataSourceBuilder.create().build();
}
/**
* @return 返回test1数据库的会话工厂
*/
@Bean(name = "test1SqlSessionFactory")
public SqlSessionFactory sqlSessionFactory(@Qualifier("test1DataSource") DataSource ds) throws Exception{
SqlSessionFactoryBean bean = new SqlSessionFactoryBean();
bean.setDataSource(ds);
return bean.getObject();
}
/**
* @return 返回test1数据库的事务
*/
@Bean(name = "test1TransactionManager")
@Primary//主事务
public DataSourceTransactionManager transactionManager(@Qualifier("test1DataSource") DataSource dataSource) {
return new DataSourceTransactionManager(dataSource);
}
/**
* @return 返回test1数据库的会话模版
*/
@Bean(name = "test1SqlSessionTemplate")
public SqlSessionTemplate sqlSessionTemplate(
@Qualifier("test1SqlSessionFactory") SqlSessionFactory sqlSessionFactory) throws Exception {
return new SqlSessionTemplate(sqlSessionFactory);
}
}
@Configuration//注解到springboot容器中
@MapperScan(basePackages="com.fz.test2.mapper",sqlSessionFactoryRef="test2SqlSessionFactory")
public class DataSource02 {
/**
* @return 返回test1数据库的数据源
*/
@Bean(name="test2DataSource")
@ConfigurationProperties(prefix="spring.datasource.test2")
public DataSource dateSource(){
return DataSourceBuilder.create().build();
}
/**
* @return 返回test1数据库的会话工厂
*/
@Bean(name = "test2SqlSessionFactory")
public SqlSessionFactory sqlSessionFactory(@Qualifier("test2DataSource") DataSource ds) throws Exception{
SqlSessionFactoryBean bean = new SqlSessionFactoryBean();
bean.setDataSource(ds);
return bean.getObject();
}
/**
* @return 返回test1数据库的事务
*/
@Bean(name = "test2TransactionManager")
public DataSourceTransactionManager transactionManager(@Qualifier("test2DataSource") DataSource dataSource) {
return new DataSourceTransactionManager(dataSource);
}
/**
* @return 返回test1数据库的会话模版
*/
@Bean(name = "test2SqlSessionTemplate")
public SqlSessionTemplate sqlSessionTemplate(
@Qualifier("test2SqlSessionFactory") SqlSessionFactory sqlSessionFactory) throws Exception {
return new SqlSessionTemplate(sqlSessionFactory);
}
}
@Service
@Transactional
public class UserServiceImpl implements UserService {
@Autowired
private UserMapper userMapper;
@Autowired
private CustomerMapper customerMapper;
public void save(String uname, String upass) {
//最后一个可以插入一条数据
//原是是Transactoinal的事务只针对userMapper有效
//customerMapper的事务由datasource02管理,所以这里的异常不影响customerMapper的执行
customerMapper.save(uname,"110");
int i = 10/0;
userMapper.save(uname,upass);
}
}
/*
* 解决方法
* 使用springboot+jta+atomikos 分布式事物管理解决方案
* 1.添加jta事务依赖
* 2.修改数据库连接配置数据
* 3.添加2个配置模型(dbconfig)
* 4.重定两个数据源配置
* 5.App中扫描dbconfig包并且配置EnableConfigurationProperties
* */
``
使用springboot+jta+atomikos 分布式事物管理解决方案
<!--多事务配置-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jta-atomikos</artifactId>
</dependency>
# Mysql 1
mysql.datasource.test1.url = jdbc:mysql://localhost:3306/springboottest1?useUnicode=true&characterEncoding=utf-8
mysql.datasource.test1.username = root
mysql.datasource.test1.password = root
mysql.datasource.test1.minPoolSize = 3
mysql.datasource.test1.maxPoolSize = 25
mysql.datasource.test1.maxLifetime = 20000
mysql.datasource.test1.borrowConnectionTimeout = 30
mysql.datasource.test1.loginTimeout = 30
mysql.datasource.test1.maintenanceInterval = 60
mysql.datasource.test1.maxIdleTime = 60
mysql.datasource.test1.testQuery = select 1
# Mysql 2
mysql.datasource.test2.url =jdbc:mysql://localhost:3306/springboottest2?useUnicode=true&characterEncoding=utf-8
mysql.datasource.test2.username =root
mysql.datasource.test2.password =root
mysql.datasource.test2.minPoolSize = 3
mysql.datasource.test2.maxPoolSize = 25
mysql.datasource.test2.maxLifetime = 20000
mysql.datasource.test2.borrowConnectionTimeout = 30
mysql.datasource.test2.loginTimeout = 30
mysql.datasource.test2.maintenanceInterval = 60
mysql.datasource.test2.maxIdleTime = 60
mysql.datasource.test2.testQuery = select 1
@ConfigurationProperties("mysql.datasource.test2")
public class DBConfig2 {
private String url;
private String username;
private String password;
private int minPoolSize;
private int maxPoolSize;
private int maxLifetime;
private int borrowConnectionTimeout;
private int loginTimeout;
private int maintenanceInterval;
private int maxIdleTime;
private String testQuery;
@ConfigurationProperties("mysql.datasource.test1")
public class DBConfig1 {
private String url;
private String username;
private String password;
private int minPoolSize;
private int maxPoolSize;
private int maxLifetime;
private int borrowConnectionTimeout;
private int loginTimeout;
private int maintenanceInterval;
private int maxIdleTime;
private String testQuery;
@Configuration//注解到springboot容器中
@MapperScan(basePackages="com.fz.test1.mapper",sqlSessionFactoryRef="test1SqlSessionFactory")
public class DataSource01 {
// 配置数据源
@Primary
@Bean(name = "test1DataSource")
public DataSource testDataSource(DBConfig1 testConfig) throws SQLException {
MysqlXADataSource mysqlXaDataSource = new MysqlXADataSource();
mysqlXaDataSource.setUrl(testConfig.getUrl());
mysqlXaDataSource.setPinGlobalTxToPhysicalConnection(true);
mysqlXaDataSource.setPassword(testConfig.getPassword());
mysqlXaDataSource.setUser(testConfig.getUsername());
mysqlXaDataSource.setPinGlobalTxToPhysicalConnection(true);
AtomikosDataSourceBean xaDataSource = new AtomikosDataSourceBean();
xaDataSource.setXaDataSource(mysqlXaDataSource);
xaDataSource.setUniqueResourceName("test1DataSource");
xaDataSource.setMinPoolSize(testConfig.getMinPoolSize());
xaDataSource.setMaxPoolSize(testConfig.getMaxPoolSize());
xaDataSource.setMaxLifetime(testConfig.getMaxLifetime());
xaDataSource.setBorrowConnectionTimeout(testConfig.getBorrowConnectionTimeout());
xaDataSource.setLoginTimeout(testConfig.getLoginTimeout());
xaDataSource.setMaintenanceInterval(testConfig.getMaintenanceInterval());
xaDataSource.setMaxIdleTime(testConfig.getMaxIdleTime());
xaDataSource.setTestQuery(testConfig.getTestQuery());
return xaDataSource;
}
@Bean(name = "test1SqlSessionFactory")
public SqlSessionFactory testSqlSessionFactory(@Qualifier("test1DataSource") DataSource dataSource)
throws Exception {
SqlSessionFactoryBean bean = new SqlSessionFactoryBean();
bean.setDataSource(dataSource);
return bean.getObject();
}
@Bean(name = "test1SqlSessionTemplate")
public SqlSessionTemplate testSqlSessionTemplate(
@Qualifier("test1SqlSessionFactory") SqlSessionFactory sqlSessionFactory) throws Exception {
return new SqlSessionTemplate(sqlSessionFactory);
}
}
@Configuration//注解到springboot容器中
@MapperScan(basePackages="com.fz.test2.mapper",sqlSessionFactoryRef="test2SqlSessionFactory")
public class DataSource02 {
// 配置数据源
@Bean(name = "test2DataSource")
public DataSource testDataSource(DBConfig2 testConfig) throws SQLException {
MysqlXADataSource mysqlXaDataSource = new MysqlXADataSource();
mysqlXaDataSource.setUrl(testConfig.getUrl());
mysqlXaDataSource.setPinGlobalTxToPhysicalConnection(true);
mysqlXaDataSource.setPassword(testConfig.getPassword());
mysqlXaDataSource.setUser(testConfig.getUsername());
mysqlXaDataSource.setPinGlobalTxToPhysicalConnection(true);
AtomikosDataSourceBean xaDataSource = new AtomikosDataSourceBean();
xaDataSource.setXaDataSource(mysqlXaDataSource);
xaDataSource.setUniqueResourceName("test2DataSource");
xaDataSource.setMinPoolSize(testConfig.getMinPoolSize());
xaDataSource.setMaxPoolSize(testConfig.getMaxPoolSize());
xaDataSource.setMaxLifetime(testConfig.getMaxLifetime());
xaDataSource.setBorrowConnectionTimeout(testConfig.getBorrowConnectionTimeout());
xaDataSource.setLoginTimeout(testConfig.getLoginTimeout());
xaDataSource.setMaintenanceInterval(testConfig.getMaintenanceInterval());
xaDataSource.setMaxIdleTime(testConfig.getMaxIdleTime());
xaDataSource.setTestQuery(testConfig.getTestQuery());
return xaDataSource;
}
@Bean(name = "test2SqlSessionFactory")
public SqlSessionFactory testSqlSessionFactory(@Qualifier("test2DataSource") DataSource dataSource)
throws Exception {
SqlSessionFactoryBean bean = new SqlSessionFactoryBean();
bean.setDataSource(dataSource);
return bean.getObject();
}
@Bean(name = "test2SqlSessionTemplate")
public SqlSessionTemplate testSqlSessionTemplate(
@Qualifier("test2SqlSessionFactory") SqlSessionFactory sqlSessionFactory) throws Exception {
return new SqlSessionTemplate(sqlSessionFactory);
}
}
// 扫描多个包{} 扫描单个包""
@ComponentScan(basePackages = "com.fz")
// 自动扫描
@EnableAutoConfiguration
@EnableConfigurationProperties(value = {DBConfig1.class, DBConfig2.class})
public class App {
public static void main(String[] args) {
SpringApplication.run(App.class,args);
}
}
log4j.rootLogger=INFO,Console,File
log4j.appender.Console=org.apache.log4j.ConsoleAppender
log4j.appender.Console.Target=System.out
log4j.appender.Console.layout = org.apache.log4j.PatternLayout
log4j.appender.Console.layout.ConversionPattern=[%p] [%d{yyyy-MM-dd HH\:mm\:ss}][%c - %L]%m%n
log4j.appender.File = org.apache.log4j.RollingFileAppender
log4j.appender.File.File = E:/logs/logs.log
log4j.appender.File.MaxFileSize = 10MB
log4j.appender.File.Threshold = ALL
log4j.appender.File.layout = org.apache.log4j.PatternLayout
log4j.appender.File.layout.ConversionPattern =[%p] [%d{yyyy-MM-dd HH\:mm\:ss}][%c - %L]%m%n
在pom文件中去除springboot的logging,添加log4j,因为自带的logging不启效果
<!--排除springboot自带的logging日志-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-logging</artifactId>
</exclusion>
</exclusions>
</dependency>
<!--重新导入logging-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-log4j</artifactId>
<version>1.3.8.RELEASE</version>
</dependency>
@Controller
public class Log4jController {
Logger logger =Logger.getLogger(Log4jController.class);
@RequestMapping("logger")
public String logger(String uname,String upass){
logger.info("====="+"uname:"+uname+"upass"+upass);
return "ok";
}
}
<!-- 使用AOP统一处理Web请求日志 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
@Aspect
@Component
// 使用AOP统一处理Web请求日志
public class WebLogAspect {
private Logger logger = Logger.getLogger(getClass());
@Pointcut("execution(public * com.fz.web..*.*(..))")
public void webLog() {
}
@Before("webLog()")
public void doBefore(JoinPoint joinPoint) throws Throwable {
// 接收到请求,记录请求内容
ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
HttpServletRequest request = attributes.getRequest();
// 记录下请求内容
logger.info("---------------request----------------");
logger.info("URL : " + request.getRequestURL().toString());
logger.info("HTTP_METHOD : " + request.getMethod());
logger.info("IP : " + request.getRemoteAddr());
Enumeration<String> enu = request.getParameterNames();
while (enu.hasMoreElements()) {
String name = (String) enu.nextElement();
logger.info("name:" + name + "value" + request.getParameter(name));
}
}
@AfterReturning(returning = "ret", pointcut = "webLog()")
public void doAfterReturning(Object ret) throws Throwable {
logger.info("---------------response----------------");
// 处理完请求,返回内容
logger.info("RESPONSE : " + ret);
}
}
server.port=8888
server.context-path=/test
注意冒号后的只能用空格,不能用tab
server:
port: 8090
context-path: /test-yml
这里Build选项是第一次构建jar,Rebuild是修改后重新构建jar,clean是删除jar
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<version>2.2.5.RELEASE</version>
<optional>true</optional>
</dependency>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>2.2.5.RELEASE</version>
<configuration>
<fork>true</fork>
<addResources>true</addResources>
</configuration>
</plugin>
</plugins>
</build>
设置自动编译:File-Settings-Compiler-Build Project automatically
找到选项Compiler autoMake allow when app running打勾
菜单栏选择 Run->Edit Configurations…
梦想也许在今天无法实现,但重要的是,它在你心里。重要的是,你一直在努力,加油!!!