Java自动化测试系列[v1.0.0][常见页面操作处理]

[控制滚动]

package util;
import org.openqa.selenium.JavascriptExecutor;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
 
 
public class ScrollBarUtil {
    /**
     * 控制滚动条向下拉到底
     * @param driver 浏览器驱动
     */
    public static void toBottom(WebDriver driver) {
        JavascriptExecutor js = (JavascriptExecutor) driver;
        //向下拉到底//
        js.executeScript("document.documentElement.scrollTop=10000");
    }
 
    /**
     * 控制滚动条向上拉到顶
     * @param driver 浏览器驱动
     */
    public static void toTop(WebDriver driver) {
        JavascriptExecutor js = (JavascriptExecutor) driver;
        //向上拉到顶
        js.executeScript("document.documentElement.scrollTop=0");
    }
 
    /**
     * 控制滚动条向下拉到底
     * @param driver 浏览器驱动
     */
    public static void scrolltoBottom(WebDriver driver) {
        JavascriptExecutor js = (JavascriptExecutor) driver;
        //向下拉到底
        js.executeScript("window.scrollTo(0,100000)");
    }
 
    /**
     * 控制滚动条向上拉到顶
     * @param driver 浏览器驱动
     */
    public static void scrolltoTop(WebDriver driver) {
        JavascriptExecutor js = (JavascriptExecutor) driver;
        //向上拉到顶
        js.executeScript("window.scrollTo(0,1)");
    }
 
    /**
     * 控制滚动条拉到中间
     * @param driver 浏览器驱动
     */
    public static void verticaltoMiddle(WebDriver driver) {
        JavascriptExecutor js = (JavascriptExecutor) driver;
        //上下拉到中间
        js.executeScript("window.scrollBy(0, 0-document.body.scrollHeight *1/2)");
    }
 
    /**
     * 控制水平滚动条左右拉到中间
     * @param driver 浏览器驱动
     */
    public static void horizontaltoMiddle(WebDriver driver) {
        JavascriptExecutor js = (JavascriptExecutor) driver;
        //左右拉到中间
        js.executeScript("window.scrollBy(0, 0-document.body.scrollWidht *1/2)");
    }
 
    /**
     * 控制滚动条拉到元素可见
     * @param driver 浏览器驱动
     * @param element 页面元素定位
     */
    public static void scrolltoPresence(WebDriver driver, WebElement element) {
        JavascriptExecutor js = (JavascriptExecutor) driver;
        //移动到元素element对象的“顶端”与当前窗口的“顶部”对齐
        //js.executeScript("arguments[0].scrollIntoView();", element);
        js.executeScript("arguments[0].scrollIntoView(true);", element);
        //移动到元素element对象的“底端”与当前窗口的“底部”对齐
        //js.executeScript("arguments[0].scrollIntoView(false);", element);
    }
 
    /**
     * 使用JavaScript的ScrollTo函数和document.body.scrollHeight参数
     * 将页面滚动到最下方
     * @param driver 浏览器驱动
     */
    public static void scrollingToBottomofPage(WebDriver driver){
        ((JavascriptExecutor) driver).executeScript("window.scrollTo(0, document.body.scrollHeight)");
        try{
            Thread.sleep(3000);
        }catch (InterruptedException e){
            e.printStackTrace();
        }
    }
 
    /**
     * 使用JavaScript的ScrollTo函数,使用0和800的横纵坐标参数
     * 将页面的滚动条纵向下滑800个像素
     * @param driver 浏览器驱动
     */
    public static void scrollingByCoordinateofPage(WebDriver driver){
 
        ((JavascriptExecutor) driver).executeScript("window.scrollBy(0,200)");
        try{
            Thread.sleep(3000);
        }catch (InterruptedException e){
            e.printStackTrace();
        }
    }
}

[模拟键盘]

package util;
import java.awt.AWTException;
import java.awt.Robot;
import java.awt.Toolkit;
import java.awt.datatransfer.StringSelection;
import java.awt.event.KeyEvent;
 
public class KeyBoardUtil {
    /**Tab键封装*/
    public static void pressTabKey(){
        Robot robot = null;
        try{
            robot = new Robot();
        }catch (AWTException e){
            e.printStackTrace();
        }
        //调用keypress方法来实现按下Tab键
        assert robot != null;
        robot.keyPress(KeyEvent.VK_TAB);
        //调用keyrelease方法来实现释放Tab键
        robot.keyRelease(KeyEvent.VK_TAB);
    }
    /**Enter键封装*/
    public static void pressEnterKey(){
        Robot robot = null;
        try{
            robot = new Robot();
        }catch (AWTException e){
            e.printStackTrace();
        }
        //调用keypress方法来实现按下Enter键
        assert robot != null;
        robot.keyPress(KeyEvent.VK_ENTER);
        //调用keyrelease方法来实现释放Enter键
        robot.keyRelease(KeyEvent.VK_ENTER);
    }
    /**将指定字符串设为剪切板内容,执行黏贴操作
     *将页面焦点切换到输入框后,调用此函数,将指定字符串黏贴到输入框
     */
    public static void setAndctrlVClipboardData(String string){
        StringSelection stringSelection = new StringSelection(string);
        Toolkit.getDefaultToolkit().getSystemClipboard().setContents(stringSelection, null);
        Robot robot = null;
        try{
            robot = new Robot();
        }catch (AWTException e){
            e.printStackTrace();
        }
        assert robot != null;
        robot.keyPress(KeyEvent.VK_CONTROL);
        robot.keyPress(KeyEvent.VK_V);
        robot.keyRelease(KeyEvent.VK_V);
        robot.keyRelease(KeyEvent.VK_CONTROL);
    }
 
    /**
     * 键盘向下键封装
     */
    public static void pressDownKey(){
        Robot robot = null;
        try{
            robot = new Robot();
        }catch (AWTException e){
            e.printStackTrace();
        }
        assert robot != null;
        robot.keyPress(KeyEvent.VK_DOWN);
        robot.keyRelease(KeyEvent.VK_DOWN);
    }
}

[修改页面元素属性]

package Util;

import org.openqa.selenium.JavascriptExecutor;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;

/**
 * Summary: add/modify/delete attribute of elements
 *
 * @author: davieyang
 * @create: 2018-08-05 2:29
 */
