Spring boot

入门示例

配置maven依赖

<?xml version="1.0" encoding="UTF-8"?>
<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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>xm</groupId>
    <artifactId>springbootTest</artifactId>
    <version>1.0-SNAPSHOT</version>

    <!-- 从Spring Boot继承默认值 -->
    <parent>
        <groupId> org.springframework.boot </groupId>
        <artifactId> spring-boot-starter-parent </artifactId>
        <version> 2.1.6.RELEASE </version>
    </parent>

    <!--添加Web应用程序的典型依赖项 -->
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
    </dependencies>

</project>

springboot对多种框架提供构建支持,称为starter pom,其中对于SpringMVC的支持是spring-boot-starter-web包,此外还有其他Starter Pom,可以进入parent依赖中查看,也可以在官网文档中查看

创建运行程序

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController //controller里面的方法都以json格式输出
@EnableAutoConfiguration//自动配置,不需要自己写xml文件
public class Example {

    @RequestMapping("/")
    String home(){
        return "Hello World!";
    }

    //程序入口
    public static void main(String[] args) {
        SpringApplication.run(Example.class,args);
    }
}

以父子模块的方式配置maven依赖的方式

首先需要创建父工程,通过父工程点击new module创建子工程,父工程的maven依赖如下:

<?xml version="1.0" encoding="UTF-8"?>
<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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>xm</groupId>
    <artifactId>SpringBoot_Parent</artifactId>
    <packaging>pom</packaging>
    <version>1.0-SNAPSHOT</version>
    <modules>
        <module>SpringBoot_Child1</module>
    </modules>

    <dependencyManagement>
        <dependencies>
            <!-- Override Spring Data release train provided by Spring Boot -->
            <dependency>
                <groupId>org.springframework.data</groupId>
                <artifactId>spring-data-releasetrain</artifactId>
                <version>Fowler-SR2</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-dependencies</artifactId>
                <version>2.1.6.RELEASE</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

</project>

子工程需要依赖父工程,并添加自己所需要的依赖:

<?xml version="1.0" encoding="UTF-8"?>
<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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>SpringBoot_Parent</artifactId>
        <groupId>xm</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>SpringBoot_Child1</artifactId>

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

</project>

注解

@EnableAutoConfiguration

该注解修饰的类将自动进行配置,不再需要xml配置文件,Spring-boot提供了多种自动配置的支持,可以在依赖包中的spring-boot-autoconfigure包中查看支持的所有依赖
如果要关闭某些自动配置,可以在注解中使用exclude属性,将不需要自动配置的类写上

//关闭Redis的自动配置
@EnableAutoConfiguration(exclude = RedisAutoConfiguration.class)

@SpringBootApplication

SpringBoot程序启动需要有一个入口,如果在每个控制器写一个入口会显得很麻烦,可以专门写一个启动类用于Spring启动,需要加上@EnableAutoConfiguration@ComponentScan注解,SpringBoot提供SpringBootApplication注解实现上面两个功能

package com.xm.app;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.ComponentScan;

//默认扫描当前包及以下的子包
//@EnableAutoConfiguration //SpringBoot自动配置
//@ComponentScan("com.xm.controller")//自动扫描
@SpringBootApplication(scanBasePackages = {"com.xm.controller"})
public class SpringApplications {
    public static void main(String[] args) {
        SpringApplication.run(SpringApplications.class,args);
    }
} 

@RestController

在控制器中,如果没有配置@ResponseBody注解,默认是进行跳转,如果一个控制器中的所有功能都是返回json,可以在类上加上@RestController注解,这样里面的所有方法就都是返回json格式,不再需要一个一个配置注解

SpringBoot同样支持RestFul风格,方式与SpringMVC一样

全局配置文件

如果不希望使用SpringBoot默认的配置,可以自己创建配置文件,文件名必须是application,后缀名可以是properties或者yml,并将文件放置在resources目录下

server:
  port: 8088
  servlet:
    context-path: /xm

这样重新启动时,端口号会改为8088,根目录会变成/xm

获取自定义属性的值

package com.xm.controller;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

@EnableAutoConfiguration
@Controller
public class BookController {

    @Value("${book.author}")//取值
    private String author;

    @Value("${book.name}")
    private String name;

    @RequestMapping("/bookInfo")
    @ResponseBody
    public String showInfo(){
        return author + ":" + name;
    }

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

类型安全的配置

如果配置文件中有多个属性,每次取值都用value注解比较繁琐,SpringBoot提供基于类型安全的配置方式:
通过@ConfigurationProperties指定前缀名,将文件中的属性与Bean相关联,同时Bean中的变量名要跟配置文件中的变量名一致,同时提供变量的get和set方法

package com.xm.controller;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

@EnableAutoConfiguration
@Controller
@ConfigurationProperties(prefix = "book")
public class BookController {

