SpringBoot核心功能

  • 二、SpringBoot核心功能
  • 1、配置文件
  • 1.1、properties文件
  • 1.2、yml文件
  • 1.2.1、简介
  • 1.2.2、基本语法
  • 1.2.3、数据类型
  • 1.2.4、配置提示
  • 2、Web开发
  • 2.1、SpringBoot中SpringMVC自动配置
  • 2.2、功能分析
  • 1、静态资源目录
  • 2、静态资源访问前缀
  • 3、支持webjars
  • 4、欢迎页支持
  • 5、自定义Favicon
  • 6、普通参数与基本注解
  • 7、视图解析与模板引擎
  • 视图解析:SpringBoot默认不支持jsp,需要引入第三方模板引擎技术实现页面渲染
  • thymeleaf模板引擎
  • 8、拦截器
  • 1、HandlerInterceptor接口
  • 2、配置拦截器
  • 3、验证拦截器
  • 9、文件上传
  • 10、Web原生组件的注入(Servlet、Filter、Listener)
  • 1、使用Servlet API
  • 2、RegistrationBean
  • 11、定制化SpringMVC原理
  • 1、定制化的常见方式
  • web应用 编写一个自定义类实现WebMvcConfigurer接口定制web功能 ;(推荐使用)+ @Bean 给容器中扩展组件
  • 2、定制化原理
  • 3、数据访问
  • 1、SQL
  • 1、数据源的自动配置 HikariDataSource
  • 2、使用Druid数据源
  • 1、druid官方github地址
  • 2、自定义方式
  • 3、引入starter官方场景
  • 3、整合MyBatis操作
  • 3.1纯配置方式
  • 3.2纯注解版
  • 3.3混合版
  • 4、SpringBoot整合mybatis-plus
  • 4、单元测试
  • 1、Junit5常用注解
  • 2、SpringBoot整合Junit
  • 5、原理解析
  • 1、application-profile功能
  • 2、@Profile条件装配功能
  • 3、profile分组


二、SpringBoot核心功能

1、配置文件

1.1、properties文件

1.2、yml文件

1.2.1、简介

YAML 是 “YAML Ain’t Markup Language”(YAML 不是一种标记语言)的递归缩写。在开发的这种语言时,YAML 的意思其实是:“Yet Another Markup Language”(仍是一种标记语言)。

非常适合用来做以数据为中心的配置文件

1.2.2、基本语法
  • key: value;kv之间有空格
  • 大小写敏感
  • 使用缩进表示层级关系
  • 缩进不允许使用tab,只允许空格
  • 缩进的空格数不重要,只要相同层级的元素左对齐即可
  • '#'表示注释
  • 字符串无需加引号,如果要加,’'与""表示字符串内容 会被 转义/不转义
1.2.3、数据类型
  • 字面量:单个的、不可再分的值。date、boolean、string、number、null
k: v
  • 对象:键值对的集合。map、hash、set、object
行内写法:  k: {k1: v1,k2: v2,k3: v3}
#或
k: 
  k1: v1
  k2: v2
  k3: v3
  • 数组:一组按次序排列的值。array、list、queue
行内写法:  k: [v1,v2,v3]
#或者
k:
 - v1
 - v2
 - v3
1.2.4、配置提示

自定义类绑定的配置提示

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


	<build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <configuration>
                    <excludes>
                        <exclude>
                            <groupId>org.springframework.boot</groupId>
                            <artifactId>spring-boot-configuration-processor</artifactId>
                        </exclude>
                    </excludes>
                </configuration>
            </plugin>
        </plugins>
    </build>

2、Web开发

2.1、SpringBoot中SpringMVC自动配置

  • 内容协商视图解析器(ContentNegotiatingViewResolver)和BeanName视图解析器(BeanNameViewResolver)
  • 静态资源(包括webjars)
  • 自动注册 Converter,GenericConverter,Formatter
  • 支持 HttpMessageConverters (后来我们配合内容协商理解原理)
  • 自动注册 MessageCodesResolver (国际化用)
  • 静态index.html 页支持
  • 自定义 Favicon
  • 自动使用 ConfigurableWebBindingInitializer ,(DataBinder负责将请求数据绑定到JavaBean上)

