用过许多的web开发框架,我是随着 Python这股热潮来参考的 web 开发方法 Django,之前也有使用过 Java 的 springMVC,RoR 框架。就着开发比较常见的几个问题,谈谈自己粗浅的看法。

结构:语言体系和开发习惯,Java 相对的定义都可以自己尽心约束和配置,完全可以按照自己公司的结构和习惯来编写,所以不存在什么灵活性一说。符合自己公司和团队的规范就好。Django也相对类似,对静态目录通过系统自带的os,path和setting配置可以指定相应的目录作为静态目录或文件的上传目录等类似的功能。在系统的功能规划方面,通过Django生成的工作目录会提供基础的程序,包括初始的wsgi,setting,url等项目基础文件之外,通过django manager startapp会在同级目录下生成相对应的app目录结构,整体来讲文件结构也普遍固定。RoR则依赖“约定大于配置“的信条把绝大部分的目录都规定的妥妥当当。做过类似开发的开发人员基本上都熟悉。完整的mvc目录结构,标准的public,static等都是按照通用的工程结构而来。

至于开发语言,单单讨论Java,Python,Ruby孰优孰劣完全没意义,不讨论,但Python那种强迫症的tab间隔习惯我很喜欢。

常用的开发场景

  • 自动化工具方面,随着Docker,Jenkins之类的工具推出。Java的自动部署和脚手架可以完全自己实现,但是就纯框架自带的功能而言,Django,RoR自带的脚手架确实比较优秀,Django可以通过脚手架自建工程、建立模块、通过模型创建数据库、建立数据库迁移任务。而RoR在这类功能基础之上还提供了一键远程部署、数据库版本回滚、
  • 开发流程和模板:RoR,Django都可以通过指令来生成模块代码,Java没有。Django开发中也封装了一些常用的ListView,DetailView,TemplateView来减少开发的代码量。生成完模块代码后,Django可以通过系统自带的Model层的定义在app中的admin.py通过@注册进入系统自带的后台管理中。不需要任何开发就可以实现web界面对数据的管理功能。这一点我相信是Django最强大也是最遭诟病的地方。优点在于不需要任何代码开发就可以把模型一件注入进入管理平台。只需要配置模型的字段就可实现模型的CURD,List页面的过滤查找。缺点是管理平台非常死板修改难度极大,比如要修改后台的模板风格、对模板变量添加一些常用的处理(比如把{{ temp }}从1替换成为”男”都需要编写代码来实现。)模板中不能使用Python的功能,需要符合模板的Api语法。Java,RoR则可以完全使用语言自带的功能,并且Java可以选择各类模板库作为自己的view展示层,但是他们都没有Django自带的实现需要自行开发。
  • 相关的插件之类:在这里的表现其实都挺不错的,相对来说可能Django,RoR更加的让开发人员“不用太想事儿“通过简单的配置就可以完成相关的功能,例如:分页、查询后参数保持的分页,防CSRF提交、CKEditor富文本编辑框、文件上传、图片切图等。相对而言,Django,RoR因为其插件方式,并且自带了相关的初始插件脚本。如:CKEditor通过pip install,bundle install之后,可以运行一个执行脚本,默认把相关的上传路径,上传的文件类型,图片的自动切图等相关配置通过脚本自动生成,更加省力而已。而Java的强项都是在系统架构方面,如:工作流模块、系统权限模块、数据缓存、分片、微服务等架构层级。所以就日常的业务代码开发而言Django,RoR的亲和力更好,开发中下规模的系统而言。Django,RoR更加具备优势。
  • API和测试:基本都差不多,swagger应该都会有相关的支持,至于测试我想Java应该更加优秀。本身就是一个庞大、繁杂的体系,定制化的自由度也更高。至于文件结构之类,那就是萝卜白菜的事也没有讨论的必要。

