springboot04

一、AOP

1.1AOP的场景

1.日志切面

2.事务切面

        @Transactional

                1)设置自动模式提交关闭set autocommit=false

                2)开启事务 start transaction

                3)dml、dql   不可以执行ddl(会自动提交)

                4)commit  rollback

                5)开启自动提交模式 set autocommit=true

3.权限切面  springsecurity

        @RequirePermission()

                //校验权限
                public void login(){}
                //校验权限(是否登录成功)
                //是否是管理员
                //查询账户

4.自定义切面(自定义业务逻辑)

1.2AOP的由来

AOP: 将与主业务无关的辅助业务逻辑,提取出来,形成aop切面,然后动态的切入到任务需要的位置。

1.3切面类

@Aspect
@Component
class MyLog{
	//切入点
	@PointCut("表达式")
	public void pt(){}
	@Before
	public void before(){}
	@After
	public void after(){}
	@Exception
	public void excetpion(){}
}

1.4自定义日志切面

1.4.1目标类、目标方法

package com.hl.springboot4.web;

import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/*
目标类
 */
@RestController
@RequestMapping("/user")
public class UserController {
    //目标方法
    @RequestMapping("/m1")
    public void m1(){
        System.out.println(1/0);
        System.out.println("m1..........");
    }
    //目标方法
    @RequestMapping("/m2")
    public void m2(){
        System.out.println("m2..........");
    }
}

1.4.2切面类、切面方法

  <!-- 切面织入的jar包-->
        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjweaver</artifactId>
        </dependency>
/*
切面类
 */
@Aspect  //将当前类标记为切面类
@Component
public class MyLog {
    
    public void before(){
        System.out.println("before method...");
    }
    
    public void after(){
        System.out.println("after method...");
    }
    
}

1.4.3定义切入点和通知

/*
切面类
 */
@Aspect  //将当前类标记为切面类
@Component
public class MyLog {
    /*
    切入点 :通过切入点,定位到具体的目标类、目标方法
    execution(* com.hl.springboot4.web.UserController.*(..))
    第一个*代表方法的返回值类型
    第二个*代表方法名
    (..) 代表方法任意形参
     */
    @Pointcut(value = "execution(* com.hl.springboot4.web.UserController.*(..))")
    //@Pointcut(value = "execution(* com.hl.springboot4..*.*(..))")
    public void pt(){}
    //切面方法
    /*
    通知 : 切面方法在目标方法上执行的时机
    前置通知:
    后置通知:
        after :目标方法是否异常,都要执行
        afterReturning:目标方法成功返回后执行
    异常通知:
    环绕通知:
     */
    @Before("pt()")
    public void before(){
        System.out.println("before method...");
    }
    @After("pt()")
    public void after(){
        System.out.println("after method...");
    }
    @AfterReturning(value = "pt()",returning = "obj")
    public void afterReturning(Object obj){
        System.out.println(obj);
        System.out.println("after returning...");
    }

    @AfterThrowing(value = "pt()",throwing = "e")
    public void afterThrowing(Throwable e){
        System.out.println("after throwing...");
    }
    /*
    环绕通知=前置通知+后置通知
     */
    @Around("pt()")
    public void around(ProceedingJoinPoint joinPoint) throws Throwable {
        //前置通知
        System.out.println("around ..... before");
        //调用目标方法
        joinPoint.proceed();
        //后置通知
        System.out.println("around ..... after");
    }
}

1.4.4测试

1.5AOP名词

aspect 面向切面编程语言 方法 方法参数 初始化

spring----针对 aspect的实现,实现了其中的部分功能

连接点一定是切入点,但是切入点不一定是连接点。

名称
Joinpoint(连接点)连接点则指可以被动态代理拦截目标类的方法。
Pointcut(切入点)又称切点,指要对哪些 Joinpoint 进行拦截,即连接点的选择器。
Advice(通知)指拦截到 Joinpoint 之后要执行的代码,即对切入点增强的内容。又称为增强。
Target(目标)指代理的目标对象,通常也被称为被通知(advised)对象。
Weaving(织入)指把增强代码应用到目标对象上,生成代理对象的过程。
Proxy(代理)指生成的代理对象。
Aspect(切面)通知和切入点共同组成了切面。
通知说明
before(前置通知)通知方法在目标方法调用之前执行
after(后置通知)通知方法在目标方法返回或异常后调用
after-returning(返回后通知)通知方法会在目标方法返回后调用
after-throwing(抛出异常通知)通知方法会在目标方法抛出异常后调用
around(环绕通知)

 

1.5.1代理模式

静态代理

提前在项目中创建好的代理类

