栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

Springboot进行SSMP整合案例笔记

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

Springboot进行SSMP整合案例笔记

学习链接

模块创建
实体类快速开发(lombok)
数据层标准开发(基础CRUD)
开启MP运行日志
分页
数据层标准开发(条件查询)
业务层标准开发(基础CRUD)
业务层快速开发(基于MyBatisPlus构建)
表现层标准开发
表现层数据一致性处理(R对象)
前后端调用(axios发送异步请求)
列表功能
添加功能
删除功能
修改功能(加载数据)
修改功能
异常消息处理
分页
分页功能维护(删除BUG)
条件查询
完结

模块创建:
勾选SpringMVC与MYSQL坐标
(手动添加Mybatis Plus和Druid的坐标)
修改配置文件为yml格式
设置服务器端口8080

学习笔记 1.模块创建

1.勾选SpringMVC与MYSQL坐标
(手动添加Mybatis Plus和Druid的坐标)
2.修改配置文件为yml格式
3.设置服务器端口8080

```xml
        
            com.baomidou
            mybatis-plus-boot-starter
            3.4.3
        
        
            com.alibaba
            druid-spring-boot-starter
            1.2.6
        
2.实体类快速开发

利用lombok进行实体类快速开发。
lombok:一个java类库,提供一组注解用于简化POJO实体类开发
1.导入lombok坐标,版本号由SpringBoot提供,故无需指定

        
            org.projectlombok
            lombok
        

2.@Data注解

//@Data代表了@Getter,@Setter等,包含有get,set,toString,hashCode,equals等方法

//@AllArgsConstructor // 有参构造
//@NoArgsConstructor // 无参构造
//实体类一般无参构造,而类默认有无参构造器,
@Data
public class Brand {
    private int id;
    private String brand_name;
    private String company_name;
    private int ordered;
    private String description;
    private int status;
    
}

补:查看实体类含有的方法;Alt+7

可以看出lombok的@Data帮助快速实现了get(),set(),toString(),hashCode()方法
补充:如果测试发现toString()方法打印String类型的数据是null,我这里原因是数据库和实体类里该变量名中有_,命名不用_即可。
如:brand_name 改为brandname

3.数据层标准开发(基础CRUD)

1.druid和Mybatisplus第三方技术坐标添加,
2.配置数据源与MybatisPlus对应配置
3.开发数据层Dao接口(继承BaseMapper,泛型是实体类)
4.制作测试类测试Dao功能是否有效
整合的druid的数据源配置方式:

server:
  port: 8080
#配置数据库链接和druid
spring:
  datasource:
    druid:
      driver-class-name: com.mysql.cj.jdbc.Driver
      url: jdbc:mysql://localhost:3306/ssm_db
      username: root
      password: 1234

#挂上表名前缀
mybatis-plus:
  global-config:
    db-config:
      table-prefix: tb_

数据层dao.BrandDao创建

package com.tsdusl.dao;

import com.tsdusl.domain.Brand;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Select;

@Mapper
public interface BrandDao {

    //Mybatis格式,Mybatis plus可以快速实现
    @Select("select * from tb_brand where id = #{id}")
    public Brand getById(Integer id);

}

测试dao.BrandDaoTestCase

package com.tsdusl.dao;

import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

@SpringBootTest
public class BrandDaoTestCase {

    @Autowired
    private BrandDao brandDao;
    @Test
    void testgetById() {
        System.out.println(brandDao.getById(1));
    }
}

数据层dao.BrandDao用Mybatis plus实现
只需要将该数据层接口继承BaseMapper,且泛型写我们要处理的实体类名即可

package com.tsdusl.dao;

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.tsdusl.domain.Brand;
import org.apache.ibatis.annotations.Mapper;

@Mapper
public interface BrandDao extends BaseMapper {
    //指定泛型Brand,使之数据层DAO知道自己对哪个实体类操作

}

Ctrl+F12查看当前接口继承的方法

数据库的id自增需要在yml文件中添加配置

#挂上表名前缀
mybatis-plus:
  global-config:
    db-config:
      table-prefix: tb_
      id-type: auto

测试:

package com.tsdusl.dao;

import com.tsdusl.domain.Brand;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

@SpringBootTest
public class BrandDaoTestCase {

    @Autowired
    private BrandDao brandDao;

    @Test
    void testselectById() {
        System.out.println(brandDao.selectById(1));
    }

    @Test
    void testSave(){
        Brand brand = new Brand();
        brand.setBrandname("lgt");
        brand.setCompanyname("nuaa");
        brand.setOrdered(1111);
        brand.setDescription("冲啊java");
        brand.setStatus(1);
        brandDao.insert(brand);
    }

    @Test
    void testUpdate(){
        Brand brand = new Brand();
        brand.setId(1);
        brand.setBrandname("lgt");
        brand.setCompanyname("nuaa");
        brand.setOrdered(1111);
        brand.setDescription("冲啊java");
        brand.setStatus(1);
        brandDao.updateById(brand);
    }
    @Test
    void testDelete(){
        brandDao.deleteById(49);
        brandDao.deleteById(50);
        brandDao.deleteById(51);
        brandDao.deleteById(52);
        brandDao.deleteById(53);
        brandDao.deleteById(54);
        brandDao.deleteById(1);
    }

    @Test
    void testGetALl(){
        System.out.println(brandDao.selectList(null));
        //这里是条件选择,设置为null则为没有条件限制,全部选择
    }


}

4.开启MP运行日志

添加日志配置

mybatis-plus:
  global-config:
    db-config:
      table-prefix: tb_
      id-type: auto
  configuration:
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl # 日志选择配置

如此以来,可在控制台实现MP对数据库进行的详细操作,那么test时也就不用输出了,只需要调用DAO的方法,具体对数据库操作的细节会由日志在控制台打出。开发测试的时候启用日志,上线服务器的时候不能开启,否则服务器难以承受。

5.分页

MP虽然实现了分页功能,但是使用与否需要自行设置;使用的话需要添加拦截器,拦截器通过配置文件添加,该配置文件要在Application文件所在包下才能被扫描到
添加config包和类;

package com.tsdusl.config;

import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

//@Configuration将其设置成配置类,使之配置信息能够被读取到
@Configuration
public class MPConfig {
    //不论做什么,本质还是spring,即都得受spring管理,而spring是管理bean的
    //使用Spring管理第三方bean的方式将bean初始化出来并将其加载给spring环境
    //第三方Bean的配置方式@Bean
    @Bean
    public MybatisPlusInterceptor mybatisPlusInterceptor(){
    //定义MP拦截器
        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();//创建拦截器的壳
        //添加具体拦截器
        interceptor.addInnerInterceptor(new PaginationInnerInterceptor());//向拦截器壳内添加page拦截器
        return interceptor;
    }
    //这里主要是创建了一个bean交给Spring,这个Bean是一个MybatisPlus的拦截器,具体拦截器是Page拦截器
}

分页测试,selectPage返回的是Ipage,其中封装了所有与page相关的数据

    @Test
    void testGetPage(){
        IPage page = new Page(1,5);
        brandDao.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());
    }

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

6.数据层标准开发(条件查询)
    @Test
    void testGetBy(){
        //queryWrapper就是查询条件
        //创建对象,泛型是实体类名
        QueryWrapper qw = new QueryWrapper<>();
        //添加条件,属性名写错的话会运行出错
        qw.like("brandname","华");
        brandDao.selectList(qw);
    }

    @Test
    void test2GetBy(){
        String s_brandname = "null";
        QueryWrapper lqw = new QueryWrapper<>();
        lqw.like(s_brandname != null,Brand::getBrandname, s_brandname);
        brandDao.selectList(lqw);
    }
7.业务层标准开发(基础CRUD)

数据层直接操作数据库
业务层进行实际业务的操作,复合调用数据层接口方法
创建业务接口及其实现类:

业务层接口创建:

package com.tsdusl.service;

import com.baomidou.mybatisplus.core.metadata.IPage;
import com.tsdusl.domain.Brand;

import java.util.List;

public interface BrandService {
    Boolean save(Brand brand);
    Boolean update(Brand brand);
    Boolean deleteById(Integer id);
    Brand getById(Integer id);
    List getAll();
    IPage getPage(int currentPage,int pagesize);

}

业务层实现类创建:
要@Service将其定义为业务层对应的Bean

package com.tsdusl.impl;

import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.tsdusl.dao.BrandDao;
import com.tsdusl.domain.Brand;
import com.tsdusl.service.BrandService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.List;

@Service //定义为业务层对应的bean
public class BrandServiceimpl implements BrandService {

    @Autowired
    private BrandDao brandDao;

    @Override
    public Boolean save(Brand brand) {
        return brandDao.insert(brand) > 0;
        //可以看到数据层的函数是针对数据库直接操作的,是影响数据库行的
        //insert返回int行数,故 > 0 表示添加成功
    }

    @Override
    public Boolean update(Brand brand) {
        return brandDao.updateById(brand) > 0;
    }

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

    @Override
    public Brand getById(Integer id) {
        return brandDao.selectById(id);
    }

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

    @Override
    public IPage getPage(int currentPage,int pagesize) {
        IPage page = new Page(currentPage,pagesize);
        return brandDao.selectPage(page,null);
    }
}

测试类:

package com.tsdusl.service;

import com.baomidou.mybatisplus.core.metadata.IPage;
import com.tsdusl.domain.Brand;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

@SpringBootTest
public class BrandServiceTestCase {

    //注入业务层对象
    @Autowired
    private BrandService brandService;

    @Test
    void testgetById(){
        System.out.println(brandService.getById(4));;
    }

    @Test
    void testSave(){
        Brand brand = new Brand();
        brand.setBrandname("lgt");
        brand.setCompanyname("nuaa");
        brand.setOrdered(1111);
        brand.setDescription("冲啊java");
        brand.setStatus(1);
        brandService.save(brand);
    }

    @Test
    void testUpdate(){
        Brand brand = new Brand();
        brand.setId(1);
        brand.setBrandname("lgt");
        brand.setCompanyname("nuaa");
        brand.setOrdered(1111);
        brand.setDescription("冲啊java");
        brand.setStatus(1);
        brandService.update(brand);
    }
    @Test
    void testDelete(){
        brandService.deleteById(55);
    }

    @Test
    void testGetALl(){
        System.out.println(brandService.getAll());;
        //这里是条件选择,设置为null则为没有条件限制,全部选择
    }

    @Test
    void testgetPage(){
        IPage page = brandService.getPage(1,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());
    }
}

8.业务层快速开发(基于MyBatisPlus构建)

使用MyBatisPlus提供的业务层通用接口IService<实体类>和ServiceImpl<数据层接口,实体类>
service接口:

package com.tsdusl.service;

import com.baomidou.mybatisplus.extension.service.IService;
import com.tsdusl.domain.Brand;

public interface IBrandService extends IService {
}

实现类:

package com.tsdusl.service.impl;

import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.tsdusl.dao.BrandDao;
import com.tsdusl.domain.Brand;
import com.tsdusl.service.IBrandService;
import org.springframework.stereotype.Service;

@Service
public class BrandServiceImpl extends ServiceImpl implements IBrandService {

}

9.表现层标准开发

基于Restful进行表现层接口开发
使用Postman测试表现层接口功能

区分不同请求所对应的表现层方法:
信号区分:
get查询
post添加
put修改
delete删除

数据传输方式区分:
@RequestBody:通过请求体传输的JSON数据
@PathVariable ,(“/{id}”)通过路径参数传参

controller包下的BrandController.java:

package com.tsdusl.controller;

import com.baomidou.mybatisplus.core.metadata.IPage;
import com.tsdusl.domain.Brand;
import com.tsdusl.service.IBrandService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import java.util.List;

@RestController
@RequestMapping("/brands")
public class BrandController {

    @Autowired // 自动装配
    private IBrandService brandService;

    @GetMapping //定义该请求为get信号
    public List getAll(){
        return brandService.list();
    }

    @PostMapping
    public Boolean save(@RequestBody Brand brand){
        return brandService.save(brand);
    }
    //保存和修改一般用 @RequestBody表示接收的数据是通过请求体传输的JSON数据
    @PutMapping
    public Boolean update(@RequestBody Brand brand){
        return brandService.updateById(brand);
    }

    @DeleteMapping("/{id}")
    public Boolean delete(@PathVariable Integer id){
        return brandService.removeById(id);
    }
    //删除和获取单个,一般是使用路径变量来传参("{id}")
    //例如://localhost:8080/books/2
    @GetMapping("/{id}")
    public Brand getById(@PathVariable Integer id){
        return brandService.getById(id);
    }

    @GetMapping("/{currentPage}/{pageSize}")
    public IPage getPage(@PathVariable int currentPage,@PathVariable int pageSize){
        return brandService.getPage(currentPage,pageSize);
    }

}

业务端接口新增自己创建的分页方法:

    IPage getPage(int currentPage,int pageSize);

10.表现层数据一致性处理(R对象)

表现层数据返回给前端使用

封装到data中,以便前端取数据

设计表现层返回结果的模型类,用于后端与前端进行数据格式统一,也称为前后端数据协议


R类:

package com.tsdusl.controller.utils;

import lombok.Data;

@Data
public class R {
    private Boolean flag;
    private Object data;

    public R() {
    }

    public R(Boolean flag, Object data) {
        this.flag = flag;
        this.data = data;
    }

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

controller.BrandController返回值修改为R类型:

package com.tsdusl.controller;

import com.tsdusl.controller.utils.R;
import com.tsdusl.domain.Brand;
import com.tsdusl.service.IBrandService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

@RestController
@RequestMapping("/brands")
public class BrandController {

    @Autowired // 自动装配
    private IBrandService brandService;

    @GetMapping //定义该请求为get信号
    public R getAll(){
        return new R(true, brandService.list());
    }

    @PostMapping
    public R save(@RequestBody Brand brand){
        return new R(brandService.save(brand));
    }
    //保存和修改一般用 @RequestBody表示接收的数据是通过请求体传输的JSON数据
    @PutMapping
    public R update(@RequestBody Brand brand){
        return new R(brandService.updateById(brand));
    }

    @DeleteMapping("/{id}")
    public R delete(@PathVariable Integer id){
        return new R(brandService.removeById(id));
    }
    //删除和获取单个,一般是使用路径变量来传参("{id}")
    //例如://localhost:8080/books/2
    @GetMapping("/{id}")
    public R getById(@PathVariable Integer id){
        return new R(true,brandService.getById(id));
    }

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

}
11.前后端调用(axios发送异步请求)

钩子函数是用来完成页面加载时的部分数据初始化工作
这里利用钩子函数调用methods中的getAll(),然后发送axios异步请求访问/brands资源,得到返回数据res,我们记得之前后端表现层设计时,返回的是R类型,那么.data即可获取其数据。

        //钩子函数,VUE对象初始化完成后自动执行
        created() {
            //调用查询全部数据的操作
            this.getAll();
        },

        methods: {
            //列表
            getAll() {
                console.log("run getAll()...")
                //发送异步请求axios
                axios.get("/brands").then((res)=>{
                    console.log(res.data);
                })
            },

这些静态资源放在resources.static包下:

12.列表功能

这里设:

        methods: {
            //列表
            getAll() {
                // console.log("run getAll()...")
                //发送异步请求axios
                axios.get("/brands").then((res)=>{
                    // console.log(res.data);
                    this.dataList = res.data.data;
                })
            },
13.添加功能

这里设置的弹窗表格添加,几个与按钮绑定的函数如下:

            //弹出添加窗口
            handleCreate() {
                this.dialogFormVisible = true;
                this.resetForm();//用于每次打开表单时,清楚其上次的数据信息
            },

            //重置表单,用于每次打开表单时,清楚其上次的数据信息
            resetForm() {
                this.formData = {};
            },

            //添加
            handleAdd () {
                //发送请求时要把数据发送过去,即formdata
                axios.post("/brands",this.formData).then((res)=>{
                    // console.log(res.data);
                    //判断当前操作是否成功
                    if(res.data.flag){
                        //关闭弹层,重新加载数据
                        this.dialogFormVisible = false;
                        this.$message.success("添加成功");//用于提醒用户操作成功与否
                    }else{
                        this.$message.error("添加失败");
                    }
                }).finally(()=>{
                    this.getAll();//不管成功与否,都要加载所有数据,所以用finally做最后操作
                })
            },

            //取消
            cancel(){
                this.dialogFormVisible = false;
                this.$message.info("当前操作取消");
            },
14.删除功能

界面编辑的删除处scope概念:

 
15.修改功能(加载数据)

通过传递当前行数据的id到后台查询;
利用前端数据双向绑定将查询到的数据进行回显;

//弹出编辑窗口//查询数据进行回显
            handleUpdate(row) {
                axios.get("/brands/" + row.id).then((res)=>{
                    if(res.data.flag && res.data.data != null){
                        // this.$message.success("删除成功");//用于提醒用户操作成功与否
                        this.formData = res.data.data;
                        this.dialogFormVisible4Edit = true;
                    }else{
                        this.$message.error("数据同步异常,操作失败");
                    }
                })
            },

16.修改功能
            //修改
            handleEdit() {
                axios.put("/brands",this.formData).then((res)=>{
                    //判断当前操作是否成功
                    if(res.data.flag){
                        //关闭弹层,重新加载数据
                        this.dialogFormVisible4Edit = false;
                        this.$message.success("修改成功");//用于提醒用户操作成功与否
                    }else{
                        this.$message.error("修改失败");
                    }
                }).finally(()=>{
                    this.getAll();//不管成功与否,都要加载所有数据,所以用finally做最后操作
                })
            },
17.异常消息处理

表现层手动添加异常进行异常测试:

    @PostMapping
    public R save(@RequestBody Brand brand) throws IOException {
        if(brand.getBrandname().equals("123")){
            throw new IOException();//手动添加异常进行异常测试
        }
        return new R(brandService.save(brand));
    }

SpringMVC中提供专用的异常处理器,通过该异常处理器可以进行异常处理。
SpringMvc属于Controller技术,所以在control.utils下创建类:

package com.tsdusl.controller.utils;

import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;

//作为springmvc的异常处理器,至于业务层,数据层的异常,最终会抛到表现层
//@RestControllerAdvice:定义为Controller的异常处理器
@RestControllerAdvice
public class ProjectExceptionAdvice {

    //如下定义一个方法并添加注解@ExceptionHandler即可实现拦截所有异常信息
    @ExceptionHandler
    public R doException(Exception ex){
        //记录日志,通知运维,开发
        ex.printStackTrace();//控制台报异常
        //前端处理,应该接收R类型数据,但是俩个成员变量不足,需补充成员变量
        return new R(false,"服务器故障,稍后再试");
    }
}

@Data
public class R {
    private Boolean flag;
    private Object data;
    private String msg;
18.分页

使用el分页组件——定义分页组件绑定的数据模型——异步调用获取分页数据——进行分页数据回显。
前端分页组件:

 
            

分页代码,注意分页返回的res.data.data中的records才是列表数据:

            //列表//分页查询
            getAll() {
                // console.log("run getAll()...")
                //发送异步请求axios
                axios.get("/brands/" + this.pagination.currentPage + "/" + this.pagination.pageSize).then((res)=>{
                    // console.log(res.data);
                    this.pagination.currentPage = res.data.data.current;
                    this.pagination.pageSize = res.data.data.size;
                    this.pagination.total = res.data.data.total;
                    this.dataList = res.data.data.records;//这里分页查询后端返回的data是页面信息,其中包含列表数据以及页面格式

                })
            },

            //切换页码
            exchangeCurrentChange(currentPage) {
                this.pagination.currentPage = currentPage;
                this.getAll();
            },
19.分页功能维护(删除BUG)

对查询结果进行校验,若当前页码值大于最大页码值,使用最大页码值作为当前页码值进行查询:

    @GetMapping("/{currentPage}/{pageSize}")
    public R getPage(@PathVariable int currentPage,@PathVariable int pageSize){
        //判断当前查询页面是否大于实际有的页面,大于的话返回最后一页。
        IPage page = brandService.getPage(currentPage, pageSize);
        if(page.getPages() < currentPage ){
            page = brandService.getPage((int)page.getPages(), pageSize);
        }
        return new R(true,page);
    }
20.条件查询

先将前端的输入框数据收集并绑定到创建的数据模型上,
因为条件查询也是查询之一,在分页查询之中,因此可在分页组件的数据模型中添加条件数据模型:

pagination: {//分页相关模型数据
                currentPage: 1,//当前页码
                pageSize:5,//每页显示的记录数
                total:0,//总记录数
                brandname: "",
                companyname: "",
                description:  ""
            }
查询 新建

条件传到后端后,需要在业务层接口与实现类进行新的getAll函数的重载:
从表现层getAll传到业务层,进行数据的处理:

    @Override
    public IPage getPage(int currentPage, int pageSize, Brand brand) {
        LambdaQueryWrapper lqw = new LambdaQueryWrapper<>();
        lqw.like(Strings.isNotEmpty(brand.getBrandname()),Brand::getBrandname,brand.getBrandname());
        lqw.like(Strings.isNotEmpty(brand.getCompanyname()),Brand::getCompanyname,brand.getCompanyname());
        lqw.like(Strings.isNotEmpty(brand.getDescription()),Brand::getDescription,brand.getDescription());
        IPage page = new Page(currentPage,pageSize);
        brandDao.selectPage(page,lqw);
        return page;
    }

(我这里用的自己的数据库表,里面有排名,ordered初始值为0,查询又没有设置排名,导致界面无数据)

21.完结


总结

提示:这里对文章进行总结:

例如:以上就是今天要讲的内容,本文仅仅简单介绍了pandas的使用,而pandas提供了大量能使我们快速便捷地处理数据的函数和方法。

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/839526.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号