个人的感觉,其实Django的开发很尴尬,介于中间的位置。说全自动又没有Rails好,说定制程度和灵活性也没有Java好,我不太喜欢它的继承父类然后重写的方式。一开始都为了这个开发绕了好久,报错信息感觉也没有特别出彩。如果是纯选择开发web我应该还是会选择RoR。接下来就是个人的见解了,因为Python对于大数据、网络抓包、系统底层的服务编程更好。这也是相对RoR的优势。至于Java,嗨,世界第一还有什么好说的。以上是我作为一个完全没有接触过 Python 的萌新的使用体验。

推荐阅读:胡阳编写的 《Django企业开发实战高效Python Web框架指南》,完完整整的自己走一遍,相信每个人都会有自己的开发理解。

在 Vue element-ui 中 from 表单常用的正则可以对此封装一次,方便表单验证使用,搜集了一批常用的正则,出处:
https://www.cnblogs.com/zqifa/p/regex-1.html

1.校验数字的表达式

  1. 数字:^[0-9]*$
  2. n位的数字:^\d{n}$
  3. 至少n位的数字:^\d{n,}$
  4. m-n位的数字:^\d{m,n}$
  5. 零和非零开头的数字:^(0|[1-9][0-9]*)$
  6. 非零开头的最多带两位小数的数字:^([1-9][0-9]*)+(.[0-9]{1,2})?$
  7. 带1-2位小数的正数或负数:^(-)?\d+(.\d{1,2})?$
  8. 正数、负数、和小数:^(-|+)?\d+(.\d+)?$
  9. 有两位小数的正实数:^[0-9]+(.[0-9]{2})?$
  10. 有1~3位小数的正实数:^[0-9]+(.[0-9]{1,3})?$
  11. 非零的正整数:^[1-9]\d$ 或 ^([1-9][0-9]){1,3}$ 或 ^+?[1-9][0-9]*$
  12. 非零的负整数:^-[1-9][]0-9″$ 或 ^-[1-9]\d$
  13. 非负整数:^\d+$ 或 ^[1-9]\d*|0$
  14. 非正整数:^-[1-9]\d*|0$ 或 ^((-\d+)|(0+))$
  15. 非负浮点数:^\d+(.\d+)?$ 或 ^[1-9]\d.\d|0.\d[1-9]\d|0?.0+|0$
  16. 非正浮点数:^((-\d+(.\d+)?)|(0+(.0+)?))$ 或 ^(-([1-9]\d.\d|0.\d[1-9]\d))|0?.0+|0$
  17. 正浮点数:^[1-9]\d.\d|0.\d[1-9]\d$ 或 ^(([0-9]+.[0-9][1-9][0-9])|([0-9][1-9][0-9].[0-9]+)|([0-9][1-9][0-9]))$
  18. 负浮点数:^-([1-9]\d.\d|0.\d[1-9]\d)$ 或 ^(-(([0-9]+.[0-9][1-9][0-9])|([0-9][1-9][0-9].[0-9]+)|([0-9][1-9][0-9])))$
  19. 浮点数:^(-?\d+)(.\d+)?$ 或 ^-?([1-9]\d.\d|0.\d[1-9]\d|0?.0+|0)$

2.校验字符的表达式

  1. 汉字:^[\u4e00-\u9fa5]{0,}$
  2. 英文和数字:^[A-Za-z0-9]+$ 或 ^[A-Za-z0-9]{4,40}$
  3. 长度为3-20的所有字符:^.{3,20}$
  4. 由26个英文字母组成的字符串:^[A-Za-z]+$
  5. 由26个大写英文字母组成的字符串:^[A-Z]+$
  6. 由26个小写英文字母组成的字符串:^[a-z]+$
  7. 由数字和26个英文字母组成的字符串:^[A-Za-z0-9]+$
  8. 由数字、26个英文字母或者下划线组成的字符串:^\w+$ 或 ^\w{3,20}$
  9. 中文、英文、数字包括下划线:^[\u4E00-\u9FA5A-Za-z0-9_]+$
  10. 中文、英文、数字但不包括下划线等符号:^[\u4E00-\u9FA5A-Za-z0-9]+$ 或 ^[\u4E00-\u9FA5A-Za-z0-9]{2,20}$
  11. 可以输入含有^%&』,;=?$\」等字符:[^%&』,;=?$\x22]+
  12. 禁止输入含有~的字符:[^~\x22]+