public class ModifyElementsAttributeByJS {
    public void setAttribute(WebDriver driver, WebElement element, String attributeName, String value){
        JavascriptExecutor js = (JavascriptExecutor) driver;
        /**
         * 调用js修改页面元素的属性值arguments[0]-arguments[2]会由element,attributeName,value替换
         */
        js.executeScript("arguments[0].setAttribute(arguments[1],arguments[2])", element,attributeName,value);
    }

    public void removeAttribute(WebDriver driver, WebElement element, String attributeName){
        JavascriptExecutor js = (JavascriptExecutor) driver;
        /**
         * 调用js修改页面元素的属性值arguments[0]-arguments[1]会由element,attributeName替换
         */
        js.executeScript("arguments[0].removeAttribute(arguments[1],arguments[2])", element,attributeName);
    }




}

[Javascript实现页面单击操作]

/*
 * the method of invoking js to do something
 *
 * @author davieyang
 * @create 2018-08-05 1:37
 */
package util;
import org.openqa.selenium.*;
import java.util.Arrays;

public class JavaScriptToDo {
    /**
     *
     * @param driver 浏览器驱动
     * @param xpath xpath定位表达式
     */
    public static void javaScriptClick(WebDriver driver, String xpath) {
        WebElement element = driver.findElement(By.xpath(xpath));
        try{
            if(element.isEnabled() && element.isDisplayed()){
                System.out.println("使用JS进行也面元素单击");
                //执行JS语句arguments[0].click();
                ((JavascriptExecutor) driver).executeScript("arguments[0].click();", element);
            }else {
                System.out.println("页面上元素无法进行单击操作");
            }
        }catch (StaleElementReferenceException e){
            System.out.println("页面元素没有附加在页面中" + Arrays.toString(e.getStackTrace()));
        }catch (NoSuchElementException e){
            System.out.println("在页面中没有找到要操作的元素" + Arrays.toString(e.getStackTrace()));
        }catch (Exception e){
            System.out.println("无法完成单击操作" + Arrays.toString(e.getStackTrace()));
        }
    }
}

[启动浏览器]

    /**
     * 定义函数initBrowser
     * @param browser:字符串参数chrome/ie/xx
     * @return 并返回驱动
     */
    public static WebDriver initBrowser(String browser) {
        if(browser.equalsIgnoreCase("firefox")) {
            System.setProperty("webdriver.gecko.driver", Path_BrowserDrivers+"geckodriver.exe");
            driver = new FirefoxDriver();
            driver.manage().timeouts().implicitlyWait(30, TimeUnit.SECONDS);
            info("启动Firefox浏览器");

        }else if (browser.equalsIgnoreCase("ie")){
            System.setProperty("webdriver.ie.driver",Path_BrowserDrivers+"IEDriverServer.exe");
            driver = new InternetExplorerDriver();
            driver.manage().timeouts().implicitlyWait(30, TimeUnit.SECONDS);
            info("启动IE浏览器");
        }else {
            System.setProperty("webdriver.chrome.driver",Path_BrowserDrivers+"chromedriver.exe");
            driver = new ChromeDriver();
            driver.manage().timeouts().implicitlyWait(30, TimeUnit.SECONDS);
            info("启动Chrome浏览器");
        }
        driver.manage().window().maximize();
        info("最大化浏览器");
        return driver;
    }

    /**
     * 进入页面url
     * @param url:驱动浏览器,打开的页面url
     * @param browser:字符串参数chrome/ie/xx
     * @param timeOutInSeconds:等待时常
     */
    public static void openBrowser(String url, String browser, int timeOutInSeconds) {
        driver = initBrowser(browser);
        driver.manage().timeouts().implicitlyWait(timeOutInSeconds, TimeUnit.SECONDS);
        driver.get(url);
    }

[JS][AWT处理点击]

方法一

selenium提供的click()方法

driver.findElement(By.xpath(".....")).click();

方法二

那么我们一定是要点了它才能完成测试用例的执行,第一种方式不行,还有什么其他方法呢,我去手动测试这个按钮,是否接受键盘的Enter键,果然响应了Enter键,于是立刻用selenium提供的方法代码实现

driver.findElement(By.xpath("...")).sendKeys(Keys.ENTER);

方法三

于是封装了敲击键盘的方法,尝试不用Selenium提供的方法,实现敲击Enter键

import java.awt.AWTException;
import java.awt.Robot;
import java.awt.Toolkit;
import java.awt.event.KeyEvent;
public class KeyBoardUtil {
 /**Enter键封装*/
    public static void pressEnterKey(){
        Robot robot = null;
        try{
            robot = new Robot();
        }catch (AWTException e){
            e.printStackTrace();
        }
        //调用keypress方法来实现按下Enter键
        assert robot != null;
        robot.keyPress(KeyEvent.VK_ENTER);
        //调用keyrelease方法来实现释放Enter键
        robot.keyRelease(KeyEvent.VK_ENTER);
    }
}

方法四

    /**
     *
     * @param driver 浏览器驱动
     * @param xpath xpath定位表达式
     */
    public static void javaScriptClick(WebDriver driver, String xpath) {
        WebElement element = driver.findElement(By.xpath(xpath));
        try{
            if(element.isEnabled() && element.isDisplayed()){
                System.out.println("使用JS进行也面元素单击");
                //执行JS语句arguments[0].click();
                ((JavascriptExecutor) driver).executeScript("arguments[0].click();", element);
            }else {
                System.out.println("页面上元素无法进行单击操作");
            }
        }catch (StaleElementReferenceException e){
            System.out.println("页面元素没有附加在页面中" + Arrays.toString(e.getStackTrace()));
        }catch (NoSuchElementException e){
            System.out.println("在页面中没有找到要操作的元素" + Arrays.toString(e.getStackTrace()));
        }catch (Exception e){
            System.out.println("无法完成单击操作" + Arrays.toString(e.getStackTrace()));
        }
    }

[AutoIt上传文件]

通常情况下实现自动化上传文件,都是通过sendKeys函数直接将文件全路径传给页面空间就能完成,然而这种情况只能对Input类型的控件有效,对于非Input类型的控件可以借助AutoIt来完成

下载AutoIt

下载地址为:https://www.autoitscript.com/site/autoit/downloads/

获取定位

