<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    paulwong

    #

    JSR-303 Bean Validation - Date String Validation

    @Past @Future只針對Date類型的驗證,如果是String類型的驗證,則不適用。
    其實可以新加一個方法返回Date類型,再配合@Future@Past 進行驗證。

    @Future(message = "Invalid CN_ID_INFO.EXPIRE_DATE.")
    private LocalDate getValidExpireDate() {
        try {
            return LocalDate.parse(this.dateString, DateTimeFormatter.ofPattern("yyyy-MM-dd"));
        } catch (Exception e) {
            return null;
        }
    }

    此方法對dateString進行解釋,返回LocalDate,如果dateString為空或格式錯誤,則返回空,再配合@Future 進行是否未來日期的驗證。

    posted @ 2021-02-25 09:44 paulwong 閱讀(326) | 評論 (0)編輯 收藏

    JSR-303 Bean Validation - Conditional Validation

    bean validation的注釋是針對單個變量的,如果要針對多個變量的聯動,則不行,需要用到這個注釋。
    這種方法避免了自定義校驗器而增加類。
    https://www.chkui.com/article/java/java_bean_validation

    @AssertTrue(message = "Missing BANK_CARD_IMG_INFO.IMG")
    private Boolean getValidImg() {
        if(YNEnum.Y.code.equals(super.getNeedChecked())) {
                return StringUtils.hasText(this.img);
            }
            return null;//igore checking.
    }

    這個是當needChecked為Y的時候才執行檢查img變量是否為空。
    有幾點注意:
    1. 方法名稱要以get開頭
    2. 返回類型用Boolean,而不用boolean
    3. 返回值有三種:true,false,null如果是null則當成通過,與true的結果一樣

    posted @ 2021-02-25 09:24 paulwong 閱讀(321) | 評論 (0)編輯 收藏

    http與https的區別

    http是將內容文字通過tcp傳送,內容是明文,未經加密,可透過tcpdump偷看。

    https將內容文字用不對稱的方式加密后再傳送,加密協議是TLS或SSL,透過tcpdump看到的內容是亂碼。而且服務器端更換密鑰無需通知client。

    How hackers love your HTTP data
    https://blog.usejournal.com/how-hackers-love-your-http-data-157e76f2c66a

    How you could get hacked at a coffee shop
    https://medium.com/bugbountywriteup/how-you-could-get-hacked-at-a-coffee-shop-3a81a53c0b4f


    Hacker Lexicon: What Is HTTPS?
    https://www.wired.com/2016/04/hacker-lexicon-what-is-https-encryption/

    posted @ 2021-02-04 17:00 paulwong 閱讀(216) | 評論 (0)編輯 收藏

    SPRING BOOT單元測試之@ActiveProfiles

    SPRING BOOT單元測試中,因為測試時可能對應的服務器地址不同于SIT等別的環境,通常會將這些地址放于application-sit.yaml中。
    在單元測試的代碼中用這個標簽指定用哪個profile,如
    @ActiveProfiles({"embedded-mongodb","test"})

    但這樣做法,由于@ActiveProfiles這個標簽是final的,如果要測試別的profile,只能復制另一份單元測試代碼,再改此標簽。

    比較靈活的做法是用default profile,default profile是如果沒指定任何profile,則會默認用這個。在application-default.yaml中再指定需激活的profile。
    spring:
       profiles:
          active: test,embedded-mongodb

    如果要測試別的profile,可以指定環境變量的方式覆蓋:
    -Dspring.profiles.active=error,embedded-mongodb

    為了安全起見,將application-default.yaml放在測試目錄中:src\test\resources。

    Setting default Spring profile for tests with override option
    https://blog.inspeerity.com/spring/setting-default-spring-profile-for-tests-with-override-option/




    posted @ 2021-02-04 15:31 paulwong 閱讀(1826) | 評論 (0)編輯 收藏

    JSR-303 Bean Validation

    接收數據的JAVA BEAN通常需要驗證其中字段的正確性,如不準為空,符合EMAIL格式等。
    JSR-303 Bean Validation則提供了這樣的便捷。

    只要在JAVA BEAN中需要驗證的字段加@NotNull這種標簽,然后在SERVISE中的輸入參數中加@Valid標簽,則就激活驗證流程。
    也可以編程的方式自己驗證:
    @MessageEndpoint
    //@Validated
    public class MqMessageCcdValidator {
        
        private static final Logger LOGGER = LoggerFactory.getLogger(MqMessageCcdValidator.class);
        
        @Autowired
        private Validator validator;
        
        @ServiceActivator
        public MqMessage<CcdRequest> validate(/* @Valid */ Message<MqMessage<CcdRequest>> requestMessage) {
            Set<ConstraintViolation<MqMessage<CcdRequest>>> set = validator.validate(requestMessage.getPayload());
            if(CollectionUtils.isNotEmpty(set)) {
                CompositeException compositeException = new CompositeException();
                set.forEach(
                    constraintViolation -> {
                                                LOGGER.info("{}", constraintViolation);
                                                ReqInfoValidationException exception =
                                                        new ReqInfoValidationException(constraintViolation.getMessage());
                                                compositeException.addException(exception);
                                           }
                );
                throw new MessageHandlingException(requestMessage, compositeException);
            }
            
            return requestMessage.getPayload();
        }

    }

    自定義驗證規則
    可用標簽來做,以下為驗證手機號的規則:
    import static java.lang.annotation.RetentionPolicy.RUNTIME;

    import java.lang.annotation.ElementType;
    import java.lang.annotation.Retention;
    import java.lang.annotation.Target;

    import javax.validation.Constraint;
    import javax.validation.Payload;
    import javax.validation.ReportAsSingleViolation;
    import javax.validation.constraints.Pattern;

    @Retention(RUNTIME)
    @Target(value = { ElementType.FIELD, ElementType.PARAMETER, ElementType.ANNOTATION_TYPE })
    @Constraint(validatedBy = {})
    @ReportAsSingleViolation
    @Pattern(regexp = "^1[3-9]\\d{9}$")
    public @interface ChinaPhone {
        String message() default "Invalid Chinese mobile No.";
        Class<?>[] groups() default {};
        Class<? extends Payload>[] payload() default {};
    }

    如果比較復雜的驗證規則,則參見:
    https://reflectoring.io/bean-validation-with-spring-boot/#implementing-a-custom-validator

    How to use Java Bean Validation in Spring Boot
    https://nullbeans.com/how-to-use-java-bean-validation-in-spring-boot/

    Complete Guide to Validation With Spring Boot
    https://reflectoring.io/bean-validation-with-spring-boot/

    Spring JMS Validate Messages using JSR-303 Bean Validation
    https://memorynotfound.com/spring-jms-validate-messages-jsr-303-bean-validation/

    Spring REST Validation Example
    https://mkyong.com/spring-boot/spring-rest-validation-example/

    Spring Boot 整合 Bean Validation 校驗數據

    https://blog.csdn.net/wangzhihao1994/article/details/108403732

    posted @ 2021-01-28 10:35 paulwong 閱讀(336) | 評論 (0)編輯 收藏

    SPRING INTEGRATION SCATTERGATHER

    場景,餐廳:
    1. 食客下單,有飲品、食物、甜點
    2. 侍應接單,傳送給廚房
    3. 廚房分三個子流程處理,即飲品、食物、甜點子流程
    4. 等待三個子流程處理完,合并成一份交付
    5. 如果廚房發現某食物欠缺,會通知侍應,展開錯誤處理,即通知食客更改食物,再交給廚房
    6. 侍應將交付品傳送給食客
    有一個主流程、三個子流程和一個聚合流程,聚合流程會聚合三個子流程的產物,通知主流程,再往下走。
    并且主流程會感知子流程的錯誤,并會交給相應錯誤處理流程處理,且將結果再交給聚合流程。

    對應SPRING INTEGRATION 的SCATTERGATHER模式:
    @Bean
    public IntegrationFlow scatterGatherAndExecutorChannelSubFlow(TaskExecutor taskExecutor) {
        return f -> f
                .scatterGather(
                        scatterer -> scatterer
                                .applySequence(true)
                                .recipientFlow(f1 -> f1.transform(p -> "Sub-flow#1"))
                                .recipientFlow(f2 -> f2
                                        .channel(c -> c.executor(taskExecutor))
                                        .transform(p -> {
                                            throw new RuntimeException("Sub-flow#2");
                                        })),
                        null,
                        s -> s.errorChannel("scatterGatherErrorChannel"));
    }

    @ServiceActivator(inputChannel = "scatterGatherErrorChannel")
    public Message<?> processAsyncScatterError(MessagingException payload) {
        return MessageBuilder.withPayload(payload.getCause().getCause())
                .copyHeaders(payload.getFailedMessage().getHeaders())
                .build();
    }

    https://github.com/adnanmamajiwala/spring-integration-sample/tree/master/dsl-scatter-gather/src/main/java/com/si/dsl/scattergather

    https://docs.spring.io/spring-integration/docs/5.1.x/reference/html/#scatter-gather

    posted @ 2021-01-28 10:11 paulwong 閱讀(301) | 評論 (0)編輯 收藏

    「測試」 - 接口測試 & mock工具Moco

    當需要調用第三方HTTP接口時,別人的接口還沒完成,可先根據接口定義文檔,返回適當的數據,以便開發。

    在LINUX上的部署結構為:
    ├── boot
    │   ├── moco-runner-1.1.0-standalone.jar
    │   └── .version
    ├── foo.json
    ├── logs
    │   ├── back
    │   └── moco.log
    ├── moco.sh
    └── startup-moco.sh

    .version文件:
    /path/to/boot/moco-runner-1.1.0-standalone.jar 1.1.0

    moco.sh
    #!/usr/bin/env bash

    # Ensure this file is executable via `chmod a+x moco`, then place it
    # somewhere on your $PATH, like ~/bin. The rest of moco will be
    # installed upon first run into the ~/.moco directory.

    if [ `id -u` -eq 0 ] && [ "$MOCO_ROOT" = "" ]; then
        echo "WARNING: You're currently running as root; probably by accident."
        echo "Press control-C to abort or Enter to continue as root."
        echo "Set MOCO_ROOT to disable this warning."
        read _
    fi

    echo $*

    #export MOCO_HOME="$
    {MOCO_HOME:-"$HOME/.moco"}"
    export MOCO_HOME=$(cd `dirname $0`; cd boot; pwd)
    VERSION_LOG_FILE="$MOCO_HOME/.version"

    # Determine the Java command to use to start the JVM.
    if [ -n "$JAVA_HOME" ] ; then
        if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
            # IBM's JDK on AIX uses strange locations for the executables
            JAVACMD="$JAVA_HOME/jre/sh/java"
        else
            JAVACMD="$JAVA_HOME/bin/java"
        fi
        if [ ! -x "$JAVACMD" ] ; then
            die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME

    Please set the JAVA_HOME variable in your environment to match the
    location of your Java installation."
        fi
    else
        JAVACMD="java"
        which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.

    Please set the JAVA_HOME variable in your environment to match the
    location of your Java installation."
    fi

    if [ "$HTTP_CLIENT" = "" ]; then
        if type -p curl >/dev/null 2>&1; then
            if [ "$https_proxy" != "" ]; then
                CURL_PROXY="-x $https_proxy"
            fi
            HTTP_CLIENT="curl $CURL_PROXY -f -L -o"
        else
            HTTP_CLIENT="wget -O"
        fi
    fi

    function download_failed_message 
    {
        echo "Failed to download $1"
        echo "It's possible your HTTP client's certificate store does not have the"
        echo "correct certificate authority needed. This is often caused by an"
        echo "out-of-date version of libssl. Either upgrade it or set HTTP_CLIENT"
        echo "to turn off certificate checks
    :"
        echo "  export HTTP_CLIENT=\"wget --no-check-certificate -O\" # or"
        echo "  export HTTP_CLIENT=\"curl --insecure -f -L -o\""
        echo "It's also possible that you're behind a firewall haven't yet"
        echo "set HTTP_PROXY and HTTPS_PROXY."
    }

    function download 
    {
        $HTTP_CLIENT "$2.pending" "$1"
        if [ $? == 0 ]; then
            # TODO
    : checksum
            mv -f "$2.pending" "$2"
        else
            rm "$2.pending" 2> /dev/null
            download_failed_message "$1"
            exit 1
        fi
    }

    function parse_tag 
    {
       tag_value=`grep "<$2>.*<.$2>" $1 | sed -e "s/^.*<$2/<$2/" | cut -f2 -d">"| cut -f1 -d"<"`
    }

    function parse_maven_metadata 
    {
        MOCO_METADATA_URL="http
    ://repo1.maven.org/maven2/com/github/dreamhead/moco-runner/maven-metadata.xml"
        MOCO_METADATA="/tmp/maven-metadata.xml"
        download $MOCO_METADATA_URL $MOCO_METADATA
        parse_tag $MOCO_METADATA latest
        LATEST_VERSION=$tag_value
    }

    function parse_standalone_latest_url 
    {
        parse_maven_metadata
        VERSION=${LATEST_VERSION%
    }
        LATEST_MOCO_STANDALONE_JAR="moco-runner-$VERSION-standalone.jar"
        MOCO_STANDLONE_URL="http://repo1.maven.org/maven2/com/github/dreamhead/moco-runner/$LATEST_VERSION/$LATEST_MOCO_STANDALONE_JAR"
    }

    function install 
    {
        echo "Install moco"
        echo "Parse the latest version of moco"
        parse_standalone_latest_url
        echo "Download the latest moco
    : $LATEST_VERSION"
        MOCO_STANDALONE="$MOCO_HOME/$LATEST_MOCO_STANDALONE_JAR"
        echo "$MOCO_STANDALONE $LATEST_VERSION" >> $VERSION_LOG_FILE
        download $MOCO_STANDLONE_URL $MOCO_STANDALONE
    }

    function load_current_version 
    {
        read MOCO_STANDALONE CURRENT_VERSION < $VERSION_LOG_FILE
        if [[ "$(uname)" -ne "Darwin" && "$(expr substr $(uname -s) 2 6)" == "CYGWIN"   ]];then
            MOCO_STANDALONE=`cygpath -m "$MOCO_STANDALONE"`
        fi
    }

    function usage 
    {
      printf "
    options
    :
           help      show help
           start     start server, e.g. moco start -p 12306 -c configfile.json
           shutdown  shutdown moco server 
           upgrade   upgrade moco
    "
    }

    if [ ! -e "$MOCO_HOME" ]
    then
        mkdir "$MOCO_HOME"
        install
    fi

    if [ "$1" = "start" ]; then
        echo "Starting"
        load_current_version
        exec "$JAVACMD" -jar "$MOCO_STANDALONE" $*
    elif [ "$1" = "http" ]; then
        echo "Starting HTTP server"
        load_current_version
        exec "$JAVACMD" -jar "$MOCO_STANDALONE" $*
    elif [ "$1" = "https" ]; then
        echo "Starting HTTPS server"
        load_current_version
        exec "$JAVACMD" -jar "$MOCO_STANDALONE" $*
    elif [ "$1" = "socket" ]; then
        echo "Starting Socket server"
        load_current_version
        exec "$JAVACMD" -jar "$MOCO_STANDALONE" $*
    elif [ "$1" = "shutdown" ]; then
        echo "Shutting down server"
        load_current_version
        exec "$JAVACMD" -jar "$MOCO_STANDALONE" $*
    elif [ "$1" = "upgrade" ]; then
        echo "Check the new version"
        parse_maven_metadata
        load_current_version

        if [ "$LATEST_VERSION" = "$CURRENT_VERSION" ]; then
            echo "The current version of moco is the latest"
        else
            echo "Upgrading"
            rm $VERSION_LOG_FILE
            install
        fi
    elif [ "$1" = "version" ]; then
        load_current_version
        echo "Moco version: $CURRENT_VERSION"
    elif [ "$1" = "help" ]; then
        usage
    else
        usage
    fi

    這是根據GIT上的原始文件作的修改。

    startup-moco.sh
    CMD_PATH=$(cd `dirname $0`; pwd)

    # 項目日志輸出絕對路徑
    LOG_DIR=$
    {CMD_PATH}"/logs"
    LOG_FILE="moco.log"
    LOG_PATH="$
    {LOG_DIR}/${LOG_FILE}"

    # 當前時間
    NOW=`date +'%Y-%m-%m-%H-%M-%S'`
    NOW_PRETTY=`date +'%Y-%m-%m %H:%M:%S'`

    # 啟動日志
    STARTUP_LOG="================================================ $
    {NOW_PRETTY} ================================================\n"

    # 日志備份目錄
    LOG_BACK_DIR="$
    {LOG_DIR}/back/"

    # 如果logs文件夾不存在,則創建文件夾
    if [[ ! -d "$
    {LOG_DIR}" ]]; then
      mkdir "$
    {LOG_DIR}"
    fi

    # 如果logs/back文件夾不存在,則創建文件夾
    if [[ ! -d "$
    {LOG_BACK_DIR}" ]]; then
      mkdir "$
    {LOG_BACK_DIR}"
    fi

    # 如果項目運行日志存在,則重命名備份
    if [[ -f "$
    {LOG_PATH}" ]]; then
        mv $
    {LOG_PATH} "${LOG_BACK_DIR}/${APPLICATION}_back_${NOW}.log"
    fi

    # 創建新的項目運行日志
    echo "" > $
    {LOG_PATH}

    # 可支持多個json配置文件
    $CMD_PATH/moco.sh http -p 8088 -g "${CMD_PATH}/root.json" > ${LOG_PATH} 2>&1 &

    # 打印啟動日志
    echo -e $
    {STARTUP_LOG}

    root.json
    [
        
    {
            "context"
    : "/service-a",
            "include": "foo.json"
        
    },
        
    {
            "context"
    : "/service-b",
            "include": "bar.json"
        
    }
    ]

    foo.json
    [
        
    {
            "request"
    : {
                "method": "post",
                "forms": {
                    "method": "uploadKycInfo"
                
    }
            },
            "response": 
    {
                "json"
    : {
                    "response": {
                        "subcode": "10000",
                        "submsg": "Success",
                        "sndDt": "20210121101800",
                        "remark": "上傳驗證基本信息",
                        "msgBody": {
                            "merOrdrNo": "A00120210121654321",
                            "retCode": "00000",
                            "retMsg": "成功/處理完成",
                            "remark": "上傳詳情或上傳信息的簡要描述"
                        
    }
                    },
                    "code": "0000",
                    "msg": "處理完成",
                    "sign": "DF2659FE3EB8184561135D9F55F5EF5"
                }
            }
        }
    ]

    訪問路徑:
    http://ip:port/service-a/

    https://github.com/dreamhead/moco/blob/master/moco-doc/apis.md
    https://zhuanlan.zhihu.com/p/60076337 
    https://www.programmersought.com/article/68272293688/

    posted @ 2021-01-21 14:09 paulwong 閱讀(597) | 評論 (0)編輯 收藏

    Java8中文件轉Base64和Base64轉文件

    有幾個項目中,都需要將圖片或者數字證書的文件轉為Base64,昨天寫代碼的時候,發現在jdk8中本就含有關于Base64的API。

    從此后不再需要其他的jar包來轉換Base64了!!!

    據說是JDK8加入的。


    先是將文件轉為Base64:
    public String encryptToBase64(String filePath) {
            if (filePath == null) {
                return null;
            }
            try {
                byte[] b = Files.readAllBytes(Paths.get(filePath));
                return Base64.getEncoder().encodeToString(b);
            } catch (IOException e) {
                e.printStackTrace();
            }
     
            return null;
        }

    Files、Paths類是JDK7里加入的,讀取文件不再需要調用IO包里的FileInputStream,簡單便捷。
    字符串參數filePath是文件的路徑。

    首先是將文件讀成二進制碼,然后通過Base64.getEncoder().encodeToString()方法將二進制碼轉換為Base64值。


    然后是將Base64轉為文件:
    public String decryptByBase64(String base64, String filePath) {
            if (base64 == null && filePath == null) {
                return "生成文件失敗,請給出相應的數據。";
            }
            try {
                Files.write(Paths.get(filePath), Base64.getDecoder().decode(base64),StandardOpenOption.CREATE);
            } catch (IOException e) {
                e.printStackTrace();
            }
            return "指定路徑下生成文件成功!";
        }

    字符串參數base64指的是文件的Base64值,filePath是指的文件將要保存的位置。
    通過Files.write()方法輕松將文件寫入指定位置,不再調用FileOutStream方法。

    第三個參數StandardOpenOption.CREATE是處理文件的方式,我設置的是不管路徑下有或沒有,都創建這個文件,有則覆蓋。

    在StandardOpenOption類中有很多參數可調用,不再累贅。

    posted @ 2021-01-07 09:44 paulwong 閱讀(3850) | 評論 (0)編輯 收藏

    微服務架構設計模式

    微服務架構及設計模式
    http://dockone.io/article/9680

    微服務架構10個最重要的設計模式
    https://developer.51cto.com/art/202012/635852.htm

    GitHub標星127K!字節內部必刷“微服務架構設計模式”
    https://blog.csdn.net/a159357445566/article/details/110006542

    微服務架構及其最重要的10個設計模式
    https://www.infoq.cn/article/Kdw69bdimlX6FSGz1bg3

    Effective Microservices: 10 Best Practices
    https://towardsdatascience.com/effective-microservices-10-best-practices-c6e4ba0c6ee2

    Microservice Architecture and its 10 Most Important Design Patterns
    https://towardsdatascience.com/microservice-architecture-and-its-10-most-important-design-patterns-824952d7fa41




    posted @ 2021-01-06 14:44 paulwong 閱讀(364) | 評論 (0)編輯 收藏

    21個2021年軟件開發趨勢預測

         摘要: 2020年是最近歷史上前所未有的一年。在過去的一百年中,人類沒有經歷過像COVID-19這樣的全球性大流行。它影響了我們星球上的所有國家,部門和幾乎所有個人。 好消息是,我們已經準備好疫苗,終于可以充滿樂觀和希望,迎接新的一年2021年。 2020年對于軟件開發行業來說是重要的一年,在許多領域都取得了明顯的突破。COVID-19大大加快了數字化轉型,到2021年這種趨勢將更加明顯。 在軟...  閱讀全文

    posted @ 2021-01-05 09:56 paulwong 閱讀(362) | 評論 (0)編輯 收藏

    僅列出標題
    共115頁: First 上一頁 10 11 12 13 14 15 16 17 18 下一頁 Last 
    主站蜘蛛池模板: 一区二区三区免费视频观看| 在线观看国产情趣免费视频| 九九全国免费视频| 亚洲人成电影网站| 久久亚洲综合色一区二区三区 | 国产传媒在线观看视频免费观看| 91香蕉国产线观看免费全集| 黄床大片免费30分钟国产精品| 国产人成亚洲第一网站在线播放| 精品亚洲成a人片在线观看少妇| 国产亚洲欧洲Aⅴ综合一区| 国产午夜无码视频免费网站| 成年人网站免费视频| 暖暖免费在线中文日本| eeuss影院免费92242部| 国产大陆亚洲精品国产| 亚洲色中文字幕在线播放| 亚洲性无码av在线| 久久亚洲国产精品成人AV秋霞| 久久国产亚洲精品麻豆| 亚洲色精品88色婷婷七月丁香 | 四虎永久在线精品免费一区二区| 在线观看亚洲AV日韩A∨| 亚洲欧洲高清有无| 亚洲综合日韩中文字幕v在线| 亚洲精品国产成人片| 亚洲热线99精品视频| 亚洲色中文字幕无码AV| 亚洲色偷偷综合亚洲AVYP| 国产亚洲一区二区三区在线不卡| 亚洲免费日韩无码系列| 亚洲日本中文字幕一区二区三区| 亚洲精品成人区在线观看| 亚洲国产一区视频| 亚洲日本在线观看视频| 亚洲熟妇中文字幕五十中出| 久久精品国产亚洲AV网站| 久久久久亚洲AV成人无码| 91亚洲精品视频| 亚洲女人18毛片水真多| 亚洲va久久久久|