🍜SpringBoot框架②


springboot框架端口 springboot框架详解_springboot框架端口



目录

  • 🍜SpringBoot框架②
  • 一、SpringBoot 整合 Mybatis
  • 1、环境搭建
  • ①、依赖导入
  • ②、项目目录(跟SSM差不多)
  • 2、实现增删查改(Rest风格编写crud)
  • ①三层开发以及映射代码
  • ②异常处理(自定义工具类)
  • ③目标对象Bean和启动类Starter
  • ④测试结果(因内容过多,不做过多细化统一处理)
  • 3、PostMan 工具下载与使用
  • 4、分页条件查询操作
  • ①、代码实现
  • ②、Rest测试结果(使用PostMan)
  • 二、SpringBoot-API && 测试单元
  • 1、API 文档构建工具 - Swagger2
  • ①、环境配置和配置类
  • ②、常用API注解
  • ③、对源代码使用API注解
  • 2、 SpringBoot 单元测试
  • ①、引入依赖
  • ②、测试Service层和Controller层
  • 三、分布式缓存和热部署
  • 1、分布式缓存 Ehcache 整合
  • ①、环境配置
  • ②、缓存注解的介绍
  • ③、通过缓存用户ID查询测试
  • 2、SpringBoot 应用热部署
  • ①、环境的配置
  • ②、热部署测试
  • 四、全局异常与事务控制、数据校验
  • 1、事务控制
  • 2、全局异常控制
  • 3、Springboot数据校验



一、SpringBoot 整合 Mybatis
1、环境搭建
  • 依赖的导入和插件引入,以及项目的目录结构(这里使用的是Mysql数据库)
①、依赖导入

pom.xml:>>>>

<!--springboot项目依赖-->
  <parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.2.2.RELEASE</version>
  </parent>

----------------------------------------------------
 <!--    web项目依赖-->
    <dependency> <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-web</artifactId>
    </dependency>

    <!--    web项目依赖-->
    <dependency> <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <!-- mybatis 集成 -->
    <dependency>
      <groupId>org.mybatis.spring.boot</groupId>
      <artifactId>mybatis-spring-boot-starter</artifactId>
      <version>2.1.1</version>
    </dependency>
    <!-- springboot 分页插件 -->
    <dependency>
      <groupId>com.github.pagehelper</groupId>
      <artifactId>pagehelper-spring-boot-starter</artifactId>
      <version>1.2.13</version>
    </dependency>
    <!-- mysql 驱动 -->
    <dependency>
      <groupId>mysql</groupId>
      <artifactId>mysql-connector-java</artifactId>
    </dependency>
    <!-- c3p0 数据源 -->
    <dependency>
      <groupId>com.mchange</groupId>
      <artifactId>c3p0</artifactId>
      <version>0.9.5.5</version>
    </dependency>

    <!--   日志依赖-->
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-logging</artifactId>
    </dependency>

②、项目目录(跟SSM差不多)

springboot框架端口 springboot框架详解_spring boot_02


不罗嗦上代码~


2、实现增删查改(Rest风格编写crud)
  • 首先实现简单的三层开发内容,以及Sql映射
  • Rest不理解的可以看我之前的文章SSM整合
①三层开发以及映射代码

mapper/UserMapper.java接口

public interface UserMapper {
    //查询
    User selectOne(String userName);
    User selectId(int userId);
    //插入
    int insert(User user);
    //删除
    int delete(int userId);
}

service/UserService.java接口和UserServiceImp.java实现类

//------------------接口------------------------------
public interface UserService {

    User findOne(String name);

    User findId(Integer id);

    void add(User user);

    void drop(Integer id);

}
//-----------------实现类-----------------------------
@Service
public class UserServiceImp implements UserService{

    @Autowired(required = false)
    private UserMapper userMapper;

    //通过用户名查找
    @Override
    public User findOne(String name) {
        return userMapper.selectOne(name);
    }

