定时任务的使用过程,以及使用分布式定时任务的意义(方便细粒度管理和调度)
https://www.jianshu.com/p/672dc60f1293
@Value注解使用下面方式注入如果配置文件中存在以配置文件中为主,配置文件中不存在则赋值默认值xxx(@Value注解不能为静态的属性赋值)
@Value("${server.web.domain:xxx}") private String domain;
1.对于mysql中的group by分组语句,涉及到合并时,默认会以数据库中id最小的数据为主(不求和就会丢弃id大的数据,如果需要根据key进行分组,value是key相同的实体的集合,可以使用stream流中的分组方法)
2.List集合中使用remove方法移除元素时,需要注意索引左移问题导致的异常(https://zhuanlan.zhihu.com/p/413921093)
3.List集合的时间复杂度要高于Set集合,使用集合中的contains方法时,优先使用Set集合(效率很高)
4.清空数据库的自增id命令 truncate 表名(会清空数据)
5.mapper起别名映射不上可以使用resultmap手动映射(待定)
6.mapper中当传入的值为integer类型的0时,会默认识别为空串(mybatis的锅)
7.使用@NotBlank(message = "不能为空!"),抛出这个异常:
HV000030: No validator could be found for constraint 'javax.validation.constraints.NotBlank' validating type 'java.lang.String'. Check configuration for
检查一下当前引入的包是不是引错了,引用javax.validation.constraints.NotBlank这个包肯定会报错,要换成org.hibernate.validator.constraints.NotBlank
8.Arrays.asList方法中的注意事项:
这个方法只适用于一些简单的场合,比如快速声明一个集合,判断某个值是否存在等等。但是如果声明后调用集合的add,clear,remove方法等,就会报java.lang.UnsupportedOperationException的异常
9.CollectionUtils工具类的使用(求集合的交集,补集,并集)
CollectionUtils工具类的常用方法_brandomCC的博客-CSDN博客_collectionutils
10.mysql使用嵌套子查询去删除数据时会报错,原因: mysql不允许对同一张表查询之后再来更新删除,而对不同的表可以执行先子查询再进行更新删除
解决方案如下:mysql 的删除修改嵌套查询问题 - 代码先锋网
11.rabbmitmq发送消息失败的补偿机制详解:
rabbitmq消息ACK确认机制及发送失败处理 - 甜菜波波 - 博客园
12.spring中Aop切面使用的例子包括自定义注解的使用:
@Aspect注解_小白不很白的博客-CSDN博客_@aspect
13.mysql将多行字段数值合并为一行字段数据
mysql将多行字段数值合并为一行字段数据_dongyue520的博客-CSDN博客_mysql 合并多行字段
14.@Value注解详解
@Value的诸多用法_weixin_45614626的博客-CSDN博客_@value
15.@RequestParm注解和@RequestBody注解的区别
@RequestBody和@RequestParam区别全面详细_一斤白菜的博客-CSDN博客_@requestparam
16.生成的单号的数字左边补充0
java补充0 java数字左侧补零补0 NumberFormat实现数字左侧补0-蒲公英云
17.如果公司可以使用分页插件可以用pagehelper,但是会出现分页失效的情况需要手写分页,下面为手写分页代码:
public static <T> List<T> pageList(List<T> list, int pageNum, int pageSize) {
// 计算总页数
int page = list.size() % pageSize == 0 ? list.size() / pageSize : list.size() / pageSize + 1;
pageNum = pageNum <= 0 ? 1 : pageNum;
pageNum = Math.min(pageNum, page);
int begin = 0;
int end = 0;
if (pageNum != page) {
begin = (pageNum - 1) * pageSize;
end = begin + pageSize;
} else {
begin = (pageNum - 1) * pageSize;
end = list.size();
}
if (CollectionUtils.isNotEmpty(list)) {
return list.subList(begin, end);
} else {
return null;
}
}
18.常用的代码整理正则如下:
单行注释替换为多行注释:
ctrl+r(替换)
//+(.*$)
/**\n *$1\n */
ctrl+alt+l
行尾注释替换:
查找:
(^[^\r\n]+[\S]+[^\r\n]+)(//.+$),
替换为:
\t$2\r\n$1,
然后Ctrl+alt+l格式化
19.@NotNull,@NotBlank,@NotEmpty注解的区别:
@NotNull用于校验基本类型,可以校验为null和""两种情况
@NotBlank用于校验字符串,可以校验为null和""和" "三种情况
@NotEmpty用于校验集合,可以校验为null和size>0两种情况
20.ThreadLocal可以实现多线程间的数据隔离,填充的数据只属于当前线程,当前线程的数据对于其他线程来说是隔离的(spring中的事务的隔离就是基于ThreadLocal+Aop来实现的;获取和数据库的交互的Connection对象也是基于ThreadLocal实现),它的底层维护着一个ThreadLocalMap(每个线程都有自己的map),map的底层基于数组实现,一个map可以存储多个ThreadLocal对应的数据,map的key是当前的ThreadLocal对象,value是对应存储的数据,当我们调用ThreadLocal的get()方法时,会先根据当前Thread去获取对应的map,然后根据ThreadLocal去获取map中对应的value数据。
参考链接:Java中ThreadLocal的实际用途是啥? - 知乎
21.动态sql中批量插入中foreach中数据量大导致的问题
被 foreach 坑惨了,再也不敢乱用了....(解决方案:①自己手写插入语句,分页分批次的插入②依旧采用动态sql插入,不要使用foreach默认的执行器,而是去使用BatchInsert这个批处理器)
22.BeanUtils中浅拷贝导致的问题
https://blog.csdn.net/qq_50652600/article/details/123400746
(最快解决方案,不使用BeanUtils工具类,而是直接使用set方法去赋值)
23.Thread中run方法和start方法区别
- start() 可以启动一个新线程,run()不能
- start()不能被重复调用,run()可以
- start()中的run代码可以不执行完就继续执行下面的代码,即进行了线程切换。直接调用run方法必须等待其代码全部执行完才能继续执行下面的代码。
- start() 实现了多线程,run()没有实现多线程
24.实现了Serializable接口还要指定serialVersionUID值的原因
为什么实现了Serializable接口还要指定serialVersionUID值呢? - 码农教程
25.maven下的依赖,提供各种加密和解密方法的jar包,详情如下:
https://www.cnblogs.com/zrbfree/p/5659848.html
26.mysql中开启慢查询日志的命令
如何开启mysql慢查询日志?_mysql开启慢查询日志_普通网友的博客-CSDN博客
27.java中拦截器(Filter)和过滤器(interceptor)的区别和使用
Java里过滤器(filter)与拦截器(Interceptor)的区别和使用_java过滤器和拦截器_落丶寞的博客-CSDN博客
28.集合工具类使用场景描述
package test.demo;
import cn.hutool.core.bean.BeanUtil;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class ConvertUtils {
public interface Producer<T, V> {
/**
* 生成数据
*
* @param filedIds
* @return
*/
List<V> generic(List<T> filedIds);
}
public static <T, K, V> Map<K, V> keyListToMap(List<?> sourceList, String sourceKeyFiled, String returnKeyFiled, Producer<T, V> producer) {
List<T> idFields = new ArrayList<>();
for (Object object : sourceList) {
idFields.add(BeanUtil.getProperty(object, sourceKeyFiled));
}
List<V> genericList = producer.generic(idFields);
Map<K, V> returnMap = new HashMap<>(genericList.size());
for (V object : genericList) {
returnMap.put(BeanUtil.getProperty(object, returnKeyFiled), object);
}
return returnMap;
}
}
//roleManagerList集合中是返回的数据集合(实体中包含areaLayer字段),
// 通过List<String> areaLayerList = roleManagerList.stream().map(RoleManager::getAreaLayer).collect(Collectors.toList());
//得到areaLayerList,List<KQBean> kqBeanList = kqService.findComkqByLayers(areaLayers) 需求是根据areaLayers查询得到kqBeanList集合,将areaLayer和KQBean中areaLayer
//相同的KQBean中的数据取一部分值,两层for循环效率低下,使用工具类先放在map中然后获取
List<RoleManager> roleManagerList = roleManagerMapper.getRoleInfoByUserName(userName);
if (CollectionUtils.isNotEmpty(roleManagerList)) {
List<String> areaLayerList = roleManagerList.stream().map(RoleManager::getAreaLayer).collect(Collectors.toList());
List<RoleManager> adminList = roleManagerMapper.getAdminByAreaLayers(areaLayerList);
Map<String, String> adminMap = new HashMap<>();
adminList.forEach(roleManager -> adminMap.put(roleManager.getAreaLayer(), roleManager.getUserName()));
Map<String, KQBean> kqBeanMap = ConvertUtils.keyListToMap(roleManagerList,
"areaLayer",
"kqlayer", (ConvertUtils.Producer<String, KQBean>) areaLayers -> {
List<KQBean> kqBeanList = kqService.findComkqByLayers(areaLayers);
return kqBeanList;
});
List<RoleManagerDTO> resultList = new ArrayList<>();
roleManagerList.forEach(roleManager -> {
RoleManagerDTO role = new RoleManagerDTO();
BeanUtils.copyProperties(roleManager, role);
KQBean kqBean = kqBeanMap.get(roleManager.getAreaLayer());
role.setLongitude(kqBean.getLongitude());
role.setLatitude(kqBean.getLatitude());
role.setKqName(kqBean.getKqname());
role.setAreaPath(kqBean.getAreapath());
role.setSuperAdmin(adminMap.get(roleManager.getAreaLayer()));
resultList.add(role);
});
return resultList;
}
return new ArrayList<>();
29.根据两个经纬度计算相距多少公里的工具类
依赖:
<dependency> <groupId>org.gavaghan</groupId> <artifactId>geodesy</artifactId> <version>1.1.3</version> </dependency>
package cn.chci.hmcs.river.monitor.utils;
import java.io.Serializable;
import java.math.BigDecimal;
import java.math.RoundingMode;
/**
* double的计算不精确,会有类似0.0000000000000002的误差,正确的方法是使用BigDecimal或者用整型
* 整型地方法适合于货币精度已知的情况,比如12.11+1.10转成1211+110计算,最后再/100即可 以下是摘抄的BigDecimal方法:
*/
/**
* 说明:Double工具类
* from:www.1b23.com
*/
public class DoubleUtil implements Serializable {
private static final long serialVersionUID = -3345205828566485102L;
// 默认除法运算精度
private static final Integer DEF_DIV_SCALE = 2;
/**
* 提供精确的加法运算。
*
* @param value1 被加数
* @param value2 加数
* @return 两个参数的和
*/
public static Double add(Double value1, Double value2) {
BigDecimal b1 = new BigDecimal(Double.toString(value1));
BigDecimal b2 = new BigDecimal(Double.toString(value2));
return b1.add(b2).doubleValue();
}
/**
* 提供精确的减法运算。
*
* @param value1 被减数
* @param value2 减数
* @return 两个参数的差
*/
public static double sub(Double value1, Double value2) {
BigDecimal b1 = new BigDecimal(Double.toString(value1));
BigDecimal b2 = new BigDecimal(Double.toString(value2));
return b1.subtract(b2).doubleValue();
}
/**
* 提供精确的乘法运算。
*
* @param value1 被乘数
* @param value2 乘数
* @return 两个参数的积
*/
public static Double mul(Double value1, Double value2) {
BigDecimal b1 = new BigDecimal(Double.toString(value1));
BigDecimal b2 = new BigDecimal(Double.toString(value2));
return b1.multiply(b2).doubleValue();
}
/**
* 提供(相对)精确的除法运算,当发生除不尽的情况时, 精确到小数点以后10位,以后的数字四舍五入。
*
* @param dividend 被除数
* @param divisor 除数
* @return 两个参数的商
*/
public static Double divide(Double dividend, Double divisor) {
return divide(dividend, divisor, DEF_DIV_SCALE);
}
/**
* 提供(相对)精确的除法运算。 当发生除不尽的情况时,由scale参数指定精度,以后的数字四舍五入。
*
* @param dividend 被除数
* @param divisor 除数
* @param scale 表示表示需要精确到小数点以后几位。
* @return 两个参数的商
*/
public static Double divide(Double dividend, Double divisor, Integer scale) {
if (scale < 0) {
throw new IllegalArgumentException("The scale must be a positive integer or zero");
}
BigDecimal b1 = new BigDecimal(dividend);
BigDecimal b2 = new BigDecimal(divisor);
return b1.divide(b2, scale, RoundingMode.HALF_UP).doubleValue();
}
/**
* 提供指定数值的(精确)小数位四舍五入处理。
*
* @param value 需要四舍五入的数字
* @param scale 小数点后保留几位
* @return 四舍五入后的结果
*/
public static double round(double value, int scale) {
if (scale < 0) {
throw new IllegalArgumentException("The scale must be a positive integer or zero");
}
BigDecimal b = new BigDecimal(Double.toString(value));
BigDecimal one = new BigDecimal("1");
return b.divide(one, scale, RoundingMode.HALF_UP).doubleValue();
}
public static Boolean ifInteger(double value){
return Math.floor(value)==Math.ceil(value);
}
}
package cn.chci.hmcs.river.monitor.utils;
import org.gavaghan.geodesy.Ellipsoid;
import org.gavaghan.geodesy.GeodeticCalculator;
import org.gavaghan.geodesy.GeodeticCurve;
import org.gavaghan.geodesy.GlobalCoordinates;
import java.text.DecimalFormat;
/**
* @author Admin
*/
public class DistanceUtils {
public static final String KMFormt = "公里";
public static final String MFormt = "米";
public static final Double KM = 1000d;
public static String meterFormat(Double meter) {
if (meter > KM) {
Double kmFormatVal = DoubleUtil.divide(meter, KM, 1);
if (DoubleUtil.ifInteger(kmFormatVal)) {
DecimalFormat decimalFormat = new DecimalFormat("#");
String formattedValue = decimalFormat.format(kmFormatVal);
return formattedValue + KMFormt;
}
return kmFormatVal + KMFormt;
}
DecimalFormat decimalFormat = new DecimalFormat("#");
String formattedValue = decimalFormat.format(meter);
return formattedValue + MFormt;
}
public static Double distanceMeterUtil(double lat1, double lng1, double lat2, double lng2) {
GlobalCoordinates source = new GlobalCoordinates(lat1, lng1);
GlobalCoordinates target = new GlobalCoordinates(lat2, lng2);
return getDistanceMeter(source, target, Ellipsoid.Sphere);
}
public static String distanceMeterFormat(double lat1, double lng1, double lat2, double lng2) {
Double distanceMeter = distanceMeterUtil(lat1, lng1, lat2, lng2);
return meterFormat(distanceMeter);
}
public static double getDistanceMeter(GlobalCoordinates gpsFrom, GlobalCoordinates gpsTo, Ellipsoid ellipsoid) {
//创建GeodeticCalculator,调用计算方法,传入坐标系、经纬度用于计算距离
GeodeticCurve geoCurve = new GeodeticCalculator().calculateGeodeticCurve(ellipsoid, gpsFrom, gpsTo);
return geoCurve.getEllipsoidalDistance();
}
public static void main(String[] args) {
String distanceMeter = distanceMeterFormat(39.909049, 116.398029, 39.486585, 115.975083);
System.out.println(distanceMeter);
}
}