前端(表单)
效果图
html 和 模板引擎
html
<%--
Created by IntelliJ IDEA.
User: Administrator
Date: 2021/3/15 0015
Time: 17:39
To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>商品列表</title>
<jsp:include page="/common/backend_common.jsp"/>
<jsp:include page="/common/page.jsp"/>
<jsp:include page="/template/product/categoryListTemplate2.jsp"/>
<jsp:include page="/template/product/productListTemplate.jsp"/>
<jsp:include page="productForm/productForm.jsp"/>
</head>
<body class="no-skin" style="background: white">
<!-- 内容 -->
<div class="main-content">
<div class="main-content-inner">
<!-- 导航路径 -->
<div class="breadcrumbs ace-save-state" id="breadcrumbs">
<ul class="breadcrumb">
<li>
<i class="ace-icon fa fa-home home-icon"></i>
<a href="/sys/admin/index.page">Home</a>
</li>
<li class="">商品管理</li>
<li class="">商品列表</li>
</ul><!-- /.breadcrumb -->
<div class="nav-search" id="nav-search">
<form class="form-search">
<span class="input-icon">
<input type="text" placeholder="Search ..." class="nav-search-input" id="nav-search-input" autocomplete="off" />
<i class="ace-icon fa fa-search nav-search-icon"></i>
</span>
<a href="#">
<span class="menu-icon fa fa-shopping-cart" style="margin-left: 30px; color: coral; font-size: 30px"></span>
</a>
</form>
</div>
</div>
<div class="page-content">
<div class="page-header">
<h1>商品管理
<small>
<i class="ace-icon fa fa-angle-double-right"></i>
商品列表
</small>
</h1>
</div><!-- /.page-header -->
<div class="row">
<div class="col-xs-12">
<div class="col-sm-2">
<div class="table-header">
商品分类列表 <a class="green" href="#"></a>
</div>
<!-- 读取分类列表 -->
<div id="categoryList"></div>
</div>
<div class="col-xs-10">
<ul class="list-inline fa-border">
<li><button type="button" class="btn btn-warning fa fa-plus product-add">添加商品</button></li>
<li><button type="button" class="btn btn-danger fa fa-trash batchDel-btn">批量删除</button></li>
</ul>
<div class="col-xs-12 fa-border">
<ul class="list-inline">
<li>展示 <select id="pageSize">
<option value="10">10</option>
<option value="25">25</option>
<option value="50">50</option>
<option value="100">100</option>
</select> 条记录</li>
<li><input type="search" id="keyword" name="keyword" placeholder="关键字"/></li>
<li>状态 <select id="search_status">
<option value="1">有效</option>
<option value="0">无效</option>
</select></li>
<li><button class="btn btn-info fa fa-check research">查询</button></li>
</ul><!--/.ul-->
<table id="simple-table" class="table table-bordered table-hover">
<thead>
<tr>
<th class="center">
<label>
<input type="checkbox" class="ace batchDel-th">
<span class="lbl"></span>
</label>
</th>
<th>图片</th>
<th>商品名称</th>
<th>描述</th>
<th>所属分类</th>
<th>价格(元)</th>
<th>创建时间</th>
<th>更新时间</th>
<th>状态</th>
<th>操作</th>
</tr>
</thead>
<tbody id="productList"></tbody>
</table>
<div class="row" id="productPage"></div>
</div>
</div>
</div>
</div><!-- /.row -->
</div><!-- /.page-content -->
</div><!-- /.main-content-inner -->
</div><!-- /.main-content -->
<script src="/js/product/product.js"></script>
</body>
</html>
模板引擎
<%--
Created by IntelliJ IDEA.
User: Administrator
Date: 2021/3/26 0026
Time: 15:45
To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<div id="dialog-product-form" style="display: none;">
<form id="productForm" enctype="multipart/form-data">
<table class="table table-striped table-bordered table-hover dataTable no-footer" role="grid" >
<tr>
<td style="width: 80px;"><label for="categorySelectId">所属分类</label></td>
<td><select id="categorySelectId" name="categoryId"
data-placeholder="选择分类" style="width: 150px;"></select></td>
</tr>
<tr>
<td><label for="productName" style="width: 60px">商品名称</label></td>
<td>
<input type="text" name="productName" id="productName" value="" class="text ui-widget-content ui-corner-all">
<input type="hidden" name="id" id="productId"/>
</td>
</tr>
<tr>
<td><label for="productPrice">价格(元)</label></td>
<td><input type="text" name="price" id="productPrice"
value="" class="text ui-widget-content ui-corner-all"></td>
</tr>
<tr>
<td><label for="productImage">商品图片</label></td>
<td><input type="file" name="productImg" id="productImage" value=""
class="text ui-widget-content ui-corner-all" style="width: 200px"></td>
</tr>
<tr>
<td><label for="productStatus">状态</label></td>
<td>
<select id="productStatus" name="productStatus" data-placeholder="状态" style="width: 150px;">
<option value="1">有效</option>
<option value="0">无效</option>
</select>
</td>
</tr>
<tr>
<td><label for="productDescribes">描述</label></td>
<td><textarea id="productDescribes" name="describes" class="text ui-widget-content ui-corner-all" rows="3" cols="20" ></textarea></td>
</tr>
</table>
</form>
</div>
<%--
Created by IntelliJ IDEA.
User: Administrator
Date: 2021/3/26 0026
Time: 15:35
To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<script id="productListTemplate" type="x-tmpl-mustache">
{{#productList}}
<tr role="row" class="product-name odd" data-id="{{id}}"><!--even -->
<td class="center">
<label>
<input type="checkbox" class="ace batchDel-check">
<span class="lbl"></span>
</label>
</td>
<td><img src="/img/{{showProductImg}}" width="80px" height="50px"/></td>
<td>{{productName}}</td>
<td>{{describes}}</td>
<td>{{showCategory}}</td>
<td>{{price}}</td>
<td>{{#create_time}}{{/create_time}}</td>
<td>{{#update_time}}{{/update_time}}</td>
<td>{{#bold}}{{showStatus}}{{/bold}}</td>
<td>
<div class="hidden-sm hidden-xs action-buttons">
<a class="blue product-edit" href="#" data-id="{{id}}">
<i class="ace-icon fa fa-pencil bigger-100"></i>
</a>
<a class="red product-del" href="#" data-id="{{id}}" data-name="{{name}}">
<i class="ace-icon fa fa-trash bigger-100"></i>
</a>
</div>
</td>
</tr>
{{/productList}}
</script>
引入对应的js文件
显示
function loadProductImgList() {
$.ajax({
url : "/product/productImg.json",
type : "post",
success : function (result) {
if (result.status == "success"){
// 将每一张图片添加到map中
$.each(result.data, function (i, img) {
productImgMap[img.id] = img;
// alert(img.imgName);
});
}
}
});
}
// 渲染商品列表
function loadProductList(categoryId) {
loadProductImgList();
// 获取页码和当前页显示条数
pageNo = $('#productPage .pageNo').val() || 1;
pageSize = $('#pageSize').val();
keyword = $('#keyword').val(); // 获取关键字
search_status = $('#search_status').val(); // 获取状态
var url = "/product/product.json?categoryId=" + categoryId; // 请求资源
$.ajax({
url: url,
type: "POST",
data : {
pageNo : pageNo,
pageSize : pageSize,
keyword : keyword,
search_status : search_status
},
success : function (result) {
renderProductListAndPage(result, url);
}
});
}
// 渲染细节
function renderProductListAndPage(result, url) {
if (result.status == "success"){
if (result.data.total > 0){
var rendered = Mustache.render(productListTemplate, {
"productList" : result.data.records,
"showCategory" : function () {
return categoryMap[this.categoryId].name;
},
"showProductImg" : function () {
return productImgMap[this.imgId].imgName;
},
"create_time" : function () {
return function (text, render){
return new Date(
this.createTime)
.Format("yyyy-MM-dd");
}
},
"update_time" : function() {
return function(text, render) {
return new Date(
this.updateTime)
.Format("yyyy-MM-dd");
}
},
"showStatus" : function() {
return this.productStatus == 1 ? '有效'
: (this.productStatus == 0 ? '无效'
: '删除');
},
"bold" : function() {
return function(text, render) {
var status = render(text);
if (status == '有效') {
return "<span class='label label-sm label-success'>有效</span>";
} else if (status == '无效') {
return "<span class='label label-sm label-warning'>无效</span>";
} else {
return "<span class='label'>删除</span>";
}
}
}
});
// 将product添加到map中
$.each(result.data.records, function (i, product) {
productMap[product.id] = product;
});
//在指定id下添加带数据的页面样式
$('#productList').html(rendered);
}else {
$('#productList').html("");
}
// 绑定操作
bindProductClick();
pageNo = $('#productPage .pageNo').val() || 1; // 获取当前页码
pageSize = $('#pageSize').val(); // 获取显示条数
// 分页页码
renderPage(
url,
result.data.total,
pageNo,
pageSize,
result.data.total > 0 ? result.data.records.length : 0,
"productPage",
renderProductListAndPage);
}else {
//showMessage("获取分类下的商品列表",result.msg, false);
}
}
添加
使用ajax上传图片,使用new FormData($(’#productForm’)[0]);读取数据 ,需加入contentType : false, 不使用默认的表头, processData : false, 不序列化表单
// 添加商品
$('.product-add').click(function () {
// 弹出框
$('#dialog-product-form').dialog({
model : true, // 背景不可点击
title : "添加商品",
open : function (event, ui) {
$(".ui-dialog").css("width", "350px");//增加模态框的宽高
// 隐藏关闭按钮
$('.ui-dialog-titlebar-close', $(this).parent()).hide();
opcategory();
// 清空表单
$('#productForm')[0].reset();
},
buttons : {
"添加" : function (e) {
// 阻止默认事件
e.preventDefault();
// 执行添加分类
updateProduct(true, function (data) {
// 添加成功后提示信息
showMessage("添加商品", data.msg, true);
// 关闭模态框
$('#dialog-product-form').dialog("close");
loadProductList(lastClickCategoryId);
}, function (data) {
// 添加失败后提示信息
showMessage("添加商品", data.msg,false);
$('#dialog-product-form').dialog("close");
});
},
"取消" : function () {
$('#dialog-product-form').dialog("close");
}
}
});
});
// 执行添加更新操作
function updateProduct(isCreate, successCallback, failCallback) {
var formData = new FormData($('#productForm')[0]);
$.ajax({
url : isCreate ? "/product/insert.json" : "/product/update.json",
type : "POST",
data : formData,
contentType : false,
processData : false,
success : function (result) {
// 数据执行成功返回的消息
if (result.status == "success"){
// 带参回调函数
loadProductList();
if (successCallback){
successCallback(result);
}
}else {
// 执行失败返回的消息
if (failCallback){
failCallback(result);
}
}
}
});
}
后台
controller
// 返回上商品列表
@RequestMapping("/product.json")
@ResponseBody
public CommonReturnType user(@RequestParam("categoryId") int categoryId, SearchProductVo productVo, PageQuery pageQuery){
IPage<Product> result = productService.productPageByCategoryId(categoryId, productVo, pageQuery);
return CommonReturnType.success(result);
}
// 获取图片
@RequestMapping("/productImg.json")
@ResponseBody
public CommonReturnType img(){
List<ProductImg> result = productService.imgList();
return CommonReturnType.success(result);
}
// 添加商品
@RequestMapping("/insert.json")
@ResponseBody
public CommonReturnType insert(ProductVo productVo) throws IOException {
productService.insertProduct(productVo);
return CommonReturnType.success("success");
}
service
// 根据分类id查询商品
@Override
public IPage<Product> productPageByCategoryId(int categoryId, SearchProductVo productVo, PageQuery pageQuery) {
// 注解检验
validator.check(pageQuery);
// 将vo赋值给dto
SearchProductDto dto = new SearchProductDto();
if (StringUtils.isNotBlank(productVo.getKeyword())){
dto.setKeyword(productVo.getKeyword());
}
if (StringUtils.isNotBlank(productVo.getSearch_status())){
dto.setSearch_status(Integer.parseInt(productVo.getSearch_status()));
}
// mybatis-plus 的查询条件
QueryWrapper<Product> queryWrapper = new QueryWrapper<>();
if (StringUtils.isNotBlank(String.valueOf(categoryId))){
queryWrapper.eq("category_id", categoryId);
}
if (StringUtils.isNotBlank(dto.getKeyword())){
// 模糊查询 %name%
queryWrapper.like("product_name", dto.getKeyword());
}
if (StringUtils.isNotBlank(String.valueOf(dto.getSearch_status()))){
queryWrapper.eq("product_status", dto.getSearch_status());
}
// 统计符合条件的数据
int count = productMapper.selectCount(queryWrapper);
IPage<Product> page = new Page<>(pageQuery.getPageNo(), pageQuery.getPageSize());
if (count > 0){
page = productMapper.selectPage(page,queryWrapper.orderByDesc("id"));
return page;
}
return page;
}
// 添加商品
@Override
public void insertProduct(ProductVo productVo) throws IOException {
validator.check(productVo);
System.out.println(productVo.getProductName());
System.out.println(productVo.getProductImg());
// 文件名
String imageName = ImageUtils.uploadImg(productVo.getProductImg());
System.out.println(imageName);
if (StringUtils.isNotBlank(imageName)){
ProductImg img = ProductImg.builder().imgName(imageName).build();
productImgMapper.insert(img);
}
// 获取图片id
QueryWrapper<ProductImg> queryWrapper = new QueryWrapper<>();
queryWrapper.eq("img_name", imageName);
int id = productImgMapper.selectOne(queryWrapper).getId();
// 商品去重
if (checkProductNameExist(productVo.getProductName(), productVo.getId())){
throw new BusinessException("商品已经存在");
}
// 建造者模式
Product entity = Product.builder().productName(productVo.getProductName())
.describes(productVo.getDescribes()).productStatus(productVo.getProductStatus())
.categoryId(productVo.getCategoryId()).imgId(id).price(productVo.getPrice())
.creator("admin").createTime(new Date()).updateTime(new Date()).build();
// 添加商品
productMapper.insert(entity);
}
// 查询所有图片
@Override
public List<ProductImg> imgList() {
List<ProductImg> imgs = productImgMapper.selectList(null);
return imgs;
}
// 商品去重
private boolean checkProductNameExist(String productName, Integer id) {
QueryWrapper<Product> queryWrapper = new QueryWrapper<>();
queryWrapper.eq("product_name", productName);
if (null != id){
queryWrapper.ne("id", id);
}
return productMapper.selectCount(queryWrapper) > 0;
}
图片上传自定义地址
package com.lzy.utils;
import org.apache.tomcat.Jar;
import org.springframework.boot.system.ApplicationHome;
import org.springframework.util.ClassUtils;
import org.springframework.web.multipart.MultipartFile;
import java.io.File;
import java.io.IOException;
import java.util.jar.JarFile;
public class ImageUtils {
public static String uploadImg(MultipartFile file) throws IOException {
// 上传地址
ApplicationHome applicationHome = new ApplicationHome(ImageUtils.class);
String path = applicationHome.getSource().getParentFile().getParentFile().getParentFile().getPath()
+ "\\SuperMarket-web\\src\\main\\webapp\\img";
// 获取图片名
String fileName = file.getOriginalFilename();
// 根据时间戳生成新的文件名
String imageName = System.currentTimeMillis() + fileName.substring(fileName.lastIndexOf("."));
// 封装上传文件位置的全路径
File targetFile = new File(path,imageName);
//把本地文件上传到封装上传文件位置的全路径
file.transferTo(targetFile);
return imageName;
}
}