    private String author;

    private String name;

    public String getAuthor() {
        return author;
    }

    public void setAuthor(String author) {
        this.author = author;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    @RequestMapping("/bookInfo")
    @ResponseBody
    public String showInfo(){
        return author + ":" + name;
    }

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

}

Profile配置

当针对不同的环境需要使用不同的配置文件时,可以使用Profile配置,其格式为:application-*.properties(application-prod.properties(生产环境),application-sit.properties(测试环境),application-dev.properties(开发环境))或者yml格式。然后需要在application.properties文件中通过string.profiles.active=prod/dev/..来指定使用哪一个配置文件

# application-dev.yml
server:
  port: 9999


# application.yml

book:
  author: Toms
  name: SpringBoots

spring:
  profiles:
    active: dev

SpringBoot整合测试

首先需要导入测试依赖:

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

<dependency>
    <groupId>org.junit.jupiter</groupId>
    <artifactId>junit-jupiter-api</artifactId>
    <version>5.5.0</version>
    <scope>test</scope>
</dependency>

测试:

package com.xm.test;

import com.xm.controller.SpringController;
import junit.framework.TestCase;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.web.WebAppConfiguration;

@SpringBootTest(classes = SpringController.class)//测试谁
@RunWith(SpringJUnit4ClassRunner.class)//用什么测试
@WebAppConfiguration
public class TestSpringController {
    @Autowired
    private SpringController springController;//注入

    @Test
    public void test1(){
        TestCase.assertEquals(this.springController.yes(),"hello");
    }
}

SpringBoot日志管理

SpringBoot的日志级别有7个,从低到高分别是:
TRACE,DEBUG,INFO,WARN,ERROR,FATAL,OFF,如果设置了某个日志级别,低于该级别的日志不会输出。
SpringBoot默认配置ERROR,WARN和INFO级别的日志输出到控制台

默认情况下,SpringBoot将日志输出到控制台,不会写到日志文件。如果需要将日志写到文件中,需要在SprngBoot配置文件application.properties中设置logging.filelogging.path属性

  • logging.file:设置文件,绝对路径或者相对路径。如:
logging.file = log/my.log(相对)
logging.file = /log/my.log(绝对)
  • logging.path:设置目录,会在该目录下创建spring.log文件,并写入日志内容
logging.path = /var/log

两者不能同时使用,如同时使用,只有logging.file生效,默认日志文件的大小达到10MB会切分一次产生新的日志文件

配置示例:

logging.level.root = WARN
logging.level.org.springframework.web = DEBUG
logging.file = 路径
logging.pattern.console = %d{yyyy/MM/dd-HH:mm:ss}
[%thread] %-5level %logger- %msg%n
[%thread] %-5level %logger- %msg&n

自定义日志配置

除了在Springboot中进行日志配置,还可以自己根据使用的日志系统写日志配置文件
文件命令建议加上-spring,这样spring boot可以为它添加一些spring boot特有的配置项,不加的情况下需要在全局配置文件中指定自己定义的文件名:

logging.config = classpath:logging-config.xml

自定义日志系统

Spring默认使用的日志是Logback,如果要使用其他类型,需要先对Logback进行排除

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>
<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>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-log4j2</artifactId>
</dependency>

配置工程为开发模式

在开发过程中,每次修改代码后需要重新启动,可以将工程设置为开发模式,代码修改不再需要重新运行,具体做法为导入以下依赖:

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>springloaded</artifactId>
</dependency>

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-devtools</artifactId>
    <optional>true</optional>
</dependency>

访问静态资源

在SpringBoot中访问静态资源跟普通Web项目不太一样,Spring Boot默认的路径是在resources/staticresources/public,也可以自己在全局配置文件中进行配置:

spring.resources.static-locations=classpath:/static/

自定义JSON转换

SpringBoot默认使用Jackson进行json解析,如果希望自定义(如使用FastJson),可以通过以下方式更改:
首先导入FastJson包

<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>fastjson</artifactId>
    <version>1.2.58</version>
</dependency>

在启动类中注入新配置:

package com.xm.app;

import com.alibaba.fastjson.serializer.SerializerFeature;
import com.alibaba.fastjson.support.config.FastJsonConfig;
import com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.http.HttpMessageConverters;
import org.springframework.context.annotation.Bean;
import org.springframework.http.converter.HttpMessageConverter;

//默认扫描当前包及以下的子包
//@EnableAutoConfiguration //SpringBoot自动配置
//@ComponentScan("com.xm.controller")//自动扫描
@SpringBootApplication(scanBasePackages = "com.xm.controller")
public class SpringApplications{
    @Bean//依赖注入
    public HttpMessageConverters fastJsonMessageConverter(){
        //创建FastJson的消息转换器
        FastJsonHttpMessageConverter converter = new FastJsonHttpMessageConverter();
        //创建FastJson的配置对象
        FastJsonConfig config = new FastJsonConfig();
        //对json数据进行格式化
        config.setSerializerFeatures(SerializerFeature.PrettyFormat);

        converter.setFastJsonConfig(config);
        HttpMessageConverter<?>con = converter;
        return new HttpMessageConverters(con);
    }


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

对于中文,默认客户端接受不一定使用URTF-8编码,可以在全局配置文件加入如下配置使客户端使用UTF-8编码:
spring.http.encoding.force = true

创建实体类进行验证:

package com.xm.com.xm.pojo;

import com.alibaba.fastjson.annotation.JSONField;

import java.util.Date;

public class Person {
    private Integer id;
    private String name;
    @JSONField(format = "yyyy-MM-dd HH:mm:ss")
    private Date date;//日期格式化

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Date getDate() {
        return date;
    }

