【SpringBoot】SpringBoot案例 | Web后端开发

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-pE6UFO7W-1686932095267)(【SpringBoot】SpringBoot案例-Web后端开发/image-20230616165459395.png)]

新建项目、更改application.properties配置:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-dn8rFK82-1686932095268)(【SpringBoot】SpringBoot案例-Web后端开发/image-20230617000958974.png)]

spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/employee_manager
spring.datasource.username=root
spring.datasource.password=

# the log of mybatis
mybatis.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl

项目结构:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-sh7x3BIj-1686932095268)(【SpringBoot】SpringBoot案例-Web后端开发/image-20230616180323808.png)]

1 部门管理

1.1 部门列表查询

GET
路径:/depts
响应数据:
{
    "code": 1,
    "msg": "success",
    "data":[
        {"id":1,"name":"学工部","createTime":"2023-06-16T18:12:36","updateTime":"2023-06-16T18:12:36"},
        {"id":2,"name":"教研部","createTime":"2023-06-16T18:12:36","updateTime":"2023-06-16T18:12:36"},
        {"id":3,"name":"咨询部","createTime":"2023-06-16T18:12:36","updateTime":"2023-06-16T18:12:36"},
        {"id":4,"name":"就业部","createTime":"2023-06-16T18:12:36","updateTime":"2023-06-16T18:12:36"},
        {"id":5,"name":"人事部","createTime":"2023-06-16T18:12:36","updateTime":"2023-06-16T18:12:36"}]
}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-YbqeUgC8-1686932095268)(【SpringBoot】SpringBoot案例-Web后端开发/image-20230616175220090.png)]

依次编写ControllerServiceMapper

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-se5ymcxy-1686932095269)(【SpringBoot】SpringBoot案例-Web后端开发/image-20230616182136135.png)]

启动前端程序,双击nginx.exe即可。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-FdnRRroS-1686932095269)(【SpringBoot】SpringBoot案例-Web后端开发/image-20230616182536108.png)]

端口为90:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-n0j5e1Ax-1686932095269)(【SpringBoot】SpringBoot案例-Web后端开发/image-20230616182719738.png)]

1.2 删除部门

DELETE
路径:/depts/{id}
根据ID删除部门数据

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-EDsoNDqV-1686932095269)(【SpringBoot】SpringBoot案例-Web后端开发/image-20230616192653465.png)]

1.3 新增部门

POST
路径:/depts
参数:json形式
{
    "name": "教研部"
}
添加部门数据

数据库表中已经设置了主键 i d id id是自增的。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-PyehdBH2-1686932095270)(【SpringBoot】SpringBoot案例-Web后端开发/image-20230616194234412.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-fgyguwVz-1686932095270)(【SpringBoot】SpringBoot案例-Web后端开发/image-20230616194454665.png)]

1.4 根据部门id查询

GET
路径:/depts/{id}
返回结果:
{
    "code": 1,
    "msg": "success",
    "data": [
        {
            "id": 1,
            "name": "计算机学院",
            "createTime": "2022-09-01T23:06:29",
            "updateTime": "2022-01-01T23:06:29"
        }
    ]
}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-bopsudcW-1686932095270)(【SpringBoot】SpringBoot案例-Web后端开发/image-20230616200042375.png)]

1.5 修改部门名称

请求路径:/depts
请求方式:PUT
参数:
{
	"id": 1,
	"name": "教研部"
}
更改编号id的部门名称为name

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-YgykJ4pK-1686932095270)(【SpringBoot】SpringBoot案例-Web后端开发/image-20230616202030775.png)]

2 员工管理

2.1 员工列表分页查询 PageHelper⭐

请求路径:/emps
请求方式:GET
参数:
【必须】page=1&pageSize=10
【可选】name=&gender=1&begin=2007-09-01&end=2022-09-01
接口描述:该接口用于员工列表数据的条件分页查询,并返回总记录数
【有一说一我觉得这个接口设计得很烂,应该把两个功能拆开的,明明是独立的功能,但为了教学也可以理解】

