基于Spring,MyBatis,SpringBoot,Thymeleaf技术实现商品模块的增删改查操作。

筹备工作

1. MySQL(5.7)2. JDK (1.8)3. Maven (3.6.3)4. STS(4.7.1)

技术架构
采纳典型的c/s架构进行实现,客户端咱们基于浏览器进行实现,服务端采纳tomacat,数据库应用mysql,具体应用层基于mvc分层架构实现

技术栈
客户端:html,css,js,bootstrap
服务端:spring,springboot,mybaties,thymeleaf
数据库:mysql,SQL
API整合

业务时序

初始化数据库
登录mysql mysql -uroot -proot
设置编码格局
set names utf8;
执行goods.sql文件

其中goods.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());

基于idea创立
创立module
我的项目配置文件
application.properties,增加如下内容:

#serverserver.port=80#server.servlet.context-path=/#spring datasourcespring.datasource.url=jdbc:mysql:///dbgoods?serverTimezone=GMT%2B8&characterEncoding=utf8spring.datasource.username=rootspring.datasource.password=root#spring mybatismybatis.mapper-locations=classpath:/mapper/*/*.xml#spring logginglogging.level.com.cy=debug#spring thymeleafspring.thymeleaf.prefix=classpath:/templates/pages/spring.thymeleaf.suffix=.htmlspring.thymeleaf.cache=false

增加依赖

<dependencies>   <dependency>      <groupId>org.springframework.boot</groupId>      <artifactId>spring-boot-starter-data-jdbc</artifactId>   </dependency>   <dependency>      <groupId>org.springframework.boot</groupId>      <artifactId>spring-boot-starter-groovy-templates</artifactId>   </dependency>   <dependency>      <groupId>org.springframework.boot</groupId>      <artifactId>spring-boot-starter-jersey</artifactId>   </dependency>   <dependency>      <groupId>org.springframework.boot</groupId>      <artifactId>spring-boot-starter-thymeleaf</artifactId>   </dependency>   <dependency>      <groupId>org.springframework.boot</groupId>      <artifactId>spring-boot-starter-web</artifactId>   </dependency>   <dependency>      <groupId>mysql</groupId>      <artifactId>mysql-connector-java</artifactId>      <scope>runtime</scope>   </dependency>

启动类查看是否能失常启动

畛域对象Pojo类定义设计及实现

第一步:定义Goods对象,用于封装从数据库查问到的商品信息。