    public void setDate(Date date) {
        this.date = date;
    }
}
package com.xm.controller;

import com.xm.com.xm.pojo.Person;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

import java.util.Date;

@Controller
public class PersonController {

    @ResponseBody
    @RequestMapping("/show")
    public Object show(){
        Person person = new Person();
        person.setId(66);
        person.setName("小明");
        person.setDate(new Date());
        return person;
    }
}

自定义拦截器

通过继承WebMvcConfigurer接口,对里面的addInterceptors方法重写,根据自己需要实现的拦截功能进行定义:

package com.xm.interceptor;

import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

@Configuration//声明这是一个配置
public class MyInterceptor implements WebMvcConfigurer {
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        HandlerInterceptor interceptor = new HandlerInterceptor() {
            @Override
            public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
                System.out.println("自定义拦截器");
                return true;
            }
        };
        registry.addInterceptor(interceptor).addPathPatterns("/**");
    }
}

在启动项中扫描的包上需要加入当前包

全局异常处理器

SpringBoot使用Aop的思想进行异常处理

package com.xm.exceptionHandler;

import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;

import java.util.HashMap;
import java.util.Map;

@ControllerAdvice
public class GlobalExceptionHandler {
    @ExceptionHandler(Exception.class)
    @ResponseBody
    public Map<String,Object> handleException(Exception exception){
        Map<String,Object> map = new HashMap<>();
        map.put("errorCode",500);
        map.put("errorMag",exception.toString());
        return map;
    }
}

异步调用

在项目中当需要访问其他接口较慢或者做耗时工作时,如果不希望程序一直卡着而是能够并行处理,可以使用多线程来并行处理任务
SpringBoot提供了异步处理方式@Async

  1. 创建服务层接口及实现类
    在相应需要开启子线程的方法上使用@Async注解
package com.xm.service;

import java.util.concurrent.Future;

public interface AsyncService {
    Future<String> doTask1() throws Exception;
    Future<String> doTask2() throws Exception;
    Future<String> doTask3() throws Exception;
}
package com.xm.service;

import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.AsyncResult;
import org.springframework.stereotype.Service;

import java.util.Random;
import java.util.concurrent.Future;

@Service
public class AsyncServiceImpl implements AsyncService {

    private static Random random = new Random();

    @Async//标示开启子进程异步调用
    @Override
    public Future<String> doTask1() throws Exception {
        System.out.println("任务一开始执行");
        long start = System.currentTimeMillis();
        Thread.sleep(random.nextInt(10000));
        long end = System.currentTimeMillis();
        System.out.println("任务一结束,耗时:"+(end-start)+"毫秒");
        return new AsyncResult<>("任务一结束");
    }

    @Async
    @Override
    public Future<String> doTask2() throws Exception {
        System.out.println("任务二开始执行");
        long start = System.currentTimeMillis();
        Thread.sleep(random.nextInt(10000));
        long end = System.currentTimeMillis();
        System.out.println("任务二结束,耗时:"+(end-start)+"毫秒");
        return new AsyncResult<>("任务二结束");
    }

