买家端实体类
@Entity
@DynamicUpdate
@Data
@Proxy(lazy = false)
public class ProductCategory {
/** 类目id **/
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer categoryId;
/** 类目名字. */
private String categoryName;
/** 类目编号. */
private Integer categoryType;
// private Date createTime;
//
// private Date updateTime;
public ProductCategory() {
}
public ProductCategory(String categoryName, Integer categoryType) {
this.categoryName = categoryName;
this.categoryType = categoryType;
}
}
其中
@Entity
表示这是个实体类,
@Id
表示这个字段是一个主键,
@GeneratedValue
表示主键生成的策略,存在的意义就是生成一个唯一标识的主键,
@DynamicUpdate
表示动态更新数据库中的时间,比如我们在插入和修改数据时,时间自动帮我们修改。
@Data
:注解在类上;提供类所有属性的 getting 和 setting 方法,此外还提供了equals、canEqual、hashCode、toString 方法。前提是要导入 lombok 依赖。
@Proxy(lazy = false)
:lazy代表延时加载,lazy=false,代表不延时。
买家端类目 dao
public interface ProductCategoryRepository extends JpaRepository<ProductCategory,Integer> {
List<ProductCategory> findByCategoryTypeIn(List<Integer> categoryTypeList);
}
测试:
@RunWith(SpringRunner.class)
@SpringBootTest
public class ProductCategoryRepositoryTest {
@Autowired
private ProductCategoryRepository repository;
@Test
public void findOneTest(){
ProductCategory productCategory = repository.getOne(3);
System.out.println(productCategory);
}
@Test
public void saveTest(){
ProductCategory productCategory = repository.findById(3).orElse(null);
productCategory.setCategoryType(4);
repository.save(productCategory);
}
@Test
public void findByCategoryTypeInTest(){
List<Integer> list = Arrays.asList(2,3,4);
List<ProductCategory> result = repository.findByCategoryTypeIn(list);
Assert.assertNotEquals(0,result.size());
}
}
@RunWith(SpringRunner.class)
:作用是让测试在Spring容器环境下执行。如测试类中无此注解,将导致service,dao等自动注入失败。
买家类目 Service
Service接口:
public interface CategoryService {
ProductCategory findOne(Integer categoryId);
List<ProductCategory> findAll();
List<ProductCategory> findByCategoryTypeIn(List<Integer> findByCategoryTypeList);
ProductCategory save(ProductCategory productCategory);
}
Service实现类:
@Service
public class CategoryServiceImpl implements CategoryService {
@Autowired
private ProductCategoryRepository repository;
@Override
public ProductCategory findOne(Integer categoryId) {
return repository.findById(categoryId).orElse(null);
}
@Override
public List<ProductCategory> findAll() {
return repository.findAll();
}
@Override
public List<ProductCategory> findByCategoryTypeIn(List<Integer> categoryTypeList) {
return repository.findByCategoryTypeIn(categoryTypeList);
}
@Override
public ProductCategory save(ProductCategory productCategory) {
return repository.save(productCategory);
}
}
买家商品dao
商品实体类
@Entity
@Data
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 productStatus;
/**类目编号*/
private Integer categoryType;
}
商品dao
public interface ProductInfoRepository extends JpaRepository<ProductInfo,String> {
List<ProductInfo> findByProductStatus(Integer productStatus);
}
测试
@RunWith(SpringRunner.class)
@SpringBootTest
public class ProductInfoRepositoryTest extends TestCase {
@Autowired
ProductInfoRepository repository;
@Test
public void saveTest() {
ProductInfo productInfo = new ProductInfo();
productInfo.setProductId("123456");
productInfo.setProductName("小米粥");
productInfo.setProductPrice(new BigDecimal(2));
productInfo.setProductStock(200);
productInfo.setProductDescription("小米粥是以小米作为主要食材熬制而成的一种独具特色的北方粥点,口味清淡,清香味,具有简单易制,健胃消食的特点。煮粥时一定要先烧开水然后放入洗净后的小米,先煮沸,然后用文火熬,汤粘稠后即可关火。");
productInfo.setProductIcon("http://xiaomizhou.jpg");
productInfo.setProductStatus(0);
productInfo.setCategoryType(6);
ProductInfo result = repository.save(productInfo);
Assert.assertNotNull(result);
}
@Test
public void testFindByProductStatus() {
List<ProductInfo> productStatus = repository.findByProductStatus(0);
Assert.assertNotEquals(0,productStatus.size());
}
}
买家商品Service
public interface ProductService {
ProductInfo findOne(String productId);
/**
* 查询左右上架的商品
* @return
*/
List<ProductInfo> findUpAll();
/**
* 分页查询所有商品
* @param pageable
* @return
*/
Page<ProductInfo> findAll(Pageable pageable);
/**
* 更新商品
* @param productInfo
* @return
*/
ProductInfo save(ProductInfo productInfo);
}
商品实现类:
@Service
public class ProductServiceImpl implements ProductService {
@Autowired
ProductInfoRepository repository;
@Override
public ProductInfo findOne(String productId) {
return repository.findById(productId).orElse(null);
}
@Override
public List<ProductInfo> findUpAll() {
return repository.findByProductStatus(ProductStatusEnum.UP.getCode());
}
@Override
public Page<ProductInfo> findAll(Pageable pageable) {
return repository.findAll(pageable);
}
@Override
public ProductInfo save(ProductInfo productInfo) {
return repository.save(productInfo);
}
}
这部分的难点就是商品分页查询,我们用到的是Pageable
的 Page 分页,可以去看看PageRequest
的源码:
/** @deprecated */
@Deprecated
public PageRequest(int page, int size) {
this(page, size, Sort.unsorted());
}
在后面做后台管理系统的时候还会用到。
实现类测试:
@Test
public void testFindOne() {
ProductInfo productInfo = productService.findOne("123456");
Assert.assertEquals("123456",productInfo.getProductId());
}
@Test
public void testFindUpAll() {
List<ProductInfo> productInfoList = productService.findUpAll();
Assert.assertNotEquals(0,productInfoList.size());
}
@Test
public void testFindAll() {
Page<ProductInfo> productInfoPage = productService.findAll(PageRequest.of(0,6));
System.out.println(productInfoPage.getTotalElements());
Assert.assertNotEquals(0,productInfoPage.getTotalElements());
}
@Test
public void testSave() {
ProductInfo productInfo = new ProductInfo();
productInfo.setProductId("12345678");
productInfo.setProductName("玉米粥");
productInfo.setProductPrice(new BigDecimal(2.8));
productInfo.setProductStock(200);
productInfo.setProductDescription(
"玉米粥是以玉米作为主要食材熬制而成的一种独具特色的北方粥点,口味清淡,清香味,具有简单易制,健胃消食的特点。煮粥时一定要先烧开水然后放入洗净后的小米,先煮沸,然后用文火熬,汤粘稠后即可关火。");
productInfo.setProductIcon("http://xiaomizhou.jpg");
productInfo.setProductStatus(ProductStatusEnum.DOWN.getCode());
productInfo.setCategoryType(6);
ProductInfo result = productService.save(productInfo);
Assert.assertNotNull(result);
}
对于商品的上架和下架,为了程序员方便查看,我们可以写个商品上架、下架的枚举类型:
@Getter
public enum ProductStatusEnum {
//表示商品在架
UP(0,"在架"),
//表示商品下架
DOWN(1,"下架");
private Integer code;
private String message;
ProductStatusEnum(Integer code,String message){
this.code = code;
this.message = message;
}
}
买家商品API
我们一般都是根据 API 文档编写接口,文档一般都是由前端来定义的,里面的字段都是和数据库的字段息息相关,数据库的字段一般都是后端人员定义,编写文档时,都要和前端人员确认,双方协商修改,认为没问题时生成 共同的文档,再按照文档开发。代码未动,文档先行。
@RestController
@RequestMapping("/buyer/product")
public class BuyerProductController {
@GetMapping("/list")
public ResultVO list(){
ResultVO resultVO = new ResultVO();
ProductVO productVO = new ProductVO();
ProductInfoVO productInfoVO = new ProductInfoVO();
productVO.setProductInfoVOList(Arrays.asList(productInfoVO));
resultVO.setData(Arrays.asList(productVO));
//把商品内容详情的data里
resultVO.setCode(0);
resultVO.setMessage("成功");
return resultVO;
}
}
为什么要创建 VO 类?
前端需要几个字段,我们就传几个字段,不要传无效的字段,很大原因出于是安全和隐私上的考虑。
比如商品的库存是不需要返回前端的,如果返回给前端了,竞争对手就会看到库存,这就对自己产品是非常不利和不安全的行为,这就是为什么要新建对象的原因。
具体的商品VO代码我就不贴了,API 文档要啥字段,我们就写什么,但是最好不要直接使用实体类传达前端页面,有安全隐患。
//请求返回的参数
@Data
public class ResultVO<T> {
/**状态码*/
private Integer code;
/**提示信息*/
private String message;
/**具体内容*/
private T data;
}
//包含商品的类目
@Data
public class ProductVO {
@JsonProperty("name")
private String categoryName;
@JsonProperty("type")
private Integer categoryType;
@JsonProperty("foods")
private List<ProductInfoVO> productInfoVOList;
}
//商品详情
@Data
public class ProductInfoVO {
@JsonProperty("id")
private Integer productId;
@JsonProperty("name")
private String productName;
@JsonProperty("price")
private BigDecimal productPrice;
@JsonProperty("description")
private String productDescription;
@JsonProperty("icon")
private String productIcon;
}