2.2、功能分析

1、静态资源目录

只要静态资源放在类路径下:called/static(or /public or /resources or /META-INF/resources

访问:当前项目根路径/+静态资源名

原理:静态资源映射:/**

请求进来,先去找Controller看能不能处理,不能处理则交给静态资源处理,如果静态资源也不能处理则404,。

修改默认的静态资源目录

spring:
  resources:
    static-locations: classpath:/haha/
2、静态资源访问前缀
spring:
  mvc:
    static-path-pattern: /res/**

访问静态资源:当前项目名+ static-path-pattern + 静态资源名 = 静态资源目录下寻找

3、支持webjars

https://www.webjars.org/

自动映射:/webjars/**

<dependency>
            <groupId>org.webjars</groupId>
            <artifactId>jquery</artifactId>
            <version>3.6.0</version>
        </dependency>

访问:http://localhost:8080/webjars/jquery/3.6.0/jquery.js

4、欢迎页支持
  • 静态资源目录下index.html
  • 可以是配置后的资源路径,但是不能配置静态资源访问前缀,会导致index.html不能访问
spring:
#  mvc:
#    static-path-pattern: /res/**   这个会导致welcome page 功能失效

  resources:
    static-locations: classpath:/haha/
  • 也可以是默认的static静态资源目录下(没有配置)
  • controller能处理的 /index 请求
5、自定义Favicon

将favicon.ico放在静态资源目录下即可。

#spring:
#  mvc:
#    static-path-pattern: /res/**   会导致这个 Favicon 功能失效
6、普通参数与基本注解
  • 注解:
    @PathVariable、@ReqestHeader、@RequestAttribute、@RequestParam、@MatrixVariable、@CookieVariable、@RequestBody
//@PathVariable、@ReqestHeader、@RequestParam、@CookieVariable 注解的使用

@RestController
public class ParameterTestController {

    @GetMapping("/car/{id}/owner/{username}")
    public Map<String,Object> getCar(@PathVariable("id") Integer id,
                                     @PathVariable("username") String username,
                                     @PathVariable Map<String,String> pv,
                                     @RequestHeader("User-Agent") String userAgent,
                                     @RequestHeader Map<String,String> header,
                                     @RequestParam List<String> interests,
                                     @RequestParam Map<String,Object> Param,
//                                     @CookieValue("_ga") String _ga,
                                     @CookieValue("_ga") Cookie cookie){

        Map<String,Object> map = new HashMap<>();
//        map.put("id",id);
//        map.put("username",username);
//        map.put("pv",pv);
//        map.put("User-Agent",userAgent);
//        map.put("header",header);
        map.put("interests",interests);
        map.put("Param",Param);
//        map.put("_ga",_ga);
        System.out.println(cookie.getName()+"===>"+cookie.getValue());
        return map;
    }
}

@RequestAttribute注解的使用

@Controller
public class RequestController {
    @GetMapping("/goto")
    public String goToPage(HttpServletRequest request){

        request.setAttribute("msg","成功了....");
        request.setAttribute("code",200);
        return "forward:/success";
    }

    //模拟读取数据回显到页面
    @ResponseBody
    @GetMapping("/success")
    public Map success(@RequestAttribute("msg") String msg,
                       @RequestAttribute("code") Integer code,
                       HttpServletRequest request){
        Object msg1 = request.getAttribute("msg");

        Map<String,Object> map = new HashMap<>();
        map.put("HttpServletRequest_msg",msg1);
        map.put("annotation_msg",msg);
        map.put("code",code);
        return map;
    }
}

@RequestBody注解的使用

@RestController
public class ParameterTestController {
    @PostMapping("/save")
    public Map getFormValues(@RequestBody String content){  //获取表单的所有提交的值
        Map<String,Object> map = new HashMap<>();
        map.put("content",content);
        return map;
    }
}

@MatrixVariable注解的使用

@RestController
public class ParameterTestController {
    //1、语法:  /cars/sell;low=34;brand=zhangsan,lisi,wangwu
    //2、SpringBoot默认是禁用掉了矩阵变量
    //      手动开启:原理。对于路径的处理:UrlPathHelper
    //              RemoveSemicolonContent 移除分号后面的内容
    //3、矩阵变量必须要有 url 路径变量  才能被解析
    @GetMapping("/cars/{path}")
    public Map matrixVariable(@MatrixVariable("low") String low,
                              @MatrixVariable("brand") List<String> brand,
                              @PathVariable("path") String path){

        Map<String,Object> map = new HashMap<>();
        map.put("low",low);
        map.put("brand",brand);
        map.put("path",path);
        return map;
    }

    //  /boss/1;age=30/2;age=18
    @GetMapping("/boss/{bossId}/{empId}")
    public Map boss(@MatrixVariable(value = "age",pathVar = "bossId") Integer bossAge,
                    @MatrixVariable(value = "age",pathVar = "empId") Integer empAge){
        Map<String,Object> map = new HashMap<>();
        map.put("bossAge",bossAge);
        map.put("empAge",empAge);
        return map;
    }
}

对应的index.html首页

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
测试基本注解:
<ul>
    <a href="car/3/owner/zhangsan?age=17&interests=basketball&interests=game">car/{id}/owner/{username}</a>
    <li>@PathVariable(路径变量)</li>
    <li>@RequestHeader(请求头)</li>
    <li>@RequestParam(获取请求参数)</li>
    <li>@CookieValue(获取cookie的值)</li>
    <li>@RequestBody(获取请求体)</li>
    <li>@RequestAttribute(获取request域属性)</li>
    <li>@MatrixVariable(矩阵变量)</li>
</ul>

<form action="/save" method="post">
    测试@RequestBody(获取请求体)<br/>
    用户名:<input type="text" name="username"/><br/>
    邮箱:<input name="email"/><br/>
    <input type="submit" value="提交"/>
</form>
/cars/sell;low=34;brand=zhangsan;brand=lisi     矩阵变量<br/>
页面开发时,cookie被禁用掉了,怎么使用session中的内容;<br/>
session.set(a,b)---> jssessionid ---> cookie ---> 每次发请求携带<br/>
url重写:/abc;jssessionid=xxx  把cookie的值使用矩阵变量的形式传递<br/>
<a href="/cars/sell;low=34;brand=zhangsan,lisi,wangwu">@MatrixVariable(矩阵变量)</a><br/>
<a href="/cars/sell;low=34;brand=zhangsan;brand=lisi;brand=wangwu">@MatrixVariable(矩阵变量)</a><br/>
<a href="/boss/1;age=30/2;age=18">@MatrixVariable(矩阵变量)</a><br/>
</body>
</html>
7、视图解析与模板引擎
视图解析:SpringBoot默认不支持jsp,需要引入第三方模板引擎技术实现页面渲染

视图处理方式:转发、重定向、自定义视图

thymeleaf模板引擎

使用方法:

1、引入thymeleaf的starter场景

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

2、在默认的目录templates下,创建html页面并引入名称空间

<html xmlns:th="http://www.thymeleaf.org">

例:success.html

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<h1 th:text="${msg}">哈哈</h1>
<h2><a href="www.baidu.com" th:href="${link}"/>我的博客</h2>
<h2><a href="www.baidu.com" th:href="@{link}"/>我的博客2</h2>
</body>
</html>

相应的处理器:ViewController

@Controller
public class ViewController {

    @GetMapping("/page")
    public String toPage(Model model){

        model.addAttribute("msg","成功了....");
        model.addAttribute("link","https://www.tainfei.top/");

        return "success";
    }
}
8、拦截器
1、HandlerInterceptor接口
2、配置拦截器
/**
 * 登录检测
 * 拦截器:
 * 1、配置拦截器要拦截哪些
 * 2、拦截器添入容器中
 *
 * @author: Herz
 * @date: 2021/5/28 9:23
 */
@Slf4j
public class LoginInterceptor implements HandlerInterceptor {

    /**
     * 目标方法执行之前
     *
     * @param request
     * @param response
     * @param handler
     * @return
     * @throws Exception
     */
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        String requestURI = request.getRequestURI();
        log.info("preHandle 拦截的请求路径:" + requestURI);

        //登录检查逻辑
        HttpSession session = request.getSession();

        Object attribute = session.getAttribute("loginUser");
        if (attribute != null) {
            //放行
            return true;
        } else {
            //拦截住,未登录
//            session.setAttribute("msg", "请先登录");
            request.setAttribute("msg","请先登录");
            //跳转登录页
//            response.sendRedirect("/");    //重定向取不到session 域中得值
            request.getRequestDispatcher("/").forward(request,response);
            return false;
        }
    }


    /**
     * 目标方法执行之后
     *
     * @param request
     * @param response
     * @param handler
     * @param modelAndView
     * @throws Exception
     */
    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        log.info("postHandle的ModelAndView{}",modelAndView);
    }


    /**
     * 页面渲染以后
     *
     * @param request
     * @param response
     * @param handler
     * @param ex
     * @throws Exception
     */
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        log.info("afterCompletion异常:",ex);
    }
}