    @Async
    @Override
    public Future<String> doTask3() throws Exception {
        System.out.println("任务三开始执行");
        long start = System.currentTimeMillis();
        Thread.sleep(random.nextInt(10000));
        long end = System.currentTimeMillis();
        System.out.println("任务三结束,耗时:"+(end-start)+"毫秒");
        return new AsyncResult<>("任务三结束");
    }
}
  1. 创建控制器调用服务层
package com.xm.controller;

import com.xm.service.AsyncService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

import java.util.concurrent.Future;

@Controller
public class SyncController {

    @Autowired
    private AsyncService asyncService;

    @RequestMapping("/async")
    @ResponseBody
    public String asyncTest() throws Exception {

        long start = System.currentTimeMillis();

        Future<String> task1 = asyncService.doTask1();
        Future<String> task2 = asyncService.doTask2();
        Future<String> task3 = asyncService.doTask3();

        while (true){
            if(task1.isDone() && task2.isDone() && task3.isDone()){
                break;
            }
            Thread.sleep(1000);
        }

        long end = System.currentTimeMillis();
        return "全部执行完成,总耗时:"+(end-start)+"毫秒";
    }
}
  1. 在启动类上添加@EnableAsync开启异步执行,同时扫描的包要加上service包

模版引擎

SpringBoot官方对于动态页面推荐使用模版引擎,动态引擎有:FreeMarker、Thymeleaf、 Mustache等

SpringBoot中整合Freemarker

  1. 首先导入freemarker依赖
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-freemarker</artifactId>
</dependency>
  1. 创建ftl文件
    SpringBoot默认会在resources/templates目录下获取后缀名为.ftl的模版引擎文件
<html>
<head> Freemarker模版引擎</head>
<body>
    ${name}
</body>
</html>
  1. 创建控制器传值
package com.xm.controller;

import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;

@Controller
public class TemplatesController {
    @RequestMapping("/index")
    public String index(Model model){
        model.addAttribute("name","小明");
        return "show";//会自动到resources/templates目录下找
    }
}

如果要改变Freemarker的默认配置,可以在全局配置文件中做自定义配置

SpringBoot整合Thymeleaf

  1. 导入spring-boot-starter-thymeleaf依赖
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
  1. 创建html文件
    Thymeleaf默认的页面文件是html文件,同时其有自己的语法
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Thymeleaf</title>
</head>
<body>
<h1 th:text="${name}"></h1>
</body>
</html>

剩下的跟上一种一样

SpringBoot整合QuartZ

QuartZ是一个用于任务调度的框架

  1. 创建定时任务:
    对需要定时执行的任务使用@Scheduled注解,同时需要将该类放入容器,使用@Component
package com.xm.job;

import org.springframework.scheduling.annotation.Scheduled;

import java.text.SimpleDateFormat;
import java.util.Date;

public class MyJob {

    @Scheduled(fixedRate = 1000)//每隔多久执行一次任务,单位毫秒
    public void run(){
        System.out.println(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));
    }
}
  1. 在启动类中开启任务调度:使用@EnableScheduling,同时扫描包要指明

数据库相关操作

SpringBoot整合JdbcTemplate

首先需要导入相关依赖:

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

<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>8.0.16</version>
</dependency>

创建相应的pojo,dao和service

package com.xm.pojo;

public class User {
    private Integer id;
    private String name;
    private Integer age;
      //省略get,set方法
}
package com.xm.dao;

import com.xm.pojo.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Repository;

@Repository
public class UserDao {

    @Autowired
    private JdbcTemplate jdbcTemplate;

    public void addUser(User user){
        jdbcTemplate.update("insert into users(name,age) values (?,?)", new Object[]{
                        user.getName(),
                        user.getAge()
                });
    }
}
package com.xm.service;

import com.xm.dao.UserDao;
import com.xm.pojo.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service
public class UserService {

    @Autowired
    private UserDao userDao;

    public void saveUser(User user){
        userDao.addUser(user);
    }
}

创建控制器:

package com.xm.controller;


import com.xm.pojo.User;
import com.xm.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

@Controller
public class UserController {

    @Autowired
    private UserService userService;

    @RequestMapping("/savaUser")
    @ResponseBody
    public String save(){
        User user = new User();
        user.setName("潘多拉");
        user.setAge(666);

        userService.saveUser(user);

        return "success";
    }
}

在全局配置文件中设置连接数据库的相关信息:

spring.datasource.driver-class-name = com.mysql.cj.jdbc.Driver
spring.datasource.username=root
spring.datasource.password= root
spring.datasource.url = jdbc:mysql://localhost:3306/spring

SpringBoot整合Mybatis

xml文件方式

  1. 添加依赖:
<dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <version>8.0.16</version>
    </dependency>

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

    <dependency>
        <groupId>com.alibaba</groupId>
        <artifactId>druid</artifactId>
        <version>1.1.19</version>
    </dependency>

    <!-- 分页插件-->
    <dependency>
        <groupId>com.github.pagehelper</groupId>
        <artifactId>pagehelper-spring-boot-starter</artifactId>
        <version>1.2.12</version>
    </dependency>

    <dependency>
        <groupId>org.mybatis.generator</groupId>
        <artifactId>mybatis-generator-maven-plugin</artifactId>
        <version>1.3.7</version>
    </dependency>

</dependencies>

<build>
    <plugins>
        <plugin>
            <groupId>org.mybatis.generator</groupId>
            <artifactId>mybatis-generator-maven-plugin</artifactId>
            <version>1.3.7</version>
            <dependencies>
                <dependency>
                    <groupId>mysql</groupId>
                    <artifactId>mysql-connector-java</artifactId>
                    <version>5.1.47</version>
                </dependency>
            </dependencies>
        </plugin>
    </plugins>
</build>
  1. 通过逆向工程创建pojo,mapper和dao,手动添加相应的注解
  2. 将生成的xxxMapper.xml文件放到sources目录下
  3. 在resources目录下创建mybatis配置文件,只需写入前提配置即可
  4. 创建全局配置文件进行配置
spring:
  datasource:
    name: test
    url: jdbc:mysql://localhost:3306/spring
    username: root
    password: root
    type: com.alibaba.druid.pool.DruidDataSource
    driver-class-name: com.mysql.cj.jdbc.Driver
    dbcp2:
      initial-size: 1
      max-wait-millis: 60000
      min-idle: 1
      time-between-eviction-runs-millis: 60000
      min-evictable-idle-time-millis: 300000
      validation-query: select 'x'
      test-while-idle: true
      test-on-borrow: false
      test-on-return: false
      pool-prepared-statements: true
      max-open-prepared-statements: 20

mybatis:
  mapper-locations: classpath:mapper/UsersMapper.xml
  config-location: classpath:mybatis/mybatis-config.xml

pagehelper:
  reasonable: true
  support-methods-arguments: true
  params: count=countSql
  helper-dialect: mysql
  1. 开发服务层和控制器层
package com.xm.service;

import com.github.pagehelper.PageHelper;
import com.xm.dao.UsersMapper;
import com.xm.pojo.Users;
import com.xm.pojo.UsersExample;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.List;

@Service
public class UsersServiceImpl implements UsersService {

    @Autowired
    private UsersMapper usersMapper;

    @Override
    public void addUser(Users users) {
        usersMapper.insert(users);
    }

    @Override
    public List<Users> findUsers(int page, int rows) {
        UsersExample example = new UsersExample();
        PageHelper.startPage(page,rows);//相当于拦截器
        List<Users> users = usersMapper.selectByExample(example);
        return users;
    }
}
package com.xm.controller;

import com.xm.pojo.Users;
import com.xm.service.UsersService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

import java.util.List;

@Controller
public class UsersController {

    @Autowired
    private UsersService usersService;

    @RequestMapping("/saveUser")
    @ResponseBody
    public String saveUsers(){
        Users users = new Users();
        users.setAge(12);
        users.setName("阿拉斯加");

        usersService.addUser(users);
        return "success";
    }

    @RequestMapping("/findUsers/{page}/{rows}")
    @ResponseBody
    public List<Users> findUsers(@PathVariable int page,@PathVariable int rows){
        return usersService.findUsers(page,rows);
    }
}

注解方式

这种方式不需要mybatis配置文件和mapper的xml文件,主要修改的地方为映射类:
在对应的方法上使用相应的注解并自己写上sql语句,同时方法中的变量使用@Param使其对应上

package com.xm.dao;

import com.xm.pojo.Users;
import com.xm.pojo.UsersExample;
import java.util.List;

import org.apache.ibatis.annotations.Insert;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select;
import org.springframework.stereotype.Repository;

@Repository
public interface UsersMapper {

    @Select("select * from users where name=#{name}")
    Users findUserByName(@Param("name") String name);

    @Insert("insert into users(name,age) values(#{name},#{age})")
    void addUser(@Param("name") String name,@Param("age") Integer age);
}

SpringBoot整合多数据源

在项目中通常会进行数据库拆分或者是引入其他数据库,从而需要配置多个数据源
区分多个数据源的方式:

  1. 通过包来区分:com.db1.mapper,com.db2.mapper
  2. 使用注解区分:需要使用大量注解,一般不推荐使用

整合流程:

  1. 在全局配置文件中配置多个数据源
#配置两个数据源
spring.datasource.db1.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.db1.username=root
spring.datasource.db1.password=root
#2.0之后的版本需要使用jdbc-url
spring.datasource.db1.jdbc-url=jdbc:mysql://localhost:3306/spring

