【基础篇】五、基于SpringBoot来整合SSM的案例(上)

曾经终败给现在 2023-10-16 08:49 127阅读 0赞

文章目录

  • 0、创建模块
  • 1、实体类的快速开发Lombok
  • 2、数据层开发(CRUD)
  • 3、分页
  • 4、条件查询
  • 5、业务层的标准开发
  • 6、业务层的快速开发(基于MyBatisPlus)
  • 7、表现层开发
  • 8、表现层数据一致性:统一结果类R

接下来在SpringBoot下,把Spring、SpringMVC、MyBatis整合在一起,来实现一个简单的增删改查。

请添加图片描述

0、创建模块

创建新模块,勾选spring-web(SpringMVC)以及MySQL的驱动,再手动导入MyBatisPlus以及Druid的依赖坐标:

在这里插入图片描述

1、实体类的快速开发Lombok

Lombok,一个Java类库,提供了一组注解,用来简化POJO实体类开发。

  1. <!-- 不用指定版本,lombok在SpringBoot的管理范围之内 -->
  2. <dependency>
  3. <groupId>org.projectlombok</groupId>
  4. <artifactId>lombok</artifactId>
  5. </dependency>

表结构:

在这里插入图片描述

实体类:

  1. @Data
  2. public class Book {
  3. private Integer id;
  4. private String type;
  5. private String name;
  6. private String description;
  7. }

@Data包括了get/set方法,toString方法,hashCode方法,equals方法等,但不包括有参和无参构造。

2、数据层开发(CRUD)

导入MyBatisPlus与Druid对应的starter:

  1. <dependency>
  2. <groupId>com.baomidou</groupId>
  3. <artifactId>mybatis-plus-boot-starter</artifactId>
  4. <version>3.4.3</version>
  5. </dependency>
  6. <dependency>
  7. <groupId>com.alibaba</groupId>
  8. <artifactId>druid-spring-boot-starter</artifactId>
  9. <version>1.2.6</version>
  10. </dependency>

配置数据源与MyBatisPlus对应的基础配置

  1. spring:
  2. datasource:
  3. druid:
  4. driver-class-name: com.mysql.cj.jdbc.Driver
  5. url: jdbc:mysql://localhost:3306/ssm_db?servierTimezone=UTC
  6. username: root
  7. password: root
  8. mybatis-plus:
  9. global-config:
  10. db-config:
  11. table-prefix: t_ # 表名和实体类相比,表名的前缀,如此就不用再实体类中加注解指定表名了
  12. id-type: auto # id生成策略使用数据库自增策略(和我数据库中设置的保持一致)
  13. # 否则插入数据时MP使用雪花算法生成一个id

继承BaseMapper并指定泛型:

  1. //要么在mapper中加@Mapper,要么去启动类加@MapperScan
  2. @Mapper
  3. public interface BookDao extends BaseMapper<Book> {
  4. }

为方便调试可以开启MyBatisPlus的日志,StdOutImpl即标准输出,即打印到控制台上

  1. mybatis-plus:
  2. configuration:
  3. log-impl: org.apache.ibatis.logging.stdout.StdOutImpl

单元测试看效果:

  1. @SpringBootTest
  2. public class BookDaoTest {
  3. @Autowired
  4. private BookDao bookDao;
  5. @Test
  6. void testSave() {
  7. Book book = new Book();
  8. book.setName("测试数据");
  9. book.setType("测试类型");
  10. book.setDescription("测试描述数据");
  11. bookDao.insert(book);
  12. }
  13. ...
  14. }

3、分页

分页操作需要设定分页对象IPage,其实现类为Page

  1. @Test
  2. void testGetPage(){
  3. IPage<Book> page = new Page<>(1,5);
  4. bookDao.selectPage(page,null);
  5. }

IPage对象中封装了分页操作中的所有数据,包括:

  • 数据
  • 当前页码值
  • 每页数据总量
  • 最大页码值
  • 数据总量

分页操作是在MyBatisPlus的常规操作基础上增强得到,内部是动态的拼写SQL语句,因此需要增强对应的功能,使用MyBatisPlus拦截器实现。

  1. @Configuration
  2. public class MpConfig {
  3. @Bean
  4. public MybatisPlusInterceptor mpInterceptor() {
  5. //1.定义Mp拦截器
  6. MybatisPlusInterceptor mpInterceptor = new MybatisPlusInterceptor();
  7. //2.添加具体的拦截器
  8. mpInterceptor.addInnerInterceptor(new PaginationInnerInterceptor());
  9. return mpInterceptor;
  10. }
  11. }

4、条件查询

关于条件查询:

  • 使用QueryWrapper对象封装查询条件,此时传的table的列名
  • 推荐使用LambdaQueryWrapper对象来封装查询条件
  • 查询条件支持动态条件拼装(方法的重载)

在单元测试中分别演示下:

  1. @Test
  2. void testGetByCondition(){
  3. QueryWrapper<Book> qw = new QueryWrapper<>();
  4. qw.like("name","Spring");
  5. bookDao.selectList(qw);
  6. }
  7. @Test
  8. void testGetByCondition(){
  9. IPage page = new Page(1,10);
  10. LambdaQueryWrapper<Book> lqw = new LambdaQueryWrapper<Book>();
  11. lqw.like(Book::getName,"Spring");
  12. bookDao.selectPage(page,lqw);
  13. }

实际开发,从前端获取的搜索关键字,如果为null而不过滤,则 where name like %null%,因此:

  1. @Test
  2. void testGetByCondition(){
  3. String name = "Spring";
  4. IPage page = new Page(1,10);
  5. LambdaQueryWrapper<Book> lqw = new LambdaQueryWrapper<Book>();
  6. lqw.like(Strings.isNotEmpty(name),Book::getName,"Spring"); //判空,为空则不拼SQL
  7. bookDao.selectPage(page,lqw);
  8. }

