写在前面,本文是有在上海某位大佬的原创文章,因个人觉得非常不错,得到本人同意后发表在本人网站上,原文链接在这,非常尊重那些在工作中独立思考、善于创作的人。也敬佩他们的分享精神。

背景

自我介绍下,四年工作经验,头两年全栈开发,后两年专职做前端,目前已达到高级前端工程师水平,经历过三家公司。第一家公司,电商行业,做阿里 ISV 供应商,为淘宝卖家服务,也是我第一次接触百万 UV 级别的产品,在第一家公司呆了两年,由于达到技术瓶颈期,随跳槽,第二家公司,航运物流行业,呆了六个月(工作强度对我来说,是真的高),身体不适,没有同意转正。目前这家,担任项目管理和前端组长,两个角色,目前呆了两年,做了很多东西,把自己的一些想法跟大家聊一聊。

阅读全文 »

Python从List中统计连续情况

前言

虽然已经很久没写东西了,但是我一直在,这次直接分享在工作中写一个小工具时统计在List中的连续情况,这个可以是数字,可以是日期,此文只分享的是一种思维;

问题

需要知道一个list如[1,2,3,5,6,8,9,10,11,12,13,15,17,18,19,22]的连续情况,像下面这样做一个统计即可:

阅读全文 »

2019 年底过的太匆忙,连续加班的日子逼至春节前夕,这里就春节前做个简单的总结预告。

19 年有收获,有遗憾,有匆忙,有闲暇。都过去了,行李还没收拾好,等春节后目前的项目做完,好好做一下 19 年的个人总结吧(前方高能预警,有关于生活,关于情感,关于旅行,关于工作,关于技能,关于思考),祝大家春节愉快!

我参考了很多代码,没有发现能够兼顾效率和准确率的代码,于是自己手写了一个能用的代码。虽然 sql 语句很长,但是能够查询的非常快,在给关键字段加了索引的情况下,查询两百万条数据不超过 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
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
SELECT NAME, IFNULL(count + count1, 0) AS `count`
FROM (
SELECT t1.NAME, t.count, t1.count1
FROM (
SELECT CASE
WHEN HOUR(DISCOVERTIME) BETWEEN 0 AND 3 THEN '00'
WHEN HOUR(DISCOVERTIME) BETWEEN 3 AND 6 THEN '03'
WHEN HOUR(DISCOVERTIME) BETWEEN 6 AND 9 THEN '06'
WHEN HOUR(DISCOVERTIME) BETWEEN 9 AND 12 THEN '09'
WHEN HOUR(DISCOVERTIME) BETWEEN 12 AND 15 THEN '12'
WHEN HOUR(DISCOVERTIME) BETWEEN 15 AND 18 THEN '15'
WHEN HOUR(DISCOVERTIME) BETWEEN 18 AND 21 THEN '18'
WHEN HOUR(DISCOVERTIME) BETWEEN 21 AND 23 THEN '21'
END AS `name`, IFNULL(COUNT(1), 0) AS `count`
FROM 表名
WHERE 1 = 1
-- 这里可以添加其他条件 比如 and flag=1 and type = 2 and isdelete = 0
-- AND to_Days(DISCOVERTIME) = to_days(now()) 这里不建议这么写,有to_days()这种运算的逻辑可以放到程序中去处理,没必要在数据库中去做运算,我们在开发过程中尽量避免这一点,可以参考下面这种写法,这个时间的处理可以参考我的另外一篇博客 http://www.fujiatian.com/post/24365.html
and DISCOVERTIME >= '2019-11-11 00:00:00' AND DISCOVERTIME < '2019-11-12 00:00:00'
GROUP BY CASE
WHEN HOUR(DISCOVERTIME) BETWEEN 0 AND 3 THEN 1
WHEN HOUR(DISCOVERTIME) BETWEEN 3 AND 6 THEN 2
WHEN HOUR(DISCOVERTIME) BETWEEN 6 AND 9 THEN 3
WHEN HOUR(DISCOVERTIME) BETWEEN 9 AND 12 THEN 4
WHEN HOUR(DISCOVERTIME) BETWEEN 12 AND 15 THEN 5
WHEN HOUR(DISCOVERTIME) BETWEEN 15 AND 18 THEN 6
WHEN HOUR(DISCOVERTIME) BETWEEN 18 AND 21 THEN 7
WHEN HOUR(DISCOVERTIME) BETWEEN 21 AND 23 THEN 8
END
) t
RIGHT JOIN (
SELECT '00' AS NAME, 0 AS count1
UNION
SELECT '03' AS NAME, 0 AS count1
UNION
SELECT '06' AS NAME, 0 AS count1
UNION
SELECT '09' AS NAME, 0 AS count1
UNION
SELECT '12' AS NAME, 0 AS count1
UNION
SELECT '15' AS NAME, 0 AS count1
UNION
SELECT '18' AS NAME, 0 AS count1
UNION
SELECT '21' AS NAME, 0 AS count1
) t1
ON t.NAME = t1.NAME
) t

