精华内容
下载资源
问答
  • 自己动手做一个adb的wifi连接

    热门讨论 2016-08-21 12:23:51
    自己动手做一个adb的wifi连接,当你忘记带数据线的时候可以连接wifi调试,关机和重启也很方便
  • 自己动手做一个开源工具 1. 为什么想自己做一个开源工具 原因1:在前不久学完设计模式的情况下,急切的想试一试设计模式带来的美感。 原因2:崇拜,向往开源的世界。当自己做的东西被千千万万人使用的时候,...

    自己动手做一个开源工具


    1. 为什么想自己做一个开源工具


    • 原因1:在前不久学完设计模式的情况下,急切的想试一试设计模式带来的美感。
    • 原因2:崇拜,向往开源的世界。当自己做的东西被千千万万人使用的时候,那种感觉对痴迷编程的程序员来说不是金钱和权利可以来衡量的。
    • 原因3:应适应景,根据现在和曾经的公司,以及以往所看到和所写的代码所出现的隐藏问题。想制造出一套能通用而且方便和可读性强的开源工具。让用到的人已最快的理解速度和上手速度,是我追求的目标。
    • 原因4:因为 项目开发慢,spring 诞生了。因为访问 jdbc 封装对象麻烦,mybatis 诞生了。因为 servlet 开发效率太低, spring mvc 诞生了。因为参数繁琐且臃肿,所以自己就做了一个简单的工具。

    特再此说明,本人只是一个刚毕业的大学生。只是对开源和编程很是痴迷。可能所写的东西根本不止一题,但对于本人来说是一种提升。我所想表达的是设计模式的力量和希望能做出一套开源工具的向往。希望各位大神和牛人勿喷。可能外面已经有实现以下功能更好的 jar 工具。但是在我没有接触过任何类似的工具时,只是凭着自己的一丝灵感和一腔热血所创造出来的一个非常简单但对于本人意义重大的工具。

    2.功能介绍

    非常简单的参数验证问题,但是为了统一管理和快速参数验证所用设计模式封装的”密不透风”;

    3.需解决的问题

    3.1 版本问题 (小问题)

    我们经常会用到字符串的非空判断,但是工具类的繁多导致开发中他用的这个版本,我用的哪个版本,虽然实现的方式差不多但是有时候还是会出现问题的(亲身经历)。例如:

            // com.alibaba.dubbo.common.utils;
            if (StringUtils.isEmpty(weChatId)) {}
            // com.alibaba.druid.util.
            if (StringUtils.isEmpty(weChatId)) {}
            // com.mysql.jdbc
            if (StringUtils.isEmpty(weChatId)) {}
            // org.apache.commons.lang
            if (StringUtils.isBlank(weChatId)) {}

    我们可以看到,仅是一个非空判断就有那么多工具类(其实还有好多),但是我们的项目都用到了这些 jar 包,比如 dubbo,druid,jdbc,commons。我们不可能因为这个原因而不用这些 jar。当我们在特殊情况下需要把一段代码复制到其他项目的代码里,因为这个原因我们的代码将会编程下面这个样子。

    if (org.apache.commons.lang3.StringUtils.isEmpty(weChatId)) {}

    非常丑陋的代码。这只是其中一个小问题而已,让我们往下看。

    3.2 代码过长问题 (中等问题)

    当我们需要验证一个参数,需要很多次判断时,代码会闲的很臃肿。例如:

           // 这只是个简单的例子,不要钻牛角尖。可能验证逻辑很复杂。
            if (StringUtils.isEmpty(weChatId)) { // 判断是否为空
                if (weChatId.length() > 10) {   // 判断是否长度大于10
                    if (weChatId.startsWith("a")) { // 判断是否是 'a' 开头
                    }
                }
            }

    或许我们还可以写成这样,变成一行代码:

    if (StringUtils.isEmpty(weChatId) && weChatId.length() > 0 && weChatId.startsWith("a")) {}

    这只是个简单的参数验证,如果参数验证中又有 “!” 号 (!true),又有括号包起来的问题。那不仅长,而且可读性太差。

    3.3 代码冗余问题 (大等问题)

    我们写接口时经常会在每个接口访问前加参数验证。但是多个接口可能需要相同的验证,这样代码冗余的问题就出现了,如果附带上 3.2 的问题。每个方法访问前都需要这么复杂的验证那要累死的,并且还很丑。

    这时可能又会有人说,可以把这种又臭又长的参数验证封装成一个静态方法放在工具类中。

    但这只是治标不治本,如果一个方法的参数需要验证,A,B,C 三次才可以访问接口,另一个方法的参数需要 A,C,D 三次才可以,种种交叉验证。那我们的工具类就变得非常长,非常冗余了,当以后想新增和维护的时候,会越来越难。

    4.工具介绍

    4.1 使用的设计模式

    本工具只是用了一种设计模式 - -。装饰者模式。来看下 UML 图。
    这里写图片描述

    来看看我的 Component 抽象类。

    public abstract class ParamComponent {
    
        /**
         * 装饰方法处理参数
         * @param param 需要效验的值
         * @return
         */
        public abstract String operation(String param) throws MyException;
    
        /**
         * 赋值装饰类
         * @param paramComponent
         */
        public abstract void setParamComponent(ParamComponent paramComponent);
    
    }

    在来看看我的 ConcreteComponent 被封装类:

    public class ParamConcreteComponent extends ParamComponent {
    
        /**
         * 校验类
         */
        private ParamComponent paramComponent;
    
        public ParamConcreteComponent(ParamComponent paramComponent) {
            this.paramComponent = paramComponent;
        }
    
        public ParamConcreteComponent() {}
    
        @Override
        public String operation(String param) throws MyException {
            return paramComponent.operation(param);
        }
    
        public ParamComponent getParamComponent() {
            return paramComponent;
        }
    
        @Override
        public void setParamComponent(ParamComponent paramComponent) {
            this.paramComponent = paramComponent;
        }
    }

    Decorator 抽象类:

    public abstract class ParamDecorator extends ParamComponent {
    
        /**
         * 要装饰的类
         */
        protected ParamComponent paramComponent;
    
        public ParamDecorator(ParamComponent paramComponent) {
            this.paramComponent = paramComponent;
        }
    
    
    
        @Override
        public String operation(String param) throws MyException {
            return paramComponent == null ? param : paramComponent.operation(param);
        }
    
        @Override
        public void setParamComponent(ParamComponent paramComponent) {
            this.paramComponent = paramComponent;
        }
    }

    再来看看我的 Decorator 抽象类子类(只发出来一个,最后会附上源码地址):

    public class ParamNotNullDecorator extends ParamDecorator {
    
        public ParamNotNullDecorator(ParamComponent paramComponent) {
            super(paramComponent);
        }
    
        @Override
        public String operation(String param) throws MyException {
            if (param != null && param.length() > 0) {
                return super.operation(param);
            }
            throw new MyException("40000",param,"param is null");
        }
    }

    或许看上去很简单,只是把一种验证封装成了一个对象而已。但是用这个模式不是只为了把他做成对象,而是更加方便的调用。
    在加上我们的工具类试试:

    public class ParamValidateUtil<T extends ParamValidateUtil> {
    
        /**
         * 被装饰的参数类
         */
        protected ParamConcreteComponent paramConcreteComponent;
    
        /**
         * 当前的验证类
         */
        protected ParamComponent thisParamComponent;
    
        protected ParamValidateUtil(ParamConcreteComponent paramConcreteComponent) {
    
            this.thisParamComponent = paramConcreteComponent;
            this.paramConcreteComponent = paramConcreteComponent;
        }
    
        /**
         * 赋值验证类
         */
        protected T assignmentDecorator(ParamComponent paramComponent) {
            thisParamComponent.setParamComponent(paramComponent);
            thisParamComponent = paramComponent;
            return (T) this;
        }
    
        /**
         * 获取实例
         *
         * @return
         */
        public static ParamValidateUtil getInstance() {
            return new ParamValidateUtil(new ParamConcreteComponent());
        }
    
        /**
         * 执行
         *
         * @return
         */
        public T execuet(String...params) throws MyException {
            for (String param : params) {
                paramConcreteComponent.operation(param);
            }
            return (T) this;
        }
        /**
         * 非空验证
         *
         * @return
         */
        public ParamValidateUtil notNull() {
            return assignmentDecorator(new ParamNotNullDecorator(null));
        }
        // ....其他验证。请在最下面的源码地址查看
    }

    我的工具类也很简单。但是就是一堆简单的代码产生的巨大的化学反应。让我们看看如何使用他把。

    5. 如何使用

    因为我们的验证失败都是以异常抛出来的。所以我们的代码都写在 try-chat 中,那原因是什么呢?

    5.1 为什么我们要以异常的形式抛出来呢?
    1. 如果以返回值的性质发送出来我们还需要接收返回值,然后做返回值的判断,这样代码又会增加几行,这不是我想看到的。
    2. 我们写接口的时候经常遇到一些我们没有抓到的异常,或许是我们没有发现哪些地方会出现异常。但是抛出异常后接口异常终止,有时就会返回给用户错误页面,这也是我们不行看到的。我们通常都会在 Controller 层调用服务的时候 try-chat 一下。防止没有捕获的异常返回给用户不好的错误页面。

    这时我们就可以把参数验证一起和调用服务时的 try-chat 写在一起。一举两得。如果参数验证错误了。会返回相应的参数验证错误信息。返还给调用者。

    5.2 使用方法

    5.2.1. 普通使用

            try {
                /** 判断是否为空,判断是否是手机号,判断长度是否大于等于1,小于12。
                 * 虽然手机号就是11位数。我这里还做了长度验证,只是为了增加一个参数验证的过程而已。
                 * 这种参数验证 看到方法就能快速的看出我们做了哪些验证。
                 */ 不论是再加一种还是再减一种都很方便
                ParamValidateUtil.getInstance()
                        .notNull()
                        .phone()
                        .size(1, 12).execuet(phone);
                // 调用 service 如果有未捕获到的异常也可以顺便捕获
                userService.getByPhone(phone);
            } catch (Exception e) {
                System.out.println(e.getMessage());
            }

    5.2.2. 双参数使用

            try {
                // 这样同一种验证我们只需要写一次验证过程,传入两个参数即可
                ParamValidateUtil.getInstance()
                        .notNull()
                        .phone()
                        .size(1, 12).execuet(newPhone, oldPhone);
                userService.updatePhone(newPhone, oldPhone);
            } catch (Exception e) {
                System.out.println(e.getMessage());
            }

    5.2.3 参数验证复用

            try {
                // 注意 : 下面的都只是为了演示,userId并不一定就是长度 112。只是为了和手机号公用一种验证方式。
                //        以下和以上的演示,只是为了演示思路和使用方法,不要太在意使用了哪些验证
                // userId 验证是否不为 null 且长度为 112 
                // phone 验证是否不为 null 且长度为 112 且符合正则手机号的标准
                ParamValidateUtil.getInstance()
                        .notNull()
                        .size(1,12).execuet(userId)
                        .phone().execuet(phone);
                 userService.updatePhoneByUserId(userId, phone);
            } catch (Exception e) {
                System.out.println(e.getMessage());
            }
    

    6. 扩展性

    如果本工具只是一个 jar 。当里面的验证方法不完全满足你的验证过程,比如你想增加一个邮箱验证,但是你并不能打开 jar,来修改源码。来让我们看看如何扩展自己的验证参数。

    6.1 首先我们需要创建一个 ParamEmailDecorator 装饰类。

    该装饰类继承 ParamDecorator 并重写 operation 方法。

    public class ParamEmailDecorator extends ParamDecorator {
    
        public ParamEmailDecorator(ParamComponent paramComponent) {
            // 传入到父类的赋值 paramComponent 属性
            super(paramComponent);
        }
    
        @Override
        public String operation(String param) throws MyException {
            /** PatternUtil 是正则匹配的验证工具,当然你也可以写在类里面方便修改
             * 这里我们只是封装调用类 PatternUtil.matcherEmail 的方法。
             * 为了更好的灵活使用邮箱验证
             * 重点: 如果自己实现复杂点的验证,一定要有下面的要求.
             */ 验证成功就调用 super.operation(param) 。失败就抛出异常
            if (PatternUtil.matcherEmail(param)) {
                return super.operation(param);
            }
            // 如果参数验证错误,产出相应的错误信息
            throw new MyException("40002", param, "email mismatch");
        }
    
    }
    6.2 扩展 ParamValidateUtil 工具类。

    该工具类继承 ParamValidateUtil 工具类。 并添加一个参数的构造器和重写 getInstance() 方法

    public class CustomParamUtil extends ParamValidateUtil<CustomParamUtil> {
    
    
        protected CustomParamUtil(ParamConcreteComponent paramConcreteComponent) {
            super(paramConcreteComponent);
        }
        /**
         * 获取实例
         *
         * @return
         */
        public static CustomParamUtil getInstance() {
            return new CustomParamUtil(new ParamConcreteComponent());
        }
    
        /**
         * 邮箱验证
         *
         * @return
         */
        public CustomParamUtil email() {
            return assignmentDecorator(new ParamEmailDecorator(null));
        }
    }

    以后我们新增参数验证,只需要在自己参数验证工具类里面增加一个对应的方法。如 email()。
    如果再增加参数验证方法时,只需要复制 email 方法。将方法名改为可读性高的名字,和修改assignmentDecorator 方法参数的 new ParamEmailDecorator(null) 这个参数即可。如:

        /**
         * 其他验证
         *
         * @return
         */
        public CustomParamUtil XXXX() {
            return assignmentDecorator(new XXXXXXX(null));
        }

    将代码中的 xxxx 改为你所需要的就可以。注意 new XXXXXXX(null) 是你实现的参数验证的装饰者类。

    工具还有很多可以更改的地方,如 new ParamEmailDecorator(null) 其实可以不用传 null 。后期会修改。

    6.3 使用自己的参数验证工具
            try {
                // 使用自己的参数验证工具
                CustomParamUtil.getInstance()
                        .notNull()
                        .size(1, 12).execuet(userId)
                        .email().execuet(email);
                userService.updateEmailByUserId(userId, email);
            } catch (Exception e) {
                System.out.println(e.getMessage());
            }

    这样我们扩展的自己的参数工具类就完成了。非常快捷方便。

    统一管理起来的参数验证问题,可以省很多事情,比如某个程序员验证某个邮箱必须是 qq 邮箱,写好的验证方法,加入到工具类中,所有人都可以使用了。而且非常灵活。可以在邮箱验证前面增加非空验证,也可以在后面增加长度验证等等。

    不需要在用一长串臃肿的 if else 语句做参数验证。
    还可以根据捕获的验证错误状态码做相应的处理。

    再次强调,本人制作出来的工具只是在生活中发现的一些隐性问题并且灵感一来而创作的。可能对于一部分人来多不怎么样,或者有自己更好的解决方案。 本人也是根据自己的想法做出来的一套工具而已(可能都不算一套工具,太小了。)。这次的博客只是为了分享以下我的想法和思路,也希望有大牛能做出一定的评价。毕竟本人才疏学浅,见识也不高,只能做出这种层次的东西。勿喷。。。

    源代码地址:https://github.com/zcsh0823/common
    装饰者类在 com.zsh.common.validate.param
    参数工具在 com.zsh.common.util


    若博客中有错误或者说的不好,请勿介意,仅代表个人想法。
    csdn博客:https://blog.csdn.net/LNView
    本文地址:https://blog.csdn.net/LNView/article/details/80675860

    有问题或者喜欢的欢迎评论。

    转载请注明出处!!!!!!

    展开全文
  • 爬虫之有道翻译+动手做一个翻译器
    展开全文
  • 自己动手做一个docker base images

    千次阅读 2019-02-04 14:48:11
    一般在手写dockerfile 的时候 ,第句都是form ...今天来动手个很简单的base iamge 看一下 1.统一环境: docker 版本 docker version Client: Version: 18.09.0 API version: 1.39 Go version: go1.10.4 Git...

    一般在手写dockerfile 的时候 ,第一句都是form 一个base image

    今天来动手打一个很简单的base iamge 看一下

    1.统一环境:

    docker 版本

    docker version
    
    Client:
     Version:           18.09.0
     API version:       1.39
     Go version:        go1.10.4
     Git commit:        4d60db4
     Built:             Wed Nov  7 00:48:22 2018
     OS/Arch:           linux/amd64
     Experimental:      false
    
    Server: Docker Engine - Community
     Engine:
      Version:          18.09.0
      API version:      1.39 (minimum version 1.12)
      Go version:       go1.10.4
      Git commit:       4d60db4
      Built:            Wed Nov  7 00:19:08 2018
      OS/Arch:          linux/amd64
      Experimental:     false
    
    

    操作系统:centos

    已经安装好

    gcc

    glibc-static

    2.创建一个文件hello.c,非常简单的hello world,代码如下:

    #include<stdio.h>
    int main()
    {
    printf("hello world\n");
    }
    

    3.编译源代码

    gcc -static hello.c -o hello
    

    生成hello 可执行文件

    4.手写dockerfile

    from scratch
    add  hello  /
    CMD ["/hello"]
    

    5.打镜像

    docker build -t mydocker .
    

    看下控制台的输出
    在这里插入图片描述

    这个时候输入 docker images

    在这里插入图片描述

    可以看到 镜像的大小只有 857 k 还是非常的小的

    运行看一下

    docker run mydocker 
    

    在这里插入图片描述

    运行成功!

    展开全文
  • 其实有人学了很久还是把docker当虚拟机来使用,但是docker其实和虚拟机是完全不一样的,如何理解这一区别呢,我觉得自己动手做一个docker的hello world镜像是最好的 先体验一下hello-world镜像 在做之前我们可以先...

    概述

    其实有人学了很久还是把docker当虚拟机来使用,但是docker其实和虚拟机是完全不一样的,如何理解这一区别呢,我觉得自己动手做一个docker的hello world镜像是最好的

    先体验一下hello-world镜像

    在做之前我们可以先自己体验一下docker官方的helloworld镜像,首先在自己的机器上安装上docker,安装完成之后从仓库里pull镜像
    sudo docker pull hello-world
    接着就是把这个镜像运行起来
    sudo docker run hello-world

      dockerfile sudo docker run hello-world
    
    Hello from Docker!
    This message shows that your installation appears to be working correctly.
    
    To generate this message, Docker took the following steps:
     1. The Docker client contacted the Docker daemon.
     2. The Docker daemon pulled the "hello-world" image from the Docker Hub.
        (amd64)
     3. The Docker daemon created a new container from that image which runs the
        executable that produces the output you are currently reading.
     4. The Docker daemon streamed that output to the Docker client, which sent it
        to your terminal.
    
    To try something more ambitious, you can run an Ubuntu container with:
     $ docker run -it ubuntu bash
    
    Share images, automate workflows, and more with a free Docker ID:
     https://hub.docker.com/
    
    For more examples and ideas, visit:
     https://docs.docker.com/engine/userguide/
    

    没错就是打印出了一些信息,这是怎么做到的呢?接下来我们了解一些基础知识

    基础知识

    首先docker和虚拟机不一样的地方就是docker使用了主机自己的内核,这就是为什么linux的容器只能跑在linux上,windows的镜像只能跑在windows上的原因了,还有docker镜像里面是没有包含内核的,只有一些软件需要的包和软件本身,也就是比如我的Ubuntu的docker镜像里面是没有Ubuntu内核的,包含了Ubuntu除了内核之外的所有东西。如果你不相信的话你可以在实体机Ubuntu下pull一个centos镜像运行起来看看是不是和你的实体机Ubuntu系统内核是一样的。

    那么docker的hello-world的原理是什么

    首先大家要知道的是hello-world镜像的Dockerfile

    FROM scratch
    ADD hello /
    CMD ["/hello"]

    什么意思呢,第一行的意思就是白手起家从零构建一个镜像,我不需要一个基础镜像,第二行意思是把本机的hello这个二进制文件拷贝到镜像中去,最后一行就是执行了,然后hello这个二进制文件就可以在自己实体机系统内核跑起来了
    所以我们制作一个最小的docker镜像第一步要准备这个hello文件

    操作

    首先准备这个二进制文件,为了简单化直接下载就好
    https://github.com/docker-library/hello-world/blob/b7a78b7ccca62cc478919b101f3ab1334899df2b/hello
    点击download下载
    接着编写Dockerfile

    FROM scratch
    ADD hello /
    CMD ["/hello"]

    之后build镜像
    docker build -t mini .

      test docker build -t mini .
    Sending build context to Docker daemon  3.584kB
    Step 1/3 : FROM scratch
     ---> 
    Step 2/3 : COPY hello /
     ---> 8b398d623500
    Step 3/3 : CMD ["/hello"]
     ---> Running in e3e476d5ea2e
    Removing intermediate container e3e476d5ea2e
     ---> 43f766e9d546
    Successfully built 43f766e9d546
    Successfully tagged mini:latest

    接着运行起来就好

      test sudo docker run mini
    Hello from Docker.
    This message shows that your installation appears to be working correctly.
    
    To generate this message, Docker took the following steps:
     1. The Docker client contacted the Docker daemon.
     2. The Docker daemon pulled the "hello-world" image from the Docker Hub.
        (Assuming it was not already locally available.)
     3. The Docker daemon created a new container from that image which runs the
        executable that produces the output you are currently reading.
     4. The Docker daemon streamed that output to the Docker client, which sent it
        to your terminal.
    
    To try something more ambitious, you can run an Ubuntu container with:
     $ docker run -it ubuntu bash
    
    For more examples and ideas, visit:
     http://docs.docker.com/userguide/

    欢迎关注Bboysoul的博客www.bboysoul.com
    Have Fun

    展开全文
  • 这使我萌生一个念头:做一个局域网聊天工具。局域网聊天工具要实现的功能可以很多,首先需要分析的是它的核心需求是什么?分析一个软件的核心需求,要看人们用这个软件的最经常的操作是什么。我观察了一下,我们用...
  • html动手做做一个简单的注册页面

    千次阅读 2018-08-07 12:58:25
    1.创建个html文件 2.根据案例图片进行设计 3.写相应的html代码 &lt;!DOCTYPE html&gt; &lt;html&gt; &lt;head&gt; &lt;META http-equiv="Content-Type" content=&...
  • 我想动手做一个Tardis书橱

    千次阅读 2014-03-27 10:35:12
    我想动手做一个Tardis书橱。灵感来源于此:   不过因为书橱,打算三面放书,不可开合,对外双开门,容一人转身之处,内部顶上装灯供照明,外部顶上也装灯可当室内灯用。木板承重...
  • 动手做一个简单的智能小车

    千次阅读 多人点赞 2020-06-26 17:23:47
    动手做一个简单的智能小车 来到CNDN一年了,看到了许多大佬的杰出作品.也该写点什么来回馈给大家了前不久接触了单片机,想提前进行实践一下所以有想法做一个实体出来,想来想去难的怕自己搞不定,但是还好找到了...
  • 自己动手做一个PLC 软PLC

    千次阅读 2019-11-04 19:42:18
    SoapBox Snap:使用C#+WPF开发的,仅支持梯形图种语言,不过却已经支持了在线调试功能,含模拟器。 我的解决方案 :我使用了Node.js+HTML5开发,仅支持梯形图种语言,不支持在线调试,使用HTML5方案最大的...
  • 自己动手做一个迷你linux系统 - 内核技术 - Linux教程,自己动手做一个迷你linux系统 - 内核技术 - Linux教程,自己动手做一个迷你linux系统 - 内核技术 - Linux教程

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 14,495
精华内容 5,798
关键字:

动手做一做