您的位置:首页 > 其它

带你逐步深入了解SSM框架——淘淘商城项目之实现商品添加

2017-12-31 14:03 621 查看

1.  课程计划

完成商品添加功能

1、商品类目选择

2、图片上传

3、图片服务器搭建

4、kindEditor富文本编辑器的使用

5、商品添加功能

 

2.  实现商品类目选择功能

2.1. 需求

在商品添加页面,点击“选择类目”显示商品类目列表:

 


2.2. 实现步骤:

1、  按钮添加点击事件,弹出窗口,加载数据显示tree

2、  将选择类目的组件封装起来,通过TT.iniit()初始化,最终调用initItemCat()方法进行初始化

3、  创建数据库、以及tb _item_cat表,初始化数据

4、  编写Controller、Service、Mapper

 

2.3. EasyUI tree数据结构

 

数据结构中必须包含:

Id:节点id

Text:节点名称

State:如果不是叶子节点就是close,叶子节点就是open。Close的节点点击后会在此发送请求查询子项目。

 


可以根据parentid查询分类列表。

 

2.4. Mapper

使用逆向工程生成的mapper文件。

 

2.5. Service

@Service
publicclass ItemCatServiceImpl
implements ItemCatService {
 
      @Autowired
      private TbItemCatMapperitemCatMapper;
     
      @Override
      public List<TbItemCat> getItemCatList(LongparentId)
throws Exception {
          
           TbItemCatExample
example = new TbItemCatExample();
          
//设置查询条件
           Criteria
criteria = example.createCriteria();
          
//根据parentid查询子节点
          
criteria.andParentIdEqualTo(parentId);
          
//返回子节点列表
           List<TbItemCat>
list = itemCatMapper.selectByExample(example);
           returnlist;
      }
 
}

 

2.6. Controller

@Controller
@RequestMapping("/item/cat")
publicclass ItemCatController {
     
      @Autowired
      private ItemCatServiceitemCatService;
 
      @SuppressWarnings({"rawtypes",
"unchecked" })
      @RequestMapping("/list")
      @ResponseBody
      //如果id为null是使用默认值,也就是parentid为0的分类列表
      publicList categoryList(@RequestParam(value="id",
defaultValue="0") LongparentId)
throws Exception {
          
List catList = new ArrayList();
          
//查询数据库
          
List<TbItemCat> list =
itemCatService.getItemCatList(parentId);
           for (TbItemCattbItemCat :
list) {
                 Map
node = new HashMap<>();
                
node.put("id",
tbItemCat.getId());
                
node.put("text",
tbItemCat.getName());
                
//如果是父节点的话就设置成关闭状态,如果是叶子节点就是open状态
                
node.put("state",
tbItemCat.getIsParent()?"closed":"open");
                
catList.add(node);
           }
           returncatList;
      }
     
}

 

3.  图片上传

3.1. 图片服务器

3.1.1.  传统项目中的图片管理

传统项目中,可以在web项目中添加一个文件夹,来存放上传的图片。例如在工程的根目录WebRoot下创建一个images文件夹。把图片存放在此文件夹中就可以直接使用在工程中引用。

优点:引用方便,便于管理

缺点:

1、如果是分布式环境图片引用会出现问题。

2、图片的下载会给服务器增加额外的压力

 


 

传统图片管理方式在分布式环境中的问题:

 


 

3.1.2.  分布式环境的图片管理

 


 

分布式环境一般都有一个专门的图片服务器存放图片。

我们使用虚拟机搭建一个专门的服务器来存放图片。在此服务器上安装一个nginx来提供http服务,安装一个ftp服务器来提供图片上传服务。

 

3.1.3.  搭建图片服务器

 

第一步:安装vsftpd提供ftp服务

详见:vsftpd安装手册.doc

第二步:安装nginx提供http服务

详见:nginx安装手册.doc

 

3.1.4.  测试图片服务器

1.     ftp服务测试。

a)使用ftp客户端

 


b)使用java程序

ftp可以需要依赖commons-net-3.3.jar包。

