SpringBoot2-基于SpringBoot2的SSMP基础整合案例-后端

1、创建模块,勾选

SpringBoot2-基于SpringBoot2的SSMP基础整合案例-后端_第1张图片

SpringBoot2-基于SpringBoot2的SSMP基础整合案例-后端_第2张图片

 2、配置pom.xml

  • 1)删除
springboot_08_ssmp
springboot_08_ssmp
  • 2)引入 MyBatis-Plus和Druid的依赖

    com.baomidou
    mybatis-plus-boot-starter
    3.4.3



    com.alibaba
    druid-spring-boot-starter
    1.2.6

3、实体类开发

  • 1)根据数据库里的表,制作对应的实体类
public class Book {
    private Integer id;
    private String type;
    private String name;
    private String description;
}
  • 2)使用Lombok,简化POJO实体类开发
    • ① 在pom.xml中添加Lombok坐标
    • ② 在实体类上加上@Data
      • @Data有getter、setter、toString、hashCode、equals等方法,但没有构造方法
        • 构造方法的注解:
          • @AllArgsConstructor:全部参数的构造方法
          • @NoArgsConstructor:无参的构造方法


    org.projectlombok
    lombok
@Data 
public class Book {
    private Integer id;
    private String type;
    private String name;
    private String description;
}

4、数据层开发 

  • 1)配置 MyBatis-Plus和Druid
spring:
  datasource:
    druid:
      driver-class-name: com.mysql.cj.jdbc.Driver
      url: jdbc:mysql://localhost:3306/ssm_crud?serverTimezone=UTC
      username: root
      password: 123abc

#设置mp相关配置
mybatis-plus:
  global-config:
    db-config:
      table-prefix: tbl_
  • 2)使用MP的标准通用接口BaseMapper加速开发,别忘了@Mapper和泛型的指定
@Mapper
public interface BookDao extends BaseMapper {
    
}
  • 3)测试-基础CRUD
    • MP技术默认的主键生成策略为雪花算法,生成的主键ID长度较大,和目前的数据库设定规则不相符,需要配置一下使MP使用数据库的主键生成策略  
    •  配置方法:id自增策略,在yml文件中添加id-type: auto
mybatis-plus:
  global-config:
    db-config:
      table-prefix: tbl_   #设置表名通用前缀
      id-type: auto   #设置主键id字段的生成策略为参照数据库设定的策略,当前数据库设置id生成策略为自增
  • 写测试类,测试增删改查
@SpringBootTest
public class BookDaoTestCase {

    @Autowired
    private BookDao bookDao;

    @Test
    void testGetById(){
        System.out.println(bookDao.selectById(1));
    }

    @Test
    void testSave(){
        Book book=new Book();
        book.setType("测试123");
        book.setName("测试123");
        book.setDescription("测试123");
        bookDao.insert(book);

    }

    @Test
    void testUpdate(){
        Book book=new Book();
        book.setId(53);
        book.setType("测试53");
        book.setName("测试123");
        book.setDescription("测试123");
        bookDao.updateById(book);

    }
    @Test
    void testDelete(){
        bookDao.deleteById(53);

    }
    @Test
    void testGetAll(){
        System.out.println(bookDao.selectList(null));

    }
}
  •  另:可添加MP运行日志,测试就不需要再写sout语句
    • 配置方法:在yml文件中添加下面两行
mybatis-plus:
  global-config:
    db-config:
      table-prefix: tbl_  #设置表名通用前缀
      id-type: auto  #设置主键id字段的生成策略为参照数据库设定的策略,当前数据库设置id生成策略为自增
  configuration:
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl   #控制台输出

总结:

  1. 手工导入starter坐标(2个),mysql驱动(1个)

  2. 配置数据源与MyBatisPlus对应的配置

  3. 开发Dao接口(继承BaseMapper)

  4. 制作测试类测试Dao功能是否有效

  5. 使用配置方式开启日志,设置日志输出方式为标准输出即可查阅SQL执行日志

  • 4)分页功能 
    • ① 写一个配置类
    • 要使用MP分页功能,需要打开一个开关,这个开关是通过MP的拦截器的形式存在的,需要定义MP拦截器并将其设置为Spring管控的bean
