SpringBoot集成mybatis以及自動化測試代碼實現


Mybatis和logback的應用配置

  • 1、在module的pom.xml文件中,加載springboot和swagger、lombok、fastjson、mysql、mybatis包
  • 2、在resources中添加配置:
  • 配置文件有兩種,一種是properties,另一種是yaml,這里使用yaml
  • yaml配置與properties一樣,只是格式不同,內容則類似。
  • 3、在配置文件application.yml中,編寫MySQL的連接配置(通過url連接數據庫course)

server:
  port: 8888         # 程序端口

logging:
  path: logs         # 在項目根路徑下
  file: mylog.log


spring:
  application:
    name: myTest       # 程序名
  datasource:
    driver-class-name: com.mysql.jdbc.Driver
    url: jdbc:mysql://localhost:3306/course
    username: root
    password: root

mybatis:
  type-aliases-package: com.course.model       #用mybatis時,需要用到的一些包,做映射
  mapper-locations:                            #用來寫SQL的
    - mapper/*                                 #指加載resource/mapper路徑下,所有的XML文件
  • 4、在resources下,創建日志配置文件logback.xml(含日志回滾),如下

<?xml version="1.0" encoding="UTF-8"?>
<configuration>

    <include resource="org/springframework/boot/logging/logback/defaults.xml"/>
    <property name="FILE_LOG_PATTERN" value="%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{80} - %msg%n"/>
    <property name="LOG_PATH" value="${LOG_PATH:-${LOG_TEMP:-${java.io.tmpdir:-/tmp}}}"/>
    <appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <!--此處加載的是application.yml文件里的log中的path和file值-->
        <file>${LOG_PATH}/${LOG_FILE}</file>
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <fileNamePattern>${LOG_PATH}/${LOG_FILE}.%d{yyyy-MM-dd}</fileNamePattern>
        </rollingPolicy>
        <encoder charset="UTF-8">
            <pattern>${FILE_LOG_PATTERN}</pattern>
        </encoder>
    </appender>


    <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
        <encoder>
            <pattern>${FILE_LOG_PATTERN}</pattern>
        </encoder>
    </appender>


    <appender name="CRAWLER_LOG" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <file>${LOG_PATH}/event.log</file>
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <fileNamePattern>${LOG_PATH}/event.%d{yyyy-MM-dd}.log</fileNamePattern>
            <maxHistory>30</maxHistory>
        </rollingPolicy>
        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
            <pattern>%msg%n</pattern>
        </encoder>
    </appender>


    <logger name="com.business.intelligence.util.CrawlerLogger" level="INFO" additivity="false">
        <appender-ref ref="CRAWLER_LOG"/>
    </logger>

    <root level="INFO">
        <appender-ref ref="STDOUT"/>
        <appender-ref ref="FILE"/>
    </root>


</configuration>
  • 5、在resources下,創建mybatis配置文件mybatis-config.xml,如下

<?xml version="1.0" encoding="UTF-8" ?>
<!--
       Copyright 2015-2016 the original author or authors.
       Licensed under the Apache License, Version 2.0 (the "License");
       you may not use this file except in compliance with the License.
       You may obtain a copy of the License at
          http://www.apache.org/licenses/LICENSE-2.0
       Unless required by applicable law or agreed to in writing, software
       distributed under the License is distributed on an "AS IS" BASIS,
       WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
       See the License for the specific language governing permissions and
       limitations under the License.
-->
<!--這里是引用的模板-->
<!DOCTYPE configuration
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-config.dtd">

<!--這里是關鍵配置,第一個是需要映射的包,第二個是需要映射(加載)的XML文件-->
<configuration>
	<!--簡化類命名空間,簡化之后我們后續引用只需要寫類名即可-->
    <typeAliases>
        <package name="com.course.model"/>
    </typeAliases>
	<!--mapper映射器,注冊一個sql映射;其中resource、url是以配置文件的方式來注冊,class是以接口的方式-->
	<!--resource:引用類路徑下的sql映射文件-->
    <mappers>
        <mapper resource="mapper/mysql.xml"/>

    </mappers>
</configuration>

使用mybatis+SpringBoot完成第一個查詢demo

  • 1、在resources下創建一個文件夾mapper,然后創建mysql.xml(存儲mybatis的SQL語句的配置文件),在mysql.xml里編寫需要執行的sql語句

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!--namespace是命名空間-->
<mapper namespace="com.course">
    <!--執行SQL時,需要用到此id來定位SQL語句;resultType是指運行SQL語句后,返回結果的數據類型;標簽里面是要執行的SQL語句-->
    <select id="getUserCount" resultType="Integer">
        select count(*) from user;

    </select>

</mapper>
  • 2、在Java下新建com.course.controller包,然后在該包下新建demo.java類,如下

package com.course.controller;

import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;

import lombok.extern.log4j.Log4j2;
import org.mybatis.spring.SqlSessionTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

@Log4j2     //日志注解,用於寫日志,是對.Log4j的優化
@RestController
@Api(value = "v1",description = "這是我的第一個版本的demo")     //這里的value值需與RequestMapping的值一致,因這里是后者的一個說明,這里表示對v1請求的說明
@RequestMapping("v1")    //表示根目錄為v1,后續的接口路徑都需要先加上該根目錄
public class Demo {

    //首先創建一個執行sql語句的對象template

    @Autowired      //該標簽是指啟動即加載,即將Demo類啟動時,就自動加載了template對象
    private SqlSessionTemplate template;

    @RequestMapping(value = "/getUserCount",method = RequestMethod.GET)     //注明請求路徑和請求方法
    @ApiOperation(value = "可以獲取到用戶數",httpMethod = "GET")           //表明該接口為get接口,以及它的作用
    public int getUserCount(){
        return template.selectOne("getUserCount");    //該請求的響應結果,即通過執行SQL語句后,把結果返回,通過id定位到需執行的sql
    }                                                             //selectOne表執行一條查詢,getUserCount即mysql.xml中的select標簽的id值

}
  • 3、在包com.course下新建一個啟動程序Application.java ,
    該啟動程序與之前的不同,之前的寫法需要指定掃描某個包,而這里的寫法則不需要指定掃描某個包,這種寫法是通用的,可以直接拿到其他的地方執行,而不需做改動。

package com.course;
//通用型入口啟動程序寫法
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.scheduling.annotation.EnableScheduling;

import javax.annotation.PreDestroy;

@EnableScheduling
@SpringBootApplication
public class Application {

    private static ConfigurableApplicationContext context;
    //啟動程序
    public static void main(String[] args){
       Application.context = SpringApplication.run(Application.class,args);
    }

    //退出程序
    @PreDestroy
    public void close(){
        Application.context.close();
    }
}
  • 4、執行入口程序后,調用接口結果如下:

使用mybaits實現數據的更新和刪除

  • user.java

package com.course.model;

import lombok.Data;

@Data
public class User {
    private int id;
    private String name;
    private String sex;
    private int age;

}
  • Demo.java

package com.course.controller;

import com.course.model.User;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;

import lombok.extern.log4j.Log4j2;
import org.mybatis.spring.SqlSessionTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

@Log4j2     //日志注解,用於寫日志,是對.Log4j的優化
@RestController
@Api(value = "v1",description = "這是我的第一個版本的demo")     //這里的value值需與RequestMapping的值一致,因這里是后者的一個說明,這里表示對v1請求的說明
@RequestMapping("v1")    //表示根目錄為v1,后續的接口路徑都需要先加上該根目錄
public class Demo {

    //首先創建一個執行sql語句的對象template

    @Autowired      //該標簽是指啟動即加載,即將Demo類啟動時,就自動加載了template對象
    private SqlSessionTemplate template;

    @RequestMapping(value = "/getUserCount",method = RequestMethod.GET)     //注明請求路徑和請求方法
    @ApiOperation(value = "可以獲取到用戶數",httpMethod = "GET")           //表明該接口為get接口,以及它的作用
    public int getUserCount(){
        return template.selectOne("getUserCount");    //該請求的響應結果,即通過執行SQL語句后,把結果返回,通過id定位到需執行的sql
    }                                                             //selectOne表執行一條查詢,getUserCount即mysql.xml中的select標簽的id值

    //插入數據的接口請求
    @RequestMapping(value = "/addUser",method = RequestMethod.POST)
    public int addUser(@RequestBody User user){
        //通過id定位到sql語句,並傳入該sql語句所需的參數user對象
        int result = template.insert("addUser",user);    //返回的結果是插入的數據條數,整型;Alt+enter可看到返回值類型
        return result;
    }

    //更新數據庫請求
    @RequestMapping(value = "/updateUser",method = RequestMethod.POST)
    public int updateUser(@RequestBody User user){
        return  template.update("updateUser",user);
    }

    //刪除請求,此時只需知道刪除條件的值,不需要知道user類里的成員,因而這里直接定義一個參數即可
    @RequestMapping(value = "/deleteUser",method = RequestMethod.GET)
    public int delUser(@RequestParam int id){
        return template.delete("deleteUser",id);
    }

}
  • mysql.xml

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!--namespace是命名空間-->
<mapper namespace="com.course">
    <!--執行SQL時,需要用到此id來定位SQL語句;resultType是指運行SQL語句后,返回結果的數據類型;標簽里面是要執行的SQL語句-->
    <select id="getUserCount" resultType="Integer">
        select count(*) from user;
    </select>

<!--通過id定位的插入語句,參數類型為User類型,插入的值對應User類里的成員,參數類型需寫到具體的包直到類,否則會定位不到該參數引用的類;
這里的變量值#{id}等與User里的成員一致-->
    <insert id="addUser" parameterType="com.course.model.User">
        insert into user(id,name,age,sex)
        values(#{id},#{name},#{age},#{sex})
    </insert>

    <!--通過id定位到更新的sql語句,后面是入參類型,這里是User類-->
    <update id="updateUser" parameterType="com.course.model.User">
        update user set name=#{name},age=#{age}
        where id=#{id}
    </update>

    <!--這里的入參類型不同,為整型,因為刪除條件中只需要某個字段的值即可,這里的#{id}是個普通參數,從另外的執行類中傳入-->
    <delete id="deleteUser" parameterType="Integer">
        delete from user where id = #{id}
    </delete>

</mapper>

跨類依賴實現

跨類依賴在類中的實現1

  • 在類上面,加上@Component的注解,該類會被作為普通組件加入bean配置中,程序運行時,會優先初始化運行該類。
  • 在有依賴關系的類下,加入@Autowired注解,用來給指定的字段或方法注入所需的外部資源。這里在該注解下申明了一個LoginTest對象,表明該類是引用外部的類,后續即可使用該對象方法

跨類依賴在類中的實現2(通過XML文件實現)

  • 1、對各個測試方法進行分組

@Test(groups = "loginTrue",description = "用戶成功登陸接口")
public void loginTrue() throws IOException {
  • 2、在XML執行文件如:testng.xml中,寫上它們之間的依賴關系

<?xml version="1.0" encoding="UTF-8" ?>

<suite name="用戶管理系統測試套件">

    <test name="用戶管理系統測試用例">
        <groups>
            <dependencies>
                <group name ="addUser" depends-on="loginTrue" />
            </dependencies>
        </groups>
        <classes>
            <class name="com.course.cases.LoginTest">
                <methods>
                    <include name="loginTrue"/>
                    <include name="loginFalse"/>
                </methods>
            </class>
            <class name="com.course.cases.AddUserTest">
            <methods>
            <include name="addUser"/>
            </methods>
            </class>
        </classes>
    </test>

    <listeners>
        <listener class-name="com.course.config.ExtentTestNGIReporterListener" />
    </listeners>

</suite>
  • 該文件表明,用戶管理系統的測試用例,包含addUser和loginTrue測試組,且addUser測試組的執行依賴於loginTrue測試組,該測試用例下,包含兩個測試類,分別是addUserTest和LoginTest,其中LoginTest包含兩個測試方法(本次需要執行的),分別是loginTrue和loginFalse。

封裝SQLsession 用於簡化數據庫操作

  • DatabaseUtil.java 如下(SQLsession是屬於mybatis的方法)

package com.course.utils;

import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;

import java.io.IOException;
import java.io.Reader;

public class DatabaseUtil {
    //工具類一般用靜態方法,方便直接引用。這里方法的數據類型是SqlSession類
    public static SqlSession getSqlSession() throws IOException {
        //獲取配置的資源文件,即加載xml的配置文件,注:這里使用的是org.apache.ibatis.io的類包
        Reader reader = Resources.getResourceAsReader("databaseConfig.xml");
        //得到SqlSessionFactory,使用類加載器加載上面獲取到的xml文件,即將上面的文件build出來
        SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(reader);
        //創建sqlSession對象,這個對象就能夠用於執行配置文件中的sql語句了,true:自動提交事務,false:手動提交,不填則默認false
        SqlSession sqlSession = factory.openSession(true);
        //返回sqlSession,后續引用即可通過getSqlSession.sql語句來執行了
        return sqlSession;
    }
}

接口代碼開發

  1. 新建model,並引用相關依賴包
  2. 在resource下新建相關基礎配置文件
  3. Swagger默認配置文件:application.yml
  4. 日志配置文件:logback.xml
  5. Mybatis的配置文件:mybatis-config.xml
  6. mapper下放存儲操作數據庫sql語句的配置文件:mysql.xml
  7. 編寫啟動類:Application.java
  8. 分層:
  9. 新建model層,用於存放數據類型類,比如User.java
  10. 配置層config,存放程序配置類,如SwaggerConfig.java,存放需在swagger上發布的接口方法、路徑等配置
  11. 控制層 controller,存放執行類,如入口執行類UserManager.java,里面存放控制本程序運行的具體業務邏輯方法。

相關代碼如下:

  • User.java

package com.course.model;

import lombok.Data;

@Data
public class User {
    private int id;
    private String userName;
    private String password;
    private int age;
    private String sex;
    private int permission;
    private int isDelete;

}
  • mysql.xml

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">

<mapper namespace="com.course">

    <!--登陸接口sql-->
    <select id="login" parameterType="com.course.model.User" resultType="Integer">

        select count(*) from user
        where userName=#{userName}
        and password=#{password}
    </select>

    <!--添加用戶接口-->
    <insert id="addUser" parameterType="com.course.model.User">
        insert into
        user (userName,password,sex,age,permission,isDelete)
        values (#{userName},#{password},#{sex},#{age},#{permission},#{isDelete});
    </insert>

    <!--獲取用戶信息sql--><!--多個不定條件查詢的寫法,此時不過存入什么字段,以下的sql語句都有效-->
    <!--動態sql的trim標簽,如果prefix有值,就在第一個匹配上的子標簽sql語句的最先面加上prefix的值,
    前部處理:如果prefixOverrides有元素,拿該元素去匹配第一個子標簽sql語句,若匹配上,就刪掉sql語句的匹配部分(前面)
    尾部處理:如果suffixOverrides有元素,拿該元素去匹配第一個子標簽sql語句,若匹配上,就刪掉sql語句的匹配部分(后面)-->
    <select id="getUserInfo" parameterType="com.course.model.User" resultType="com.course.model.User">
        select * from user
        <trim prefix="WHERE" prefixOverrides="and">
            <!--如果引用該sql語句的測試程序中,符合標簽里的條件,則取標簽中的值-->
            <if test="null != id and '' !=id">
                AND id=#{id}
            </if>
            <if test="null != userName and '' !=userName">
                AND userName=#{userName}
            </if>
            <if test="null != password and '' !=password">
                AND password=#{password}
            </if>
            <if test="null != sex and '' !=sex">
                AND sex=#{sex}
            </if>
            <if test="null != age and '' !=age">
                AND age=#{age}
            </if>
            <if test="null != permission and '' !=permission">
                AND permission=#{permission}
            </if>
            <if test="null != isDelete and '' !=isDelete">
                AND isDelete=#{isDelete}
            </if>
        </trim>
    </select>

    <!--更新/刪除用戶信息動作-->
    <update id="updateUserInfo" parameterType="com.course.model.User">
        update user
        <trim prefix="SET" suffixOverrides=",">
            <if test="null != userName and '' !=userName">
                userName=#{userName},
            </if>
            <if test="null != sex and '' !=sex">
                sex=#{sex},
            </if>
            <if test="null != age and '' !=age">
                age=#{age},
            </if>
            <if test="null != permission and '' !=permission">
                permission=#{permission},
            </if>
            <if test="null != isDelete and '' !=isDelete">
                isDelete=#{isDelete},
            </if>
        </trim>
        where id = #{id}
    </update>

</mapper>
  • SwaggerConfig.java

package com.course.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import springfox.documentation.builders.ApiInfoBuilder;
import springfox.documentation.builders.PathSelectors;
import springfox.documentation.service.ApiInfo;
import springfox.documentation.service.Contact;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.annotations.EnableSwagger2;

//Configuration和EnableSwagger2這兩個注解標簽用於自動加載swagger的配置文件
@Configuration
@EnableSwagger2
public class SwaggerConfig {
    @Bean
    //固定寫法,方法名api自定義
    public Docket api(){
        return new Docket(DocumentationType.SWAGGER_2)
                //括號里加載的是下面創建的apiInfo方法
                .apiInfo(apiInfo())
                //配置整個的訪問路徑,這里為根路徑
                .pathMapping("/")
                //選擇上前面的目錄,根路徑
                .select()
                //路徑選擇器,正則配置controller下的方法,這里選擇根目錄下的所有方法
                .paths(PathSelectors.regex("/.*"))
                //build下該文件
                .build();
    }

    private ApiInfo apiInfo(){
        //swagger界面標題,聯系人(含姓名,鏈接,郵箱),描述,該應用本次發布的版本,最后build這個文件
        return new ApiInfoBuilder().title("我的接口文檔")
                .contact(new Contact("junjun","http://test.com","test168test@126.com"))
                .description("this is UserManager service API")
                .version("1.0.0.0")
                .build();

    }
}
  • UserManager.java

package com.course.controller;

import com.course.model.User;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.log4j.Log4j2;
import org.mybatis.spring.SqlSessionTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.List;
import java.util.Objects;

@Log4j2     //日志注解,用於寫日志,是對.Log4j的優化
@RestController
@Api(value = "v1",description = "用戶管理系統")
@RequestMapping("v1")
public class UserManager {

    //首先獲取一個執行sql語句的對象

    @Autowired
    private SqlSessionTemplate template;

    @ApiOperation(value = "登陸接口",httpMethod = "POST")
    @RequestMapping(value = "/login",method = RequestMethod.POST)
    public Boolean login(HttpServletResponse response, @RequestBody User user){
        int i  = template.selectOne("login",user);
        log.info("查看到的結果是"+i);
        if(i==1){
            log.info("登錄的用戶是:"+user.getUserName());
            Cookie cookie = new Cookie("login","true");
            response.addCookie(cookie);
            return true;
        }
        return false;
    }

    @ApiOperation(value = "添加用戶接口",httpMethod = "POST")
    @RequestMapping(value = "/addUser",method = RequestMethod.POST)
    public boolean addUser(HttpServletRequest request, @RequestBody User user){
        Boolean x = verifyCookies(request);
        int result = 0;
        if(x ==true){
            result = template.insert("addUser",user);
        }
        if(result>0){
            log.info("添加用戶的數量是:"+result);
            return true;
        }
        return false;     //其他情況(即不符合上面兩個條件的),返回此結果
    }

    @ApiOperation(value = "獲取用戶(列表)信息接口",httpMethod = "POST")
    @RequestMapping(value = "/getUserInfo",method = RequestMethod.POST)
    public List<User> getUserInfo(HttpServletRequest request, @RequestBody User user){
        Boolean x = verifyCookies(request);
        if(x==true){
            List<User> users = template.selectList("getUserInfo",user);
            log.info("getUserInfo獲取到的用戶數量是" +users.size());
            return users;     //返回查詢到的具體結果信息
        }else {
            return null;
        }
    }

    @ApiOperation(value = "更新/刪除用戶接口",httpMethod = "POST")
    @RequestMapping(value = "/updateUserInfo",method = RequestMethod.POST)
    public int updateUser(HttpServletRequest request,@RequestBody User user){
        Boolean x = verifyCookies(request);
        int i = 0;
        if(x==true) {
            i = template.update("updateUserInfo", user);
        }
        log.info("更新數據的條目數為:" + i);
        return i;

    }

    private Boolean verifyCookies(HttpServletRequest request) {
        Cookie[] cookies = request.getCookies();
        if(Objects.isNull(cookies)){
            log.info("cookies為空");
            return false;       //執行了return后,表明該方法已結束,后續的語句不會再被執行
        }
        for(Cookie cookie : cookies){
            if(cookie.getName().equals("login") &&
                    cookie.getValue().equals("true")){
                log.info("cookies驗證通過");
                return true;
            }
        }
        return false;       //若前面的條件都不滿足,則該方法直接返回此結果,結束該方法
    }

}
  • 發布后,多個參數的請求如下:

自動化測試代碼二次開發

  • GetUserInfoTest.java

package com.course.cases;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.course.config.TestConfig;
import com.course.model.GetUserInfoCase;
import com.course.model.User;
import com.course.utils.DatabaseUtil;
import org.apache.http.HttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.util.EntityUtils;
import org.apache.ibatis.session.SqlSession;
import org.testng.Assert;
import org.testng.annotations.Test;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

public class GetUserInfoTest {

    //@Test(dependsOnGroups="loginTrue",description = "獲取userId為1的用戶信息")
    @Test(groups = "getUserInfo",description = "獲取userId為1的用戶信息")
    public void getUserInfo() throws IOException, InterruptedException {
        SqlSession session = DatabaseUtil.getSqlSession();
        GetUserInfoCase getUserInfoCase = session.selectOne("getUserInfoCase",1);
        System.out.println(getUserInfoCase.toString());
        System.out.println(TestConfig.getUserInfoUrl);

        //執行接口測試
        JSONArray resultJson = getJsonResult(getUserInfoCase);

        Thread.sleep(2000);
        //傳入的getUserInfoCase只有userId,即從user表取出userId的用戶信息,獲取到的是字典
        User user = session.selectOne(getUserInfoCase.getExpected(),getUserInfoCase);
        System.out.println("自己查庫獲取用戶信息:"+user.toString());

        //把字典轉成字典列表的形式,否則無法轉成json數組,以下申明了一個列表
/*      List是一個接口,而ArrayList是List接口的一個實現類。創建了一個ArrayList實現類的對象后把它上溯到了List接口。此時它就是一個List對象了,它有些ArrayList類具有的,
        但是List接口沒有的屬性和方法,它就不能再用了。而ArrayList list=newArrayList();創建一對象則保留了ArrayList的所有屬性和方法。*/
        List userList = new ArrayList();
        //將user這個json對象添加到列表中,形成json列表。不寫下標,則表示在列表的末尾追加元素
        userList.add(user);

        JSONArray jsonArray= JSONArray.parseArray(JSON.toJSONString(userList));
        System.out.println("獲取用戶信息:"+jsonArray.toString());
        System.out.println("調用接口獲取用戶信息:"+resultJson.toString());

