试用期总结

三个月的试用时间一晃就要到了,我在2018年3月28日有幸来到了公司的系统集成部任职软件开发工程师这一岗位。入职当天同事们的热情我至今都没有忘记,当时我就感觉到了这个肯定是一个很有爱的大家庭,我的选择没有错。事实也证明确实如此。老师们十分和蔼,一点都没有架子,我有不理解的地方也会时常去问老师。在公司领导的关心和指导下,在同事们的热情帮助下,我较快熟悉了公司环境,适应了新的工作岗位,现将我试用期的工作情况作简要小结如下:

  • 严格遵守公司各项规章制度。做到了无迟到、早退、违规现象。

  • 主动学习、尽快适应,迅速熟悉环境,了解工作内容。主动、虚心向领导、同事们请教、学习,基本掌握了相关的工作内容,工作流程和工作方法。

  • 工作积极、认真、负责,通过不断学习、请教,定期自我总结,较好地完成了领导安排的各项工作任务。

    • 在领导安排下将健康监测项目的源码进行了反编译,并成功运行部署在服务器上
    • 帮助编写了同济大学土木实验室偏振仪的指令控制代码
    • 对之前的健康监测项目进行了重构,使其变得精简,可读性大幅提升,并成功接入了倾角仪的数据监测服务
  • 虽然之前也是从事物联网相关,但在这短短试用期间深刻认识到自己的涉猎还不够广,之前的NodeJs也只是初步接触,所以希望自己能在这方面加强一些。尤其是当看到身边的许多研究生同学时,在学历上的不足就更需要用不断的学习来弥补了。

  • 存在的问题及解决方法:

    • 我自己可能是比较慢热的人,所以外表看上去感觉好像不太好相处,会让别人感觉很冷漠。其实只要稍稍了解点就不会这么认为了。也可能我在外面的工位上,再加之大家岗位都比较忙,使得同事间的交流就没有那么多了。这还是需要时间的累积吧。
    • 由于我是计算机专业,所以对于建筑这方面缺少了解,一些专业名词更是之前都没听过。后来在老师的指导下,我自己也上网买了相关的书籍。毕竟经常会跟建筑打交道,所以决定在这方面也要下点心思学习学习。
  • 总之,在短短的三个月时间里我接触到了之前未曾接触过的技术,也更加磨炼了自己的构思能力。之后我将进一步严格要求自己,克服不足,加强学习,认真地完成好每一项工作。


My97DatePicker时间日期插件使用示例

前言

  • My97DatePicker目录是一个整体,不可破坏里面的目录结构,也不可对里面的文件改名,可以改目录名
  • My97DatePicker.htm是必须文件,不可删除

各目录及文件的用途

  • WdatePicker.js配置文件,在调用的地方仅需使用该文件,可多个共存,以xx_WdatePicker.js方式命名
  • config.js 语言和皮肤配置文件,无需引入
  • calendar.js 日期库主文件,无需引入
  • My97DatePicker.htm 临时页面文件,不可删除
  • 目录lang 存放语言文件,你可以根据需要清理或添加语言文件
  • 目录skin 存放皮肤的相关文件,你可以根据需要清理或添加皮肤文件包
  • 当WdatePicker.js里的属性:$wdate=true时,在input里加上class=”Wdate”就会在选择框右边出现日期图标,如果您不喜欢这个样式,可以把class=”Wdate”去掉,另外也可以通过修改skin目录下的WdatePicker.css文件来修改样式

示例

没有对控件进行设置

<input class="Wdate" type="text" onfocus="WdatePicker()"/>

限制日期的范围是 2006-09-10到2008-12-20

1
<input id="d411" class="Wdate" type="text" onfocus="WdatePicker({skin:'whyGreen',minDate: '2006-09-10', maxDate: '2008-12-20' })"/>

限制日期的范围是 2008-3-8 11:30:00 到 2008-3-10 20:59:30

1
2
3
<input type="text" class="Wdate" id="d412"
onfocus="WdatePicker({skin:'whyGreen',dateFmt: 'yyyy-MM-dd HH:mm:ss',
minDate: '2008-03-08 11:30:00', maxDate: '2008-03-10 20:59:30' })" value="2008-03-09 11:00:00"/>

限制日期的范围是 2008年2月 到 2008年10月

1
<input type="text" class="Wdate" id="d413" onfocus="WdatePicker({dateFmt: 'yyyy年M月', minDate: '2008-2', maxDate: '2008-10' })"/>

