SpringBoot是Pivotal团队提供的全新框架,其设计目的是用来简化Spring应用的初始搭建以及开发过程
//Rest模式
@RestController
@RequestMapping("/books")
public class BookController {
@GetMapping
public String getById(){
System.out.println("springboot is running ...");
return "springboot is running";
}
}
1. 打开SpringBoot官网,选择Quickstart Your Project
2.创建工程,并保存项目
3.解压项目,通过IDE导入项目
小技巧:
起步依赖(简化依赖配置)
自动配置(简化常用工程相关配置)
辅助功能(内置服务器,……)
1.开发SpringBoot程序要继承spring-boot-starter-parent
2.spring-boot-starter-parent中定义了若干个依赖管理
3.继承parent模块可以避免多个依赖使用相同技术时出现依赖版本冲突
4.继承parent的形式也可以采用引入依赖的形式实现效果
org.springframework.boot
spring-boot-starter-parent
3.0.0
点进去:(Ctrl+B)
org.springframework.boot
spring-boot-dependencies
3.0.0
再点进去:(Ctrl+B)
会发现定义了很多版本控制以及依赖
SpringBoot中常见项目名称,定义了当前项目使用的所有依赖坐标,以达到减少依赖配置的目的
和parent比较:
parent:所有Springboot项目要继承的项目,定义了若干个坐标版本号(依赖管理,而非依赖),以达到减少依赖冲突的目的
spring-boot-starter-parent各版本间存在着诸多坐标版本不同
starter小结:
1.开发springboot程序需要导入坐标时通常导入对应的starter
2.每个不同的starter根据功能不同,通常包含多个依赖坐标
3.使用starter可以实现快速配置的效果,达到简化配置的目的
1.SpringBoot工程提供引导类用来启动程序
2.SpringBoot工程启动后创建并初始化Spring容器
@SpringBootApplication
public class Demo1Application {
public static void main(String[] args) {
SpringApplication.run(Demo1Application.class, args);
}
}
SpringBoot的引导类是Boot工程的执行入口,运行main方法就可以启动项目
SpringBoot工程运行后初始化Spring容器,扫描引导类所在包加载bean
内嵌tomcat工作原理是将tomcat服务器作为对象运行,并将该对象交给Spring容器管理
org.springframework.boot
spring-boot-starter-tomcat
3.0.0
compile
点进去,有内嵌的tomcat服务器:
org.apache.tomcat.embed
tomcat-embed-core
10.1.1
compile
tomcat-annotations-api
org.apache.tomcat
springboot内置服务器:
tomcat(默认):apache出品,粉丝多,应用面广,负载了若干较重的组件
jetty:更轻量级,负载性能远不及tomcat
undertow:负载性能勉强能跑赢tomcat
REST:表现形式状态转换
传统风格资源描述形式:
http://localhost/user/getById?id=1
http://localhost/user/saveUser
REST风格描述形式:
http://localhost/user/1
http://localhost/user
优点:
1.隐藏资源的访问行为,无法通过地址得知对资源是何种操作
2.书写简化
@RequestBody @RequestParam @PathVariable
区别:
@RequestParam用于接收url地址传参或表单传参
@RequestBody用于接收json数据
@PathVariable用于接收路径参数,使用{参数名称}描述路径参数
应用:
后期开发中,发送请求参数超过1个时,以json格式为主,@RequestBody应用较广
如果发送非json格式数据,选用@RequestParam接受请求参数
采用RESTful进行开发时,当参数数量较少时,例如1个,可以采用@PathVariable接收请求路径变量,通常用于传递id值
package com.itheima.controller;
import com.itheima.User;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;
//Rest模式
@Controller
@ResponseBody
public class UserController {
@RequestMapping(value="/users",method= RequestMethod.POST)
public String save(){
System.out.println("user save");
return "user save";
}
@RequestMapping(value="/users/{id}",method=RequestMethod.DELETE)
public String delete(@PathVariable Integer id){
System.out.println(" user delete "+id);
return "user delete";
}
@RequestMapping(value="/users",method=RequestMethod.PUT)
public String update(@RequestBody User user){
System.out.println("user update..."+user);
return "user update";
}
@RequestMapping(value="/users/{id}",method=RequestMethod.GET)
public String getById(@PathVariable Integer id){
System.out.println("user getById"+id);
return "getById";
}
@RequestMapping(value="/users",method=RequestMethod.GET)
public String getUsers(){
System.out.println("users");
return "getUsers";
}
}
对入门案例简化开发
package com.itheima.controller;
import com.itheima.User;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;
//Rest模式
@RestController
@RequestMapping("/users")
public class UserController {
@PostMapping
public String save(){
System.out.println("user save");
return "user save";
}
@DeleteMapping("/{id}")
public String delete(@PathVariable Integer id){
System.out.println(" user delete "+id);
return "user delete";
}
@PutMapping
public String update(@RequestBody User user){
System.out.println("user update..."+user);
return "user update";
}
@GetMapping("/{id}")
public String getById(@PathVariable Integer id){
System.out.println("user getById"+id);
return "getById";
}
@GetMapping
public String getUsers(){
System.out.println("users");
return "getUsers";
}
}
原则:
保留工程基础结构
抹掉原始工程痕迹
①复制一份副本文件
②删掉除了src和pom.xml以外的文件
③进入idea,导入一个新模块
记得勾选maven项目:
小结:
修改服务器端口
SpringBoot默认配置文件application.properties,通过键值对配置对应属性
# 服务器端口配置
server.port=80
更多配置:
# 服务器端口配置
server.port=80
#修改banner
#spring.main.banner-mode=off
#日志
#logging.level.root=debug
#logging.level.root=error
SpringBoot提供了多种属性配置方式
application.properties
application.yml (主流格式)
application.yaml
优先级:.properties>.yml>.yaml
不同那个配置文件中相同配置按照加载优先级相互覆盖,不同配置文件中不同配置全部保留
YAML:一种数据序列化格式
优点:
容易阅读
容易与脚本语言交互
以数据为核心,重数据轻格式
YAML文件扩展名:
.yml(主流)
.yaml
yml语法规则
①大小写敏感
②属性层级关系使用多行描述,每行结尾时用冒号结束
③属性值前面添加空格(属性名与属性值之间使用冒号+空格作为分隔)
④#表示注释
⑤使用缩进标识层级关系,同层级左侧对齐,只允许使用空格(不允许使用Tab键)
country: china
province: beijing
city: beijing
area: haidian
port: 8080
party: true
birthday: 1949-10-1
user:
name: itcast
age: 16
likes:
- game
- music
- sleep
likes2: [game,music,sleep]
users:
- name: zhangsan
age: 18
- name: lisi
age: 17
users2:
-
name: zhangsi
age: 19
-
name: lisan
age: 25
users3: [{name:zhangsan,age:lisi},{name:lisi,age:17}]
使用@Value配合SpEL读取单个数据
如果数据存在多层级,依次书写层级名称即可
//Rest模式
@RestController
@RequestMapping("/users")
public class UserController {
@Value("${country}")
private String country;
@Value("${user1.name}")
private String name;
@Value("${likes[2]}")
private String likes1;
@Value("${users[1].age}")
private int age;
@GetMapping
public String getCountry(){
System.out.println("country--->"+country);
System.out.println("name--->"+name);
System.out.println("likes1--->"+likes1);
System.out.println("age--->"+age);
return "springboot``";
}
}
在配置文件中可以使用${属性名}方式引用属性值
如果属性中出现特殊字符,可以使用双引号包裹起来作为字符解析
baseDir: c:\windows
tempDir: ${baseDir}\temp
使用Environment对象封装全部配置信息
使用@Autowired自动装配数据到Environment对象中
//使用自动装配将所有的数据封装到一个对象Environment中
@Autowired
private Environment env;
@GetMapping("/env")
public String getEnv(){
System.out.println(env.getProperty("country"));
return "env";
}
1.使用@ConfigurationProperties注解绑定配置信息到封装类中
2.封装类需要定义为Spring管理的bean,否则无法进行属性注入
#创建类,用于封装下面的数据
#由spring帮我们去加载数据到对象中,一定要告诉spring加载这组信息
#使用的时候从spring中直接获取信息使用
datasource:
driver: com.myswl.cj.jdbc.Driver
url: jdbc:mysql://localhost/db_springboot
username: root
password: root
package com.itheima;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
//1.定义数据模型封装yaml文件中对应的数据
//2.定义为spring管控的bean
@Component
//3.指定加载的数据
@ConfigurationProperties(prefix="datasource")
public class MyDataSource {
private String driver;
private String url;
private String username;
private String password;
public MyDataSource(){}
public MyDataSource(String driver, String url, String username, String password) {
this.driver = driver;
this.url = url;
this.username = username;
this.password = password;
}
public String getDriver() {
return driver;
}
public void setDriver(String driver) {
this.driver = driver;
}
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
@Override
public String toString() {
return "MyDataSource{" +
"driver='" + driver + '\'' +
", url='" + url + '\'' +
", username='" + username + '\'' +
", password='" + password + '\'' +
'}';
}
}
测试:
@Autowired
private MyDataSource myDataSource;
@GetMapping("/datasource")
public String getMyDatasource(){
System.out.println(myDataSource);
return "source";
}
①简单的junit使用小案例
1.导入测试对应的starter
2.测试类使用@SpringBootTest修饰
3.使用自动装配的形式添加要测试的对象
public interface BookDao {
public void save();
}
@Repository
public class BookDaoImpl implements BookDao {
@Override
public void save(){
System.out.println("book dao is running...");
}
}
@SpringBootTest
class SpringbootJunitApplicationTests {
//1.注入你要测试的对象
//2.执行要测试的对象对应的方法
@Autowired
private BookDao bookDao;
@Test
void testSave(){
bookDao.save();
}
@Test
void contextLoads() {
System.out.println("test...");
}
}
②问题:当测试类不在引导类所在包及其子包下,测试无法通过
解决方法:
a)用@SpringBootTest 显式的写出引导类
@SpringBootTest(classes= SpringbootJunitApplication.class)
class SpringbootJunitApplicationTests {
//1.注入你要测试的对象
//2.执行要测试的对象对应的方法
@Autowired
private BookDao bookDao;
@Test
void testSave(){
bookDao.save();
}
@Test
void contextLoads() {
System.out.println("test...");
}
}
b)使用@ContextConfiguration
@SpringBootTest
@ContextConfiguration(classes=SpringbootJunitApplication.class)
class SpringbootJunitApplicationTests {
//1.注入你要测试的对象
//2.执行要测试的对象对应的方法
@Autowired
private BookDao bookDao;
@Test
void testSave(){
bookDao.save();
}
@Test
void contextLoads() {
System.out.println("test...");
}
}
核心配置:数据库连接相关信息(连什么、连谁、什么权限)
映射配置:SQL映射(XML/注解)
①整合MyBatis需要在创建模块/工程的时候在SQL中勾选:
MySQL Driver
MyBatis Framework
=====>导入对应的stater
org.mybatis.spring.boot
mybatis-spring-boot-starter
3.0.0
com.mysql
mysql-connector-j
runtime
②设置数据源参数
#2.配置相关信息
spring:
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/db_springboot
username: root
password: root
③创建实体类
public class Book {
private Integer id;
private String type;
private String name;
private String description;
……
}
④创建dao(定义数据层接口与映射配置)
数据库SQL映射需要添加@Mapper被容器识别到
@Mapper
public interface BookDao {
@Select("select * from tb_book where id=#{id}")
public Book getById(Integer id);
}
⑤测试
@SpringBootTest
class MybatisDemoApplicationTests {
@Autowired
private BookDao bookDao;
@Test
public void testBookDao(){
Book book = bookDao.getById(1);
System.out.println(book);
}
}
测试结果:
可能遇到的问题
MyBatis-Plus与MyBatis区别:
导入坐标不同
数据层实现简化
①创建模块的时候修改服务器URL
②选择关系型数据库,添加依赖
如果不想执行上述①②步,也可以直接手动导入坐标
com.baomidou
mybatis-plus-boot-starter
3.4.2
同时去掉坐标:
org.springframework.boot
spring-boot-starter
③配置数据源
spring:
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/db_springboot
username: root
password: root
mybatis-plus:
global-config:
db-config:
table-prefix: tb_
④配置实体类(和MyBatis一样)
⑤dao层
@Mapper
public interface BookDao extends BaseMapper {
}
⑤测试
@SpringBootTest
class MybatisPlusApplicationTests {
@Autowired
private BookDao bookDao;
@Test
void contextLoads() {
System.out.println(bookDao.selectById(2));
}
}
①自行导入Druid的坐标
com.alibaba
druid
1.2.11
②配置数据源
spring:
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/db_springboot
username: root
password: 0529Love
type: com.alibaba.druid.pool.DruidDataSource
测试:
@SpringBootTest
class MybatisDemoApplicationTests {
@Autowired
private BookDao bookDao;
@Test
public void testBookDao(){
Book book = bookDao.getById(2);
System.out.println(book);
}
}
测试通过~
1.勾选SpringMVC与MySQL坐标
2.修改配置文件为yml格式
3.设置端口为80方便访问
需要手动导入添加的依赖:
com.baomidou
mybatis-plus-boot-starter
3.4.2
com.alibaba
druid-spring-boot-starter
1.1.9
org.projectlombok
lombok
注解@Data:
为当前实体类在编译期设置对应的get/set方法,toString方法,hashCode方法,equals方法等
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Book {
@TableId(type= IdType.AUTO)
private Integer id;
private String type;
private String name;
private String description;
}
server:
port: 80
spring:
datasource:
druid:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/db_springboot?serverTimezone=UTC
username: root
password: root
mybatis-plus:
global-config:
db-config:
table-prefix: tb_
create table tb_book(
id int primary key auto_increment,
type varchar(30) not null,
name varchar(30) not null,
description varchar(255)
)auto_increment=1;
insert into tb_book(type,name,description) values
('计算机理论','Spring实战 第五版','Spring入门经典教程,深入理解Spring原理技术内幕');
insert into tb_book(type,name,description) values
('计算机理论','Spring实战 核心原理','Spring入门经典教程,深入理解Spring原理技术内幕');
insert into tb_book(type,name,description) values
('计算机理论','Spring实战 设计模式','Spring入门经典教程,深入理解Spring原理技术内幕');
insert into tb_book(type,name,description) values
('计算机理论','Spring实战 入门到开发','Spring入门经典教程,深入理解Spring原理技术内幕');
insert into tb_book(type,name,description) values
('计算机理论','Java核心技术卷','Spring入门经典教程,深入理解Spring原理技术内幕');
使用配置方式开启日志,设置日志输出方式为标准输出
mybatis-plus:
configuration:
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
效果:
分页操作需要设定分页对象IPage
IPage对象中封装了分页操作中的所有数据
数据值
当前页码值
每页数据总量
最大页码值(总页码值)
数据总量
配置类:
@Configuration
public class MPConfig {
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor(){
MybatisPlusInterceptor interceptor=new MybatisPlusInterceptor();
interceptor.addInnerInterceptor(new PaginationInnerInterceptor());
return interceptor;
}
}
测试实例:
@Test
void testGetPage(){
IPage page=new Page(1,3);
bookDao.selectPage(page,null);
}
解释:
bookDao.selectPage(page,null);调用结束后返回的仍然是IPage对象的实例,有如下方法:
分别打印输出可得:
@Test
void testGetPage(){
IPage page=new Page(1,3);
bookDao.selectPage(page,null);
System.out.println(page.getCurrent());
System.out.println(page.getSize());
System.out.println(page.getTotal());
System.out.println(page.getPages());
System.out.println(page.getRecords());
}
1.使用QueryWrapper对象封装查询条件
2.推荐使用LambdaQueryWrapper对象
3.所有查询操作封装成方法调用
4.查询条件支持动态条件拼接
@Test
void testLambdaQueryWrapper(){
LambdaQueryWrapper wrapper=new LambdaQueryWrapper<>();
wrapper.like(Book::getName,"Spring");
bookDao.selectList(wrapper);
}
如果传入的判断条件为null,sql会直接将null认为是字符串直接拼接,所以需要做处理:
如果不满足条件,则不会进行此次like xxx拼接
@Test
void testLambdaQueryWrapper(){
String name=null;
LambdaQueryWrapper wrapper=new LambdaQueryWrapper<>();
wrapper.like(name!=null,Book::getName,name);
bookDao.selectList(wrapper);
}
Service层接口定义与数据层接口定义具有较大的区别,不要混用
selectByUserNameAndPassword(String username,String password);
login(String username,String password);
1.Service接口名称定义为业务名称,并与Dao接口名称进行区分
2.制作测试类测试Service功能是否有效
public interface BookService {
boolean save(Book book);
boolean update(Book book);
boolean delete(Integer id);
Book getById(Integer id);
List getAll();
IPage getPage(int currentPage,int pageSize);
}
@Service
public class bookServiceImpl implements BookService {
@Autowired
private BookDao bookDao;
@Override
public boolean save(Book book) {
return bookDao.insert(book)>0;
}
@Override
public boolean update(Book book) {
return bookDao.updateById(book)>0;
}
@Override
public boolean delete(Integer id) {
return bookDao.deleteById(id)>0;
}
@Override
public Book getById(Integer id) {
return bookDao.selectById(id);
}
@Override
public List getAll() {
return bookDao.selectList(null);
}
@Override
public IPage getPage(int currentPage, int pageSize) {
IPage page=new Page<>(currentPage,pageSize);
return bookDao.selectPage(page,null);
}
}
@SpringBootTest
public class BookServiceCase {
@Autowired
private BookService bookService;
@Test
void testGetById(){
System.out.println(bookService.getById(4));
}
@Test
void testSave(){
Book book=new Book(null,"悬疑","盗墓笔记","南派三叔匠心制作");
System.out.println(bookService.save(book));
}
@Test
void update(){
Book book=new Book();
book.setId(4);
book.setDescription("入门神作");
bookService.update(book);
}
@Test
void testGetPage(){
IPage page=bookService.getPage(2,2);
System.out.println(page.getTotal());
System.out.println(page.getSize());
System.out.println(page.getPages());
System.out.println(page.getCurrent());
System.out.println(page.getRecords());
}
快速开发方案:
使用MyBatisPlus提供有业务层通用接口(IService
)与业务层通用实现类(ServiceImpl )) 在通用类基础上做功能重载或功能追加
注意重载时不要覆盖原始操作,避免原始提供的功能丢失
业务层接口:
public interface IBookService extends IService {
}
业务层实现类:
@Service
public class BookServiceImpl extends ServiceImpl implements IBookService {
}
测试用例:
@SpringBootTest
public class BookServiceTest {
@Autowired
private IBookService iBookService;
@Test
void testSave(){
Book book=new Book(null,"游戏","全职高手","人生有梦,各自精彩");
iBookService.save(book);
}
@Test
void testUpdate(){
Book book=new Book();
book.setId(8);
book.setDescription("这一次回国,我会夺回属于我的一切");
iBookService.updateById(book);
}
@Test
void testDelete(){
iBookService.removeById(8);
}
@Test
void testGetAll(){
List list = iBookService.list();
list.forEach(System.out::println);
}
@Test
void testGetPage(){
IPage page=new Page<>(2,3);
iBookService.page(page);
System.out.println(page.getRecords());
}
}
基于Restful进行表现层接口开发
新增:POST
删除:DELETE
修改:PUT
查询:GET
基于Postman测试表现层接口功能
实体数据:@RequestBody
路径变量:@PathVariable
@RestController
@RequestMapping("/books")
public class BookController {
@Autowired
private IBookService bookService;
@GetMapping
public List getAll(){
return bookService.list();
}
@PostMapping
public Boolean save(@RequestBody Book book){
return bookService.save(book);
}
@PutMapping
public Boolean update(@RequestBody Book book){
return bookService.updateById(book);
}
@DeleteMapping("/{id}")
public Boolean delete(@PathVariable("id") Integer id){
return bookService.removeById(id);
}
@GetMapping("/{id}")
public Book getById(@PathVariable("id") Integer id){
return bookService.getById(id);
}
}
getPage功能:
IBookService.java
public interface IBookService extends IService {
IPage getPage(int currentPage,int pageSize);
}
BookServiceImpl.java
@Service
public class BookServiceImpl extends ServiceImpl implements IBookService {
@Autowired
private BookDao bookDao;
@Override
public IPage getPage(int currentPage, int pageSize) {
IPage page=new Page<>(currentPage,pageSize);
bookDao.selectPage(page,null);
return page;
}
}
BookController.java
@GetMapping("/{currentPage}/{pageSize}")
public IPage getPage(@PathVariable int currentPage,@PathVariable int pageSize){
return bookService.getPage(currentPage, pageSize);
}
设计表现层返回结果的模型类,用于后端与前端进行数据格式统一,也称为前后端数据协议
@Data
@NoArgsConstructor
@AllArgsConstructor
public class R {
private Boolean flag;
private Object data;
public R(Boolean flag){
this.flag=flag;
}
}
BookController.java
@RestController
@RequestMapping("/books")
public class BookController {
@Autowired
private IBookService bookService;
@GetMapping
public R getAll(){
return new R(true,bookService.list());
}
@PostMapping
public R save(@RequestBody Book book){
return new R(bookService.save(book));
}
@PutMapping
public R update(@RequestBody Book book){
return new R(bookService.updateById(book));
}
@DeleteMapping("/{id}")
public R delete(@PathVariable("id") Integer id){
return new R(bookService.removeById(id));
}
@GetMapping("/{id}")
public R getById(@PathVariable("id") Integer id){
return new R(true,bookService.getById(id));
}
@GetMapping("/{currentPage}/{pageSize}")
public R getPage(@PathVariable int currentPage,@PathVariable int pageSize){
return new R(true,bookService.getPage(currentPage,pageSize));
}
}
前后端分离结构设计中页面归属前端服务器
单体工程中页面放置在resources目录下的static目录中(建议执行clean)
前端没学,不会,TBC……