淘淘商城——day3(商品的添加)

6.3.1.四、Controller层html

1、课程计划

后台管理商品的添加功能前端

              商品分类选择java

                上传图片node

             富文本编辑器(kindEditor)linux

             实现商品的添加nginx

            课后做业(商品的修改、删除)git

2、商品添加功能说明

3、类目选择

3.一、需求

    点击类目选择按钮弹出类目选择窗口,窗口中是一个树形视图。分级展现商品分类。github

   当选择商品分类的叶子节点后,关闭窗口并将选中的商品分类的名称显示到网页上。web

一、初始化tree的url:spring

              /item/cat/list

二、请求的参数

     Id(当前节点的id,根据此id查询子节点)

3.返回数据的格式json数据:

[{    

    "id": 1,    //当前节点的id

    "text": "Node 1",    //节点显示的名称

   "state": "closed"    //节点的状态,若是是closed就是一个文件夹形式,不展开叶结子点

                                 // 当打开时还会 作一次请求。若是是open就显示为叶子节点。

},{    

      "id": 2,    

      "text": "Node 2",    

      "state": "closed"   

}]

3.1.1分析

      添加商品的时候必需要选择商品的分类,也就是类目选择,咱们须要从数据库中将类目信息查询出来,咱们须要查询tb_item_cat

    能够看见: 该表中有一个字段是parent_id与本表中的id列有关系,这种关系叫自关联,就是说,本表中的字段与本表中的字段有关系

3.1.二、前端页面

  能够看见类目选择方法在:    common.js中

       Url:/item/cat/list

      参数:parentId

     返回值:EUTreeNode

     由于返回的结果中带有id和类目名等,遇到这种状况咱们的第一反应就是建立实体类封装数据。

3.二、mapper

    单表操做,直接用逆向工程便可

3.2.0 数据库中的表

3.2.1Sql语句

  SELECT * FROM `tb_item_cat` where parent_id=父节点id(=0时表明是一级的类目);

咱们这里是直接使用的逆向工程生成的mapper。

3.三、建立实体类Tree Node的pojo--EUTreeNode

  该实体类须要建立到taotao-common工程下。(由于是做为工具类,用来封装返回值对象)

   属性:id,text,state

package com.taotao.pojo;
public class EUTreeNode {
	private long id;//类目id(当前节点的id)
	private String text;//节点显示的名称
	private String state;//节点的状态,若是是closed就是一个文件夹形式不显示叶子结点;若是是open就显示为叶子节点。
	
	public long getId() {
		return id;
	}
	public void setId(long id) {
		this.id = id;
	}
	public String getText() {
		return text;
	}
	public void setText(String text) {
		this.text = text;
	}
	public String getState() {
		return state;
	}
	public void setState(String state) {
		this.state = state;
	}
	//构造方法
	//toString
	
}

3.三、Service层

     功能:根据parentId(父节点,=0时表明是一级的类目)查询商品分类列表。

     参数:parentId

     返回值:返回tree所须要的数据结构,是一个节点列表。

    能够建立一个tree node的pojo表示节点的数据,也可使用map。

     List<TreeNode>

调用dao查询数据,返回数据,封装到EUTreeNode中

package com.taotao.service.impl;

import java.util.ArrayList;
import java.util.List;

import javax.annotation.Resource;

import org.springframework.stereotype.Service;
import com.taotao.mapper.TbItemCatMapper;
import com.taotao.pojo.EUTreeNode;
import com.taotao.pojo.TbItemCat;
import com.taotao.pojo.TbItemCatExample;
import com.taotao.pojo.TbItemCatExample.Criteria;
import com.taotao.service.ItemCatService;
@Service
public class ItemCatServiceImpl implements ItemCatService {
	@Resource
	private TbItemCatMapper tbItemCatMapper;
	
	// 经过parentId查询子节点。
	@Override
	public List<EUTreeNode> getItemCatList(Long parentId) {
		//根据parentId(父节点)查询分类列表
		TbItemCatExample example = new TbItemCatExample();
		//设置查询条件
		 Criteria criteria = example.createCriteria();
		 criteria.andParentIdEqualTo(parentId);
		 //执行查询
		 List<TbItemCat> list = tbItemCatMapper.selectByExample(example);
		//分类列表转换成TreeNode的列表
		ArrayList<EUTreeNode> resultList = new ArrayList<>();
		for (TbItemCat tbItemCat : list) {
		  //建立一个TreeNode对象
			EUTreeNode node = new EUTreeNode(tbItemCat.getId(), tbItemCat.getName(), tbItemCat.getIsParent()?"closed":"open");
			resultList.add(node);
		}
		return resultList;
	}
}

3.四、Controller层

    功能:接收页面传递过来的id,做为parentId查询子节点。

   参数:Long id

   返回值:要返回json数据要使用@ResponseBody。List<TreeNode>

接收jsp的请求,返回他要的结果便可,返回的是JSON格式

package com.taotao.controller;

import java.util.List;

import javax.annotation.Resource;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;

import com.fasterxml.jackson.annotation.JsonFormat.Value;
import com.taotao.pojo.EUTreeNode;
import com.taotao.service.ItemCatService;

@Controller
@RequestMapping("/item/cat")
public class ItemCatController {
	
  @Resource
  private ItemCatService itemCatService;
  
