‘编程学习’ 分类下的所有文章
202012 月16

Java实现加减乘除验证码

pom.xml

<dependency>
    <groupId>com.github.whvcse</groupId>
    <artifactId>easy-captcha</artifactId>
    <version>1.6.2</version>
</dependency>

生成验证码:

public NutMap getCode() {
        String uuid = UUID.randomUUID().toString().replace("-", "");
        ArithmeticCaptcha captcha = new ArithmeticCaptcha(120, 40);
        captcha.getArithmeticString();  // 获取运算的公式:3+2=?
        String text = captcha.text();
        redisService.setex(RedisConstant.REDIS_CAPTCHA_KEY + uuid, 180, text);
        return NutMap.NEW().addv("key", uuid).addv("codeUrl", captcha.toBase64());
    }

验证验证码:(表单传递验证码及验证码key)

public void checkCode(String key, String code) throws CaptchaException {
        String codeFromRedis = redisService.get(RedisConstant.REDIS_CAPTCHA_KEY + key);

        if (Strings.isBlank(code)) {
            throw new CaptchaException("请输入验证码");
        }
        if (Strings.isEmpty(codeFromRedis)) {
            throw new CaptchaException("验证码已过期");
        }
        if (!Strings.equalsIgnoreCase(code, codeFromRedis)) {
            throw new CaptchaException("验证码不正确");
        }
        redisService.del(RedisConstant.REDIS_SMSCODE_KEY + key);
    }

try {
      validateService.checkCode(key, code);
} catch (CaptchaException e) {
      return Result.error(e.getMessage());
}

异常类:

public class CaptchaException extends Exception{
    public CaptchaException(String message) {
        super(message);
    }
}

202012 月2

Java分页获取文件目录列表工具类


package com.budwk.app.base.utils;

import org.nutz.lang.util.NutMap;

import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.stream.Stream;

/**
 * @author wizzer@qq.com
 */
public class FileUtil {

    /**
     * 分页获取文件列表
     *
     * @param basePath   目录
     * @param pageNumber 页码
     * @param pageSize   页大小
     * @param sort       按文件名排序
     * @return 列表
     * @throws Exception
     */
    public static NutMap readListPage(String basePath, Integer pageNumber, Integer pageSize, String sort)
            throws Exception {
        int offset = (pageNumber - 1) * pageSize;
        int limit = pageNumber * pageSize;
        long total = 0;
        List<NutMap> list = new ArrayList<>();
        Comparator<Path> comparator = Comparator.naturalOrder();
        if ("desc".equals(sort)) {
            comparator = Comparator.reverseOrder();
        }
        try (Stream<Path> fileList = Files.list(Paths.get(basePath))) {
            total = fileList.count();
        }
        try (Stream<Path> fileList = Files.list(Paths.get(basePath)).sorted(comparator).skip(offset)
                .limit(limit)) {
            fileList.forEach(file -> {
                NutMap nutMap = NutMap.NEW();
                String fileName = file.getFileName().toString();
                nutMap.addv("fileName", fileName);
                if (Files.isDirectory(file.toAbsolutePath())) {
                    nutMap.addv("folder", true);
                    nutMap.addv("suffix", "folder");
                } else {
                    String suffix = fileName.substring(fileName.indexOf(".") + 1).toLowerCase();
                    nutMap.addv("folder", false);
                    nutMap.addv("suffix", suffix);
                }
                list.add(nutMap);
            });
            return NutMap.NEW().addv("total", total).addv("list", list);
        }
    }
}

202010 月28

BudWK V6 之微信支付V3开发流程

  • 一、商户后台设置V3 Key密钥及下载V3 API证书(三个文件分别为apiclient_key.pem、apiclient_cert.pem、apiclient_cert.p12)
  • 二、设计表结构实现管理功能
package com.budwk.nb.wx.models;

import com.budwk.nb.commons.base.model.BaseModel;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.nutz.dao.entity.annotation.*;
import org.nutz.dao.interceptor.annotation.PrevInsert;

import java.io.Serializable;

/**
 * 微信支付配置表
 * @author wizzer@qq.com
 */
@Data
@EqualsAndHashCode(callSuper = true)
@Table("wx_pay")
public class Wx_pay extends BaseModel implements Serializable {
    private static final long serialVersionUID = 1L;
    @Column
    @Name
    @Comment("ID")
    @ColDefine(type = ColType.VARCHAR, width = 32)
    @PrevInsert(els = {@EL("uuid()")})
    private String id;

    @Column
    @ColDefine(type = ColType.VARCHAR, width = 32)
    private String name;

    @Column
    @ColDefine(type = ColType.VARCHAR, width = 32)
    private String mchid;

    @Column
    @ColDefine(type = ColType.VARCHAR, width = 50)
    private String v3key;

    /**
     * apiclient_key.pem 物理路径
     */
    @Column
    @ColDefine(type = ColType.VARCHAR, width = 255)
    private String v3keyPath;

    /**
     * apiclient_cert.pem 物理路径
     */
    @Column
    @ColDefine(type = ColType.VARCHAR, width = 255)
    private String v3certPath;

    /**
     * apiclient_cert.p12 物理路径
     */
    @Column
    @ColDefine(type = ColType.VARCHAR, width = 255)
    private String v3certP12Path;

   /**
     * 平台证书失效时间
     */
    @Column
    private Long expire_at;
}
package com.budwk.nb.wx.models;

import com.budwk.nb.commons.base.model.BaseModel;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.nutz.dao.entity.annotation.*;
import org.nutz.dao.interceptor.annotation.PrevInsert;

import java.io.Serializable;

/**
 * 平台证书临存表
 * @author wizzer@qq.com
 */
@Data
@EqualsAndHashCode(callSuper = true)
@Table("wx_pay_cert")
@TableIndexes({@Index(name = "INDEX_WX_PAY_CERT", fields = {"mchid", "serial_no"}, unique = true)})
public class Wx_pay_cert extends BaseModel implements Serializable {
    private static final long serialVersionUID = 1L;
    @Column
    @Name
    @Comment("ID")
    @ColDefine(type = ColType.VARCHAR, width = 32)
    @PrevInsert(els = {@EL("uuid()")})
    private String id;

    @Column
    @ColDefine(type = ColType.VARCHAR, width = 32)
    private String mchid;

    @Column
    @ColDefine(type = ColType.VARCHAR, width = 255)
    private String serial_no;

    @Column
    @ColDefine(type = ColType.VARCHAR, width = 255)
    private String effective_time;

    @Column
    private Long effective_at;

    @Column
    @ColDefine(type = ColType.VARCHAR, width = 255)
    private String expire_time;

    @Column
    private Long expire_at;

    @Column
    @ColDefine(type = ColType.VARCHAR, width = 255)
    private String algorithm;

    @Column
    @ColDefine(type = ColType.VARCHAR, width = 255)
    private String nonce;

    @Column
    @ColDefine(type = ColType.VARCHAR, width = 255)
    private String associated_data;

    @Column
    @ColDefine(type = ColType.TEXT)
    private String ciphertext;

    @Column
    @ColDefine(type = ColType.TEXT)
    private String certificate;
}
  • 三、封装下订单/JSAPI/平台证书更新等功能服务类
package com.budwk.nb.web.commons.ext.wx;

import com.alibaba.dubbo.config.annotation.Reference;
import com.budwk.nb.web.commons.base.Globals;
import com.budwk.nb.wx.models.Wx_pay;
import com.budwk.nb.wx.models.Wx_pay_cert;
import com.budwk.nb.wx.services.WxPayCertService;
import com.budwk.nb.wx.services.WxPayService;
import org.nutz.dao.Chain;
import org.nutz.dao.Cnd;
import org.nutz.ioc.loader.annotation.Inject;
import org.nutz.ioc.loader.annotation.IocBean;
import org.nutz.json.Json;
import org.nutz.lang.Strings;
import org.nutz.lang.Times;
import org.nutz.lang.util.NutMap;
import org.nutz.log.Log;
import org.nutz.log.Logs;
import org.nutz.weixin.bean.WxPay3Response;
import org.nutz.weixin.util.WxPay3Api;
import org.nutz.weixin.util.WxPay3Util;

import java.nio.charset.StandardCharsets;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.List;

/**
 * @author wizzer@qq.com
 */
@IocBean
public class WxPay3Service {
    private static final Log log = Logs.get();
    private static final SimpleDateFormat DATE_TIME_ZONE = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssXXX");
    @Inject
    @Reference(check = false)
    private WxPayCertService wxPayCertService;
    @Inject
    @Reference(check = false)
    private WxPayService wxPayService;

    // 通过商户号获取 wx_pay 对象
    public synchronized Wx_pay getWxPay(String mchid) {
        Wx_pay wxPay = Globals.WxPay3Map.getAs(mchid, Wx_pay.class);
        if (wxPay == null) {
            wxPay = wxPayService.fetch(Cnd.where("mchid", "=", mchid));
            Globals.WxPay3Map.put(wxPay.getMchid(), wxPay);
        }
        checkPlatfromCerts(wxPay);
        return wxPay;
    }

    // 检查及更新平台证书机制
    public void checkPlatfromCerts(Wx_pay wxPay) {
        if (wxPay == null)
            throw new IllegalStateException("Wx_pay is null");
        if (wxPay.getExpire_at() == null || wxPay.getExpire_at() == 0 || wxPay.getExpire_at() < 8 * 3600 * 1000 + System.currentTimeMillis()) {
            getPlatfromCerts(wxPay.getMchid(), wxPay.getV3key(), wxPay.getV3keyPath(), wxPay.getV3certPath());
            wxPay = wxPayService.fetch(Cnd.where("mchid", "=", wxPay.getMchid()));
            Globals.WxPay3Map.put(wxPay.getMchid(), wxPay);
        }
    }

    // jsapi 订单下单
    public WxPay3Response v3_order_jsapi(String mchid, String body) throws Exception {
        log.debug("v3_order_jsapi body::" + body);
        String serialNo = WxPay3Util.getCertSerialNo(getWxPay(mchid).getV3certPath());
        return WxPay3Api.v3_order_jsapi(mchid, serialNo, getWxPay(mchid).getV3keyPath(), body);
    }

    // 通过jsapi 订单号生成js参数
    public NutMap v3_call_jsapi(String mchid, String appid, String prepay_id) throws Exception {
        return WxPay3Util.getJsapiSignMessage(appid, prepay_id, getWxPay(mchid).getV3keyPath());
    }

    // 验证http响应签名结果
    public boolean verifySignature(WxPay3Response wxPay3Response, String mchid) throws Exception {
        Wx_pay_cert wxPayCert = wxPayCertService.fetch(Cnd.where("mchid", "=", mchid).and("serial_no", "=", wxPay3Response.getHeader().get("Wechatpay-Serial")));
        return WxPay3Util.verifySignature(wxPay3Response, wxPayCert.getCertificate());
    }

    // 验证回调通知签名及内容
    public String verifyNotify(String mchid, String serialNo, String body, String signature, String nonce, String timestamp) throws Exception {
        Wx_pay_cert wxPayCert = wxPayCertService.fetch(Cnd.where("mchid", "=", mchid).and("serial_no", "=", serialNo));
        return WxPay3Util.verifyNotify(serialNo, body, signature, nonce, timestamp,
                getWxPay(mchid).getV3key(), wxPayCert.getCertificate());
    }

