乐趣区

关于java:SpringBoot快速入门

先说一些废话

尽管我的工作中更多的是与数据库打交道,然而作为一个 Coder,我感觉把握前后端的Web 技术来说是十分有必要的。

不仅能够帮忙咱们在工作中更好的了解其余岗位与你对接的人他的工作痛点,也能在公司须要人手的时候成为一个无力的应急帮手,比方之前公司的数据中台我就参加架构和局部开发工作,更重要的是我私下里能够使用一些疾速框架来搭建一些有意思的网站,比方我的个人主页和集体博客都是我自学 javajs所做进去的作品。

所以明天我心愿整合一些我以往的教训和看过的教程文档,来写一篇文章,帮忙你在一天之内通过这篇文章疾速学习 SpringBoot 框架以及各种开发必备的工具与插件!!!

MVC

什么是 MVC

  1. MVC 三层架构是指:视图层 View、服务层 Service,与长久层 Dao,它们别离实现不同的性能

    • View 层:用于接管用户提交申请的代码在这里编写
    • Service 层:零碎的业务逻辑次要在这里实现
    • Dao 层:间接操作数据库的代码在这里编写
  2. 为了更好的升高各层间的耦合度,在三层架构程序设计中,采纳面向形象编程,即下层对上层的调用,是通过接口实现的,而上层对下层的真正服务提供者,是上层接口的实现类
  3. 服务规范(接口)是雷同的,服务提供者(实现类)能够更换,这就实现了层间解耦合

MVC 架构程序的工作流程

  1. 用户通过 View 页面向服务端提出申请,能够是表单申请、超链接申请、AJAX 申请等
  2. 服务端 Controller 控制器接收到申请后对申请进行解析,找到相应的 Model 对用户申请进行解决
  3. Model 解决后,将处理结果再交给 Controller
  4. Controller 在接到处理结果后,依据处理结果找到要作为向客户端发回的响应 View 页面,页面经渲染(数据填充)后,再发送给客户端

应用 xml 还是注解

  1. 利用的根本配置应用 xml,比方数据源和资源文件等
  2. 业务开发应用注解,比方 service 注入 bean
  3. 然而 xml 越来越多导致越来越臃肿,最终倒退到应用齐全基于注解开发

注解

申明 Bean 注解

@Component 组件没有明确规定其角色,作用在类级别上申明以后类为一个业务组件,被 Spring IOC 容器 保护
@Service 在业务逻辑层(Service)类级别进行申明
@Registory 在数据拜访层(Dao)类级别进行申明
@Controller 在展示层(MVC)应用,标注以后类为一个控制器

注入 Bean 注解

@Autowired 它能够对类成员变量、办法及构造函数进行标注,实现主动拆卸的工作,通过 @Autowired 的应用来打消 set、get 办法
@Inject 作用同上,是 JSR-330 规范
@Resource 作用同上,是JSR-250 规范
以上三种注解在 Set 办法或属性上申明,个别状况下更习惯申明在属性上,代码简洁清晰

配置与获取 Bean 注解

@Configuration 将以后类申明为一个配置类,相当于一个 xml 配置文件
@ComponentScan 主动扫描包下标注有 @Repository @Service @Controller
@Component 注解的类并有 Spring IOC 容器 进行实例化和保护
@Bean 作用于办法上,申明以后办法的返回值是一个 Bean 对象,相当于xml 文件<bean>申明以后办法返回一个 bean 对象
@Value 获取properties 文件 指定的key/value

pom.xml

作用是增加坐标相干配置,次要是各种依赖 jar 包

组合注解和元注解

所谓元注解其实就是能够注解到别的注解上的注解,被注解的注解称之为组合注解,组合注解具备元注解的性能,次要的作用是打消反复注解

自定义注解

个性化的定义本人所须要的性能并申明一个注解,简化工程,能够参考文章————SPRINGBOOT 自定义注解学习

罕用注解

能够参考文章————SpringBoot 罕用注解汇合具体学习,这里前期会补上阐明

@RestController、@ResponseBody、@RequestBody

  1. 相当于 @Controller + @ResponseBody 两个注解的联合,返回 JSON 数据不须要在办法后面加 @ResponseBody 注解了,
    但应用 @RestController 这个注解,就不能返回 jsp、html 页面,视图解析器无奈解析 jsp、html 页面 v
  2. @ResponseBody示意该办法的返回后果间接写入 HTTP response body 中,个别在异步获取数据时应用(也就是 AJAX),
    在应用 @RequestMapping 后,返回值通常解析为跳转门路,然而加上 @ResponseBody 后返回后果不会被解析为跳转门路,而是间接写入 HTTP response body 中,
    比方异步获取 JSON 数据,加上 @ResponseBody 后,会间接返回 JSON 数据
  3. @RequestBody将 HTTP 申请注释插入方法中,应用适宜的 HttpMessageConverter 将申请体写入某个对象

    @MapperScan、@Mapper

  4. @Mapper 注解:

    • 作用:在接口类上增加了 @Mapper,在编译之后会生成相应的接口实现类
    • 增加地位:接口类下面
    • 如果想要每个接口都要变成实现类,那么须要在每个接口类上加上 @Mapper 注解,比拟麻烦,解决这个问题用 @MapperScan 注解
  5. @MapperScan 注解:

    • 作用:指定要变成实现类的接口所在的包,而后包上面的所有接口在编译之后都会生成相应的实现类
    • 增加地位:是在 Springboot 启动类下面增加
    • 增加 @MapperScan("com.winter.da") 注解当前,com.winter.dao包上面的接口类,在编译之后都会生成相应的实现类

