谷粒商城--分布式基础篇P28~P101(完结)
阅读原文时间:2021年07月25日阅读:1

谷粒商城--分布式基础篇P28~P101(完结)

前面1-27节主要是环境配置特别难,后面的28~101节主要是前端编写的代码较多以及后台的CRUD操作比较多。因为内容很多,所以我是根据自己想学的点进行相应学习,故前端我直接跳过了,前端代码用的别人完整的。主要学习点集中在后台三级目录、库表设计、OSS以及代码规范的相关学习了。

Fork代码:https://gitee.com/empirefree/GuliMall

(个人建议学后端的只用renren-fast-vue前端代码,后端代码除开CRUD的操作,其余都自己敲)






@

目录

1.商品服务

1.1 商品树形图(Lambda8代码实现)
  • 排序类:id,parentId,sort(权重)、List(自定义添加)

  • 组装逻辑:先获取所有商品,然后再获取第一级商品,递归并排序找到所有子商品。代码如下

1.2 网关配置

​ 前端为了统一管理,全部向网关发起访问。所以验证码、后续数据获取端口都需要修改。修改逻辑如下:

  1. 原始验证码地址:http://localhost:8080/renren-fast/captcha.jpg
  2. 前端发起访问的地址:http://localhost:88/api/captcha.jpg
  3. 经过Gateway从nacos映射与路径转换:http://localhost:8080/renrenfast/captcha.jpg(前面的8080路径是从nacos中找到的renrenfast端口,后面路径是gateway转换的路径)

GateWay请求拦截与转换

spring:
  cloud:
    gateway:
      routes:
        - id: product_route
          uri: lb://gulimall-product
          predicates:
            - Path=/api/product/**
          filters:
            - RewritePath=/api/(?<segment>.*),/$\{segment}

        - id: third_party_route
          uri: lb://gulimall-third-party
          predicates:
            - Path=/api/thirdparty/**
          filters:
            - RewritePath=/api/thirdparty/(?<segment>.*),/thirdparty/$\{segment}

        - id: member_route
          uri: lb://gulimall-member
          predicates:
            - Path=/api/member/**
          filters:
            - RewritePath=/api/(?<segment>.*),/$\{segment}

        - id: ware_route
          uri: lb://gulimall-ware
          predicates:
            - Path=/api/ware/**
          filters:
            - RewritePath=/api/(?<segment>.*),/$\{segment}

        - id: admin_route
          uri: lb://renren-fast
          predicates:
            - Path=/api/**
          filters:
            - RewritePath=/api/(?<segment>.*),/renren-fast/$\{segment}
1.3 阿里云oss

​ 官网给的oss的dependency无法导入,应该使用如下dependency

        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alicloud-oss</artifactId>
        </dependency>

​ 另外,共有2种上传文件方式

  1. client->server->oss(不推荐但很常见):服务器处理上传
  2. server返回policy
1.4 获取商品id完整路径

​ 针对上面给的商品树,给出某个id获取根id到这个id路径

2.代码规范环境

JSR303、全局异常处理、全局统一返回、全局跨域处理、VO与TO与PO划分

2.1.JSR303

​ 就是入参的校验注解,极大简化了对于前端入参的代码判断

    /**
     * 为空的数据就不查询了
     */
    @JsonInclude(JsonInclude.Include.NON_EMPTY)
    /**
     * 表中不存在
     */
    @TableField(exist = false)

2.2.全局异常处理与统一返回

​ 在正常前后端分离项目中,前端对于参数的要求有个规范,所以无论正确还是错误代码,后端都需要有个全局参数的返回

package com.empirefree.gulimall.product.exception;

import com.empirefree.common.exception.BizCodeEnum;
import com.empirefree.common.utils.R;
import lombok.extern.slf4j.Slf4j;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.bind.support.WebExchangeBindException;

import java.util.HashMap;
import java.util.Map;

/**
 * <p>Title: MallExceptionControllerAdvice</p>
 * Description:集中处理所有异常
 * date:2020/6/1 21:19
 */
@Slf4j
@RestControllerAdvice(basePackages = "com.empirefree.gulimall.product.controller")
public class MallExceptionControllerAdvice {

    @ExceptionHandler(value = {WebExchangeBindException.class})
    public R handleVaildException(WebExchangeBindException e) {
        log.error("数据校验出现问题{},异常类型:{}", e.getMessage(), e.getClass());
        BindingResult bindingResult = e.getBindingResult();

        Map<String, String> errorMap = new HashMap<>();
        bindingResult.getFieldErrors().forEach((fieldError) -> {
            // 错误字段 、 错误提示
            errorMap.put(fieldError.getField(), fieldError.getDefaultMessage());
        });
        return R.error(BizCodeEnum.VAILD_EXCEPTION.getCode(), BizCodeEnum.VAILD_EXCEPTION.getMsg()).put("data", errorMap);
    }

    @ExceptionHandler(value = Throwable.class)
    public R handleException(Throwable throwable) {

        log.error("错误:", throwable);
        return R.error(BizCodeEnum.UNKNOW_EXCEPTION.getCode(), BizCodeEnum.UNKNOW_EXCEPTION.getMsg());
    }
}
2.3.全局跨域处理

​ 由于前端统一访问gateway网关,所以gateway需要配置允许跨域

package com.empirefree.gulimall.gateway.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.reactive.CorsWebFilter;
import org.springframework.web.cors.reactive.UrlBasedCorsConfigurationSource;

@Configuration
public class GulimallCorsConfiguration {

    @Bean
    public CorsWebFilter corsWebFilter() {
        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();

        CorsConfiguration corsConfiguration = new CorsConfiguration();
        //1、配置跨域
        corsConfiguration.addAllowedHeader("*");
        corsConfiguration.addAllowedMethod("*");
        corsConfiguration.addAllowedOrigin("*");
        corsConfiguration.setAllowCredentials(true);

        source.registerCorsConfiguration("/**", corsConfiguration);
        return new CorsWebFilter(source);
    }
}
2.4.VO、TO

​ 由于入参出参数据与dao层差距很大,所以需要自定义一些参数,结合代码赋值完成参数传递

    BeanUtils.copyProperties(group, attrVo);

(我用的比较多的就是XXrequest、XXresponse、XXDTO、XXVO)

3.总结

​ 老师后端讲得很多东西虽然都是一句话带过,但是其实真的很重要,而且我觉得需要有针对性学习,个人感觉效率高点

  • 分布式相关内容:nacos,gateway,feign
  • 后端相关内容:oss,树形商品,商品路径,全局处理(异常、跨域、统一处理),代码规范(JSR303,VO|DTO|DO)
  • 数据库相关内容:库表的设计(重要:个人感觉对提高后端开发有启迪性作用)
  • 服务器相关内容:docker(还只是停留在使用阶段,自己还需要提高)

书山有路勤为径,学海无涯苦作舟。程序员不仅要懂代码,更要懂生活,关注我,一起进步。