文章目录
- 0、创建模块
- 1、实体类的快速开发Lombok
- 2、数据层开发(CRUD)
- 3、分页
- 4、条件查询
- 5、业务层的标准开发
- 6、业务层的快速开发(基于MyBatisPlus)
- 7、表现层开发
接下来在SpringBoot下,把Spring、SpringMVC、MyBatis整合在一起,来实现一个简单的增删改查。
0、创建模块
创建新模块,勾选spring-web(SpringMVC)以及MySQL的驱动,再手动导入MyBatisPlus以及Druid的依赖坐标:
1、实体类的快速开发Lombok
Lombok,一个Java类库,提供了一组注解,用来简化POJO实体类开发。
<!-- 不用指定版本,lombok在SpringBoot的管理范围之内 -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
表结构:
实体类:
@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.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.4.3</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>1.2.6</version>
</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接口,泛型传入实体类,即可有上面标准开发的那些方法。另外你业务需要的定制的方法,自己接着写就行。
此时的实现类:注意泛型中的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<T>)与
业务层通用实现类(ServiceImpl<M,T>)
- 在通用类基础上做功能重载或功能追加
- 注意重载时不要覆盖原始操作,避免原始提供的功能丢失
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】