1.Spring Boot整合连接池

1.1 SpringBoot概述
实际开发中应用程序与数据库交互时,“获得连接”或“释放资源”是非常消耗系统资源的两个过程,为了解决此类性能问题,通常情况我们采用连接池技术来重用连接Connection对象,如图-1所示:
a.png

Java为数据库连接池提供了公共的接口:javax.sql.DataSource,各个厂商需要让自己的连接池实现这个接口。然后我们的应用程序中耦合与这个接口,便可以方便的切换不同厂商的连接池,常见的连接池有DBCP、C3P0,DRUID,HikariCP等。

通过连接池获取连接的一个基本过程,如图-2所示:
b.png
在图-2中,执行原理如下所示
用户通过DataSource对象的getConnection()方法,获取一个连接。假如池中有连接,则直接将连接返回给用户。假如池中没有连接,则会调用Dirver(驱动,由数据库厂商进行实现)对象的connect方法从数据库获取,拿到连接以后,可以将连接在池中放一份,然后将连接返回给调用方。
1.2 数据初始化
打开mysql控制台,然后按如下步骤执行goods.sql文件:
第一步:登录mysql

mysql –uroot –proot

第二步:设置控制台编码(MySql客户端(client))方式

set names utf8; --通知服务器客户端所使用的编码为utf8

第三步:执行goods.sql文件

source d:/goods.sql   -- 注意source 后面跟的是goods.sql文件的位置,不要直接将sql文件的内容之间拿到命令行或图形化界面工具中直接运行,若sql文件中有中文,就会出现乱码!在实际开发拿到sql文件也不要立刻去执行,否则会造成不可估量的损失!

备注:当mysql连接数据库失败时,检测服务是否启动,可尝试先启动服务(windows中需要以管理员方式打开控制台,然后在控制台执行net start mysql启动服务即可,停止mysql服务器执行指令是 net stop mysql)

1.3 整合HikariCP连接池
HikariCP连接池概述(背景介绍)
HiKariCP号称是目前世界上最快的连接池,有江湖一哥的称号,目前在springboot工程默认推荐使用HiKariCP连接池。
现在我们创建一个新的SpringBoot项目,项目名为CGB-SBOOT-04,在此工程中整合HiKariCP,其步骤如下:
step1:创建SpringBoot项目。
step2,添加依赖(两个--MySQL驱动,Spring-JDBC)
编辑项目中pom.xml,右键项目的pom.xml文件,选择spring,如图-3所示:1.png
然后查找mysql 驱动依赖,JDBC API依赖,如图-4所示:
2.png
依赖添加以后,在pom.xml文件中会自动添加如下两个依赖配置:
mysql数据库驱动依赖。

<dependency>

 <groupId>mysql</groupId>

 <artifactId>mysql-connector-java</artifactId>

 <scope>runtime</scope>

</dependency>

spring对象jdbc支持(此时会默认帮我们下载HiKariCP连接池)。

<dependency>

 <groupId>org.springframework.boot</groupId>

 <artifactId>spring-boot-starter-jdbc</artifactId>

</dependency>

step3,配置连接池(配置连接数据库的url,username,password)
打开application.properties配置文件,添加如下内容。

##spring datesource
spring.datasource.url=jdbc:mysql:///dbgoods?serverTimezone=GMT%2B8
spring.datasource.username=root
spring.datasource.password=root

step4:编写单元测试类DataSourceTests从池中获取连接(Connection)(测试包中编写,测试类必须放在启动类所在包或其子包中!)

package com.cy.pj.commom.datasource;

import java.sql.Connection;
import java.sql.SQLException;

import javax.sql.DataSource;

import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

/**
 * 整合hikariCP连接池
 *1)创建SpringBoot项目
 *2)添加依赖(两个-MySQL驱动,Spring-JDBC)
 *3)配置(application.properties)连接数据库url,username,password
 * 3.1)spring.datasource.url=jdbc:mysql://localhost:3306/dbgoods?serverTimezone=GMT%2B8&characterEnconding=utf8
 * 3.2)spring.datasource.username=root
 * 3.3)spring.datasource.password=root
 *4)编写测试类DataSourceTests从池中获取连接(Connection)
 * @author Administrator
 *
 */

