四阶段-day05--微服务课程关于上传文件的实践练习

一 工程创建与初始化

1 创建父工程

file-->new module

2 pom.xml 文件添加依赖

<?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>com.jt</groupId>
    <artifactId>02-sca-files</artifactId>
    <version>1.0-SNAPSHOT</version>

    <properties>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
    </properties>
    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-dependencies</artifactId>
                <version>2.3.2.RELEASE</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>

            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>Hoxton.SR9</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>

            <dependency>
                <groupId>com.alibaba.cloud</groupId>
                <artifactId>spring-cloud-alibaba-dependencies</artifactId>
                <version>2.2.6.RELEASE</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

</project>

3 删除父工程的src,再新建它的子过程

如果失误删除了创建的子过程,那么重新创建的时候会提示,该工程名已经exist存在,那是因为创建子工程时父工程下会有个modules标签,要把它删除掉,才可以创建同名的子工程.

注意:再创建它的子工程时,可能子工程的pom文件不可用,就要 :

在这里插入图片描述

 4 子工程pom.xml文件添加所需依赖

<?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>02-sca-files</artifactId>
        <groupId>com.jt</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>sca-resource</artifactId>

    <properties>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
    </properties>
<!--添加所需的依赖-->
    <dependencies>
      <!--Spring Boot Web-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
      <!--Nacos Discovery-->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
        </dependency>
      <!--Nacos Config-->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
        </dependency>
      <!--Sentinel-->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
        </dependency>
      <!--spring boot 流量监控-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>
      <!--热部署-->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.20</version>
            <scope>provided</scope>
        </dependency>
    </dependencies>

</project>

5 子工程resource包下创建bootstrap.yml配置文件

server:
  port: 8881
spring:
  application:
    name: sca-resource
  cloud:
    nacos:
      config:
        server-addr: localhost:8848
        file-extension: yml
      discovery:
        server-addr: localhost:8848
 #   sentinel:
 #     eager: true  #服务启动时与sentinel通讯,在sentinel控制台创建服务菜单
 #     transport:
 #       dashboard: localhost:8180
 #       port: 8719

6 子工程创建启动类

package com.jt;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

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

7 IDE中设置nacos启动

 启动nacos: 启动后查看又没有coused by ,有没有报错的地方,检查原因再重新启动,ok即可

 

 8 再创建一个子工程用于编辑UI界面

 9 创建UI子工程的启动类,pom.xml文件添加web的依赖

package com.jt;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class ResourceUIApplication {
    public static void main(String[] args) {
        SpringApplication.run(ResourceUIApplication.class, args);
    }
}
<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
        <version>2.3.2.RELEASE</version>
    </dependency>
</dependencies>

10 UI工程的resource包创建html文件用于编辑前端上传文件页面

10.1 resource下创建静态目录,名为static

 10.2  目录下创建html文件,并编辑部分内容进行测试

 1) 编辑测试内容:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
</head>
<body>
<h1>文件上传案例演示</h1>
<form id="fileForm" method="post" enctype="multipart/form-data" onsubmit="return doUpload()">
    <div>
        <label>上传文件
            <input id="uploadFile" type="file" name="uploadFile">
        </label>
    </div>
    <button type="submit">上传文件</button>
</form>
</body>
<script>
    //jquery代码的表单提交事件
    function doUpload(){
        debugger  //可以在页面(客户端)控制台进行debug操作
        //获得用户选中的所有图片(获得数组)
        let files=document.getElementById("uploadFile").files;
        if(files.length>0){
            //获得用户选中的唯一图片(从数组中取出)
            let file=files[0];
            //开始上传这个图片
            //由于上传代码比较多,不想和这里其它代码干扰,所以定义一个方法调用
            upload(file);
        }
        //阻止表单提交效果
        return false;
    };
    // 将file上传到服务器的方法
    function upload(file){
        //定义一个表单
        let form=new FormData();
        //将图片添加到表单中
        form.append("uploadFile",file);
        //异步提交,ajax请求最大弊端是不能跨域,一种方式是加@CrossOrigin
        axios({
            url:"http://localhost:8881/resource/upload/",
            method:"post",
            data:form
        }).then(function(response){
            alert("upload ok")
            console.log(response.data);
        })
    }
