一. spring boot简介

springboot特点:基于编程式和注解式配置,习惯(约定)优于配置。

springboot优势:

①:springboot让配置更简单

springboot推出了starter组件,即自动配置器,我们只需要在应用中引入相关组件的starter即可完成配置,从spring应用中复杂而繁琐的配置中解脱出来,实现项目的快速搭建。

springboot官方提供的starter命名格式为spring-boot-starter-×××

第三方提供的starter命名格式为×××-spring-boot-starter

②:springboot让开发更简单

springboot支持内嵌容器,如tomcat,jetty,应用自带服务器,直接启动应用即可,无需额外安装服务器。

springboot提供了强大的开发工具包,支持热启动。

③:springboot让测试更简单

springboot内置了常用的测试框架,仅需引入一个spring-boot-starter-test依赖包,即可进行各种测试

④:springboot让部署更加简单

springboot应用默认打包jar包

⑤:springboot让监控更简单

springboot就是一款自带监控的框架,专门提供了监控组件来完成这个工作。

眺望springcloud:

spring为应对互联网应用的要求(高可靠,高并发,能够负载均衡等),基于springboot推出了微服务框架springcloud,因此springcloud完全建立在springboot之上。

二. 开发一个springboot应用,引入依赖

 <!--引入springboot父项目:该父项目中内置了很多习惯性配置和jar版本号之间的关联-->
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.6.4</version>
    </parent>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
            <version>2.6.4</version><!--此处版本号可以省略,因为springboot父项目中已经内置配置好了-->
        </dependency>
        <!--引入springboot开发工具包,可以支持热启动-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
        </dependency>
        <!-- 引入mybatis的starter -->
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>2.2.1</version>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.27</version>
        </dependency>
        <!--引入springboot测试支持-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
        </dependency>
        <!-- pagehelper-spring-boot-starter -->
        <dependency>
            <groupId>com.github.pagehelper</groupId>
            <artifactId>pagehelper-spring-boot-starter</artifactId>
            <version>1.4.1</version>
        </dependency>

    </dependencies>

    <!--引入springboot构建插件,用于打包生成可执行jar文件-->
    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <version>2.6.4</version>
            </plugin>
        </plugins>
    </build>

parent:spring-boot-starter-parent:引入springboot父项目:该父项目中内置了很多习惯性配置和jar版本号之间的关联

dependencies:

①:spring-boot-starter-web:web组件

②:spring-boot-devtools:引入springboot开发工具包,可以支持热启动

③:mybatis-spring-boot-starter

④:mysql-connector-java

⑤:spring-boot-starter-test:springboot测试组件

⑥:pagehelper-spring-boot-starter:分页组件

build:

spring-boot-maven-plugin:引入springboot构建插件,用于打包生成可执行jar文件

三. 开发springboot启动类

import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

//说明本应用为springboot应用,
// 而且还说明这是一个springboot的启动类,同时还说明这是一个配置类
//而且还是一个自动配置类

//主类所在的包,就是springboot应用的根包
//在springboot应用中,一般所有的组件如:controller,service,和dao等对象都应该在应用根包下或其子包下

@SpringBootApplication
//自动扫描映射器,并放入spring容器
@MapperScan("org.xupt.ygq.demo.dao")
public class MyApp {
    public static void main(String[] args) {
        //该语句为springboot应用的启动语句
        SpringApplication.run(MyApp.class,args);
    }
}

两个注解:

①:@SpringBootApplication:

说明本应用为springboot应用,而且还说明这是一个springboot的启动类,同时还说明这是一个配置类。

主类所在的包,就是springboot应用的根包,在springboot应用中,一般所有的组件如:controller,service,和dao,等对象都应该在应用根包或者根包的子包下面

②:@MapperScan:自动扫描映射器(也就是dao包),并存放在spring容器中

一条语句:

SpringApplication.run(MyApp.class,args);启动语句!!!

四. 配置application.properties资源文件

#配置内置服务器端口号,默认为8080
server.port=9999
#配置根日志的输出级别,默认为info
logging.level.root=info
#配置org.xupt.ygq.demo.dao包下的日志输出级别为trace,可以打印mybatis映射器执行结果
logging.level.org.xupt.ygq.demo.dao=trace
logging.level.org.xupt.ygq.demo=debug
#配置springmvc的日志
logging.level.web=trace
#配置数据源
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/wddb
spring.datasource.username=root
spring.datasource.password=123456

#配置mybatis

#配置映射文件位置,在类路径下,mapper目录下的任意层级文件夹下的以.xml结尾的文件
mybatis.mapper-locations=classpath:mapper/**/*.xml

