1.提交事务再执行其他方法。
使用场景:有时候事务比较大,当前事务允许先提交的情况下再执行后续动作,那么就可以使用此方式进行处理
@Transactional
public void add() {
//插入数据逻辑
TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronizationAdapter() {
@Override
public void afterCommit() {
//发送消息
}
});
}
2.stream使用
Map<Long, List<Brand>> collect = brandService.listByIds(brandIdList).stream().collect(Collectors.groupingBy(Brand::getId));
#将list的实体的某字段用英文逗号拼接
String systemChineseName = systemList.stream().map(SystemListVO::getfChineseName).collect(Collectors.joining(","));
list转map
写法1:
Map<Long, Supplier> supplierMap = supplierService.listByIds(new ArrayList<>(supplierIdSet)).stream().collect(Collectors.toMap(Supplier::getId, a -> a, (k1, k2) -> k1));
写法2:
Map<String, Product> productMap = productList.stream().collect(Collectors.toMap(Product::getSku, v -> v));
Map<String, MultiDimensionalAvailableInventoryResponse> collect = inventoryResponses.stream().collect(Collectors.toMap(x -> x.getSku() + "_" + x.getWhId(), v -> v));
取出某个字段作为list
//1.提取出list对象中的一个属性
List<String> stIdList1 = stuList.stream().map(Student::getId).collect(Collectors.toList());
//2.提取出list对象中的一个属性+判空
HashSet<String> costCenterCodes = lines.stream().map(SieBoeLineYueXiu::getCostCenterCode).filter(StrUtil::isNotBlank).collect(Collectors.toCollection(HashSet::new));
Map<String, String> costCentorMap = centerCodes.stream().collect(Collectors.toMap(CostCenter::getCostCenterCode,CostCenter::getCostCenterName));
分组
Map<String, List<PurchaseDetailVO>> purchaseMaps = purchaseAndDetailByNo.getData().stream().collect(Collectors.groupingBy(p -> p.getSku() + StrUtil.DASHED + p.getSkuType()));
Map<String, Product> productMap = RemoteObjectMapper.getProductRst(remoteProductService, details.stream().map(InboundDetail::getSku).collect(Collectors.toSet()).stream().collect(Collectors.toList()));
List<SupplierContacts>supplierContacts = ConvertUtils.convertList(processProductListTemp, OutSourceProcessAndDetailResponse.ProcessProduct.class);
求和:
list.stream().map(Tea::getSalory).filter(ObjectUtil::isNotNull).reduce(BigDecimal.ZERO, BigDecimal::add);
汇总数量返回
Map<String, IntSummaryStatistics> skuQtyMap = outboundQtyVOS.stream().collect(Collectors.groupingBy(ProcessOutboundQtyVO::getSku,
Collectors.summarizingInt(ProcessOutboundQtyVO::getOutboundQty)));
设置显示百分比
NumberFormat format = NumberFormat.getPercentInstance();
format.setMaximumFractionDigits(2);
// 设置百分比字符串
detailVO.setDiscountRateStr(format.format(detailVOItem.getDiscountRate()));
比较:(按照部门ID倒序,StoryAnalysisListVO::getDepartmentId为null时,报NPE异常)
voList=voList.stream().sorted(Comparator.comparing(StoryAnalysisListVO::getDepartmentId).reversed()).collect(Collectors.toList());
2.1 注意事项
2.1.1 Collectors.toMap的value如果为null,会报异常,使用时需要注意
2.2 list按实体某个字段去重
import java.util.*;
import java.util.stream.*;
public class Main {
public static void main(String[] args) {
List<Employee> employees = Arrays.asList(
new Employee("001"),
new Employee("002"),
new Employee("001"),
new Employee("003"),
new Employee("002")
);
// 使用Stream API去除employeeNumber重复的实体
List<Employee> uniqueEmployees = employees.stream()
.collect(Collectors.groupingBy(Employee::getEmployeeNumber,
Collectors.collectingAndThen(Collectors.toList(),
list -> list.stream().findFirst().orElse(null))))
.values()
.stream()
.filter(Objects::nonNull)
.collect(Collectors.toList());
System.out.println("Unique Employees: " + uniqueEmployees);
}
static class Employee {
private String employeeNumber;
public Employee(String employeeNumber) {
this.employeeNumber = employeeNumber;
}
public String getEmployeeNumber() {
return employeeNumber;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Employee employee = (Employee) o;
return Objects.equals(employeeNumber, employee.employeeNumber);
}
@Override
public int hashCode() {
return Objects.hash(employeeNumber);
}
@Override
public String toString() {
return "Employee{" +
"employeeNumber='" + employeeNumber + '\'' +
'}';
}
}
}
2.3 list按某个字段统计出现次数
Map<String, Long> duplicateMap = list.stream().collect(Collectors.groupingBy(FbpEmployee::getEmployeeNumber, Collectors.counting())).entrySet().
stream().filter(e -> e.getValue() > 1).collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
if (duplicateMap != null && duplicateMap.size() > 0) {
log.error("UIC员工信息同步,有重复数据,请检查UIC数据,重复数据有:{}条,入参:{}", duplicateMap.size(), JSONUtil.toJsonStr(duplicateMap));
return;
}
3.java工具类Collections使用
3.1 比较
正序:
Collections.sort(userDTOS, Comparator.comparing(UserDTO::getAge));
倒叙:
Collections.sort(userDTOS, Comparator.comparing(UserDTO::getAge).reversed());
需要注意的是,如果UserDTO::getAge结果为null,会抛空指针异常。所以比较的时候看实际情况,null给默认值或者过滤出非null的进行比较。
4.树结构组装
树结构实体
//树结构类demo
@Data
@ApiModel(value = "DeptInfo对象", description = "部门信息表")
public class DeptInfoVo {
/**
* 主键id
*/
private Long id;
@ApiModelProperty("部门名称")
private String deptName;
@ApiModelProperty("部门ID")
private String deptId;
@ApiModelProperty("父级部门ID")
private String parentId;
@ApiModelProperty("子节点")
private List<DeptInfoVo> children = new ArrayList<>();
}
4.1 不指定父节点构建树结构-返回list结构
/**
* 构建树结构(找不到父id则放在根节点)
* @param nodeList
* @return
*/
private List<DeptInfoVo> buildTree(List<DeptInfoVo> nodeList) {
// 创建一个Map来存储每个节点,键为部门ID,值为节点对象
Map<String, DeptInfoVo> nodeMap = new HashMap<>();
for (DeptInfoVo node : nodeList) {
nodeMap.put(node.getDeptId(), node);
}
// 初始化一个根节点集合
List<DeptInfoVo> roots = new ArrayList<>();
// 遍历节点列表,构建树结构
for (DeptInfoVo node : nodeList) {
String parentId = node.getParentId();
if(ObjectUtil.isNull(nodeMap.get(parentId))){
// 如果当前节点的pId不存在,则把它当做根节点
roots.add(node);
}else {
DeptInfoVo parentNode = nodeMap.get(parentId);
if (parentNode != null) {
// 若父节点存在,则将当前节点添加到其子节点列表中
parentNode.getChildren().add(node);
}
}
}
return roots;
}
4.2 指定父节点(返回指定父节点)
/**
* 组装树结构
*
* @param dtoList 所有数据
* @param pid 父主键
* @return 树形结构
*/
private DeptInfoVo buildTree(List<DeptInfoVo> dtoList, String pid) {
//先选出非顶级的节点
List<DeptInfoVo> list = dtoList.parallelStream().filter(item -> (!StrUtil.equals(item.getParentId(),pid))).collect(Collectors.toList());
//将这些非顶级节点的数据按pid进行分组
Map<String, List<DeptInfoVo>> sub = list.parallelStream().collect(Collectors.groupingBy(DeptInfoVo::getParentId));
//循环设置对应的子节点(根据id = pid)
dtoList.parallelStream().forEach(node -> node.setChildren(sub.get(node.getDeptId())));
//过滤掉父节点数据
DeptInfoVo deptInfoVo = dtoList.parallelStream().filter(node -> StrUtil.equals(node.getParentId(), pid))
.collect(Collectors.toList()).stream().findFirst().orElse(new DeptInfoVo());
return deptInfoVo;
}
5.easyExcel校验表头
5.1 前提准备
(1)使用@ExcelProperty注解配置模板表头字段
(2)创建监听类并继承AnalysisEventListener类,重写invokeHeadMap方法,在该方法中判断是否符合模板
import com.alibaba.excel.annotation.ExcelIgnore;
import com.alibaba.excel.annotation.ExcelProperty;
import com.alibaba.excel.annotation.write.style.ColumnWidth;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.math.BigDecimal;
/**
* KPI导入
*
*
*/
@Data
@ColumnWidth(20)
public class OrgKpiImportVo {
@ApiModelProperty("年度*")
@ExcelProperty(index = 0, value = {"年度*"})
private Integer yearly;
@ApiModelProperty("ID")
@ExcelIgnore
private Long id;
@ApiModelProperty("上级ID")
@ExcelIgnore
private Long pId;
@ApiModelProperty("上级编号")
@ExcelProperty(index = 1, value = {"上级编号"})
private String pCode;
@ApiModelProperty("上级考核指标")
@ExcelProperty(index = 2, value = {"上级考核指标"})
private String pName;
@ApiModelProperty("编号*")
@ExcelProperty(index = 3, value = {"编号*"})
private String code;
@ApiModelProperty("考核指标*")
@ExcelProperty(index = 4, value = {"考核指标*"})
private String name;
@ApiModelProperty("集团战略权重")
@ExcelProperty(index = 5, value = {"集团战略权重%"})
private BigDecimal groupWeight;
@ApiModelProperty("DC权重")
@ExcelProperty(index = 6, value = {"DC权重%"})
private BigDecimal weight;
@ApiModelProperty("部门权重*")
@ExcelProperty(index = 7, value = {"部门权重% *"})
private BigDecimal deptWeight;
@ApiModelProperty("指标定义*")
@ExcelProperty(index = 8, value = {"指标定义*"})
private String definition;
@ApiModelProperty("部门ID*")
@ExcelProperty(index = 9, value = {"部门ID*"})
private String deptCode;
@ApiModelProperty("部门名称")
@ExcelProperty(index = 10, value = {"部门名称"})
private String deptName;
@ApiModelProperty("负责人工号*")
@ExcelProperty(index = 11, value = {"负责人工号*"})
private String chargePerson;
@ApiModelProperty("负责人")
@ExcelProperty(index = 12, value = {"负责人"})
private String chargePersonName;
@ApiModelProperty("代理人工号")
@ExcelProperty(index = 13, value = {"代理人工号"})
private String followBy;
@ApiModelProperty("代理人")
@ExcelProperty(index = 14, value = {"代理人"})
private String followByName;
@ApiModelProperty("认定/审定/数据来源部门")
@ExcelProperty(index = 15, value = {"认定/审定/数据来源部门"})
private String sources;
@ApiModelProperty("计量单位*")
@ExcelProperty(index = 16, value = {"计量单位*"})
private String unit;
@ApiModelProperty("评分制度*")
@ExcelProperty(index = 17, value = {"评分制度*"})
private String scoreSystem;
@ApiModelProperty("保底值*")
@ExcelProperty(index = 18, value = {"保底值*"})
private BigDecimal minimumValue;
@ApiModelProperty("目标值*")
@ExcelProperty(index = 19, value = {"目标值*"})
private BigDecimal targetValue;
@ApiModelProperty("挑战值*")
@ExcelProperty(index = 20, value = {"挑战值*"})
private BigDecimal challengeValue;
@ApiModelProperty("指标性质*")
@ExcelProperty(index = 21, value = {"指标性质*"})
private String indicatorPropertyName;
@ApiModelProperty("指标性质")
@ExcelIgnore
private String indicatorProperty;
@ApiModelProperty("创建人姓名")
@ExcelIgnore
private String createByName;
@ApiModelProperty("创建人")
@ExcelIgnore
protected String createBy;
}
5.2 表头校验判断
/**
* 在这里进行模板的判断
* @param headMap 存放着导入表格的表头,键是索引,值是名称
* @param context
*/
@Override
public void invokeHeadMap(Map<Integer, String> headMap, AnalysisContext context) {
/*
count 记录模板表头有几个,用以判断用户导入的表格是否和模板完全一致
如果用户导入表格较模板的表头多,但其余符合模板,这样不影响则不需要
*/
int count = 0;
// 获取数据实体的字段列表
Field[] fields = OrgKpiImportVo.class.getDeclaredFields();
// 遍历字段进行判断
for (Field field : fields) {
// 获取当前字段上的ExcelProperty注解信息
ExcelProperty fieldAnnotation = field.getAnnotation(ExcelProperty.class);
// 判断当前字段上是否存在ExcelProperty注解
if (fieldAnnotation != null) {
++count;
// 存在ExcelProperty注解则根据注解的index索引到表头中获取对应的表头名
String headName = headMap.get(fieldAnnotation.index());
// 判断表头是否为空或是否和当前字段设置的表头名不相同
if (StringUtils.isEmpty(headName) || !headName.equals(fieldAnnotation.value()[0])) {
// 如果为空或不相同,则抛出异常不再往下执行
throw new RuntimeException("模板错误,请检查导入模板");
}
}
}
// 判断用户导入表格的标题头是否完全符合模板
if (count != headMap.size()) {
throw new RuntimeException("请使用正确的导入模板!");
}
}
6. excel列索引取对应字母
// 自定义方法将列索引转换为列字母表示
public static String convertToColumnLetter(int columnIndex) {
StringBuilder columnLetter = new StringBuilder();
while (columnIndex > 0) {
int remainder = (columnIndex - 1) % 26;
columnLetter.append((char) ('A' + remainder));
columnIndex = (columnIndex - 1) / 26;
}
return columnLetter.reverse().toString();
}
7. 控制台日志打印
例如mybatis-plus、tkMybatis或者mongodb的日志打印,配置
#mybatis-plus日志打印
mybatis-plus.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl
#这是关键,打印查询语句就靠这个配置
logging.level.org.springframework.data.mongodb.core=DEBUG
#tkMybatis
#打印sql,logging.level后面是dao的包路径
logging.level.com.xxx.mapper.xx=debug
8.Mybatis使用
8.1 mybatis中的if标签的等号使用
mybatis映射文件,是使用的ognl表达式,所以在判断字符串变量是否相等时,有两种方式。
方式1:
<if test="sex=='Y'.toString()">
方式2:
<if test = 'sex== "Y"'>
不能使用:
<if test="sex=='Y'">
and 1=1
</if>
因为mybatis会把'Y'解析为字符char类型,而不是String类型,不能做到判断的效果,java是强类型语言,所以不能这样写。