注意本项目完全不用前端接口使用Apifox进行调用1. 三级分类编写代码编写略2. 跨域问题处理2.1 解决方案一使用nginx部署为同一域通过nginx代理请求从头到尾都是nginx的请求地址2.2 解决方案二配置当次请求允许跨域解决方法在网关中定义“GulimallCorsConfiguration”类该类用来做过滤允许所有的请求跨域。ConfigurationpublicclassGulimallCorsConfiguration{BeanpublicCorsWebFiltercorsWebFilter(){UrlBasedCorsConfigurationSourcesourcenewUrlBasedCorsConfigurationSource();CorsConfigurationcorsConfigurationnewCorsConfiguration();corsConfiguration.addAllowedHeader(*);corsConfiguration.addAllowedMethod(*);corsConfiguration.addAllowedOrigin(*);corsConfiguration.setAllowCredentials(true);source.registerCorsConfiguration(/**,corsConfiguration);returnnewCorsWebFilter(source);}}3. 经过网关的负载接口调用在gateway项目中添加路由配置-id:product_routeuri:lb://mall-productpredicates:-Path/api/product/**filters:-RewritePath/api/(?segment.*),/${segment}调用商品类型列表http://localhost:88/api/product/category/list/tree。可以看到返回值4. 配置mybatis逻辑删除添加配置mybatis3.3之后的版本已经不需要添加逻辑删除配置了mybatis-plus:mapper-locations:classpath:/mapper/**/*.xmlglobal-config:db-config:id-type:autologic-delete-value:1#逻辑删除的值为1logic-not-delete-value:0#无逻辑删除的值0在具体的entity中配置逻辑删除字段属性publicclassCategoryEntityimplementsSerializable{/** * 是否显示[0-不显示1显示] */TableLogic(value1,delval0)privateIntegershowStatus;//省略其他属性.........}设置日志级别打印SQL语句logging:level:root:debugapifox执行结果5. OSS文件上传华为云、阿里云、腾讯云的都可以。关于购买、配置不多赘述。5.1 腾讯云COS基本使用具体的使用可见腾讯云COS官方文档5.1.1 术语5.1.2 Maven安装dependencygroupIdcom.qcloud/groupIdartifactIdcos_api/artifactIdversion5.6.227/version/dependency5.1.3 demo编写TestpublicvoidtestUpload(){StringsecretIdid;StringsecretKeykey;StringbucketNamemall-appId;Stringregionap-shanghai;// 初始化用户身份信息(secretId, secretKey)COSCredentialscrednewBasicCOSCredentials(secretId,secretKey);// 设置 bucket 的区域, COS 地域的简称请参照 https://cloud.tencent.com/document/product/436/6224ClientConfigclientConfignewClientConfig(newRegion(region));// 生成 cos 客户端COSClientcosClientnewCOSClient(cred,clientConfig);Stringkeyabc/abc.txt;StringlocalPath/xx/product/abc.txt;PutObjectRequestputObjectRequestnewPutObjectRequest(bucketName,key,newFile(localPath));try{PutObjectResultputObjectResultcosClient.putObject(putObjectRequest);System.out.println(putObjectResult.getRequestId());}catch(CosServiceExceptioncse){cse.printStackTrace();}catch(CosClientExceptioncce){cce.printStackTrace();}}5.1.4 结果查看5.2 阿里云OSS基本使用官方文档5.2.1 maven安装dependencygroupIdcom.aliyun.oss/groupIdartifactIdaliyun-sdk-oss/artifactIdversion3.18.4/version/dependency5.2.2 代码编写// yourEndpoint填写Bucket所在地域对应的Endpoint。以华东1杭州为例Endpoint填写为https://oss-cn-hangzhou.aliyuncs.com。StringendpointyourEndpoint;// 阿里云账号AccessKey拥有所有API的访问权限风险很高。强烈建议您创建并使用RAM用户进行API访问或日常运维请登录RAM控制台创建RAM用户。StringaccessKeyIdyourAccessKeyId;StringaccessKeySecretyourAccessKeySecret;// 创建OSSClient实例。OSSossClientnewOSSClientBuilder().build(endpoint,accessKeyId,accessKeySecret);// 创建PutObjectRequest对象。// 依次填写Bucket名称例如examplebucket、Object完整路径例如exampledir/exampleobject.txt和本地文件的完整路径。Object完整路径中不能包含Bucket名称。// 如果未指定本地路径则默认从示例程序所属项目对应本地路径中上传文件。PutObjectRequestputObjectRequestnewPutObjectRequest(examplebucket,exampledir/exampleobject.txt,newFile(D:\\localpath\\examplefile.txt));// 如果需要上传时设置存储类型和访问权限请参考以下示例代码。// ObjectMetadata metadata new ObjectMetadata();// metadata.setHeader(OSSHeaders.OSS_STORAGE_CLASS, StorageClass.Standard.toString());// metadata.setObjectAcl(CannedAccessControlList.Private);// putObjectRequest.setMetadata(metadata);// 上传文件。ossClient.putObject(putObjectRequest);// 关闭OSSClient。ossClient.shutdown();5.3 最简单的使用SpringCloud Alibaba OSS注意springboot新版本可能不支持官方文档5.3.1 maven安装dependencygroupIdcom.alibaba.cloud/groupIdartifactIdspring-cloud-starter-alicloud-oss/artifactIdversion2.2.0.RELEASE/versionscopecompile/scope/dependency5.3.2 配置连接alibaba:alicloud:access-key:xxxsecret-key:xxxoss:endpoint:oss-cn-hangzhou.aliyuncs.com5.3.3 直接使用Testvoidtest1()throwsFileNotFoundException{// 上传文件流。InputStreaminputStreamnewFileInputStream(/Users/haixinyu/Documents/IdeaProjects/study_mall/mall-product/src/test/java/com/messi/mall/product/abc.txt);ossClient.putObject(fxjs-test2023,321.txt,inputStream);// 关闭OSSClient。ossClient.shutdown();System.out.println(上传完成...);}6. 入参校验6.1 基本使用如果你的springboot版本没有默认引入就导入依赖!--jsr3参数校验器--dependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-validation/artifactId/dependency里面依赖了hibernate-validator 在非空处理方式上提供了NotNullNotBlank和NotEmpty。在实体类的属性上使用如上的注解DataTableName(pms_brand)publicclassBrandEntityimplementsSerializable{privatestaticfinallongserialVersionUID1L;/** * 品牌id */TableIdprivateLongbrandId;/** * 品牌名 */NotBlankprivateStringname;/** * 品牌logo地址 */privateStringlogo;/** * 介绍 */privateStringdescript;/** * 显示状态[0-不显示1-显示] */NotNullprivateIntegershowStatus;/** * 检索首字母 */NotEmptyprivateStringfirstLetter;/** * 排序 */NotNullMin(0)privateIntegersort;}controller中加校验注解Valid开启校验RequestMapping(/save)publicRsave(RequestBodyValidBrandEntitybrand){brandService.save(brand);returnR.ok();}设置参数校验失败返回信息NotBlank(message品牌名必须非空)privateStringname;6.2 配置统一异常处理可以使用SpringMvc所提供的ControllerAdvice通过“basePackages”能够说明处理哪些路径下的异常。在product.exception.AchangExceptionControllerAdvice编写Slf4jRestControllerAdvice(basePackagescom.messi.mall.product)publicclassAchangExceptionControllerAdvice{ExceptionHandler(valueException.class)// 也可以返回ModelAndViewpublicRhandleValidException(MethodArgumentNotValidExceptionexception){MapString,StringmapnewHashMap();// 获取数据校验的错误结果BindingResultbindingResultexception.getBindingResult();bindingResult.getFieldErrors().forEach(fieldError-{StringmessagefieldError.getDefaultMessage();StringfieldfieldError.getField();map.put(field,message);});log.error(数据校验出现问题{},异常类型{},exception.getMessage(),exception.getClass());returnR.error(400,数据校验出现问题).put(data,map);}}测试http://localhost:88/api/product/brand/save6.3 分组校验规则给校验注解标注上groups指定什么业务情况下才需要进行校验。groups里面的内容要以接口的形式显示出来。如指定在更新和添加的时候都需要进行校验。但是新增时不需要带id修改时必须带id。在common.vail添加接口//更新校验publicinterfaceUpdateVail{}//新增校验publicinterfaceAddVail{}在实例类上添加groupsNotNull(message修改必须定制品牌id,groups{UpdateVailGroup.class})Null(message新增不能指定id,groups{AddVailGroup.class})privateLongbrandId;具体方法添加validated注意默认情况下在分组校验情况下没有指定指定分组的校验注解将不会生效它只会在不分组的情况下生效6.4 自定义校验注解场景要校验showStatus的01状态可以用正则但我们可以利用其他方式解决复杂场景。添加依赖dependencygroupIdjavax.validation/groupIdartifactIdvalidation-api/artifactIdversion2.0.1.Final/version/dependency编写自定义的校验注解/** * 自定义校验注解 */DocumentedConstraint(validatedBy{ListValueConstraintValidator.class})Target({METHOD,FIELD,ANNOTATION_TYPE,CONSTRUCTOR,PARAMETER,TYPE_USE})Retention(RUNTIME)publicinterfaceListValue{// 使用该属性去Validation.properties中取Stringmessage()default{com.atguigu.common.valid.ListValue.message};Class?[]groups()default{};Class?extendsPayload[]payload()default{};int[]value()default{};//传入可通过校验的值[]}自定义校验器/** * 自定义校验器 */publicclassListValueConstraintValidatorimplementsConstraintValidatorListValue,Integer{//泛型左边自定义校验注解泛型右边校验的类型privateSetIntegersetnewHashSet();Overridepublicvoidinitialize(ListValueconstraintAnnotation){int[]valueconstraintAnnotation.value();//获取可通过的值for(inti:value){set.add(i);}}Override//左侧传入需要校验的值publicbooleanisValid(Integervalue,ConstraintValidatorContextcontext){returnset.contains(value);}}关联校验器和校验注解一个校验注解可以匹配多个校验器DocumentedConstraint(validatedBy{ListValueConstraintValidator.class})// 使用自定义校验器Target({METHOD,FIELD,ANNOTATION_TYPE,CONSTRUCTOR,PARAMETER,TYPE_USE})Retention(RUNTIME)publicinterfaceListValue{Stringmessage()default{com.athl,common.valid.ListValue.message};Class?[]groups()default{};Class?extendsPayload[]payload()default{};int[]values();}具体使用/** * 显示状态[0-不显示1-显示] * 标识只能接受0,1其他值都不能通过校验 */ListValue(value{0,1},groups{AddGroup.class})privateIntegershowStatus;7. 统一异常配置之前使用的异常处理是我们手动随意设置的状态码。然而正规开发过程中错误状态码有着严格的定义规则。为了定义这些错误状态码我们可以单独定义一个常量类用来存储这些错误状态码在common.exception中添加异常常量/** * 错误码和错误信息定义类 * 1. 错误码定义规则为5为数字 * 2. 前两位表示业务场景最后三位表示错误码。例如100001。10:通用 001:系统未知异常 * 3. 维护错误码后需要维护错误描述将他们定义为枚举形式 * 错误码列表 * 10: 通用 * 001参数格式校验 * 11: 商品 * 12: 订单 * 13: 购物车 * 14: 物流 */publicenumBizCodeEnum{UNKNOW_EXEPTION(10000,系统未知异常),VALID_EXCEPTION(10001,参数格式校验失败);privateintcode;privateStringmsg;BizCodeEnum(intcode,Stringmsg){this.codecode;this.msgmsg;}publicintgetCode(){returncode;}publicStringgetMsg(){returnmsg;}}8. SPU和SKUSPUstandard product unit(标准化产品单元)是商品信息聚合的最小单位是一组可复用、易检索的标准化信息的集合该集合描述了一个产品的特性。如iphoneX是SPU同一个SPU拥有的特性叫基本属性。如机身长度这个是手机共用的属性SKUstock keeping unit(库存量单位)库存进出计量的基本单元可以是件/盒/托盘等单位。SKU是对于大型连锁超市DC配送中心物流管理的一个必要的方法。现在已经被引申为产品统一编号的简称每种产品对应有唯一的SKU号。如iphoneX 64G 黑色 是SKU而每款手机的属性值不同能决定库存量的叫销售属性。如颜色、内存基本属性[规格参数]与销售属性 每个分类下的商品共享规格参数与销售属性。只是有些商品不一定要用这个分类下全部的属性属性是以三级分类组织起来的 规格参数中有些是可以提供检索的 规格参数也是基本属性他们具有自己的分组 属性的分组也是以三级分类组织起来的 属性名确定的但是值是每一个商品不同来决定的8.1 表的建设8.1.1 分类属性关联商品属性表其中catelog_id代表所属分类属性分组关联表属性分组表8.1.2 SPU-SKU-属性关联荣耀V20有两个属性网络和像素但是这两个属性的spu是同一个代表是同款手机。sku表里保存spu是同一手机sku可能相同可能不同相同代表是同一款不同代表是不同款。9. 配置不为空不返回// children字段不为空的时候才返回这个数据JsonInclude(JsonInclude.Include.NON_EMPTY)TableField(existfalse)privateListCategoryEntitychildren;10. 添加mybatisplus分页配置在product.config添加BeanpublicMybatisPlusInterceptormybatisPlusInterceptor(){MybatisPlusInterceptorinterceptornewMybatisPlusInterceptor();interceptor.addInnerInterceptor(newPaginationInnerInterceptor(DbType.MYSQL));returninterceptor;}11. POJO主要用处就是接收前端传过来的参数和返回参数给前端VOPO持久对象PO就是对应数据库中某个表中的一条记录多个记录可以用PO的集合。PO中应该不包含任何对数据的操作。DODomain 0bject)领域对象就是从现实世界中推象出来的有形或无形的业务实体。TO(Transfer 0bject)数据传输对象传输的对象 不同的应用程序之间传输的对象。微服DTO(Data Transfer Obiect)数据传输对象概念来源于J2EE的设汁模式原来的目的是为了EJB的分布式应用握供粗粒度的数据实体以减少分布式调用的次数从而握分布式调用的性能和降低网络负载但在这里泛指用于示层与服务层之间的数据传输对象。VO(value object)值对象通常用干业务层之闾的数据传递和PO一样也是仅仅包含数据而已。但应是抽象出的业务对象可以和表对应也可以不这根据业务的需要。用new关韃字创建由GC回收的Viewobject视图对象接受页面传递来的对象封装对象将业务处理完成的对象封装成页面要用的数据BO(business object)业务对象从业务模型的度看见IJML元#领嵫模型的领嵫对象。封装业务逻辑的java对象通过用DAO方法结合PO,VO进行业务操作。businessobject:业务对象主要作用是把业务逻辑封装为一个对苤。这个对象可以包括一个或多个其它的对彖。比如一个简历有教育经历、工怍经历、社会关系等等。我们可以把教育经历对应一个PO工作经历12.设置日期数据规则spring:jackson:date-format:yyyy-MM-dd HH:mm:sstime-zone:GMT813. IDEA一键启动项目设置
2026版商城项目--基础篇(二)
发布时间:2026/6/5 7:23:40
注意本项目完全不用前端接口使用Apifox进行调用1. 三级分类编写代码编写略2. 跨域问题处理2.1 解决方案一使用nginx部署为同一域通过nginx代理请求从头到尾都是nginx的请求地址2.2 解决方案二配置当次请求允许跨域解决方法在网关中定义“GulimallCorsConfiguration”类该类用来做过滤允许所有的请求跨域。ConfigurationpublicclassGulimallCorsConfiguration{BeanpublicCorsWebFiltercorsWebFilter(){UrlBasedCorsConfigurationSourcesourcenewUrlBasedCorsConfigurationSource();CorsConfigurationcorsConfigurationnewCorsConfiguration();corsConfiguration.addAllowedHeader(*);corsConfiguration.addAllowedMethod(*);corsConfiguration.addAllowedOrigin(*);corsConfiguration.setAllowCredentials(true);source.registerCorsConfiguration(/**,corsConfiguration);returnnewCorsWebFilter(source);}}3. 经过网关的负载接口调用在gateway项目中添加路由配置-id:product_routeuri:lb://mall-productpredicates:-Path/api/product/**filters:-RewritePath/api/(?segment.*),/${segment}调用商品类型列表http://localhost:88/api/product/category/list/tree。可以看到返回值4. 配置mybatis逻辑删除添加配置mybatis3.3之后的版本已经不需要添加逻辑删除配置了mybatis-plus:mapper-locations:classpath:/mapper/**/*.xmlglobal-config:db-config:id-type:autologic-delete-value:1#逻辑删除的值为1logic-not-delete-value:0#无逻辑删除的值0在具体的entity中配置逻辑删除字段属性publicclassCategoryEntityimplementsSerializable{/** * 是否显示[0-不显示1显示] */TableLogic(value1,delval0)privateIntegershowStatus;//省略其他属性.........}设置日志级别打印SQL语句logging:level:root:debugapifox执行结果5. OSS文件上传华为云、阿里云、腾讯云的都可以。关于购买、配置不多赘述。5.1 腾讯云COS基本使用具体的使用可见腾讯云COS官方文档5.1.1 术语5.1.2 Maven安装dependencygroupIdcom.qcloud/groupIdartifactIdcos_api/artifactIdversion5.6.227/version/dependency5.1.3 demo编写TestpublicvoidtestUpload(){StringsecretIdid;StringsecretKeykey;StringbucketNamemall-appId;Stringregionap-shanghai;// 初始化用户身份信息(secretId, secretKey)COSCredentialscrednewBasicCOSCredentials(secretId,secretKey);// 设置 bucket 的区域, COS 地域的简称请参照 https://cloud.tencent.com/document/product/436/6224ClientConfigclientConfignewClientConfig(newRegion(region));// 生成 cos 客户端COSClientcosClientnewCOSClient(cred,clientConfig);Stringkeyabc/abc.txt;StringlocalPath/xx/product/abc.txt;PutObjectRequestputObjectRequestnewPutObjectRequest(bucketName,key,newFile(localPath));try{PutObjectResultputObjectResultcosClient.putObject(putObjectRequest);System.out.println(putObjectResult.getRequestId());}catch(CosServiceExceptioncse){cse.printStackTrace();}catch(CosClientExceptioncce){cce.printStackTrace();}}5.1.4 结果查看5.2 阿里云OSS基本使用官方文档5.2.1 maven安装dependencygroupIdcom.aliyun.oss/groupIdartifactIdaliyun-sdk-oss/artifactIdversion3.18.4/version/dependency5.2.2 代码编写// yourEndpoint填写Bucket所在地域对应的Endpoint。以华东1杭州为例Endpoint填写为https://oss-cn-hangzhou.aliyuncs.com。StringendpointyourEndpoint;// 阿里云账号AccessKey拥有所有API的访问权限风险很高。强烈建议您创建并使用RAM用户进行API访问或日常运维请登录RAM控制台创建RAM用户。StringaccessKeyIdyourAccessKeyId;StringaccessKeySecretyourAccessKeySecret;// 创建OSSClient实例。OSSossClientnewOSSClientBuilder().build(endpoint,accessKeyId,accessKeySecret);// 创建PutObjectRequest对象。// 依次填写Bucket名称例如examplebucket、Object完整路径例如exampledir/exampleobject.txt和本地文件的完整路径。Object完整路径中不能包含Bucket名称。// 如果未指定本地路径则默认从示例程序所属项目对应本地路径中上传文件。PutObjectRequestputObjectRequestnewPutObjectRequest(examplebucket,exampledir/exampleobject.txt,newFile(D:\\localpath\\examplefile.txt));// 如果需要上传时设置存储类型和访问权限请参考以下示例代码。// ObjectMetadata metadata new ObjectMetadata();// metadata.setHeader(OSSHeaders.OSS_STORAGE_CLASS, StorageClass.Standard.toString());// metadata.setObjectAcl(CannedAccessControlList.Private);// putObjectRequest.setMetadata(metadata);// 上传文件。ossClient.putObject(putObjectRequest);// 关闭OSSClient。ossClient.shutdown();5.3 最简单的使用SpringCloud Alibaba OSS注意springboot新版本可能不支持官方文档5.3.1 maven安装dependencygroupIdcom.alibaba.cloud/groupIdartifactIdspring-cloud-starter-alicloud-oss/artifactIdversion2.2.0.RELEASE/versionscopecompile/scope/dependency5.3.2 配置连接alibaba:alicloud:access-key:xxxsecret-key:xxxoss:endpoint:oss-cn-hangzhou.aliyuncs.com5.3.3 直接使用Testvoidtest1()throwsFileNotFoundException{// 上传文件流。InputStreaminputStreamnewFileInputStream(/Users/haixinyu/Documents/IdeaProjects/study_mall/mall-product/src/test/java/com/messi/mall/product/abc.txt);ossClient.putObject(fxjs-test2023,321.txt,inputStream);// 关闭OSSClient。ossClient.shutdown();System.out.println(上传完成...);}6. 入参校验6.1 基本使用如果你的springboot版本没有默认引入就导入依赖!--jsr3参数校验器--dependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-validation/artifactId/dependency里面依赖了hibernate-validator 在非空处理方式上提供了NotNullNotBlank和NotEmpty。在实体类的属性上使用如上的注解DataTableName(pms_brand)publicclassBrandEntityimplementsSerializable{privatestaticfinallongserialVersionUID1L;/** * 品牌id */TableIdprivateLongbrandId;/** * 品牌名 */NotBlankprivateStringname;/** * 品牌logo地址 */privateStringlogo;/** * 介绍 */privateStringdescript;/** * 显示状态[0-不显示1-显示] */NotNullprivateIntegershowStatus;/** * 检索首字母 */NotEmptyprivateStringfirstLetter;/** * 排序 */NotNullMin(0)privateIntegersort;}controller中加校验注解Valid开启校验RequestMapping(/save)publicRsave(RequestBodyValidBrandEntitybrand){brandService.save(brand);returnR.ok();}设置参数校验失败返回信息NotBlank(message品牌名必须非空)privateStringname;6.2 配置统一异常处理可以使用SpringMvc所提供的ControllerAdvice通过“basePackages”能够说明处理哪些路径下的异常。在product.exception.AchangExceptionControllerAdvice编写Slf4jRestControllerAdvice(basePackagescom.messi.mall.product)publicclassAchangExceptionControllerAdvice{ExceptionHandler(valueException.class)// 也可以返回ModelAndViewpublicRhandleValidException(MethodArgumentNotValidExceptionexception){MapString,StringmapnewHashMap();// 获取数据校验的错误结果BindingResultbindingResultexception.getBindingResult();bindingResult.getFieldErrors().forEach(fieldError-{StringmessagefieldError.getDefaultMessage();StringfieldfieldError.getField();map.put(field,message);});log.error(数据校验出现问题{},异常类型{},exception.getMessage(),exception.getClass());returnR.error(400,数据校验出现问题).put(data,map);}}测试http://localhost:88/api/product/brand/save6.3 分组校验规则给校验注解标注上groups指定什么业务情况下才需要进行校验。groups里面的内容要以接口的形式显示出来。如指定在更新和添加的时候都需要进行校验。但是新增时不需要带id修改时必须带id。在common.vail添加接口//更新校验publicinterfaceUpdateVail{}//新增校验publicinterfaceAddVail{}在实例类上添加groupsNotNull(message修改必须定制品牌id,groups{UpdateVailGroup.class})Null(message新增不能指定id,groups{AddVailGroup.class})privateLongbrandId;具体方法添加validated注意默认情况下在分组校验情况下没有指定指定分组的校验注解将不会生效它只会在不分组的情况下生效6.4 自定义校验注解场景要校验showStatus的01状态可以用正则但我们可以利用其他方式解决复杂场景。添加依赖dependencygroupIdjavax.validation/groupIdartifactIdvalidation-api/artifactIdversion2.0.1.Final/version/dependency编写自定义的校验注解/** * 自定义校验注解 */DocumentedConstraint(validatedBy{ListValueConstraintValidator.class})Target({METHOD,FIELD,ANNOTATION_TYPE,CONSTRUCTOR,PARAMETER,TYPE_USE})Retention(RUNTIME)publicinterfaceListValue{// 使用该属性去Validation.properties中取Stringmessage()default{com.atguigu.common.valid.ListValue.message};Class?[]groups()default{};Class?extendsPayload[]payload()default{};int[]value()default{};//传入可通过校验的值[]}自定义校验器/** * 自定义校验器 */publicclassListValueConstraintValidatorimplementsConstraintValidatorListValue,Integer{//泛型左边自定义校验注解泛型右边校验的类型privateSetIntegersetnewHashSet();Overridepublicvoidinitialize(ListValueconstraintAnnotation){int[]valueconstraintAnnotation.value();//获取可通过的值for(inti:value){set.add(i);}}Override//左侧传入需要校验的值publicbooleanisValid(Integervalue,ConstraintValidatorContextcontext){returnset.contains(value);}}关联校验器和校验注解一个校验注解可以匹配多个校验器DocumentedConstraint(validatedBy{ListValueConstraintValidator.class})// 使用自定义校验器Target({METHOD,FIELD,ANNOTATION_TYPE,CONSTRUCTOR,PARAMETER,TYPE_USE})Retention(RUNTIME)publicinterfaceListValue{Stringmessage()default{com.athl,common.valid.ListValue.message};Class?[]groups()default{};Class?extendsPayload[]payload()default{};int[]values();}具体使用/** * 显示状态[0-不显示1-显示] * 标识只能接受0,1其他值都不能通过校验 */ListValue(value{0,1},groups{AddGroup.class})privateIntegershowStatus;7. 统一异常配置之前使用的异常处理是我们手动随意设置的状态码。然而正规开发过程中错误状态码有着严格的定义规则。为了定义这些错误状态码我们可以单独定义一个常量类用来存储这些错误状态码在common.exception中添加异常常量/** * 错误码和错误信息定义类 * 1. 错误码定义规则为5为数字 * 2. 前两位表示业务场景最后三位表示错误码。例如100001。10:通用 001:系统未知异常 * 3. 维护错误码后需要维护错误描述将他们定义为枚举形式 * 错误码列表 * 10: 通用 * 001参数格式校验 * 11: 商品 * 12: 订单 * 13: 购物车 * 14: 物流 */publicenumBizCodeEnum{UNKNOW_EXEPTION(10000,系统未知异常),VALID_EXCEPTION(10001,参数格式校验失败);privateintcode;privateStringmsg;BizCodeEnum(intcode,Stringmsg){this.codecode;this.msgmsg;}publicintgetCode(){returncode;}publicStringgetMsg(){returnmsg;}}8. SPU和SKUSPUstandard product unit(标准化产品单元)是商品信息聚合的最小单位是一组可复用、易检索的标准化信息的集合该集合描述了一个产品的特性。如iphoneX是SPU同一个SPU拥有的特性叫基本属性。如机身长度这个是手机共用的属性SKUstock keeping unit(库存量单位)库存进出计量的基本单元可以是件/盒/托盘等单位。SKU是对于大型连锁超市DC配送中心物流管理的一个必要的方法。现在已经被引申为产品统一编号的简称每种产品对应有唯一的SKU号。如iphoneX 64G 黑色 是SKU而每款手机的属性值不同能决定库存量的叫销售属性。如颜色、内存基本属性[规格参数]与销售属性 每个分类下的商品共享规格参数与销售属性。只是有些商品不一定要用这个分类下全部的属性属性是以三级分类组织起来的 规格参数中有些是可以提供检索的 规格参数也是基本属性他们具有自己的分组 属性的分组也是以三级分类组织起来的 属性名确定的但是值是每一个商品不同来决定的8.1 表的建设8.1.1 分类属性关联商品属性表其中catelog_id代表所属分类属性分组关联表属性分组表8.1.2 SPU-SKU-属性关联荣耀V20有两个属性网络和像素但是这两个属性的spu是同一个代表是同款手机。sku表里保存spu是同一手机sku可能相同可能不同相同代表是同一款不同代表是不同款。9. 配置不为空不返回// children字段不为空的时候才返回这个数据JsonInclude(JsonInclude.Include.NON_EMPTY)TableField(existfalse)privateListCategoryEntitychildren;10. 添加mybatisplus分页配置在product.config添加BeanpublicMybatisPlusInterceptormybatisPlusInterceptor(){MybatisPlusInterceptorinterceptornewMybatisPlusInterceptor();interceptor.addInnerInterceptor(newPaginationInnerInterceptor(DbType.MYSQL));returninterceptor;}11. POJO主要用处就是接收前端传过来的参数和返回参数给前端VOPO持久对象PO就是对应数据库中某个表中的一条记录多个记录可以用PO的集合。PO中应该不包含任何对数据的操作。DODomain 0bject)领域对象就是从现实世界中推象出来的有形或无形的业务实体。TO(Transfer 0bject)数据传输对象传输的对象 不同的应用程序之间传输的对象。微服DTO(Data Transfer Obiect)数据传输对象概念来源于J2EE的设汁模式原来的目的是为了EJB的分布式应用握供粗粒度的数据实体以减少分布式调用的次数从而握分布式调用的性能和降低网络负载但在这里泛指用于示层与服务层之间的数据传输对象。VO(value object)值对象通常用干业务层之闾的数据传递和PO一样也是仅仅包含数据而已。但应是抽象出的业务对象可以和表对应也可以不这根据业务的需要。用new关韃字创建由GC回收的Viewobject视图对象接受页面传递来的对象封装对象将业务处理完成的对象封装成页面要用的数据BO(business object)业务对象从业务模型的度看见IJML元#领嵫模型的领嵫对象。封装业务逻辑的java对象通过用DAO方法结合PO,VO进行业务操作。businessobject:业务对象主要作用是把业务逻辑封装为一个对苤。这个对象可以包括一个或多个其它的对彖。比如一个简历有教育经历、工怍经历、社会关系等等。我们可以把教育经历对应一个PO工作经历12.设置日期数据规则spring:jackson:date-format:yyyy-MM-dd HH:mm:sstime-zone:GMT813. IDEA一键启动项目设置