SpringBoot2 笔记目录
初次学习SpringBoot,底层原理听的迷迷糊糊。因此,目前没有写关于底层的原理,仅记录一些基本的使用,毕竟先学会使用,才有兴趣了解底层,不然一开始就学习了解底层,个人感觉十分枯燥乏味。
一:创建可直接运行的 SpringBoot 项目
1 创建项目:
使用 Spring Initializr 可以快速创建一个SpringBoot项目,且无需配置即可运行出一个简单的 Hello World
选中需要的 依赖 或 工具等,此时选择了web (代表是一个web项目),thymeleaf (类似jsp,html),pom.xml 配置文件中会自动生成这些依赖配置(starter)
加入DevTools 在项目启动后进行代码修改后可以用Ctrl+F9进行编译(不用重新启动);
加入Lombok可以简化JavaBean和日志等开发,比如其中的Data注解可以为实体类中的属性生成getter、setter、toString等方法


2 创建一个Controller:

3 编写业务代码:
@RestController //此注解相当于 @Controller + @ResponseBody
public class testHelloWorldController {
@GetMapping("/testHelloWorld") //相当于GET方式的 @RequestMapping
public String testHelloWorld() {
return "Hello World !!!";
}
}
4 启动项目,并测试:

二:配置文件
1 配置文件类型:
resources 路径下有一个自动生成的 properties 配置文件,使用方式和以前相同。
2 yaml:
这里使用 yaml 来作为 配置文件
yaml 的使用:
@Data
public class Person {
private String userName;
private Boolean boss;
private Date birth;
private Integer age;
private Pet pet;
private String[] interests;
private List<String> animal;
private Map<String, Object> score;
private Set<Double> salarys;
private Map<String, List<Pet>> allPets;
}
@Data
public class Pet {
private String name;
private Double weight;
}
使用yaml来表示:
# yaml表示以上对象
person:
userName: zhangsan
boss: false
birth: 2019/12/12 20:12:33
age: 18
pet:
name: tomcat
weight: 23.4
interests: [篮球,游泳]
animal:
- jerry
- mario
score:
english:
first: 30
second: 40
third: 50
math: [131,140,148]
chinese: {first: 128,second: 136}
salarys: [3999,4999.98,5999.99]
allPets:
sick:
- {name: tom}
- {name: jerry,weight: 47}
health: [{name: mario,weight: 47}]
3 配置 yaml (测试:修改Tomcat 端口号)
默认端口号为8080
按照个人习惯修改端口号 (ps: 不要使用已占用的端口号):
重新启动项目,发现端口号已经变为8888
4 yaml中配置 视图解析器 前缀 后缀
controller中返回字符串时自动拼接为 /xxx.html
spring:
mvc:
view:
prefix: /
suffix: .html
三:Web开发
1 静态资源访问:
将静态资源放在自动生成的static文件夹下
(也可以放在和static同级目录的名称为 public 或 resources文件夹下;这几种方法都不用配置静态资源的路径,如果放在其他目录下需要配置访问路径)