/*        JSONObject actual = (JSONObject) resultJson.get(0);    //獲取json數組的第1項,並將其轉成json對象,即{}部分(鍵值對)
        JSONObject expect = (JSONObject) jsonArray.get(0);
        Assert.assertEquals(expect.toString(), actual.toString());   //將json對象轉成字符串,然后比較*/
        Assert.assertEquals(jsonArray,resultJson);     //直接比較json數組
    }

    private JSONArray getJsonResult(GetUserInfoCase getUserInfoCase) throws IOException {
        HttpPost post = new HttpPost(TestConfig.getUserInfoUrl);
        JSONObject param = new JSONObject();
        param.put("id",getUserInfoCase.getUserId());
        //設置請求頭信息 設置header
        post.setHeader("content-type","application/json");
        //將參數信息添加到方法中
        StringEntity entity = new StringEntity(param.toString(),"utf-8");
        post.setEntity(entity);
        //執行post請求,並帶上上下文的全局設置中的cookie信息
        HttpResponse response =TestConfig.client.execute(post,TestConfig.context);
        //聲明一個對象來進行響應結果的存儲
        String result;
        //獲取響應結果,json字符串
        result = EntityUtils.toString(response.getEntity(),"utf-8");
        System.out.println("調用接口result:"+result);

        //將json字符串轉成json數組,即json字符串的中括號[]及里面的內容
        JSONArray jsonArray = JSONArray.parseArray(result);

        return jsonArray;

    }
}
  • GetUserInfoListTest.java