启动AutoIt Window Info,如图右侧窗口所示,拖动Finder Tool到你想获取信息的控件上,即可获取控件相关信息
在这里插入图片描述

编写SciTE Script

编写SciTE Script, 如图函数中的参数均是在第一步使用Finder Tool获取
在这里插入图片描述
编辑完,可以执行测试一下是否能完成上传动作,之后保存成.au3格式的文件
在这里插入图片描述

生成可执行文件

启动AutoIt的Compile Script to .exe, 选中刚才保存的.au3文件,点击Convert按钮即可生成.exe文件
在这里插入图片描述

执行上传代码示例

编写java脚本,在合适的位置调用该.exe文件完成文件的上传
在这里插入图片描述

[处理Table]

测试代码

    @Test
    public void test_Table() throws Exception {//获取表单,xpath是表单的定位
        WebElement tableElement=driver.findElement(By.xpath("//*[@id='app']/section/section/main/section/div[1]/div[3]/table"));
        //将表单的所有tr放进列表,每个tr是表单的一行,逐行遍历
        List<WebElement> rows=tableElement.findElements(By.tagName("tr"));
        for (int i = 0; i < rows.size(); i++) {
            //将表单的td放进list里,每个td是表单的一列,逐列遍历
            List<WebElement> cols=rows.get(i).findElements(By.tagName("td"));
            for (int j = 0; j < cols.size();) {
                String tdText = cols.get(j).getText();
                sleep(1000);
                System.out.println(tdText +"\t");
                //判断哪行哪列的内容包含字段"mysql01", 如果包含则进行操作
                if(tdText.contains("mysql01")){
                    System.out.println(i+1);
                    System.out.println(j+1);
                    int row = i + 1;
                    //点击mysql01所在行的下拉按钮
                    WebElement dropdown = driver.findElement(By.xpath("//*[@id='app']/section/section/main/section/div[1]/div[3]/table/tbody/tr["+row+"]/td[6]/div/div/span"));
                    dropdown.click();
                }break;
            }
        }
 
    }

实际上如果页面存在检索功能,完全可以写几步检索操作,让页面只有一条你要的数据,那么它的位置就是固定了,然后再进行操控

处理Table方法

package util;
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import java.util.List;
import java.util.NoSuchElementException;
import static util.WaitElementUtil.sleep;
 
/*
 * some method of controlling table
 *
 * @author: davieyang
 * @create: 2018-08-05 14:04
 */
public class TableUtil {
    //声明一个WebElement对象,用于存储页面的表格元素对象
    private WebElement _table;
 
    //为构造函数传入页面表格元素对象参数,调用TableUtil类的settable方法,将页面表格元素赋值给TableUtil类的_table成员变量
    public TableUtil (WebElement table){
        setTable(table);
    }
    //获取页面表格对象的方法
    public WebElement getTable(){
        return _table;
    }
    //将页面表格元素赋值给TableUtil类中_table成员变量的方法
    public void setTable(WebElement _table){
        this._table = _table;
    }
    //获取表格元素的行数,查找表格元素有几个tr元素,有几个tr元素,就可以知道表格有几行,tr数量和表格行数相一致
    public int getRowCount(){
        List<WebElement> tableRows = _table.findElements(By.tagName("tr"));
        return tableRows.size();
    }
    //获取表格元素的列数,使用get(0)从容器中取出表格第一行的元素,查找有几个“td”,td数量和列数一致
    public int getColumnCount(){
        List<WebElement> tableRows = _table.findElements(By.tagName("tr"));
        return tableRows.get(0).findElements(By.tagName("td")).size();
    }
    //获取表格中某行某列的单元格对象
    public WebElement getCell(int rowNo, int colNo)throws NoSuchElementException{
        try{
            List<WebElement> tableRows = _table.findElements(By.tagName("tr"));
            System.out.println("行总数:" + tableRows.size());
            System.out.println("行号:" + rowNo);
            WebElement currentRow = tableRows.get(rowNo - 1);
            List<WebElement> tableCols = currentRow.findElements(By.tagName("td"));
            System.out.println("列总数:" + tableCols.size());
            WebElement cell = tableCols.get(colNo-1);
            System.out.println("列号:" + colNo);
            return cell;
        }catch (NoSuchElementException e){
            throw new NoSuchElementException("没有找到相关元素");
        }
    }
    /**
     * 获得表格中某行某列的单元格中的某个页面元素对象,by参数用于定位某个表格中的页面元素,例如by.xpath("input[@type='text']")可以定义到表格中的输入框
     */
    public WebElement getWebElementInCell(int rowNo, int colNo, By by)throws NoSuchElementException{
        try{
            List<WebElement> tableRows = _table.findElements(By.tagName("tr"));
            //找到表格中的某一行,行号从0开始,例如第三行,则需要进行3-1来获取即“2”
            WebElement currentRow = tableRows.get(rowNo-1);
            List<WebElement> tableCols = currentRow.findElements(By.tagName("td"));
            //找到表格中的某一列,因为也是从0开始,所以要找到第三列,则需要进行3-1来获取即“2”
            WebElement cell = tableCols.get(colNo-1);
            return cell.findElement(by);
        }catch (NoSuchElementException e){
            throw new NoSuchElementException("没有找到相关元素");
        }
    }
 
    /**
     *
     * @param driver 浏览器驱动
     * @param row 行号
     * @param column 列号
     * @return 函数接受浏览器驱动,表格行数和列数,注意表头行,返回某个cell的值
     */
    public static String tableCell(WebDriver driver, int row, int column) {
        String text = null;
        //avoid get the head line of the table
        row=row+1;
        String xpath="//*[@id='table138']/tbody/tr["+row+"]/td["+column+"]";
        WebElement table=driver.findElement(By.xpath(xpath));
        text=table.getText();
        return text;
    }
}

[兼容性测试]

兼容性测试的思路实际上可行的只有两个,一个是分布式自动化,由一个大脑驱动若干分支,另一个就是为不同的环境编写不同的测试代码实例,然后在程序入口分别调用

/*
 * @FileName Demo: Demo
 * @author davieyang
 * @create 2018-11-06 16:01
 */
package testscript;

import org.apache.log4j.Logger;
import org.apache.log4j.xml.DOMConfigurator;
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.firefox.FirefoxDriver;
import org.openqa.selenium.ie.InternetExplorerDriver;
import org.openqa.selenium.remote.DesiredCapabilities;
import org.testng.annotations.Parameters;
import org.testng.annotations.Test;