  /*   经过parentId查询子节点。
   *  参数:Long id 
   *  返回值:要返回json数据要使用@ResponseBody。List<TreeNode>
   */
  @RequestMapping("/list")
  @ResponseBody
  public List<EUTreeNode> getItemCatList(@RequestParam(value="id",defaultValue="0")Long parentId){
	  List<EUTreeNode> list=itemCatService.getItemCatList(parentId);
	  return list;	  
  }
  
}

3.5 展现效果图

4、图片上传

4.一、传统图片管理方式

出现的问题:若是把图片放到工程中,在集群环境下,会出现找不到图片的状况。

4.二、集群环境下上传图片

图片服务器两个服务:

    http:能够使用nginx作静态资源服务器。也可使用apache。推荐使用nginx,效率更高。

         Nginx:

                http服务

                反向代理

                负载均衡

 ftp服务:

         使用linux作服务器,在linux中有个ftp(图片服务器)组件vsftpd。

4.三、图片服务器(ftp)

     能够把图片上传到ftp上保存,须要的时候从图片服务器ftp上拿就能够

       ftp:是一个协议

      ftp协议完成图片的上传,须要在Linux中安装vsftpd服务。而后咱们可使用nginx完成图片路径的映射,咱们就能够经过nginx提供的http服务访问图片。

4.3.一、搭建

     要求安装vmware虚拟机。

     Linux:CentOS7(64)

    Nginx:

    Vsftpd:须要在线安装。

4.3.二、安装nginx、安装ftp服务器(图片服务器)

     linux安装nginx参考连接:https://mp.csdn.net/postedit/88779062

    linux安装ftp服务器参考连接:https://mp.csdn.net/postedit/88832707

4.3.三、配置图片服务器

进入conf目录,修改nginx.conf配置文件

location /images/ {
	         alias /home/vsftpd/leo;
            autoindex on;
        }

4.3.四、上传图片并测试

咱们向上边配置的目录中上传图片并访问浏览器

上边这几步在安装ftp时都有说明

流程:选择图片上传,上传过程当中须要图片重命名,防止名字重复,上传完成以后再将图片的路径返回到jsp中完成图片回显

4.3.五、使用Java编写测试类

package com.taotao.controller;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.net.SocketException;
import org.apache.commons.net.ftp.FTP;
import org.apache.commons.net.ftp.FTPClient;
import org.junit.Test;

public class FTPTest {

	@Test
	public void testFtpClient() throws SocketException, IOException {
		//建立FTPClient对象
		FTPClient ftpClient = new FTPClient();
		//建立FTP链接,端口号默认为21
		ftpClient.connect("192.168.132.101",21);
		//登录FTP服务器,使用用户名和密码
		ftpClient.login("leo","123");
		//上传文件
		//读取本地文件
		FileInputStream inputStream = new FileInputStream(new File("E:\\1.png"));
		ftpClient.changeWorkingDirectory("/");//图片上传的根目录
		ftpClient.setFileType(FTP.BINARY_FILE_TYPE);//设置二进制的格式上传图片
		ftpClient.storeFile("123.jpg", inputStream);
		inputStream.close();
		
		ftpClient.logout();
		//关闭资源
	}
}

4.4 文件上传工具类

     对工具类进行封装

在taotao-common下

package com.taotao.util;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import org.apache.commons.net.ftp.FTP;
import org.apache.commons.net.ftp.FTPClient;
import org.apache.commons.net.ftp.FTPFile;
import org.apache.commons.net.ftp.FTPReply;

/**
 * ftp上传下载工具类
 */
public class FtpUtil {

	/** 
	 * Description: 向FTP服务器上传文件 
	 * @param host FTP服务器hostname 
	 * @param port FTP服务器端口 
	 * @param username FTP登陆帐号 
	 * @param password FTP登陆密码 
	 * @param basePath FTP服务器基础目录
	 * @param filePath FTP服务器文件存放路径。例如分日期存放:/2019/01/01。文件的路径为basePath+filePath
	 * @param filename 上传到FTP服务器上的文件名 
	 * @param input 输入流 
	 * @return 成功返回true,不然返回false 
	 */  
	public static boolean uploadFile(String host, int port, String username, String password, String basePath,
			String filePath, String filename, InputStream input) {
		boolean result = false;
		FTPClient ftp = new FTPClient();
		try {
			int reply;
			ftp.connect(host, port);// 链接FTP服务器
			// 若是采用默认端口,可使用ftp.connect(host)的方式直接链接FTP服务器
			ftp.login(username, password);// 登陆
			reply = ftp.getReplyCode();
			if (!FTPReply.isPositiveCompletion(reply)) {
				ftp.disconnect();
				return result;
			}
			//切换到上传目录
			if (!ftp.changeWorkingDirectory(basePath+filePath)) {
				//若是目录不存在建立目录
				String[] dirs = filePath.split("/");
				String tempPath = basePath;
				for (String dir : dirs) {
					if (null == dir || "".equals(dir)) continue;
					tempPath += "/" + dir;
					if (!ftp.changeWorkingDirectory(tempPath)) {
						if (!ftp.makeDirectory(tempPath)) {
							return result;
						} else {
							ftp.changeWorkingDirectory(tempPath);
						}
					}
				}
			}
			//设置上传文件的类型为二进制类型
			ftp.setFileType(FTP.BINARY_FILE_TYPE);
			//上传文件
			if (!ftp.storeFile(filename, input)) {
				return result;
			}
			input.close();
			ftp.logout();
			result = true;
		} catch (IOException e) {
			e.printStackTrace();
		} finally {
			if (ftp.isConnected()) {
				try {
					ftp.disconnect();
				} catch (IOException ioe) {
				}
			}
		}
		return result;
	}
	
