赞
踩
学习要求
环境要求
学习资料
Java基础语法
Spring与SpringMVC
知道Spring是用来管理bean,能够基于Restful实现页面请求交互功能
Mybatis与Mybatis-Plus
基于Mybatis和MybatisPlus能够开发出包含基础CRUD功能的标准Dao模块
数据库MySQL
能够读懂基础CRUD功能的SQL语句
服务器
知道服务器与web工程的关系,熟悉web服务器的基础配置
maven
知道maven的依赖关系,知道什么是依赖范围,依赖传递,排除依赖,可选依赖,继承
web技术(含vue,ElementUI)
知道vue如何发送ajax请求,如何获取响应数据,如何进行数据模型双向绑定
①:创建新模块,选择Spring Initializr,并配置模块相关基础信息
②:选择当前模块需要使用的技术集
③:开发控制器类
//Rest 模式
@RestController
@RequestMapping("/books")
public class BookController {
@GetMapping
public String getById() {
System.out.println("springboot is running...");
return "springboot is running...";
}
}
④:运行自动生成的Application类
⑤:打开浏览器访问url地址为:http://localhost:8080/books
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.5.6</version> </parent> <groupId>com.example</groupId> <artifactId>springboot-01-quickstart</artifactId> <version>0.0.1-SNAPSHOT</version> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> </dependencies> </project>
@SpringBootApplication
public class Springboot0101QuickstartApplication {
public static void main(String[] args) {
SpringApplication.run(Springboot0101QuickstartApplication.class, args);
}
}
小结:
小结:
注意事项:
小结:
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.5.6</version> </parent> <groupId>com.example</groupId> <artifactId>springboot_01_04_quickstart</artifactId> <version>1.0-SNAPSHOT</version> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> </dependencies> </project>
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
小结:
总结:
2018版的做法:
较新版本的做法 :
小结:
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.5.6</version> </parent> <groupId>com.example</groupId> <artifactId>springboot-01-quickstart</artifactId> <version>0.0.1-SNAPSHOT</version> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> </dependencies> </project>
按住Ctrl点击pom.xml中的spring-boot-starter-parent,跳转到了spring-boot-starter-parent的pom.xml,xml配置如下(只摘抄了部分重点配置):
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>2.5.6</version>
</parent>
按住Ctrl点击pom.xml中的spring-boot-starter-dependencies,跳转到了spring-boot-starter-dependencies的pom.xml,xml配置如下(只摘抄了部分重点配置):
<properties> <activemq.version>5.15.3</activemq.version> <antlr2.version>2.7.7</antlr2.version> <appengine-sdk.version>1.9.63</appengine-sdk.version> <artemis.version>2.4.0</artemis.version> <aspectj.version>1.8.13</aspectj.version> <assertj.version>3.9.1</assertj.version> <atomikos.version>4.0.6</atomikos.version> <bitronix.version>2.1.4</bitronix.version> <build-helper-maven-plugin.version>3.0.0</build-helper-maven-plugin.version> <byte-buddy.version>1.7.11</byte-buddy.version> ... ... ... </properties> <dependencyManagement> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot</artifactId> <version>2.0.1.RELEASE</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-test</artifactId> <version>2.0.1.RELEASE</version> </dependency> ... ... ... </dependencies> </dependencyManagement> <build> <pluginManagement> <plugins> <plugin> <groupId>org.jetbrains.kotlin</groupId> <artifactId>kotlin-maven-plugin</artifactId> <version>${kotlin.version}</version> </plugin> <plugin> <groupId>org.jooq</groupId> <artifactId>jooq-codegen-maven</artifactId> <version>${jooq.version}</version> </plugin> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> <version>2.0.1.RELEASE</version> </plugin> ... ... ... </plugins> </pluginManagement> </build>
从上面的spring-boot-starter-dependencies的pom.xml中我们可以发现,一部分坐标的版本、依赖管理、插件管理已经定义好,所以我们的SpringBoot工程继承spring-boot-starter-parent后已经具备版本锁定等配置了。所以起步依赖的作用就是进行依赖的传递。
小结:
<?xml version="1.0" encoding="UTF-8"?> <project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> <modelVersion>4.0.0</modelVersion> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starters</artifactId> <version>2.0.1.RELEASE</version> </parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> <version>2.0.1.RELEASE</version> <name>Spring Boot Web Starter</name> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter</artifactId> <version>2.0.1.RELEASE</version> <scope>compile</scope> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-json</artifactId> <version>2.0.1.RELEASE</version> <scope>compile</scope> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-tomcat</artifactId> <version>2.0.1.RELEASE</version> <scope>compile</scope> </dependency> <dependency> <groupId>org.hibernate.validator</groupId> <artifactId>hibernate-validator</artifactId> <version>6.0.9.Final</version> <scope>compile</scope> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-web</artifactId> <version>5.0.5.RELEASE</version> <scope>compile</scope> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> <version>5.0.5.RELEASE</version> <scope>compile</scope> </dependency> </dependencies> </project>
从上面的spring-boot-starter-web的pom.xml中我们可以发现,spring-boot-starter-web就是将web开发要使用的spring-web、spring-webmvc等坐标进行了“打包”,这样我们的工程只要引入spring-boot-starter-web起步依赖的坐标就可以进行web开发了,同样体现了依赖传递的作用。
小结:
@SpringBootApplication
public class Springboot0101QuickstartApplication {
public static void main(String[] args) {
ConfigurableApplicationContext ctx = SpringApplication.run(Springboot0101QuickstartApplication.class, args);
//获取bean对象
BookController bean = ctx.getBean(BookController.class);
System.out.println("bean======>" + bean);
}
}
小结:
<dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> <!--web 起步依赖环境中,排除 Tomcat 起步依赖 --> <exclusions> <exclusion> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-tomcat</artifactId> </exclusion> </exclusions> </dependency> <!-- 添加 Jetty 起步依赖,版本由 SpringBoot 的 starter 控制 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-jetty</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> </dependencies>
小结:
什么是 rest :
REST(Representational State Transfer)表现形式状态转换
传统风格资源描述形式
http://localhost/user/getById?id=1 (得到id为1的用户)
http://localhost/user/saveUser (保存用户)
REST风格描述形式
http://localhost/user/1 (得到id为1的用户)
http://localhost/user (保存用户)
优点:
按照REST风格访问资源时使用行为动作区分对资源进行了何种操作
GET 用来获取资源,POST 用来新建资源,PUT 用来更新资源,DELETE 用来删除资源
注意:
上述行为是约定方式,约定不是规范,可以打破,所以称REST风格,而不是REST规范
描述模块的名称通常使用复数,也就是加s的格式描述,表示此类资源,而非单个资源,例如: users、 books、 accounts…
根据REST风格对资源进行访问称为RESTful
小结:
步骤:
①:设定http请求动作(动词)
使用 @RequestMapping
注解的 method 属性声明请求的方式
使用 @RequestBody
注解 获取请求体内容。直接使用得到是 key=value&key=value…结构的数据。get 请求方式不适用。
使用@ResponseBody
注解实现将 controller 方法返回对象转换为 json 响应给客户端。
@RequestMapping(value="/users",method=RequestMethod.POST)
②:设定请求参数(路径变量)
使用@PathVariable
用于绑定 url 中的占位符。例如:请求 url 中 /delete/{id}
,这个{id}
就是 url 占位符。
@RestController
注解开发 RESTful 风格@RequestMapping
注解开发小结:
# 服务器端口配制
server.port=80
小结:
# 服务器端口配置
server.port=80
# 修改banner
# spring.main.banner-mode=off
# spring.banner.image.location=logo.png
# 日志
logging.level.root=info
小结:
server.port=80
server:
port: 81
server:
port: 82
小结:
小结:
小结:
优点:
YAML文件扩展名
key: value
-> value 前面一定要有空格#
表示注释server:
servlet:
context-path: /hello
port: 82
# 字面值表示方式
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: 2018-02-17 # 日期必须使用 yyyy-MM-dd 格式
datetime: 2018-02-17T15:02:31+08:00 # 时间和日期之间使用 T 连接,最后使用 + 代表时区
subject: - Java - 前端 - 大数据 enterprise: name: zhangsan age: 16 subject2: - Java - 前端 - 大数据 likes: [王者荣耀,刺激战场] # 数组书写缩略格式 users: # 对象数组格式 - name: Tom age: 4 - name: Jerry age: 5 users2: # 对象数组格式二 - name: Tom age: 4 - name: Jerry age: 5 # 对象数组缩略格式 users3: [ { name:Tom , age:4 } , { name:Jerry , age:5 } ]
小结:
1. yaml语法规则
大小写敏感
属性层级关系使用多行描述,每行结尾使用冒号结束
使用缩进表示层级关系,同层级左侧对齐,只允许使用空格(不允许使用Tab键)
属性值前面添加空格(属性名与属性值之间使用冒号+空格作为分隔)
# 表示注释
2. 注意属性名冒号后面与数据之间有一个空格
3. 字面值、对象数据格式、数组数据格式(略)
@Value("${country}") private String country1; @Value("${user.age}") private String age1; @Value("${likes[1]}") private String likes1; @Value("${users[1].name}") private String name1; @GetMapping public String getById() { System.out.println("springboot is running2..."); System.out.println("country1=>" + country1); System.out.println("age1=>" + age1); System.out.println("likes1=>" + likes1); System.out.println("name1=>" + name1); return "springboot is running2..."; }
小结:
在配置文件中可以使用属性名引用方式引用属性
属性值中如果出现转移字符,需要使用双引号包裹
小结:
小结:
# 创建类,用于封装下面的数据
# 由spring帮我们去加载数据到对象中,一定要告诉spring加载这组信息
# 使用时候从spring中直接获取信息使用
datasource:
driver: com.mysql.jdbc.Driver
url: jdbc:mysql://localhost/springboot_db
username: root
password: root666123
//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;
//省略get/set/tostring 方法
}
使用自动装配封装指定数据
@Autowired
private MyDataSource myDataSource;
输出查看
System.out.println(myDataSource);
小结:
<!--测试的起步依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
@SpringBootTest
class Springboot07JunitApplicationTests {
@Autowired
private BookService bookService;
@Test
public void testSave(){
bookService.save();
}
}
@SpringBootTest
class Springboot05JUnitApplicationTests {}
小结:
@SpringBootTest(classes = Springboot04JunitApplication.class)
//@ContextConfiguration(classes = Springboot04JunitApplication.class)
class Springboot04JunitApplicationTests {
//1.注入你要测试的对象
@Autowired
private BookDao bookDao;
@Test
void contextLoads() {
//2.执行要测试的对象对应的方法
bookDao.save();
System.out.println("two...");
}
}
注意:
小结:
①:创建新模块,选择Spring初始化,并配置模块相关基础信息
②:选择当前模块需要使用的技术集(MyBatis、MySQL)
③:设置数据源参数
#DB Configuration:
spring:
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/springboot_db
username: root
password: 123456
④:创建user表
在 springboot_db 数据库中创建 user 表
-- ---------------------------- -- Table structure for `user` -- ---------------------------- DROP TABLE IF EXISTS `user`; CREATE TABLE `user` ( `id` int(11) NOT NULL AUTO_INCREMENT, `username` varchar(50) DEFAULT NULL, `password` varchar(50) DEFAULT NULL, `name` varchar(50) DEFAULT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=10 DEFAULT CHARSET=utf8; -- ---------------------------- -- Records of user -- ---------------------------- INSERT INTO `user` VALUES ('1', 'zhangsan', '123', '张三'); INSERT INTO `user` VALUES ('2', 'lisi', '123', '李四');
⑤:创建实体Bean
public class User {
// 主键
private Long id;
// 用户名
private String username;
// 密码
private String password;
// 姓名
private String name;
//此处省略getter,setter,toString方法 .. ..
}
⑥: 定义数据层接口与映射配置
@Mapper
public interface UserDao {
@Select("select * from user")
public List<User> getAll();
}
⑦:测试类中注入dao接口,测试功能
@SpringBootTest
class Springboot05MybatisApplicationTests {
@Autowired
private UserDao userDao;
@Test
void contextLoads() {
List<User> userList = userDao.getAll();
System.out.println(userList);
}
}
⑧:运行如下
[User{id=1, username='zhangsan', password='123', name='张三'}, User{id=2, username='lisi', password='123', name='李四'}]
总结:
SpringBoot版本低于2.4.3(不含),Mysql驱动版本大于8.0时,需要在url连接串中配置时区
jdbc:mysql://localhost:3306/springboot_db?serverTimezone=UTC
或在MySQL数据库端配置时区解决此问题
1.MySQL 8.X驱动强制要求设置时区
2.驱动类过时,提醒更换为com.mysql.cj.jdbc.Driver
①:手动添加SpringBoot整合MyBatis-Plus的坐标,可以通过mvnrepository获取
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.4.3</version>
</dependency>
注意事项: 由于SpringBoot中未收录MyBatis-Plus的坐标版本,需要指定对应的Version
②:定义数据层接口与映射配置,继承BaseMapper
@Mapper
public interface UserDao extends BaseMapper<User> {
}
③:其他同SpringBoot整合MyBatis
(略)
④:测试类中注入dao接口,测试功能
@SpringBootTest
class Springboot06MybatisPlusApplicationTests {
@Autowired
private UserDao userDao;
@Test
void contextLoads() {
List<User> users = userDao.selectList(null);
System.out.println(users);
}
}
⑤: 运行如下:
[User{id=1, username='zhangsan', password='123', name='张三'}, User{id=2, username='lisi', password='123', name='李四'}]
注意: 如果你的数据库表有前缀要在 application.yml 添加如下配制
#设置Mp相关的配置
mybatis-plus:
global-config:
db-config:
table-prefix: tbl_
小结:
1.手工添加MyBatis-Plus对应的starter
2.数据层接口使用BaseMapper简化开发
3.需要使用的第三方技术无法通过勾选确定时,需要手工添加坐标
①: 导入Druid对应的starter
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>1.2.6</version>
</dependency>
②: 指定数据源类型 (这种方式只需导入一个 Druid 的坐标)
#DB Configuration:
spring:
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/springboot_db?serverTimezone=UTC
username: root
password: 123456
type: com.alibaba.druid.pool.DruidDataSource
或者 变更Druid的配置方式(推荐) 这种方式需要导入 Druid对应的starter
spring:
datasource:
druid:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/springboot_db?serverTimezone=UTC
username: root
password: 123456
小结:
1.整合Druid需要导入Druid对应的starter
2.根据Druid提供的配置方式进行配置
3.整合第三方技术通用方式
1. 案例实现方案分析
实体类开发————使用Lombok快速制作实体类
Dao开发————整合MyBatisPlus,制作数据层测试类
Service开发————基于MyBatisPlus进行增量开发,制作业务层测试类
Controller开发————基于Restful开发,使用PostMan测试接口功能
Controller开发————前后端开发协议制作
页面开发————基于VUE+ElementUI制作,前后端联调,页面数据处理,页面消息处理
列表、新增、修改、删除、分页、查询
项目异常处理
按条件查询————页面功能调整、Controller修正功能、Service修正功能
2. SSMP案例制作流程解析
先开发基础CRUD功能,做一层测一层
调通页面,确认异步提交成功后,制作所有功能
添加分页功能与查询功能
pom.xml
<dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <scope>runtime</scope> </dependency> <dependency> <groupId>com.baomidou</groupId> <artifactId>mybatis-plus-boot-starter</artifactId> <version>3.4.3</version> </dependency> <dependency> <groupId>com.alibaba</groupId> <artifactId>druid-spring-boot-starter</artifactId> <version>1.2.6</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> </dependencies>
DROP TABLE IF EXISTS `tbl_book`; CREATE TABLE `tbl_book` ( `id` int(11) NOT NULL AUTO_INCREMENT, `type` varchar(20) DEFAULT NULL, `name` varchar(50) DEFAULT NULL, `description` varchar(255) DEFAULT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=13 DEFAULT CHARSET=utf8; -- ---------------------------- -- Records of tbl_book -- ---------------------------- INSERT INTO `tbl_book` VALUES ('1', '计算机理论', 'Spring实战第5版', 'Spring入门经典教程,深入理解Spring原理技术内幕'); INSERT INTO `tbl_book` VALUES ('2', '计算机理论', 'Spring 5核心原理与30个类手写实战', '十年沉淀之作,写Spring精华思想'); INSERT INTO `tbl_book` VALUES ('3', '计算机理论', 'Spring 5设计模式', '深入Spring源码剖析Spring源码中蕴含的10大设计模式'); INSERT INTO `tbl_book` VALUES ('4', '计算机理论', 'Spring MVC+ MyBatis开发从入门到项目实战', '全方位解析面向Web应用的轻量级框架,带你成为Spring MVC开发高手'); INSERT INTO `tbl_book` VALUES ('5', '计算机理论', '轻量级Java Web企业应用实战', '源码级剖析Spring框架,适合已掌握Java基础的读者'); INSERT INTO `tbl_book` VALUES ('6', '计算机理论', 'Java核心技术卷|基础知识(原书第11版)', 'Core Java第11版,Jolt大奖获奖作品,针对Java SE9、10、 11全面更新'); INSERT INTO `tbl_book` VALUES ('7', '计算机理论', '深入理解Java虚拟机', '5个维度全面剖析JVM,面试知识点全覆盖'); INSERT INTO `tbl_book` VALUES ('8', '计算机理论', 'Java编程思想(第4版)', 'Java学习必读经典殿堂级著作!赢得了全球程序员的广泛赞誉'); INSERT INTO `tbl_book` VALUES ('9', '计算机理论', '零基础学Java (全彩版)', '零基础自学编程的入门]图书,由浅入深,详解Java语言的编程思想和核心技术'); INSERT INTO `tbl_book` VALUES ('10', '市场营销', '直播就该这么做:主播高效沟通实战指南', '李子柒、李佳琦、薇娅成长为网红的秘密都在书中'); INSERT INTO `tbl_book` VALUES ('11', '市场营销', '直播销讲实战一本通', '和秋叶一起学系列网络营销书籍'); INSERT INTO `tbl_book` VALUES ('12', '市场营销', '直播带货:淘宝、天猫直播从新手到高手', '一本教你如何玩转直播的书, 10堂课轻松实现带货月入3W+');
小结:
server:
port: 80
<!--lombok-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
@Data
public class Book {
private Integer id;
private String type;
private String name;
private String description;
}
小结:
1. 实体类制作
2. 使用lombok简化开发
导入lombok无需指定版本,由SpringBoot提供版本
@Data注解
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.4.3</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>1.2.6</version>
</dependency>
# druid 数据源配制
spring:
datasource:
druid:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/springboot_db?serverTimezone=UTC
username: root
password: 123456
# mybatis-plus
mybatis-plus:
global-config:
db-config:
table-prefix: tbl_
id-type: auto # 主键策略
@Mapper
public interface BookDao extends BaseMapper<Book> {
/**
* 查询一个
* 这是 Mybatis 开发
* @param id
* @return
*/
@Select("select * from tbl_book where id = #{id}")
Book getById(Integer id);
}
@SpringBootTest public class BookDaoTestCase { @Autowired private BookDao bookDao; @Test void testGetById() { System.out.println(bookDao.getById(1)); System.out.println(bookDao.selectById(1)); } @Test void testSave() { Book book = new Book(); book.setType("测试数据123"); book.setName("测试数据123"); book.setDescription("测试数据123"); bookDao.insert(book); } @Test void testUpdate() { Book book = new Book(); book.setId(13); book.setType("测试数据asfd"); book.setName("测试数据123"); book.setDescription("测试数据123"); bookDao.updateById(book); } @Test void testDelete() { bookDao.deleteById(13); } @Test void testGetAll() { System.out.println(bookDao.selectList(null)); } @Test void testGetPage() { } @Test void testGetBy() { } }
小结:
# mybatis-plus
mybatis-plus:
global-config:
db-config:
table-prefix: tbl_
id-type: auto # 主键策略
configuration:
# 开启MyBatisPlus的日志
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
小结:
@Test
void testGetPage() {
IPage page = new Page(1, 5);
bookDao.selectPage(page, null);
}
IPage对象中封装了分页操作中的所有数据
数据
当前页码值
每页数据总量
最大页码值
数据总量
分页操作是在MyBatisPlus的常规操作基础上增强得到,内部是动态的拼写SQL语句,因此需要增强对应的功能,
使用MyBatisPlus拦截器实现
@Configuration
public class MybatisPlusConfig {
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
//1. 定义 Mp 拦截器
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
//2. 添加具体的拦截器 分页拦截器
interceptor.addInnerInterceptor(new PaginationInnerInterceptor());
return interceptor;
}
}
@Test
void testGetPage() {
IPage page = new Page(1, 5);
bookDao.selectPage(page, null);
System.out.println(page.getCurrent());
System.out.println(page.getSize());
System.out.println(page.getPages());
System.out.println(page.getTotal());
System.out.println(page.getRecords());
}
小结:
@Test
void testGetBy2() {
LambdaQueryWrapper<Book> lambdaQueryWrapper = new LambdaQueryWrapper<>();
lambdaQueryWrapper.like(Book::getName, "Spring");
bookDao.selectList(lambdaQueryWrapper);
}
@Test
void testGetBy() {
QueryWrapper<Book> queryWrapper = new QueryWrapper<>();
queryWrapper.like("name", "Spring");
bookDao.selectList(queryWrapper);
}
@Test
void testGetBy2() {
String name = "1";
LambdaQueryWrapper<Book> lambdaQueryWrapper = new LambdaQueryWrapper<>();
//if (name != null) lambdaQueryWrapper.like(Book::getName,name);
lambdaQueryWrapper.like(Strings.isNotEmpty(name), Book::getName, name);
bookDao.selectList(lambdaQueryWrapper);
}
小结:
Service层接口定义与数据层接口定义具有较大区别,不要混用
selectByUserNameAndPassword(String username,String password); 数据层接口
login(String username,String password); Service层接口
接口定义
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 { @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<Book> getAll() { return bookDao.selectList(null); } @Override public IPage<Book> getPage(int currentPage, int pageSize) { IPage page = new Page(currentPage, pageSize); bookDao.selectPage(page, null); return page; } }
@SpringBootTest public class BookServiceTestCase { @Autowired private BookService bookService; @Test void testGetById() { System.out.println(bookService.getById(4)); } @Test void testSave() { Book book = new Book(); book.setType("测试数据123"); book.setName("测试数据123"); book.setDescription("测试数据123"); bookService.save(book); } @Test void testUpdate() { Book book = new Book(); book.setId(14); book.setType("测试数据asfd"); book.setName("测试数据123"); book.setDescription("测试数据123"); bookService.update(book); } @Test void testDelete() { bookService.delete(14); } @Test void testGetAll() { System.out.println(bookService.getAll()); } @Test void testGetPage() { IPage<Book> page = bookService.getPage(2, 5); System.out.println(page.getCurrent()); System.out.println(page.getSize()); System.out.println(page.getPages()); System.out.println(page.getTotal()); System.out.println(page.getRecords()); } }
小结:
public interface IBookService extends IService<Book> {
}
public interface IBookService extends IService<Book> {
// 追加的操作与原始操作通过名称区分,功能类似
Boolean delete(Integer id);
Boolean insert(Book book);
Boolean modify(Book book);
Book get(Integer id);
}
@Service
public class BookServiceImpl extends ServiceImpl<BookDao, Book> implements IBookService {
}
@Service public class BookServiceImpl extends ServiceImpl<BookDao, Book> implements IBookService { @Autowired private BookDao bookDao; public Boolean insert(Book book) { return bookDao.insert(book) > 0; } public Boolean modify(Book book) { return bookDao.updateById(book) > 0; } public Boolean delete(Integer id) { return bookDao.deleteById(id) > 0; } public Book get(Integer id) { return bookDao.selectById(id); } }
@SpringBootTest public class BookServiceTest { @Autowired private IBookService bookService; @Test void testGetById() { System.out.println(bookService.getById(4)); } @Test void testSave() { Book book = new Book(); book.setType("测试数据123"); book.setName("测试数据123"); book.setDescription("测试数据123"); bookService.save(book); } @Test void testUpdate() { Book book = new Book(); book.setId(14); book.setType("==========="); book.setName("测试数据123"); book.setDescription("测试数据123"); bookService.updateById(book); } @Test void testDelete() { bookService.removeById(14); } @Test void testGetAll() { System.out.println(bookService.list()); } @Test void testGetPage() { IPage<Book> page = new Page<>(2, 5); bookService.page(page); System.out.println(page.getCurrent()); System.out.println(page.getSize()); System.out.println(page.getPages()); System.out.println(page.getTotal()); System.out.println(page.getRecords()); } }
小结:
表现层开发
@RestController @RequestMapping("/books") public class BookController { @Autowired private IBookService bookService; @GetMapping public List<Book> getAll() { return bookService.list(); } @PostMapping public Boolean save(@RequestBody Book book) { return bookService.save(book); } @PutMapping public Boolean update(@RequestBody Book book) { return bookService.modify(book); } @DeleteMapping("{id}") public Boolean delete(@PathVariable Integer id) { return bookService.delete(id); } @GetMapping("{id}") public Book getById(@PathVariable Integer id) { return bookService.getById(id); } @GetMapping("{currentPage}/{pageSize}") public IPage<Book> getPage(@PathVariable Integer currentPage, @PathVariable int pageSize) { return bookService.getPage(currentPage, pageSize); } }
添加 分页的业务层方法
IBookService
IPage<Book> getPage(int currentPage,int pageSize);
BookServiceImpl
@Override
public IPage<Book> getPage(int currentPage, int pageSize) {
IPage page = new Page(currentPage, pageSize);
bookDao.selectPage(page, null);
return page;
}
功能测试
小结:
之前的格式
增加一个 data 属性,把数据全部封装到 data 里
当数据为 null 可能出现的问题
增加 一个状态属性
设计表现层返回结果的模型类,用于后端与前端进行数据格式统一,也称为前后端数据协议
@Data public class R { private Boolean flag; private Object data; public R() { } /** * 不返回数据的构造方法 * * @param flag */ public R(Boolean flag) { this.flag = flag; } /** * 返回数据的构造方法 * * @param flag * @param data */ public R(Boolean flag, Object data) { this.flag = flag; this.data = data; } }
@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.modify(book)); } @DeleteMapping("{id}") public R delete(@PathVariable Integer id) { return new R(bookService.delete(id)); } @GetMapping("{id}") public R getById(@PathVariable Integer id) { return new R(true, bookService.getById(id)); } @GetMapping("{currentPage}/{pageSize}") public R getPage(@PathVariable Integer currentPage, @PathVariable int pageSize) { return new R(true, bookService.getPage(currentPage, pageSize)); } }
小结:
Method definition shorthands are not supported by current JavaScript version
表示:该方法定义的缺陷是不支持当前的JavaScript版本,虽然可以程序可以正常运行,但是这个方法会出现红色的波浪线,很不爽
解决:
打开 File -> Settings -> Languages & Frameworks -> Javascript
把JavaScript版本为ECMAScript 6就可以了
//钩子函数,VUE对象初始化完成后自动执行
created() {
//调用查询全部数据的操作
this.getAll();
},
//列表
getAll() {
//发送异步请求
axios.get("/books").then((res)=>{
console.log(res.data);
})
},
小结:
//列表
getAll() {
//发送异步请求
axios.get("/books").then((res) => {
//console.log(res.data);
this.dataList = res.data.data;
})
},
小结:
// 弹出添加窗口
handleCreate() {
this.dialogFormVisible = true;
},
//重置表单
resetForm() {
this.formData = {};
},
//弹出添加窗口
handleCreate() {
this.dialogFormVisible = true;
this.resetForm();
},
//添加 handleAdd() { axios.post("/books", this.formData).then((res) => { //判断当前操作是否成功 if (res.data.flag) { //1.关闭弹层 this.dialogFormVisible = false; this.$message.success("添加成功"); } else { this.$message.error("添加失败"); } }).finally(() => { //2.重新加载数据 this.getAll(); }) },
//取消
cancel() {
//1.关闭弹层
this.dialogFormVisible = false;
//2.提示用户
this.$message.info("当前操作取消");
},
小结:
// 删除
handleDelete(row) {
axios.delete("/books/" + row.id).then((res) => {
if (res.data.flag) {
this.$message.success("删除成功");
} else {
this.$message.error("删除失败");
}
}).finally(() => {
this.getAll();
});
}
// 删除 handleDelete(row) { //1. 弹出提示框 this.$confirm("些操作永久删除当前信息,是否继续?", "提示", {type: "info"}).then(() => { //2. 做删除业务 axios.delete("/books/" + row.id).then((res) => { //判断当前操作是否成功 if (res.data.flag) { this.$message.success("删除成功"); } else { this.$message.error("删除失败"); } }).finally(() => { //2.重新加载数据 this.getAll(); }) }).catch(() => { //3. 取消删除 this.$message.info("取消操作"); }); },
小结:
//弹出编辑窗口
handleUpdate(row) {
axios.get("/books/" + row.id).then((res) => {
if (res.data.flag && res.data.data != null) {
// 展示弹层,加载数据
this.dialogFormVisible4Edit = true;
this.formData = res.data.data;
} else {
this.$message.error("数据同步失败,自动刷新");
}
}).finally(() => {
//重新加载数据
this.getAll();
});
},
// 删除 handleDelete(row) { //1. 弹出提示框 this.$confirm("些操作永久删除当前信息,是否继续?", "提示", {type: "info"}).then(() => { //2. 做删除业务 axios.delete("/books/" + row.id).then((res) => { //判断当前操作是否成功 if (res.data.flag) { this.$message.success("删除成功"); } else { this.$message.error("数据同步失败,自动刷新"); } }).finally(() => { //2.重新加载数据 this.getAll(); }); }).catch(() => { //3. 取消删除 this.$message.info("取消操作"); }); },
小结:
//修改 handleEdit() { axios.put("/books", this.formData).then((res) => { //判断当前操作是否成功 if (res.data.flag) { //1.关闭弹层 this.dialogFormVisible4Edit = false; this.$message.success("修改成功"); } else { this.$message.error("修改失败"); } }).finally(() => { //2.重新加载数据 this.getAll(); }); },
//取消
cancel() {
//1.关闭弹层
this.dialogFormVisible = false;
this.dialogFormVisible4Edit = false;
//2.提示用户
this.$message.info("当前操作取消");
},
小结:
{
"flag": true,
"data": null
}
{
"flag": false,
"data": null
}
{
"timestamp": "2021-11-07T12:44:29.343+00:00",
"status": 500,
"error": "Internal Server Error",
"path": "/books"
}
@RestControllerAdvice
public class ProjectExceptionAdvice {
//拦截所有的异常信息
@ExceptionHandler(Exception.class)
public R doException(Exception ex) {
// 记录日志
// 发送消息给运维
// 发送邮件给开发人员 ,ex 对象发送给开发人员
ex.printStackTrace();
return new R(false, null, "系统错误,请稍后再试!");
}
}
@Data
public class R{
private Boolean flag;
private Object data;
private String msg;
public R(Boolean flag,Object data,String msg){
this.flag = flag;
this.data = data;
this.msg = msg;
}
}
//添加 handleAdd() { axios.post("/books", this.formData).then((res) => { //判断当前操作是否成功 if (res.data.flag) { //1.关闭弹层 this.dialogFormVisible = false; this.$message.success("添加成功"); } else { this.$message.error(res.data.msg); } }).finally(() => { //2.重新加载数据 this.getAll(); }) },
@PostMapping
public R save(@RequestBody Book book) throws IOException {
//if (book.getName().equals("123")) throw new IOException();
boolean flag = bookService.save(book);
return new R(flag, flag ? "添加成功^_^" : "添加失败-_-!");
}
//添加 handleAdd() { axios.post("/books", this.formData).then((res) => { //判断当前操作是否成功 if (res.data.flag) { //1.关闭弹层 this.dialogFormVisible = false; this.$message.success(res.data.msg); } else { this.$message.error(res.data.msg); } }).finally(() => { //2.重新加载数据 this.getAll(); }) },
小结:
<!--分页组件--> <div class="pagination-container"> <el-pagination class="pagiantion" @current-change="handleCurrentChange" :current-page="pagination.currentPage" :page-size="pagination.pageSize" layout="total, prev, pager, next, jumper" :total="pagination.total"> </el-pagination> </div>
data: {
pagination: { // 分页相关模型数据
currentPage: 1, // 当前页码
pageSize: 10, // 每页显示的记录数
total: 0, // 总记录数
}
},
getAll() {
axios.get("/books/" + this.pagination.currentPage + "/" + this.pagination.pageSize).then((res) => {});
},
@GetMapping("{currentPage}/{pageSize}")
public R getPage(@PathVariable Integer currentPage, @PathVariable int pageSize) {
return new R(true, bookService.getPage(currentPage, pageSize));
}
//分页查询
getAll() {
//发送异步请求
axios.get("/books/" + this.pagination.currentPage + "/" + this.pagination.pageSize).then((res) => {
//console.log(res.data);
this.pagination.currentPage = res.data.data.current;
this.pagination.pageSize = res.data.data.size;
this.pagination.total = res.data.data.total;
this.dataList = res.data.data.records;
})
},
//切换页码
handleCurrentChange(currentPage) {
//修改页码值为当前选中的页码值
this.pagination.currentPage = currentPage;
//执行查询
this.getAll();
},
小结:
@GetMapping("{currentPage}/{pageSize}")
public R getPage(@PathVariable Integer currentPage, @PathVariable int pageSize) {
IPage<Book> page = bookService.getPage(currentPage, pageSize);
// 如果当前页码值大于了总页码值,那么重新执行查询操作,使用最大页码值作为当前页码值
if (currentPage > page.getPages()) {
page = bookService.getPage((int) page.getPages(), pageSize);
}
return new R(true, page);
}
小结:
pagination: {//分页相关模型数据
currentPage: 1,//当前页码
pageSize: 10,//每页显示的记录数
total: 0,//总记录数
type: "",
name: "",
description: ""
}
<div class="filter-container">
<el-input placeholder="图书类别" v-model="pagination.type" class="filter-item" />
<el-input placeholder="图书名称" v-model="pagination.name" class="filter-item" />
<el-input placeholder="图书描述" v-model="pagination.description" class="filter-item" />
<el-button @click="getAll()" class="dalfBut">查询</el-button>
<el-button type="primary" class="butT" @click="handleCreate()">新建</el-button>
</div>
//分页查询 getAll() { console.log(this.pagination.type); // /books/1/10?type=???&name=???&decription=?? ; //1. 获取查询条件 , 拼接查询条件 param = "?name=" + this.pagination.name; param += "&type=" + this.pagination.type; param += "&description=" + this.pagination.description; //console.log("-----------------" + param); //发送异步请求 axios.get("/books/" + this.pagination.currentPage + "/" + this.pagination.pageSize + param).then((res) => { //console.log(res.data); this.pagination.currentPage = res.data.data.current; this.pagination.pageSize = res.data.data.size; this.pagination.total = res.data.data.total; this.dataList = res.data.data.records; }) },
@GetMapping("{currentPage}/{pageSize}")
public R getAll(@PathVariable int currentPage,@PathVariable int pageSize,Book book) {
System.out.println("参数=====>"+book);
IPage<Book> pageBook = bookService.getPage(currentPage,pageSize);
return new R(null != pageBook ,pageBook);
}
/**
* 分页的条件查询
*
* @param currentPage
* @param pageSize
* @param book
* @return
*/
IPage<Book> getPage(Integer currentPage, int pageSize, Book book);
@Override
public IPage<Book> getPage(Integer currentPage, int pageSize, Book book) {
LambdaQueryWrapper<Book> lambdaQueryWrapper = new LambdaQueryWrapper<>();
lambdaQueryWrapper.like(Strings.isNotEmpty(book.getType()), Book::getType, book.getType());
lambdaQueryWrapper.like(Strings.isNotEmpty(book.getName()), Book::getName, book.getName());
lambdaQueryWrapper.like(Strings.isNotEmpty(book.getDescription()), Book::getDescription, book.getDescription());
IPage page = new Page(currentPage, pageSize);
bookDao.selectPage(page, lambdaQueryWrapper);
return page;
}
@GetMapping("{currentPage}/{pageSize}")
public R getPage(@PathVariable Integer currentPage, @PathVariable int pageSize, Book book) {
// System.out.println("book=>" + book);
IPage<Book> page = bookService.getPage(currentPage, pageSize, book);
// 如果当前页码值大于了总页码值,那么重新执行查询操作,使用最大页码值作为当前页码值
if (currentPage > page.getPages()) {
page = bookService.getPage((int) page.getPages(), pageSize, book);
}
return new R(true, page);
}
//分页查询 getAll() { console.log(this.pagination.type); // /books/1/10?type=???&name=???&decription=?? ; //1. 获取查询条件 , 拼接查询条件 param = "?name=" + this.pagination.name; param += "&type=" + this.pagination.type; param += "&description=" + this.pagination.description; //console.log("-----------------" + param); //发送异步请求 axios.get("/books/" + this.pagination.currentPage + "/" + this.pagination.pageSize + param).then((res) => { //console.log(res.data); this.pagination.currentPage = res.data.data.current; this.pagination.pageSize = res.data.data.size; this.pagination.total = res.data.data.total; this.dataList = res.data.data.records; }) },
小结:
总结:
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。