myronliu


  • 首页

  • 标签

  • 分类

  • 归档

  • 搜索

多模块mapper扫描

发表于 2020-07-15

java grpc初体验

发表于 2020-06-07 | 分类于 技术

文档

定义proto

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
syntax = "proto3";

option java_multiple_files = true;
option java_package = "io.grpc.examples.routeguide";
option java_outer_classname = "RouteGuideProto";
option objc_class_prefix = "RTG";

package routeguide;

// Interface exported by the server.
service RouteGuide {
// A simple RPC.
//
// Obtains the feature at a given position.
//
// A feature with an empty name is returned if there's no feature at the given
// position.
rpc GetFeature(Point) returns (Feature) {}

// A server-to-client streaming RPC.
//
// Obtains the Features available within the given Rectangle. Results are
// streamed rather than returned at once (e.g. in a response message with a
// repeated field), as the rectangle may cover a large area and contain a
// huge number of features.
rpc ListFeatures(Rectangle) returns (stream Feature) {}

// A client-to-server streaming RPC.
//
// Accepts a stream of Points on a route being traversed, returning a
// RouteSummary when traversal is completed.
rpc RecordRoute(stream Point) returns (RouteSummary) {}

// A Bidirectional streaming RPC.
//
// Accepts a stream of RouteNotes sent while a route is being traversed,
// while receiving other RouteNotes (e.g. from other users).
rpc RouteChat(stream RouteNote) returns (stream RouteNote) {}
}

// Points are represented as latitude-longitude pairs in the E7 representation
// (degrees multiplied by 10**7 and rounded to the nearest integer).
// Latitudes should be in the range +/- 90 degrees and longitude should be in
// the range +/- 180 degrees (inclusive).
message Point {
int32 latitude = 1;
int32 longitude = 2;
}

// A latitude-longitude rectangle, represented as two diagonally opposite
// points "lo" and "hi".
message Rectangle {
// One corner of the rectangle.
Point lo = 1;

// The other corner of the rectangle.
Point hi = 2;
}

// A feature names something at a given point.
//
// If a feature could not be named, the name is empty.
message Feature {
// The name of the feature.
string name = 1;

// The point where the feature is detected.
Point location = 2;
}

// Not used in the RPC. Instead, this is here for the form serialized to disk.
message FeatureDatabase {
repeated Feature feature = 1;
}

// A RouteNote is a message sent while at a given point.
message RouteNote {
// The location from which the message is sent.
Point location = 1;

// The message to be sent.
string message = 2;
}

// A RouteSummary is received in response to a RecordRoute rpc.
//
// It contains the number of individual points received, the number of
// detected features, and the total distance covered as the cumulative sum of
// the distance between each point.
message RouteSummary {
// The number of points received.
int32 point_count = 1;

// The number of known features passed while traversing the route.
int32 feature_count = 2;

// The distance covered in metres.
int32 distance = 3;

// The duration of the traversal in seconds.
int32 elapsed_time = 4;
}

mybatis SQL注入

发表于 2020-06-06 | 分类于 web安全

mybatis SQL注入

order by

mybatis中#{}表示预编译,${}表示拼接,order by不能做预编译,假如给Flast_update_time排序,预编译后,就变成了order by “Flast_update_time”,所以还是需要使用拼接,这里要注意防注入。

我理解本质原因是预编译后,会给传入的字符串加上双引号。所以order by这种是无法做预编译的,只能拼接。

解决方法

order by的字段不直接拼接前端传入的字符串,而是通过映射转换为实际的字段,这样就可以避免注入

like

如果使用like模糊查询时,如果这样使用,语法会有问题,还是因为双引号。

1
select * from xxx where xxx like '%#{title}%'
解决方法

使用concat函数做拼接。

