SpringBoot终极讲义第一章笔记

01.Spring Boot简介

1.Spring的本质和作用

spring的本质就是一个"容器",它负责创建并管理容器中的对象(组件,也称为Bean),并管理组件之间的依赖关系(何为依赖关系:A组件需要调用B组件方法,称为A依赖于B)

因此学习Spring最常用的两个注解:

@Component:将被修饰的类变成容器中的组件

        @Controller  @Service  @Repository本质都是@Component只不过更形象的表示哪个层级

        控制层,业务层,持久层.表示清楚而已

@AutoWired:完成依赖注入

2.javaEE和Spring

3.java后端开发涉及的技术

MVC层:Spring WebFlux,Spring MVC,Struts2等

安全领域:Spring Security,Shiro等

消息组件:ActiveMQ,RabbitMQ,Kafka等

缓存:JCache,EhCache,Hazelcast,Redis等 

持久层框架:JPA,Mybatis,JOOQ,R2DBC等

分布式:Zookeeper,Dubbo等.

NOSQL存储:Redsi,MongoDB,Neo4J,Cassandra,Geodo,CouchBase等

全文检索引擎:Lucene,Solr,Elastichsearch等

数据库存储:Mysql,PostgreSQL,Oracle等

Web服务器:Tomcat,Jetty,Undertow等

4.Spring与SpringBoot

SpringBoot依然以Spring为核心,Spring的缺点是配置过多

SpringBoot为绝大部分第三方框架的快速整合提供了自动配置

针对各种框架提供了对应的Starter,只要添加该Starter即可完成第三方框架的自动整合

SpringBoot整合了绝大对数常用的第三方框架

5.SrpingBoot能做什么和不能做什么

内嵌Tomcat,Jetty等服务器,因此SpringBoot 应用无需部署到其他服务器

SpringBoot应用可做成独立的java应用程序--不需要是web应用

意味着可以通过"java 主类"命令来运行应用.

提供产品级监控功能(Spring Actuator),如运行状况检查和外部化配置等

不要夸大SpringBoot的功能,SpringBoot直译就是Spring启动 

它主要功能就是为Spring及第三方框架的快速启动提供了自动配置

-----------------------------------------------------------------------------------------------------------------

02.SpringBoot的项目结构

创建时引入的依赖

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

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-devtools</artifactId>
        <scope>runtime</scope>
        <optional>true</optional>
    </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>
</dependencies>

<build>
    <plugins>
        <plugin>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-maven-plugin</artifactId>
            <configuration>
                <excludes>
                    <exclude>
                        <groupId>org.projectlombok</groupId>
                        <artifactId>lombok</artifactId>
                    </exclude>
                </excludes>
            </configuration>
        </plugin>
    </plugins>
</build>

03.控制器访问

当访问localhost:8080/index时候无法访问,原因是这里是返回视图

04.SpringBoot整合Thymeleaf作为视图模板技术

引入Thymeleaf依赖

<!--Thymeleaf依赖-->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>

SpringBoot支持Webjar技术

webjars:用于将各种前端资源(JS/CSS等打成jar包)

引入bootstarp依赖:

<!--bootstarp依赖-->
<dependency>
    <groupId>org.webjars</groupId>
    <artifactId>bootstrap</artifactId>
    <version>4.6.0</version>
</dependency>

Thymeleaf模板页面要放在resources/templates下

在resources/templates/hello.html

<!DOCTYPE html>
<!--导入thymeleaf-->
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>欢迎页面</title>
    <!--引入webjar中bootstrap样式-->
    <link rel="stylesheet" th:href="@{/webjars/bootstrap/4.6.0/css/bootstrap.css}">
</head>
<body>
<div class="container">
    <div th:text="${tip}" class="alert alert-primary">提示信息</div>
</div>
</body>
</html>

访问localhost:8080/index  视图转发到hello.html

05.SpringBoot启动类作用

06.运行及打包SpringBoot应用

启动该项目

第一种方式:进入项目的pom.xml所在路径 执行    mvn spring-boot:run

CTRL+C  退出

第二种方式:将SpringBoot应用打包

打包有可能出错,如果是test问题

进入target目录    java -jar xxx.jar   或者 java -jar xxx.jar &

java -jar xxx.jar 是在当前窗口运行    java -jar xxx.jar & 是在后台运行