请求示例

/emps?name=张&gender=1&begin=2007-09-01&end=2022-09-01&page=1&pageSize=10

返回示例:

{
  "code": 1,
  "msg": "success",
  "data": {
    "total": 2,
    "rows": [
       {
        "id": 1,
        "username": "jinyong",
        "password": "123456",
        "name": "金庸",
        "gender": 1,
        "image": "https://web-framework.oss-cn-hangzhou.aliyuncs.com/2022-09-02-00-27-53B.jpg",
        "job": 2,
        "entrydate": "2015-01-01",
        "deptId": 2,
        "createTime": "2022-09-01T23:06:30",
        "updateTime": "2022-09-02T00:29:04"
      },
      {
        "id": 2,
        "username": "zhangwuji",
        "password": "123456",
        "name": "张无忌",
        "gender": 1,
        "image": "https://web-framework.oss-cn-hangzhou.aliyuncs.com/2022-09-02-00-27-53B.jpg",
        "job": 2,
        "entrydate": "2015-01-01",
        "deptId": 2,
        "createTime": "2022-09-01T23:06:30",
        "updateTime": "2022-09-02T00:29:04"
      }
    ]
  }
}

分析:

# 从0开始查找5条数据
select * from emp limit 0, 5
# 查找第page页的数据
select * from emp limit (page - 1) * page, pageSize

获取总记录数:

select count(*) from emp

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-XscK9Aqo-1686932095271)(【SpringBoot】SpringBoot案例-Web后端开发/image-20230616221438197.png)]

调用Mapper的两个函数来实现功能。

【分页查询插件 PageHelper】

maven依赖:

		<dependency>
            <groupId>com.github.pagehelper</groupId>
            <artifactId>pagehelper-spring-boot-starter</artifactId>
            <version>1.4.2</version>
        </dependency>

更改后:

@Service
public class EmpServiceImpl implements EmpService {

    @Autowired
    EmpMapper empMapper;

    @Override
    public PageBean pageList(Integer page, Integer pageSize) {
        // 1、设置分页参数
        PageHelper.startPage(page, pageSize);

        // 2、执行查询,封装为PageHelper中的page
        List<Emp> list = empMapper.selectAll();
        Page<Emp> pageHelper = (Page<Emp>) list;

        // 3、封装PageBean对象
        return new PageBean(pageHelper.getTotal(), pageHelper.getResult());
    }
}
package com.koukou.manager.mapper;

import com.koukou.manager.model.Emp;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Select;

import java.util.List;

@Mapper
public interface EmpMapper {

    /**
     * 查询Emp表的所有记录
     * @return
     */
    @Select("select * from emp")
    public List<Emp> selectAll();
}

2.2 在分页基础上加入查找条件

注意这里的类型,不是LocalDateTime

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-n3qvdHWa-1686932095271)(【SpringBoot】SpringBoot案例-Web后端开发/image-20230616233030632.png)]

@Slf4j
@RestController
public class EmpController {

    @Autowired
    private EmpService empService;

    /**
     * @param page 页面
     * @param pageSize 页面大小
     * @param name 搜索关键字
     * @param gender 性别
     * @param begin 最早入职时间
     * @param end 最晚入职时间
     * @return Page{记录数, 本页员工列表}
     */
    @GetMapping("/emps")
    public Result pageList(@RequestParam(defaultValue = "1") Integer page,
                           @RequestParam(defaultValue = "10") Integer pageSize,
                           String name, Short gender,
                           @DateTimeFormat(pattern = "yyyy-MM-dd") LocalDate begin,
                           @DateTimeFormat(pattern = "yyyy-MM-dd") LocalDate end) {
        log.info("按要求查询某页员工");
        PageBean data = empService.pageList(page, pageSize, name, gender, begin, end);
        return Result.success(data);
    }
}

