其他分享
首页 > 其他分享> > SpringBoot 2.X 快速掌握

SpringBoot 2.X 快速掌握

作者:互联网

0、重写博文的原因



1、什么是springboot?

1.1、老规矩:百度百科一下

截图



2、对springboot快速上手

2.1、通过官网来创建 - 了解

这里面的创建方式不做过多说明,只需要在官网里面创建好了,然后下载解压,就可以了,我这里直接使用编辑器创建
springboot搭建项目官网
截图



2.2、使用IDEA编辑器创建

截图

截图

截图

选完之后,idea就会去拉取相应的jar包,创建结果如下:
截图



启动项目

截图

截图

截图



编写controller

截图

重新启动主方法,输入请求
截图

这样就创建成功了一个springboot项目



3、小彩蛋 - banner

截图



上面这玩意儿,我不想看到它

截图

截图



4、了解yml语法

截图

4.1、使用yml给实体类赋值


        <!--    这个jar包就是为了实体类中使用@ConfigurationProperties(prefix = "person")
        这个注解而不报红
         -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-configuration-processor</artifactId>
            <optional>true</optional>
        </dependency>


截图



5、jsr303检验

依赖


        <!--JSR303校验的依赖 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-validation</artifactId>
        </dependency>


使用jsr303检验

截图




空检查
	@Null 验证对象是否为null
	@NotNull 验证对象是否不为null, 无法查检长度为0的字符串
	@NotBlank 检查约束字符串是不是Null还有被Trim的长度是否大于0,只对字符串,且会去掉前后空格.
	@NotEmpty 检查约束元素是否为NULL或者是EMPTY.


Booelan检查
	@AssertTrue 验证 Boolean 对象是否为 true
	@AssertFalse 验证 Boolean 对象是否为 false


长度检查
	@Size(min=, max=) 验证对象(Array,Collection,Map,String)长度是否在给定的范围之内
	@Length(min=, max=) Validates that the annotated string is between min and max included.


日期检查
	@Past 验证 Date 和 Calendar 对象是否在当前时间之前,验证成立的话被注释的元素一定是一个过去的日期
	@Future 验证 Date 和 Calendar 对象是否在当前时间之后 ,验证成立的话被注释的元素一定是一个将来的日期
	@Pattern 验证 String 对象是否符合正则表达式的规则,被注释的元素符合制定的正则表达式,regexp:正则表达式 flags: 指定 Pattern.Flag 的数组,表示正则表达式的相关选项。


数值检查
	建议使用在Stirng,Integer类型,不建议使用在int类型上,因为表单值为“”时无法转换为int,但可以转换为Stirng为”“,Integer为null
	@Min 验证 Number 和 String 对象是否大等于指定的值
	@Max 验证 Number 和 String 对象是否小等于指定的值
	@DecimalMax 被标注的值必须不大于约束中指定的最大值. 这个约束的参数是一个通过BigDecimal定义的最大值的字符串表示.小数存在精度
	@DecimalMin 被标注的值必须不小于约束中指定的最小值. 这个约束的参数是一个通过BigDecimal定义的最小值的字符串表示.小数存在精度
	@Digits 验证 Number 和 String 的构成是否合法
	@Digits(integer=,fraction=) 验证字符串是否是符合指定格式的数字,interger指定整数精度,fraction指定小数精度。
	@Range(min=, max=) 被指定的元素必须在合适的范围内
	@Range(min=10000,max=50000,message=”range.bean.wage”)
	@Valid 递归的对关联对象进行校验, 如果关联对象是个集合或者数组,那么对其中的元素进行递归校验,如果是一个map,则对其中的值部分进行校验.(是否进行递归验证)
	@CreditCardNumber信用卡验证
	@Email 验证是否是邮件地址,如果为null,不进行验证,算通过验证。
	@ScriptAssert(lang= ,script=, alias=)
	@URL(protocol=,host=, port=,regexp=, flags=)



6、yml多环境配置

截图

截图

还有一种标准的配置,即:采用多个yml文件,如:application-test.yml 就是测试环境的配置appilication-dev.yml 就是开发环境的配置appilication-pro.yml 就是生产环境配置



7、设置默认首页

7.1、页面在static目录中时


7.2、页面在templates模板引擎中时

截图

这种需要导入相应的启动器


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


编写controller

截图

测试

截图



8、简单认识thymeleaf

官网学习地址


8.1、什么是thymeleaf?

一张图看明白:

解读:


SpringBoot推荐使用模板引擎:


8.2、thymeleaf的取数据方式

提取出来看一下,从而在springboot中演示一下



8.3、在springboot中使用thymeleaf

依赖


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


怎么使用thymeleaf?

截图

截图





8.4、延伸:传输数据

8.4.1、开胃菜

截图


编写后台,存入数据

截图


在前台获取数据

截图


表空间约束链接如下,这个在thymeleaf官网中有


	xmlns:th="http://www.thymeleaf.org"