import java.util.concurrent.TimeUnit;

import static org.testng.Assert.assertEquals;

public class Demo_Compatibility_Testing {
    static {
        //指定log4j配置文件为log4j.xml
        DOMConfigurator.configure("log4j.xml");
    }

    // 主要方法是使用 InternetExplorerDriver  FirefoxDriver  ChromeDriver 运行相同的测试脚本,
    // 将每一种Driver  的启动写成 @Test 的方法,如下所示:
    @Test
    @Parameters( { "webSite" })
    public void setUp_InternetExplorerDriver(String webSite) throws Exception {
        //.\\lib\\IEDriverServer.exe  是lib目录下的驱动
        System.setProperty("webdriver.ie.driver", ".\\lib\\IEDriverServer.exe");
        DesiredCapabilities capabilities = DesiredCapabilities.internetExplorer();
        capabilities.setCapability(InternetExplorerDriver.INTRODUCE_FLAKINESS_BY_IGNORING_SECURITY_DOMAINS,
        true);
        WebDriver driver = new InternetExplorerDriver(capabilities);
        String baseUrl = webSite;
        driver.manage().timeouts().implicitlyWait(30, TimeUnit.SECONDS);
        script(driver);
        }

    @Test
    @Parameters( { "firefox_dir", "webSite" })
    public void setUp_FirefoxDriver(String firefox_dir, String webSite)
        throws Exception {
        //firefox_dir 为本机 firefox安装目录
        System.setProperty("webdriver.firefox.bin", firefox_dir);
        WebDriver driver = new FirefoxDriver();
        String baseUrl = webSite;
        driver.manage().timeouts().implicitlyWait(30, TimeUnit.SECONDS);
        script(driver);
        }

    @Test
    @Parameters( { "webSite" })
    public void setUp_ChromeDriver(String webSite) throws Exception {
        //.\\lib\\IEDriverServer.exe  是lib目录下的驱动
        System.setProperty("webdriver.chrome.driver", "./lib/chromedriver.exe");
        WebDriver driver = new ChromeDriver();
        String baseUrl = webSite;
        driver.manage().timeouts().implicitlyWait(30, TimeUnit.SECONDS);
        script(driver);
        }
        // 对于具体的测试脚本,写成一个新的方法,每一个driver都会调用该方法,如下所示:
    private void script(WebDriver driver) throws Exception {
        try {
            String baseUrl = "http://www.baidu.com";
            Logger logger=Logger.getLogger(Demo_Compatibility_Testing.class);
            logger.info("开始");
            driver.get(baseUrl);
            driver.findElement(By.id("kw")).clear();
            driver.findElement(By.id("kw")).sendKeys("selenium");
            driver.findElement(By.id("kw")).submit();
            driver.findElement(By.linkText("下一页>")).click();
            driver.findElement(By.linkText("下一页>")).click();
            driver.findElement(By.linkText("下一页>")).click();
            assertEquals("selenium", driver.findElement(By.id("kw")).getAttribute("value"));
            logger.info("结束");
        } catch (Exception e) {
            throw e;
        } finally {
            driver.quit();
        }
    }
}



[Log4j处理日志]

Log4j是个开源项目,可以控制日志信息的输出目的地,例如控制台、文件、GUI组件等,其配置文件用来设置日志的级别,文件格式只能是XML、json、yaml或properties

配置依赖

    <!-- https://mvnrepository.com/artifact/log4j/log4j -->
    <dependency>
      <groupId>log4j</groupId>
      <artifactId>log4j</artifactId>
      <version>1.2.17</version>
    </dependency>

Log4j配置文件properties

log4j.rootLogger=info, toConsole, toFile
log4j.appender.file.encoding=UTF-8
log4j.appender.toConsole=org.apache.log4j.ConsoleAppender
log4j.appender.toConsole.Target=System.out
log4j.appender.toConsole.layout=org.apache.log4j.PatternLayout
log4j.appender.toConsole.layout.ConversionPattern=[%d{yyyy-MM-dd HH:mm:ss}] [%p] %m%n
log4j.appender.toFile=org.apache.log4j.DailyRollingFileAppender
log4j.appender.toFile.file=result/log/testlog.log
log4j.appender.toFile.append=false
log4j.appender.toFile.Threshold=info
log4j.appender.toFile.layout=org.apache.log4j.PatternLayout
log4j.appender.toFile.layout.ConversionPattern=[%d{yyyy-MM-dd HH:mm:ss}] [%p] %m%n

Log4j引用

package com.davieyang.springboot;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.apache.log4j.Logger;
import org.apache.log4j.PropertyConfigurator;


@SpringBootApplication
//@SpringBootApplication 代表将程序作为SpringBoot应用来运行
public class Application {
    static Logger logger = Logger.getLogger(Application.class.getName());
    public static void main(String[] args){
        PropertyConfigurator.configure("log4j.properties");
        // DOMConfigurator.configure("D:\\SpringBootDemo\\result\\log4j.xml");
        SpringApplication.run(Application.class, args);
        logger.debug("debug message");
        logger.info("info message");
        logger.error("error message");
        //调用run方法并传入当前Class作为参数来运行程序,同时传入main方法的args参数
    }
}

Log4j配置文件XML

<?xml version="1.0" encoding = "GB2312" ?>
<!DOCTYPE log4j:configuration SYSTEM "http://logging.apache.org/log4j/1.2/apidocs/org/apache/log4j/xml/doc-files/log4j.dtd">
<log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/" debug="true">
<appender name="fileAppender" class="org.apache.log4j.FileAppender">
<param name="Threshold" value="INFO" />
<param name="File" value="Automation.log" />
<layout class="org.apache.log4j.PatternLayout">
<param name="ConversionPattern" value="%d %-5p [%c{1}] %m %n" />
</layout>
</appender>
<root>
<level value="INFO"/>
<appender-ref ref="fileAppender"/>
</root>
</log4j:configuration>

二次封装

package util;
import org.apache.log4j.Logger;

import java.io.IOException;