@Configuration //配置类
public class MyConfig {
    @Bean
    public MybatisPlusInterceptor mybatisPlusInterceptor(){
        //创建MP的拦截器
        MybatisPlusInterceptor interceptor=new MybatisPlusInterceptor();
        //添加分页拦截器
        interceptor.addInnerInterceptor(new PaginationInnerInterceptor());
        return interceptor;
    }
}
  • ②MP提供的分页操作API如下

SpringBoot2-基于SpringBoot2的SSMP基础整合案例-后端_第3张图片

  •  ③ 设定分页对象IPage 
    • IPage对象中封装了分页操作中的所有数据
@Test
void testGetPage(){
   IPage page=new Page(1,5);
   bookDao.selectPage(page,null);

   System.out.println(page.getCurrent());
   System.out.println(page.getSize());
   System.out.println(page.getTotal());
   System.out.println(page.getPages());
   System.out.println(page.getRecords());
}

总结:

  1. 使用IPage封装分页数据

  2. 分页操作依赖MyBatisPlus分页拦截器实现功能

  3. 借助MyBatisPlus日志查阅执行SQL语句

  • 5)条件查询功能
    • 使用LambdaQueryWrapper对象,所有查询操作封装成方法调用
@Test
void testGetBy2(){
    String name=null;
    LambdaQueryWrapper lqw=new LambdaQueryWrapper<>();
    //name为空时查询全部,不为空时按条件查询
    lqw.like(name!=null,Book::getName,name);  //API接口提供控制开关
    bookDao.selectList(lqw);
}

总结:

  1. 使用QueryWrapper对象封装查询条件

  2. 推荐使用LambdaQueryWrapper对象

  3. 所有查询操作封装成方法调用

  4. 查询条件支持动态条件拼装

 5、业务层开发

  • 1)接口定义
public interface BookService {

    Boolean save(Book book);
    Boolean update(Book book);
    Boolean delete(Integer id);
    Book getById(Integer id);
    List getAll();
    IPage getPage(int currentPage,int pageSize);
}
  • 2)实现类定义
@Service //定义成业务层对应的bean
public class BookServiceImpl implements BookService {

    @Autowired
    private BookDao bookDao;

    @Override
    public Boolean save(Book book) {

        return bookDao.insert(book)>0;
    }

    @Override
    public Boolean update(Book book) {
        return bookDao.updateById(book)>0;
    }

    @Override
    public Boolean delete(Integer id) {
        return bookDao.deleteById(id)>0;
    }

    @Override
    public Book getById(Integer id) {
        return bookDao.selectById(id);
    }

    @Override
    public List getAll() {
        return bookDao.selectList(null);
    }

    @Override
    public IPage getPage(int currentPage, int pageSize) {
        IPage iPage=new Page<>(currentPage,pageSize);
        bookDao.selectPage(iPage,null); //返回的类型还是iPage
        return iPage;
    }
}
  •  3)测试类定义
@SpringBootTest
public class BookServiceTestCase {

    //注入业务层对象
    @Autowired
    private BookService bookService;

    @Test
    void testGetById(){
        System.out.println(bookService.getById(1));
    }
    @Test
    void testSave(){
        Book book = new Book();
        book.setType("测试aaa");
        book.setName("测试aaa");
        book.setDescription("测试aaa");
        bookService.save(book);
    }
    @Test
    void testDeleteById(){
        bookService.delete(54);
    }

    @Test
    void testGetAll(){
        bookService.getAll();
    }
    @Test
    void testUpdate(){
        Book book = new Book();
        book.setId(13);
        book.setType("测试bbb");
        book.setName("测试aaa");
        book.setDescription("测试aaa");
        bookService.update(book);
    }
    @Test
    void testGetPage(){
        IPage page = bookService.getPage(2, 5);
        System.out.println(page.getCurrent());
        System.out.println(page.getSize());
        System.out.println(page.getTotal());
        System.out.println(page.getPages());
        System.out.println(page.getRecords());
    }
}

总结:

  1. Service接口名称定义成业务名称,并与Dao接口名称进行区分

  2. 制作测试类测试Service功能是否有效

 

 6、业务层快速开发

  • 1)业务层接口快速开发
public interface IBookService extends IService {
    //添加非通用操作API接口
}
  • 2)业务层接口实现类快速开发,继承的类需要传入两个泛型,一个是数据层接口,另一个是实体类  