3.特殊需求表达式

  1. Email地址:^\w+([-+.]\w+)@\w+([-.]\w+).\w+([-.]\w+)*$
  2. 域名:[a-zA-Z0-9][-a-zA-Z0-9]{0,62}(/.[a-zA-Z0-9][-a-zA-Z0-9]{0,62})+/.?
  3. InternetURL:[a-zA-z]+://[^\s]* 或 ^http://([\w-]+.)+[\w-]+(/[\w-./?%&=]*)?$
  4. 手机号码(可根据目前国内收集号扩展前两位开头号码):^(13[0-9]|14[5|7]|15[0|1|2|3|5|6|7|8|9]|18[0|1|2|3|5|6|7|8|9])\d{8}$
  5. 电话号码(「XXX-XXXXXXX」、」XXXX-XXXXXXXX」、」XXX-XXXXXXX」、」XXX-XXXXXXXX」、」XXXXXXX」和」XXXXXXXX):^((\d{3,4}-)|\d{3.4}-)?\d{7,8}$
  6. 国内电话号码(0511-4405222、021-87888822):\d{3}-\d{8}|\d{4}-\d{7}
    7.15位身份证号:^[1-9]\d{5}\d{2}((0[1-9])|(10|11|12))(([0-2][1-9])|10|20|30|31)\d{2}$
    8.18位身份证号:^[1-9]\d{5}(18|19|([23]\d))\d{2}((0[1-9])|(10|11|12))(([0-2][1-9])|10|20|30|31)\d{3}[0-9Xx]$
  7. 帐号是否合法(字母开头,允许5-16字节,允许字母数字下划线):^[a-zA-Z][a-zA-Z0-9_]{4,15}$
  8. 密码(以字母开头,长度在6~18之间,只能包含字母、数字和下划线):^[a-zA-Z]\w{5,17}$
  9. 强密码(必须包含大小写字母和数字的组合,不能使用特殊字符,长度在8-10之间):^(?=.\d)(?=.[a-z])(?=.*[A-Z]).{8,10}$
  10. 日期格式:^\d{4}-\d{1,2}-\d{1,2}
  11. 一年的12个月(01~09和1~12):^(0?[1-9]|1[0-2])$
  12. 一个月的31天(01~09和1~31):^((0?[1-9])|((1|2)[0-9])|30|31)$
  13. 钱的输入格式:
    (1)有四种钱的表示形式我们可以接受:」10000.00″ 和 「10,000.00」, 和没有 「分」 的 「10000」 和 「10,000」:^[1-9][0-9]$ (2)这表示任意一个不以0开头的数字,但是,这也意味着一个字符」0″不通过,所以我们采用下面的形式:^(0|[1-9][0-9])$
    (3)一个0或者一个不以0开头的数字.我们还可以允许开头有一个负号:^(0|-?[1-9][0-9])$ (4)这表示一个0或者一个可能为负的开头不为0的数字.让用户以0开头好了.把负号的也去掉,因为钱总不能是负的吧.下面我们要加的是说明可能的小数部分:^[0-9]+(.[0-9]+)?$ (5)必须说明的是,小数点后面至少应该有1位数,所以」10.」是不通过的,但是 「10」 和 「10.2」 是通过的:^[0-9]+(.[0-9]{2})?$ (6)这样我们规定小数点后面必须有两位,如果你认为太苛刻了,可以这样:^[0-9]+(.[0-9]{1,2})?$ (7)这样就允许用户只写一位小数.下面我们该考虑数字中的逗号了,我们可以这样:^[0-9]{1,3}(,[0-9]{3})(.[0-9]{1,2})?$
    (8)1到3个数字,后面跟着任意个 逗号+3个数字,逗号成为可选,而不是必须:^([0-9]+|[0-9]{1,3}(,[0-9]{3})*)(.[0-9]{1,2})?$