package com.course.cases;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.course.config.TestConfig;
import com.course.model.GetUserListCase;
import com.course.model.User;
import com.course.utils.DatabaseUtil;
import org.apache.http.HttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.util.EntityUtils;
import org.apache.ibatis.session.SqlSession;
import org.testng.Assert;
import org.testng.annotations.Test;

import java.io.IOException;
import java.util.List;

public class GetUserInfoListTest {

    //@Test(dependsOnGroups="loginTrue",description = "獲取性別為男的用戶信息")
    @Test(groups = "getUserList",description = "獲取性別為男的用戶信息")
    public void getUserListInfo() throws IOException, InterruptedException {

        SqlSession session = DatabaseUtil.getSqlSession();
        GetUserListCase getUserListCase = session.selectOne("getUserListCase",1);
        System.out.println(getUserListCase.toString());
        System.out.println(TestConfig.getUserListUrl);

        //執行接口測試
        JSONArray resultJson = getJsonResult(getUserListCase);

        Thread.sleep(2000);
        //通過獲取數據庫中的期望結果,得到getUserList,通過定位id為getUserList的sql語句,查詢數據庫得到結果為字典列表
        //傳入的getUserListCase只有sex有值,因而查詢條件為sex,即從user表取出性別為男的用戶信息
        List<User> userList = session.selectList(getUserListCase.getExpected(),getUserListCase);
        System.out.println("數據庫返回結果列表:"+userList);  //[{},{}]
        //返回的是多條記錄的結果,遍歷出來為字典
        for(User u : userList){
            System.out.println("list獲取的user:"+u.toString());
        }
        //JSONArray userListJson = new JSONArray(userList);
        //把列表轉成json字符串,然后再轉成json數組,即[{},{}]
        JSONArray userListJson= JSONArray.parseArray(JSON.toJSONString(userList));
        System.out.println("list轉成json數組后:"+userListJson);

        //取json數組的長度,用size();取列表長度,才用length(),這里比較用戶數是否等於預期
        Assert.assertEquals(userListJson.size(),resultJson.size());
        //將用戶從json數組中取出,對比具體的用戶信息是否等於預期
        for(int i = 0;i<resultJson.size();i++){
            JSONObject actual = (JSONObject) resultJson.get(i);    //獲取json數組的第i項,並將其轉成json對象,即{}部分(鍵值對)
            JSONObject expect = (JSONObject) userListJson.get(i);
            Assert.assertEquals(expect.toString(), actual.toString());   //將json對象轉成字符串,然后比較
        }

    }