#pagehelper
#配置方言,即配置使用哪一个数据库
pagehelper.helper-dialect=mysql
#分页的合理化配置,即如果请求页码不合理时,自动合理化,比如:请求-9页,自动合理化成第一页
pagehelper.reasonable=true

五.因为要做分页查询,封装分页

 5.1 分页类

import java.util.List;

public class Page<T> {
    //当前页
    private Integer current;
    //首页
    private Integer first;
    //上页
    private Integer pre;
    //下页
    private Integer next;
    //尾页
    private Integer last;


    //每页最大记录数
    private Integer pageSize;
    //总记录数
    private Long total;
    //总页数
    private Integer pages;
    //当前页实际记录数
    private Integer currSize;


    //当前页数据记录
    private List<T> list;

    public Integer getCurrent() {
        return current;
    }

    public void setCurrent(Integer current) {
        this.current = current;
    }

    public Integer getFirst() {
        return first;
    }

    public void setFirst(Integer first) {
        this.first = first;
    }

    public Integer getPre() {
        return pre;
    }

    public void setPre(Integer pre) {
        this.pre = pre;
    }

    public Integer getNext() {
        return next;
    }

    public void setNext(Integer next) {
        this.next = next;
    }

    public Integer getLast() {
        return last;
    }

    public void setLast(Integer last) {
        this.last = last;
    }

    public Integer getPageSize() {
        return pageSize;
    }

    public void setPageSize(Integer pageSize) {
        this.pageSize = pageSize;
    }

    public Long getTotal() {
        return total;
    }

    public void setTotal(Long total) {
        this.total = total;
    }

    public Integer getPages() {
        return pages;
    }

    public void setPages(Integer pages) {
        this.pages = pages;
    }

    public Integer getCurrSize() {
        return currSize;
    }

    public void setCurrSize(Integer currSize) {
        this.currSize = currSize;
    }

    public List<T> getList() {
        return list;
    }

    public void setList(List<T> list) {
        this.list = list;
    }

    @Override
    public String toString() {
        return "Page{" +
                "current=" + current +
                ", first=" + first +
                ", pre=" + pre +
                ", next=" + next +
                ", last=" + last +
                ", pageSize=" + pageSize +
                ", total=" + total +
                ", pages=" + pages +
                ", currSize=" + currSize +
                ", list=" + list +
                '}';
    }
}

类定义成泛型的:因为查询到的结果list,里面装的对象是什么,是不确定的。

5.2 分页参数

public class PageParam {

    private Integer pageNum=1;//请求页码
    private Integer pageSize=5;//每页最大记录数

    public Integer getPageNum() {
        return pageNum;
    }

    public void setPageNum(Integer pageNum) {
        this.pageNum = pageNum;
    }

    public Integer getPageSize() {
        return pageSize;
    }

    public void setPageSize(Integer pageSize) {
        this.pageSize = pageSize;
    }
}

在进行分页之前要先设置分页参数(包含两个属性,页码pageName和每页记录数pageSize)

PageHelper.startPage(pageParam);

5.3 分页查询api

import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import org.xupt.ygq.demo.common.page.Page;
import org.xupt.ygq.demo.common.page.PageParam;
import org.xupt.ygq.demo.common.page.QueryAction;
import java.util.List;

public class Utils {
    public static <T> Page<T> getPage(PageParam pageParam, QueryAction<T> queryAction){
        //在查询之前设置分页参数,再执行查询和设置分页参数之间不能有其他的查询。
        //该方法用于设置分页参数对象(含有页码pageName和每页记录数pageSize两个属性)
        PageHelper.startPage(pageParam);
        List<T> list = queryAction.executeQuery();//执行一个查询,获得List集合
        //紧挨在查询之后构造分页信息对象
        PageInfo<T> pageInfo = new PageInfo<>(list);
        Page<T> page = new Page<>();
        page.setCurrent(pageInfo.getPageNum());//当前页
        page.setFirst(1);//首页
        page.setPre(pageInfo.getPrePage());//上一页
        page.setNext(pageInfo.getNextPage());//下一页
        page.setLast(pageInfo.getPages());//最后一页
        page.setPageSize(pageInfo.getPageSize());//每页最大记录数
        page.setTotal(pageInfo.getTotal());//总记录数
        page.setPages(pageInfo.getPages());//总页数
        page.setCurrSize(pageInfo.getSize());//当前页实际记录数
        page.setList(pageInfo.getList());//当前页数据记录
        return page;
    }
}

定义一个泛型生成分页对象的泛型类:(两个参数)

①:PageParame:声明分页参数,

