自营型电商有哪些「自营电商是什么意思」

互联网 2023-04-09 21:09:40

今天给大家普及一下自营型电商有哪些「自营电商是什么意思」相关知识,最近很多在问自营型电商有哪些「自营电商是什么意思」,希望能帮助到您。

类别管理--添加类别--持久层8.1. 配置

续前日,无新增

8.2. 规划需要执行的SQL语句

续前日,无新增

8.3. 接口与抽象方法

此前需要执行的SQL语句大致是:

select id from pms_category where name=?;

在csmall-pojo的根包下创建vo.CategorySimpleVO类,用于封装以上查询结果:

@Datapublic class CategorySimpleVO implements Serializable {private Long id;}

在csmall-product-webapi的CategoryMapper接口中添加抽象方法:

CategorySimpleVO getByName(String name);8.4. 配置SQL语句

在csmall-product-webapi的CategoryMapper.xml中添加配置:

<!-- CategorySimpleVO getByName(String name); --><select id="getByName" resultMap="SimpleResultMap">select id from pms_category where name=#{name}</select><resultMap id="SimpleResultMap" type="cn.celinf.csmall.pojo.vo.CategorySimpleVO"><id column="id" property="id" /></resultMap>8.5. 测试

在csmall-product-webapi的srctestresources下创建insert_data.sql文件,用于插入测试数据:

insert into pms_category (name) value ('类别001'), ('类别002');

然后,在CategoryMapperTests中添加测试方法:

