JavaWeb(五)

1.事务管理

1.1 事务回顾

  • 概念

事务 是一组操作的集合,它是一个不可分割的工作单位,这些操作 要么同时成功,要么同时失败

  • 操作
开启事务(一组操作开始前,开启事务): start transaction / begin ;
提交事务(这组操作全部成功后,提交事务): commit ;
回滚事务(中间任何一个操作出现异常,回滚事务): rollback ;

  •  案例:解散部门:删除部门,同时删除该部门下的员工
DeptServiceImpl.java
@Override
    public void deleteById(Integer id) {
        deptMapper.deleteById(id);

        empMapper.deleteByDeptId(id);

    }
EmpMapper.java
@Delete("delete from tlias.emp where tlias.emp.dept_id=#{deptId}")
    void deleteByDeptId(Integer deptId);

  • 问题

即使程序运行抛出了异常,部门依然删除了,但是部门下的员工却没有删除,造成了数据的不一致。

  • 解决方案

1.2 spring事务管理

  • 注解
注解:@ Transactional
位置:业务( service )层的方法上、类上、接口上
作用:将当前方法交给 spring 进行事务管理,方法执行前,开启事务;成功执行完毕,提交事务;出现异常,回滚事务

  • 开启日志
logging:
  level:
    org.springframework.jdbc.support.JdbcTransactionManager: debug

1.3 事务进阶

1.3.1 rollbackFor
默认情况下,只有出现 RuntimeException 才回滚异常。 rollbackFor 属性用于控制出现何种异常类型,回滚事务。
@Transactional(rollbackFor = Exception.class )
    @Override
    public void deleteById(Integer id) throws Exception {
        deptMapper.deleteById(id);

        if(true){
            throw new Exception("出错啦。。。。");
        }

        empMapper.deleteByDeptId(id);

    }
1.3.2 propagation
事务传播行为:指的就是当一个事务方法被另一个事务方法调用时,这个事务方法应该如何进行事务控制。

属性值

含义

REQUIRED

默认值需要事务,有则加入,无则创建新事务

REQUIRES_NEW

需要新事务,无论有无,总是创建新事务

SUPPORTS

支持事务,有则加入,无则在无事务状态中运行

NOT_SUPPORTED

不支持事务,在无事务状态下运行,如果当前存在已有事务,则挂起当前事务

MANDATORY

必须有事务,否则抛异常

NEVER

必须没事务,否则抛异常

  • 案例

需求:解散部门时,无论是成功还是失败,都要记录操作日志。

步骤:

  . 解散部门:删除部门、删除部门下的员工

  . 记录日志到数据库表中

@Transactional
    @Override
    public void deleteById(Integer id) throws Exception {


        try {
            deptMapper.deleteById(id);

            int t=1/0;


            empMapper.deleteByDeptId(id);


        } finally {
            DeptLog deptLog=new DeptLog();
            deptLog.setCreateTime(LocalDateTime.now());
            deptLog.setDescription("");
            deptLogService.insert(deptLog);
        }

    }
@Transactional(propagation = Propagation.REQUIRES_NEW)
@Service
public class DeptLogServiceImpl implements DeptLogService {


    @Autowired
    private DeptLogMapper deptLogMapper;

    @Override
    public void insert(DeptLog deptLog) {
        deptLogMapper.insert(deptLog);
    }
}
  • 场景
REQUIRED :大部分情况下都是用该传播行为即可。
REQUIRES_NEW :当我们不希望事务之间相互影响时,可以使用该传播行为。比如:下订单前需要记录日志,不论订单保存成功与否,都需要保证日志记录能够记录成功。

2 AOP基础

2.1 AOP基础概述

  • AOPAspect Oriented Programming面向切面编程、面向方面编程),其实就是面向特定方法编程。
  • 场景:案例部分功能运行较慢,定位执行耗时较长的业务方法,此时需要统计每一个业务方法的执行耗时

  • 实现:动态代理是面向切面编程最主流的实现。而SpringAOPSpring框架的高级技术,旨在管理bean对象的过程中,主要通过底层的动态代理机制,对特定的方法进行编程。

2.2 AOP快速入门

  • 导入依赖:在pom.xml中导入AOP的依赖
<dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-aop</artifactId>
</dependency>
  • 编写AOP程序:针对于特定方法根据业务需要进行编程