spring.datasource.db2.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.db2.username=root
spring.datasource.db2.password=root
spring.datasource.db2.jdbc-url=jdbc:mysql://localhost:3306/sm
  1. 对每个数据源进行配置
    DataSource1.java:
package com.xm.datasource;


import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.SqlSessionTemplate;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.jdbc.DataSourceBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;

import javax.sql.DataSource;

@Configuration //注册到Spring容器中
//扫描对应的mapper的包还有对应sqlSessionFactory的引用
@MapperScan(basePackages="com.xm.db1.mapper",sqlSessionFactoryRef = "db1SqlSessionFactory")
public class DataSource1 {

    /**
     * 配置db1数据库,生成数据源对象
     * @return
     */
    @Bean(name = "db1Datasource")
    @ConfigurationProperties(prefix = "spring.datasource.db1")//对应全局配置文件前缀
    public DataSource testDataSource(){
        return DataSourceBuilder.create().build();
    }

    /**
     * 创建SqlSessionFactory
     * @param dataSource
     * @return
     * @throws Exception
     */
    @Bean(name="db1SqlSessionFactory")
    @Primary //自动装配时优先使用
    public SqlSessionFactory testSqlSessionFactory(@Qualifier("db1Datasource")DataSource dataSource)
            throws Exception {
        SqlSessionFactoryBean bean = new SqlSessionFactoryBean();
        bean.setDataSource(dataSource);
        return bean.getObject();
    }

    /**
     * 配置事务管理
     * @param dataSource
     * @return
     */
    @Bean(name="db1TransactionManager")
    public DataSourceTransactionManager testTransactionManager(
            @Qualifier("db1Datasource")DataSource dataSource){
        return new DataSourceTransactionManager(dataSource);
    }

    /**
     * 整合数据库和mybatis时用于实现数据库操作
     * @param sqlSessionFactory
     * @return
     */
    @Bean(name="db1SqlSessionTemplate")
    public SqlSessionTemplate testSqlSessionTemplate(
            @Qualifier("db1SqlSessionFactory") SqlSessionFactory sqlSessionFactory){
        return new SqlSessionTemplate(sqlSessionFactory);
    }
}

另一个数据源大致相同,只需要相应的改成2就可以了
3. 创建mapper文件,需要将两个数据源放在不用的包中
需要注意注解指定相应的数据源

package com.xm.db1.mapper;

import org.apache.ibatis.annotations.Insert;
import org.apache.ibatis.annotations.Param;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Repository;

@Qualifier("db1SqlSessionFactory")
@Repository("db1UserMapper")
public interface UsersMapper {

    @Insert("insert into users(name,age) values(#{name},#{age})")
    void addUser(@Param("name")String name, @Param("age")Integer age);
}
  1. 开发相应的service
package com.xm.db1.service;

import com.xm.db1.mapper.UsersMapper;
import com.xm.db1.pojo.Users;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;

@Service("db1UsersService")
public class UsersServiceImpl implements UsersService {

    @Resource(name = "db1UserMapper")
    private UsersMapper usersMapper;

    @Override
    public void saveUser(Users users) {
        usersMapper.addUser(users.getName(),users.getAge());
    }
}
  1. 创建控制器层
import org.springframework.web.bind.annotation.ResponseBody;

import javax.annotation.Resource;

@Controller
public class IndexController {

    @Resource(name = "db1UsersService")//对应不同的service
    private UsersService usersService1;

    @Resource(name = "db2UsersService")
    private com.xm.db2.service.UsersService usersService2;

    @RequestMapping("/addUser")
    @ResponseBody
    public String addUser(){
        Users users1 = new Users();
        users1.setName("哈士奇");
        users1.setAge(111);

        usersService1.saveUser(users1);
        return "OK";
    }
}

SpringBoot事务管理

在SpringBoot中推荐使用@Transactional注解声明事务管理,只需要在需要开启事务的方法上加上即开启事务

SpringBoot整合JPA

jpa是一种数据持久化的规范,其实现最受欢迎的有Hibernate,Springboot也针对jpa做了实现:其可以根据实体类自动生成数据库表

  1. 导入依赖
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
  1. 全局配置文件配置数据库连接和JPA
spring.datasource.driver-class-name = com.mysql.cj.jdbc.Driver
spring.datasource.username=root
spring.datasource.password= root
spring.datasource.url = jdbc:mysql://localhost:3306/spring