	/** 
	 * Description: 从FTP服务器下载文件 
	 * @param host FTP服务器hostname 
	 * @param port FTP服务器端口 
	 * @param username FTP登陆帐号 
	 * @param password FTP登陆密码 
	 * @param remotePath FTP服务器上的相对路径 
	 * @param fileName 要下载的文件名 
	 * @param localPath 下载后保存到本地的路径 
	 * @return 
	 */  
	public static boolean downloadFile(String host, int port, String username, String password, String remotePath,
			String fileName, String localPath) {
		boolean result = false;
		FTPClient ftp = new FTPClient();
		try {
			int reply;
			ftp.connect(host, port);
			// 若是采用默认端口,可使用ftp.connect(host)的方式直接链接FTP服务器
			ftp.login(username, password);// 登陆
			reply = ftp.getReplyCode();
			if (!FTPReply.isPositiveCompletion(reply)) {
				ftp.disconnect();
				return result;
			}
			ftp.changeWorkingDirectory(remotePath);// 转移到FTP服务器目录
			FTPFile[] fs = ftp.listFiles();
			for (FTPFile ff : fs) {
				if (ff.getName().equals(fileName)) {
					File localFile = new File(localPath + "/" + ff.getName());

					OutputStream is = new FileOutputStream(localFile);
					ftp.retrieveFile(ff.getName(), is);
					is.close();
				}
			}

			ftp.logout();
			result = true;
		} catch (IOException e) {
			e.printStackTrace();
		} finally {
			if (ftp.isConnected()) {
				try {
					ftp.disconnect();
				} catch (IOException ioe) {
				}
			}
		}
		return result;
	}
	
	public static void main(String[] args) {
		try {  
	        FileInputStream in=new FileInputStream(new File("E:\\1.png"));  
	        boolean flag = uploadFile("192.168.132.101", 21, "leo", "123", "/","/2019/01/01", "hello.jpg", in);  
	        System.out.println(flag);  
	    } catch (FileNotFoundException e) {  
	        e.printStackTrace();  
	    }  
	}
}

Source配置文件

#FTP
FTP_ADDRESS=192.168.132.101
FTP_PORT=21
FTP_USER=leo
FTP_PASS=123
FTP_BASE_PATH=/
#picture server
IMG_BASE_URL=http://192.168.132.101/images

修改配置文件

4.五、JSP

    咱们使用kindeEditor(富文本编辑器)实现文件上传,上传以后要接收结果。成功回显图片,失败提示失败

返回值:

          

      参考文档:http://kindeditor.net/docs/upload.html

4.6 dao层

       直接上传图片到图片服务器,而不是数据库。不涉及到dao层

4.7Service层

        实现文件上传,将文件经过ftp协议上传到图片服务器上,咱们经过FTPUtil工具类实现上传

        上传成功以后图片要回显,咱们返回值url是图片的访问路径

功能:接收Controller传递过来的参数,一个文件MultiPartFile对象。把文件上传到ftp服务器上,生成一个新的文件名,返回文件url路径。须要保证图片上传插件要求的数据格式(即前边提到的 image)

这里可使用map实现,也可使用实体类封装对象,我使用的是map

4.7.1 使用IDUtils工具类,随机生成图片名

package com.taotao.util;

import java.util.Random;

/**
 * 各类id生成策略
 */
public class IDUtils {
	/**
	 * 图片名生成
	 */
	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;
	}
	
	/**
	 * 商品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;
	}
	
	public static void main(String[] args) {
		for(int i=0;i< 100;i++)
		System.out.println(genItemId());
	}
}

4.7.2 service

package com.taotao.service.impl;

import java.util.HashMap;
import java.util.Map;

import org.joda.time.DateTime;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.multipart.commons.CommonsMultipartFile;

import com.taotao.service.PictureService;
import com.taotao.util.FtpUtil;
import com.taotao.util.IDUtils;
@Service
public class PictureServiceImpl implements PictureService {

	
	/*
	 *  实现文件上传,将文件经过ftp协议上传到图片服务器上,咱们经过FTPUtil工具类实现上传
	 * 功能:接收Controller传递过来的参数(页面传过来的图片),一个文件MultiPartFile对象。
	 *     把文件上传到ftp服务器上,生成一个新的文件名,上传成功以后图片要回显,咱们返回值url是图片的访问路径,返回文件url路径。
	 *     须要保证图片上传插件要求的数据格式(即前边提到的 image)
	 * 
	 */
	
	// 向FTP服务器上传文件 
	@Value("${FTP_ADDRESS}")
	private String FTP_ADDRESS;  // FTP服务器hostname 
	@Value("${FTP_PORT}")
	private Integer FTP_PORT;    //FTP服务器端口 
	@Value("${FTP_USER}")
	private String FTP_USER_NAME;	// FTP登陆帐号 
	@Value("${FTP_PASS}")
	private String FTP_PASSWORD;
	@Value("${FTP_BASE_PATH}")
	private String FTP_BASE_PATH; //FTP服务器基础目录
	@Value("${IMG_BASE_URL}")
	private String IMG_BASE_URL;  //图片访问的映射路径
	
	
	@Override
	public Map uploadPicture(CommonsMultipartFile uploadFile) {
		Map resuleMap=new HashMap<>();
		try {
			//获取文件名(即图片名)
			String oldName = uploadFile.getOriginalFilename();
			/*
			 * 使用IDUtils工具类
			 * 从新生成新的名字
			 * 
			 */
			String newName = IDUtils.genImageName();//生成新的文件名
			newName=newName+oldName.substring(oldName.lastIndexOf("."));//将原来的文件名的后缀加到新名字里,如jsp newName为上传到FTP服务器上的文件名 
			//图片上传
			String imgpath = new DateTime().toString("/yyyy/MM/dd");//服务器文件存放路径,文件的路径为basePath+filePath(/2019/01/01);ftp存放图片的路径是根据日期存放的
		
			boolean result = FtpUtil.uploadFile(FTP_ADDRESS, FTP_PORT, FTP_USER_NAME, FTP_PASSWORD, FTP_BASE_PATH, imgpath, newName,uploadFile.getInputStream());
			if (!result) {
				resuleMap.put("error", 1);
				resuleMap.put("message", "文件上传失败");
				return resuleMap;				
			}
				resuleMap.put("error", 0);
				resuleMap.put("url", IMG_BASE_URL+imgpath+"/"+newName);
				return resuleMap;
		}catch (Exception e) {
			resuleMap.put("error", 1);
			resuleMap.put("message", "文件上传异常");
			return resuleMap;
		}
	
	}
}