@Service
public class BookServiceImpl extends ServiceImpl implements IBookService {
    @Autowired
    private BookDao bookDao;
	//添加非通用操作API
}
  • 3)测试
@SpringBootTest
public class BookServiceTest {

    //注入业务层对象
    @Autowired
    private IBookService bookService;

    @Test
    void testGetById(){
        System.out.println(bookService.getById(1));
    }
    @Test
    void testSave(){
        Book book = new Book();
        book.setType("测试ccc");
        book.setName("测试aaa");
        book.setDescription("测试aaa");
        bookService.save(book);
    }
    @Test
    void testDeleteById(){
        bookService.removeById(14);
    }

    @Test
    void testGetAll(){
        bookService.list();
    }
    @Test
    void testUpdate(){
        Book book = new Book();
        book.setId(13);
        book.setType("测试ddd");
        book.setName("测试aaa");
        book.setDescription("测试aaa");
        bookService.updateById(book);
    }
    @Test
    void testGetPage(){
        IPage page=new Page<>(2,5);
        bookService.page(page);
        System.out.println(page.getCurrent());
        System.out.println(page.getSize());
        System.out.println(page.getTotal());
        System.out.println(page.getPages());
        System.out.println(page.getRecords());
    }
}

总结:

  1. 使用通用接口(ISerivce)快速开发Service

  2. 使用通用实现类(ServiceImpl)快速开发ServiceImpl

  3. 可以在通用接口基础上做功能重载或功能追加

  4. 注意重载时不要覆盖原始操作,避免原始提供的功能丢失

7、表现层开发

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

    //注入业务层
    @Autowired
    private IBookService bookService;

    @GetMapping
    public List getAll(){
        return bookService.list();
    }

    @PostMapping
    public Boolean save(@RequestBody Book book){
        return bookService.save(book);
    }

    //传json数据要用@RequestBody
    @PutMapping
    public Boolean update(@RequestBody Book book){
        return bookService.updateById(book);
    }

    @DeleteMapping("/{id}")
    public Boolean delete(@PathVariable Integer id){
        return bookService.removeById(id);
    }

    @GetMapping("/{id}")
    public Book getById(@PathVariable Integer id){
        return bookService.getById(id);
    }
}

总结:

  1. 基于Restful制作表现层接口

    • 新增:POST

    • 删除:DELETE

    • 修改:PUT

    • 查询:GET

  2. 接收参数

    • 实体数据:@RequestBody

    • 路径变量:@PathVariable

 8、表现层消息一致性处理

  • 1)设计表现层返回结果的模型类,用于后端与前端进行数据格式统一,也称为前后端数据协议
    • flag用于标识操作是否成功,data用于封装操作数据
@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;
    }
}
  • 2)表现层接口统一返回值类型结果
@RestController
@RequestMapping("/books")
public class BookController {

    //注入业务层
    @Autowired
    private IBookService bookService;

    @GetMapping
    public R getAll(){
        return new R(true,bookService.list());
    }

    @PostMapping
    public R save(@RequestBody Book book){
        return new R(bookService.save(book));
    }

    //传json数据要用@RequestBody
    @PutMapping
    public R update(@RequestBody Book book){
        return new R(bookService.updateById(book));
    }

    @DeleteMapping("/{id}")
    public R delete(@PathVariable Integer id){
        return new R(bookService.removeById(id));
    }

    @GetMapping("/{id}")
    public R getById(@PathVariable Integer id){
        return new R(true,bookService.getById(id));
    }

    @GetMapping("{currentPage}/{pageSize}")
    public R getPage(@PathVariable int currentPage,@PathVariable int pageSize){
        return new R(true,bookService.getPage(currentPage,pageSize));
    }
}

总结:

  1. 设计统一的返回值结果类型便于前端开发读取数据

  2. 返回值结果类型可以根据需求自行设定,没有固定格式

  3. 返回值结果模型类用于后端与前端进行数据格式统一,也称为前后端数据协议

 

9、业务消息一致性处理

  • 1)修改表现层返回结果的模型类,封装出现异常后对应的信息,新增构造方法
@Data
public class R {
    private Boolean flag;
    private Object data;
    private String msg;

    public R(Boolean flag,String msg){
        this.flag=flag;
        this.msg=msg;
    }