@SpringBootTest //该注解作用将类交给spring管理
public class DatasourceTests {
    //思考:
    //1)这里dataSource变量指向的对象是谁? 你怎么知道的? --指向的是HikariDateSource 通过断点调试或获取dateSouece变量指向的对象的具体类型的全类名
    @Autowired
    private DataSource dataSource;
    
    @Test
    void testConnnction01() throws SQLException {
        //获取dateSouece变量指向的对象的具体类型的全类名
        //System.out.println("类型="+dataSource.getClass().getName());
        //思考:这个连接的获取过程是怎样的? 你怎么知道的?
        System.out.println(dataSource.getConnection());
        
    }
    
    @Test
    void testConnnction02() throws SQLException, InterruptedException {
//        long start =System.currentTimeMillis();
//        System.out.println(dataSource.getConnection());
//        long end =System.currentTimeMillis();
//        System.out.println("first:"+(end-start));
//        System.out.println(dataSource.getConnection());
//        long last =System.currentTimeMillis();
//        System.out.println("second:"+(end-last));
        
        Connection conn1 = dataSource.getConnection();
        System.out.println("conn1="+conn1);
        Connection conn2 = dataSource.getConnection();
        System.out.println("conn2="+conn2);
        conn1.close();
        conn2.close();
        Thread.sleep(3000);
        Connection conn3 = dataSource.getConnection();
        System.out.println("conn3="+conn3);
        System.out.println(conn1==conn2);//false
    }
}

step5:原理分析,如图-5所示
0.png

图-5中,演示了我们在测试类DataSourceTests中基于DataSource获取连接的一个基本过程。对于图-5中的连接建立过程,可以在Driver接口的实现中的connect方法上添加断点,然后进行断点测试,如图-6显示了API方法的调用执行过程(按箭头方向开代码),这个了解了解即可4.png

当我们需要了解,基于HikariCP连接池获取数据库连接,并将获取到的连接放入到连接池中的过程进行了解,可以参考图-7中的断点设计进行查看即可(不做具体要求)。image5.png
在基于图-7中设置的断点序号位置进行单元测试时,可以每次按F8进行断点跟踪,了解HiKariCP连接池获取连接存储连接的过程,其中API不理解的可以在搜索引擎中进行查阅分析。

2 Spring Boot 整合MyBatis框架

2.1 Mybatis概述(背景介绍)
Mybatis是一个优秀的持久层框架,底层基于JDBC实现与数据库的交互。并在JDBC操作的基础上做了封装和优化,它借助灵活的SQL定制,参数及结果集的映射方式,更好的适应了当前互联网技术的发展。Mybatis框架的简单应用架构,如图-8所示:
image18.png
在当今的互联网应用中项目,mybatis框架通常会由spring框架进行资源整合,作为数据层技术实现数据交互操作。
2.2 初始配置
2.2.1 添加mybatis启动依赖
参考官网mybatis.org/spring,找到springboot菜单选项.基于菜单项找到MyBatis启动依赖。

 <dependency>

 <groupId>org.mybatis.spring.boot</groupId>

 <artifactId>mybatis-spring-boot-starter</artifactId>

 <version>2.1.1</version>

 </dependency>

注意:在添加此依赖时,一定指定其版本(version),因为在springboot默认配置中没有设置mybatis框架版本。
我们添加了mybatis依赖以后,spring框架启动时会对mybatis进行自动配置。例如SqlSessionFactory工厂对象的创建。
2.2.2 Mybatis简易配置
假如需要对mybatis框架进行简易配置,可以打开application.properties文件,在此文件中进行基本配置(可选,暂时可以不配置),例如:

mybatis.configuration.default-statement-timeout=30

开启驼峰映射

mybatis.configuration.map-underscore-to-camel-case=true

