SpringBoot从入门到高级

本文涉及的产品
云数据库 Redis 版,社区版 2GB
推荐场景:
搭建游戏排行榜
云数据库 RDS MySQL Serverless,0.5-2RCU 50GB
简介: 前言:学习SpringBoot不应该直接就是开始使用SpringBoot,如果直接拿来用肯定会有很多人不是很明白特别刚开始入门的,当然官网上也有快速上手的教程但是官网上跨度有点大,在这片文章中为主要是从以前没使用SpringBoot之前我们怎么做的以...

前言:学习SpringBoot不应该直接就是开始使用SpringBoot,如果直接拿来用肯定会有很多人不是很明白特别刚开始入门的,当然官网上也有快速上手的教程但是官网上跨度有点大,在这片文章中为主要是从以前没使用SpringBoot之前我们怎么做的以及慢慢的引入SpringBoot,我希望通过自己的体会和认识来帮助更多朋友来学习SpringBoot

目录结构

  • SpringJavaConfig
    • @Configuration和基础的@Bean
    • @ComponentScan和测试
    • @Bean标签属性详解
    • @Import标签
    • XML和Annotation的混用
    • 其他常用标签(@PropertySource和@PropertySources,@Profile和@ActiveProfile)
  • 第一个HelloWorld
  • Springboot简介
  • Springboot基本使用
    • 应用构建
    • SpringApplication
    • 参数配置
  • 日志
    • 默认日志
    • 外部日志框架LogBack
  • Springboot开发WEB应用
    • 静态资源
    • Freemarker集成
    • 错误处理
    • mybatis集成
    • 事务处理
    • 文件上传

首先了解 Spring Java Config(Spring的java配置)

(在这里我们先以最原始的方式来创建项目和测试)
创建一个Maven项目添加依赖和加入配置文件application.xml
SomeBean.java

public class SomeBean {}

application.xml

    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xmlns:tx="http://www.springframework.org/schema/tx"
       xsi:schemaLocation="
            http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
            http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
            http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd
            http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd">
        <bean id="someBean" class="com.jd.javaconfig.SomeBean"></bean>
     </beans>

这个是基于XML配置的方式
MyTest.java

public class MyTest {
@Test
public void test1(){
    ApplicationContext ctx=new ClassPathXmlApplicationContext("application.xml");
    SomeBean sb = ctx.getBean(SomeBean.class);
    System.out.println(sb);
}
上面是我们最简单的一个Spring  Demo

下面通过标签来配置Spring
OtherBean.java

public class OtherBean {}

下面我们写了一个方法返回一个SomeBean的对象我们要告诉Spring这个方法是Spring帮我们管理的bean通过@Bean标签

AppConfig .java

    // 作为Spring的主配置文件
    //@Configuration标签表示这个类可被Spring识别的配置对象的类,只有有这个标记的标签的类才能使用@Bean标签作用于对应的方法上面
    @Configuration
    public class AppConfig {
    //@Bean标签表示让Spring帮我们管理bean
    @Bean
    public SomeBean someBean(){
        return new SomeBean();
    }
    @Bean
    public OtherBean otherBean(){
        return new  OtherBean();
    }
    }

不像上一个demo,这个是基于AnnotationConfigApplicationContext来配置的
MyTest.java

@Test
public void test() {
    ApplicationContext ctx = new AnnotationConfigApplicationContext(AppConfig.class);
    SomeBean sb = ctx.getBean(SomeBean.class);
    OtherBean ob = ctx.getBean(OtherBean.class);
    System.out.println(sb);
    System.out.println(ob);
}

到这里我们就已经学完了两个重要的标签 @Configuration和@Bean,
@Configuration标签表示这个类可被Spring识别的配置对象的类,只有有这个标记的标签的类才能使用
@Bean标签作用于对应的方法上面
@Bean(destroyMethod = "destory", initMethod = "init")也可以通过这样的写法来配置bean的初始化方法和销毁方法

@Component标签
@Component
public class SomeBean {}

@Component
public class OtherBean {}

//@Configuration标签表示这个类可被Spring识别的配置对象的类,这有有这个标记的标签的类才能使用@Bean标签作用于对应的方法上面
// @ComponentScan:开启组件自动扫描;默认情况下,它会扫描当前类所在的包及其子包中的所有标签对象加载到Spring容器
@Configuration
@ComponentScan(basePackages="com.jd.scan")
public class AppConfig {}

public class MyTest {
@Test
public void test() {
    ApplicationContext ctx = new AnnotationConfigApplicationContext(AppConfig.class);
    SomeBean sb = ctx.getBean(SomeBean.class);
    OtherBean ob = ctx.getBean(OtherBean.class);
    System.out.println(sb);
    System.out.println(ob);
}
}

@ComponentScan:开启组件自动扫描;默认情况下,它会扫描当前类所在的包及其子包中的所有标签对象加载到Spring容器

对象的关系引用

在someBean里依赖一个otherBean

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = AppConfig.class)
public class MyTest {
@Autowired
@Qualifier("somebean")
private SomeBean somebean;
  //@Autowired
 //@Qualifier("somebean2")
 //private SomeBean somebean2;
@Test
public void test() {
    System.out.println(somebean.getOtherBean());
 //System.out.println(somebean2.getOtherBean());
}
}

   @Configuration
    public class AppConfig {
//第一种方式(对象的注入)
@Bean(destroyMethod = "destory", initMethod = "init")
public SomeBean somebean(OtherBean otherbean) {
    SomeBean sBean = new SomeBean();
    sBean.setOtherBean(otherbean);
    return sBean;
  }
//第二种方式
  //    @Bean
 // public SomeBean somebean2() {
 //     SomeBean sBean = new SomeBean();
  //        sBean.setOtherBean(otherbean());
  //        return sBean;
 // }

@Bean
public OtherBean otherbean() {
    return new OtherBean();
}
}