本片完结!

mysql 查询当日数据

在本次大屏项目的开发过程中, 我主要用 java 写后端接口,为大屏提供数据,这里不写接口的设计,直接总结写 sql 语句的一些心得吧。

需求:

在页面需要统计功能的时候,可能需要展示当天、本年,本季度、本月、本周的数据,当数据量多了之后,查询效率和如何写 sql 语句实现都是需要考虑的问题,下面我就以最简单的查当日数据做一个简单的分析与总结

  1. 写法一:
1
2
3
4
5
6
7
SELECT
*
FROM
表名
WHERE
regid = 'xxxx'
AND TO_DAYS( createtime ) = TO_DAYS( now() );
  1. 写法二:
1
2
3
4
5
6
7
8
SELECT
*
FROM
表名
WHERE
regid = 'xxxx'
AND createtime >= '2019-10-27 00:00:00'
AND createtime < '2019-10-28 00:00:00'

分析:

写法一和写法二,经过我的实际测试,在没有加索引的情况下,查询效率是差不多的,我测试的表有 170 万条数据,每天还在大量的新增数据,在本地查询数据是 8 秒多,这样的查询速度肯定是不能忍受的;mysql慢
在给 regid 字段和 createtime 加了索引后,查询数据有了天与地的巨大差别,直接上图:
mysql快

总结:

在数据量超过 10w 条以后,通过实际检验,在查询数据库的过程中就不建议使用to_days()这样的数据量内置函数了,这样会导致内部数据大量的复制计算,最后才去做比较,这样性能消耗太大了,能直接用程序去计算,然 sql 查询语句只做最简单的大于,小于,等于这样的比较就好了,这样效率能达到比较好的结果。
同理查询当年数据,查询当月数据,查询当前季度,查询本周数据都是这么个道理,如何写相关的 sql 语句,参考博客

特别说明:

因为我是使用 Java 开发后端接口,所以直接使用mybatis plus一把梭哈了,简单高效!

1
2
3
4
5
6
		// 获取一个时间,并格式化
Date datetime = (param.getInputTime() == null || param.getInputTime() == "") ? new Date() : DateUtils.parseDate(param.getInputTime());
QueryWrapper<User> queryWrapper = new QueryWrapper<>();//创建一个查询构造器
// 不需要查询所有字段,所以只需要我需要的字段。
queryWrapper.select("name", "createtime" ).eq("streetname", param.getStreetName()).ge("createtime", DateUtils.getMonthBeginTime(datetime)).lt("createtime", DateUtils.getMonthEndTime(datetime)).orderByDesc("createtime");
List<User> selectList = rxajDao.selectList(queryWrapper); //拿到数据

DateUtils.getMonthBeginTime()这个写的一个静态工具类,只需要传入一个时间,就自动得到这个月的开始时间,DateUtils.getMonthEndTime()获取本月的结束时间,同理可以直接写获取当天开始时间和当天结束时间的方法,去查询当日的所有数据,这个只需要一个 java 的时间工具类就可以了,这个在网上找一大把这里就不推荐了,找到后,自己适当的改改一般没啥大问题;

mysql 常用时间类的内置函数:

函数 说明 示例语句 结果
curdate() 获取当天的日期 yyyy-mm-dd select curdate(); 2019-11-15
curtime() 获取到当前时间点,精确到秒,HH:mm:ss select curtime(); 11:33:44
now() 获取当前时间 yyyy-mm-dd HH:mm:ss select now(); 2019-11-15 11:35:05
unix_timestamp() 时间戳 select unix_timestamp(now()) 1573789055
from_unixtime() 将时间戳转为时间 select from_unixtime(1573788997); 2019-11-15 11:36:37
year() 获取年份 select year(now()); 2019
week() 获取本年的第几周 select week(now()) 45;表示今天是 2019 年的第 45 周
hour() 获取小时数 select hour(curtime()) 11
minute() 获取分钟数 select minute(curtime()) 44,代表现在是 44 分钟
monthname() 获取月份英文名 select monthname(now()); November
month() 获取月份数 select month(now()); 11
date_format(时间,格式) 格式化时间 select date_format(now(),”%Y-%m-%d %H:%i”); 2019-11-15 11:47 获取到分钟

