外贸领航
首页行业资讯 > 自营型电商有哪些「自营电商是什么意思」

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

来源:互联网 2024-05-18 09:04:04
类别管理--添加类别--持久层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); // 断言查询结果不为null assertNotNull(category); });}@Test@Sql({"classpath:truncate.sql"})public void testGetByNameFailBecauseNotFound() { // 测试数据 String name = "类别999"; // 断言不会抛出异常 assertDoesNotThrow(() -> { // 执行查询 CategorySimpleVO category = mapper.getByName(name); // 断言查询结果为null assertNull(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 { @Override public 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); // 断言查询结果不为null assertNotNull(category); });}@Test@Sql({"classpath:truncate.sql"})public void testGetByIdFailBecauseNotFound() { // 测试数据 Long id = -1L; // 断言不会抛出异常 assertDoesNotThrow(() -> { // 执行查询 CategorySimpleVO category = mapper.getById(id); // 断言查询结果为null assertNull(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); // 断言受影响的行数为1 assertEquals(1, rows); });}@Test@Sql({"classpath:truncate.sql"})public void testUpdateIsParentByIdFailBecauseNotFound() { // 测试数据 Long id = -1L; Integer isParent = 1; // 断言不会抛出异常 assertDoesNotThrow(() -> { // 执行测试 int rows = mapper.updateIsParentById(id, isParent); // 断言受影响的行数为0 assertEquals(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 { @Autowired CategoryMapper categoryMapper; @Override public void addNew(CategoryAddNewDTO categoryAddNewDTO) { // 从参数中取出尝试添加的类别的名称 String name = categoryAddNewDTO.getName(); // 调用categoryMapper.getByName()方法查询 CategorySimpleVO queryResult = categoryMapper.getByName(name); // 判断查询结果是否不为null if (queryResult != null) { // 是:抛出ServiceException throw new ServiceException(); } // 从参数中取出父级类别的id:parentId Long parentId = categoryAddNewDTO.getParentId(); // 判断parentId是否为0,当前尝试新增的类别的depth默认为1 Integer depth = 1; CategorySimpleVO parentCategory = null; if (parentId != 0) { // 否:此次尝试添加的不是一级类别,则应该存在父级类别,调用categoryMapper.getById()方法查询父级类别的信息 parentCategory = categoryMapper.getById(parentId); // -- 判断查询结果是否为null if (parentCategory == null) { // -- 是:抛出ServiceException throw new ServiceException(); } // -- 否:当前depth >>> 父级depth 1 depth = 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 >>> 0 category.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); // 判断返回的受影响的行数是否不为1 if (rows != 1) { // 是:抛出ServiceException throw new ServiceException(); } // 判断父级类别的isParent是否为0 // 以下判断条件有部分多余,但不会报错 if (parentId != 0 && parentCategory != null && parentCategory.getIsParent() == 0) { // 是:调用categoryMapper.updateIsParentById()方法,将父级类别的isParent修改为1,获取返回的受影响的行数 rows = categoryMapper.updateIsParentById(parentId, 1); // 判断返回的受影响的行数是否不为1 if (rows != 1) { // 是:抛出ServiceException throw 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 { @Autowired ICategoryService 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进行回滚处理,有必要的话,也可以配置为其它异常类型

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

郑重声明:本文版权归原作者所有,转载文章仅为传播更多信息之目的,如有侵权行为,请第一时间联系我们修改或删除,多谢。

CopyRight © 外贸领航 2023 All Rights Reserved.