使用try来关闭容器

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes=AppConfig.class)
public class MyTest2 {
@Test
public void test() {
    try (AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class)) {
        SomeBean sb = context.getBean(SomeBean.class, "somebean");
        System.out.println(sb);
    }
}
}
@import标签
public class MyDataSource {}

public class MyRedisTemplate {}

@Configuration
public class ConfigRedis {
@Bean
public MyRedisTemplate myRedisTemplate(){
    return new MyRedisTemplate();
}
}

@Configuration
public class ConfigDataSource {
@Bean
public MyDataSource myDatasource(){
return new MyDataSource();  
}
}

AppConfig这个类因为打上@Configuration标签所以是主配置文件,他需要连接着两个类ConfigDataSource.class,ConfigRedis.class 只需要使用@Import 标签就可以表示导入类

@Configuration
@Import({ConfigDataSource.class,ConfigRedis.class})
public class AppConfig {
}

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = AppConfig.class)
public class MyTest {
@Autowired
private MyDataSource datasource;
@Autowired
private MyRedisTemplate redisTemplate;
@Test
public void test(){
    System.out.println(datasource);
    System.out.println(redisTemplate);
}
}
@importresource标签 在javaconfig中混用xml

OtherBean.java

public class OtherBean {}

application.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop" xmlns:jee="http://www.springframework.org/schema/jee"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="
        http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
        http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee.xsd
        http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd
        http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd">
<bean id="otherbean" class="com.jd.importresource.OtherBean" /> 
</beans>

SomeBean.java

@Setter@Getter
public class SomeBean {

private OtherBean otherBean;

public void init() {
    System.out.println("===init====");
}

public void destory() {
    System.out.println("====destory=====");
}
}

AppConfig.java

@Configuration
// @importresource标签来在javaconfig中混用xml config
@ImportResource("classpath:com/jd/importresource/application.xml")
public class AppConfig {
@Bean(destroyMethod = "destory", initMethod = "init")
public SomeBean somebean(OtherBean otherbean) {
    SomeBean sBean = new SomeBean();
    sBean.setOtherBean(otherbean);
    return sBean;
}
}

MyTest.java

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = AppConfig.class)
 public class MyTest {
@Autowired
private SomeBean somebean;

@Test
public void test() {
    System.out.println(somebean.getOtherBean());
}
}

@ImportResource("classpath:com/jd/importresource/application.xml") 通过使用@ImportResource标签来导入资源

引入外部的.properties资源文件(2种方式)

db.properties

db.username=username
db.password=password
db.url=url
db.driverClass=driverClass

MyDatasource .java

@Setter@Getter@ToString@AllArgsConstructor
public class MyDatasource {

private String username;
private String password;
private String url;
private String driverClass;
}

第一种方式

AppConfig .java

@Configuration
 // @PropertySource代表引入外部的.properties资源文件
 //@PropertySources嵌套@PropertySource引入多个外部资源文件

@PropertySource("classpath:com/jd/properties/db.properties")
public class AppConfig {

@Value("${db.username}")
private String username;
@Value("${db.password}")
private String password;
@Value("${db.url}")
private String url;
@Value("${db.driverClass}")
private String driverClass;

@Bean
public static PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer (){
    return new PropertySourcesPlaceholderConfigurer();
}
@Bean
public MyDatasource datasource(){
    return new MyDatasource(username, password, url, driverClass);

}
}

MyTest .java

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = AppConfig.class)
public class MyTest {

@Autowired
private MyDatasource datasource;

@Test
public void test() {
    System.out.println(datasource);
}
}

第二种方式

@Configuration
 // @PropertySource代表引入外部的.properties资源文件
 //@PropertySources嵌套@PropertySource引入多个外部资源文件

@PropertySource("classpath:com/jd/properties/db.properties")
public class AppConfig {
 //Environment代表spring的环境,在环境里面只有两种东西: 1,读入的外部资源文件(properties); 2,profile
 
@Autowired
private Environment env;

@Bean
public MyDatasource datasource() {
    return new MyDatasource(env.getProperty("db.username"), env.getProperty("db.password"),
            env.getProperty("db.url"), env.getProperty("db.driverClass"));
}
}
profile

db-dev.properties db-profile.properties

db.username=username
db.password=password
db.url=url
db.driverClass=driverClass  

MyDatasource.java

@Setter@Getter@ToString@AllArgsConstructor
public class MyDatasource {

private String username;
private String password;
private String url;
private String driverClass;
}

//生产环境的配置对象
@Configuration
@Profile("pro")
@PropertySource("classpath:com/jd/profile/db-pro.properties")
public class ConfigPro {

@Value("${db.username}")
private String username;
@Value("${db.password}")
private String password;
@Value("${db.url}")
private String url;
@Value("${db.driverClass}")
private String driverClass;
@Bean
public MyDatasource datasource() {
    return new MyDatasource(username, password, url, driverClass);
}
}