关于大屏项目中分辨率和高宽比的总结

前言:

最近做第一次大屏项目,虽然我是写后端,但是前端和整个项目也是紧密相连的,项目组因为客户显示的大屏分辨率和设计图的一些问题浪费了一些不必要的时间。所以在这里记录一下;

问题:

情况说明:客户现场的大屏幕是由一般二十几寸的 1920 * 1080 分辨率的小屏幕,由 5 x 3 拼接成的一个大屏幕,我们错误的是按照 1920 *5 :1080 * 3 这样的分辨率去设计了第一版 UI,发现连内容都显示不完整,大小比例都严重不协调。导致前端 UI 重做,浪费的大量的人力物力。

屏幕高宽比非常重要

分析:

去详细了解了关于拼接的大屏幕分辨率,高宽比一些基本的常识,原来 15 个 1920 * 1080 的显示器拼接的大屏最后显示的还是 1920 *1080 的分辨率显示,只是高宽比原来更大了,高宽比也变成了 80:27,单个的小显示器是 16:9 的宽高比。从理论上讲,是可以实现 1920 * 5 : 1080 * 3 的分辨率的,这样电脑的显卡也不支持啊,是不是?这个是由大屏的拼接技术决定的,而目前的大屏还是逻辑分辨率(1920 * 1080 ),在大屏幕上只是同比例放大了而已,由于拼接后的大屏高宽比和电脑显示器的不一致,会导致投放到大屏上的页面一定的拉伸和压缩;
1
2

处理方案:

解决办法:目前只能以 1920 * 1080 的分辨率去设计页面,页面的大小按照客户现场的大屏高宽比(16 * 5 :9 * 3)去设计,这样能达到最好的显示效果;

最后强调: 屏幕高宽比非常重要!屏幕高宽比非常重要!屏幕高宽比非常重要!

_参考博客_:

http://www.woshipm.com/ucd/198774.html > https://blog.csdn.net/qq_42061692/article/details/85566174

不知不觉服务器都已经买了一年了,服务器的 SSL 证书也要更新了,这里做一个记录

服务器配置:

  1. 系统 windows server 2012
  2. IIS7

证书申请:

  1. 域名是托管在某良心云的,所以通过良心云可以免费申请 SSL 证书,申请 SSL 链接
  2. 下载 SSL 证书获取 IIS 文件的文件,这里面的文件夹是需要的,其他的按需获取
    SSL
  3. 上传到服务器桌面

服务器更新 SSL 证书流程:

  1. 打开 IIS 服务器管理器,双击服务器名称、双击服务器证书1
  2. 点击导入2
  3. 导入 SSL 证书(第二项密码是 IIS 文件夹内 keystorePass.txt 文件的内容)3
  4. 网站绑定证书3
  5. 443 端口绑定证书56

查看效果:

如图所示,网站 SSL 证书更新成功

网站SSL证书更新成功

指令 含义 备注
mkdir soft 在当前目录建一个 soft 文件夹
cd soft/ 打开这个文件夹
ll 查看当前文件夹内的所有文件(包含所有文件夹)
rz 上传文件到当前目录中
tar-zxvf 文件名.后缀 解压文件
./configure – prefix=/usr/local/nginx 执行当前目录的./configure命令, prefix=/usr/local/nginx 表示安装到这个目录中去
make 执行编译
make install 命令进行安装
more config.conf 查看 config.conf 文件

1
2
3
4
5
6
/usr/local/nginx/sbin/nginx -c  /usr/loca/nginx/conf/nginx.conf

// 查看是是否启动成功
ps -ef | grep nginx


2019 年 9 月 13 日,过了一个猿宵节,花了一天多增加了一个日志页面,在本博客的左边心情栏进入。

前言

因为看到大神SaltyLeo的文章,觉得 3D 滚动的随笔页面还不错,就打算自己写一个,这个功能在 github 上也有源码,但是我在使用的过程中发现,这个数据源是写了一个 js 文件,以提供静态的 json 数据。于是我就想能够自己动态添加就好了,于是自己写了一个后端程序,后端管理日志的页面,然后这个页面能够动态获取 api 的数据。实现了在随处写写心情、日志的功能。下面写写实现的过程。

技术栈

  • 后端:提供 api,提供增删改查的功能

    1. .net WebAPI ; framework4.6
    2. sqlsugar:充当 ORM 连接数据库
    3. mysql 5.7.27
    4. swagger
  • 后端管理页面:对数据进行增删改查的操作

    1. html + css + js
    2. layui ;版本信息:2.5.5
    3. ajax
  • 日志页面

  • 实用工具

    1. vs2017
    2. vs code
    3. Navicat Premium
    4. chrome
  • 部署环境

    • 1C2G1M 服务器(Windows)
    • Nginx
    • node.js + git 部署

