6.3.1.四、Controller层html
后台管理商品的添加功能前端
商品分类选择java
上传图片node
富文本编辑器(kindEditor)linux
实现商品的添加nginx
课后做业(商品的修改、删除)git
点击类目选择按钮弹出类目选择窗口,窗口中是一个树形视图。分级展现商品分类。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"
}]
添加商品的时候必需要选择商品的分类,也就是类目选择,咱们须要从数据库中将类目信息查询出来,咱们须要查询tb_item_cat
能够看见: 该表中有一个字段是parent_id与本表中的id列有关系,这种关系叫自关联,就是说,本表中的字段与本表中的字段有关系
能够看见类目选择方法在: common.js中
Url:/item/cat/list
参数:parentId
返回值:EUTreeNode
由于返回的结果中带有id和类目名等,遇到这种状况咱们的第一反应就是建立实体类封装数据。
单表操做,直接用逆向工程便可
SELECT * FROM `tb_item_cat` where parent_id=父节点id(=0时表明是一级的类目);
咱们这里是直接使用的逆向工程生成的mapper。
该实体类须要建立到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 }
功能:根据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; } }
功能:接收页面传递过来的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; } }
出现的问题:若是把图片放到工程中,在集群环境下,会出现找不到图片的状况。
图片服务器两个服务:
http:能够使用nginx作静态资源服务器。也可使用apache。推荐使用nginx,效率更高。
Nginx:
http服务
反向代理
负载均衡
ftp服务:
使用linux作服务器,在linux中有个ftp(图片服务器)组件vsftpd。
能够把图片上传到ftp上保存,须要的时候从图片服务器ftp上拿就能够
ftp:是一个协议
ftp协议完成图片的上传,须要在Linux中安装vsftpd服务。而后咱们可使用nginx完成图片路径的映射,咱们就能够经过nginx提供的http服务访问图片。
要求安装vmware虚拟机。
Linux:CentOS7(64)
Nginx:
Vsftpd:须要在线安装。
linux安装nginx参考连接:https://mp.csdn.net/postedit/88779062
linux安装ftp服务器参考连接:https://mp.csdn.net/postedit/88832707
进入conf目录,修改nginx.conf配置文件
location /images/ { alias /home/vsftpd/leo; autoindex on; }
咱们向上边配置的目录中上传图片并访问浏览器
上边这几步在安装ftp时都有说明
流程:选择图片上传,上传过程当中须要图片重命名,防止名字重复,上传完成以后再将图片的路径返回到jsp中完成图片回显
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(); //关闭资源 } }
在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(); } } }
#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
修改配置文件
咱们使用kindeEditor(富文本编辑器)实现文件上传,上传以后要接收结果。成功回显图片,失败提示失败
返回值:
参考文档:http://kindeditor.net/docs/upload.html
直接上传图片到图片服务器,而不是数据库。不涉及到dao层
实现文件上传,将文件经过ftp协议上传到图片服务器上,咱们经过FTPUtil工具类实现上传
上传成功以后图片要回显,咱们返回值url是图片的访问路径
功能:接收Controller传递过来的参数,一个文件MultiPartFile对象。把文件上传到ftp服务器上,生成一个新的文件名,返回文件url路径。须要保证图片上传插件要求的数据格式(即前边提到的 image)
这里可使用map实现,也可使用实体类封装对象,我使用的是map
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()); } }
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; } } }
接收上传的图片,调用service层,返回json数据
功能:接收页面传递过来的图片。调用service上传到图片服务器。返回结果。
参数:MultiPartFile uploadFile
返回值:返回json数据,应该返回一个pojo,PictureResult对象。
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; } }
<!-- 定义文件上传解析器 --> <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>
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; } }
第一步:在JSP中引入富文本编译器
第二步:在富文本编译器出现的位置添加一个textarea域
第三步:调用JS方法初始化富文本编译器
第四步:提交表单时调用富文本编译器sync方法,把富文本编译器中的内容同步到textarea中。
规格参数
规格项:规格值
规律:
一、同一类商品的规格项分组相同。
二、同一类商品的规格项目是相同的。规格项目是跟商品关联。
三、不一样商品规格参数的值是不一样的
可使用模板的思路来解决此问题。
1 每个商品分类对一个规格参数模板。
2 使用模板
每一个商品对应一个惟一的规格参数。在添加商品时,能够根据规格参数的模板。生成一个表单。
保存规格参数时。还能够生成规格参数的json数据。保存到数据库中。
规格参数模板表:
商品的规格参数表:
优势:
一、不须要作多表管理。
二、若是要求新添加的商品规格项发生改变,以前的商品不变是很简单的。
缺点:
复杂的表单和json之间的转换。对js的编写要求很高。
选择商品分类后根据选择的商品分类到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.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.3.1 、需求分析
6.3.3.2 、service修改
当表中的字段是text类型时,须要使用大文本格式查询,用来检索大字段。普通的方法查询不到
6.3.3.2 、效果图
咱们要将商品保存到tb_item表中,咱们是点击提交按钮以后进行保存。
请求url:/item/save
请求方式:post请求
参数:$("#itemAddForm").serialize() k-v对结构 (将表单数据序列化成k-v形式) 将表单中的数据序列化,以key-value的形式存在,key为name值,value为value值
响应内容:返回TaotaoResult,咱们该项目中响应页面数据的实体类
把商品信息插入到商品表,单表操做。可使用逆向工程生成的代码
返回值设置响应状态
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; } } }
接收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(); }
接收前端表单数据,封装到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; }
后台要接收前台页面提交的商品信息和商品描述,商品信息和商品描述都要保存。
商品信息添加到tb_item中。商品描述添加到tb_item_desc表中
把商品描述的信息保存到tb_item_desc表中,咱们使用逆向工程生成的代码便可
接收商品描述调用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(); }
接收参数,调用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; }
提交表单以前,先把规格参数表单中的内容转换成json数据而后跟商品基本信息、商品描述同时提交给后台。保存至数据库。
转换后把规格参数的信息放到表单的hidden域中:
随着表单的提交同时提交。
须要向tb_item_param_item表中添加数据
接收规格参数的内容,和商品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(); } }
功能:接收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; } }
看一下网络:
看一下数据库,