4.8 Controller层

     接收上传的图片,调用service层,返回json数据

功能:接收页面传递过来的图片。调用service上传到图片服务器。返回结果。

参数:MultiPartFile uploadFile

返回值:返回json数据,应该返回一个pojo,PictureResult对象。

4.8.1Json解析工具类

package com.taotao.util;

import java.util.List;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;

/**
 * 淘淘商城自定义响应结构
 */
public class JsonUtils {

    // 定义jackson对象
    private static final ObjectMapper MAPPER = new ObjectMapper();

    /**
     * 将对象转换成json字符串。
     * <p>Title: pojoToJson</p>
     * <p>Description: </p>
     * @param data
     * @return
     */
    public static String objectToJson(Object data) {
    	try {
			String string = MAPPER.writeValueAsString(data);
			return string;
		} catch (JsonProcessingException e) {
			e.printStackTrace();
		}
    	return null;
    }
    
    /**
     * 将json结果集转化为对象
     * 
     * @param jsonData json数据
     * @param clazz 对象中的object类型
     * @return
     */
    public static <T> T jsonToPojo(String jsonData, Class<T> beanType) {
        try {
            T t = MAPPER.readValue(jsonData, beanType);
            return t;
        } catch (Exception e) {
        	e.printStackTrace();
        }
        return null;
    }
    
    /**
     * 将json数据转换成pojo对象list
     * <p>Title: jsonToList</p>
     * <p>Description: </p>
     * @param jsonData
     * @param beanType
     * @return
     */
    public static <T>List<T> jsonToList(String jsonData, Class<T> beanType) {
    	JavaType javaType = MAPPER.getTypeFactory().constructParametricType(List.class, beanType);
    	try {
    		List<T> list = MAPPER.readValue(jsonData, javaType);
    		return list;
		} catch (Exception e) {
			e.printStackTrace();
		}
    	
    	return null;
    }
    
}

4.8.2 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="10000000000" />
		<property name="maxInMemorySize" value="10240" />
	</bean>

4.8.3 写控制层

package com.taotao.controller;

import java.util.Map;
import javax.annotation.Resource;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.multipart.commons.CommonsMultipartFile;
import com.taotao.service.PictureService;
import com.taotao.util.JsonUtils;

@Controller
public class PictureController {

	@Resource
	private PictureService pictureService;
	
	/*
	 * 功能:接收页面传递过来的图片。调用service上传到图片服务器。返回结果。
	 * 参数:MultiPartFile uploadFile
	 * 返回值:返回json数据,应该返回一个pojo,PictureResult对象。
	 */

	@RequestMapping("/pic/upload")
	@ResponseBody
	public String pictureUpload(@RequestParam("uploadFile") CommonsMultipartFile uploadFile) {
		Map map=pictureService.uploadPicture(uploadFile);
		/*
		 * 使用JsonUtils工具类 能够将对象转换为json
		 * 返回json格式   返回值map类型转换为json
		 */
		String json = JsonUtils.objectToJson(map);//将返回值map类型(对象)转换为json字符串
		System.out.println(json);
		return json;
		
	}
	
}

4.9 效果图

五  富文本编辑器

 5.一、使用方法

第一步:在JSP中引入富文本编译器

第二步:在富文本编译器出现的位置添加一个textarea域

第三步:调用JS方法初始化富文本编译器

第四步:提交表单时调用富文本编译器sync方法,把富文本编译器中的内容同步到textarea中。

六 商品规格

6.一、什么是商品规格

规格参数

   规格项:规格值

   规律:

      一、同一类商品的规格项分组相同。

      二、同一类商品的规格项目是相同的。规格项目是跟商品关联。

       三、不一样商品规格参数的值是不一样的