    private JSONArray getJsonResult(GetUserListCase getUserListCase) throws IOException {
        HttpPost post = new HttpPost(TestConfig.getUserListUrl);
        JSONObject param = new JSONObject();
        param.put("userName",getUserListCase.getUserName());
        param.put("sex",getUserListCase.getSex());
        param.put("age",getUserListCase.getAge());
        //設置請求頭信息 設置header
        post.setHeader("content-type","application/json");
        //將參數信息添加到方法中
        StringEntity entity = new StringEntity(param.toString(),"utf-8");
        post.setEntity(entity);
        //執行post請求,並帶上上下文的全局設置中的cookie信息
        HttpResponse response =TestConfig.client.execute(post,TestConfig.context);
        //聲明一個對象來進行響應結果的存儲
        String result;
        //獲取響應結果,這里將響應結果轉成轉成字符串,然后將響應體保存在result中,即響應結果為json字符串
        result = EntityUtils.toString(response.getEntity(),"utf-8");
        //JSONArray jsonArray = new JSONArray(result);
        //將json字符串轉成json數組,即json字符串的中括號[]及里面的內容
        JSONArray jsonArray = JSONArray.parseArray(result);

        System.out.println("調用接口list result:"+result);

        return jsonArray;

    }
}


/*
JSON就是一串字符串 只不過元素會使用特定的符號標注
{} 雙括號表示對象

[] 中括號表示數組

"" 雙引號內是屬性或值
1,JSONObject
  json對象,就是一個鍵對應一個值,使用的是大括號{ },如:{key:value}

2,JSONArray
  json數組,使用中括號[ ],只不過數組里面的項也是json鍵值對格式的

  [{name1:{name2:{name3:'value1',name4:'value2'}}},{}]
   取出name4值過程步驟:1,將以上字符串轉換為JSONArray對象;2,取出對象的第一項,JSONObject對象;
   3,取出name1的值JSONObject對象;4,取出name2的值JSONObject對象;5,取出name4的值value2。
*/

