diff --git a/Resource/BrowersDriver/Chrom/83.0.4103.39/chromedriver.exe b/Resource/BrowersDriver/Chrom/83.0.4103.39/chromedriver.exe new file mode 100644 index 0000000..4850c8d Binary files /dev/null and b/Resource/BrowersDriver/Chrom/83.0.4103.39/chromedriver.exe differ diff --git a/src/main/java/pres/auxiliary/work/selenium/event/AbstractEvent.java b/src/main/java/pres/auxiliary/work/selenium/event/AbstractEvent.java index c436379..54e081b 100644 --- a/src/main/java/pres/auxiliary/work/selenium/event/AbstractEvent.java +++ b/src/main/java/pres/auxiliary/work/selenium/event/AbstractEvent.java @@ -47,4 +47,12 @@ public abstract class AbstractEvent { public void setWaitTime(long waitTime) { wait.withTimeout(Duration.ofSeconds(waitTime)); } + + /** + * 用于返回存储的{@link WebDriver}类对象 + * @return{@link WebDriver}类对象 + */ + public WebDriver getDriver() { + return driver; + } } diff --git a/src/main/java/pres/auxiliary/work/selenium/event/EventInformation.java b/src/main/java/pres/auxiliary/work/selenium/event/EventInformation.java index df15359..56f2c48 100644 --- a/src/main/java/pres/auxiliary/work/selenium/event/EventInformation.java +++ b/src/main/java/pres/auxiliary/work/selenium/event/EventInformation.java @@ -41,7 +41,7 @@ public class EventInformation { this.method = method; this.args = args; //提取Element类对象 - getElement(); + toElement(); } /** @@ -60,10 +60,18 @@ public class EventInformation { return args; } + /** + * 用于返回传入到方法中{@link Element}类对象集合 + * @return {@link Element}类对象集合 + */ + public ArrayList getElement() { + return elementList; + } + /** * 用于将args中为Element类对象的参数进行转换并存储至elementList中 */ - private void getElement() { + private void toElement() { Arrays.stream(args).forEach(arg -> { if (arg instanceof Element) { elementList.add((Element) arg); diff --git a/src/main/java/pres/auxiliary/work/selenium/event/EventProxy.java b/src/main/java/pres/auxiliary/work/selenium/event/EventProxy.java index 2a65625..d097dca 100644 --- a/src/main/java/pres/auxiliary/work/selenium/event/EventProxy.java +++ b/src/main/java/pres/auxiliary/work/selenium/event/EventProxy.java @@ -6,12 +6,52 @@ import java.util.Arrays; import java.util.LinkedHashMap; import java.util.regex.Pattern; +import org.openqa.selenium.WebDriver; import org.springframework.cglib.proxy.Enhancer; import org.springframework.cglib.proxy.MethodInterceptor; import org.springframework.cglib.proxy.MethodProxy; +import pres.auxiliary.work.selenium.brower.ChromeBrower; import pres.auxiliary.work.selenium.element.Element; +/** + *

文件名:EventProxy.java

+ *

用途: + * 用于对事件类进行代理,使其能在对应的事件方法执行前后能执行指定方法,以增强事件的执行。 + * 类中提供6种增强方法的方式,其名称与执行顺序为:方法前置通知、元素前置通知、方法成功/失败通知(两种)、 + * 元素后置通知、方法最终通知,解释如下: + *

    + *
  1. 方法前置通知:根据方法名,匹配到相应的方法后,在执行事件前执行的方法
  2. + *
  3. 元素前置通知:根据元素名称,匹配到传入方法的元素后,在执行事件前执行的方法
  4. + *
  5. 方法成功通知:根据方法名,匹配到相应的方法后,在事件成功执行(未抛出异常)后执行的方法
  6. + *
  7. 方法失败通知:根据方法名,匹配到相应的方法后,在事件失败执行(抛出异常)后执行的方法
  8. + *
  9. 元素后置通知:根据元素名称,匹配到传入方法的元素后,在执行事件后(无论是否抛出异常)执行的方法
  10. + *
  11. 方法最终通知:根据方法名,匹配到相应的方法后,在执行事件后(无论是否抛出异常)执行的方法
  12. + *
+ * 可参考以下示例: + *

+ * 假设存在元素xpah:元素1“//*[text()='登录']”、元素2“//*[@name='account']”、元素3“//*[@name='password']”, + * 在点击元素1前,需要先在元素2和元素3中分别输入“admin”、“123456”,并且在此前定义了{@link ChromeBrower}浏览器对象,变量名为 + * chrome,此时,可以将代码写作
+ *

{@code 
+ * EventProxy clickEventProxy = new EventProxy(new ClickEvent(chrome.getDriver()));
+ * 
+ * clickProxy.addAcion(ActionType.ELEMENT_BEFORE, ".*登录.*", (info) -> {
+ * 			TextEvent text = inputProxy.getProxyInstance();
+ * 			text.input(by.getElement("//*[@name='account']"), "admin");
+ * 			text.input(by.getElement("//*[@name='password']"), "1111111");
+ * 		});
+ * clickEventProxy.getProxyInstance().click(new CommnBy(chrome).getElement("//*[text()='登录']"));
+ * 	
+ * 
+ *

+ *

+ *

编码时间:2020年7月12日 下午1:35:22

+ *

修改时间:2020年7月12日 下午1:35:22

+ * @author 彭宇琦 + * @version Ver1.0 + * @since JDK 12 + */ public class EventProxy implements MethodInterceptor { /** * 用于存储方法前置通知,key表示方法名称匹配规则,value表示调用的方法 @@ -42,6 +82,7 @@ public class EventProxy implements MethodInterceptor { * 事件类对象 */ private T target; + private WebDriver driver; /** * 构造代理类 @@ -49,6 +90,7 @@ public class EventProxy implements MethodInterceptor { */ public EventProxy(T target) { this.target = target; + driver = ((AbstractEvent) target).getDriver(); } /** @@ -58,14 +100,53 @@ public class EventProxy implements MethodInterceptor { */ @SuppressWarnings("unchecked") public T getProxyInstance(){ - //1.工具类 + //工具类 Enhancer en = new Enhancer(); - //2.设置父类 + //设置父类 en.setSuperclass(target.getClass()); - //3.设置回调函数 + //设置回调函数 en.setCallback(this); - //4.创建子类(代理对象) - return (T) en.create(); + //创建子类(代理对象) + return (T) en.create(new Class[] {WebDriver.class}, new Object[] {driver}); +// return (T) en.create(); + } + + /** + * 根据相应的执行的方法类型,添加指定的名称匹配规则及执行方法 + * @param actionType 通知类型枚举类{@link ActionType} + * @param regex 名称匹配规则,元素名称或者方法名称,规则为正则表达式 + * @param action 需要执行的方法 + */ + public void addAcion(ActionType actionType, String regex, EventAction action) { + //指向需要添加通知的map + LinkedHashMap> actionMap = null; + //根据不同类型的通知,将actionMap指向相应的map + switch (actionType) { + case FUNCTION_BEFORE: + actionMap = functionBeforeActionMap; + break; + case ELEMENT_BEFORE: + actionMap = elementBeforeActionMap; + break; + case FUNCTION_SUCCESS_AFTER: + actionMap = functionSuccessActionMap; + break; + case FUNCTION_FAIL_AFTER: + actionMap = functionFailActionMap; + break; + case ELEMENT_AFTER: + actionMap = elementAfterActionMap; + break; + case FUNCTION_FINAL: + actionMap = functionFinalActionMap; + break; + default: + break; + } + + //执行添加通知的方法 + mapAddAction(regex, action, actionMap); + } @Override @@ -75,8 +156,38 @@ public class EventProxy implements MethodInterceptor { //按照方法名或元素名,匹配到相应的通知后,运行通知,若通知运行出现异常,则直接跳过 //运行方法前置通知 - functionBeforeActionMap.forEach((key, value) -> { - if (Pattern.compile(key).matcher(method.getName()).matches()) { + runFuntionAction(eventInformation, functionBeforeActionMap); + + //运行元素前置通知 + runElementAction(eventInformation, elementBeforeActionMap); + + //执行目标对象的方法 + try { + Object returnValue = method.invoke(target, args); + //运行方法成功执行通知 + runFuntionAction(eventInformation, functionSuccessActionMap); + return returnValue; + } catch (Exception exception) { + //运行方法失败执行通知 + runFuntionAction(eventInformation, functionFailActionMap); + throw exception; + } finally { + //运行元素后置通知 + runElementAction(eventInformation, elementAfterActionMap); + + //运行方法最终通知 + runFuntionAction(eventInformation, functionFinalActionMap); + } + } + + /** + * 运行方法通知 + * @param eventInformation 事件信息类对象 + * @param actionMap 需要执行的通知 + */ + private void runFuntionAction(EventInformation eventInformation, LinkedHashMap> actionMap) { + actionMap.forEach((key, value) -> { + if (Pattern.compile(key).matcher(eventInformation.getMethod().getName()).matches()) { value.forEach(action -> { //出现异常则不进行处理 try { @@ -86,10 +197,16 @@ public class EventProxy implements MethodInterceptor { }); } }); - - //运行元素前置通知 - Arrays.stream(args).filter(arg -> arg instanceof Element).forEach(arg -> { - elementBeforeActionMap.forEach((key, value) -> { + } + + /** + * 执行元素通知 + * @param eventInformation 事件类对象 + * @param actionMap 需要执行的通知 + */ + private void runElementAction(EventInformation eventInformation, LinkedHashMap> actionMap) { + Arrays.stream(eventInformation.getParam()).filter(arg -> arg instanceof Element).forEach(arg -> { + actionMap.forEach((key, value) -> { if (Pattern.compile(key).matcher(((Element) arg).getName()).matches()) { value.forEach(action -> { try { @@ -100,64 +217,57 @@ public class EventProxy implements MethodInterceptor { } }); }); - - //执行目标对象的方法 - try { - Object returnValue = method.invoke(target, args); - //运行方法成功执行通知 - functionSuccessActionMap.forEach((key, value) -> { - if (Pattern.compile(key).matcher(method.getName()).matches()) { - value.forEach(action -> { - //出现异常则不进行处理 - try { - action.action(eventInformation); - } catch (Exception e) { - } - }); - } - }); - return returnValue; - } catch (Exception exception) { - //运行方法失败执行通知 - functionFailActionMap.forEach((key, value) -> { - if (Pattern.compile(key).matcher(method.getName()).matches()) { - value.forEach(action -> { - //出现异常则不进行处理 - try { - action.action(eventInformation); - } catch (Exception e) { - } - }); - } - }); - throw exception; - } finally { - //运行元素后置通知 - Arrays.stream(args).filter(arg -> arg instanceof Element).forEach(arg -> { - elementAfterActionMap.forEach((key, value) -> { - if (Pattern.compile(key).matcher(((Element) arg).getName()).matches()) { - value.forEach(action -> { - try { - action.action(eventInformation); - } catch (Exception e) { - } - }); - } - }); - }); - - //运行方法最终通知 - functionFinalActionMap.forEach((key, value) -> { - if (Pattern.compile(key).matcher(method.getName()).matches()) { - value.forEach(action -> { - //出现异常则不进行处理 - try { - action.action(eventInformation); - } catch (Exception e) { - } - }); - } - }); + } + + /** + * 用于向相应的通知map中添加通知 + * @param regex 匹配规则 + * @param action 通知 + * @param actionMap 存储通知的map + */ + private void mapAddAction(String regex, EventAction action, LinkedHashMap> actionMap) { + //判断actionMap中是否存在regex,若不存在,则将regex加入到actionMap,并构造ArrayList类 + if (!actionMap.containsKey(regex)) { + actionMap.put(regex, new ArrayList()); } + + //在相应的regex中添加action + actionMap.get(regex).add(action); + } + + /** + *

文件名:EventProxy.java

+ *

用途:用于标记通知的类型

+ *

编码时间:2020年7月12日 上午11:24:57

+ *

修改时间:2020年7月12日 上午11:24:57

+ * @author 彭宇琦 + * @version Ver1.0 + * @since JDK 8 + */ + public enum ActionType { + /** + * 表示方法前置通知 + */ + FUNCTION_BEFORE, + /** + * 表示元素前置通知 + */ + ELEMENT_BEFORE, + /** + * 表示方法执行成功通知 + */ + FUNCTION_SUCCESS_AFTER, + /** + * 表示方法执行失败通知 + */ + FUNCTION_FAIL_AFTER, + /** + * 表示元素后置通知 + */ + ELEMENT_AFTER, + /** + * 表示方法最终通知 + */ + FUNCTION_FINAL; } } diff --git a/src/test/java/pres/auxiliary/work/selenium/event/EventProxyTest.java b/src/test/java/pres/auxiliary/work/selenium/event/EventProxyTest.java new file mode 100644 index 0000000..f4215dd --- /dev/null +++ b/src/test/java/pres/auxiliary/work/selenium/event/EventProxyTest.java @@ -0,0 +1,59 @@ +package pres.auxiliary.work.selenium.event; + +import java.io.File; + +import org.testng.annotations.AfterClass; +import org.testng.annotations.BeforeClass; +import org.testng.annotations.Test; + +import pres.auxiliary.work.selenium.brower.ChromeBrower; +import pres.auxiliary.work.selenium.brower.ChromeBrower.ChromeOptionType; +import pres.auxiliary.work.selenium.element.CommonBy; +import pres.auxiliary.work.selenium.event.EventProxy.ActionType; + +public class EventProxyTest { + EventProxy clickProxy; + EventProxy inputProxy; + ChromeBrower chrome; + CommonBy by; + + @BeforeClass + public void init() { + chrome = new ChromeBrower(new File("Resource/BrowersDriver/Chrom/83.0.4103.39/chromedriver.exe")); + chrome.addConfig(ChromeOptionType.CONTRAL_OPEN_BROWER, "127.0.0.1:9222"); + clickProxy = new EventProxy<>(new ClickEvent(chrome.getDriver())); + inputProxy = new EventProxy<>(new TextEvent(chrome.getDriver())); + by = new CommonBy(chrome); + } + + @AfterClass + public void showResult() { + ClickEvent click = clickProxy.getProxyInstance(); + click.doubleClick(by.getElement("//*[text()='登录']")); + } + + @Test + public void addAcionTest() { + TextEvent textEvent = new TextEvent(chrome.getDriver()); + textEvent.input(by.getElement("//*[@name='account']"), "admin"); + textEvent.input(by.getElement("//*[@name='password']"), "1111111"); + + inputProxy.addAcion(ActionType.FUNCTION_BEFORE, ".*input.*", (info) -> { + inputProxy.getProxyInstance().clear(info.getElement().get(0)); + }); + + clickProxy.addAcion(ActionType.ELEMENT_BEFORE, ".*登录.*", (info) -> { + TextEvent text = inputProxy.getProxyInstance(); + text.input(by.getElement("//*[@name='account']"), "admin"); + text.input(by.getElement("//*[@name='password']"), "1111111"); + }); + + clickProxy.addAcion(ActionType.ELEMENT_AFTER, ".*登录.*", (info) -> { + try { + Thread.sleep(2000); + } catch (InterruptedException e) { + } + by.alertAccept(); + }); + } +}