07-SpringBoot+MyBatis+Spring 技术整合实现商品品牌模块的CRUD操作

需求分析

任何一个电商系统中都有一个商品子系统,而与商品相关联都会有一个品牌信息管理,在当前业务系统设计中我们就是要对商品品牌信息进行设计和实现。

业务架构

在品牌(Brand)信息管理中就是要实现对商品品牌信息的添加,修改,查询,删除等业务,user是后台管理员,如图所示

07-SpringBoot+MyBatis+Spring 技术整合实现商品品牌模块的CRUD操作_第1张图片

原型设计

基于品牌业务描述,对品牌模块的业务原型进行分析和设计,如图所示

技术架构

在品牌管理模块实现郭晨,我们采用典型的C/S架构进行实现,客户端我们基于浏览器实现,服务端采用Tomcat,数据库使用MySQL,具体应用层基于MVC分成架构进行实现

技术栈选型

客户端技术:HTML,CSS,JavaScript,bootstrap
服务端技术:spring,mybatis,springboot,thymeleaf
数据库:MySql,SQL

数据库及表设计

drop database if exists dbbrand;
create database dbbrand default character set utf8;
use dbbrand;
create table tb_brand(
     id bigint primary key auto_increment,
     name varchar(100) not null,
     remark text,
     createdTime datetime not null
)engine=InnoDB;
insert into tb_brand values (null,'联想','very good',now());
insert into tb_brand values (null,'小米','very good',now());
insert into tb_brand values (null,'美的','very good',now());
insert into tb_brand values (null,'九阳','very good',now());
insert into tb_brand values (null,'TCL','very good',now());
insert into tb_brand values (null,'创维','very good',now());
insert into tb_brand values (null,'华为','very good',now());

项目环境初始化

准备操作

(1)JDK 1.8
(2)Maven 3.6.3
(3)IDEA 2020.2
(4)MySql 5.7+

初始化数据库

在cmd窗口下进行如下操作

登录mysql
mysql -uroot -proot
设置客户端编码
set names utf8;
执行sql脚本
source:d/brand.sql

创建项目Mouble

07-SpringBoot+MyBatis+Spring 技术整合实现商品品牌模块的CRUD操作_第2张图片

添加项目Moudle依赖


    org.springframework.boot
    spring-boot-starter-data-jdbc


    org.mybatis.spring.boot
    mybatis-spring-boot-starter
    2.1.3


    org.springframework.boot
    spring-boot-starter-web


    org.springframework.boot
    spring-boot-starter-thymeleaf


    mysql
    mysql-connector-java
    runtime


    org.springframework.boot
    spring-boot-starter-test
    test
    
        
            org.junit.vintage
            junit-vintage-engine
        
    

项目Mouble基础配置

打开项目Mouble配置文件applicatin.properties,并添加如下内容

