经过上文的学习,我相信大家都应该知道了富文本编辑器的使用方法,我们能走到这步,实属不易,本文终于可以来实现商品添加这个功能了。
在item-add.jsp页面当中,当点击提交按钮后,会触发submitForm方法,如下图所示。
在咱们提交表单前还需要校验输入的内容是否合法,如下图所示。
下面我们看下数据库中商品表的建表信息,可以看到价格定义的字段类型是long型,单位为分,之所以这样做是为了避免使用小数点,因为小数点使用起来比较麻烦,因此存到数据库商品表中的价格都是价格(用户输入价格时一般都是喜欢以元为单位,难道不是这样吗?)乘以100的(变为分)。
从上图中,我们发现在商品表当中并没有商品描述这个字段,怎么会没有呢?其实商品描述是专门用一张表来存放的,如下图所示,可以看到商品描述与商品id是一一对应的,之所以把商品描述单独放到一张表当中是因为它是个大文本字段,存储的信息量会非常大,对于不需要商品描述的查询情况来说,连带这个字段查询会影响到查询效率,因此单独存放。
接下来,我们来看看表单中是如何表示的,如下图所示,可以看到有两个<input>
控件,第一个<input>
控件用来展示商品的价格,即单位为元的价格(这更符合用户的习惯),第二个<input>
控件是个隐藏域,专门用来存放以分为单位的价格(即将以元为单位的价格乘以100),表单提交时便会提交name="price"
的价格并保存到数据库表中。
当用户填写完商品详细信息后,会以Ajax的post方式提交表单,如下图所示,post方法中的第一个参数是请求的url,即/item/save
;第二个参数是$("#itemAddForm").serialize()
,它主要用于将表单的数据序列化为key-value形式的字符串。最后,如果表单提交成功后则返回200的状态码。
由于每个操作都需要有状态码(status)来表示操作成功与否以及相关信息,因此我们定义一个TaotaoResult类来专门处理,该类定义了三个属性,分别是状态、消息以及数据,由于这个类会被多个工程所使用,因此放到taotao-common工程的com.taotao.common.pojo包下。
TaotaoResult类的全部代码如下所示,其中里面最常用的便是ok方法和build方法。
package com.taotao.common.pojo;import java.io.Serializable;
import java.util.List;import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;/*** 淘淘商城自定义响应结构*/
public class TaotaoResult implements Serializable {// 定义jackson对象private static final ObjectMapper MAPPER = new ObjectMapper();// 响应业务状态private Integer status;// 响应消息private String msg;// 响应中的数据private Object data;public static TaotaoResult build(Integer status, String msg, Object data) {return new TaotaoResult(status, msg, data);}public static TaotaoResult ok(Object data) {return new TaotaoResult(data);}public static TaotaoResult ok() {return new TaotaoResult(null);}public TaotaoResult() {}public static TaotaoResult build(Integer status, String msg) {return new TaotaoResult(status, msg, null);}public TaotaoResult(Integer status, String msg, Object data) {this.status = status;this.msg = msg;this.data = data;}public TaotaoResult(Object data) {this.status = 200;this.msg = "OK";this.data = data;}// public Boolean isOK() {
// return this.status == 200;
// }public Integer getStatus() {return status;}public void setStatus(Integer status) {this.status = status;}public String getMsg() {return msg;}public void setMsg(String msg) {this.msg = msg;}public Object getData() {return data;}public void setData(Object data) {this.data = data;}/*** 将json结果集转化为TaotaoResult对象* * @param jsonData json数据* @param clazz TaotaoResult中的object类型* @return*/public static TaotaoResult formatToPojo(String jsonData, Class<?> clazz) {try {if (clazz == null) {return MAPPER.readValue(jsonData, TaotaoResult.class);}JsonNode jsonNode = MAPPER.readTree(jsonData);JsonNode data = jsonNode.get("data");Object obj = null;if (clazz != null) {if (data.isObject()) {obj = MAPPER.readValue(data.traverse(), clazz);} else if (data.isTextual()) {obj = MAPPER.readValue(data.asText(), clazz);}}return build(jsonNode.get("status").intValue(), jsonNode.get("msg").asText(), obj);} catch (Exception e) {return null;}}/*** 没有object对象的转化* * @param json* @return*/public static TaotaoResult format(String json) {try {return MAPPER.readValue(json, TaotaoResult.class);} catch (Exception e) {e.printStackTrace();}return null;}/*** Object是集合转化* * @param jsonData json数据* @param clazz 集合中的类型* @return*/public static TaotaoResult formatToList(String jsonData, Class<?> clazz) {try {JsonNode jsonNode = MAPPER.readTree(jsonData);JsonNode data = jsonNode.get("data");Object obj = null;if (data.isArray() && data.size() > 0) {obj = MAPPER.readValue(data.traverse(),MAPPER.getTypeFactory().constructCollectionType(List.class, clazz));}return build(jsonNode.get("status").intValue(), jsonNode.get("msg").asText(), obj);} catch (Exception e) {return null;}}}
温馨提示:TaotaoResult类一定要实现序列化接口,很多人都会忘记哟!!!
添加商品信息和商品描述对应的都是单表操作,因此我们使用逆向工程生成的代码即可,也就是说我们不用编写dao层的代码。下面我们重点来编写service层的代码。
首先在ItemService接口当中新增一个添加商品的方法(这一个方法要操作两张表,一张是商品表,另一张是商品描述表),如下图所示,该方法的参数有两个,一个是代表商品表的pojo,另一个是商品描述。
然后我们在service层中来实现这个接口,如下图所示,我们在ItemServiceImpl实现类当中实现了addItem方法,其中商品id(也叫商品编号)是采用当前毫秒数加两位随机数来生成的,为了方便以后调用,我们专门封装了一个叫做IDUtils的工具类,里面不仅封装了商品id的生成方法而且还封装了图片名称的生成方法。由于该类会被多个工程使用,因此我们也放到taotao-common工程的com.taotao.common.utils包下。
为了方便大家复制,现将ItemServiceImpl实现类的代码贴出。
package com.taotao.service.impl;import java.util.Date;
import java.util.List;import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.taotao.common.pojo.EasyUIDataGridResult;
import com.taotao.common.pojo.TaotaoResult;
import com.taotao.common.utils.IDUtils;
import com.taotao.mapper.TbItemDescMapper;
import com.taotao.mapper.TbItemMapper;
import com.taotao.pojo.TbItem;
import com.taotao.pojo.TbItemDesc;
import com.taotao.pojo.TbItemExample;
import com.taotao.service.ItemService;@Service
public class ItemServiceImpl implements ItemService {@Autowiredprivate TbItemMapper tbItemMapper;@Autowiredprivate TbItemDescMapper itemDescMapper;@Overridepublic TbItem getItemById(Long itemId) {TbItem item = tbItemMapper.selectByPrimaryKey(itemId);return item;}@Overridepublic EasyUIDataGridResult getItemList(Integer page, Integer rows) {// 1. 设置分页的信息,使用PageHelperif (page == null) {page = 1;}if (rows == null) {rows = 30;}PageHelper.startPage(page, rows);// 2. 注入Mapper// 3. 创建一个TbItemExample对象,而且不需要设置查询条件TbItemExample example = new TbItemExample();// 4. 根据Mapper调用查询所有数据的方法List<TbItem> list = tbItemMapper.selectByExample(example);// 5. 获取分页信息PageInfo<TbItem> info = new PageInfo<TbItem>(list);// 6. 封装到EasyUIDataGridResult对象中并返回EasyUIDataGridResult result = new EasyUIDataGridResult();result.setTotal((int)info.getTotal());result.setRows(info.getList());return result;}@Overridepublic TaotaoResult addItem(TbItem item, String desc) {// 生成商品idlong itemId = IDUtils.genItemId();// 补全item对象的属性item.setId(itemId);// 商品状态,1:正常,2:下架,3:删除item.setStatus((byte) 1);item.setCreated(new Date());item.setUpdated(new Date());// 向商品表中插入数据tbItemMapper.insert(item);// 创建一个商品描述表对应的pojoTbItemDesc itemDesc = new TbItemDesc();// 补全pojo的属性itemDesc.setItemId(itemId);itemDesc.setItemDesc(desc);itemDesc.setCreated(new Date());itemDesc.setUpdated(new Date());// 向商品描述表中插入数据itemDescMapper.insert(itemDesc);// 返回结果return TaotaoResult.ok();}}
其中,IDUtils工具类的代码如下所示。
package com.taotao.common.utils;import java.util.Random;/*** 各种id生成策略* <p>Title: IDUtils</p>* <p>Description: </p>* <p>Company: www.itcast.com</p> * @author 入云龙* @date 2015年7月22日下午2:32:10* @version 1.0*/
public class IDUtils {/*** 图片名生成*/public static String genImageName() {//取当前时间的长整形值包含毫秒long millis = System.currentTimeMillis();//long millis = System.nanoTime();//加上三位随机数Random random = new Random();int end3 = random.nextInt(999);//如果不足三位前面补0String str = millis + String.format("%03d", end3);return str;}/*** 商品id生成*/public static long genItemId() {//取当前时间的长整形值包含毫秒long millis = System.currentTimeMillis();//long millis = System.nanoTime();//加上两位随机数Random random = new Random();int end2 = random.nextInt(99);//如果不足两位前面补0String str = millis + String.format("%02d", end2);long id = new Long(str);return id;}public static void main(String[] args) {for(int i=0;i< 100;i++)System.out.println(genItemId());}
}
接着我们来编写Controller层的代码。我们应在ItemController类中添加一个如下addItem方法,其中@RequestMapping("/item/save")
注解中的url请求路径是在item-add.jsp页面的js代码当中定义好的,我们要保持一致才行。
紧接着我们便来测试一下我们的商品添加功能是否好使,由于taotao-common工程以及taotao-manager工程都做了修改,因此我们需要对这两个工程重新打包,如何打包在此不再赘述。
当我们重启完taotao-manager工程和taotao-manager-web工程之后,跳转到新增商品页面,输入相关商品信息,最后点击提交
按钮。
这时,我们会发现弹出了一个提示框,提示我们商品添加成功了,添加完之后,我们到商品列表中去查询,看是否有我们刚才添加的商品,我们直接查看最后一页的数据,发现最后一条就是刚才添加的商品信息,这已说明添加商品成功了。
我们再到数据库表中看看添加的商品信息,首先查看下tb_item表,我们还是到最后一页去查看,发现有刚才添加的商品信息,如下图所示。
再查看下商品描述表,我们可通过商品id来快速筛选出添加的商品信息描述,如下图所示。
这说明数据存储完全没问题。这样,我们的商品添加功能便实现了。