</script>
</html>

2)  启动sca-resource和sca-resouceui的两个启动类,ui工程未创建yml配置文件来修改端口号,所以ui工程的端口号默认是8080,所以就在网页输入下面的url,可以查看到如下效果:

 11 sca-resourse下创建控制层,用于实现文件上传服务

package com.jt.resource.controller;

import lombok.extern.slf4j.Slf4j;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import java.io.File;
import java.io.IOException;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.UUID;

/*通过此对象实现文件的上传服务*/
@CrossOrigin//跨域的一种方式,但是如果以后加拦截器,这种方式就没有作用了
@Slf4j
@RestController
@RequestMapping("/resource/")
public class ResourceController {
    //当类上面添加了@Slf4J就不用自己创建下面的日志对象了
//    private static final Logger log =
//            LoggerFactory.getLogger(ResourceController.class);

    private String resourcePath="d:/uploads/" ;

    @PostMapping("/upload/")
    public String uploadFile(MultipartFile uploadFile) throws IOException {
       //1.创建文件存储目录(按照时间创建--yyyy/MM/dd)
        //1.1获取当前时间的目录--JDK8新特性
        String dateDir = DateTimeFormatter.ofPattern("yyyy/MM/dd")
                .format(LocalDate.now());
        //1.2构建目录文件对象
        File uploadFileDir = new File(resourcePath,dateDir);
        if (!uploadFileDir.exists())uploadFileDir.mkdirs();
        //2.给文件起个名字,(尽量不重复)
        //2.1获取原始文件后缀
        String originalFilename = uploadFile.getOriginalFilename();
        String ext = originalFilename.substring(
                originalFilename.lastIndexOf("."));
        //2.2 构建新的文件名--前缀+后缀
        String newFilePrefix = UUID.randomUUID().toString();
        String newFileName=newFilePrefix+ext;
        //3.开始实现文件上传
        //3.1构建新的文件对象,指向实际上传的文件最终地址
        File file=new File(uploadFileDir,newFileName);
        //3.2上传文件(向指定服务位置写文件数据)
        uploadFile.transferTo(file);
        return "upload ok";
    }
}

       

注意: 前端使用Ajax异步请求局部刷新,但是缺点就是无法跨域,所以需要解决跨域的问题,

之前学过使用@CrossOrigin解决跨域的方式,但是如果以后添加过滤器,这种方式就没有作用了,会判定这种方式不合法!!!!!

目前,先以该跨域方式上传图片进行测试:

 页面控制台:

12 sca-resource下添加过滤器跨域配置类,创建对象交给spring管理

package com.jt.resource.config;

import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.Ordered;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import org.springframework.web.filter.CorsFilter;

/*第二种跨域方式:基于过滤器作跨域配置*/
@Configuration
public class CorsFilterConfig {
    //Spring MVC中注册过滤器使用FilterRegistrationBean对象
    @Bean
    public FilterRegistrationBean<CorsFilter>
               filterRegistrationBean (){
        //1.构建基于Url方式的跨域对象
        UrlBasedCorsConfigurationSource configSource =
                  new UrlBasedCorsConfigurationSource();
        //2.构建url请求规则配置
        CorsConfiguration config =new CorsConfiguration();
        //2.1允许所有请求头跨域
        config.addAllowedHeader("*");
        //2.2允许所有请求方式(get,post,put,delete...)
        config.addAllowedMethod("*");//get,post...
        //2.3允许所有你请求ip,
        config.addAllowedOrigin("*");//http://ip:port
        //2.4允许携带cookie进行跨域
        config.setAllowCredentials(true);
        //2.5将这个跨域配置应用到具体的url
        configSource.registerCorsConfiguration("/**",config);
        //3.注册过滤器
        FilterRegistrationBean fBean =
                new FilterRegistrationBean(
                        new CorsFilter(configSource));
        //4.设置过滤器优先升级
        //fBean.setOrder(Integer.MIN_VALUE);//数字越小优先级越高
        fBean.setOrder(Ordered.HIGHEST_PRECEDENCE);//和上面一样,整数的最小值
        return fBean;
    }
}

