服务器上如何建设多个网站,wordpress the7使用教程,彩票网站开发亿云,php制作网站目录一、AOP 动态代理切入方法(1) Aspect Oriented Programming(2) 切入点表达式二、SpringBoot 项目扫描类(1) ResourceLoader 扫描类(2) Map 的 computeIfAbsent 方法(3) 反射几个常用 api① 创建一个测试注解② 创建测试 PO 类③ 反射 api 获取指定类的指定注解信息(4) 返回…
目录一、AOP 动态代理切入方法(1) Aspect Oriented Programming(2) 切入点表达式二、SpringBoot 项目扫描类(1) ResourceLoader 扫描类(2) Map 的 computeIfAbsent 方法(3) 反射几个常用 api① 创建一个测试注解② 创建测试 PO 类③ 反射 api 获取指定类的指定注解信息(4) 返回第一个不为空的字符串(5) 判断一个【字符】是大写字母还是小写字母(6) 让英文单词的首字母变小写(7) 驼峰转下划线形式(8) GForeignTableInfo外键表信息(9) 遍历 Class 对象的全部属性学习不使用数据库外键的情况下保证有关联的表之间的数据的一致性 一、AOP 动态代理切入方法
(1) Aspect Oriented Programming AOPAspect Oriented Programming面向切面编程 Spring 使用 AOP 技术封装了动态代理功能 它依赖 AspectJ 库 dependencygroupIdorg.aspectj/groupIdartifactIdaspectjrt/artifactIdversion1.9.6/version/dependencydependencygroupIdorg.aspectj/groupIdartifactIdaspectjweaver/artifactIdversion1.9.6/version/dependencydependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-aop/artifactId/dependency(2) 切入点表达式 ① 任意公共方法 execution(public * *(..)) ② 方法名以 set 开头的全部方法 execution(* set*(..)) ③ UserService 接口定义的全部方法 execution(* com.guoqing.service.UserService.*(..)) ④ service 包下定义的全部方法不包括子包 execution(* com.guoqing.service.*.*(..)) ⑤ service 包下定义的全部方法包括子包 execution(* com.guoqing.service..*.*(..)) ⑥ 包含两个 String 类型参数的全部方法 execution(* *(String, String)) ⑦ 只有一个 Serializable 参数的全部方法 args(java.io.Serializable) ⑧ service 包中的全部方法 within(com.guoqing.service.*) ⑨ service 包中的全部方法包括子包 within(com.guoqing.service..*) Slf4j
Aspect
Component
public class GForeignAspect {Around(execution(* com.guoqing.service..*.remove*(..)))public Object handleRemove(ProceedingJoinPoint point) throws Throwable {Object target point.getTarget();if (!(target instanceof IService)) return point.proceed();IService? service (IService?) target;// MP 泛型的类型genericType是 PO, 是要被删除的【表】Class? genericType service.getEntityClass();// eg: class com.guoqing.po.WechatUser// 知道要被删除的类型PO后, 就可以知道该 PO 被哪些表引用着log.info(【庆】{}, genericType.toString());return point.proceed();}}二、SpringBoot 项目扫描类 ① 实现implementsApplicationContextAware 接口并实现它的 void setApplicationContext(ApplicationContext) 方法 这是 Spring Bean 的生命周期方法 通过该方法可以获取 Spring 的 IoC 容器进而获取到某个类的实例通过它的 getBean() 方法 Component
public class TestLifecycle implements ApplicationContextAware {private ApplicationContext iocContext;Overridepublic void setApplicationContext(ApplicationContext applicationContext)throws BeansException {this.iocContext applicationContext;UserController userController (UserController) iocContext.getBean(Users);}
}② 实现implements InitializingBean 接口并实现它的 void afterPropertiesSet() 方法 这是 Spring Bean 的生命周期方法 当实现该接口的类的属性被设置注入完毕后afterPropertiesSet() 方法被调用 Component
public class GForeignAspect implements ApplicationContextAware, InitializingBean {private ApplicationContext iocContext;// 属性被设置注入完毕时InitializingBean 接口的 afterPropertiesSet 被调用Autowired private ResourceLoader resourceLoader; Overridepublic void setApplicationContext(ApplicationContext applicationContext)throws BeansException {this.iocContext applicationContext; }Overridepublic void afterPropertiesSet() throws Exception {}
}(1) ResourceLoader 扫描类 Spring 框架的 org.springframework.core.io.ResourceLoader 类 Slf4j
Aspect
Component
public class GForeignAspect implements InitializingBean {// 要被扫描的类的 class 文件private static final String SCAN_CLASS classpath*:com/guoqing/po/**/*.class;Autowiredprivate ResourceLoader resourceLoader;/*** 扫描全部的 PO 类*/Overridepublic void afterPropertiesSet() throws Exception {// 通过资源加载器拿到资源匹配解析器ResourcePatternResolver resolver ResourcePatternUtils.getResourcePatternResolver(resourceLoader);// 通过资源加载器拿到元数据读取工厂类CachingMetadataReaderFactory metadataReaderFactory new CachingMetadataReaderFactory(resourceLoader);// 通过资源匹配解析器读取到类的 class 资源Resource[] resources resolver.getResources(SCAN_CLASS);if (resources.length 0) {log.info(没有可供扫描的 PO);throw new Exception(没有可供扫描的 PO);}// 遍历 class 资源, 通过元数据解析器读取 class 资源的信息如 类名for (Resource resource : resources) {// 通过元数据读取工厂获取到元数据读取器MetadataReader metadataReader metadataReaderFactory.getMetadataReader(resource);// 通过元数据读取器拿到 class 元数据读取器ClassMetadata classMetadata metadataReader.getClassMetadata();// 通过元数据读取器拿到 class 的类名String className classMetadata.getClassName();/*output:className com.guoqing.po.PeopleclassName com.guoqing.po.WechatUser*/System.out.println(className className);}}
}上面的一段代码都是比较固定的直接复制使用即可 通过元数据读取器还可调用下面的方法获取其他 class 信息 上面的代码中获取到了 class或类的完整路径。可通过 Java 的反射机制创建相应类的实例 (2) Map 的 computeIfAbsent 方法
compute: 计算absent: 不存在
先看懂下面的代码然后用 computeIfAbsent 改写下面的代码
public class TestTest {Testpublic void testComputeIfAbsent() {HashMapString, SetString hashMap new HashMap();SetString set new HashSet();set.add(杨天荣);hashMap.put(boy, set);// 判断 Map 中是否存在 key 是【boy】的键值对if (hashMap.containsKey(boy)) {// 如果有, 获取该 keyboy对应的 valueSet 类型// 并往其中添加值【庆医】hashMap.get(boy).add(庆医);} else {// 如果没有, 新创建一个 Set, 把值【庆医】添加其中// 然后把新创建的这个 Set 添加到 Map 中SetString tmpSet new HashSet();tmpSet.add(庆医);hashMap.put(boy, tmpSet);}// output: {boy[杨天荣, 庆医]}System.out.println(hashMap.toString());}}✏️ 上面代码的逻辑很容易但是写起来比较麻烦 ✏️ Map 提供了 computeIfAbsent 方法用以实现类型上面的逻辑功能且写法很优美 public class TestTest {Testpublic void testComputeIfAbsent() {HashMapString, SetString hashMap new HashMap();HashSetString set new HashSet();set.add(杨天荣);hashMap.put(boy, set);// hashMap.computeIfAbsent(boy, this::getSetInstance).add(庆医);hashMap.computeIfAbsent(boy, key - getSetInstance(key)).add(庆医);// output: {boy[杨天荣, 庆医]}System.out.println(hashMap.toString());}private SetString getSetInstance(String key) {return new HashSet();}}computeIfAbsent: 如果存在映射的值则返回该值否则返回计算值 (3) 反射几个常用 api
① 创建一个测试注解
Documented
Retention(RetentionPolicy.RUNTIME)
Target(ElementType.TYPE)
public interface MyTestAnnotation {String function() default 该类作用显而易见, 不予解释;}✏️ 当和反射结合的时候注解的作用非常强大 ✏️ 注解没有和反射结合的时候注解毫无作用 ✏️ 上面的代码是一个简单的注解案例如需了解更多 关于注解 https://zgqwillbeverylucky.blog.csdn.net/article/details/127098256 ② 创建测试 PO 类
Data
public class BasePo {private Integer id;private String name;private String createTime;}EqualsAndHashCode(callSuper true)
MyTestAnnotation(function 人类, 用于构建人)
Data
public class People extends BasePo {private String phone;private String job;}③ 反射 api 获取指定类的指定注解信息 已知 People 类的完整类名是com.guoqing.po.People 已知 People 类有 MyTestAnnotation 注解 获取出 People 类的 MyTestAnnotation 注解信息 public class TestReflection {private static final String CLASS_FULL_NAME com.guoqing.po.People;Testpublic void test() throws ClassNotFoundException {// 使用 Class 类的 forName 静态方法, 传入完整类名, 创建该类的【类对象】Class? clsObj Class.forName(CLASS_FULL_NAME);// 通过【类对象】的 getAnnotation 方法获取注解信息MyTestAnnotation annotation clsObj.getAnnotation(MyTestAnnotation.class);// annotation com.guoqing.common.aop.foreign.annotation.MyTestAnnotation(function人类, 用于构建人)System.out.println(annotation annotation);// annotation.function 人类, 用于构建人System.out.println(annotation.function annotation.function());}
}(4) 返回第一个不为空的字符串
public class GCommonUtil {/*** 判断一个字符串是否为 null 或空串*/public static boolean isEmptyStr(String string) {return string null || .equals(string);}/*** 传入多个字符串 (可以是可变参数, 或数组), 返回第一个不为空的字符串*/public static String firstNotEmptyStr(String... strings) {if (strings null || strings.length 1) return null;if (strings.length 1) return strings[0];for (String string : strings) {if (!isEmptyStr(string)) {return string;}}return null;}}(5) 判断一个【字符】是大写字母还是小写字母
public class GCommonUtil {/*** 当一个字符是【大】写英文字母的时候返回 true*/public static boolean isBigLetter(char source) {return source A source Z;}/*** 当一个字符是【小】写英文字母的时候返回 true*/public static boolean isSmallLetter(char source) {return source a source z;}}(6) 让英文单词的首字母变小写
大写英文字符如 A、E、F、B加上数字 32 后变为小写英文字符
public class GCommonUtil {// 大写英文字符加上数字 32 后变为小写英文字符private static final int DELTA a - A; // 32/*** 传入一个字符串, 若它的首字母是小写, 通过它的首字母创建 StringBuilder 对象返回* 若它的首字母是大写, 把首字母转换为小写后通过首字母创建 StringBuilder 对象返回*/public static StringBuilder firstLetterLowerStringBuilder(String source) {StringBuilder sb new StringBuilder();if (isEmptyStr(source)) return sb;// 取出字符串的首字母char firstLetter source.charAt(0);if (isBigLetter(firstLetter)) { // 如果首字母是大写的sb.append((char) (firstLetter DELTA));} else {sb.append(firstLetter);}return sb;} /*** 返回英文字符串的首字母小写形式* 【 BOY- bOY】*/public static String firstLetterLowercase(String source) {if (isEmptyStr(source)) return source;StringBuilder sb firstLetterLowerStringBuilder(source);int length source.length();for (int i 1; i length; i) {sb.append(source.charAt(i));}return sb.toString();} }(7) 驼峰转下划线形式 /*** 驼峰转下划线形式* LoveYou - love_you*/public static String camel2underline(String source) {if (isEmptyStr(source)) return null;StringBuilder sb firstLetterLowerStringBuilder(source);int len source.length();for (int i 1; i len; i) {char curChar source.charAt(i);if (isBigLetter(curChar)) {sb.append(_);sb.append((char) (curChar DELTA));} else {sb.append(curChar);}}return sb.toString();}(8) GForeignTableInfo外键表信息 ✏️ 该类用以描述类和表的信息 ✏️ 该类的内容很多该节先介绍一部分后面慢慢补充 ① cacheClassTableMap 该属性缓存某个表的 class 对象和外键表GForeignTableInfo信息。它是 static 属性常量 static final所以它的 JVM 中只占用独一无二的一份内存 ② clsObj 该属性记录类对象class信息。它作为 key和对应的 GForeignTableInfo 相映射 ③ tableName 该属性记录了该外键表信息对应的表的名字 Getter
Setter
public class GForeignTableInfo {// 缓存【类】和【表】的映射关系private static final MapClass?, GForeignTableInfo CACHE_CLASS_TABLE_MAP new HashMap();private Class? clsObj;private String tableName;public static GForeignTableInfo getInfo(Class? clsObj, boolean newIfAbsent) {if (!newIfAbsent) return CACHE_CLASS_TABLE_MAP.get(clsObj);return CACHE_CLASS_TABLE_MAP.computeIfAbsent(clsObj, k - {GForeignTableInfo foreignTableInfo new GForeignTableInfo();foreignTableInfo.setClsObj(clsObj);// 设置表名String tableName;// 获取 clsObj 的 GForeignTable 注解信息GForeignTable annotation clsObj.getAnnotation(GForeignTable.class);if (annotation ! null) {// 获取 GForeignTable 注解中 name 或 value 注解信息// name 或 value 注解信息都可以表示表名tableName GCommonUtil.firstNotEmptyStr(annotation.name(), annotation.value());} else {String clsSimpleName clsObj.getSimpleName();tableName GCommonUtil.firstLetterLowercase(clsSimpleName);}foreignTableInfo.setTableName(tableName);return foreignTableInfo;});}}(9) 遍历 Class 对象的全部属性