Bootstrap

Spring Boot 入门到精通(二)

五、SpringBoot整合MyBatis

5.1 mapper 配置

(1)启动器

  • 内含HikariCP 驱动
  • 内含jdbc驱动
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>2.1.0</version>
        </dependency>

(2)启动器依赖关系
在这里插入图片描述

5.2 mapper映射配置:配置文件方式

  • 配置文件放置在resources目录下(编译后的类路径下)
    在这里插入图片描述

5.3 注解配置方式

(1)@Mapper注解

  • 在每个 使用mybatis操作注解的接口上 加上 @Mapper注解,SpringBoot 会生成一个此接口的代理对象加入Spring容器中进行管理,从而实现对数据库的持久化操作
    在这里插入图片描述

(2)@MapperScan注解

  • 引导类上加@MapperScan注解,并指明要扫描的包,SpringBoot会为所指明包下的每一个接口生成一个代理对象,并将其加入Spring容器中进行管理,进而实现对数据库的持久化操作
    在这里插入图片描述

六. 自定义部分SpringMvc配置。

6.1 SpringBoot整合日期转换器

  • 通过实现WebMvcConfigurer并添加@Configuration注解来实现自定义部分SpringMvc配置。
  • 如果你想要保持Spring Boot 的一些默认MVC特征,同时又想自定义一些MVC配置(包括:拦截器格式化器, 视图控制器消息转换器 等等)

6.1.1 配置原理

  • 拦截器、转换器也是我们经常需要使用的,在SpringBoot中该如何配置呢?
  • 拦截器、转换器不是一个普通属性,而是一个类,所以就要用到java配置方式了。在SpringBoot官方文档中有这么一段说明:

If you want to keep Spring Boot MVC features and you want to add additional MVC configuration (interceptors, formatters, view controllers, and other features), you can add your own @Configuration class of type WebMvcConfigurer but without @EnableWebMvc. If you wish to provide custom instances of RequestMappingHandlerMapping, RequestMappingHandlerAdapter, or ExceptionHandlerExceptionResolver, you can declare a WebMvcRegistrationsAdapter instance to provide such components.

If you want to take complete control of Spring MVC, you can add your own @Configuration annotated with @EnableWebMvc.

  • 翻译:

如果你想要保持Spring Boot 的一些默认MVC特征,同时又想自定义一些MVC配置(包括:拦截器,格式化器, 视图控制器、消息转换器 等等),你应该让一个类实现WebMvcConfigurer,并且添加@Configuration注解,但是千万不要@EnableWebMvc注解。如果你想要自定义HandlerMappingHandlerAdapterExceptionResolver等组件,你可以创建一个WebMvcRegistrationsAdapter实例 来提供以上组件。

如果你想要完全自定义SpringMVC,不保留SpringBoot提供的一切特征,你可以自己定义类并且添加@Configuration注解和@EnableWebMvc注解

  • 总结: 通过实现WebMvcConfigurer并添加@Configuration注解来实现自定义部分SpringMvc配置。

6.1.2 日期转换器整合

(1)引入日期格式转化依赖(工具类)

<!--        日期转换-->
        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-lang3</artifactId>
            <version>3.0</version>
        </dependency>

(2)自定义日期转换器(实现了Converter接口)

import org.springframework.core.convert.converter.Converter;
import org.apache.commons.lang3.time.DateUtils;

import java.text.ParseException;
import java.util.Date;

public class DateConverter implements Converter<String, Date> {
    @Override
    public Date convert(String s) {

//       方式1: 使用工具类(commons.lang3)包下
        String[] patterns = new String[]{
                "yyyy-MM-dd","yyyy-MM-dd hh:mm:ss","yyyy/MM/dd","yyyy/MM/dd hh:mm:ss",
                "MM-dd-yyyy","dd-MM-yyyy"};
        Date date=null;
        try {
             date= DateUtils.parseDate(s, patterns);
        } catch (ParseException e) {
            e.printStackTrace();
        }
        return date;

//      方式2: 基本方法
//        SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd");
//        Date date=null;
//        try {
//        date = sdf.parse(s);
//        } catch (ParseException e) {
//            e.printStackTrace();
//        }
//        return date;
    }
}

(3)配置日期转换器

  • 在实现WebMvcConfigurer并添加@Configuration注解类中,实现自定义部分SpringMvc配置
  • 通过重写addXXXXXX方法,在其中注册相应的转换器拦截器 等等