1
select * from xxx where xxx like concat('%',#{xxx}, '%')
in查询
解决方法

使用Mybatis自带循环指令

参考

Mybatis框架下SQL注入漏洞面面观

Mybatis使用order by排序使用#无法正确执行的解决之#与$的区别

java填坑

发表于 2020-04-04 | 分类于 技术

java异常

java gson fastjson

rest接口,class上注解@RestController,然后返回的对象会自动转换为json格式,使用的是Jackson,如果返回的对象中有datetime格式的字段,返回的格式是这样的

1
2020-04-24T07:31:40.000+0000

需要设置jackson格式

1
2
spring.jackson.date-format=yyyy-MM-dd HH:mm:ss
spring.jackson.time-zone=GMT+8

排除全局包

  • 模块启动时报错
    1
    2
    3
    4
    5
    6
    java -jar web_vb_base_ekyc.jar
    SLF4J: Class path contains multiple SLF4J bindings.
    SLF4J: Found binding in [jar:file:/data/apps/web_vb_base_ekyc/web_vb_base_ekyc.jar!/BOOT-INF/lib/slf4j-nop-1.7.29.jar!/org/slf4j/impl/StaticLoggerBinder.class]
    SLF4J: Found binding in [jar:file:/data/apps/web_vb_base_ekyc/web_vb_base_ekyc.jar!/BOOT-INF/lib/logback-classic-1.2.3.jar!/org/slf4j/impl/StaticLoggerBinder.class]
    SLF4J: See http://www.slf4j.org/codes.html#multiple_bindings for an explanation.
    SLF4J: Actual binding is of type [org.slf4j.helpers.NOPLoggerFactory]

在pom.xml中增加

1
2
3
4
5
6
7
8
9
10
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-nop</artifactId>
<exclusions>
<exclusion>
<groupId>*</groupId>
<artifactId>*</artifactId>
</exclusion>
</exclusions>
</dependency>

这样相当于全局排除了slf4j-nop

jar包内部构造

打印db查询语句

在mybatis-config.xml中设置

1
<setting name="logImpl" value="SLF4J"/>

在logback.xml中配置

1
<logger name="com.fusionbank.base.ekyc.dao" level="DEBUG" />

打印中文乱码

中文解密出来后,首先编码为UTF-8格式

1
2
3
4
5
6
public String decryptString(String sourceStr)
throws KeyException, UnsupportedEncodingException {
KeyApi keyApi = new KeyApi();
return new String(keyApi.decrypt2(ekycProperties.getSecretKey(), sourceStr,
0), StandardCharsets.UTF_8);
}

写入文件时,指定UTF-8

1
2
3
BufferedWriter bw = new BufferedWriter(
new OutputStreamWriter(new FileOutputStream("/tmp/tu_result.txt"),
StandardCharsets.UTF_8));

Spring Boot多模块踩坑

发表于 2020-03-29 | 分类于 技术

多模块pom.xml

packaging

packaging是项目的打包类型,常用的有如下几种:

  • war:打包为war包
  • jar:打包为jar包
  • pom:用在父级工程或者聚合工程中,做jar包的版本控制

module如果访问了外部的程序,需要在pom中引入依赖

1
2
3
4
5
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-exec</artifactId>
<version>1.3</version>
</dependency>

注入问题

解决方法

  • 添加包扫描

    1
    2
    3
    4
    5
    6
    @SpringBootApplication(scanBasePackages={"com.fusionbank"})
    public class HelloWorldApplication {
    public static void main(String[] args) {
    SpringApplication.run(HelloWorldApplication.class, args);
    }
    }
  • 移动application文件到com.fusionbank层级,本质也是为了扫描到这个层级下的包

异常

写了一个java的middle server,在里面调用的middle版本的server,请求过去后,看java的日志,只打印了

1
2020-03-29 11:50:48.542 [nioEventLoopGroup-3-3] ^[[39mDEBUG^[[0;39m c.f.m.a.framework.server.RpcRequestProcessService - middle call service:get_id

后来发现

1
2
3
4
5
public Builder setTableName(
java.lang.String value) {
if (value == null) {
throw new NullPointerException();
}

这里set时传入的字符串未设置,抛出来了异常没有捕捉

redis连接断开

发表于 2020-03-21 | 分类于 技术

背景

va_list的bug,修改后,在开发环境验证时,发现执行redisCommand函数时,会卡住,直到进程被杀掉重启。为啥生产环境直接进入了第二次循环,没有卡住呢?

两种情况

  • redis没有切过master,老的连接有时也不能用,报错Connection reset by peer,这时会自动重连,大概一天2次这种报错,为啥连接会中断,这个还没找到原因。
  • 为何我验证的情景下,请求老的连接时会卡住呢?是因为我是通过封禁redis端口的方法触发redis切换的。切换master后,分两种情况:
  1. redis之前的master变成了slave,再次请求时,报错server closed the connection redis,这种情况也会自动重连。

  2. 如果把master的端口禁用,redis切换master后,业务模块再请求之前的连接会卡住,这种情况需要设置超时时间。

    1
    2
    3
    4
    5
    6
    iRet = redisSetTimeout(m_pstRedisLink, timeout);
    if(iRet != 0)
    {
    m_strErrMsg = "redis set timeout fail";
    return iRet;
    }

所以当前发到生产环境的版本,redis服务重启的情况,业务模块是可以重连的,网络中断的话,业务模块请求redis时会卡住,直到网络恢复或者middle杀掉进程重启。

分析

封禁端口,网卡就不再处理这个端口的包,相当于网线断开了。这种情况下,客户端收不到服务器的任何回包,就会一直等待,如果没有设置超时时间,就卡住了。
redis有两个配置,一个是timeout,这个参数如果设置为0,表示服务端不会主动断开连接,非0,表示会清理空闲时间超过这个值的连接。另一个是tcp-keepalive,这个参数表示服务器定时发送ack包探测客户端是否存活。

python异步

发表于 2020-03-14 | 分类于 技术

最近在研究怎么接入libco,所以先了解一下python是怎么支持异步的。

功能 异步库
http aiohttp
Redis aioredis
MongoDB motor
mysql aiomysql

http multipart/form-data

发表于 2019-12-01 | 分类于 技术

背景

tws从来未处理过视频流。这次主要研究一下怎么接收解析视频信息。

实验

我大概知道Content-Type是multipart/form-data格式,所以首先不做任何转换,将Content-Type和Post直接透传到人脸服务,服务响应正常。证明这两个字段是没有问题的

multipart/form-data

上面的实验没有问题,说明tws只是将原始的数据全部解析到post字段,我们取出来之后,需要按照multipart/form-data协议进行解析。

  1. 从Content-Type字段中解析boundary字段
  2. 从post字段中查找以--boundary字段开始,\r\n\r\n结束的字符串,这个字符串就是每一段的描述信息
  3. 从描述信息中可以解析出字段名或者文件名
  4. 继续查找以\r\n\r\n开始,\r\n--boundary结束的字符串,这个字符串就是字段的value或者文件的具体内容。这里要注意的是,查找时不要用\r\n作为结束标志查找,因为可能文件中刚好有这个字符,造成读取文件不完整。我就遇到了解析出来的视频信息播放有问题,最终发现是这个原因
  5. 按照上述流程循环解析,直到步骤2没有找到
  6. 进行后续业务处理

leetcode一些记录

发表于 2019-10-07 | 分类于 技术

14.最长公共前缀

使用的是基本的暴力查找,可以先查找到最大的字符串和最小的字符串,然后只比较这两个字符串的公共前缀就是整个数组的公共前缀。

11.盛最多水的容器

这个双指针平移的解法很爽。

redis中的数据结构

发表于 2019-10-03 | 分类于 技术

sorted set

sorted set是有序键值对集合,查询结果按照分数排序

1
zrange key 0 -1 withscores

还可以根据field获取到score的值

1
zscore key field

那么内部的是怎么实现的呢?

跳跃表

跳跃表是链表的升级,查询效率是O(log(N)),比链表查询效率高。新增节点和删除节点时,只需要更新临近节点的指针指向,比平衡树插入和删除时操作简单,属于空间换时间。
但是

  • 根据field查询score
  • 根据field查询rank
  • 查询rank范围内的数据

这三种场景如果在跳跃表中实现,需要遍历,复杂度O(N)。所以,
redis同时使用了哈希表,键为field,值为score,这样就支持了O(1)的复杂度根据field查询score。为了能够支持rank相关查询,redis里对跳跃表做了改进,增加了range,使得查询rank相关的操作也能达到O(log(N))。

bitmap

redis的bitmap结构可以支持位图相关操作,有个命令是bitcount,用来计算为1的位个数,这里引申出来了汉明重量,redis使用的是variable-precision SWAR算法。

参考

Redis为什么用跳表而不用平衡树?
bitcount优化之路

12

一个人的技术水平的提高来自于持续不断的钻研

13 日志
2 分类
13 标签
© 2020
由 Hexo 强力驱动
|
主题 — NexT.Pisces v5.1.4