15-基于Spring,MyBatis,SpringBoot,Vue技术实现购物券系统的增删改查操作。
发布于 10月19日
业务描述
基于Spring,MyBatis,SpringBoot,VUE技术实现购物券的增删改查操作。
项目环境初始化
准备工作
1. MySQL(5.7)
2. JDK (1.8)
3. Maven (3.6.3)
4. IDEA(2020.2)
数据库初始化
打开mysql控制台,然后按如下步骤执行dbretail.sql文件。
第一步:登录mysql。
mysql –uroot –proot
第二步:设置控制台编码方式。
set names utf8;
第三步:执行dbretail.sql文件(切记不要打开文件复制到mysql客户端运行)。
source d:/dbretail.sql
其中dbvoucher.sql文件内容如下:
drop database if exists dbretail;
create database dbretail default character set utf8;
use dbretail;
CREATE TABLE tb_voucher(
`id` INT UNSIGNED PRIMARY KEY AUTO_INCREMENT COMMENT '主键',
`deno` DECIMAL(10,2) UNSIGNED NOT NULL COMMENT '面值',
`requirement` DECIMAL(10,2) UNSIGNED NOT NULL COMMENT '订单多少钱可以使用',
`startTime` DATETIME COMMENT '起始日期',
`endTime` DATETIME COMMENT '截至日期',
`maxNum` INT COMMENT '代金卷发放最大数量',
`remark` varchar(200) COMMENT '备注',
`createdTime` DATETIME COMMENT '创建日期'
) COMMENT='购物券表';
insert into tb_voucher values (null,100,1000,'2020/05/07','2020/06/07',200,'Remark',now());
insert into tb_voucher values (null,80,800,'2020/05/07','2020/06/07',300,'Remark',now());
insert into tb_voucher values (null,50,500,'2020/05/07','2020/06/07',400,'Remark',now());
insert into tb_voucher values (null,30,300,'2020/05/07','2020/06/07',500,'Remark',now());
insert into tb_voucher values (null,10,100,'2020/05/07','2020/06/07',600,'Remark',now());
创建项目并添加依赖
基于IDEA创建
第一步:创建Empty项目并设置基本信息(假如Empty项目已经存在则无需创建)
第二步:基于start.spring.io 创建项目Module,并设置基本信息。
第三步:创建项目module时指定项目核心依赖
第四步:继续完成module的创建并分析其结构
项目配置文件内容初始化
#server
server.port=80
#spring datasource
spring.datasource.url=jdbc:mysql:///dbvoucher?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.retail=debug
项目API架构设计
其API架构设计,如图所示:
商品查询业务实现
业务描述
从数据库查询购物卷信息,并将购物卷信息呈现在页面上,如图所示:
业务时序分析
查询所有购物券信息,其业务时序分析,如图所示:
Pojo类定义
定义Voucher对象,用于封装从数据库查询到的购物券信息。
package com.cy.retail.voucher.pojo;
import com.fasterxml.jackson.annotation.JsonFormat;
import java.io.Serializable;
import java.util.Date;
/**购物卷*/
public class Voucher implements Serializable {
private static final long serialVersionUID = -8863293149012534747L;
private Integer id;
/**面值*/
private Integer deno;
/**条件(多少钱可以使用)*/
private Integer requirement;
/**起始时间*/
@JsonFormat(pattern = "yyyy/MM/dd HH:mm")
private Date startTime;
/**结束时间*/
@JsonFormat(pattern = "yyyy/MM/dd HH:mm")
private Date endTime;
/**代金卷发放最大数量*/
private Integer maxNum;
/**备注*/
private String remark;
/**创建时间*/
private Date createdTime;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public Integer getDeno() {
return deno;
}
public void setDeno(Integer deno) {
this.deno = deno;
}
public Integer getRequirement() {
return requirement;
}
public void setRequirement(Integer requirement) {
this.requirement = requirement;
}
public Date getStartTime() {
return startTime;
}
public void setStartTime(Date startTime) {
this.startTime = startTime;
}
public Date getEndTime() {
return endTime;
}
public void setEndTime(Date endTime) {
this.endTime = endTime;
}
public Integer getMaxNum() {
return maxNum;
}
public void setMaxNum(Integer maxNum) {
this.maxNum = maxNum;
}
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 "Voucher{" +
"id=" + id +
", deno=" + deno +
", requirement=" + requirement +
", startTime=" + startTime +
", endTime=" + endTime +
", maxNum=" + maxNum +
", remark='" + remark + ''' +
", createdTime=" + createdTime +
'}';
}
}
Dao接口方法及映射定义
在GoodsDao接口中定义商品查询方法以及SQL映射,基于此方法及SQL映射获取所有商品信息。代码如下:
package com.cy.retail.voucher.dao;
import com.cy.retail.voucher.pojo.Voucher;
import org.apache.ibatis.annotations.Delete;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Select;
import java.util.List;
@Mapper
public interface VoucherDao {
@Select("select count(*) from tb_voucher")
int getRowCount();
@Select("select * from tb_voucher order by createdTime desc limit #{startIndex},#{pageSize}")
List<Voucher> findPageObjects(Integer startIndex, Integer pageSize);
}
编写单元测试类进行测试分析:
package com.cy.retail.voucher.dao;
import com.cy.retail.voucher.pojo.Voucher;
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 VoucherDaoTests {
@Autowired
private VoucherDao voucherDao;
@Test
void testGetRowCount(){
int rowCount=voucherDao.getRowCount();
System.out.println("rowCount="+rowCount);
}
@Test
void testFindPageObjects(){
List<Voucher> list=voucherDao.findPageObjects(0,3);
list.forEach(item-> System.out.println(item));
}
}
Service接口方法定义及实现
业务逻辑层分页逻辑封装对象定义,代码如下:
package com.cy.retail.common.pojo;
import java.io.Serializable;
import java.util.List;
public class PageObject<T> implements Serializable {
/**总记录数*/
private Integer rowCount;
/**当前页记录*/
private List<T> records;
/**总页数(计算出来)*/
private Integer pageCount;
/**当前页码值*/
private Integer pageCurrent;
/**页面大小(每页最多显示多少条记录)*/
private Integer pageSize;
public PageObject(Integer rowCount, List<T> records, Integer pageCurrent, Integer pageSize) {
this.rowCount = rowCount;
this.records = records;
this.pageCurrent = pageCurrent;
this.pageSize = pageSize;
this.pageCount=rowCount/pageSize;
if(this.rowCount%this.pageSize!=0)this.pageCount++;
}
public Integer getRowCount() {
return rowCount;
}
public void setRowCount(Integer rowCount) {
this.rowCount = rowCount;
}
public List<T> getRecords() {
return records;
}
public void setRecords(List<T> records) {
this.records = records;
}
public Integer getPageCount() {
return pageCount;
}
public void setPageCount(Integer pageCount) {
this.pageCount = pageCount;
}
public Integer getPageCurrent() {
return pageCurrent;
}
public void setPageCurrent(Integer pageCurrent) {
this.pageCurrent = pageCurrent;
}
public Integer getPageSize() {
return pageSize;
}
public void setPageSize(Integer pageSize) {
this.pageSize = pageSize;
}
@Override
public String toString() {
return "PageObject{" +
"rowCount=" + rowCount +
", records=" + records +
", pageCount=" + pageCount +
", pageCurrent=" + pageCurrent +
", pageSize=" + pageSize +
'}';
}
}
VoucherService接口及查询方法定义
package com.cy.retail.voucher.service;
import com.cy.retail.common.pojo.PageObject;
import com.cy.retail.voucher.pojo.Voucher;
public interface VoucherService {
/**
* 分页查询Voucher信息
* @param pageCurrent
* @param pageSize
* @return
*/ PageObject<Voucher> findPageObjects(Integer pageCurrent,Integer pageSize);
}
VoucherService接口实现类VoucherServiceImpl定义及方法实现
package com.cy.retail.voucher.service.impl;
import com.cy.retail.common.pojo.PageObject;
import com.cy.retail.voucher.dao.VoucherDao;
import com.cy.retail.voucher.pojo.Voucher;
import com.cy.retail.voucher.service.VoucherService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
@Service
public class VoucherServiceImpl implements VoucherService {
@Autowired
private VoucherDao voucherDao;
@Override
public int deleteById(Integer id) {
return voucherDao.deleteById(id);
}
@Override
public PageObject<Voucher> findPageObjects(Integer pageCurrent, Integer pageSize) {
int rowCount=voucherDao.getRowCount();
int startIndex=(pageCurrent-1)*pageSize;
List<Voucher> records=voucherDao.findPageObjects(startIndex,pageSize);
return new PageObject<>(rowCount,records,pageCurrent,pageSize);
}
}
编写单元测试类进行测试分析
package com.cy.retail.voucher.service;
import com.cy.retail.common.pojo.PageObject;
import com.cy.retail.voucher.dao.VoucherDao;
import com.cy.retail.voucher.pojo.Voucher;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
@SpringBootTest
public class VoucherServiceTests {
@Autowired
private VoucherService voucherService;
@Test
void testFindPageObjects(){
PageObject<Voucher> pageObject=
voucherService.findPageObjects(1,3);
System.out.println(pageObject);
}
}
Controller对象方法定义及实现
控制逻辑层响应数据标准对象设计及实现,代码如下:
package com.cy.retail.common.pojo;
import java.io.Serializable;
public class ResponseResult implements Serializable {
private static final long serialVersionUID = -4971076199594828397L;
/**状态:1 ok,0 error*/
private Integer state=1;
/**状态信息*/
private String message="ok";
/**业务层返回的正确响应数据*/
private Object data;
public ResponseResult(){}
public ResponseResult(String message){ //new JsonResult("update ok");
this.message=message;
}
public ResponseResult(Object data){
this.data=data;
}
public ResponseResult(Throwable e){
this.state=0;
this.message=e.getMessage();
}
public Integer getState() {
return state;
}
public void setState(Integer state) {
this.state = state;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
public Object getData() {
return data;
}
public void setData(Object data) {
this.data = data;
}
}
定义VoucherController类,并添加doFindPageObjects方法,代码如下:
ackage com.cy.retail.voucher.controller;
import com.cy.retail.common.pojo.PageObject;
import com.cy.retail.common.pojo.ResponseResult;
import com.cy.retail.voucher.service.VoucherService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class VoucherController {
@Autowired
private VoucherService voucherService;
@GetMapping("/voucher/doFindPageObjects/{pageCurrent}/{pageSize}")
public ResponseResult doFindPageObjects(@PathVariable Integer pageCurrent,@PathVariable Integer pageSize){
return new ResponseResult(voucherService.findPageObjects(pageCurrent,pageSize));
}
}
控制层统一异常处理类设计及实现,关键代码如下:
package com.cy.retail.common.web;
import com.cy.retail.common.pojo.ResponseResult;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
@RestControllerAdvice
public class GlobalExceptionHandler {
private static final Logger log= LoggerFactory.getLogger(GlobalExceptionHandler.class);
@ExceptionHandler(RuntimeException.class)
public ResponseResult doHandleRuntimeException(RuntimeException e){
e.printStackTrace();//控制台输出
log.error("exception msg {}"+e.getMessage());
return new ResponseResult(e);
}
}
Voucher页面设计及实现
在static目录中添加voucher.html页面,代码如下:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<link href="/bootstrap/css/bootstrap.min.css" rel="stylesheet">
</head>
<body>
<div id="app" class="container">
<h1>The Voucher Page</h1>
<table class="table">
<thead>
<tr>
<th>序号</th>
<th>面值</th>
<th>可用条件</th>
<th>起始日期</th>
<th>截止日期</th>
<th>数量</th>
<th>操作</th>
</tr>
</thead>
<tbody>
<tr v-for="(v,i) of vouchers" :key="i">
<td>{{i+1}}</td>
<td>{{v.deno}}</td>
<td>{{v.requirement}}</td>
<td>{{v.startTime}}</td>
<td>{{v.endTime}}</td>
<td>{{v.maxNum}}</td>
<td><button class="btn btn-danger btn-xs">delete</button></td>
</tr>
</tbody>
</table>
<div id="pageId" class="box-footer clearfix" dm="100">
<ul class="pagination pagination-sm no-margin pull-right">
<li><a class="first" @click="doJumpToPage">首页</a></li>
<li><a class="pre" @click="doJumpToPage">上一页</a></li>
<li><a class="next" @click="doJumpToPage">下一页</a></li>
<li><a class="last" @click="doJumpToPage">尾页</a></li>
<li><a class="rowCount">总记录数({{rowCount}})</a></li>
<li><a class="pageCount">总页数({{pageCount}})</a></li>
<li><a class="pageCurrent">当前页({{pageCurrent}})</a></li>
</ul>
</div>
</div>
<script src="/js/axios.min.js"></script>
<script src="/js/vue.js"></script>
<script> var vm=new Vue({
el:"#app",
data:{
vouchers:{},
pageCurrent:1,
pageCount:0,
rowCount:0
},
methods:{
doFindPageObjects(){
let url=`voucher/doFindPageObjects/${this.pageCurrent}/3`;
axios.get(url).then(function(result){
let respData=result.data.data;
this.vm.vouchers=respData.records;
this.vm.rowCount=respData.rowCount;
this.vm.pageCount=respData.pageCount;
this.vm.pageCurrent=respData.pageCurrent;
})
},
doJumpToPage(event){
let cls=event.target.getAttribute("class");
if(cls=="first"){
this.pageCurrent=1;
}else if(cls=="pre"&& this.pageCurrent>1){
this.pageCurrent--;
}else if(cls=="next"&& this.pageCurrent< this.pageCount){
this.pageCurrent++;
}else if(cls=="last"){
this.pageCurrent= this.pageCount;
}else{
return;
}
//3.基于新的页码值重新执行查询
this.doFindPageObjects();
}
},
mounted:function(){
this.doFindPageObjects();
}
}); </script>
</body>
</html>
启动服务器进行访问测试分析
首先,启动tomcat,然后在打开浏览器,在地址栏输入访问地址,获取服务端数据并进行呈现,如图所示:
购物券删除业务实现
业务描述
从数据库查询购物券信息后,点击页面上删除按钮,基于id删除当前行记录,如图所示:
业务时序分析
在购物券呈现页面,用户执行删除操作,其删除时序如图所示:
Dao接口方法及映射定义
在VoucherDao接口中定义删除方法以及SQL映射,代码如下:
@Delete("delete from tb_voucher where id=#{id}")
int deleteById(Integer id);
Service接口方法定义及实现
在VoucherService接口中添加删除方法,代码如下:
int deleteById(Integer id);
在VoucherService的实现类VoucherServiceImpl中添加deleteById方法实现。代码如下。
@Override
public int deleteById(Integer id) {
int rows=voucherDao.deleteById(id);
return rows;
}
Controller对象方法定义及实现
在VoucherController中的添加doDeleteById方法,代码如下:
@DeleteMapping("/voucher/doDeleteById/{id}")
public ResponseResult doDeleteById(@PathVariable Integer id){
voucherService.deleteById(id);
return new ResponseResult(id);
}
说明:Restful 风格为一种软件架构编码风格,定义了一种url的格式,其url语法为/a/b/{c}/{d},在这样的语法结构中{}为一个变量表达式。假如我们希望在方法参数中获取rest url中变量表达式的值,可以使用@PathVariable注解对参数进行描述。
Voucher页面上删除按钮事件处理
在voucher.html页面中添加删除事件,代码如下:
<button @click="doDeleteById(v.id)" class="btn btn-danger btn-xs">delete</button>
在vue的methods对象中添加删除方法,代码如下:
doDeleteById(id){
let url=`voucher/doDeleteById/${id}`;
axios.delete(url).then(function(result){
alert(result.data.message);
this.vm.doFindPageObjects();
})
}
启动tomcat服务器进行访问测试分析
启动tomcat,然后在打开浏览器,在地址栏输入访问地址,获取服务端数据并进行呈现,接下来点击页面上的删除按钮进行测试。
购物券添加业务设计实现
业务描述
在购物券页面中设计添加表单,然后点击表单中的Save 按钮时将表单数据异步提交到服务端进行保存,如图所示:
业务时序设计及分析
在购物券页面,输入购物券信息,然后提交到服务端进行保存,其时序分析如图所示:
DAO接口方法设计及实现
在VoucherDao中添加用于保存商品信息的接口方法,代码如下:
int insertObject(Voucher entity);
在VoucherMapper文件中添加insertObject方法对应的SQL映射,代码如下:
<?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.retail.voucher.dao.VoucherDao">
<insert id="insertObject">
insert into tb_voucher
(deno,requirement,startTime,endTime,maxNum,remark,createdTime)
values
(#{deno},#{requirement},#{startTime},#{endTime},#{maxNum},#{remark},now())
</insert>
</mapper>
Service接口方法设计及实现
在VoucherService接口中添加业务方法,用于实现购物券信息添加,代码如下:
int saveObject(Voucher entity);
在VoucherSerivceImpl类中添加接口方法实现,代码如下:
@Override
public int saveObject(Voucher entity) {
return voucherDao.insertObject(entity);
}
Controller类中方法设计及实现
在VoucherController类中添加用于处理添加请求的方法,代码如下:
@PostMapping("/voucher/doSaveObject")
public ResponseResult doSaveObject(@RequestBody Voucher entity){
System.out.println(entity);
voucherService.saveObject(entity);
return new ResponseResult("save ok");
}
购物券页面表单元素设计及事件处理
在voucher.html页面代码中设计添加表单,代码如下:
<div>
<form>
<input type="hidden" v-model="id">
<div class="form-group">
<label for="denoId">面值</label>
<input type="text" v-model="deno" class="form-control" id="denoId" placeholder="面值">
</div>
<div class="form-group">
<label for="requirementId">应用条件</label>
<input type="text" v-model="requirement" class="form-control" id="requirementId" placeholder="应用条件">
</div>
<div class="form-group">
<label for="startTimeId">起始日期</label>
<input type="text" v-model="startTime" class="form-control" id="startTimeId" placeholder="起始日期">
</div>
<div class="form-group">
<label for="endTimeId">截至日期</label>
<input type="text" v-model="endTime" class="form-control" id="endTimeId" placeholder="截至日期">
</div>
<div class="form-group">
<label for="maxNumId">最大数量</label>
<input type="text" v-model="maxNum" class="form-control" id="maxNumId" placeholder="最大数量">
</div>
<div class="form-group">
<label for="maxNumId">备注</label>
<textarea v-model="remark" class="form-control" id="remarkId" placeholder="备注"></textarea>
</div>
<div class="form-group">
<input type="button" @click="doSaveOrUpdate" value="Save Data" class="btn btn-primary"/>
</div>
</form>
</div>
在Vue对象的Data区添加属性数据,代码如下:
deno:"",
requirement:"",
startTime:"",
endTime:"",
maxNum:"",
remark:"",
在Vue对象中的Methods区,添加保存按钮事件处理函数,代码如下:
doSaveOrUpdate(){
let url="voucher/doSaveObject";
let params={"id":this.id,"deno":this.deno,"requirement":this.requirement,"startTime":this.startTime,"endTime":this.endTime,"maxNum":this.maxNum,"remark":this.remark};
console.log(params);
axios.post(url,params).then(function(result){
alert(result.data.message);
this.vm.doFindPageObjects();
this.vm.id="";
this.vm.deno="";
this.vm.requirement="";
this.vm.startTime="";
this.vm.endTime="";
this.vm.maxNum="";
this.vm.remark="";
})
}
购物券修改业务设计实现
业务描述
在购物券页面中设计修改按钮,并在点击修改按钮时候基于id查询购物券信息,然后呈现在表单中,如图所示:
业务时序设计及分析
基于用户更新设计其执行时序。
Dao接口方法设计及实现
在VoucherDao中添加基于id查询和更新的方法,代码如下:
@Select("select * from tb_voucher where id=#{id}")
Voucher findById(Integer id);
int updateObject(Voucher entity);
将updateObject方法的SQL映射添加到映射文件(建议SQL内容比较多的写到映射文件),代码如下:
<update id="updateObject">
update tb_voucher
set
deno=#{deno},
requirement=#{requirement},
startTime=#{startTime},
endTime=#{endTime},
maxNum=#{maxNum},
remark=#{remark}
where id=#{id}
</update>
Service接口方法设计及实现
在VoucherService中添加基于id查询和更新的方法,代码如下:
Voucher findById(Integer id);
int updateObject(Voucher entity);
在VoucherServiceImpl类中添加基于id查询和更新的方法,代码如下:
@Override
public Voucher findById(Integer id) {
return voucherDao.findById(id);
}
@Override
public int updateObject(Voucher entity) {
return voucherDao.updateObject(entity);
}
Controller类中方法设计及实现
在VoucherController类中添加处理基于id的查询请求方法和更新购物券信息的方法,代码如下:
@GetMapping("/voucher/doFindById/{id}")
public ResponseResult doFindById(@PathVariable Integer id){
Voucher voucher=voucherService.findById(id);
return new ResponseResult(voucher);
}
@PostMapping("/voucher/doUpdateObject")
public ResponseResult doUpdateObject(@RequestBody Voucher entity){
voucherService.updateObject(entity);
return new ResponseResult("update ok");
}
Voucher页面中更新设计设计及实现
在voucher页面设计中,在vue对象中的methods区添加基于id的查询请求方法,代码如下:
doFindById(id){
let url=`voucher/doFindById/${id}`;
axios.get(url).then(function(result){
console.log(result.data);
this.vm.id=result.data.data.id;
this.vm.deno=result.data.data.deno;
this.vm.requirement=result.data.data.requirement;
this.vm.startTime=result.data.data.startTime;
this.vm.endTime=result.data.data.endTime;
this.vm.maxNum=result.data.data.maxNum;
this.vm.remark=result.data.data.remark;
})
}
在voucher页面设计中,在vue对象中的methods区修改doSaveOrUpdate方法,代码如下:
doSaveOrUpdate(){
let url=this.id?"voucher/doUpdateObject":"voucher/doSaveObject";
let params={"id":this.id,"deno":this.deno,"requirement":this.requirement,"startTime":this.startTime,"endTime":this.endTime,"maxNum":this.maxNum,"remark":this.remark};
console.log(params);
axios.post(url,params).then(function(result){
alert(result.data.message);
this.vm.doFindPageObjects();
this.vm.id="";
this.vm.deno="";
this.vm.requirement="";
this.vm.startTime="";
this.vm.endTime="";
this.vm.maxNum="";
this.vm.remark="";
})
}
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。