//针对开发环境的配置
@Configuration
@Profile("dev")
@PropertySource("classpath:com/jd/profile/db-dev.properties")
public class ConfigDev {

@Value("${db.username}")
private String username;
@Value("${db.password}")
private String password;
@Value("${db.url}")
private String url;
@Value("${db.driverClass}")
private String driverClass;

@Bean
public MyDatasource datasource() {
    return new MyDatasource(username, password, url, driverClass);
}
}

AppConfig .java

@Configuration
@Import({ ConfigDev.class, ConfigPro.class })
public class AppConfig {

@Bean
public static PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer() {
    return new PropertySourcesPlaceholderConfigurer();
}
}

MyTest.java

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = AppConfig.class)
@ActiveProfiles("dev")
public class MyTest {
@Autowired
private MyDatasource datasource;
@Test
public void test() {
    System.out.println(datasource);
}
}

到这里我们把需要回顾和拓展的知识都有一定加深下面我们开始正式学习SpringBoot

SpringBoot的HelloWorld

先演示在地址栏访问loclhost:8080/hello返回字符串hello world

1.在pom.xml文件中加入依赖
 <parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>1.5.6.RELEASE</version>
</parent>

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
</dependencies>
2.创建一个Controller:

HelloSpringBoot.java

@SpringBootApplication
@Controller
public class HelloSpringBoot {
@RequestMapping("hello")
@ResponseBody
public String hello() {
    return "hello world";
}

public static void main(String[] args) {
    SpringApplication.run(HelloSpringBoot.class, args);
}
}
img_53e94a58a11afe1ee25607686ff4353d.png
Snip20170910_30.png
3.运行 main方法

. ____ _ __ _ _
/\ / ' __ _ () __ __ _ \ \ \
( ( )_
_ | '_ | '| | ' / ` | \ \ \
\/ )| |)| | | | | || (| | ) ) ) )
' |____| .
|| ||| |_, | / / / /
=========|
|==============|/=////
:: Spring Boot :: (v1.5.6.RELEASE)

img_ff73d362afcf0f74e23275ccb97773cb.png

分析:
1,继承spring-boot-starter-parent,引入基本的依赖管理配置;
2,引入spring-boot-starter-web,自动引入了springweb相关的包;
3,@SpringBootApplication:这个注解告诉springboot自动的去完成相关配置,包括基础类的加载,bean的扫描等等,这个后面详细介绍;简单理解为这个标签为我们的应用配置完成了很多基本功能;
4,SpringApplication.run:这个是springboot为我们提供的最大的区别,在于springboot不再是一个web应用,需要我们自己去打包,部署,启动tomcat,springboot默认把tomcat打包到应用中,我们可以以正常的运行jar的方式来运行springboot应用;

应用独立运行:
1,pom文件中添加:

<build>
    <plugins>
        <plugin>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-maven-plugin</artifactId>
        </plugin>
    </plugins>
</build>

2,使用package命令打包,在命令行中使用java -jar xx.jar运行;注意,一定要引入spring-boot-maven-plugin之后运行package打包才能正常运行;

img_2651f0ed6747918e612b82ca9606d261.png

3,直接使用maven插件:spring-boot:run运行;

Springboot的优缺点
1. 创建独立的Spring应用程序
2. 嵌入的Tomcat,无需部署WAR文件
3. 简化Maven配置
4. 自动配置Spring
5. 提供生产就绪型功能,如日志,健康检查和外部配置
6. XML没有要求配置
7. 非常容易和第三方框架集成起来;
缺点:
1,版本更新较快,可能出现较大变化;
2,因为约定大于配置,所以经常会出现一些很难解决的问题;