# 让控制器输出json字符串格式
spring.jackson.serialization.indent-output=true
spring.jpa.hibernate.ddl-auto=update
spring.jpa.show-sql=true
spring.jooq.sql-dialect=MySQL5Dialect
  1. 创建实体类,对实体类使用Entity注解表示自动生成表
    生成的表的表名默认和实体类的类名相同,可以通过使用注解@Table(name="xxx"指定表名
    对于需要作为表中主键的属性,使用@Id注解,同时对于主键上的值的生成规则做指定:
    使用@GenerateValue(strategy=GenerationType.xxxx注解
  • AUTO表示自动生成
  • IDENTITY表示自动增长
    对于其他的属性,默认属性名跟字段名相同,可以使用@Column(name="xx")注解指明字段名,如果字段不允许为空,可以设置@Column(nullable=false)
package com.xm.pojo;


import javax.persistence.*;
import java.util.Date;

@Entity
@Table(name="t_user")
public class User {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Integer id;
    private String name;
    private Integer age;
    private Date birthday;

    public Integer getId() {
        return id;
    }

    public void setId(Integer 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;
    }

    public Date getBirthday() {
        return birthday;
    }

    public void setBirthday(Date birthday) {
        this.birthday = birthday;
    }
}
  1. 创建Dao层
    只需要创建一个接口并且继承JpaRepository,这个子类提供了增删改查的功能,它有两个范型,第一个是实体类,第二个是实体类中主键属性的类型
package com.xm.dao;

import com.xm.pojo.User;
import org.springframework.data.jpa.repository.JpaRepository;

public interface UserDao extends JpaRepository<User, Integer> {
}
  1. service层和controller层
package com.xm.service;

import com.xm.dao.UserDao;
import com.xm.pojo.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service
public class UserServiceImpl implements UserService {

    @Autowired
    private UserDao userDao;

    @Override
    public void addUser(User user) {
        userDao.save(user);
    }
}

@RestController
public class UserController {

    @Autowired
    private UserService userService;

    @RequestMapping("/saveUser")
    public String saveUser(){
        User user = new User();
        user.setName("巴啦啦小魔仙");
        user.setAge(6);
        user.setBirthday(new Date());

        userService.addUser(user);
        return "OK";
    }
}
  1. 启动类需要使用相应的注解扫描
package com.xm.app;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.domain.EntityScan;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;

@SpringBootApplication(scanBasePackages = "com.xm")
@EntityScan("com.xm.pojo")//扫描实体类从而生成表
@EnableJpaRepositories("com.xm.dao")//扫描dao
public class SpringBootApp {
    public static void main(String[] args) {
        SpringApplication.run(SpringBootApp.class,args);
    }
}

未解决问题:启动后出现异常:java.lang.IllegalStateException: Error processing condition on org.springframework.boot.autoconfigure.data.web.SpringDataWebAutoConfiguration.pageableCustomizer
无法正常启动

SpringBoot整合Mail

发送普通邮件

导入spring-boot-starter-mail依赖
配置全局配置文件

spring.mail.host=smtp.qq.com
spring.mail.username=934933088@qq.com
# 授权码,在qq邮箱设置里获取
spring.mail.password=xxxxx
spring.mail.properties.mail.smtp.auth=true
spring.mail.properties.mail.smtp.starttls.enable=true
spring.mail.properties.mail.smtp.starttls.required=true

读取邮件发送者:

package com.xm.mail;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

@Component
public class EmailConfig {

    @Value("${spring.mail.username}")
    private String emailFrom;

    public String getEmailFrom(){
        return emailFrom;
    }

    public void setEmailFrom(String emailFrom){
        this.emailFrom = emailFrom;
    }
}

服务层实现:

package com.xm.mail;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.mail.SimpleMailMessage;
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.stereotype.Service;

@Service
public class EmailServiceImpl implements EmailService {

    @Autowired
    private EmailConfig emailConfig;

    @Autowired
    private JavaMailSender mailSender;

    @Override
    public void sendSimpleMail(String sendTo, String title, String content) {
        //简单邮件的发送
        SimpleMailMessage message = new SimpleMailMessage();//构造邮件实体类
        message.setFrom(emailConfig.getEmailFrom());
        message.setTo(sendTo);
        message.setSubject(title);
        message.setText(content);

        mailSender.send(message);//发送邮件
    }
}

带附件的邮件

@Override
public void sendAttachmentMail(String sendTo, String title, String content, File file) {
    MimeMessage msg = mailSender.createMimeMessage();//将邮件封装成对象

    try {
        MimeMessageHelper helper = new MimeMessageHelper(msg,true);//设置为multipart格式
        helper.setFrom(emailConfig.getEmailFrom());
        helper.setTo(sendTo);
        helper.setSubject(title);
        helper.setText(content);

        FileSystemResource resource = new FileSystemResource(file);
        helper.addAttachment("附件",resource);
    } catch (MessagingException e) {
        e.printStackTrace();
    }
    mailSender.send(msg);
}
@RequestMapping("/sendFileMail")
@ResponseBody
public String sendAttachmentEmail(){
    File file = new File("SpringBoot_Child5/src/main/resources/static/66.txt");
    emailService.sendAttachmentMail("934933088@qq.com","hello","看文件",file);
    return "success";
}

发送模版邮件

需要导入模版引擎,同时在resources/templates目录下创建模版
service层:

@Service
public class EmailServiceImpl implements EmailService {

    @Autowired
    private EmailConfig emailConfig;

    @Autowired
    private JavaMailSender mailSender;

    @Autowired
    private FreeMarkerConfigurer freeMarkerConfigurer;
      
      @Override
    public void sendTemplateMail(String sendTo, String title, String info) {
          //info为模版的文件名(包含后缀)
        MimeMessage message = mailSender.createMimeMessage();
        try {
            MimeMessageHelper helper = new MimeMessageHelper(message,true);
            helper.setFrom(emailConfig.getEmailFrom());
            helper.setTo(sendTo);
            helper.setSubject(title);

            //封装模版使用的数据
            Map<String,Object> model = new HashMap<>();
            model.put("username","小红");

            //得到模版
            Template template = freeMarkerConfigurer.getConfiguration().getTemplate(info);
            String html = FreeMarkerTemplateUtils.processTemplateIntoString(template, model);

            helper.setText(html,true);
        } catch (Exception e) {
            e.printStackTrace();
        }
        mailSender.send(message);
    }
}

控制器:

@RequestMapping("/sendTemplateEmail")
@ResponseBody
public String sendTemplateEmail(){
    emailService.sendTemplateMail("934933088@qq.com","模版邮箱","info.html");
    return "success";
}

文件操作

SpringBoot实现文件上传

依赖web包之后,文件上传的包就自动依赖上了
如果需要控制上传文件的大小,可以通过全局配置文件的设置

#上传单个文件的大小
spring.servlet.multipart.max-file-size=500MB
#上传全部文件的总大小
spring.servlet.multipart.max-request-size= 500MB
  1. 使用模版引擎编写文件上传页面
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>文件上传</title>
</head>
<body>
    <h2>文件上传</h2>
    <hr/>
    <form method="post" enctype="multipart/form-data" action="/upload">
        <p>
            文件<input type="file" name="file"/>
        </p>
        <p>
            <input type="submit" value="上传"/>
        </p>
    </form>
</body>
</html>
  1. 实现文件上传控制器
package com.xm.controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletRequest;
import java.io.File;
import java.io.IOException;
import java.util.UUID;

@Controller
public class UploadController {

    //页面不能直接访问,需要通过控制器跳转
    @RequestMapping("/toUpload")
    public String toUpload(){
        return "upload";
    }

    @RequestMapping(value = "/upload",method = RequestMethod.POST)
    @ResponseBody
    public String uploadFile(MultipartFile file, HttpServletRequest request){

        //创建文件在服务器端的存放路径
        String dir = request.getServletContext().getRealPath("/upload");
        File fileDir = new File(dir);
        if(!fileDir.exists())
            fileDir.mkdirs();
        //生成文件在服务器端存放的名字
        String fileSuffix = file.getOriginalFilename().substring(file.getOriginalFilename().lastIndexOf("."));
        String fileName = UUID.randomUUID().toString()+fileSuffix;
        File files = new File(fileDir+"/"+fileName);
        //上传
        try {
            file.transferTo(files);
        } catch (IOException e) {
            e.printStackTrace();
            return "上传失败";
        }
        return "success";
    }
}

批量文件上传

@RequestMapping(value = "/upload/batch",method = RequestMethod.POST)
@ResponseBody
public String uploadFiles(MultipartFile[] files,HttpServletRequest request){
    //创建文件在服务器端的存放路径
    String dir = request.getServletContext().getRealPath("/upload");
    File fileDir = new File(dir);
    if(!fileDir.exists())
        fileDir.mkdirs();

    //遍历数组
    for(int i=0;i<files.length;i++){
        String fileSuffix = files[i].getOriginalFilename().substring(files[i].getOriginalFilename().lastIndexOf("."));
        String fileName = UUID.randomUUID().toString()+fileSuffix;
        File file = new File(fileDir+"/"+fileName);
        //上传
        try {
            files[i].transferTo(file);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    return "success";
}