    /**
     * 请求并保存新证书
     *
     * @param mchid
     * @return
     */
    public void getPlatfromCerts(String mchid, String v3Key, String v3KeyPatch, String v3CertPath) {
        try {
            wxPayCertService.clear(Cnd.where("mchid", "=", mchid).and("expire_at", "<", System.currentTimeMillis()));
            String serialNo = WxPay3Util.getCertSerialNo(v3CertPath);
            WxPay3Response wxPay3Response = WxPay3Api.v3_certificates(mchid, serialNo, v3KeyPatch);
            if (wxPay3Response.getStatus() == 200) {
                NutMap nutMap = Json.fromJson(NutMap.class, wxPay3Response.getBody());
                List<NutMap> list = nutMap.getList("data", NutMap.class);
                for (NutMap cert : list) {
                    Wx_pay_cert wxPayCert = new Wx_pay_cert();
                    wxPayCert.setMchid(mchid);
                    wxPayCert.setEffective_time(cert.getString("effective_time"));
                    wxPayCert.setExpire_time(cert.getString("expire_time"));
                    long expire_at = 0;
                    try {
                        expire_at = Times.parse(DATE_TIME_ZONE, cert.getString("expire_time")).getTime();
                        wxPayCert.setEffective_at(Times.parse(DATE_TIME_ZONE, cert.getString("effective_time")).getTime());
                        wxPayCert.setExpire_at(expire_at);
                    } catch (ParseException e) {
                        e.printStackTrace();
                    }
                    wxPayCert.setSerial_no(cert.getString("serial_no"));
                    NutMap encrypt_certificate = cert.getAs("encrypt_certificate", NutMap.class);
                    wxPayCert.setAlgorithm(encrypt_certificate.getString("algorithm"));
                    wxPayCert.setAssociated_data(encrypt_certificate.getString("associated_data"));
                    wxPayCert.setCiphertext(encrypt_certificate.getString("ciphertext"));
                    wxPayCert.setNonce(encrypt_certificate.getString("nonce"));
                    String platformCertificate = WxPay3Util.decryptToString(v3Key.getBytes(StandardCharsets.UTF_8),
                            encrypt_certificate.getString("associated_data").getBytes(StandardCharsets.UTF_8),
                            encrypt_certificate.getString("nonce").getBytes(StandardCharsets.UTF_8),
                            encrypt_certificate.getString("ciphertext")
                    );
                    wxPayCert.setCertificate(platformCertificate);
                    try {
                        wxPayCertService.insert(wxPayCert);
                    } catch (Exception e) {
                        //重复的插入会报错,不管它
                    }
                }
                Wx_pay_cert wxPayCert = wxPayCertService.fetch(Cnd.where("mchid", "=", mchid).orderBy("effective_at", "desc"));
                if (wxPayCert != null) {
                    wxPayService.update(Chain.make("expire_at", wxPayCert.getExpire_at()), Cnd.where("mchid", "=", mchid));
                }
            }
        } catch (Exception e) {
            log.errorf("获取平台证书失败,mchid=%s", mchid, e);
        }
    }
}
  • 四、小程序支付业务代码
@Test
    public void test_v3_order() throws Exception {
        String orderPayNo = R.UU32();
        String orderId = R.UU32();
        NutMap wxPayUnifiedOrder = NutMap.NEW();
        wxPayUnifiedOrder.addv("appid", appid);
        wxPayUnifiedOrder.addv("mchid", mchid);
        wxPayUnifiedOrder.addv("description", new String(("LaiShop-order-" + orderId).getBytes(), StandardCharsets.UTF_8));
        wxPayUnifiedOrder.addv("out_trade_no", orderPayNo);
        Date now = new Date();
        wxPayUnifiedOrder.addv("time_expire", DateUtil.getDateAfterMinute(now, 30));
        // 回调通知URL传递mchid商户号,便于系统支持接入N个小程序及支付商户账号
        wxPayUnifiedOrder.addv("notify_url", Globals.AppDomain + "/shop/open/wxpay/" + mchid + "/notify");
        wxPayUnifiedOrder.addv("amount", NutMap.NEW().addv("total", 1).addv("currency", "CNY"));
        wxPayUnifiedOrder.addv("payer", NutMap.NEW().addv("openid", "o9Bnd4lXKfNsOci-6H98zCMWyBps"));
        String body = Json.toJson(wxPayUnifiedOrder);
        System.out.println("body::" + body);
        WxPay3Response wxPay3Response = wxPay3Service.v3_order_jsapi(mchid, body);
        System.out.println("wxPay3Response::" + Json.toJson(wxPay3Response));
        boolean verifySignature = wxPay3Service.verifySignature(wxPay3Response, mchid);
        System.out.println("verifySignature::" + verifySignature);
        NutMap v3order = Json.fromJson(NutMap.class, wxPay3Response.getBody());
        NutMap resp = wxPay3Service.v3_call_jsapi(mchid, appid, v3order.getString("prepay_id"));
        System.out.println("resp::" + Json.toJson(resp));
    }
  • 五、回调通知业务代码
package com.budwk.nb.web.controllers.open.pay;

import com.alibaba.dubbo.config.annotation.Reference;
import com.budwk.nb.web.commons.ext.wx.WxPay3Service;
import io.swagger.v3.oas.annotations.OpenAPIDefinition;
import io.swagger.v3.oas.annotations.servers.Server;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.nutz.ioc.loader.annotation.Inject;
import org.nutz.ioc.loader.annotation.IocBean;
import org.nutz.json.Json;
import org.nutz.lang.Streams;
import org.nutz.lang.util.NutMap;
import org.nutz.log.Log;
import org.nutz.log.Logs;
import org.nutz.mvc.adaptor.VoidAdaptor;
import org.nutz.mvc.annotation.AdaptBy;
import org.nutz.mvc.annotation.At;
import org.nutz.mvc.annotation.Ok;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.Reader;
import java.nio.charset.StandardCharsets;

/**
 * @author wizzer@qq.com
 */
@IocBean
@At("/shop/open/wxpay")
@Ok("json")
@OpenAPIDefinition(tags = {@Tag(name = "商城_微信支付回调")}, servers = @Server(url = "/"))
public class WxPay3NotifyController {
    private static final Log log = Logs.get();
    @Inject
    private WxPay3Service wxPay3Service;