@Configuration
public class MyConfig implements WebMvcConfigurer {

//    1.拦截器注册
    /**
     * @param registry :注册自定义的拦截器
     */
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        /**
         * addPathPatterns:要拦截的访问路径
         * excludePathPatterns:在拦截访问路径的基础上,排除哪些路径不拦截
         */
        registry.addInterceptor(new LoginInterceptor()).addPathPatterns("/user/**").excludePathPatterns("/admin/**");
    }
    
//    2.转换器注册
    /**
     * @param registry : 注册自定义的转换器
     */
    @Override
    public void addFormatters(FormatterRegistry registry) {
        registry.addConverter(new DateConverter());
    }
}

6.2 SpringBoot整合拦截器

(1)自定义拦截器

  • 实现HandlerInterceptor接口,重写preHandle方法
public class LoginInterceptor implements HandlerInterceptor {

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
			书写业务逻辑
    }

(2)配置拦截器

@Configuration
public class MyConfig implements WebMvcConfigurer {

//    1.拦截器注册
    /**
     * @param registry :注册自定义的拦截器
     */
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        /**
         * addPathPatterns:要拦截的访问路径
         * excludePathPatterns:在拦截访问路径的基础上,排除哪些路径不拦截
         */
        registry.addInterceptor(new LoginInterceptor()).addPathPatterns("/user/**").excludePathPatterns("/admin/**");
    }
    
//    2.转换器注册
    /**
     * @param registry : 注册自定义的转换器
     */
    @Override
    public void addFormatters(FormatterRegistry registry) {
        registry.addConverter(new DateConverter());
    }
}

七. Spring Boot 自定义日志配置(基于AOP)

  • 基本思路
    在service.impl层设置切面(切点+通知),记录每个方法的执行开始和结束,以及出现异常时抛出的异常信息
  • 实现代码(LogConfig.java)
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.annotation.Configuration;

import java.util.Date;

/**
 * @ClassName LogConfig
 * @Description TODO
 * @Author 非乐
 * @Date 2022/9/21 19:50
 * @Version 1.0
 **/
@Configuration
@Aspect
public class LogConfig {
//    声明日志
    private final static Logger LOG=LoggerFactory.getLogger(LogConfig.class);

//    定义切点
    @Pointcut("execution(* *.*.service.impl.*.*(..))")
    public void put(){}

    @Around("put()")
    public Object logMessage(ProceedingJoinPoint proceedingJoinPoint) {
//        获取方法信息
        MethodSignature signature = (MethodSignature) proceedingJoinPoint.getSignature();
//        打印日志
        LOG.debug("==========开始执行方法:{}"+signature.getMethod().getName()+"====="+new Date() +"=====");
        Object proceed = null;
        try {
            proceed =  proceedingJoinPoint.proceed();
            LOG.debug("方法执行成功:{}"+signature.getMethod().getName());
        } catch (Throwable throwable) {
            LOG.error("方法出现异常:{}"+signature.getMethod().getName());
            LOG.error("异常信息:"+throwable.getMessage().toString());
            throwable.printStackTrace();
        }finally {
            LOG.debug("==========方法执行结束:{}"+signature.getMethod().getName()+"====="+new Date() +"=====");
        }
        return proceed;
    }
}
  • 配置文件
    • 虽然定义的切点在service.impl包下,但实质上的日志打印是在所定义的日志文件下(LOG打印),所以配置文件的日志打印要定义在日志文件所在的包下
logging:
    level:
      com:
        edu:
          config: debug

八、Spring Boot 整合JPA

8.1 JPA 简介

(1)概念: JPA 是一个全自动化 ORM 持久层框架,具有以下特点:

  • ORM映射元数据
    JPA支持XML和JDK5.0注解两种元数据的形式,元数据描述对象和表之间的映射关系,框架据此将实体对象持久化到数据库表中
  • API
    用来操作实体对象,执行CRUD操作,框架在后台替代我们完成所有的事情,开发者从繁琐的JDBC和SQL代码中解脱出来。
  • 查询语言
    这是持久化操作中很重要的一个方面,通过面向对象而非面向数据库的查询语言查询数据,避免程序的SQL语句紧密耦合。一般只对单表进行操作