备注:这就是最终结果了,别忘了」+」可以用」*」替代如果你觉得空字符串也可以接受的话(奇怪,为什么?)最后,别忘了在用函数时去掉去掉那个反斜杠,一般的错误都在这里

  1. xml文件:^([a-zA-Z]+-?)+[a-zA-Z0-9]+\.[x|X][m|M][l|L]$
  2. 中文字符的正则表达式:[\u4e00-\u9fa5]
  3. 双字节字符:^\x00-\xff
  4. 空白行的正则表达式:\n\s*\r (可以用来删除空白行)
  5. HTML标记的正则表达式:<(\S?)[^>]>.?|<.? /> (网上流传的版本太糟糕,上面这个也仅仅能部分,对于复杂的嵌套标记依旧无能为力)
  6. 首尾空白字符的正则表达式:^\s|\s$或(^\s)|(\s$) (可以用来删除行首行尾的空白字符(包括空格、制表符、换页符等等),非常有用的表达式)
  7. 腾讯QQ号:[1-9][0-9]{4,} (腾讯QQ号从10000开始)
  8. 中国邮政编码:[1-9]\d{5}(?!\d) (中国邮政编码为6位数字)
  9. IP地址:\d+.\d+.\d+.\d+ (提取IP地址时有用)
  10. IP地址:((?:(?:25[0-5]|2[0-4]\d|[01]?\d?\d)\.){3}(?:25[0-5]|2[0-4]\d|[01]?\d?\d))

使用了 el-upload 的插件,但是一直都是报 404 ,在这个过程中,请注意您使用的 request header 中的 content-type 不同的类型需要的 NodeJS 的 request 解析方式不一样。在 Node 服务端接到用户的数据之后,就需要使用 fs 模块把图片解析成可以保存的文件流,存入磁盘中或者调用后台接口保存。调试了一个小时之后成功通过。把代码留下来,方便日后进行查询。

Vue 层
-------------------------------------
<el-upload class="avatar-uploader" accept="image/jpeg" action="agency/uploadPicForAgency" :data="{agencyId:'1',picFlag:'1'}" :multiple="false" :show-file-list="false" :on-success="handleAvatarSuccess" :before-upload="beforeBackgroundAvatarUpload">
  <img v-if="backgroundUrl" :src="backgroundUrl" width="100%" height="100%" class="avatar">
  <i v-else="" class="el-icon-plus avatar-uploader-icon"></i>
</el-upload>

express 层
-----------------------------------
/**
 * @api {post} agency/uploadPicForAgency 代理商图片上传接口,返回图片存入服务器的URL
 * @apiName agency/uploadPicForAgency
 * @apiGroup agency
 * 
 * @apiParam   {FileObject}   imgInfo    图片文件对象
 * @apiParam   {String}       agencyId   代理商ID
 * @apiParam   {String}       picFlag    图片标记(1-登录页logo图,2-登录页背景图,3-内容页logo图)
 * 
 * @apiParamExample  {type} Request-Example:
 * 传统的FORM表单提交
 * Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryzJ4Ys0x4h70Z8heR
 * 
 * ------WebKitFormBoundaryzJ4Ys0x4h70Z8heR
    Content-Disposition: form-data; name="agencyId"

    000192
    ------WebKitFormBoundaryzJ4Ys0x4h70Z8heR
    Content-Disposition: form-data; name="picFlag"

    1
    ------WebKitFormBoundaryzJ4Ys0x4h70Z8heR
    Content-Disposition: form-data; name="file"; filename="Intel-logo.jpg"
    Content-Type: image/jpeg


    ------WebKitFormBoundaryzJ4Ys0x4h70Z8heR--
 * 
 * @apiSuccessExample {Object} Success-Response:
 * {
 *    message: ""
 *    success: true
 *    data: {
 *      imageStr: "/9j/4AAQSkZJRgABAgAAZABkAAD/7AARRHVja3kAAQAEAAAAXA.............."
        uploadPath: "agency/2019/05/54e4c76df1db41bbbca80c9a7ef16c5f.jpg"
      }
 * }
 */
