看到mybatis-plus有个写法
image.png
原本我们应该写数据库列名”asset_id”。但是这种写法是一种魔数值,我们写代码应该尽量避免未经定义的变量出现在代码里。所以参考mbp,重复造了个轮子。

函数式接口

函数式接口是必须的,且函数式接口必须继承Serializable。

  1. /**
  2. * @author zhy
  3. * @date 2021/1/2810:07
  4. */
  5. @FunctionalInterface
  6. public interface Func<T, R> extends Serializable {
  7. /**
  8. * 函数式接口的唯一方法
  9. * @param t
  10. * @throws
  11. * @return R
  12. * @author zhy
  13. * @date 2021/1/28 11:36
  14. */
  15. R apply(T t);
  16. }

这样在方法中以函数式接口为参数,传入lambda表达式,就会将表达式生成成一个匿名类。继承Serializable的原因是,匿名类的将会多生成一个私有静态方法writeReplace()。而这个方法是关键,会返回一个SerializedLambda对象。SerializedLambda中有我们传进去的方法名称,例如getName 这种。通过get方法来解析出对应的类属性,和数据库字段

LambdaUtil

  1. /**
  2. *
  3. * @author zhy
  4. * @date 2021/1/2814:57
  5. */
  6. @Slf4j
  7. public class LambdaUtil {
  8. /** 大写正则表达式 */
  9. private static Pattern upperPattern = Pattern.compile("[A-Z]");
  10. /** 下划线 */
  11. private static char underLine = '_';
  12. private LambdaUtil(){}
  13. /**
  14. * 获取lambda对应的属性名称
  15. * @param func
  16. * @throws
  17. * @return java.lang.String
  18. * @author zhy
  19. * @date 2021/1/28 10:51
  20. */
  21. public static <T, R> String getPropertyName(Func<T, R> func) {
  22. String implMethodName = getImplMethodName(func);
  23. return methodToProperty(implMethodName);
  24. }
  25. /**
  26. * 获取lambda对应的数据库字段名称
  27. * 遵循通用定义:转化对应属性名,将属性名中的大写字母改为小写,并在前面加下划线
  28. * @param func
  29. * @throws
  30. * @return java.lang.String
  31. * @author zhy
  32. * @date 2021/1/28 10:51
  33. */
  34. public static <T, R> String getSqlColumn(Func<T, R> func) {
  35. String implMethodName = getImplMethodName(func);
  36. String property = methodToProperty(implMethodName);
  37. return upperCharToUnderLine(property);
  38. }
  39. /**
  40. * 转化字符串中的大写字母为 _小写
  41. * @param param
  42. * @throws
  43. * @return java.lang.String
  44. * @author zhy
  45. * @date 2021/1/28 15:37
  46. */
  47. private static String upperCharToUnderLine(String param){
  48. StringBuilder builder=new StringBuilder(param);
  49. Matcher mc=upperPattern.matcher(param);
  50. int i=0;
  51. while (mc.find()) {
  52. builder.replace(mc.start()+i, mc.end()+i, "_"+mc.group().toLowerCase());
  53. i++;
  54. }
  55. if(underLine == builder.charAt(0)){
  56. builder.deleteCharAt(0);
  57. }
  58. return builder.toString();
  59. }
  60. /**
  61. * 根据lambda表达式获取方法名称
  62. * @param func
  63. * @throws
  64. * @return java.lang.String
  65. * @author zhy
  66. * @date 2021/1/28 10:53
  67. */
  68. private static <T, R> String getImplMethodName(Func<T, R> func){
  69. Method writeReplace = null;
  70. Object o = null;
  71. try {
  72. // 直接调用writeReplace
  73. writeReplace = func.getClass().getDeclaredMethod("writeReplace");
  74. writeReplace.setAccessible(true);
  75. //反射调用
  76. o = writeReplace.invoke(func);
  77. } catch (Exception e) {
  78. log.error("",e);
  79. throw new CecServerException(CecServerCodeMessage.error(CecServerCodeMessageEnum.SYSTEM_EXECUTION_ERROR.getMessage()));
  80. }
  81. SerializedLambda lambda = (SerializedLambda) o;
  82. return lambda.getImplMethodName();
  83. }
  84. /**
  85. * 通过方法名称获取字段名称
  86. * @param methodName
  87. * @throws
  88. * @return java.lang.String
  89. * @author zhy
  90. * @date 2021/1/28 10:51
  91. */
  92. private static String methodToProperty(String methodName) {
  93. if (methodName.startsWith("is")) {
  94. methodName = methodName.substring(2);
  95. } else {
  96. if (!methodName.startsWith("get") && !methodName.startsWith("set")) {
  97. throw new CecServerException("Error parsing property name '" + methodName + "'. Didn't start with 'is', 'get' or 'set'.");
  98. }
  99. methodName = methodName.substring(3);
  100. }
  101. if (methodName.length() == 1 || methodName.length() > 1 && !Character.isUpperCase(methodName.charAt(1))) {
  102. methodName = methodName.substring(0, 1).toLowerCase(Locale.ENGLISH) + methodName.substring(1);
  103. }
  104. return methodName;
  105. }
  106. }