1. MP分页查询
1.1 编辑ItemController
@RestController
@RequestMapping("/item")
public class ItemController {
@Autowired
private ItemService itemService;
/**
* 业务说明: 根据分页实现商品查询
* URL地址: http://localhost:8091/item/query?page=1&rows=20
* 参数: page/rows
* 返回值: EasyUITable
*/
@RequestMapping("/query")
public EasyUITable findItemByPage(Integer page, Integer rows){
return itemService.findItemByPage(page,rows);
}
}
1.2 编辑ItemServiceImpl
@Override
public EasyUITable findItemByPage(Integer page, Integer rows) {
//1.通过分页对象 将page rows 进行参数封装
IPage iPage = new Page(page,rows);
QueryWrapper<Item> queryWrapper = new QueryWrapper<>();
//倒序排列,按照更新时间排序
queryWrapper.orderByDesc("updated");
//通过iPage对象封装其他的分页数据
iPage = itemMapper.selectPage(iPage,queryWrapper);
//获取记录总数
long total = iPage.getTotal();
//获取当前页的记录
List<Item> itemList = iPage.getRecords();
//返回给页面
return new EasyUITable(total,itemList);
}
1.3 编辑MP配置类
package com.jt.config;
import com.baomidou.mybatisplus.annotation.DbType;
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.plugins.PaginationInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
import com.baomidou.mybatisplus.extension.plugins.pagination.optimize.JsqlParserCountOptimize;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration //标识配置类
public class MybatisPlusConfig {
//MP工作原理: MP --分页拦截器(分页策略)-- Mybatis -----DB
// 最新版
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
return interceptor;
}
/*@Bean
public PaginationInterceptor paginationInterceptor() {
PaginationInterceptor paginationInterceptor = new PaginationInterceptor();
// 设置请求的页面大于最大页后操作, true调回到首页,false 继续请求 默认false
// paginationInterceptor.setOverflow(false);
// 设置最大单页限制数量,默认 500 条,-1 不受限制
// paginationInterceptor.setLimit(500);1
// 开启 count 的 join 优化,只针对部分 left join
paginationInterceptor.setCountSqlParser(new JsqlParserCountOptimize(true));
return paginationInterceptor;
}*/
}
运行测试:
扩展:
//在bean对象实例化之后执行一般都是为属性赋值用的
@PostConstruct
public void aa(){
}
// spring容器对象销毁之前会执行关闭操作一般用来释放链接/资源
@PreDestroy
public void bb(){
}
2. 商品分类业务实现
2.1 商品分类表结构
2.2 封装ItemCat Pojo对象
package com.jt.pojo;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import lombok.experimental.Accessors;
@TableName("tb_item_cat")
@Data
@Accessors(chain = true)
public class ItemCat extends BasePojo{
//private long id = 0
//private Long id = null
@TableId(type = IdType.AUTO)
private Long id;
private Long parentId;
private String name;
private Integer status;
private Integer sortOrder; //排序号
private Boolean isParent; //false 0 true 1
}
2.2.1 配置mapper、service、controller
ItemCatMapper
public interface ItemCatMapper extends BaseMapper<ItemCat> {
}
ItemCatService
public interface ItemCatService {
}
ItemCatServiceImpl
public class ItemCatServiceImpl implements ItemCatService{
@Autowired
private ItemCatMapper itemCatMapper;
}
ItemCatController
public class ItemCatController {
@Autowired
private ItemCatService itemCatService;
}
2.3 数据格式化操作
2.3.1 格式化时间
1).编辑页面HTML代码
item-list.jsp
<th data-options="field:'created',width:130,align:'center',formatter:KindEditorUtil.formatDateTime">创建日期</th>
<th data-options="field:'updated',width:130,align:'center',formatter:KindEditorUtil.formatDateTime">更新日期</th>
2).编辑页面JS
//只要通过formatter属性进行调用,则都会传递2个参数 参数1:当前值 参数2:行数据
// 格式化时间
formatDateTime : function(val,row){
//console.log(val);
//console.log(row);
//将数据库时间 转化为JS对象
var now = new Date(val);
//通过js函数,格式化时间
return now.format("yyyy-MM-dd hh:mm:ss");
},
2.3.2 格式化状态
1).编辑html页面
<th data-options="field:'status',width:60,align:'center',formatter:KindEditorUtil.formatItemStatus">状态</th>
2).编辑页面JS
// 格式化商品的状态
formatItemStatus : function formatStatus(val,row){
if (val == 1){
return '<span style="color:green;">正常</span>';;
} else if(val == 2){
return '<span style="color:red;">下架</span>';
} else {
return '未知';
}
},
2.4 实现商品分类回显
2.4.1 业务说明
说明:根据商品分类的Id,动态的查询数据库获取商品分类的名称,进行展现.
2.4.2 编辑页面HTML
<th data-options="field:'cid',width:100,align:'center',formatter:KindEditorUtil.findItemCatName">叶子类目</th>
2.4.3 编辑页面JS
common.js
//格式化名称 发起ajax请求,实现商品分类展现
//Ajax嵌套问题,则需要将内层ajax设置为同步
findItemCatName : function(val,row){
let name = ''
$.ajax({
type: "get",//GET请求
url: "/itemCat/findItemCatById", //请求路径
data: {id: val}, //提交的参数
success: function(result){
//result要求返回的是ItemCat对象
name = result.name
},
error: function(result){
console.log("查询失败")
},
async: false
})
return name
},
2.4.4 编辑ItemCatController
package com.jt.controller;
import com.jt.pojo.ItemCat;
import com.jt.service.ItemCatService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/itemCat")
public class ItemCatController {
@Autowired
private ItemCatService itemCatService;
/**
* 业务需求: 根据商品分类Id查询商品分类对象
* URL地址: /itemCat/findItemCatById?id=497
* 类型: Request Method: GET
* 参数: id
* 返回值: ItemCat对象
*/
@RequestMapping("/findItemCatById")
public ItemCat findItemCatById(Long id){
return itemCatService.findItemCatById(id);
}
}
2.4.5 编辑ItemCatService
package com.jt.service;
import com.jt.mapper.ItemCatMapper;
import com.jt.pojo.ItemCat;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
public class ItemCatServiceImpl implements ItemCatService{
@Autowired
private ItemCatMapper itemCatMapper;
@Override
public ItemCat findItemCatById(Long id) {
return itemCatMapper.selectById(id);
}
}
2.4.6 页面效果展现
2.5 关于common.js导入说明
2.5.1 问题说明
京淘后台js是如何导入到项目中的?
导入过程: index.jsp中
导入common.js
2.6 商品分类树形结构展现
2.6.1 弹出框效果
$("#btn1").bind("click",function(){
$("#win1").window({
title:"弹出框",
width:400,
height:400,
modal:true //这是一个模式窗口,只能点击弹出框,不允许点击别处
})
})
2.6.2 商品分类数据结构展现
/*查询一级商品分类信息*/
SELECT * FROM tb_item_cat WHERE parent_id=0
/*查询二级商品分类信息*/
SELECT * FROM tb_item_cat WHERE parent_id=1
/*查询三级商品分类信息*/
SELECT * FROM tb_item_cat WHERE parent_id=2
2.6.3 树形结构控件
$("#tree").tree({
url:"tree.json", //加载远程JSON数据
method:"get", //请求方式 POST
animate:false, //表示显示折叠端口动画效果
checkbox:true, //表述复选框
lines:true, //表示显示连接线
dnd:true, //是否拖拽
onClick:function(node){ //添加点击事件
//控制台
console.info(node);
}
});
2.6.4 树形结构数据展现
发现 最外层是数组[ ], 数组中的每个元素都是一个对象 {id,text,state}
2.6.5 封装树形结构节点
package com.jt.vo;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.experimental.Accessors;
@Data
@Accessors(chain = true)
@NoArgsConstructor
@AllArgsConstructor
public class EasyUITree {
private Long id; //节点编号
private String text; //节点名称
private String state; //节点状态 open打开 closed关闭
}
2.6.6 树形控件JS分析
2.6.7 关于异步树形控件的说明
树控件读取URL。子节点的加载依赖于父节点的状态。当展开一个封闭的节点,如果节点没有加载子节点,它将会把节点id的值作为http请求参数并命名为’id’,通过URL发送到服务器上面检索子节点。
说明: 如果用户初始化时,没有点击节点时 不会传递ID.所以需要默认值
2.6.7 编辑ItemCatController
/**
* 查询商品分类树形结构控件
* 1.url地址: http://localhost:8091/item/cat/list
* 2.参数: 暂时没有
* 3.返回值结果: List<EasyUITree>
* 4.实现数据传递 id: xxxx
*/
@RequestMapping("/item/cat/list")
public List<EasyUITree> findItemCatList(Long id){
//查询商品分类信息 1级菜单
//如果用户没有点击按钮 将不会传递Id值,应该设定默认值
long parentId = (id==null?0:id);//0 一级菜单 判断是否点击,点击了就传值
return itemCatService.findItemCatList(parentId);
}
2.6.7 编辑ItemCatServiceImpl
/**
* 1.根据parentId查询商品分类列表信息 一级商品分类信息
* 2.将商品分类列表转化为List<VO>对象
* 3.返回vo的list集合
* @param parentId
* @return
*/
@Override
public List<EasyUITree> findItemCatList(long parentId) {
//1.根据父级id查询子级的信息
QueryWrapper<ItemCat> queryWrapper = new QueryWrapper<>();
queryWrapper.eq("parent_id", parentId);
List<ItemCat> itemCatList = itemCatMapper.selectList(queryWrapper);
//2.将itemCat对象 转化为VO对象
//itemCatList.size() 限定长度
List<EasyUITree> voList = new ArrayList<>(itemCatList.size());
//获取数据库建记录
for (ItemCat itemCat : itemCatList){
//动态获取id和名称
long id = itemCat.getId();
String text = itemCat.getName();
//如果是父级则闭合,否则打开
//state 状态
String state = itemCat.getIsParent() ? "closed" : "open";
//封装数据
EasyUITree tree = new EasyUITree(id,text, state);
//把数据传回去
voList.add(tree);
}
return voList;
}
3.后台商品CURD操作
3.1 商品新增
<td>商品标题:</td>
<td><input class="easyui-textbox" type="text" name="title" data-options="required:true" style="width: 280px;"></input></td>
<td>商品价格:</td>
<td><input class="easyui-numberbox" type="text" name="priceView" data-options="min:1,max:99999999,precision:2,required:true" />
<td>库存数量:</td>
<td><input class="easyui-numberbox" type="text" name="num" data-options="min:1,max:99999999,precision:0,required:true" /></td>
3.1.1 页面URL分析
1.请求路径
2.请求参数
3.1.2 检查页面JS
3.1.3 系统返回值SysResult对象
由于是系统返回值变量,所以应该定义到jt-common中。
package com.jt.vo;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.experimental.Accessors;
//通过SysResult对象 实现前后端数据交互的载体
@Data
@Accessors(chain = true)
@NoArgsConstructor
@AllArgsConstructor
public class SysResult {
private Integer status; //如果后端服务器运行正常 返回200 否则返回201 表示失败
private String msg; //服务器返回提示
private Object data; //服务器返回业务数据.
//失败的方法
public static SysResult fail(){
return new SysResult(201, "服务器异常请求稍后", null);
}
//成功的方法
public static SysResult success(){
return new SysResult(200, "服务器执行成功", null);
}
//成功的方法,重载,针对不同的用户的需求
public static SysResult success(Object data){
return new SysResult(200, "服务器执行成功", data);
}
public static SysResult success(String msg,Object data){
return new SysResult(200, msg ,data);
}
}
3.1.4 编辑ItemController
/**
* 业务说明: 商品新增
* URL地址: http://localhost:8091/item/save
* 请求参数: form表单 item对象接收
* 返回值: SysResult对象
*/
@RequestMapping("/save")
public SysResult saveItem(Item item){
try {
itemService.saveItem(item);
return SysResult.success();
}catch (Exception e){
e.printStackTrace();
return SysResult.fail();
}
}
3.1.5 编辑ItemService
@Transactional //标记方式使用事务控制
@Override
public void saveItem(Item item) {
item.setStatus(1) //设定启动状态
.setCreated(new Date())
.setUpdated(item.getCreated());
itemMapper.insert(item);
}
3.2 全局异常处理
说明: 在jt-common中添加全局异常处理机制
package com.jt.aop;
import com.jt.vo.SysResult;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
//spring中的通知 核心原理:Spring AOP机制
@RestControllerAdvice //只对Controller代码层级有效.
public class SysResultException {
//当程序发生异常时, 如果没有try-catch则直接向上抛出异常.
//该注解只拦截运行时异常.
@ExceptionHandler({RuntimeException.class})
public SysResult exception(Exception e){
e.printStackTrace();
return SysResult.fail();
}
}
3.3 MP自动填充实现
3.3.1 业务说明
说明: 由于入库时需要手动的完成时间字段的操作,但是该操作比较通用,任何一张表的入库/更新都需要操作时间.
需求: 能否简化代码
3.3.2 标识属性
说明: 将需要自动填充的属性 进行标识 由于是系统设置,所以在jt-common中编辑
//pojo基类,完成2个任务,2个日期,实现序列化
@Data
@Accessors(chain=true)
public class BasePojo implements Serializable{
@TableField(fill = FieldFill.INSERT)
private Date created; //新增操作有效
@TableField(fill = FieldFill.INSERT_UPDATE)
private Date updated; //新增和更新操作有效
}
3.3.3 编辑配置类
package com.jt.config;
import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler;
import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.reflection.MetaObject;
import org.springframework.stereotype.Component;
import java.util.Date;
@Slf4j
@Component
public class MyMetaObjectHandler implements MetaObjectHandler {
//新增入库时,需要维护 created/updated
@Override
public void insertFill(MetaObject metaObject) {
Date date = new Date();
this.setFieldValByName("created", date, metaObject);
this.setFieldValByName("updated", date, metaObject);
}
@Override
public void updateFill(MetaObject metaObject) {
this.setFieldValByName("updated", new Date(), metaObject);
}
}