配置mybatis中的sql日志的输出:(com.cy为我们写的项目的根包)

logging.level.com.cy=DEBUG

2.3 业务分析及实现

2.3.1 基本业务实现及单元测试
基于Spring对MyBatis框架的整合,实现对商品库中数据的删除操作。
第一步:业务API架构设计,如图-9所示(从右往左看):image8.png
第二步:基于id执行商品信息删除,其业务时序,如图-10所示:image13.png

第三步:定义商品业务数据层接口及业务方法。

package com.cy.pj.goods.dao;

import org.apache.ibatis.annotations.Delete;

import org.apache.ibatis.annotations.Mapper;

@Mapper

public interface GoodsDao {

 @Delete("delete from tb_goods where id=#{id}")

 int deleteById(Integer id);

}

其中:@Mapper是由MyBatis框架中定义的一个描述数据层接口的的注解(所有的注解只起到一个描述性的作用),用于告诉Spring框架此接口的实现类由mybatis创建,并将其实现类对象存储到spring容器.

第四步:定义测试类,对GoodsDao对象进行应用测试

@SpringBootTest

public class GoodsDaoTests { 

 @Autowired

 private GoodsDao goodsDao;

 @Test

 public void testDeleteById() {

 int rows=goodsDao.deleteById(10);

 System.out.println("rows="+rows);

 }

}

第五步:删除业务时序图增强分析,如图-11所示(了解SqlSession应用):image4.png

第六步:MyBatis API 对象应用过程分析,如图-12所示:
image25.png
在图-12中,展示业务设计中API对象的一种调用关系。例如我们的数据访问对象调用MyBatis API,然后MyBatis API底层通过使用JDBC API(两大部分:java.sql.*,javax.sql.*)访问数据库。

2.3.2 业务进阶分析及实现

在MyBatis框架中定义SQL映射的方式有两种:一种是将SQL映射定义在我们的xml映射文件中,一种方式是借助注解将其声明在接口方法上。我们在实际项目中对于简单的SQL映射可以直接以注解方式进行声明即可,复杂SQL还是要写到xml中,充分利用动态SQL进行设计会更好一些。
本小节,基于XML方式定义GoodsDao接口中的方法映射,并进行单元测试:
Step01:在GoodsDao中,定义删除方法,具体代码如下:

int deleteObjects(@Param("ids")Integer... ids);

说明:当接口方法对应的映射语句相对比较复杂时,建议将映射语句写到对应映射文件。
Step02:在src/main/resources目录下创建mapper/goods目录,然后在其目录中添加GoodsMapper.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.cy.pj.goods.dao.GoodsDao"\>

 <delete id="deleteObjects"\>

 delete from tb\_goods

 where id in <!-- (1,2,3,4,5) -->

 <foreach collection="ids"

 open="("

 close=")"

 separator=","

 item="id"\>

 #{id}

 </foreach\>

 </delete\>

</mapper\>

Step03:在application.properties文件中添加如下配置:

mybatis.mapper-locations=classpath:/mapper/\*/\*.xml

Step04:在GoodsDaoTests类中添加如下单元测试方法进行单元测试:

@Test

public void testDeleteObjects() {

 int rows\=goodsDao.deleteObjects(17,18);

 System.out.println(rows);

}

2.4 构建业务层接口及实现类
参考图-13的设计,进行代码实现,具体业务自己设计(例如查询)。image32.png
图-13

在图-13中,我们的测试类GoodsServiceTest,通过耦合与GoodsService接口实现具体商品业务处理。而在GoodsService接口的实现GoodsServiceImpl中通过耦合GoodsDao接口完成具体的数据逻辑处理。
课堂练习:基于图-13的设计,实现商品信息的查询,并将查询到的数据在测试类中进行输出。具体步骤如下:
第一步:定义pojo对象(Goods)用于存储从数据库查询到的商品信息.
第二步:定义dao接口方法,用于查询数据库数据。
第三步:定义业务层接口以及实现类,然后在类中添加商品查询的业务方法。
第四步:定义单元测试类,对业务层方法进行单元测试
代码实现:
第一步:Goods对象定义