IDEA的Terminal窗口:运行mvn spring-boot:run

CTRL+C     Y结束

双击CTRL键盘 回车

这些真无聊  还可以

还可以这样  这是闲的

07.整合Thymeleaf添加service及dao

为了项目看起来不那么乱,有迭代效果,复制一份

templates下的文件不能直接访问,用控制器转发

添加持久层依赖,这里用Spring Data JPA

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

<!--Spring data jpa-->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>

建库 

Spring data jpa会自动帮你根据实体类创建表

在application.properties配置

spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://xxxx:3306/jpatest?serverTimezone=Asia/Shanghai
spring.datasource.username=xxxx
spring.datasource.password=xxxx

#指定显示SQL语句
spring.jpa.show-sql=true
#指定根据尸体自动建表
spring.jpa.generate-ddl=true

实体类

package com.example.pojo;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.experimental.Accessors;

import javax.persistence.*;

/**
 * @author hrui
 * @date 2023/10/1 2:12
 */
@Data
@NoArgsConstructor
@AllArgsConstructor
@Accessors(chain = true)
@Entity
@Table(name="book_inf")
public class Book {

    @Id
    @Column(name="book_id")
    @GeneratedValue(strategy = GenerationType.IDENTITY)//主键自增
    private Integer id;

    private String name;

    private Double price;

    private String author;

    //如果需要排除掉@Transient

}

持久层接口

package com.example.dao;

import com.example.pojo.Book;
import org.springframework.data.repository.CrudRepository;

/**
 * @author hrui
 * @date 2023/10/1 4:46
 */
//继承CrudRepository 泛型写实体类  主键类型
public interface BookDao extends CrudRepository<Book,Integer> {
}

业务层接口

package com.example.service;

import com.example.pojo.Book;

import java.util.List;

/**
 * @author hrui
 * @date 2023/10/1 2:06
 */
public interface BookService {

    int addBook(Book book);

    List<Book> getAllBooks();

    void deleteBook(Integer id);

}

业务实现类

package com.example.service.impl;

import com.example.dao.BookDao;
import com.example.pojo.Book;
import com.example.service.BookService;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;

/**
 * @author hrui
 * @date 2023/10/1 2:06
 */
@Service
@Transactional
public class BookServiceImpl implements BookService {

    private BookDao bookDao;

    public BookServiceImpl(BookDao bookDao) {
        this.bookDao = bookDao;
    }

    @Override
    public int addBook(Book book) {
        bookDao.save(book);//执行后会将主键id传回封装到book
        return book.getId();
    }

    @Override
    public List<Book> getAllBooks() {
        return (List<Book>) bookDao.findAll();
    }

    @Override
    public void deleteBook(Integer id) {
        bookDao.deleteById(id);
    }
}

控制器

package com.example.controller;

import com.example.pojo.Book;
import com.example.service.BookService;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.*;


import java.util.HashMap;
import java.util.Map;

/**
 * @author hrui
 * @date 2023/9/30 22:44
 */
@Controller
public class BookController {

    private BookService bookService;

    public BookController(BookService bookService) {
        this.bookService = bookService;
    }


    @PostMapping("/addBook")
    public String addBook(Book book,Model model){
        if(bookService.addBook(book)>0){
            return "redirect:listBooks";//重定向
        }

        model.addAttribute("tip", "添加图书失败");
        return "bookForm";
    }

    @GetMapping("/bookForm")
    public String bookForm(){
        return "bookForm";
    }

    @RequestMapping("/listBooks")
    public String list(Model model){
        //查询系统中所有的图书 存入books属性
        model.addAttribute("books", bookService.getAllBooks());
        return "listBooks";//转发
    }