//代理类
class TargetProxy{
	aspect.before()
	target.m1()
	aspect.after()
}
动态代理

在项目运行过程中,动态创建的代理类

$Proxy  =  Proxy.create(Target,Aspect);
jdk代理模式:针对接口的代理,要求被代理的类必须实现接口
cglib代理:针对类的处理

1.6spring整合jdbc实现事务操作

1.6.1jar包准备

<!--        mysql-->
<dependency>
    <groupId>com.mysql</groupId>
    <artifactId>mysql-connector-j</artifactId>
</dependency>
<!--springboot-jdbc-->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>

1.6.2配置文件

server:
  port: 8080
#数据库连接
spring:
  datasource:
    url: jdbc:mysql://localhost:3306/yan9
    driver-class-name: com.mysql.cj.jdbc.Driver
    username: root
    password: 123456

1.6.3数据库表

create table account(
	id int primary key auto_increment,
	name char(16),
	money double
);

insert into account(name,money) values ('佳鑫',10000),('李凯',2000); 

1.6.4web层

@RestController
public class AccountController {
    @Autowired
    private AccountService accountService;

    @RequestMapping("/transfer")
    public Object transfer(Integer fromId, Integer toId, Double money){
        //接收数据,传递数据到业务层
        boolean flag = accountService.transfer(fromId, toId, money);
        //返回结果给客户端
        return flag;
    }
}

1.6.5service层

public interface AccountService {
    public boolean transfer(Integer fromId, Integer toId, double money);
}
@Service
@Transactional
public class AccountServiceImpl implements AccountService{
    @Autowired
    private AccountDao accountDao;
    @Override
//    @Transactional//事务注解
    public boolean transfer(Integer fromId, Integer toId, double money) {
        //转出方法
        int num1 = accountDao.transferOut(fromId,money);
        System.out.println(1/0);
        //转入方法
        int num2 = accountDao.transferIn(toId,money);
        return num1==num2&&num1>0 ? true : false;
    }
}

1.6.6dao层

public interface AccountDao {
    //转出
    public int transferOut(Integer fromId,Double money);
    //转入
    public int transferIn(Integer toId,Double money);
}
package com.hl.springboot4.dao;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Repository;
import org.springframework.web.bind.annotation.RequestMapping;

@Repository
public class AccountDaoImpl implements AccountDao{
    @Autowired
    private JdbcTemplate jdbcTemplate;
    @Override
    public int transferOut(Integer fromId, Double money) {
        String sql = "update account set money = money - ? where id = ?";
        return jdbcTemplate.update(sql, money, fromId);
    }

    @Override
    public int transferIn(Integer toId, Double money) {
        String sql = "update account set money = money + ? where id = ?";
        return jdbcTemplate.update(sql, money, toId);
    }
}

 

1.7@Transactional


@EnableTransactionManagement 开启全局事务支持
@Transactional 使用事务
    readOnly = true, 只读事务  当前事务中查询出的数据,不能用户更新操作
    rollbackFor = Exception.class  当遇到特定异常,执行rollback回滚
    noRollbackFor = {} 当发生某种异常,不回滚
    timeout=数值   超时时间
    propagation =  事务的传播机制  a--调用-->b b是否能够使用事务的问题
            Propagation.REQUIRED
    isolation =  事务的隔离行为  两个方法在使用事务时,对方操作的数据是否可见
 

事务的传播行为

事务传播描述的事务与事务之间的传播关系, 常见的场景是在一个嵌套调用的方法中,外部方法和内部每个方法都添加了事务管理, 不同的传播行为配置,决定了最终是这些方法是使用同一个事务,还是在不同的事务中运行。

面试

1、aop切面相关的名词(掌握)

名称
Joinpoint(连接点)连接点则指可以被动态代理拦截目标类的方法。
Pointcut(切入点)又称切点,指要对哪些 Joinpoint 进行拦截,即连接点的选择器。
Advice(通知)指拦截到 Joinpoint 之后要执行的代码,即对切入点增强的内容。又称为增强。
Target(目标)指代理的目标对象,通常也被称为被通知(advised)对象。
Weaving(织入)指把增强代码应用到目标对象上,生成代理对象的过程。
Proxy(代理)指生成的代理对象。
Aspect(切面)通知和切入点共同组成了切面。