    @At("/{mchid}/notify")
    @Ok("raw")
    @AdaptBy(type = VoidAdaptor.class)
    public void notify(String mchid, Reader reader, HttpServletRequest req, HttpServletResponse resp) throws IOException {
        try {
            NutMap map = NutMap.NEW();
            String timestamp = req.getHeader("Wechatpay-Timestamp");
            String nonce = req.getHeader("Wechatpay-Nonce");
            String serialNo = req.getHeader("Wechatpay-Serial");
            String signature = req.getHeader("Wechatpay-Signature");
            log.debugf("timestamp=%s,nonce=%s,serialNo=%s,signature=%s", timestamp, nonce, serialNo, signature);
            String body = Streams.readAndClose(reader);
            // 需要通过证书序列号查找对应的证书,verifyNotify 中有验证证书的序列号
            String plainText = wxPay3Service.verifyNotify(mchid, serialNo, body, signature, nonce, timestamp);
            log.debugf("支付通知明文=%s", plainText);
            NutMap res = Json.fromJson(NutMap.class, plainText);
            NutMap payer = res.getAs("payer", NutMap.class);
            String trade_state = res.getString("trade_state");
            String out_trade_no = res.getString("out_trade_no");
            String openid = payer.getString("openid");
            boolean ok = true;//业务代码入库
            if ("SUCCESS".equals(trade_state) && ok) {
                resp.setStatus(200);
                map.put("code", "SUCCESS");
                map.put("message", "SUCCESS");
            } else {
                resp.setStatus(500);
                map.put("code", "ERROR");
                map.put("message", "签名错误");
            }
            resp.setHeader("Content-type", "application/json");
            resp.getOutputStream().write(Json.toJson(map).getBytes(StandardCharsets.UTF_8));
            resp.flushBuffer();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

本文档以 BudWk 框架代码为例,源码地址: https://gitee.com/budwk/budwk-nutzboot

演示地址: https://demo.budwk.com

20209 月12

群晖NAS DS220+ 入手

前言

为何要入手群晖呢……主要动机是因上段时间,电脑Windows 10 自动更新,重启后找不到SSD硬盘,硬盘数据完全丢失,痛定思痛下血本入手了群晖NAS,哭……

在入群晖之前家里已有软路由(J1900+8G内存+1T SSD),装了爱快+LEDE双系统,做下载机使用。软路由稳定运行一年多,性能尚可,但已无做黑裙等性能升级可能性,加之了解群晖主要的卖点是各类客户端软件,也省得自己折腾了。

家庭网络拓扑图

入手

DS220+ 双盘位

2G内存+免费升级至6G内存 + 酷狼8T硬盘 优惠后4300

PS:入手后才知道有个微信朋友有渠道,从他那买可以便宜500以上,啊啊啊

一块硬盘还是觉得不太安全(一块硬盘做不了raid1啊),但8T实在太贵,只好另加一块4T做备份用,至于这么做备份,后面软件章节介绍。

软件

Moments – 私人相册,利用手机客户端同步手机相册及微信相册

Photo – 家庭相册,将精选的相片放到相册里,可以家人共享也可以分享给其他人

Drive – 核心应用,同步电脑及NAS文件夹

Video – 家庭媒体服务器,占用空间比较大,收藏了N年的电影/科幻片/动画片/周星驰/成龙/宫崎骏等

媒体服务器 – 提供DLNA服务,感觉没“网络邻居”共享文件夹来的速度快

Hyper Backup – 备份任务,将重要文件同步到第二块硬盘(没做raid1的情况下备份利器)

Cloud Sync – 同步百度云数据,百度云比较垃圾啊,又限速又经常断开要重新授权

经验

Video 视频播放没有音频的问题:

详见教程 https://wp.gxnas.com/7561.html

自动安装是不可能的啦,首先要开SSH,获取root权限,然后手动安装ffmpeg

root教程 https://wp.gxnas.com/1385.html

后面配置自动获取电影封面和介绍,也需要root权限哦

Video 电影封面及介绍下载(自动或手动)问题:

获取密钥 https://www.synology.com/zh-cn/knowledgebase/DSM/tutorial/Multimedia/How_to_apply_for_a_personal_API_key_to_get_video_info

更改hosts文件

vi /etc/hosts

31.13.70.9 api.themoviedb.org

噪音问题:

这款NAS风扇一点声音都没有,主要是硬盘读写有咯咯咯的声音,放客厅或弱电箱(靠近餐桌)都能明显听到,最后把它放阳台了,好在装修的时候阳台都预留了网口和电源,网购了一个4U机柜保护一下,防止浇花洒水等碰到。

20209 月12

NutzWk 5.2.7 发布,Java 国产微服务分布式开发框架

本次 v5.2.7 发布带来三个版本:

  • v5.2.7-nacos Nacos 注册中心及配置中心功能微服务版本
  • v5.2.7-zookeeper Zookeeper 注册中心微服务版本
  • v5.2.7-mini 单应用一个 Jar 或 War 即可启动运行版本

技术体系

后端技术:nutzboot(国产,基于国产nutz) + dubbo + redis + shiro + quartz + logback + beetl 等主流技术
前端技术:jquery + vue.js + elementUI 和 jquery + bootstrap 两个版本可选

演示地址

V6演示地址: https://demo.budwk.com (前后端分离 nuxt+vue+elementUI)

V5演示地址: https://nutzwk.wizzer.cn (beetl+html+vue.js+elementUI)

项目介绍

NutzWk(V6起更名为BudWk)发展自2010年,2012年开始用于商业项目,至今已服务于全国各地公司大大小小上千个项目,行业涉及政务、电商、物联网等,随着经验积累及从事行业的不同分别发布了v1.x至v6.x多个版本,每个版本都是完整运行且完全开源免费的,您可以根据项目规模选择不同版本。本项目案例众多,省厅级项目、市级平台、大数据项目、电商平台、物联网平台等等,详见官网 https://budwk.com

源码地址:

V6源码地址: https://gitee.com/budwk/budwk-nutzboot

V1-V5源码地址: https://gitee.com/wizzer/NutzWk

20201 月17

Debian 9 安装 MariaDB root登陆不需要密码问题

CREATE USER 'budwk'@'localhost' IDENTIFIED BY '123';
GRANT ALL PRIVILEGES ON budwk_demo.* TO budwk@localhost;
FLUSH PRIVILEGES;
20198 月2

NutzWk 5.2.6 及 5.2.6-mini 发布,Java 微服务分布式开发框架

项目介绍:

NutzWk 是有五年多历史的Java Web开源开发框架,其5.x 是Java 微服务分布式版本,采用nutzboot(nutz核心)、dubbo、redis、zookeeper、shiro、quartz、beetl、logback、vue、sentinel(流控框架,可选)、seata(分布式事务,可选) 等开源技术的微服务分布式版本,自带系统管理、简易CMS、微信模块、定时任务、服务API等功能,目前已应用于全国各地上千个各类商业项目中。

演示地址(Vue版本): https://nutzwk.wizzer.cn

后端技术架构:nutzboot(国产,基于国产nutz) + dubbo(国产) + redis + zookeeper + shiro + quartz + logback 等主流技术 前端技术架构:vue+ element

NutzWk v5.2.6 更新内容:

  • 修改错误页机制,将前后台404/403/505 错误页严格区分;
  • 修改POJO类,引入 @PrevInsert 注解,在执行fastInsert数据快速入库时有效;
  • 修改web项目,Globals类 Map 对象改为 NutMap 方便开发;
  • 修改vue后台,系统管理中的页面弹出框,改为手动关闭;
  • 修复vue后台,数据字典管理的排序问题;
  • 其他功能的完善,vue页面优化等;
  • 相关jar包及第三方依赖的版本升级;

NutzWk v5.2.6-mini 版本发布:

  • 具有v5.2.6 全部功能的微服务mini版本(系统管理/CMS管理/微信管理/API接口等功能齐全);
  • 管理后台 vue + element;
  • 非分布式,一个jar包即可运行(无dubbo依赖、无需zookepper,只需安装数据库+redis);
  • 非常适合小型项目快速开发;
20193 月19

NutzWk 5.2.0(一周年版) 微服务开发框架,运维中心重磅发布

NutzWk 5.2.0 版本已发布,演示地址: https://nutzwk.wizzer.cn

源码Github:https://github.com/Wizzercn/NutzWk 码云Gitee:https://gitee.com/wizzer/NutzWk

后端技术架构:nutzboot + dubbo + sentinel + redis + zookeeper 前端技术架构:vue.js + element.js

简述: 自 2018.03.20 发布 v5.0.1 第一个微服务分布式版本、2018.11.13 发布 v5.1.0 第一个Vue版本,一年来 NutzWk 根据项目实践及业务需要,逐步完善功能、修复bug、添加新特性,朝着“快速开发、功能丰富、扩展性强、性能优越”,在力所能及的情况下,最大限度的提高Web开发人员的生产力的目标继续前进。

随着项目越做越多,运维成了繁重的工作,本次 v5.2.0 周年版本主要带来了可在线上传jar包、编辑配置文件、关闭实例进程、启动新实例进程、动态修改日志等级、查看服务器资源占用情况等功能,支持分布式部署。详见:发行注记

01 02 03 04
20191 月24

NutzWk 5.1.4 发布,Java 微服务分布式开发框架

NutzWk 5.1.4 Vue版本已发布,演示地址: https://nutzwk.wizzer.cn

源码Github:https://github.com/Wizzercn/NutzWk 码云Gitee:https://gitee.com/wizzer/NutzWk

 

NutzWk 5.1.4 更新内容:

  • * 集成 Sentinel 流控框架,支持流量控制、熔断降级、系统负载保护等(默认不启用);
  • * 日志系统从 log4j 改为 logback,编写starter-logback-exts 方便微服务模块调用(默认启用);
  • * 新增系统监控功能,后台可查看运行实例的进程ID、运行时间、JVM内存情况等,并可在不重启的情况下动态修改各微服务模块的日志等级;
  • * 系统微服务模块原 daocache 数据库缓存改为 wkcache 方法缓存,支持分布式部署;
  • * 为每个微服务模块瘦身,去掉多余的依赖包;
  • * 一些第三方依赖包的版本升级;
  • * 一些功能的修复及完善;

 

NutzWk 是 Java 微服务分布式开发框架,5.x 是采用nutzboot、nutz、dubbo、sentinel、redis、zookeeper、shiro、quartz、beetl、logback等开源技术的微服务分布式版本,自带系统管理、简易CMS、微信模块、定时任务、服务API等功能,目前已全面应用于各类商业项目中。

201811 月12

NutzWk 5.1.0 微服务开发框架,Vue版本已发布

NutzWk 5.1.0 Vue版本已发布,演示地址: https://nutzwk.wizzer.cn

源码Github:https://github.com/Wizzercn/NutzWk 码云Gitee:https://gitee.com/wizzer/NutzWk

本次更新内容:

  • wk-nb-web-vue 新增全新的Vue后台管理界面,基于Vue.js + Element.js 等,增强交互体验;
  • 基础服务类 BaseService 新增一些常用的查询方法;
  • 微信模块增加图片自动回复、群发图片、微信菜单可配小程序等功能;
  • CMS模块增加前台模板标签示例代码;
  • 增强Oracle及MySQL兼容性;
  • 支持Openjdk 11;

后端技术架构:java nutzboot + dubbo + zookeeper 前端技术架构:vue.js + element.js + bootstrap

20187 月19

MqttWk: 基于nutzboot + t-io + redis + kafka 实现的MQTT服务端开源项目

项目首页:https://github.com/Wizzercn/MqttWk

MqttWk

基于 nutzboot + t-io + redis + kafka 实现的MQTT服务broker

本项目代码主要来源于 netty/t-io/iot-mqtt-server 等众多项目,开源免费,欢迎交流学习

参考项目

使用说明

软件架构说明

  1. 使用t-io实现通信及协议解析
  2. 使用nutzboot提供依赖注入及属性配置
  3. 使用redis实现消息缓存,集群
  4. 使用kafka实现消息代理

项目结构

MqttWk
  ├── mqtt-codec -- MQTT协议解析的t-io实现
  ├── mqtt-auth -- MQTT服务连接时用户名和密码认证
  ├── mqtt-broker -- MQTT服务器功能的核心实现
  ├── mqtt-common -- 公共类及其他模块使用的服务接口及对象
  ├── mqtt-store -- MQTT服务器会话信息(redis缓存及kafka加载)
  ├── mqtt-zoo -- 教程文档或文件
    ├── mqtt-test-kafka -- kafka消费者接收消息
    ├── mqtt-test-websocket -- websocket通信测试示例

功能说明

  1. 参考MQTT3.1.1规范实现
  2. 完整的QoS服务质量等级实现
  3. 遗嘱消息, 保留消息及消息分发重试
  4. 心跳机制
  5. MQTT连接认证(可选择是否开启)
  6. SSL方式连接(可选择是否开启)
  7. 主题过滤(支持单主题订阅如 /mqtt/test –不可以/结尾, 通配符订阅 /mqtt/# –以/#结尾)
  8. Websocket支持(可选择是否开启)
  9. 集群功能

快速开始

  • 下载已打包好的可运行的jar文件
  • 运行jar文件(如果需要修改配置项,可以在application.properties修改)
  • 打开mqtt-spy客户端, 填写相应配置下载
  • 连接端口:8885, websocket 端口: 9995 websocket path: /mqtt
  • 连接使用的用户名: demo
  • 连接使用的密码: 8F3B8DE2FDC8BD3D792BE77EAC412010971765E5BDD6C499ADCEE840CE441BDEF17E30684BD95CA708F55022222CC6161D0D23C2DFCB12F8AC998F59E7213393
  • 连接使用的证书在 mqtt-zoo\keystore\server.cer

集群使用

  • 多机环境集群:
    • mqttwk.broker.kafka.bootstrap.servers=192.168.1.101:9092,192.168.1.102:9093
    • redis.mode=cluster
    • redis.nodes=192.168.1.103:16379,192.168.1.104:26379
  • 单机环境集群:
    • mqttwk.broker.kafka.bootstrap.servers=127.0.0.1:9092,127.0.0.1:9093
    • redis.mode=normal
    • redis.host=127.0.0.1

自定义 – 连接认证

  • 默认只是简单使用对用户名进行RSA密钥对加密生成密码, 连接认证时对密码进行解密和相应用户名进行匹配认证
  • 使用中如果需要实现连接数据库或其他方式进行连接认证, 只需要重写mqtt-auth模块下的相应方法即可

自定义 – 服务端证书

  • 服务端证书存储在mqtt-brokerresources/keystore/server.jks
  • 用户可以制作自己的证书, 但存储位置和文件名必须使用上述描述的位置及文件名

生成环境部署

  • 生成环境部署建议使用keepalived+nginx+mqtt-broker方式
  • 使用nginx的tcp和websocket反向代理mqtt-broker集群实现负载均衡
  • 使用keepalived实现nginx的高可用
20186 月9

NutzWk 5.0.x 微服务分布式版本开发及部署说明

NutzWk 5.x 已发布一段时间,这段时间基于此版本开发了智慧水务系统(NB-IOT)、某物联网平台、某设备租赁平台、某智慧睡眠平台、某智慧园区项目等,开发和部署过程中遇到一些小问题,开这个帖子把一些经验分享出来省的大家走弯路。

项目地址1: https://github.com/Wizzercn/NutzWk 项目地址2: https://gitee.com/wizzer/NutzWk

1、运行环境 其实项目readme和wk-wiki 已经写的很清楚了,在此强调一下,不是说非这些版本不可,但对于新手来说最好版本号保持一致,能跑起来了您再折腾玩~~

<span class="pln">JDK </span>
<span class="lit">8</span> <span class="lit">162</span> <span class="pun">+</span>
<span class="typ">Maven</span> <span class="lit">3.5</span>
<span class="pun">.</span>
<span class="lit">3</span> <span class="pun">+</span>
<span class="typ">Redis</span> <span class="lit">4.0</span>
<span class="pun">.</span>
<span class="lit">8</span> <span class="pun">+</span>
<span class="typ">MySql</span> <span class="lit">5.7</span> <span class="pun">+</span>
<span class="typ">Zookeeper</span> <span class="lit">3.4</span>
<span class="pun">.</span>
<span class="lit">11</span> <span class="pun">+</span>

2、开发环境 一般建议使用IDEA进行开发,因为是maven多模块的项目,直接用IDEA打开项目根目录,它会通过maven下载jar包,自动构建项目 然后如何启动项目呢,有很多种方式,简单说几个: 1)打开每个NB项目(nutzboot简称)项目里的main类,右击运行,例如 cn.wizzer.sys.commons.core.***MainLauncher 2)通过IDEA 的Run 配置 Application 运行,详见 https://github.com/Wizzercn/NutzWk/blob/nutzboot-dubbo/wk-wiki/01.QuickStart/01.02.Start.md 3)命令行在NB项目根目录运行mvn compile nutzboot:run 或者IDEA右侧Maven管理界面里通过插件运行,,详见 https://github.com/nutzam/nutzboot-maven-plugin

3、启动顺序 保证MySQL、Redis、Zookeeper 都正常启动且为默认端口及默认配置(当然这些配置项可以在application.properties 修改的) 1)MySQL创建一个空白数据库,编码格式为UTF-8,数据库名称 nutzwk_nb 2)NB项目的模块启动顺序是 sys –> cms[可选] –> wx[可选] –> task[可选] –> web-platform –> web-api[可选] 3)如上所述,如果想运行访问后台,只需要启动 sys 和 web-platform即可,注意是有启动顺序的,其他模块需要用就启 4)task 定时任务是依赖于sys的,而web-platform系统管理对定时任务管理是依赖于 task模块的,如果你想让task独立运行并且不需要通过页面进行管理,自己少做改动即可,不是不可以哦

4、部署注意事项 1)因为登录页面对密码进行了RSA加密,有时候部署会遇到怎么也登录不了,而后台抛异常 java.lang.SecurityException: JCE cannot authenticate the provider BC 的情况,解决方法在代码注释里已写明了,不过很少有人去看 https://github.com/Wizzercn/NutzWk/blob/nutzboot-dubbo/wk-app/wk-nb-web-platform/src/main/java/cn/wizzer/app/web/commons/shiro/filter/PlatformAuthenticationFilter.java