习惯大于配置指标

Spring Boot 的指标是疾速运行,疾速创立 web 利用,并独立机型部署(jar 包形式,war 包形式),相比于 Spring 框架是全新重写的框架

外围配置

批改 Banner 图标

次要是通过批改 /src/main/resources 目录下的 banner.txt 文件,如果没有则默认应用 SpringBoot 初始 Banner
能够个性化制作 Banner 的网站制订相应的 txt 文件

全局配置

默认是 application.properties 或者 application.yml
坐标依赖都配置在 pom.xml 中,如果增加了依赖当前标红能够应用 Maven -> Reload project 即可

入口类依附组合注解@SpringBootApplication

@SpringBootConfiguration 自身是一个配置类,启动类启动的时候会加载
@EnableAutoConfiguration 组合了@AutoConfigurationPackage&@Import(AutoConfigurationImportSelector.class)
@AutoConfigurationPackage 底层是一个 @Import(AutoConfigurationPackage.Registrar.class),其会把启动类的包下组合都扫描到 Spring 容器中
@AutoConfigurationImportSelector 读取大量的主动配置类,实现主动配置,其读取的是 classpath 下的META-INF/spring.factories 下的配置文件

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(
    excludeFilters = {@Filter(
    type = FilterType.CUSTOM,
    classes = {TypeExcludeFilter.class}
), @Filter(
    type = FilterType.CUSTOM,
    classes = {AutoConfigurationExcludeFilter.class}
)}
)

Profile 配置————辨别生产和开发环境

通过在 application.yml 中设置 spring.profiles.active=test/dev/prod 来动静切换不同环境,例如:

# 开发环境配置文件
application-dev.yml
server:
  prot: 8098

# 测试环境配置文件
application-test.yml
server:
  prot: 8097

# 生产环境配置文件
application-prod.yml
server:
  prot: 8099

# 主配置文件
application.yml
spring:
  profiles:
    active: dev

日志配置

SpringBoot 默认应用 LogBack 日志零碎,个别支流的日志都是用 log4j 日志零碎

如果反复启动 Spring 我的项目,可能会有端口占用的报错

  1. 思路是杀死占用端口的过程即可,次要是上面两个命令
  2. 应用 netstat -aon|findstr "被占用的端口" 或者 tasklist |findstr "过程名称" 查问到端口的过程号
  3. 应用 taskkill /f /t /im "过程名称" 或者 taskkill /f /t /pid "过程 PID" 杀死过程即可

事务管制

申明式事务

能够参考文章————SpringBoot 申明式事务的简略使用具体学习,这里前期会补上阐明
次要利用在新增批改删除上,利用注解即可

全局异样

应用 @ControllerAdvice 配合 @ExceptionHandler

能够参考文章————Springboot 系列 -@ControllerAdvice 应用具体学习,这里前期会补上阐明
此注解其实是一个加强的Controller,应用这个Controller,可实现三个方面的性能,因为这是 SpringMVC 提供的性能,所以能够在 springboot 中间接应用

  1. 全局异样解决(@ExceptionHandler)
  2. 全局数据绑定(@InitBinder)
  3. 全局数据预处理(@ModelAttribute)

    package com.fx67ll.springboot.exceptions;
    
    import com.fx67ll.springboot.po.vo.ResultInfo;
    import org.springframework.web.bind.annotation.ControllerAdvice;
    import org.springframework.web.bind.annotation.ExceptionHandler;
    import org.springframework.web.bind.annotation.ResponseBody;
    
    @ControllerAdvice
    public class TestGlobalExceptionHandler {@ExceptionHandler(value = Exception.class)
     @ResponseBody
     public ResultInfo exceptionHandler(Exception exception) {ResultInfo resultInfo = new ResultInfo();
         resultInfo.setCode(978);
         resultInfo.setMsg("全局异样拦挡,操作失败!");
    //        if (exception instanceof ParamsException) {//            ParamsException paramsException = (ParamsException) exception;
    //            resultInfo.setMsg(paramsException.getMsg());
    //            resultInfo.setCode(paramsException.getCode());
    //        }
         return resultInfo;
     }
    }

数据校验

为什么要进行后端数据校验

数据的校验是交互式网站一个不可或缺的性能,前端的 js 校验 能够涵盖大部分的校验职责,如用户名唯一性,生日格局,邮箱格局校验等等罕用的校验。
然而个别前端传来的数据是不可信的,前端校验过了,后端也应该从新校验,因为不排除用户绕过浏览器间接通过 Http 工具 向后端申请的状况。
所以服务端的数据校验也是必要的,能够避免脏数据落到数据库中,如果数据库中呈现一个非法的邮箱格局,也会让运维人员头疼不已。

