任何一个电商系统中都有一个商品子系统,而与商品相关联都会有一个品牌信息管理,在当前业务系统设计中咱们就是要对商品品牌信息的管理进行设计和实现.javascript
在品牌(Brand)信息管理中就是要实现对商品品牌信息的添加,修改,查询,删除等业务,如图所示:
css
基于品牌业务描述,对品牌模块的业务原型进行分析和设计,如图所示:html
在品牌管理模块实现过程,咱们采用典型的C/S架构进行实现.客户端咱们基于浏览器进行实现,服务端采用tomcat,数据库使用MySQL.具体应用层基于MVC分层架构进行实现.java
基于分层架构设计思想,现对品牌API进行设计,如图所示:mysql
假如数据库已存在,则先删除数据库,代码以下:web
drop database if exists dbbrand;
建立新的数据库,代码以下:spring
create database dbbrand default character set utf8;
打开数据库,语句以下:sql
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;
将数据库设计脚本写到brand.sql中,而后按以下步骤执行:bootstrap
打开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+
打开idea,而后基于设计,建立项目module,如图所示:
<dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <scope>runtime</scope> </dependency>
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-jdbc</artifactId> </dependency>
<dependency> <groupId>org.mybatis.spring.boot</groupId> <artifactId>mybatis-spring-boot-starter</artifactId> <version>2.1.3</version> </dependency>
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency>
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-thymeleaf</artifactId> </dependency>
打开项目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技术进行呈现,如图所示:
基于查询请求,进行访问时序设计,如图所示:
设置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 + '}'; } }
设计用于访问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分析?
业务逻辑对象负责模块的具体业务处理,例如参数校验,事务控制,权限控制,日志记录等.
第一步:定义业务接口
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分析
在控制逻辑对象中主要是负责请求和响应逻辑控制,例如请求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执行品牌删除操做,删除成功之后,从新刷新页面.如图所示:
客户端向服务端发起删除请求,服务器端的处理时序以下:
基于业务,在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); }
在业务逻辑对象方法中,要处理删除操做须要的一些业务逻辑(后续有参数校验,权限控制,....).
第一步:在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分析?
在控制层对象中定义处理删除请求的方法,具体代码以下:
@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按钮就数据提交到服务端进行保存.
第一步:在BrandDao中添加用于保存品牌信息的方法,代码以下:
int insertBrand(Brand brand);
第二步:在BrandMapper中添加品牌保存操做对应的sql映射,代码以下:
<insert id="insertBrand"> insert into tb_brand (name,remark,createdTime) values (#{name},#{remark},now()) </insert>
第一步:在BrandService业务接口中中定义用于保存品牌信息的方法,代码以下:
int saveBrand(Brand brand);
第二步:在BrandServiceImpl业务实现类中添加保存品牌信息的具体实现,代码以下:
public int saveBrand(Brand brand){ int rows=brandDao.insertBrand(brand); return rows; }
第一步:在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"; }
在品牌列表页面,点击当前行的修改按钮,先基于id查询当前行记录,并将记录呈如今编辑页面,如图所示:
基于id查询品牌信息并呈如今页面上,其时序分析如图所示:
在品牌编辑页面,编辑数据,点击save按钮保存更新,其时序如图所示:
在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);
在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); }
在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>
启动服务,先进入品牌列表页面,而后点击修改按钮如图所示:
此时,进入品牌编辑页面,如图所示:
在品牌编辑页面,编辑数据之后,点击save按钮,执行更新操做。
本章节,主要基于学过的springboot,Hikaricp,MyBatis,Spring,Thymeleaf等技术,对商品品牌模块作了具体实现。重点掌握其基本设计及实现过程。