    //通过id查询用胡
    @Override
    public User findId(Integer id) {
        return userMapper.selectId(id);
    }

//添加插入
    @Override
    public void add(User user) {
        //可能是空数据引入插件
        AccessUtil.isOK(StringUtils.isBlank(user.getUserName()),"用户名不能为空");
        //判断用户id
        AccessUtil.isOK(StringUtils.isBlank(user.getUserPwd()),"密码不能为空");

        //查询是否重复
        User users=findOne(user.getUserName());
        AccessUtil.isOK(users!=null,"用户名不能重复");
        //判断插入是否成共
        AccessUtil.isOK(userMapper.insert(user)<1,"插入失败");

    }
//删除
    @Override
    public void drop(Integer id) {
        AccessUtil.isOK(id==null || findId(id)==null,"删除记录不存在~");
        //判断是否删除成功
        int num=userMapper.delete(id);
        AccessUtil.isOK(num<1,"删除失败!");
    }
}

controller/UserController.java

@RestController
public class SpringTest {
    @Autowired
    private UserService userService;

    @GetMapping("test")
    public String test(){
        return "is ok";
    }

    //查询
    @GetMapping("select/{name}")
    public User selectOne(@PathVariable("name") String name){
        return userService.findOne(name);
    }

    //查询
    @GetMapping("selectid/{userId}")
    public User selectid(@PathVariable("userId") Integer userId){
        return userService.findId(userId);
    }



    //插入
    @GetMapping("insert")
    public CheckMsg insert(User user){
        CheckMsg cm=new CheckMsg();
        //捕获异常
        try{
            userService.add(user);
            cm.setCode(100);
            cm.setMsg("插入成功");
        }catch (CheckException ce){
            cm.setCode(ce.getCode());
            cm.setMsg(ce.getMsg());
        }catch (Exception e){
            cm.setMsg(e.getMessage());
        }
        return cm;
    }
    //删除
    @RequestMapping("delete/{userId}")
    public CheckMsg delete(@PathVariable("userId") int userId){
        CheckMsg cm=new CheckMsg();
        //捕获异常
        try{
            userService.drop(userId);
            cm.setCode(100);
            cm.setMsg("删除成功");
        }catch (CheckException ce){
            cm.setCode(ce.getCode());
            cm.setMsg(ce.getMsg());
        }catch (Exception e){
            cm.setMsg(e.getMessage());
        }
        return cm;
    }

    @GetMapping("page")
    public PageInfo<User> pageSelect(PageQuery pq){
       return userService.PageSelect(pq);
    }

}