启动sca-resource-ui和和sca-resource工程的启动类,进行上传文件测试:

观察控制台发现没有问题,再查看上传到指定路径下有没有上传成功

 

 拓展

如果上传文件,启动后失败页面控制台报错,就需要在前端html文件添加debugger,来断点调试,找原因

13 上传图片,图片返回地址给后端控制台,这个地址在网页上可以显示出来

13.1 修改sca-resource控制层

package com.jt.resource.controller;

import lombok.extern.slf4j.Slf4j;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import java.io.File;
import java.io.IOException;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.UUID;

/*通过此对象实现文件的上传服务*/
//@CrossOrigin//跨域的一种方式,但是如果以后加拦截器,这种方式就没有作用了
@Slf4j
@RestController
@RequestMapping("/resource/")
public class ResourceController {
    //当类上面添加了@Slf4J就不用自己创建下面的日志对象了
//    private static final Logger log =
//            LoggerFactory.getLogger(ResourceController.class);

    @Value("${jt.resource.path}")//写到配置文件中
    private String resourcePath;//="d:/uploads/" ;
    @Value("${jt.resource.host}")
    private String resourceHost;//="http://localhost:8881/";

    @PostMapping("/upload/")
    public String uploadFile(MultipartFile uploadFile) throws IOException {
       //1.创建文件存储目录(按照时间创建--yyyy/MM/dd)
        //1.1获取当前时间的目录--JDK8新特性
        String dateDir = DateTimeFormatter.ofPattern("yyyy/MM/dd")
                .format(LocalDate.now());
        //1.2构建目录文件对象
        File uploadFileDir = new File(resourcePath,dateDir);
        if (!uploadFileDir.exists())uploadFileDir.mkdirs();
        //2.给文件起个名字,(尽量不重复)
        //2.1获取原始文件后缀
        String originalFilename = uploadFile.getOriginalFilename();
        String ext = originalFilename.substring(
                originalFilename.lastIndexOf("."));
        //2.2 构建新的文件名--前缀+后缀
        String newFilePrefix = UUID.randomUUID().toString();
        String newFileName=newFilePrefix+ext;//不加后缀ext会下载,因为它不识别
        //3.开始实现文件上传
        //3.1构建新的文件对象,指向实际上传的文件最终地址
        File file=new File(uploadFileDir,newFileName);
        //3.2上传文件(向指定服务位置写文件数据)
        uploadFile.transferTo(file);
        String fileRealPath = resourceHost + dateDir + "/" + newFileName;
        log.debug("fileRealPath {}",fileRealPath);
        //后续可以将上传的文件信息写入到数据库?
        return fileRealPath;
    }
}

13.2  配置中心收入资源存储地址,可动态获取资源地址和服务地址

这是因为以后上传的地址可能会发生变化,所以设为了动态

nacos服务注册中心的配置列表,新建sca-resource

13.3 上传图片操作

13.4 控制台返回值图片的地址,复制地址在网页查看

由地址级别返回的地址:

 cv地址在网页查看:

14 添加网关gateway,进行跨域/限制转发请求以及负载均衡的功能(后期再学习如何认证)

 14.1 在02-sca-files父工程下创建网关子工程sca-resource-gateway

注意:不能和其他工程的网关工程名字相同,有可能启动时调用失败

14.2  网关工程的pom.xml文件添加网关/nacos依赖

<dependencies>
<!--网关-->
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-gateway</artifactId>
    </dependency>
<!--nacos注册与发现-->
    <dependency>
        <groupId>com.alibaba.cloud</groupId>
        <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
    </dependency>
<!--nacos配置中心-->
    <dependency>
        <groupId>com.alibaba.cloud</groupId>
        <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
    </dependency>