(2)JPA 注解

  • 由于是面向对象的,所以在实体上添加注解,标记、表示、实现与数据库的映射
  • 注解
    • @Entity: 表示此实体使用JPA实体映射
    • @Table: 表明要映射到数据库中哪一张表(name=“名”)
    • @Id: 表明此属性是主键
    • @GeneratedValue: 表明主键的策略(是否是自增长)
    • @Column: 当实体属性名与数据库字段名称不相同时,使用此注解可以实现二者对应
    • @Transient: 表明此字段不加入数据库中(不对数据库表字段进行映射)

在这里插入图片描述

8.2 Spring Boot 整合JPA

  • JPA 操作数据库是通过自身框架实现的,底层依靠hibernate实现
  • JPA底层封装有面向对象查询的SQL语句,但也提供了注解支持原生SQL语句的查询

(1)引入JPA启动器

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

在这里插入图片描述

(2)JPA 配置
在这里插入图片描述
(3)JPA 操作接口

  • 必须继承JpaRepository<映射实体,映射实体主键类型>接口
public interface PermissionRepository extends JpaRepository<Permission,Integer>{
			自定义相关操作
}
  • 当继承了JpaRepository接口后,Spring Boot 会为其继承接口生成一个代理类,并将其加入Spring容器中进行管理
  • JPA接口默认提供了基本的增删改查方法API,可以直接调用
  • JPA 接口提供了以findBy...开始的单体字段查询API
//    支持以 findBy... 单条件查询
    Student findStudentByStudentName(String name);

//  支持以 findBy... 的 多条件查询
    List<Student> findStudentByAgeAndStudentNameLike(int gge,String name);

    List<Student> findStudentByAgeOrStudentNameLike(int gge,String name);
  • JPA 提供注解@Query,实现原生SQL语句的操作
//    查询权限集合
    /**
     *@Query:支持原生SQL语句查询
     *      value:SQL语句,支持传参操作,?1:表示第一个参数(与传入形参相对应)
     *      nativeQuery = true:表示开启原生SQL语句查询
     * @param name:参数
     * @return
     */
    @Query(value = "select tp.permission_name\n" +
            "from tb_user tu,tb_role tr,tb_permission tp,tb_user_role tur,tb_role_permission trp\n" +
            "where \n" +
            "\ttu.id=tur.userid and\n" +
            "\ttur.roleid=tr.id and\n" +
            "\ttr.id = trp.roleid and\n" +
            "\ttrp.perid=tp.id and\n" +
            "\ttu.user_name=?1",nativeQuery = true)
    List<String> findPermissionByName(String name);

九、Spring Boot 整合邮件发送

(1)引入邮件发送启动器

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

(2)配置邮件发送
在这里插入图片描述
(3)代码整合(以验证码为例)

//     注册密码加密
    @Autowired
    CreateMD5 createMD5;

//    持久层
    @Autowired
    UserRepository userRepository;

//    注册邮件发送bean(SpringBoot提供,自动装配时加载)
    @Autowired
    JavaMailSender javaMailSender;

//    发送源邮箱
    @Value("${spring.mail.username}")
    String from;

//    获取验证码
    @Override
    public String sendEmail(TbUser tbUser, HttpSession session) {
//        1.判断邮箱是否已经被注册
        TbUser byEmail = userRepository.findByEmail(tbUser.getEmail());
        if (byEmail!=null){
            return "邮箱已被注册!";
        }

//        2.给指定邮箱发送验证码(创建信息携带体)
        SimpleMailMessage simpleMailMessage = new SimpleMailMessage();
//        设置源邮箱
        simpleMailMessage.setFrom(from);
//        设置目的邮箱
        simpleMailMessage.setTo(tbUser.getEmail());
//        设置发送主题
        simpleMailMessage.setSubject("注册用户验证码");
//      设置发送内容(验证码)
        StringBuffer stringBuffer = new StringBuffer();
        for (int i=0;i<4;i++){
            int i1 = new Random().nextInt(10);
            stringBuffer.append(i1);
        }
        simpleMailMessage.setText(stringBuffer.toString());
//        3.发送验证码
        javaMailSender.send(simpleMailMessage);
//        4.将验证码保存在sessin中,供注册验证使用
        session.setAttribute("code",stringBuffer.toString());
        session.setAttribute("email",tbUser.getEmail());

        return "发送成功";
    }

;