企业🤖AI智能体构建引擎,智能编排和调试,一键部署,支持私有化部署方案 广告
[TOC] ## 步骤 1 : 先运行,看到效果,再学习 先将完整的 spring 项目(向老师要相关资料),配置运行起来,确认可用之后,再学习做了哪些步骤以达到这样的效果。 ## 步骤 2 : 模仿和排错 在确保可运行项目能够正确无误地运行之后,再严格照着教程的步骤,对代码模仿一遍。 模仿过程难免代码有出入,导致无法得到期望的运行结果,此时此刻通过比较**正确答案** ( 可运行项目 ) 和自己的代码,来定位问题所在。 采用这种方式,**学习有效果,排错有效率**,可以较为明显地提升学习速度,跨过学习路上的各个槛。 ## 步骤 3 : 效果 重启tomcat,通过访问地址 `http://localhost:8080/tmall_ssm/admin_property_list?categoryId=30` 可以看到属性管理的界面 注: 这categoryId=12是分类的id,根据你的实际运行情况,采取不同的id值 ![](https://box.kancloud.cn/3269896e366aca2f284690f1254f93d0_1822x461.png) ## 步骤 4 : Property Property实体类已经和其他所有的实体类一起,在**所有逆向工程** 这个环节就一起自动生成好了。 不过仅仅有自动生成的实体类代码,还不足以支撑业务需要,所以在Property基础上增加了一个Category 字段。 这个属性的用途将会在**编辑功能讲解** 步骤里进行讲解。 > 生成category字段对应getter/setter方法。 ``` package com.dodoke.tmall.pojo; public class Property { private Integer id; private String name; private Integer categoryId; /* 非数据库字段 */ private Category category; public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name == null ? null : name.trim(); } public Integer getCategoryId() { return categoryId; } public void setCategoryId(Integer categoryId) { this.categoryId = categoryId; } public Category getCategory() { return category; } public void setCategory(Category category) { this.category = category; } } ``` ## 步骤 5 : PropertyService 新建PropertyService,提供CRUD一套。 需要注意的是,因为在业务上需要查询某个分类下的属性,所以list方法会带上对应分类的id。 ``` package com.dodoke.tmall.service; import java.util.List; import com.dodoke.tmall.pojo.Property; public interface PropertyService { void add(Property c); void delete(int id); void update(Property c); Property get(int id); List list(int categoryId); } ``` ## 步骤 6 : PropertyServiceImpl 新增PropertyServiceImpl实现PropertyService对应的方法。通过调用自动生成的PropertyMapper就可以实现大部分方法了。 值得注意的是查询的时候用到了辅助查询类:PropertyExample 它的使用也很方便,这一行表示查询categoryId字段 `example.createCriteria().andCategoryIdEqualTo(categoryId);` ``` package com.dodoke.tmall.service.impl; import java.util.List; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import com.dodoke.tmall.mapper.PropertyMapper; import com.dodoke.tmall.pojo.Property; import com.dodoke.tmall.pojo.PropertyExample; import com.dodoke.tmall.service.PropertyService; @Service public class PropertyServiceImpl implements PropertyService { @Autowired PropertyMapper propertyMapper; @Override public void add(Property c) { propertyMapper.insert(c); } @Override public void delete(int id) { propertyMapper.deleteByPrimaryKey(id); } @Override public void update(Property c) { propertyMapper.updateByPrimaryKeySelective(c); } @Override public Property get(int id) { return propertyMapper.selectByPrimaryKey(id); } @Override public List list(int categoryId) { PropertyExample example =new PropertyExample(); example.createCriteria().andCategoryIdEqualTo(categoryId); example.setOrderByClause("id desc"); return propertyMapper.selectByExample(example); } } ``` ## 步骤 7 : PropertyController 然后就是控制器类,用于映射不同路径的访问。 这个类每个方法的详解将在后续步骤一一展开。 ``` package com.dodoke.tmall.controller; import java.util.List; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.RequestMapping; import com.dodoke.tmall.pojo.Category; import com.dodoke.tmall.pojo.Property; import com.dodoke.tmall.service.CategoryService; import com.dodoke.tmall.service.PropertyService; import com.dodoke.tmall.util.Page; import com.github.pagehelper.PageHelper; import com.github.pagehelper.PageInfo; @RequestMapping("") @Controller public class PropertyController { @Autowired CategoryService categoryService; @Autowired PropertyService propertyService; @RequestMapping("admin_property_add") public String add(Model model, Property p) { propertyService.add(p); return "redirect:admin_property_list?categoryId="+p.getCategory_id(); } @RequestMapping("admin_property_delete") public String delete(int id) { Property p = propertyService.get(id); propertyService.delete(id); return "redirect:admin_property_list?categoryId="+p.getCategory_id(); } @RequestMapping("admin_property_edit") public String edit(Model model, int id) { Property p = propertyService.get(id); Category c = categoryService.get(p.getCategory_id()); p.setCategory(c); model.addAttribute("p", p); return "admin/editProperty"; } @RequestMapping("admin_property_update") public String update(Property p) { propertyService.update(p); return "redirect:admin_property_list?categoryId="+p.getCategory_id(); } @RequestMapping("admin_property_list") public String list(int categoryId, Model model, Page page) { Category c = categoryService.get(categoryId); PageHelper.offsetPage(page.getStart(),page.getCount()); List<Property> ps = propertyService.list(categoryId); int total = (int) new PageInfo<>(ps).getTotal(); page.setTotal(total); page.setParam("&categoryId="+c.getId()); model.addAttribute("ps", ps); model.addAttribute("c", c); model.addAttribute("page", page); return "admin/listProperty"; } } ``` ## 步骤 8 : listProperty.jsp和editProperty.jsp 然后是新建查询和编辑的jsp页面 ## 步骤 9 : 查询功能讲解 查询地址`admin_property_list`映射的是PropertyController的`list()`方法 1. 获取分类 categoryId,和分页对象page 2. 通过PageHelper设置分页参数 3. 基于categoryId,获取当前分类下的属性集合 4. 通过PageInfo获取属性总数 5. 把总数设置给分页page对象 6. 拼接字符串`"&categoryId="+c.getId()`,设置给page对象的Param值。 **因为属性分页都是基于当前分类下的分页**,所以分页的时候需要传递这个categoryId 7. 把属性集合设置到 request的 "ps" 属性上 8. 把分类对象设置到 request的 "c" 属性上。 ( 这个c有什么用呢? 在后面步骤的 其他-面包屑导航 中会用于显示分类名称) 9. 把分页对象设置到 request的 "page" 对象上 10. 服务端跳转到`admin/listProperty.jsp`页面 11. 在listProperty.jsp页面上使用c:forEach 遍历ps集合,并显示 ![](https://box.kancloud.cn/fcc16b5bb3b9573480cfb9720da78913_1813x313.png) PropertyController片段: ``` @RequestMapping("admin_property_list") public String list(int categoryId, Model model, Page page) { Category c = categoryService.get(categoryId); PageHelper.offsetPage(page.getStart(), page.getCount()); List<Property> ps = propertyService.list(categoryId); int total = (int) new PageInfo<>(ps).getTotal(); page.setTotal(total); page.setParam("&categoryId=" + c.getId()); model.addAttribute("ps", ps); model.addAttribute("c", c); model.addAttribute("page", page); return "admin/listProperty"; } ``` listProperty.jsp: ``` <c:forEach items="${ps}" var="p"> <tr> <td>${p.id}</td> <td>${p.name}</td> <td><a href="admin_property_edit?id=${p.id}"><span class="glyphicon glyphicon-edit"></span></a></td> <td><a deleteLink="true" href="admin_property_delete?id=${p.id}"><span class="glyphicon glyphicon-trash"></span></a></td> </tr> </c:forEach> ``` ## 步骤 10 : 增加功能讲解 1. 在listProperty.jsp页面提交数据的时候,除了提交属性名称,还会提交categoryId 2. 在PropertyController通过参数Property 接受注入 3. 通过propertyService保存到数据库 4. 客户端跳转到admin_property_list,并带上参数categoryId ![](https://box.kancloud.cn/07df94a4e9ff883ffe602e435de1e3e3_518x211.png) listProperty.jsp: ``` <form method="post" id="addForm" action="admin_property_add" enctype="multipart/form-data"> <table class="addTable"> <tr> <td>属性名称</td> <td><input id="name" name="name" type="text" class="form-control"></td> </tr> <tr class="submitTR"> <td colspan="2" align="center"> <input type="hidden" name="categoryId" value="${c.id}"> <button type="submit" class="btn btn-success">提 交</button> </td> </tr> </table> </form> ``` PropertyController: ``` @RequestMapping("admin_property_add") public String add(Model model, Property p) { propertyService.add(p); return "redirect:admin_property_list?categoryId=" + p.getCategoryId(); } ``` ## 步骤 11 : 编辑功能讲解 1. 在PropertyController的edit方法中,根据id获取Property对象 2. 根据properoty对象的categoryId属性获取Category对象,并把其设置在Property对象的category属性上 3. 把Property对象放在request的 "p" 属性中 4. 服务端跳转到`admin/editProperty.jsp` ``5. 在editProperty.jsp中显示属性名称 6. 在editProperty.jsp中隐式提供id和categoryId( categoryId 通过 `p.category.id` 获取) ``` <input type="hidden" name="id" value="${p.id}"> <input type="hidden" name="categoryId" value="${p.category.id}"> ``` ![](../images/6147``````.png) PropertyController: ``` @RequestMapping("admin_property_edit") public String edit(Model model, int id) { Property p = propertyService.get(id); Category c = categoryService.get(p.getCategoryId()); p.setCategory(c); model.addAttribute("p", p); return "admin/editProperty"; } ``` editProperty.jsp: ``` <input type="hidden" name="id" value="${p.id}"> <input type="hidden" name="categoryId" value="${p.category.id}"> ``` ## 步骤 12 : 修改功能讲解 1. 在PropertyController的update方法中获取Property对象 2. 借助propertyService更新这个对象到数据库 3. 客户端跳转到`admin_property_list`,并带上参数categoryId ![](https://box.kancloud.cn/bbccb3f273c3ea7470141f2204ba600c_481x200.png) PropertyController: ``` @RequestMapping("admin_property_update") public String update(Property p) { propertyService.update(p); return "redirect:admin_property_list?categoryId=" + p.getCategoryId(); } ``` ## 步骤 13 : 删除功能讲解 1. 在PropertyController的delete方法中获取id 2. 根据id获取Property对象 3. 借助propertyService删除这个对象对应的数据 4. 客户端跳转到`admin_property_list`,并带上参数categoryId ![](https://box.kancloud.cn/6e5c3489a6eb639922fc9a86cecffaf2_95x202.png) ``` @RequestMapping("admin_property_delete") public String delete(int id) { Property p = propertyService.get(id); propertyService.delete(id); return "redirect:admin_property_list?categoryId=" + p.getCategoryId(); } ``` ## 步骤 14 : 其他-面包屑导航 在属性管理页面的页头,有一个面包屑导航 第一个连接跳转到`admin_category_list` 第二个连接跳转到`admin_property_list?categoryId=` `` 样式用的是Bootstrap面包屑导航 ![](https://box.kancloud.cn/498df9ca3f290c571e4b49f2baed6727_348x46.png) ``` <ol class="breadcrumb"> <li><a href="admin_category_list">所有分类</a></li> <li><a href="admin_property_list?categoryId=${c.id}">${c.name}-属性</a></li> <li class="active">属性管理</li> </ol> ``` ## 步骤 15 : `其他-分页` 这里的分页比起分类管理中的分页多了一个参数categoryId 1. 在`PropertyController.list()` 方法中,把`&categoryId=` 参数设置到在page对象的param属性上 2. 在adminPage.jsp页面中通过`${page.param}`取出这个参数 ## 步骤 16 : 自己做一遍 关于属性管理这一块的学习,推荐如下思路: 1. 先拿到本章节对应项目,配置好了跑一遍。 2. 根据接着的讲解,把里面的每一块代码的逻辑,思路,设计思想搞明白,不明白的及时问老师。 3. 都理清楚之后,把可运行项目删掉,按照:查询,增加,删除,编辑,修改的顺序自己从头到尾做一遍。 只有,能够独立的做出来,才叫做把这些知识点的内容转化为自己的技能。 > 删除中需要注意,属性下有没有对应属性值,没有属性值才能删除,学员自行添加相应逻辑。