②:QueryAction:一个查询行为的接口,表示要进行分页的查询行为

其中要注意分页信息对象:PageInfo:我们对于自己的分页对象的设置基于分页信息对象

最后返回一个分页对象:

5.4 定义抽象的查询行为

import java.util.List;
/*
* 表示抽象的查询的行为,该查询将获得一个List集合
* */

public interface QueryAction<T> {
    public List<T> executeQuery();
}

5.5 封装返回结果

public class Result<T> {
    public static final int CODE_OK = 200;
    public static final int CODE_ERR_BUSINESS = 500;
    public static final int CODE_ERR_SYS = 530;
    public static final int CODE_ERR_UNLOGINED = 520;

    public static <T>Result<T> ok(){
        return new Result(true,CODE_OK,null,null);
    }
    public static <T>Result<T> ok(String message){
        return new Result(true,CODE_OK,message,null);
    }
    public static <T>Result<T> ok(T data){
        return new Result(true,CODE_OK,null,data);
    }
    public static <T>Result<T> ok(String message,T data){
        return new Result(true,CODE_OK,message,data);
    }

    public static <T>Result<T> err(int errCode ,String message){
        return new Result(false,errCode,message,null);
    }
    public static <T>Result<T> err(int errCode ,String message,T data){
        return new Result(false,errCode,message,data);
    }

    private boolean success;//是否成功
    private int code;//200 成功 500 业务失败,530 系统错误,520 未登录
    private String message;//概要信息
    private T data;

    public Result(boolean success, int code, String message, T data) {
        this.success = success;
        this.code = code;
        this.message = message;
        this.data = data;
    }

    public boolean isSuccess() {
        return success;
    }

    public int getCode() {
        return code;
    }

    public String getMessage() {
        return message;
    }

    public T getData() {
        return data;
    }
}

六. 开发model和dto

import com.fasterxml.jackson.annotation.JsonFormat;

import java.util.Date;

public class Employee {
    private String e_id;
    private Integer d_id;//部门编号
    private Integer e_sex;
    private String e_name;
    private Date e_birth;

    public String getE_id() {
        return e_id;
    }

    public void setE_id(String e_id) {
        this.e_id = e_id;
    }

    public Integer getD_id() {
        return d_id;
    }

    public void setD_id(Integer d_id) {
        this.d_id = d_id;
    }

    public Integer getE_sex() {
        return e_sex;
    }

    public void setE_sex(Integer e_sex) {
        this.e_sex = e_sex;
    }

    public String getE_name() {
        return e_name;
    }

    public void setE_name(String e_name) {
        this.e_name = e_name;
    }
    //声明生成json的时间格式和时区
    @JsonFormat(pattern = "yyyy-MM-dd",timezone = "GMT=8")
    public Date getE_birth() {
        return e_birth;
    }

    public void setE_birth(Date e_birth) {
        this.e_birth = e_birth;
    }

    @Override
    public String toString() {
        return "Employee{" +
                "e_id='" + e_id + '\'' +
                ", d_id=" + d_id +
                ", e_sex=" + e_sex +
                ", e_name='" + e_name + '\'' +
                ", e_birth=" + e_birth +
                '}';
    }
}
import java.util.Date;

//表示封装查询条件的dto
public class EmployeeQueryDto extends PageParam {
    private String e_id;
    private Integer d_id;//部门编号
    private Integer e_sex;
    private String e_name;
    private Date e_birth_start;
    private Date e_birth_end;

    public String getE_id() {
        return e_id;
    }

    public void setE_id(String e_id) {
        this.e_id = e_id;
    }

    public Integer getD_id() {
        return d_id;
    }

    public void setD_id(Integer d_id) {
        this.d_id = d_id;
    }

    public Integer getE_sex() {
        return e_sex;
    }

    public void setE_sex(Integer e_sex) {
        this.e_sex = e_sex;
    }

    public String getE_name() {
        return e_name;
    }

    public void setE_name(String e_name) {
        this.e_name = e_name;
    }
    @DateTimeFormat(pattern = "yyyy-MM-dd")//对前端传来的时间格式说明
    public Date getE_birth_start() {
        return e_birth_start;
    }

    public void setE_birth_start(Date e_birth_start) {
        this.e_birth_start = e_birth_start;
    }

    public Date getE_birth_end() {
        return e_birth_end;
    }
    @DateTimeFormat(pattern = "yyyy-MM-dd")//对前端传来的时间格式说明
    public void setE_birth_end(Date e_birth_end) {
        this.e_birth_end = e_birth_end;
    }
}