测试:

截图



8.4.2、开整

截图


后台

截图


前台

截图


测试

截图


其他的玩法都差不多



9、静态资源处理方式

截图

截图



9.1、webjars的方式处理静态资源


使用jQuery做演示


<dependency>
    <groupId>org.webjars</groupId>
    <artifactId>jquery</artifactId>
    <version>3.4.1</version>
</dependency>

截图


截图


截图


getStaticLocations(),点进去看一下

发现是如下这么一个方法


        public String[] getStaticLocations() {
            return this.staticLocations;
        }


截图

截图


"classpath:/META-INF/resources/",   <!--这个就不多说明,指的就是再建一个META-INF文件夹,里面再建一个resources目录,参照Java基础中的web项目目录-->

"classpath:/resources/",

"classpath:/static/",

"classpath:/public/"



9.1.1、resources/ static/ public的优先级

截图


测试
截图


删掉resources中的资源文件,继续测试

截图

截图



9.1.1.1、总结:resources、static、public优先级


资源放置建议:



10、整合jdbc、druid、druid实现日志监控

10.1、整合jdbc、druid

依赖


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

        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <scope>runtime</scope>
        </dependency>


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


编写application.yml


spring:
  datasource:
    driver-class-name: com.mysql.jdbc.Driver
    url: jdbc:mysql://localhost:3306/mybatis_spring?useUnicode=true&characterEncoding=utf-8
    username: root
    password: "072413"

测试
截图



10.2、整合druid

依赖


<!--要玩druid的话,需要导入下面这个依赖 -->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid-spring-boot-starter</artifactId>
            <version>1.1.10</version>
        </dependency>


修改yml文件

截图


测试
截图



10.3、druid实现日志监控


<!--
	玩druid实现监控日志,需要web启动器支持,因为:druid的statViewServlet本质是继承了servlet
	因此:需要web的依赖支持 / servlet支持
-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>


编写配置


package cn.xiegongzi.config;

// 这个类是为了延伸druid的强大功能 ————— 监控后台
// 注意:这个需要spring的web启动器支持,即:这个监控后台的本质StatViewServlet就是servlet,所以需要servlet支持

import com.alibaba.druid.support.http.StatViewServlet;
import org.springframework.boot.web.servlet.ServletRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.util.HashMap;

@Configuration
public class DruidConfig {

    @Bean
    public ServletRegistrationBean StatViewServlet() {

        ServletRegistrationBean bean = new ServletRegistrationBean<>(new StatViewServlet(), "/druid/*");

        HashMap<String, String> initParameters = new HashMap<>();

    // 下面这些参数可以在 com.alibaba.druid.support.http.StatViewServlet 
    // 的父类 com.alibaba.druid.support.http.ResourceServlet 中找到
        initParameters.put("loginUsername", "zixieqing");  // 登录日志监控的用户名
        initParameters.put("loginPassword", "072413");    // 登录密码

        initParameters.put("allow", "`localhost`");    // 运行谁可以访问日志监控

        bean.setInitParameters(initParameters);
        return bean;
    }
}


测试

截图

截图



11、整合mybatis


11.1、xml版

导入依赖


<!--
        mybatis-spring-boot-starter是第三方( mybatis )jar包,不是spring官网的
        spring自己的生态是:spring-boot-stater-xxxx
-->
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>1.3.2</version>
        </dependency>

        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid-spring-boot-starter</artifactId>
            <version>1.1.10</version>
        </dependency>

        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.47</version>
        </dependency>

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


编写实体


package cn.xiegongzi.entity;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.io.Serializable;

@Data
@AllArgsConstructor
@NoArgsConstructor
public class User implements Serializable {

    private Integer id;
    private String username;
    private String password;
}


编写dao / mapper层


package cn.xiegongzi.mapper;

import cn.xiegongzi.entity.User;
import org.apache.ibatis.annotations.Mapper;

import java.util.List;

/*
*   @Mapper 这个注解是mybati-spring提供的,即:和自动装配是一样的效果
*   还可以用:
*       @Repository   是spring本身提供的
* 
*   以及:在启动类( main )中使用@mapperScan扫包
* */

@Mapper

public interface IUserMapper {

    List<User> findALLUser();
}


编写xml的sql语句

截图


编写yml


# 编写连接池
spring:
  datasource:
    driver-class-name: com.mysql.jdbc.Driver
    url: jdbc:mysql://localhost:3306/mybatis_spring?useUnicode=true&characterEncoding=utf-8
    username: root
    password: "072413"
    type: com.alibaba.druid.pool.DruidDataSource