package com.cy.pj.goods.pojo;import java.text.SimpleDateFormat;import java.util.Date;/\*\*  
\* pojo对象,基于此对象封装从数据库查询到的数据  
\* 思考:对象靠什么存储数据?属性  
\*/  
public class Goods { private Long id;//id bigint primary key auto\_increment  private String name;//name varchar(100) not null  private String remark;//remark text  private Date createdTime;//createdTime datetime  public Long getId() { return id;  
        } public void setId(Long id) { this.id = id;  
        } public String getName() { return name;  
        } public void setName(String name) { this.name = name;  
        } public String getRemark() { return remark;  
        } public void setRemark(String remark) { this.remark = remark;  
        } public Date getCreatedTime() { return createdTime;  
        } public void setCreatedTime(Date createdTime) { this.createdTime = createdTime;  
        } @Override  public String toString() { return "Goods \[id=" + id + ", name=" + name + ", remark=" + remark + ", createdTime=" + createdTime + "\]";  
        }  
}

第二步:GoodsDao中添加查询方法(一行记录映射为一个Goods对象)


@Select("select id,name,remark,createdTime from tb\_goods")  
List<Goods> findObjects();

第三步:添加GoodsService接口和实现类

package com.cy.pj.goods.service;import java.util.List;import com.cy.pj.goods.pojo.Goods;public interface GoodsService {  
  
           List<Goods> findGoods();  
}

package com.cy.pj.goods.service.impl;import java.util.List;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.stereotype.Service;import com.cy.pj.goods.dao.GoodsDao;import com.cy.pj.goods.pojo.Goods;import com.cy.pj.goods.service.GoodsService;/\*\*  
\* 商品业务层对象,负责业务逻辑处理。  
\* @author qilei  
\*/  
@Service  
public class GoodsServiceImpl implements GoodsService { //has a  @Autowired  private GoodsDao goodsDao; @Override  public List<Goods> findGoods() { long start=System.currentTimeMillis();  
                List<Goods> list=goodsDao.findObjects(); long end=System.currentTimeMillis();  
                System.out.println("query time:"+(end-start)); return list;  
        }  
}

第四步:添加单元测试类

package com.cy.pj.goods.service;

import java.util.List;import org.junit.jupiter.api.Test;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.boot.test.context.SpringBootTest;import com.cy.pj.goods.pojo.Goods;@SpringBootTest  
public class GoodsServiceTests { @Autowired  private GoodsService goodsService; @Test  public void testFindGoods() {  
                List<Goods> list=goodsService.findGoods(); //System.out.println(list);//toString()  for(Goods g:list) {  
                        System.out.println(g);//toString() }  
                list=goodsService.findGoods();  
        }//  
}

3 Spring Boot整合SpringMVC应用

3.1 SpringMVC概述(背景介绍)
MVC(Model–view–controller)是软件工程中的一种软件架构模式,基于此模式把软件系统分为三个基本部分:模型(Model)、视图(View)和控制器(Controller)。目的是通过这样的设计使程序结构更加简洁、直观,降低问题的复杂度。其中各个组成部分的职责为:

  • 视图(View) - UI设计人员进行图形界面设计,负责实现与用户交互。
  • 控制器(Controller)- 负责获取请求,处理请求,响应结果。
  • 模型(Model) - 实现业务逻辑,数据逻辑实现。

我们在软件设计时,通常要遵循一定的设计原则。MVC架构模式的设计中,首先基于单一职责原则(SRP-Single responsibility principle)让每个对象各司其职,各尽所能。然后再基于“高内聚,低耦合”的设计思想实现相关层对象之间的交互。这样可以更好提高程序的可维护性和可扩展性。

JavaEE(Entrprise Edition)技术体系中,MVC设计思想的实现,如图-14所示:
image2.png

