SpringBoot——自学笔记

SpringBoot——自学笔记

学习视频B站狂神说:https://www.bilibili.com/video/BV1PE411i7CV

1、springboot自动装配原理浅理解

在编写springboot项目时,主项目会有一个@SpringBootApplication,在这个注解的源码中包含了三个主要注解

  1. @SpringBootConfiguration

    通过源码得知他是一个@Configuration,所以也就是对spring原生注解的封装

  2. @EnableAutoConfiguration

    加上此注解会自动开启装配功能,也就是说spring会在自己的classpath(类路径)下找到所有配置的Bean进行装配

  3. @ComponentScan

    默认扫描的是与该类同级的类或者同级包下的所有类(这也就是为什么我们的项目代码建包或者建类需要在启动类的同级包下的原因

总的来说:

springboot自动装配原理利用了SpringFactoriesLoader来加载META-INF/spring.factories文件里的所有配置的EnableAutoConfiguration,通过start启动器(有一个注解叫:@ConditionalOnClass)判断是否生效,最后确定要装配的类

精髓

1、SpringBoot启动会加载大量的自动配置类

2、我们看我们需要的功能有没有在SpringBoot默认写好的自动配置类当中;

3、我们再来看这个自动配置类中到底配置了哪些组件;(只要我们要用的组件存在在其中,我们就不需要再手动配置了)

4、给容器中自动配置类添加组件的时候,会从properties类中获取某些属性。我们只需要在配置文件中指定这些属性的值即可;

**xxxxAutoConfigurartion:自动配置类;**给容器中添加组件

xxxxProperties:封装配置文件中相关属性;

2、主启动类的run()方法

run()

首先需要明白,该方法不仅仅只是一个简单的main方法,它启动时会开启一个服务!

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

SpringApplication.run分析

分析该方法主要分两部分,一部分是SpringApplication的实例化,二是run方法的执行;

SpringApplication

这个类主要做了以下四件事情:

1、推断应用的类型是普通的项目还是Web项目

2、查找并加载所有可用初始化器 , 设置到initializers属性中

3、找出所有的应用程序监听器,设置到listeners属性中

4、推断并设置main方法的定义类,找到运行的主类

3、YAML了解及使用

详情见博客:https://blog.csdn.net/weixin_46508271/article/details/118678699?spm=1001.2014.3001.5501

4、使用YAML注入配置文件

1、在springboot项目的resource目录新建文件application.yml

2、导入配置注解处理器依赖文件

<dependency>
    <groupId>org.springframework.bootgroupId>
    <artifactId>spring-boot-configuration-processorartifactId>
    <optional>trueoptional>
dependency>

3、编写两个实体类

​ Dog:

@Component//注册bean
public class Dog {
    private String name;
    private String age;
    
    //省略构造函数,get、set方法等...
}

​ Person:

@Component//注册bean
public class Person {
    private String name;
    private String age;
    private Date birth;
    private Dog dog;
    private List<String> hobby;
    private Map<Object,Object> maps;
    
    //省略构造函数,get、set方法等...
}

4、编写application.yml配置文件

person:
  name: 小梁
  age: 20
  birth: 2021/07/12
  dog:
    name: 小梁的狗
    age: 3
  hobby:
    - 唱歌
    - 跳舞
    - rap
    - 篮球
  maps: {k1: v1, k2: v2}

5、注入到Person类中

@Component
@ConfigurationProperties(prefix = "person")
public class Person {
    private String name;
    private String age;
    private Date birth;
    private Dog dog;
    private List<String> hobby;
    private Map<Object,Object> maps;
    
    //省略构造函数,get、set方法等...
}

@ConfigurationProperties作用:
将配置文件中配置的每一个属性的值,映射到这个组件中;
告诉SpringBoot将本类中的所有属性和配置文件中相关的配置进行绑定;
参数 prefix = “person” : 将配置文件中的person下面的所有属性一一对应;

6、测试

@SpringBootTest
class Springboot01ApplicationTests {
    @Autowired
    Person person;//将person自动注入进来
    @Test
    void contextLoads() {
        System.out.println(person.toString());//打印person的信息
    }
}

SpringBoot——自学笔记_第1张图片

5、JSR303校验

1、导入依赖

2、在类上添加注解:@Validated

3、在需要进行数据规范的属性上进行注解标注(此处以邮箱格式为例)

@Component//注册bean
@ConfigurationProperties(prefix = "person")
@Validated//数据校验
public class Person {
    @Email//标明name属性的值必须为邮箱格式
    private String name;
    private String age;
    private Date birth;
    private Dog dog;
    private List<String> hobby;
    private Map<Object,Object> maps;
    //省略构造函数,get、set方法等...
}

输入格式错误时:

SpringBoot——自学笔记_第2张图片


  1. Bean Validation 中内置的 constraint

SpringBoot——自学笔记_第3张图片

  1. Hibernate Validator 附加的 constraint
    SpringBoot——自学笔记_第4张图片

6、多环境切换

profile是Spring对不同环境提供不同配置功能的支持,可以通过激活不同的环境版本,实现快速切换环境;

我们在主配置文件编写的时候,文件名可以是 application-{profile}.properties/yml , 用来指定多个环境版本;

6.1、properties的多文档块

application-test.properties 代表测试环境配置

application-dev.properties 代表开发环境配置

但是Springboot并不会直接启动这些配置文件,它默认使用application.properties主配置文件

我们需要通过一个配置来选择需要激活的环境:

#比如在配置文件中指定使用dev环境,我们可以通过设置不同的端口号进行测试;
#我们启动SpringBoot,就可以看到已经切换到dev下的配置了;spring.profiles.active=dev

6.2、yaml的多文档块


server:
  port: 8081
#选择要激活那个环境块
spring:
  profiles:
    active: prod

---
server:
  port: 8083
spring:
  profiles: dev #配置环境的名称


---

server:
  port: 8084
spring:
  profiles: prod  #配置环境的名称

注意:如果yml和properties同时都配置了端口,并且没有激活其他环境 , 默认会使用properties配置文件的

6.2、配置文件加载优先级

springboot 启动会扫描以下位置的application.properties或者application.yml文件作为Spring boot的默认配置文件:

优先级1:项目路径下的config文件夹配置文件
优先级2:项目路径下配置文件
优先级3:资源路径下的config文件夹配置文件
优先级4:资源路径下配置文件

优先级由高到底,高优先级的配置会覆盖低优先级的配置;

7、静态资源处理

7.1、静态资源映射规则

ResourceProperties :


// 进入方法
public String[] getStaticLocations() {
    return this.staticLocations;
}
// 找到对应的值
private String[] staticLocations = CLASSPATH_RESOURCE_LOCATIONS;
// 找到路径
private static final String[] CLASSPATH_RESOURCE_LOCATIONS = { 
    "classpath:/META-INF/resources/",
    "classpath:/resources/", 
    "classpath:/static/", 
    "classpath:/public/" 
};

其中的classpath:代表的就是我们的资源文件夹:resources

ResourceProperties 可以设置和我们静态资源有关的参数;这里面指向了它会去寻找资源的文件夹,即上面数组的内容。

所以我们可以得出结论,以下四个目录存放的静态资源可以被我们识别读取

"classpath:/META-INF/resources/"
"classpath:/resources/"
"classpath:/static/"
"classpath:/public/"

一般就存放在下面三个文件就行

8、首页处理


@Bean
public WelcomePageHandlerMapping welcomePageHandlerMapping(ApplicationContext applicationContext,
                                                           FormattingConversionService mvcConversionService,
                                                           ResourceUrlProvider mvcResourceUrlProvider) {
    WelcomePageHandlerMapping welcomePageHandlerMapping = new WelcomePageHandlerMapping(
        new TemplateAvailabilityProviders(applicationContext), applicationContext, getWelcomePage(), // getWelcomePage 获得欢迎页
        this.mvcProperties.getStaticPathPattern());
    welcomePageHandlerMapping.setInterceptors(getInterceptors(mvcConversionService, mvcResourceUrlProvider));
    return welcomePageHandlerMapping;
}

继续深入:


private Optional<Resource> getWelcomePage() {
    String[] locations = getResourceLocations(this.resourceProperties.getStaticLocations());
    // ::是java8 中新引入的运算符
    // Class::function的时候function是属于Class的,应该是静态方法。
    // this::function的funtion是属于这个对象的。
    // 简而言之,就是一种语法糖而已,是一种简写
    return Arrays.stream(locations).map(this::getIndexHtml).filter(this::isReadable).findFirst();
}
// 欢迎页就是一个location下的的 index.html 而已
private Resource getIndexHtml(String location) {
    return this.resourceLoader.getResource(location + "index.html");
}

欢迎页,静态资源文件夹下的所有 index.html 页面;被 /** 映射。

比如我访问 http://localhost:8080/ ,就会找静态资源文件夹下的 index.html

9、Thymeleaf模板引擎

SpringBoot推荐使用Thymeleaf模板引擎

9.1、引入Thymeleaf

Thymeleaf 官网:https://www.thymeleaf.org/

Thymeleaf 在Github 的主页:https://github.com/thymeleaf/thymeleaf

Spring官方文档:找到我们对应的版本

https://docs.spring.io/spring-boot/docs/2.5.0.RELEASE/reference/htmlsingle/#using-boot-starter

找到对应的依赖并导入:


<dependency>
    <groupId>org.springframework.bootgroupId>
    <artifactId>spring-boot-starter-thymeleafartifactId>
dependency>

9.2、使用Thymeleaf

在我们需要操作的html界面中添加命名空间xmlns:th="http://www.thymeleaf.org"

DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    ....
head>

Thymeleaf基本语法

Selection Variable Expressions: *{...}:选择表达式:和${}在功能上是一样;  
Message Expressions: #{...}:获取国际化内容  
Link URL Expressions: @{...}:定义URL
Fragment Expressions: ~{...}:片段引用表达式

比如我们在controller层中写一个请求:

@Controller
public class MsgController {
    @RequestMapping("/test")
    public ModelAndView test(){
        ModelAndView mv = new ModelAndView("test");
        mv.addObject("msg","欢迎来到SpringBoot!");
        mv.addObject("users", Arrays.asList("小梁","大梁","老梁"));
        return mv;
    }
}

在前端界面接收:

DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>SpringBoot Testtitle>
head>
<body>
<div th:text="${msg}">div>
<h3 th:each="user:${users}" th:text="${user}">h3>
body>
html>

显示结果:

SpringBoot——自学笔记_第5张图片

10、员工管理系统:准备工作

10.1、新建springboot项目

这里为了偷懒,导入一下lombok的依赖(如果第一次使用需要先安装插件)

<dependency>
    <groupId>org.projectlombokgroupId>
    <artifactId>lombokartifactId>
dependency>

10.2、导入静态资源

SpringBoot——自学笔记_第6张图片

10.3、创建实体类

Department

@Data
@AllArgsConstructor
@NoArgsConstructor
public class Department {
    private Integer id;
    private String department;
}

Employee

@Data
@NoArgsConstructor
public class Employee {
    private Integer id;
    private String name;
    private String email;
    private Integer gender;
    private Department department;
    private Date birth;

    //这里手写有参构造的原因是直接给birth初始值,省的后面还得去赋值
    public Employee(Integer id, String name, String email, Integer gender, Department department) {
        this.id = id;
        this.name = name;
        this.email = email;
        this.gender = gender;
        this.department = department;
        this.birth = new Date();
    }
}

10.4、编写dao

DepartmentDao

//部门表dao
@Repository
public class DepartmentDao {
    //模拟数据库中的数据
    private static Map<Integer, Department> departments = null;

    static {
        //创建一个部门表
        departments = new HashMap<Integer,Department>();
        departments.put(101,new Department(101,"教学部"));
        departments.put(102,new Department(102,"研发部"));
        departments.put(103,new Department(103,"运维部"));
        departments.put(104,new Department(104,"后勤部"));
        departments.put(105,new Department(105,"市场部"));
    }

    //查询所有部门信息
    public Collection<Department> getDepartments(){
        return departments.values();
    }

    //根据id查询部门信息
    public Department getDepartmentByID(Integer id){
        return departments.get(id);
    }

}

EmployeeDao

//员工表dao
@Repository
public class EmployeeDao {
    //模拟数据
    public static Map<Integer,Employee> employees = null;
    //员工所属部门
    @Autowired
    private DepartmentDao departmentDao;

    static {
        employees = new HashMap<Integer,Employee>();//创建员工表

        employees.put(1001,new Employee(1001,"AAA","[email protected]",0,new Department(101,"教学部")));
        employees.put(1002,new Employee(1002,"BBB","[email protected]",1,new Department(102,"研发部")));
        employees.put(1003,new Employee(1003,"CCC","[email protected]",0,new Department(103,"运维部")));
        employees.put(1004,new Employee(1004,"DDD","[email protected]",1,new Department(104,"后勤部")));
        employees.put(1005,new Employee(1005,"EEE","[email protected]",0,new Department(105,"市场部")));
    }

    //主键自增
    public Integer initId = 1006;

    //增加员工
    public void add(Employee employee){
        if (employee.getId() == null){
            employee.setId(initId++);
        }

        employee.setDepartment(departmentDao.getDepartmentByID(employee.getDepartment().getId()));

        employees.put(employee.getId(),employee);
    }

    //查询所有员工信息
    public Collection<Employee> getEmployees(){
        return employees.values();
    }

    //通过ID查询员工信息
    public Employee getEmployeeByID(Integer id){
        return employees.get(id);
    }

    //通过ID删除员工
    public void del(Integer id){
        employees.remove(id);
    }
}

11、员工管理系统:首页实现

编写mvc配置类,我这里命名为:MyMVCConfig

@Configuration
public class MyMVCConfig implements WebMvcConfigurer {
    //修改首页配置
    @Override
    public void addViewControllers(ViewControllerRegistry registry) {
        registry.addViewController("/").setViewName("index");
        registry.addViewController("/index.html").setViewName("index");
    }
}

启动项目,访问localhost:8080 检查项目是否正常

建议配置一下项目路径:

在springboot的配置文件application.properties中:

# 配置项目路径
server.servlet.context-path=/teng

这样的话访问项目欢迎界面:localhost:8080/teng

12、员工管理系统:国际化

1、新建一个名叫“i18n”的包,我们用来存放国际化配置,然后在这个包下,我们再创建几个properties的配置文件,用来配置语言,如图所示

SpringBoot——自学笔记_第7张图片

2、给配置文件添加内容

SpringBoot——自学笔记_第8张图片

3、在application.properties配置文件中添加

spring.messages.basename=i18n.login

4、修改index.html,按照配置的国际化参数都设置好

SpringBoot——自学笔记_第9张图片

5、自定义配置,使我们页面中的中英文切换生效

5.1、先给两个按钮添加链接

SpringBoot——自学笔记_第10张图片

5.2、编写MyLocaleResolver实现接口LocaleResolver,重写方法

public class MyLocaleResolver implements LocaleResolver {
    @Override
    public Locale resolveLocale(HttpServletRequest request) {
        String l = request.getParameter("l");
        Locale locale = Locale.getDefault();
        if (!StringUtils.isEmpty(l)){
            String[] splits = l.split("_");
            locale = new Locale(splits[0],splits[1]);
        }
        return locale;
    }

    @Override
    public void setLocale(HttpServletRequest request, HttpServletResponse response, Locale locale) {

    }
}

5.3、在MyMVCConfig中将MyLocaleResolver注入springboot中

@Bean
public LocaleResolver localeResolver(){
    return new MyLocaleResolver();
}

可能导致国际化不成功的问题:

1、SpringBoot——自学笔记_第11张图片

这个地方填入的是语言的种类,而不是配置文件名(比如"login_en_US.properties")!

2、application.properties配置文件是否正确配置了spring.messages.basename=i18n.login

3、在配置类中,标红处的名字必须是localeResolver,因为spring会根据这个固定的名称去自动装配,如果改名了那spring自然无法识别!

SpringBoot——自学笔记_第12张图片

13、员工管理系统:登录功能实现

1、编写登录请求

@Controller
public class LoginController {
    @RequestMapping("/user/login")//请求地址
    public ModelAndView login(String userName, String password, HttpSession session){
        ModelAndView mv = new ModelAndView();
        if (!StringUtils.isEmpty(userName) && password.equals("123456")){
            session.setAttribute("loginInfo",userName);//登录成功添加session信息
            mv.setViewName("redirect:/main.html");//登陆成功——>重定向到main.html
        }
        else {
            mv.addObject("msg","用户名或密码错误!");//错误提示
            mv.setViewName("index");
        }
        return mv;
    }
}

2、在MyMVCConfig设置跳转界面

registry.addViewController("/main.html").setViewName("dashboard");

3、修改html表单提交请求

SpringBoot——自学笔记_第13张图片

14、员工管理系统:登录拦截

1、编写拦截器MyHandlerInterceptor

//登录拦截器
public class MyHandlerInterceptor implements HandlerInterceptor {
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        Object loginSession = request.getSession().getAttribute("loginInfo");
        if (loginSession == null){
            request.setAttribute("msg","没有权限,请先登录!");
            request.getRequestDispatcher("/index.html").forward(request,response);
            return false;
        }
        else {
            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);
    }
}

2、在MyMVCConfig中注册拦截器

//注册登录拦截器
@Override
public void addInterceptors(InterceptorRegistry registry) {
    registry.addInterceptor(new MyHandlerInterceptor()).addPathPatterns("/**").excludePathPatterns(
            "/","/user/login","/index.html","/css/**","/js/**","/img/**");
}

addPathPatterns()为拦截的界面

excludePathPatterns()为放行资源


展示员工列表、增加员工实现、修改员工信息略

15、员工管理系统:删除及404处理

16、整合JDBC使用

16.1、准备阶段

1、创建项目,导入依赖

SpringBoot——自学笔记_第14张图片

2、编写application.yml配置文件,这里的连接对象以mybatis数据库为例

spring:
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://localhost:3306/mybatis?useEncoding=true&characterEncoding=utf-8
    username: root
    password: 123456

3、在测试类中进行简单测试

@SpringBootTest
class Springboot04JdbcApplicationTests {

    //DI注入数据源
    @Autowired
    DataSource dataSource;
    @Test
    void contextLoads() throws SQLException {
        //打印默认数据源
        System.out.println(dataSource.getClass());

        Connection conn = dataSource.getConnection();
        System.out.println(conn);
        conn.close();
    }

}

从控制台输出可知:在springboot中默认的数据源为:class com.zaxxer.hikari.HikariDataSource

HikariDataSource 号称 Java WEB 当前速度最快的数据源,相比于传统的 C3P0 、DBCP、Tomcat jdbc 等连接池更加优秀;

16.2、CRUD操作数据库

JDBCTemplate

​ JDBCTemplate是Spring对JDBC的封装,目的是使JDBC更加易于使用。JdbcTemplate是Spring的一部分。JdbcTemplate处理了资源的建立和释放。他帮助我们避免一些常见的错误,比如忘了总要关闭连接。他运行核心的JDBC工作流,如Statement的建立和执行,而我们只需要提供SQL语句和提取结果。

在JdbcTemplate中执行SQL语句的方法大致分为3类:

  1. execute:可以执行所有SQL语句,一般用于执行DDL语句。
  2. update:用于执行INSERTUPDATEDELETE等DML语句。
  3. queryXxx:用于DQL数据查询语句。

编写JDBCController测试:

package com.teng.controller;


import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.List;
import java.util.Map;

@RestController
@RequestMapping("/jdbc")
public class jdbcController {
    @Autowired
    JdbcTemplate jdbcTemplate;

    //查询所有用户
    @RequestMapping("/list")
    public List<Map<String,Object>> userList(){
        String sql = "select * from mybatis.user";
        return jdbcTemplate.queryForList(sql);
    }

    //增加用户
    @RequestMapping("add")
    public String addList(){
        String sql = "insert mybatis.user(id,name,pwd) values(5,'法外狂徒','123456')";
        jdbcTemplate.update(sql);
        return "addList-OK!";
    }

    //修改用户信息
    @RequestMapping("/update/{id}")
    public String updateList(@PathVariable("id")Integer id){
        String sql = "update mybatis.user set name=?,pwd=? where id ="+id;
        Object[] objects = new Object[2];
        objects[0]="麻六";
        objects[1]="147258";
        jdbcTemplate.update(sql,objects);
        return "updateList-OK!";
    }

    //删除用户
    @RequestMapping("/del/{id}")
    public String delUser(@PathVariable("id")int id){
        String sql = "delete from mybatis.user where id=?";
        jdbcTemplate.update(sql,id);
        return "deleteUser-OK!";
    }
}

17、整合Druid数据源

Druid

Java程序很大一部分要操作数据库,为了提高性能操作数据库的时候,又不得不使用数据库连接池。
Druid 是阿里巴巴开源平台上一个数据库连接池实现,结合了 C3P0、DBCP 等 DB 池的优点,同时加入了日志监控。
Druid 可以很好的监控 DB 池连接和 SQL 的执行情况,天生就是针对监控而生的 DB 连接池。
Druid已经在阿里巴巴部署了超过600个应用,经过一年多生产环境大规模部署的严苛考验。
Spring Boot 2.0 以上默认使用 Hikari 数据源,可以说 Hikari 与 Driud 都是当前 Java Web 上最优秀的数据源,我们来重点介绍 Spring Boot 如何集成 Druid 数据源,如何实现数据库监控。

17.1、配置数据源

1、导入依赖

<dependency>
    <groupId>com.alibabagroupId>
    <artifactId>druid-spring-boot-starterartifactId>
    <version>1.2.6version>
dependency>

2、在配置文件中切换数据源并配置设置项

spring:
  datasource:
    druid:
      driver-class-name: com.mysql.cj.jdbc.Driver
      url: jdbc:mysql://localhost:3306/mybatis?useEncoding=true&characterEncoding=utf-8
      username: root
      password: 123456
      #Spring Boot 默认是不注入这些属性值的,需要自己绑定
      #druid 数据源专有配置

      minIdle: 5
      maxActive: 20
      maxWait: 60000
      timeBetweenEvictionRunsMillis: 60000
      minEvictableIdleTimeMillis: 300000
      validationQuery: SELECT 1 FROM DUAL
      testWhileIdle: true
      testOnBorrow: false
      testOnReturn: false
      poolPreparedStatements: true

      #配置监控统计拦截的filters,stat:监控统计、log4j:日志记录、wall:防御sql注入
      #如果允许时报错  java.lang.ClassNotFoundException: org.apache.log4j.Priority
      #则导入 log4j 依赖即可,Maven 地址:https://mvnrepository.com/artifact/log4j/log4j
      filters: stat,wall,log4j
      maxPoolPreparedStatementPerConnectionSize: 20
      useGlobalDataSourceStat: true
      connectionProperties: druid.stat.mergeSql=true;druid.stat.slowSqlMillis=500

3、导入log4j依赖项

<dependency>
    <groupId>log4jgroupId>
    <artifactId>log4jartifactId>
    <version>1.2.17version>
dependency>

4、编写log4j.properties

log4j.rootLogger=DEBUG, stdout
# Console output...
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%5p [%t] - %m%n

5、为 DruidDataSource 绑定全局配置文件中的参数,再添加到容器中,而不再使用 Spring Boot 的自动生成了;我们需要 自己添加 DruidDataSource 组件到容器中,并绑定属性

@Configuration
public class DruidConfig {
    //绑定配置文件
    @ConfigurationProperties(prefix = "spring.datasource.druid")//注意:prefix中的不能使用驼峰写法,必须全部小写
    public DataSource druidDataSource(){
        return new DruidDataSource();
    }
}

6、测试

@SpringBootTest
class Springboot04JdbcApplicationTests {

    //DI注入数据源
    @Autowired
    DataSource dataSource;
    @Test
    void contextLoads() throws SQLException {
        //看一下默认数据源
        System.out.println(dataSource.getClass());
        //获得连接
        Connection connection =   dataSource.getConnection();
        System.out.println(connection);

        DruidDataSource druidDataSource = (DruidDataSource) dataSource;
        System.out.println("druidDataSource 数据源最大连接数:" + druidDataSource.getMaxActive());
        System.out.println("druidDataSource 数据源初始化连接数:" + druidDataSource.getInitialSize());

        connection.close();
    }

}

SpringBoot——自学笔记_第15张图片

测试成功,参数生效

17.2、配置Druid数据源监控

​ Druid 数据源具有监控的功能,并提供了一个 web 界面方便用户查看,类似安装 路由器 时,人家也提供了一个默认的 web 页面。

在DruidConfig类中设置 Druid 的后台管理页面,比如 登录账号、密码等配置后台管理;

@Configuration
public class DruidConfig {
    //获取yml配置文件的配置
    @ConfigurationProperties(prefix = "spring.datasource")
    //将druid数据源注入ioc容器
    @Bean
    public DataSource druid(){
        return  new DruidDataSource();
    }

    //配置Druid的监控
    //1、配置管理后台的Servlet
    @Bean
    public ServletRegistrationBean DruidServlet(){
        ServletRegistrationBean bean = new ServletRegistrationBean(new StatViewServlet(), "/druid/*");
        Map<String,String> initParams = new HashMap<>();
        //druid后台登录的用户名
        initParams.put("loginUsername","admin");
        //druid后台登录的密码
        initParams.put("loginPassword","111111");
        //默认就是允许所有访问
        initParams.put("allow","");
        bean.setInitParameters(initParams);
        return bean;
    }
    
        //2、配置监控的filter
    @Bean
    public FilterRegistrationBean druidStatFilter(){
        FilterRegistrationBean bean = new FilterRegistrationBean();
        bean.setFilter(new WebStatFilter());
        Map<String,String> initParams = new HashMap<>();
        initParams.put("exclusions","*.js,*.css,/druid/*");
        bean.setInitParameters(initParams);
        bean.setUrlPatterns(Arrays.asList("/*"));
        return  bean;
    }

}

启动项目,访问地址:localhost:8080/druid/login.html

SpringBoot——自学笔记_第16张图片

使用设置的账号密码登录

SpringBoot——自学笔记_第17张图片

18、整合mybatis

1、新建springboot项目,勾选相关依赖,配置资源过滤

SpringBoot——自学笔记_第18张图片

<resources>
    <resource>
        <directory>src/main/resourcesdirectory>
        <includes>
            <include>**/*.propertiesinclude>
            <include>**/*.xmlinclude>
            <include>**/*.ymlinclude>
        includes>
        <filtering>truefiltering>
    resource>
resources>

2、配置数据库连接信息

spring:
  datasource:
    druid:
      driver-class-name: com.mysql.cj.jdbc.Driver
      url: jdbc:mysql://localhost:3306/mybatis?useEncoding=true&characterEncoding=utf-8
      username: root
      password: 123456
      #Spring Boot 默认是不注入这些属性值的,需要自己绑定
      #druid 数据源专有配置

      minIdle: 5
      maxActive: 20
      maxWait: 60000
      timeBetweenEvictionRunsMillis: 60000
      minEvictableIdleTimeMillis: 300000
      validationQuery: SELECT 1 FROM DUAL
      testWhileIdle: true
      testOnBorrow: false
      testOnReturn: false
      poolPreparedStatements: true

      #配置监控统计拦截的filters,stat:监控统计、log4j:日志记录、wall:防御sql注入
      #如果允许时报错  java.lang.ClassNotFoundException: org.apache.log4j.Priority
      #则导入 log4j 依赖即可,Maven 地址:https://mvnrepository.com/artifact/log4j/log4j
      filters: stat,wall,log4j
      maxPoolPreparedStatementPerConnectionSize: 20
      useGlobalDataSourceStat: true
      connectionProperties: 	    			druid.stat.mergeSql=true;druid.stat.slowSqlMillis=500
mybatis:
  type-aliases-package: com.teng.entity #别名
  mapper-locations: classpath:mapper/*.xml #mapper映射

3、搭建实体类User

@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {
    private int id;
    private String name;
    private String password;
}

4、编写UserMapper

@Mapper
@Repository
public interface UserMapper {
    List<User> getUsers();

    User getUserByID(@Param("id") int id);

    int updateUser(@Param("id") int id);

    int insertUser(User user);

    int deleteUser(@Param("id") int id);
}

5、编写UserMapper.xml


DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">

<mapper namespace="com.teng.mapper.UserMapper">
    <select id="getUsers" resultType="user">
        select * from mybatis.user;
    select>

    <select id="getUserByID" resultType="user">
        select * from mybatis.user where id=#{id};
    select>

    <update id="updateUser">
        update mybatis.user set name=#{name},pwd=#{pwd} where id=#{id};
    update>

    <insert id="insertUser" parameterType="user">
        insert into mybatis.user(id, name, pwd)
        values (#{id},#{name},#{pwd});
    insert>
mapper>

6、编写UserService

public interface UserService {
    List<User> getUsers();

    User getUserByID(int id);

    int updateUser(int id);

    int insertUser(User user);

    int deleteUser(int id);
}

7、编写UserServiceImpl

@Service
public class UserServiceImpl implements UserService{
    @Autowired
    UserMapper userMapper;
    @Override
    public List<User> getUsers() {
        return userMapper.getUsers();
    }

    @Override
    public User getUserByID(int id) {
        return userMapper.getUserByID(id);
    }

    @Override
    public int updateUser(int id) {
        return userMapper.updateUser(id);
    }

    @Override
    public int insertUser(User user) {
        return userMapper.insertUser(user);
    }

    @Override
    public int deleteUser(int id) {
        return userMapper.deleteUser(id);
    }
}

8、编写UserController

@RestController
public class UserController {
    @Autowired
    UserMapper userMapper;

    @RequestMapping("/list")
    public List<User> getUsers(){
        return userMapper.getUsers();
    }
}

整个项目结构:

SpringBoot——自学笔记_第19张图片

19、SpringSecurity的简单使用

SpringSecurity简介

Spring Security是一个能够为基于Spring的企业应用系统提供声明式的安全访问控制解决方案的安全框架。它提供了一组可以在Spring应用上下文中配置的Bean,充分利用了Spring IoC,DI(控制反转Inversion of Control ,DI:Dependency Injection 依赖注入)和AOP(面向切面编程)功能,为应用系统提供声明式的安全访问控制功能,减少了为企业系统安全控制编写大量重复代码的工作。

记住几个类:

  • WebSecurityConfigurerAdapter:自定义Security策略
  • AuthenticationManagerBuilder:自定义认证策略
  • @EnableWebSecurity:开启WebSecurity模式

Spring Security的两个主要目标是 “认证” 和 “授权”(访问控制)。

“认证”(Authentication)

身份验证是关于验证您的凭据,如用户名/用户ID和密码,以验证您的身份。

身份验证通常通过用户名和密码完成,有时与身份验证因素结合使用。

“授权” (Authorization)

授权发生在系统成功验证您的身份后,最终会授予您访问资源(如信息,文件,数据库,资金,位置,几乎任何内容)的完全权限。

这个概念是通用的,而不是只在Spring Security 中存在。

19.1、环境准备

1、新建一个springboot项目,引入web和thymeleaf依赖

SpringBoot——自学笔记_第20张图片

2、导入静态资源文件

SpringBoot——自学笔记_第21张图片

3、编写RouterController

package com.teng.controller;

import org.springframework.http.HttpRequest;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;

import javax.servlet.http.HttpSession;

@Controller
public class RouterController {

    @RequestMapping({"/","/index"})
    public String index(){
        return "index";
    }

    @RequestMapping("/toLogin")
    public String toLogin(){
        return "views/login";
    }

    @RequestMapping("/level1/{id}")
    public String level1(@PathVariable("id")int id){
        return "views/level1/"+id;
    }

    @RequestMapping("/level2/{id}")
    public String level2(@PathVariable("id")int id){
        return "views/level2/"+id;
    }

    @RequestMapping("/level3/{id}")
    public String level3(@PathVariable("id")int id){
        return "views/level3/"+id;
    }
}

19.2、SpringSecurity的使用

1、引入依赖文件

<dependency>
    <groupId>org.springframework.bootgroupId>
    <artifactId>spring-boot-starter-securityartifactId>
dependency>

<dependency>
    <groupId>org.thymeleaf.extrasgroupId>
    <artifactId>thymeleaf-extras-springsecurity5artifactId>
    <version>3.0.4.RELEASEversion>
dependency>

2、新建SecurityConfig类

package com.teng.config;

import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;

@EnableWebSecurity //开启WebSecurity模式
public class SecurityConfig extends WebSecurityConfigurerAdapter {
    //权限管理
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        //定制请求规则
        http.authorizeRequests().antMatchers("/").permitAll() //首页所有人可以访问
            .antMatchers("/level1/**").hasRole("vip1")
            .antMatchers("/level2/**").hasRole("vip2")
            .antMatchers("/level3/**").hasRole("vip3");

        //定制登录页
        http.formLogin()
                .usernameParameter("username")
                .passwordParameter("password")
                .loginPage("/toLogin")
                .loginProcessingUrl("/login");

        //开启注销功能,注销成功后来到首页
        http.csrf().disable();//关闭csrf功能:跨站请求伪造,默认只能通过post方式提交logout请求
        http.logout().logoutSuccessUrl("/");

        //记住我
        http.rememberMe().rememberMeParameter("remember");
    }

    //认证规则
    //可以在内存中自定义,也可以从数据库中拿取数据
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.inMemoryAuthentication().passwordEncoder(new BCryptPasswordEncoder())//passwordEncoder密码加密规则,spring security推荐BCrypt加密规则
            .withUser("xiaoliang").password(new BCryptPasswordEncoder().encode("123456")).roles("vip1","vip2")//xiaoliang用户拥有vip1和vip2的权限
            .and().withUser("admin").password(new BCryptPasswordEncoder().encode("123456")).roles("vip1","vip2","vip3")
            .and().withUser("guest").password(new BCryptPasswordEncoder().encode("123456")).roles("vip3");
    }
}

3、前端界面设置

引入命名空间

xmlns:sec="http://www.thymeleaf.org/extras/spring-security"

这里主要展示登录注销,其他的进行类似设置


<div class="right menu">
    
    <div sec:authorize="!isAuthenticated()">
        <a class="item" th:href="@{/toLogin}">
            <i class="address card icon">i> 登录
        a>
    div>
   
    <div sec:authorize="isAuthenticated()">
        <a class="item">
            用户名:<span sec:authentication="name">span>
        a>
    div>
    <div sec:authorize="isAuthenticated()">
        <a class="item" th:href="@{/logout}">
            <i class="iconfont icon-log-out">i> 注销
        a>
    div>
div>

这里的sec:authorize="!isAuthenticated()"为条件判断,如果成立则显示对应的div块,sec:authentication="name"提取登录用户的信息

4、测试

首页:

SpringBoot——自学笔记_第22张图片

点击登录时弹出的登录页:

SpringBoot——自学笔记_第23张图片

填写用户信息后展示的首页:

SpringBoot——自学笔记_第24张图片

登录账户为“xiaoliang”,因为只给该用户授予了vip1和vip2的权限,所以level3模块不显示!

21、邮件任务

1、引入依赖

<dependency>
    <groupId>org.springframework.bootgroupId>
    <artifactId>spring-boot-starter-mailartifactId>
dependency>

2、编写application.properties文件

spring.mail.username=1208805413
spring.mail.password=wdxjddcitclubaei
spring.mail.host=smtp.qq.com
spring.mail.properties.mail.smtp.ssl.enable=true

3、装配JavaMailSenderImpl

@Autowired
JavaMailSenderImpl mailSender;

4、测试简单邮件任务和复杂邮件任务

package com.teng;

import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.mail.MailSender;
import org.springframework.mail.SimpleMailMessage;
import org.springframework.mail.javamail.JavaMailSenderImpl;
import org.springframework.mail.javamail.MimeMessageHelper;

import javax.mail.MessagingException;
import javax.mail.internet.MimeMessage;
import java.io.File;

@SpringBootTest
class Springboot09AsyncApplicationTests {
    @Autowired
    JavaMailSenderImpl mailSender;

    @Test
    void contextLoads() {
        //简单邮件
        SimpleMailMessage mailMessage = new SimpleMailMessage();
        mailMessage.setFrom("[email protected]");
        mailMessage.setTo("[email protected]");
        mailMessage.setSubject("测试-简单的邮件发送功能");
        mailMessage.setText("buling~");
        mailSender.send(mailMessage);
    }

    @Test
    void contextLoads01() throws MessagingException {
        //复杂邮件发送功能
        MimeMessage mimeMessage = mailSender.createMimeMessage();
        MimeMessageHelper helper = new MimeMessageHelper(mimeMessage, true);

        helper.setFrom("[email protected]");
        helper.setTo("[email protected]");
        helper.setSubject("测试-复杂的邮件发送功能");
        helper.setText("

这是一行有颜色的文本段落

"
,true); //发送附件 helper.addAttachment("18计算机四班.xlsx",new File("D:\\ssh\\18计算机四班.xlsx")); mailSender.send(mimeMessage); } }

22、定时任务

1、在主启动类上添加注解

@EnableScheduling //开启基于注解的定时任务

2、测试,编写ScheduledService

@Service
public class ScheduledService {
    //秒   分   时     日   月   周几
    //0 * * * * MON-FRI
    //注意cron表达式的用法;
    @Scheduled(cron = "0/2 * * * * ?")
    public void hello(){
        System.out.println("定时任务已发送!");
    }
}

常用表达式:

1)0/2 * * * * ?   表示每2秒 执行任务
(1)0 0/2 * * * ?   表示每2分钟 执行任务
(1)0 0 2 1 * ?   表示在每月的1日的凌晨2点调整任务
(2)0 15 10 ? * MON-FRI   表示周一到周五每天上午10:15执行作业
(3)0 15 10 ? 6L 2002-2006   表示2002-2006年的每个月的最后一个星期五上午10:15执行作
(4)0 0 10,14,16 * * ?   每天上午10点,下午2点,4点
(5)0 0/30 9-17 * * ?   朝九晚五工作时间内每半小时
(6)0 0 12 ? * WED   表示每个星期三中午12点
(7)0 0 12 * * ?   每天中午12点触发
(8)0 15 10 ? * *   每天上午10:15触发
(9)0 15 10 * * ?     每天上午10:15触发
(10)0 15 10 * * ?   每天上午10:15触发
(11)0 15 10 * * ? 2005   2005年的每天上午10:15触发
(12)0 * 14 * * ?     在每天下午2点到下午2:59期间的每1分钟触发
(13)0 0/5 14 * * ?   在每天下午2点到下午2:55期间的每5分钟触发
(14)0 0/5 14,18 * * ?     在每天下午2点到2:55期间和下午6点到6:55期间的每5分钟触发
(15)0 0-5 14 * * ?   在每天下午2点到下午2:05期间的每1分钟触发
(16)0 10,44 14 ? 3 WED   每年三月的星期三的下午2:10和2:44触发
(17)0 15 10 ? * MON-FRI   周一至周五的上午10:15触发
(18)0 15 10 15 * ?   每月15日上午10:15触发
(19)0 15 10 L * ?   每月最后一日的上午10:15触发
(20)0 15 10 ? * 6L   每月的最后一个星期五上午10:15触发
(21)0 15 10 ? * 6L 2002-2005   2002年至2005年的每月的最后一个星期五上午10:15触发
(22)0 15 10 ? * 6#3   每月的第三个星期五上午10:15触发

23、热部署

1、引入devtools依赖

<dependency>
    <groupId>org.springframework.bootgroupId>
    <artifactId>spring-boot-devtoolsartifactId>
    <optional>trueoptional>
dependency>

2、打开setting设置——Build、Execution、Deployment——Compiler——勾选Build project automatically

SpringBoot——自学笔记_第25张图片

3、使用ctrl+shift+alt+/,在弹出来的消息框中选择Register,找到wen.app.running,勾选Value
SpringBoot——自学笔记_第26张图片

你可能感兴趣的:(SpringBoot,spring,5)