2、如何实现自定义切面(掌握)

  1. 定义切面类(加@Aspect@Component注解)

  2. 配置切入点表达式(@Pointcut

  3. 编写通知方法(@Before/@After/@Around等)

  4. 启用AOP支持(@EnableAspectJAutoProxy

3、事务的四个特性

特性说明
原子性(Atomicity)事务是不可分割的工作单位,要么全部成功,要么全部失败回滚
一致性(Consistency)事务执行前后,数据库从一个一致状态变到另一个一致状态
隔离性(Isolation)多个事务并发执行时,一个事务不应影响其他事务
持久性(Durability)事务提交后,对数据库的改变是永久性的

4、如何使用事务@Transactional

* @EnableTransactionManagement
* @Transactional
*       readOnly = true 只读事务   当前事务查询出的数据,不能用户更新操作
*       rollbackFor = Exception.class  当遇到特定异常,执行rollback回滚
*       noRollbackFor = {}  当发生某种异常,不回滚
*       timeout = 1000  超时时间
*       propagation = 事务的传播机制  a--调用-->b b是否能够使用事务的问题
*               Propagation.REQUIRE
*       isolation = 事物的隔离行为  两个方法在使用事务时,对方操作的数据是否可见*/

5、事务的传播机制

传播行为说明
REQUIRED(默认)当前有事务则加入,没有则新建
SUPPORTS当前有事务则加入,没有则以非事务运行
MANDATORY当前必须有事务,否则抛异常
REQUIRES_NEW新建事务,挂起当前事务(若有)
NOT_SUPPORTED以非事务方式执行,挂起当前事务(若有)
NEVER以非事务方式执行,当前有事务则抛异常
NESTED当前有事务则在嵌套事务内执行

6、springboot整合jdbc过程

  1. 添加依赖:spring-boot-starter-jdbc + 数据库驱动

  2. 配置数据源(application.yml):

    spring:
      datasource:
        url: jdbc:mysql://localhost:3306/db
        username: root
        password: 123456
        driver-class-name: com.mysql.cj.jdbc.Driver
  3. 注入JdbcTemplate使用:

    @Autowired
    private JdbcTemplate jdbcTemplate;
    
    public List<User> findAll() {
        return jdbcTemplate.query("SELECT * FROM user", 
            (rs, rowNum) -> new User(rs.getInt("id"), rs.getString("name")));
    }

7、文件上传、下载功能如何实现

文件上传
后端控制器

@RequestMapping("/save")
    public R save(User user, MultipartFile file) throws IOException {
        //获取文件大小
        long size = file.getSize();
        System.out.println("文件大小字节数:"+size);
        //保存文件到服务器(本地磁盘)
        String path = "D:\\AStudy\\shixipeixun\\springbootProject\\springboot2\\src\\main\\resources\\static\\";
        String oldFileName = file.getOriginalFilename();
        String suffix = oldFileName.substring(oldFileName.lastIndexOf("."));
        String newFileName = UUID.randomUUID()+ suffix;
        IOUtils.copy(file.getInputStream(),new FileOutputStream(path+newFileName));
 
        //将文件名or相对路径+文件名 保存到数据库表中
        // (文件服务器)保存绝对路径到数据库表中
        user.setImgPath(newFileName);
        int num = userDao.save(user);
        return R.ok();
    }


 springboot 环境下

前端 ----post请求、body-->form-data---选择file类型

后端----  接受文件对象  @PostMapping  public String  upload(MultipartFile  file)

              保存文件对象  接收到的临时文件转存到指定目录(底层是字节流copy   从输出流copy到输入流)

              返回文件路径

文件下载
后端控制器

@RequestMapping("/download")
    public void download(String filename,HttpServletResponse response) throws IOException{
        //根据下载的文件名,找到文件对象
        File f = new File("D:\\AStudy\\shixipeixun\\springbootProject\\springboot2\\src\\main\\resources\\static\\"+filename);
        InputStream in = new FileInputStream(f);
        //设置响应头
        response.setHeader("Content-Disposition","attachment;filename"+filename);
        //从输入流,copy到输出流
        IOUtils.copy(in,response.getOutputStream());
        //关闭流
        response.getOutputStream().close();
        in.close();
    }


1)前端发起请求,传递要下载的文件名

heep://localhost:8080/user/download?filename=001.jpg

2)接受要下载的文件名

3)找到文件路径

File file = new File(path+"/"+filename)

4)将file对象转为输出相应流,响应给前端

OutputStream out = HttpServletResponse.getOutputStream();

5) response.setHeader("Content-Disposition","attachment;filename"+filename);

通知浏览器以下载附件的方式打开响应流

IOUtils.copy(in,out)

6)关闭流

8、aop使用场景

  1. 日志记录:自动记录方法调用日志

  2. 事务管理:声明式事务实现

  3. 权限控制:方法调用前的权限校验

  4. 性能监控:统计方法执行时间

  5. 异常处理:统一异常捕获和处理

  6. 缓存管理:方法结果缓存

  7. 数据校验:参数自动校验

  8. 接口限流:控制方法调用频率

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值