在图-14中,Servlet充当MVC中的Controller,负责调用model处理业务,负责转发或重定向某个页面,在页面(view)上呈现数据。
模块封装了对Servlet的技术的应用,简化了程序员对请求和响应过程中数据的处理,其简易架构分Spring MVC 是Spring 框架中基于MVC设计思想实现的一个用于处理Web请求的模块。这个SpringMVC如图-15所示:
image1.png

图-15中,核心组件分析:

  • DispatcherServlet :前端控制器, 处理请求的入口。
  • HandlerMapping:映射器对象, 用于管理url与对应controller的映射关系。
  • Interceptors:拦截器,实现请求响应的共性处理。
  • Controller:后端控制器-handler, 负责处理请求的控制逻辑。
  • ViewResolver:视图解析器,解析对应的视图关系(前缀+viewname+后缀)。

备注:假如希望了解Spring MVC的详细处理流程可以基于断点调试法进行跟踪。

3.2 初始配置
3.2.1 添加Spring MVC依赖
编辑pom.xml文件,添加web依赖,Thymeleaf依赖,代码如下:
Web依赖(提供了Spring MVC核心API,同时会嵌入一个Tomcat服务器)或者在pom文件上鼠标右键选择edit starters,搜索web依赖和thymaleaf依赖。

<dependency>

 <groupId>org.springframework.boot</groupId>

 <artifactId>spring-boot-starter-web</artifactId>

</dependency>

Thymeleaf依赖(提供了一个视图解析器对象以及数据绑定机制)

<dependency>

  <groupId>org.springframework.boot</groupId>

  <artifactId>spring-boot-starter-thymeleaf</artifactId>

</dependency>

其中: Spring Web Starter 提供Spring MVC 依赖支持,并会自动添加一个tomcat依赖,作为嵌入式web服务器使用.thymeleaf是一个html模板引擎,提供了与Spring MVC进行整合的API,可作为MVC架构中Web应用的View层。
3.2.2 配置Spring MVC 核心对象
在application.properties文件中添加视图解析器配置(假如没有配置也会默认配置,在默认配置中prefix默认值为classpath:/templates/,后缀默认为.html)。

spring.thymeleaf.prefix=classpath:/templates/pages/
spring.thymeleaf.suffix=.html

说明:要基于配置在src/main/resources目录下创建templates/pages目录

3.3 Spring MVC 进行入门实践
第一步:编写GoodsController类并将其交给spring管理。这样的Controller在SpringMVC 规范中通常称之为Handler(处理器),我们在企业中有时也会将此对象理解为一个后端控制器。具体代码如下所示:

package com.cy.pj.goods.controller;

@Controller

@RequestMapping("/goods/")

public class GoodsController {

 @RequestMapping("doGoodsUI")

public String doGoodsUI() {

 return "goods";

}

}

第二步:需要在/templates/pages/目录下创建goods.html

第三步:启动服务器(默认项目嵌入的是tomcat),打开浏览器进行访问测试。

课堂练习:

练习一:   将数据库中的商品数据查询出来更新到页面上。
编写controller层的代码,如下所示:

/**
     * 此方法为GoodsController中处理页面请求的一个方法
     * 这个方法的返回值现在是一个模板页面。
     * 思考:
     *  1)这个方法由谁调用? (前端控制器DispatcherServlet调用)
     *  2)这个方法的返回值传递谁?(谁调用此方法这个方法的返回值就传递给谁)
     *  3)这个方法的返回值后续要做怎样的处理? (DispatcherServlet调用视图解析器进行解析,
     *    添加对应的前缀后缀,构成/templates/pages/goods.html)
     * @return
     */
    @RequestMapping("doGoodsUI")
    public String doGoodsUI(Model model) { //model对象可以将数据存储到请求作用域
        List<Goods> list = goodsService.findGoods();
        model.addAttribute("list", list);
        return "goods";//跳转到goods.html
        
    }

Dao层代码,如下:

