业务形容

需要形容

任何一个电商零碎中都有一个商品子系统,而与商品相关联都会有一个品牌信息管理,在以后业务零碎设计中咱们就是要对商品品牌信息的治理进行设计和实现.

业务架构剖析

在品牌(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 serverserver.port=80# spring datasourcespring.datasource.url=jdbc:mysql:///dbbrand?serverTimezone=GMT%2B8&characterEncoding=utf8spring.datasource.username=rootspring.datasource.password=root# spring mybatismybatis.mapper-locations=classpath:/mapper/*/*.xml# spring loglogging.level.com.cy=debug#spring thymeleafspring.thymeleaf.cache=falsespring.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;@Mapperpublic 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;@SpringBootTestspublic 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;@Servicepublic 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;@SpringBootTestpublic 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)查询方法设计及实现

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

第一步:定义Controller类

package com.cy.pj.brand.controller;@Controllerpublic 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,进行拜访,其数据出现过程,如图所示:

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

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

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

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

业务形容

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

业务时序剖析与设计

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

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

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

int deleteById(Integer id);

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

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

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

@Testvoid 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类中增加单元测试办法,对其删除业务做测试?

@Testvoid 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按钮,执行更新操作。

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

  • 405 异样

  • 出现的数据不正确

  • 页面元素解析异样