router.post('/uploadPicForAgency', function (req, res, next) {
  const methodName = 'MAgencyPlatformDataAPI.uploadPicForAgency';
  var form = new formidable.IncomingForm();

  form.encoding = 'utf-8'; //设置编辑
  form.keepExtensions = true; //保留后缀
  form.maxFieldsSize = 2 * 1024 * 1024; //设置单文件大小限制
  form.parse(req, function (err, fields, files) {
    const agencyId = fields.agencyId;
    const picFlag = fields.picFlag;
    var imageBuf = fs.readFileSync(files.file.path);
    var imagebase = imageBuf.toString("base64");
    var imgInfo = {
      imgName: files.file.name,
      imgStr: imagebase,
    }
    util.JSONRPC(methodName, [imgInfo,agencyId,picFlag], function (data) {
      res.json({
        success: true,
        data: {
          uploadPath: data,
          imageStr: imagebase
        },
        message: ''
      })
    }, res);
  })
});

React小书:http://huziketang.mangojuice.top/books/react/lesson1
React 开发者学习线路图(2018):https://www.css88.com/archives/10111
React中文文档:https://react.css88.com/
WebPack 4 教程,从零配置到生产发布:https://www.css88.com/archives/9436
React入门教程:https://react.docschina.org/tutorial/tutorial.html#%E8%AF%BE%E5%89%8D%E5%87%86%E5%A4%87
React Router 教程:https://react-guide.github.io/react-router-cn/docs/guides/basics/IndexRoutes.html

因为 Kaminari 使用的必须是 ActiveRecord 对象,一开始报了个错,半天搞不懂,回头自己重新查询了一下资料,其实官方的 Github 上就已经写好了。

把代码贴出来一下其实挺简单的:

def index
user_name
= params[:user_name]
tempSQL = "select o.*,u.user_name,u.nick_name,u.phone,f.title from
orders o, users u, flies f where o.user_id = u.id and o.goods_id = f.id"
if
!user_name.nil?
puts 'run here'
tempSQL += " and u.user_name = '#{user_name}'"
end
@orders
= Kaminari.paginate_array(Order.find_by_sql(tempSQL)).page(params[:page])
end

Kaminari.paginate_array 中已经就能够完成转换功能了,大家继续,玩得开心哦。

Electron的开发相对还是蛮简单的,看了一写简单的资料就能快速上手开发了。留下三篇相对全的资料,以备查询:
开发:https://juejin.im/post/5a6a91276fb9a01cbd58ce32
打包:https://juejin.im/entry/5805e39ad20309006854e58f
https://www.jianshu.com/p/1c2ad78df208
更新:https://segmentfault.com/a/1190000012904543

剛好在使用CSS中發現,Google Font的服務一直無法使用。之前國内有 360 的替代方案。後來數字公司的服務就下綫了。導致用戶訪問速度一直非常慢。在網上搜過資料原來很多提供靜態資源,CDN服務的公司都相繼下綫了自己的產品。經過谷歌大法,通過一個個的嘗試最後確定 fonts.loli.net 的業務仍然可以使用。

先不多说,上图:

JSDuck文档说明

初步使用,感觉还不错,因为其使用的运行环境是 Gem,所以需要安装 Ruby 相关的环境。安装可以参考链接:https://my.oschina.net/lsjcoder/blog/1583072

常用的命令表如下:

参数 含义
— 或 空 需要生成文档的文件或者目录,也可以是一个集合
–output 文档存放的目录
–config 配置文件路径
–encoding 文档编码方式
–exclude 不生成文档的目录或文件,可以是一个集合
–title 文档标题
–footer 文档标尾
–head-html 文档页面的head中需要添加的内容
–body-html 文档页面的body中需要添加的内容
–css 额外添加的样式​
–welcome 欢迎页面
–guides 向导配置
–examples 示例配置
–categories 分类配置
–images 图片路径配置
–tags 自定义标签
–examples-base-url 示例文件的基础路径
–help 查看命令帮助
–version 查看当前版本

随着 JavaScript 在越来越多的工程中扮演越来越重要的角色,文档的完善越来越重要,同时也开始约束 JSer 慢慢开始学习工程化,系统化的编写代码。开始自我改造吧。