@Select("select id,name,remark,createdTime from tb_goods")
    /**
     * 查询商品所有信息,一行记录映射为一个Goods对象,多个对象存储到List集合,
     *     1)底层查询还是JDBC
     *  2)查询结果的映射(Mybatis框架):假如是JDBC我们需要获取结果ResultSet,然后取
     *   数据手动进行映射内容中映射过程
     *  2.1)迭代ResultSet(这个对象中封装了数据库中的查询结果)
     *  2.2)构建Goods对象(迭代一次构建一个Goods对象)
     *  2.3)从ResultSet中取值然后通过反射调用Goods对象set方法或者直接为属性赋值
     * @return 
     */
    List<Goods> findGoods();

service层的代码,如下:

/**
     * 查询(获取)所有的商品信息
     * @return
     */
    List<Goods> findGoods();

service接口实现类的代码,如下:

@Override
    public List<Goods> findGoods() {
        long start = System.currentTimeMillis();
        List<Goods> list = goodsDao.findGoods();
        long end = System.currentTimeMillis();
        log.info("query time:{}",(end-start));//可以输入到console,写可以写入到文件中
        return list;
    }
    

在浏览器端(客户端)的goods.html页面显示所有的商品信息。

练习二:基于ID删商品库中的商品信息。
controller层的代码,如下:

    //===============  delete  ================
    /** 根据删除商品方式一 */
    //restful 风格url的定义(resultful为一种软件架构编码风格,定义了一种url的格式)
    //restful 风格的url语法:/a/b/{c}/{d},在这样的语法结构中{}为一个变量表达式
    @RequestMapping("doDeleteById/{id}")  //"goods/doDeleteById/{id}"
    //假如我们希望在方法参数中resuful url中变量表达式的值,可以使用@PathVariable注解对参数进行描述
    public String doDeleteById(@PathVariable Integer id,Model model) {
        System.out.println("删除的id="+id);
        goodsService.deleteById(id);
        List<Goods> list = goodsService.findGoods();
        model.addAttribute("list", list);
        return "goods";  
        //return "forward:doGoodsUI"; //转发这种写法也要基于url找资源,也要通过反射调用方法  //这里报400错误的原因:客户端提交的参数与服务器接收的参数不匹配(格式、类型、格式)导致的
        //return "redirect:/goods/doGoodsUI"; //重定向这种写法性能比较差(客户单与服务端需要重新建立连接)
    }
    

    
    
    /** 根据删除商品方式二 */
//    @RequestMapping("doDeleteById")
//    public String doDeleteById(Integer id,Model model) {
//        System.out.println("删除的id="+id);
//        goodsService.deleteById(id);
//        List<Goods> list = goodsService.findGoods();
//        model.addAttribute("list", list);
//        return "goods";
//    }
    
    /** 根据删除商品方式三 */
//    @RequestMapping("doDeleteById")
//    public String doDeleteById(Integer id) {
//        goodsService.deleteById(id);
//        return "redirect:doGoodsUI";
//    }
    

Dao接口的代码,如下;

/**
    
    
    /**
     * 基于商品id执行删除业务
     * @param id 商品id
     * @return 删除的行数
     *  数据层方法    对象的sql映射,简单sql可以以注解方式进行定义,负责将sql写到映射文件中(xml)
     */
    @Delete("delete from tb_goods where id=#{id}")  //当接口中的方法只有一个,并且不是集合或数组,占位符中名称可以是任意的,并不要求与形参名保持一致。
    int deleteById(Integer id);
    

service层的代码,如下:

/**
     * 基于id执行删除操作
     * @param id  商品id
     * @return 删除的行数
     */
    int deleteById(Integer id);

service接口的实现类的代码,如下:

@Override
    public int deleteById(Integer id) {
        long start = System.currentTimeMillis();
        int rows = goodsDao.deleteById(id);
        long end = System.currentTimeMillis();
        //System.out.println("execute time:"+(end-start));
        log.info("execute time:{}",(end-start));//可以输入到console,写可以写入到文件中
        return rows;
    }

service接口的实现类代码,如下:

@Override
    public int deleteById(Integer id) {
        long start = System.currentTimeMillis();
        int rows = goodsDao.deleteById(id);
        long end = System.currentTimeMillis();
        //System.out.println("execute time:"+(end-start));
        log.info("execute time:{}",(end-start));//可以输入到console,写可以写入到文件中
        return rows;
    }

在商品页面,点击删除按钮,将商品信息从页面中删除,进而显示最新商品信息。

练习三:将页面用户输入的商品信息写入到数据库。
controller层的代码,如下:

@RequestMapping("doGoodsAddUI")
    public String doGoodsAddUI() {
        return "goods_add";
    }
    
    
    //添加商品方式一
//    @RequestMapping("doSaveGoods")
//    public String doSaveGoods(Goods entity,Model model) {
//        goodsService.saveObject(entity);
//        List<Goods> list = goodsService.findGoods();
//        model.addAttribute("list", list);
//        return "redirect:/goods/doGoodsUI"; //跳转到goods.html
//    }
    
    //添加商品方式二
    @RequestMapping("doSaveGoods")
    public String doSaveGoods(String name,String remark,Model model) {
        goodsService.saveObject(name, remark);
        List<Goods> list = goodsService.findGoods();
        model.addAttribute("list", list);
        return "redirect:/goods/doGoodsUI"; 
    }

Dao层代码,如下:

/** 添加一条商品信息*/
    @Insert("insert into tb_goods(name,remark,createdTime) values(#{name},#{remark},now())")
//    int insertObject(Goods entity);  //方式一
    int insertObject(String name,String remark); //方式二

service层的代码,如下;

/**
     * 保存商品信息
     * @param entity  
     * @return
     */
//    int saveObject(Goods entity);
    int saveObject(String name,String remark);

service层实现类代码,如下:

@Override
    public int saveObject(String name,String remark) {
        long start = System.currentTimeMillis();
        int rows = goodsDao.insertObject(name,remark);
        long end = System.currentTimeMillis();
        log.info("execute time:{}",(end-start));//可以输入到console,写可以写入到文件中
        return rows;
    }
    

在商品页面,点击添加商品按钮,跳转到商品添加页面,填写商品的name和remark,点击save按钮,将商品信息写入到数据库中,进而在goods.html页面呈现最新商品信息

练习四:根据商品id进行修改操作 。 步骤:先根据商品id进行查询,再根据id进行修改操作。
controller层代码,如下:

@RequestMapping("doFindById/{id}")
    public String doFindById(@PathVariable Integer id,Model model) {
        Goods goods = goodsService.findById(id);
        model.addAttribute("goods", goods);
        return "goods_update";  //view name
    }
        
    
    @RequestMapping("doUpdateGoods")
    public String doSaveGoods(Goods entity) {
        goodsService.updateGoods(entity);
        return "forward:/goods/doGoodsUI";
        //return "redirect:/goods/doGoodsUI";
    }

Dao层代码,如下:

@Select("select * from tb_goods where id=#{id}")
    Goods findById(Integer id);
    
    
    /** 更新商品信息,将更新的商品信息写入到数据库中*/
    @Update("update tb_goods set name=#{name},remark=#{remark} where id=#{id}")
    int updateGoods(Goods entity);

service层的代码,如下:

int updateGoods(Goods entity);
    
Goods findById(Integer id);

service层实现类的代码,如下:

@Override
    public int updateGoods(Goods entity ) {
        int rows = goodsDao.updateGoods(entity);
        return rows;
    }
    
    @Override
    public Goods findById(Integer id) {
        //其它业务暂时不写
        Goods goods = goodsDao.findById(id);
        return goods;
    }

在商品页面,点击修改按钮,跳转的goods_update.html页面,获取商品的name和remark,进行修改操作,修改完后,点击update按钮,提交到服务器,在商品页面呈现最新商品信息。

练习总结:
API应用设计,如图-16所示:

image16.png

查询时序分析:如图-17所示
image31.png

