6.3.1.4、Controller层
后台管理商品的添加功能
商品分类选择
上传图片
富文本编辑器(kindEditor)
实现商品的添加
课后作业(商品的修改、删除)
点击类目选择按钮弹出类目选择窗口,窗口中是一个树形视图。分级展示商品分类。
当选择商品分类的叶子节点后,关闭窗口并将选中的商品分类的名称显示到网页上。
1、初始化tree的url:
/item/cat/list
2、请求的参数
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
调用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 getItemCatList(Long parentId) {
//根据parentId(父节点)查询分类列表
TbItemCatExample example = new TbItemCatExample();
//设置查询条件
Criteria criteria = example.createCriteria();
criteria.andParentIdEqualTo(parentId);
//执行查询
List list = tbItemCatMapper.selectByExample(example);
//分类列表转换成TreeNode的列表
ArrayList 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
接收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
*/
@RequestMapping("/list")
@ResponseBody
public List getItemCatList(@RequestParam(value="id",defaultValue="0")Long parentId){
List 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字符串。
* Title: pojoToJson
* Description:
* @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 jsonToPojo(String jsonData, Class beanType) {
try {
T t = MAPPER.readValue(jsonData, beanType);
return t;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
/**
* 将json数据转换成pojo对象list
* Title: jsonToList
* Description:
* @param jsonData
* @param beanType
* @return
*/
public static List jsonToList(String jsonData, Class beanType) {
JavaType javaType = MAPPER.getTypeFactory().constructParametricType(List.class, beanType);
try {
List list = MAPPER.readValue(jsonData, javaType);
return list;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
}
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、同一类商品的规格项目是相同的。规格项目是跟商品关联。
3、不同商品规格参数的值是不同的
可以使用模板的思路来解决此问题。
1 每一个商品分类对一个规格参数模板。
2 使用模板
每个商品对应一个唯一的规格参数。在添加商品时,可以根据规格参数的模板。生成一个表单。
保存规格参数时。还可以生成规格参数的json数据。保存到数据库中。
规格参数模板表:
商品的规格参数表:
优点:
1、不需要做多表管理。
2、如果要求新添加的商品规格项发生改变,之前的商品不变是很简单的。
缺点:
复杂的表单和json之间的转换。对js的编写要求很高。
选择商品分类后根据选择的商品分类到tb_item_param规格参数模板表中取规格模板,取到了说明此商品分类的规格模板已经添加提示不能添加。如果没有取得则正常添加。
6.3.1.1、功能分析
Url:/item/param/query/itemcatid/{itemCatId}
参数:itemCatId,从url中获得
返回值:TaotaoResult
6.3.1.2、Dao层
从tb_item_param表中根据商品分类id查询内容。
单表操作。可以实现逆向工程的代码。
6.3.1.3、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 list = itemParamMapper.selectByExampleWithBLOBs(tbItemParamExample);
//判断是否查询到结果
if (list!=null &&list.size()>0) {
return TaotaoResult.ok(list.get(0));
}
return TaotaoResult.ok();
}
}
6.3.1.4、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.1、提交规格参数模板
首先把页面中所有文本框中的内容转换成json数据。把json字符串提交给后台。保存到规格参数表中。
请求URL:/item/param/save/{cid}
参数:StringParamData
返回值:TaoTaoResult
6.3.2.2、Dao层
保存规格参数模板,向tb_item_param表中添加一条记录,可以使用逆向工程
6.3.2.3、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 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.4、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.5、效果
在商品添加功能中,读取此商品对应的规格模板,生成表单。供使用者添加规格参数
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 list = tbItemMapper.selectByExample(tbItemExample);
//设置分页
//存储数据
PageInfo pageInfo = new PageInfo(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;
}
}
看一下网络:
看一下数据库,