package cn.jxust.tliaswebmanagement.aop;


import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.stereotype.Component;

@Component
@Slf4j
@Aspect
public class TimeAspect {

    public Object record(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
        long begin = System.currentTimeMillis();

        Object res = proceedingJoinPoint.proceed();

        long end = System.currentTimeMillis();

        log.info("执行时间为:{}ms",end-begin);

        return  res;


    }

}
  • 场景

记录操作日志、权限控制、事务管理、、、

  • 优势

代码无侵入、减少重复代码、提高开发效率、维护方便、、、 

2.3 AOP核心概念

  • 连接点:JoinPoint,可以被AOP控制的方法(暗含方法执行时的相关信息)
  • 通知:Advice,指哪些重复的逻辑,也就是共性功能(最终体现为一个方法)
  • 切入点:PointCut,匹配连接点的条件,通知仅会在切入点方法执行时被应用
  • 切面:Aspect,描述通知与切入点的对应关系(通知+切入点)
  • 目标对象:Target,通知所应用的对象

  •  AOP执行流程

代码

3 AOP进阶

3.1 通知类型

  • 通知类型

1. @Around :环绕通知,此注解标注的通知方法在目标方法前、后都被执行
2. @Before :前置通知,此注解标注的通知方法在目标方法前被执行
3. @After :后置通知,此注解标注的通知方法在目标方法后被执行,无论是否有异常都会执行
4. @AfterReturning 返回后通知,此注解标注的通知方法在目标方法后被执行,有异常不会执行
5. @AfterThrowing 异常后通知,此注解标注的通知方法发生异常后执行
  • 注意事项
@Around 环绕通知需要自己调用 ProceedingJoinPoint.proceed () 来让原始方法执行,其他通知不需要考虑目标方法执行
@Around 环绕通知方法的返回值,必须指定为 Object ,来接收原始方法的返回值。

代码

  • @PointCut:该注解的作用是将公共的切点表达式抽取出来,需要用到时引用该切点表达式即可。 
 @Pointcut("execution(* cn.jxust.springbootaopquickstart.service.impl.DeptServiceImpl.*(..))")
    public void pt(){}

无侵入

3.2 通知顺序

 当有多个切面的切入点都匹配到了目标方法,目标方法运行时,多个通知方法都会被执行。

  • 执行顺序

1. 不同切面类中,默认按照切面类的 类名字母排序
目标方法前的通知方法:字母排名靠前的先执行
目标方法后的通知方法:字母排名靠前的后执行
2. @Order( 数字 ) 加在切面类上来控制顺序
目标方法前的通知方法:数字小的先执行
目标方法后的通知方法:数字小的后执行

3.3 切入点表达式

切入点表达式:

  • 切入点表达式:描述切入点方法的一种表达式
  • 作用:主要用来决定项目中的哪些方法需要加入通知
  • 常见形式:
  • 1.execution(……):根据方法的签名来匹配
  • 2.@annotation(……) :根据注解匹配
3.3.1 切入点表达式--excution

execution 主要根据方法的返回值、包名、类名、方法名、方法参数等信息来匹配,语法为: 

