SpringBoot程序优点:
起步依赖(简化依赖配置)
自动配置(简化常用工程相关配置)
引导类
springboot的启动方式:
辅助功能(内置服务器,……)
REST(Representational State Transfer): 表现形式状态转换。
REST风格访问资源时使用 行为动作 区分对资源进行了何种操作
RESTful:按照REST风格对资源进行访问。
@RequestMapping
注解的路径设置,通过 @PathVariable
注解绑定参数@PostMapping
@GetMapping
@DeleteMapping
@PutMapping
@RestController
类注解@Controller
与@RresponseBody
组合@RequestBody、 @RequestParam 、 @PathVariable 和 @Vaild 注解的使用及区别
原则:
步骤:
src
目录与pom.xml
文件pom.xml
文件中的artifactId
与新工程/模块名相同SpringBoot内置属性查询: https://docs.spring.io/spring-boot/docs/current/reference/html/application-properties.html#application-properties
SpringBoot配置文件加载顺序: application.properties > application.yml > application.yaml
如果点击不了OK的解决方案:
YAML(YAML Ain’t Markup Language): 一种数据序列化格式。
优点:
YAML文件扩展名:
yaml语法规则:
:
结束#
表示注释字面值表示方式:
boolean: TRUE #TRUE,true,True,FALSE,false,False均可
float: 3.14 #6.8523015e+5 #支持科学计数法
int: 123 #0b1010_0111_0100_1010_1110 #支持二进制、八进制、十六进制
null: ~ #使用~表示null
string: HelloWorld #字符串可以直接书写
string2: "Hello World" #可以使用双引号包裹特殊字符
date: 2022-06-10 #日期必须使用yyyy-MM-dd格式
datetime: 2022-06-10T15:02:31+08:00 #时间和日期之间使用T连接,最后使用+代表时区
数组表示方式:
subject:
- Java
- 前端
- 大数据
enterprise:
name: itcast
age: 16
subject:
- Java
- 前端
- 大数据
likes: [王者荣耀,刺激战场] #数组书写缩略格式
users: #对象数组格式
- name: Tom
age: 4
- name: Jerry
age: 5
users: #对象数组格式二
-
name: Tom
age: 4
-
name: Jerry
age: 5 #对象数组缩略格式
users2: [ { name:Tom , age:4 } , { name:Jerry , age:5 } ]
使用@Value
读取单个数据,属性名引用方式:${一级属性名.二级属性名……}
lesson: SpringBoot
server:
port: 82
enterprise:
name: itcast
age: 16
tel: 4006184000
subject:
- Java
- 前端
- 大数据
@RestController
@RequestMapping("/books")
public class BookController {
@Value("${lesson}")
private String lessonName;
@Value("${server.port}")
private int port;
@Value("${enterprise.subject[1]}")
private String[] subject_01;
}
在配置文件中可以使用属性名引用方式引用属性
baseDir: /usr/local/fire
center:
dataDir: ${baseDir}/data
tmpDir: ${baseDir}/tmp
logDir: ${baseDir}/log
msgDir: ${baseDir}/msgDir
属性值中如果出现转移字符,需要使用双引号包裹
lesson: "Spring\tboot\nlesson"
封装全部数据到Environment对象
lesson: SpringBoot
server:
port: 82
enterprise:
name: itcast
age: 16
tel: 4006184000
subject:
- Java
- 前端
- 大数据
@RestController
@RequestMapping("/books")
public class BookController {
@Value("${lesson}")
private String lessonName;
@Value("${server.port}")
private int port;
@Value("${enterprise.subject[1]}")
private String[] subject_01;
}
自定义对象封装指定数据 @ConfigurationProperties(prefix = "")
lesson: SpringBoot
server:
port: 82
enterprise:
name: itcast
age: 16
tel: 4006184000
subject:
- Java
- 前端
- 大数据
@Component
@ConfigurationProperties(prefix = "enterprise")
public class Enterprise {
private String name;
private Integer age;
private String[] subject;
}
@RestController
@RequestMapping("/books")
public class BookController {
@Autowired
private Enterprise enterprise;
}
导入测试对应的starter:
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-testartifactId>
<scope>testscope>
dependency>
测试类使用@SpringBootTest修饰:
@SpringBootTest
class SpringbootDemo1ApplicationTests {
@Test
void contextLoads() {
}
}
使用自动装配的形式添加要测试的对象(impl实现类)
当路径不一致的时候,如下:
此时测试类就无法依赖注入,需要做以下配置(任选其一):
@SpringBootTest(classes = SpringbootDemo1Application.class)
@ContextConfiguration(classes = SpringbootDemo1Application.class)
导入依赖:
<dependency>
<groupId>org.mybatis.spring.bootgroupId>
<artifactId>mybatis-spring-boot-starterartifactId>
<version>2.1.2version>
dependency>
<dependency>
<groupId>mysqlgroupId>
<artifactId>mysql-connector-javaartifactId>
dependency>
设置数据源参数:
spring:
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/book
username: root
password: root
注意: SpringBoot版本低于2.4.3(不含),Mysql驱动版本大于8.0时,需要在url连接串中配置时区
jdbc:mysql://localhost:3306/ssm_db?serverTimezone=UTC
或在MySQL数据库端配置时区解决此问题
定义实体类:
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Book {
private String name;
private Integer id;
private String type;
private BigDecimal price;
}
定义数据层接口与映射配置:
@Mapper
public interface BookDao {
@Select("select * from book")
public List<User> getAll();
}
测试类中注入dao接口,测试功能:
@SpringBootTest
class Springboot08MybatisApplicationTests {
@Autowired
private BookDao bookDao;
@Test
public void testGetById() {
Book book = bookDao.getById(1);
System.out.println(book);
}
}
https://blog.csdn.net/qq_41402200/article/details/88891511
<dependency>
<groupId>com.alibabagroupId>
<artifactId>druid-spring-boot-starterartifactId>
<version>1.1.22version>
dependency>
spring:
main:
banner-mode: off
datasource:
druid:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/ssm_db?serverTimezone=UTC
username: root
password: root
项目完整目录结构:
项目初始化:
SQL语句:
create database `spbt`;
use `spbt`;
create table `sp_book` (
`id` int primary key auto_increment comment '主键id',
`type` varchar(20) not null comment '书籍类型',
`name` varchar(30) not null comment '书籍名称',
`description` varchar(100) not null comment '书籍描述'
)default charset=utf8 comment '书籍表';
insert into `sp_book`(`type`,`name`,`description`)
values
('科幻','地球往事','《三体》三部曲第一部,作品讲述了地球人类文明和三体文明的信息交流、生死搏杀及两个文明在宇宙中的兴衰历程。'),
('科幻','黑暗森林','《三体》三部曲第二部,作品讲述了地球人类文明和三体文明的信息交流、生死搏杀及两个文明在宇宙中的兴衰历程。'),
('科幻','死神永生','《三体》三部曲第三部,作品讲述了地球人类文明和三体文明的信息交流、生死搏杀及两个文明在宇宙中的兴衰历程。'),
('仙侠','将夜','这本小说讲述的是一段可歌可泣可笑可爱的草根崛起史,一个物质要求宁滥勿缺的开朗少年行。小说基于修真世界,却又胜于修真,讲述了人定胜天,花开彼岸天的历史,引人深思。'),
('仙侠','雪中悍刀行','该小说讲述一个关于庙堂权争与刀剑交错的时代,一个暗潮涌动粉墨登场的江湖。'),
('都市','大国重工','国家重大装备办处长冯啸辰穿越到了1980年,看他如何与同代人一道,用汗水和智慧,铸就大国重工。'),
('架空','赘婿','本书主要讲述了主角从现代金融界巨头的身份回到了古代,进入一个商贾之家最没地位的赘婿身体后,涉及到一系列家国天下事的故事。'),
('科幻','北京折叠','该小说讲述北京在未来按照社会阶层被分成三个空间,生活在第三空间的垃圾工老刀穿越三层空间送信的故事。'),
('鬼怪','地煞七十二变','地煞七十二般变化,每一般变化,就是一项神通。一本神奇的黄壳书将李长安送回古代世界,每斩杀一个妖魔,就获得一项神通。'),
('魔幻','诡秘之主','作品融汇了克苏鲁风格、西方魔幻元素、第一次工业革命时代风情和蒸汽朋克情怀。这是一个蒸汽与机械的世界,这是一段“愚者”的传说。'),
('幻想','第一序列','作品讲述了主角任小粟通过吸收正能量一步步崛起,同时逐渐改变了世界的故事。'),
('人文','明朝那些事儿','作品主要讲述的是从1344年到1644年这三百年间关于明朝的一些故事 。'),
('人文','三国那些事儿','本书分为上下两篇,上篇为读者介绍了三国里的著名人物,下篇讲述了发生在这些人物身上的经典故事。'),
('都市','余罪','警校学生余罪从一场特殊的选拔开始,进入了生活和社会矛盾之中,成为一个卧底,是一种挑战,也是一种难以想象的痛苦生活的开始。'),
('科幻','安德的游戏','第三次虫族入侵已迫在眉睫,而地球舰队尚未找到任何抵抗的可能。世界即将毁灭。人类最后的救世主 ,是一个六岁的儿童——安德。'),
('科幻','死者代言人','安德遭遇了一起残忍而离奇的虐杀事件。安德隐匿身份,再次踏入一个异生物星球。随着调查的深入,他一步步走向异种生物的圈套,而真相,居然与他童年的那段回忆有千丝万缕的联系……'),
('科幻','安德的影子','当安德和队员们全力以赴挑战最后的难关时,只有一人早已知晓这背后残酷的真相。他是影子,在英雄如阳光照射大地之时,只有影子能承接必然尾随而至的黑暗。'),
('惊悚','我有一座冒险屋','作该作品讲述主人公陈歌在翻旧物时寻得黑色手机,在手机的指引下探寻世界的另一面。'),
('科幻','星门','传说,在那古老的星空深处,伫立着一道血与火侵染的红色之门。'),
('仙侠','凡人修仙传','小说讲述了一个普通的山村穷小子,偶然之下,跨入到一个江湖小门派,虽然资质平庸,但依靠自身努力和合理算计最后修炼成仙的故事。'),
('惊悚','地狱公寓','在这公寓内,如果住户房间的墙壁上出现了血字,住户就必须完成血字任务,一旦违背就会死亡。'),
('仙侠','求魔','该书主要讲述了主角苏铭不甘命运被掌控,与命运斗争的故事。修仙觅长生,热血任逍遥,踏莲曳波涤剑骨,凭虚御风塑圣魂。'),
('仙侠','仙逆','作该小说讲述的是一个平庸的少年,踏入仙途,如何一步一步走向巅峰,凭一己之力扬名修真界的故事。'),
('诗集','炸裂志','陈年喜以其平实婉转的文字,在诗句中建构了一个中年男人的世界,以白雪抗衡黑洞,以爱感悟生死,以诗超越世间。'),
('仙侠','大奉打更人','作者巧妙地将俗世朝堂背景,百家文化与仙侠修炼结合起来,并设计了一个个精妙的案件作为引线,一步步展现出了一个波澜壮阔的全新世界');
创建实体类:
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Book {
private Integer id;
private String type;
private String name;
private String description;
}
配置数据源:
spring:
datasource:
druid:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/spbt?serverTimezone=UTC
username: root
password: admin
mybatis-plus:
global-config:
db-config:
# 表前缀
table-prefix: sp_
# 设置数据库的自增策略
id-type: auto
# 开启mybatis-plus的运行日志
configuration:
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
注意: mybatis-plus不用提交事务。
mapper接口:
@Mapper
public interface QueryBookMapper extends BaseMapper<Book> {
}
测试类:
@SpringBootTest
public class BookMapperTests {
@Autowired
private BookMapper mapper;
@Test
void testGetById() {
System.out.println(mapper.selectById(1));
}
@Test
void testGetAll() {
System.out.println(mapper.selectList(null));
}
@Test
void testSave() {
Book book = new Book();
book.setName("一念永恒");
book.setType("仙侠");
book.setDescription("一念成沧海,一念化桑田。一念斩千魔,一念诛万仙。");
mapper.insert(book);
}
@Test
void testUpdate() {
Book book = new Book();
book.setId(20);
book.setDescription("韩老魔的杀人夺宝一路升级的传奇故事");
mapper.updateById(book);
}
@Test
void testDelet() {
mapper.deleteById(26);
}
}
/*分页查询*/
@Test
void testGetPage() {
IPage page = new Page(2,5);
mapper.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());
}
分页查询工具类
@Configuration
public class MPConfig {
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
interceptor.addInnerInterceptor(new PaginationInnerInterceptor());
return interceptor;
}
}
QueryWrapper
对象封装查询条件,推荐使用LambdaQueryWrapper
对象,所有查询操作封装成方法调用 /*条件*/
@Test
void testGetBy() {
/* 一般写法
QueryWrapper qw = new QueryWrapper<>();
qw.like("type","仙");
mapper.selectList(qw);*/
/*Lambda写法*/
String type = "仙";
LambdaQueryWrapper<Book> lqw = new LambdaQueryWrapper<>();
lqw.like(type!=null, Book::getType, type);
mapper.selectList(lqw);
}
业务接口:
public interface BookService {
Boolean save(Book book);
Boolean update(Book book);
Boolean delete(Integer id);
Book getById(Integer id);
List<Book> getAll();
IPage<Book> getPage(int currentPage, int pageSize);
}
实现类:
@Service
public class BookServiceImpl implements BookService {
@Resource
BookMapper mapper;
@Override
public Boolean save(Book book) {
return mapper.insert(book) > 0;
}
@Override
public Boolean update(Book book) {
return mapper.updateById(book) > 0;
}
@Override
public Boolean delete(Integer id) {
return mapper.deleteById(id) > 0;
}
@Override
public Book getById(Integer id) {
return mapper.selectById(id);
}
@Override
public List<Book> getAll() {
return mapper.selectList(null);
}
@Override
public IPage<Book> getPage(int currentPage, int pageSize) {
IPage page = new Page(currentPage, pageSize);
mapper.selectPage(page, null);
return page;
}
}
选中实体类名,Ctrl shift t 快速创建测试类
@SpringBootTest
public class BookServiceImplTest {
@Resource
BookServiceImpl bookService;
@Test
void save() {
Book book = new Book();
book.setName("诛仙");
book.setType("仙侠");
book.setDescription("天地不仁,以万物为刍狗");
bookService.save(book);
}
@Test
void update() {
Book book = new Book();
book.setId(5);
book.setDescription("高人雅士、王者之痴、匹夫之怒、美人之勇、凡人琐事");
bookService.update(book);
}
@Test
void delete() {
bookService.delete(27);
}
@Test
void getById() {
bookService.getById(5);
}
@Test
void getAll() {
bookService.getAll();
}
@Test
void getPage() {
IPage<Book> page = bookService.getPage(2,5);
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());
}
}
接口:
public interface IBookService extends IService<Book> {
}
实现类:
@Service
public class IBookServiceImpl extends ServiceImpl<BookMapper, Book> implements IBookService {
}
测试类:
@SpringBootTest
class IBookServiceImplTest {
@Resource
private IBookServiceImpl iBookService;
@Test
void testGetById() {
System.out.println(iBookService.getById(1));
}
@Test
void testGetAll() {
System.out.println(iBookService.list(null));
}
@Test
void testSave() {
Book book = new Book();
book.setName("重生之超级战舰");
book.setType("科幻");
book.setDescription("探索宇宙之中的奥秘,和系外行星,各种恒星,白矮星,中子星,黑洞,类星体等进行亲密接触,和各种宇宙文明进行血腥厮杀,探寻被隐藏在重重迷雾之后的宇宙真理……");
iBookService.save(book);
}
@Test
void testUpdate() {
Book book = new Book();
book.setId(20);
book.setDescription("韩老魔的杀人夺宝一路升级的传奇故事");
iBookService.updateById(book);
}
@Test
void testDelet() {
iBookService.removeById(26);
}
/*分页*/
@Test
void testGetPage() {
IPage<Book> page = new Page<>(2,5);
iBookService.page(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());
}
}
注意: 如果有特殊的业务需求,可以在 IBookService 中重写方法。
使用REST风格写接口:
@RestController
@RequestMapping("/books")
public class BookController {
@Resource
private IBookService iBookService;
@GetMapping
public List<Book> getAll() {
return iBookService.list(null);
}
@PostMapping
public Boolean save(@RequestBody Book book){
return iBookService.save(book);
}
@PutMapping
public Boolean update(@RequestBody Book book){
return iBookService.updateById(book);
}
@DeleteMapping("{id}")
public Boolean delete(@PathVariable Integer id){
return iBookService.removeById(id);
}
@GetMapping("{id}")
public Book getById(@PathVariable Integer id){
return iBookService.getById(id);
}
@GetMapping("{currentPage}/{pageSize}")
public IPage<Book> getPage(@PathVariable int currentPage, @PathVariable int pageSize){
IPage<Book> page = new Page<>(currentPage,pageSize);
iBookService.page(page,null);
return page;
}
}
本文采用的测试工具是: ApiPost
接口测试目录文档: https://console-docs.apipost.cn/preview/7f61bffaaafd5a1c/44eae2dee5dca510
设计表现层返回结果的模型类,用于后端与前端进行数据格式统一,也称为前后端数据协议。
工具类:
@Data
@AllArgsConstructor
@NoArgsConstructor
public class R {
// 标志接口是否成功执行
private Boolean flag;
// 调用接口返回数据格式
private Object data;
public R(Boolean flag) {
this.flag = flag;
}
}
升级版的表现层:
@RestController
@RequestMapping("/books")
public class BookControllerPro {
@Resource
private IBookService iBookService;
@GetMapping
public R getAll() {
return new R(true, iBookService.list());
}
@PostMapping
public R save(@RequestBody Book book){
return new R(iBookService.save(book));
}
@PutMapping
public R update(@RequestBody Book book){
return new R(iBookService.updateById(book));
}
@DeleteMapping("{id}")
public R delete(@PathVariable Integer id){
return new R(iBookService.removeById(id));
}
@GetMapping("{id}")
public R getById(@PathVariable Integer id){
return new R(true, iBookService.getById(id));
}
@GetMapping("{currentPage}/{pageSize}")
public R getPage(@PathVariable int currentPage, @PathVariable int pageSize){
IPage<Book> page = new Page<>(currentPage,pageSize);
return new R(true, iBookService.page(page,null));
}
}
工具类:
@Data
@AllArgsConstructor
@NoArgsConstructor
public class R {
// 标志接口是否成功执行
private Boolean flag;
// 调用接口返回数据格式
private Object data;
// 返回状态信息
private String msg;
public R(Boolean flag) {
this.flag = flag;
}
public R(Boolean flag, Object data) {
this.flag = flag;
this.data = data;
}
public R(Boolean flag, String msg) {
this.flag = flag;
this.msg = msg;
}
}
@RestControllerAdvice
public class ProjectExceptionAdvice {
@ExceptionHandler
public R doException(Exception e) {
return new R(false, "服务器故障,稍后再试");
}
}
新增接口修改:
@PostMapping
public R save(@RequestBody Book book){
boolean flag = iBookService.save(book);
return new R(flag, flag ? "新增成功" : "新增失败");
}
前端save接口调用:
//添加
handleAdd () {
axios.post("/books", this.formData).then((res) => {
// 判断是否添加成功
if (res.data.flag) {
// 关闭弹窗
this.dialogFormVisible = false;
this.$message({
message: '新增成功',
type: 'success'
});
} else {
// this.$message.error('新增失败');
this.$message.error(res.data.msg);
}
}).finally(() => {
// 重新加载一下数据
this.getAll();
})
},
项目代码地址:[email protected]:Crashinging/ssmp.git
本部分到此为止了…