6.2 实现方案

 可使用模板的思路来解决此问题。

 1  每个商品分类对一个规格参数模板。

 2 使用模板

         每一个商品对应一个惟一的规格参数。在添加商品时,能够根据规格参数的模板。生成一个表单。

        保存规格参数时。还能够生成规格参数的json数据。保存到数据库中。

6.2.二、数据库存储

规格参数模板表:

商品的规格参数表:

优势:

    一、不须要作多表管理。

    二、若是要求新添加的商品规格项发生改变,以前的商品不变是很简单的。

缺点:

      复杂的表单和json之间的转换。对js的编写要求很高。

6.3 建立规格参数模板

6.3.一、选择商品分类

      选择商品分类后根据选择的商品分类到tb_item_param规格参数模板表中取规格模板,取到了说明此商品分类的规格模板已经添加提示不能添加。若是没有取得则正常添加。

6.3.1.一、功能分析

   Url:/item/param/query/itemcatid/{itemCatId}

  参数:itemCatId,从url中得到

  返回值:TaotaoResult

6.3.1.二、Dao层

  从tb_item_param表中根据商品分类id查询内容。

  单表操做。能够实现逆向工程的代码。

6.3.1.三、Service层

功能:接收商品分类id。调用mapper查询tb_item_param表,返回结果TaotaoResult。


 

package com.taotao.service.impl;

import java.util.Date;
import java.util.List;

import javax.annotation.Resource;

import org.springframework.stereotype.Service;

import com.taotao.mapper.TbItemParamMapper;
import com.taotao.pojo.TaotaoResult;
import com.taotao.pojo.TbItemParam;
import com.taotao.pojo.TbItemParamExample;
import com.taotao.pojo.TbItemParamExample.Criteria;
import com.taotao.service.ItemParamService;
@Service
public class ItemParamServiceImpl implements ItemParamService {

	//关联TbItemParamMapper
	@Resource
	private TbItemParamMapper itemParamMapper;
	
	/*
	 * 一   选择商品分类
	 *    选择商品分类(类目)后,根据选择的商品分类到tb_item_param:规格参数模板表 中取规格模板,
	 * 取到了说明此商品分类的规格模板已经添加,提示不能添加;若是没有取得则正常添加。
	 *    功能:接收商品分类id。调用mapper查询tb_item_param表,返回结果TaotaoResult。
	 */
		
	@Override
	public TaotaoResult getItemParamByCid(Long cid) {
	TbItemParamExample tbItemParamExample = new TbItemParamExample();
	//设置条件
	Criteria criteria = tbItemParamExample.createCriteria();
	criteria.andItemCatIdEqualTo(cid);
	List<TbItemParam> list = itemParamMapper.selectByExampleWithBLOBs(tbItemParamExample);
	//判断是否查询到结果
	if (list!=null &&list.size()>0) {
		return TaotaoResult.ok(list.get(0));
	}
		return TaotaoResult.ok();
	}



}

6.3.1.四、Controller层

package com.taotao.controller;

import javax.annotation.Resource;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

import com.taotao.pojo.TaotaoResult;
import com.taotao.pojo.TbContent;
import com.taotao.pojo.TbItemParam;
import com.taotao.service.ItemParamService;

@Controller
@RequestMapping("/item/param")
public class ItemParamController {
	
	@Resource
	private ItemParamService itemParamService;
	
	
	/*一 选择商品分类
	 *    选择商品分类(类目)后,根据选择的商品分类到tb_item_param:规格参数模板表 中取规格模板,
	 * 取到了说明此商品分类的规格模板已经添加,提示不能添加;若是没有取得则正常添加。
	 *    @PathVariable:是用来对指定请求的URL路径里面的变量,请求入参
	 *    @PathVariable和@RequestParam的区别就在于:@RequestParam用来得到静态的URL请求入参
	 */
	
	
	@RequestMapping("/query/itemcatid/{itemcatid}")
	@ResponseBody
	public TaotaoResult getItemParamByCid(@PathVariable Long itemcatid) {
		return itemParamService.getItemParamByCid(itemcatid);
	}
}

6.3.二、提交规格参数模板

6.3.2.一、提交规格参数模板

首先把页面中全部文本框中的内容转换成json数据。把json字符串提交给后台。保存到规格参数表中。

请求URL:/item/param/save/{cid}

参数:StringParamData

返回值:TaoTaoResult

6.3.2.二、Dao层

    保存规格参数模板,向tb_item_param表中添加一条记录,可使用逆向工程

6.3.2.三、Service层

接收TbItemParam对象,调用Mapper插入到表中,返回TaoTaoResult对象

package com.taotao.service.impl;

import java.util.Date;
import java.util.List;

import javax.annotation.Resource;

import org.springframework.stereotype.Service;

import com.taotao.mapper.TbItemParamMapper;
import com.taotao.pojo.TaotaoResult;
import com.taotao.pojo.TbItemParam;
import com.taotao.pojo.TbItemParamExample;
import com.taotao.pojo.TbItemParamExample.Criteria;
import com.taotao.service.ItemParamService;
@Service
public class ItemParamServiceImpl implements ItemParamService {

	//关联TbItemParamMapper
	@Resource
	private TbItemParamMapper itemParamMapper;
	