限制日期的范围是 8:00:00 到 11:30:00

1
<input type="text" class="Wdate" id="d414" onfocus="WdatePicker({dateFmt: 'H:mm:ss', minDate: '8:00:00', maxDate: '11:30:00' })"/>

只能选择今天以前的日期(包括今天)

1
<input id="d421" class="Wdate" type="text" onfocus="WdatePicker({skin:'whyGreen',maxDate: '%y-%M-%d' })"/>

使用了运算表达式 只能选择今天以后的日期(不包括今天)

1
<input id="d422" class="Wdate" type="text" onfocus="WdatePicker({minDate: '%y-%M-#{%d+1}' })"/>

只能选择本月的日期1号至本月最后一天

1
<input id="d423" class="Wdate" type="text" onfocus="WdatePicker({minDate: '%y-%M-01', maxDate: '%y-%M-%ld' })"/>

只能选择今天7:00:00至明天21:00:00的日期

1
<input id="d424" class="Wdate" type="text" onfocus="WdatePicker({dateFmt:'yyyy-M-d H:mm:ss',minDate: '%y-%M-%d 7:00:00', maxDate: '%y-%M-#{%d+1} 21:00:00' })"/>

使用了运算表达式 只能选择 20小时前 至 30小时后 的日期

1
2
<input id="d425" class="Wdate" type="text"
onClick="WdatePicker({dateFmt:'yyyy-MM-dd HH:mm',minDate: '%y-%M-%d #{%H-20}:%m:%s' ,maxDate: '%y-%M-%d #{%H+30}:%m:%s' })"/>

前面的日期不能大于后面的日期且两个日期都不能大于 2020-10-01

合同有效期从 到

