先说一些废话
尽管我的工作中更多的是与数据库打交道,然而作为一个 Coder
,我感觉把握前后端的Web
技术来说是十分有必要的。
不仅能够帮忙咱们在工作中更好的了解其余岗位与你对接的人他的工作痛点,也能在公司须要人手的时候成为一个无力的应急帮手,比方之前公司的数据中台我就参加架构和局部开发工作,更重要的是我私下里能够使用一些疾速框架来搭建一些有意思的网站,比方我的个人主页和集体博客都是我自学 java
和js
所做进去的作品。
所以明天我心愿整合一些我以往的教训和看过的教程文档,来写一篇文章,帮忙你在一天之内通过这篇文章疾速学习 SpringBoot
框架以及各种开发必备的工具与插件!!!
MVC
什么是 MVC
-
MVC 三层架构是指:视图层 View、服务层 Service,与长久层 Dao,它们别离实现不同的性能
- View 层:用于接管用户提交申请的代码在这里编写
- Service 层:零碎的业务逻辑次要在这里实现
- Dao 层:间接操作数据库的代码在这里编写
- 为了更好的升高各层间的耦合度,在三层架构程序设计中,采纳面向形象编程,即下层对上层的调用,是通过接口实现的,而上层对下层的真正服务提供者,是上层接口的实现类
- 服务规范(接口)是雷同的,服务提供者(实现类)能够更换,这就实现了层间解耦合
MVC 架构程序的工作流程
- 用户通过 View 页面向服务端提出申请,能够是表单申请、超链接申请、AJAX 申请等
- 服务端 Controller 控制器接收到申请后对申请进行解析,找到相应的 Model 对用户申请进行解决
- Model 解决后,将处理结果再交给 Controller
- Controller 在接到处理结果后,依据处理结果找到要作为向客户端发回的响应 View 页面,页面经渲染(数据填充)后,再发送给客户端
应用 xml 还是注解
- 利用的根本配置应用 xml,比方数据源和资源文件等
- 业务开发应用注解,比方 service 注入 bean
- 然而 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
- 相当于
@Controller + @ResponseBody
两个注解的联合,返回JSON
数据不须要在办法后面加@ResponseBody
注解了,
但应用 @RestController 这个注解,就不能返回 jsp、html 页面,视图解析器无奈解析 jsp、html 页面 v @ResponseBody
示意该办法的返回后果间接写入HTTP response body
中,个别在异步获取数据时应用(也就是 AJAX),
在应用@RequestMapping
后,返回值通常解析为跳转门路,然而加上@ResponseBody
后返回后果不会被解析为跳转门路,而是间接写入HTTP response body
中,
比方异步获取JSON
数据,加上@ResponseBody
后,会间接返回JSON
数据-
@RequestBody
将 HTTP 申请注释插入方法中,应用适宜的 HttpMessageConverter 将申请体写入某个对象@MapperScan、@Mapper
-
@Mapper 注解:
- 作用:在接口类上增加了 @Mapper,在编译之后会生成相应的接口实现类
- 增加地位:接口类下面
- 如果想要每个接口都要变成实现类,那么须要在每个接口类上加上
@Mapper
注解,比拟麻烦,解决这个问题用@MapperScan
注解
-
@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 我的项目,可能会有端口占用的报错
- 思路是杀死占用端口的过程即可,次要是上面两个命令
- 应用
netstat -aon|findstr "被占用的端口"
或者tasklist |findstr "过程名称"
查问到端口的过程号 - 应用
taskkill /f /t /im "过程名称"
或者taskkill /f /t /pid "过程 PID"
杀死过程即可
事务管制
申明式事务
能够参考文章————SpringBoot 申明式事务的简略使用具体学习,这里前期会补上阐明
次要利用在新增批改删除上,利用注解即可
全局异样
应用 @ControllerAdvice 配合 @ExceptionHandler
能够参考文章————Springboot 系列 -@ControllerAdvice 应用具体学习,这里前期会补上阐明
此注解其实是一个加强的Controller
,应用这个Controller
,可实现三个方面的性能,因为这是 SpringMVC 提供的性能,所以能够在 springboot 中间接应用
- 全局异样解决(@ExceptionHandler)
- 全局数据绑定(@InitBinder)
-
全局数据预处理(@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 工具
向后端申请的状况。
所以服务端的数据校验也是必要的,能够避免脏数据落到数据库中,如果数据库中呈现一个非法的邮箱格局,也会让运维人员头疼不已。
如何进行后端数据校验
SpringBoot
中个别应用Spring Validation
来进行后端数据校验,它是对Hibernate Validation
进行了二次封装,
在SpringMVC
模块中增加了主动校验,并将校验信息封装进了特定的类中- 在应用时咱们只须要引入
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) 具体学习,这里前期会补上阐明
示例代码
-
/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; }
-
在
Bean
文件/com/fx67ll/springboot/dao/User.java
中公有字段上应用注解来校验,不贴所有代码了,仅贴局部重点代码@NotBlank(message = "用户名称不能为空!") private String userName; @NotBlank(message = "用户明码不能为空!") @Length(min = 6, max = 20, message = "明码长度起码六位且最多二十位!") private String userPwd;
-
在全局自定义异样拦挡中
/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 包
- 个别用于编写依赖工具包
-
打包
- 在 IDEA
Run/Debug Configurations
下Command line
配置clean complie package -Dmaven.test.skip=true
执行打包命令 target
目录失去待部署的我的项目文件
- 在 IDEA
-
部署
- 在 dos 窗口中,执行命令
java -jar jar 包所在的本地目录
- 在 dos 窗口中,执行命令
war 包
- 在生产环境中最为常见的部署形式
-
批改
pom.xml
,设置打包模式为 war 包<groupId>com.fx67ll</groupId> <artifactId>springboot-quickstart</artifactId> <version>0.1.0</version> <!-- 设置为 war 包模式 --> <packaging>war</packaging>
-
疏忽内嵌 Tomcat
<!-- 设置为内部已提供,示意疏忽 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-tomcat</artifactId> <scope>provided</scope> </dependency>
-
配置生成的 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>
-
批改
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); } }
- 这里通过继承
-
打包
- 在 IDEA
Run/Debug Configurations
下Command line
配置clean complie package -Dmaven.test.skip=true
执行打包命令 target
目录失去待部署的我的项目文件
- 在 IDEA
-
部署并拜访
- 搁置到内部 tomcat 中,执行 bin 目录下 start 脚本即可
热部署
热部署,就是在利用正在运行的时候降级软件,却不须要重新启动利用,次要利用在开发过程中
热部署原理
spring-boot-devtools
是一个为开发者服务的一个模块,其中最重要的性能就是主动利用代码更改到最新的 App 下面去,
原理是在发现代码有更改之后,重新启动利用,然而速度比手动进行后再启动还要更快,更快指的不是节俭进去的手工操作的工夫-
其深层原理是应用了两个
ClassLoader
,一个Classloader
加载那些不会扭转的类(第三方 Jar 包),另一个ClassLoader
加载会更改的类,称为restart ClassLoader
,
这样在有代码更改的时候,原来的restart ClassLoader
被抛弃,从新创立一个restart ClassLoader
,因为须要加载的类相比拟少,所以实现了较快的重启工夫, 大略在 5 秒以内devtools 原理
- devtools 会监听 classpath 下的文件变动,并且会立刻重启利用(产生在保留机会)留神:因为其采纳的虚拟机机制,该项重启是很快的
-
devtools 能够实现页面热部署(即页面批改后会立刻失效,这个能够间接在
application
文件中配置spring.thymeleaf.cache=false
来实现 留神:不同的模板配置不一样热部署次要步骤
-
在
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>
-
批改
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
-
批改 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......
- 批改了 java 类之后,IDEA 默认是不主动编译的,而
-
配置完须要重启一下,而后有批改的话我的项目会自动更新,然而如果是主动触发的话,会造成频繁更新,对硬件有肯定的累赘,所以能够改成手动触发模式
- 点击右上角
Run/Debug Configurations
- 抉择下拉
Configuration -> Spring Boot -> Running Application Update Policies -> On 'Update' action
- 抉择
Update classes and resources
- 如果有更新能够,应用快捷键
Ctrl + F10
从新编译
- 点击右上角
- 快捷键
Ctrl + F9
,应用热部署重新启动
单元测试
依赖
<!-- 单元测试 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
Service 业务层————业务逻辑办法测试
须要留神的是:
- 如果在和
main 文件夹
平级的test 文件夹
下新建了java 文件夹
,然而无奈新建java class
文件 -
那么就须要右键文件夹
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
。
次要有两个实现:StandaloneMockMvcBuilder
和 DefaultMockMvcBuilder
,别离对应两种测试形式,
即独立装置和集成 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
-
@ApiModel 常常用于申请的入参对象和响应返回值对象的形容
- 入参是对象,即 @RequestBody 时,用于封装申请(包含数据的各种校验)数据
- 返回值是对象,即 @ResponseBody 时,用于返回值对象的形容
-
@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 API
和SOAP 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 的应用
-
在
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>
-
增加
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>
-
在
application.yml
增加缓存配置# Ehcache 缓存配置 cache: ehcache: config: classpath:ehcache.xml
- 在入口类增加
@EnableCaching
注解,示意开启缓存 - Java Bean 对象实现序列化,
public class User implements Serializable
- 在须要应用的中央应用现关注解,实现缓存能够缩小从数据库查问的次数
定时调度工具 Quartz
能够参考文章————Quartz 定时调度具体学习,这里前期会补上阐明
什么是 Quartz
在日常我的项目运行中,咱们总会有需要在某一时间段周期性的执行某个动作,比方每天在某个时间段导出报表,或者每隔多久统计一次当初在线的用户量等。
在 SpringBoot 中有 Java 自带的 java.util.Timer
类,也能够在启动类增加 @EnableScheduling
注解引入定时工作环境
Quartz 的应用
-
在
pom.xml
增加依赖<!--Quartz 工具依赖 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-quartz</artifactId> </dependency>
-
增加
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......"); } }
-
构建调度配置类,创立 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 操作 | 生产环境开发 |
操作代码资源地址
- springboot-quickstart
- springboot-mybatis
- springboot-mybatis-crud
- springboot-mybatis-crud-prod
参考资料
- 参考教程 ———— 两天搞定 SpringBoot 框架
- 参考文档 ———— JavaSpringBoot 中 @Autowired 用法
- 参考文档 ———— SpringBoot – @Configuration、@Bean 注解的应用详解(配置类的实现)
- 参考文档 ————【Spring Boot】Spring 根底 —— 组合注解与元注解
- 参考文档 ———— @RestController 和 @Controller 的区别
- 参考文档 ———— MapperScan 注解详解
- 参考文档 ———— Mapper.xml 详解
- 参考文档 ———— MVC 三层架构(详解)
- 参考文档 ———— 配置 devtools 热部署
- 参考文档 ———— (十三)SpringBoot2.0 热部署 Devtools 原理
- 参考文档 ———— 2021 版 IDEA 没有 compiler.automake.allow.when.app.running
- 参考文档 ———— SpringBoot 根底之 MockMvc 单元测试
- 参考文档 ———— Ehcache 具体解读
- 参考文档 ———— spring boot 接入 ehcache
- 参考文档 ———— SpringBoot(十二):validation 罕用注解
- 参考文档 ———— SpringBoot 之——Validator 校验相干的注解
- 参考文档 ———— 强悍的 Spring 之 spring validation
- json 格局校验并显示谬误_应用 Spring Validation 优雅地进行参数校验
我是 fx67ll.com,如果您发现本文有什么谬误,欢送在评论区探讨斧正,感谢您的浏览!
如果您喜爱这篇文章,欢送拜访我的 本文 github 仓库地址,为我点一颗 Star,Thanks~ :)
转发请注明参考文章地址,非常感谢!!!