redis安装与操作

mac安装redis客户端

  • 安装brew cask : 在终端中输入下面语句 回车
1
ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)" < /dev/null 2> /dev/null ; brew install caskroom/cask/brew-cask 2> /dev/null
  • 安装Redis Desktop Manager
    安装完cask之后,在终端中输入 回车
1
brew cask install rdm

通过python方式连接redis

1.安装python redis

1
pip install redis

2.使用redis增删改查

1
2
3
import redis
r = redis.StrictRedis(host='001.pub.redis.xxx.xxx.xxx',port=xxx,db=0)
print r.get('ip:172.16.68.169')

get后面为key

使用原生方式连接

需要在服务器安装redis client
redis-cli -h 001.pub.redis.xx.xx.xx -p 6379

查看以这个开头的所有key
keys stanlee:de:access*

查看value:
get stanlee:de:access:process:kk

springboot搭建feature回归系统(二)mybatis

mybatis

  • 简介:基于java的轻量级的持久层框架
    面向对象--->面向配置(切片)的编程,增强程序的可维护性

以下为基于官方的一个步骤

0.创建数据库

创建数据库,建立表,添加一条记录

“数据库表”
“添加一条记录”

1.创建product实体类

1
2
3
4
5
6
public class Product {
private int id;
private String productName;
private String comment;
private String status;
//批量添加set,get方法

ruby -e “$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)” < /dev/null 2> /dev/null ; brew install caskroom/cask/brew-cask 2> /dev/null

2.创建配置文件 mybatisConfig.xml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="xx.xx.xx.xx"/>
<property name="url" value="jdbc:mysql://xx"/>
<property name="username" value="xx"/>
<property name="password" value="xx"/>
</dataSource>
</environment>
</environments>
<mappers>
<mapper resource="mapping/procuctMapper.xml"/>
</mappers>
</configuration>

其中mybatisConfig.xml中引用map文件的方式种类举例

  • 相对路径引用
1
2
3
<mappers>
<mapper resource ="jike/book/map/jikeUser.xml">
<mappers>
  • 绝对路径引用
1
2
3
<mappers>
<mapper resource ="file:///var/jike/book/map/jikeUser.xml">
<mappers>
  • 包路径引用
1
<package name = "a.b.c">

3. 创建dao文件 ProductMapper.java

1
2
3
public interface ProductMapper {
Product selectByStatus(String status);
}

4. 创建map文件 productMapper.xml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="xx.xx.xx.dao.ProductMapper">
#注意,上面的mapper的namespace应该为dao的地址
#注意:这里的id :selectByStatus 与上面的接口名一致
<select id="selectByStatus" parameterType="java.lang.String" resultType="xx.xx.xx.model.Product">
select *
from product
where status = #{status}
</select>
</mapper>

5.编写测试类

