注意productId是String类型,不用自增长
package com.imooc.sell.dataobject;
import lombok.Data;
import org.hibernate.annotations.Proxy;
import javax.persistence.Entity;
import javax.persistence.Id;
import java.math.BigDecimal;
@Entity
@Data
@Proxy(lazy = false)
public class ProductInfo {
@Id
private String productId;
/** 名字. */
private String productName;
/** 单价. */
private BigDecimal productPrice;
/** 库存. */
private Integer productStock;
/** 描述. */
private String productDescription;
/** 小图. */
private String productIcon;
/** 状态,0正常1下架. */
private Integer categoryStatus;
/** 类目编号. */
private Integer categoryType;
}
6.2.1ProductInfoRepository接口
package com.imooc.sell.repository;
import com.imooc.sell.dataobject.ProductInfo;
import org.springframework.data.jpa.repository.JpaRepository;
import java.util.List;
public interface ProductInfoRepository extends JpaRepository{
List findByCategoryStatus(Integer productStatus);
}
6.2.2单元测试
package com.imooc.sell.repository;
import com.imooc.sell.dataobject.ProductInfo;
import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
import java.math.BigDecimal;
import java.util.List;
import static org.junit.Assert.*;
@RunWith(SpringRunner.class)
@SpringBootTest
public class ProductInfoRepositoryTest {
@Autowired
private ProductInfoRepository repository;
@Test
public void saveTest(){
ProductInfo productInfo=new ProductInfo();
productInfo.setProductId("123456");
productInfo.setProductName("皮蛋粥");
productInfo.setProductPrice(new BigDecimal(3.2));
productInfo.setProductStock(100);
productInfo.setProductDescription("很好喝的粥");
productInfo.setProductIcon("http://xxxxx.jps");
productInfo.setCategoryStatus(0);
productInfo.setCategoryType(2);
ProductInfo result= repository.save(productInfo);
Assert.assertNotNull(result);
}
@Test
public void findByProductStatus(){
List productInfoList=repository.findByCategoryStatus(0);
Assert.assertNotEquals(0,productInfoList.size());
}
}
6.3.1 ProductService接口
package com.imooc.sell.service;
import com.imooc.sell.dataobject.ProductInfo;
import org.springframework.data.domain.Pageable;
import java.util.List;
public interface ProductService {
/**
* 查询所有在架商品
* @param productId
* @return
*/
ProductInfo findOne(String productId);
List findUpAll();
//查找所有商品 需要分页 注意使用的pageable是org.springframework.data.domain.Pageable这个包的
List findAll(Pageable pageable);
ProductInfo save(ProductInfo productInfo);
//加库存(后面添加)
//减库存(后面添加)
}
6.3.2 ProductServiceImpl实现
6.3.2.1这里注意其中一个方法findUpAll查询上架商品的实现
我们会发现我们传入的数值“0”,不是很容易搞清是什么值,这里我们可以使用枚举。
在enums包下建一个枚举ProductStatusEnum
package com.imooc.sell.enums;
import lombok.Getter;
/**
* 商品状态
*/
@Getter //自动生成get方法
public enum ProductStatusEnum {
UP(0, "在架"),
DOWN(1, "下架")
;
private Integer code;
private String message;
ProductStatusEnum(Integer code,String message) {
this.code = code;
this.message = message;
}
}
之前传入的0可写为ProductStatusEnum.UP.getCode()
6.3.2.2注意查找所有商品这个方法
由于需要分页我们传入了pageable,他返回的是一个对象而不是list,所以要将List改为page对象,同样接口也要修改
6.3.2.3 代码
package com.imooc.sell.service.service.impl;
import com.imooc.sell.dataobject.ProductInfo;
import com.imooc.sell.enums.ProductStatusEnum;
import com.imooc.sell.repository.ProductInfoRepository;
import com.imooc.sell.service.ProductService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;
import java.util.List;
@Service
public class ProductServiceImpl implements ProductService {
@Autowired
private ProductInfoRepository repository;
@Override
public ProductInfo findOne(String productId) {
return repository.getOne(productId);
}
@Override
public List findUpAll() {
return repository.findByCategoryStatus(ProductStatusEnum.UP.getCode());
}
@Override
public Page findAll(Pageable pageable) {
return repository.findAll(pageable);
}
@Override
public ProductInfo save(ProductInfo productInfo) {
return repository.save(productInfo);
}
}
package com.imooc.sell.service;
import com.imooc.sell.dataobject.ProductInfo;
import com.imooc.sell.enums.ProductStatusEnum;
import com.imooc.sell.service.impl.ProductServiceImpl;
import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.test.context.junit4.SpringRunner;
import java.math.BigDecimal;
import java.util.List;
import static org.junit.Assert.*;
@RunWith(SpringRunner.class)
@SpringBootTest
public class ProductServiceImplTest {
@Autowired
private ProductServiceImpl productService;
@Test
public void findOne() {
ProductInfo productInfo=productService.findOne("123456");
Assert.assertEquals("123456",productInfo.getProductId());
}
@Test
public void findUpAll() {
List list=productService.findUpAll();
Assert.assertNotEquals(0,list.size());
}
@Test
public void findAll() {
PageRequest request=new PageRequest(0,2);
Page productInfoPage=productService.findAll(request);
//System.out.print(productInfoPage.getTotalElements());
Assert.assertNotEquals(0,productInfoPage.getTotalElements());
}
@Test
public void save() {
ProductInfo productInfo=new ProductInfo();
productInfo.setProductId("12345");
productInfo.setProductName("皮皮虾");
productInfo.setProductPrice(new BigDecimal(3.2));
productInfo.setProductStock(100);
productInfo.setProductDescription("很好吃的虾");
productInfo.setProductIcon("http://xxxxx.jps");
productInfo.setCategoryStatus(ProductStatusEnum.DOWN.getCode());
productInfo.setCategoryType(2);
ProductInfo result=productService.save(productInfo);
Assert.assertNotNull(result);
}
根据API需要先配置下包名
在appliction.yml中添加如下配置
6.4.1.1API
6.4.1.2根据API我们在VO(ViewObject视图对象)包中创建一个resultVO接收最外层对象
package com.imooc.sell.VO;
import lombok.Data;
/**
* http请求返回的最外层对象
* @param
*/
@Data
public class ResultVO {
/** 错误码. */
private Integer code;
/** 提示信息. */
private String msg;
/** 具体内容.
* 返回的是对象,用泛型来接收
* */
private T data;
}
测试一下
报错:The last packet sent successfully to the server was 0 milliseconds ago. The driver has not received any packets from the
原因:远程数据库没启
https://blog.csdn.net/txwtech/article/details/80795633
6.4.1.3 ProductVO
再起一个对象ProductVO。注意ProductVO跟ProductInfo属性是不大一样的。
为什么不用ProductInfo这个对象?其实原则上前端需要几个字段你就给它返回几个字段,不要返回那么多的内容。原因上呢是出于安全以及引资上的一些考虑。
例如商品对象ProductInfo的库存返回给前端,你的竞争对手就可以看到你有多少库存了。这个其实对自己的产品是一个很危险的行为。或者是上下架,总之都是一些不安全的行为。不光是技术上,还有产品、引资上都是不安全的。这就是为什么我们要重新建一个对象的原因。
package com.imooc.sell.VO;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Data;
import java.util.List;
/**
* 商品(包含类目)
*/
@Data
public class ProductVO {
@JsonProperty("name")//返回给前端,这样子再把对象序列化的时候返回给前端它就是一个name了。
private String categoryName;
@JsonProperty("type")//明确是什么名字,类目的名字那就是categoryName
private Integer categoryType;
@JsonProperty("foods")
private List productInfoVOList;
}
6.4.1.4ProductInfoVO
package com.imooc.sell.VO;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Data;
import java.math.BigDecimal;
/**
* 商品详情
*/
@Data
public class ProductInfoVO {
@JsonProperty("id")
private String productId;
@JsonProperty("name")
private String productName;
@JsonProperty("price")
private BigDecimal productPrice;
@JsonProperty("description")
private String productDescription;
@JsonProperty("icon")
private String productIcon;
}
测试一下(在浏览器上安装JsonView格式可查看json格式)
6.4.1.5查询数据库
我们看一下如果要从数据库中查出来并展示要做什么事呢
第一点,我们应该能想到查询所有上架的商品,因为这个地方不需要分页,所以我们直接查询所有的
第二点,是查询类目,注意一点是我们肯定查询的是我们需要的,注意一定要一次性查询,你不能查询出十条商品,进行一个for循环,再去查10次的类目,你那样查询耗时就久了。为了性能的提升,一定要一次性的查询。
第三点,那就是数据拼装了,我们要把数据拼装成跟演示的JSON格式那样子。
下面进行逐一的编写
查询商品,用到ProductService。
查询类目,用到CategoryService。lambda表达式很强大,它可以做很多很多事情。比如说如果要进行一些过滤的话,那么这个用起来也是特别的爽。现在Java 9都出来了,所以我觉得Java 8你在生产环境上都可以用了。作者的公司就在用Java 8,并且项目里面也会有lambda表达式。
productInfoVO要设置五个值,代码不够优雅,有点啰嗦。Spring提供了一个BeanUtils这个类,可以把productInfo的值拷贝到productInfoVO。
package com.imooc.sell.controller;
import com.imooc.sell.VO.ProductInfoVO;
import com.imooc.sell.VO.ProductVO;
import com.imooc.sell.VO.ResultVO;
import com.imooc.sell.dataobject.ProductCategory;
import com.imooc.sell.dataobject.ProductInfo;
import com.imooc.sell.service.CategoryService;
import com.imooc.sell.service.ProductService;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
/**
* 买家商品
* Created by zhongzh
* 2018-05-28 14:42
*
*/
@RestController//返回的是JSON格式,所以这里写@RestController
@RequestMapping("/buyer/product")//给它一个URL的前缀,我这个URL前缀其实跟类名很相似
public class BuyerProductController {
@Autowired
private ProductService productService;
@Autowired
private CategoryService categoryService;
@GetMapping("/list")//Get请求,list,返回为null
public ResultVO list(){
//1. 查询所有的上架商品
List productInfoList = productService.findUpAll();
//2. 查询类目(一次性查询)
//List categoryTypeList = new ArrayList<>();
//传统方法
/*for (ProductInfo productInfo : productInfoList) {
categoryTypeList.add(productInfo.getCategoryType());
}*/
//精简方法(java8, lambda表达式)
List categoryTypeList = productInfoList.stream()
.map(e -> e.getCategoryType())
.collect(Collectors.toList());
List productCategoryList = categoryService.findByCategoryTypeIn(categoryTypeList);
//3. 数据拼装
List productVOList = new ArrayList<>();
for(ProductCategory productCategory : productCategoryList){
ProductVO productVO = new ProductVO();
productVO.setCategoryType(productCategory.getCategoryType());
productVO.setCategoryName(productCategory.getCategoryName());
//productVO.setProductInfoVOList();
List productInfoVOList = new ArrayList<>();
//遍历商品详情
for(ProductInfo productInfo : productInfoList) {
if(productInfo.getCategoryType().equals(productCategory.getCategoryType())){
//根据类目的Type来判断是否相等,相等才做
ProductInfoVO productInfoVO = new ProductInfoVO();
//productInfoVO.set
//一般是要设置五个值
// productInfoVO.setProductId(productInfo.getProductId());
// productInfoVO.setProductName(productInfo.getProductName());
// productInfoVO.setProductPrice(productInfo.getProductPrice());
// productInfoVO.setProductIcon(productInfo.getProductIcon());
// productInfoVO.setProductDescription(productInfo.getProductDescription());
//精简方法
BeanUtils.copyProperties(productInfo,productInfoVO);
productInfoVOList.add(productInfoVO);
}
}
productVO.setProductInfoVOList(productInfoVOList);
productVOList.add(productVO);
}
ResultVO resultVO = new ResultVO();
resultVO.setCode(0);
resultVO.setMsg("成功");
/**
ProductVO productVO = new ProductVO();
ProductInfoVO productInfoVO = new ProductInfoVO();
productVO.setProductInfoVOList(Arrays.asList(productInfoVO));
*/
//resultVO.setData(productVO);
//resultVO.setData(Arrays.asList(productVO));
resultVO.setData(productVOList);
return resultVO;
}
}
测试一下
第一步和第二步都是数据库的查询,我们把数据库查出来之后呢,然后再在代码里面把它拼装。最需要提醒大家的一点是,不要把数据库的查询放到for循环里面去。这样子你一旦循环的数目过大,比如说你要循环一万条,那么能进行一万次数据库的查询,这个时间开销是很大的,承受不起。你一个接口返回ResultVO对象都要这样来写,先new然后再set进去。这样写有点麻烦,把它封装一下。写一个utils包。ResultVOUtil写几个静态方法吧。
package com.imooc.sell.utils;
import com.imooc.sell.VO.ResultVO;
public class ResultVOUtil {
public static ResultVO success(Object object){
ResultVO resultVO=new ResultVO();
resultVO.setCode(0);
resultVO.setMsg("成功");
resultVO.setData(object);
return resultVO;
}
public static ResultVO success(){ //有可能什么数据都不传
return success(null);
}
public static ResultVO error(Integer code,String msg){ //出错时,调用error方法
ResultVO resultVO=new ResultVO();
resultVO.setMsg(msg);
resultVO.setCode(code);
return resultVO;
}
}
之前的代码就简单一些了,你也不需要new和set
6.4.1.5尝试访问
没有问题。现在跟前端联调起来。现在访问一下虚拟机,发现它会跳转
为什么会做这么个逻辑,到后面的微信授权会讲到,现在只要设置一下cookie,让他能正常访问,我们看一下api是否生效就好了
我们可以先这么来做
先访问192.168.204.128/#/order,这一页没有对cookie的判断
在控制台设置一下cookie
cookie的值随便写(推荐用谷歌浏览器)
再访问下虚拟机
访问的url为虚拟机地址,需要改为本机地址
修改虚拟机ngin配置
nginx -s reload 重启一下
刷新页面
将地址改为域名
还是更改nginx配置
修改hosts文件(使用SwitchHosts工具)
重新访问,地址sell.com
欢迎进群交流258897306或关注公众号“IT群英汇”