如何进行后端数据校验

  1. SpringBoot中个别应用 Spring Validation 来进行后端数据校验,它是对 Hibernate Validation 进行了二次封装,
    SpringMVC 模块中增加了主动校验,并将校验信息封装进了特定的类中
  2. 在应用时咱们只须要引入 spring-boot-starter-web 依赖即可,该模块会主动依赖spring-boot-starter-validation

Spring Validation 罕用注解

@Null:被正文的元素必须为 null
@NotNull:被正文的元素不能为null,能够为空字符串
@AssertTrue:被正文的元素必须为true
@AssertFalse:被正文的元素必须为false
@Min(value):被正文的元素必须是一个数字,其值必须大于等于指定的最小值
@Max(value):被正文的元素必须是一个数字,其值必须小于等于指定的最大值
@DecimalMin(value):被正文的元素必须是一个数字,其值必须大于等于指定的最小值
@DecimalMax(value):被正文的元素必须是一个数字,其值必须小于等于指定的最大值
@Size(max,min):被正文的元素的大小必须在指定的范畴内
@Digits(integer,fraction):被正文的元素必须是一个数字,其值必须在可承受的范畴内
@Past:被正文的元素必须是一个过来的日期
@Future:被正文的元素必须是一个未来的日期
@Pattern(value):被正文的元素必须合乎指定的正则表达式
@Email:被正文的元素必须是电子邮件地址
@Length:被正文的字符串的大小必须在指定的范畴内
@Range:被正文的元素必须在适合的范畴内
@URL:被注解的元素必须是一个URL
@NotEmpty:用在汇合类上,不能为null,并且长度必须大于 0
@NotBlank:只能作用在String 上,不能为 null,而且调用trim() 后,长度必须大于 0

自定义注解

能够参考文章————Spring 自定义注解 (validation) 具体学习,这里前期会补上阐明

示例代码

  1. /com/fx67ll/springboot/controller/UserController.java在传参的地位增加 @Vaild 注解示意这里的参数须要校验,须要留神 JSON 格局和表单格局传过来的参数异样会有些区别,须要在前面留神

    // 增加用户
    @PutMapping("/adduser")
    public ResultInfo saveUser(@RequestBody @Valid User user) {ResultInfo resultInfo = new ResultInfo();
        userService.saveUser(user);
        return resultInfo;
    }
  2. Bean 文件 /com/fx67ll/springboot/dao/User.java 中公有字段上应用注解来校验,不贴所有代码了,仅贴局部重点代码

    @NotBlank(message = "用户名称不能为空!")
    private String userName;
    
    @NotBlank(message = "用户明码不能为空!")
    @Length(min = 6, max = 20, message = "明码长度起码六位且最多二十位!")
    private String userPwd;
  3. 在全局自定义异样拦挡中 /com/fx67ll/springboot/exceptions/TestGlobalExceptionHandler.java 向用户返回错误代码和信息

    package com.fx67ll.springboot.exceptions;
    
    import com.fx67ll.springboot.po.vo.ResultInfo;
    import org.springframework.web.bind.MethodArgumentNotValidException;
    import org.springframework.web.bind.annotation.ControllerAdvice;
    import org.springframework.web.bind.annotation.ExceptionHandler;
    import org.springframework.web.bind.annotation.ResponseBody;
    
    @ControllerAdvice
    public class TestGlobalExceptionHandler {@ExceptionHandler(value = Exception.class)
        @ResponseBody
        public ResultInfo exceptionHandler(Exception exception) {ResultInfo resultInfo = new ResultInfo();
            resultInfo.setCode(978);
            resultInfo.setMsg("全局异样拦挡,操作失败!");
            // 全局数据校验,留神!!!应用 json 申请体调用接口,校验异样抛出 MethodArgumentNotValidException
            if (exception instanceof MethodArgumentNotValidException) {MethodArgumentNotValidException methodArgumentNotValidException = (MethodArgumentNotValidException) exception;
                resultInfo.setCode(1023);
                resultInfo.setMsg(methodArgumentNotValidException.getBindingResult().getFieldError().getDefaultMessage());
            }
            return resultInfo;
        }
    }

动态资源

默认配置下,咱们能够在 resources 资源目录下寄存 web 利用动态资源文件
自定义动态资源门路,能够通过在 spring.resources.static-locations 前面追加一个配置classpath:/ 你自定义的配置目录 /,例如:

# application.yml
spring:
  resources:
    # 多个目录应用逗号隔开
    static-loaction: classpath:/public/,classpath:/static/,classpath:/fx67ll/

打包和部署

jar 包

  1. 个别用于编写依赖工具包
  2. 打包

    • 在 IDEARun/Debug ConfigurationsCommand line 配置 clean complie package -Dmaven.test.skip=true 执行打包命令
    • target目录失去待部署的我的项目文件
  3. 部署

    • 在 dos 窗口中,执行命令java -jar jar 包所在的本地目录