publicstatic
void
main(String[]args)
throws Exception {
           FTPClient
ftpClient = new FTPClient();
          
ftpClient.connect("192.168.25.200");
          
ftpClient.login("ftpuser",
"ftpuser");
           FileInputStream
inputStream = new FileInputStream(new File("D:\\Documents\\Pictures\\pics\\21.jpg"));
          
ftpClient.setFileType(FTP.BINARY_FILE_TYPE);
          
ftpClient.storeFile("123.jpg",
inputStream);
          
inputStream.close();
          
          
ftpClient.logout();
      }

 

 

2.     http服务测试

a)        浏览器测试

 

3.1.5.  SpringMVC中实现图片上传

上传思路:

第一步:

导入common-fileupload的依赖

<!--
文件上传组件 -->
          
<dependency>
                
<groupId>commons-fileupload</groupId>
                
<artifactId>commons-fileupload</artifactId>
           </dependency>

 

第二步:

在SpringMVC配置文件中添加文件上传解析器

 

<!--
定义文件上传解析器 -->
      <beanid="multipartResolver"
          
class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
          
<!-- 设定默认编码 -->
          
<property name="defaultEncoding"value="UTF-8"></property>
          
<!-- 设定文件上传的最大值5MB,5*1024*1024 -->
          
<property name="maxUploadSize"value="5242880"></property>
      </bean>

 

 

3.1.6.  Service实现

1.   获取资源配置文件的内容

第一步:

创建资源配置文件



FILI_UPLOAD_PATH=D:/temp/imagestest/webapps/images
IMAGE_BASE_URL=http://localhost:9000/images

 

第二步:

在Spring(taotao-manage-servlet.xml)容器中加载资源文件

 


第二步:

在Service中获取资源配置:

      @Value("${FILI_UPLOAD_PATH}")
      private StringFILI_UPLOAD_PATH;
      @Value("${IMAGE_BASE_URL}")
      private StringIMAGE_BASE_URL;

 

2.   图片名生成策略

时间+随机数:

/**
       *图片名生成
       */
      publicstatic String genImageName() {
          
//取当前时间的长整形值包含毫秒
           longmillis = System.currentTimeMillis();
          
//long millis = System.nanoTime();
          
//加上三位随机数
           Random
random = new Random();
           intend3 =
random.nextInt(999);
          
//如果不足三位前面补0
           String
str = millis + String.format("%03d",end3);
          
           returnstr;
      }

 

使用UUID:

UUID.randomUUID();

 

3.   Service实现

@Service
publicclass PictureServiceImpl
implements PictureService {
 
      @Value("${IMAGE_BASE_URL}")
      private StringIMAGE_BASE_URL;
      @Value("${FILI_UPLOAD_PATH}")
      private StringFILI_UPLOAD_PATH;
      @Value("${FTP_SERVER_IP}")
      private StringFTP_SERVER_IP;
      @Value("${FTP_SERVER_PORT}")
      private IntegerFTP_SERVER_PORT;
      @Value("${FTP_SERVER_USERNAME}")
      private StringFTP_SERVER_USERNAME;
      @Value("${FTP_SERVER_PASSWORD}")
      private StringFTP_SERVER_PASSWORD;
 
      @Override
      public PictureResult uploadFile(MultipartFileuploadFile)
throws Exception {
 
          
// 上传文件功能实现
           String
path = savePicture(uploadFile);
          
// 回显
           PictureResult
result = new PictureResult(0,IMAGE_BASE_URL +
path);
           returnresult;
      }
 
      private String savePicture(MultipartFileuploadFile) {
           String
result = null;
           try {
                
// 上传文件功能实现
                
// 判断文件是否为空
                 if (uploadFile.isEmpty())
                      returnnull;
                
// 上传文件以日期为单位分开存放,可以提高图片的查询速度
                 String
filePath = "/" + new SimpleDateFormat("yyyy").format(new Date()) +"/"
                            +
new
SimpleDateFormat("MM").format(new Date()) +"/"
                            +
new
SimpleDateFormat("dd").format(new Date());
 
                
// 取原始文件名
                 String
originalFilename = uploadFile.getOriginalFilename();
                
// 新文件名
                 String
newFileName = IDUtils.genImageName() +
originalFilename.substring(originalFilename.lastIndexOf("."));
                
// 转存文件,上传到ftp服务器
                
FtpUtil.uploadFile(FTP_SERVER_IP,FTP_SERVER_PORT,
FTP_SERVER_USERNAME,FTP_SERVER_PASSWORD,
                           
FILI_UPLOAD_PATH, filePath,
newFileName, uploadFile.getInputStream());
                
result = filePath +
"/" + newFileName;
           } catch (Exceptione) {
                
e.printStackTrace();
           }
 
           returnresult;
      }
 
}

 