Service先进行分页设置,然后按常规进行条件查询,封装为Page<Emp>,返回。

	@Override
    public PageBean pageList(Integer page, Integer pageSize,
                             String name, Short gender,
                             LocalDate begin, LocalDate end) {
        // 1、设置分页参数
        PageHelper.startPage(page, pageSize);

        // 2、执行查询,封装为PageHelper中的page
        List<Emp> list = empMapper.select(name, gender, begin, end);
        Page<Emp> pageHelper = (Page<Emp>) list;

        // 3、封装PageBean对象
        return new PageBean(pageHelper.getTotal(), pageHelper.getResult());
    }

Mapper,xml文件中<需要进行转义,SQL语句末尾没有分号:

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">

<mapper namespace="com.koukou.manager.mapper.EmpMapper">

    <select id="select" resultType="com.koukou.manager.model.Emp">
        select * from emp
        <where>
            <if test="name != null">name like concat('%', #{name}, '%')</if>
            <if test="gender != null">and gender = #{gender}</if>
            <if test="begin != null">and entrydate &gt;=  #{begin}</if>
            <if test="end != null">and entrydate &lt;=  #{end}</if>
        </where>
        order by update_time desc
    </select>

</mapper>

2.3 批量删除员工

DELETE
路径:/emps/{ids},参数为数组
根据ID批量删除员工

例子:/emps/1,2,3

接收数组参数

	@DeleteMapping("/emps/{ids}")
    public Result delete(@PathVariable List<Integer> ids) {
        empService.delete(ids);
        return Result.success();
    }

xml文件中删除,注意是#{id}

    <delete id="delete">
        delete from emp where id in
        <foreach collection="ids" item="id" separator="," open="(" close=")">
            #{id}
        </foreach>
    </delete>

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-QhUXOtUu-1686932095271)(【SpringBoot】SpringBoot案例-Web后端开发/image-20230617000752645.png)]

2.4 新增员工

请求路径:/emps
请求方式:POST
接口描述:该接口用于添加员工的信息
名称类型是否必须备注
usernamestring必须用户名
namestring必须姓名
gendernumber必须性别, 说明: 1 男, 2 女
imagestring非必须图像
deptIdnumber非必须部门id
entrydatestring非必须入职日期
jobnumber非必须职位, 说明: 1 班主任,2 讲师, 3 学工主管, 4 教研主管, 5 咨询师

参数:

{
  "image": "https://web-framework.oss-cn-hangzhou.aliyuncs.com/2022-09-03-07-37-38222.jpg",
  "username": "linpingzhi",
  "name": "林平之",
  "gender": 1,
  "job": 1,
  "entrydate": "2022-09-18",
  "deptId": 1
}

json格式的数据,用一个实体Bean进行接收。

    @Override
    public void add(Emp emp) {
        emp.setCreateTime(LocalDateTime.now());
        emp.setUpdateTime(LocalDateTime.now());
        empMapper.add(emp);
    }
    <insert id="add">
        insert into emp(username, name, gender, image, job, entrydate, dept_id, create_time, update_time)
        values (#{username}, #{name}, #{gender}, #{image}, #{job}, #{entrydate}, #{deptId}, #{createTime}, #{updateTime})
    </insert>

2.5 文件上传

请求路径:/upload
请求方式:POST
接口描述:上传图片接口
参数:image{type = file}
返回:
{
    "code": 1,
    "msg": "success",
    "data": "https://web-framework.oss-cn-hangzhou.aliyuncs.com/2022-09-02-00-27-0400.jpg"
}

上传文件

  1. MultipartFile用于接收上传文件
  2. UUID构造唯一文件名
  3. image.transferTo用于保存文件
@Slf4j
@RestController
public class UploadController {

    @PostMapping("/upload")
    public Result upload(String username, Integer age, MultipartFile image) throws IOException {
        // 使用MultipartFile接收文件,保存在本地

        // 1、构造唯一文件名
        // 得到文件类型
        String originalName = image.getOriginalFilename();
        int index = originalName.lastIndexOf('.');
        String type = originalName.substring(index);
        // uuid 通用唯一识别码,生成文件名字
        String newName = UUID.randomUUID().toString() + type;

        // 2、保存文件
        image.transferTo(
                new File("E:\\leetcode\\project\\manager\\src\\main\\resources\\static\\image\\" + newName)
        );

        return Result.success();
    }
}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-vq5KNnNN-1686989396815)(【SpringBoot】SpringBoot案例-Web后端开发/image-20230617123317243.png)]