将拦截器注册到容器中

/**
 * 1、编写一个拦截器实现 HandlerInterceptor 接口
 * 2、拦截器注册到容器中(实现 WebMvcConfigurer 接口的 addInterceptors 方法)
 * 3、指定拦截器规则【如果是拦截所有请求,静态资源的访问也会被拦截】
 *
 *
 * @author: Herz
 * @date: 2021/5/28 10:17
 */
@Configuration
public class AdminWebConfig implements WebMvcConfigurer {

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new LoginInterceptor())
                .addPathPatterns("/**")                 //拦截的请求路径,静态资源访问也被拦截
                .excludePathPatterns("/","/login","/css/**","/fonts/**","/images/**","/js/**");      //不拦截的请求路径
    }
}
3、验证拦截器
9、文件上传
@Slf4j
@Controller
public class FormTestController {

    /**
     * 自动封装上传过来的文件
     * @param email
     * @param username
     * @param headerImg
     * @param photos
     * @return
     * @throws IOException
     */
    @PostMapping("/upload")
    public String uploads(@RequestParam("email") String email,
                          @RequestParam("username") String username,
                          @RequestParam("headerImg") MultipartFile headerImg,
                          @RequestParam("photos") MultipartFile[] photos) throws IOException {

        log.info("上传的信息:email={},username={},headerImg={},Photos={}",email,username,headerImg.getSize(),photos.length);

        if (!headerImg.isEmpty()){
            //上传到文件服务器,OSS服务器
            String originalFilename = headerImg.getOriginalFilename();
            headerImg.transferTo(new File("F:\\FormTest\\"+originalFilename));
        }

        for (MultipartFile photo : photos) {
            if (!photo.isEmpty()){
                String originalFilename = photo.getOriginalFilename();
                photo.transferTo(new File("F:\\FormTest\\"+originalFilename));
            }
        }

        return "main";
    }



