乐趣区

关于java:实现商品CRUD操作

基于 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, 增加如下内容:

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

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

#spring logging
logging.level.com.cy=debug

#spring thymeleaf
spring.thymeleaf.prefix=classpath:/templates/pages/
spring.thymeleaf.suffix=.html
spring.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;

@Mapper
public interface GoodsDao {@Select("select * from tb_brand where name like concat('%',#{name},'%')and name!=null or name!=''")
      // 这样太简单,简单用映射比拟好
      List<Goods> findGoods(String name);
}

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

@Mapper
public 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;
@SpringBootTest
public 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;
@Service
public 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;
@SpringBootTest
public 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;
@Controller
public 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;
@Controller
public 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 办法实现。代码如下。

@Override
public 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

@Test
void 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 选项, 进入更新页面

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

完结

退出移动版