整合第三方技术

整合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数据库配置
  1. 驱动类过时,提醒更换为:com.mysql.cj.jdbc.Driver
整合MyBatis-Plus
  • MyBatis-plus与MyBatis区别
  • 导入坐标不同
  • 数据层实现简化
  1. 手动添加SpringBoot整合MyBatis-Plus坐标,可以通过mvnrepository获取
<dependency>
    <groupId>com.baomidou</groupId>
    <artifactId>mybatis-plus-boot-starter</artifactId>
    <version>3.5.2</version>
</dependency>
  1. 定义数据层接口与映射配置,继承BaseMapper
@Mapper
public interface BookMapper extends BaseMapper<Book> {
}
整合Druid
  1. 需要导入Druid对应的starter
<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>druid</artifactId>
    <version>1.2.8</version>
</dependency>
  1. 根据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
  1. 整合第三方技术通用方式
  • 导入对应的starter
  • 根据提供的配置格式,配置非默认值对应的配置项

基于SpringBoot的SSMP整合案例

  1. 实体类开发——使用Lombok快速制作实体类
  2. Dao开发——整合MyBatisPlus,制作数据层测试
  3. Service开发——基于MyBatisPlus进行增量开发,制作业务层测试类
  4. Controller开发——基于Restful开发,使用PostMan测试接口功能
  5. Controller开发——前后端开发协议制作
  6. 页面开发——基于VUE+ElementUI制作,前后端联调,页面数据处理,页面消息处理
  • 列表
  • 新增
  • 修改
  • 删除
  • 分页
  • 查询
  1. 项目异常处理
  2. 按条件查询————页面功能调整、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>)
  • 在通用类基础上做功能重载或功能追加
  • 注意重载时不要覆盖原始操作,避免原始提供的功能丢失
  • 接口定义
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();
    }
    ……
}
  1. 基于Restful制作表现层接口
  • 新增:POST
  • 删除:DELETE
  • 修改:PUT
  • 查询:GET
  1. 接收参数
  • 实体数据:@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"
}
前后端协议联调(略)
  1. 前后端分离结构设计中页面归属前端服务器
  2. 单体工程页面放置在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("操作取消");
},