# the file upload setting
spring.servlet.multipart.max-file-size=10MB
spring.servlet.multipart.max-request-size=100MB

2.6 修改员工信息

名称类型是否必须备注
idnumber必须id
usernamestring必须用户名
namestring必须姓名
gendernumber必须性别, 说明: 1 男, 2 女
imagestring非必须图像
deptIdnumber非必须部门id
entrydatestring非必须入职日期
jobnumber非必须职位, 说明: 1 班主任,2 讲师, 3 学工主管, 4 教研主管, 5 咨询师
> 请求路径:/emps
> 请求方式:PUT
> 接口描述:该接口用于修改员工的数据信息


{
  "id": 1,
  "image": "https://web-framework.oss-cn-hangzhou.aliyuncs.com/2022-09-03-07-37-38222.jpg",
  "username": "linpingzhi",
  "name": "林平之",
  "gender": 1,
  "job": 1,
  "entrydate": "2022-09-18",
  "deptId": 1
}
    <update id="edit">
        update emp
            <set>
                <if test="username != null"> username = #{username}, </if>
                <if test="name != null"> name=#{name}, </if>
                <if test="gender != null"> gender=#{gender}, </if>
                <if test="image != null"> image = #{image}, </if>
                <if test="deptId != null"> image = #{deptId}, </if>
                <if test="entrydate != null"> image = #{entrydate}, </if>
                <if test="job != null"> image = #{job}</if>
            </set>
        where id = #{id}
    </update>

3 登录

3.1 密码是否正确

最基本的操作:

    @Select("select * from emp where username = #{username} and password = #{password};")
    public Emp login(String username, String password);

看看这条查询语句是否返回null。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-kqDpl5Fu-1687010649269)(【SpringBoot】SpringBoot案例-Web后端开发/image-20230617162819372.png)]

3.2 登录校验

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-rViTRZyd-1687010649269)(【SpringBoot】SpringBoot案例-Web后端开发/image-20230617163214816.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-T8v60zg3-1687010649270)(【SpringBoot】SpringBoot案例-Web后端开发/image-20230617163343046.png)]

3.2.1 JWT令牌

JSON Web Token

  • json数据格式传输信息:将json数据格式进行安全的封装

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-gOGm6FbK-1687010649270)(【SpringBoot】SpringBoot案例-Web后端开发/image-20230617165113931.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-GI7Ri7DQ-1687010649270)(【SpringBoot】SpringBoot案例-Web后端开发/image-20230617165150690.png)]

依赖:

		<dependency>
            <groupId>io.jsonwebtoken</groupId>
            <artifactId>jjwt</artifactId>
            <version>0.9.1</version>
        </dependency>

        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.76</version>
        </dependency>

生成JWT令牌:

	@Test
    public void genjwt() {
        Map<String, Object> claims = new HashMap<>();
        claims.put("id", 1);
        claims.put("psw", 188);

        // 载荷、签名算法、有效期
        String jwt = Jwts.builder()
                .setClaims(claims)
                .signWith(SignatureAlgorithm.HS256, "koukou")
                .setExpiration(new Date(System.currentTimeMillis() + 12 * 3600 * 1000))
                .compact();

        System.out.println(jwt);
    }
eyJhbGciOiJIUzI1NiJ9.eyJwc3ciOjE4OCwiaWQiOjEsImV4cCI6MTY4NzAzNTY2Nn0.K70wIsLMcsO2kVqTRkOjtj6nAijEqGyVRKPZAEhSP44

解析JWT令牌:

    @Test
    public void parseJwt() {
        Claims claims = Jwts.parser()
                .setSigningKey("koukou")
            .parseClaimsJws("eyJhbGciOiJIUzI1NiJ9.eyJwc3ciOjE4OCwiaWQiOjEsImV4cCI6MTY4NzAzNTY2Nn0.K70wIsLMcsO2kVqTRkOjtj6nAijEqGyVRKPZAEhSP44")
                .getBody();
        System.out.println(claims);
    }
{psw=188, id=1, exp=1687035666}

3.2.2 发令牌

令牌生成:登陆成功后,生成 JWT令牌,并返回给前端

令牌校验:请求到达服务器端后,对令牌进行统一拦截、校验。

工具类:

public class JwtUtils {
    private static String signKey = "koukou";
    private static Long expire = 12 * 3600 * 1000L;

    /**
     * 生成Jwt令牌
     * @param claims json参数
     */
    public static String genJwt(Map<String, Object> claims) {
        // 载荷、签名算法、有效期
        String jwt = Jwts.builder()
                .setClaims(claims)
                .signWith(SignatureAlgorithm.HS256, signKey)
                .setExpiration(new Date(System.currentTimeMillis() + expire))
                .compact();
        return jwt;
    }

    /**
     * 解析JWT令牌
     */
    public static Claims parseJwt(String jwt) {
        Claims claims = Jwts.parser()
                .setSigningKey(signKey)
                .parseClaimsJws(jwt)
                .getBody();
        return claims;
    }
}

3.3 校验令牌 Filter

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-MPkuvmq2-1687010649270)(【SpringBoot】SpringBoot案例-Web后端开发/image-20230617180218017.png)]

把对资源的请求拦截下来,从而实现特殊功能。

启动类上加上注解@ServletComponentScan

@ServletComponentScan
@SpringBootApplication
public class ManagerApplication {

创建Filter类,重写3个方法:

@Slf4j
@WebFilter("/*")
public class LoginCheckFilter implements Filter {
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        // 初始化方法,Web服务器启动,创建Filter时调用
        Filter.super.init(filterConfig);
    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain) throws IOException, ServletException {
        // 拦截请求时调用
        HttpServletRequest req = (HttpServletRequest) request;
        HttpServletResponse resp = (HttpServletResponse) response;

        // 1、执行放行前逻辑
        // (1)获取请求url,判断请求是否为login
        String url = req.getRequestURL().toString();

        // (2) 如果不是login请求,需要校验令牌
        if (!url.contains("login")) {
            String jwt = resp.getHeader("token");
            // [1]如果jwt不存在
            if (jwt == null || jwt.length() <= 0) {
                log.info("请求头token为空,未登录");
                Result error = Result.error("NOT_LOGIN");
                // 手动转换,返回json格式的error
                String notLogin = JSONObject.toJSONString(error);
                // 响应结果
                resp.getWriter().write(notLogin);
                return;
            }
            // [2]解析token
            try {
                JwtUtils.parseJwt(jwt);
            }
            catch (Exception e) {
                log.info("解析令牌失败,返回未登录错误信息");
                String error = JSONObject.toJSONString(Result.error("NOT_LOGIN"));
                resp.getWriter().write(error);
                return;
            }
        }

        // 2、放行
        filterChain.doFilter(request, response);
        // 执行放行后逻辑
    }

    @Override
    public void destroy() {
        // 销毁方法,服务器关闭时调用
        Filter.super.destroy();
    }
}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-gXMZqKVn-1687010649271)(【SpringBoot】SpringBoot案例-Web后端开发/image-20230617182926907.png)]

3.4 拦截器Interceptor

写一个拦截器类,继承自HandlerInterceptor,具有注解@Component

@Slf4j
@Component
public class LoginCheckInterceptor implements HandlerInterceptor {
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        // 目标资源方法运行前运行,true放行,false不放行
        String url = request.getRequestURL().toString();

        if (url.contains("login")) {
            log.info("直接放行");
            return true;
        }

        // 得到token
        String token = request.getHeader("token");
        try {
            JwtUtils.parseJwt(token);
        }
        catch (Exception e) {
            // 解析失败,返回错误信息
            String errorInfo = JSONObject.toJSONString(Result.error("NOT_LOGIN"));
            response.getWriter().write(errorInfo);
            return false;
        }
        return true;
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        HandlerInterceptor.super.postHandle(request, response, handler, modelAndView);
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        HandlerInterceptor.super.afterCompletion(request, response, handler, ex);
    }
}

配置拦截器:

@Configuration
public class WebConfig implements WebMvcConfigurer {
    /**
     * 配置类,注册配置拦截器
     */
    @Autowired
    private LoginCheckInterceptor loginCheckInterceptor;

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(loginCheckInterceptor).addPathPatterns("/**").excludePathPatterns("/login");
    }
}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-83QkRQRi-1687010649271)(【SpringBoot】SpringBoot案例-Web后端开发/image-20230617184057882.png)]

3.5 全局异常处理器

@RestControllerAdvice
public class GlobalExceptionHandler {

    @ExceptionHandler(Exception.class)
    public Result catchExcp(Exception ex) {
        ex.printStackTrace();
        return Result.error("对不起,操作失败");
    }
    
}

4 事务管理

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ZuheVue4-1687010649271)(【SpringBoot】SpringBoot案例-Web后端开发/image-20230617191043366.png)]

例子:

删除部门,同时删除部门的所有员工。
1、根据ID删除部门
2、根据部门ID删除所有员工

加入@Transactional注解,整个方法若执行都执行,若不执行都不执行:

@Transactional
@Override
public void deleteDeptById(Integer id) {
    deptMapper.deleteDeptById(id);
    empMapper.deleteByDeptId(id);
}

开启事务管理日志:

# the transaction log
logging.level.org.springframework.jdbc.support.JdbcTransactionManager=debug
@Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRE_NEW)

4.1 AOP

面向特定方法编程。

依赖:

		<dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-aop</artifactId>
        </dependency>
@Slf4j
@Component
@Aspect
public class TimeAspect {

    @Around("execution(* com.koukou.manager.service.*.*(..))")
    public Object recordTime(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
        long begin = System.currentTimeMillis();
        
        Object object = proceedingJoinPoint.proceed();
        
        long end = System.currentTimeMillis();
        log.info("执行耗时:{}", end - begin);
        return object;
    }
}

JoinPoint:连接点,可以被AOP控制的方法

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-pk3GHLj0-1687010649271)(【SpringBoot】SpringBoot案例-Web后端开发/image-20230617212828220.png)]

Advice:通知,哪些是重复的逻辑

  • Around、Before、After、AfterReturning、AfterThrowing

PointCut:匹配连接点的条件,通知只会在切入点方法执行时被应用

  • 切入点表达式
execution(访问修饰符? 返回值 包名.类名.?方法名(方法参数) throws 异常?)

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-cjmYyHwx-1687010649272)(【SpringBoot】SpringBoot案例-Web后端开发/image-20230617212611275.png)]

// 使用标识注解
@Pointcut("@annotation(com.koukou.aop.myLog)")

Aspect:切面

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-s8LPbseg-1687010649272)(【SpringBoot】SpringBoot案例-Web后端开发/image-20230617211538278.png)]

执行流程:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ThVc03hy-1687010649272)(【SpringBoot】SpringBoot案例-Web后端开发/image-20230617211815933.png)]

顺序:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-WcvVM5dM-1687010649272)(【SpringBoot】SpringBoot案例-Web后端开发/image-20230617212220996.png)]

  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值