到此,数据层的开发结束。

5、业务层的标准开发

写业务层之前,说下Mapper层和Service层接口方法名的命名,Mapper要起的偏数据库,Service则偏业务,Mapper接口的方法名看完就知道大概的SQL咋写的,Service层看方法名就知道是做啥业务的,以登录为例,如:

  1. //Mapper
  2. selectByUserNameAndPassword(String username,String password);
  3. //Service
  4. login(String username,String password);

Service层接口定义:

  1. public interface BookService {
  2. boolean save(Book book);
  3. boolean delete(Integer id);
  4. boolean update(Book book);
  5. Book getById(Integer id);
  6. List<Book> getAll();
  7. IPage<Book> getByPage(int currentPage,int pageSize);
  8. }

写实现类:

  1. @Service
  2. public class BookServiceImpl implements BookService {
  3. @Autowired
  4. private BookDao bookDao;
  5. public Boolean save(Book book) {
  6. return bookDao.insert(book) > 0;
  7. }
  8. public Boolean delete(Integer id) {
  9. return bookDao.deleteById(id) > 0;
  10. }
  11. public Boolean update(Book book) {
  12. return bookDao.updateById(book) > 0;
  13. }
  14. public Book getById(Integer id) {
  15. return bookDao.selectById(id);
  16. }
  17. public List<Book> getAll() {
  18. return bookDao.selectList(null);
  19. }
  20. public IPage<Book> getByPage(int currentPage, int pageSize) {
  21. IPage page = new Page<Book>(currentPage,pageSize);
  22. return bookDao.selectPage(page,null);
  23. }
  24. }

6、业务层的快速开发(基于MyBatisPlus)

继承IService接口,泛型传入实体类,即可有上面标准开发的那些方法。另外你业务需要的定制的方法,自己接着写就行。

在这里插入图片描述

此时的实现类:注意泛型中的M和T,M传Mapper类型,T是实体类

  1. @Service
  2. public class BookServiceImpl2 extends ServiceImpl<BookDao,Book> implements IBookService {
  3. }

除了基础的MP提供的方法,其余你的定制业务方法,自己加就好:

  1. @Service
  2. public class BookServiceImpl2 extends ServiceImpl<BookDao,Book> implements IBookService {
  3. @Autowired
  4. private BookDao bookDao;
  5. public Boolean insertSome(Book book) {
  6. return bookDao.insert(book) > 0;
  7. }
  8. }

总结就是:

  • 使用MyBatisPlus提供有业务层通用接口(ISerivce<T>)与业务层通用实现类(ServiceImpl<M,T>)
  • 在通用类基础上做功能重载或功能追加
  • 注意重载时不要覆盖原始操作,避免原始提供的功能丢失

7、表现层开发

基于Restful进行表现层接口开发:

  1. @RestController
  2. @RequestMapping("/books")
  3. public class BookController {
  4. @Autowired
  5. private IBookService bookService;
  6. @GetMapping
  7. public List<Book> getAll(){
  8. return bookService.list();
  9. }
  10. @PostMapping
  11. public Boolean save(@RequestBody Book book){
  12. return bookService.insert(book);
  13. }
  14. @PutMapping
  15. public Boolean update(@RequestBody Book book){
  16. return bookService.modify(book);
  17. }
  18. @DeleteMapping("/{id}")
  19. public Boolean delete(@PathVariable Integer id){
  20. return bookService.delete(id);
  21. }
  22. @GetMapping("/{currentPage}/{pageSize}")
  23. public List<Book> getAll(@PathVariable Integer currentPage,@PathVariable Integer pageSize){
  24. return bookService.getPage(currentPage,pageSize).getRecords();
  25. }
  26. }
  27. //接口功能实现,但返回结果不统一
  28. //待续...

这里遇到个坑,注入Service层的Bean的时候,发现有两个可用的Bean而启动失败,参考【解决:缩小Mapper扫描范围,避免产生不必要的Bean】

8、表现层数据一致性:统一结果类R

设计表现层返回结果的模型类,用于后端与前端进行数据格式统一,也称为前后端数据协议。说白了,找个盛饭的碗,查出来的数据就是饭,找个统一结果类来装一下。

  1. //属性自己决定,平时用msg和data,这个flag看的我别扭
  2. @Data
  3. public class R{
  4. private Boolean flag;
  5. private Object data;
  6. public R(){
  7. }
  8. public R(Boolean flag){
  9. this.flag = flag;
  10. }
  11. public R(Boolean flag,Object data){
  12. this.flag = flag;
  13. this.data = data;
  14. }
  15. //也可以定义个静态方法,里面封装构造方法
  16. public static R success(Object data){
  17. return new R(ture,data)
  18. }
  19. }

改下Controller层的返回类型和逻辑:

  1. @RestController
  2. @RequestMapping("/books")
  3. public class BookController {
  4. @Autowired
  5. private IBookService bookService;
  6. ...
  7. @GetMapping
  8. public R getAll(){
  9. List<Book> bookList = bookService.list();
  10. return new R(true ,bookList);
  11. }
  12. @GetMapping("/{currentPage}/{pageSize}")
  13. public R getAll(@PathVariable Integer currentPage,@PathVariable Integer pageSize){
  14. IPage<Book> page = bookService.getPage(currentPage, pageSize);
  15. return new R(true,page);
  16. }
  17. }

发表评论

表情:
评论列表 (有 0 条评论,127人围观)

还没有评论,来说两句吧...

相关阅读