删除时序分析:如图-18所示:
image11.png

添加时序分析:如图-19所示:
image26.png

修改时序分析,图略。

4 SpringBoot小节总结

4.1 重难点分析

  • 掌握基于Spring boot 实现HikariCP连接池整合与测试应用的过程
  • 掌握基于Spring boot 实现MyBatis框架资源的整合与测试。
  • 掌握基于Spring boot 实现Spring MVC资源的整合与测试。
  • 掌握Mybatis框架中的核心API以及应用关系
  • 掌握Spring MVC 中的核心API对象以及这些对象之间的调用关系。
  • 了解基于连接池获取数据库连接的基本过程。
  • 了解HiKariCP连接池常用API以及设计原理。
  • 了解thymeleaf模板引擎的基本应用过程(基于官方文档可以查询使用)。

4.2 FAQ分析

  • Java中连接池对象的标准API是什么?(DataSource)
  • Java中基于DataSource接口定义的连接池有哪些?(DBCP,C3P0,DRUID,HiKariCP,..)
  • Java中标准JDBC API中哪个对象负责与数据库建立连接?(Driver)
  • Java 中连接池中的连接也是通过Driver对象获取的吗?
  • SpringBoot 内置的连接池配置是什么?(HiKariCP)
  • SpringBoot 连接数据库的配置没有问题,数据库连不上?(服务,驱动)
  • SpringBoot 整合MyBatis时,为什么需要添加mybatis版本?
  • @Mapper注解的作用什么?(描述数据层接口,是由mybatis框架定义的规范,系统底层会基于此注解的描述

    • 为接口创建其实现类(子类)的对象,然后此对象会交给spring框架管理。)
  • @Mapper 描述数据层接口时,底层会为接口做点什么?(创建实现类,创建实现类对象,并将对象存储到spring容器-bean池。)
  • 框架底层基于@Mapper描述的接口创建实现类对象,其内部做什么?
  • SpringBoot 整合mybatis时候是否可以同时存在注解和xml的映射?
  • SpringBoot 整合mybatis时如何实现SQL日志的输出?
    在application.properties文件中添加 logging.level.com.cy=DEBUG即可
  • Spring MVC 核心组件对象有哪些?(DispatcherServlet,HandlerMapping,....)
  • Spring MVC 核心组件中DispatcherServlet的作用什么?
    前端控制器, 处理请求的入口。
  • Spring MVC 应用中请求参数的映射过程?(直接量,pojo对象)
  • Spring MVC 应用的请求转发和重定向?(服务端跳转-转发,客户端跳转-重定向)
  • 请求转发,如图所示:07-forward.png
  • 请求重定向,如图所示06-redirect.png
  • Thymeleaf 是什么,应用场景,官网的地址?(thymeleaf.org)
    Thymeleaf 是html页面的模板引擎。是适用于Web和独立环境的现代服务器端Java模板引擎。 应用场景:前后端分离 作用:能够处理HTML,XML,JavaScript,CSS甚至纯文本。
    Thymeleaf的优点:1. 开箱即用,它提供标准和spring标准两种方言,可以直接套用模板实现JSTL、 OGNL表达式效果,避免每天套模板、改jstl、改标签的困扰。同时开发人员也可以扩展和创建自定义的方言;
  1. Thymeleaf 提供spring标准方言和一个与 SpringMVC 完美集成的可选模块,可以快速的实现表单绑定、属性编辑器、国际化等功能。
  2. 有网无网的情况下模版页面都可以执行,美工的页面拿来就可以用,相对jsp减少了额外的标签,页面也更加简洁。
  • Thymeleaf 模板引擎中的标签属性如何使用?(查询官方docs文档)
  • STS 工具常用快捷键(alt+/,ctrl+shift+t,ctrl+t,ctrl+o, ctrl+n...)
  • 断点操作时f5不能进入方法内部,解决办法,如下:

(https://blog.csdn.net/fly_sky333/article/details/79516566)


人忘七年°
4 声望2 粉丝