public class LogUtil {
    private static Logger Log = Logger.getLogger(LogUtil.class.getName());
    //定义测试用例开始执行的打印方法,在日志中打印开始执行测试用例的信息
    public static void startTestCases(String testCaseName){
        Log.info("------------------    \"" + testCaseName + "\"开始执行   -----------------");
    }
    //定义测试用例执行完毕的打印方法,在日志中打印测试用例执行完毕的心
    public static void endTestCases(String testCaseName){
        Log.info("------------------    \"" + testCaseName + "\"执行结束   -----------------");
    }
    //定义打印info级别日志的方法
    public static void info(String message){
        Log.info(message);
    }
    //定义打印error级别日志的方法
    public static void error(String message, IOException e){
        Log.error(message);
    }
    //定义打印debug级别日志的方法
    public static void debug(String message){
        Log.debug(message);
    }
}

引用Log4j

package util;
import org.apache.log4j.xml.DOMConfigurator;
import org.openqa.selenium.*;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.firefox.FirefoxDriver;
import org.openqa.selenium.ie.InternetExplorerDriver;
import org.openqa.selenium.support.ui.Select;
import org.testng.Assert;
import org.testng.Reporter;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import static constants.Constants.MainPageandNavigation_Property;
import static constants.Constants.Path_BrowserDrivers;
import static util.LogUtil.info;

public class KeyActionsUtil {
    //声明静态的Webdriver对象,用于在此类中相关Driver的操作
    public static WebDriver driver;
    //声明存储定位表达式配置文件的ObjectMap对象
    private static GetElementUtil getElementUtil = new GetElementUtil(MainPageandNavigation_Property);
    static {
        //指定log4j配置文件为log4j.xml
        DOMConfigurator.configure("log4j.xml");
        }

    /**
     * 定义函数initBrowser
     * @param browser:字符串参数chrome/ie/xx
     * @return 并返回驱动
     */
    public static WebDriver initBrowser(String browser) {
        if(browser.equalsIgnoreCase("firefox")) {
            System.setProperty("webdriver.gecko.driver", Path_BrowserDrivers+"geckodriver.exe");
            driver = new FirefoxDriver();
            driver.manage().timeouts().implicitlyWait(30, TimeUnit.SECONDS);
            info("启动Firefox浏览器");

        }else if (browser.equalsIgnoreCase("ie")){
            System.setProperty("webdriver.ie.driver",Path_BrowserDrivers+"IEDriverServer.exe");
            driver = new InternetExplorerDriver();
            driver.manage().timeouts().implicitlyWait(30, TimeUnit.SECONDS);
            info("启动IE浏览器");
        }else {
            System.setProperty("webdriver.chrome.driver",Path_BrowserDrivers+"chromedriver.exe");
            driver = new ChromeDriver();
            driver.manage().timeouts().implicitlyWait(30, TimeUnit.SECONDS);
            info("启动Chrome浏览器");
        }
        driver.manage().window().maximize();
        info("最大化浏览器");
        return driver;
    }

    /**
     * 进入页面url
     * @param url:驱动浏览器,打开的页面url
     * @param browser:字符串参数chrome/ie/xx
     * @param timeOutInSeconds:等待时常
     */
    public static void openBrowser(String url, String browser, int timeOutInSeconds) {
        driver = initBrowser(browser);
        driver.manage().timeouts().implicitlyWait(timeOutInSeconds, TimeUnit.SECONDS);
        driver.get(url);
    }
    //定义函数navigate,用于获取浏览器要访问的链接
    public static void navigate(String url){
        driver.get(url);
        info("访问地址为"+url);
    }


    //通过从剪切板黏贴的方式,在文件上传框体的文件名输入框中输入要上传文件的路径和名称"uploadpathandname"
    public static void uploadFileName(String uploadpathandname){
        try{
            KeyBoardUtil.setAndctrlVClipboardData(uploadpathandname);
        }catch (Exception e){
            e.printStackTrace();
        }
    }
    //页面上不止一个相同功能并且xpath相同的元素,此种情况处理是将他们存储到List中,然后用索引的方式用其一
    public static void twoWay(String ElementNameInproFile){
        try {
            List<WebElement> elements = driver.findElements(getElementUtil.getLocator(ElementNameInproFile));
            elements.get(0).click();
            System.out.println("按钮被成功点击");
        }catch (Exception e){
            e.printStackTrace();
        }
    }
    /**
     * 断言文字内容
     * @param driver:浏览器驱动
     * @param assertstring:要断言的字符串
     */
    public static void assertString(WebDriver driver,String assertstring){
        try{
            Assert.assertTrue(driver.getPageSource().contains(assertstring));
            Reporter.log("成功断言关键字“"+ assertstring +"”");
        }catch (AssertionError e){
            Reporter.log("断言失败,具体失败信息为:" + e.getMessage());
            System.out.println("断言失败");
            throw e;
        }
    }
    //断言文字不存在
    public static void assertNoString(WebDriver driver, String assertstring){
        try{
            Assert.assertFalse(driver.getPageSource().contains(assertstring)); 
            info("成功断言关键字“"+ assertstring +"” + “不存在”");
        }catch (AssertionError e){
            info("断言失败,具体信息为:" + e.getMessage());
            System.out.println("断言失败");
        }
    }
}

此处除了用到了封装好的info方法,还用到了TestNG的Reporter.log("断言失败,具体失败信息为:" + e.getMessage());

配置文件详解

Appenders配置项描述
ConsoleAppender控制台,输出结果到system.out或system.err
FileAppender输出结果到指定文件,同时可以指定输出数据的格式appender=true指定追加到文件末尾
DailyRollingFileAppender每天产生一个日志文件
RollingFileAppender文件大小到达指定数值后生成新的文件
WriterAppender将日志信息以流格式发送到任意指定的地方

Level值描述
OFF关闭所有日志
FATAL致命错误
ERROR严重错误
WARN警告信息
INFO通知类一般类状态类普通信息
DEBUG调试信息
TRACE追踪信息
ALL输出所有日志

Layout配置项描述
HTMLLayout以HTML表格形式布局
PatternLayout可以灵活的指定布局模式
SimpleLayout包含日志信息的级别和信息字符串
TTCCLayout包含日志产生的时间线程类别等信息