[注意: 两个日期的日期格式必须相同.
dp. 相当于 document.getElementByIdx_x 函数.
那么为什么里面的 ’ 使用 \’ 呢? 那是因为 ” 和 ’ 都被外围的函数使用了,故使用转义符 \ ,否则会提示JS语法错误.所以您在其他地方使用时注意把 \’ 改成 ” 或者 ’ 来使用。
#F{$dp.$D(\'d4312\')||\'2020-10-01\'} 表示当 d4312 为空时, 采用 2020-10-01 的值作为最大值]

1
2
<input id="d4311" class="Wdate" type="text" onFocus="WdatePicker({maxDate: '#F{$dp.$D(\'d4312\')||\'2020-10-01\'}' })"/>
<input id="d4312" class="Wdate" type="text" onFocus="WdatePicker({minDate: '#F{$dp.$D(\'d4311\')}' ,maxDate:'2020-10-01' })"/>

取值和赋值

html:

1
2
<input class="p-Wdate" type="text"   onfocus="WdatePicker()"/>
<p><button class="tijiaoBtn">提交</button></p>

js:

1
2
3
4
5
6
//赋值
$(".p-Wdate").val("2019-01-01");
//取值
$(".tijiaoBtn").on("click",function(){
console.log($(".p-Wdate").val());
});

参考


Spring Data JPA 初次使用心得

前言

  • 最近在给公司的老项目换个架构,之前的架构太繁琐古老了些,用的是SSH,还是老版的Hibernate3,配置文件看花眼还有Struts2确实看着不习惯,感觉有点费眼,不过在改的过程我觉得它能共享参数有时候还是挺便捷的。
  • 因为之前用的是Hibernate所以我决定用Spring Data JPA,对了,今天我要说下有关于JPA的一些注意点,也是我亲自踩完后发现的,因为之前没有接触过它。
  • Entity实体类与Hibernate没有多大区别@Entity定义实体 @Table定义表明 @Id定义主键 @Column定义数据库中字段映射
    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
    @Entity
    @Table(name = "alarmtable")
    public class AlarmEntity {
    private String channelNumber;
    private double alarmValue;

    @Id
    @Column(name = "channelNumber", length = 20, nullable = false)
    public String getChannelNumber() {
    return this.channelNumber;
    }

    public void setChannelNumber(String channelNumber) {
    this.channelNumber = channelNumber;
    }

    @Column(name = "alarmValue", nullable = false)
    public double getAlarmValue() {
    return this.alarmValue;
    }

    public void setAlarmValue(double alarmValue) {
    this.alarmValue = alarmValue;
    }
    }

这里注意的是当你用驼峰命名字段时会自动用下划线分割,如alarmValue会变成alarm_value

JPA优点

  • 很多人喜欢用JPA的原因是什么,不就是它能省事么,一些基本的CRUD都能替你完成只需要调其方法即可。不过JPA它有特定的命名规则,不能瞎写,写之前还是要去网上看看,这里就不贴示例了。
  • 首先需要先添加依赖,我用的是maven:
    1
    2
    3
    4
    5
    <!-- JPA依赖 -->
    <dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-jpa</artifactId>
    </dependency>
  • 如果你要自定义方法SQL查询,直接使用@Query注解即可,示例:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    /**
    * 查询所有的端口号
    *
    * @return
    */
    @Query(value = "select distinct port from relationtable order by port", nativeQuery = true)
    List<Integer> getAllPort();

    /**
    * 根据设备号删除数据
    *
    * @param instru_serial
    */
    @Transactional
    @Modifying
    @Query(value = "delete from relationTable where instru_serial = :instru_serial", nativeQuery = true)
    void deleteByInstru_serial(@Param("instru_serial") String instru_serial);
    nativeQuery = true说明该sql为原生sql,本地sql查询。

    所谓本地查询,就是使用原生的sql语句(根据数据库的不同,在sql的语法或结构方面可能有所区别)进行查询数据库的操作。

做删除操作时记得加上这两个注解 @Transactional @Modifying

Query的写法有很多种,我这只是其中一种个人认为较为不错的写法,其余可以自行搜索。

Dao层

  • 这里我还是习惯称之为Dao,也就是Repository。如果要使用JPA来操作实体映射类的方法时,你需要继承JpaRepository。JpaRepository有两个参数,第一个是相对于的Entity类即映射实体类,第二个为主键类。

JpaRepository<RelationEntity, Integer> 第一个参数好理解,第二个参数就是对应Entity中用@Id注解表示的字段的类型,若是int则为Integer,String则为String等等。

  • 不过这里我要说的是复合主键,就是当你一个表中存在多个主键的时候。通过查找许多资料后得出方法。@IdClass可以解决我们的问题。把Entity中用@Id定义的字段重新建一个class来制定。请看示例:

Entity Class :

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
package com.tonglei.aiot.entity;

import java.io.Serializable;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.IdClass;
import javax.persistence.Table;

import com.tonglei.aiot.entity.idclass.DVWIdClass;
/**
* 应变映射实体类
*
* @author ffj
*
*/
@Entity
@IdClass(DVWIdClass.class)
@Table(name = "dvw16_instrument_Info")
public class DVWInstrumentInfoEntity implements Serializable {
private static final long serialVersionUID = 1L;
private String instruSerial;
/**
* 通道
*/
private int channel;
/**
* 采样率
*/
private String ratio;
private String channelNumber;

@Id
@Column(name = "Instru_serial", length = 8, nullable = false)
public String getInstruSerial() {
return this.instruSerial;
}

public void setInstruSerial(String instru_serial) {
this.instruSerial = instru_serial;
}

@Id
@Column(name = "channel", length = 11, nullable = false)
public int getChannel() {
return this.channel;
}

public void setChannel(int channel) {
this.channel = channel;
}

@Column(name = "ratio", length = 30, nullable = false)
public String getRatio() {
return this.ratio;
}

public void setRatio(String ratio) {
this.ratio = ratio;
}

@Column(name = "number", length = 20, nullable = false)
public String getChannelNumber() {
return this.channelNumber;
}

public void setChannelNumber(String channelNumber) {
this.channelNumber = channelNumber;
}
}

Id Class :

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
package com.tonglei.aiot.entity.idclass;

import java.io.Serializable;
/**
* 应变复合主键类
*
* @author ffj
*
*/
public class DVWIdClass implements Serializable {
/**
*
*/
private static final long serialVersionUID = 1L;
String instruSerial;
int channel;

public String getInstruSerial() {
return instruSerial;
}

public void setInstruSerial(String instruSerial) {
this.instruSerial = instruSerial;
}

public int getChannel() {
return channel;
}

public void setChannel(int channel) {
this.channel = channel;
}

}

Dao :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
package com.tonglei.aiot.dao;

import org.springframework.data.jpa.repository.JpaRepository;

import com.tonglei.aiot.entity.DVWInstrumentInfoEntity;
import com.tonglei.aiot.entity.idclass.DVWIdClass;
/**
* 应变Dao层接口
*
* @author ffj
*
*/
public interface DVWInstrumentInfoDao extends JpaRepository<DVWInstrumentInfoEntity, DVWIdClass> {

DVWInstrumentInfoEntity findByInstruSerialAndChannel(String instruSerial, int channel);
}

需要注意的是,复合主键类必须实现Serializable接口不然启动会报错。

总结

  • 由于也是第一次使用Spring Data JPA,之前都是用Mybatis的比较多。通过这次的使用发现如果业务上都是一些不太复杂的增删改的话确实能提高不少的效率的。
  • 相对于Mybatis节省了许多配置,懒人首选。
  • 现在还没有用到它的一些复杂的操作,比如多表联查,多表关联什么的,后面用到再详细说明。
  • 通过这次框架的重构也使得我对于其内部方法的调用更加熟悉,虽然还有好多方法我觉得可以更加简单,这个慢慢再优化吧。
  • 终于不用看那一大堆配置文件了。

参考资料


Windows/CMD/Linux/Git常用命令整理

Windows/CMD/Linux/Git常用命令整理,由于平常经常会使用故趁热把这些都一起整理下。

总览


Windows Win+R 快捷操作

有时候不用去挨个点开什么控制面板啊再计算机什么的直接命令快速打开,列举平常使用率较高的几个

打开本地服务

services.msc这个对于开发人员是经常需要操作的

打开注册表

regedit有时候卸载或者重装软件的时候会需要操作注册表

打开CMD界面

cmd这个就不用说了,用管理员方式打开则需要右击操作

打开组策略

gpedit.msc可以查看计算机配置和用户配置

打开记事本

notepad

磁盘清理

cleanmgr可以快速清理一些回收垃圾

查看win版本

winver

打开画图板

mspaint

远程连接

mstsc

shutdown

  • shutdown -r表示重启
  • shutdown -s -t 60表示60秒后正常关机
  • shutdown -s -t 60 -c 关机则多了个提示消息

    常用参数有:"-s"正常关机、"-f"强制关机、"-r"重启、"-t"定时关机、"-c" 设置提示信息、"-a" 是取消定时关机

CMD常用命令

由于本人使用的都是Windows系统,平时难免会需要经常接触CMD来方便一些操作,列举平常使用率较高的几个(cd/dir/切换磁盘什么的这些就不说了…)

查看IP信息

ipconfig

修改本机IP

netsh interface ip set address "以太网" static 192.168.30.100 255.255.255.0 192.168.30.1

注:这里以太网是网络名称,192.168.30.100是你要修改的IP255.255.255.0为子网掩码192.168.30.1为网关

网络诊断

ping putop.top就是给putop.top发送数据包看有没有返回

无线WLAN操作

只要你输入netsh wlan就会出现许多提示,只要能看懂字就会操作了

netsh wlan connect wuxian就是连接无线名为wuxian的无线网络了,netsh wlan disconnect就是断开无线连接

查看端口状态

  • netstat -ano查看所有端口占用情况
  • netstat -aon|findstr "8080"查看指定端口占用情况8080为端口号
  • tasklist|findstr "2018"查看指定PID对应的进程2018为PID
  • taskkill /f /t /im java.exe删除指定进程

    完整语法为:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    TASKKILL [/S system [/U username [/P [password]]]]
    { [/FI filter] [/PID processid | /IM imagename] } [/T] [/F]

    /S system 指定要连接的远程系统。
    /U [domain\]user 指定应该在哪个用户上下文执行这个命令。
    /P [password] 为提供的用户上下文指定密码。如果忽略,提示输入。
    /FI filter 应用筛选器以选择一组任务。允许使用 "*"。例如,映像名称 eq acme*
    /PID processid 指定要终止的进程的 PID。使用 TaskList 取得 PID。
    /IM imagename 指定要终止的进程的映像名称。通配符 '*'可用来指定所有任务或映像名称。
    /T 终止指定的进程和由它启用的子进程。
    /F 指定强制终止进程。
    /? 显示帮助消息。

Linux常用命令

平时部署项目也会用到Linux系统,整理下平时常用的几个(cd/ls/ll这些也不说了…)说来惭愧,经常用ftp操作感觉还挺方便还是Windows用多了啊

系统显示

  • date显示系统时间
  • cal 2018显示2018年的日历表
  • date 060610502018.00设置日期和时间 月日时分年.秒
  • clock -w将时间修改保存到BIOS中
  • cat /proc/cpuinfo显示CPU info的信息
  • lsusb -tv显示USB设备

关机、重启

  • shutdown -h now关闭系统
  • shutdown -h hours:minutes &按预定时间关闭系统
  • shutdown -c取消按预定时间关闭系统
  • shutdown -r now重启
  • logout注销

文件和目录

  • mkdir dir创建名为dir的目录
  • rmdir dir删除名为dir的目录
  • rm -rf dir删除名为dir的目录并同时删除其内容
  • rm -f file删除名为file的文件
  • mv dir new_dir重命名/移动名为dir的目录
  • cp file same_file复制一个名为file的文件叫做same_file
  • cp -a dir same_dir复制一个名为dir的目录叫做same_dir
  • cp dir/* .复制一个目录下的所有文件到当前工作目录
  • cp -a /tmp/dir复制一个目录到当前工作目录

磁盘空间

  • df -h显示已经挂载的分区列表
  • du -sh dir估算目录dir已经使用的磁盘空间

文件权限

  • ls -lh显示权限
  • chmod ugo+rwx dir设置目录的所有人(u)、群组(g)以及其他人(o)以读(r)、写(w)和执行(x)的权限,使用 “+” 设置权限,使用 “-“ 用于取消
  • chattr +a file只允许以追加方式读写文件
  • chattr +i file1设置成不可变的文件,不能被删除、修改、重命名或者链接
  • chattr +S file一旦应用程序对这个文件执行了写操作,使系统立刻把修改的结果写到磁盘
  • chattr +u file若文件被删除,系统会允许你在以后恢复这个被删除的文件
  • lsattr显示特殊的属性

解压/压缩文件

  • 压缩
    • tar –cvf jpg.tar *.jpg将目录里所有jpg文件打包成tar.jpg
    • tar –czf jpg.tar.gz *.jpg将目录里所有jpg文件打包成jpg.tar后,并且将其用gzip压缩,生成一个gzip压缩过的包,命名为jpg.tar.gz
    • tar –cjf jpg.tar.bz2 *.jpg将目录里所有jpg文件打包成jpg.tar后,并且将其用bzip2压缩,生成一个bzip2压缩过的包,命名为jpg.tar.bz2
    • tar –cZf jpg.tar.Z *.jpg将目录里所有jpg文件打包成jpg.tar后,并且将其用compress压缩,生成一个umcompress压缩过的包,命名为jpg.tar.Z
    • rar a jpg.rar *.jpgrar格式的压缩,需要先下载rar for linux
    • zip jpg.zip *.jpgzip格式的压缩,需要先下载zip for linux
  • 解压
    • tar –xvf file.tar解压 tar包
    • tar -xzvf file.tar.gz解压tar.gz
    • tar -xjvf file.tar.bz2解压 tar.bz2
    • tar –xZvf file.tar.Z解压tar.Z
    • unrar e file.rar解压rar
    • unzip file.zip解压zip

查看文件内容

  • cat file从第一个字节开始正向查看文件file的内容
  • tac file从最后一行开始反向查看文件file的内容
  • more file查看一个长文件的内容
  • head -2 file查看一个文件的前两行
  • tail -2 file查看一个文件的最后两行
  • tail -f /var/log/messages实时查看被添加到一个文件中的内容,这个平时查看日志经常会用到

进程

  • ps -ef查看所有运行进程
  • ps -ef|grep java指定查看java进程,java开发人员经常使用,比如鄙人
  • kill PID停止该PID表示进程,必要时加上- 9强制

部署

  • nohup java -jar xx.jar >/dev/null &这是jar包的后台部署,加上&就是后台运行

top视图

  • top进入top视图

    视图数据详解:
    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
    第一行:
    10:01:23 — 当前系统时间
    126 days, 14:29 — 系统已经运行了126天14小时29分钟(在这期间没有重启过)
    2 users — 当前有2个用户登录系统
    load average: 1.15, 1.42, 1.44 — load average后面的三个数分别是1分钟、5分钟、15分钟的负载情况。

    第二行:
    Tasks — 任务(进程),系统现在共有183个进程,其中处于运行中的有1个,182个在休眠(sleep),stoped状态的有0个,zombie状态(僵尸)的有0个。

    第三行:cpu状态
    6.7% us — 用户空间占用CPU的百分比。
    0.4% sy — 内核空间占用CPU的百分比。
    0.0% ni — 改变过优先级的进程占用CPU的百分比
    92.9% id — 空闲CPU百分比
    0.0% wa — IO等待占用CPU的百分比
    0.0% hi — 硬中断(Hardware IRQ)占用CPU的百分比
    0.0% si — 软中断(Software Interrupts)占用CPU的百分比

    第四行:内存状态
    8306544k total — 物理内存总量(8GB)
    7775876k used — 使用中的内存总量(7.7GB)
    530668k free — 空闲内存总量(530M)
    79236k buffers — 缓存的内存量 (79M)

    第五行:swap交换分区
    2031608k total — 交换区总量(2GB)
    2556k used — 使用的交换区总量(2.5M)
    2029052k free — 空闲交换区总量(2GB)
    4231276k cached — 缓冲的交换区总量(4GB)

    第六行是空行

    第七行以下:各进程(任务)的状态监控
    PID — 进程id
    USER — 进程所有者
    PR — 进程优先级
    NI — nice值。负值表示高优先级,正值表示低优先级
    VIRT — 进程使用的虚拟内存总量,单位kb。VIRT=SWAP+RES
    RES — 进程使用的、未被换出的物理内存大小,单位kb。RES=CODE+DATA
    SHR — 共享内存大小,单位kb
    S — 进程状态。D=不可中断的睡眠状态 R=运行 S=睡眠 T=跟踪/停止 Z=僵尸进程
    %CPU — 上次更新到现在的CPU时间占用百分比
    %MEM — 进程使用的物理内存百分比
    TIME+ — 进程使用的CPU时间总计,单位1/100秒
    COMMAND — 进程名称(命令名/命令行)

Git常用命令

不免要使用git来版本管理

  • git init创建版本库
  • git clone克隆仓库
  • git add添加文件到暂存区
  • git commit提交更改,加上- m增加提交说明
  • git status查看状态
  • git rm删除文件
  • git diff文件对比
  • git log日志显示
  • git push上传
  • git merge合并
  • git branch -d删除分支
  • git fetch获取分支
  • git pull更新

参考资料


Java中一些小知识点

今天来总结一些平时不起眼的东西。For Java.


for循环进行遍历删除元素

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
ArrayList<String> list = new ArrayList(Arrays.asList("a", "b", "c", "d"));
System.out.println("before :" + list);
// 在这个方法中有一个严重的错误。当一个元素被删除时,列表的大小缩小并且下标变化,
// 所以当你想要在一个循环中用下标删除多个元素的时候,它并不会正常的生效。
for (int i = 0; i < list.size(); i++) {
String s = list.get(i);
System.out.println("s :" + s);
if ("a".equals(s)) {
list.remove(s);
}
if ("b".equals(s)) {
list.remove(s);
}
}
System.out.println("after :" + list);

上述代码结果不尽人意:

1
2
3
4
5
before :[a, b, c, d]
s :a
s :c
s :d
after :[b, c, d]

这正是因为注释中说的那样,list.remove()操作完的时候list就已经改变了大小以及下标,故当”a”删除后list变成了["b","c","d"],然而下标变成了1,这时候取值就是变成了”c”,所以”b”这个元素就自然跳过了。
故我们在进行遍历删除list中元素时要使用Iterator迭代器来操作

变量声明

今天自己写了几行简单测试了下:

1.
1
2
3
4
5
6
7
8
9
System.out.println("----------------start------------------");
int num = 100000;
long start = System.currentTimeMillis();
for (int i = 0; i < 9999999; i++) {
num += 20000;
}
long end = System.currentTimeMillis();
System.out.println("时间差 >> :" + (end - start));

结果为:

1
2
----------------start------------------
时间差 >> :2
2.
1
2
3
4
5
6
7
8
9
System.out.println("----------------start------------------");
Integer num = 100000;
long start = System.currentTimeMillis();
for (int i = 0; i < 9999999; i++) {
num += 20000;
}
long end = System.currentTimeMillis();
System.out.println("时间差 >> :" + (end - start));

结果为:

1
2
----------------start------------------
时间差 >> :20

结果差了整10倍。想必数据一大自动拆装箱也挺累的吧。故之后变量要多次基本操作声明尽量不用包装类

String相关

  • intern()

    1
    2
    3
    4
    5
    6
    7
    8
    9
    String str = "sss";
    String str1 = new String("sss");
    String str2 = str1;

    System.out.println("str2.intern() == str1 >>" + (str2.intern() == str1));
    System.out.println("str2.intern() == str3 >>" + (str2.intern() == str));
    System.out.println("str2.intern().equals(str1) >>" + str2.intern().equals(str1));
    System.out.println("str2 == str1 >>" + (str2 == str1));
    System.out.println("str2.equals(str1) >>" + str2.equals(str1));

    结果:

    1
    2
    3
    4
    5
    str2.intern() == str1 >>false
    str2.intern() == str3 >>true
    str2.intern().equals(str1) >>true
    str2 == str1 >>true
    str2.equals(str1) >>true

    我个人理解是,str2.intern()即是str1.intern()指向的故是常量池中的”sss”,常量池中的”sss”就是str,str1指向一个String对象,而equals比较大小就不说了。这里面说得就详细多了。

  • new String

    1
    2
    3
    4
    5
    6
    7
    char[] c = { '1', '2', '3', '4', '5', '6', '7', '8' };
    String strC = new String(c, 2, 3);
    System.out.println("strC >>" + strC);

    int[] arrInt = { 1, 2, 3, 4, 5, 6, 7, 8 };
    String strI = new String(arrInt, 2, 3);
    System.out.println("strI >>" + strI);

    结果:

    1
    2
    strC >>345
    strI >>

    从下标2位置(包含)开始截取,数量为3

  • join

    1
    2
    String joinS = String.join(":", "e", "r", "y");
    System.out.println("joinS >>" + joinS);

    结果:

    1
    joinS >>e:r:y

    我们走进join源码看一下:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    public static String join(CharSequence delimiter, CharSequence... elements) {
    Objects.requireNonNull(delimiter);
    Objects.requireNonNull(elements);
    // Number of elements not likely worth Arrays.stream overhead.
    StringJoiner joiner = new StringJoiner(delimiter);
    for (CharSequence cs: elements) {
    joiner.add(cs);
    }
    return joiner.toString();
    }

    发现了StringJoiner

  • StringJoiner

所以也可以这么用:

1
2
3
StringJoiner joiner = new StringJoiner(",");
joiner.add("a").add("b").add("c");
System.out.println(joiner.toString());

结果:

1
a,b,c

Today End.


Face++与Java简单应用(新)

开篇

  • 前段时间逛了下旷视官网,真是变化好大页面好漂亮现在,依稀记得最开始上的官网哪来这么炫酷
  • 然后就继续点进去看了下Face++API,果不其然参数变了不少,识别点越来越多了
  • 再接下来我又翻了翻自己很久前写的一篇博文,这不行了,这之前写的啥玩意,代码也找不到了,而且现在也不能用了,故,立了个flag

操刀

开始操刀了,还是一样我选择了SpringBoot,没什么,就是方便。这次选择用BootStrap框架。

  • 首先操刀之前,先去上面官网去注册用户,创建个应用,目的是为了获取它的api-key和api-secret
  • 现在不像之前那样复杂了,那时候还得下个jar包导入才能调它的方法,现在直接在线调用即可。具体代码如图位置:这样的话只需要把你需要识别的图片路径,你刚获取的api-key和api-secret替换就行了,然后你就可以得到一串json格式的字符串。太长我就不放了,主要信息就在faces中。我这里主要就是简单获取faces下面attributes中的一些参数。具体可直接看它官网的API,很详细的。
  • 图片上传我使用的是BootStrap-FileInput插件,这个插件确实很美观,刚开始使用的时候不太会,故研究了会。特别需要注意需要导入此插件的js和css,不然你就会有种想砸键盘的感觉了。

html:

1
2
3
4
<div class="modal-body" style="text-align: center;">  
<a href="" class="form-control" style="border:none;">上传照骗</a>
<input type="file" name="picFile" id="picFile" class="file-loading" />
</div>

js:

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
//参数1:控件id、参数2:上传地址  
init("picFile", "/sendPic");

//初始化fileinput控件(第一次初始化)
function init(ctrlName, uploadUrl) {
var control = $('#' + ctrlName);
//初始化上传控件的样式
control.fileinput({
language: 'zh', //设置语言
uploadUrl: uploadUrl, //上传的地址
allowedFileExtensions: ['jpg', 'png', 'jpeg'], //接收的文件后缀
showUpload: true, //是否显示上传按钮
showCaption: false, //是否显示标题
browseClass: "btn btn-primary", //按钮样式
dropZoneEnabled: false, //是否显示拖拽区域
//minImageWidth: 50, //图片的最小宽度
//minImageHeight: 50, //图片的最小高度
//maxImageWidth: 1000, //图片的最大宽度
//maxImageHeight: 1000, //图片的最大高度
maxFileSize: 2048, //单位为kb,如果为0表示不限制文件大小
//minFileCount: 0,
//maxFileCount: 10, //表示允许同时上传的最大文件个数
//enctype: 'multipart/form-data',
validateInitialCount:true,
previewFileIcon: "<i class='glyphicon glyphicon-king'></i>",
//msgFilesTooMany: "选择上传的文件数量({n}) 超过允许的最大数值{m}!",
uploadExtraData:function (previewId, index) { //传参
var data = {
//此处自定义传参
};
return data;
}
});

//导入文件上传完成之后的事件
$("#picFile").on("fileuploaded", function (event, data, previewId, index) {

});
}

文件上传成功后后台还需要接收它,如何接收?且听我慢慢道来:

1
2
MultipartHttpServletRequest multipartRequest = (MultipartHttpServletRequest) request;
List<MultipartFile> fileList = multipartRequest.getFiles(dstFileName);

这两句可以接收到对应页面上传的图片,List说明它可以一次上传多张。既然能接收到,那就什么都不是事了。接下来想怎么玩就怎么玩。

  • 在页面用到BootStrap模态框的时候我发现它不能拖拽,然后网上冲浪了一会,发现把jquery-ui导入就可以使用draggable()方法。可全局可单页面,我这里是全局设置。

    1
    2
    3
    4
    5
    6
    // 使模态框可拖拽		    
    $(document).on("show.bs.modal", ".modal", function(){
    $(this).draggable();
    $(this).css("overflow-y", "scroll");
    // 防止出现滚动条,出现的话,你会把滚动条一起拖着走的
    });
  • 前端知识还需要恶补啊,现在页面想做点炫酷的效果是一点办法没有,布局排版还丑的一批。还需努力啊!

Screenshots

  • Index

  • One Person Result

  • More than One Person Result


那一天,那一月,那一年

文章首发个人公众号:普度狗生

那一天,
我闭目在经殿的香雾中,
蓦然听见,
你诵经中的真言;

那一月,
我摇动所有的经筒,
不为超度,
只为触摸你的指尖;

那一年,
磕长头匍匐在山路,
不为觐见,
只为贴着你的温暖;

那一世,
转山转水转佛塔,
不为修来世,
只为途中与你相见;

那一夜,
我听了一宿梵唱,
不为参悟,
只为寻你的一丝气息;

那一月,
我转过所有经筒,
不为超度,
只为触摸你的指纹;

那一年,
我磕长头拥抱尘埃,
不为朝佛,
只为贴着你的温暖;

那一世,
我翻遍十万大山,
不为修来世,
只为路中能与你相遇;

那一瞬,
我飞升成仙,
不为长生,
只为佑你平安喜乐;

只是,
就在那一夜,
我忘却了所有,
抛却了信仰,
舍弃了轮回,
只为,
那曾在佛前哭泣的玫瑰,
早已失去旧日的光泽。


个人博客今日开启

说说为什么弄了这个博客呢

  • 首先最近比较闲 - - 不太忙应该这么说
  • 其次呢前几天终于下狠心买了个一年的云服务器(超低配,搞活动..),心想,我这资源不能浪费啊,怎么说也是好几张老毛啊

然后决定开搞那就搞,上网开始搜一些博客模板,之前了解过WordPress/Hexo,后来还是决定就Hexo了还能托管在GitHub上也方便。


于是乎就去找适合自己的主题了呗,一个猛子扎下去,我的乖宝贝,这些五花八门的主题还真是炫酷炸宇宙啊。可是,我喜欢简约的。


就在这时,melody出现在我眼前。还真是确认过眼神,你就是我想要的简约啊…
so,选定离手,开始操刀了。


前前后后也是弄了一天时间吧,因为之前没有弄过这些类似的静态博客还是一步步看其他兄弟的详细步骤操刀下来的。一路走下来,看自己的博客逐步搭好也是莫名舒坦。


部署到GitHub上/部署到云服务器上


博客搭是搭好了,可惜没有干货啊..( ▼-▼ )


Hello World

This is a Test Page …


## 这是hexo的一个测试