dto继承了PageParam:继承了他的分页参数,方便一起从前端页面传回数据。这样子就可以把dto和分页参数融合在一起进行参数传递。

七. 开发控制器组件

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import org.xupt.ygq.demo.common.Result;
import org.xupt.ygq.demo.common.page.Page;
import org.xupt.ygq.demo.dto.EmployeeQueryDto;
import org.xupt.ygq.demo.model.Employee;
import org.xupt.ygq.demo.service.EmpService;

@RestController
public class MyController {
    @Autowired
    private EmpService empService;
    @GetMapping("/emp")
    //分页查询需要分页参数,dto继承了分页参数类,所以他里面就有分页参数
    public Result empList(EmployeeQueryDto dto){
        Page<Employee> page = empService.getEmpPage(dto);
        return Result.ok(page);
    }
}

三个注解:

①:RestController

②:Autowired

③:GetMapping

定义处理方法:传递参数

八. 开发业务对象

import org.xupt.ygq.demo.common.page.Page;
import org.xupt.ygq.demo.common.page.PageParam;
import org.xupt.ygq.demo.model.Employee;


public interface EmpService {
    public Page<Employee> getEmpPage(PageParam pageParam);
}

 这里为什么用PageParam接受呢,因为dto对象时PageParam的子类,所以用父类型接收。

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.xupt.ygq.demo.common.Utils;
import org.xupt.ygq.demo.common.page.Page;
import org.xupt.ygq.demo.common.page.PageParam;
import org.xupt.ygq.demo.dao.EmpDao;
import org.xupt.ygq.demo.model.Employee;
import org.xupt.ygq.demo.service.EmpService;

@Service//表示本对象是业务对象,并且受spring容器管理
@Transactional//声明本业务对象的所有方法都是事务性的
public class EmpServiceImpl implements EmpService {
    @Autowired
    private EmpDao empDao;
    /*
    * pageHelper是一个适用于MyBatis的分页插件,通过该插件可以很方便的实现分页查询
    * */
    /*@Override
    public Page<Employee> getEmpPage(PageParam pageParam) {
        QueryAction<Employee> action = new QueryAction<Employee>() {
            @Override
            public List<Employee> executeQuery() {
                return empDao.findEmpList();
            }
        } ;

        return Utils.getPage(pageParam,action);
    }*/
//    @Override
//    public Page<Employee> getEmpPage(PageParam pageParam) {
//        QueryAction<Employee> action =()->{
//                return empDao.findEmpList();
//            };
//
//        return Utils.getPage(pageParam,action);
//    }
    @Override
    public Page<Employee> getEmpPage(PageParam pageParam) {
        //QueryAction<Employee> action =()-> empDao.findEmpList();

        return Utils.getPage(pageParam,()-> empDao.findEmpList(pageParam));
    }
}

实现类里面有一个重要的点:就是调用分页查询api的时候,参数QueryAction接口的实现是内部类,再加上接口中只有一个方法,所以可以简化书写

九. 开发持久层

import org.xupt.ygq.demo.common.page.PageParam;
import org.xupt.ygq.demo.model.Employee;

import java.util.List;

public interface EmpDao {
    //@Select("select * from t_emp")
    public List<Employee> findEmpList(PageParam pageParam);
}

持久层返回的List在Service实现中被封装成了page对象。

十. 开发mapper

<?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="org.xupt.ygq.demo.dao.EmpDao">
    <!-- 需求: 通过给定属性 查询用户 -->
    <select id="findEmpList" resultType= "org.xupt.ygq.demo.model.Employee">
        select * from t_emp
        <where>
            <!--<include refid="sql_query_where"></include>-->
            <if test="e_id!=null and e_id!='' ">
                and e_id like concat('%',#{e_id},'%')
            </if>
            <if test="e_name!=null and e_name!='' ">
                and e_name like concat('%',#{e_name},'%')
            </if>

            <if test="e_sex!=null ">
                and e_sex=#{e_sex}
            </if>
            <if test="d_id!=null ">
                and d_id=#{d_id}
            </if>

            <if test="e_birth_start!=null  ">
                and e_date &gt;= #{e_date_start}
            </if>
            <if test="e_birth_end!=null  ">
                and e_date &lt;= #{e_date_end}
            </if>
        </where>
    </select>
</mapper>

整个分页由插件完成!!!

mapper需要在application.properties中配置映射路径。

还需要注意映射的包:

 

十一. 测试 

 

Logo

华为开发者空间,是为全球开发者打造的专属开发空间,汇聚了华为优质开发资源及工具,致力于让每一位开发者拥有一台云主机,基于华为根生态开发、创新。

更多推荐