    public R(String msg){
        this.flag=false;
        this.msg=msg;
    }
  • 2)对异常进行统一处理,出现异常后,返回指定信息
@RestControllerAdvice
public class ProjectExceptionAdvice {

    //拦截所有的异常信息
    @ExceptionHandler(Exception.class)
    public R doException(Exception ex){
        //记录日志
        //通知运维
        //通知开发
        ex.printStackTrace();
        return new R("服务器故障,请稍后再试!");
    }
}
  • 3)在表现层Controller中进行消息统一处理
@PostMapping
    public R save(@RequestBody Book book) throws IOException {

        if(book.getName().equals("123")) throw new IOException();//模拟失败
        boolean flag = bookService.save(book);

        return new R(flag,flag?"添加成功^_^":"添加失败-_-!");
    }
  • 4)页面消息处理
//添加
handleAdd () {
	//发送ajax请求
    axios.post("/books",this.formData).then((res)=>{
        //如果操作成功,关闭弹层,显示数据
        if(res.data.flag){
            this.dialogFormVisible = false;
            this.$message.success(res.data.msg);
        }else {
            this.$message.error(res.data.msg);			//消息来自于后台传递过来,而非固定内容
        }
    }).finally(()=>{
        //2.重新加载数据
        this.getAll();
    });
},

 

10、删除功能维护

  • 问题:由于使用了分页功能,当最后一页只有一条数据时,删除操作就会出现BUG,最后一页无数据但是独立展示
  • 解决方法:如果当前页码值大于总页码值,那么重新执行查询操作,使用最大页码值作为当前页码值
@GetMapping("{currentPage}/{pageSize}")
public R getPage(@PathVariable int currentPage,@PathVariable int pageSize){
    IPage page = bookService.getPage(currentPage, pageSize);
    //如果当前页码值大于了总页码值,那么重新执行查询操作,使用最大页码值作为当前页码值
    if( currentPage > page.getPages()){
        page = bookService.getPage((int)page.getPages(), pageSize);
    }
    return new R(true, page);
}

 

11、条件查询

  •  1)后台代码中定义实体类封查询条件,Controller接收参数
@GetMapping("{currentPage}/{pageSize}")
    public R getPage(@PathVariable int currentPage,@PathVariable int pageSize,Book book){
        IPage page = bookService.getPage(currentPage, pageSize,book);
        //如果当前页码值大于总页码值,那么重新执行查询操作,使用最大页码值作为当前页码值
        if(currentPage>page.getPages()){
            page = bookService.getPage((int) page.getPages(), pageSize,book);
        }
        return new R(true,page);
    }
  • 2)业务层接口功能开发
public interface IBookService extends IService {

    IPage getPage(int currentPage,int pageSize);

    IPage getPage(int currentPage, int pageSize, Book book);
}
@Service
public class BookServiceImpl extends ServiceImpl implements IBookService {
    @Autowired
    private BookDao bookDao;
    @Override
    public IPage getPage(int currentPage, int pageSize) {
        IPage page=new Page<>(currentPage,pageSize);
        bookDao.selectPage(page,null);
        return page;
    }

    @Override
    public IPage getPage(int currentPage, int pageSize, Book book) {
        LambdaQueryWrapper lqw=new LambdaQueryWrapper<>();
        lqw.like(Strings.isNotEmpty(book.getType()),Book::getType,book.getType());
        lqw.like(Strings.isNotEmpty(book.getName()),Book::getName,book.getName());
        lqw.like(Strings.isNotEmpty(book.getDescription()),Book::getDescription,book.getDescription());
        IPage page=new Page<>(currentPage,pageSize);
        bookDao.selectPage(page,lqw);
        return page;    }
}

 

 基于SpringBoot的SSMP整合案例总结:

  • 1.pom.xml
    • 配置起步依赖
  • 2.application.yml
    • 设置数据源、端口、框架技术相关配置等
  • 3.dao
    • 继承BaseMapper、设置@Mapper
  • 4.dao测试类
  • 5.service
    • 调用数据层接口或MyBatis-Plus提供的接口快速开发
  • 6.service测试类
  • 7.controller
    • 基于Restful开发,使用Postman测试跑通功能
  • 8.页面
    • 放置在resources目录下的static目录中

-----------------基于黑马Spring Boot2基础篇的整理-----------------

你可能感兴趣的:(java,spring,idea,maven,sql)