ConversionPatter配置项描述
%m输出代码中指定的信息
%p输出优先级 DEBUG、INFO、WARN、ERROR、FATAL
%r输出自应用启动到输出该log信息耗费的毫秒数
%c输出所属的类,通常为类的全名
%t输出产生日志事件的线程名
%n输出一个回车换行符,Windows平台中为“rn”, UNIX平台为“n”
%d输入日志时间点的日期或时间,默认格式为ISO8601,也可以在其后指定格式,例如%d{yyyy MMM dd HH:mm:ss,SSS}, 输出类似于2020年8月20日3:39:00 921
%l输出日志事件的发生位置,包含类名线程以及代码中的行数

[模拟鼠标]

package util;
 
import org.openqa.selenium.By;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.interactions.Actions;
import org.openqa.selenium.WebDriver;
 
public class MouseUtil {
    /**
     * 模拟鼠标左键单击
     * @param driver
     * @param xpathExpression
     */
    public void lefClick(WebDriver driver, String xpathExpression) {
        Actions actions = new Actions(driver);
        // 鼠标左键在当前停留的位置做单击操作
        actions.click();
        // 鼠标左键点击指定的元素
        actions.click(driver.findElement(By.xpath(xpathExpression)));
    }
 
    /**
     * 模拟鼠标右键单击
     * @param driver
     * @param xpathExpression
     */
    public void rightClick(WebDriver driver, String xpathExpression) {
        Actions actions = new Actions(driver);
        // 鼠标右键在当前停留的位置做单击操作
        actions.contextClick();
        // 鼠标右键点击指定的元素
        actions.contextClick(driver.findElement(By.xpath(xpathExpression)));
    }
 
    /**
     * 模拟鼠标左键双击
     * @param driver
     * @param xpathExpression
     */
    public void doubleClick(WebDriver driver, String xpathExpression) {
        Actions actions = new Actions(driver);
        // 鼠标在当前停留的位置做双击操作
        actions.doubleClick();
        // 鼠标双击指定的元素
        actions.doubleClick(driver.findElement(By.xpath(xpathExpression)));
 
    }
 
    /**
     * 模拟鼠标拖拽
     * @param driver
     * @param source
     * @param target
     */
    public void dragAction(WebDriver driver, WebElement source, WebElement target) {
        Actions actions = new Actions(driver);
        // 鼠标拖拽动作,将 source 元素拖放到 target 元素的位置
        actions.dragAndDrop(source, target);
    }
 
    /**
     * 模拟鼠标拖拽到某坐标
     * @param driver
     * @param source
     * @param xOffset
     * @param yOffset
     */
    public void dragtoXY(WebDriver driver, WebElement source, int xOffset, int yOffset) {
        Actions actions = new Actions(driver);
        // 鼠标拖拽动作,将 source 元素拖放到 (xOffset, yOffset) 位置,其中 xOffset 为横坐标,yOffset 为纵坐标
        actions.dragAndDropBy(source, xOffset, yOffset);
 
    }
 
    /**
     * 模拟鼠标拖拽从元素A到元素B
     * @param driver
     * @param source
     * @param target
     */
    public void dragActionReleaseMouse(WebDriver driver, WebElement source, WebElement target) {
        Actions actions = new Actions(driver);
        // 鼠标拖拽动作,将 source 元素拖放到 target 元素的位置
        actions.clickAndHold(source).moveToElement(target).perform();
        actions.release();
    }
 
    /**
     * 模拟鼠标单击并不释放
     * @param driver
     * @param element
     */
    public void clickAndHole(WebDriver driver, WebElement element) {
        Actions actions = new Actions(driver);
        //action.clickAndHold();鼠标悬停在当前位置,既点击并且不释放
        // 鼠标悬停在 onElement 元素的位置
        actions.clickAndHold(element);
    }
 
    /**
     * 模拟鼠标拖拽
     * @param driver
     * @param xOffset
     * @param yOffset
     */
    public void moveToXY(WebDriver driver, int xOffset, int yOffset){
        Actions actions = new Actions(driver);
        /**将鼠标移到元素 toElement 的 (xOffset, yOffset) 位置,这里的 (xOffset, yOffset) 是以元素 toElement 的左上角为 (0,0) 开始的 (x, y) 坐标轴
         *action.moveToElement(toElement,xOffset,yOffset)
         *以鼠标当前位置或者 (0,0) 为中心开始移动到 (xOffset, yOffset) 坐标轴*/
        actions.moveByOffset(xOffset, yOffset);
        actions.release();// 释放鼠标
    }

[JavaScript实现高亮元素]

/*
 * the method of invoking js to do something
 *
 * @author davieyang
 * @create 2018-08-05 1:37
 */
package util;
import org.openqa.selenium.*;
import java.util.Arrays;

public class JavaScriptToDo {
    /**
     *
     * @param driver 浏览器驱动
     * @param element 页面元素对象
     */
    public static void highLightElement(WebDriver driver, WebElement element){
        JavascriptExecutor js = (JavascriptExecutor) driver;
        /*调用js将传入参数的页面元素对象的背景颜色和边框颜色分别设定为黄色和红色*/
        js.executeScript("arguments[0].setAttribute('style', arguments[1]);", element, "background: yellow; border:2px solid red;");
    }
}

[智能等待]

package util;
import org.openqa.selenium.By;
import org.openqa.selenium.TimeoutException;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.ui.ExpectedCondition;
import org.openqa.selenium.support.ui.ExpectedConditions;
import org.openqa.selenium.support.ui.WebDriverWait;
import org.testng.Assert;
import org.testng.Reporter;

import static util.LogUtil.info;

public class WaitElementUtil {
    //public WebDriver driver = null;
    //private int timeOutInSeconds =10;
    /**用于测试执行过程中暂停程序执行的等待方法*/
    public static void sleep(long millsecond){
        try{
            Thread.sleep(millsecond);
            Reporter.log("强制等待"+ millsecond + "毫秒...");
        }catch (Exception e){
            e.printStackTrace();
        }
    }
    /**
     * 同上
     * @param driver
     * @param by
     * @param timeOutInSeconds
     */
    public static void waitWebElementPresence(WebDriver driver, By by, int timeOutInSeconds){
        WebDriverWait wait = new WebDriverWait(driver, timeOutInSeconds);
        WebElement element = wait.until(ExpectedConditions.presenceOfElementLocated(by));
    }