war 包

  1. 在生产环境中最为常见的部署形式
  2. 批改pom.xml,设置打包模式为 war 包

    <groupId>com.fx67ll</groupId>
    <artifactId>springboot-quickstart</artifactId>
    <version>0.1.0</version>
    <!-- 设置为 war 包模式 -->
    <packaging>war</packaging>
  3. 疏忽内嵌 Tomcat

    <!-- 设置为内部已提供,示意疏忽 -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-tomcat</artifactId>
        <scope>provided</scope>
    </dependency>
  4. 配置生成的 war 包名称

    <build>
    <!-- 设置 war 包名称 -->
        <finalName>fx67ll-springboot-quickstart-test</finalName>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>
  5. 批改 Starter 类,增加容器启动加载文件(相似读取 web.xml 文件)

    • 这里通过继承 SpringBootServletInitiallizer 类并重写 configure 办法来实现
    • 在部署我的项目的时候指定内部 Tomcat 读取我的项目入口办法

      @SpringBootApplication
      public class Starter extends SpringBootServletInitializer {public static void main(String[] args) {SpringApplication.run(Starter.class);
       }
       
       @Override
       protected SpringApplicationBuilder configure(SpringApplicationBuilder builder) {return builder.sources(Starter.class);
       }
      }
  6. 打包

    • 在 IDEARun/Debug ConfigurationsCommand line 配置 clean complie package -Dmaven.test.skip=true 执行打包命令
    • target目录失去待部署的我的项目文件
  7. 部署并拜访

    • 搁置到内部 tomcat 中,执行 bin 目录下 start 脚本即可

热部署

热部署,就是在利用正在运行的时候降级软件,却不须要重新启动利用,次要利用在开发过程中

