本篇文章将持续更新,汇总一些在实际开发中遇到的一些问题,希望能给有缘人一点帮助
List排序
利用java8出来stream和lambda公式处理集合。
场景一:需要根据List中Map的某个key-value值进行排序。
//这里有一个list
方式一:
List<Map<String,Object>> list;
//假如Map中有个字段orderNum是排序号,也就是我们需要根据这个orderNum值进行排序
//操作如下:
//先定义一个orderNum排序的
private static String comparingByOrderNum(Map<String,Object>){
return map.get("orderNum") == null ? "" : map.get("orderNum").toString();
}
//排序,默认是升序排序
list = list.stream().sorted(Comparator.comparing(comparingByOrderNum所在的类名::comparingByOrderNum)).collect(Collectors.toList());
//倒序
list = list.stream().sorted(Comparator.comparing(comparingByOrderNum所在的类名::comparingByOrderNum).reversed()).collect(Collectors.toList());
方式二:利用lambda
list.sort((o1,o2) -> {
Integer orderNumOne = (Integer)o1.get("orderNum");
Integer orderNumTwo = (Integer)o2.get("orderNum");
//倒序就交换orderNumOne和orderNumTwo的比较位置
return orderNumOne.compareTo(orderNumTwo);
});
场景二:需要根据实体中某个属性值进行排序。
//关于某个List<实体>的排序,建议直接将默认的排序方式写在获取list时的sql语句中,尽量不要在应用层排序,除非要修改排序方式。
//还是用stream方式排序,默认升序排序
list = list.stream().sorted(Comparator.comparing(实体的类名::getOrderNum)).collect(Collectors.toList());
构建通用的树形结构
开发一些后端管理系统中经常会用到分类树形结构,或者分类下面加了该分类下的具体选项,比如空文件的文件夹的层级显示,以及另一种有文件情况下,每个文件在对应的文件夹中层级显示。下面两个场景可根据自己的需求结合成一个构建树型结构的帮助类。我这里只提供思路,因为很可能我写的方法不完全适合你,但是构建树的核心思想基本一致。况且明白了构建树型结构的核心思路,自己写一遍也会更加理解业务需求
通常,如何判断哪个分类是另一个分类的子分类,都会在数据库定一个两个字段用来表示,这里我就用code,parentCode作为区分。
场景三:只需要构建分类树型结果
//构建树的方式一般有两种,一是从最底层孩子结点往上遍历到根结点,二是从根结点往下遍历到最底层孩子结点,这看你需求,但两者原理一致可以互相转换。
//本文从根结点往下遍历到最底层孩子结点。
//思路如下:
//1.先获取需要进行构建树形结构的数据集(调用方法前)
List<实体类> tests= 获取该数据集的方法();
//2.再定义testLists用来接收将tests转换成List<Map<String, Object>>类型(调用方法前)
List<Map<String, Object>> testLists= Lists.newArrayList();
//3.转换方式如下,利用java8和fastjson的fluentPut方式:(调用方法前)
//本来tests中还有其他的字段属性,这里由于前端子需要这个几个,我就只取这几个字段,其他的看需求添加
tests.forEach(e -> testLists.add(new JSONObject()
.fluentPut("id", e.getId())
.fluentPut("name", e.getCatName())
.fluentPut("code", e.getCode())
.fluentPut("desc", e.getDesc())
.fluentPut("parentCode", e.getParentCode())
.fluentPut("orderNum", e.getOrderNum())));
//4.转换成List<Map<String, Object>>就可以开始调用构建树的方法,由于这里只需要构建树形结构,则调用我自己写的buildOnlyTreeFromParentToChild
List<Map<String, Object>> resultList = buildTreeFromParentToChild(treeList,rootTag,selfTag,parentTag,additionalMap,addTag);
/*
* @param treeList 传入需要构建的实体list
* @param selfTag 树状关系表中表示当前层级的标签,例如id,code等
* @param parentTag 树状关系表中表示父母的标签,例如parent_id,parent_code等
* @param attrParams 定义要放在atributes中的参数
* @param removeParams 定义要移除显示的参数
* @return 返回完整的菜单树
* @throws DataAccessException
*/
private static List<Map<String, Object>> buildOnlyTreeFromChildToParent(List<Map<String, Object>> treeList,String rootTag,String selfTag,String parentTag,List<String> attrParams,List<String> removeParams) throws DataAccessException {
//定义好接受树形结构的类型,我这定义为List<Map<String,Object>>
List<Map<String, Object>> rootList = new ArrayList<>();
for (Map<String, Object> temp : treeList) {
//根节点的parentTag,是否和当前的parentTag,默认为root值标志为根节点。并存入当前层级的rootList
if (rootTag.equals(String.valueOf(temp.get(parentTag)))) {
rootList.add(temp);
}
}
//根据orderNum排序
rootList = rootList.stream().sorted(Comparator.comparing(BuildTreeUtil::comparingByOrderNum)).collect(Collectors.toList());
//递归调用自己,获取孩子之后,调用formateJson方法格式化节点信息
for (Map<String, Object> temp : rootList) {
List<Map<String, Object>> childs = buildOnlyTreeFromChildToParent(temp, treeList,selfTag,parentTag,attrParams,removeParams);
formateJson(childs,temp,attrParams,removeParams);
}
return rootList;
}
/*
* @param childs 传入childs列表,需要将childs放入当前结点key为childs的属性中
* @param temp 当前的节点信息
* @param attrParams 定义要放入temp节点key为atributes中的参数
* @param removeParams 定义要移除一些没必要显示的参数
* @throws DataAccessException
*/
private static void formateJson(List<Map<String, Object>> childs,Map<String, Object> temp,List<String> attrParams,List<String> removeParams){
//判断是否有孩子,从而判断是否是叶子节点,前端可根据这个判断是否到底
if(childs.size() > 0){
temp.put("isLeaf" ,0);
}else{
temp.put("isLeaf" ,1);
}
//新增的uuid,避免显示数据库id
String uuid = new RandomGUID().toString();
temp.put("uuid",uuid);
//将孩子的列表放入这个key
temp.put("childs", childs);
//循环attrParams,添加到当前的attributes中
Map<String, Object> attributes = Maps.newHashMap();
if(attrParams.size() > 0){
for(String param : attrParams){
attributes.put(param,temp.get(param));
}
}
temp.put("attributes", attributes);
//清除前端不需要用的key-value
for(String param : removeParams){
temp.remove(param);
}
}
场景四:不仅要构建分类树,还要将该分类下的数据放在对应的分类下面。比如我们按正常的文件夹目录存在文件夹和文件一样。
//树形结构中增加文件其实很简单,就是在分类每次添加到上一个分类的孩子中之前,先获取所属于上一个分类下的文件即可,一般文件属于哪个文件夹,都会有个标记字段,比如catId。但是得注意,由于分类和文件不一样的性质,所以需要跟场景三不同的处理方式
//这样就将上面的buildOnlyTreeFromChildToParent修改一下即可
//思路如下:
//1.先获取需要进行构建树形结构的数据集,一个是对应的分类数据集,另一个是文件数据集(调用方法前)
List<实体类> testCats= 获取该数据集的方法();
List<实体类> testFiles= 获取该数据集的方法();
//2.再定义testLists用来接收将tests转换成List<Map<String, Object>>类型(调用方法前)
List<Map<String, Object>> testCatLists= Lists.newArrayList();
List<Map<String, Object>> testFileLists= Lists.newArrayList();
//3.转换方式跟前面一样,利用java8和fastjson的fluentPut方式:(调用方法前)
//fileList中包含标记属于哪个cat的catId,但是如果catID为空,则表示他跟最顶层文件夹放在一起
testCatLists.forEach(e -> testLists.add(new JSONObject()
.fluentPut("id", e.getId())
.fluentPut("name", e.getCatName())
.fluentPut("code", e.getCode())
.fluentPut("desc", e.getDesc())
.fluentPut("parentCode", e.getParentCode())
.fluentPut("orderNum", e.getOrderNum())));
testFileLists.forEach(e -> testLists.add(new JSONObject()
.fluentPut("id", e.getId())
.fluentPut("name", e.getCatName())
.fluentPut("catId", e.getCatId())
.fluentPut("desc", e.getDesc())
.fluentPut("orderNum", e.getOrderNum())));
//4.转换完成后调用buildTreeFromParentToChild
List<Map<String, Object>> resultLis = buildTreeFromParentToChild(testCatLists, "root", "code", "parentCode", testFileLists);
/*
* @param treeList 传入需要构建的实体分类catlist
* @param selfTag 树状关系表中表示当前层级的标签,例如id,code等
* @param parentTag 树状关系表中表示父母的标签,例如parent_id,parent_code等
* @param filesList 要跟分类绑定的文件列表
* @return 返回完整的菜单树
* @throws DataAccessException
*/
private static List<Map<String, Object>> buildTreeByChildCode(Map<String, Object> tempTree, List<Map<String, Object>> treeList,List<Map<String, Object>> filesList ) throws DataAccessException {
// 子菜单
List<Map<String, Object>> tree = new ArrayList<>();
for (Map<String, Object> temp : treeList) {
// 遍历所有节点,判断父子关系
if (String.valueOf(temp.get("parentCode")).equals(String.valueOf(tempTree.get("code")))) {
tempTree.put("isLeaf",0);
tree.add(temp);
}
}
//根据排序号orderNum排序
tree = tree.stream().sorted(Comparator.comparing(BuildTreeUtil::comparingByOrderNum)).collect(Collectors.toList());
filesList = metaTabMapfilesList .stream().sorted(Comparator.comparing(BuildTreeUtil::comparingByOrderNum)).collect(Collectors.toList());
//添加根节点资源表
for(Map<String, Object> fileTemp : filesList ){
//如果该资源的bizid为空,即无所属分类,放在根节点,否则就判断是当前分类下是否具有文件
if ( fileTemp .get("catId") == null ){
//这里对file进行格式化处理
rootList.add( initFileJson(fileTemp ));
}else{
if(fileTemp .get("catId").equals(fileTemp.get("id"))) {
rootList.add( initFileJson(fileTemp ));
}
}
}
//添加当前分类的孩子
for (Map<String, Object> temp : rootList) {
if( temp.get("code") != null) {
List<Map<String, Object>> childs = buildTreeByChildCode(temp, treeList, filesList );
//格式化分类
formateJson(childs,temp);
}
}
return tree;
}
集合工具类的使用
建议加入google.common.collect依赖,基本上组装了所有的集合类的所有操作方法。
场景五:利用google.common.collect对各类集合的初始化
List<> list = Lists.newArrayList();
List<> list = Lists.newLinkedList();
Map<> map = Lists.newHashMap();
Map<> map = Lists.newLinkedHashMap();
...
//这里面有太多的方法可以使用,功能强大。
//创建一个集合类的空集合
//可以用java.util中的Collections
Collections.emptyList;
Collections.emptyMap;
....
开发中的性能问题建议
- 应用层处理数据确实快,但也不能一次性获取太多的数据处理
尽量不要一次性把数据取出来再在应用层过滤,很可能你一次性取出来的数据过大,导致响应速度过慢,甚至超过了内存限制,造成了堆栈溢出。
建议:应用层每次取出来的数据尽量是一次处理的结果,另一次就重新再取一次,再结合在数据库的sql语句中增加过滤条件。 - for循环中尽量不要出现访问数据库的操作
for循环中尽量不要用getList(这是从数据库中获取一批数据的方法),这样也会造成性能问题。
建议:这种情况很常见,数据量少是没有什么性能问题的,但是数据量一大,对数据库的压力很大。这个时候可以利用数据库的批量处理的sql语句来解决问题。具体情况综合考虑,不是非必要优化。 - 如何避免两个for循环获取List中指定数据处理的情况
这里我贴上另一篇文章的连接,比较详细。
开发中的可能遇到的一些小操作,但是不经常用又容易忘掉。
为了避免总是去百度和搜索,记录下自己在开发中遇到的一些不常用的小技巧,但是有可能用到的小操作。
// 获取指定date日志的年、月、日、时、分、秒
//如果要获取常用的日期组合,例如年-月-日、日-月-年等建议用DateFormat
//举个例子,我只想获取date的时分秒
DateFormat dateFormat = DateFormat.getTimeInstance();
String format = dateFormat.format(date);
//只想获取年月日
DateFormat dateFormat = DateFormat.getDateInstance();
String format = dateFormat.format(date);
//获取完整的年月日时分秒
DateFormat dateFormat = DateFormat.getDateTimeInstance();
String format = dateFormat.format(date);
//但是如果你只想获取date中的某个数值,比如date的年份、月份、日等单个数据,建议用Calendar
Calendar cal = Calendar.getInstance();
cal.setTime(date);
int year = cal.get(Calendar.YEAR);//获取年份
int month=cal.get(Calendar.MONTH);//获取月份
int day=cal.get(Calendar.DATE);//获取日
int hour=cal.get(Calendar.HOUR);//小时
int minute=cal.get(Calendar.MINUTE);//分
int second=cal.get(Calendar.SECOND);//秒
int WeekOfYear = cal.get(Calendar.DAY_OF_WEEK);//一周的第几天
数据库知识
1.更新已有数据的表的字段属性
oracle是不允许直接更改的,需要进行如下操作
//先对表数据进行备份表
create table test_bak as select * from test;
//再删除原来的表数据
delete from test;
//修改表结构
alter table test modify field varchar2(100);
//将备份表数据重插回原表中
insert into test select * from test_bak;
//最后删除备份表。
drop table test;
//提交事务
commit;