JAVA
1.数字格式化
DecimalFormat format = new DecimalFormat("000");
2.Logger日志输出以这种方式
logger.info("=== 消息队列接收信息 : {}", msg);
3.Jackson 高性能的JSON处理 ObjectMapper
可以把json转换成各种对象,各种对象转json,可以用于消息队列的传递
前端传一个map,map的一个key对应的value是List对象,后台拿到map怎么转
1 | private ObjectMapper mapper = new ObjectMapper(); |
4.线程安全队列
一个线程安全的队列实现方式有两种:1是使用阻塞方法、2是使用非阻塞。阻塞就是加锁,非阻塞采用循环CAS的方式实现
1 | ConcurrentLinkedQueue是一个基于链接节点的无界线程安全队列,它采用先进先出的规则对节点进行排序,当我们添加一个元素的时候,它会添加到队列的尾部,当我们获取一个元素时,它会返回队列头部的元素。 |
5.SpringBoot定时任务
定时任务:@Scheduled \
fixedRate 任务两次执行时间间隔是任务的开始点 \
fixedDelay 的间隔是前次任务的结束与下次任务的开始 \
cron 表达式
6.RandomAccessFiles随机流
针对文件内容进行操作,完成随机读取功能,可以读取指定位置的内容
7.求日期相差天数
1 | int day = (int) ((x.getDeadline().getTime() - new Date().getTime()) / (1000 * 3600 * 24)); |
8.排序
list.sort(Comparator.comparing(x->x.getId));
9.SpringBoot项目打成jar后获取classpath下文件
1 | ClassPathResource resource = new ClassPathResource("application.yml"); |
ModelMapper:对象与DTO转换
1 | IssueDTO issueDTO = modelMapper.map(issue,IssueDTO.class); |
ResponseEntity:封装返回的HttpStatus,可定义
bootstrap 和 application 的区别
和application 配置文件相比,bootstrap 配置文件具有以下几个特性:
bootstrap 由父ApplicationContext加载,比application优先加载;
bootstrap里面的属性不能被覆盖
开启线程
1)extends Thread
重写run方法
2)implements Runabled
实现run方法,.start()开启
悲观锁与乐观锁
- 悲观锁
总是假设最坏的情况,每次取数据时都认为其他线程会修改,所以都会加锁(读锁、写锁、行锁等),当其他线程想要访问数据时,都需要阻塞挂起。可以依靠数据库实现,如行锁、读锁和写锁等,都是在操作之前加锁,在Java中,synchronized的思想也是悲观锁
- 乐观锁
总是认为不会产生并发问题,每次去取数据的时候总认为不会有其他线程对数据进行修改,因此不会上锁,但是在更新时会判断其他线程在这之前有没有对数据进行修改,一般会使用版本号version机制或CAS操作实现。
Java transient关键字
java 的transient关键字为我们提供了便利,你只需要实现Serilizable接口,将不需要序列化的属性前添加关键字transient,序列化对象的时候,这个属性就不会序列化到指定的目的地中。序列化指的是通过实现Serializable接口后的自动序列化
一旦变量被transient修饰,变量将不再是对象持久化的一部分,该变量内容在序列化后无法获得访问。
transient关键字只能修饰变量,而不能修饰方法和类。注意,本地变量是不能被transient关键字修饰的。变量如果是用户自定义类变量,则该类需要实现Serializable接口。
被transient关键字修饰的变量不再能被序列化,一个静态变量不管是否被transient修饰,均不能被序列化
String的几种类型
String 字符串常量,不可变
StringBuffer 字符串变量(线程安全),可变
StringBuilder 字符串变量(非线程安全),可变
Integer是不可变类,进入一个方法后,在里面的值的改变不会影响方法外的引用
基本类型的变体引用类型和String都不能直接当纯引用类型来用,比如Integer,Double等都是int与double的引用类型,但是你不能像普通引用类型那样直接对他的值做改变,因为在他们里面封装的原始int与double都用了final进行声明。所以你就算重新赋值了原始的int与double都不会改变
RxJava异步框架
相当于观察者模式,异步线程去执行代码,可以使用该异步框架实现:
1、失败重试机制(当短时间内,比如发消息的方式,发生大量的数据库操作,可能导致数据库被锁而执行失败)
2、异步执行
3、观察者模式
1 | Observable.just(stateMachineId) |
Spring工具类
AntPathMatcher:路径匹配工具
ApplicationContextHelper:获取注入的对象
1 | ApplicationContextHelper.getSpringFactory().getBean(xx.class) |
Java泛型
泛型:即“参数化类型”。一提到参数,最熟悉的就是定义方法时有形参,然后调用此方法时传递实参。那么参数化类型怎么理解呢?顾名思义,就是将类型由原来的具体的类型参数化,类似于方法中的变量参数,此时类型也定义成参数形式(可以称之为类型形参),然后在使用/调用时传入具体的类型(类型实参)
在泛型接口、泛型类和泛型方法的定义过程中,我们常见的如T、E、K、V等形式的参数常用于表示泛型形参,由于接收来自外部使用时候传入的类型实参。泛型类型在逻辑上看以看成是多个不同的类型,实际上都是相同的基本类型(即class是同一个,泛型参数在编译期会被擦除)
- 上限与下限
1 | <? extends T>表示该通配符所代表的类型是T类型的子类 |
参考文献:Java总结篇系列:Java泛型
在方法上加final
该方法无法被重写或覆盖
好用的java类库
- guava:谷歌开源的java库,提供用于集合,缓存,支持原语,并发性,常见注解,字符串处理,I/O和验证的实用方法
代码规范
Spring中用构造注入方式替代@Autowired
Java序列化的三种方式
- 实现
Serializable
接口(隐式序列化):自动序列化非static和非transient的成员变量 - 实现
Externalizable
接口(显式序列化):Externalizable接口继承自Serializable, 我们在实现该接口时,必须实现writeExternal()和readExternal()方法 - 实现
Serializable
接口+添加writeObject()
和readObject()
方法。(显+隐序列化):添加writeObject()和readObject()方法,方法必须要被private修饰,第一行调用默认的defaultRead/WriteObject();
java文本转义
URLDecoder.decode(text,"UTF-8")
java执行命令行语句
1 | String [] cmd={"cmd","/C","copy exe1 exe2"}; |
git
1.想要查看最新的远程分支必须先pull新的master
2.查看远程仓库地址
git remote -v
3.git缓存区
- git stash save xxx 保存stash有名字
- git stash clear 清空缓存
- git stash list 缓存列表
- git stash apply stash@{0} 应用缓存
4.版本回退
1 | git log |
5.分支强行替换名字
1 | git branch -m master old-master |
在新master直接push时会提示当前分支的引用并非与服务器上的master相同,执行它提示的命令即可更换新的引用
6.rebase 变基
1 | git rebase |
若出现重复的提交记录,可以在推到仓库的自己分支增加–force强推,覆盖自己之前push的记录
git忽略提交
- 在项目根目录,创建.gitignore(该文件会传至仓库与大家共享),配置忽略的文件
需要让gitignore生效,需要git rm -r --cached . // 删除本地缓存
- 在项目下,.git/info/exclude文件中添加本地提交要忽略的文件,不与仓库共享
根据tag切分支
1 | git branch <new-branch-name> <tag-name> |
删除tag
1 | git tag -d [tag]; |
git初始化仓库
1 | git remote add origin git@github.com:chenshinan/111.git |
常用命令
1 | git branch -a #查看本地和远程所有的分支 |
sql
根据日期拉取报表
SELECT COUNT(*), DATE(CreateTime) FROM event_order WHERE YEAR(CreateTime) = '2016' GROUP BY DAY(CreateTime)
\
详细可见:http://blog.csdn.net/jiang_2992/article/details/73801366
拼接、截取、分组拼接
拼接:CONCAT('yykj',code)
\
截取:right(str,index)、substring(str,index)
\
分组拼接:select name,group_concat(id) from tab group by name
结果:小明 | 1,3,5
连接查询
- left join(左联接) 返回包括左表中的所有记录和右表中联结字段相等的记录
- right join(右联接) 返回包括右表中的所有记录和左表中联结字段相等的记录
- inner join(等值连接) 只返回两个表中联结字段相等的行
给用户添加数据库权限
grant all privileges on state_machine_service.* to 'choerodon'@'%';
删除表、清空表
存在则删除:drop table if exists 表名 \
删除表:delete from 表名 \
清空表:truncate table 表名
mysql workbench 的安全模式
SET SQL_SAFE_UPDATES = 0;
SQL最后一行求总和
1 | SELECT |
ALTER语句
添加列:
ALTER TABLE test ADD (c1 char(1),c2 char(1));
ALTER TABLE test ADD COLUMN (c1 char(1),c2 char(1));
ALTER TABLE test ADD c1 char(1),ADD c2 char(1);
修改列:
ALTER TABLE test CHANGE c1 c3 char(1),CHANGE c2 c4 char(1);
ALTER TABLE test CHANGE COLUMN c1 c3 char(1),CHANGE COLUMN c2 c4 char(1);
删除列:
ALTER TABLE test DROP c1,drop c2;
ALTER TABLE test DROP COLUMN c1,DROP COLUMN c2;
对于获取组织和组织的用户人数,推荐的优化方式是先通过groupby用户,再join组织表
select for update
概念:该语句用来锁定特定的行(如果有where子句,就是满足where条件的那些行)。当这些行被锁定后,其他会话可以选择这些行,但不能更改或删除这些行,直到该语句的事务被commit语句或rollback语句结束为止
,防止select之后,update之前,数据已经发送改变导致再update出现错误数据
在select…for update之后,可以使用of子句选择对select的特定数据表进行加锁操作。默认情况下,不使用of子句表示在select所有的数据表中加锁。
更新判断语句
1 | update agile_issue |
insert into select(查询到的数据插入)
1 | Insert into Table2(field1,field2,...) select value1,value2,... from Table1 |
insert ignore into(存在则忽略)
order by case 的用法
当进行order by
排序时,需要安装特定的顺序排序,则有case ... when ... then ... end
的用法
1 | select id,name from priority |
update + select
1 | update kb_page_content,kb_page |
1 | update kb_page_content pc set pc.title= ( |
mysql用命令运行大sql文件
1 | 进入mysql |
sql正则表达式
context可以选多值,用“,”分隔,sql可以用REGEXP匹配,注意使用的是${xx}
1 | select * from field |
数据库连接池大小的设置
连接数 = ((核心数 * 2) + 有效磁盘数)
如果说你的服务器CPU是4核i7的,连接池大小应该为((4*2)+1)=9,即使有 10000 个并发访问,同样只需要10个线程这样数据库的吞吐量最高。参考文献
mybatis
循环数组判断为空
1 | <if test="userIds != null and userIds.size()>0"> |
if other
1 | <choose> |
resultMap的用法
association:一对一/多对一
collection:一对多/多对多
1 | <resultMap id="boardDependInfo" type="io.choerodon.agile.api.dto.BoardDependInfoDTO"> |
mybatis的缓存
一级缓存:是SQlSession
级别的缓存。在操作数据库时需要构造 SqlSession 对象,在对象中有一个数据结构(HashMap)用于存储缓存数据。不同的 SqlSession 之间的缓存数据区域(HashMap)是互相不影响的
二级缓存:是mapper
级别的缓存,多个 SqlSession 去操作同一个mapper的sql语句,多个 SqlSession 可以共用二级缓存,二级缓存是跨 SqlSession 的,当某一个作用域(一级缓存Session/二级缓存Namespaces)的进行了 C/U/D 操作后,默认该作用域下所有 select 中的缓存将被clear
工作机制:
一个会话, 查询一条数据, 这个数据就会被保存在当前会话的一次缓存(SqlSession)中
如果关闭会话, 那么一次缓存中的数据就会被保存到二级缓存(namespace)中,新的会话查询的内容, 就可以参照二级缓存
一个 xxxMapper 对应一个 namespace, 不同的 namespace 查出的数据会保存在自己对应的二级缓存中
查出的数据会先被保存在一级缓存中, 只有会话关闭或者提交之后, 以及缓存中的数据才会被转移到二级缓存
Mybatis中$与#的区别
#是将传入的值当做字符串的形式,$是将传入的数据直接显示生成sql语句
docker
删除未启动的容器:docker rm $(docker ps -a -q)
运行docker-compose:$ docker-compose up -d(在docker-compose.yml所在目录,-d是指后台运行)
复制容器中的文件到宿主机
1 | docker cp 71e53ddad89f:/usr/local/tomcat/bin/catalina.sh tomcat-conf/ |
查看容器中运行的进程信息
1 | docker top mymysql |
maven
查看依赖树
1 | mvn dependency:tree >> /tree.txt; |
包依赖分析插件:Maven Helper
在IDEA中安装插件:Maven Helper
,安装后即可在pom.xml中查看包依赖
dockerfile
安装vim
1 | RUN apt-get update && apt-get install vim -y |
mysqldump的使用
- 备份命令:mysqldump -h主机名 -P端口 -u用户名 -p密码 –database 数据库名 > 文件名.sql
- 备份压缩:mysqldump -h主机名 -P端口 -u用户名 -p密码 –database 数据库名 | gzip > 文件名.sql.gz
- 同时备份多个库:mysqldump -h主机名 -P端口 -u用户名 -p密码 –databases 数据库名1 数据库名2 数据库名3 > 文件名.sql
- 备份实例上所有的数据库:mysqldump -h主机名 -P端口 -u用户名 -p密码 –all-databases > 文件名.sql
- 备份数据库结构,不备份数据:mysqldump -h主机名 -P端口 -u用户名 -p密码 –no-data 数据库名1 数据库名2 数据库名3 > 文件名.sql
Linux
1 | lsof -i tcp:6479 查看端口号对应的进程 |
其他
IDEA快捷键
- Alt+ left/right 切换代码视图
- Alt+ Up/Down 在方法间快速移动定位
- Ctrl+Shift+Up/Down 整行代码向上/下移动。
- Ctrl+D 复制行
- Ctrl+X 删除行
- 快速展示类的元素: Ctrl + F12
- 实现接口或抽象类的方法: Ctrl + I
- 向类中插入getter, setter方法: Alt + Insert
- 打开接口的实现类: Ctrl + H
- 导包: alt+enter
工具
热部署工具:JRebel、Spring Loaded、spring-boot-devtools
代码构建工具:maven、apache ant
Arthas 是Alibaba开源的Java诊断工具:
1 | trace -j io.choerodon.issue.api.service.impl.ProjectConfigServiceImpl queryTransformsByProjectId |
excel导入
导入内容包含回车换行问题
10:Line Feed (馈行)、11:Vertical Tab (垂直制表)、12:Form Feed (馈页)、13:Carriage Return (回车),此处换行字符需要
1 | for(int i=10;i<14;i++){ |
获取时间为数值问题
方法1:获取后处理
1 | Calendar c = new GregorianCalendar(1900,0,-1); |
方法2:获取时处理
1 | case NUMERIC: |
获取百分比
1 | cell.setCellType(Cell.CELL_TYPE_NUMERIC); |
导出excel
文本换行
1 | 1.设置自动换行样式 |
Spring security
Spring Security是基于spring的应用程序提供声明式安全保护的安全性框架,它提供了完整的安全性解决方案,能够在web请求级别和方法调用级别
处理身份证验证和授权.它充分使用了依赖注入和面向切面的技术.
Spring security主要是从两个方面解决安全性问题:
web请求级别:使用servlet过滤器保护web请求并限制URL级别的访问
方法调用级别:使用Spring AOP保护方法调用,确保具有适当权限的用户采用访问安全保护的方法.
在Spring Security中,认证过程称之为Authentication(验证),指的是建立系统使用者信息( principal )的过程。使用者可以是一个用户、设备、或者其他可以在我们的应用中执行某种操作的其他系统。
Authorization(授权)指的是判断某个 principal 在我们的应用是否允许执行某个操作。在 进行授权判断之前,要求其所要使用到的规则必须在验证过程中已经建立好了。
最基础的对象是 SecurityContextHolder,这是我们在应用中存储当前安全细节的地方,包含了当前在应用中使用到的principal细节。
默认情况下, SecurityContextHolder 使用一个 ThreadLocal 对象来存储这些细节
,这表示对于在同一个线程中执行的方法,安全上下文(security context)都是可用的,即使安全上下文没有显式的当做方法的参数进行传递。
通过这种方式使用 ThreadLocal 是很安全的,如果当前使用到的规则需要在请求处理完之后被清空。
当然,Spring Security帮你自动的处理了这些,你不需要考虑。
Spock集成单元测试
重名校验记得取的id即为当前名字的id
调用controller方法失败(格式错误等),entity为空,actRequest为false
调用成功,执行controller方法时抛出异常,未处理的异常,entity返回值非200,actRequest为false
调用成功,执行controller方法时抛出异常,被捕获,entity返回值为200,actRequest为true
在path和param中的参数均有null校验,若传null,调用成功,被spring抛出异常,被捕获,entity返回值为200,actRequest为true
spring基础
bean的作用域
- singleton:只有一个实例,也即是单例模式
- prototype:访问一次创建一个实例,相当于new
bootstrap.yml与application.yml
bootstrap.yml先加载application.yml后加载,bootstrap.yml用于应用程序上下文的引导阶段
一旦bootStrap.yml 被加载,则内容不会被覆盖,即便后期加载的application.yml的内容标签与bootstrap的标签一致,application 也不会覆盖bootstrap,而application.yml 里面的内容可以动态替换。