热部署原理

  1. spring-boot-devtools是一个为开发者服务的一个模块,其中最重要的性能就是主动利用代码更改到最新的 App 下面去,
    原理是在发现代码有更改之后,重新启动利用,然而速度比手动进行后再启动还要更快,更快指的不是节俭进去的手工操作的工夫
  2. 其深层原理是应用了两个 ClassLoader,一个Classloader 加载那些不会扭转的类(第三方 Jar 包),另一个 ClassLoader 加载会更改的类,称为 restart ClassLoader
    这样在有代码更改的时候,原来的restart ClassLoader 被抛弃,从新创立一个 restart ClassLoader,因为须要加载的类相比拟少,所以实现了较快的重启工夫, 大略在 5 秒以内

    devtools 原理

  3. devtools 会监听 classpath 下的文件变动,并且会立刻重启利用(产生在保留机会)留神:因为其采纳的虚拟机机制,该项重启是很快的
  4. devtools 能够实现页面热部署(即页面批改后会立刻失效,这个能够间接在 application 文件中配置 spring.thymeleaf.cache=false 来实现 留神:不同的模板配置不一样

    热部署次要步骤

  5. pom.xml 中增加依赖,同时增加 devtools 失效标记插件

    <!-- 热部署插件 devtools-->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-devtools</artifactId>
        <!-- 示意以后这个我的项目被继承之后,这个不向下传递 -->
        <optional>true</optional>
    </dependency>
    
    <plugin>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-maven-plugin</artifactId>
        <!-- 在原有的根底上增加 -->
        <configuration>
            <!-- 如果没有该配置,热部署插件 devtools 不失效 -->
            <fork>true</fork>
        </configuration>
    </plugin>
  6. 批改 application.yml 全局配置文件,在 application.yml 中配置 spring.devtools.restart.enable=false,此时restart 类加载器还会初始化,但不会监督文件更新

    spring:
      # 热部署配置
      devtools:
        restart:
          enabled: true
          # 设置重启的目录,增加目录的文件须要 restart
          additional-paths: src/main/java
          # 解决我的项目启动从新编译后接口报 404 的问题
          poll-interval: 3000
          quiet-period: 1000
  7. 批改 IDEA 配置

    • 批改了 java 类之后,IDEA 默认是不主动编译的,而 spring-boot-devtools 又是监测 classpath 下的文件发生变化才会重启利用,所以须要设置 IDEA 的主动编译
    • 设置主动配置 File -> Settings -> Build -> Complier -> Build Project automatically
    • 批改 Register 属性,执行快捷键ctrl + shift + alt + /,抉择Register,勾上Complier autoMake allow when app running
    • 留神 IDEA 2021.2.3 版本中没有下面的选项,迁徙到了File -> Settings -> Tools -> Advanced Settings -> Complier -> Allow auto-make to start......
  8. 配置完须要重启一下,而后有批改的话我的项目会自动更新,然而如果是主动触发的话,会造成频繁更新,对硬件有肯定的累赘,所以能够改成手动触发模式

    • 点击右上角 Run/Debug Configurations
    • 抉择下拉 Configuration -> Spring Boot -> Running Application Update Policies -> On 'Update' action
    • 抉择 Update classes and resources
    • 如果有更新能够,应用快捷键 Ctrl + F10 从新编译
  9. 快捷键Ctrl + F9,应用热部署重新启动

单元测试

依赖

<!-- 单元测试 -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-test</artifactId>
    <scope>test</scope>
</dependency>

Service 业务层————业务逻辑办法测试

须要留神的是:

  1. 如果在和 main 文件夹 平级的 test 文件夹 下新建了 java 文件夹,然而无奈新建java class 文件
  2. 那么就须要右键文件夹 Mark Directory as -> Test Sources Root之后,文件夹变绿即可

    # 示例代码
    package com.fx67ll.springboot.service;
    
    import com.fx67ll.springboot.Starter;
    import com.fx67ll.springboot.po.User;
    import com.fx67ll.springboot.query.UserQuery;
    import com.fx67ll.springboot.srevice.UserService;
    import com.github.pagehelper.PageInfo;
    import org.junit.After;
    import org.junit.Before;
    import org.junit.Test;
    import org.junit.runner.RunWith;
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    import org.springframework.boot.test.context.SpringBootTest;
    import org.springframework.test.context.junit4.SpringRunner;
    
    import javax.annotation.Resource;
    
    /**
     * Service 业务办法测试
     *
     * Junit 中的 RunWith 注解 示意该类是单元测试的执行类
     * SpringRunner 是 spring-test 提供的测试执行单元类(是 Spring 单元测试中 SpringJUnit4ClassRunner 的新名字)* SpringBootTest 注解 是执行测试程序的疏导类
     */
    @RunWith(SpringRunner.class)
    @SpringBootTest(classes = {Starter.class})
    public class TestUserService {
    
     // 日志的应用
     private Logger logger = LoggerFactory.getLogger(TestUserService.class);
    
     @Resource
     private UserService userService;
    
     @Before
     public void before() {logger.info("单元测试开始......");
     }
    
     @Test
     public void testQueryUserById() {logger.info("测试依据用户 id 查问......");
    
         User user = userService.queryUserById(1);
         logger.info("用户记录: {}", user.toString());
     }
    
     @Test
     public void testSelectUserListByParams() {logger.info("测试依据分页条件查问用户列表......");
    
         UserQuery userQuery = new UserQuery();
         PageInfo<User> pageInfo = userService.selectUserListByParams(userQuery);
         logger.info(pageInfo.toString());
     }
    
     @After
     public void after() {logger.info("单元测试完结......");
     }
    }

controller 管制层————接口办法测试

应用 MockMVC 进行测试

MockMvc是由 spring-test 包提供,实现了对 Http 申请 的模仿,可能间接应用网络的模式,转换到 Controller 的调用,使得测试速度快、不依赖网络环境。
同时提供了一套验证的工具,后果的验证非常不便

什么是 Mock

在面向对象的程序设计中,模仿对象 mock object 是以可控的形式模仿实在对象行为的假对象。
在编程过程中,通常通过模仿一些输出数据,来验证程序是否达到预期后果

接口 MockMvcBuilder

提供一个惟一的 build 办法,用来结构MockMvc
次要有两个实现:StandaloneMockMvcBuilderDefaultMockMvcBuilder,别离对应两种测试形式,
即独立装置和集成 Web 环境测试(并不会集成真正的 web 环境,而是通过相应的Mock API 进行模仿测试,毋庸启动服务器)。
MockMvcBuilders 提供了对应的创立办法 standaloneSetup 办法和 webAppContextSetup 办法,在应用时间接调用即可。

# 示例代码
# PS:尽管提醒测试通过,然而控制台始终没有打印出返回信息的记录,前期有空看看
package com.fx67ll.springboot.controller;

import com.fx67ll.springboot.Starter;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.http.MediaType;
import org.springframework.mock.web.MockHttpServletResponse;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.MvcResult;
import org.springframework.test.web.servlet.ResultActions;
import org.springframework.test.web.servlet.request.MockHttpServletRequestBuilder;
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
import org.springframework.test.web.servlet.result.MockMvcResultMatchers;

@RunWith(SpringRunner.class)
@SpringBootTest(classes = {Starter.class})
@AutoConfigureMockMvc
public class TestUserController {

    // 日志的应用
    private Logger logger = LoggerFactory.getLogger(TestUserController.class);

    @Autowired
    private MockMvc mockMvc;

    /**
     * 模仿测试用户列表查问
     * 其实就在模仿实在环境下前端对后端发动的申请
     */
    @Test
    public void apiTestSelectUserListByParams() throws Exception {logger.info("开始模仿发送查问用户列表的申请......");

        // 构建申请
        MockHttpServletRequestBuilder requestBuilder = MockMvcRequestBuilders.get("/user/list")
                .contentType("text/html") // 设置申请头信息
                .accept(MediaType.APPLICATION_JSON); // 设置申请 Accept 头信息

        // 发送申请
        ResultActions perform = mockMvc.perform(requestBuilder);

        // 校验申请后果
        perform.andExpect(MockMvcResultMatchers.status().isOk());

        // 获取执行实现后返回的后果
        MvcResult mvcResult = perform.andReturn();

        // 失去执行后的响应
        MockHttpServletResponse response = mvcResult.getResponse();

        // 打印后果
        logger.info(String.valueOf(response.getContentLength()));
        logger.info("响应状态:", response.getStatus());
        logger.info("响应信息:", response.getContentAsString());

        logger.info("完结模仿发送查问用户列表的申请......");
    }

    @Test
    public void apiTestQueryUserByUsername() throws Exception {logger.info("开始模仿依据用户名查问用户记录的申请......");

        // 构建申请并发送
        MvcResult mvcResult = mockMvc.perform(MockMvcRequestBuilders.get("/user/name/admin"))
                .andExpect(MockMvcResultMatchers.status().isOk()).andReturn();

        // 打印后果
        logger.info("响应状态:", mvcResult.getResponse().getStatus());
        logger.info("响应信息:", mvcResult.getResponse().getContentAsString());

        logger.info("完结模仿依据用户名查问用户记录的申请......");
    }
}

Swagger2 文档工具

依赖

pom.xml 中增加以下代码

<dependency>
    <groupId>io.springfox</groupId>
    <artifactId>springfox-swagger2</artifactId>
    <version>2.9.2</version>
</dependency>
<dependency>
    <groupId>io.springfox</groupId>
    <artifactId>springfox-swagger-ui</artifactId>
    <version>2.9.2</version>
</dependency>

罕用注解

能够参考文章————swagger2 注解阐明具体学习,这里前期会补上阐明

@Api

次要是用在申请类上,用于阐明该类的作用

# 示例
@Api(tags = "xx 模块")

@ApiOperation

次要是用在申请的办法上,阐明办法的作用

# 示例
@ApiOperation(value = "xx 办法的作用", notes = "xx 办法的备注阐明")

@ApiImplicitParams、@ApiImplicitParam

次要是用在申请的办法上,阐明办法的参数

# 具体参数阐明
@ApiImplicitParams:用在申请的办法上,蕴含一组参数阐明
    @ApiImplicitParam:对单个参数的阐明        
        name:参数名
        value:参数的阐明、形容
        required:参数是否必须必填
        paramType:参数放在哪个中央
            · query --> 申请参数的获取:@RequestParam
            · header --> 申请参数的获取:@RequestHeader          
            · path(用于 restful 接口)--> 申请参数的获取:@PathVariable
            · body(申请体)-->  @RequestBody User user
            · form(一般表单提交)dataType:参数类型,默认 String,其它值 dataType="Integer"       
        defaultValue:参数的默认值
    
# 单个参数示例    
@ApiImplicitParam(name = "xxx", value = "xxx", required = true, paramType = "path", dataType = "String", defaultValue = "")

# 多个参数示例
@ApiImplicitParams({@ApiImplicitParam(name = "xxxa", value = "xxxa", required = true, paramType = "body", dataType = "String", defaultValue = ""),
    @ApiImplicitParam(name = "xxxb", value = "xxxb", required = true, paramType = "body", dataType = "String", defaultValue = ""),
})

@ApiResponses、@ApiResponse

次要是用在申请的办法上,阐明谬误响应的信息

# 具体参数阐明
@ApiResponses:响应状态的阐明。是个数组,可蕴含多个 @ApiResponse
    @ApiResponse:每个参数的阐明
        code:数字,例如 400
        message:信息,例如 "申请参数没填好"
        response:抛出异样的类
    
# 多个参数示例,个别响应都是多个 code,所以不写单个参数的示例了
@ApiResponses({@ApiResponse(code = 200, message = "申请胜利"),
        @ApiResponse(code = 578, message = "申请参数谬误"),
        @ApiResponse(code = 404, message = "申请门路没有或页面跳转门路不对")
})

@ApiModel、@ApiModelProperty

  1. @ApiModel 常常用于申请的入参对象和响应返回值对象的形容

    • 入参是对象,即 @RequestBody 时,用于封装申请(包含数据的各种校验)数据
    • 返回值是对象,即 @ResponseBody 时,用于返回值对象的形容
  2. @ApiModelProperty 用于每个属性下面,阐明属性的含意

    # 示例
    @ApiModel(description = "用户实体类")
    public class User {@ApiModelProperty(value = "用户名", required = true, example = "0")
     private Integer id;
     
     @ApiModelProperty(value = "用户 ID", required = true, example = "fx67ll")
     private String userName;
     
     @ApiModelProperty(value = "用户明码", required = true, example = "xxxxxxxx")
     private String userPwd;
    }

分布式缓存工具 Ehcache

什么是 Ehcache

EhCache是一个 纯 Java的过程内缓存框架,具备疾速、精干等特点,是 Hibernate 中默认 CacheProvider
Ehcache 是一种宽泛应用的开源 Java 分布式缓存,次要面向通用缓存,Java EE轻量级容器
它具备内存和磁盘存储,缓存加载器,缓存扩大,缓存异样处理程序,一个 gzip 缓存 servlet 过滤器,反对 REST APISOAP API等特点。

SpringCache 相干注解

SpringBoot 缓存实现外部应用 SpringCache 实现缓存管制,这里集成 Ehcache 实际上是对 SpringCache 形象的一种实现
能够参考文章————Spring Cache 简介具体学习,这里前期会补上阐明

@EnableCaching

开启缓存性能,个别放在启动类上

@CacheConfig

当咱们须要缓存的中央越来越多,你能够应用 @CacheConfig(cacheNames = {"cacheName"}) 注解在 Class 之上来对立指定 value 的值,
这时可省略 value,如果你在你的办法仍旧写上了value,那么仍然以办法的value 值为准

@Cacheable

依据办法对其返回后果进行缓存,下次申请时,如果缓存存在,则间接读取缓存数据返回;如果缓存不存在,则执行办法,并把返回的后果存入缓存中,个别用在查询方法上
留神 value 前面要应用 ehcache.xml 文件中所列的cache.name

# 单个参数示例代码
@Cacheable(value = "fx67llCache", key = "#xxx")

# 多个参数示例,采纳拼接的形式
@Cacheable(value = "fx67llCache", key = "#xxx.xxx +'-'+ #xxx.xxx +'-'+ #xxx.xxx")

@CachePut

应用该注解标记的办法,每次都会执行,并将后果存入指定的缓存中。其余办法能够间接从响应的缓存中读取缓存数据,而不须要再去查询数据库,个别用在新增办法上

# 示例代码
@CachePut(value = "fx67llCache", key = "#xxx.xxx")

@CacheEvict

应用该注解标记的办法,会清空指定的缓存,个别用在更新或者删除办法上

# 示例代码
@CacheEvict(value = "fx67llCache", key = "#xxx")

@Caching

该注解能够实现同一个办法上同时应用多种注解

Ehcache 的应用

  1. pom.xml 增加依赖

    <!--Ehcache 工具依赖 -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-cache</artifactId>
    </dependency>
    <dependency>
        <groupId>net.sf.ehcache</groupId>
        <artifactId>ehcache</artifactId>
    </dependency>
  2. 增加 ehcache.xml 文件

    <?xml version="1.0" encoding="UTF-8"?>
    <ehcache name="fx67llCache">
        <!--
           diskStore:为缓存门路,ehcache 分为内存和磁盘两级,此属性定义磁盘的缓存地位。参数解释如下:user.home – 用户主目录
           user.dir  – 用户当前工作目录
           java.io.tmpdir – 默认临时文件门路
         -->
        <diskStore path="D:\Java\test-ehcache-cache"/>
    
        <!--
           defaultCache:默认缓存策略,当 ehcache 找不到定义的缓存时,则应用这个缓存策略。只能定义一个。-->
    
        <!--
          name: 缓存名称。maxElementsInMemory: 缓存最大数目
          maxElementsOnDisk:硬盘最大缓存个数。eternal: 对象是否永恒无效,一但设置了,timeout 将不起作用。overflowToDisk: 是否保留到磁盘,当零碎当机时
          timeToIdleSeconds: 设置对象在生效前的容许闲置工夫(单位:秒)。仅当 eternal=false 对象不是永恒无效时应用,可选属性,默认值是 0,也就是可闲置工夫无穷大。timeToLiveSeconds: 设置对象在生效前容许存活工夫(单位:秒)。最大工夫介于创立工夫和生效工夫之间。仅当 eternal=false 对象不是永恒无效时应用,默认是 0.,也就是对象存活工夫无穷大。diskPersistent:是否缓存虚拟机重启期数据 Whether the disk store persists between restarts of the Virtual Machine. The default value is false.
          diskSpoolBufferSizeMB:这个参数设置 DiskStore(磁盘缓存)的缓存区大小。默认是 30MB。每个 Cache 都应该有本人的一个缓冲区。diskExpiryThreadIntervalSeconds:磁盘生效线程运行工夫距离,默认是 120 秒。memoryStoreEvictionPolicy:当达到 maxElementsInMemory 限度时,Ehcache 将会依据指定的策略去清理内存。默认策略是 LRU(最近起码应用)。你能够设置为 FIFO(先进先出)或是 LFU(较少应用)。clearOnFlush:内存数量最大时是否革除。memoryStoreEvictionPolicy: 可选策略有:LRU(最近起码应用,默认策略)、FIFO(先进先出)、LFU(起码拜访次数)。FIFO,first in first out,这个是大家最熟的,先进先出。LFU,Less Frequently Used,就是下面例子中应用的策略,直白一点就是讲始终以来起码被应用的。如下面所讲,缓存的元素有一个 hit 属性,hit 值最小的将会被清出缓存。LRU,Least Recently Used,最近起码应用的,缓存的元素有一个工夫戳,当缓存容量满了,而又须要腾出中央来缓存新的元素的时候,那么现有缓存元素中工夫戳离以后工夫最远的元素将被清出缓存。-->
        <defaultCache
                maxElementsInMemory="10000"
                eternal="false"
                timeToIdleSeconds="120"
                timeToLiveSeconds="120"
                maxElementsOnDisk="10000000"
                diskExpiryThreadIntervalSeconds="120"
                memoryStoreEvictionPolicy="LRU"/>
    
        <cache
                name="fx67llCache"
                eternal="false"
                maxElementsInMemory="100"
                overflowToDisk="false"
                diskPersistent="false"
                timeToIdleSeconds="0"
                timeToLiveSeconds="300"
                memoryStoreEvictionPolicy="LRU"/>
    
    </ehcache>
  3. application.yml 增加缓存配置

    # Ehcache 缓存配置
    cache:
      ehcache:
        config: classpath:ehcache.xml
  4. 在入口类增加 @EnableCaching 注解,示意开启缓存
  5. Java Bean 对象实现序列化,public class User implements Serializable
  6. 在须要应用的中央应用现关注解,实现缓存能够缩小从数据库查问的次数

定时调度工具 Quartz

能够参考文章————Quartz 定时调度具体学习,这里前期会补上阐明

什么是 Quartz

在日常我的项目运行中,咱们总会有需要在某一时间段周期性的执行某个动作,比方每天在某个时间段导出报表,或者每隔多久统计一次当初在线的用户量等。
在 SpringBoot 中有 Java 自带的 java.util.Timer 类,也能够在启动类增加 @EnableScheduling 注解引入定时工作环境

Quartz 的应用

  1. pom.xml 增加依赖

    <!--Quartz 工具依赖 -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-quartz</artifactId>
    </dependency>
  2. 增加 job 包 并编写 job 工作,实现job 接口,并在execute 办法 中实现本人的业务逻辑

    package com.fx67ll.springboot.jobs;
    
    import org.quartz.*;
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    
    import java.text.SimpleDateFormat;
    import java.util.Date;
    
    public class TestQuartzJob implements Job {private Logger logger = LoggerFactory.getLogger(TestQuartzJob.class);
    
        @Override
        public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
    
            // 获取整顿好的日期工夫
            SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
            // 查问触发器名称和触发器属于哪个分组
            TriggerKey triggerKey = jobExecutionContext.getTrigger().getKey();
    
            // 打印日志
            logger.info("以后触发器是:" + triggerKey.getName() + ",它所属的组别是:" + triggerKey.getGroup() +
                    "---------- 触发工夫:" + simpleDateFormat.format(new Date()) +
                    "-->" + "Hello fx67ll Spring Boot Quartz......");
        }
    }
  3. 构建调度配置类,创立 JobDetail 实例并定义 Trigger 注册到 scheduler,启动 scheduler 开启调度

    package com.fx67ll.springboot.conf;
    
    import com.fx67ll.springboot.jobs.TestQuartzJob;
    import org.quartz.*;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    
    @Configuration
    public class QuartzCOnf {
        @Bean
        /**
         * 具体的能够被执行的调度程序
         */
        public JobDetail jobDetailTestQuartz(){return JobBuilder.newJob(TestQuartzJob.class).storeDurably().build();
        }
    
        @Bean
        /**
         * 第一个测试触发器,次要是配置参数提醒什么时候调用
         * 利用场景有比方定时发送邮件之类的
         */
        public Trigger triggerTestQuartzFirst(){SimpleScheduleBuilder simpleScheduleBuilder = SimpleScheduleBuilder.simpleSchedule()
                    // 每五秒执行一次
                    .withIntervalInSeconds(1)
                    // 永恒反复,始终执行上来
                    .repeatForever();
            return TriggerBuilder.newTrigger()
                    // 设置触发器名称和分组
                    .withIdentity("triggerTestQuartzFirst","groupTestQuartz")
                    .withSchedule(simpleScheduleBuilder)
                    .forJob(jobDetailTestQuartz())
                    .build();}
    
        @Bean
        /**
         * 第二个测试触发器
         */
        public Trigger triggerTestQuartzSecond(){return TriggerBuilder.newTrigger()
                    // 设置触发器名称和分组
                    .withIdentity("triggerTestQuartzSecond","groupTestQuartz")
                    // 这里是通过定义表达式来示意每 5 秒执行一次,后续再深入研究下
                    .withSchedule(CronScheduleBuilder.cronSchedule("0/5 * * * * ? *"))
                    .forJob(jobDetailTestQuartz())
                    .build();}
    }

