关于springboot:SpringBoot强化篇五SpringMVCMyBatisSpring-技术整合

35次阅读

共计 11230 个字符,预计需要花费 29 分钟才能阅读完成。

SpringMVC+MyBatis+Spring 技术整合

业务架构剖析

在品牌 (Brand) 信息管理中就是要实现对商品品牌信息的增加, 批改, 查问, 删除等业务, 如图所示:

业务根本原型设计

基于品牌业务形容, 对品牌模块的业务原型进行剖析和设计, 如图所示:

  • 品牌列表页面

  • 品牌编辑页面

我的项目品牌模块外围 API 剖析与设计

基于分层架构设计思维,现对品牌 API 进行设计,如图所示:

数据库及表的剖析与设计

设计并创立数据库

如果数据库已存在, 则先删除数据库, 代码如下:

drop database if exists dbbrand;

创立新的数据库, 代码如下:

create database dbbrand default character set utf8;

设计并创立品牌 (Brand) 表

关上数据库,语句如下:

use dbbrand;

在 dbbrand 数据库中创立品牌表.

create table tb_brand(
     id bigint primary key auto_increment,
     name varchar(100) not null,
     remark text,
     createdTime datetime not null
)engine=InnoDB;

基于 SQL 脚本执行数据库初始化

将数据库设计脚本写到 brand.sql 中, 而后按如下步骤执行:

关上 mysql 自带客户端, 登录 mysql, 指令如下:

mysql -uroot -proot

设置客户端编码,指令如下:

set names utf8;

执行 sql 脚本,指令如下:

source d:/brand.sql

脚本执行胜利当前,在客户端查问数据之前,先执行如下语句:

set names gbk;

我的项目环境初始化

筹备操作

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

创立我的项目 Module

关上 idea,而后基于设计,创立我的项目 module,如图所示:

增加我的项目 Module 依赖

  • MySQL 驱动
<dependency>
   <groupId>mysql</groupId>
   <artifactId>mysql-connector-java</artifactId>
   <scope>runtime</scope>
</dependency>
  • Srping Jdbc 提供了 HikariCP 连接池
<dependency>
   <groupId>org.springframework.boot</groupId>
   <artifactId>spring-boot-starter-data-jdbc</artifactId>
</dependency>
  • MyBatis 资源
<dependency>
   <groupId>org.mybatis.spring.boot</groupId>
   <artifactId>mybatis-spring-boot-starter</artifactId>
   <version>2.1.3</version>
</dependency>
  • Spring Web 依赖 (内置一个 tomcat 服务)
<dependency>
   <groupId>org.springframework.boot</groupId>
   <artifactId>spring-boot-starter-web</artifactId>
</dependency>
  • Thymeleaf 依赖 (html 模板引擎)
<dependency>
   <groupId>org.springframework.boot</groupId>
   <artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>

我的项目 Module 根底配置

关上我的项目 Module 配置文件 application.properties, 并增加如下内容:

#spring server
server.port=80
# spring datasource
spring.datasource.url=jdbc:mysql:///dbbrand?serverTimezone=GMT%2B8&characterEncoding=utf8
spring.datasource.username=root
spring.datasource.password=root

# spring mybatis

