制作流程
导入依赖后Maven刷新
druid-spring-boot-starter//版本号
spring-webmvc
lombok//简化pojo开发
spring-boot-starter-jdbc
spring-boot-starter-web
mybatis-plus-boot-starter//版本号
mysql-connector-java
spring-boot-starter-test
实体类pojo:对应数据表单
-
实体类名=表名
-
属性=列名
-
驼峰命名问题可以选择关闭or打开
mybatis-plus: configuration: # 是否开启自动驼峰命名规则(camel case)映射, # 即从经典数据库列名 A_COLUMN(下划线命名) # 到经典 Java 属性名 aColumn(驼峰命名) 的类似映射 map-underscore-to-camel-case: false
在domain包下
//@AllArgsConstructor
//@NoArgsConstructor
//因为实际使用中都是用get set方法,所以不需要上面的构造器注释
@Data
public class t_user {
private Integer id;
private String name;
private String phone;
}
数据层开发:MybatisPlus+Druid
yml配置信息
server:
port: 80
spring:
datasource:
druid:
username: root
password: zjh521418
url: JDBC://localhost:3306/yeb
driver-class-name: com.mysql.cj.jdbc.Driver
#mybatis-plus:
# global-config:
# db-config:
# table-prefix: t_
## 表名前缀,例如t_jobLevel前缀就是这个
数据层开发Dao
数据层接口Dao:整合MP
- 接口是interface不是class!!!!
- 接口可以extends接口~
- 这个Dao接口要继承BaseMapper接口
- 使用之前要@Autowried注入Dao
@Mapper
public interface UserDao extends BaseMapper<t_user>{
}
@Data
public class t_user {
private Integer id;
private String name;
private String phone;
}
@Autowired
UserDao userDao;
MP:CRUD
@Test
public void testUserAdd(){
t_user tu = new t_user();
tu.setId(2);
tu.setName("sada");
tu.setPhone("5654653215");
userDao.insert(tu);
}
BUG记录
- java.lang.IllegalStateException: Failed to load ApplicationContext
Caused by: java.lang.NoSuchFieldError: APPLICATION_NDJSON
要保证命名规则相同 以及 属性类型对应
Mybatis-Plus的配置
开启日志:log下
log即日志
测试的时候可以开,但上线运行千万不要开,服务器会裂开
StdOutImpl:控制台输出
包括了创建sql+预编译+参数等信息
有了这个配置就不需要sout了
分页查询:拦截器+MP
创建MPconfig配置类:拦截器,固定操作
//Mybatis-plus配置类,需要在此添加拦截器才能正常实现分页查询
@Configuration
public class MPconfig {
@Bean
public MybatisPlusInterceptor mpi(){
//1,定义拦截器
MybatisPlusInterceptor mpi = new MybatisPlusInterceptor();
//2,添加具体的拦截器__PaginationInnerInterceptor分页查询拦截器
mpi.addInnerInterceptor(new PaginationInnerInterceptor());
//3,返回拦截器
return mpi;
}
}
数据层:分页查询
@Test
public void testUserPage(){
/*********分页查询*********/
IPage iPage = new Page(2,3);
//按顺序,每页size=3条数据,分页;选择第current=2页
userDao.selectPage(iPage, null);//第二个参数是queryWrapper条件
//这个方法还会返回这个iPage对象本身
System.out.println("*******iPage对象的6个属性值*******");
System.out.println(iPage.getCurrent());//2
System.out.println(iPage.getRecords());//[]
System.out.println(iPage.getSize());//3
System.out.println(iPage.getTotal());//0
System.out.println(iPage.getPages());//0
}
在yaml中配置了log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
如下的运行结果
条件查询:queryWrapper
简单查询
@Test
public void testUserQuery(){//基础的条件查询
QueryWrapper<t_user> qw = new QueryWrapper<>();//查询包实例化,绑定查询的表单
qw.like("name", "张三");
qw.like("id", 1);//多条like就是“且”
//查询id=1 name=张三 的数据
userDao.selectList(qw);//返回一个list
}
lambda表达式安全绑定
@Test
public void testUserLambdaQuery(){//加入lambda表达式防止写错字符
LambdaQueryWrapper<t_user> lqw = new LambdaQueryWrapper<>();//查询包实例化
lqw.like(t_user::getName, "aaaa");
//t_user是个pojo类
userDao.selectList(lqw);
}
lambda + if
@Test
public void testUserLambdaIf(){//lambda + if + 条件
String namefrom = "bbb";//前端传来的数据可能为null值
LambdaQueryWrapper<t_user> lqw = new LambdaQueryWrapper<>();
lqw.like(namefrom!=null , t_user::getName , namefrom);
//参数解析:
//条件1:如果前端传入的namefrom值不为空,数据才查询
//条件2:安全获取t_user的pojo类的name属性名
//条件3: 传入namefrom属性的值
userDao.selectList(lqw);
}
like条件查询的其他用法
业务层开发Service
相比数据层(关心如何跟数据库交互),业务层更关心业务名称,不要混用,例如:同样的登录操作,
- 在数据层的接口:selectByUserNameAndPassword( 形参 )
- 在业务层的接口:login( 形参 )
业务层也可以在调用数据层方法的同时,添加自己的逻辑
Service接口和实现类
-
实现类中注入Dao,那么使用时注入Service就可以通过Service使用Dao了
-
增删改的返回值用Boolean,查询才返回一个实体类
public interface UserService {//是接口 Boolean save(t_user u);// Boolean update(t_user u);// Boolean deleteById(Integer id);// t_user getById(Integer id);// List<t_user> getAll(); } /*******实现类**********/ @Service//注入业务层的bean public class UserServiceImpl implements UserService{//Impl就是implement @Autowired private UserDao userDao; //嵌套调用,因为使用中,需要注入Service //在Service中嵌套注入Dao //即可在业务层操作数据 @Override public Boolean save(t_user u) {//业务层的save对应数据层的insert return userDao.insert(u) > 0; //MybatisPlus定义的CRUD方法返回值是“修改了多少个数据” //因此判断 > 0 即可 } @Override public Boolean update(t_user u) { return userDao.update(u,null )>0; //在业务层中调用数据层的方法 } @Override public Boolean deleteById(Integer id) { return userDao.deleteById(id)>0; } @Override public t_user getById(Integer id) { return userDao.selectById(id); } @Override public List<t_user> getAll() { return userDao.selectList(null); } }
Service测试
@SpringBootTest
public class TUserServiceTestCase {
@Autowired
private UserService userService;
//注入业务层对象
@Test
public void testGetById(){
System.out.println(userService.getById(1));
//业务层看不了日志,所以需要打印
//如果查询结果有多个,则会报错
}}
Service层的分页查询
-
在Service接口中定义抽象方法 IPage<t_user> getPage(int currentPage,int pageSize);
-
在Service实现类中重写抽象方法
@Override public IPage<t_user> getPage(int currentPage, int pageSize) { IPage<t_user> iPage = new Page<>(currentPage,pageSize);//定义如何分页 return userDao.selectPage(iPage,null);//返回值本身就是ipage }
-
业务层进行查询没有log,需要sout输出
@Test public void testSelectByPage(){ System.out.println(userService.getPage(2, 2)); //返回一个ipage对象,但toString在@Service下已重载,可以正常输出 }
-
仍然需要保证注解的嵌套注入
-
下面证明BaseMapper接口下“分页查询selectPage”返回值就是形参ipage
IPage<t_user> iPage = new Page<>(currentPage,pageSize);//定义如何分页 IPage<t_user> iPage1 = userDao.selectPage(iPage, null);//返回值本身就是ipage System.out.println(iPage==iPage1);//true
为什么有了MP,还要重写这么多方法?
因为mybatispplus的核心功能是封装dao层,dao层不用写sql语句;对业务层的封装是次要的;而业务层的很多功能例如:getbyid等方法,如果不重写,返回值都是一个int类型,但前端axios请求的逻辑一般是“先判断有没有”所以需要后端返回给前端一个boolean类型的数据进行判断,所以在实际业务开发中,mp对dao层的封装可以直接使用,而业务层需要跟前端交互,一些常用的方法如:CRUD,分页查询,需要用业务层的返回值为boolean类型的方法来调用已经封装好的dao方法,间接操作数据库,并且返回值boolean可以交给前端进行判断。
因此即便是使用了mybatisplus,业务层重写封装的方法也是很有必要的
MP业务层快速开发
MP不光简化了数据层的操作(在Dao上@Mapper,并extends BaseMapper<>,就能直接调用CRUD)
MP还简化了业务层的开发~(IService<>接口)
MP业务层接口
@Service
public interface IMPUserService extends IService<t_user> {//继承IService
//idea下Ctrl+O查看IService提供的方法
//还可以自己再根据业务添加方法
//I开头表示接口,MP代表mybatis plus整合业务层快速开发
//这里面可以写抽象方法,自定义业务层的方法
}
MP业务层实现类
package com.bootadmin1.bootajaxtest.service.impl;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.bootadmin1.bootajaxtest.service.IMPUserService;
import com.bootadmin1.bootajaxtest.dao.UserDao;
import com.bootadmin1.bootajaxtest.domain.t_user;
//导入了4个必要的包,4个类都被MP托管了
import org.springframework.stereotype.Service;
/**
* @author zjh
* @create 2022-01-25 18:49
*/
//@Service之后可以被Spring托管,才能注入后使用
@Service
public class MPUserServiceImpl extends ServiceImpl<UserDao,t_user> implements IMPUserService {
//继承ServiceImpl可以免去写很多个IMPUserService的重载方法
//泛型指定Dao和实体类
//同时实现“实现了IService接口”的接口IMPUserService
//现在就可以不用手动重写那么多的方法了,Ctrl+O可以看能用的方法
}
需要添加自定义方法的话,跟不用Mybatisplus托管操作是一样的
测试
@Autowired
private IMPUserService impUserService;
//注入MP快速搭建的业务层接口@Service
//查get
@Test
public void testGetById(){
t_user byId = impUserService.getById(1);//这个方法是MP提供的
//只要实现了IService接口就能使用这些个方法
System.out.println(byId);
}
调用分析
-
public interface IMPUserService extends IService<实体类>
-
@Service
public class MPUserServiceImpl extends ServiceImpl<Dao,实体类> implements IMPUserService -
@Test @Autowired 注入父类子类都OK,多态性的体现
@Autowired private IMPUserService impUserService; //private 其子类MPUserServiceImpl也可以 impUserService;
表现层开发Controller
package com.bootadmin1.bootajaxtest.controller;
import com.bootadmin1.bootajaxtest.domain.t_user;
import com.bootadmin1.bootajaxtest.service.IMPUserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.List;
/**
* @author zjh
* @create 2022-01-25 19:45
*/
@RestController
@RequestMapping("/users")//users是有说法的,复数嘛
public class UserController {
@Autowired
private IMPUserService impUserService;
//同样因为多态性,这里也可以注入其子类
@GetMapping
public List<t_user> getAll(){
return impUserService.list();
}
//增:Post提交,save:mp的保存方法
@PostMapping
public boolean save(@RequestBody t_user u){
// @ResponseBody请求体参数,异步提交json数据
return impUserService.save(u);
}
//改:Put提交,update:mp的修改方法
@PutMapping
public boolean updata(@RequestBody t_user u){
return impUserService.updateById(u);
}
//http://localhost:8080/users/id
@DeleteMapping("{id}")
public boolean delete(@PathVariable Integer id){
//@PathVariable表示从url路径获取的变量
return impUserService.removeById(id);
}
@GetMapping("{id}")
public t_user getByid(@PathVariable Integer id){
return impUserService.getById(id);
}
}
postman测试
查所有
ID查
增
- 换Post提交
- Body下选raw,换位JSON,写JSON字符串
然后把数据设置合理
改
分页查询:自定义
业务层接口定义抽象方法
public interface IMPUserService extends IService<t_user> {//继承IService
//idea下Ctrl+O查看IService提供的方法
//还可以自己再根据业务添加方法
//I开头表示接口,MP代表mybatis plus整合业务层快速开发
IPage<t_user> getPage(int current,int size);
}
业务层实现类实现抽象方法:需要注入Dao
//@Service之后可以被Spring托管,才能注入后使用
@Service
public class MPUserServiceImpl extends ServiceImpl<UserDao,t_user> implements IMPUserService {
//继承ServiceImpl可以免去写很多个IMPUserService的重载方法
//泛型指定Dao和实体类
//同时实现“实现了IService接口”的接口IMPUserService
//现在就可以不用手动重写那么多的方法了,Ctrl+O可以看能用的方法
@Autowired
private UserDao userDao;
//自定义方法肯定需要注入Dao来操作数据库了
@Override
public IPage<t_user> getPage(int current, int size) {
Page<t_user> ipage = new Page<>(current, size);
return userDao.selectPage(ipage,null );
}
}
表现层控制请求
//分页查询
@GetMapping("{current}/{size}")
public IPage<t_user> getPages(@PathVariable Integer current, @PathVariable Integer size){
return impUserService.getPage(current,size );//调用自定义的方法
}
Restful风格总结
基于Restful风格制作的表现层接口
- 增:POST
- 删:DELETE
- 改:PUT
- 查:GET
对于增,改操作,会从客户端读取数据参数
- 实体数据:@RequestBody
- 路径变量:@PathVariable