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

文章目录

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

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

【基础篇】五、基于SpringBoot来整合SSM的案例(上)_第1张图片

0、创建模块

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

【基础篇】五、基于SpringBoot来整合SSM的案例(上)_第2张图片

1、实体类的快速开发Lombok

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


<dependency>
	<groupId>org.projectlombokgroupId>
	<artifactId>lombokartifactId>
dependency>

表结构:

【基础篇】五、基于SpringBoot来整合SSM的案例(上)_第3张图片

实体类:

@Data
public class Book {
	private Integer id;
	private String type;
	private String name;
	private String description;
}

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

2、数据层开发(CRUD)

导入MyBatisPlus与Druid对应的starter:

<dependency>
	<groupId>com.baomidougroupId>
	<artifactId>mybatis-plus-boot-starterartifactId>
	<version>3.4.3version>
dependency>

<dependency>
	<groupId>com.alibabagroupId>
	<artifactId>druid-spring-boot-starterartifactId>
	<version>1.2.6version>
dependency>

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

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

继承BaseMapper并指定泛型:

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

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

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

单元测试看效果:

@SpringBootTest
public class BookDaoTest {

	@Autowired
	private BookDao bookDao;
	
	@Test
	void testSave() {
		Book book = new Book();
		book.setName("测试数据");
		book.setType("测试类型");
		book.setDescription("测试描述数据");
		bookDao.insert(book);
	}
	...
}

3、分页

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

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

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

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

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

@Configuration
public class MpConfig {
	@Bean
	public MybatisPlusInterceptor mpInterceptor() {
		//1.定义Mp拦截器
		MybatisPlusInterceptor mpInterceptor = new MybatisPlusInterceptor();
		//2.添加具体的拦截器
		mpInterceptor.addInnerInterceptor(new PaginationInnerInterceptor());
		return mpInterceptor;
	}
}

4、条件查询

关于条件查询:

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

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

@Test
void testGetByCondition(){
	QueryWrapper<Book> qw = new QueryWrapper<>();
	qw.like("name","Spring");
	bookDao.selectList(qw);
}

@Test
void testGetByCondition(){
	IPage page = new Page(1,10);
	LambdaQueryWrapper<Book> lqw = new LambdaQueryWrapper<Book>();
	lqw.like(Book::getName,"Spring");
	bookDao.selectPage(page,lqw);
}

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

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

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

5、业务层的标准开发

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

//Mapper
selectByUserNameAndPassword(String username,String password);
//Service
login(String username,String password);

Service层接口定义:

public interface BookService {

	boolean save(Book book);
	
	boolean delete(Integer id);
	
	boolean update(Book book);
	
	Book getById(Integer id);
	
	List<Book> getAll();
	
	IPage<Book> getByPage(int currentPage,int pageSize);
	
}

写实现类:

@Service
public class BookServiceImpl implements BookService {

	@Autowired
	private BookDao bookDao;
	
	public Boolean save(Book book) {
		return bookDao.insert(book) > 0;
	}
	
	public Boolean delete(Integer id) {
		return bookDao.deleteById(id) > 0;
	}
	
	public Boolean update(Book book) {
		return bookDao.updateById(book) > 0;
	}
	
	public Book getById(Integer id) {
		return bookDao.selectById(id);
	}
	
	public List<Book> getAll() {
		return bookDao.selectList(null);
	}
	
	public IPage<Book> getByPage(int currentPage, int pageSize) {
		IPage page = new Page<Book>(currentPage,pageSize);
		return bookDao.selectPage(page,null);
	}
}

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

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

【基础篇】五、基于SpringBoot来整合SSM的案例(上)_第4张图片

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

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

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

@Service
public class BookServiceImpl2 extends ServiceImpl<BookDao,Book> implements IBookService {

	@Autowired
	private BookDao bookDao;
	
	public Boolean insertSome(Book book) {
		return bookDao.insert(book) > 0;
	}
}

总结就是:

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

7、表现层开发

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

@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.insert(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("/{currentPage}/{pageSize}")
	public List<Book> getAll(@PathVariable Integer currentPage,@PathVariable Integer pageSize){
		return bookService.getPage(currentPage,pageSize).getRecords();
	}
		
}

//接口功能实现,但返回结果不统一
//待续...

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

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

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

//属性自己决定,平时用msg和data,这个flag看的我别扭
@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;
	}
	//也可以定义个静态方法,里面封装构造方法
	public static R success(Object data){
		return new R(ture,data)
	}
}

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

@RestController
@RequestMapping("/books")
public class BookController {

	@Autowired
	private IBookService bookService;
	
	...
	@GetMapping
	public R getAll(){
		List<Book> bookList = bookService.list();
		return new R(true ,bookList);
	}
	
	@GetMapping("/{currentPage}/{pageSize}")
	public R getAll(@PathVariable Integer currentPage,@PathVariable Integer pageSize){
		IPage<Book> page = bookService.getPage(currentPage, pageSize);
		return new R(true,page);
	}
}

你可能感兴趣的:(SpringBoot,spring,boot,后端,java)