resources/mappers/UserMapper.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.yjxxt.mapper.UserMapper">
<!--    插入-->
    <insert id="insert">
        insert into user (userName,userPwd) values (#{userName},#{userPwd})
    </insert>
<!--    删除操作-->
    <delete id="delete">
        delete from user where userId=#{userId}
    </delete>
    <!--  查询-->
    <select id="selectOne" resultType="com.yjxxt.bean.User">
        select * from user where userName=#{userName}
    </select>
<!--    Id查询-->
    <select id="selectId" resultType="com.yjxxt.bean.User">
        select * from user where userId=#{userId}
    </select>
</mapper>

以上便实现了简单的增删查改,还差一点~~~


②异常处理(自定义工具类)
  • 引入依赖StringUtils 工具类
<!-- StringUtils 工具类,需要引入 commons-lang3 依赖。-->
    <dependency>
      <groupId>org.apache.commons</groupId>
      <artifactId>commons-lang3</artifactId>
    </dependency>

自定义异常类:exceptions/CheckException.java

public class CheckException extends RuntimeException{
    private int code=101;
    private String msg="发生异常》》》》";
//重载构造器,get和set方法自己不全~!!!
    public CheckException() {
        super("发生异常》》》》");
    }

    public CheckException(int code){
        super("发生异常》》》》");
        this.code=code;
    }

    public CheckException(String msg){
        super(msg);
        this.msg=msg;
    }

    public CheckException(String msg,int code){
        super(msg);
        this.msg=msg;
        this.code=code;
    }
}

com.yjxxt.util/CheckMsg.java自定义状态码对象:

public class CheckMsg {
    //状态码
    private int code=100;
    private String msg="插入成功";
    //自动补全set 、get方法
    }

com.yjxxt.util/AccessUtil.java对异常的间接调用

public class AccessUtil {
    //静态方法进行数据审核
    public static void isOK(boolean bl,String msg){
        if(bl){
            throw new CheckException(msg);
        }
    }
}

③目标对象Bean和启动类Starter

Bean/User.java这里字段与数据库最好同步

public class User implements Serializable {
    private String userName;
    private Integer userId;
    private String userPwd;
}

启动类:>>>>>

@SpringBootApplication
@MapperScan("com.yjxxt.mapper")//扫描mapper下内容
public class Starter {
    public static void main(String[] args) {
        SpringApplication.run(Starter.class,args);
    }
}

④测试结果(因内容过多,不做过多细化统一处理)

简单的浏览器测试一个:

springboot框架端口 springboot框架详解_java_03


根据用户名查询:

springboot框架端口 springboot框架详解_java_04


Rest风格URL插入,以及异常的展示:

springboot框架端口 springboot框架详解_postman_05


springboot框架端口 springboot框架详解_springboot框架端口_06


springboot框架端口 springboot框架详解_spring boot_07


总体上即完成了Mybatis的集成,也实现了异常的处理,还有PostMan辅助软件进行Rest风格URL测试,最后呢,想到此,应该有人发现貌似修改这个能力没有编写,这里直接省略,与插入的编写类似,不做多解释~~


3、PostMan 工具下载与使用

在企业 web 应用开发中,对服务器端接口进行测试,通常借助接口测试工具,这里使用 Postman 接口测试工具来对后台 restful 接口进行测试。
Postman 工具下载地址 : https://www.getpostman.com/apps ,选中对应平台下载即可。

springboot框架端口 springboot框架详解_java_08


下载安装后,启动 Postman 根据后台接口地址发送响应请求即可对接口进行测试。


4、分页条件查询操作
  • 其实就是通过Sql里的limit+动态sql+PageInfo类+PageHelper类实现

①、代码实现

自定义:query包/PageQuery.java

public class PageQuery {
    //第几页
    private Integer pageNum;
    //显示几条
    private Integer pageTotle;
    //查找的用户户名
    private String userName;
//get set toString 构造器记得生成!!!此处略
}

mapper/UserMapper.java

public interface UserMapper {
    //分页查找
    List<User> pageQuery(PageQuery pg);
}

service/UserService.java和UserServiceImp.java

public interface UserService {
    PageInfo<User> PageSelect(PageQuery pq);
}
//--------------------UserServiceImp.java------------
@Service
public class UserServiceImp implements UserService{

    @Autowired(required = false)
    private UserMapper userMapper;

    //分页查找
    @Override
    public PageInfo<User> PageSelect(PageQuery pq) {
        //进行分页初始化分页规则
        PageHelper.startPage(pq.getPageNum(),pq.getPageTotle());
        List<User> luser=userMapper.pageQuery(pq);
        //进行分页
        PageInfo<User> pagelist=new PageInfo<User>(luser);
        System.out.println(pagelist.isHasNextPage());
        System.out.println(pagelist.getPageNum());
        System.out.println(pagelist.isHasPreviousPage());
        return pagelist;
    }
}

controller/UserController.java

@RestController
public class SpringTest {
    @Autowired
    private UserService userService;
    
    @GetMapping("page")
    public PageInfo<User> pageSelect(PageQuery pq){
       return userService.PageSelect(pq);
    }

}

mappers/UserMapper.java: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" >
<mapper namespace="com.yjxxt.mapper.UserMapper">

<!--    分页查找-->
    <select id="pageQuery" resultType="com.yjxxt.bean.User">
-- 如果没有输入userName参数,则查询全部数据
-- select * from user where userName like %{userName}%
        select * from user
        <where>
            <if test="userName!=null and userName!=''">
                and userName like "%${userName}%"
            </if>
        </where>
    </select>
</mapper>

②、Rest测试结果(使用PostMan)

pageNum:第几页,pageTotle:显示几条,userName:查询用户的名字

springboot框架端口 springboot框架详解_postman_09


浏览器:

springboot框架端口 springboot框架详解_rest_10


二、SpringBoot-API && 测试单元

1、API 文档构建工具 - Swagger2
  • 由于 Spring Boot 能够快速开发、便捷部署等特性,通常在使用 Spring Boot 构建 Restful 接口应用时考虑到多终端的原因,这些终端会共用很多底层业务逻辑,因此我们会抽象出这样一层来同时服务于多个移动端或者Web 前端。对于不同的终端公用一套接口 API 时,对于联调测试的时候就需要知道后端提供的接口 API列表文档,对于服务端开发人员来说就需要编写接口文档,描述接口的调用地址、参数结果等,这里借助第三方构建工具 Swagger2 来实现 API 文档生成功能。

①、环境配置和配置类
  • 导入依赖
<!--API文档依赖-->
    <dependency>
      <groupId>io.springfox</groupId>
      <artifactId>springfox-swagger2</artifactId>
      <version>2.9.2</version>
    </dependency>
<!--    API生成依赖-->
    <dependency>
      <groupId>io.springfox</groupId>
      <artifactId>springfox-swagger-ui</artifactId>
      <version>2.9.2</version>
    </dependency>

API配置类config/swagger2.java

package com.yjxxt.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.builders.RequestHandlerSelectors;
import springfox.documentation.service.ApiInfo;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.annotations.EnableSwagger2;

@Configuration
@EnableSwagger2
public class Swagger2 {
    @Bean
    public Docket createRestApi() {
        return new Docket(DocumentationType.SWAGGER_2)
                .apiInfo(apiInfo())
                .select()
                .apis(RequestHandlerSelectors.basePackage("com.yjxxt.controller"))
                .paths(PathSelectors.any())
                .build();
    }
    private ApiInfo apiInfo() {
        return new ApiInfoBuilder()
                .title("用户管理接口API文档")
                .version("1.0")
                .build();
    }
}

②、常用API注解
  • @Api
@Api:用在请求的类上,说明该类的作用 
	tags="说明该类的作用"
----------------------------------------------
@Api(tags="APP用户注册Controller")
  • @ApiOperation
@ApiOperation:"用在请求的方法上,说明方法的作用" 
	value="说明方法的作用" 
	notes="方法的备注说明"
-----------------------------------------------
@ApiOperation(value="用户注册",notes="手机号、密码都是必填项,年龄是选填项,但必须是数字")
  • @ApiImplicitParams
@ApiImplicitParams:用在请求的方法上,包含一组参数说明 
	@ApiImplicitParam:用在 @ApiImplicitParams 注解中,指定一个请求参数的配置信息 
		name:参数名 
		value:参数的汉字说明、解释 
		required:参数是否必须传 
		paramType:参数放在哪个地方
			 · header --> 请求参数的获取:@RequestHeader
			  · query --> 请求参数的获取:@RequestParam 
			  · path(用于restful接口)--> 请求参数的获取:@PathVariable
			  · body(不常用)
			  · form(不常用)
	   dataType:参数类型,默认String,其它值dataType="Integer" 
	   defaultValue:参数的默认值
@ApiImplicitParams({ 
@ApiImplicitParam(name="mobile",value="手机 号",required=true,paramType="form"), 
@ApiImplicitParam(name="password",value="密 码",required=true,paramType="form"), 
@ApiImplicitParam(name="age",value="年 龄",required=true,paramType="form",dataType="Integer"
) })
  • @ApiResponses
@ApiResponses:用于请求的方法上,表示一组响应 
	@ApiResponse:用在@ApiResponses中,一般用于表达一个错误的响应信息 
		code:数字,例如400 
		message:信息,例如"请求参数没填好" 
		response:抛出异常的类
---------------------------------------------
@ApiOperation(value = "select请求", notes = "多个参数,多种的查询参数类型") 
@ApiResponses({ 
	@ApiResponse(code=400, message="请求参数没填好"), 
	@ApiResponse(code=404, message="请求路径没有或页面跳转路径不对")
 })
  • @ApiModel
@ApiModel:用于响应类上,表示一个返回响应数据的信息 
(这种一般用在post创建的时候,使用@RequestBody这样的场景, 请求参数无法使用@ApiImplicitParam注解进行描述的时候)
	 @ApiModelProperty:用在属性上,描述响应类的属性
@ApiModel(description= "返回响应数据")
public class RestMessage implements Serializable{ 
@ApiModelProperty(value = "是否成功") 
private boolean success=true;
@ApiModelProperty(value = "返回对象") 
private Object data; 
@ApiModelProperty(value = "错误编号") 
private Integer errCode; 
@ApiModelProperty(value = "错误信息") 
private String message; 
/* getter/setter */ 
}

③、对源代码使用API注解

User.java类加入API注解

@ApiModel(description = "响应结果-用户信息")
public class User implements Serializable {
    @ApiModelProperty(value = "用户名")
    private String userName;
    @ApiModelProperty(value = "用户id",example = "0")
    private Integer userId;
    @ApiModelProperty(value = "用户密码")
    private String userPwd;
 }

controller层/UserController.java

//此处只给这三个方法增夹了API注解,其余类似
@RestController
public class SpringTest {
    @Autowired
    private UserService userService;

    @ApiOperation(value = "测试springboot环境是否正常")
    @GetMapping("test")
    public String test(){
        return "is ok";
    }

    //查询
    @ApiOperation(value = "根据用户名查询用户信息")
    @ApiImplicitParam(name = "name",value = "查询参数",required = true,paramType = "path")
    @GetMapping("select/{name}")
    public User selectOne(@PathVariable("name") String name){
        return userService.findOne(name);
    }

    //查询
    @ApiOperation(value = "根据用户ID获取用户信息")
    @ApiImplicitParam(name = "userId",value = "查询参数",required = true,paramType = "path")
    @GetMapping("selectid/{userId}")
    @CachePut(value = "users", key = "#userId")
    public User selectid(@PathVariable("userId") Integer userId){
        return userService.findId(userId);
    }
}

启动项目,访问地址浏览器访问 :http://localhost:8081/springboot/swagger-ui.html

springboot框架端口 springboot框架详解_spring boot_11


springboot框架端口 springboot框架详解_springboot框架端口_12


springboot框架端口 springboot框架详解_java_13


2、 SpringBoot 单元测试

做过 web 项目开发的对于单元测试都并不陌生了,通过它能够快速检测业务代码功能的正确与否,SpringBoot 框架对单元测试也提供了良好的支持,来看 SpringBoot 应用中单元测试的使用。


①、引入依赖
<!--    单元测试-->
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-test</artifactId>
    </dependency>

②、测试Service层和Controller层

src/Test/java/com/yjxxt/bean/ServiceTest.java

@RunWith(SpringRunner.class)
@SpringBootTest(classes = {Starter.class})
public class ServiceTest {

    @Autowired
    private UserService userService;
    @Before
    public void before(){
        System.out.println("before........");
    }
    @Test
    public void test(){
        System.out.println(userService.findId(4));
    }

    @After
    public void after(){
        System.out.println("after........");
    }
}

springboot框架端口 springboot框架详解_rest_14

新建测试类ControllerTest.java

@RunWith(SpringRunner.class)
@SpringBootTest(classes = {Starter.class})
@AutoConfigureMockMvc
public class ControllerTest {
    private Logger log = LoggerFactory.getLogger(ControllerTest.class);
    @Autowired
    private MockMvc mockMvc;
    //用户列表查询
    @Test
    public void apiTest01() throws Exception{
        // 构建请求
        MockHttpServletRequestBuilder request = MockMvcRequestBuilders
                .get("/page")
                .contentType("text/html")
        // 指定请求的contentType头信息
                .accept(MediaType.APPLICATION_JSON);
        // 指定请求的Accept头信息
        // 发送请求,获取请求结果
        ResultActions perform = mockMvc.perform(request);
        // 请求结果校验
        perform.andExpect(MockMvcResultMatchers.status().isOk());
        // 表示执行完成后返回相应的结果
        MvcResult mvcResult = perform.andReturn();
        // 得到执行后的响应
        MockHttpServletResponse response = mvcResult.getResponse();
        log.info("响应状态:{}", response.getStatus());
        log.info("响应内容:{}", response.getContentAsString());
    }
    // 用户名记录查询
@Test
public void apiTest02() throws Exception{
        MvcResult mvcResult = mockMvc.perform(MockMvcRequestBuilders.get("/select/wang"))
                . andExpect(MockMvcResultMatchers.status().isOk()).andReturn();
        log.info("响应状态:{}",mvcResult.getResponse().getStatus());
        log.info("响应内容:{}",mvcResult.getResponse().getContentAsString());
    }
}

三、分布式缓存和热部署

1、分布式缓存 Ehcache 整合

EhCache 是一个比较成熟的 Java 缓存框架,最早从 hibernate 发展而来, 是进程中的缓存系统,它提供了用内存,磁盘文件存储,以及分布式存储方式等多种灵活的 cache 管理方案,快速简单。
Spring Boot 对 Ehcache 的使用提供支持,所以在 Spring Boot 中只需简单配置即可使用 Ehcache 实现数据缓存处理。


①、环境配置
  • 依赖导入
<!-- 缓存依赖Ehcache -->
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-cache</artifactId>
    </dependency>
    <dependency>
    <groupId>net.sf.ehcache</groupId>
    <artifactId>ehcache</artifactId>
    </dependency>

  • ehcache.xml配置文件
<ehcache name="mycache">
    <!--
      如果不使用磁盘存储,只需要将diskStore注释掉即可;
      如果使用,需要在ehcache.xml文件中的ehcahce元素下的定义一个diskStore元素并指定其path属性。
  -->
    <diskStore path="C:\java\cache"/>
    <!--
        name:缓存名称。
        maxElementsInMemory:缓存最大数目
        maxElementsOnDisk:硬盘最大缓存个数。
        eternal:对象是否永久有效,一但设置了,timeout将不起作用。
        overflowToDisk:是否保存到磁盘,当系统宕机时
        timeToIdleSeconds:设置对象在失效前的允许闲置时间(单位:秒)。
        	仅当eternal=false对象不是永久有效时使用,可选属性,默认值是0,表示可闲置时间无穷大。
        timeToLiveSeconds:设置对象在失效前允许存活时间(单位:秒)。
            最大时间介于创建时间和失效时间之间。
			仅当eternal=false对象不是永久有效时使用,默认是0,也就是对象存活时间无穷大。
        diskPersistent:是否缓存虚拟机重启期数据
			Whether the disk store persists between restarts of the Virtual Machine. 			 The default value is false.
        diskSpoolBufferSizeMB:这个参数设置DiskStore(磁盘缓存)的缓存区大小。
			默认是30MB。每个Cache都应该有自己的一个缓冲区。
        diskExpiryThreadIntervalSeconds:磁盘失效线程运行时间间隔,默认是120秒。
        memoryStoreEvictionPolicy:当达到maxElementsInMemory限制时,会根据指定的策略去清理内存
             默认策略是LRU(最近最少使用)。你可以设置为FIFO(先进先出)或是LFU(较少使用)。
        clearOnFlush:内存数量最大时是否清除。
        memoryStoreEvictionPolicy:
			可选策略有:
				LRU(最近最少使用,默认策略)
					Less Frequently Used,就是例子中使用的策略,就是一直以来最少被使用的。
				FIFO(先进先出)
					first in first out,这个是大家最熟的,先进先出。
				LFU(最少访问次数)
					Least Recently Used,最近最少使用的。
					缓存的元素有一个时间戳,当缓存容量满了,而又需要腾出地方来缓存新的元素的时候,
					那么现有缓存元素中时间戳离当前时间最远的元素将被清出缓存。
        -->
    <defaultCache
            maxElementsInMemory="10000"
            eternal="false"
            timeToIdleSeconds="120"
            timeToLiveSeconds="120"
            maxElementsOnDisk="10000000"
            diskExpiryThreadIntervalSeconds="120"
            memoryStoreEvictionPolicy="LRU">
    </defaultCache>

    <cache
            name="users"
            eternal="false"
            maxElementsInMemory="100"
            overflowToDisk="false"
            diskPersistent="false"
            timeToIdleSeconds="0"
            timeToLiveSeconds="300"
            memoryStoreEvictionPolicy="LRU"/>
</ehcache>

②、缓存注解的介绍
  • @CacheConfig
用于标注在类上,可以存放该类中所有缓存的公有属性,比如设置缓存的名字
@CacheConfig(cacheNames = "users") 
public interface UserService {。。。}

  • @Cacheable
//用于读取数据的方法上
@Cacheable(value = "user", key = "#id")
 User selectUserById(final Integer id);

  • @CachePut
//用于写数据的方法上
@CachePut(value = "user", key = "#user.id")
 public User save(User user) { users.add(user); return user; }

  • @CacheEvict
//用于移除数据的方法上
@CacheEvict(value = "user", key = "#id") 
void delete(final Integer id);

  • @CacheConfig
//组合多个 Cache 注解使用
@Caching(
	 put = { 
	 	@CachePut(value = "user", key = "#user.id"), 
		@CachePut(value = "user", key = "#user.username"),
 		@CachePut(value = "user", key = "#user.age") 
	 } 
 }

自动装配时,如果一个接口的实现类不止一个,则用@Resource指定名字装配,一个则使用@Autowired装配


③、通过缓存用户ID查询测试

UserService.java/selectid方法

@Service
public class UserServiceImp implements UserService{

    @Autowired(required = false)
    private UserMapper userMapper;

    //通过id查询用胡
    @Override
    @CachePut(value = "users", key = "#id")
    public User findId(Integer id) {
        return userMapper.selectId(id);
    }
   }

第一次查询

springboot框架端口 springboot框架详解_postman_15

删除控制台的查询信息,再次刷新页面查询

springboot框架端口 springboot框架详解_springboot框架端口_16


2、SpringBoot 应用热部署
  • 热部署,就是在应用正在运行的时候升级软件(增加业务/修改bug),却不需要重新启动应用。
  • 在原理上是使用了两个 ClassLoader,一个 ClassLoader 加载那些不会改变的类(第三方 Jar 包),另一个ClassLoader 加载会更改的类,称为 restart ClassLoader,这样在有代码更改的时候,原来的restart ClassLoader 被丢弃,重新创建一个 restart ClassLoader,由于需要加载的类相比较少,所以实现了较快的重启时间。

①、环境的配置
  • 引入依赖 DevTools同时在 plugin 中添加 devtools 生效标志
<!-- 热部署依赖DevTools 的坐标 -->
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-devtools</artifactId>
      <!--当前这个项目被继承之后,这个不向下传递-->
      <optional>true</optional>
    </dependency>
<!--打包工具-->
      <plugin>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-maven-plugin</artifactId>
        <configuration>
          <fork>true</fork>
          <!-- 如果没有该配置,热部署的devtools不生效 -->
        </configuration>
      </plugin>

devtools 可以实现页面热部署(即页面修改后会立即生效,这个可以直接在 application.properties文件中配置 spring.thymeleaf.cache=false 来实现),实现类文件热部署(类文件修改后不会立即生效),实现对属性文件的热部署。即devtools 会监听 classpath 下的文件变动,并且会立即重启应用(发生在保存时机),注意:因为其采用的虚拟机机制,该项重启是很快的。配置了后在修改 java 文件后也就支持了热启动,不过这种方式是属于项目重启(速度比较快的项目重启),会清空 session 中的值,也就是如果有用户登陆的话,项目重启后需要重新登陆。


  • 配置application.yml文件
## 热部署配置
  devtools:
    restart:
      enabled: true
      # 设置重启的目录,添加目录的文件需要restart
      additional-paths: src/main/java
      # 解决项目自动重新编译后接口报404的问题
      poll-interval: 3000
      quiet-period: 1000

  • IDEA配置
    自动编译配置File -> Settings -> Compiler -> Build Project automatically

springboot框架端口 springboot框架详解_java_17


Registry 属性修改 ctrl + shift + alt + /,选择Registry,勾上 Compiler autoMake allow when app running

springboot框架端口 springboot框架详解_rest_18

springboot框架端口 springboot框架详解_rest_19


②、热部署测试

springboot框架端口 springboot框架详解_springboot框架端口_20

修改接口代码 控制台打印接收的 userName 参数,ctrl+f9 键重新编译,浏览器访问

springboot框架端口 springboot框架详解_postman_21


四、全局异常与事务控制、数据校验
1、事务控制

这里 Spring Boot 集成了 mybatis 框架,mybatis 底层数据访问层实现基于 jdbc 来实现,所以在Spring Boot 环境下对事务进行控制,事务实现由 Spring Boot 实现并自动配置,在使用时通过注解方式标注相关方法加入事务控制即可。

在相关方法上加上注解@Transactional()即可

@Transactional(propagation = Propagation.REQUIRED)

2、全局异常控制
  • 首先编写一个全局异常类GlobalExceptionHandler
  • @ExceptionHandler:
    该注解在 Spring 3.X 版本引入,在处理异常时标注在方法级别,代表当前方法处理的异常类型有哪些具体应用以 Restful 接口为例,测试保存用户接口。
  • @ControllerAdvice:
    该注解组合了 @Component 注解功能,最常用的就是作为全局异常处理的切面类,同时通过该注解可以指定包扫描的范围。@ControllerAdvice 约定了几种可行的返回值,如果是直接返回 model 类的话,需要使用@ResponseBody 进行 json 转换
//全局异常处理类
    @ControllerAdvice
    public class GlobalExceptionHandler{
        /*** 全局异常处理 返回json*/
        @ExceptionHandler(value = Exception.class)
        @ResponseBody
        public CheckMsg exceptionHandler(Exception e){
            CheckMsg resultInfo = new CheckMsg();
            resultInfo.setCode(300);
            resultInfo.setMsg("操作失败!");
            if(e instanceof CheckException){
                CheckException pe = (CheckException) e;
                resultInfo.setMsg(pe.getMsg());
                resultInfo.setCode(pe.getCode());
            }
            return resultInfo;
        }
    }

这里对我们的全局异常类进行测试,将ID查询直接报异常看是否能够捕获到

//查询
    @ApiOperation(value = "根据用户ID获取用户信息")
    @ApiImplicitParam(name = "userId",value = "查询参数",required = true,paramType = "path")
    @GetMapping("selectid/{userId}")
    @CachePut(value = "users", key = "#userId")
    public User selectid(@PathVariable("userId") Integer userId){
    //报异常
        AccessUtil.isOK(true,"测试一下......");
        return null;
    }

springboot框架端口 springboot框架详解_spring boot_22


3、Springboot数据校验

常用注解校验如下:

springboot框架端口 springboot框架详解_postman_23


案列演示:》》》①、对User类添加注解

@ApiModel(description = "响应结果-用户信息")
public class User implements Serializable {
    @NotBlank(message = "用户名不能为空!")
    @ApiModelProperty(value = "用户名")
    private String userName;

    @ApiModelProperty(value = "用户id",example = "0")
    private Integer userId;
    @NotBlank(message = "用户ID不能为空!")
    @Length(min = 6, max = 10,message = "密码长度至少6位但不超过10位!")
    @ApiModelProperty(value = "用户密码")
    private String userPwd;
}
//set和get方法略

②、UserController.java插入方法增加@Valid和修改

//插入
    @PostMapping("insert")
    public CheckMsg insert(@Valid User user){
        CheckMsg cm=new CheckMsg();
//        //捕获异常
//        try{
            userService.add(user);
            cm.setCode(100);
            cm.setMsg("插入成功");
//        }catch (CheckException ce){
//            cm.setCode(ce.getCode());
//            cm.setMsg(ce.getMsg());
//        }catch (Exception e){
//            cm.setMsg(e.getMessage());
//        }
        return cm;
    }

测试结果:》》》

springboot框架端口 springboot框架详解_spring boot_24

springboot框架端口 springboot框架详解_postman_25


完结撒花~~~~

springboot框架端口 springboot框架详解_rest_26