3.1.7.  Controller实现

@Controller
@RequestMapping("/pic")
publicclass PictureController {
     
      @Autowired
      private PictureServicepictureService;
 
      @RequestMapping("/upload")
      @ResponseBody
      public PictureResult uploda(MultipartFileuploadFile)
throws Exception {
          
//调用service上传图片
           PictureResult
pictureResult = pictureService.uploadFile(uploadFile);
          
//返回上传结果
           returnpictureResult;
          
      }
}

3.1.8.  前端JS实现图片上传

1.   Js实现逻辑

 


 


 


KindEditor 4.x 文档

http://kindeditor.net/doc.php

上传图片使用kindeditor的上传组件实现。

 


 

2.   上传图片请求url:



3.   返回值

参考文档:

http://kindeditor.net/docs/upload.html

 

返回格式(JSON)

 

//成功时

{

        "error" : 0,

        "url" : "http://www.example.com/path/to/file.ext"

}

//失败时

{

        "error" : 1,

        "message" : "错误信息"

}

 

返回值数据类型:

 

publicclass PictureResult {
 
      /**
       *上传图片返回值,成功:0 
失败:1   
       */
      private Integererror;
      /**
       *回显图片使用的url
       */
      private Stringurl;
      /**
       *错误时的错误消息
       */

}

 

 

4.  kindeditor(富文本编辑器)的使用

4.1. kindeditor的使用过程:

1、导入js:

 


2、定义多行文本(不可见、给定name)







3、调用TT.createEditor





4、效果

 


4.2. 取文本编辑器中的内容

将编辑器的内容设置到原来的textarea控件里。

editor.sync();


 

5.  新增商品实现

5.1. js编写逻辑

//提交表单
      function submitForm(){
          
//有效性验证
           if(!$('#itemAddForm').form('validate')){
                 $.messager.alert('提示','表单还未填写完成!');
                 return ;
           }
          
//取商品价格,单位为“分”
           $("#itemAddForm [name=price]").val(eval($("#itemAddForm [name=priceView]").val()) * 100);
          
//同步文本框中的商品描述
           itemAddEditor.sync();
          
//取商品的规格
          
/*
           var paramJson = [];
           $("#itemAddForm .params li").each(function(i,e){
                 var trs = $(e).find("tr");
                 var group = trs.eq(0).text();
                 var ps = [];
                 for(var i = 1;i<trs.length;i++){
                      var tr = trs.eq(i);
                      ps.push({
                            "k" : $.trim(tr.find("td").eq(0).find("span").text()),
                            "v" : $.trim(tr.find("input").val())
                      });
                 }
                 paramJson.push({
                      "group" : group,
                      "params": ps
                 });
           });
           //把json对象转换成字符串
           paramJson = JSON.stringify(paramJson);
           $("#itemAddForm [name=itemParams]").val(paramJson);
           */
          
//ajax的post方式提交表单
          
//$("#itemAddForm").serialize()将表单序列号为key-value形式的字符串
           $.post("/item/save",$("#itemAddForm").serialize(),function(data){
                 if(data.status == 200){
                      $.messager.alert('提示','新增商品成功!');
                 }
           });
      }

 

5.2. 提交请求的数据格式

$("#itemAddForm").serialize()将表单序列号为key-value形式的字符串

以post 的形式将表单的内容提交。

 

请求的url:

/item/save

 

返回的结果:

淘淘自定义返回结果:

1、状态码

2、响应的消息

3、响应的数据

 

/**
 *
淘淘商城自定义响应结构
 */