	/*
	 * 一   选择商品分类
	 *    选择商品分类(类目)后,根据选择的商品分类到tb_item_param:规格参数模板表 中取规格模板,
	 * 取到了说明此商品分类的规格模板已经添加,提示不能添加;若是没有取得则正常添加。
	 *    功能:接收商品分类id。调用mapper查询tb_item_param表,返回结果TaotaoResult。
	 */
		
	@Override
	public TaotaoResult getItemParamByCid(Long cid) {
	TbItemParamExample tbItemParamExample = new TbItemParamExample();
	//设置条件
	Criteria criteria = tbItemParamExample.createCriteria();
	criteria.andItemCatIdEqualTo(cid);
	List<TbItemParam> list = itemParamMapper.selectByExampleWithBLOBs(tbItemParamExample);
	//判断是否查询到结果
	if (list!=null &&list.size()>0) {
		return TaotaoResult.ok(list.get(0));
	}
		return TaotaoResult.ok();
	}


	/*二  提交规格参数模板
	 * 2 接收前台传过来的json字符串,保存到规格参数表中。
	 * 接收TbItemParam对象,调用Mapper插入到表中,返回TaoTaoResult对象
	 */
	
	@Override
	public TaotaoResult insertItemParam(TbItemParam itemParam) {
		//补全TbItemParam对象
		itemParam.setCreated(new Date());
		itemParam.setUpdated(new Date());
		//插入到数据库
		itemParamMapper.insert(itemParam);
		return TaotaoResult.ok();
	}

}

 

6.3.2.四、Controller层

功能:接收cid、规格参数模板。建立一TbItemParam对象。调用Service返回TaotaoResult。返回json数据

package com.taotao.controller;

import javax.annotation.Resource;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

import com.taotao.pojo.TaotaoResult;
import com.taotao.pojo.TbContent;
import com.taotao.pojo.TbItemParam;
import com.taotao.service.ItemParamService;

@Controller
@RequestMapping("/item/param")
public class ItemParamController {
	
	@Resource
	private ItemParamService itemParamService;
	
	
	/*一 选择商品分类
	 *    选择商品分类(类目)后,根据选择的商品分类到tb_item_param:规格参数模板表 中取规格模板,
	 * 取到了说明此商品分类的规格模板已经添加,提示不能添加;若是没有取得则正常添加。
	 *    @PathVariable:是用来对指定请求的URL路径里面的变量,请求入参
	 *    @PathVariable和@RequestParam的区别就在于:@RequestParam用来得到静态的URL请求入参
	 */
	
	
	@RequestMapping("/query/itemcatid/{itemcatid}")
	@ResponseBody
	public TaotaoResult getItemParamByCid(@PathVariable Long itemcatid) {
		return itemParamService.getItemParamByCid(itemcatid);
	}
	
	/*二 提交规格参数模板
	 * 2  功能:接收cid、规格参数模板。建立一TbItemParam对象。调用Service返回TaotaoResult。返回json数据
	 * 
	 */
	@RequestMapping("save/{itemcatid}")
	@ResponseBody
	public TaotaoResult insertItemParam(@PathVariable Long itemcatid,String paramData) {
		TbItemParam tbItemParam = new TbItemParam();
		tbItemParam.setItemCatId(itemcatid);
		tbItemParam.setParamData(paramData);
		return itemParamService.insertItemParam(tbItemParam);	
	}

}

6.3.2.五、效果

 

6.3.三、根据规格参数模板生成表单

在商品添加功能中,读取此商品对应的规格模板,生成表单。供使用者添加规格参数

6.3.3.1 、需求分析

6.3.3.2 、service修改

     当表中的字段是text类型时,须要使用大文本格式查询,用来检索大字段。普通的方法查询不到

6.3.3.2 、效果图

六 商品添加功能实现

6.一、需求分析

咱们要将商品保存到tb_item表中,咱们是点击提交按钮以后进行保存。

6.2  jsp

    请求url:/item/save

    请求方式:post请求

   参数:$("#itemAddForm").serialize() k-v对结构       (将表单数据序列化成k-v形式)   将表单中的数据序列化,以key-value的形式存在,key为name值,value为value值

    响应内容:返回TaotaoResult,咱们该项目中响应页面数据的实体类

6.三、Dao层

    把商品信息插入到商品表,单表操做。可使用逆向工程生成的代码

6.4  实体类

     返回值设置响应状态

package com.taotao.pojo;

import java.util.List;

import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;

/**
 * 淘淘商城自定义响应结构
 */
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;
        }
    }

}

6.五、Service层

  接收TbItem对象调用Mapper,补全实体类须要的数据,id,createtime,updatetime,向tb_item表中添加数据,返回TaoTaoResult

/*
	 * 添加商品
	 * 	   接收TbItem对象调用Mapper,
	 *   补全实体类须要的数据,id,createtime,updatetime,
	 *   向tb_item表中添加数据,返回TaoTaoResult
	 * 
	 */
	@Override
	public TaotaoResult createItem(TbItem item) {
		//补全item(根据商品表tb_item 中的字段  补全   前端传过来的参数item)
		long itemId = IDUtils.genItemId();//使用IDUtils随机生成商品的id(能够去数据库看一眼,商品id虽然为主键,可是并无设置递增)
		//设置商品的信息
		item.setId(itemId);//商品id
		item.setStatus((byte)1);//设置状态
		item.setCreated(new Date());//建立时间
		item.setUpdated(new Date());//更改时间
		//将补全后的数据    插入到数据库
		tbItemMapper.insert(item);
		return TaotaoResult.ok();		
	}

