SpringBootV12和mybatis全部知识点

时间:2024-07-10 07:03:56

框架: 快速开发项目的一个架子

image-20230624230313370

ssh

ssm

spring --> applicationContext.xml配置文件(spring不是业务层,是管理其他框架的)

springmvc --> springmvc.xml配置文件 (对应之前servlet)

mybatis —> mybatis-config.xml配置文件(对应之前jdbc)

—> springboot优化了之前的框架配置,思想是约定大于配置

一、引言


1.1 初始化配置

为了使用SSM框架去开发,准备SSM框架的模板配置。

1.2 整合第三方框架

为了Spring整合第三方框架,单独的去编写xml文件。

1.3 后期维护

后期SSM项目后期xml文件特别多,维护xml文件的成本是很高的

1.4 部署工程

SSM工程部署也是很麻烦,依赖第三方的容器

1.5 敏捷式开发

基于Java的SSM开发方式是很笨重,而现在的python,php,NodeJS的敏捷式开发已经盖过Java一头

二、SpringBoot介绍


SpringBoot是由Pivotal团队研发的,SpringBoot并不是一门新技术,只是将之前常用的Spring,SpringMVC,data-jpa等常用的框架封装到了一起,帮助你隐藏这些框架的整合细节,实现敏捷开发。 约定大于配置

SpringBoot就是一个工具集。

官网:https://spring.io/projects/spring-boot

SpringBoot特点:

  • SpringBoot项目不需要模板化的配置。
  • SpringBoot中整合第三方框架时,只需要导入相应的starter依赖包,就自动整合了。约定大于配置。
  • SpringBoot默认只有一个.properties或者.yml的配置文件,不推荐使用xml,后期会采用.java的文件去编写配置信息。
  • SpringBoot工程在部署时,采用的是jar包的方式,内部自动依赖Tomcat容器,提供了多环境的配置。
  • 后期要学习的微服务框架SpringCloud需要建立在SpringBoot的基础上。

三、SpringBoot快速入门


3.1 快速构建SpringBoot

3.1.1 选择构建项目的类型

选择构建项目的类型
image-20230624230840419

注意:根据网络状况,可能会提示无法连接。如果不能连接,使用http://start.springboot.io(或者http://start.aliyun.com)

3.1.2 指定SpringBoot版本和需要的依赖

指定SpringBoot版本和需要的依赖
image-20230624231046116

ps: 如果2.7.13版本创建完项目会报错,提示alimaven找不到依赖的情况,就手动将pom文件中版本改成2.7.2

<parent>
 <groupId>org.springframework.boot</groupId>
 <artifactId>spring-boot-starter-parent</artifactId>
 <version>2.7.2</version>
 <relativePath/> 
</parent>

3.1.3 导入依赖

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

3.1.4 编写了Controller

Controller就是之前的Servlet,用于接收请求做出响应

创建一个controller包,单独写controller类

@Controller
public class TestController {

    @RequestMapping("/test")
    public String test(){
        return "ok.html";
    }
}

3.1.5 编写页面

在resources/static下创建ok.html页面

ps: 默认的固定格式,只能在resources下,且只能是static

image-20230817202540837

3.1.6 测试

主类点击启动项目

image-20230624233626353

SpringBoot项目启动成功后,不会主动打开浏览器,需要自己手动打开浏览器测试

效果
image-20230624233656863image-20230817202613225手动访问/tset路径,看到页面跳转

3.2 SpringBoot的目录结构

3.2.1 pom.xml文件

  • 指定了一个父工程: 指定当前工程为SpringBoot,帮助我们声明了starter依赖的版本。

       <!-- 没有这个的话,有dependencyManagement也行 --> 
       <parent>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-parent</artifactId>
            <version>2.7.2</version>
            <relativePath/> 
        </parent>
    
       <!-- 有这个dependencyManagement,就不需要上面parent --> 
       <dependencyManagement>
            <dependencies>
                <dependency>
                    <groupId>org.springframework.boot</groupId>
                    <artifactId>spring-boot-dependencies</artifactId>
                    <version>${spring-boot.version}</version>
                    <type>pom</type>
                    <scope>import</scope>
                </dependency>
            </dependencies>
        </dependencyManagement>
    
  • 项目的元数据:包名,项目名,版本号。

       <groupId>com.qf</groupId>
       <artifactId>test_springboot01</artifactId>
       <version>0.0.1-SNAPSHOT</version>
       <name>TestSpringboot01</name>
    
  • 指定了properties信息:指定了java的版本为1.8

        <properties>
            <java.version>1.8</java.version>
        </properties>
    
  • 导入依赖:按需导入(web,mysql等等)

  • 插件:spring-boot-maven-plugin (如果有报错,也可以不要)

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