后端提供 API

后端使用了.net WebApi 的 MVC 的分层模式,分别是逻辑层,数据层,控制器,我再加了一个公共方法类的 Common 层,方便自己维护,或者以后添加新功能。创建项目很简单,这里不再赘述,着重讲使用sqlsugar的一些心得,迫于在.net 中使用 EF 太庞大,虽然使用起来很方便,然而我需要的功能不要难么多,所以我选择了比较精小强悍的sqlsugar,性能也不错,使用也方便。sqlsugar 官网有很详尽的文档可以参考。

  1. 引用:在引用sqlsugar的时候请注意本地.net framework 版本相对应,引用方法:在类库中右击引用,选择 管理 NugGet 程序包 如图所示:引用sqlsugar

  2. 建立连接数据库上下文,可以直接参考官网的代码:

    1
    2
    3
    4
    5
    6
    7
    8
    SqlSugarClient db = new SqlSugarClient(
    new ConnectionConfig()
    {
    ConnectionString = "server=.;uid=sa;pwd=@jhl85661501;database=SqlSugar4XTest",
    DbType = DbType.SqlServer,//设置数据库类型
    IsAutoCloseConnection = true,//自动释放数据务,如果存在事务,在事务结束后释放
    InitKeyType = InitKeyType.Attribute //从实体特性中读取主键自增列信息
    });

    但我为了让后期有扩展和可维护的空间,我专门为连接上下文的类进行了简单封装处理,连接数据库的字符串写在网站的we.config文件中;

    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
    public  class DBContextHelper
    {
    // 读取数据库连接字符串
    internal static string DbConnectionString = ConfigurationManager.ConnectionStrings["DefaultConnection"].ConnectionString;
    internal static DbType DbType = DbType.MySql;

    public static SqlSugarClient CurrentDbContext
    {
    get
    {
    return DbContextRepository.DbContext;
    }
    }

    public static SimpleClient SimpleContext
    {
    get
    {
    return DbContextRepository.SimpleContext;
    }
    }

    private static DBContextRepository DbContextRepository
    {
    get
    {
    return new DBContextRepository(DbType, DbConnectionString);
    }
    }
  3. 使用连接上下文:在具体写逻辑的时候可以看sqlsugar官网的 demo,使用 linq 或者 lambda 样式写都没问题,随你的便(开心就好 😂)

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
     // 在一个类中先定义db
    private SqlSugarClient db = DBContextHelper.CurrentDbContext;
    public ResultModel GetMoodList()
    {
    var list = db.Queryable<log>().Where(t => t.isdelete == false).OrderBy("createtime desc").ToList();
    var data = list.MapToList<log, logDto>();
    ResultModel response = new ResultModel();
    response.data = data;
    return response;
    }
  4. 使用接口管理工具 Swagger 进行 api 的测试管理,也是通过 NUgget 管理工具直接引入项目中,就可以直接打开熟悉的 api 管理页面了。swagger

日志管理界面

日志管理界面,使用的是layui的表格(包含分页功能)、form,弹出层等组建,官网的教程写的很详细,这里就不贴代码了。主要想说的是,因为 layui 动态表格分页功能是GET请求的方式,而且对返回的数据格式、字段有一定要求,比如code=0等,这些,需要注意。我在这里花费了比较大量的时间;因为个人需要的功能比较单一,就没有封装Ajax请求后端的方法,就是用了原生的方法,这里使用的比较多的坑点。始终相信:兵来将挡,水来土掩,总会解决的。

给一张效果图:

后端管理界面

日志页面

这里只需要去GitHub 下载源码,引入相应的jscss文件,加载好数据,就能够有 3D 翻转的炫酷效果,当然,因为原生的是加载quotes.js文件中的静态数据,而我是需要获取 api 的数据,所以进行了一番魔改,style.css文件也相应的改了一点,但是改动不多。

这里贴上效果图:

效果图

这里贴上主要的代码:

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
<!DOCTYPE html>
<html>
<head>
<title>FuJiaTian | 日志</title>
<meta charset="utf-8" />
<meta
name="viewport"
content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no, minimal-ui"
/>
<link
href="https://fonts.googleapis.com/css?family=Play:400,700"
rel="stylesheet"
type="text/css"
/>
<link rel="stylesheet" href="css/style.css" />
</head>

<body>
<section id="info">
<header>
<hgroup>
<h1>FuJiaTian</h1>
<h2>愿这里是福家田园</h2>
</hgroup>
<a target="_blank" href="https://www.fujiatian.com">田园野望者</a>
</header>
<aside>
<p>
Quotes:
<a href="http://www.fujiatian.com/" target="_blank"
>www.fujiatian.com</a
>
</p>
</aside>
</section>
<section class="quotes"></section>
<script src="js/jquery.min.js"></script>
<script src="js/foldscroll.js"></script>
<script src="js/quotes.js"></script>
<script type="text/javascript">
$(function() {
var ua = navigator.userAgent;

var ipad = ua.match(/(iPad).*OS\s([\d_]+)/),
isIphone = !ipad && ua.match(/(iPhone\sOS)\s([\d_]+)/),
isAndroid = ua.match(/(Android)\s+([\d.]+)/),
isMobile = isIphone || isAndroid;

//判断

if (isMobile) {
$("#info").css("display", "none");
}
$.ajax({
//请求方式
type: "GET",
//请求的媒体类型
contentType: "application/json;charset=UTF-8",
//请求地址
url: "你的api接口地址",
//数据,json字符串
// data: JSON.stringify(list),
//请求成功
success: function(res) {
getFoldscroll(res.data);
},

//请求失败,包含具体的错误信息

error: function(e) {
getFoldscroll(quotes);
}
});
});
// Call the foldscroll plugin
function getFoldscroll(data) {
var limit = 15;
var $container = $(".quotes");
for (var i = 0, n = Math.min(limit, data.length); i < n; i++) {
$container.append(
"<article>" +
"<p>" +
data[i].quote +
"</p>" +
"<em>" +
data[i].author +
"</em> <br />" +
"<cite>" +
data[i].createtime +
"</cite>" +
"</article>"
);
$container.foldscroll({
perspective: 900,
margin: "220px"
});
}
}
</script>
</body>
</html>

总结与待解决的问题

通过这次自己做小项目,也发现了自己的一些问题,比如form表单的请求方式(如actionmethod都不是很熟悉,也算是自己查漏补缺了。目前也只是能够使用的阶段,还没到完成的地步。希望共勉吧

  1. .net WebApi前后端分离跨域问题,但是这个问题通过某度google搜索,已经暂时解决了,解决办法是在WebApiConfig.cs文件中添加一下代码config.EnableCors(new EnableCorsAttribute("*", "*", "*"));,如下:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    public static class WebApiConfig
    {
    public static void Register(HttpConfiguration config)
    {
    // Web API 配置和服务
    // Web API 路由
    config.MapHttpAttributeRoutes();
    // 解决跨域问题
    config.EnableCors(new EnableCorsAttribute("*", "*", "*"));
    config.Routes.MapHttpRoute(
    name: "DefaultApi",
    routeTemplate: "api/{controller}/{action}/{id}",
    defaults: new { id = RouteParameter.Optional }
    );

    }
    }
  2. 未解决的神奇 Bug:Failed to load resource: the server responded with a status of 401 (Unauthorized),现在在IIS服务器上都没解决,但是我另辟蹊径在nginx部署上了代码。没有这个问题。

    bug

  3. 不知道是服务器原因,还是.net代码的问题,或者是form表单post请求的问题,返回的时候导致会出现服务器错误的问题,但是数据已经正确提交到数据库了(目前已经满足了个人需求了)。

  4. .net WebApi返回的时间带大写字母T的问题,还没解决,网上查过的方法(修改WebApiConfig.cs)已经尝试过了,不管用。

  5. (完)

序言

因为本博客使用的是 hexo 框架,使用的 valine 无后端评论系统,技术支持是leancloud,今日,leancloud官方发了邮件,说从 10 月 1 号开始,将对没绑定域名的应用暂停提供服务,所以本人就本着相应国家号召,做合法的好公民的初心,积极营造健康,开放的互联网环境,分享自己在leancloud绑定域名的操作步骤,为了自己的博客系统能够正常的发展下去。

邮件

LeanCloud 绑定自定义域名

  • 通过官方网站登陆;
  • 进入自己的应用点击设置>域名绑定,自定义一个二级域名,在云引擎域名这里填入你自己自定义的二级域名,按下图填入。
    绑定域名第一步

添加域名 CNAME 解析

在 leancloud 应用中添加域名后,还需要在自己的域名服务商那里添加CNAME解析,下图在腾讯云平台的操作图。
域名解析

最后效果

最后直接上图吧,域名需要备案,域名备案环节不在本篇的讨论范围。
效果

0%