    @RequestMapping("/deleteBook/{id}")
    public String delete(@PathVariable Integer id,Model model){
        bookService.deleteBook(id);
        return "redirect:/listBooks";
    }

resources/templates/下的3个文件

hello.html

<!DOCTYPE html>
<!--导入thymeleaf-->
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>欢迎页面</title>
    <!--引入webjar中bootstrap样式-->
    <link rel="stylesheet" th:href="@{/webjars/bootstrap/4.6.0/css/bootstrap.css}">
</head>
<body>
<div class="container">
    <div th:text="${tip}" class="alert alert-primary">提示信息</div>
</div>
</body>
</html>

bookForm.html

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
	<meta charset="UTF-8">
	<title>添加图书</title>
	<!-- 导入Webjar中的Boostrap资源 -->
	<link rel="stylesheet" th:href="@{/webjars/bootstrap/4.6.0/css/bootstrap.css}">
</head>
<body>
<div class="container">
	<!-- 使用th:text将表达式的值绑定到标准HTML元素 -->
	<div class="alert alert-primary" th:text="${tip}">提示信息</div>
	<h2>添加图书</h2>
	<form method="post" th:action="@{/addBook}">
		<div class="form-group row">
			<label for="name" class="col-sm-3 col-form-label">图书名:</label>
			<div class="col-sm-9">
				<input type="text" id="name" name="name"
					   class="form-control" placeholder="输入图书名">
			</div>
		</div>
		<div class="form-group row">
			<label for="author" class="col-sm-3 col-form-label">作者:</label>
			<div class="col-sm-9">
				<input type="text" id="author" name="author"
					   class="form-control" placeholder="输入作者">
			</div>
		</div>
		<div class="form-group row">
			<label for="price" class="col-sm-3 col-form-label">价格:</label>
			<div class="col-sm-9">
				<input type="number" step="0.1" id="price" name="price"
					   class="form-control" placeholder="输入价格">
			</div>
		</div>
		<div class="form-group row">
			<div class="col-sm-6 text-right">
				<button type="submit" class="btn btn-primary">添加</button>
			</div>
			<div class="col-sm-6">
				<button type="reset" class="btn btn-danger">重设</button>
			</div>
		</div>
	</form>
</div>
</body>
</html>

listBooks.html

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
	<meta charset="UTF-8">
	<title>欢迎页面</title>
	<!-- 导入Webjar中的Boostrap资源 -->
	<link rel="stylesheet" th:href="@{/webjars/bootstrap/4.6.0/css/bootstrap.css}">
</head>
<body>
<div class="container">
	<table class="table table-hover">
		<tr>
			<th>书名</th>
			<th>价格</th>
			<th>作者</th>
			<th>删除</th>
		</tr>
		<tr th:each="book: ${books}">
			<td th:text="${book.name}">书名</td>
			<td th:text="${book.price}">价格</td>
			<td th:text="${book.author}">作者</td>
			<td><a th:href="@{/deleteBook/} + ${book.id}">删除</a></td>
		</tr>
	</table>
	<div class="text-right"><a class="btn btn-primary" th:href="@{/bookForm}">添加图书</a></div>
</div>
</body>
</html>

效果

访问localhost:8080/bookForm

点击添加

08.SpringBoot对单元测试的支持

复制个新的springboot-003

添加SpringBoot的测试依赖,这个依赖原先就放进去了

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

在控制器新增几个方法

@PostMapping("/books")
@ResponseBody
public ResponseEntity<Book> restAddBook(@RequestBody Book book){
    if(bookService.addBook(book)>0){
        return new ResponseEntity<>(book,HttpStatus.OK);
    }
    return new ResponseEntity<>(null, HttpStatus.BAD_REQUEST);
}

@GetMapping("/books")
@ResponseBody
public ResponseEntity<List<Book>> restList(){
    return new ResponseEntity<>(bookService.getAllBooks(), HttpStatus.OK);
}

@DeleteMapping("/books/{id}")
public ResponseEntity<Integer> restDelete(@PathVariable Integer id){
    bookService.deleteBook(id);
    return new ResponseEntity<>(id, HttpStatus.OK);
}

1.用postman测试

Post      http://localhost:8080/books

Get      http://localhost:8080/books  body体里不管,反正后端没接收

Delete   http://localhost:8080/books/7

2.使用TestRestTemplate测试RESTFUL接口

测试类使用@SpringBootTest(webEnvironment=WebEnvironment.RANDOM_PORT)修饰

Spring整合Junit5 出了方法上加@Test之外 还可以使用

@ParameterizedTest
@CsvSource({"Tomcat与Java web,111.0,孙卫琴","Vue.js,128,杜聚宾"})
public void testAddBook2(String name,double price,String author){
    Book book=new Book(null,name,price,author);
    Book resBook = testRestTemplate.postForObject("/books", book, Book.class);
    System.out.println(resBook);
    //使用断言
    Assertions.assertEquals("Spring data jpa", resBook.getName());
    Assertions.assertEquals(129.0, resBook.getPrice());
}


@ParameterizedTest
@ValueSource(ints = {9, 10, 11})
void testIsPositive(Integer id) {
    testRestTemplate.delete("/books/{id}",id);
}

@Test
public void testList(){
    var forObject = testRestTemplate.getForObject("/books", List.class);
    forObject.forEach(System.out::println);

}

测试类

package com.example;

import com.example.pojo.Book;


import lombok.var;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.CsvSource;
import org.junit.jupiter.params.provider.MethodSource;
import org.junit.jupiter.params.provider.ValueSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.web.client.TestRestTemplate;
import org.springframework.util.Assert;

import java.util.List;

//@SpringBootTest
@SpringBootTest(webEnvironment= SpringBootTest.WebEnvironment.RANDOM_PORT)
class Springboot001ApplicationTests {


