豪翔天下

Change My World by Program

0%

帮助方法

  • Laravel中的帮助方法无法重写,如果要重写,只能自己单独写放在app/helpers.php里面去,还需要在composer.json中添加配置:

    1
    2
    3
    4
    5
    6
    "autoload": {
    ...
    "files": [
    "app/helpers.php"
    ]
    }

数组和对象

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
# 返回第一个或最后一个元素
head($array);
last($array);

# 合并多个数组为一个单一的数组
Arr::collapse([[1,2,3], [4,5,6], [7,8,9]]); // [1,2,3,4,5,6,7,8,9]

# 从数组/字典移除指定的key
$array = ['name' => 'Desk', 'price' => 100, 'products' => ['desk' => ['price' => 100]]];
Arr::except($array, ['price']); // ['name' => 'Desk']
# 还可以通过点号的方式来移出多级key
Arr::forget($array 'products.desk'); // ['name' => 'Desk', 'price' => 100]
# 使用点号获取多级的值,第三个参数为默认值
$array = ['products' => ['desk' => ['price' => 100]]];
Arr::get($array, 'products.desk.price', $defaultValue); // 100
data_get($array, 'products.desk.price', $defaultValue); // 同上
data_get($array, '*.name');// 设置支持通配符
# 可使用has来查看是否有某个key,或多个key
Arr::has($array, ['product.price', 'product.discount']);
# 查看是否包含多个key中的一个
Arr::hasAny($array, ['product.name', 'product.discount']);
# 给数组添加元素
Arr::prepend($array, 'zero');
Arr::prepend($array, 'Desk', 'name'); // 会添加一个'name' => 'Desk'
# 获取并移除一个元素
Arr::pull($array, 'name', $defaultValue)

# 检查数组是否存在某个key
Arr::exists($array, 'key');

# 查找第一个回调函数返回true的元素,第三个参数可以指定默认值
Arr::first($array, function($value, $key) {return $value >= 2;}, $defaultValue);

# 仅返回指定key组成的数组
$array = ['name' => 'Desk', 'price' => 100, 'orders' => 10];
Arr::only($array, ['name', 'price']); // ['name' => 'Desk', 'price' => 100]

# 将数组/字典所有的value组成一个单一的数组
$array = ['name' => 'Joe', 'languages' => ['PHP', 'Ruby']];
$flattened = Arr::flatten($array); // ['Joe', 'PHP', 'Ruby']
# 将指定的key的value组成一个单一的数组
$array = [
['developer' => ['id' => 1, 'name' => 'Taylor']],
['developer' => ['id' => 2, 'name' => 'Abigail']],
];
Arr::pluck($array, 'developer.name'); // ['Taylor', 'Abigail']
Arr::pluck($array, 'developer.name', 'developer.id'); // [1 => 'Taylor', 2 => 'Abigail']

// 将数组作为url的查询参数
$array = ['name' => 'Taylor', 'order' => ['column' => 'created_at', 'direction' => 'desc']];
Arr::query($array); // name=Taylor&order[column]=created_at&order[direction]=desc

// 从数组中随机取一个元素
Arr::random($array);
Arr::random($array, 2); // 第二个参数表示随机取N个元素

// 数组排序
Arr::sort($array);
array_values(Arr::sort($array, function ($value) { // 如果是字段需要指定排序方式
return $value['name'];
}));

// 返回符合条件的元素组成的数组,类似于js里面的filter
Arr::where($array, function ($value, $key) {
return is_string($value);
});
阅读全文 »

前两天团队接到一个新项目,我需要为其配置Circle CI,于是就又折腾了一下,不过还好,毕竟之前做过运维的,CI的基本原理是知道的,所以很快就弄好了,这里也简单的记录一下。

1. 为项目开启Circle CI

这一步需要在circleci后台项目列表里面为指定的项目开启配置Set Up Project,因为第一步已经编写好了配置文件,所以这里可以直接选择start building。这一步circleci会自动在对应的项目里面添加Deploy Key并且会自动配置到circleci的项目管理里面,如下:

阅读全文 »

禁用csrf认证

全局禁用csrf

app/Http/Kernel.php中,$middleware表示全局中间件,而$routeMiddleware表示针对某个路由的中间件,所以只需要把csrf在$middleware中注释掉,然后在$routeMiddleware中添加'csrf' => 'App\Http\Middleware\VerifyCsrfToken'
如果要在某个路由上使用就这样:

1
2
3
Route::group(['middleware' => 'csrf'], function(){     // csrf保护的接口
Route::get('/', 'HomeController@index');
}
针对某几个接口单独禁用csrf

可以在app/Http/Middleware/VerifyCsrfToken$except添加,但是这里的添加只能以正则的方式来匹配,不能使用路由别名,如果路由中有参数可以用星号代替

1
2
3
4
protected $except = [
'webhook/*',
'users/*/profile'
];

一个页面调用多个接口如何传递CSRF Token

由于csrf_token是存储于session的,依照laravel的实现机制,同一时间只能有一个_token,所以无法实现一个页面设置多个csrf token,要解决这个问题要么将非必要的接口忽略csrf,要么每次请求api后从后台生成并返回一个新的token

阅读全文 »

在需要这个效果的时候首先在npm仓库找到了vue-dragscroll库,但是应用在我们自己项目上的时候拖动起来却非常慢,元素跟不上鼠标的移动速度,无奈,就自己简单的实现了一个拖拽指令:

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
import Vue from 'vue'

Vue.directive('dragscroll', function (el) {
el.onmousedown = function (ev) {
const disX = ev.clientX
const disY = ev.clientY
const originalScrollLeft = el.scrollLeft
const originalScrollTop = el.scrollTop
const originalScrollBehavior = el.style['scroll-behavior']
const originalPointerEvents = el.style['pointer-events']
el.style['scroll-behavior'] = 'auto'
// 鼠标移动事件是监听的整个document,这样可以使鼠标能够在元素外部移动的时候也能实现拖动
document.onmousemove = function (ev) {
ev.preventDefault()
const distanceX = ev.clientX - disX
const distanceY = ev.clientY - disY
el.scrollTo(originalScrollLeft - distanceX, originalScrollTop - distanceY)
// 由于我们的图片本身有点击效果,所以需要在鼠标拖动的时候将点击事件屏蔽掉
el.style['pointer-events'] = 'none'
}
document.onmouseup = function () {
document.onmousemove = null
document.onmouseup = null
el.style['scroll-behavior'] = originalScrollBehavior
el.style['pointer-events'] = originalPointerEvents
}
}
})

由于我们项目使用了是Nuxtjs,如果完全由后端渲染,是无法在document上进行事件监听的,所以在nuxt.config.js中这样定义插件:

1
2
3
plugins: [
{ src: '@/plugins/dragscroll', ssr: false }
],

最后可以在任何元素上应用该指令:

1
<div dragscroll><img /></div>

最终的结果类似这样

布局

栅格布局

  • el-rowel-col可以搭配实现24格的栅格布局

  • el-row支持如下属性

参数 含义 说明 可选值 默认值
gutter 每两个栅格之间的间隔(单位是px) number - 0
type 布局模式 string - -
justify flex布局下的水平排列方式 string start/end/center/space-around/space-between start
align flex布局下的垂直排列方式 string top/middle/bottom top
tag 自定义元素标签 string * div
  • el-col支持如下属性
参数 含义 说明 可选值 默认值
span 栅格占据的列数 number - 24
offset 栅格左侧的间隔格数 number - 0
push 栅格向右移动格数 number - 0
pull 栅格向左移动格数 number - 0
xs <768px 响应式栅格数或者栅格属性对象 number/object (例如: {span: 4, offset: 4})
sm ≥768px 响应式栅格数或者栅格属性对象 number/object (例如: {span: 4, offset: 4})
md ≥992px 响应式栅格数或者栅格属性对象 number/object (例如: {span: 4, offset: 4})
lg ≥1200px 响应式栅格数或者栅格属性对象 number/object (例如: {span: 4, offset: 4})
xl ≥1920px 响应式栅格数或者栅格属性对象 number/object (例如: {span: 4, offset: 4}) - -
tag 自定义元素标签 string * Div

栅格布局一般会根据实际的各个分辨率下的情况来设置每个布局的宽度,如果想要直接换行,也可以某一种分辨率之和超过24,这样只要两个col超过24就会换行,例如:

1
2
3
4
5
6
<el-row :gutter="24">
<el-col :xs="20" :sm="6" :md="4" :lg="3" :xl="1"><div></div></el-col>
<el-col :xs="20" :sm="6" :md="8" :lg="9" :xl="11"><div></div></el-col>
<el-col :xs="20" :sm="6" :md="8" :lg="9" :xl="11"><div</div></el-col>
<el-col :xs="20" :sm="6" :md="4" :lg="3" :xl="1"><div</div></el-col>
</el-row>
阅读全文 »

这个周末有点闲暇时间,老婆在我身后准备期末考试(回老家一人一张书桌),所以我准备做个年终总结。因为疫情、老婆怀孕、换工作,所以年初的计划基本全部被打乱了。

工作方面

万万没想到在上家公司的最后半年会这么累,不过也还好,这让我蓄谋已久的离职也变得顺理成章了。本来上家公司的工资一直很低,但好在工作清闲,所以虽然我一直说要离职,但始终没有下定决心。不过由于公司内部调整,阴差阳错地进入了一个业务部门。我实在无法适应大公司的业务部门,仅用半个月的时间就超过了我过去三年所有的加班时间,并且周末还得时刻神经紧绷,因为公司的问题电话会随时打给你,哪怕问题和你根本没半毛钱关系,你也得拿出电脑去解决。那种感觉是我再也不想经历的。所以,在请完婚假后第一天就去提交离职申请了。年初我就计算过,今年产检、年假、婚假、产检、离职、疫情,可能往后几十年,就数今年的假期最多了,不过假期多也没什么用,因为老婆假期不多,即使婚假也得在家复习。所以我过了所有人都无法想象的婚假: 在家撸代码。

技术方面

去年年底由于工作安排,强迫学习了Java,基本达到了能熟练开发Java项目的地步。不过由于那边业务比较单一历史框架死板,所以也没遇到多少技术难题,加班主要是因为任务太紧。6月底至今在新公司,全栈开发岗位,不过大部分是前端Vuejs + Nodejs,所以前面两周也很累的,每天下班后都需要恶补一下前端知识。但远程工作好的地方是不加班,以后我会详细介绍远程工作的爽与不爽。几周过去,也算是入门前端了,基本能够配合框架快速实现想要的效果了,也渐渐地开始尝试看Vue源码,因为总感觉自己的前端代码写得有点low。不出意外,下半年在技术上主要是针对前端和AWS的深入学习了。对了,新公司基本是用英语交流的,所以英语学习也至关重要;据老板说转正后每周有和外国友人直接语音交流的机会,不过在一群高手面前,转正还得继续努力💪。

生活方面

一方面因为换到了远程工作且新工作不给买社保,所以上半年一直在研究社保和个人所得税方面的问题,现在的我自我感觉算是半个这方面的专家了。现在,我是以个人身份参加了职工医保和养老保险,算下来一个月一千多,不用说,肯定公司帮忙交划算,不过个人如果不用其它险种和公积金,这样交才是最划算的。

另一方面,家里要迎来新成员了。做了好多的计划,买了好多的东西,本来6月份因为多干了一些活儿多几千块收入,但是618买一波母婴用品花得干干净净的。第一次知道他们为啥被称为“四脚吞金兽”了。唯一让我压力小点的就是有极大的可能是女儿,我那时相当高兴的呀。虽然我积攒已久的育儿经验都得改一下,但是女孩子的话是真的真的好轻松,感谢老婆!

为什么要用nuxt.js,主要就是因为它可以服务端渲染(SSR),相比于传统的vue单页应用,将渲染放到服务器这边,性能肯定能得到很大提升,并且首次加载无需加载特别大的资源,且对搜索引擎友好,所以没有什么理由不用它。

目录结构

assets: 资源目录,用于组织未编译的静态资源

components: 组件目录

layouts: 布局目录

middleware: 中间件目录

pages: 页面目录

plugins: 插件目录

static: 插件目录,会被直接映射到根目录下,可以放置favicon.ico/robots.txt等文件

store: 用于组织应用的vuex状态树文件

nuxt.config.js: 个性化配置文件

阅读全文 »

Spring Initializr:Spring项目初始化工具。

打包

打包成war: mvn clean package

框架分层结构

调用顺序

Controller –> Service Interface –> Service Impl –> Dao Interface –> Dao Impl –> Mapper –> DB

BIZ层

Service(业务逻辑,可以建立子文件夹来进行分类,这样每个biz就可以更细分,如果Biz和Servic都单独作为一层,那么Biz的粒度更细,Service则是提供给别人的接口)、Schedule(定时任务)、Common(一些中间件认证登录等)、Manager、RPC Service、MQTask、JobTask。也有Service和BIZ平行的分层方式,这种情况,一般是Service在调用Biz,Biz执行数据库操作,类似于Manager。

BO(Business Object)

COMMON层

一些公共的对象,公共的抽象类、公共的异常、公共的帮助方法等

DAO层

一般是由MyBatis等工具自动生成的。

DO/PO(Data Object/Persistant Object,与数据表直接对应,也叫Entity层或者Model层):用于存放实体类,与数据库中的属性值保持一致。

Mapper: 对数据库进行数据持久化操作,它的内部方法就是直接对数据库进行操作的。它类似于manager层。可以封装对数据库的复杂的操作。

VO(value object,类似于将数据库的字段抽象为新的业务相关的字段): VO往往用于请求处理层,即Controller。

INTEGRATE层

外部系统的一些接口

Web层

Controller、Config(一些初始化配置,例如线程池、缓存池等配置的初始化)

阅读全文 »

安装

  • npm install -g @vue/cli && vue create my-project

  • 可以在new Vue之前使用window.函数名=function() {}创建一个全局的函数方法

  • vue中使用bootstrap可以直接用BootstrapVue,如果要单独安装可以这样做:npm install --save bootstrap jquery popper.js ,然后在main.js中加入即可

    1
    2
    import 'bootstrap/dist/css/bootstrap.min.css'
    import 'bootstrap/dist/js/bootstrap.min'

配置

vue.config.js

  • 用vue-clic3脚手架新建的项目,默认是没有vue.config.js文件的,可以手动创建,如果项目根目录里面有它,它会被@vue/clic-service
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
const CopyWebpackPlugin = require('copy-webpack-plugin');

module.exports = {
outputDir: '../cordova/www',
publicPath: '.',
pluginOptions: {
rules: [
{
test: /\.scss$/,
use: [
'vue-style-loader',
'css-loader',
'sass-loader'
]
}
]
},
configureWebpack: {
devtool: 'source-map',
plugins: [
new CopyWebpackPlugin([{
from: 'public'
}])
],

}

自动加载模板语法

  • 模板中如果遇到这种类型的三目运算符a ? a : b,最好用{a || b}来代替
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
// v-bind
<a v-bind:href="url">...</a>
<a v-bind:href="`/api/${item.id}`">...</a> // 属性绑定的时候拼接字符串,也可以用['/api/' + item.id]的方式
<a :href="url">...</a> // 缩写
<a title="test"></a>// 如果仅想传入一个字符串作为props给组件,那么不用加冒号
<a :hidden="shouldHidden==='letshidden'"> // 在v-bind中直接用表达式
<img v-bind:src="pic" v-for="pic in pics" />

// v-model
<input type="text" v-model="msg"> // 等价于<input type="text" :value='msg' @input='handleInput'>
<select v-model="selection"></select> // 如果是select那么model需要绑定到select上,可以直接获取其selected value

// 遍历v-for
<li v-for="item in items">{{item}}</li>
<li v-for="(item, index) in items">{{item}}的索引是{{index}}</li>
<li v-for="(value, name, index) in items">遍历key=>value格式的数组,遍历字典,顺便还有索引</li>
<li v-for="(item,index) in items"><span v-if="index !== items.length-1">判断是否是列表最后一个元素,目前没找到更好的方法</span></li>

// v-on
<a v-on:click="doSomething">...</a>
<a @click="doSomething">...</a>

// v-html,将内容不转义直接展示为html内容,如果是用户输入的内容,这里一定要防止XSS攻击,最简单的方法就是使用https://github.com/leizongmin/js-xss在外面处理一下
<div v-html="XSS(data)"></div>
<div v-html="$options.filter.myfilter(data)"></div> // v-html中使用过滤器

// v-if, v-else, v-else-if, 条件判断
// v-show,只是控制是否展示,DOM是存在的
阅读全文 »

建议安装Mybatis-plus

Mybatis官方文档

目录结构

  • Mapper.xml文件是真实的SQL语句对应关系

MyBatis生成的DAO层文件目录如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
.
├── entity
│   ├── Table1.java # 这是数据Model,即使数据记录对应的Java类,里面包含对应表的字段、注释及get和set方法
│   ├── Table1Example.java # MySQL查询相关的一些简单的语句拼接,针对每个字段都有几个常用的SQL语句拼接方法。比如等于、大于、小于等方法
│   ├── Table2.java
│   └── Table2Example.java
└── mapper
├── Table1Mapper.java
├── Table1Mapper.xml
├── Table2Mapper.java
├── Table2Mapper.xml
└── ext # MyBatis并不会默认生成,可以在这里编写自定义的查询方法
├── MyExtMapper.java
└── MyExtMapper.xml
阅读全文 »