execution(访问修饰符?  返回值  包名.类名.?方法名(方法参数) throws 异常?)
  • 其中带 ? 的表示可以省略的部分
  • 访问修饰符:可省略(比如: publicprotected
  • 包名.类名: 可省略
  • throws 异常:可省略(注意是方法上声明抛出的异常,不是实际抛出的异常)
  • 可以使用通配符描述切入点
  • * :单个独立的任意符号,可以通配任意返回值、包名、类名、方法名、任意类型的一个参数,也可以通配包、类、方法名的一部分
execution(* com.*.service.*.update*(*))
  • .. :多个连续的任意符号,可以通配任意层级的包,或任意类型、任意个数的参数
execution(* com.itheima..DeptService.*(..))
  • 注意事项:根据业务需要,可以使用 且(&&)、或(||)、非(!) 来组合比较复杂的切入点表达式。
  • 书写建议
  • 所有业务方法名命名时尽量规范,方便切入点表达式快速匹配。如:查询类方法都是 find 开头,更新类方法都是 update开头。
  • 描述切入点方法通常基于接口描述,而不是直接描述实现类,增强拓展性
  • 在满足业务需要的前提下,尽量缩小切入点的匹配范围。如:包名匹配尽量不使用 ..,使用 * 匹配单个包。
3.3.2 切入点表达式-@annotation
  • @annotation 切入点表达式,用于匹配标识有特定注解的方法。
@annotation(com.itheima.anno.Log)
package cn.jxust.springbootaopquickstart.aop;


import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface MyLog {
}
 @Pointcut("@annotation(cn.jxust.springbootaopquickstart.aop.MyLog)")
    public void pt(){}

3.4 AOP连接点

  • Spring中用JoinPoint抽象了连接点,用它可以获得方法执行时的相关信息,如目标类名、方法名、方法参数等。
  • 对于 @Around 通知,获取连接点信息只能使用  ProceedingJoinPoint
@Around("execution(* com.itheima.service.DeptService.*(..))")
    public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
        String className = joinPoint.getTarget().getClass().getName(); //获取目标类名
        Signature signature = joinPoint.getSignature(); //获取目标方法签名
        String methodName = joinPoint.getSignature().getName(); //获取目标方法名
        Object[] args = joinPoint.getArgs(); //获取目标方法运行参数
        Object res = joinPoint.proceed(); //执行原始方法,获取返回值(环绕通知)
        return res;
    }
  • 对于其他四种通知,获取连接点信息只能使用 JoinPoint ,它是 ProceedingJoinPoint 的父类型
 @Before("execution(* com.itheima.service.DeptService.*(..))")
    public void before(JoinPoint joinPoint) {
        String className = joinPoint.getTarget().getClass().getName(); //获取目标类名
        Signature signature = joinPoint.getSignature(); //获取目标方法签名
        String methodName = joinPoint.getSignature().getName(); //获取目标方法名
        Object[] args = joinPoint.getArgs(); //获取目标方法运行参数 
    }

4 AOP案例

  • 要求:将案例中 增、删、改 相关接口的操作日志记录到数据库表中。
  • 操作日志:日志信息包含:操作人、操作时间、执行方法的全类名、执行方法名、方法运行时参数、返回值、方法执行时长
  • 思路分析:
    • 需要对所有业务类中的增、删、改 方法添加统一功能,使用 AOP 技术最为方便
    • 由于增、删、改 方法名没有规律,可以自定义 @Log 注解完成目标方法匹配

  • 准备:
  • 在案例工程中引入AOP的起步依赖
  • 导入资料中准备好的数据库表结构,并引入对应的实体类
  • 编码:
  • 自定义注解 @Log
  • 定义切面类,完成记录操作日志的逻辑
  •  获取当前登录用户:获取request对象,从请求头中获取到jwt令牌,解析令牌获取出当前用户的id。
  • 代码

LogAspect.java

package cn.jxust.tliaswebmanagement.aop;


import cn.jxust.tliaswebmanagement.mapper.OperateLogMapper;
import cn.jxust.tliaswebmanagement.pojo.OperateLog;
import cn.jxust.tliaswebmanagement.utils.JwtUtils;
import com.alibaba.fastjson2.JSONObject;
import io.jsonwebtoken.Claims;
import jakarta.servlet.http.HttpServletRequest;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.time.LocalDateTime;
import java.util.Arrays;

@Slf4j
@Component
@Aspect
public class LogAspect {


    @Autowired
    private HttpServletRequest request;


    @Autowired
    private OperateLogMapper operateLogMapper;

    @Around("@annotation(cn.jxust.tliaswebmanagement.anno.Log)")
    public Object recordLog(ProceedingJoinPoint joinPoint) throws Throwable {

        //操作人ID
        String jwt = request.getHeader("token");
        Claims claims = JwtUtils.parseJWT(jwt);

        Integer id = (Integer)claims.get("id");

        //操作时间
        LocalDateTime now = LocalDateTime.now();

        //操作类名
        String name = joinPoint.getTarget().getClass().getName();

        //操作方法名
        String method = joinPoint.getSignature().getName();

        //操作方法参数
        Object[] args = joinPoint.getArgs();
        String s = Arrays.toString(args);


        long begin = System.currentTimeMillis();
        //方法的返回值
        Object result = joinPoint.proceed();
        String jsonString = JSONObject.toJSONString(result);

        long end = System.currentTimeMillis();


        //操作耗时
        Long time=end-begin;

        OperateLog operateLog=new OperateLog(null,id,now,name,method,s,jsonString,time);
        operateLogMapper.insert(operateLog);

        return result;
    }



}