    @GetMapping("/form_layouts")
    public String form_layouts(){

        return "form/form_layouts";
    }
}

对应的文件上传表单

<form role="form" th:action="@{/upload}" method="post" enctype="multipart/form-data">
                            <div class="form-group">
                                <label for="exampleInputEmail1">邮箱</label>
                                <input type="email" class="form-control" name="email" id="exampleInputEmail1" placeholder="Enter email">
                            </div>
                            <div class="form-group">
                                <label for="exampleInputUsername1">姓名</label>
                                <input type="text" class="form-control" name="username" id="exampleInputUsername1" placeholder="username">
                            </div>
                            <div class="form-group">
                                <label for="exampleInputFile">头像</label>
                                <input type="file" id="exampleInputFile" name="headerImg">
                            </div>
                            <div class="form-group">
                                <label for="InputFiles">生活照</label>
                                <input type="file" id="InputFiles" name="photos" multiple>
                            </div>
                            <div class="checkbox">
                                <label>
                                    <input type="checkbox"> Check me out
                                </label>
                            </div>
                            <button type="submit" class="btn btn-primary">提交</button>
                        </form>

配置文件上传的大小与总的请求大小

spring.servlet.multipart.max-file-size=10MB
spring.servlet.multipart.max-request-size=100MB
10、Web原生组件的注入(Servlet、Filter、Listener)
1、使用Servlet API