3.2.2 .gitignore文件

默认帮我们忽略了一些文件和目录,避免提交到Git仓库中

3.2.3 目录结构

-src
  -main	  
    -java
      -包名
      启动类.java # 需要将controller类,放在启动类的子包中或者同级包下,否则需要使用@ComponentScan 注解,并指定扫描的包即可
    -resources  # resources下放除了java代码之外其他资源文件
      -static				  # 存放静态资源的,js,css,html
      -templates			  # 存储模板页面的,Thymeleaf,jsp,freemarker
      application.properties  # SpringBoot提供的配置文件,后缀支持2种:1.properties 2.yml(推荐),用来修改默认配置
  -test   				      # 只是为了测试用的

image-20240701114556614

3.3 补充

可以给主类加上如下代码即可启动成功后,自动打开浏览器

public static void main(String[] args) {
    int port = 8080;
    String portPrefix = "--server.port=";
    for (String arg : args) {
        if (arg.startsWith(portPrefix)) {
            port = Integer.parseInt(arg.substring(portPrefix.length()));
        }
    }
    SpringApplication.run(Day35Springboot01Application.class, args);
    try {
        Runtime.getRuntime().exec("cmd /c start http://localhost:" + port);
    } catch (IOException e) {
        e.printStackTrace();
    }
}

四、Spring

介绍…balabala

spring的核心功能

Spring是一个容器,帮助管理对象生命周期(创建对象,使用对象,对象销毁等),
Spring框架中主要的功能有
- IOC,DI
- AOP
- MVC
- Dao(JDBCTemplate)等
  • IOC,DI
  • AOP

image-20240701144050050

4.1 IOC+DI[重点]

4.1.0 引言

以前写的[登录+查询全部功能]

// 控制层
public class LoginServlet extends HttpServlet{
    UserService service;
    void doGet(){
        service.findAdminByLogin(username,password);
    }
}
// 业务层接口
public interface UserService{
    Admin findUseryLogin(String username,String password);
}

// 业务层实现类
public class UserServiceImpl implements AdminService {
    Admin findUseryLogin(String username,String password) {
     // ...   
    }
}

public class UserServiceImpl2 implements AdminService {
    Admin findUseryLogin(String username,String password) {
     // ...   
    }
}

以上这样写有缺点:

1 LoginServlet类还是需要和UserService和UserServiceImpl耦合

2 扩展性不好,假如有新的实现类UserServiceImpl2,就需要改动代码


现在需要一种技术,降低耦合且还可以根据运行时状态给属性动态赋值

4.1.1 介绍

IOC是Spring框架的核心功能之一,IOC(inversion of control)控制反转

控制: 控制创建对象的能力(以前是自己需要什么对象,自己创建)

反转: 原来创建对象是自己做,反转就是将创建对象的能力交给Spring


IOC(控制反转): 将创建对象的能力反转给Spring,由Spring创建对象

DI(dependency injection) 依赖注入,即 属性赋值


spring的ioc,帮助我们创建对象,是通过注解实现的, 常用的创建对象的注解

  • @Controller 在控制层代码上使用
  • @Service 在业务层代码上使用
  • @Repository 在数据层代码上使用
  • @Component 在其他代码上使用

–> 以上四个注解都是创建对象用的,只不过建议是各层用对应的

属性赋值(依赖注入的注解)

  • @Autowired
  • @Resource

4.1.2 演示1

需求: 项目中控制层Controller中需要使用到业务层service对象来处理业务,例如AdminController中需要创建AdminService对象使用,使用IOC+DI完成

AdminService和AdminServiceImpl

public interface AdminService {
    void login();
}

@Service // 加上该注解,AdminServiceImpl类就会被spring容器创建对象
public class AdminServiceImpl implements AdminService{

    @Override
    public void login() {
        System.out.println("业务层执行..." );
    }
}

AdminController

@Controller // 创建对象
public class AdminController {

    // 在控制层中需要使用业务层对象
    // 不再主动new对象,而是从容器中拿
    // @Autowired注解就会从容器中找到该类型的对象赋值给该变量
    // 即这就是属性赋值,也就是依赖注入,即DI
    @Autowired // 属性赋值
    private AdminService adminService;

    @RequestMapping("/login")
    public String login() {
        adminService.login();
        return "ok.html";
    }
}

练习: 在AdminService中使用AdminDao对象

创建dao,和dao.impl包以及AdminDao,AdminDaoImpl

public interface AdminDao {
    void login();
}
@Repository // 创建Dao对象
public class AdminDaoImpl implements AdminDao {
    @Override
    public void login() {
        System.out.println("持久层执行" );
    }
}