附录

操作代码目录阐明

springboot-quickstart springboot-mybatis springboot-mybatis-crud springboot-mybatis-crud-prod
疾速入门 整合 mybatis 整套 crud 操作 生产环境开发

操作代码资源地址

  1. springboot-quickstart
  2. springboot-mybatis
  3. springboot-mybatis-crud
  4. springboot-mybatis-crud-prod

参考资料

  1. 参考教程 ———— 两天搞定 SpringBoot 框架
  2. 参考文档 ———— JavaSpringBoot 中 @Autowired 用法
  3. 参考文档 ———— SpringBoot – @Configuration、@Bean 注解的应用详解(配置类的实现)
  4. 参考文档 ————【Spring Boot】Spring 根底 —— 组合注解与元注解
  5. 参考文档 ———— @RestController 和 @Controller 的区别
  6. 参考文档 ———— MapperScan 注解详解
  7. 参考文档 ———— Mapper.xml 详解
  8. 参考文档 ———— MVC 三层架构(详解)
  9. 参考文档 ———— 配置 devtools 热部署
  10. 参考文档 ———— (十三)SpringBoot2.0 热部署 Devtools 原理
  11. 参考文档 ———— 2021 版 IDEA 没有 compiler.automake.allow.when.app.running
  12. 参考文档 ———— SpringBoot 根底之 MockMvc 单元测试
  13. 参考文档 ———— Ehcache 具体解读
  14. 参考文档 ———— spring boot 接入 ehcache
  15. 参考文档 ———— SpringBoot(十二):validation 罕用注解
  16. 参考文档 ———— SpringBoot 之——Validator 校验相干的注解
  17. 参考文档 ———— 强悍的 Spring 之 spring validation
  18. json 格局校验并显示谬误_应用 Spring Validation 优雅地进行参数校验

我是 fx67ll.com,如果您发现本文有什么谬误,欢送在评论区探讨斧正,感谢您的浏览!
如果您喜爱这篇文章,欢送拜访我的 本文 github 仓库地址,为我点一颗 Star,Thanks~ :)
转发请注明参考文章地址,非常感谢!!!

退出移动版