</dependencies>

14.2 创建网关工程的启动类

package com.jt;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

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

14.3  网关工程的resource包下创建名为bootsrap.yml的配置文件,连接noacs和网关路由配置等功能

server:
  port: 9000
spring:
  application:
    name: sca-resource-gateway
  cloud:
    nacos:
      discovery:
        server-addr: localhost:8848
      config:
        file-extension: yml
        server-addr: localhost:8848
    gateway:
      discovery:
        locator:
          enabled: true
      routes:
        - id: router01
          uri: lb://sca-resource
          predicates:
            - Path=/sca/resource/upload/**
          filters:
            - StripPrefix=1

14.4 解决跨域问题第一种方式:  创建跨域配置类

注意: 添加网关跨域配置类,需要把sca-resource包下的跨域配置类的@Configuretion注释掉,以后都有网关,所以跨域配置在网关编辑即可

package com.jt.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.cors.CorsConfiguration;
//import org.springframework.web.cors.UrlBasedCorsConfigurationSource;要和reactive的包区别开
import org.springframework.web.cors.reactive.CorsWebFilter;
import org.springframework.web.cors.reactive.UrlBasedCorsConfigurationSource;

@Configuration //写个此跨域配置类也可以在bootstrap.yml文件中编辑跨域的配置,二选一即可
public class CorsFilterConfig {
    @Bean
    public CorsWebFilter corsWebFilter(){
        //1.构建基于URL方式的跨域配置
        UrlBasedCorsConfigurationSource source =
                new UrlBasedCorsConfigurationSource();
        //2.进行跨域配置
        CorsConfiguration config=new CorsConfiguration();
        //2.1允许所有ip:port进行跨域
        config.addAllowedOrigin("*");
        //2.2允许所有的请求头跨域
        config.addAllowedHeader("*");
        //2.3允许所有的请求方式跨域
        config.addAllowedMethod("*");
        //2.4允许携带有效cookie跨域
        config.setAllowCredentials(true);
        source.registerCorsConfiguration("/**",config);
        return new CorsWebFilter(source);
    }
}

14.5 解决跨域问题第二种方式: 在网关配置文件bootstrap.yml文件中添加跨域配置

server:
  port: 9000
spring:
  application:
    name: sca-resource-gateway
  cloud:
    nacos:
      discovery:
        server-addr: localhost:8848
      config:
        file-extension: yml
        server-addr: localhost:8848
    gateway:
      discovery:
        locator:
          enabled: true
      routes:
        - id: router01
          uri: lb://sca-resource
          predicates:
            - Path=/sca/resource/upload/**
          filters:
            - StripPrefix=1 #去掉1个前缀,即path中的sca
      globalcors: #跨域配置 或者写个跨域配置类二选一即可
        cors-configurations:
          '[/**]':
             allowedOrigins: "*"   #都要带s
             allowedHeaders: "*"
             allowedMethods: "*"
             allowedCredentials: true

注意:解决跨域问题的两种方式二选一即可,第二中要注意格式,以及都要加s,选择第二种,要把第一种的@Configuration注释掉,启动时没就不会被调用,但是如果两种方式都用的话,会报错

14.6 修改UI子工程访问服务资源客户端的url

 14.6 测试

第一步: 首先nacos启动再启动三个服务器(sca-resource/sca-resource-ui/sca-resource-gateway)

页面输入网页fileupload.html文件中的url进行上传文件

 第二步:查看后端sca-resource服务器的控制台,复制返回的文件地址

 第三步:复制文件地址,在网页上粘贴查看,若能查看代表成功

15 网关层面添加sentinel限流熔断功能

15.1 网关工程pom.xml文件添加sentinel依赖,进行限流和监控

<!--sentinel限流-->
    <dependency>
        <groupId>com.alibaba.cloud</groupId>
        <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
    </dependency>
<!--限流监控-->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-actuator</artifactId>
    </dependency>
<!--网关依赖-->
    <dependency>
        <groupId>com.alibaba.cloud</groupId>
        <artifactId>spring-cloud-alibaba-sentinel-gateway</artifactId>
    </dependency>

15.2 网关工程的bootstrap.yml文件添加sentinel配置

    sentinel: #限流设计 ,在spring.cloud下的
      transport:
        dashboard: localhost:8180
      eager: true

15.3 启动网关项目,检测sentinel控制台的网关菜单

启动时,添加sentinel的jvm参数,通过此菜单可以让网关服务在sentinel控制台显示不一样的菜单

-Dcsp.sentinel.app.type=1

假如是在idea中,可以参考下面的图进行配置

15.4 自定义网关限流返回值

注意:这里要添加一个对象转换成json串的依赖Gson或者fastJson都可以,此时我们选择Gson,在网关工程pom.xml文件添加依赖为:

<!--Gson-->
    <dependency>
        <groupId>com.google.code.gson</groupId>
        <artifactId>gson</artifactId>
        <version>2.8.5</version>
    </dependency>
package com.jt.config;

import com.alibaba.csp.sentinel.adapter.gateway.sc.callback.BlockRequestHandler;
import com.alibaba.csp.sentinel.adapter.gateway.sc.callback.GatewayCallbackManager;
import com.google.gson.Gson;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.reactive.function.server.ServerResponse;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

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

/*自定义网关限流返回值*/
@Configuration
public class GatewayConfig {
    public GatewayConfig(){ //构造方法
        GatewayCallbackManager.setBlockHandler(new BlockRequestHandler() {
            @Override
            public Mono<ServerResponse> handleRequest(
                    ServerWebExchange serverWebExchange,
                    Throwable throwable) {
                //1.构建响应数据
                Map<String,Object> map=new HashMap<>();
                map.put("state",429);
                map.put("message","two many request");
                //2.返回值方式一:基于alibaba 的fastjson将对象转换为json串
                //String jsonStr = JSON.toJSONString(map);//fastjson
                //2.返回值方式二:基于Google公司的gson将对象转换为json
                Gson gson=new Gson();
                String jsonStr = gson.toJson(map);
                //3.创建Mono对象,将结果响应到客户端
                return ServerResponse.ok().body(Mono.just(jsonStr),String.class);
            }
        });
    }
}