2 index.html 欢迎页支持
将 index.html 放在 static目录下,访问项目时会默认访问该页面。
放在 static目录下
测试:访问该项目时,默认访问 index.html 文件
3 自定义 Favicon
将 favicon.ico 放在static 目录下,可以更改网页图标
测试:(Ctrl + F5 强制刷新,若仍然不变,可重启 idea)
4 Rest 使用
和 SpringMVC 使用方式一样,但简化了配置
主要是delete 和 put 方式,和 springmvc 学习的相同,表单请求为post,再写一个name 为_method的隐藏域,value 注明时 delete 还是 put
① 编写 html(以 index.html 为例)
<!-- get -->
<form method="get" action="/testRest">
<input type="submit" value="测试GET">
</form>
<!-- post -->
<form method="post" action="/testRest">
<input type="hidden" name="_method" value="POST">
<input type="submit" value="测试POST">
</form>
<!-- delete -->
<form method="post" action="/testRest">
<input type="hidden" name="_method" value="DELETE">
<input type="submit" value="测试DELETE">
</form>
<!-- put -->
<form method="post" action="/testRest">
<input type="hidden" name="_method" value="PUT">
<input type="submit" value="测试PUT">
</form>
② 配置 过滤器
springmvc 中说过, delete和 put 是通过 过滤器来实现判断的
③ 编写 Controller
ps:
@GetMapping 可以表示 @RequestMapping(method=RequestMethod.GET)
@PostMapping 可以表示 @RequestMapping(method=RequestMethod.POST)
@RestController //此注解相当于 @Controller + @ResponseBody
public class TestRest {
@RequestMapping(value = "/testRest",method = RequestMethod.GET)
public String testGet() {
return "GET";
}
@RequestMapping(value = "/testRest",method = RequestMethod.POST)
public String testPost() {
return "POST";
}
@RequestMapping(value = "/testRest",method = RequestMethod.DELETE)
public String testDelete() {
return "DELETE";
}
@RequestMapping(value = "/testRest",method = RequestMethod.PUT)
public String testPut() {
return "PUT";
}
5 基本注解的使用
(1) @PathVariable 注解:
① 编写 Controller
@RestController
public class TestParamter {
@GetMapping("/testPathVariable/{id}")
public String testPathVariable(@PathVariable("id") int id) {
return "id值为: "+id;
}
}
② 测试:

(2)@RequestHeader 注解:
① 编写 Controller:
@GetMapping("/testRequestHeader")
public String testReuqestHeader(@RequestHeader("User-Agent") String header) {
return "UA为:" + header;
}
② 测试:

(3) @RequestParam 注解:
① 编写 html:
<form action="/testRequestParam">
<input type="text" name="name">
<input type="submit" value="提交">
</form>
② 编写 Controller:
@GetMapping("/testRequestParam")
public String testRequestParam(@RequestParam("name") String name) {
return name;
}
③ 测试:
输入 “zhangsan",然后提交
输出结果:
(4)@RequestBody 注解:
(@RequestBody 只能有一个,必须为 Post 请求才能被接收 , @RequestParam 可以有多个)
① 编写 html:
<form action="/testRequestBody" method="post">
用户名:<input name="username"><br>
密码: <input name="password"><br>
爱好: <input name="hobby"><br>
<input type="submit" value="提交">
</form>
② 编写Controller:
@PostMapping("/testRequestBody")
public Map testRequestBody(@RequestBody String content) {
Map<String,Object> map = new HashMap<>();
map.put("content",content);
return map;
}
③ 测试:

6 自定义对象参数
和 SpringMVC所学一样,可以自动类型转换与格式化,可以级联封装
(1)编写 实体类:
① Person 类:
@Data //lombok中的此注解:自动生成getter,setter,toString等
public class Person {
private String name;
private String pwd;
private Pet pet;
}
② Pet 类:
@Data //lombok中的此注解:自动生成getter,setter,toString等
public class Pet {
private String name;
private String kind;
}
(2)编写 Html:
<form action="/test">
用户名:<input name="name"> <br>
密码:<input name="pwd"> <br>
宠物名:<input name="pet.name"> <br>
宠物种类:<input name="pet.kind"> <br>
<input type="submit" value="提交">
</form>
(3) 编写Controller:
@RestController
public class TestParamter222 {
@GetMapping("/test")
public String test(Person person) {
return "接收到的数据: " + person;
}
}
(4) 测试:
输入:
结果:
7 模板引擎-Thymeleaf
(一开始创建项目时,选中的 tool,使用与 jsp 相似)
8 拦截器
(1) 编写一个拦截器实现 HandlerInterceptor
@Slf4j
public class MyInterceptor implements HandlerInterceptor {
@Override //目标方法执行前
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
String requestURI = request.getRequestURI();
log.info("preHandle拦截的请求路径是{}",requestURI);
log.info("放行!");
return true;
}
(2) 拦截器注册到容器中(实现webMvcConfigurer的addInterceptors)
指定拦截器规则(如果是拦截所有,静态资源也会被拦截)
@Configuration // 该类为配置类
public class InterceptorConfig implements WebMvcConfigurer {
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new MyInterceptor()) //拦截器注册到容器中
.addPathPatterns("/**"); //拦截所有请求路径
}
}
(3) 编写 Html :
<!-- 测试拦截器 -->
<form method="post" action="/testInterceptor">
用户名:<input name="name"> <br>
密码:<input name="pwd"> <br>
宠物名:<input name="pet.name"> <br>
宠物种类:<input name="pet.kind"> <br>
<input type="submit" value="登录">
</form>
(4) 编写 Controller:
@Slf4j
@RestController
public class TestInterceptor {
@PostMapping("/testInterceptor")
public void testInterceptor(Person person, HttpSession session) {
log.info("到达Controller");
}
}
(5) 测试:


9 文件上传
① 编写 html:
(multiple:支持多文件上传)
<form action="/testFileUpload" method="post" enctype="multipart/form-data">
<input type="file" name="file" multiple><br>
<input type="submit" value="上传">
</form>
② 编写 Controller:
@Controller
public class TestFileUpload {
@PostMapping("/testFileUpload")
public String testFileUpload(@RequestPart("file") MultipartFile[] files) throws IOException {
if(files.length > 0) { //有文件
for (MultipartFile file : files) {
// 获取原文件名
String originalFilename = file.getOriginalFilename();
// 把该文件 放到该目录下
file.transferTo(new File("C:/Users/ACER/Desktop/file/"+originalFilename));
}
return "success";
}
return "";
}
}
③ 配置 上传文件的大小
单个文件大小最大1MB,一次总上传文件大小最大为10MB
spring
servlet:
multipart:
max-file-size: 1MB
file-size-threshold: 10MB
④ 测试:
选中 符合配置的文件,然后上传,在目标文件下就可以看到文件已经传过来了
10 自定义异常
在 error 目录下,放入404.html 和 500.html,当出现404异常时,会自动使用404.html。500异常同理。
(404.html 中 <img src="404.jpg">)
(500.html 中 <img src="500.png">)
(1) 测试 404 异常:
随便访问个不存在的路径:
(2) 测试 500 异常:
编写 一个会触发500异常的Controller
@Controller
public class TestError {
@GetMapping("/testError")
public void testError() {
int i = 1/0;
}
}
直接访问该 controller
11 Web原生组件注入 (Servlet、Filter)
(1) Servlet
① 指定扫描包:
在主程序上方写注解指定扫描包:
@ServletComponentScan("com.heitao.boot") //指明原生组件的位置

② 编写Servlet:
@WebServlet("/testServlet") //指定处理的路径
public class MyServlet extends HttpServlet {
// 重写doGet 和 doPost
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.getWriter().println("this is MyServlet!!!!");
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req,resp);
}
}
③ 测试:

(2) Filter
① 编写 MyFilter:
@Slf4j //日志: log.info() 可以自定义日志信息
@WebFilter({"/ttt/*"}) //指定过滤的路径
public class MyFilter extends HttpFilter {
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
log.info("MyFilter 工作");
}
@Override
public void init(FilterConfig filterConfig) throws ServletException {
log.info("MyFilter 初始化");
}
@Override
public void destroy() {
}
}
② 创建 ttt 目录 测试过滤器:

③ 测试


