Springboot整合mybatisplus实战

news2024/11/16 21:33:01

Springboot整合mybatisplus,纯后端,验证结果是通过postman调用的,记录一下

1、建表语句以及初始化数据脚本

CREATE TABLE `tbl_book` (
  `id` int NOT NULL AUTO_INCREMENT,
  `type` varchar(20) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL,
  `name` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL,
  `description` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL,
  PRIMARY KEY (`id`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=10014 DEFAULT CHARSET=utf8

INSERT INTO `tbl_book` VALUES (10000, '计算机理论', 'Java编程思想(第4版)', 'Java学习经典,殿堂级著作!赢得了全球程序员的广泛赞誉。');
INSERT INTO `tbl_book` VALUES (10001, '计算机理论', '计算机组成原理', '资深的计算机体系结构教育家Alan Clements博士编写,涵盖计算机系统的组成和体系结构的基本概念、指令系统以及处理器实现等涉及计算机组成原理课程的内容。');
INSERT INTO `tbl_book` VALUES (10002, '程序设计', 'C++ Primer Plus 第6版 中文版', 'C++程序设计经典教程,畅销30年的C++大百科全书全新升级,经典C++入门教程十年新版再现\')');
INSERT INTO `tbl_book` VALUES (10003, '程序设计', 'RocketMQ技术内幕:RocketMQ架构设计与实现原理(第2版)', '畅销书升级,RocketMQ创始人高度评价,深入源码分析技术架构和实现原理,打造高性能、高可用、高吞吐量、低延迟RocketMQ');
INSERT INTO `tbl_book` VALUES (10004, '程序设计', ' 深入理解Java虚拟机:JVM高级特性与实践(第3版)', '周志明虚拟机新作,第3版新增内容近50%,5个维度全面剖析JVM,大厂面试知识点全覆盖。与 Java编程思想、Effective Java、Java核心技术 堪称:Java四大名著');
INSERT INTO `tbl_book` VALUES (10005, '历史', '见识城邦·人类简史:从动物到上帝(新版)', '以色列新锐历史学家尤瓦尔·赫拉利代表作,第十届文津图书奖获奖作品');
INSERT INTO `tbl_book` VALUES (10006, '历史', '中国通史', '吕思勉先生写给普通读者的中国通史入门书,用白话文写成的中国通史,把历史从“帝王的家谱”转变为人类的进化史');
INSERT INTO `tbl_book` VALUES (10007, '哲学', '理想国(柏拉图代表作)', '奠定西方哲学史的源流之作。2021新译本,以斯灵斯校勘本为底本,遵照“字对字”的原则,从古希腊原文直译,兼顾准确性和语言通顺性,助你读懂理想国。');
INSERT INTO `tbl_book` VALUES (10008, '哲学', '苏格拉底的申辩', '《柏拉图注疏集:苏格拉底的申辩》记述的是公元前399年,一个叫莫勒图斯的年轻人在雅典状告哲学家苏格拉底,说他不信城邦诸神,引进新的精灵之事,败坏青年。 于是,苏格拉底被传讯,在500人组成的陪审团面前作了著名的申辩。');
INSERT INTO `tbl_book` VALUES (10009, '文学', '鲁迅全集', '大师全集,完整收录,鲁迅毕生之心血尽归于此。\r\n\r\n  鲁迅是中国20世纪的文学家、思想家、革命家,中国近代文学巨匠。他早年留学于日本,后来弃医从文,他用笔耕不辍的文字为新一代青年们指引方向,在国内外思想文化领域有着极高的声誉。');
INSERT INTO `tbl_book` VALUES (10010, '文学', '人间清醒', '茅盾文学奖获得者梁晓声2021全新力作');
INSERT INTO `tbl_book` VALUES (10011, '经济', '八次危机:中国的真实经验1949-2009', '著名“三农”专家温铁军,用经济的独特视角,重新审视中国的1949-2009,历史给我了我们怎样的真实经验?');

2、项目目录

 3、pom文件

<?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.1.1.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.example</groupId>
    <artifactId>springboot</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>springboot</name>
    <description>Demo project for Spring Boot</description>

    <properties>
        <java.version>8</java.version>
    </properties>

    <dependencies>
        <!--web-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <!--mysql-connector-->
        <!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java -->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.20</version>
        </dependency>

        <!--lombok-->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>


        <!--mybatis-plus-->
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
            <version>3.1.1</version>
        </dependency>
        <!--druid-->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid-spring-boot-starter</artifactId>
            <version>1.2.6</version>
        </dependency>


    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <configuration>
                    <excludes>
                        <exclude>
                            <groupId>org.projectlombok</groupId>
                            <artifactId>lombok</artifactId>
                        </exclude>
                    </excludes>
                </configuration>
            </plugin>
        </plugins>
    </build>

</project>

4、application文件

spring:
  datasource:
    druid:
      driver-class-name: com.mysql.cj.jdbc.Driver
      url: jdbc:mysql://localhost:3306/myproject?serverTimezone=UTC
      username: root
      password: root
mybatis-plus:
  global-config:
    db-config:
      table-prefix: tbl_
      id-type: auto
  configuration:
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl  #开启MP运行日志信息

5、PO类以及VO类

package com.example.po;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@AllArgsConstructor
@NoArgsConstructor
public class Book {
    private Integer id;
    private String type;
    private String name;
    private String description;
}
package com.example.vo;
/**
 * 供页面显示使用的类
 */

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;


@Data
@AllArgsConstructor
@NoArgsConstructor
public class BookVo {
    private String type;
    private String name;
    private String description;
}

6、Dao层

package com.example.dao;

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.example.po.Book;
import org.apache.ibatis.annotations.Mapper;
import org.springframework.stereotype.Component;

@Mapper
@Component
public interface BookDao extends BaseMapper<Book> {
}

7、service以及实现类

package com.example.service;

import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.IService;
import com.example.po.Book;

/**
 * 基于 mybatisplus 实现CRUD快速开发
 */
public interface IBookService extends IService<Book> {
    IPage<Book> getPage(Integer currentPage,Integer pageSize);
    IPage<Book> getPage(Integer currentPage,Integer pageSize,Book book);
}
package com.example.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.example.dao.BookDao;
import com.example.po.Book;
import com.example.service.IBookService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

@Service
public class IBookServiceImpl extends ServiceImpl<BookDao, Book> implements IBookService {
    @Autowired
    private BookDao bookDao;

    @Override
    public IPage<Book> getPage(Integer currentPage, Integer pageSize) {
        Page<Book> page = new Page<>(currentPage,pageSize);
        bookDao.selectPage(page,null);
        return page;
    }

    @Override
    public IPage<Book> getPage(Integer currentPage, Integer pageSize, Book book) {
        LambdaQueryWrapper<Book> queryWrapper = new LambdaQueryWrapper<Book>();
        queryWrapper.like(!StringUtils.isEmpty(book.getType()),Book::getType,book.getType());
        queryWrapper.like(!StringUtils.isEmpty(book.getName()),Book::getName,book.getName());
        queryWrapper.like(!StringUtils.isEmpty(book.getDescription()),Book::getDescription,book.getDescription());
        Page<Book> page = new Page<>(currentPage,pageSize);
        bookDao.selectPage(page,queryWrapper);
        return page;
    }
}

8、controller层

package com.example.controller;

import com.baomidou.mybatisplus.core.metadata.IPage;
import com.example.global.PlatErrorCodeEnum;
import com.example.po.Book;
import com.example.global.Response;
import com.example.global.ResponseBuilder;
import com.example.service.IBookService;
import com.example.vo.BookVo;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.List;
import java.util.stream.Collectors;

@RestController
@RequestMapping("/books")
public class BookController {
    @Autowired
    private IBookService bookService;

    //查询所有数据
    @GetMapping
    public Response<List<BookVo>> getBooks(){
        List<BookVo> bookList = bookService.list().stream().map(po -> {
            BookVo vo = new BookVo();
            //将两个字段相同的对象进行属性值的复制
            BeanUtils.copyProperties(po, vo);
            return vo;
        }).collect(Collectors.toList());
        return ResponseBuilder.buildNormalResponse(bookList);


    }

    //添加数据
    @PostMapping("/save")
    public Response<Boolean> saveBook(@RequestBody Book book){
        Boolean flag = bookService.save(book);
        return flag == true ? ResponseBuilder.buildNormalResponse() : ResponseBuilder.buildErrorResponse(PlatErrorCodeEnum.ADD_DATA_FAILED);
    }

    @PutMapping("/update")
    public Response<Boolean> updateBook(@RequestBody Book book){
        boolean flag = bookService.updateById(book);
        return flag == true ? ResponseBuilder.buildNormalResponse() : ResponseBuilder.buildErrorResponse(PlatErrorCodeEnum.UPDATE_DATA_FAILED);
    }
    //查询单个数据
    @GetMapping("{id}")
    public Response<BookVo> getBookById(@PathVariable Integer id){
        Book book = bookService.getById(id);
        BookVo vo = new BookVo();
        BeanUtils.copyProperties(book,vo);
        return ResponseBuilder.buildNormalResponse(vo);
    }
    //删除单个数据
    @DeleteMapping("{id}")
    public Response<Boolean> deleteBook(@PathVariable Integer id){
        boolean flag = bookService.removeById(id);
        return flag == true ? ResponseBuilder.buildNormalResponse() : ResponseBuilder.buildErrorResponse(PlatErrorCodeEnum.DELETE_DATA_FAILED);
    }

    //分页查询数据
    @GetMapping("{currentPage}/{pageSize}")
    public Response<List<BookVo>> getBooksByPage(@PathVariable Integer currentPage,@PathVariable Integer pageSize){
        IPage<Book> page = bookService.getPage(currentPage,pageSize);
        //避免查出来所有的数据,增加一个vo类,只展示需要的字段
        List<BookVo> bookVos = page.getRecords().stream().map(po -> {
            BookVo vo = new BookVo();
            //将两个字段相同的对象进行属性值的复制
            BeanUtils.copyProperties(po, vo);
            return vo;
        }).collect(Collectors.toList());
        return ResponseBuilder.buildNormalResponse(bookVos);
    }

}

9、为了给前端返回统一的值,再加一些优化

package com.example.global;

public enum PlatErrorCodeEnum {

	ADD_DATA_FAILED("10000", "添加数据失败"),
    UPDATE_DATA_FAILED("10001", "更新数据失败"),
    DELETE_DATA_FAILED("10001", "删除数据失败"),



    ;

    public static final String ERROR_CODE="000";

    private String code;
    private String message;

    PlatErrorCodeEnum(String code, String message) {
        this.code = code;
        this.message = message;
    }

	public String getCode() {
		return code;
	}

	public String getMessage() {
		return message;
	}

}
package com.example.global;

import lombok.Data;
import lombok.ToString;

import java.io.Serializable;

@Data
@ToString(callSuper = true)
public class Response<T> implements Serializable {

	private static final long serialVersionUID = -2644259941898334897L;

	private String returnCode;
	private String returnMsg;
	private T returnData;

	public Response(){

	}

	public Response(String returnCode){
		this.returnCode = returnCode;
	}

	public Response(String returnCode, String returnMsg){
		this.returnCode = returnCode;
		this.returnMsg = returnMsg;
	}

	public Response(String returnCode, String returnMsg, T returnData){
		this.returnCode = returnCode;
		this.returnMsg = returnMsg;
		this.returnData = returnData;
	}

	public T getReturnData() {
		return returnData;
	}

	public Response<T> setReturnData(T returnData) {
		this.returnData = returnData;
		return this;
	}
}
package com.example.global;


/**
 * 构造响应结果
 */
public final class ResponseBuilder {
	/**
	 * 返回成功.
	 */
	public static final String RESPONSE_OK = "0000";
	public static final String RESPONSE_MESSAGE = "响应成功";
	
	/**
	 * 构造一个失败响应
	 */
	public static <T> Response<T> buildErrorResponse(PlatErrorCodeEnum enums) {
		Response<T> entity = new Response<>();
		entity.setReturnCode(String.valueOf(enums.getCode()));
		entity.setReturnMsg(enums.getMessage());
		return entity;
	}

	/**
	 * 构造一个失败响应
	 */
	public static <T> Response<T> buildErrorResponse(String error, String message) {
		Response<T> entity = new Response<>();
		entity.setReturnCode(error);
		entity.setReturnMsg(message);
		return entity;
	}
	
	/**
	 * 构造一个正常的没有返回数据的响应
	 */
	public static <T> Response<T> buildNormalResponse() {
		return new Response<T>(RESPONSE_OK, RESPONSE_MESSAGE);
	}

	/**
	 * 构造一个正常的有返回数据的响应
	 * @param returnData
	 * @param <T>
	 * @return
	 */
	public static <T> Response<T> buildNormalResponse(T returnData) {
		Response<T> entity = buildNormalResponse();
		entity.setReturnData(returnData);
		return entity;
	}

}

10、mybatisplus分页插件配置

package com.example.config;

/**
 * 配置mybatisplus分页插件
 */

import com.baomidou.mybatisplus.extension.plugins.PaginationInterceptor;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
@MapperScan("com.example.dao")
public class MyBatisPlusConf {
    @Bean
    public PaginationInterceptor mybatisPlusInterceptor(){
        //创建拦截器 SpringBoot 低版本用 PaginationInterceptor 高版本用 MybatisPlusInterceptor
        PaginationInterceptor interceptor = new PaginationInterceptor();
        return interceptor;

    }

}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/670922.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Django之模板层

一、模板简介 在刚刚介绍完的视图层中我们提到&#xff0c;浏览器发送的请求信息会转发给视图进行处理&#xff0c;而视图在经过一系列处理后必须要有返回信息给浏览器。如果我们要返回html标签、css等数据给浏览器进行渲染&#xff0c;我们可以在视图中这么做 from django.s…

Git进阶系列 | 3. 基于Pull Request实现更好的协作

Git是最流行的代码版本控制系统&#xff0c;这一系列文章介绍了一些Git的高阶使用方式&#xff0c;从而帮助我们可以更好的利用Git的能力。本系列一共8篇文章&#xff0c;这是第3篇。原文&#xff1a;Better Collaboration With Pull Requests[1] 本文是“Git进阶系列”的第三篇…

Keil 重定向 fputc 函数 以及 printf 函数的代码尺寸测试

本文的开发环境为 Keil Cortex-M3 内核处理器。 重定向 fputc 函数方法 如果想使用库函数 printf &#xff0c;必须要将 fputc 重定向到自己的串口上。 术语 重定向 可以理解为用户重写 fputc 函数&#xff0c;在重写的函数体内调用自己硬件的串口发送函数。 在 Keil 环境中…

Android Binder通信原理(二):servicemanager启动

源码基于&#xff1a;Android R 0. 前言 下图是android 8.0 之前binder 的软件框架&#xff0c;依赖的驱动设备是/dev/binder&#xff0c;binder机制的四要素分别是client、server、servicemanager和binder驱动。 对于android 8.0后的binder 和vndbinder依然同这个框架&#…

【Python版】手把手带你如何进行Mock测试

什么是mock&#xff1f; mock测试是以可控的方式模拟真实的对象行为。程序员通常创造模拟对象来测试对象本身该具备的行为&#xff0c;很类似汽车设计者使用碰撞测试假人来模拟车辆碰撞中人的动态行为 为什么要使用Mock&#xff1f; 之所以使用mock测试&#xff0c;是因为真…

js+html+css 封装一个弹窗组件

HTML中通过一个按钮触发显示弹窗的函数showPopup()&#xff0c;弹窗的内容包含在一个div元素中&#xff0c;初始设置为隐藏状态。 CSS中定义了弹窗的样式&#xff0c;包括背景、位置、边框等。 JavaScript中定义了两个函数showPopup()和hidePopup()&#xff0c;分别用于显示和隐…

CORS原理及解决办法

浏览器的同源策略阻止读取来自不同来源的资源。这种机制阻止恶意站点读取另一个站点的数据&#xff0c;但它也阻止合法使用。 一般情况下&#xff0c;我们可以通过两种方式解决浏览器的同源策略&#xff0c;JSONP和CORS,CORS解决方案更为通用&#xff08;推荐&#xff09;。 …

算法程序设计 之 胖男孩问题(7/8)

一、题目分析 问题描述 麦克结婚后&#xff0c;在上个月他胖了70磅。因为手指上的脂肪过多&#xff0c;使他连给他最亲密的朋友斯拉夫克写一个电子邮件都很困难。 每晚麦克都详细地描述那一天他所吃的所有东西&#xff0c;但有时当他只想按一次某键时往往会按了不止一次&…

java 读取图片中的文字

Maven依赖导入Tess4j <!-- https://mvnrepository.com/artifact/net.sourceforge.tess4j/tess4j --><dependency><groupId>net.sourceforge.tess4j</groupId><artifactId>tess4j</artifactId><version>4.5.4</version></de…

基于SpringBoot的二手书交易系统的设计与实现(源码、数据库、文档)

作为新兴事物&#xff0c;校园电子商务是&#xff0c;首先是指在校园范围内&#xff0c;其技术手段是校园网&#xff0c;而服务对象是全部师生。主要经营形式为学生自主经营&#xff0c;能够满足多群体生活学习需求&#xff0c;同时具备范围小&#xff0c;安全性高&#xff0c;…

《Web应用技术》期末复习(END)

说明&#xff1a;不知道是哪位兄台在群里说了一句&#xff0c;整的我压力山大。这是我个人的期末复习梳理&#xff0c;自己使用并且提供给几位有需要的朋友使用&#xff0c;并不确定期末考试考不考这些。请大家视情况查看和使用&#xff0c;如果有错误&#xff0c;也欢迎大家找…

opencv如何使用GPU的三种方法

我在工作实验涉及到图像和视频处理时&#xff0c;通常使用opencv提供的库来做处理&#xff0c;虽然OpenCV是一个广泛使用的库&#xff0c;它提供了丰富的功能和工具。然而&#xff0c;有时候在处理大量图片或视频时&#xff0c;我们可能会面临速度受限的问题。 opencv执行图像…

SpringMvc拦截器入门

文章目录 前言五、拦截器入门1.拦截器简介2.拦截器入门案例3.拦截器参数4. 拦截器链配置 总结 前言 为了巩固所学的知识&#xff0c;作者尝试着开始发布一些学习笔记类的博客&#xff0c;方便日后回顾。当然&#xff0c;如果能帮到一些萌新进行新技术的学习那也是极好的。作者…

管理Linux目录、用户、组以及文档的权限和归属

文章目录 一、管理Linux目录和文件1、查看及切换目录pwd&#xff1a;查看当前工作目录cd&#xff1a;切换工作目录ls&#xff1a;列出文档及属性alias&#xff1a;别名cat查看文件内容less分页显示长文件 2.新建目录/文件mkdir 创建目录touch创建文件 3.删除/移动/复制rm删除mv…

ai描述生成器绘画有哪些?ai绘画生成器描述介绍

从前&#xff0c;有一个名叫小华的画家&#xff0c;他是一位非常出色的艺术家&#xff0c;但是他总是感到自己还没有达到他理想中作品的水平。他一直在寻找一种方法来创造出高质量的艺术品。有一天&#xff0c;他听说了一种神奇的技术&#xff0c;可以让计算机通过人工智能生成…

MySQL全备+binlog恢复方法之伪装master

利用mysql全备 binlog server恢复方法之伪装master 单实例试验 一、试验环境 10.72.7.40 实例 mysql3306为要恢复的对象&#xff0c;mysql3306的全备binlog server&#xff08;目录/data/mysql/mysql3306/backup&#xff09; 实例mysql3307为伪装master 实例mysql3308为伪…

黑马程序员前端 Vue3 小兔鲜电商项目——(四)Home 页面布局

文章目录 Home 页面组件结构组件结构拆分Home 模块中引入组件 分类实现模板代码渲染数据 banner 轮播图实现模板代码封装接口渲染数据 面板组件封装创建公共组件复用抽取主题和副主题 新鲜好物实现模版代码封装接口渲染数据 人气推荐实现模板代码封装接口渲染数据 懒加载指令实…

Java实现加密(五)Base64编码

目录 一、Base64是怎么诞生的二、Base64定义三、Base64原理1.ASCII码转Base64&#xff08;字节数 % 3 0&#xff09;2.ASCII码转Base64&#xff08;字节数 % 3 2&#xff09;3.ASCII码转Base64&#xff08;字节数 % 3 1&#xff09;4.UTF-8转Base64 四、Java实现Base64编解码…

Android Binder通信原理(一):简介

源码基于&#xff1a;Android R 0. 前言 在Linux 系统中现有的进程间通信&#xff08;IPC&#xff09;方式&#xff1a; 管道(PIPE)&#xff1a;在创建时分配一个page大小的内存&#xff0c;缓存区大小比较有限&#xff1b;命名管道(FIFO)&#xff1a;考虑 PIPE_BUF 和原子操…

华为流程体系:IPD流程之敏捷开发(限制版)

目录 前言 敏捷 逐步采用敏捷原则 专栏列表 CSDN学院课程地址 前言 今天继续来谈谈 IPD 体系中敏捷开发所涉及的一些相关内容。 无论是硬件产品的开发过程&#xff0c;还是在应用或者是学习 IPD 的过程中。 瀑布式流程几乎都是标配。 这其实跟硬件产品或者是传统 IPD …