@Test@Sql({"classpath:truncate.sql", "classpath:insert_data.sql"})public void testGetByNameSuccessfully() {// 测试数据String name = "类别001";// 断言不会抛出异常assertDoesNotThrow(() -> {// 执行查询CategorySimpleVO category = mapper.getByName(name);// 断言查询结果不为nullassertNotNull(category);});}@Test@Sql({"classpath:truncate.sql"})public void testGetByNameFailBecauseNotFound() {// 测试数据String name = "类别999";// 断言不会抛出异常assertDoesNotThrow(() -> {// 执行查询CategorySimpleVO category = mapper.getByName(name);// 断言查询结果为nullassertNull(category);});}

完成后,执行整个测试类(将执行此类中所有测试方法),应该全部通过测试。

9. 类别管理--添加类别--业务逻辑层9.1. 接口与抽象方法

在使用Dubbol的微服务架构中,需要将业务逻辑层的接口声明在专门的Module中,便于被其它微服务Module依赖,所以,先在csmall-product下创建新的Module,名为csmall-product-service,创建参数:

Group:cn.celinfArtifact:csmall-product-servicePackage Name:cn.celinf.csmall.product.service

首先,应该调用新Module的pom.xml如下:

<?xml version="1.0" encoding="UTF-8"?><project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><!-- 父级项目 --><parent><groupId>cn.celinf</groupId><artifactId>csmall-product</artifactId><version>0.0.1-SNAPSHOT</version></parent><!-- 当前项目的信息 --><groupId>cn.celinf</groupId><artifactId>csmall-product-service</artifactId><version>0.0.1-SNAPSHOT</version><!-- 当前项目需要使用的依赖项 --><dependencies><!-- Csmall POJO --><dependency><groupId>cn.celinf</groupId><artifactId>csmall-pojo</artifactId></dependency></dependencies></project>

然后,在csmall-product的pom.xml中补充此子级Module:

<!-- 当前Project的各子级Module --><modules><module>csmall-product-webapi</module><module>csmall-product-service</module> <!-- 新增 --></modules>

接下来,需要删除不必要的文件:

启动类srcmainresources及其下的配置文件srctest

接下来,需要创建接口并添加抽象方法,方法的参数应该是封装的对象(因为一个String或Long等简单数据不足以完成添加类别的操作),则先在csmall-pojo的根包下创建dto.CategoryAddNewDTO类,并在类中添加必要的属性:

import lombok.Data;import java.io.Serializable;@Datapublic class CategoryAddNewDTO implements Serializable {private String name;private Long parentId;private String keywords;private Integer sort;private String icon;private Integer isDisplay;}

然后,在csmall-product-service中,在cn.celinf.csmall.product.service下创建ICategoryService接口:

public interface ICategoryService {void addNew(CategoryAddNewDTO categoryAddNewDTO);}9.2. 实现

在csmall-product-service中只存放业务逻辑层的接口,而业务逻辑层的实现类仍在csmall-product-webapi中,所以,需要在csmall-product-webapi中依赖csmall-product-service。

先在Project的pom.xml中添加对csmall-product-service的依赖管理:

<!-- ===== 原有其它代码 ===== --><!-- 依赖管理,主要管理各依赖项的版本,使得子级Module添加依赖时不必指定版本 --><dependencyManagement><dependencies><!-- Csmall Product Service --><dependency><groupId>cn.celinf</groupId><artifactId>csmall-product-service</artifactId><version>${csmall.version}</version></dependency><!-- ===== 原有其它代码 ===== -->

然后,在csmall-product-webapi中添加依赖:

<!-- ===== 原有其它代码 ===== --><!-- 当前项目需要使用的依赖项 --><dependencies><!-- Csmall Product Service --><dependency><groupId>cn.celinf</groupId><artifactId>csmall-product-service</artifactId></dependency><!-- ===== 原有其它代码 ===== -->

在cn.celinf.csmall.product.webapi下创建service.CategoryServiceImpl类,此类应该实现ICategoryService接口,此类还应该添加@Service注解:

import cn.celinf.csmall.pojo.dto.CategoryAddNewDTO;import cn.celinf.csmall.product.service.ICategoryService;import org.springframework.stereotype.Service;@Servicepublic class CategoryServiceImpl implements ICategoryService {@Overridepublic void addNew(CategoryAddNewDTO categoryAddNewDTO) {}}

关于以上业务的实现分析:

@Autowiredprivate CategoryMapper categoryMapper;// 注意:需要创建异常// 注意:需要在CategoryMapper中补充getById()方法,至少返回:depth// 注意:需要在CategoryMapper中补充updateIsParentById()方法public void addNew(CategoryAddNewDTO categoryAddNewDTO) {// 从参数中取出尝试添加的类别的名称// 调用categoryMapper.getByName()方法查询// 判断查询结果是否不为null// 是:抛出ServiceException// 从参数中取出父级类别的id:parentId// 判断parentId是否为0// 是:此次尝试添加的是一级类别,没有父级类别,则当前depth >>> 1// 否:此次尝试添加的不是一级类别,则应该存在父级类别,调用categoryMapper.getById()方法查询父级类别的信息// -- 判断查询结果是否为null// -- 是:抛出ServiceException// -- 否:当前depth >>> 父级depth 1// 创建Category对象// 调用BeanUtils.copyProperties()将参数对象中的属性值复制到Category对象中// 补全Category对象中的属性值:depth >>> 前序运算结果// 补全Category对象中的属性值:enable >>> 1(默认即启用)// 补全Category对象中的属性值:isParent >>> 0// 补全Category对象中的属性值:gmtCreate, gmtModified >>> LocalDateTime.now()// 调用categoryMapper.insert(Category)插入类别数据,获取返回的受影响的行数// 判断返回的受影响的行数是否不为1// 是:抛出ServiceException// 判断父级类别的isParent是否为0// 是:调用categoryMapper.updateIsParentById()方法,将父级类别的isParent修改为1,获取返回的受影响的行数// 判断返回的受影响的行数是否不为1// 是:抛出ServiceException}

要实现以上业务,需要先在持久层完成“根据id查询类别信息”的功能,则在CategorySimpleVO中添加private Integer depth;属性(原getByName()方法对应的查询也作对应的修改,虽然不是必须的)。

然后,还需要在CategorySimpleVO中补充private Integer isParent;属性,并且,必须在接下的查询中,查出此值。

然后CategeoryMapper接口中添加:

CategorySimpleVO getById(Long id);

然后在CategoryMapper.xml中配置以上方法映射的SQL:

<!-- CategorySimpleVO getById(Long id); --><select id="getById" resultMap="SimpleResultMap">select id, depth from pms_category where id=#{id}</select>

完成后,还需要在CategoryMapperTests中添加2个测试,以检验以上功能是否正常运行:

@Test@Sql({"classpath:truncate.sql", "classpath:insert_data.sql"})public void testGetByIdSuccessfully() {// 测试数据Long id = 1L;// 断言不会抛出异常assertDoesNotThrow(() -> {// 执行查询CategorySimpleVO category = mapper.getById(id);// 断言查询结果不为nullassertNotNull(category);});}@Test@Sql({"classpath:truncate.sql"})public void testGetByIdFailBecauseNotFound() {// 测试数据Long id = -1L;// 断言不会抛出异常assertDoesNotThrow(() -> {// 执行查询CategorySimpleVO category = mapper.getById(id);// 断言查询结果为nullassertNull(category);});}

在CategoryMapper接口中添加:

int updateIsParentById(@Param("id") Long id, @Param("isParent") Integer isParent);

然后在CategoryMapper.xml中配置以上方法映射的SQL:

<!-- int updateIsParentById(@Param("id") Long id, @Param("isParent") Integer isParent); --><update id="updateIsParentById">update pms_category set is_parent=#{isParent} where id=#{id}</update>

完成后,还需要在CategoryMapperTests中添加2个测试,以检验以上功能是否正常运行:

@Test@Sql({"classpath:truncate.sql", "classpath:insert_data.sql"})public void testUpdateIsParentByIdSuccessfully() {// 测试数据Long id = 1L;Integer isParent = 1;// 断言不会抛出异常assertDoesNotThrow(() -> {// 执行测试int rows = mapper.updateIsParentById(id, isParent);// 断言受影响的行数为1assertEquals(1, rows);});}@Test@Sql({"classpath:truncate.sql"})public void testUpdateIsParentByIdFailBecauseNotFound() {// 测试数据Long id = -1L;Integer isParent = 1;// 断言不会抛出异常assertDoesNotThrow(() -> {// 执行测试int rows = mapper.updateIsParentById(id, isParent);// 断言受影响的行数为0assertEquals(0, rows);});}

在实现业务逻辑之前,还需要创建自定义的异常类型,由于后续还有不少需要被多个Module共同使用的类、接口等,所以,此异常类型和后续可能被共用的类、接口都应该放在一个公共的Module中,则在Project下创建csmall-common这个新的Module,创建成功后,需要:

在csmall-common中,修改pom.xml中的父项目在csmall-common中,在pom.xml删除依赖项在csmall-common中,在pom.xml删除<build>配置在csmall-common中,删除src/test在csmall-common中,删除src/main/resources在csmall-common中,删除启动类在Project的pom.xml中,添加<module>在Project的pom.xml中,添加对新Module的依赖管理在csmall-product-webapi中的pom.xml中,添加对csmall-common的依赖

在csmall-common的根包下创建ex.ServiceException类:

public class ServiceException extends RuntimeException {// 暂时不加构造方法}

然后,在csmall-product-webapi中的CategoryServiceImpl中实现业务:

import cn.celinf.csmall.common.ex.ServiceException;import cn.celinf.csmall.pojo.dto.CategoryAddNewDTO;import cn.celinf.csmall.pojo.entity.Category;import cn.celinf.csmall.pojo.vo.CategorySimpleVO;import cn.celinf.csmall.product.service.ICategoryService;import cn.celinf.csmall.product.webapi.mapper.CategoryMapper;import org.springframework.beans.BeanUtils;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.stereotype.Service;import java.time.LocalDateTime;@Servicepublic class CategoryServiceImpl implements ICategoryService {@AutowiredCategoryMapper categoryMapper;@Overridepublic void addNew(CategoryAddNewDTO categoryAddNewDTO) {// 从参数中取出尝试添加的类别的名称String name = categoryAddNewDTO.getName();// 调用categoryMapper.getByName()方法查询CategorySimpleVO queryResult = categoryMapper.getByName(name);// 判断查询结果是否不为nullif (queryResult != null) {// 是:抛出ServiceExceptionthrow new ServiceException();}// 从参数中取出父级类别的id:parentIdLong parentId = categoryAddNewDTO.getParentId();// 判断parentId是否为0,当前尝试新增的类别的depth默认为1Integer depth = 1;CategorySimpleVO parentCategory = null;if (parentId != 0) {// 否:此次尝试添加的不是一级类别,则应该存在父级类别,调用categoryMapper.getById()方法查询父级类别的信息parentCategory = categoryMapper.getById(parentId);// -- 判断查询结果是否为nullif (parentCategory == null) {// -- 是:抛出ServiceExceptionthrow new ServiceException();}// -- 否:当前depth >>> 父级depth 1depth = parentCategory.getDepth() 1;}// 创建Category对象Category category = new Category();// 调用BeanUtils.copyProperties()将参数对象中的属性值复制到Category对象中BeanUtils.copyProperties(categoryAddNewDTO, category);// 补全Category对象中的属性值:depth >>> 前序运算结果category.setDepth(depth);// 补全Category对象中的属性值:enable >>> 1(默认即启用)category.setEnable(1);// 补全Category对象中的属性值:isParent >>> 0category.setIsParent(0);// 补全Category对象中的属性值:gmtCreate, gmtModified >>> LocalDateTime.now()LocalDateTime now = LocalDateTime.now();category.setGmtCreate(now);category.setGmtModified(now);// 调用categoryMapper.insert(Category)插入类别数据,获取返回的受影响的行数int rows = categoryMapper.insert(category);// 判断返回的受影响的行数是否不为1if (rows != 1) {// 是:抛出ServiceExceptionthrow new ServiceException();}// 判断父级类别的isParent是否为0// 以下判断条件有部分多余,但不会报错if (parentId != 0 && parentCategory != null && parentCategory.getIsParent() == 0) {// 是:调用categoryMapper.updateIsParentById()方法,将父级类别的isParent修改为1,获取返回的受影响的行数rows = categoryMapper.updateIsParentById(parentId, 1);// 判断返回的受影响的行数是否不为1if (rows != 1) {// 是:抛出ServiceExceptionthrow new ServiceException();}}}}9.3. 测试

在src/test/java下的根包下创建service.CategoryServiceTests测试类,编写并执行测试:

import cn.celinf.csmall.common.ex.ServiceException;import cn.celinf.csmall.pojo.dto.CategoryAddNewDTO;import cn.celinf.csmall.product.service.ICategoryService;import org.junit.jupiter.api.Test;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.boot.test.context.SpringBootTest;import org.springframework.test.context.jdbc.Sql;import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;import static org.junit.jupiter.api.Assertions.assertThrows;@SpringBootTestpublic class CategoryServiceTests {@AutowiredICategoryService service;@Test@Sql("classpath:truncate.sql")public void testAddNewSuccessfully() {// 测试数据CategoryAddNewDTO category = new CategoryAddNewDTO();category.setName("大屏智能手机");category.setParentId(0L);category.setIcon("未上传类别图标");category.setKeywords("未设置关键字");category.setSort(88);category.setIsDisplay(1);// 断言不会抛出异常assertDoesNotThrow(() -> {// 执行测试service.addNew(category);});}@Test@Sql({"classpath:truncate.sql", "classpath:insert_data.sql"})public void testAddNewFailBecauseNameDuplicate() {// 测试数据CategoryAddNewDTO category = new CategoryAddNewDTO();category.setName("类别001");// 断言不会抛出异常assertThrows(ServiceException.class, () -> {// 执行测试service.addNew(category);});}@Test@Sql({"classpath:truncate.sql"})public void testAddNewFailBecauseParentNotFound() {// 测试数据CategoryAddNewDTO category = new CategoryAddNewDTO();category.setName("类别001");category.setParentId(-1L);// 断言不会抛出异常assertThrows(ServiceException.class, () -> {// 执行测试service.addNew(category);});}}10. 基于Spring JDBC的事务管理

事务:是一种能够保证同一个业务中多个写(增删改)操作要么全部成功,要么失败的机制!

在业务方法上添加@Transactional即可保证此方法是业务性(要么全部成功,要么全部失败)的。

在Spring JDBC中,处理事务的机制大致是:

开启事务:Begintry {你的业务方法提交:Commit} catch (RuntimeException e) {回滚:Rollback}

所以,为了保证事务性,所有的写操作在执行之后,必须有某个判定为失败的标准,且判断定为失败后,必须抛出RuntimeException或其子孙类异常!

Spring JDBC默认对RuntimeException进行回滚处理,有必要的话,也可以配置为其它异常类型

学习记录,如有侵权请联系删除