    /**
     * 显示等待页面元素可被点击状态,参数为页面元素xpath定位表达式
     * @param driver
     * @param by
     * @param timeOutInSeconds
     */
    public static void waitWebElementToBeClickable(WebDriver driver, By by,  int timeOutInSeconds){
        WebDriverWait waitElement = new WebDriverWait(driver, timeOutInSeconds);
        WebElement element = waitElement.until(ExpectedConditions.elementToBeClickable(by));
    }

    /**
     * 显示等待页面元素被选中状态,参数为页面元素xpath定位表达式
     * @param driver
     * @param xpathExpression
     * @param timeOutInSeconds
     */
    public static void waitWebElementToBeSelected(WebDriver driver, String xpathExpression, int timeOutInSeconds){
        WebDriverWait waitElement = new WebDriverWait(driver, timeOutInSeconds);
        Boolean element = waitElement.until(ExpectedConditions.elementToBeSelected(By.xpath(xpathExpression)));
    }

    /**
     * 显示等待页面元素出现,参数为页面元素xpath定位表达式
     * @param driver
     * @param xpathExpression
     * @param text
     * @param timeOutInSeconds
     */
    public static void waitWebElementToBePresentInElementValue(WebDriver driver, String xpathExpression, String text, int timeOutInSeconds){
        WebDriverWait waitElement = new WebDriverWait(driver, timeOutInSeconds);
        Boolean element = waitElement.until(ExpectedConditions.textToBePresentInElementValue(By.xpath(xpathExpression), text));
    }

    /**
     * 显示等待页面标题包含"title"元素出现,参数为页面元素xpath定位表达式
     * @param driver
     * @param title
     * @param timeOutInSeconds
     */
    public static void waitWebElementTitleContains(WebDriver driver, String title, int timeOutInSeconds){
        WebDriverWait waitElement = new WebDriverWait(driver, timeOutInSeconds);
        Boolean element = waitElement.until(ExpectedConditions.titleContains(title));
    }
    /**
     * 显示等待页面元素加载
     * @param by:等待元素elementName加载完成
     * @param timeOutInSeconds:等待时常
     * @throws Exception
     */
    public static void waitElement(WebDriver driver, By by, int timeOutInSeconds) throws Exception {
        try{
            waitWebElementPresence(driver, by, timeOutInSeconds);
            info("显示等待页面元素出现成功, 页面元素是" + by);
        }catch (Exception e){
            info("显示等待页面元素时出现异常,异常信息为:" + e.getMessage());
            e.printStackTrace();
        }
    }

    /**
     * 显示等待元素加载
     * @param driver:浏览器驱动
     * @param timeOut:等待时常
     * @param by:元素定位
     */
    public static void intelligentWait(WebDriver driver,int timeOut, final By by) {
        try {
            (new WebDriverWait(driver, timeOut)).until(new ExpectedCondition<Boolean>() {
                public Boolean apply(WebDriver driver) {
                    WebElement element = driver.findElement(by);
                    return element.isDisplayed();
                }
            });
        } catch (TimeoutException e) {
            Assert.fail("超时L !! " + timeOut + " 秒之后还没找到元素 [" + by + "]", e);
        }
    }
}

[截图方法]

package util;
import org.apache.commons.io.FileUtils;
import org.openqa.selenium.OutputType;
import org.openqa.selenium.TakesScreenshot;
import org.openqa.selenium.WebDriver;
import java.io.File;
import java.io.IOException;
import java.util.Date;

public class ScreenShotUtil {
    public WebDriver driver;

    public ScreenShotUtil(WebDriver driver) {
        this.driver = driver;
    }

    /**截图并存储到screenPath
     *
     * @param driver
     * @param screenPath
     */
    private static void takeScreenshot(WebDriver driver, String screenPath) {
        try {
            File scrFile = ((TakesScreenshot) driver).getScreenshotAs(OutputType.FILE);
            FileUtils.copyFile(scrFile, new File(screenPath));
        } catch (IOException e) {
            System.out.println("Screen shot error: " + screenPath);
        }
    }

