当前位置 博文首页 > 努力充实,远方可期:谷粒商城笔记-分布式高级(3/4)

    努力充实,远方可期:谷粒商城笔记-分布式高级(3/4)

    作者:[db:作者] 时间:2021-08-11 09:50

    • 笔记-基础篇-1(P1-P28):https://blog.csdn.net/hancoder/article/details/106922139

    • 笔记-基础篇-2(P28-P100):https://blog.csdn.net/hancoder/article/details/107612619

    • 笔记-高级篇(P340):https://blog.csdn.net/hancoder/article/details/107612746

    • 笔记-vue:https://blog.csdn.net/hancoder/article/details/107007605

    • 笔记-elastic search、上架、检索:https://blog.csdn.net/hancoder/article/details/113922398

    • 笔记-认证服务:https://blog.csdn.net/hancoder/article/details/114242184

    • 笔记-分布式锁与缓存:https://blog.csdn.net/hancoder/article/details/114004280

    • 笔记-集群篇:https://blog.csdn.net/hancoder/article/details/107612802

    • springcloud笔记:https://blog.csdn.net/hancoder/article/details/109063671

    • 笔记版本说明:2020年提供过笔记文档,但只有P1-P50的内容,2021年整理了P340的内容。请点击标题下面分栏查看系列笔记

    • 声明:

      • 可以白嫖,但请勿转载发布,笔记手打不易
      • 本系列笔记不断迭代优化,csdn:hancoder上是最新版内容,10W字都是在csdn免费开放观看的。
      • 离线md笔记文件获取方式见文末。2021-3版本的md笔记打完压缩包共500k(云图床),包括本项目笔记,还有cloud、docker、mybatis-plus、rabbitMQ等个人相关笔记
    • sql:https://github.com/FermHan/gulimall/sql文件

    • 本项目其他笔记见专栏:https://blog.csdn.net/hancoder/category_10822407.html

    请直接ctrl+F搜索内容

    学到高级篇已经击败90%的人了,加油

    一、Elastic Search

    ES笔记:https://blog.csdn.net/hancoder/article/details/113922398

    二、公用工具

    商品发布只是可以上架了,上架后才可被检索

    Feign

    远程调用源码

    // ReflectiveFeign
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        if (!"equals".equals(method.getName())) {
            if ("hashCode".equals(method.getName())) {
                return this.hashCode();
            } else {
                return "toString".equals(method.getName()) ? this.toString() : ((MethodHandler)this.dispatch.get(method)).invoke(args);
            }
        } else {
            try {
                Object otherHandler = args.length > 0 && args[0] != null ? Proxy.getInvocationHandler(args[0]) : null;
                return this.equals(otherHandler);
            } catch (IllegalArgumentException var5) {
                return false;
            }
        }
    }
    
    // SynchronousMethodHandler.JAVA;
    
    public Object invoke(Object[] argv) throws Throwable {
        // 传过来的数据,构造 RequestTemplate,里面body有数据
        RequestTemplate template = this.buildTemplateFromArgs.create(argv);
        Options options = this.findOptions(argv);
        // 重试器,要注意重复调用、接口幂等性。可以写重试器自己的实现
        Retryer retryer = this.retryer.clone();
    
        while(true) {
            try {
                // 执行后得到响应,解码得到bean
                return this.executeAndDecode(template, options);
            } catch (RetryableException var9) {
                RetryableException e = var9;
    
                try {
                    retryer.continueOrPropagate(e);
                } catch (RetryableException var8) {
                    Throwable cause = var8.getCause();
                    if (this.propagationPolicy == ExceptionPropagationPolicy.UNWRAP && cause != null) {
                        throw cause;
                    }
                    throw var8;
                }
            }
        }
    }
    

    body里是数据,feign将bean转为了 json

    Object executeAndDecode(RequestTemplate template, Options options) throws Throwable {
        // 构造出请求
        Request request = this.targetRequest(template);
        if (this.logLevel != Level.NONE) {
            // 打印日志
            this.logger.logRequest(this.metadata.configKey(), this.logLevel, request);
        }
    
        long start = System.nanoTime();
    
        Response response;
        try {
            // 执行。client是LoadBalancerFeignClient。跳转到远程
            response = this.client.execute(request, options);
            response = response.toBuilder().request(request).requestTemplate(template).build();
        } catch (IOException var16) {
            if (this.logLevel != Level.NONE) {
                this.logger.logIOException(this.metadata.configKey(), this.logLevel, var16, this.elapsedTime(start));
            }
    
            throw FeignException.errorExecuting(request, var16);
        }
    。。。
    

    公共返回类R

    因为是个hashmap,所以setData不成功

    public class R<T> extends HashMap<String,Object>{
        //     把setData重写成PUT
        public R setData(Object data){
            put("data", data);
            return this;
        }
    
        public <T> T getData(TypeReference<T> typeReference){
            // get("data") 默认是map类型 所以再由map转成string再转json
            Object data = get("data");//得到list,list每个值是map类型
            // list<Map>转json
            String s = JSON.toJSONString(data);
            // json转list<T>
            return JSON.parseObject(s, typeReference);
        }
    }
    
    在其他处是new TypeReference<List<T>>
    

    data的值对应的是List,而list的每个值是map

    三、商城系统首页

    P136

    页面与静态资源处理

    不使用前后端分离开发了,管理后台用vue

    页面在课件位置: 【高级篇-资料源码.zip\代码\html】

    静态资源处理

    nginx发给网关集群,网关再路由到微服务

    静态资源放到nginx中,后面的很多服务都需要放到nginx中

    html\首页资源\index放到gulimall-product下的static文件夹

    把index.html放到templates中

    pom依赖

    导入thymeleaf依赖、热部署依赖devtools使页面实时生效

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-devtools</artifactId>
    </dependency>
    
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-thymeleaf</artifactId>
    </dependency>
    

    关闭thymeleaf缓存,方便开发实时看到更新

      thymeleaf:
        cache: false
        suffix: .html
        prefix: classpath:/templates/
    

    web开发放到web包下,原来的controller是前后分离对接手机等访问的,所以可以改成app,对接app应用

    渲染一级分类菜单

    刚导入index.html时,里面的分类菜单都是写死的,我们要访问数据库拿到放到model中,然后在页面foreach填入

    thymeleaf笔记:https://blog.csdn.net/hancoder/article/details/113945941

    @GetMapping({"/", "index.html"})
    public String getIndex(Model model) {
        //获取所有的一级分类
        List<CategoryEntity> catagories = categoryService.getLevel1Catagories();
        model.addAttribute("catagories", catagories);
        return "index";
    }
    

    页面遍历菜单数据

    <li th:each="catagory:${catagories}" >
        <a href="#" class="header_main_left_a" ctg-data="3" th:attr="ctg-data=${catagory.catId}"><b th:text="${catagory.name}"></b></a>
    </li>
    

    渲染三级分类菜单

    @ResponseBody
    @RequestMapping("index/catalog.json")
    public Map<String, List<Catelog2Vo>> getCatlogJson() {
    
        Map<String, List<Catelog2Vo>> map = categoryService.getCatelogJson();
        return map;
    }
    
    
    @Override
    public Map<String, List<Catelog2Vo>> getCatelogJson() {
        List<CategoryEntity> entityList = baseMapper.selectList(null);
        // 查询所有一级分类
        List<CategoryEntity> level1 = getCategoryEntities(entityList, 0L);
        Map<String, List<Catelog2Vo>> parent_cid = level1.stream().collect(Collectors.toMap(k -> k.getCatId().toString(), v -> {
            // 拿到每一个一级分类 然后查询他们的二级分类
            List<CategoryEntity> entities = getCategoryEntities(entityList, v.getCatId())