四:数据访问
1 druid 数据源 (使用 starter)
(1) 官方 GitHub:
写的很清楚:官方 GitHub 链接
(2) 配置 pom.xml
① 引入 druid-spring-boot-starter
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>1.1.17</version>
</dependency>
② spring-boot-starter-jdbc
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
② mysql-connector-java
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.19</version>
</dependency>
(3) 配置示例:
(雷神笔记)
spring:
datasource:
url: jdbc:mysql://localhost:3306/db_account
username: root
password: 123456
driver-class-name: com.mysql.jdbc.Driver
druid:
aop-patterns: com.atguigu.admin.* #监控SpringBean
filters: stat,wall # 底层开启功能,stat(sql监控),wall(防火墙)
stat-view-servlet: # 配置监控页功能
enabled: true
login-username: admin
login-password: admin
resetEnable: false
web-stat-filter: # 监控web
enabled: true
urlPattern: /*
exclusions: '*.js,*.gif,*.jpg,*.png,*.css,*.ico,/druid/*'
filter:
stat: # 对上面filters里面的stat的详细配置
slow-sql-millis: 1000
logSlowSql: true
enabled: true
wall:
enabled: true
config:
drop-table-allow: false
(4) 编写 Controller:
@RestController
public class TestDruid {
@Autowired
JdbcTemplate jdbcTemplate;
@GetMapping("/sql")
public String sql() {
Long aLong = jdbcTemplate.queryForObject("select count(*) from student", long.class);
return "student中的数据条数: " + aLong;
}
}
(5) 测试:

多刷新几次sql页面(看到次数为 6)
2 mybatis 数据源
(1) 注解方式:
① 在 pom.xml 中引入 mybatis 的 starter
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.1.4</version>
</dependency>
② 数据库 和 实体类
数据库:
实体类: Student
@Data //lombak工具中的此注解可以自动生成setter,getter,tostring等方法
public class Student {
private int sno;
private String sname;
private int sage;
}
③ StudentMapper (相当于Dao层)
@Mapper
public interface StudentMapper {
@Select("select * from student where sno = #{sno}")
public Student findStudentById(int sno);
}
④ StudentService (Service层)
(测试,简单写写)
@Service
public class StudentService {
@Autowired
StudentMapper studentMapper; //可能有红色下划线,运行没有问题
public Student findStudentById(int sno) {
return studentMapper.findStudentById(sno);
}
}
⑤ TestMybatis (Controller 控制层)
@Controller
public class TestMybatis {
@Autowired
StudentService studentService;
@ResponseBody
@GetMapping("/testMybatis")
public Student testMybatis(int sno) {
return studentService.findStudentById(sno);
}
}
⑥ 测试:

(2) xml 方式:
和注解方式的不同之处主要是,xml方式不是直接使用注解写sql语句,而是通过xml,所以需要一些配置
(在注解方式的基础上,把 @Select 注解删除)
① 编写sql映射文件并绑定mapper接口

StudentMapper.xml 代码:
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!-- 绑定 Mapper 接口 -->
<mapper namespace="com.heitao.boot.Mapper.StudentMapper">
<!-- 编写 sql映射 语句 -->
<select id="findStudentById" resultType="com.heitao.boot.entity.Student">
select * from student where sno = #{sno}
</select>
</mapper>
② 在 yaml 配置文件中,指明 mapper配置文件 的位置
mybatis:
mapper-locations: classpath:mybatis/mapper/*.xml
③ 测试

五:单元测试
1 JUnit 5:
常用注解:
@Test :表示方法是测试方法。但是与JUnit4的@Test不同,他的职责非常单一不能声明任何属性,拓展的测试将会由Jupiter提供额外测试
@ParameterizedTest :表示方法是参数化测试,下方会有详细介绍
@RepeatedTest :表示方法可重复执行,下方会有详细介绍
@DisplayName :为测试类或者测试方法设置展示名称
@BeforeEach :表示在每个单元测试之前执行
@AfterEach :表示在每个单元测试之后执行
@BeforeAll :表示在所有单元测试之前执行
@AfterAll :表示在所有单元测试之后执行
@Tag :表示单元测试类别,类似于JUnit4中的@Categories
@Disabled :表示测试类或测试方法不执行,类似于JUnit4中的@Ignore
@Timeout :表示测试方法运行如果超过了指定时间将会返回错误
@ExtendWith :为测试类或测试方法提供扩展类引用
① 找到自动创建的 test

② 编写测试内容:
@SpringBootTest
class BootApplicationTests {
@Test //测试1
void contextLoads() {
System.out.println("test1");
}
@Test //测试2
void test2() {
System.out.println("test2");
}
@BeforeAll //表示在所有单元测试之前执行
static void beforeAll() {
System.out.println("开始全部单元测试");
}
@AfterAll //表示在所有单元测试之后执行
static void afterAll() {
System.out.println("全部单元测试完毕");
}
@BeforeEach //表示在每个单元测试之前执行
void beforeEach() {
System.out.println("开始进行一个单元测试");
}
@AfterEach //表示在每个单元测试之后执行
void afterEach() {
System.out.println("完成一个单元测试");
}
}
③ 运行结果:


2 断言
(1) 简单断言

@Test
public void test() {
//判断两个对象或两个原始类型是否相等
assertEquals(3,1+2);
//判断两个对象或两个原始类型是否不相等
assertNotEquals(3,2+2);
Object obj1 = new Object();
Object obj2 = new Object();
//判断两个对象引用是否指向同一个对象
assertSame(obj1,obj1);
//判断两个对象引用是否指向不同的对象
assertNotSame(obj1,obj2);
//判断给定的布尔值是否为 true
assertTrue(1<2);
//判断给定的布尔值是否为 false
assertFalse(1>2);
//判断给定的对象引用是否为 null
assertNull(null);
//判断给定的对象引用是否不为 null
assertNotNull(obj1);
}
(2) 数组断言
@Test
public void test() {
int a[] = new int[]{1,2,3};
int b[] = new int[]{1,2,3};
//通过 assertArrayEquals 方法来判断两个对象或原始类型的数组是否相等
assertArrayEquals(a,b);
}
(3) 组合断言
@Test
public void test() {
//都成功,才成功
assertAll(()->assertEquals(2,1+1),
()->assertTrue(1 < 2));
}
(4) 快速失败
@Test
public void test() {
if(1>2){
//此时不失败,会打印 aaaaa,若条件符合执行fail,则不会打印aaaaa
fail();
}
System.out.println("aaaaa");
}
3 参数化测试
@ValueSource: 为参数化测试指定入参来源,支持八大基础类以及String类型,Class类型
@NullSource: 表示为参数化测试提供一个null的入参
@EnumSource: 表示为参数化测试提供一个枚举入参
@CsvFileSource:表示读取指定CSV文件内容作为参数化测试入参
@MethodSource:表示读取指定方法的返回值作为参数化测试入参(注意方法返回需要是一个流)
(1) 测试 @ValueSource
@ParameterizedTest
@ValueSource(strings = {"aaa","bbb","ccc"})
public void test(String s) {
System.out.println(s);
assertNotEquals(s,"ddd");
}
