一、工程创建
1.1、搭建多模块
- 父子级多模块整合请参考这篇文章: springcloud核心技术之应用通信(三)
1、项目结构如下所示
- doc:存放需求、技术文档
- config-server:配置中心应用
- eureka-server:服务注册中心应用
- mall-common:存放公共的类、工具、实体
- order-server:订单服务
- product-server:商品服务
- user-server:用户服务
2、订单、商品、用户引入mall-common依赖
- 在订单、商品、用户这三个模块中引入下列依赖:
<dependency>
<groupId>com.mall</groupId>
<artifactId>mall-common</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
3、eureka-server端配置
server:
port: 8761
eureka:
instance:
hostname: localhost # 指定注册中心主机名称
server:
enable-self-preservation: false # 关闭自我保护模式(默认为打开);生产环境不能这样子做
eviction-interval-timer-in-ms: 5000 # 续期时间,即扫描失效服务的间隔时间(缺省为60*1000ms)
client:
register-with-eureka: false # 关闭自我注册功能
fetch-registry: false # 由于自己就是服务器,不需要从服务器获取注册信息
4、config-server配置:
server:
port: 8081
eureka:
client:
service-url:
defaultZone: http://localhost:8761/eureka/
spring:
application:
name: config
5、order-server配置
server:
port: 8082
eureka:
client:
service-url:
defaultZone: http://localhost:8761/eureka/
spring:
application:
name: order
6、product-server配置
server:
port: 8083
eureka:
client:
service-url:
defaultZone: http://localhost:8761/eureka/
spring:
application:
name: product
7、user-server配置
server:
port: 8084
eureka:
client:
service-url:
defaultZone: http://localhost:8761/eureka/
spring:
application:
name: user
8、测试注册中心
- 注册中心测试成功
9、技术选型
- springboot
- springcloud
- jpa
- redis
二、商品模块业务逻辑编写
2.1、项目依赖包引入
1、父工程pom引入的依赖包
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
</dependency>
<!--lombok插件-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<!--fastjson工具-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>${fastjson.version}</version>
</dependency>
<!--集成freemarker模板引擎-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-freemarker</artifactId>
</dependency>
<!--引入redis相关包-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
2、product-server的依赖配置
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<dependency>
<groupId>com.mall</groupId>
<artifactId>mall-common</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
<!--引入jpa依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>${mysql.version}</version>
</dependency>
2.2、dao层业务编写:product-server商品
1、product_info 实体类
- 注意:类名和属性名使用驼峰式命名,jpa会自动与数据库中的product_info,product_id 进行映射
@Data
@Entity
//注意:类名和属性名使用驼峰式命名,会自动与数据库中的product_info,product_id 进行映射
public class ProductInfo {
/**
* 商品ID
*/
@Id
private String productId;
/**
* 商品名字
*/
private String productName;
/**
* 商品单价
*/
private BigDecimal productPrice;
/**
* 商品数量
*/
private Integer productStock;
/**
* 商品状态:1代表正常,0代表下架
*/
private Integer productStatu;
/**
* 商品描述
*/
private String productDescription;
/**
* 商品log
*/
private String productIcon;
/**
* 类目类型
*/
private Integer categoryType;
/**
* 创建时间
*/
private Date creatTime;
/**
* 更新时间
*/
private Date updateTime;
/*
* 是否删除标志:0代表已删除,1代表在用
*/
private Integer deleteStatus;
}
2、product_info的repository接口:根据商品状态和商品删除状态获取所有的商品列表
- 需要继承JpaRepository接口
/** * ProductInfo数据库操作接口 */ public interface ProductInfoRepository extends JpaRepository<ProductInfo,String> { /** * 根据商品状态和商品删除状态获取所有的商品列表 * @param productStatus,deleteStatus * @return */ List<ProductInfo> findAllByProductStatuAndDeleteStatus(int productStatus,int deleteStatus); }
3、给product-server添加热部署
- 详情请参考这篇文章:spring boot核心技术之实现热部署(五)
4、商品数据库业务接口:主要是集成数据的相关操作
/**
* 商品数据库业务接口:主要是集成数据的相关操作
*/
public interface IProductService {
/**
* 获取所有在架商品
*/
List<ProductInfo> getUpAll();
/**
* 获取所有下架的商品
*/
List<ProductInfo> getDownAll();
}
-
实现类:
/** * 商品数据库业务的实现类 */ @Service public class IProductServiceImpl implements IProductService { @Autowired private ProductInfoRepository productInfoRepository; /** * 获取所有在架商品 */ @Override public List<ProductInfo> getUpAll() { return productInfoRepository.findAllByProductStatuAndDeleteStatus(ProductStatusEnum.UP.getCode(), DeleteStatusEnum.ON_USE.getCode()); } /** * 获取所有下架商品 */ @Override public List<ProductInfo> getDownAll() { return productInfoRepository.findAllByProductStatuAndDeleteStatus(ProductStatusEnum.DOWN.getCode(), DeleteStatusEnum.ON_USE.getCode()); } }
2.3、dao层业务编写:product-server商品类目
1、商品类目实体类
/**
* 商品类目实体
*/
@Data
@Entity
public class ProductCategory {
/**
* 类目主键:自增
*/
@Id
@GeneratedValue
private Integer categoryId;
/**
* 类目名字
*/
private String categoryName;
/**
* 类目类型
*/
private Integer categoryType;
/**
* 创建时间
*/
private Date creatTime;
/**
* 更新时间
*/
private Date updateTime;
/*
* 类目是否删除标志:0代表已删除,1代表在用
*/
private Integer deleteStatus;
}
2、ProductCategory 的repository接口:根据多个商品类目类型以及商品类目删除状态获取商品类目列表
/**
* 商品类目数据库操作接口
*/
public interface ProductCategoryRepository extends JpaRepository<ProductCategory,Integer> {
/**
* 根据多个商品类目类型以及商品删除状态获取商品类目列表
* @return
*/
List<ProductCategory> findByCategoryTypeInAndDeleteStatus(List<Integer> categoryTypes,int deleteStatus);
}
3、商品类目数据库业务接口:主要是集成数据库相关操作
/**
* 商品类目数据库业务接口:主要是集成数据库相关操作
*/
public interface IProductCategoryService {
/**
* 根据多个商品类目类型获取商品类目列表
* @return
*/
List<ProductCategory> findListByCategoryTypes(List<Integer> categoryTypes);
}
-
实现类
/** * 商品数据库业务实现类 */ @Service public class IProductCategoryServiceImpl implements IProductCategoryService { @Autowired private ProductCategoryRepository productCategoryRepository; /** * 根据多个商品类目类型获取商品类目列表 * @return */ @Override public List<ProductCategory> findListByCategoryTypes(List<Integer> categoryTypes) { return productCategoryRepository.findByCategoryTypeInAndDeleteStatus(categoryTypes, DeleteStatusEnum.ON_USE.getCode()); } }
2.4、公共VO:cloud-common
1、resultVo:平台返回结果VO
@Data
public class ResultVo<T> {
//返回结果的状态码
@JsonProperty("status")
private Integer status;
//返回结果的信息
@JsonProperty("message")
private String message;
//返回结果的实体主体
@JsonProperty("data")
private T data;
}
2、商品类目Vo:包含它下面的所有在架商品
@Data
public class ProductCategoryVo {
@JsonProperty("name")
private String categoryName;
@JsonProperty("type")
private Integer categoryType;
@JsonProperty("foods")
private List<ProductInfoVo> productInfoVoList;
}
3、商品信息VO:包含商品的基本信息
- @JsonProperty(“id”):是指数据返回成json数据的名称
Data
public class ProductInfoVo{
/**
* 商品id
*/
@JsonProperty("id")
private String productId;
/**
* 商品名字
*/
@JsonProperty("name")
private String productName;
/**
* 商品单价
*/
@JsonProperty("price")
private BigDecimal productPrice;
/**
* 商品描述
*/
@JsonProperty("description")
private String productDescription;
/**
* 商品log
*/
@JsonProperty("icon")
private String productIcon;
}
2.5、自定义异常
1、自定义运行时异常类:继承RuntimeException
@Getter
public class MyException extends RuntimeException{
private int code;
public MyException(String message) {
super(message);
}
public MyException(ResultEnum resultEnum) {
super(resultEnum.getMessage());
this.code = resultEnum.getCode();
}
}
2.6、公共枚举类:cloud-common
1、数据库删除标识枚举类
@Getter
public enum DeleteStatusEnum {
ON_USE(1,"在用"),
HAD_DELETE(0,"已删除")
;
private int code;
private String message;
DeleteStatusEnum(int code, String message) {
this.code = code;
this.message = message;
}
}
2、结果枚举类
@Getter
public enum ResultEnum {
OK(200,"此次请求成功"),
UP_PRODUCT_NOT_EXIST(201,"当前没有任何在架的商品"),
CATEGORY_NOT_EXIST(202,"当前查询的商品类目不存在"),
;
private int code;
private String message;
ResultEnum(int code, String message) {
this.code = code;
this.message = message;
}
}
3、商品上下架状态枚举类
@Getter
public enum ProductStatusEnum {
DOWN(0,"下架"),
UP(1,"在架")
;
private int code;
private String message;
ProductStatusEnum(int code, String message) {
this.code = code;
this.message = message;
}
}
2.7、公共工具类:cloud-common
1、结果实体返回工具类
/**
* 结果实体返回工具类
*/
public class ResultVOUtils {
/**
* 返回访问成功的resultVO实体
* @param object
* @return
*/
public static ResultVo success(Object object){
ResultVo resultVo = new ResultVo();
resultVo.setStatus(ResultEnum.OK.getCode());
resultVo.setMessage(ResultEnum.OK.getMessage());
resultVo.setData(object);
return resultVo;
}
/**
* 请求失败时返回resultVo实体
* @param code
* @param message
* @return
*/
public static ResultVo error(int code,String message){
ResultVo resultVo = new ResultVo();
resultVo.setStatus(code);
resultVo.setMessage(message);
return resultVo;
}
}
2.8、product-server业务编写:查询商品类目列表
1、商品业务接口:主要关注于具体与商品相关的业务逻辑的编写,忽略数据库操作
public interface ProductService {
/**
* 查询商品类目Vo:包含所有已存在的在架的商品
* @return
*/
List<ProductCategoryVo> getUpAllProductCategoryVo();
}
2、接口API
- 基本结构就是:返回所有的商品类目及其在架的所有商品
3、商品业务接口实现类:
- 四步走:
1、查询所有在架商品
2、获取所有的类目列表
3、根据类目列表获取类目数据
4、拼接构造数据
@Service
public class ProductServiceImpl implements ProductService {
@Autowired
IProductService iProductService;
@Autowired
IProductCategoryService iProductCategoryService;
/**
* 查询商品类目Vo:包含所有已存在的在架的商品
* @return
*/
@Override
public List<ProductCategoryVo> getUpAllProductCategoryVo() {
List<ProductCategoryVo> productCategoryVoList = new ArrayList<>();
//1、查询所有在架商品
List<ProductInfo> productInfoList = iProductService.getUpAll();
if(productInfoList.size() == 0){
throw new MyException(ResultEnum.UP_PRODUCT_NOT_EXIST);
}
//2、获取所有的类目列表
List<Integer> categoryTypeList = new ArrayList<>();
Set<Integer> categoryTypeSet = new HashSet<>();
for (ProductInfo productInfo : productInfoList) {
//使用set对categoryType去重
categoryTypeSet.add(productInfo.getCategoryType());
}
Iterator<Integer> categoryTypeIterator = categoryTypeSet.iterator();
while (categoryTypeIterator.hasNext()){
categoryTypeList.add(categoryTypeIterator.next());
}
//3、根据类目列表获取类目数据
List<ProductCategory> productCategoryList = iProductCategoryService.findListByCategoryTypes(categoryTypeList);
if(productCategoryList.size() == 0){
throw new MyException(ResultEnum.CATEGORY_NOT_EXIST);
}
//4、拼接构造数据
for (ProductCategory productCategory : productCategoryList) {
ProductCategoryVo productCategoryVo = new ProductCategoryVo();
BeanUtils.copyProperties(productCategory,productCategoryVo);
List<ProductInfoVo> productInfoVoList = new ArrayList<>();
for (ProductInfo productInfo : productInfoList) {
if (productInfo.getCategoryType() == productCategoryVo.getCategoryType()){
ProductInfoVo productInfoVo = new ProductInfoVo();
BeanUtils.copyProperties(productInfo,productInfoVo);
productInfoVoList.add(productInfoVo);
}
}
productCategoryVo.setProductInfoVoList(productInfoVoList);
productCategoryVoList.add(productCategoryVo);
}
return productCategoryVoList;
}
}
2.9、商品模块MVC
1、获取商品类目列表:包含所有在架的商品信息
/**
* 商品信息操作类
*/
@RestController
@RequestMapping("/product")
public class ProductController {
@Autowired
ProductService productService;
@GetMapping("/list")
public ResultVo getProductList(){
ResultVo resultVo = new ResultVo();
try {
List<ProductCategoryVo> productCategoryVoList = productService.getUpAllProductCategoryVo();
resultVo = ResultVOUtils.success(productCategoryVoList);
}catch (MyException myException){
resultVo = ResultVOUtils.error(myException.getCode(),myException.getMessage());
}
return resultVo;
}
}