6.六、Controller层

   接收前端表单数据,封装到TbItem中,调用service,向前段页面返回TaoToResult对象,返回Json数据,须要使用@ResponseBody注解

分析:

     由于添加成功后是添加到TbItem表中,以前那个查询全部商品的表也是TbItem.因此写在一个控制层,service里便可。

/*
	 * 添加商品
	 *   接收前端表单数据,封装到TbItem中,调用service,
	 *   向前段页面返回TaoToResult对象,返回Json数据,须要使用@ResponseBody注解
	 * 
	 */
	@RequestMapping("/save")
	@ResponseBody
	public TaotaoResult creatItem(TbItem item) {
		TaotaoResult result=itemService.createItem(item);
		return result;
	}

6.7 展现效果

七 添加商品时 添加商品描述

        后台要接收前台页面提交的商品信息和商品描述,商品信息和商品描述都要保存。

商品信息添加到tb_item中。商品描述添加到tb_item_desc表中

dao层

       把商品描述的信息保存到tb_item_desc表中,咱们使用逆向工程生成的代码便可

service

    接收商品描述调用dao层把商品描述添加到表中

    参数:String商品描述

    返回值:TaoTaoResult

//注入TbItemMapper
	@Resource
	private TbItemMapper tbItemMapper;
	
	//注入商品描述表TbItemDescMapper
	@Resource
	private TbItemDescMapper tbItemDescMapper;



    /*
	 * 二   添加商品
	 * 	   接收TbItem对象调用Mapper,
	 *   补全实体类须要的数据,id,createtime,updatetime,
	 *   向tb_item表中添加数据,返回TaoTaoResult
	 * 
	 */
	// 2添加商品时添加商品描述
	@Override
	public TaotaoResult createItem(TbItem item,String desc) {
		try {
			//防止出现错误,回滚
			//补全item(根据商品表tb_item 中的字段  补全   前端传过来的参数item)
			long itemId = IDUtils.genItemId();//使用IDUtils随机生成商品的id(能够去数据库看一眼,商品id虽然为主键,可是并无设置递增)
			//设置商品的信息
			item.setId(itemId);//商品id
			item.setStatus((byte)1);//设置状态
			item.setCreated(new Date());//建立时间
			item.setUpdated(new Date());//更改时间
			//将补全后的数据    插入到数据库
		   tbItemMapper.insert(item);
		   //添加商品描述信息,调用底下的方法
		    TaotaoResult result = insertDesc(itemId, desc);
		    //System.out.println(result);
		    if (result.getStatus()!=200) {
				throw new Exception();
			}		
			    return TaotaoResult.ok();				
		} catch (Exception e) {
			e.printStackTrace();
			return null;
		}
			
	}
	private TaotaoResult insertDesc(Long itemId,String desc) {
		 //添加商品描述   完善商品描述类、商品id、商品描述、时间
		TbItemDesc tbItemDesc = new TbItemDesc();
		tbItemDesc.setItemId(itemId);//商品id
		tbItemDesc.setItemDesc(desc);//商品描述
		tbItemDesc.setCreated(new Date());
		tbItemDesc.setUpdated(new Date());
		//将补全后的信息添加到数据库
		tbItemDescMapper.insert(tbItemDesc);
		return TaotaoResult.ok();	
	}

controller

接收参数,调用service

/*
	 * 二   添加商品
	 *        接收前端表单数据,封装到TbItem中,调用service,
	 *        向前段页面返回TaoToResult对象,返回Json数据,须要使用@ResponseBody注解
	 * 
	 */
	// 2添加商品时添加商品描述
	@RequestMapping("/save")
	@ResponseBody
	public TaotaoResult creatItem(TbItem item,String desc) {
		TaotaoResult result=itemService.createItem(item,desc);
		return result;
	}

展现

八  添加商品时 添加规格参数

8.1 需求分析

   提交表单以前,先把规格参数表单中的内容转换成json数据而后跟商品基本信息商品描述同时提交给后台。保存至数据库。

转换后把规格参数的信息放到表单的hidden域中:

随着表单的提交同时提交。

8.2 dao层

须要向tb_item_param_item表中添加数据

8.3  Service 层

    接收规格参数的内容,和商品id,拼装成pojo。调用mapper 的方法,向tb_item_param_item表中添加数据返回

package com.taotao.service.impl;

import java.util.Date;
import java.util.List;

import javax.annotation.Resource;

import org.springframework.stereotype.Service;

import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.taotao.mapper.TbItemDescMapper;
import com.taotao.mapper.TbItemMapper;
import com.taotao.mapper.TbItemParamItemMapper;
import com.taotao.pojo.EUDataGridResult;
import com.taotao.pojo.TaotaoResult;
import com.taotao.pojo.TbItem;
import com.taotao.pojo.TbItemDesc;
import com.taotao.pojo.TbItemExample;
import com.taotao.pojo.TbItemExample.Criteria;
import com.taotao.pojo.TbItemParamItem;
import com.taotao.service.ItemService;
import com.taotao.util.IDUtils;
@Service
public class ItemServiceImpl implements ItemService {
	
