淘淘商城第三天

课程计划

完成商品添加功能

  1. 商品类目选择
  2. 图片上传
  3. 图片服务器搭建
  4. kindEditor富文本编辑器的使用
  5. 商品添加功能
  6. 实现商品类目选择功能
    1. 需求

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

    1. 实现步骤:
  1. 按钮添加点击事件,弹出窗口,加载数据显示tree
  2. 将选择类目的组件封装起来,通过TT.iniit()初始化,最终调用initItemCat()方法进行初始化
  3. 创建数据库、以及tb _item_cat表,初始化数据
  4. 编写Controller、Service、Mapper
    1. EasyUI tree数据结构

数据结构中必须包含:

Id:节点id

Text:节点名称

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

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

    1. Mapper

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

    1. Service

@Service

public class ItemCatServiceImpl implements ItemCatService {

 

@Autowired

private TbItemCatMapper itemCatMapper;

 

@Override

public List<TbItemCat> getItemCatList(Long parentId) throws Exception {

 

TbItemCatExample example = new TbItemCatExample();

//设置查询条件

Criteria criteria = example.createCriteria();

//根据parentid查询子节点

criteria.andParentIdEqualTo(parentId);

//返回子节点列表

List<TbItemCat> list = itemCatMapper.selectByExample(example);

return list;

}

 

}

    1. Controller

@Controller

@RequestMapping("/item/cat")

public class ItemCatController {

 

@Autowired

private ItemCatService itemCatService;

 

@SuppressWarnings({ "rawtypes", "unchecked" })

@RequestMapping("/list")

@ResponseBody

//如果id为null是使用默认值,也就是parentid为0的分类列表

public List categoryList(@RequestParam(value="id", defaultValue="0") Long parentId) throws Exception {

List catList = new ArrayList();

//查询数据库

List<TbItemCat> list = itemCatService.getItemCatList(parentId);

for (TbItemCat tbItemCat : 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);

}

return catList;

}

 

}

 

  1. 图片上传
    1. 图片服务器
      1. 传统项目中的图片管理

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

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

缺点:

  1. 如果是分布式环境图片引用会出现问题。
  2. 图片的下载会给服务器增加额外的压力

 

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

 

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

 

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

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

      1. 搭建图片服务器

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

详见:vsftpd安装手册.doc

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

详见:nginx安装手册.doc

      1. 测试图片服务器
        1. ftp服务测试。
  1. 使用ftp客户端

  1. 使用java程序

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

public static 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();

}

        1. http服务测试
    1. 浏览器测试
      1. SpringMVC中实现图片上传

上传思路:

第一步:

导入common-fileupload的依赖

<!-- 文件上传组件 -->

<dependency>

<groupId>commons-fileupload</groupId>

<artifactId>commons-fileupload</artifactId>

</dependency>

第二步:

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

<!-- 定义文件上传解析器 -->

<bean id="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>

      1. 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 String FILI_UPLOAD_PATH;

@Value("${IMAGE_BASE_URL}")

private String IMAGE_BASE_URL;

  1. 图片名生成策略

时间+随机数:

/**

 * 图片名生成

 */

public static String genImageName() {

//取当前时间的长整形值包含毫秒

long millis = System.currentTimeMillis();

//long millis = System.nanoTime();

//加上三位随机数

Random random = new Random();

int end3 = random.nextInt(999);

//如果不足三位前面补0

String str = millis + String.format("%03d", end3);

 

return str;

}

使用UUID:

UUID.randomUUID();

  1. Service实现

@Service

public class PictureServiceImpl implements PictureService {

 

@Value("${IMAGE_BASE_URL}")

private String IMAGE_BASE_URL;

@Value("${FILI_UPLOAD_PATH}")

private String FILI_UPLOAD_PATH;

@Value("${FTP_SERVER_IP}")

private String FTP_SERVER_IP;

@Value("${FTP_SERVER_PORT}")

private Integer FTP_SERVER_PORT;

@Value("${FTP_SERVER_USERNAME}")

private String FTP_SERVER_USERNAME;

@Value("${FTP_SERVER_PASSWORD}")

private String FTP_SERVER_PASSWORD;

 

@Override

public PictureResult uploadFile(MultipartFile uploadFile) throws Exception {

 

// 上传文件功能实现

String path = savePicture(uploadFile);

// 回显

PictureResult result = new PictureResult(0, IMAGE_BASE_URL + path);

return result;

}

 

private String savePicture(MultipartFile uploadFile) {

String result = null;

try {

// 上传文件功能实现

// 判断文件是否为空

if (uploadFile.isEmpty())

return null;

// 上传文件以日期为单位分开存放,可以提高图片的查询速度

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 (Exception e) {

e.printStackTrace();

}

 

return result;

}

 

}

      1. Controller实现

@Controller

@RequestMapping("/pic")

public class PictureController {

 

@Autowired

private PictureService pictureService;

 

@RequestMapping("/upload")

@ResponseBody

public PictureResult uploda(MultipartFile uploadFile) throws Exception {

//调用service上传图片

PictureResult pictureResult = pictureService.uploadFile(uploadFile);

//返回上传结果

return pictureResult;

 

}

}

      1. 前端JS实现图片上传
  1. Js实现逻辑

 

 

 

KindEditor 4.x 文档

http://kindeditor.net/doc.php

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

 

 

  1. 上传图片请求url:

  1. 返回值

参考文档:

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

返回格式(JSON)

//成功时

{

        "error" : 0,

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

}

//失败时

{

        "error" : 1,

        "message" : "错误信息"

}

返回值数据类型:

public class PictureResult {

 

/**

 * 上传图片返回值,成功:0 失败:1

 */

private Integer error;

/**

 * 回显图片使用的url

 */

private String url;

/**

 * 错误时的错误消息

 */

}

  1. kindeditor(富文本编辑器的使用
    1. kindeditor的使用过程:

1、导入js:

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

3、调用TT.createEditor

4、效果

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

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

editor.sync();

  1. 新增商品实现
    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('提示','新增商品成功!');

}

});

}

    1. 提交请求的数据格式

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

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

请求的url:

/item/save

返回的结果:

淘淘自定义返回结果:

  1. 状态码
  2. 响应的消息
  3. 响应的数据

/**

 * 淘淘商城自定义响应结构

 */

public class TaotaoResult {

 

    // 定义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;

        }

    }

 

}

    1. 获得商品id

临时主键生成策略:

/**

 * 商品id生成

 */

public static long genItemId() {

//取当前时间的长整形值包含毫秒

long millis = System.currentTimeMillis();

//long millis = System.nanoTime();

//加上两位随机数

Random random = new Random();

int end2 = random.nextInt(99);

//如果不足两位前面补0

String str = millis + String.format("%02d", end2);

long id = new Long(str);

return id;

}

    1. ItemServiceImpl

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

@Override

public void saveItem(TbItem item, String desc, String itemParams) throws Exception {

Date date = new Date();

//获得商品id

long id = 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);

 

}

    1. Controller实现

@RequestMapping("/save")

@ResponseBody

public TaotaoResult saveItem(TbItem item, String desc) throws Exception {

//添加商品信息

itemService.saveItem(item, desc, null);

return TaotaoResult.ok();

}

  1. 课后作业

完成商品修改功能。

现在一定有更加成熟的文件图片上传,或则是富文本编辑器,但是大概的原理都差不了多少!还需要后期自己去学习一些新的项目,自己去总结!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值