server.port=80
spring.datasource.url=jdbc:mysql:///dbgoods?serverTimezone=GMT%2B8&characterEncoding=utf8
spring.datasource.username=root
spring.datasource.password=root
mybatis.mapper-locations=classpath:/mapper/*/*.xml
logging.level.com.cy=debug
spring.thymeleaf.cache=false
spring.thymeleaf.prefix=classpath:/templates/
spring.thymeleaf.suffix=.html

启动项目并进行初步环境测试分析

07-SpringBoot+MyBatis+Spring 技术整合实现商品品牌模块的CRUD操作_第3张图片

品牌模块整体API设计

07-SpringBoot+MyBatis+Spring 技术整合实现商品品牌模块的CRUD操作_第4张图片

品牌数据的查询及呈现

业务描述

将数据库中的品牌查询出来,然后在客户端基于Html技术进行呈现,如图所示

服务端查询时序设计

07-SpringBoot+MyBatis+Spring 技术整合实现商品品牌模块的CRUD操作_第5张图片

领域对象(POJO)设计及实现

设置Brand对象,基于此对象封装从数据库查询到的品牌信息,代码如下
第一步:定义BrandDao接口,代码如下:

package com.cy.pj.brand.pojo;
import java.util.Date;
public class Brand {
    private Integer id;
    private String name;
    private String logo;
    private String remark;
    private Date createdTime;
    public Integer getId() {
        return id;
    }
    public void setId(Integer id) {
        this.id = id;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public String getLogo() {
        return logo;
    }
    public void setLogo(String logo) {
        this.logo = logo;
    }
    public String getRemark() {
        return remark;
    }
    public void setRemark(String remark) {
        this.remark = remark;
    }
    public Date getCreatedTime() {
        return createdTime;
    }
    public void setCreatedTime(Date createdTime) {
        this.createdTime = createdTime;
    }
    @Override
 public String toString() {
        return "Brand{" +
                "id=" + id +
                ", name='" + name + ''' +
                ", logo='" + logo + ''' +
                ", remark='" + remark + ''' +
                ", createdTime=" + createdTime +
                '}';
    }
}

数据逻辑对象(DAO)查询方法设计及实现

第一步:定义Brand接口,代码如下:

package com.cy.pj.brand.dao;
import org.apache.ibatis.annotations.Mapper;
@Mapper
public class BrandDao {
}

第二步:在BrandDao中定义品牌查询方法

List findBrands(String name);

第三步:基于查询方法定义SQL映射(本次SQL映射基于注解方法定义),
在resources目录中创建mapper/brand目录,并在目录中添加BrandMapper.xml文件代码如下:

简单SQL语句用注解形式,复杂的SQL语句用xml文件配置
@Select("select * from tb_brand where name like concat('%',#{name},'%')")
List findBrands(String name);

其中concat为mysql中提供的字符串连接函数
当然,对于这个SQL映射也可以写映射文件(BrandMapper.xml)

第四步:对数据层的查询进行单元测试,代码如下:

package com.cy.pj.brand.dao;
import com.cy.pj.brand.pojo.Brand;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import java.util.List;
@SpringBootTest
public class BrandDaoTests {
    @Autowired
 private BrandDao brandDao;
    @Test
 public void testFindBrands(){
        List list=brandDao.findBrands("TCL");
        for (Brand b:list
 ) {
            System.out.println(b);
        }
    }
}

第五步:测试过程中的BUG分析?

BindingException,如图所示

07-SpringBoot+MyBatis+Spring 技术整合实现商品品牌模块的CRUD操作_第6张图片

ExecutorException,如图所示:

07-SpringBoot+MyBatis+Spring 技术整合实现商品品牌模块的CRUD操作_第7张图片

SQL异常:检查自己的数据库语句是否正确
测试输出对象为对象地址表现形式,而不是内容?(检查toString方法是否重写)

知识点自己了解内容之/具体索引的定义/

业务逻辑对象(Service)查询方法设计及实现

业务逻辑对象负责模块的具体业务管理,例如参数校验,事务控制,权限控制,日志记录等

第一步:定义业务接口

package com.cy.pj.brand.service;
public interface BrandService {}

第二步:在BrandService接口中添加品牌查询方法

List findBrands(String name);

第三步:定义BrandService接口实现类BrandServiceImpl

package com.cy.pj.brand.service.impl;
import com.cy.pj.brand.dao.BrandDao;
import com.cy.pj.brand.pojo.Brand;
import org.slf4j.Logger;    //slf4j-Simple Log Facade For Java
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
@Service
public class BrandServiceiImpl implements BrandService {
    //这里用到了门面模式--日志
 private static final Logger log = //这里的实现在springboot默认选择的是logback
 LoggerFactory.getLogger(BrandServiceiImpl.class);
    @Autowired
 private BrandDao brandDao;
    @Override
 public List findBrands(String name) {
        long t1 = System.currentTimeMillis();
        List list = brandDao.findBrands(name);
        long t2 = System.currentTimeMillis();
        log.info("time:{}", t2 - t1);
        return list;
    }
}

第四步:定义BrandService接口方法的单元测试类,并对业务进行测试分析

package com.cy.pj.brand.service;
import com.cy.pj.brand.pojo.Brand;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import java.util.List;
@SpringBootTest
public class BrandServiceTests {
    @Autowired
 private BrandService brandService;
    @Test
 public void testFindBrands() {
        List list = brandService.findBrands("小米");
        System.out.println(list.size());
        //断言测试
 Assertions.assertEquals(1, list.size());
        System.out.println("test ok");
//        for (Brand b:list){
//            System.out.println(b);
//        }
//        list.forEach(brand->System.out.println(brand));
 list.forEach(System.out::println);//jdk1.8方法引用
 }
}

测试过程中的Bug分析

NoSuchBeanDefinition,如图所示:

07-SpringBoot+MyBatis+Spring 技术整合实现商品品牌模块的CRUD操作_第8张图片

NullPointerException,如图所示:

image.png

控制逻辑对象(Controller)查询方法设计及实现

在控制逻辑对象中主要是负责请求和响应逻辑控制,例如请求url映射,参数映射,请求方式,结果集的封装,解析,响应的设计等

第一步:定义Controller类

package com.cy.pj.brand;
import com.cy.pj.brand.pojo.Brand;
import com.cy.pj.brand.service.BrandService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import java.util.List;
@Controller
public class controller {
    @Autowired
 private BrandService brandService;
    @GetMapping("doFindBrands")
    public String doFindBrands(@PathVariable String name, Model model){
        List list=brandService.findBrands(name);
        model.addAttribute("list", list);
        return "brand/brand";//view name
 }
}

访问网址:http:localhost:8080/brand/doFindBrands/tcl

第二步:在Controller添加处理请求的方法

package com.cy.pj.brand;
import com.cy.pj.brand.pojo.Brand;
import com.cy.pj.brand.service.BrandService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.*;
import java.util.List;
@Controller
public class controller {
    @Autowired
 private BrandService brandService;
 //http://localhost:8080/brand/doFindBrands?name=tcl
 //http:localhost:8080/brand/doFindBrands/tcl //rest风格(一种软件架构编码风格)
 //其语法为a/b/{c}/d/{e},在url可以定义变量,这个变量需要使用{}括起来
 //rest风格可以更好实现跨平台
 //@PathVariable 注解用于修饰方法参数,目的是告诉springmvc,参数的值来自于url
 @GetMapping(value={"/brand/doFindBrands","/brand/doFindBrands/{name}"})
    public String doFindBrands(@PathVariable(required = false) String name, Model model){
        List list=brandService.findBrands(name);
        model.addAttribute("list", list);
        //第一个brand为目录,第二个目录为view name
 return "brand/brand";
    }//所有与数据相关的问题,一定要学会去跟踪你数据
 //例如:
 //1.客户端向服务端提交的数据,在服务端没有收到?(一定要看客户端提交数据的方式与服务端
 //2.服务端向客户端响应数据时,假如客户端没有收到?(先检测服务端响应数据之前的数据时
}

其中,
(1)@GetMapping描述方法时,表示这个方法只能处理Get请求,注解内部的value属性可以指定多个url
(2)@PathVariable用于描述方法参数,表示方法参数的值可以来自url中{}内部的变量值,required=false表示参数可以不传值

rest风格(一种软件架构编码风格):其语法为a/b/{c}/d/{e},在url可以定义变量,这个变量需要使用{}括起来,rest风格可以更好实现跨平台
@PathVariable:注解用于修饰方法参数,目的是告诉springmvc,参数的值来自于url

客户端品牌列表页面设计及实现

第一步:在resources目录下新建一个目录,命名为templates.brand,代码如下

注意templates.brand中的.不能写.要用/分割,建好了之后显示.



    
    Title


The Brand Page

id name createdTime
10 AAA 2020/10/11

其中,
(1)${}为thymeleaf为中的EL表达式,用于从服务端model中获取数据
(2)th:each为thymeleaf定义的自定义标签属性,用于迭代数据
(3)th:text为thymeleaf定义的自定义标签属性,用于设置文本内容

启动服务进行访问测试并对结果进行分析

启动服务,打开浏览器输入指定url,进行访问,其数据呈现过程,如图所示:
07-SpringBoot+MyBatis+Spring 技术整合实现商品品牌模块的CRUD操作_第9张图片


启动及运行过程中的Bug分析及解决方案

500错误:看自己的控制台报错信息
405错误:服务器与客户端请求不匹配--检查表单上方和contrller里的提交方式是否一样
07-SpringBoot+MyBatis+Spring 技术整合实现商品品牌模块的CRUD操作_第10张图片

,页面元素解析异常,如图所示:

07-SpringBoot+MyBatis+Spring 技术整合实现商品品牌模块的CRUD操作_第11张图片

模板页面找不到,如图所示:

07-SpringBoot+MyBatis+Spring 技术整合实现商品品牌模块的CRUD操作_第12张图片

品牌模块删除业务实现分析及实现

业务描述

在品牌列表页面中,点击当前行记录后面的删除按钮,基于当前行的记录执行id执行品牌删除操作,删除成功以后,重新刷新页面,如图所示

业务时序分析与设计

客户端向服务端发起删除请求,服务器端的处理时序如下:
07-SpringBoot+MyBatis+Spring 技术整合实现商品品牌模块的CRUD操作_第13张图片

数据逻辑对象(DAO)中删除方法及实现

基于业务,在BrandDao接口中添加删除方法,代码如下:


int deleteById(Integer id);

基于方法定义SQL映射(本次直接以注解方式进行定义),代码如下:

@Delete("delete from tb_brand where id=#{id}")
int deleteById(Integer id);

在BrandTests单元测试类中添加单元测试方法,对删除操作进行测试,代码如下

@Test
public void testDeleteById() {
    int rows = brandDao.deleteById(10);
    System.out.println("rows=" + rows);
}

业务逻辑对象(Service)中删除方法设计及实现

第一步:在BrandService接口中添加,品牌删除的业务方法,代码如下:

int deleteById(Integer id);

第二步:在BrandServiceImpl类中添加删除业务的具体实现,代码如下:

@Override
public int deleteById(Integer id) {
    //1.参数校验
 //2.执行删除逻辑业务
 int rows = brandDao.deleteById(id);
    //3.校验结果
 //4.返回结果
 return rows;
}

第三步;在BrandServiceTests类中添加单元测试方法,对其删除业务做测试?

@Test
public void testDeleteById() {
    int rows = brandService.deleteById(10);
    System.out.println("rows=" + rows);
}

第四步:测试过程中的Bug分析?

控制逻辑对象(Controller)中删除方法设计及实现

在控制层对象中定义处理删除请求的方法,具体代码如下:

@GetMapping("/brand/doDeleteById/{id}")
public String doDeleteById(@PathVariable Integer id, Model model) {
    brandService.deleteById(id);
    List list = brandService.findBrands(null);
    model.addAttribute("list", list);
    return "/brand/brand";
}

想要优化一下,在用户点击删除的时候提示一下是否要删除,在brand.html中把删除的超链接改成button
代码如下:


    

在script里添加function方法

function doDeleteById(id) {
    if(!confirm("您确定要删除么"))return;
    location.href=`http://localhost:8080/brand/doDeleteById/${id}`;
}

Bug分析

400错误

07-SpringBoot+MyBatis+Spring 技术整合实现商品品牌模块的CRUD操作_第14张图片

品牌模块修改业务分析及实现

业务描述

在品牌列表页面,点击当前行的修改按钮,先基于id查询当前行记录,并把记录呈现在编辑页面,如图所示

修改时序分析及设计

基于id查询品牌信息并呈现在页面上,其时序分析如图所示
07-SpringBoot+MyBatis+Spring 技术整合实现商品品牌模块的CRUD操作_第15张图片
在品牌编辑页面,编辑数据,点击save按钮保存更新,其时序如图所示

数据逻辑对象(Dao)中方法设计及实现

第一步:在BrandDao中添加用于保存品牌信息的方法,代码如下:

@Select("select * from tb_brand where id=#{id}")
Brand findById(Integer id);

在BrandDao中添加基于id执行品牌更新的方法及SQL映射,代码如下:

@Update("update tb_brand set name=#{name},remark=#{remark} where id=#{id}")
int updateById(Brand brand);

业务逻辑对象(Service)中方法设计及实现

在BrandService中添加基于id查询品牌信息和更新品牌信息的方法,代码如下:

Brand findById(Integer id);
int updateById(Brand brand);

在BrandServiceImpl中基于id查询品牌信息的更新品牌信息的方法,代码如下:

@Override
public Brand findById(Integer id) {
    //.....
 return brandDao.findById(id);
}
@Override
public int updateById(Brand brand) {
    int rows = brandDao.updateById(brand);
    return rows;
}

控制逻辑对象(Controller)中方法设计及实现

在BrandController中添加基于id查询品牌信息的方法,代码如下:

@RequestMapping("brand/toUpdateById/{id}")
public String doUpdateById(@PathVariable("id") Integer id,Model model) {
    Brand brand =  brandService.findById(id);
    model.addAttribute("brand",brand);
    return "brand/brand-update";
}

在BrandController中添加更新品牌信息的方法,代码如下:

 @PostMapping("/brand/doUpdateBrand")
    public String doUpdateBrand(Brand brand,Model model){
//        System.out.println("update.brand"+brand);
 brandService.updateById(brand);
        List list = brandService.findBrands(null);
        model.addAttribute("list", list);
        return "/brand/brand";
//        return "redirect:/brand/doUpdateBrand";
 }

客户端操作设计及实现




    
    Insert title here
   


The Goods Update Page

  • name:
  • remark:

启动服务进行访问测试分析

启动程序,先进入品牌列表页面,然后点击修改按钮,此时进入品牌编辑页面,如图所示
07-SpringBoot+MyBatis+Spring 技术整合实现商品品牌模块的CRUD操作_第16张图片
在品牌编辑页面,编辑数据以后,点击save按钮,执行更新操作

品牌模块添加业务分析及实现

总结(Summary)

本章节,主要基于学过的springboot,Hikaricp,MyBatis,Spring,Thymeleaf等技术,对商品品牌模块做了具体实现,重点掌握其基本设计及实现过程

你可能感兴趣的:(springboot)