业务层注入Dao层对象

@Service // 加上这个注解,spring容器就会创建该类对象
public class AdminServiceImpl implements AdminService {

    @Autowired // 注入Dao对象
    private AdminDao dao;

    @Override
    public void login() {
        System.out.println("业务层执行..." );
        dao.login();
    }
}

4.1.3 演示2-@Autowired 依赖注入(属性赋值)的原理

@Autowired给属性赋值,是如何绑定属性赋值的? 是按照类型注入的


但是如果spring容器中有多个同类型的对象时,@Autowired注入就会失败

image-20240407144830339

如果spring容器中有多个同类型的对象时 , 如何解决?
此时通过对象名来确定指定注入(赋值)哪个对象. @Qualifier("as2")

对象名是什么? 默认通过@Controller,@Service等这些创建的对象,对象名默认是类名首字母小写,
也可以通过在@Controller,@Service等这些注解后设置对象名,例如@Service(“as1”)

image-20240407145510331

image-20240701154924379

思考,课下扩展: @Autowired和@Resource什么异同

4.1.4 演示3

演示@Component注解创建对象

假如有个类Admin,现在需要该类对象,就可以在该类上加上@Component注解,并在其他地方使用@Autowired注入

image-20230823155730068

4.2 AOP

4.2.1 介绍

Spring中另外一个核心功能,AOP


AOP(Aspect Oriented Programming),即面向切面编程.

OOP(Object Oriented Programming ),即面向对象编程.

AOP面向切面编程,利用 一种称为"横切"的技术,剖开封装的对象内部,并将那些影响了 多个类的公共行为抽取出封装到一个可重用模块,并将其命名 为"Aspect",即切面。所谓"切面",简单说就是那些与业务无关,却为业务模块所共同调用的逻辑或责任封装起来,便于减少系统的重复代码,降低模块之间的耦合度,并有利于未来的可操作性和可维护性。

image-20230612114224473

面向切面编程的作用:就是将项目中与核心逻辑无关的代码横向抽取成切面类,通过织入作用到目标方法,以使目标方法执行前后达到增强的效果.

原理: AOP底层使用的就是动态代理,给AOP指定哪些类型(目标类)需要增强,就会产生对应的代理对象,代理对象执行方法前后会先执行增 强的方法.

好处:减少系统的重复代码,降低模块之间的耦合度,便于维护,可以只关注核心业务

补充:
AOP底层实现原理是代理设计模式,且是动态代理

静态代理
动态代理(jdk动态代理技术 / cglib动态代理技术)
-----
jdk代理技术,要求目标类必须是接口
cglib代理技术, 目标类可以是接口也可以是类

想详细了解的: 
https://www.bilibili.com/video/BV1uN411r7MB/?spm_id_from=333.999.0.0

4.2.2 AOP术语

连接点(Joinpoint):连接点是程序类中客观存在的方法,可被Spring拦截并切入内容。即每个方法在切入之前,都是连接点

切入点(Pointcut):被Spring切入连接点。即真正会增强的目标方法

通知、增强(Advice):可以为切入点添加额外功能,分为:前置通知、后置通知、异常通知、环绕通知等。

目标对象(Target):被代理的目标对象

织入(Weaving):把通知应用到具体的类,进而创建新的代理类的过程。

代理(Proxy):被AOP织入通知后,产生的结代理类。

切面(Aspect):由切点和通知组成

4.2.3 应用场景

  • 事务管理
    • 后续spring管理事务用的AOP原理
  • 权限校验
    • 后期使用Spring Security注解开发时,其实利用了AOP思想
  • 日志记录
  • 性能检测
  • 等等

4.2.4 演示: 前置增强

需求: 实现业务层代码执行时,能出现一些增强的效果

开发步骤

  1. 创建切面类,类上加注解

    • @Component ,加上该注解,springboot框架就会创建该类对象

    • @Aspect , 加上该注解,springboot框架内部就会知道该类是一个切面类

    • 设置切入点方法,并加注解

      • @Pointcut , 用于定义要增强的目标方法路径
  2. 设置各种增强(或者叫通知)方法

  • 注解 解释
    @Around 环绕通知
    @Before 前置通知
    @After 后置通知
    @AfterReturning 后置返回通知
    @AfterThrowing 异常通知

pom.xml添加aop依赖

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

演示给业务层代码设置前置增强

package com.qf.aspect;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.stereotype.Component;

/**
 * --- 天道酬勤 ---
 *
 * @author QiuShiju
 * @date 2024/7/1
 * @desc 切面类,定义增强的方法
 */
@Component  // 由spring创建对象
@Aspect  // 让框架知道,这是一个切面
public class MyAspect {


