业务形容
需要形容
任何一个电商零碎中都有一个商品子系统, 而与商品相关联都会有一个品牌信息管理, 在以后业务零碎设计中咱们就是要对商品品牌信息的治理进行设计和实现.
业务架构剖析
在品牌 (Brand) 信息管理中就是要实现对商品品牌信息的增加, 批改, 查问, 删除等业务, 如图所示:
业务根本原型设计
基于品牌业务形容, 对品牌模块的业务原型进行剖析和设计, 如图所示:
我的项目技术架构剖析及设计
在品牌治理模块实现过程, 咱们采纳典型的 C / S 架构进行实现. 客户端咱们基于浏览器进行实现, 服务端采纳 tomcat, 数据库应用 MySQL. 具体应用层基于 MVC 分层架构进行实现.
我的项目技术栈利用剖析及选型
- 客户端技术:html,css,javascript,bootstrap
- 服务端技术:hikaricp,mybatis,spring,springboot,thymeleaf
- 数据库技术:mysql,sql
- 开发工具集:jdk1.8,maven3.6.3,idea2020.2
我的项目品牌模块外围 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);
}
}
}
第五步: 测试过程中的 BUG 剖析?
- BindingException, 如图所示:
- ExecutorException, 如图所示:
业务逻辑对象 (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);
}
}
}
第四步: 测试过程中的 Bug 剖析?
- NoSuchBeanDefinition, 如图所示:
- NullPointerException, 如图所示:
管制逻辑对象 (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}ss`;
}
品牌模块增加业务剖析及实现
业务形容
在列表页面上, 设计增加按钮, 当点击增加按钮时, 跳转到增加页面, 而后在增加页面上数据品牌信息, 点击 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=brandService.saveBrand(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";}
第四步: 在品牌增加页面输出品牌信息, 间接将数据提交到服务端执行保留操作