# 把实现类xml文件添加进来
mybatis:
  mapper-locations: classpath:mapper/*.xml
  type-aliases-package: cn.xiegongzi.entity   # 给实体类配置别名
  configuration:
    map-underscore-to-camel-case: true    # 开启驼峰命名映射

截图


测试

截图



11.2、注解版

截图


截图



12、整合pageHelper分页插件

依赖


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



测试

截图



13、集成swagger


13.1、快速上手

导入依赖


        <!--swagger所需要的依赖-->
        <dependency>
            <groupId>io.springfox</groupId>
            <artifactId>springfox-swagger2</artifactId>
            <version>2.8.0</version>
        </dependency>
        <dependency>
            <groupId>io.springfox</groupId>
            <artifactId>springfox-swagger-ui</artifactId>
            <version>2.8.0</version>
        </dependency>
        <!--这个依赖是为了渲染swagger文档页面的( 为了好看一点罢了 ) ,swagger真正的依赖是上面两个-->
        <dependency>
            <groupId>com.github.xiaoymin</groupId>
            <artifactId>swagger-bootstrap-ui</artifactId>
            <version>1.8.5</version>
        </dependency>

        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <scope>runtime</scope>
        </dependency>

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

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

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


编写swagger配置文件

截图


	package cn.xiegongzi.config;


	import org.springframework.context.annotation.Bean;
	import org.springframework.context.annotation.Configuration;
	import springfox.documentation.builders.ApiInfoBuilder;
	import springfox.documentation.builders.PathSelectors;
	import springfox.documentation.builders.RequestHandlerSelectors;
	import springfox.documentation.service.ApiInfo;
	import springfox.documentation.service.Contact;
	import springfox.documentation.spi.DocumentationType;
	import springfox.documentation.spring.web.plugins.Docket;
	import springfox.documentation.swagger2.annotations.EnableSwagger2;

	@Configuration      // 表明当前类是一个配置类,并把当前类丢到spring容器中去
	@EnableSwagger2     // 开启swagger功能
	public class SwaggerConfig {

		@Bean
		public Docket createRestApi() {
			// http://ip地址:端口/项目名/swagger-ui.html#/
			ApiInfo apiInfo = new ApiInfoBuilder()
					// 网站标题    即:生成的文档网址标题
					.title( "悠忽有限公司" )
					 // 网站描述     即:对生成文档的描述
					.description( "这是一个很nice的接口文档" )
					 // 版本
					.version( "9.0" )
					 // 联系人
					.contact( new Contact("紫邪情","https://www.cnblogs.com/xiegongzi/","110" ) )
					 // 协议  http / https都可以
					.license( "tcp" )
					// 协议url 即:进入到swagger文档页面的地址
					.licenseUrl( "http://localhost:8080/" )
					.build();

			// swagger版本
			return new Docket( DocumentationType.SWAGGER_2 )
					// 请求映射路径  就是:controller中有一个接口,然后前台访问的那个接口路径
					// 这个可以在生成的文档中进行调试时看到
					.pathMapping( "/" )
					 // 根据pathMapping去进行查询( 做相应的操作 )
					.select()
					// 扫描包   即:哪些地方可以根据我们的注解配置帮我们生成文档
					.apis( RequestHandlerSelectors.basePackage( "cn.xiegongzi" ) )
					.paths( PathSelectors.any() )
					.build()
					.apiInfo( apiInfo );
		}

	}


编写yml文件


	spring:
	  datasource:
	  	# 注意这里加了cj啊,即:MySQL驱动用的是8.x的
		driver-class-name: com.mysql.cj.jdbc.Driver
		url: jdbc:mysql://localhost:3306/mybatis_spring?useUnicode=true&characterEncoding=utf-8
		username: root
		# 注意:在yml中,这种自己写的内容最好用字符串写法,以后玩Redis也是一样,不然有时出现坑,即:密码无效 / 这里面填入的值没有解析出来,不匹配
		password: "072413"


编写实体类


	package cn.xiegongzi.entity;

	import io.swagger.annotations.ApiModel;
	import io.swagger.annotations.ApiModelProperty;
	import lombok.AllArgsConstructor;
	import lombok.Data;
	import lombok.NoArgsConstructor;

	import java.io.Serializable;

	@Data
	@AllArgsConstructor
	@NoArgsConstructor

/**
 * @ApiModel(description = "描述")
 * 表明这个实体类就是需要的数据名和类型
 * 后台接收前端的参数是一个对象时使用( controller写的是@RequestBody OrderPaidDTO orderPaid ),即:后端接收参数封装成了一个xxxxDTO( PO、BO、Entity、DTO、DAO含义和关系是什么,自行百度 )
 * 这个东西可以先不加,在做增加、修改时可以用这个测试一下,从而去swagger中看效果
*/
	@ApiModel(description = "用户信息")
	public class User implements Serializable {

		 // 数据属性配置,这里面可以跟几个属性,常见的是value、required、dataType、hidden,在待会后面附加的链接中有解释
		@ApiModelProperty
		private Integer id;

		@ApiModelProperty
		private String username;

		@ApiModelProperty
		private String phone;
	}