附錄

報錯問題解決(執行入口程序后):

  • 1、Error starting ApplicationContext. To display the conditions report re-run your application with 'debug' enabled.
    2019-06-20 22:37:15.167 [main] ERROR org.springframework.boot.SpringApplication - Application run failed
    org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'demo': Unsatisfied dependency expressed through field 'template'; nested exception is org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'sqlSessionTemplate' defined in class path resource
  • 解決:一般是數據庫配置有問題,比如application.yml文件中,數據庫的url: jdbc:mysql://localhost:3306/course,若該數據庫只有localhost有鏈接權限,其他ip都無權限,則報此錯誤,如將localhost改成127.0.0.1,就會出現這種錯誤。
  • 2、ERROR com.zaxxer.hikari.pool.HikariPool - HikariPool-1 - Exception during pool initialization.
    java.sql.SQLException: The server time zone value '�й���׼ʱ��' is unrecognized or represents more than one time zone. You must configure either the server or JDBC driver (via the serverTimezone configuration property) to use a more specifc time zone value if you want to utilize time zone support.
  • 解決:造成這個原因是因為mysql的版本過高。修改為:

<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>5.1.24</version>
    <scope>runtime</scope>
</dependency>

SpringBoot 去除"No MyBatis mapper was found in '[com.XXX]' package. " 警告

仔細觀察發現,這個包恰恰是 Application 主類的包,看樣子是默認掃描了。雖然不影響使用,但不想讓這個警告出現,怎么去掉這個警告呢?偶然想到一個思路,既然你要找主類包里的mapper,我就給你一個mapper。如下


NoWarnMapper.java

package com.course;

@org.apache.ibatis.annotations.Mapper
public interface NoWarnMapper {
}

請求的響應中,出現EDT錯誤


解決如下:(若沒有出現EDT錯誤,則不需要加如下內容)
在application.yml中,加入serverTimezone=GMT


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM