03,SpringBoot学习笔记03-整合MyBatis、本地测试、日志处理、面向切面编程、文件上传、文件下载

1. 整合Mybatis框架

回顾: spring框架如何整合mybatis?

1.1 回顾

1.1.1 spring框架中如何整合mybatis框架

 1.引入依赖
      spring 相关
      mysql 相关 驱动 数据源
      mybatis 相关  mybatis核心jar  mybatis和spring框架整合
  2.spring.xml
      a.开启注解扫描
      b.创建数据源对象
          注入 指定使用那种数据源类型  注入dirverClassName  注入url 注入username password
      c.创建sqlSessionFactory
          注入 数据源  注入mapper配置文件位置  注入实体别名包
      d.创建Dao对象
          注入SqlSessionFactory 以及Dao接口所在包
      e.创建事务管理器      DataSourceTranacationManager 
          注入 数据源对象   
      f.在业务层组件上加入事务注解 @Transacational
          <tx:annotation-driven  transaction-manager="transactionManager"/>
3.测试
      1).建表
      2).开发实体类
      3).开发DAO接口
      4).开发Mapper配置文件
      5).开发Service接口
      6).开发ServiceImpl实现类
      7).测试ServiceImpl

1.1.2 springboot框架中如何整合mybatis框架

 1.引入依赖
      spring-boot-stater-web
      mysql相关 mysql驱动  druid数据源
      mybatis相关的 (mybatis-spring-boot-stater) 依赖 (mybatis mybatis-spring)2.书写配置
      a.开启注解扫描 @SpringBootApplication  @ComponentScan  省略
      b.创建数据源  
          1.指定数据源类型
          2.指定数据库驱动
          3.指定url
          4.指定username
          5.指定password
      c.创建SqlSessionFactory
          1.指定mapper配置文件位置
          2.指定实体所在包位置 起别名
      d.创建DAO
          1.指定DAO接口所在包
      e.创建事务管理器  开启注解式事务生效  省略
      
  3.测试
      1).建表
      2).开发实体类
      3).开发DAO接口
      4).开发Mapper配置文件
      5).开发Service接口
      6).开发ServiceImpl实现类
      7).测试ServiceImpl

1.2 pom.xml中引入依赖

<!--druid-->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid</artifactId>
            <version>1.1.24</version>
        </dependency>

        <!--mysql-->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.46</version>
        </dependency>

        <!--mybatis-spring-boot-starter-->
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>2.1.4</version>
        </dependency>

        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.24</version>
        </dependency>

1.3 application.yml编写相关配置

# 公共配置
server:
  port: 8888 # 修改内嵌服务器端口号
  servlet:
    context-path: /spring-boot-day03

# 数据源相关配置
spring:
  datasource:
    type: com.alibaba.druid.pool.DruidDataSource # 指定连接池类型
    driver-class-name: com.mysql.jdbc.Driver # mysql 5.x版本驱动
    # driver-class-name: com.mysql.cj.jdbc.Driver # mysql 8.x版本驱动
    url: jdbc:mysql://localhost:3306/school?characterEncoding=UTF-8 # 指定url
    username: root # 指定用户名和密码
    password: Root-123 # 指定密码

# mybatis相关配置
mybatis:
  mapper-locations: classpath:mapper/*.xml # 指定mapper配置文件位置
  type-aliases-package: com.study.entity # 指定实体类的包名,默认别名:类名或类名首字母小写两种

1.4 启动类中添加注解扫描DAO接口所在包

//入口类加入如下配置:
@SpringBootApplication
/**
 * @Mapper 注解
 * 修饰范围:只能放在DAO接口上,且每个DAO接口都需要放置此注解
 * 作用:用来在工厂中创建DAO对象
 */
//@Mapper
/**
 * @MapperScan 注解
 * 修饰范围:用在类上
 * 作用:用来扫描DAO接口所在包,同时将所有DAO接口在工厂中创建对象
 */
@MapperScan("com.study.mapper")
public class SpringBootDay03Application {
    public static void main(String[] args) {
        SpringApplication.run(SpringBootDay03Application.class, args);
    }
}

1.5 建表

CREATE TABLE IF NOT EXISTS t_user(
   id INT(11) NOT NULL AUTO_INCREMENT COMMENT '主键id',
   name VARCHAR(40) COMMENT '姓名', 
   birthday TIMESTAMP COMMENT '生日',
   salary DOUBLE(10,2) COMMENT '工资',
   PRIMARY KEY(id)
  )ENGINE=INNODB DEFAULT CHARSET=utf8mb4;

1.6 创建 User实体类

@Data
public class User {
    private Integer id;
    private String name;
    private String birthday;
    private Double salary;

    public User() {
    }

    public User(Integer id, String name, String birthday, Double salary) {
        this.id = id;
        this.name = name;
        this.birthday = birthday;
        this.salary = salary;
    }

    @Override
    public String toString() {
        return "User{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", birthday=" + birthday +
                ", salary=" + salary +
                '}';
    }
}

1.7 创建 UserMapper 接口


@Mapper
public interface UserMapper {

    /**
     * 查询所有用户
     * @return
     */
    List<User> findAll();

    /**
     * 保存用户
     */
    void save(User user);
}

1.8 创建 UserMapper.xml

<?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.study.mapper.UserMapper">
    <select id="findAll" resultType="com.study.entity.User">
          select
              id,name,birthday,salary
          from t_user
    </select>

    <insert id="save" parameterType="com.study.entity.User" useGeneratedKeys="true" keyProperty="id">
        insert into t_user values(#{id},#{name},#{birthday},#{salary})
    </insert>
</mapper>

1.9 创建 UserService 接口

package com.study.service;

import com.study.entity.User;

import java.util.List;

public interface UserService {
    /**
     * 查询所有用户
     * @return
     */
    List<User> findAll();

    /**
     * 保存用户
     */
    void save(User user);
}

1.10 创建 UserServiceImpl

package com.study.service.impl;

import com.study.entity.User;
import com.study.mapper.UserMapper;
import com.study.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.List;

@Service
public class UserServiceImpl implements UserService {
    @Autowired
    private UserMapper userMapper;

    @Override
    public List<User> findAll() {
        return userMapper.findAll();
    }

    @Override
    public void save(User user) {
        userMapper.save(user);
    }
}

1.11 创建 UserController

package com.study.controller;

import com.study.entity.User;
import com.study.service.UserService;
import org.springframework.beans.factory.annotation.Autowire;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import java.util.List;

@RestController
@RequestMapping("user")
public class UserController {
    @Autowired
    UserService userService;

    @GetMapping("findAll")
    private List<User> findAll(){
        return userService.findAll();
    }

    @PostMapping("save")
    private String save(@RequestBody User user){
        userService.save(user);
        return "保存成功";
    }
}

1.12 测试

在这里插入图片描述
在这里插入图片描述

1.13 @MapperScan和@Mapper注解区别

 /**
   * @Mapper 注解
   * 修饰范围:只能放在DAO接口上,每个接口都需要放置
   * 作用:用来在工厂中创建DAO对象
   *//**
   * @MapperScan 注解 推荐使用
   * 修饰范围:用在类上,可以一次性扫描所有DAO接口所在包中的接口
   * 作用:用来扫描DAO接口所在包,同时将所有DAO接口在工厂中创建对象
   */

2,本地测试

往往在开发过程中业务代码课程非常复杂频繁启动服务器测试,非常麻烦!这个时候使用本地测试就是一个很好的解决方案,springboot也提供了本地测试解决方案!

2.1 引入测试依赖

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

2.2 编写测试类

@SpringBootTest

1,修饰范围:用在类上
2,作用:用来启动本地Spring环境

2.2.1 编写 BasicTests

@SpringBootTest
public class BasicTests {
}

2.2.2 编写 UserDAOTests

public class UserDAOTests extends BasicTests{
    @Autowired
    private UserMapper userMapper;

    @Test
    public void testFindAll(){
        List<User> all = userMapper.findAll();
        for (User user : all) {
            System.out.println(user.toString());
        }
    }
}

在这里插入图片描述

3,日志处理

3.1 引言

springboot框架集成了logback 日志, Logback是由log4j创始人设计的又一个开源日志组件。目前,logback分为三个模块:logback-core,logback-classic和logback-access,logback-core是其它两个模块的基础模块;logback-classic是log4j的一个改良版本。此外logback-classic完整实现SLF4J API使你可以很方便地更换成其它日志系统如log4j或JDK14 Logging;logback-access访问模块与Servlet容器集成提供通过Http来访问日志的功能。该日志是对log4j日志展示进一步改进!即: logback 也是一个开源日志组件,和 log4j作用一致,都是用来生成日志,两者相比logback更加轻量!

3.2 日志的级别

在这里插入图片描述
级别从高到低依次为: All < Trace < DEBUG < INFO < WARN < ERROR < Fatal < OFF

 - OFF   | 关闭:最高级别,不打印日志。 
  - FATAL | 致命:指明非常严重的可能会导致应用终止执行错误事件。
  - ERROR | 错误:指明错误事件,但应用可能还能继续运行。 
  - WARN | 警告:指明可能潜在的危险状况。 
  - INFO | 信息:指明描述信息,从粗粒度上描述了应用运行过程。 
  - DEBUG | 调试:指明细致的事件信息,对调试应用最有用。
  - TRACE | 跟踪:指明程序运行轨迹,比DEBUG级别的粒度更细。 
  - ALL | 所有:所有日志级别,包括定制级别。

日志级别由低到高: 日志级别越高输出的日志信息越多

3.3 项目中日志分类

- 一种是rootLogger(根全局日志) : 用来监听项目中所有的运行日志,包括引入依赖jar中的日志 
- 一种是logger(指定包级别日志) :  用来监听项目中指定包中的日志信息

3.4 项目中使用日志

3.4.1修改 application.yml

logging:
  level:
    root: info # 指定根日志级别(一般不推荐修改根日志,输出信息太多,推荐使用子日志)
    com.study.dao: info #指定dao包中日输出级别
  file:
    name: info.log # 指定生成的日志另存为文件的名称
    path: ./  # 指定日志文件在项目目录下保存

3.4.2 修改 UserServiceImpl

private static final Logger log = LoggerFactory.getLogger(UserServiceImpl.class);
    
    @Autowired
    private UserMapper userMapper;

    @Override
    public List<User> findAll() {
        log.debug("into debug,{}","findAll");//根日志默认为info级别,不能输出debug信息
        log.info("into info,{}","findAll");
        log.warn("into warn,{}","findAll");
        log.error("into error,{}","findAll");

        List<User> list = userMapper.findAll();
        for (User user : list) {
            log.info("user==>"+user.toString());
        }
        return list;
    }

3.4.3 测试

在这里插入图片描述

4,面向切面编程(AOP)

4.1 引言

springboot是对原有项目中spring框架和springmvc的进一步封装,因此在springboot中同样支持spring框架中AOP切面编程,不过在springboot中为了快速开发仅仅提供了注解方式的切面编程。

4.2 切面使用

4.2.1 切面注解

  - @Aspect 用来类上,代表这个类是一个切面  Aspect 切面  = Advice 附加操作 + Pointcut 切入点
  - @Before 用在方法上代表这个方法是一个前置通知方法 
  - @After 用在方法上代表这个方法是一个后置通知方法 
  - @Around 用在方法上代表这个方法是一个环绕的方法

4.2.2 切入点表达式

 execution 方法级别切入点表达式 save update 运行效率越低

4.3 自定义注解

package com.study.annotations;

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 MyAdvice {
}


4.4 创建aop配置类

package com.study.aop;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.context.annotation.Configuration;

@Configuration  //代表当前这个类是一个spring的配置类,相当于spring.xml
@Aspect //代表这是一个切面配置类
public class MyAspectConfig {
        /**
         * @MethodName before
         * @Description 前置通知
         * @param: joinPoint
         * @Author Jiangnan Cui
         * @Date 2022/6/2 9:22
         */
        @Before("execution(* com.study.service.*.*(..))")
        public void before(JoinPoint joinPoint){
            System.out.println("前置附加操作");
            System.out.println("当前执行目标类:" + joinPoint.getTarget());
            System.out.println("当前执行目标类中方法:" + joinPoint.getSignature().getName());
            System.out.println("当前执行目标类中方法参数:" + joinPoint.getArgs());
        }

        /**
         * @MethodName after
         * @Description 后置通知
         * @param: joinPoint
         * @Author Jiangnan Cui
         * @Date 2022/6/2 9:22
         */
        @After("execution(* com.study.service.*.*(..))")
        public void after(JoinPoint joinPoint){
            System.out.println("后置附加操作");
            System.out.println("当前执行目标类:" + joinPoint.getTarget());
            System.out.println("当前执行目标类中方法:" + joinPoint.getSignature().getName());
            System.out.println("当前执行目标类中方法参数:" + joinPoint.getArgs());
        }
    /**
     * @MethodName around
     * @Description 环绕通知
     * @param: proceedingJoinPoint
     * @return: java.lang.Object 用来将业务方法返回结果给调用者
     * @Author Jiangnan Cui
     * @Date 2022/6/2 9:21
     */
    @Around("execution(* com.study.service.*.*(..))")
//    @Around("@annotation(com.study.annotations.MyAdvice)") //仅对业务逻辑方法上含有@MyAdvice注解的方法生效
    public Object around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
        System.out.println("环绕前置附加操作");
        System.out.println("当前执行目标类:" + proceedingJoinPoint.getTarget());
        System.out.println("当前执行目标类中方法:" + proceedingJoinPoint.getSignature().getName());
        System.out.println("当前执行目标类中方法参数:" + proceedingJoinPoint.getArgs());
        //进行目标方法的放行操作,即:继续执行业务逻辑方法
        Object proceed = proceedingJoinPoint.proceed();
        System.out.println("proceed = " + proceed);
        System.out.println("环绕后置附加操作");
        return proceed;
    }

}

4.5 测试

在这里插入图片描述

5,文件上传

  
a.提供一张上传页面,提交方式必须:post,enctype属性必须为 multipart/form-data(文本类型、二进制类型文件均可做编码),默认的application/x-www-form-urlencoded只能对文本类型(字符串)进行编码
b.开发上传controller

5.1,修改 application.yml

spring:
  servlet:
    multipart: # 修改文件上传的大小限制,默认10M(10485760B)
      max-request-size: 120MB # 运行请求传递文件大小最大为120MB,单位可以直接写MB
      max-file-size: 120MB # 运行服务器可以处理的最大文件大小为120MB

# 指定本地上传测试目录
file:
  upload:
    dir: E:\a_linailong\myProject\springboot_basics\springboot03_integration_other_frame\upload_file

5.2,完成 FileService 接口

public interface FileService {
    void upload(MultipartFile file) throws IOException;
}

5.3,完成 FileServiceImpl

package com.study.service.impl;

import com.study.service.FileService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import java.io.File;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;

@Service
@Slf4j
public class FileServiceImpl implements FileService {

    @Value("${file.upload.dir}")
    private String fileDir;

    @Override
    public void upload(MultipartFile file) throws IOException {
        //获得原始文件名
        String originalFilename = file.getOriginalFilename();
        log.info("文件名:{}", originalFilename);
        log.info("文件大小:{}",file.getSize());//以字节为单位
        log.info("文件类型:{}",file.getContentType());

        //1.根据相对上传路径"/upload"获取绝对路径(真实路径) 动态获取
        // 即:/users/桌面... 或 /home/springboot_day5/...
        String realPath = fileDir;
        log.info("获取绝对路径:{}",realPath);

        //2.上传文件
        //获取文件名后缀  FileNameUtil工具类需要引入jar包
        String ext = originalFilename.substring(originalFilename.lastIndexOf("."));
        //拼接新文件名                  时间戳                             SSS毫秒
        String newFileName = new SimpleDateFormat("yyyyMMddHHmmssSSS").format(new Date()) + ext;
        log.info("新文件名:" + newFileName);
        //上传文件 参数1: 将文件写入到那个目录 参数2:文件名
        file.transferTo(new File(realPath, newFileName));
    }
}

