Vue ElmentUI 趟过的坑-1
1、el-tabs 中放置 el-tree 使用 this.$ref[‘tree’] 获取不到对象
使用 this.$ref[‘tree’][0] 可以取到
2、el-cascader 动态加载行政区划,修改表单时无法初始化选中的值
需要设置属性 :key=”xx” ,在数据加载完成后让 xx ++ 自加1
1、el-tabs 中放置 el-tree 使用 this.$ref[‘tree’] 获取不到对象
使用 this.$ref[‘tree’][0] 可以取到
2、el-cascader 动态加载行政区划,修改表单时无法初始化选中的值
需要设置属性 :key=”xx” ,在数据加载完成后让 xx ++ 自加1
rpm -ivh TDengine-server-2.0.18.0-Linux-x64.rpm
vi /etc/taos/taos.cfg
加上当前服务器 hostname 主机名# first fully qualified domain name (FQDN) for TDengine system
firstEp wizzer-test:6030
# local fully qualified domain name (FQDN)
fqdn wizzer-test
taos
或 taos -h 127.0.0.1
执行数据库创建命令taos > create database test;
C:\Windows\System32\drivers\etc\hosts
ip wizzer-test
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.budwk</groupId>
<artifactId>test</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<nutzboot.version>2.4.2-SNAPSHOT</nutzboot.version>
<jaxb-api.version>2.3.1</jaxb-api.version>
<slf4j.version>1.7.25</slf4j.version>
<logback.version>1.2.3</logback.version>
<taos-jdbcdriver.version>2.0.23</taos-jdbcdriver.version>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
</properties>
<dependencies>
<dependency>
<groupId>org.nutz</groupId>
<artifactId>nutzboot-core</artifactId>
</dependency>
<dependency>
<groupId>org.nutz</groupId>
<artifactId>nutzboot-starter-nutz-dao</artifactId>
</dependency>
<dependency>
<groupId>org.nutz</groupId>
<artifactId>nutzboot-starter-jdbc</artifactId>
</dependency>
<dependency>
<groupId>com.taosdata.jdbc</groupId>
<artifactId>taos-jdbcdriver</artifactId>
<version>${taos-jdbcdriver.version}</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>${slf4j.version}</version>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-core</artifactId>
<version>${logback.version}</version>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>${logback.version}</version>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.nutz</groupId>
<artifactId>nutzboot-parent</artifactId>
<version>${nutzboot.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<repositories>
<repository>
<id>nutz</id>
<url>http://jfrog.nutz.cn/artifactory/libs-release</url>
</repository>
<repository>
<id>nutz-snapshots</id>
<url>http://jfrog.nutz.cn/artifactory/snapshots</url>
<snapshots>
<enabled>true</enabled>
<updatePolicy>always</updatePolicy>
</snapshots>
<releases>
<enabled>false</enabled>
</releases>
</repository>
</repositories>
<pluginRepositories>
<pluginRepository>
<id>nutz-snapshots</id>
<url>http://jfrog.nutz.cn/artifactory/snapshots</url>
<snapshots>
<enabled>true</enabled>
<updatePolicy>always</updatePolicy>
</snapshots>
<releases>
<enabled>false</enabled>
</releases>
</pluginRepository>
</pluginRepositories>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.7.0</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
<compilerArgs>
<arg>-parameters</arg>
</compilerArgs>
<useIncrementalCompilation>false</useIncrementalCompilation>
</configuration>
</plugin>
<plugin>
<groupId>org.nutz.boot</groupId>
<artifactId>nutzboot-maven-plugin</artifactId>
<version>${nutzboot.version}</version>
</plugin>
</plugins>
</build>
</project>
/**
* 注意 TDengine 表及字段名都为小写字母
*/
@Table("iot_dev")
public class Iot_dev implements Serializable {
private static final long serialVersionUID = 1L;
@Column
@Comment("ID")
@ColDefine(type = ColType.TIMESTAMP)
private Date ts;
@Column("devid") //字段名都为小写字母
@Comment("设备 ID")
@ColDefine(type = ColType.VARCHAR, width = 32)
private String devId;
@Column("devtype") //字段名都为小写字母
@Comment("设备类型")
@ColDefine(type = ColType.BINARY, width = 32)
private String devType;
@Column
@Comment("状态")
@ColDefine(type = ColType.BOOLEAN)
private Boolean status;
@Column
@Comment("读数 1")
@ColDefine(type = ColType.DOUBLE)
private Double val1;
@Column
@Comment("读数 2")
@ColDefine(type = ColType.INT)
private Integer val2;
@Column
@Comment("读数 3")
@ColDefine(type = ColType.INT,width = 3)
private Integer val3;
@Column
@Comment("读数 4")
@ColDefine(type = ColType.INT,width = 2)
private Integer val4;
}
本插件不同于V5代码生成器插件,无须引入项目中其他jar包,无须事先编译POJO类:
插件下载:
https://gitee.com/budwk/budwk-codegenerator/releases
插件源码:
1、终端设置代理
export http_proxy=socks5://127.0.0.1:1080
export https_proxy=socks5://127.0.0.1:1080
2、安装Homebrew
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
3、Spotlight 索引占有CPU过高
关闭
sudo mdutil -a -i off
打开
sudo mdutil -a -i on
之前,长期是 ThinkPad 忠实用户,从 X230 、X1 2016直到X1 2019。
X1 2019 太让人失望了(挂闲鱼卖了),首先配置是 i7 10710u + 16G + 1T + 4K,CPU 6核12线程,单核起步频率1.1GHz最高4.7GHz。表现起来还没 X1 2016款来的快,因为它动态调整频率,睿频上下波动。
撸码编译时风扇爆转,吹出的热气烫手,而且风扇口设计不合理,刚好对着鼠标位置的手面吹。夜里稍微多开个任务,那风扇的噪音能把娃吵醒,电池撑死能用两小时,最后20%电量掉电非常快。4K屏幕就是个鸡肋,GPU比较弱,占用资源不说玩LOL掉帧厉害,平时也没啥用途。
用 X1 2019 最悲惨得一次是,死机后SSD硬盘居然坏了,售后免费更换新的,但十几年的数据都丢了(好在部分重要资料有备份),害得我不得不上了群晖 NAS 以保万无一失。自从用 X1 2019, 蓝屏 2 次,死机N次,用得太心累了,提心吊胆的,刚巧看到M1性能评测那么高,下定决心换之。
自从换了 M1,那感受完全不一样,首先性能爆表,编译或玩游戏,CPU占用在10-20%之间,很少超过20%,偶尔一次50%。CPU占用不光低,关键风扇还不转,都不用动一下去散热的!底部外壳冰冷冰冷的,看来也只能通过处理4K视频压CPU来暖手了?
Mac系统上的优势就更不用说了,首先不用去磁盘分区,不用考虑C盘分多少,够不够用啊,D盘分多少?不用关机,X1 2019 Windows 10要等半天电脑才能关掉,有时候很关不掉要强制关机,Mac合上盖子拎起就走。有一次X1睡眠放包里,回到家包里温度很烫都快炸了都感觉,打开一看电量所剩无几,而Mac完全不会。
说到电池,M1的电池非常给力,看两小时视频+浏览一小时网页,玩了一个晚上还剩余82%的电量,以后下班不用带电源线回家了。
软件方面,目前M1用于Java开发足够了,相信后面原生支持M1的应用会越来越多,那时候M1性能可以充分发挥出来。
使用root权限修改文件
sudo vi ~/.bash_profile
vi 操作命令省略,插入如下内容
export MAVEN_HOME=/Users/wizzer/work/server/apache-maven-3.6.3
export PATH=$PATH:$MAVEN_HOME/bin
只读文件强制保存
:wq!
source ~/.bash_profile
解决新窗口和重启找不到mvn命令的问题:
touch ~/.zshrc
open ~/.zshrc
文件内容如下,command+S保存
source ~/.bash_profile
<el-cascader ref="area" v-model="infoForm.area" :props="cascaderProps" style="width: 500px;"
size="small" placeholder="请选择区域"></el-cascader>
cascaderProps: {
lazy: true,
value: 'id',
label: 'text',
lazyLoad: function (node, resolve) {
if (node.level === 0) {
var url = base + "/assets/platform/plugins/zoning/0.json";
$.get(url, function (d) {
resolve(d);
}, "json");
} else {
var pidaspath = node.data.id > 0 ? (node.data.id.substring(0, 2) + "/" + node.data.id) : 0;
var url = base + "/assets/platform/plugins/zoning/"+pidaspath+".json";
$.get(url, function (d) {
resolve(d);
}, "json");
}
}
},
infoForm: {
type: 'designer',
area: [],
areaCode: '',
areaText: '',
},
// 后台返回数据时
this.$set(this.infoForm,'area',this.infoForm.areaCode.split(','))
// 前端入库数据处理
if (this.infoForm.area) {
this.$set(this.infoForm, 'areaCode', this.infoForm.area.toString());
}
if (this.$refs['area']) {
var tree = this.$refs['area'].getCheckedNodes();
this.$set(this.infoForm, 'areaText', tree[0].pathLabels.toString());
}
File[] files=Files.lsDir(new File("D://node/zoning/dist/zoning-3"),"");
for(File dir:files){
if(Files.isDirectory(dir)){
File[] files2=Files.lsAll(dir.getAbsoluteFile(),"json");
for(File file:files2){
System.out.println(file.getAbsolutePath());
System.out.println(file.getName());
if(file.getName().length()==9||file.getName().equalsIgnoreCase("81.json")||file.getName().equalsIgnoreCase("82.json")){
String str=Files.read(file);
List<NutMap> list=Json.fromJsonAsList(NutMap.class,str);
List<NutMap> list2=new ArrayList<>();
for(NutMap nutMap:list){
nutMap.addv("leaf",true);
list2.add(nutMap);
}
Files.write(file,Json.toJson(list2, JsonFormat.compact()));
}
}
}
}
PS:临时用,不要纠结命名~~
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);
}
}
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);
}
}
}
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;
}
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
为何要入手群晖呢……主要动机是因上段时间,电脑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 电影封面及介绍下载(自动或手动)问题:
更改hosts文件
vi /etc/hosts
31.13.70.9 api.themoviedb.org
噪音问题:
这款NAS风扇一点声音都没有,主要是硬盘读写有咯咯咯的声音,放客厅或弱电箱(靠近餐桌)都能明显听到,最后把它放阳台了,好在装修的时候阳台都预留了网口和电源,网购了一个4U机柜保护一下,防止浇花洒水等碰到。
Nacos 注册中心及配置中心功能微服务版本
Zookeeper 注册中心微服务版本
单应用一个 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
使用 WPF + CefSharp 技术,C/S客户端 + B/S浏览器的组合,利用客户端实现IC卡读写器的集成开发,实现IC卡表的读写功能,利用B/S浏览器,将营收系统嵌入浏览器,实现WEB营收业务代码热更新、数据统一管理等功能。
抽象设备接入层,实现电信AEP平台、移动OneNET、厂家物联网平台等平台接入,实现 NB-IOT/MQTT/HTTP 等协议的适配和转换,将各表厂繁杂不一的数据格式转换为本平台统一数据格式,并利用规则引擎技术,实现数据的智能化处理。
系统内置预付费、后付费、表端计费等计费类型,支持“购气/退气”和“充值/退费”等业务形态,支持阶梯计价、区域计价等价格规则。
燃气报装、报修、维修、安检等业务流程标准化、制度化,通过流程配置、节点配置、权限配置等,实现业务工单的动态分配和统一管理。
采用 BudWk 国产微服务分布式架构,基于 nutzboot + dubbo + nacos + druid 技术体系,核心框架为国产开源框架 nutzboot,采用 Sa-Token权限系统及JWT。根据业务划分微服务模块,如:
采用 Vite + Vue3 + ElementPlus 常用组合,前后端分离开发模式,封装集成多语言、路由、权限控制、文件上传等功能。
BudWk(原名NutzWk)发展自2010年,2012年开始用于商业项目,至今已服务于全国各地公司大大小小数千个项目,行业涉及政务、电商、物联网等,随着个人经验积累及从事行业的不同分别发布了1.x至8.x多个版本,您可以根据项目规模选择不同版本。本项目案例众多,省厅级项目、市级平台、大数据项目、电商平台、物联网平台等等。
https://demo.budwk.com V8演示地址
https://nutzwk.wizzer.cn V5演示地址
https://budwk.com 官网及开发指南
CREATE USER 'budwk'@'localhost' IDENTIFIED BY '123'; GRANT ALL PRIVILEGES ON budwk_demo.* TO budwk@localhost; FLUSH PRIVILEGES;
谈谈使用体验:
实体店现货买的翡冷翠(本来预订青山黛,但实在等不了一个月,看有现货就拿了),6899¥什么优惠都没,就送了个透明手机壳,手机壳还是满合身的,满满的安全感。考虑屏幕那么大,还是花了299¥买了碎屏险。手机出厂自带贴膜(据说第一批出厂手机没贴膜),所以这点比较好,不用纠结贴什么膜了,上手即用。
对于做IT的来说,上手很快,摸索一圈就知道权限如何设置、通知啊、广告怎么移除等。隔空手势用了,感觉实用性不大,试想下看着抖音,用手悬停半秒,然后隔空滑动屏幕,手抬着很累的手酸了都,还没手动滑屏比较快。
发现一个bug,或也可以说设置不合理的地方,156版本系统,短信的通知关闭后不知道如何打开。设置项不在“通知”里,也不在“应用”一级菜单里,而是需要到“应用”下面的“应用管理”里面,找到“信息”,然后再点“通知管理”,对于新手来说,跟捉迷藏一样,不百度或者问客服,真不知道。
APP的打开及使用,响应速度很快,几乎和iOS系统一样,为什么说几乎呢,是因为一些功能细节上,能感觉出比iOS系统慢那么一丢丢,比如微信支付成功的通知,可能与系统的通知机制不一样造成的,不过不影响使用,几乎察觉不出来。游戏还没安装,暂时略过。
短信拦截/手机拦截等功能太好了,每天收到几十条推销短信/电话,不用单独安装拦截软件,太爽了吧。
NFC功能也很好,8P虽然带NFC但是几乎没有用武之地,华为手机的NFC可以模拟小区门禁卡,真是很方便的。
关于提子,装了v2xxxNG,正好昨天又申请新的G服务器,搭建提子可以上x网,但是没有G套件,只能通过网页访问G的服务,还不是很方便。
壁纸和锁屏界面,可以自动更新一些精美的照片,很好。
情景智能,是自动弹出来的一个功能,开通后可以绑定手机号,通过快递查询平台查询到关联的所有快递物流信息,功能还是比较贴心的。
说几点不爽之处吧:
1)Android系统里的一些官方APP内嵌广告,这个在苹果APP里很少见;
2)各种APP各种请求权限,什么存储、位置、读取设备信息等等,一般很难判断该不该禁用,有的权限禁用了APP就启动不了了,如果都赋权,那么感觉手机像裸奔。
屏幕很亮眼,逛商城的时候四五个小姐姐围着手机看,有一定的误操作的几率,可能用习惯就好了吧,毕竟拿到手还没有48小时。
屏幕分辨率,刚从8p LCD切换过来的时候还不习惯,看多了也就习惯了,给眼睛一个适应过程。
额,怎么说呢,广角拍出来效果很好,但AI有点过度,色彩失真。近距拍摄,不是那么清晰的感觉,可能每个人体验不一样吧,个人感觉摄像头数量很多,但效果不是说的那么神(不知道为啥群里的网友拍的都那么好看?我是买到了假的么……23333)。平时拍照少,也就无所谓了。
这个要吐槽一下了,后置摄像头有AI美化,前置摄像头一点AI和美化都没有,当镜子照啊,可以非常清晰的看到脸上的斑点/粉刺/黑头,额……
比较给力的,比之前用的ip8p持久的多了。
今早上班开车20来分钟,60%电量充到80%,目测一天不用手动充电,上班下班通过车载充电就够用了啊哈哈哈。买的27W功率的那款。
Freebuds 3 双11刚买,EMS 12号中午就送到了。耳机支持蓝牙5.1协议版本,Mate 30 Pro 5G 也是5.1协议,搭配起来很爽哦,正好坐在靠路边的窗口位置,试用了下降噪功能,开启主动降噪功能,路上的车水马龙声音真的消失了,,不过办公室里的说话声音是过滤不掉的。耳机不带调节音量功能 – -。
还有个买蓝牙耳机的重要原因,那就是Mate 30 系列打电话是屏幕发声,不开免提都能听到声音,所以为了隐私,打电话还是用蓝牙耳机比较好。
项目介绍:
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 更新内容:
NutzWk v5.2.6-mini 版本发布:
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包、编辑配置文件、关闭实例进程、启动新实例进程、动态修改日志等级、查看服务器资源占用情况等功能,支持分布式部署。详见:发行注记。
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 更新内容:
NutzWk 是 Java 微服务分布式开发框架,5.x 是采用nutzboot、nutz、dubbo、sentinel、redis、zookeeper、shiro、quartz、beetl、logback等开源技术的微服务分布式版本,自带系统管理、简易CMS、微信模块、定时任务、服务API等功能,目前已全面应用于各类商业项目中。
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