    /**
     * 自己定义一个方法,用于增强
     * 例如: 权限校验
     * @Before注解,可以在目标方法执行前,执行这个myBefore方法
     * 注解内写的就是,目标方法路径
     *  第一个* ,是返回值任意
     *  com.qf.service.impl.* 是指impl包下的任意类
     *  .* 类中任意方法名
     *  (..) 方法参数任意
     * ------------------------
     * 参数 JoinPoint,就是目标对象
     */
    @Before("execution(* com.qf.service.impl.*.*(..))")
    public void myBefore(JoinPoint joinPoint) {
        System.out.println("方法执行前: 权限校验" );
        System.out.println("目标方法名:"+ joinPoint.getSignature( ).getName( ));

        // 权限校验,如果通过,无事发生,正常执行
        // 权限校验,如果不通过,可以抛出异常,让代码停止,目标方法不执行
        // throw new RuntimeException("权限校验失败");

    }
}

启动项目,测试

  • 正常发请求访问控制层,控制层调用业务层代码时,就会触发AOP的增强机制

image-20240701170011578

4.2.5 演示各种增强

package com.qf.aspect;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;
/**
 * --- 天道酬勤 ---
 *
 * @author QiuShiju
 * @desc
 */
@Component
@Aspect
public class MyAspect {
    /**
     * 将目标方法路径,提取成公共的路径,直接调用
     * 后续其他增强就不用每次都写
     */
    @Pointcut("execution(* com.qf.service.*.*(..))")
    public void myPointcut() {}
    
    /**
     * @Around 注解说明该方法是环绕通知的方法
     * 注解内写的目标方法的路径模板
     *  execution 固定关键词
     *  * 返回值任意
     *  com.qf.day33_springboot.service 包路径
     *  .* 该包下所有文件
     *  .* 该类下所有方法
     *  (..) 该方法所有参数
     *-------------------------
     * ProceedingJoinPoint 参数代表目标方法对象
     */
    @Around("myPointcut()")
    public Object myAround(ProceedingJoinPoint joinPoint) throws Throwable {
        // 目标方法前:
        System.out.println("开启事务/权限校验" );

        // 目标方法执行
        Object ret = joinPoint.proceed( );
        System.out.println("目标方法返回值---> " + ret );
        // 目标方法后:
        System.out.println("提交事务/日志记录" );
        return ret;
    }

    /**
    JoinPoint 是目标方法对象
    */
    @Before("myPointcut()")
    public void myBefore(JoinPoint joinPoint) {
        // 目标对象
        Object target = joinPoint.getTarget( );
        System.out.println("target = " + target);
        // 获得目标方法签名(方法名)
        Signature signature = joinPoint.getSignature( );
        System.out.println("signature = " + signature);

        System.out.println("前置通知--->权限校验--->OK" );

        // 假设权限校验没有通过,通过抛出异常让代码停下,不再执行目标方法
        // System.out.println("前置通知--->权限校验--->ERROR" );
        // throw new RuntimeException("权限校验--->ERROR");
    }

    @After("myPointcut()")
    public void myAfter() {
        // 获得ip
        // 获得时间
        // 获得人名
        // 获得日志描述信息
        System.out.println("后置通知--->记录日志,释放资源" );
    }

    /**
     * 后置返回增强,一般用于接收目标方法的返回值
     * --------------------------------
     * 当注解括号内参数只有一个,且参数名是value,那么可以省略value直接写值
     * 当多于1个参数,所有参数都需要写k=v
     * ---------------------------------
     * @AfterReturning 后置返回增强,用于目标方法的返回值
     *  参数value用于指定目标方法
     *  参数returning用于指定返回值,该返回值需要定义在本方法的参数上
     */
    @AfterReturning(value = "myPointcut()",returning = "ret")
    public Object myAfterRet(Object ret) {
        System.out.println("后置返回通知,接收到目标方法返回值--->" + ret);
        return ret;
    }

    @AfterThrowing(value = "myPointcut()",throwing = "e")
    public void myException(Exception e) {
        System.out.println("目标方法报的错---> " + e.getMessage());
    }
}

4.2.6 AOP实战-Log记录

暂时无法完成,还有部分知识没讲,等讲完mvc和mybatis后再来实战,暂时可以大概看一眼

实战需求参考若依系统首页 (ruoyi.vip)

image-20230819185633620

即将用户在系统中做的任何操作都记录到数据库,供后续查看

首先设计日志表,将来存储日志信息

CREATE TABLE `log` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `log_time` datetime DEFAULT NULL,
  `log` varchar(255) DEFAULT NULL,
  `ip` varchar(255) DEFAULT NULL,
  `name` varchar(255)