OperateLog.java

package cn.jxust.tliaswebmanagement.pojo;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.time.LocalDateTime;

@Data
@NoArgsConstructor
@AllArgsConstructor
public class OperateLog {
    private Integer id; //ID
    private Integer operateUser; //操作人ID
    private LocalDateTime operateTime; //操作时间
    private String className; //操作类名
    private String methodName; //操作方法名
    private String methodParams; //操作方法参数
    private String returnValue; //操作方法返回值
    private Long costTime; //操作耗时
}

 5.配置优先级

  • SpringBoot 中支持三种格式的配置文件:
    • server.port=8081
    • server:

         port: 8082

    • server:

         port: 8083

  • 注意事项:虽然springboot支持多种格式配置文件,但是在项目开发时,推荐统一使用一种格式的配置 yml是主流)

  • SpringBoot 除了支持配置文件属性配置,还支持Java系统属性命令行参数的方式进行属性配置。

  • 优先级(低→高)

    • application.yaml(忽略)
    • application.yml
    • application.properties
    • java系统属性(-Dxxx=xxx
    • 命令行参数(--xxx=xxx

6 Bean管理

6.1 获取bean

  • 默认情况下,Spring项目启动时,会把bean都创建好放在IOC容器中,如果想要主动获取这些bean,可以通过如下方式:
    • 根据name获取bean:Object getBean(String name)
    • 根据类型获取bean:<T> T getBean(Class<T> requiredType)
    • 根据name获取bean(带类型转换):<T> T getBean(String name, Class<T> requiredType)
@Autowired
    private ApplicationContext applicationContext;

    @Test
    public void testBean(){
        DeptServiceImpl deptServiceImpl = (DeptServiceImpl) applicationContext.getBean("deptServiceImpl");
        System.out.println(deptServiceImpl);

        DeptServiceImpl bean = applicationContext.getBean(DeptServiceImpl.class);
        System.out.println(bean);

        DeptServiceImpl bean1 = applicationContext.getBean("deptServiceImpl", DeptServiceImpl.class);
        System.out.println(bean1);
    }
  • 注意事项

上述所说的 【Spring项目启动时,会把其中的bean都创建好还会受到作用域及延迟初始化影响,这里主要针对于 默认的单例非延迟加载的bean而言。

6.2 Bean的作用域

  • Spring支持五种作用域,后三种在web环境才生效:

作用域

说明

singleton

容器内同 名称 bean 只有一个实例(单例)(默认)

prototype

每次使用该 bean 时会创建新的实例(非单例)

request

每个请求范围内会创建新的实例(web环境中,了解)

session

每个会话范围内会创建新的实例(web环境中,了解)

application

每个应用范围内会创建新的实例(web环境中,了解)

  • 可以通过 @Scope 注解来进行配置作用域:
@Scope("prototype")
@RestController
@RequestMapping("/depts")
public class DeptController {
}
  • 注意事项
默认 singleton bean ,在容器启动时被创建,可以使用 @Lazy 注解来延迟初始化(延迟到第一次使用时)。
prototype bean ,每一次使用该 bean 的时候都会创建一个新的实例。
实际开发当中,绝大部分的 Bean 是单例的,也就是说绝大部分 Bean 不需要配置 scope 属性。

6.3 第三方Bean

  • 如果要管理的bean对象来自于第三方(不是自定义的),是无法用 @Component 及衍生注解声明bean的,就需要用到 @Bean注解。
  • 要管理的第三方bean对象,建议对这些bean进行集中分类配置,可以通过 @Configuration 注解声明一个配置类。
package cn.jxust.tliaswebmanagement.config;


import org.dom4j.io.SAXReader;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class CommonConfig {


    @Bean
    public SAXReader reader(){
        return new SAXReader();
    }

}
  • 通过@Bean注解的namevalue属性可以声明bean的名称,如果不指定,默认bean的名称就是方法名。
  • 如果第三方bean需要依赖其它bean对象,直接在bean定义方法中设置形参即可,容器会根据类型自动装配。
  • @Component 及衍生注解 与 @Bean注解使用场景?
  • 项目中自定义的,使用@Component及其衍生注解
  • 项目中引入第三方的,使用@Bean注解

6.4 解析XML文件

依赖



<dependency>
            <groupId>org.dom4j</groupId>
            <artifactId>dom4j</artifactId>
            <version>2.1.3</version>
        </dependency>
@Autowired
    private SAXReader saxReader;

    @Test
    public void testXML() throws DocumentException {
//        SAXReader saxReader=new SAXReader();
        Document document = saxReader.read(this.getClass().getClassLoader().getResource("1.xml"));

        Element rootElement = document.getRootElement();
        String name = rootElement.element("name").getText();
        String age = rootElement.element("age").getText();

        System.out.println(name+' '+age);
    }

7 springboot原理(自动配置)

7.1 自动配置原理

  • 方案一:@ComponentScan 组件扫描
@ComponentScan({"com.example","com.itheima"})
@SpringBootApplication
public class SpringbootWebConfig2Application {
}
  • 方案二:@Import 导入。使用@Import导入的类会被Spring加载到IOC容器中导入形式主要有以下几种:
  • 导入 普通类
  • 导入 配置类
  • 导入 ImportSelector 接口实现类
  • @EnableXxxx注解,封装@Import注解
@Import({TokenParser.class, HeaderConfig.class})
@SpringBootApplication
public class SpringbootWebConfig2Application {
}
  • 源码跟踪

@SpringBootApplication:该注解标识在SpringBoot工程引导类上,是SpringBoot最最最重要的注解。该注解由三个部分组成:

  • @SpringBootConfiguration:该注解与 @Configuration 注解作用相同,用来声明当前也是一个配置类。
  • @ComponentScan:组件扫描,默认扫描当前引导类所在包及其子包。
  • @EnableAutoConfigurationSpringBoot实现自动化配置的核心注解。
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(excludeFilters = { @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
		@Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })
public @interface SpringBootApplication {
}
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Configuration
@Indexed
public @interface SpringBootConfiguration {
    @AliasFor(
        annotation = Configuration.class
    )
    boolean proxyBeanMethods() default true;
}
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
@Import(AutoConfigurationImportSelector.class)
public @interface EnableAutoConfiguration {

	/**
	 * Environment property that can be used to override when auto-configuration is
	 * enabled.
	 */
	String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration";

	/**
	 * Exclude specific auto-configuration classes such that they will never be applied.
	 * @return the classes to exclude
	 */
	Class<?>[] exclude() default {};

	/**
	 * Exclude specific auto-configuration class names such that they will never be
	 * applied.
	 * @return the class names to exclude
	 * @since 1.3.0
	 */
	String[] excludeName() default {};

}
  • @Conditional
    • 作用:按照一定的条件进行判断,在满足给定条件后才会注册对应的bean对象Spring IOC容器中。
    • 位置:方法、类
    • @Conditional 本身是一个父注解,派生出大量的子注解:
    • @ConditionalOnClass判断环境中是否有对应字节码文件,才注册beanIOC容器。
    • @ConditionalOnMissingBean判断环境中没有对应的bean(类型 或 名称) ,才注册beanIOC容器。
    • @ConditionalOnProperty判断配置文件中有对应属性和值,才注册beanIOC容器。
@Bean
@ConditionalOnClass(name = "io.jsonwebtoken.Jwts") //当前环境存在指定的这个类时,才声明该bean 
public HeaderParser headerParser(){...}
@Bean
@ConditionalOnMissingBean //当不存在当前类型的bean时,才声明该bean 
public HeaderParser headerParser(){...}
@Bean
@ConditionalOnProperty(name = "name",havingValue = "itheima") //配置文件中存在对应的属性和值,才注册bean到IOC容器。
public HeaderParser headerParser(){...}

7.2 案例(自定义starter)

  • 场景:在实际开发中,经常会定义一些公共组件,提供给各个项目团队使用。而在SpringBoot的项目中,一般会将这些公共组件封装为SpringBoot starter
  • 需求:
    • 需求:自定义aliyun-oss-spring-boot-starter,完成阿里云OSS操作工具类 AliyunOSSUtils 的自动配置。
    • 目标:引入起步依赖引入之后,要想使用阿里云OSS,注入 AliyunOSSUtils直接使用即可。
  • 步骤:
    • 创建 aliyun-oss-spring-boot-starter 模块
    • 创建 aliyun-oss-spring-boot-autoconfigure 模块,在starter中引入该模块
    • aliyun-oss-spring-boot-autoconfigure 模块中的定义自动配置功能,并定义自动配置文件 META-INF/spring/xxxx.imports
  • 依赖管理功能:aliyun-oss-spring-boot-starter
<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>
	<parent>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-parent</artifactId>
		<version>3.1.5</version>
		<relativePath/> <!-- lookup parent from repository -->
	</parent>
	<groupId>com.aliyun.oss</groupId>
	<artifactId>aliyun-oss-spring-boot-starter</artifactId>
	<version>0.0.1-SNAPSHOT</version>

	<properties>
		<java.version>17</java.version>
	</properties>
	<dependencies>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter</artifactId>
		</dependency>

		<dependency>
			<groupId>com.aliyun.oss</groupId>
			<artifactId>aliyun-oss-spring-boot-autoconfigure</artifactId>
		</dependency>


	</dependencies>



</project>
  • 自动配置功能:aliyun-oss-spring-boot-autoconfigure
<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>3.1.5</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.aliyun.oss</groupId>
    <artifactId>aliyun-oss-spring-boot-autoconfigure</artifactId>
    <version>0.0.1-SNAPSHOT</version>



    <properties>
        <java.version>17</java.version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
        </dependency>

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

        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>


        <!--阿里云OSS-->
        <dependency>
            <groupId>com.aliyun.oss</groupId>
            <artifactId>aliyun-sdk-oss</artifactId>
            <version>3.15.1</version>
        </dependency>

        <dependency>
            <groupId>javax.xml.bind</groupId>
            <artifactId>jaxb-api</artifactId>
            <version>2.3.1</version>
        </dependency>
        <dependency>
            <groupId>javax.activation</groupId>
            <artifactId>activation</artifactId>
            <version>1.1.1</version>
        </dependency>
        <!-- no more than 2.3.3-->
        <dependency>
            <groupId>org.glassfish.jaxb</groupId>
            <artifactId>jaxb-runtime</artifactId>
            <version>2.3.3</version>
        </dependency>

    </dependencies>



</project>
package com.aliyun.oss;


import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
@EnableConfigurationProperties(AliOssProperties.class)
public class AliOSSAutoConfiguration {



    @Bean
    public AliOSSUtils aliOSSUtils(AliOssProperties aliOssProperties){
        AliOSSUtils aliOSSUtils = new AliOSSUtils();
        aliOSSUtils.setAliOssProperties(aliOssProperties);
        return aliOSSUtils;
    }
}
package com.aliyun.oss;

import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;

/**
 * 封装属性键值对值
 */
@Data
@ConfigurationProperties(prefix = "aliyun.oss")
public class AliOssProperties {

    private String endpoint;    //aliyun.oss.endpoint
    private String accessKeyId;  //aliyun.oss.access-key-id
    private String accessKeySecret;
    private String bucketName;

}
package com.aliyun.oss;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.io.InputStream;
import java.util.UUID;

/**
 * 阿里云 OSS 工具类
 */

public class AliOSSUtils {


    private AliOssProperties aliOssProperties;


    public void setAliOssProperties(AliOssProperties aliOssProperties) {
        this.aliOssProperties = aliOssProperties;
    }

    /**
     * 实现上传图片到OSS
     */
    public String upload(MultipartFile file) throws IOException {

        String endpoint = aliOssProperties.getEndpoint();
        String accessKeyId = aliOssProperties.getAccessKeyId();
        String accessKeySecret = aliOssProperties.getAccessKeySecret();
        String bucketName = aliOssProperties.getBucketName();


        // 获取上传的文件的输入流
        InputStream inputStream = file.getInputStream();

        // 避免文件覆盖
        String originalFilename = file.getOriginalFilename();//原始文件名  abc.jpg
        //UUID.randomUUID()   保证随机字符串唯一  sfasdfdsfsdgfsdgsdf.jpg
        String fileName = UUID.randomUUID().toString() + originalFilename.substring(originalFilename.lastIndexOf("."));

        //上传文件到 OSS
        OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);
        ossClient.putObject(bucketName, fileName, inputStream);

        //文件访问路径
        String url = endpoint.split("//")[0] + "//" + bucketName + "." + endpoint.split("//")[1] + "/" + fileName;
        // 关闭ossClient
        ossClient.shutdown();
        return url;// 把上传到oss的路径返回
    }

}
com.aliyun.oss.AliOSSAutoConfiguration

8 Web后端开发总结

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值