流程

  • 读取配置文件(数据库连接基本信息)
  • 生成sqlSessionFactory
  • 建立sqlSession
  • 调用Mybatis提供的api(执行sql)
  • 查询mpl配置
  • 返回结果
  • 关闭sqlSession
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public class ProductController {
public static void main(String[] args) {
String resource = "mapping/MyBatisConfig.xml";
InputStream inputStream = null;
try {
inputStream = Resources.getResourceAsStream(resource);
} catch (IOException e) {
e.printStackTrace();
}
SqlSessionFactory sqlMapper = new SqlSessionFactoryBuilder().build(inputStream);
SqlSession session = sqlMapper.openSession();
Product result = session.selectOne("selectByStatus","normal");
System.out.println(result.getProduct());
session.close();

6.查看mybatis的sql可以通过配置日志看到

加入日志配置文件log4j.properties
log4j.rootLogger-DEBUG,Console

log4j.rootCategory=debug, stdout , R0

log4j.appender.stdout = org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout = org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern = %-20d{yyyy-MM-dd HH\:mm\:ss}%-5p (%F\:%L) - %m%n

log4j.appender.R0=org.apache.log4j.DailyRollingFileAppender
log4j.appender.R0.layout=org.apache.log4j.PatternLayout
log4j.appender.R0.layout.ConversionPattern=%-20d{yyyy-MM-dd HH\:mm\:ss}%-5p (%F\:%L) - %m%n
log4j.appender.R0.DatePattern=’.’yyyy-MM-dd
log4j.appender.R0.File=logs/jsDataRoadApp.log

附:文件结构
“文件结构”

python的多线程

python中的线程

如何使用

1
2
3
4
5
6
7
8
import threading #首先导入threading 模块,这是使用多线程的前提。
threads = [] #创建threads数组
t1 = threading.Thread(target=music,args=(u'爱情买卖',)) #创建线程t1
threads.append(t1) #把创建好的线程装入threads数组中

使用threading.Thread()方法,在这个方法中调用music方法target=music,args方法对music进行传参。

1
2
3
4
5
6
7
8
if __name__ == '__main__':
for t in threads:
t.setDaemon(True) #申明守护线程,必须在start方法调用之前设置,如果不设置为守护线程,程序会被无限刮起。
t.start()
t.join() #在子线程完成运行之前,这个子线程的父线程将一直被阻塞;如果没有添加,则父线程执行完成后,导致子线程终止
print "all over %s" %ctime()

java多线程

List list = new ArrayList<>()

多线程:指的是这个程序(一个进程)运行时产生了不止一个线程
并行与并发:
并行:多个cpu实例或者多台机器同时执行一段处理逻辑,是真正的同时。
并发:通过cpu调度算法,让用户看上去同时执行,实际上从cpu操作层面不是真正的同时。并发往往在场景中有公用的资源,那么针对这个公用的资源往往产生瓶颈,我们会用TPS或者QPS来反应这个系统的处理能力。

http://172.16.50.50:8086/query?pretty=true&db=decision_assistant&q=SELECT* FROM func_result WHERE strategyCode=%27fansizheStrategy%27 and uuid=%2743338ab0-16a2-4cd5-a964-2235f534cb21%27

java代码基本语法辨析

final可以修饰类,方法,属性(因为不能被改变,不能和abstract共同使用)

final 用于声明属性,方法和类,分别表示属性不可变,方法不可覆盖,类不可继承。
finally 是异常处理语句结构的一部分,表示总是执行。
finalize 是Object类的一个方法,在垃圾收集器执行时会先调用被回收对象的此方法,可以覆盖此方法提供垃圾收集时的其他资源回收,例如关闭文件等

类 final

不能被继承,没有子类,final类中的方法默认是final的。
在设计类时候,如果这个类不需要有子类,类的实现细节不允许改变,并且确信这个类不会载被扩展,那么就设计为final类。

方法 final

如果一个类不允许其子类覆盖某个方法,则可以把这个方法声明为final方法。

面向对象的主要特征:抽象、继承、封装、多态性
抽象只关注对象有哪些属性和行为,不关注行为细节
多态性:允许不同子类型的对象对同一消息作出不同的响应;调用同一个对象的同一个方法得到不同的响应
方法重载:编译时的多态
方法重写:运行时的多态(子类继承父类并重写父类中已有的或抽象的方法)
()

python接口测试注意点

背景

使用flask自己搭建了一套接口自动化框架,编写接口用例时,一些注意点纪录总结下

  • 数据初始化的两个方法 flask-fixture,用来包裹测试用例
    setup_module/teardown_module 在所有测试用例执行之后和之后执行。

setup_function/teardown_function 在每个测试用例之后和之后执行。

  • 接口用例设计
    一般接口

python

特征值mock工具

需求背景:

风控决策引擎中,根据用户的特征值来得出策略结果,用户特征值部分的产生较为负责,需要一系列数据符合一些规则才会产生需要的特征值,所以测试策略结果时,如果能跳过特征值产生而插入特定数据这一步,直接mock,分层测试,会让测试策略更有效率

最终效果图
“feature-mock工具”

服务端代码分析

  • part 1 : 使用flask框架产生接口路由部分
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
from flask import Flask,jsonify,render_template,url_for,request
app = Flask(__name__)
@app.route('/', methods=['GET', 'POST'])
def index():
#render_template渲染模版
return render_template("index.html")
@app.route("/changefeatureall",methods=["POST"])
def changefeatureall():
commitid = request.form.get('commitid')
wht_msg.generate(commitid)
if mydomain:
res = {"code": "0", "data":"成功" }
wht_msg.update_sql_all(commitid)
return jsonify(res)
  • part 2 :数据库连接部分
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
def connect(sql,flag,db="haixin"):
config = {
'host':'xxx',
'port':xxx,
'user':'xxx',
'password':'xxx',
'db':db,
'charset':'utf8mb4',
'cursorclass':pymysql.cursors.DictCursor,
}
connection = pymysql.connect(**config)
try:
with connection.cursor() as cursor:
# 执行sql语句,插入记录
cursor.execute(sql);
if flag ==1:
result = cursor.fetchone()
connection.commit()
else:
result = cursor.fetchall()
print len(result)
# 没有设置默认自动提交,需要主动提交,以保存所执行的语句
connection.commit()
return result
finally:
connection.close()
  • part 3 : 数据库逻辑处理部分

    1
    2
    3
    4
    5
    6
    #具体逻辑较复杂,展示最简单的插入与 u
    def insert_sql(domain,content):
    sql = "insert into mk_domain_value(domain_name,content)VALUES('%s','%s')" %(domain,content)
    print sql
    result = connect(sql,1)
    print result
  • part 4 :前端展示部分

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#展示数据前后端交互部分
$(document).ready(function() {
$.ajax({
type: 'post',
url: "/changefeatureall",
dataType: 'json',
data: {
'mydomain': 'http://xxxxxxx',
'commitid': $('#commitid').val(),
},
error: function () {
alert('请求失败,原因可能是:' +'输入参数错误或请求失败' +'!');
},
success: function (data) {
alert("yes");
}
});
  • part 5:功能描述
1
2
3
4
1.初始化:根据策略,绘制参数输入框,输入参数后,请求制定参数对应的数据,产生初次mock数据
2.初次mock链接会替换系统中的feature请求链接
3.此时修改feature结果,就能动态修改mock数据,见截图
4.替换的请求链接可以还原

springboot搭建feature回归系统(一)需求

springboot入门教程:
http://www.cnblogs.com/winner-0715/p/6666302.html
http://www.jianshu.com/p/99fcead32d35
http://www.jianshu.com/p/a9e695a2f3f6
https://github.com/435242634/Spring-Boot-Demo/tree/feature/4-spring-boot-mybatis-xml

flex

需求背景:

风控决策引擎中,根据用户的特征值来得出策略结果,用户特征值部分的产生较为负责,需要一系列数据符合一些规则才会产生需要的特征值,所以测试策略结果时,如果能跳过特征值产生而插入特定数据这一步,直接mock,分层测试,会让测试策略更有效率

涉及技术栈:

据说最爽的Web组合开发就是Intellij IDEA + Maven + Spring Boot + Velocity + Boostrap + jQuery了

SB使用Velocity的依赖

1
2
3
4
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-velocity</artifactId>
</dependency>

默认配置下spring boot会从src/main/resources/templates目录中去找模板

SB的velocity配置

application.properties配置

lightsword/src/main/resources/application.properties

1
2
3
4
5
6
7
# VELOCITY TEMPLATES (VelocityAutoConfiguration)
spring.velocity.charset=UTF-8
spring.velocity.properties.input.encoding=UTF-8
spring.velocity.properties.output.encoding=UTF-8
spring.velocity.resourceLoaderPath=classpath:/templates/
spring.velocity.suffix=.html
spring.velocity.toolbox-config-location=/WEB-INF/toolbox.xml

mybatis 配置

正常配置需要添加三个文件,这里使用mybatis-generator来生成mybatis相关文件
教程:http://www.jianshu.com/p/73b6cb2e04fc;教程中第四步的Plugins在idea的左侧“maven projects”中

框架搭建完成

http://www.jianshu.com/p/99fcead32d35

设计模块和类

@所有人 大家工程建完后,在下周上课前把模块和类设计下,分下任务,就先按照自己的思路来写就行了,你要写在一个类里面也没有问题的。然后下周我会讲下简单的springboot、maven的东西,反正你们照着抄就行了,原理等后面帛书给你们讲

java注解学习

https://juejin.im/entry/5952649f6fb9a06bc06a34ac

数据库创建

项目原型图:
随便用用axure,只是表达意思,动态效果较少请见谅
“首页”
“列表”
“用例创建”
“回归比对”
“sql插入工具”

项目分析:

数据库表设计

json自定义格式内容对比工具

需求背景:

风控决策引擎的需求树和配置界面比对,由于树比较“粗壮”,人工比对工作量实在太大,由于树是有json绘制而成,故可以将树的json与配置界面的结果——数据库中的json做比对,提升工作效率。

  • part 1 :json文件导入
1
2
3
import json
d1 = json.load(open('/文件目录/json1.json'))
d2 = json.load(open('/文件目录/json2.json'))
  • part 2 : 修改自定义规则部分
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
#遍历json,将两个json中对应的key,但命名不一致部分修改为相同的;将value格式不同的修改为相同的
def cmp_dict(a,b):
if isinstance(a,dict):
for key,value in a.items():
keyb = key
if key == 'code':
a[key] = a[key].replace('_','.')
value = value.replace('_','.')
keyb = '_name'
if key == 'condition':
keyb = 'conditions'
if key == 'math':
keyb = 'ruleFusion'
for case in switch(a[key]):
if case('VECTORNORM(2)'):
a[key] = 'rfmNorm2'
break
if case(): # 默认
print "something else!"
#将json中多个值组装后,再匹配 的逻辑较多,不展示了
#最后,加个递归调用
cmp_dict(a[key],b[keyb])
  • part 3 :由于上面switch部分较多,为了避免写太多if…else导致可读性太差,编写了一个switch类
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
class switch(object):
def __init__(self, value):
self.value = value
self.fall = False
def __iter__(self):
"""Return the match method once, then stop"""
yield self.match
raise StopIteration
def match(self, *args):
"""Indicate whether or not to enter a case suite"""
if self.fall or not args:
return True
elif self.value in args: # changed for v1.5, see below
self.fall = True
return True
else:
return False
  • part 4 处理dict中嵌套list的情况
1
2
3
4
5
6
elif isinstance(a,list):
#sorted方法为python中list的排序方法;zip方法将两个list中对应的数据打包成元组
for src_list, dst_list in zip(sorted(a, key=lambda x : (x.get('level', 0))),sorted(b, key=lambda x : (x.get('level', 0)))):
#将json中多个值组装后,再匹配 的逻辑较多,不展示了
#最后,加个递归调用
cmp_dict(src_list, dst_list)
  • part 5 :异常处理及测试
1
2
3
4
5
6
7
8
try
...
except:
f=open("/文件目录/log.txt",'a')
traceback.print_exc(file=f)
f.flush()
f.close()
1
2
3
4
5
if __name__ == "__main__":
xx = {"111":None,"23456":{"22222":9999,"33333":"0000","list":["3333","4444","111"]}}
yy = {"111":None,"23456":{"22222":9999,"33333":"0000","list":["111","3333","4444"]}}
mp_dict(x,y)
cmp_dict(d1,d2)