1,Springboot应用的基本结构:通过start.spring.io(网址)创建一个springboot应用:
2,spring-boot-starter-parent简介:
1,包含了常用版本属性;
要修改java编译版本,可以修改: <properties> <java.version>1.7</java.version> </properties>
2,包含了常用的dependenceManagement;
3,Springboot非常优秀的地方在于提供了非常多以spring-boot-starter-开头的开箱即用的工具包,常见工具包有以下一些:
spring-boot-starter:核心的工具包,提供了自动配置的支持,日志和YAML配置支持;
spring-boot-starter-activemq:针对快速集成ActiveMQ的工具包;
spring-boot-starter-aop:提供了快速集成SpringAOP和AspectJ的工具包;
spring-boot-starter-data-redis:提供了快速集成Redis和Jedis的工具包;
spring-boot-starter-freemarker:提供了快速集成Freemarker的工具包;
spring-boot-starter-mail:提供了快速集成邮件发送的工具包;
spring-boot-starter-test:提供了对Springboot应用的测试工具包;
spring-boot-starter-web:提供了对web开发的工具包,包括基于SpringMVC的RESTful应用开发,内置的tomcat服务器等;
spring-boot-starter-actuator:提供了对生产环境中应用监控的工具包;
spring-boot-starter-logging:提供了对日志的工具包,默认使用Logback;
3,Springboot应用的热部署:
除了使用JRebel来实现热部署,还可以使用Springboot提供的spring-boot-devtools包来完成Springboot应用热部署;
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<optional>true</optional>
</dependency>
1)原理:
SpringBoot重启是reload重启,通过监控classpath的变化,如果classpath中的文件发生变化,即触发重启。springboot通过两个classpath来完成reload,一个basic classloader中加载不变的类,一个restart classloader中加载classpath中的类,重启的时候,restart classloader中的类丢弃并重新加载;
2)排除资源:
spring.devtools.restart.exclude=static/
,templates/*
spring.devtools.restart.additional-exclude=public/** (处理默认配置排除之外的)
spring.devtools.restart.enabled=false (禁用自动重启)

@SpringBootApplication简介:
@SpringBootApplication由三个主要的标签构成:@SpringBootConfiguration,@EnableAutoConfiguration,@ComponentScan
1)@SpringBootConfiguration:本质就是一个@Configuration,代表这是spring容器的主配置类;
2)@EnableAutoConfiguration:开启自动配置,Springboot使用这个标签自动的把内置的符合条件的@Configuration类加载进入应用;
可以查看spring-boot-autoconfigure包中的META-INF/spring.factories文件中的配置项(原理,由@EnableAutoConfiguration标签引入的AutoConfigurationImportSelector类中,使用Spring的SpringFactoriesLoader类实现加载)
3)@ComponentScan:自动扫描;

SpringApplication简介:
1,SpringApplication类提供了一个标准化的应用执行流程,并在这个执行流程中为我们提供了一些应用扩展点;但大部分情况下,我们只需要使用它就可以了;
2,SpringBoot提供了一些扩展点,比如修改Banner:
1)创建一个banner.txt
2)设置banner,在配置文件中使用spring.main.banner-mode=off
3,可以通过创建对象的方式来运行SpringApplication

img_ab10a84b273462d3ee355f38d91a0249.png
 2)通过builder完成:
img_be57ca93f8348020d6d7325148cf4776.png

4,参数的处理:在应用启动过程中,可以通过启动参数给应用传递一些额外的参数来控制应用的运行;
1,在main方法中可以直接使用传入的参数;
2,可以任何类中直接通过@Autowired注入一个ApplicationArguments对象;

img_04df30620e9b85cbdf8f9f764fed4012.png
Springboot中的日志

为什么要用日志?
1.比起System.out.println,日志框架可以把日志的输出和代码分离;
2.日志框架可以方便的定义日志的输出环境,控制台,文件,数据库;
3.日志框架可以方便的定义日志的输出格式和输出级别;

Springboot的默认日志使用:
1.Springboot默认已经开启日志;默认的日志格式为:时间 日志级别 PID 线程名称 日志类 日志说明
2.Springboot的日志区别系统日志和应用日志;
3.Springboot推荐使用Logback作为日志框架(common-logging,java-logging,log4j,logback,slf4j)

Logback使用方法(推荐使用logback自己的配置文件)
1.springboot默认支持logback.xml或者logback-spring.xml,推荐使用logback-spring.xml,springboot会增加额外功能;
2.可以通过logging.config=classpath:mylogback.xml指定自己的logback配置文件(不推荐);
3.一个典型的logback配置文件:

img_6b460d6ee669875b4aa901914ed36a23.png

Logback使用介绍:
1,<configuration>:Logback配置根元素
属性包括:
1,scan: 当此属性设置为true时,配置文件如果发生改变,将会被重新加载,默认值为true。
2,scanPeriod: 设置监测配置文件是否有修改的时间间隔,如果没有给出时间单位,默认单位是毫秒。当scan为true时,此属性生效。默认的时间间隔为1分钟。
3,debug: 当此属性设置为true时,将打印出logback内部日志信息,实时查看logback运行状态。默认值为false。
子元素:
<contextName>:上下文名字;
<property>:定义属性,可以使用${}在配置文件中使用;

2,<appender>:在logback中是用于具体记录日志的组件,可以用来配置日志记录方式,日志记录格式等;
属性包括:
name:appender的名字,用于下面在配置日志的时候指定;
class:使用到的appender类;

常见的appender:
1,ch.qos.logback.core.ConsoleAppender:输出到控制台;
2,ch.qos.logback.core.FileAppender:输出到文件;
3,ch.qos.logback.core.rolling.RollingFileAppender:输出到文件,可以配置滚动策略,当日志达到某个条件之后分文件记录;
4,还有其他的appender,比如写到数据库等;

<appender>元素的基本格式:
<appender name="" class="">
<encoder>
<pattern>...</pattern>
</encoder>
<otherconfig></otherconfig>
</appender>

<encoder>元素用来规定日志的输出格式,所有表达式都以%开始表示接下来是一个特殊标识符
常见标识符:
1,%logger{n}:输出Logger对象类名,n代表长度;
2,%class{n}:输出所在类名,
3,d{pattern}或者date{pattern}:输出日志日期,格式同java;
4,L/line:日志所在行号;
5,m/msg:日志内容;
6,method:所在方法名称;
7,p/level:日志级别;
8,thread:所在线程名称;

常见的appender使用:
1)ConsoleAppender输出到控制台,子元素:
<encoder>:日志格式化
<target>:System.out(默认)或者System.err

img_1be0817d3f1aee8b95f2f1225c24a090.png
图片.png

2)FileAppender输出到文件,子元素:
file:被写入的文件名,可以是相对目录,也可以是绝对目录,如果上级目录不存在会自动创建,没有默认值。
append:文件结尾,如果是 false,清空现存文件,默认是true。
encoder:对日志进行格式化

img_649e12a365777b4a8347ee66655827a3.png
图片.png

3)RollingFileAppender输出到文件,可以设置文件滚动(分割)条件,子元素:
append:如果是 true,日志被追加到文件结尾,如果是 false,清空现存文件,默认是true。
rollingPolicy:滚动策略,涉及文件移动和重命名。
常用滚动策略:
ch.qos.logback.core.rolling.TimeBasedRollingPolicy:按照时间控制来控制记录文件;
fileNamePattern:文件名称格式,以%d{pattern};
maxHistory:
可选节点,控制保留的归档文件的最大数量,超出数量就删除旧文件。(以文件最小时间为准)

img_0217dfcdf536bfe9795b55bdf105995f.png
图片.png

SizeAndTimeBasedRollingPolicy:按照时间和大小控制记录文件;
fileNamePattern:文件名称格式,可以使用%i来控制索引编号;
maxFileSize:这是活动文件的大小,默认值是10MB
maxHistory:
可选节点,控制保留的归档文件的最大数量,超出数量就删除旧文件。(以文件最小时间为准)

img_a4e73aa514f75e77b9a37bbf91f2256b.png

下面我们来通过一个小Demo来说明
application.properties

db.username=username
db.password=password
db.url=url
springboot.randomlong=${random.long[1,100]}

MyDatasource.java

@Setter@Getter
public class MyDatasource {
private String username;
private String password;
private String url;
}

HelloController.java

@Controller
public class HelloController {
private static final Logger logger = LoggerFactory.getLogger(HelloController.class);
@Autowired
private MyDatasource datasource;
@RequestMapping("hello")
@ResponseBody
public String hello() {
    //error<warn<info<debug<trace
    logger.info("转出成功");
    if (logger.isDebugEnabled()) {
        logger.debug("准备转出10000");
    }
    if (logger.isTraceEnabled()) {
        logger.trace("连接数据库");
        logger.trace("查询账户余额为12000");
    }
    if (logger.isDebugEnabled()) {
        logger.debug("检查转出账户...");
        logger.debug("转出检查成功");
        logger.debug("执行转出10000");
        logger.debug("转出成功");
    }
    logger.info("转入成功");
    System.out.println(datasource);
    return "hello world";
}
}

App.java

@SpringBootApplication
public class App {
@Bean
@ConfigurationProperties(prefix = "db")
public MyDatasource datasource() {
    return new MyDatasource();
}
public static void main(String[] args) {
    new SpringApplicationBuilder(App.class).bannerMode(Mode.OFF).build().run(args);
}

}


logback日志的xml配置文件

logback-spring.xml

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
    <encoder>
        <pattern>%-4relative [%thread] %-5level %logger{35} - %msg %n</pattern>
    </encoder>
    <target>System.out</target>
</appender>

<appender name="FILE" class="ch.qos.logback.core.FileAppender">
    <encoder>
        <pattern>%-4relative [%thread] %-5level %logger{35} - %msg %n</pattern>
    </encoder>
    <file>springbootdemo.log</file>
    <append>true</append>
</appender>

<appender name="ROLLFILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
    <encoder>
        <pattern>%-4relative [%thread] %-5level %logger{35} - %msg %n</pattern>
    </encoder>
    <append>true</append>
    <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
        <fileNamePattern>springboot.%d{yyyy-MM-dd}.log</fileNamePattern>
        <maxHistory>30</maxHistory>
    </rollingPolicy>
</appender>

<appender name="SIZEROLLFILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
    <encoder>
        <pattern>%-4relative [%thread] %-5level %logger{35} - %msg %n</pattern>
    </encoder>
    <append>true</append>
    <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
        <fileNamePattern>springboot.%d{yyyy-MM-dd}.%i.log</fileNamePattern>
        <maxFileSize>10MB</maxFileSize>
        <maxHistory>30</maxHistory>
    </rollingPolicy>
</appender>

<root level="DEBUG">
    <appender-ref ref="CONSOLE" />
    <appender-ref ref="SIZEROLLFILE" />
</root>
</configuration>

Springboot的WEB开发

Springmvc和freemarker的集成

添加依赖
引入spring-boot-starter-freemarker;

    <dependency>
        <groupId>org.freemarker</groupId>
        <artifactId>freemarker</artifactId>
        <version>2.3.23</version>
    </dependency>

web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" id="WebApp_ID" version="3.0">
<display-name>freemarker</display-name>
  <!-- SpringMVC前端控制器 -->
   <servlet>
<servlet-name>springMVC</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>classpath:application-web.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
  </servlet>
  <servlet-mapping>
<servlet-name>springMVC</servlet-name>
<url-pattern>*.do</url-pattern>
</servlet-mapping>
  <!-- 编码过滤器 -->
  <filter>
<filter-name>encodingFilter</filter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
<init-param>
    <param-name>encoding</param-name>
    <param-value>utf-8</param-value>
</init-param>
  </filter>
  <filter-mapping>
<filter-name>encodingFilter</filter-name>
<url-pattern>/*</url-pattern>
  </filter-mapping>
  <welcome-file-list>
<welcome-file>index.do</welcome-file>
  </welcome-file-list>
</web-app>

application.xml

<!--开启注解扫描 -->
<context:component-scan base-package="com.xmg" />

application-web.xml

<import resource="classpath:application.xml" />
<!-- 支持springmvc的注解驱动 -->
<mvc:annotation-driven />
<!-- 配置一个freemarker的配置对象 -->
<bean
class="org.springframework.web.servlet.view.freemarker.FreeMarkerConfigurer">
    <!-- 配置freemarker的文件编码 -->
    <property name="defaultEncoding" value="UTF-8" />
    <!-- 配置freemarker寻找模板的路径 -->
    <property name="templateLoaderPath" value="/WEB-INF/views/" />
</bean>
<!-- 配置一个针对于freemarker的viewresovler -->
<bean id="viewResolver"
class="org.springframework.web.servlet.view.freemarker.FreeMarkerViewResolver">
    <!-- 配置逻辑视图自动添加的后缀名 -->
    <property name="suffix" value=".ftl" />
    <!-- 配置视图的输出HTML的contentType -->
    <property name="contentType" value="text/html;charset=UTF-8" />
</bean>

FreemarkerController.java

@Controller
public class FreemarkerController {

@RequestMapping("hello")
public String hello(Model model){
    model.addAttribute("msg","hello 我是 freemarker");
    return "hello";
}
}

Springboot和freemarker的集成

添加依赖

<properties>
    <java.version>1.8</java.version>
</properties>
<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>1.5.6.RELEASE</version>
</parent>
<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-freemarker</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-devtools</artifactId>
    </dependency>
</dependencies>
<build>
    <plugins>
        <plugin>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-maven-plugin</artifactId>
        </plugin>
    </plugins>
</build>

创建模板

img_722b8dd95fb6cdaf21454a31187176df.png
Snip20170910_27.png
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
<h1>${msg}</h1>
</body>
</html>

FreemarkerController.java

@Controller
public class FreemarkerController {

@RequestMapping("hello")
public String hello(Model model){
    model.addAttribute("msg","hello 我是 freemarker");
    return "hello";
}
}

App.java

//运行main
@SpringBootApplication
public class App {
public static void main(String[] args) {
    SpringApplication.run(App.class, args);
}
}

访问网页

img_0bd9375ffec6260f0e2c63ff8d9e590e.png

Springboot对freemarker的配置:
1,spring.freemarker.enabled=true:是否开启freemarker支持;
2,spring.freemarker.allow-request-override:是否允许request中的属性覆盖model中同名属性;默认false;
3,spring.freemarker.allow-session-override:是否允许session中的属性覆盖model中同名属性;默认false;
4,spring.freemarker.cache:是否支持模板缓存;默认false;
5,spring.freemarker.charset=UTF-8:模板编码
6,spring.freemarker.content-type=text/html:模板contenttype;
7,spring.freemarker.expose-request-attributes:是否开启request属性expose,默认false;
8,spring.freemarker.expose-session-attributes:是否开启session属性expose,默认false;
9,spring.freemarker.expose-spring-macro-helpers:是否开启spring的freemarker宏支持;默认为false;
10,spring.freemarker.prefer-file-system-access:默认为true,支持实时检查模板修改;
11,spring.freemarker.prefix:加载模板时候的前缀;
12,spring.freemarker.settings.*:直接配置freemarker参数
13,spring.freemarker.suffix:模板文件后缀;
14,spring.freemarker.template-loader-path=classpath:/templates/:模板加载地址

一般情况下我们会把以下配置加入进去的 系统会自动读取

application.properties

spring.freemarker.charset=UTF-8
spring.freemarker.content-type=text/html;charset=UTF-8
spring.freemarker.expose-session-attributes=true

Springboot错误统一处理(@ControllerAdvice)

1).@ControllerAdvice
通过使用@ControllerAdvice定义统一的异常处理类,而不是在每个Controller中逐个定义。@ExceptionHandler用来定义函数针对的异常类型。


GlobalExceptionHandler.java

@ControllerAdvice
public class GlobalExceptionHandler {
    //@ExceptionHandler(logicException.class)也可以分情况处理异常
@ExceptionHandler(Exception.class)
public String errorHandler(Model model, Exception e) {
    model.addAttribute("error", e.getMessage());
    //到模板找到err.ftl将错误信息显示出来
    return "err";
    }
}

2)统一的异常页面
1,SpringBoot默认情况下,把所有错误都重新定位到/error这个处理路径上,由BasicErrorController类完成处理;
2,SpringBoot提供了默认的替换错误页面的路径:
1,静态错误页面默认结构:(按照这个目录结构放置错误页面报错时就会自动找到相应的界面)
src/ resources/public/error/404.html
src/ resources/public/error/ 403.html
src/ resources/public/error/ 5xx.html

2,也可以使用模板页面:
src/resources/templates/error/5xx.ftl
该路径方式是通过ErrorMvcAutoConfiguration中的DefaultErrorViewResolver完成的;

Springboot集成DataSource和mybatis

集成DataSource方式1:
先加入依赖

<!-- druid -->
    <dependency>
        <groupId>com.alibaba</groupId>
        <artifactId>druid</artifactId>
        <version>1.0.14</version>
    </dependency>
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <scope>runtime</scope>
    </dependency>

DatasourceController .java

@Controller
public class DatasourceController {
@Autowired
private DataSource dataSource;

@RequestMapping("ds")
@ResponseBody
public String datasource() {
    return dataSource.getClass() + "  " + dataSource.toString();
}
}

运行main

@SpringBootApplication
public class App {
  //使用代码的方式实现datasource
@Bean
public DataSource dataSource() {
    DruidDataSource dataSource = new DruidDataSource();
    dataSource.setUrl("jdbc:mysql:///p2p");
    dataSource.setUsername("root");
    dataSource.setPassword("123456");
    dataSource.setDriverClassName("com.mysql.jdbc.Driver");
    dataSource.setInitialSize(5);
    dataSource.setMinIdle(5);
    return dataSource;
}
public static void main(String[] args) {
    SpringApplication.run(App.class, args);
}
}
img_53e94a58a11afe1ee25607686ff4353d.png

集成DataSource方式2:

使用配置文件的方式
application.properties

ds.username=root
ds.password=123456
ds.url=jdbc:mysql:///p2p
ds.driverClassName=com.mysql.jdbc.Driver
ds.initialSize=3

img_b00bba7fc6d08cda719f4f98343b874f.png

App.java

@Bean
@ConfigurationProperties(prefix = "ds")
public DataSource dataSource(Properties properties) throws Exception {
    return DruidDataSourceFactory.createDataSource(properties);
}

public static void main(String[] args) {
    SpringApplication.run(App.class, args);
}
img_019c43ce02cf4fec8c68dec66caa46a3.png

集成DataSource方式3:
修改配置文件

spring.datasource.username=root
spring.datasource.password=123456
spring.datasource.url=jdbc:mysql:///p2p
spring.datasource.driverClassName=com.mysql.jdbc.Driver
spring.datasource.initialSize=3
spring.datasource.type=com.alibaba.druid.pool.DruidDataSource
img_46bada6e960637de5af703d018213941.png
Springboot集成mybatis

mybatis集成:
使用mybatis-spring-boot-starter来完成mybatis集成;

1,引入依赖:

<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>1.3.0</version>
</dependency>

2,正常完成mapper接口和mapper.xml
3,mybatis-spring-boot-starter提供了以下配置(具体参考MyBatisProperties对象):

mybatis.configLocation:mybatis的配置文件地址;
mybatis.mapperLocations:映射文件地址;
mybatis.typeAliasesPackage:别名扫描包;

spring.datasource.username=root
spring.datasource.password=123456
spring.datasource.url=jdbc:mysql:///p2p
spring.datasource.driverClassName=com.mysql.jdbc.Driver
spring.datasource.initialSize=3
spring.datasource.type=com.alibaba.druid.pool.DruidDataSource
mybatis.mapperLocation=classpath:com/jd/springboot/mybatis3/*Mapper.xml
mybatis.typeAliasesPackage=com.jd.springboot.mybatis3

img_a489055376db8d1b2dc2c4151a1f5a6e.png

4,使用@MapperScan标签扫描mapper接口

@SpringBootApplication
@MapperScan(basePackages="com.jd.springboot.mybatis3")
 public class App {
public static void main(String[] args) {
    SpringApplication.run(App.class, args);
}
}
img_afb24aafcc032a19ac96d4c861dd04ac.png

事务处理

1,直接开启@EnableTransactionManagement注解;相当于在xml中配置<tx:annotation-driven/>

@SpringBootApplication
@MapperScan(basePackages="com.jd.springboot.demo.mybatis1.mapper")
@EnableTransactionManagement
public class App {
public static void main(String[] args) {
    SpringApplication.run(App.class, args);
}
}

如果在classpath中添加的是spring-boot-starter-jdbc,那么springboot自动创建DataSourceTranscationManager;

2,使用代码的方式:

@Bean
public PlatformTransactionManager transactionManager(DataSource dataSource) {
    return new DataSourceTransactionManager(dataSource);
}
s1,如果开启了@EnableTransactionManagement,只需要在service上面使用@Transactional即可;

2,使用xml配置
将事务相关配置抽取到XML中,使用importResource引入

1,引入aop

<dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-aop</artifactId>
    </dependency>

2,application-tx.xml

<tx:advice id="advice" transaction-manager="transactionManager">
    <tx:attributes>
        <tx:method name="list*" read-only="true" />
        <tx:method name="get*" read-only="true" />
        <tx:method name="query*" read-only="true" />
        <tx:method name="*" />
    </tx:attributes>
</tx:advice>

<aop:config>
    <aop:pointcut expression="execution(* com.jd.springboot.demo..service.*Service.*(..))"
        id="pointCut" />
    <aop:advisor advice-ref="advice" pointcut-ref="pointCut" />
</aop:config>

3,引入配置

@SpringBootApplication
@MapperScan(basePackages = "com.jd.springboot.demo.mybatis1.mapper")
@ImportResource(locations="classpath:application-tx.xml")
public class App {}
文件上传

1,仍然使用MultipartFile完成上传,Springboot是使用Servlet3中的Part对象完成上传,不是使用的fileupload;

2,上传相关配置:
spring.http.multipart.enabled=true:是否允许处理上传;

spring.http.multipart.maxFileSize=1MB:允许最大的单文件上传大小,单位可以是kb,mb;

spring.http.multipart.maxRequestSize=10MB:允许的最大请求大小;

3,也可以通过创建一个MultipartConfigElement类型的bean对上传进行配置:

@Bean
public MultipartConfigElement multipartConfigElement() {
    MultipartConfigFactory mcf = new MultipartConfigFactory();
    mcf.setMaxFileSize("1MB");
    mcf.setMaxRequestSize("10MB");
    return mcf.createMultipartConfig();
}

4,关于上传文件的处理:
因为应用是打成jar包,所以一般会把上传的文件放到其他位置,并通过设置
spring.resources.static-locations
来完成资源位置映射。

spring.resources.static-locations=classpath:/META-INF/resources/,
classpath:/resources/,
classpath:/static/,
classpath:/public/,
file:/Users/zhangshuai/devs/workspace/springboot-demo/upload/

SpringBoot总结

1.Maven中项目的继承依赖包的管理
第1:在父项目中添加dependency,子项目不需要添加
第2:在父项目中添加dependencyManagement标签,然后在添加dependency,子类对应的添加需要的dependency,但不需要写版本号
2.项目分为前台和后台两个应用的好处
从安全性考虑,后台是给公司管理人员用的,前台是给用户用的,访问的URL地址是不一样的,那这样的话前台用户就不可能通过各种尝试去访问后台管理系统了。
从性能方面考虑,项目分成前台和后台把请求分发到不同的服务器中,降低单个服务器的压力。
3.什么是乐观锁?乐观锁能解决什么问题?
乐观锁(Optimistic Lock): 顾名思义,就是很乐观,每次去拿数据的时候都认为别人不会修改,所以不会上锁,但是在更新的时候会判断一下在此期间别人有没有去更新这个数据
sql 上的体现:加版本/时间戳控制语句
update set version = version+1 ... from .... where version = xxx
解决的问题:数据并发问题(丢失更新/脏读)

4.事务是什么?事务有哪些特性?事务用来干什么?
(1)在数据库中,所谓事务是指一组逻辑操作单元,使数据从一种状态变换到另一种状态。
特性:

  1. 原子性(Atomicity)原子性是指事务是一个不可分割的工作单位,事务中的操作要么都发生,要么都不发生。
  2. 一致性(Consistency)事务必须使数据库从一个一致性状态变换到另外一个一致性状态。(数据不被破坏)
  3. 隔离性(Isolation)事务的隔离性是指一个事务的执行不能被其他事务干扰,即一个事务内部的操作及使用的数据对并发的其他事务是隔离的,并发执行的各个事务之间不能互相干扰(事务空间)。
  4. 持久性(Durability)持久性是指一个事务一旦被提交,它对(3)数据库中数据的改变就是永久性的,接下来的其他操作和数据库故障不应该对其有任何影响

为确保数据库中数据的一致性,数据的操纵应当是离散的成组的逻辑单元:当它全部完成时,数据的一致性可以保持,而当这个单元中的一部分操作失败,整个事务应全部视为错误,所有从起始点以后的操作应全部回退到开始状态。

5.Springboot应用的启动原理?
Springboot应用可以在一个主启动类中运行main方法或者打成jar包直接运行该jar包。
因为Springboot应用一定会在主启动类贴上一个@SpringBootApplication注解,该注解有包含很多配置,相当于spring的主配置文件,并且springboot应用内嵌web服务器,在我们启动应用时,会先根据@SpringBootApplication注解的配置初始化spring容器,并运行在内嵌的web服务器上。

6.@Configuration标签,@ComponentScan和@Bean标签各自的作用;
@Configuration:贴上该注解的类会被spring当成配置对象解析,可以在该配置对象创建bean注入到spring容器(相当于之前我们application.xml写的配置)
@ComponentScan:该注解与@Configuration:结合一起使用,可以扫描应用中的组件,比如贴了@Controller,@Service,@Component的类,并注入到spring容器中。此外,改注解可以填写扫描的包路径,如果不写的话就默认扫描贴了该注解的类所在的包及其子包。
@Bean:该注解结合@Configuration一起使用,作用是把贴上该注解的方法返回的类注入到spring容器中。
7.@ConfigurationProperties标签的作用;
该注解起到参数绑定的作用,可以非常方便的把配置文件的配置信息绑定到Properties对象上,并且可以控制到具体哪些前缀的配置信息需要绑定
8.日志级别:
error>warn>Info>debug>trace

我的博客即将入驻“云栖社区”,诚邀技术同仁一同入驻。

目录
相关文章
|
3月前
|
消息中间件 缓存 监控
spring boot 高级篇
spring boot 高级篇
101 1
|
3月前
|
Java 数据安全/隐私保护
SpringBoot - 优雅的实现【参数分组校验】高级进阶
SpringBoot - 优雅的实现【参数分组校验】高级进阶
37 0
|
7月前
|
Java 容器 Spring
SpringBoot高级 3
SpringBoot高级
36 1
|
7月前
|
NoSQL Java Redis
SpringBoot高级 2
SpringBoot高级
42 1
|
3月前
|
安全 Java 容器
SpringBoot - 优雅的实现【业务校验】高级进阶
SpringBoot - 优雅的实现【业务校验】高级进阶
67 0
|
3月前
|
Java Spring
SpringBoot - 优雅的实现【自定义参数校验】高级进阶
SpringBoot - 优雅的实现【自定义参数校验】高级进阶
41 0
|
3月前
|
JSON 前端开发 Java
SpringBoot - 优雅的实现【参数校验】高级进阶
SpringBoot - 优雅的实现【参数校验】高级进阶
44 0
|
4月前
|
Java API
SpringBoot【集成ElasticSearch 01】2种方式的高级客户端 RestHighLevelClient 使用(依赖+配置+客户端API测试源码)
SpringBoot【集成ElasticSearch 01】2种方式的高级客户端 RestHighLevelClient 使用(依赖+配置+客户端API测试源码)
74 0
|
4月前
|
前端开发 Java 测试技术
SpringBoot测试——高级配置
SpringBoot测试——高级配置
32 0
|
4月前
|
消息中间件 SQL Java
spring boot Rabbit高级教程(三)
spring boot Rabbit高级教程
65 0