编写mapper


	package cn.xiegongzi.mapper;

	import cn.xiegongzi.entity.User;
	import org.apache.ibatis.annotations.Mapper;
	import org.apache.ibatis.annotations.Select;

	import java.util.List;

	@Mapper
	public interface IUserMapper {

		@Select("select * from user")
		List<User> findAllUser();
	}


编写service接口和实现类

截图


编写controller

截图


	package cn.xiegongzi.controller;

	import cn.xiegongzi.service.IUserService;
	import com.alibaba.fastjson.JSON;
	import io.swagger.annotations.Api;
	import io.swagger.annotations.ApiOperation;
	import org.springframework.beans.factory.annotation.Autowired;
	import org.springframework.web.bind.annotation.GetMapping;
	import org.springframework.web.bind.annotation.RestController;

	@RestController
	/*
		@Api
			表示当前类可以被生成一个swagger文档
			可以跟参数tags,参数表示:这整个接口的名字( 前端是接口,后端是controller控制层 )
	*/
	@Api(tags = "用户管理接口集")
	public class UserController {

		@Autowired
		private IUserService userService;


		/*
			@ApiImplicitParam 这个注解是对请求参数做限制用的,如:请求时要求前台传递一个id,那么:在这个注解里面:就可以声明这个参数的类型( 对象类型中要求属性限制,可以使用@ApiModelProperty 也可以使用 符合jsr303规范的数据检验方式 )
		*/
		// 遵循restful风格  要是使用@RequestMapping的话,会生成多个接口swagger文档( 即:对应post、get.... )
		@GetMapping("/swaggger/doc")
		// value这个接口的名字;notes 对这个接口的描述
		@ApiOperation(value = "获取全部用户接口" , notes = "获取全部的用户")
		public String findAllUser() {

			return JSON.toJSONString( userService.findAllUser() );
		}
	}


测试

截图

截图



13.2、结语



14、集成JPA

数据库表字段信息

截图


导入依赖


        <!--导入jpa需要的依赖-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-jpa</artifactId>
        </dependency>


        <!--项目需要的依赖-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-jdbc</artifactId>
        </dependency>

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

        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>

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

        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid-spring-boot-starter</artifactId>
            <version>1.1.10</version>
        </dependency>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.75</version>
        </dependency>

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

        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
        </dependency>


编写yml文件


spring:
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://localhost:3306/mybatis_spring?useUnicode=true&characterEncoding=utf-8
    username: root
    password: "072413"

  jpa:
# 这里可以不用hibernate,还可以用hikari( 这个在前面整合jdbc时见过,就是当时输出的那句话 )
    hibernate:
# 指定为update,每次启动项目检测表结构有变化的时候会新增字段,表不存在时会新建表
      ddl-auto: update
# 如果指定create,则每次启动项目都会清空数据并删除表,再新建
# 这里面还可以跟:create-drop/create/none
      naming:
        # 指定jpa的自动表生成策略,驼峰自动映射为下划线格式
        implicit-strategy: org.hibernate.boot.model.naming.ImplicitNamingStrategyLegacyJpaImpl  # 默认就是这个
#        physical-strategy: org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl
# 注掉的这种是:不用驼峰名字,直接把实体类的大写字母变小写就完了

    show-sql: true		# 在控制台显示sql语句( 不是真的sql语句,而是相当于:说明 ),默认是false
# 使用INNODB引擎
    properties.hibernate.dialect: org.hibernate.dialect.MySQL55Dialect
    database-platform: org.hibernate.dialect.MySQL55Dialect
# 使用JPA创建表时,默认使用的存储引擎是MyISAM,通过指定数据库版本,可以使用InnoDB

编写实体类


package cn.xiegongzi.entity;

import lombok.Data;
import org.springframework.data.annotation.Id;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import java.io.Serializable;


@Data
// @AllArgsConstructor
// @NoArgsConstructor

@Entity
/** @Entity
 * 表明:当前类和数据库中的这个同类名的数据库表形成ORM映射关系
 * 要是数据库中没有这个表,那么:根据yml配置的ddl-auto: update 就会自动帮我们生成
*/
public class ZiXieQing implements Serializable {

    @javax.persistence.Id
    @Id     // 表明这个属性是数据库表中的主键
    @GeneratedValue(strategy = GenerationType.IDENTITY)     // 表示:自增  默认是auto,即:和数据库中的auto_increment是一样的
    private int id;

    @Column( length = 15 )          // 生成数据库中的列字段,里面的参数不止这些,还可以用其他的,对应数据库列字段的那些操作
                                    // 可以点进源码看一下
    private String name;

    // public ZiXieQing() {
    // }


    public ZiXieQing(int id, String name) {
        this.id = id;
        this.name = name;
    }
}


附:@Column注解中可以支持的属性