    @Autowired
    private TestRestTemplate testRestTemplate;

    @Test
    public void testAddBook(){
        Book book=new Book(null,"Spring data jpa",129.0,"xxx");
        Book resBook = testRestTemplate.postForObject("/books", book, Book.class);
        System.out.println(resBook);
        //使用断言
        Assertions.assertEquals("Spring data jpa", resBook.getName());
        Assertions.assertEquals(129.0, resBook.getPrice());
    }

    @ParameterizedTest
    @CsvSource({"Tomcat与Java web,111.0,孙卫琴","Vue.js,128,杜聚宾"})
    public void testAddBook2(String name,double price,String author){
        Book book=new Book(null,name,price,author);
        Book resBook = testRestTemplate.postForObject("/books", book, Book.class);
        System.out.println(resBook);
        //使用断言
        Assertions.assertEquals("Spring data jpa", resBook.getName());
        Assertions.assertEquals(129.0, resBook.getPrice());
    }


    @ParameterizedTest
    @ValueSource(ints = {9, 10, 11})
    void testIsPositive(Integer id) {
        testRestTemplate.delete("/books/{id}",id);
    }

    @Test
    public void testList(){
        var forObject = testRestTemplate.getForObject("/books", List.class);
        forObject.forEach(System.out::println);

    }

//    @ParameterizedTest
//    @MethodSource("xxx某个方法") 有兴趣自己查下


    @Test
    void contextLoads() {
    }

}

3.模拟Web环境测试控制器(暂时理解成测试转发或重定向的一些接口)

不需要真正启动Web服务器,只是对Web环境进行简单的模拟.

使用@SpringBootTest(webEnvironment=WebEnvironment.RANDOM_PORT)

和@AutoConfigureMockMvc修饰测试用例

测试用例类定义接收依赖注入的MockMvc类型的实例变量,通过该实例变量可模拟浏览器来发送请求,获取返回值ModelAndView

新建测试类

package com.example;

import com.example.pojo.Book;
import lombok.var;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.CsvSource;
import org.junit.jupiter.params.provider.ValueSource;
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.boot.test.web.client.TestRestTemplate;
import org.springframework.test.web.servlet.MockMvc;

import java.util.List;


@SpringBootTest(webEnvironment= SpringBootTest.WebEnvironment.RANDOM_PORT)
@AutoConfigureMockMvc
class Springboot001ApplicationTests2 {


    @Autowired
    private MockMvc mockMvc;


}

4.测试Service

package com.example;

import com.example.pojo.Book;
import lombok.var;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.CsvSource;
import org.junit.jupiter.params.provider.ValueSource;
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.boot.test.web.client.TestRestTemplate;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.ResultActions;
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
import org.springframework.web.servlet.ModelAndView;

import java.util.List;


@SpringBootTest(webEnvironment= SpringBootTest.WebEnvironment.RANDOM_PORT)
@AutoConfigureMockMvc
class Springboot001ApplicationTests2 {


    @Autowired
    private MockMvc mockMvc;

    @Test
    public void testIndex() throws Exception {
        //发送请求,获取控制器方法返回的ModelAndView
        ModelAndView mv = mockMvc.perform(MockMvcRequestBuilders.get("/index")).andReturn().getModelAndView();
        Object tip = mv.getModel().get("tip");//放在model的里东西
        Assertions.assertEquals("第一个SpringBoot应用", tip);
        String viewName = mv.getViewName();//返回的视图组件
        Assertions.assertEquals("hello", viewName);
    }

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

hrui0706

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值