mybatis.mapper-locations=classpath:/mapper/*/*.xml

# spring log

logging.level.com.cy=debug

#spring thymeleaf
spring.thymeleaf.cache=false
spring.thymeleaf.prefix=classpath:/templates/
spring.thymeleaf.suffix=.html

品牌数据的查问及出现

业务形容

将数据库中的品牌信息查问进去, 而后在客户端基于 html 技术进行出现, 如图所示:

服务端品牌查问时序设计

基于查问申请, 进行拜访时序设计, 如图所示:

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

设置 Brand 对象, 基于此对象封装从数据库查问到的品牌信息, 代码如下:

package com.cy.pj.brand.pojo;
import java.util.Date;
public class Brand {
    private Integer id;
    private String name;
    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 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 + '''+", remark='"+ remark +''' +
                ", createdTime=" + createdTime +
                '}';
    }
}

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

设计用于拜访 Brand 数据的数据拜访对象及办法, 其关键步骤如下:

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

package com.cy.pj.brand.dao;
@Mapper
public interface BrandDao{}

第二步: 在 BrandDao 中定义品牌查询方法, 代码如下:

List<Brand> findBrands(String name);

第三步: 基于查询方法定义 SQL 映射.
在 resources 目录中创立 mapper/brand 目录, 并在目录中增加 BrandMapper.xml 文件, 要害代码如下:

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
 PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
 "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.cy.pj.brand.dao.BrandDao">
    <select id="findBrands" resultType="com.cy.pj.brand.pojo.Brand">
        select id,name,remark,createdTime
        from tb_brand
        <if test="name!=null and name!=''">
            where name like concat("%",#{name},"%")
        </if>
    </select>
</mapper>

其中:concat 为 mysql 中提供的字符串连贯函数.

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

package com.cy.pj.brand.dao;
@SpringBootTests
public class BrandDaoTests{
     @Autowired
     private BrandDao brandDao;
     @Test
     void testFindBrands(){List<Brand> list=brandDao.findBrands("TCL");
        for(Brand b:list){System.out.println(b);
        }
     }
}

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

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

第一步: 定义业务接口

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

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

List<Brand> findBrands(String name);

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

package com.cy.pj.brand.service.impl;

@Service
public class BrandServiceImpl implements BrandService{
     private static final Logger log=
     LoggerFactory.getLogger(BrandServiceImpl.class);
     
     @Autowired
     private BrandDao brandDao;
     public List<Brand> findBrands(String name){long t1=System.currentTimeMillis();
            List<Brand> list=brandDao.findBrands(name);
            long t2=System.currentTimeMillis();
            log.info("findBrands->time->{}",(t2-t1));
            return list;
     }
} 

第三步: 定义 BrandService 接口办法的单元测试类, 并业务进行测试剖析

package com.cy.pj.brand.service;
@SpringBootTest
public class BrandServiceTests{
    @Autowired
    private BrandService brandService;
    @Test
    void testFindBrands(){List<Brand> list=brandService.findBrands();
        for(Brand b:list){System.out.println(b);
        }
    }
}

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

在管制逻辑对象中次要是负责申请和响应逻辑管制, 例如申请 url 映射, 参数映射, 申请形式, 后果集的封装, 解析, 响应的设计等.

第一步: 定义 Controller 类

package com.cy.pj.brand.controller;
@Controller
public class BrandController{
   @Autowired
   private BrandService brandService;
}

第二步: 在 Controller 增加解决查问申请的办法

@GetMapping(value={"/brand/doFindBrands/{name}","/brand/doFindBrands"})
public String doFindBrands(@PathVariable(required = false) String name, Model model){List<Brand> list=brandService.findBrands(name);
    model.addAttribute("list", list);
    return "brand/brand";// 第一个 brand 为目录, 第二 brand 为 view name
} 

其中,
1)@GetMapping 形容办法时, 示意这个办法只能解决 Get 申请, 注解外部的 value 属性能够指定多个 url.
2)@PathVariable 用于形容办法参数, 示意办法参数的值能够来自 url 中 {} 外部的变量值,required=false 示意参数能够不传值.

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

在我的项目的 templates 目录下创立 brand 目录并增加 brand.html 页面, 其要害代码如下:

<table>
    <thead>
      <tr>
        <th>id</th>
        <th>name</th>
        <th>createdTime</th>
      </tr>
    </thead>
    <tbody>
      <tr th:each="brand: ${list}">
         <td th:text="${brand.id}">10</td>
         <td th:text="${brand.name}">AAA</td>
         <td th:text="${#dates.format(brand.createdTime,'yyyy/MM/dd  
         HH:mm')}">2020/10/11</td>
       </tr>
 </tbody>
</table>

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

启动服务进行拜访测试并对后果进行剖析

启动服务, 关上浏览器输出指定 url, 进行拜访, 其数据出现过程, 如图所示:

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

业务形容

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

业务时序剖析与设计

客户端向服务端发动删除申请, 服务器端的解决时序如下:

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

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

int deleteById(Integer id);

基于删除办法, 定义 SQL 映射(本次间接以注解形式进行定义), 代码如下:

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

在 BrandDaoTests 单元测试类中增加单元测试办法, 对删除操作进行测试, 要害代码如下

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

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

在业务逻辑对象办法中, 要解决删除操作须要的一些业务逻辑(后续有参数校验, 权限管制,….).

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

int deleteById(Integer id);

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

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

第三步: 在 BrandServiceTests 类中增加单元测试办法, 对其删除业务做测试?

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

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

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

在管制层对象中定义解决删除申请的办法, 具体代码如下:

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

客户端删除按钮事件定义及解决

在 tbody 的 tr 中增加一列, 代码如下:

<td>
 <button type="button" th:onclick="doDeleteById([[${brand.id}]])">delete</button>
</td>

定义 javascript 函数, 解决删除事件, 代码如下:

function doDeleteById(id){
    // 给出提示信息
 if(!confirm("您确认删除吗"))return;//confirm 为浏览器中 window 对象的函数
 // 执行删除业务
 location.href=`http://localhost/brand/doDeleteById/${id}`;
}

品牌模块增加业务剖析及实现

业务形容

在列表页面上, 设计增加按钮, 当点击增加按钮时, 跳转到增加页面, 而后在增加页面上数据品牌信息, 点击 Save 按钮就数据提交到服务端进行保留.

增加时序剖析及设计

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

第一步: 在 BrandDao 中增加用于保留品牌信息的办法, 代码如下:

int insertBrand(Brand brand);

第二步: 在 BrandMapper 中增加品牌保留操作对应的 sql 映射, 代码如下:

<insert id="insertBrand">
     insert into tb_brand 
     (name,remark,createdTime)
     values
     (#{name},#{remark},now())
</insert>

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

第一步: 在 BrandService 业务接口中中定义用于保留品牌信息的办法, 代码如下:

int saveBrand(Brand brand);

第二步: 在 BrandServiceImpl 业务实现类中增加保留品牌信息的具体实现, 代码如下:

public int saveBrand(Brand brand){int rows=brandDao.insertBrand(brand);
    return rows;
}

管制逻辑对象 (Controller) 中办法设计及实现

第一步: 在 BrandController 中增加用于解决申请增加页面的办法, 代码如下:

@GetMapping("/brand/doAddUI")
public String doAddUI(){return "brand/brand-add";}

第二步: 在 BrandController 增加用于解决增加品牌信息页面的办法, 代码如下:

@PostMapping("/brand/doSaveBrand")
public String doSaveBrand(Brand brand,Model model){System.out.println("save.brand="+brand);
    brandService.saveBrand(brand);
    List<Brand> list=brandService.findBrands(null);
    model.addAttribute("list",list);
    return "brand/brand";
}

品牌增加操作客户端业务剖析、设计及实现.

第一步: 设计品牌增加页面 brand-add.html, 代码如下

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <link rel="stylesheet" href="/bootstrap/css/bootstrap.css">
</head>
<body>
   <div class="container">
       <h1>The Brand Add Page</h1>
       <form th:action="@{/brand/doSaveBrand}" method="post">
           <div class="form-group">
               <label for="nameId">Name</label>
               <input type="text" class="form-control" name="name" id="nameId" placeholder="Brand Name">
           </div>
           <div class="form-group">
               <label for="remarkId">Remark</label>
               <textarea class="form-control" rows="5" cols="100" name="remark" id="remarkId">
               </textarea>
           </div>
           <button type="submit" class="btn btn-default">Submit</button>
       </form>
   </div>
</body>
</html>

第二步: 在品牌列表 brand.html 页面, 设计增加按钮, 代码如下:

<button type="button" onclick="doAddUI()" class="btn btn-primary btn-sm">Add Brand</button>

第三步: 点击增加按钮时, 加载品牌增加页面, 事件处理函数如下:

function doAddUI(){location.href="/brand/doAddUI";}

启动服务进行拜访测试剖析

启动及运行过程中的 BUG 剖析

  • 客户端提交到服务端的数据拿不到?

品牌模块批改业务剖析及实现

业务形容

在品牌列表页面,点击以后行的批改按钮,先基于 id 查问以后行记录,并将记录出现在编辑页面,如图所示:

业务时序剖析与设计

基于 id 查问品牌信息并出现在页面上,其时序剖析如图所示:

在品牌编辑页面,编辑数据,点击 save 按钮保留更新,其时序如图所示:

数据逻辑对象 (Dao) 中办法设计与实现

在 BrandDao 中增加基于 id 查问品牌信息的办法及 SQL 映射, 代码如下:

@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 updateBrand(Brand Brand);

业务逻辑对象 (Service) 中办法设计与实现

在 BrandService 中增加基于 id 查问品牌信息和更新品牌信息的办法, 代码如下:

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

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

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

管制逻辑对象 (Controller) 中办法设计与实现

在 BrandController 中增加基于 id 查问品牌信息的办法, 代码如下:

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

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

 @RequestMapping("/brand/doUpdateBrand")
    public String doUpdateBrand(Brand brand,Model model) {brandService.updateBrand(brand);
        List<Brand> list=brandService.findBrands(null);
       model.addAttribute("list",list);
     return "brand/brand";
    }

客户端品牌编辑页面设计与实现

第一步: 设计品牌批改页面 brand-update.html, 代码如下

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <link rel="stylesheet" href="/bootstrap/css/bootstrap.css">
</head>
<body>
   <div class="container">
       <h1>The Brand Update Page</h1>
       <input type="hidden" name="id" th:value="${brand.id}">
       <form th:action="@{/brand/doUpdateBrand}" method="post">
           <div class="form-group">
               <label for="nameId">Name</label>
               <input type="text" class="form-control" name="name" id="nameId" th:value="${brand.name}" placeholder="Brand Name">
           </div>
           <div class="form-group">
               <label for="remarkId">Remark</label>
               <textarea class="form-control" rows="5" cols="100" name="remark" th:text="${brand.remark}" id="remarkId">
               </textarea>
           </div>
           <button type="submit" class="btn btn-default">Submit</button>
       </form>
   </div>
</body>
</html>

启动 Tomcat 服务进行拜访测试剖析

启动服务,先进入品牌列表页面,而后点击批改按钮如图所示:

此时,进入品牌编辑页面,如图所示:

在品牌编辑页面,编辑数据当前,点击 save 按钮,执行更新操作。

正文完
 0