@Target({ElementType.METHOD, ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
public @interface Column {
    String name() default "";

    boolean unique() default false;

    boolean nullable() default true;

    boolean insertable() default true;

    boolean updatable() default true;

    String columnDefinition() default "";

    String table() default "";

    int length() default 255;

    int precision() default 0;

    int scale() default 0;
}


编写mapper


package cn.xiegongzi.mapper;

import cn.xiegongzi.entity.ZiXieQing;
import org.springframework.data.jpa.repository.JpaRepository;

@Repository
/**
 * 注:这里别用@Mapper这个注解,因为:@mapper是mybatis提供的注解
 * JpaRepository相对mybatis来说就是是外部的东西。因此:并不能支持@mapper注解
 */
public interface ZiXieQingMapper extends JpaRepository<ZiXieQing , Integer> {

    /*
		JpaRepository这里面有默认的一些方法,即:增删查改...
    	JpaRepository<ZiXieQing , Integer> 本来样子是:JpaRepository<T , ID>
    	T  表示:自己编写的实体类 类型
    	ID  表示: 实体类中id字段的类型      注:本示例中,实体类中id是int 因为要弄自增就必须为int,不然和数据库映射时对不上
    */

}


附:JpaRepository中提供的方法

截图


编写service接口和实现类

截图


编写controller

截图


测试

截图


现在去看一下数据库

截图

生成出来了,完成



15、集成mybatis-plus


导入依赖


        <!--mybatis-plus需要的依赖-->
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
            <version>3.3.2</version>
        </dependency>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid-spring-boot-starter</artifactId>
            <version>1.1.10</version>
        </dependency>


编写yml


spring:
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://localhost:3306/mybatis_spring?useUnicode=true&characterEncoding=utf-8
    username: root
    password: "072413"
    type: com.alibaba.druid.pool.DruidDataSource

mybatis-plus:
  configuration:
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl   # mybatis-plus配置日志
    map-underscore-to-camel-case: true    # 开启驼峰映射 即:实体类属性名和数据库字段采用驼峰映射
    auto-mapping-behavior: full     # 自动映射字段
  mapper-locations: classpath:mapper/*.xml    # 如果使用了mybatis和mybatis-plus 那么这里就可以把mybatis的实现类xml集成进来
    # 但是:最好别这种做,用了mybatis就别用mybatis-plus,二者最好只用其一

注:别把mybatis和mybatis-plus一起集成到spring中,否则:很容易出问题,虽然:mybatis-plus是mybatis的增强版,既然是增强版,那么就不会抛弃它原有的东西,只会保留原有的东西,然后新增功能,但是:mybatis和mybatis-plus集成到一起之后很容易造成版本冲突,因此:对于单个系统模块 / 单个系统来说,建议二者只选其一集成 ( PS:当然事情不是绝对的 我说的是万一,只是操作不当很容易触发错误而已,但是:二者一起集成也是可以的,当出现报错时可以解决掉,不延伸了 ,这不是这里该做的事情 )


编写实体类


package cn.xiegongzi.entity;

import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.io.Serializable;

@Data
@AllArgsConstructor
@NoArgsConstructor
@TableName(value = "user")      // 表名注解
public class User implements Serializable {

    @TableId(type = IdType.AUTO)        // 表示主键,这个主键是一个Long类型的值( 即:snowflake雪花算法 )
    private Integer id;
    @TableField("username")         // 数据库字段名   就是:当实体类中的字段和数据库字段不一样时可以使用
    private String name;
    private String phone;
}


编写mapper


package cn.xiegongzi.mapper;

import cn.xiegongzi.entity.User;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.Mapper;

@Mapper         // 不想在每个mapper层都写这个注解,那把@MapperScan("cn.xiegongzi.mapper") 在启动类中加入这个注解也可以实现
public interface IUserMapper extends BaseMapper<User> {

    /*
		BaseMapper 和 JPA一样,内部有很多方法 , 即:CRUD.....,还有分页( 分页就是page()这个方法 )
		BaseMapper原来的样子是:BaseMapper<T>  T表示实体类 类型
	*/

}

附:BaseMapper<T>提供的方法如下:
截图


测试

截图


其他的知识,在mybatis-plus官网中都有



15、分布式本地缓存技术ehcache


15.1、Ehcache介绍


15.2、ehcache常用注解

15.2.1、@CacheConfig注解


@CacheConfig(cacheNames = "users")
public class UserService{

}



15.2.2、@Cacheable注解( 读数据时 ) - 用得最多


@Cacheable(value = "user", key = "#userId")
User selectUserById( Integer userId );


@Cacheable注解的属性









15.2.3、@CachePut注解 ( 写数据时 )


@CachePut(value="user", key = "#userId")
public User save(User user) {
	users.add(user);
	return user;
}



15.2.4、@CacheEvict注解 ( 删除数据时 )


@CacheEvict(value = "user", key = "#userId")
void delete( Integer userId);



15.2.5、@Cacheing组合注解 - 推荐


@Caching(
	put = {
		@CachePut(value = "user", key = "#userId"),
		@CachePut(value = "user", key = "#username"),
		@CachePut(value = "user", key = "#userAge"),
	}
)



15.3、SpringBoot集成Ehcache

15.3.1、配置Ehache

依赖


        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-cache</artifactId>
        </dependency>
        <dependency>
            <groupId>net.sf.ehcache</groupId>
            <artifactId>ehcache</artifactId>
        </dependency>


application.yml配置文件中加入配置


	cache:
		ehcache:
			# 配置ehcache.xml配置文件所在地
			config: class:ehcache.xml


在主启动类开启缓存功能


@SpringBootAllication
@EnableCaching
public class Starter {
	public static void main(String[] args) {
		SpringApplication.run(Starter.class);
	}
}


编写ehcache.xml配置文件


<ehcache name="myCache">
    <!--缓存磁盘保存路径-->
    <diskStore path = "D:/test/cache"/>

    <!--默认的缓存配置
        maxElementsInMemory 缓存最大数目
        eternal 对象是否永久有效 一旦设置了,那么timeout将不再起作用
        timeToIdleSeconds 设置对象在实效前能允许的闲置时间( 单位:秒 ),默认值是0,即:可闲置时间无穷大
                            仅当eternal=“false"对象不是永久有效时使用
        timeToLiveSeconds 设置对象失效前能允许的存活时间( 单位:秒 )
                             最大时间介于创建时间和失效时间之间
        maxElementsOnDisk 磁盘最大缓存个数
        diskExpiryThreadIntervalSeconds 磁盘失效时,线程运行时间间隔,默认是120秒
        memoryStoreEvictionPolicy 当达到设定的maxElementsInMemory限制时,Ehcache将会根据指定的策略去清理内存
                                    默认策略是LRU( 即:最近最少使用策略 )
                                    还可以设定的策略:
                                        FIFO    先进先出策略
                                        LFU     最近最少被访问策略
                                        LRU     最近最少使用策略
                                                    缓存的元素有一个时间戳,当缓存容量满了,同时又需要腾出地方来缓存新的元素时,
                                                    那么现有缓存元素中的时间戳 离 当前时间最远的元素将被清出缓存

    -->
    <defaultCache
            maxElementsInMemory="10000"
            eternal="false"
            timeToIdleSeconds="120"
            timeToLiveSeconds="120"
            maxElementsOnDisk="10000000"
            diskExpiryThreadIntervalSeconds="120"
            memoryStoreEvictionPolicy="LRU"/>

    <!--下面的配置是自定义缓存配置,可以复制粘贴,用多套
        name 起的缓存名
        overflowToDisk 当系统宕机时,数据是否保存到上面配置的<diskStore path = "D:/test/cache"/>磁盘中
        diskPersistent 是否缓存虚拟机重启期数据

        另外的配置项:
            clearOnFlush  内存数量最大时是否清除
            diskSpoolBufferSizeMB 设置diskStore( 即:磁盘缓存 )的缓冲区大小,默认是30MB
                                    每个Cache都应该有自己的一个缓冲区
    -->
    <cache
        name="users"
        eternal="false"
        maxElementsInMemory="100"
        overflowToDisk="false"
        diskPersistent="false"
        timeToIdleSeconds="0"
        timeToLiveSeconds="300"
        memoryStoreEvictionPolicy="LRU"
    />
</ehcache>



15.3.2、在项目中使用ehcahe


查询条件是单个时( service实现类中直接开注解 )


// 这里的value值就是前面xml中配置的哪个cache name值
@Cacheable(value="users", key = "#username")
public User queryUserByUsername(String username) {
	return userMapper.selectUserByUsername(username);
}


查询条件是多个时( service实现类中直接开注解 )


// 这里的UserDAO.username+就是封装的UserDAO,里面的属性有username、userage、userPhone
@Cache(value="users", key = "#UserDAO.username+'-'+#UserDAO.userage+'-'+#UserDAO.userPhone")
public User queryUserByUsername(UserDAO userDAO) {
	return userMapper.selectUserByUserDAO(userDAO);
}


其他的注解也都是差不多的



16、定时任务

16.1、小顶堆数据结构

image

image



16.2、时间轮算法

image


16.3、基础型时间轮



16.4、round型时间轮



16.5、分量时间轮



16.6、Timer定时任务

image

package com.tuling.timer;

import java.util.Date;
import java.util.Timer;
import java.util.TimerTask;

public class TimerTest {

    public static void main(String[] args) {
        Timer t = new Timer();// 任务启动
        for (int i=0; i<2; i++){
            TimerTask task = new FooTimerTask("foo"+i);
            t.scheduleAtFixedRate(task,new Date(),2000);// 任务添加   10s 5次   4 3
            // 预设的执行时间nextExecutorTime 12:00:00   12:00:02  12:00:04
            // schedule  真正的执行时间 取决上一个任务的结束时间  ExecutorTime   03  05  08  丢任务(少执行了次数)
            // scheduleAtFixedRate  严格按照预设时间 12:00:00   12:00:02  12:00:04(执行时间会乱)
            // 单线程  任务阻塞  任务超时
        }
    }
}

class FooTimerTask extends TimerTask {

    private String name;

    public FooTimerTask(String name) {
        this.name = name;
    }

    public void run() {
        try {
            System.out.println("name="+name+",startTime="+new Date());
            Thread.sleep(3000);
            System.out.println("name="+name+",endTime="+new Date());

            // 因为是单线程,所以解决办法:使用线程池执行
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}




16.7、定时任务线程池

image

package com.tuling.pool;

import java.util.Date;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

public class ScheduleThreadPoolTest {

    public static void main(String[] args) {
        // 这种线程池叫做垃圾 - 了解即可
        // 缺点:允许的请求队列长度为 Integer.MAX_VALUE,可能会堆积大量的请求,从而导致 OOM
        ScheduledExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(5);
        for (int i=0;i<2;i++){

            scheduledThreadPool.scheduleAtFixedRate(new Task("task-"+i),0,2, TimeUnit.SECONDS);
        }
    }
}
class Task implements Runnable{

    private String name;

    public Task(String name) {
        this.name = name;
    }

    public void run() {
        try {
            System.out.println("name="+name+",startTime="+new Date());
            Thread.sleep(3000);
            System.out.println("name="+name+",endTime="+new Date());

        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}



16.8、@Scheduled注解实现


这个注解的几个属性


cron表达式说明

image

通配符 意义
? 表示不指定值,即不关心某个字段的取值时使用
需要注意的是,月份中的日期和星期可能会起冲突,因此在配置时这两个得有一个是?
* 表示所有值,例如:在秒的字段上设置 * ,表示每一秒都会触发
, 用来分开多个值,例如在周字段上设置 "MON,WED,FRI" 表示周一,周三和周五触发
- 表示区间,例如在秒上设置 "10-12",表示 10,11,12秒都会触发
/ 用于递增触发,如在秒上面设置"5/15" 表示从5秒开始,每增15秒触发(5,20,35,50)
# 序号(表示每月的第几个周几),例如在周字段上设置"6#3"表示在每月的第三个周六,(用
在母亲节和父亲节再合适不过了)
L 表示最后的意思
在日字段设置上,表示当月的最后一天(依据当前月份,如果是二月还会自动判断是否是润年
在周字段上表示星期六,相当于"7"或"SAT"(注意周日算是第一天)
如果在"L"前加上数字,则表示该数据的最后一个。例如在周字段上设置"6L"这样的格式,则表
示"本月最后一个星期五"
W 表示离指定日期的最近工作日(周一至周五)
例如在日字段上设置"15W",表示离每月15号最近的那个工作日触发。如果15号正好是周六,则找最近的周五(14号)触发, 如果15号是周未,则找最近的下周一(16号)触发,如果15号正好在工作日(周一至周五),则就在该天触发
如果指定格式为 "1W",它则表示每月1号往后最近的工作日触发。如果1号正是周六,则将在3号下周一触发。(注,"W"前只能设置具体的数字,不允许区间"-")
LW组合 如果在日字段上设置"LW",则表示在本月的最后一个工作日触发(一般指发工资 )
周字段的设置 若使用英文字母是不区分大小写的 ,即 MON 与mon相同

cron表达式举例

“0 0 12 * * ?”				每天中午12点触发

“0 15 10 ? * *”				每天上午10:15触发
“0 15 10 * * ?”
“0 15 10 * * ? *”

“0 15 10 * * ? 2005”		2005年的每天上午10:15 触发

“0 0/5 14 * * ?”			在每天下午2点到下午2:55期间的每5分钟触发

“0 0-5 14 * * ?”			在每天下午2点到下午2:05期间的每1分钟触发

“0 10,44 14 ? 3 WED”		每年三月的星期三的下午2:10和2:44触发

“0 15 10 ? * MON-FRI”		周一至周五的上午10:15触发

“0 15 10 ? * 6L”			每月的最后一个星期五上午10:15触发

“0 15 10 ? * 6L 2002-2005”	2002年至2005年的每月的最后一个星期五上午10:15触发

“0 15 10 ? * 6#3”			每月的第三个星期五上午10:15触发

0 23-7/2,8 * * *		   晚上11点到早上8点之间每两个小时,早上八点

0 11 4 * 1-3				每个月的4号和每个礼拜的礼拜一到礼拜三的早上11点



16.9、Redis实现 - 分布式定时任务


16.8.1、zset实现

逻辑

import redis.clients.jedis.Jedis;
import utils.JedisUtils;
import java.time.Instant;
import java.util.Set;

public class DelayQueueExample {
    // zset key
    private static final String _KEY = "myTaskQueue";

    public static void main(String[] args) throws InterruptedException {
        Jedis jedis = JedisUtils.getJedis();
        // 30s 后执行
        long delayTime = Instant.now().plusSeconds(30).getEpochSecond();
        jedis.zadd(_KEY, delayTime, "order_1");
        // 继续添加测试数据
        jedis.zadd(_KEY, Instant.now().plusSeconds(2).getEpochSecond(), "order_2");
        jedis.zadd(_KEY, Instant.now().plusSeconds(2).getEpochSecond(), "order_3");
        jedis.zadd(_KEY, Instant.now().plusSeconds(7).getEpochSecond(), "order_4");
        jedis.zadd(_KEY, Instant.now().plusSeconds(10).getEpochSecond(), "order_5");
        // 开启定时任务队列
        doDelayQueue(jedis);
    }

    /**
     * 定时任务队列消费
     * @param jedis Redis 客户端
     */
    public static void doDelayQueue(Jedis jedis) throws InterruptedException {
        while (true) {
            // 当前时间
            Instant nowInstant = Instant.now();
            long lastSecond = nowInstant.plusSeconds(-1).getEpochSecond(); // 上一秒时间
            long nowSecond = nowInstant.getEpochSecond();
            // 查询当前时间的所有任务
            Set<String> data = jedis.zrangeByScore(_KEY, lastSecond, nowSecond);
            for (String item : data) {
                // 消费任务
                System.out.println("消费:" + item);
            }
            // 删除已经执行的任务
            jedis.zremrangeByScore(_KEY, lastSecond, nowSecond);
            Thread.sleep(1000); // 每秒查询一次
        }
    }
}


16.8.2、键空间实现

逻辑

import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPubSub;
import utils.JedisUtils;

public class TaskExample {
    public static final String _TOPIC = "__keyevent@0__:expired"; // 订阅频道名称
    public static void main(String[] args) {
        Jedis jedis = JedisUtils.getJedis();
        // 执行定时任务
        doTask(jedis);
    }

    /**
     * 订阅过期消息,执行定时任务
     * @param jedis Redis 客户端
     */
    public static void doTask(Jedis jedis) {
        // 订阅过期消息
        jedis.psubscribe(new JedisPubSub() {
            @Override
            public void onPMessage(String pattern, String channel, String message) {
                // 接收到消息,执行定时任务
                System.out.println("收到消息:" + message);
            }
        }, _TOPIC);
    }
}



16.8.Quartz任务调度

image


16.8.1.简单示例

依赖

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


定义job

public class MyJob implements Job {
    private Logger log = LoggerFactory.getLogger(MyJob.class);

    @Override
    public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {

        SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

        TriggerKey triggerKey = jobExecutionContext.getTrigger().getKey();

        log.info("触发器:{},所属组:{},执行时间:{},执行任务:{}",
                triggerKey.getName(),triggerKey.getGroup(),dateFormat.format(new Date()),"hello SpringBoot Quartz...");
    }
}


编写QuartzConfig

public class QuartzConfig {

    @Bean
    public JobDetail jobDetail() {
        return JobBuilder.newJob(MyJob.class)
                .storeDurably()
                .build();
    }

    @Bean
    public Trigger trigger01() {
        SimpleScheduleBuilder scheduleBuilder = SimpleScheduleBuilder.simpleSchedule()
                // 每一秒执行一次
                .withIntervalInSeconds(1)
                // 永久重复,一直执行下去
                .repeatForever();

        return TriggerBuilder.newTrigger()
                // 参数1、trigger名字;参数2、当前这个trigger所属的组 - 参考时间轮存储任务,那个刻度后面是怎么存的任务
                .withIdentity("trigger01", "group1")
                .withSchedule(scheduleBuilder)
                // 哪一个job,上一个方法中bean注入
                .forJob("jobDetail")
                .build();
    }

    /**
     * 每两秒触发一次任务
     */
    @Bean
    public Trigger trigger02() {
        return TriggerBuilder
                .newTrigger()
                .withIdentity("triiger02", "group1")
                // cron时间表达式
                .withSchedule(CronScheduleBuilder.cronSchedule("0/5 * * * * ? *"))
                .forJob("jobDetail")
                .build();
    }
}


最后:SpringBoot还有很多内容,那些也就是整合各种框架而已,到了现在整合了这么多,那也有点门路了,其实都差不多是通同样的套路:1、引入SpringBoot整合的对应框架依赖;2、编写对应的配置;3、使用对应的注解 / 编写业务逻辑。差不多都是这样的套路,因此:到时需要时直接面向百度编程即可


另外:SpringBoot原理篇链接:https://www.cnblogs.com/xiegongzi/p/15522405.html

标签:SpringBoot,掌握,spring,boot,org,import,快速,public,注解
来源: https://www.cnblogs.com/xiegongzi/p/16312315.html