package com.cy.pj.goods.pojo;import java.util.Date;public class Goods {    private Integer id;//id bigint primary key auto_increment    private String name;//name varchar(100) not null    private String remark;//remark text    private Date createdTime;//createdTime datetime    public Long getId() {        return id;    }    public void setId(Long 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 "Goods [id=" + id + ", name=" + name + ",           remark=" + remark + ", createdTime=" + createdTime + "]";    }}

第二步:### Dao接口办法
在GoodsDao接口中定义商品查询方法以及SQL映射,基于此办法及SQL映射获取所有商品信息。代码如下:
**动静代码最好用映射办法
简略的sql间接用注解写在办法上**

package com.cy.pj.goods.dao;import java.util.List;import org.apache.ibatis.annotations.Select;import com.cy.pj.goods.pojo.Goods;@Mapperpublic interface GoodsDao {      @Select("select * from tb_brand where name like concat('%',#{name},'%')and name!=null or name!=''")      //这样太简单,简单用映射比拟好      List<Goods> findGoods(String name);}

映射与注解俩者取其一
映射代码

@Mapperpublic interface GoodsDao { List<Goods> findGoods(String name); }

在resources目录下创立mapper文件
在创立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.goods.Dao.GoodsDao">  <select id="findGoods" resultType="com.cy.pj.goods.pojo.Goods">      select *      from tb_brand      <if test="name!=null and name!=''">      where name like concat("%",#{name},"%")      </if>  </select></mapper> ```第三步:进行测试ackage com.cy.pj.goods.dao;import com.cy.pj.goods.pojo.Goods;import org.junit.jupiter.api.Test;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.boot.test.context.SpringBootTest;import java.util.List;@SpringBootTestpublic class GoodsDaoTests {  @Autowired private GoodsDao goodsDao;  @Test void testFindGoods(){      List<Goods> goodsList=goodsDao.findGoods(null);      for(Goods g:goodsList){          System.out.println(g);      }  }}

测试后果问题剖析

  • 数据库连不上,如图所示:

  • 连贯数据库的url 配置问题,如图所示:

  • Sql映射反复定义问题,如图所示:

  • 空指针问题,如图所示:

  • SQL语法问题,如图所示:

业务逻辑对象
是对象负责模块的具体业务解决如:日志,权限等等
第一步:定义业务接口,增加品牌查询方法

import com.cy.pj.goods.pojo.Goods;import java.util.List;public interface GoodsService {    List<Goods> findBrannds(String name);}

第二步:定义接口实现类

package com.cy.pj.goods.pojo;import com.cy.pj.goods.Dao.GoodsDao;import com.cy.pj.goods.Dao.GoodsService;import org.slf4j.Logger;import org.slf4j.LoggerFactory;import org.springframework.beans.factory.annotation.Autowired;import java.util.List;@Servicepublic class GoodsImp implements GoodsService {    private static final Logger log= LoggerFactory.getLogger(GoodsImp.class);    @Autowired private GoodsDao goodsDao;    @Override public List<Goods> findBrannds(String name) {        long t1=System.currentTimeMillis();        List<Goods> list=goodsDao.findGoods(name);        long t2=System.currentTimeMillis();        log.info("find->",t2-t1);        return list;    }}

第三步:进行单元测试

package com.cy.pj;import com.cy.pj.goods.Dao.GoodsService;import com.cy.pj.goods.pojo.Goods;import org.junit.jupiter.api.Test;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.boot.test.context.SpringBootTest;import java.util.List;@SpringBootTestpublic class BrandTest {    @Autowired private GoodsService goodsService;    @Test void dou(){      List<Goods> list=goodsService.findGoods("小米");System.out.println(list.size());Assertions.assertEquals(1, list.size());//断言测试System.out.println("OK");list.forEach(brand->System.out.println());//jdk1.8lambda表达式    }}

Controller对象办法定义及实现

定义GoodsController类,并增加doGoodsUI办法,增加查问商品信息代码,并将查问到的商品信息存储到model,并返回goods页面。

package com.cy.pj.goods;import com.cy.pj.goods.one.GoodsService;import com.cy.pj.goods.pojo.Goods;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;@Controllerpublic class CollerGoods {    @Autowired private GoodsService goodsService; //@PathVariable用于润饰参数,通知mvc,参数来的url   @GetMapping(value = {"/goods/doFind","/goods/doFind/{name}"})    public String doFind(@PathVariable(required = false) String name, Model model){        List<Goods> list=goodsService.findGoods(name);        model.addAttribute("list", list);        return "brand";    }}

测试:http://localhost/goods/doFind...

革新成:

package com.cy.pj.goods;import com.cy.pj.goods.one.GoodsService;import com.cy.pj.goods.pojo.Goods;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 java.util.List;@Controllerpublic class CollerGoods {    @Autowired private GoodsService goodsService;    @GetMapping("/goods/doFind")    public String doFind( String name, Model model){        List<Goods> list=goodsService.findGoods(name);        model.addAttribute("list", list);        return "brand";    }}

测试:http://localhost/goods/doFind

客户端向服务器提交数据,在服务器没有收到?
一点要看客户端提交数据的形式和服务端的申请形式
服务端向客户端响应数据时,如果客户端没有收到?
先检测服务端响应数据之前的数据是什么

brand.html:

<html><head>    <title>Good Thymes Virtual Grocery</title>    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />    <link rel="stylesheet" type="text/css" media="all" href="../../css/gtvg.css" data-th-href="@{/css/gtvg.css}" /></head><body><!--传统形式--><!--<form th:action="@{/goods/doFind}" method="get">--><!--    <input type="text" name="name">--><!--    <input type="submit" value="查问">--><!--    <input type="submit" value="返回首页">--><!--</form>--><!--rs--><form>    <input type="text" name="name">    <input type="button" onclick="doba()" value="查问">    <input type="button" onclick="doqu()" value="返回首页"></form><table width="50%">    <thead>    <th>id</th>    <th>name</th>    <th>remark</th>    <th>createdTime</th>    <th>operation</th>    </thead>    <tbody>    <tr th:each="g:${list}">        <td th:text="${g.id}">1</td>        <td th:text="${g.name}">MySQL</td>        <td th:text="${g.remark}">DBMS</td>        <td th:text="${#dates.format(g.createdTime, 'yyyy/MM/dd HH:mm')}">2020/07/03</td>        <td><a>delete</a></td>    </tr>    </tbody></table><script>    function doba(){    //获取form表单中的数据    var name=document.forms[0].name.value;    console.log("name",name);    var url="http://localhost/goods/doFind/"+name;    location.href=url;    }function doqu(){   var url="http://localhost/goods/doFind/";   //拜访的url(当前换异步)   location.href=url;}</script></body></html>

我的项目启动及运行过程中BUG及问题剖析

  • STS控制台“?”符号,如图所示:

  • 服务启动失败,如图所示:

  • 模板不存在谬误,如图所示:

  • 日期格局不正确,如图所示:

  • 页面上${}内容谬误,如图所示:

  • 页面日期格局不正确,如图所示:

  • 依赖注入失败,如图所示:

  • 空指针异样(NullPointerException),如图所示:

405异样示意客户端提交的申请形式与服务端可解决的申请不匹配

商品删除业务实现

业务形容

从商品库查问商品信息后,点击页面上删除超链接,基于id删除以后行记录

业务时序剖析

在商品出现页面,用户执行删除操作,其删除时序如图所示:

Dao接口办法及映射定义

在GoodsDao接口中定义商品删除办法以及SQL映射

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

brand.html增加删除

<td><a th:href="@{/goods/doFind/{id}(id=@{g.id})}">delete</a></td>

按钮模式

<td><button type="button" th:onclick="delectBy([[${g.id}]])">删除</button></td>function delectBy(id){if(!confirm("确定删除吗")) return;location.href="http://localhost/goods/delectBy/"+id;}

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

Service接口办法定义及实现

在GoodsService接口中增加删除办法,代码如下:

int findGoods02(Integer id);

在GoodsService的实现类GoodsImp中增加deleteById办法实现。代码如下。

@Overridepublic int findGoods02(Integer id) {    long t1=System.currentTimeMillis();   int rows=goodsDao.findGoods02(id);    long t2=System.currentTimeMillis();    log.info("find02->{}",t2-t1);    return rows;}

在实现类中的增加doDeleteById办法,代码如下:

 @GetMapping("/goods/delectBy/{id}")public String delectBy(@PathVariable Integer id,Model model){   goodsService.findGoods02(id);    List<Goods> list=goodsService.findGoods(null);    model.addAttribute("list", list);   return "brand";}

测试:失常运行就根本ok

@Testvoid testwo(){    int rows=goodsService.findGoods02(10); Assertions.assertNotEquals(-1, rows);    System.out.println(rows);}

我的项目启动及运行过程中的Bug及问题剖析

  • SQL映射元素定义问题,如图所示:

  • 客户端申请参数与服务端参数不匹配,如图所示:

商品增加业务实现

业务形容

在Goods列表页面,增加增加按钮,进行增加页面,而后在增加页面输出商品相干信息,而后保留到数据库,

商品增加页面,设计如图所示:

业务时序剖析

在商品增加页面,输出商品信息,而后提交到服务端进行保留,其时序剖析如图所示:

Dao接口办法及映射定义

在GoodsDao中增加用于保留商品信息的接口办法以及SQL映射,代码如下:

@Insert("insert into tb_goods(name,remark,createdTime) values (#{name},#{remark},now())")int insertObject(Goods entity);

阐明:当SQL语句比较复杂时,也能够将SQL定义到映射文件(xml文件)中。

Service接口办法定义及实现

在GoodsService接口中增加业务办法,用于实现商品信息增加,代码如下:

int saveGoods(Goods entity);

在GoodsSerivceImpl类中增加接口办法实现,代码如下:

 @Override    public int saveGoods(Goods entity) {        int rows=goodsDao.insertObject(entity);        return rows;    } 

写一个Good.html,来看胜利是否
如下:

<!DOCTYPE html><html lang="en"><head>    <meta charset="UTF-8">    <title>Title</title></head><body><form>    <input type="button" onclick="doqu()" value="返回首页"></form><h1>胜利</h1><script>    function doqu(){   var url="http://localhost/goods/doFind";   location.href=url;}</script></body></html>

Controller对象办法定义及实现

在GoodsController类中增加用于解决商品增加申请的办法,代码如下:

@RequestMapping("/goods/doAll")public String doAll(Goods en){    goodsService.saveGoods(en);    return "Good";}

在GoodsController类中增加用于返回商品增加页面的办法,代码如下:

@GetMapping("/goods/doGoodsAddUI")public String doGoodsAddUI() {    return "one";}

Goods增加页面设计及实现

在templates的pages目录中增加one.html页面,代码如下

<!DOCTYPE html><html><head><meta charset="UTF-8"><style type="text/css"> ul li {list-style-type: none;} </style></head><body><h1>The Goods Add Page</h1><form th:action="@{/goods/doAll}" method="post">    <ul>        <li>name:        <li><input type="text" name="name">        <li>remark:        <li><textarea rows="5" cols="50" name="remark"></textarea>        <li><input type="submit" value="提交">    </ul></form></body></html>

在brand.html页面中增加,超链接能够跳转到增加页面,要害代码如下:

<a th:href="@{/goods/doGoodsAddUI}">增加商品</a><!-按钮跳转--><td><button type="button" th:onclick="Allone()">增加商品</button><script>function Allone(){var url="http://localhost/goods/doGoodsAddUI";location.href=url;}</script>

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

第一步:启动web服务器,检测启动过程是否OK,如果没有问题进入下一步。
第二步:关上浏览器在地址里输出http://localhost/goods/doGood...),呈现如下界面,如图所示:

第三步:在增加页面中填写表单,而后点击save按钮将表单数据提交到服务端,如图所示:

我的项目启动及运行过程中的Bug及问题剖析

  • 客户端显示400异样,如图所示:

  • 保留时500异样,如图所示:

  • 数据库完整性束缚异样,如图所示:

商品批改业务实现

业务形容

在商品列表页面,点击update选项,基于商品id查问以后行记录而后将其更新到goods-update页面,如图所示:

在update页面选中,批改商品信息,而后点击 update goods 将表单数据提交到服务端进行更新

业务时序剖析

基于id查问商品信息的时序设计

将goods-update页面中的数据提交到服务端进行更新的时序设计

Dao接口办法及映射定义

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

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

在GoodsDao中增加基于id执行Goods商品更新的办法及SQL映射,代码如下:

 @Update("update tb_brand set name=#{name},remark=#{remark} where id=#{id}") int updateGoods(Goods goods);

Service接口办法定义及实现

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

Goods findById(Integer id);int updateGoods(Goods goods);

在brand.html页面中增加,超链接能够跳转到批改页面,要害代码如下:

<td><button type="button" th:onclick="updateone([[${g.id}]])">批改</button><script>function updateone(id){if(!confirm("确定批改吗")) return;var url="http://localhost/goods/doFindBy/"+id;location.href=url;}</script>

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

 @Override    public Goods findById(Integer id) {        //.....        return goodsDao.findById(id);    }
 @Override    public int updateGoods(Goods goods) {        return goodsDao.updateGoods(goods);    }

Controller对象办法定义及实现

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

@GetMapping("/goods/doFindBy/{id}")public String doFindBy(@PathVariable Integer id,Model model){    Goods goods=goodsService.findById(id);   model.addAttribute("goods",goods);    return "update";}

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

 @GetMapping("/goods/doUpdate")public String doUpdategoods(Goods goods){    goodsService.updateGoods(goods);    return "Good";}

Goods批改页面设计及实现

在templates目录中增加update.html页面,代码设计如下:

<!DOCTYPE html><html><head><meta charset="UTF-8"><title>Insert title here</title><style type="text/css"> ul li {list-style-type: none} </style></head><body>   <h1>The Goods Update Page</h1>   <form th:action="@{/goods/doUpdate}" method="get">    <input type="hidden" name="id" th:value="${goods.id}">    <ul>        <li>name:        <li><input type="text" name="name" th:value="${goods.name}">        <li>remark:        <li><textarea rows="3" cols="30" name="remark" th:text="${goods.remark}"></textarea>        <li><input type="submit" value="提交">    </ul></form></body></html>

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

启动tomcat服务,拜访商品列表页面,如图所示:

在列表页面,点击update选项,进入更新页面

在更新页面更新表单数据,而后提交,进入列表页面查看更新后果,如图所示:

完结