publicclass TaotaoResult {
 
    //
定义jackson对象
    privatestatic
final
ObjectMapperMAPPER =
new ObjectMapper();
 
    //
响应业务状态
    private Integerstatus;
 
    //
响应消息
    private Stringmsg;
 
    //
响应中的数据
    private Objectdata;
 
    publicstatic TaotaoResult build(Integer
status, String msg, Object
data) {
        returnnew TaotaoResult(status,msg,
data);
    }
 
    publicstatic TaotaoResult ok(Object
data) {
        returnnew TaotaoResult(data);
    }
 
    publicstatic TaotaoResult ok() {
        returnnew TaotaoResult(null);
    }
 
    public TaotaoResult() {
 
    }
 
    publicstatic TaotaoResult build(Integer
status, String msg) {
        returnnew TaotaoResult(status,msg,
null);
    }
 
    public TaotaoResult(Integerstatus, String
msg, Objectdata) {
        this.status =status;
        this.msg =msg;
        this.data =data;
    }
 
    public TaotaoResult(Objectdata) {
        this.status = 200;
        this.msg ="OK";
        this.data =data;
    }
 
//    public Boolean isOK() {
//        return this.status == 200;
//    }
 
    public Integer getStatus() {
        returnstatus;
    }
 
    publicvoid setStatus(Integer
status) {
        this.status =status;
    }
 
    public String getMsg() {
        returnmsg;
    }
 
    publicvoid setMsg(String
msg) {
        this.msg =msg;
    }
 
    public Object getData() {
        returndata;
    }
 
    publicvoid setData(Object
data) {
        this.data =data;
    }
 
    /**
     *
json结果集转化为TaotaoResult对象
     *

     *
@param jsonDatajson数据
     *
@param clazz TaotaoResult中的object类型
     *
@return
     */
    publicstatic TaotaoResult formatToPojo(StringjsonData, Class<?>
clazz) {
        try {
            if (clazz ==null) {
                returnMAPPER.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);
                } elseif (data.isTextual()) {
                   
obj = MAPPER.readValue(data.asText(),clazz);
                }
            }
            returnbuild(jsonNode.get("status").intValue(),jsonNode.get("msg").asText(),obj);
        } catch (Exceptione) {
            returnnull;
        }
    }
 
    /**
     *
没有object对象的转化
     *

     *
@param json
     *
@return
     */
    publicstatic TaotaoResult format(String
json) {
        try {
            returnMAPPER.readValue(json, TaotaoResult.class);
        } catch (Exceptione) {
           
e.printStackTrace();
        }
        returnnull;
    }
 
    /**
     * Object是集合转化
     *

     *
@param jsonDatajson数据
     *
@param clazz集合中的类型
     *
@return
     */
    publicstatic TaotaoResult formatToList(StringjsonData, 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));
            }
            returnbuild(jsonNode.get("status").intValue(),jsonNode.get("msg").asText(),obj);
        } catch (Exceptione) {
            returnnull;
        }
    }
 
}

 

5.3. 获得商品id

临时主键生成策略:

/**
       *商品id生成
       */
      publicstatic
long
genItemId() {
          
//取当前时间的长整形值包含毫秒
           longmillis = System.currentTimeMillis();
          
//long millis = System.nanoTime();
          
//加上两位随机数
           Random
random = new Random();
           intend2 =
random.nextInt(99);
          
//如果不足两位前面补0
           String
str = millis + String.format("%02d",end2);
           longid =
new Long(str);
           returnid;
      }

 

5.4. ItemServiceImpl

调用mapper的insert方法添加商品信息

@Override
      publicvoid saveItem(TbItem
item, String desc, String
itemParams) throws Exception {
           Date
date = new Date();
          
//获得商品id
           longid = IDUtils.genItemId();
          
//添加商品信息
          
item.setId(id);
          
//商品状态,1-正常,2-下架,3-删除
          
item.setStatus((byte) 1);
          
item.setCreated(date);
          
item.setUpdated(date);
          
itemMapper.insert(item);
          
//添加商品描述
          
//创建TbItemDesc对象
           TbItemDesc
itemDesc = new TbItemDesc();
          
//获得一个商品id
          
itemDesc.setItemId(id);
          
itemDesc.setItemDesc(desc);
          
itemDesc.setCreated(date);
          
itemDesc.setUpdated(date);
          
//插入数据
          
itemDescMapper.insert(itemDesc);
          
      }

 

5.5. Controller实现

 

@RequestMapping("/save")
@ResponseBody
      public TaotaoResult saveItem(TbItemitem, String
desc)throws Exception {
          
//添加商品信息
          
itemService.saveItem(item,
desc, null);
           return TaotaoResult.ok();
      }

 
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