整合第三方技术
整合JUnit
@SpringBootTest
-
类型:测试类注解
-
位置测试类定义上方
-
作用:设置Junit加载的SpringBoot启动类
@SpringBootTest class SpringbootJunitApplicationTests {}
-
classes:设置SpringBoot启动类
- 如果测试类不在引导类所在的包或者子包中需要通过classes属性指定引导类
@SpringBootTest(classes = SpringbootJunitApplicationTests.class) class SpringbootJunitApplicationTests {}
-
整合MyBatis
-
核心配置:数据库链接相关信息
-
映射配置:SQL映射(XML/注解)
-
设置Application.yml链接SQL
spring: datasource: driver-class-name: com.mysql.jdbc.Driver url: jdbc:mysql://localhost:3306/数据库名 username: SQL账号 password: SQL密码
-
选择依赖项:
- Mybatis Framework
- MySQL Driver
-
编写字段表,如:
// 需要导入Lombok依赖 @Data public class User{ private Integer id; private String type; private String name; }
-
定义数据层接口与映射配置
@Mapper public interface UserMapper { @Select("select * from 表名") Book getAll(); }
-
测试类中注入dao接口,测试功能
@SpringBootTest class SpringbootMybatisApplicationTests { @Autowired private UserMapper userMapper; @Test void contextLoads() { System.out.println(UserMapper.getAll()); } }
MySQL配置问题
-
MySQL 8.x驱动强制要求设置时区
-
修改rul,添加sererTimezone设定
url: jdbc:mysql://localhost:3306/ssm_db?sererTimezone = utf
-
修改MySQL数据库配置
-
-
驱动类过时,提醒更换为:com.mysql.cj.jdbc.Driver
整合MyBatis-Plus
- MyBatis-plus与MyBatis区别
- 导入坐标不同
- 数据层实现简化
-
手动添加SpringBoot整合MyBatis-Plus坐标,可以通过mvnrepository获取
<dependency> <groupId>com.baomidou</groupId> <artifactId>mybatis-plus-boot-starter</artifactId> <version>3.5.2</version> </dependency>
-
定义数据层接口与映射配置,继承BaseMapper
@Mapper public interface BookMapper extends BaseMapper<Book> { }
整合Druid
-
需要导入Druid对应的starter
<dependency> <groupId>com.alibaba</groupId> <artifactId>druid</artifactId> <version>1.2.8</version> </dependency>
-
根据Druid提供的配置方式进行配置(不加默认使用Hikari)
spring: datasource: driver-class-name: com.mysql.cj.jdbc.Driver url: jdbc:mysql://localhost:3306/ssm_db username: root password: root type: com.alibaba.druid.pool.DruidDataSource
或者
spring: datasource: druid: driver-class-name: com.mysql.cj.jdbc.Driver url: jdbc:mysql://localhost:3306/ssm_db username: root password: root
-
整合第三方技术通用方式
- 导入对应的starter
- 根据提供的配置格式,配置非默认值对应的配置项
基于SpringBoot的SSMP整合案例
- 实体类开发——使用Lombok快速制作实体类
- Dao开发——整合MyBatisPlus,制作数据层测试
- Service开发——基于MyBatisPlus进行增量开发,制作业务层测试类
- Controller开发——基于Restful开发,使用PostMan测试接口功能
- Controller开发——前后端开发协议制作
- 页面开发——基于VUE+ElementUI制作,前后端联调,页面数据处理,页面消息处理
- 列表
- 新增
- 修改
- 删除
- 分页
- 查询
- 项目异常处理
- 按条件查询————页面功能调整、Controller修正功能、Service修正功能
数据层开发
-
配置数据源与MyBatisPlus对应的基础配置
spring: datasource: driver-class-name: com.mysql.cj.jdbc.Driver url: jdbc:mysql://localhost:3306/ssm_db username: root password: root type: com.alibaba.druid.pool.DruidDataSource mybatis-plus: global-config: db-config: table-prefix: tbl_ id-type: auto
-
继承BaseMapper并指定泛型
@Mapper public interface BookMapper extends BaseMapper<Book> {}
-
制作测试类测试结果
@SpringBootTest class Springboot07SsmpApplicationTests { @Autowired private BookMapper bookMapper; @Test void contextLoads() { System.out.println(bookMapper.selectById(1)); } @Test void testSave(){ Book book = new Book(); book.setName("张三"); book.setType("张三"); book.setDescription("张三"); bookMapper.insert(book); } @Test void testUpdate(){ Book book = new Book(); book.setId("输入需要更改的id"); book.setName("张三123"); book.setType("张三123"); book.setDescription("张三123"); bookMapper.updateById(book); } @Test void testDelete(){ bookMapper.deleteById(58007553); } @Test void testGetAll(){ System.out.println(bookMapper.selectList(null)); } …… }
开启MP运行日志
-
方便调试可以开启MyBatisPlus日志
mybatis-plus: configuration: log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
数据层开发——分页功能
-
分页操作需要设定分页对象Page
@Test void testGetPage(){ Page<Book> page = new Page<>(1, 5); System.out.println(bookMapper.selectPage(page,null)); }
-
分页操作是在MyBatisPlus的上操作的,内部是动拼写SQL语句,因此需要增强对应的功能,使用MyBatisPlus拦截器实现
@Configuration public class MPConfig { @Bean public MybatisPlusInterceptor mybatisPlusInterceptor(){ MybatisPlusInterceptor mybatisPlusInterceptor = new MybatisPlusInterceptor(); mybatisPlusInterceptor.addInnerInterceptor(new PaginationInnerInterceptor()); return mybatisPlusInterceptor; } }
数据层开发——查询功能
-
使用QueryWrapper对象封装查询条件,推荐使用LambdaQueryWrapper对象
@Test void testGetBy(){ QueryWrapper<Book> qw = new QueryWrapper<>(); qw.like("name","spring"); bookMapper.selectList(qw); }
@Test void testGetBy2(){ LambdaQueryWrapper<Book> qw = new LambdaQueryWrapper<>(); String name = null; qw.like(name != null,Book::getName,name); bookMapper.selectList(qw); }
业务层开发
业务层标准开发——CRUD构建
-
接口定义
public interface BookService { Book getById(Integer id); List<Book> getAll(); IPage<Book> getPage(int currentPage,int pageSize); }
-
实现类定义
@Service public class BookServiceImpl implements BookService { @Autowired private BookMapper bookMapper; @Override public Book getById(Integer id) { return bookMapper.selectById(id); } @Override public List<Book> getAll() { return bookMapper.selectList(null); } @Override public IPage<Book> getPage(int currentPage, int pageSize) { IPage<Book> bookIPage = new Page<Book>(currentPage, pageSize); bookMapper.selectPage(bookIPage,null); return bookIPage; } }
-
测试类定义
@SpringBootTest public class BookServiceTestCase { @Autowired private BookService bookService; @Test void testGetById(){ System.out.println(bookService.getById(1)); } @Test void testGetAll(){ System.out.println(bookService.getAll()); } @Test void testGetPage(){ IPage<Book> page = bookService.getPage(1, 5); System.out.println(page); System.out.println(page.getRecords()); } }
业务层快速开发——MyBatisPlus构建
-
快速开发方案
- 使用MyBatisPlus提供有业务层通用接口
(IService<T>)
与业务层通用实现类(ServiceImpl<M,T>)
- 在通用类基础上做功能重载或功能追加
- 注意重载时不要覆盖原始操作,避免原始提供的功能丢失
- 使用MyBatisPlus提供有业务层通用接口
-
接口定义
public interface BookIService extends IService<Book> { // 追加的操作与原始操作通过命名区分 }
-
实现类定义
@Service public class BookIServiceImpl extends ServiceImpl<BookMapper, Book> implements BookIService { // 在BookIService类追加的操作,在此类追加功能 }
表现层开发
- 基于Restful进行表现层接口开发
- 使用Postman测试表现层接口功能
@RestController
@RequestMapping("/books")
public class BookController {
@Autowired
private BookIService bookIService;
@GetMapping
public List<Book> getAll(){
return bookIService.list();
}
……
}
- 基于Restful制作表现层接口
- 新增:POST
- 删除:DELETE
- 修改:PUT
- 查询:GET
- 接收参数
- 实体数据:@RequestBody
- 路径变量:@pathVariable
表现层信息——一致性处理
-
设计表现层返回结果的模型类,用于后端与前端进行数据格式统一
@Data public class R { private Boolean flag; private Object data; public R(){} public R(Boolean flag){ this.flag = flag; } public R(Boolean flag,Object data){ this.flag = flag; this.data = data; } }
-
表现层接口统一返回值类型结果
@RestController @RequestMapping("/books") public class BookController { @Autowired private BookIService bookIService; @PostMapping public R save(@RequestBody Book book){ return new R(bookIService.save(book)); } @GetMapping public R getAll(){ return new R(true,bookIService.list()); } }
-
业务操作成功或失败返回数据格式
{ "flag": true/false, "data": null }
-
后台代码BUG导致数据格式不统一性
{ "timestamp": "2023-01-11T04:39:12.424+00:00", "status": 500, "error": "Internal Server Error", "path": "/books" }
前后端协议联调(略)
- 前后端分离结构设计中页面归属前端服务器
- 单体工程页面放置在resources目录下的static目录中(建议执行clean)
弹出添加窗口
handleCreate() {
// 重置表单
this.resetForm();
this.dialogFormVisible = true;
},
清除数据
// 重置表单
resetForm() {
this.formData = {};
},
添加
//添加
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(){
this.dialogFormVisible = false;
this.$message.info("操作取消");
},
删除
// 删除
handleDelete(row) {
console.log(row);
this.$confirm("此操作永久删除当前信息,是否继续?","提示",{type: "info"}).then(()=>{
axios.delete("/books/"+row.id).then((res)=>{
if (res.data.flag){
this.$message.success("删除成功");
}else {
this.$message.error("删除失败");
}
}).finally(()=>{
this.getAll();
})
}).catch(()=>{
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();
});
},
修改
-
修改
//修改 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(){ this.dialogFormVisible = false; //添加修改弹窗 this.dialogFormVisible4Edit = false; this.$message.info("操作取消"); },