5.4 ,完成 FileController

package com.study.controller;

import com.study.service.FileService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletRequest;
import java.io.File;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;


@RestController
@RequestMapping("/file")
public class FileController {
    @Autowired
    private FileService fileService;

    /**
     * @MethodName upload
     * @Description 用来测试文件上传,注意此种方式不能用于jar包部署
     * 由于这种方式存在局限性,所以现在不推荐使用了
     * @param: file 定义接收文件对象multipartFile,file变量名要与form中input type="file"标签name属性名一致
     * @param: request
     * @return: java.lang.String
     * @Author Jiangnan Cui
     * @Date 2022/6/2 18:02
     */
    @PostMapping("upload")
    public String upload(MultipartFile file, HttpServletRequest request) throws IOException {
        fileService.upload(file);
        return "upload success";
    }
}

5.5 ,测试

在这里插入图片描述
在这里插入图片描述

6,文件下载

将服务器某个资源文件下载到用户本地计算机过程

6.1 修改 FileService 接口

void download(String fileName, HttpServletResponse response) throws FileNotFoundException, UnsupportedEncodingException,IOException;

6.2 修改 FileServiceImpl

@Override
    public void download(String fileName, HttpServletResponse response) throws FileNotFoundException, UnsupportedEncodingException,IOException {
        log.debug("当前下载文件名为:{}",fileName);
        log.debug("当前下载文件路径为为:{}",fileDir);

        //1.指定在绝对路径中读取文件
        File file = new File(fileDir, fileName);

        //2.将文件读取为文件输入流
        FileInputStream fis = new FileInputStream(file);

        //3.获取响应流之前一定要设置以附件形式下载,否则只能在浏览器进行页面展示;为防止文件名中文乱码,需要指定编码
        response.setHeader("content-disposition","attachment;filename="+ URLEncoder.encode(fileName,"UTF-8"));

        //4.获取响应输出流
        ServletOutputStream sos = response.getOutputStream();

        //spring工具类
        FileCopyUtils.copy(fis,sos);
    }

6.3 修改 FileController

/**
     * @MethodName download
     * @Description 测试文件下载
     * @param: fileName
     * @param: response
     * @Author Jiangnan Cui
     * @Date 2022/6/3 23:14
     */
    @PostMapping("download")
    public void download(@RequestParam("fileName") String fileName, HttpServletResponse response) throws IOException {
        fileService.download(fileName,response);
    }

6. 4 测试

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值