Servlet

@WebServlet(urlPatterns = "/my")  //效果:直接响应,没有经过拦截器
public class MyServlet extends HttpServlet {

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        resp.getWriter().write("666666");
    }
}




@ServletComponentScan(basePackages = "com.tianfei.admin") //指明原生Servlet组件放在哪里
@SpringBootApplication
public class Boot04WebAdminApplication {

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

Filter

@Slf4j
@WebFilter(urlPatterns = {"/css/*","/images/*"})
public class MyFilter implements Filter {
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
      log.info("MyFilter初始化");
    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        log.info("方法被过滤");
        filterChain.doFilter(servletRequest,servletResponse);
    }

    @Override
    public void destroy() {
        log.info("MyFilter销毁");
    }
}

Listener

@Slf4j
@WebListener
public class MyContextListener implements ServletContextListener {

    @Override
    public void contextInitialized(ServletContextEvent sce) {
        log.info("MyContextListener监听到项目初始化完成");
    }

    @Override
    public void contextDestroyed(ServletContextEvent sce) {
        log.info("MyContextListener监听到项目销毁");
    }
}

注意:需要在SpringBoot的主方法上添加 @ServletComponentScan(basePackages = “com.tianfei.admin”) //指明原生Servlet组件放在哪里

2、RegistrationBean

自定义一个Servlet

public class MyServlet extends HttpServlet {

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        resp.getWriter().write("666666");
    }
}

自定义一个Filter

@Slf4j
public class MyFilter implements Filter {
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
      log.info("MyFilter初始化");
    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        log.info("MyFilter工作");
        filterChain.doFilter(servletRequest,servletResponse);
    }

    @Override
    public void destroy() {
        log.info("MyFilter销毁");
    }
}

自定义一个Listener

@Slf4j
public class MyContextListener implements ServletContextListener {

    @Override
    public void contextInitialized(ServletContextEvent sce) {
        log.info("MyContextListener监听到项目初始化完成");
    }

    @Override
    public void contextDestroyed(ServletContextEvent sce) {
        log.info("MyContextListener监听到项目销毁");
    }
}

使用RegistrationBean注册到容器中

//(proxyBeanMethods = true):保证依赖的组件始终是单实例的
@Configuration(proxyBeanMethods = true)
public class MyRegisterConfig {

    @Bean
    public ServletRegistrationBean getServlet(){

        MyServlet myServlet = new MyServlet();

        return new  ServletRegistrationBean(myServlet,"/my","/my02");
    }

    @Bean
    public FilterRegistrationBean getFilter(){

//        return new FilterRegistrationBean(new MyFilter(),getServlet());   //过滤路径和  getServlet()映射路径相同

        FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean(new MyFilter());
        filterRegistrationBean.setUrlPatterns(Arrays.asList("/my","/css/*"));
        return filterRegistrationBean;
    }

    @Bean
    public ServletListenerRegistrationBean getListener(){

        return new ServletListenerRegistrationBean(new MyContextListener());
    }
}
11、定制化SpringMVC原理
1、定制化的常见方式
  • 修改配置文件;
  • 编写自定义配置类 xxxxConfiguration; + @Bean替换、增加容器中得组件;视图解析器;
  • 编写自定义类 xxxCustomizer
@Component
public class MyWebServerFactoryCustomizer implements WebServerFactoryCustomizer<ConfigurableServletWebServerFactory> {

    @Override
    public void customize(ConfigurableServletWebServerFactory server) {
        server.setPort(9000);
    }
}
web应用 编写一个自定义类实现WebMvcConfigurer接口定制web功能 ;(推荐使用)+ @Bean 给容器中扩展组件
@Configuration
public class AdminWebConfig implements WebMvcConfigurer {

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new LoginInterceptor())
                .addPathPatterns("/**")                 //拦截的请求路径,静态资源访问也被拦截
                .excludePathPatterns("/","/login","/css/**","/fonts/**","/images/**","/js/**");      //不拦截的请求路径
    }
}
  • @EnableWebMvc + 实现WebMvcConfigurer接口 —— @Bean 可以完全接管SpringMVC,自己重新指定规则;实现定制和扩展功能