15.5 启动服务器,查看访问效果:

1)启动顺序:

nacos->sentinel->sca-resource/sca-resource-ui/sca-resource-gateway

2) 网页输入页面url: http://localhost:8080/fileupload.html  进行文件上传

3) 修改ui界面客户端请求后触发的返回数据

4) 登录并查看sentinel控制台

15.6 编辑流控规则,查看网关限流效果

 网页连续上传文件查看网页效果:

16 使用AOP添加日志对象,在方法执行之前和之后作日志记录

16.1 sca-resource工程pom.xml文件添加AOP依赖

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

16.2 自定义注解作为切入点

package com.jt.resource.annotation;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**自定义注解@RequiredLog*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface RequiredLog {
    String value() default "";
}

 16.3 创建切面对象,用于做日志业务增强

package com.jt.resource.aspect;

import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;
@Slf4j  //创建日志对象
@Aspect //切面类的标识
@Component //交给spring管理的对象
public class LogAspect {
    @Pointcut("@annotation(com.jt.resource.annotation.RequiredLog)")
    public void doLog(){}//锦--注解描述的方法

    @Around("doLog()")
    //@Around("@annotation(com.jt.resource.annotation.RequiredLog)")//可以直接把切入点写在Around里,但不好理解
    public Object doAround(ProceedingJoinPoint joinPoint) throws Throwable {
        log.debug("Before {}",System.currentTimeMillis());
        Object result = joinPoint.proceed();//执行执行链(其他切面,目标方法--锦)
        log.debug("After {}",System.currentTimeMillis());
        return result;//目标方法--切入点方法的执行结果

    }
}

16.4 在控制层或者业务层的方法上添加自定义注解切入点进行日志业务的拓展

 16.5 启动服务器,上传文件,查看后台日志业务的执行效果

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值