    /**截图并存储到固定目录下test-output/snapshot中
     *
     * @param driver 浏览器驱动
     */
    public void takeScreenshot(WebDriver driver) {
        String screenName = String.valueOf(new Date().getTime()) + ".jpg";
        File dir = new File("test-output/snapshot");
        if (!dir.exists())
            dir.mkdirs();
        String screenPath = dir.getAbsolutePath() + "/" + screenName;
        this.takeScreenshot(driver, screenPath);
    }
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/263625.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

简单了解一下当前火热的大数据 -- Kylin

神兽麒麟 一、Apache Kylin 是什么&#xff1f;二、Kylin架构结语 一、Apache Kylin 是什么&#xff1f; 由eBay公司中国团队研发&#xff0c;是一个免费开源的OLAP多维数据分析引擎优点 超快的响应速度&#xff0c;亚秒级支持超大数据集&#xff08;PB以上&#xff0c;千亿记…

这样使用云渲染又快又省钱

我们都知道使用云渲染是要钱的&#xff0c;而且渲染的时间越久&#xff0c;需要的渲染费越多&#xff0c;哪么如何又快又省钱的拿到效果图呢&#xff1f;用炫云的渲染质量&#xff0c;保准让你使用云渲染渲染效果图又快又省钱。 我们使用炫云的时候&#xff0c;根据自己的需求…

互联网加竞赛 python图像检索系统设计与实现

0 前言 &#x1f525; 优质竞赛项目系列&#xff0c;今天要分享的是 &#x1f6a9; python图像检索系统设计与实现 &#x1f947;学长这里给一个题目综合评分(每项满分5分) 难度系数&#xff1a;3分工作量&#xff1a;3分创新点&#xff1a;4分 该项目较为新颖&#xff0c…

PIC单片机项目(7)——基于PIC16F877A的智能灯光设计

1.功能设计 使用PIC16F877A单片机&#xff0c;检测环境关照&#xff0c;当光照比阈值低的时候&#xff0c;开灯。光照阈值可以通过按键进行设置&#xff0c;同时阈值可以保存在EEPROM中&#xff0c;断电不丢失。使用LCD1602进行显示&#xff0c;第一行显示测到的实时光照强度&a…

BUUCTF-Linux Labs

Linux Labs 根据题目给出的内容&#xff0c;在kali中连接靶机&#xff0c;输入密码进入命令行模式 ls发现什么都没有&#xff0c;有可能进入到了一个空文件夹 cd .. 切换到上一层目录&#xff0c;ls查看此目录下的内容&#xff0c;发现flag.txt文件&#xff0c;查看文件是flag …

听GPT 讲Rust源代码--src/tools(22)

File: rust/src/tools/tidy/src/lib.rs rust/src/tools/tidy/src/lib.rs是Rust编译器源代码中tidy工具的实现文件之一。tidy工具是Rust项目中的一项静态检查工具&#xff0c;用于确保代码质量和一致性。 tidy工具主要有以下几个作用&#xff1a; 格式化代码&#xff1a;tidy工具…

Lang–Kobayashi方程实现混沌python实现混沌序列图像

Lang–Kobayashi方程描述为&#xff1a; 第一部分&#xff08;Drive laser&#xff09;是描述的驱动激光器&#xff0c;第二部分&#xff08;Response laser&#xff09;描述的是响应激光器。实验结构图如下&#xff1a; 虚线框表示响应激光器中的闭环配置。开环中响应激光器无…

beaglebone black狗板,交叉编译Qt5(eglfs)

1. 下载buildroot-2023.023.7版本 make beaglebone_qt5_defconfig 然后编译&#xff0c;出现错误大多数是因为下载不了包&#xff0c;用bing搜索找到放到对应的dl目录下&#xff0c;最终完成编译。 备注&#xff1a;用系统默认配置&#xff0c;不要参考网上的&#xff0c;网…

天津web前端就业培训班,Web机构选择重点

Web前端培训是目前非常热门的培训领域之一。很多领域都会涉及到web前端开发&#xff0c;比如传统互联网、房地产、金融、游戏、影视传媒等行业都需要web前端技术的支持。越来越多的企业和个人也需要建立自己的网站和移动应用程序&#xff0c;因此市场对web前端工程师的需求是非…

Docker 学习总结(80)—— 轻松驾驭容器,玩转 LazyDocker

前言 LazyDocker 是一个用户友好的命令行工具,简化了 Docker 的管理。它能够通过单一命令执行常见的 Docker 任务,如启动、停止、重启和移除容器。LazyDocker 还能轻松查看日志、清理未使用的容器和镜像,并自定义指标。 简绍 LazyDocker 是一个用户友好的 CLI 工具,可以轻…

Linux基本内容学习

Linux 命令 文件命令 命令释义语法格式lslist&#xff0c;用于显示目录中文件及其属性信息ls [参数名] [文件名]cdchange directory&#xff0c;用于更改当前所处的工作目录&#xff0c;路径可以是绝对路径&#xff0c;也可以是相对路径&#xff0c;若省略不写则会跳转至当前…

使用GitZip下载GitHub指定文件

目录 一、GitZip二、安装GitZip三、链接GitHub四、检验是否安装成功五、总结 一、GitZip GitZip是一个非常实用的浏览器插件&#xff0c;它主要有以下几个优点&#xff1a; 下载指定文件&#xff1a;在我们浏览Github时&#xff0c;如果只想下载某个子目录的内容&#xff0c;…

【爬虫软件】孔夫子二手书采集

项目演示 孔网爬取图书信息 目录结构 [ |-- api-ms-win-core-synch-l1-2-0.dll, |-- api-ms-win-core-sysinfo-l1-1-0.dll, |-- api-ms-win-core-timezone-l1-1-0.dll, |-- api-ms-win-core-util-l1-1-0.dll, |-- api-ms-win-crt-conio-l1-1-0.dll, |-- api…

STL中优先队列(堆)的详解

文章目录 priority_queue的基本介绍堆(heap)堆的概念与结构 priority_queue 的介绍与使用 priority_queue的基本介绍 这个priority_queue翻译成中文就是优先级队列&#xff0c;但其实我们很难去一眼看出他的意思到底是什么&#xff0c;他的逻辑结构实际上类似于数据结构中的堆…

王美莲(瑞美)在博鳌乡村振兴产业发展大会荣获“乡村振兴带头人”殊荣

近日,博鳌乡村振兴产业发展大会2023年会,在博鳌亚洲论坛国际会议中心隆重召开。本届大会由中国乡村发展协会指导,中国民族贸易促进会、博鳌乡村振兴产业发展大会组委会主办,深圳市益米播科技有限公司承办。 右:原文化部副部长、国家博物馆首任馆长潘震宙 左:广州市越秀区大塘…

电容内容介绍

0 Preface/Foreword 电容&#xff0c;Capacitance&#xff0c;i.e. 电容量&#xff0c;指在给定电位差下自由电荷的储存量&#xff0c;符号为C&#xff0c;单位为F&#xff08;法拉&#xff09;。 电容&#xff0c;指容纳电荷的能力。任何静电场都是由许多电容组成&#xff0…

HTML---盒子模型

文章目录 前言一、pandas是什么&#xff1f;二、使用步骤 1.引入库2.读入数据总结 一.盒子模型概述 HTML中的盒子模型是一种用于描述和布局元素的概念。每个 HTML 元素都可以被表示为一个矩形的盒子&#xff0c;这个盒子包括四个部分&#xff1a;内容区域、内边距、边框和外边距…

图灵日记之java奇妙历险记--数据类型与变量运算符

目录 数据类型与变量字面常量数据类型变量语法格式整型变量浮点型变量字符型变量希尔型变量类型转换自动类型转换(隐式)强制类型转换(显式) 类型提升不同数据类型的运算小于4字节数据类型的运算 字符串类型 运算符算术运算符关系运算符逻辑运算符逻辑与&&逻辑或||逻辑非…

SpringIOC之MethodBasedEvaluationContext

博主介绍&#xff1a;✌全网粉丝5W&#xff0c;全栈开发工程师&#xff0c;从事多年软件开发&#xff0c;在大厂呆过。持有软件中级、六级等证书。可提供微服务项目搭建与毕业项目实战&#xff0c;博主也曾写过优秀论文&#xff0c;查重率极低&#xff0c;在这方面有丰富的经验…

MyBatis的增删改查(CRUD)

目录 查询 1.单个参数绑定 2.序号参数绑定 3.注解参数绑定&#xff08;推荐&#xff09; 4.对象参数绑定&#xff08;推荐&#xff09; 5.Map参数绑定 6.模糊查询 7.sql注入 8.聚合函数查询 删除 修改 添加&#xff08;主键回填&#xff09; 数据库 程序结构 查询 …