2、定制化原理

场景starter导入---- xxxAutoConfiguration --导入依赖组件 --绑定properties配置文件 ----- 绑定配置文件项

3、数据访问

1、SQL

1、数据源的自动配置 HikariDataSource

导入JDBC场景依赖:

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

导入数据库驱动:

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

这里数据库驱动有版本仲裁(默认版本:8.0.25),想要修改到自己所需要的版本:

1、导入驱动时直接指定版本号(maven中得依赖就近原则)
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.47</version>
        </dependency>
2、在pom.xml配置文件中配置属性(maven中得属性就近原则)
    <properties>
        <mysql.version>5.1.47</mysql.version>
    </properties>

修改自动配置属性:

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

  jdbc:
    template:
      query-timeout: 3

测试代码:

@Slf4j
@SpringBootTest
class Boot05JdbcApplicationTests {

    @Autowired
    JdbcTemplate jdbcTemplate;

    @Test
    void contextLoads() {
        Long nums = jdbcTemplate.queryForObject("select COUNT(*) from t_account", Long.class);
        log.info("总记录数为:"+nums);
    }
}
2、使用Druid数据源
1、druid官方github地址

https://github.com/alibaba/druid

整合第三方技术的两种方式:

  • 自定义
  • 引入starter场景
2、自定义方式

引入相关依赖

<!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java -->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.47</version>
        </dependency>
        <!-- https://mvnrepository.com/artifact/com.alibaba/druid -->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid</artifactId>
            <version>1.2.6</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-jdbc</artifactId>
        </dependency>
@Configuration
public class MyDataSourceConfig {

    @ConfigurationProperties(prefix = "spring.datasource")
    //默认的自动配置数据源是容器中没有才会配置@ConditionalOnMissingBean({ DataSource.class, XADataSource.class })
    @Bean
    public DataSource dataSource() throws SQLException {
        DruidDataSource dataSource = new DruidDataSource();
        //打开监控功能、防火墙
        dataSource.setFilters("stat,wall");
        dataSource.setMaxActive(10);
        return dataSource;
    }


    /**
     * 监控页面的 sql监控
     * web.xml中得配置
     *   <servlet>
     *       <servlet-name>DruidStatView</servlet-name>
     *       <servlet-class>com.alibaba.druid.support.http.StatViewServlet</servlet-class>
     *   </servlet>
     *   <servlet-mapping>
     *       <servlet-name>DruidStatView</servlet-name>
     *       <url-pattern>/druid/*</url-pattern>
     *   </servlet-mapping>
     *
     *
     * @return
     */
    @Bean
    public ServletRegistrationBean statViewServlet(){
        StatViewServlet statViewServlet = new StatViewServlet();
        ServletRegistrationBean<StatViewServlet> registrationBean = new ServletRegistrationBean<>(statViewServlet,"/druid/*");
        //配置监控页访问密码
        registrationBean.addInitParameter("loginUsername","druid");
        registrationBean.addInitParameter("loginPassword","druid");
        return registrationBean;
    }


    /**
     * 监控页面的 web应用监控
     * web.xml中得配置
     *   <filter>
     *   	<filter-name>DruidWebStatFilter</filter-name>
     *   	<filter-class>com.alibaba.druid.support.http.WebStatFilter</filter-class>
     *   	<init-param>
     *   		<param-name>exclusions</param-name>
     *   		<param-value>*.js,*.gif,*.jpg,*.png,*.css,*.ico,/druid/*</param-value>
     *   	</init-param>
     *   </filter>
     *   <filter-mapping>
     *   	<filter-name>DruidWebStatFilter</filter-name>
     *   	<url-pattern>/*</url-pattern>
     *   </filter-mapping>
     *
     *
     * @return
     */
    @Bean
    public FilterRegistrationBean webStatFilter(){
        WebStatFilter webStatFilter = new WebStatFilter();
        FilterRegistrationBean<WebStatFilter> registrationBean = new FilterRegistrationBean<>(webStatFilter);
        registrationBean.setUrlPatterns(Arrays.asList("/*"));
        registrationBean.addInitParameter("exclusions","*.js,*.gif,*.jpg,*.png,*.css,*.ico,/druid/*");
        return registrationBean;
    }
}
3、引入starter官方场景
<dependency>
   <groupId>com.alibaba</groupId>
   <artifactId>druid-spring-boot-starter</artifactId>
   <version>1.1.17</version>