	//注入TbItemMapper
	@Resource
	private TbItemMapper tbItemMapper;	
	//注入商品描述表TbItemDescMapper
	@Resource
	private TbItemDescMapper tbItemDescMapper;	
	//注入商品规格参数表
	@Resource
	private TbItemParamItemMapper tbItemParamItemMapper;
	
	//一  查询全部商品列表
	@Override
	public EUDataGridResult selectItem(Integer page, Integer rows) {
		//先设置分页策略
		PageHelper.startPage(page, rows);
		//查询,注意不能传null值
		TbItemExample tbItemExample = new TbItemExample();
		//Criteria criteria = tbItemExample.createCriteria();
		List<TbItem> list = tbItemMapper.selectByExample(tbItemExample);
		//设置分页
		//存储数据
		PageInfo<TbItem> pageInfo = new PageInfo<TbItem>(list);
		EUDataGridResult result = new EUDataGridResult();
		//list:全部的数据
		//pageInfo:装的本页的数据
		result.setRows(pageInfo.getList());
		result.setTotal(pageInfo.getTotal());
		return result;
	}

	/*
	 * 二   添加商品
	 * 	   接收TbItem对象调用Mapper,
	 *   补全实体类须要的数据,id,createtime,updatetime,
	 *   向tb_item表中添加数据,返回TaoTaoResult
	 * 
	 */
	// 2添加商品时添加商品描述
	// 3 添加商品时添加商品规格信息
	@Override
	public TaotaoResult createItem(TbItem item,String desc,String paramData) {
		try {
			//防止出现错误,回滚
			//补全item(根据商品表tb_item 中的字段  补全   前端传过来的参数item)
			long itemId = IDUtils.genItemId();//使用IDUtils随机生成商品的id(能够去数据库看一眼,商品id虽然为主键,可是并无设置递增)
			//设置商品的信息
			item.setId(itemId);//商品id
			item.setStatus((byte)1);//设置状态
			item.setCreated(new Date());//建立时间
			item.setUpdated(new Date());//更改时间
			//将补全后的数据    插入到数据库
		   tbItemMapper.insert(item);
		   //添加商品描述信息,调用底下的方法
		   TaotaoResult result=insertDesc(itemId, desc);
		   if (result.getStatus()!=200) {
				throw new Exception();
		  }
		    //添加商品规格参数
		   result=insertItemParamItem(itemId, paramData);		 
		   return TaotaoResult.ok();
		 } catch (Exception e) {
			e.printStackTrace();
			return TaotaoResult.build(500, "添加异常");
		}
			
	}
	//商品描述信息
	private TaotaoResult insertDesc(long itemId,String desc) {
		 //添加商品描述   完善商品描述类、商品id、商品描述、时间
		TbItemDesc tbItemDesc = new TbItemDesc();
		tbItemDesc.setItemId(itemId);//商品id
		tbItemDesc.setItemDesc(desc);//商品描述
		tbItemDesc.setCreated(new Date());
		tbItemDesc.setUpdated(new Date());
		//将补全后的信息添加到数据库
		tbItemDescMapper.insert(tbItemDesc);
		return TaotaoResult.ok();
	}

	//商品规格信息
	private TaotaoResult insertItemParamItem(long itemId,String itemParams) {
		//建立一个pojo
		TbItemParamItem tbItemParamItem = new TbItemParamItem();
		tbItemParamItem.setItemId(itemId);//商品id
		tbItemParamItem.setParamData(itemParams);//商品规格参数
		tbItemParamItem.setCreated(new Date());
		tbItemParamItem.setUpdated(new Date());
		//向表中插入数据
		tbItemParamItemMapper.insert(tbItemParamItem);
		return TaotaoResult.ok();

	}
	
}

8.4 Controller

功能:接收cid、规格参数模板。建立一TbItemParam对象。调用Service返回TaotaoResult。返回json数据

      将表单中的数据序列化提交,以key-value的形式存在。这样就是将表单对象序列化,就不用每一个name日后台传一次值了。key值就是把表单中的name属性,value就是表单中的value值(因此传参的话传的就是name值,value值若是没写的话就是空,例如非必填项有时候咱们不写,这时候他的value值就是空)

package com.taotao.controller;
import javax.annotation.Resource;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import com.taotao.pojo.EUDataGridResult;
import com.taotao.pojo.TaotaoResult;
import com.taotao.pojo.TbItem;
import com.taotao.service.ItemService;

@Controller
@RequestMapping("/item")
public class ItemContoller {
	
	@Resource
	private ItemService itemService;
	
	/**
	 * 一   查询全部商品列表
	 *       返回值:EUDataGridResult,封装数据
	 *        调用Service查询
	 */
	@RequestMapping("/list")
	@ResponseBody
	public EUDataGridResult selectItem(Integer page,Integer rows){
		return itemService.selectItem(page,rows);	
	}
	
	/*
	 * 二   添加商品
	 *        接收前端表单数据,封装到TbItem中,调用service,
	 *        向前段页面返回TaoToResult对象,返回Json数据,须要使用@ResponseBody注解
	 * 
	 */
	// 2添加商品时添加商品描述
	// 3 添加商品规格参数
	@RequestMapping(value="/save",method=RequestMethod.POST)
	@ResponseBody
	public TaotaoResult creatItem(TbItem item,String desc,String itemParams) {
		TaotaoResult result=itemService.createItem(item,desc,itemParams);
		return result;
	}
	

}

8.5 效果

看一下网络:

看一下数据库,