<span class="lit">1</span>
<span class="pun">、编辑文件</span> <span class="pun">/</span>
<span class="pln">usr</span>
<span class="pun">/</span>
<span class="pln">java</span>
<span class="pun">/</span>
<span class="pln">jdk1</span>
<span class="pun">.</span>
<span class="lit">8.0</span>
<span class="pln">_162</span>
<span class="pun">/</span>
<span class="pln">jre</span>
<span class="pun">/</span>
<span class="pln">lib</span>
<span class="pun">/</span>
<span class="pln">security</span>
<span class="pun">/</span>
<span class="pln">java</span>
<span class="pun">.</span>
<span class="pln">security
     </span>
<span class="pun">在</span>
<span class="lit">9</span>
<span class="pun">下面添加</span>
<span class="pln"> security</span>
<span class="pun">.</span>
<span class="pln">provider</span>
<span class="pun">.</span>
<span class="lit">10</span>
<span class="pun">=</span>
<span class="pln">org</span>
<span class="pun">.</span>
<span class="pln">bouncycastle</span>
<span class="pun">.</span>
<span class="pln">jce</span>
<span class="pun">.</span>
<span class="pln">provider</span>
<span class="pun">.</span>
<span class="typ">BouncyCastleProvider</span>
<span class="lit">2</span>
<span class="pun">、拷贝</span>
<span class="pln"> bcprov</span>
<span class="pun">-</span>
<span class="pln">jdk16</span>
<span class="pun">-</span>
<span class="lit">143.jar</span> <span class="pun">和</span>
<span class="pln"> bcprov</span>
<span class="pun">-</span>
<span class="pln">jdk15</span>
<span class="pun">-</span>
<span class="lit">135.jar</span> <span class="pun">到</span> <span class="pun">/</span>
<span class="pln">usr</span>
<span class="pun">/</span>
<span class="pln">java</span>
<span class="pun">/</span>
<span class="pln">jdk1</span>
<span class="pun">.</span>
<span class="lit">8.0</span>
<span class="pln">_162</span>
<span class="pun">/</span>
<span class="pln">jre</span>
<span class="pun">/</span>
<span class="pln">lib</span>
<span class="pun">/</span>
<span class="pln">ext </span>
<span class="pun">目录下</span>
<span class="lit">3</span>
<span class="pun">、别问我上面两个文件怎么找……</span>

(如果您是https的话可以把RSA加密方式改掉弃用哦) 2)服务器注意事项:服务器时间同步做没做、hosts里配没配主机名hostname和127.0.0.1的映射关系、内存够不够用(有没有给jar指定内存大小)等

5、其他 1)请关注 NutzWk 的动态,有新的版本发布建议及时更新,往往会修复问题或新增功能 2)如果 NutzWk 给了您帮助,或已用于生产, https://wizzer.cn/donation 欢迎打赏一定金额以资鼓励,创造国内良好的开源环境 3)最后感谢兽兽及nutz社区广大网友的帮助和鼓励,没有您们的支持,这个项目不会历经6年多还在更新前进

20184 月24

Java代码中使用代理

//设置代理  
System.setProperty("http.proxySet", "true");  
System.setProperty("http.proxyHost", "127.0.0.1");  
System.setProperty("http.proxyPort", "1080");
20182 月26

利用nutz+t-io实现硬件设备的socket通信

 

1、MainServer 启动类

/**
 * Created by Wizzer on 2018/2/26.
 */
@IocBean
public class MainServer {
    private static final Log log = Logs.get();

    public static void main(String[] args) {
        try {
            ComboIocLoader loader = new ComboIocLoader(
                    new String[]{"*json", "config/ioc/", "*anno", "cn.wizzer","*rabbitmq"}
            );
            NutIoc ioc = new NutIoc(loader);
            //socket
            ioc.get(SocketServer.class).init();
            //http
            ioc.get(HttpServer.class).init();
            //mq
            String topicQueue = "sweeper-tioTopicQueue";
            ConnectionFactory factory = ioc.get(ConnectionFactory.class, "rabbitmq_cf");
            Connection rabbitmq_conn = factory.newConnection();
            Channel rabbitmq_channel = rabbitmq_conn.createChannel();
            rabbitmq_channel.queueDeclare(topicQueue, true, false, false, null);
            rabbitmq_channel.exchangeDeclare("sweeper-tioTopicExchange", BuiltinExchangeType.TOPIC, true);
            rabbitmq_channel.queueBind(topicQueue, "sweeper-tioTopicExchange", "tio.#");

        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

 

2、SocketServer 数据接收

 

/**
 * Created by Wizzer on 2018/2/26.
 */
@IocBean
public class SocketServer {
    private static final Log log = Logs.get();
    //handler, 包括编码、解码、消息处理
    @Inject
    private MyServerAioHandler myServerAioHandler;
    //事件监听器,可以为null,但建议自己实现该接口,可以参考showcase了解些接口
    private ServerAioListener aioListener;
    //一组连接共用的上下文对象
    private ServerGroupContext serverGroupContext;
    //aioServer对象
    private AioServer aioServer;
    //有时候需要绑定ip,不需要则null
    private String serverIp;
    @Inject
    private PropertiesProxy conf;

    public void init() throws Exception {
        int port = conf.getInt("server.socket.port", 8600);
        log.debug("socket port::" + port);
        serverGroupContext = new ServerGroupContext("tio", myServerAioHandler, aioListener);
        serverGroupContext.setHeartbeatTimeout(30000);
        aioServer = new AioServer(serverGroupContext);
        aioServer.start(serverIp, port);
    }
}

3、socket 数据包的解析

4、RabbitMQ 队列+消费者 实现数据入库

5、HttpServer 提供HTTP API用于对设备发送命令

6、socket 命令包的下发

 

源码:https://gitee.com/wizzer/demo



20181 月21

Elasticsearch 6.1.2 (二)分页查询、排序、关键词查询,集合beetl实现前台展示

后台代码,自定义tag:

<span class="kwd">package</span>
<span class="pln"> cn</span>
<span class="pun">.</span>
<span class="pln">wizzer</span>
<span class="pun">.</span>
<span class="pln">app</span>
<span class="pun">.</span>
<span class="pln">web</span>
<span class="pun">.</span>
<span class="pln">modules</span>
<span class="pun">.</span>
<span class="pln">tags</span>
<span class="pun">;</span>

<span class="kwd">import</span>
<span class="pln"> cn</span>
<span class="pun">.</span>
<span class="pln">wizzer</span>
<span class="pun">.</span>
<span class="pln">app</span>
<span class="pun">.</span>
<span class="pln">web</span>
<span class="pun">.</span>
<span class="pln">commons</span>
<span class="pun">.</span>
<span class="pln">ex</span>
<span class="pun">.</span>
<span class="pln">elasticsearch</span>
<span class="pun">.</span>
<span class="typ">EsService</span>
<span class="pun">;</span>
<span class="kwd">import</span>
<span class="pln"> cn</span>
<span class="pun">.</span>
<span class="pln">wizzer</span>
<span class="pun">.</span>
<span class="pln">app</span>
<span class="pun">.</span>
<span class="pln">web</span>
<span class="pun">.</span>
<span class="pln">commons</span>
<span class="pun">.</span>
<span class="pln">utils</span>
<span class="pun">.</span>
<span class="typ">YcDateUtil</span>
<span class="pun">;</span>
<span class="kwd">import</span>
<span class="pln"> cn</span>
<span class="pun">.</span>
<span class="pln">wizzer</span>
<span class="pun">.</span>
<span class="pln">app</span>
<span class="pun">.</span>
<span class="pln">ycold</span>
<span class="pun">.</span>
<span class="pln">modules</span>
<span class="pun">.</span>
<span class="pln">services</span>
<span class="pun">.</span>
<span class="typ">YcoldInquiryService</span>
<span class="pun">;</span>
<span class="kwd">import</span>
<span class="pln"> cn</span>
<span class="pun">.</span>
<span class="pln">wizzer</span>
<span class="pun">.</span>
<span class="pln">framework</span>
<span class="pun">.</span>
<span class="pln">page</span>
<span class="pun">.</span>
<span class="typ">Pagination</span>
<span class="pun">;</span>
<span class="kwd">import</span>
<span class="pln"> org</span>
<span class="pun">.</span>
<span class="pln">apache</span>
<span class="pun">.</span>
<span class="pln">commons</span>
<span class="pun">.</span>
<span class="pln">lang3</span>
<span class="pun">.</span>
<span class="typ">BooleanUtils</span>
<span class="pun">;</span>
<span class="kwd">import</span>
<span class="pln"> org</span>
<span class="pun">.</span>
<span class="pln">apache</span>
<span class="pun">.</span>
<span class="pln">commons</span>
<span class="pun">.</span>
<span class="pln">lang3</span>
<span class="pun">.</span>
<span class="typ">StringUtils</span>
<span class="pun">;</span>
<span class="kwd">import</span>
<span class="pln"> org</span>
<span class="pun">.</span>
<span class="pln">apache</span>
<span class="pun">.</span>
<span class="pln">commons</span>
<span class="pun">.</span>
<span class="pln">lang3</span>
<span class="pun">.</span>
<span class="pln">math</span>
<span class="pun">.</span>
<span class="typ">NumberUtils</span>
<span class="pun">;</span>
<span class="kwd">import</span>
<span class="pln"> org</span>
<span class="pun">.</span>
<span class="pln">beetl</span>
<span class="pun">.</span>
<span class="pln">core</span>
<span class="pun">.</span>
<span class="typ">GeneralVarTagBinding</span>
<span class="pun">;</span>
<span class="kwd">import</span>
<span class="pln"> org</span>
<span class="pun">.</span>
<span class="pln">elasticsearch</span>
<span class="pun">.</span>
<span class="pln">action</span>
<span class="pun">.</span>
<span class="pln">search</span>
<span class="pun">.</span>
<span class="typ">SearchRequestBuilder</span>
<span class="pun">;</span>
<span class="kwd">import</span>
<span class="pln"> org</span>
<span class="pun">.</span>
<span class="pln">elasticsearch</span>
<span class="pun">.</span>
<span class="pln">action</span>
<span class="pun">.</span>
<span class="pln">search</span>
<span class="pun">.</span>
<span class="typ">SearchResponse</span>
<span class="pun">;</span>
<span class="kwd">import</span>
<span class="pln"> org</span>
<span class="pun">.</span>
<span class="pln">elasticsearch</span>
<span class="pun">.</span>
<span class="pln">action</span>
<span class="pun">.</span>
<span class="pln">search</span>
<span class="pun">.</span>
<span class="typ">SearchType</span>
<span class="pun">;</span>
<span class="kwd">import</span>
<span class="pln"> org</span>
<span class="pun">.</span>
<span class="pln">elasticsearch</span>
<span class="pun">.</span>
<span class="pln">common</span>
<span class="pun">.</span>
<span class="pln">text</span>
<span class="pun">.</span>
<span class="typ">Text</span>
<span class="pun">;</span>
<span class="kwd">import</span>
<span class="pln"> org</span>
<span class="pun">.</span>
<span class="pln">elasticsearch</span>
<span class="pun">.</span>
<span class="pln">index</span>
<span class="pun">.</span>
<span class="pln">query</span>
<span class="pun">.</span>
<span class="typ">BoolQueryBuilder</span>
<span class="pun">;</span>
<span class="kwd">import</span>
<span class="pln"> org</span>
<span class="pun">.</span>
<span class="pln">elasticsearch</span>
<span class="pun">.</span>
<span class="pln">index</span>
<span class="pun">.</span>
<span class="pln">query</span>
<span class="pun">.</span>
<span class="typ">QueryBuilders</span>
<span class="pun">;</span>
<span class="kwd">import</span>
<span class="pln"> org</span>
<span class="pun">.</span>
<span class="pln">elasticsearch</span>
<span class="pun">.</span>
<span class="pln">search</span>
<span class="pun">.</span>
<span class="typ">SearchHits</span>
<span class="pun">;</span>
<span class="kwd">import</span>
<span class="pln"> org</span>
<span class="pun">.</span>
<span class="pln">elasticsearch</span>
<span class="pun">.</span>
<span class="pln">search</span>
<span class="pun">.</span>
<span class="pln">fetch</span>
<span class="pun">.</span>
<span class="pln">subphase</span>
<span class="pun">.</span>
<span class="pln">highlight</span>
<span class="pun">.</span>
<span class="typ">HighlightBuilder</span>
<span class="pun">;</span>
<span class="kwd">import</span>
<span class="pln"> org</span>
<span class="pun">.</span>
<span class="pln">elasticsearch</span>
<span class="pun">.</span>
<span class="pln">search</span>
<span class="pun">.</span>
<span class="pln">fetch</span>
<span class="pun">.</span>
<span class="pln">subphase</span>
<span class="pun">.</span>
<span class="pln">highlight</span>
<span class="pun">.</span>
<span class="typ">HighlightField</span>
<span class="pun">;</span>
<span class="kwd">import</span>
<span class="pln"> org</span>
<span class="pun">.</span>
<span class="pln">elasticsearch</span>
<span class="pun">.</span>
<span class="pln">search</span>
<span class="pun">.</span>
<span class="pln">sort</span>
<span class="pun">.</span>
<span class="typ">SortOrder</span>
<span class="pun">;</span>
<span class="kwd">import</span>
<span class="pln"> org</span>
<span class="pun">.</span>
<span class="pln">nutz</span>
<span class="pun">.</span>
<span class="pln">ioc</span>
<span class="pun">.</span>
<span class="pln">impl</span>
<span class="pun">.</span>
<span class="typ">PropertiesProxy</span>
<span class="pun">;</span>
<span class="kwd">import</span>
<span class="pln"> org</span>
<span class="pun">.</span>
<span class="pln">nutz</span>
<span class="pun">.</span>
<span class="pln">ioc</span>
<span class="pun">.</span>
<span class="pln">loader</span>
<span class="pun">.</span>
<span class="pln">annotation</span>
<span class="pun">.</span>
<span class="typ">Inject</span>
<span class="pun">;</span>
<span class="kwd">import</span>
<span class="pln"> org</span>
<span class="pun">.</span>
<span class="pln">nutz</span>
<span class="pun">.</span>
<span class="pln">ioc</span>
<span class="pun">.</span>
<span class="pln">loader</span>
<span class="pun">.</span>
<span class="pln">annotation</span>
<span class="pun">.</span>
<span class="typ">IocBean</span>
<span class="pun">;</span>
<span class="kwd">import</span>
<span class="pln"> org</span>
<span class="pun">.</span>
<span class="pln">nutz</span>
<span class="pun">.</span>
<span class="pln">lang</span>
<span class="pun">.</span>
<span class="typ">Strings</span>
<span class="pun">;</span>
<span class="kwd">import</span>
<span class="pln"> org</span>
<span class="pun">.</span>
<span class="pln">nutz</span>
<span class="pun">.</span>
<span class="pln">lang</span>
<span class="pun">.</span>
<span class="typ">Times</span>
<span class="pun">;</span>
<span class="kwd">import</span>
<span class="pln"> org</span>
<span class="pun">.</span>
<span class="pln">nutz</span>
<span class="pun">.</span>
<span class="pln">log</span>
<span class="pun">.</span>
<span class="typ">Log</span>
<span class="pun">;</span>
<span class="kwd">import</span>
<span class="pln"> org</span>
<span class="pun">.</span>
<span class="pln">nutz</span>
<span class="pun">.</span>
<span class="pln">log</span>
<span class="pun">.</span>
<span class="typ">Logs</span>
<span class="pun">;</span>

<span class="kwd">import</span>
<span class="pln"> java</span>
<span class="pun">.</span>
<span class="pln">util</span>
<span class="pun">.</span>
<span class="typ">ArrayList</span>
<span class="pun">;</span>
<span class="kwd">import</span>
<span class="pln"> java</span>
<span class="pun">.</span>
<span class="pln">util</span>
<span class="pun">.</span>
<span class="typ">Date</span>
<span class="pun">;</span>
<span class="kwd">import</span>
<span class="pln"> java</span>
<span class="pun">.</span>
<span class="pln">util</span>
<span class="pun">.</span>
<span class="typ">List</span>
<span class="pun">;</span>
<span class="kwd">import</span>
<span class="pln"> java</span>
<span class="pun">.</span>
<span class="pln">util</span>
<span class="pun">.</span>
<span class="typ">Map</span>
<span class="pun">;</span>

<span class="com">/**
 * Created by wizzer on 2018/1/20.
 */</span>
<span class="lit">@IocBean</span>
<span class="kwd">public</span> <span class="kwd">class</span> <span class="typ">YcoldInquiryListTag</span> <span class="kwd">extends</span> <span class="typ">GeneralVarTagBinding</span> <span class="pun">{</span>
    <span class="kwd">private</span> <span class="kwd">final</span> <span class="kwd">static</span> <span class="typ">Log</span>
<span class="pln"> log </span>
<span class="pun">=</span> <span class="typ">Logs</span>
<span class="pun">.</span>
<span class="kwd">get</span>
<span class="pun">();</span>
    <span class="lit">@Inject</span>
    <span class="kwd">private</span> <span class="typ">EsService</span>
<span class="pln"> esService</span>
<span class="pun">;</span>
    <span class="lit">@Inject</span>
    <span class="kwd">private</span> <span class="typ">YcoldInquiryService</span>
<span class="pln"> ycoldInquiryService</span>
<span class="pun">;</span>
    <span class="lit">@Inject</span>
    <span class="kwd">private</span> <span class="typ">PropertiesProxy</span>
<span class="pln"> cfg</span>
<span class="pun">;</span>

    <span class="lit">@Override</span>
    <span class="kwd">public</span> <span class="kwd">void</span>
<span class="pln"> render</span>
<span class="pun">()</span> <span class="pun">{</span>
        <span class="typ">String</span>
<span class="pln"> startDate </span>
<span class="pun">=</span> <span class="typ">Strings</span>
<span class="pun">.</span>
<span class="pln">sNull</span>
<span class="pun">(</span>
<span class="kwd">this</span>
<span class="pun">.</span>
<span class="pln">getAttributeValue</span>
<span class="pun">(</span>
<span class="str">"startDate"</span>
<span class="pun">));</span>
        <span class="typ">String</span>
<span class="pln"> endDate </span>
<span class="pun">=</span> <span class="typ">Strings</span>
<span class="pun">.</span>
<span class="pln">sNull</span>
<span class="pun">(</span>
<span class="kwd">this</span>
<span class="pun">.</span>
<span class="pln">getAttributeValue</span>
<span class="pun">(</span>
<span class="str">"endDate"</span>
<span class="pun">));</span>
        <span class="typ">String</span>
<span class="pln"> keyword </span>
<span class="pun">=</span> <span class="typ">Strings</span>
<span class="pun">.</span>
<span class="pln">sNull</span>
<span class="pun">(</span>
<span class="kwd">this</span>
<span class="pun">.</span>
<span class="pln">getAttributeValue</span>
<span class="pun">(</span>
<span class="str">"keyword"</span>
<span class="pun">));</span>
        <span class="kwd">int</span>
<span class="pln"> pageNumber </span>
<span class="pun">=</span> <span class="typ">NumberUtils</span>
<span class="pun">.</span>
<span class="pln">toInt</span>
<span class="pun">(</span>
<span class="typ">Strings</span>
<span class="pun">.</span>
<span class="pln">sNull</span>
<span class="pun">(</span>
<span class="kwd">this</span>
<span class="pun">.</span>
<span class="pln">getAttributeValue</span>
<span class="pun">(</span>
<span class="str">"pageNumber"</span>
<span class="pun">)),</span> <span class="lit">1</span>
<span class="pun">);</span>
        <span class="kwd">int</span>
<span class="pln"> pageSize </span>
<span class="pun">=</span> <span class="typ">NumberUtils</span>
<span class="pun">.</span>
<span class="pln">toInt</span>
<span class="pun">(</span>
<span class="typ">Strings</span>
<span class="pun">.</span>
<span class="pln">sNull</span>
<span class="pun">(</span>
<span class="kwd">this</span>
<span class="pun">.</span>
<span class="pln">getAttributeValue</span>
<span class="pun">(</span>
<span class="str">"pageSize"</span>
<span class="pun">)),</span> <span class="lit">10</span>
<span class="pun">);</span>
        <span class="kwd">boolean</span>
<span class="pln"> highlight </span>
<span class="pun">=</span> <span class="typ">BooleanUtils</span>
<span class="pun">.</span>
<span class="pln">toBoolean</span>
<span class="pun">(</span>
<span class="typ">Strings</span>
<span class="pun">.</span>
<span class="pln">sNull</span>
<span class="pun">(</span>
<span class="kwd">this</span>
<span class="pun">.</span>
<span class="pln">getAttributeValue</span>
<span class="pun">(</span>
<span class="str">"highlight"</span>
<span class="pun">)));</span>
        <span class="kwd">boolean</span>
<span class="pln"> explain </span>
<span class="pun">=</span> <span class="typ">BooleanUtils</span>
<span class="pun">.</span>
<span class="pln">toBoolean</span>
<span class="pun">(</span>
<span class="typ">Strings</span>
<span class="pun">.</span>
<span class="pln">sNull</span>
<span class="pun">(</span>
<span class="kwd">this</span>
<span class="pun">.</span>
<span class="pln">getAttributeValue</span>
<span class="pun">(</span>
<span class="str">"explain"</span>
<span class="pun">)));</span>
        <span class="typ">String</span>
<span class="pln"> sortName </span>
<span class="pun">=</span> <span class="typ">Strings</span>
<span class="pun">.</span>
<span class="pln">sNull</span>
<span class="pun">(</span>
<span class="kwd">this</span>
<span class="pun">.</span>
<span class="pln">getAttributeValue</span>
<span class="pun">(</span>
<span class="str">"sortName"</span>
<span class="pun">));</span>
        <span class="typ">String</span>
<span class="pln"> sortOrder </span>
<span class="pun">=</span> <span class="typ">Strings</span>
<span class="pun">.</span>
<span class="pln">sNull</span>
<span class="pun">(</span>
<span class="kwd">this</span>
<span class="pun">.</span>
<span class="pln">getAttributeValue</span>
<span class="pun">(</span>
<span class="str">"sortOrder"</span>
<span class="pun">));</span>
        <span class="typ">Pagination</span>
<span class="pln"> page </span>
<span class="pun">=</span> <span class="kwd">new</span> <span class="typ">Pagination</span>
<span class="pun">();</span>
<span class="pln">
        page</span>
<span class="pun">.</span>
<span class="pln">setPageNo</span>
<span class="pun">(</span>
<span class="pln">pageNumber</span>
<span class="pun">);</span>
<span class="pln">
        page</span>
<span class="pun">.</span>
<span class="pln">setPageSize</span>
<span class="pun">(</span>
<span class="pln">pageSize</span>
<span class="pun">);</span>
        <span class="kwd">try</span> <span class="pun">{</span>
            <span class="typ">BoolQueryBuilder</span>
<span class="pln"> query </span>
<span class="pun">=</span> <span class="typ">QueryBuilders</span>
<span class="pun">.</span>
<span class="pln">boolQuery</span>
<span class="pun">();</span>
            <span class="com">//根据名称查询</span>
            <span class="kwd">if</span> <span class="pun">(</span>
<span class="typ">Strings</span>
<span class="pun">.</span>
<span class="pln">isNotBlank</span>
<span class="pun">(</span>
<span class="pln">keyword</span>
<span class="pun">))</span> <span class="pun">{</span>
<span class="pln">
                query</span>
<span class="pun">.</span>
<span class="pln">must</span>
<span class="pun">(</span>
<span class="typ">QueryBuilders</span>
<span class="pun">.</span>
<span class="pln">wildcardQuery</span>
<span class="pun">(</span>
<span class="str">"CASNM"</span>
<span class="pun">,</span> <span class="str">"*"</span> <span class="pun">+</span>
<span class="pln"> keyword </span>
<span class="pun">+</span> <span class="str">"*"</span>
<span class="pun">));</span>
            <span class="pun">}</span>
            <span class="com">//截止时间大于等于现在</span>
<span class="pln">
            query</span>
<span class="pun">.</span>
<span class="pln">must</span>
<span class="pun">(</span>
<span class="typ">QueryBuilders</span>
<span class="pun">.</span>
<span class="pln">rangeQuery</span>
<span class="pun">(</span>
<span class="str">"IQDAT"</span>
<span class="pun">).</span>
<span class="pln">gte</span>
<span class="pun">(</span>
<span class="typ">Times</span>
<span class="pun">.</span>
<span class="pln">format</span>
<span class="pun">(</span>
<span class="str">"yyyyMMddHHmmss"</span>
<span class="pun">,</span> <span class="kwd">new</span> <span class="typ">Date</span>
<span class="pun">())));</span>
            <span class="com">//公共日期起</span>
            <span class="kwd">if</span> <span class="pun">(</span>
<span class="typ">Strings</span>
<span class="pun">.</span>
<span class="pln">isNotBlank</span>
<span class="pun">(</span>
<span class="pln">startDate</span>
<span class="pun">))</span> <span class="pun">{</span>
<span class="pln">
                query</span>
<span class="pun">.</span>
<span class="pln">must</span>
<span class="pun">(</span>
<span class="typ">QueryBuilders</span>
<span class="pun">.</span>
<span class="pln">rangeQuery</span>
<span class="pun">(</span>
<span class="str">"ANNODAT"</span>
<span class="pun">).</span>
<span class="pln">gte</span>
<span class="pun">(</span>
<span class="pln">startDate</span>
<span class="pun">.</span>
<span class="pln">replaceAll</span>
<span class="pun">(</span>
<span class="str">"-"</span>
<span class="pun">,</span>
<span class="str">""</span>
<span class="pun">)));</span>
            <span class="pun">}</span>
            <span class="com">//公共日期至</span>
            <span class="kwd">if</span> <span class="pun">(</span>
<span class="typ">Strings</span>
<span class="pun">.</span>
<span class="pln">isNotBlank</span>
<span class="pun">(</span>
<span class="pln">endDate</span>
<span class="pun">))</span> <span class="pun">{</span>
<span class="pln">
                query</span>
<span class="pun">.</span>
<span class="pln">must</span>
<span class="pun">(</span>
<span class="typ">QueryBuilders</span>
<span class="pun">.</span>
<span class="pln">rangeQuery</span>
<span class="pun">(</span>
<span class="str">"ANNODAT"</span>
<span class="pun">).</span>
<span class="pln">lte</span>
<span class="pun">(</span>
<span class="pln">endDate</span>
<span class="pun">.</span>
<span class="pln">replaceAll</span>
<span class="pun">(</span>
<span class="str">"-"</span>
<span class="pun">,</span>
<span class="str">""</span>
<span class="pun">)));</span>
            <span class="pun">}</span>
            <span class="com">//几个状态条件</span>
<span class="pln">
            query</span>
<span class="pun">.</span>
<span class="pln">must</span>
<span class="pun">(</span>
<span class="typ">QueryBuilders</span>
<span class="pun">.</span>
<span class="pln">matchQuery</span>
<span class="pun">(</span>
<span class="str">"BUYER_STS"</span>
<span class="pun">,</span> <span class="str">"N"</span>
<span class="pun">));</span>
<span class="com">//采购商状态</span>
<span class="pln">
            query</span>
<span class="pun">.</span>
<span class="pln">must</span>
<span class="pun">(</span>
<span class="typ">QueryBuilders</span>
<span class="pun">.</span>
<span class="pln">matchQuery</span>
<span class="pun">(</span>
<span class="str">"STS"</span>
<span class="pun">,</span> <span class="str">"A"</span>
<span class="pun">));</span>
<span class="com">//状态</span>
<span class="pln">
            query</span>
<span class="pun">.</span>
<span class="pln">must</span>
<span class="pun">(</span>
<span class="typ">QueryBuilders</span>
<span class="pun">.</span>
<span class="pln">matchQuery</span>
<span class="pun">(</span>
<span class="str">"ANNOMK"</span>
<span class="pun">,</span> <span class="str">"Y"</span>
<span class="pun">));</span>
<span class="com">//公告註記</span>
            <span class="typ">SearchRequestBuilder</span>
<span class="pln"> srb </span>
<span class="pun">=</span>
<span class="pln"> esService</span>
<span class="pun">.</span>
<span class="pln">getClient</span>
<span class="pun">().</span>
<span class="pln">prepareSearch</span>
<span class="pun">(</span>
<span class="pln">cfg</span>
<span class="pun">.</span>
<span class="kwd">get</span>
<span class="pun">(</span>
<span class="str">"es.index.name"</span>
<span class="pun">))</span>
                    <span class="pun">.</span>
<span class="pln">setSearchType</span>
<span class="pun">(</span>
<span class="typ">SearchType</span>
<span class="pun">.</span>
<span class="pln">DFS_QUERY_THEN_FETCH</span>
<span class="pun">)</span>
                    <span class="pun">.</span>
<span class="pln">setTypes</span>
<span class="pun">(</span>
<span class="str">"inquiry"</span>
<span class="pun">)</span>
                    <span class="pun">.</span>
<span class="pln">setQuery</span>
<span class="pun">(</span>
<span class="pln">query</span>
<span class="pun">)</span>
                    <span class="com">//分页</span>
                    <span class="pun">.</span>
<span class="pln">setFrom</span>
<span class="pun">((</span>
<span class="pln">pageNumber </span>
<span class="pun">-</span> <span class="lit">1</span>
<span class="pun">)</span> <span class="pun">*</span>
<span class="pln"> pageSize</span>
<span class="pun">).</span>
<span class="pln">setSize</span>
<span class="pun">(</span>
<span class="pln">pageSize</span>
<span class="pun">)</span>
                    <span class="com">//是否按匹配度排序</span>
                    <span class="pun">.</span>
<span class="pln">setExplain</span>
<span class="pun">(</span>
<span class="pln">explain</span>
<span class="pun">);</span>

            <span class="kwd">if</span> <span class="pun">(</span>
<span class="pln">highlight</span>
<span class="pun">)</span> <span class="pun">{</span>
                <span class="typ">HighlightBuilder</span>
<span class="pln"> highlightBuilder </span>
<span class="pun">=</span> <span class="kwd">new</span> <span class="typ">HighlightBuilder</span>
<span class="pun">().</span>
<span class="pln">field</span>
<span class="pun">(</span>
<span class="str">"*"</span>
<span class="pun">).</span>
<span class="pln">requireFieldMatch</span>
<span class="pun">(</span>
<span class="kwd">false</span>
<span class="pun">);</span>
<span class="pln">
                highlightBuilder</span>
<span class="pun">.</span>
<span class="pln">preTags</span>
<span class="pun">(</span>
<span class="str">"<span style=\"color:red\">"</span>
<span class="pun">);</span>
<span class="pln">
                highlightBuilder</span>
<span class="pun">.</span>
<span class="pln">postTags</span>
<span class="pun">(</span>
<span class="str">"</span>"</span>
<span class="pun">);</span>
<span class="pln">
                srb</span>
<span class="pun">.</span>
<span class="pln">highlighter</span>
<span class="pun">(</span>
<span class="pln">highlightBuilder</span>
<span class="pun">);</span>
            <span class="pun">}</span>
            <span class="kwd">if</span> <span class="pun">(</span>
<span class="typ">Strings</span>
<span class="pun">.</span>
<span class="pln">isNotBlank</span>
<span class="pun">(</span>
<span class="pln">sortName</span>
<span class="pun">))</span> <span class="pun">{</span>
                <span class="typ">String</span>
<span class="pun">[]</span>
<span class="pln"> sortNames </span>
<span class="pun">=</span> <span class="typ">StringUtils</span>
<span class="pun">.</span>
<span class="pln">split</span>
<span class="pun">(</span>
<span class="pln">sortName</span>
<span class="pun">,</span> <span class="str">","</span>
<span class="pun">);</span>
                <span class="kwd">if</span> <span class="pun">(</span>
<span class="str">"asc"</span>
<span class="pun">.</span>
<span class="pln">equalsIgnoreCase</span>
<span class="pun">(</span>
<span class="pln">sortOrder</span>
<span class="pun">))</span> <span class="pun">{</span>
                    <span class="kwd">for</span> <span class="pun">(</span>
<span class="typ">String</span>
<span class="pln"> s </span>
<span class="pun">:</span>
<span class="pln"> sortNames</span>
<span class="pun">)</span> <span class="pun">{</span>
<span class="pln">
                        srb</span>
<span class="pun">.</span>
<span class="pln">addSort</span>
<span class="pun">(</span>
<span class="pln">s</span>
<span class="pun">,</span> <span class="typ">SortOrder</span>
<span class="pun">.</span>
<span class="pln">ASC</span>
<span class="pun">);</span>
                    <span class="pun">}</span>
                <span class="pun">}</span> <span class="kwd">else</span> <span class="pun">{</span>
                    <span class="kwd">for</span> <span class="pun">(</span>
<span class="typ">String</span>
<span class="pln"> s </span>
<span class="pun">:</span>
<span class="pln"> sortNames</span>
<span class="pun">)</span> <span class="pun">{</span>
<span class="pln">
                        srb</span>
<span class="pun">.</span>
<span class="pln">addSort</span>
<span class="pun">(</span>
<span class="pln">s</span>
<span class="pun">,</span> <span class="typ">SortOrder</span>
<span class="pun">.</span>
<span class="pln">DESC</span>
<span class="pun">);</span>
                    <span class="pun">}</span>
                <span class="pun">}</span>
            <span class="pun">}</span>
<span class="pln">
            log</span>
<span class="pun">.</span>
<span class="pln">debug</span>
<span class="pun">(</span>
<span class="str">"srb:::\r\n"</span> <span class="pun">+</span>
<span class="pln"> srb</span>
<span class="pun">.</span>
<span class="pln">toString</span>
<span class="pun">());</span>

            <span class="typ">SearchResponse</span>
<span class="pln"> response </span>
<span class="pun">=</span>
<span class="pln"> srb</span>
<span class="pun">.</span>
<span class="pln">execute</span>
<span class="pun">().</span>
<span class="pln">actionGet</span>
<span class="pun">();</span>
            <span class="typ">SearchHits</span>
<span class="pln"> hits </span>
<span class="pun">=</span>
<span class="pln"> response</span>
<span class="pun">.</span>
<span class="pln">getHits</span>
<span class="pun">();</span>
<span class="pln">
            page</span>
<span class="pun">.</span>
<span class="pln">setTotalCount</span>
<span class="pun">((</span>
<span class="kwd">int</span>
<span class="pun">)</span>
<span class="pln"> hits</span>
<span class="pun">.</span>
<span class="pln">getTotalHits</span>
<span class="pun">());</span>
            <span class="typ">List</span>
<span class="pun"><</span>
<span class="typ">Map</span>
<span class="pun"><</span>
<span class="typ">String</span>
<span class="pun">,</span> <span class="typ">Object</span>
<span class="pun">>></span>
<span class="pln"> list </span>
<span class="pun">=</span> <span class="kwd">new</span> <span class="typ">ArrayList</span>
<span class="pun"><>();</span>
<span class="pln">
            hits</span>
<span class="pun">.</span>
<span class="pln">forEach</span>
<span class="pun">(</span>
<span class="pln">searchHit </span>
<span class="pun">-></span> <span class="pun">{</span>
                <span class="typ">Map</span>
<span class="pun"><</span>
<span class="typ">String</span>
<span class="pun">,</span> <span class="typ">Object</span>
<span class="pun">></span>
<span class="pln"> source </span>
<span class="pun">=</span>
<span class="pln"> searchHit</span>
<span class="pun">.</span>
<span class="pln">getSourceAsMap</span>
<span class="pun">();</span>
                <span class="typ">Map</span>
<span class="pun"><</span>
<span class="typ">String</span>
<span class="pun">,</span> <span class="typ">HighlightField</span>
<span class="pun">></span>
<span class="pln"> highlightFields </span>
<span class="pun">=</span>
<span class="pln"> searchHit</span>
<span class="pun">.</span>
<span class="pln">getHighlightFields</span>
<span class="pun">();</span>
                <span class="com">//name高亮</span>
                <span class="typ">HighlightField</span>
<span class="pln"> nameField </span>
<span class="pun">=</span>
<span class="pln"> highlightFields</span>
<span class="pun">.</span>
<span class="kwd">get</span>
<span class="pun">(</span>
<span class="str">"CASNM"</span>
<span class="pun">);</span>
                <span class="kwd">if</span> <span class="pun">(</span>
<span class="pln">nameField </span>
<span class="pun">!=</span> <span class="kwd">null</span>
<span class="pun">)</span> <span class="pun">{</span>
                    <span class="typ">Text</span>
<span class="pun">[]</span>
<span class="pln"> fragments </span>
<span class="pun">=</span>
<span class="pln"> nameField</span>
<span class="pun">.</span>
<span class="pln">fragments</span>
<span class="pun">();</span>
                    <span class="typ">String</span>
<span class="pln"> tmp </span>
<span class="pun">=</span> <span class="str">""</span>
<span class="pun">;</span>
                    <span class="kwd">for</span> <span class="pun">(</span>
<span class="typ">Text</span>
<span class="pln"> text </span>
<span class="pun">:</span>
<span class="pln"> fragments</span>
<span class="pun">)</span> <span class="pun">{</span>
<span class="pln">
                        tmp </span>
<span class="pun">+=</span>
<span class="pln"> text</span>
<span class="pun">;</span>
                    <span class="pun">}</span>
<span class="pln">
                    source</span>
<span class="pun">.</span>
<span class="pln">put</span>
<span class="pun">(</span>
<span class="str">"CASNM"</span>
<span class="pun">,</span>
<span class="pln"> tmp</span>
<span class="pun">);</span>
                <span class="pun">}</span>
<span class="pln">
                source</span>
<span class="pun">.</span>
<span class="pln">put</span>
<span class="pun">(</span>
<span class="str">"IQDAT"</span>
<span class="pun">,</span> <span class="typ">YcDateUtil</span>
<span class="pun">.</span>
<span class="pln">get_yyyyMMdd_HHmm</span>
<span class="pun">(</span>
<span class="typ">Strings</span>
<span class="pun">.</span>
<span class="pln">sNull</span>
<span class="pun">(</span>
<span class="pln">source</span>
<span class="pun">.</span>
<span class="kwd">get</span>
<span class="pun">(</span>
<span class="str">"IQDAT"</span>
<span class="pun">))));</span>
<span class="pln">
                source</span>
<span class="pun">.</span>
<span class="pln">put</span>
<span class="pun">(</span>
<span class="str">"ANNODAT"</span>
<span class="pun">,</span> <span class="typ">YcDateUtil</span>
<span class="pun">.</span>
<span class="pln">get_yyyyMMdd</span>
<span class="pun">(</span>
<span class="typ">Strings</span>
<span class="pun">.</span>
<span class="pln">sNull</span>
<span class="pun">(</span>
<span class="pln">source</span>
<span class="pun">.</span>
<span class="kwd">get</span>
<span class="pun">(</span>
<span class="str">"ANNODAT"</span>
<span class="pun">))));</span>
<span class="pln">
                list</span>
<span class="pun">.</span>
<span class="pln">add</span>
<span class="pun">(</span>
<span class="pln">source</span>
<span class="pun">);</span>
            <span class="pun">});</span>
<span class="pln">
            page</span>
<span class="pun">.</span>
<span class="pln">setList</span>
<span class="pun">(</span>
<span class="pln">list</span>
<span class="pun">);</span>
        <span class="pun">}</span> <span class="kwd">catch</span> <span class="pun">(</span>
<span class="typ">Exception</span>
<span class="pln"> e</span>
<span class="pun">)</span> <span class="pun">{</span>
<span class="pln">
            e</span>
<span class="pun">.</span>
<span class="pln">printStackTrace</span>
<span class="pun">();</span>
        <span class="pun">}</span>
        <span class="kwd">this</span>
<span class="pun">.</span>
<span class="pln">binds</span>
<span class="pun">(</span>
<span class="pln">page</span>
<span class="pun">);</span>
        <span class="kwd">this</span>
<span class="pun">.</span>
<span class="pln">doBodyRender</span>
<span class="pun">();</span>
    <span class="pun">}</span>
<span class="pun">}</span>

前台beetl页面:

<span class="pln">  <#ycold_inquiry_list pageNumber="${pageNumber}" pageSize="${pageSize}" startDate="${startDate}" endDate="${endDate}" keyword="${keyword}" sortName="ANNODAT" sortOrder="desc" highlight="false" var="p">

    </span>
<span class="tag"><table</span> <span class="atn">class</span>
<span class="pun">=</span>
<span class="atv">"list_table_blue even_table"</span>
<span class="tag">></span>
        <span class="tag"><thead></span>
        <span class="tag"><tr></span>
            <span class="tag"><th></span>
<span class="pln">公告日期</span>
<span class="tag"></th></span>
            <span class="tag"><th></span>
<span class="pln">案件名称</span>
<span class="tag"></th></span>
            <span class="tag"><th></span>
<span class="pln">交货地点</span>
<span class="tag"></th></span>
            <span class="tag"><th></span>
<span class="pln">报价截止日期</span>
<span class="tag"></th></span>
            <span class="tag"><th</span> <span class="atn">width</span>
<span class="pun">=</span>
<span class="atv">"110"</span>
<span class="tag">></span>
<span class="pln">查看详细</span>
<span class="tag"></th></span>
        <span class="tag"></tr></span>
        <span class="tag"></thead></span>
        <span class="tag"><tbody></span>
        <span class="pun"><%</span>
<span class="kwd">for</span>
<span class="pun">(</span>
<span class="pln">o </span>
<span class="kwd">in</span>
<span class="pln"> p</span>
<span class="pun">.</span>
<span class="pln">list</span>
<span class="pun">){</span>
<span class="pln">%>
        </span>
<span class="tag"><tr></span>
            <span class="tag"><td></span>
<span class="pln">${o.ANNODAT!}</span>
<span class="tag"></td></span>
            <span class="tag"><td</span> <span class="atn">class</span>
<span class="pun">=</span>
<span class="atv">"l_text"</span>
<span class="tag">><a</span> <span class="atn">href</span>
<span class="pun">=</span>
<span class="atv">"${base!}/purchase/info/${o.XUID!}"</span> <span class="atn">target</span>
<span class="pun">=</span>
<span class="atv">"_blank"</span> <span class="atn">class</span>
<span class="pun">=</span>
<span class="atv">"td_a hide1"</span>
<span class="tag">></span>
<span class="pln">${o.CASNM!}</span>
<span class="tag"></a></span>
            <span class="tag"></td></span>
            <span class="tag"><td</span> <span class="atn">class</span>
<span class="pun">=</span>
<span class="atv">"l_text"</span>
<span class="tag">></span>
<span class="pln">${o.DLSITE!}</span>
<span class="tag"></td></span>
            <span class="tag"><td></span>
<span class="pln">${o.IQDAT!}</span>
<span class="tag"></td></span>
            <span class="tag"><td><a</span> <span class="atn">href</span>
<span class="pun">=</span>
<span class="atv">"${base!}/purchase/info/${o.XUID!}"</span> <span class="atn">target</span>
<span class="pun">=</span>
<span class="atv">"_blank"</span> <span class="atn">class</span>
<span class="pun">=</span>
<span class="atv">"more_a png"</span>
<span class="tag">></a></td></span>
        <span class="tag"></tr></span>
        <span class="pun"><%}</span>
<span class="pln">%>
        </span>
<span class="tag"></tbody></span>
    <span class="tag"></table></span>
    <span class="pun"><%</span>
<span class="kwd">if</span>
<span class="pun">(</span>
<span class="pln">p</span>
<span class="pun">.</span>
<span class="pln">totalCount</span>
<span class="pun">></span>
<span class="lit">1</span>
<span class="pun">){</span>
<span class="pln">%>
    </span>
<span class="tag"><div</span> <span class="atn">class</span>
<span class="pun">=</span>
<span class="atv">"page round_s_a"</span>
<span class="tag">></div></span>
    <span class="tag"><script</span> <span class="atn">type</span>
<span class="pun">=</span>
<span class="atv">"text/javascript"</span>
<span class="tag">></span>
<span class="pln">
        $</span>
<span class="pun">(</span>
<span class="kwd">function</span> <span class="pun">()</span> <span class="pun">{</span>
<span class="pln">
            $</span>
<span class="pun">(</span>
<span class="str">".page"</span>
<span class="pun">).</span>
<span class="pln">createPage</span>
<span class="pun">({</span>
<span class="pln">
                pageCount</span>
<span class="pun">:</span>
<span class="pln"> $</span>
<span class="pun">{</span>
<span class="pln">p</span>
<span class="pun">.</span>
<span class="pln">totalPage</span>
<span class="pun">},</span>
<span class="pln">
                totalCount</span>
<span class="pun">:</span>
<span class="pln"> $</span>
<span class="pun">{</span>
<span class="pln">p</span>
<span class="pun">.</span>
<span class="pln">totalCount</span>
<span class="pun">},</span>
<span class="pln">
                current</span>
<span class="pun">:</span>
<span class="pln"> $</span>
<span class="pun">{</span>
<span class="pln">p</span>
<span class="pun">.</span>
<span class="pln">pageNo</span>
<span class="pun">},</span>
<span class="pln">
                backFn</span>
<span class="pun">:</span> <span class="kwd">function</span> <span class="pun">(</span>
<span class="pln">p</span>
<span class="pun">)</span> <span class="pun">{</span>
<span class="pln">
                    window</span>
<span class="pun">.</span>
<span class="pln">location</span>
<span class="pun">.</span>
<span class="pln">href </span>
<span class="pun">=</span> <span class="str">"?page="</span> <span class="pun">+</span>
<span class="pln"> p </span>
<span class="pun">+</span> <span class="str">"&size=${p.pageSize}"</span>
<span class="pun">;</span>
                <span class="pun">}</span>
            <span class="pun">});</span>
        <span class="pun">});</span>
    <span class="tag"></script></span>
    <span class="pun"><%}</span>
<span class="pln">%></span>
20181 月21

Elasticsearch 6.1.2 (一)中文分词设置、字符串字段排序设置

<span class="kwd">if</span> <span class="pun">(!</span>
<span class="pln">esService</span>
<span class="pun">.</span>
<span class="pln">isExistsType</span>
<span class="pun">(</span>
<span class="pln">cfg</span>
<span class="pun">.</span>
<span class="kwd">get</span>
<span class="pun">(</span>
<span class="str">"es.index.name"</span>
<span class="pun">),</span>
<span class="pln"> type</span>
<span class="pun">))</span> <span class="pun">{</span>
                <span class="com">//初始化索引表</span>
                <span class="typ">XContentBuilder</span>
<span class="pln"> mapping </span>
<span class="pun">=</span>
<span class="pln"> jsonBuilder</span>
<span class="pun">().</span>
<span class="pln">startObject</span>
<span class="pun">()</span>
                        <span class="pun">.</span>
<span class="pln">startObject</span>
<span class="pun">(</span>
<span class="pln">type</span>
<span class="pun">)</span>
                        <span class="pun">.</span>
<span class="pln">startObject</span>
<span class="pun">(</span>
<span class="str">"_all"</span>
<span class="pun">)</span>
<span class="com">//设置IK分词</span>
                        <span class="pun">.</span>
<span class="pln">field</span>
<span class="pun">(</span>
<span class="str">"analyzer"</span>
<span class="pun">,</span> <span class="str">"ik_max_word"</span>
<span class="pun">)</span>
                        <span class="pun">.</span>
<span class="pln">field</span>
<span class="pun">(</span>
<span class="str">"search_analyzer"</span>
<span class="pun">,</span> <span class="str">"ik_max_word"</span>
<span class="pun">)</span>
                        <span class="pun">.</span>
<span class="pln">field</span>
<span class="pun">(</span>
<span class="str">"term_vector"</span>
<span class="pun">,</span> <span class="str">"no"</span>
<span class="pun">)</span>
                        <span class="pun">.</span>
<span class="pln">field</span>
<span class="pun">(</span>
<span class="str">"store"</span>
<span class="pun">,</span> <span class="str">"false"</span>
<span class="pun">)</span>
                        <span class="pun">.</span>
<span class="pln">endObject</span>
<span class="pun">()</span>
                        <span class="pun">.</span>
<span class="pln">startObject</span>
<span class="pun">(</span>
<span class="str">"properties"</span>
<span class="pun">)</span>
                        <span class="pun">.</span>
<span class="pln">startObject</span>
<span class="pun">(</span>
<span class="str">"CASNM"</span>
<span class="pun">).</span>
<span class="pln">field</span>
<span class="pun">(</span>
<span class="str">"type"</span>
<span class="pun">,</span> <span class="str">"text"</span>
<span class="pun">).</span>
<span class="pln">field</span>
<span class="pun">(</span>
<span class="str">"analyzer"</span>
<span class="pun">,</span> <span class="str">"ik_max_word"</span>
<span class="pun">).</span>
<span class="pln">endObject</span>
<span class="pun">()</span>
                        <span class="pun">.</span>
<span class="pln">startObject</span>
<span class="pun">(</span>
<span class="str">"IQDAT"</span>
<span class="pun">).</span>
<span class="pln">field</span>
<span class="pun">(</span>
<span class="str">"type"</span>
<span class="pun">,</span> <span class="str">"text"</span>
<span class="pun">).</span>
<span class="pln">field</span>
<span class="pun">(</span>
<span class="str">"index"</span>
<span class="pun">,</span> <span class="str">"true"</span>
<span class="pun">).</span>
<span class="pln">field</span>
<span class="pun">(</span>
<span class="str">"fielddata"</span>
<span class="pun">,</span>
<span class="str">"true"</span>
<span class="pun">).</span>
<span class="pln">endObject</span>
<span class="pun">()</span>
                        <span class="pun">.</span>
<span class="pln">startObject</span>
<span class="pun">(</span>
<span class="str">"ANNODAT"</span>
<span class="pun">).</span>
<span class="pln">field</span>
<span class="pun">(</span>
<span class="str">"type"</span>
<span class="pun">,</span> <span class="str">"text"</span>
<span class="pun">).</span>
<span class="pln">field</span>
<span class="pun">(</span>
<span class="str">"index"</span>
<span class="pun">,</span> <span class="str">"true"</span>
<span class="pun">).</span>
<span class="pln">field</span>
<span class="pun">(</span>
<span class="str">"fielddata"</span>
<span class="pun">,</span>
<span class="str">"true"</span>
<span class="pun">).</span>
<span class="pln">endObject</span>
<span class="pun">()</span>
                        <span class="pun">.</span>
<span class="pln">endObject</span>
<span class="pun">()</span>
                        <span class="pun">.</span>
<span class="pln">endObject</span>
<span class="pun">()</span>
                        <span class="pun">.</span>
<span class="pln">endObject</span>
<span class="pun">();</span>
<span class="pln">
                esService</span>
<span class="pun">.</span>
<span class="pln">putMapping</span>
<span class="pun">(</span>
<span class="pln">cfg</span>
<span class="pun">.</span>
<span class="kwd">get</span>
<span class="pun">(</span>
<span class="str">"es.index.name"</span>
<span class="pun">),</span> <span class="str">"inquiry"</span>
<span class="pun">,</span>
<span class="pln"> mapping</span>
<span class="pun">);</span>
            <span class="pun">}</span>

    <span class="com">/**
     * @param indexName 索引名
     * @param type      数据类型(表名)
     * @param mapping   mapping对象
     */</span>
    <span class="kwd">public</span> <span class="kwd">boolean</span>
<span class="pln"> putMapping</span>
<span class="pun">(</span>
<span class="typ">String</span>
<span class="pln"> indexName</span>
<span class="pun">,</span> <span class="typ">String</span>
<span class="pln"> type</span>
<span class="pun">,</span> <span class="typ">XContentBuilder</span>
<span class="pln"> mapping</span>
<span class="pun">)</span> <span class="pun">{</span>
        <span class="typ">PutMappingRequest</span>
<span class="pln"> mappingRequest </span>
<span class="pun">=</span> <span class="typ">Requests</span>
<span class="pun">.</span>
<span class="pln">putMappingRequest</span>
<span class="pun">(</span>
<span class="pln">indexName</span>
<span class="pun">).</span>
<span class="pln">type</span>
<span class="pun">(</span>
<span class="pln">type</span>
<span class="pun">).</span>
<span class="pln">source</span>
<span class="pun">(</span>
<span class="pln">mapping</span>
<span class="pun">);</span>
        <span class="typ">PutMappingResponse</span>
<span class="pln"> response </span>
<span class="pun">=</span>
<span class="pln"> getClient</span>
<span class="pun">().</span>
<span class="pln">admin</span>
<span class="pun">().</span>
<span class="pln">indices</span>
<span class="pun">().</span>
<span class="pln">putMapping</span>
<span class="pun">(</span>
<span class="pln">mappingRequest</span>
<span class="pun">).</span>
<span class="pln">actionGet</span>
<span class="pun">();</span>
        <span class="kwd">return</span>
<span class="pln"> response</span>
<span class="pun">.</span>
<span class="pln">isAcknowledged</span>
<span class="pun">();</span>
    <span class="pun">}</span>

.field(“fielddata”,”true”) //text字段默认不允许排序,是单独设置数据格式

20179 月15

使用Java API绘制验证码图片

import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.io.OutputStream;
import java.util.Random;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * 生成验证码,将验证码绘制成一张图片返回浏览器
 * 
 * @author FreeDroid
 *
 */
public class CheckcodeServlet extends HttpServlet {
    private static final long serialVersionUID = 1L;

    public void service(HttpServletRequest request, 
              HttpServletResponse response) throws 
                     ServletException, IOException {
        /*
         * step1.绘图
         */
        Random r = new Random();
        //从getString()方法取出A-Z,0-9的指定长度随机字符串
        String number = getString(5);
        //先创建一个画布(内存映像对象)
        BufferedImage image = new BufferedImage(80, 30, BufferedImage.TYPE_INT_BGR);
        //获得画笔
        Graphics g = image.getGraphics();
        //给画笔设置颜色
        g.setColor(new Color(255, 255, 255));
        //给画布设置背景颜色
        g.fillRect(0, 0, 80, 30);
        //设置字体
        g.setFont(new Font(null, Font.BOLD|Font.ITALIC, 20));
        //给每个字符设置随机颜色,并画到画布上
        for (int i = 0; i < number.length(); i++) {
            //给画笔设置颜色
            g.setColor(new Color(r.nextInt(255),r.nextInt(255),r.nextInt(255)));
            //在画布上画字符
            g.drawString(String.valueOf(number.charAt(i)), i*15, 25);
        }
        //加一些干扰线
        for (int i = 0; i < 8; i++) {
            //给画笔设置颜色
            g.setColor(new Color(r.nextInt(255),r.nextInt(255),r.nextInt(255)));
            //在画布范围内画线
            g.drawLine(r.nextInt(80), r.nextInt(30), r.nextInt(80), r.nextInt(30));
        }

        /*
         * step2.将图片压缩,然后输出
         */
        //设置响应内容类型为JPEG格式的图片
        response.setContentType("image/jpeg");
        //获得字节输出流(图片是二进制数据)
        OutputStream os = response.getOutputStream();
        //将原始图片(image)按照指定的算法压缩(jpeg)
                //然后将压缩之后得到的字节写入response对象。
        javax.imageio.ImageIO.write(image, "jpeg", os);
        os.close();     
    }

    /**
     * 随机生成指定长度的大写字母和数字组合
     * @param length
     * @return
     */
    private String getString(int length) {
        StringBuilder str = new StringBuilder();
        Random r = new Random();
        //取出大写字母
        for (int i = 0; i < 26; i++) {
            str.append((char) ('A' + i));
        }
        //取出数字
        for (int i = 0; i < 10; i++) {
            str.append((char) ('0' + i));
        }
        //从字符串str随机取length个字符放进str2组成新的字符串
        StringBuilder str2 = new StringBuilder();
        for (int i = 0; i < length; i++) {
            str2.append(str.charAt(r.nextInt(str.length())));
        }
        return str2.toString();
    }

}
20178 月11

UTF-8中文字符编码和解码,用位运算实现

/**
 * UTF中文字符编码和解码
 * 中文字符占3个字节,前缀分别是:1110XXXX 10XXXXXX 10XXXXXX
 * 
 * @author FreeDroid
 *
 */
public class Utf8codeANDdecode {

    public static void main(String[] args) {
        int ch = '我';
        byte[] bytes = codeUTF8(ch);
        char ch2 = decodeUTF8(bytes);
        System.out.println(ch2);
    }

    /**
     * 解码
     * @param bytes
     * @return
     */
    public static char decodeUTF8(byte[] bytes) {
        int ch = (bytes[0]<<12&0xffff)|(bytes[1]<>> 6 & 0x3f | 0x80;
        int b1 = ch >>> 12 & 0xf | 0xe0;
        return new byte[] { (byte) b1, (byte) b2, (byte) b3 };
    }

}
20177 月30

同名文件自动建立副本递归实现

public void newFile(File file){
    try {
        if (file.createNewFile()) {
            System.out.println("文件创建成功!");
        } else {
            String cName = changeName(file);
            File files = new File("." + File.separator + cName);
            newFile(files);
        }
    } catch (IOException e) {
        e.printStackTrace();
    }
}
public String changeName(File file) {
    String name = file.getName();
    int index = name.lastIndexOf('.');
    int index2 = name.lastIndexOf("_副本");
    if (index2 < 0) {
        return name.substring(0, index) + "_副本1" + name.substring(index);
    } else {
        String num = name.substring(index2+3, index);
        int i = Integer.valueOf(num)+1;
        return name.substring(0, index2) + "_副本" + i + name.substring(index);
    }
}
20173 月23

NutzWk: 微信AccessToken没有持久化造成超出调用限制的问题解决

1、wx_config 实体类添加三个字段,对应的表结构也要手动修改:

    @Column
    @Comment("access_token")
    @ColDefine(type = ColType.VARCHAR, width = 255)
    private String access_token;

    @Column
    @Comment("access_token_expires")
    @ColDefine(type = ColType.INT)
    private Integer access_token_expires;

    @Column
    @Comment("access_token_lastat")
    @ColDefine(type = ColType.VARCHAR, width = 50)
    private String access_token_lastat;

    get  set ...方法生成出来

2、nutzwx版本升级为1.r.61-SNAPSHOT

        
            org.nutz
            nutzwx
            1.r.61-SNAPSHOT
        

3、nutz版本升级为1.r.60

        
            org.nutz
            nutz
            1.r.60
        

4、WxConfigService 类getWxApi2替换为如下代码(主要是DaoAccessTokenStore从数据库取access_token)

    public WxApi2 getWxApi2(String wxid) {
        Wx_config appInfo = this.fetch(Cnd.where("id", "=", wxid));
        DaoAccessTokenStore myDaoAccessTokenStore = new DaoAccessTokenStore(dao());
        Map params = new HashMap();
        params.put("id", appInfo.getId());
        myDaoAccessTokenStore.setTableAccessToken("access_token");
        myDaoAccessTokenStore.setTableAccessTokenExpires("access_token_expires");
        myDaoAccessTokenStore.setTableAccessTokenLastat("access_token_lastat");
        myDaoAccessTokenStore.setFetch("select access_token,access_token_expires,access_token_lastat from wx_config where id=@id");
        myDaoAccessTokenStore.setUpdate("update wx_config set access_token=@access_token, access_token_expires=@access_token_expires, access_token_lastat=@access_token_lastat where id=@id");
        myDaoAccessTokenStore.setParams(params);
        WxApi2Impl wxApi2 = new WxApi2Impl();
        wxApi2.setAppid(appInfo.getAppid());
        wxApi2.setAppsecret(appInfo.getAppsecret());
        wxApi2.setEncodingAesKey(appInfo.getEncodingAESKey());
        wxApi2.setToken(appInfo.getToken());
        wxApi2.setAccessTokenStore(myDaoAccessTokenStore);
        return wxApi2;
    }