</dependency>

相关配置

spring:
  datasource:
    url: jdbc:mysql://localhost:3306/userdb?useUnicode=true&characterEncoding=utf-8&serverTimezone=GMT%2B8&useSSL=false
    username: root
    password: tianfei
    driver-class-name: com.mysql.jdbc.Driver

    druid:
      stat-view-servlet:
        enabled: true   #功能开启
        login-username: druid
        login-password: druid
        reset-enable: false   #重置按钮

      web-stat-filter:
        enabled: true
        url-pattern: /*
        exclusions: '*.js,*.gif,*.jpg,*.png,*.css,*.ico,/druid/*'

      aop-patterns: com.tianfei.admin/*      #监控的包
      filters: stat,wall    #底层功能开启,stat(sql监控功能),wall(防火墙功能)
      filter:
        stat:
          slow-sql-millis: 1000
          log-slow-sql: true    #日志记录慢查询
        wall:
          enabled: true
3、整合MyBatis操作

starter

官方的starter:spring-boot-starter-*

第三方的starter:*-spring-boot-starter

3.1纯配置方式
spring:
  datasource:
    driver-class-name: com.mysql.jdbc.Driver
    url: jdbc:mysql://localhost:3306/userdb?useUnicode=true&characterEncoding=utf-8&serverTimezone=GMT%2B8&useSSL=false
    username: root
    password: tianfei

#mybatis配置规则
mybatis:
  config-location: classpath:mybatis/mybatis-config.xml   #mybatis的核心配置文件位置
  mapper-locations: classpath:mybatis/mapper/*.xml      #sql映射文件文职

整合步骤:

  • 导入官方的starter
<dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>2.2.0</version>
        </dependency>
  • 编写mapper接口(注意标注 @Mapper 注解)
@Mapper
public interface AccountMapper {

    public Account getById(Integer id);
}
  • 编写sql映射文件,并绑定mapper接口。
<?xml version="1.0" encoding="UTF-8" ?>
        <!DOCTYPE configuration
                PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
                "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
        <settings>
                <!-- 开启驼峰命名规则 -->
                <setting name="mapUnderscoreToCamelCase" value="true"/>
        </settings>
</configuration>
  • 在application.yaml配置文件中,指定mybatis核心配置文件位置和sql映射文件位置以及全局配置文件的信息(建议:配置在yaml文件中mybatis.configuration)
3.2纯注解版
@Mapper
public interface CityMapper {

    @Select("select * from city where id=#{id}")
    public City getById(Integer id);

    @Insert("insert into city(`name`,`state`,`country`) values (#{name},#{state},#{country})")
    @Options(useGeneratedKeys = true,keyProperty = "id")
    public void insert(City city);
}
3.3混合版
@Mapper
public interface CityMapper {

    @Select("select * from city where id=#{id}")
    public City getById(Integer id);

    public void insert(City city);
}
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">

<mapper namespace="com.tianfei.boot06mybatisannotation.mapper.CityMapper">
    <insert id="insert" parameterType="com.tianfei.boot06mybatisannotation.bean.City" useGeneratedKeys="true" keyProperty="id">
        insert into city(`name`,`state`,`country`) values (#{name},#{state},#{country});
    </insert>
</mapper>

最佳实战:

  • 导入mybatis的官方starter
  • 在配置文件application.yaml中配置mapper-locations sql映射文件的位置
  • 编写mapper接口,并添加@Mapper注解
  • 简单的sql语句直接使用注解方式
  • 复杂的sql语句编写mapper接口后,进行绑定映射
  • @MapperScan(“com.tianfei.boot06mybatisannotation.mapper”) 可以简化,其他接口不用添加 @Mapper 注解
4、SpringBoot整合mybatis-plus
  • 导入mybatis-plus官方starter
<dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
            <version>3.4.3</version>
        </dependency>
  • 在application.yaml配置文件中配置数据源
spring:
  datasource:
    url: jdbc:mysql://localhost:3306/userdb?useUnicode=true&characterEncoding=utf-8&serverTimezone=GMT%2B8&useSSL=false
    username: root
    password: tianfei
    driver-class-name: com.mysql.jdbc.Driver
  • 编写一个mapper接口继承BaseMapper 接口
public interface UserMapper extends BaseMapper<User> {

}
  • 编写一个Service接口继承 IService接口,并编写Service的实现类继承ServiceImpl<M,T>类
public interface UserService extends IService<User> {
}

@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {
}
  • 编写一个controller
@Controller
public class TableController {

    @Autowired
    UserService service;

    @GetMapping("/dynamic_table")
    @ResponseBody
    public String dynamic_table(@RequestParam(value = "pn",defaultValue = "1") Integer pn, Model model) {
        //分页查询数据
        Page<User> userPage = new Page<>(pn,2);
        //分页查询的结果
        Page<User> page = service.page(userPage, null);
        
        model.addAttribute("page",page);
        List<User> records = page.getRecords();
        long pages = page.getPages();

        return "dynamic_table";
    }
}
  • 在主程序上添加@MapperScan(“com.tianfei.boot07mybatisplus.mapper”) 注解,开启扫描mapper包下的mapper接口
@MapperScan("com.tianfei.boot07mybatisplus.mapper")
@SpringBootApplication
public class Boot07MybatisplusApplication {

    public static void main(String[] args) {
        SpringApplication.run(Boot07MybatisplusApplication.class, args);
    }
}
  • 测试访问:localhost:8080/项目名/dynamic_table

注意!!!!使用mybatisPlus的分页插件时,需创建一个配置类MybatisPlusConfig

@Configuration
@MapperScan("com.tianfei.admin.mapper.*")
public class MybatisPlusConfig {
    @Bean
    public MybatisPlusInterceptor mybatisPlusInterceptor() {
        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
        // 设置请求的页面大于最大页后操作, true调回到首页,false 继续请求  默认false
        // paginationInterceptor.setOverflow(false);
        // 设置最大单页限制数量,默认 500 条,-1 不受限制
        // paginationInterceptor.setLimit(500);
        // 开启 count 的 join 优化,只针对部分 left join

        //分页拦截器
        PaginationInnerInterceptor paginationInnerInterceptor = new PaginationInnerInterceptor();
        paginationInnerInterceptor.setOverflow(true);
        paginationInnerInterceptor.setMaxLimit(500L);
        interceptor.addInnerInterceptor(paginationInnerInterceptor);
        return interceptor;
    }
}

4、单元测试

1、Junit5常用注解

https://junit.org/junit5/docs/current/user-guide/#writing-tests-annotations

2、SpringBoot整合Junit

  • 编写测试方法:@Test标注(注意需要使用junit5版本的注解)
  • Junit类具有Spring的功能,@Autowired、比如 @Transactional 标注测试方法,测试完成后自动回滚

5、原理解析

1、application-profile功能

  • 默认配置文件 application.yaml;任何时候都会加载
  • 指定环境配置文件 application-{env}.yaml
  • 激活指定环境
  • 配置文件激活
  • 命令行激活:java -jar xxx.jar –spring.profiles.active=prod --person.name=haha
  • 修改配置文件的任意值,命令行优先
  • 默认配置与环境配置同时生效
  • 同名配置项,profile配置优先

2、@Profile条件装配功能

//@Profile("prod")
@Configuration
public class MyConfig {
    @Profile("prod")
    @Bean
    public Color red(){
        return new Color();
    }

    @Profile("test")
    @Bean
    public Color green(){
        return new Color();
    }
}

3、profile分组

spring.profiles.group.myprod[0]=proddb
spring.profiles.group.myprod[1]=prodmq

使用:spring.profiles.active=myprod  激活