SpringBoot

1Spring 的优缺点分析

1 Spring的优点分析

Spring是Java企业版(Java Enterprise Edition,JEE,也称J2EE)的轻量级代替品。无需开发重量级的Enterprise JavaBean(EJB),Spring为企业级Java开发提供了一种相对简单的方法,通过依赖注入和面向切面编程,用简单的Java对象(Plain Old Java Object,POJO)实现了EJB的功能。

2 Spring的缺点分析

虽然Spring的组件代码是轻量级的,但它的配置却是重量级的。一开始,Spring用XML配置,而且是很多XML配置。Spring 2.5引入了基于注解的组件扫描,这消除了大量针对应用程序自身组件的显式XML配置。Spring 3.0引入了基于Java的配置,这是一种类型安全的可重构配置方式,可以代替XML。

所有这些配置都代表了开发时的损耗。因为在思考Spring特性配置和解决业务问题之间需要进行思维切换,所以编写配置挤占了编写应用程序逻辑的时间。和所有框架一样,Spring实用,但与此同时它要求的回报也不少。

除此之外,项目的依赖管理也是一件耗时耗力的事情。在环境搭建时,需要分析要导入哪些库的坐标,而且还需要分析导入与之有依赖关系的其他库的坐标,一旦选错了依赖的版本,随之而来的不兼容问题就会严重阻碍项目的开发进度。

1. Spring 的优点
   1.1 Spring 是什么? 一个框架、解决Java企业开发复杂度
   1.2 Spring 优点? IOC/AOP/容器/非侵入式
   IOC/DI区别(编程思想/具体实现)
   
2. Spring 的缺点
   1.配置复杂
   2.依赖复杂

2. SpringBoot 的概述

1约定优于配置

其实人们把Spring Boot 称为搭建程序的脚手架。其最主要作用就是帮我们快速的构建庞大的spring项目,并且尽可能的减少一切xml配置,做到开箱即用,迅速上手,让我们关注与业务而非配置。

java一直被人诟病的一点就是臃肿、麻烦。当我们还在辛苦的搭建项目时,可能Python程序员已经把功能写好了,究其原因注意是两点:

  • 复杂的配置

    项目各种配置其实是开发时的损耗, 因为在思考 Spring 特性配置和解决业务问题之间需要进行思维切换,所以写配置挤占了写应用程序逻辑的时间。

  • 一个是混乱的依赖管理

    项目的依赖管理也是件吃力不讨好的事情。决定项目里要用哪些库就已经够让人头痛的了,你还要知道这些库的哪个版本和其他库不会有冲突,这难题实在太棘手。并且,依赖管理也是一种损耗,添加依赖不是写应用程序代码。一旦选错了依赖的版本,随之而来的不兼容问题毫无疑问会是生产力杀手。

Spring Boot 简化了基于Spring的应用开发,只需要“run”就能创建一个独立的、生产级别的Spring应用。Spring Boot为Spring平台及第三方库提供开箱即用的设置(提供默认设置,存放默认配置的包就是启动器starter),这样我们就可以简单的开始。多数Spring Boot应用只需要很少的Spring配置。

3. SpringBoot的特点

Spring Boot 主要目标是:

  • 为所有 Spring 的开发者提供一个非常快速的、广泛接受的入门体验
  • 开箱即用(启动器starter-其实就是SpringBoot提供的一个jar包),但通过自己设置参数(.properties),即可快速摆脱这种方式。
  • 提供了一些大型项目中常见的非功能性特性,如内嵌服务器、安全、指标,健康检测、外部化配置等
  • 绝对没有代码生成,也无需 XML 配置。

4、SpringBoot 的两个核心功能

  1. 起步依赖: 将具有某种功能的坐标打包到一起,统一对外提供服务
  2. 自动配置: 采用大量的默认配置,用户零配置或者少量配置

1)起步依赖

起步依赖本质上是一个Maven项目对象模型(Project Object Model,POM),定义了对其他库的传递依赖,这些东西加在一起即支持某项功能。

简单的说,起步依赖就是将具备某种功能的坐标打包到一起,并提供一些默认的功能。

在这里插入图片描述

在这里插入图片描述

2)自动配置

Spring Boot的自动配置是一个运行时(更准确地说,是应用程序启动时)的过程,考虑了众多因素,才决定Spring配置应该用哪个,不该用哪个。该过程是Spring自动完成的。

采用大量的默认配置,用户零配置或者少量配置

1. SpringBoot 的项目需要继承哪个parent ?

spring-boot-starter-parent
  1. spring-boot-starter-parent 的作用是

    依赖版本锁定

3 流程分析

1pom.xml
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.1.4.RELEASE</version>
    </parent>

    <dependencies>
              <!--SpringBoot 的 SpringMVC 起步依赖-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
    </dependencies>
2启动类 @SpringBootApplication注解
  1. 什么是引导类?
    引导类就是带 @SpringBootApplication 注解 的普通 Java 类
  2. SpringBoot 引导类要怎么编写?
  • 注解:@SpringBootApplication 包含了一下三个注解

    @SpringBootConfiguration

    ​ 在这个注解上面,又有一个@Configuration注解。通过’上面的注释阅读我们知道:这个注解的作用就是声明当前类是一个配置类,然后Spring会自动扫描到添加了@Configuration的类,并且读取其中的配置信息。而@SpringBootConfiguration是来声明当前类是SpringBoot应用的配置类,项目中只能有一个。所以一般我们无需自己添加。

    @EnableAutoConfiguration

    SpringBoot内部对大量的第三方库或Spring内部库进行了默认配置,这些配置是否生效,取决于我们是否引入了对应库所需的依赖,如果有那么默认配置就会生效。

    所以,我们使用SpringBoot构建一个项目,只需要引入所需框架的依赖,配置就可以交给SpringBoot处理了。除非你不希望使用SpringBoot的默认配置,它也提供了自定义配置的入口。

    @ComponentScan

  • run方法:SpringApplication.run()

@SpringBootApplication
public class MySpringBootApplication {
	public static void main(String[] args) {
        SpringApplication.run(MySpringBootApplication.class, args);
	}
}
3 SpringMVC Controller 接口?

@RestController @GetMapping

引导类的同一级或者下一级,SpringBootApplication已经扫包

  1. SpringBoot 的 SpringMVC 起步依赖是什么?

    spring-boot-starter-web
    
//@RestController   等于下面的和
		//@Controller
		//@ResponseBody //返回JSON格式数据


@RestController 
@RequestMapping("/quick")
public class QuickController {

	@GetMapping
	public String quick() {
		return "SpringBoot 从入门到精通!!";
	}
}
4 测试 junit

起步依赖:

<!--springboot集成junit起步依赖-->
<dependency>
   <groupId>org.springframework.boot</groupId>
   <artifactId>spring-boot-starter-test</artifactId>
   <scope>test</scope>
</dependency>

//替换运行器
@RunWith(SpringRunner.class)
//指定启动类
//@SpringBootTest(classes = XiaofeifeiApplication.class)
@SpringBootTest  //如果测试类在引导类的同级目录或者子目录下可以省略指定
public class Test01_junit {


    @Autowired
    private BookService bookService;

    @Test
    public void test(){
        Book book = bookService.queryById(1);
        System.out.println(book);
    }
}

4.1配置文件

SpringBoot的properties的配置文件的名称是? application.properties

1 yml配置

目标
掌握yml文件的语法,创建普通数据、对象数据、对象数组数据

yaml文件介绍:

YML文件格式是YAML (YAML Aint Markup Language)编写的文件格式,YAML是一种直观的能够被电脑识别的的数据序列化格式,并且容易被人类阅读,容易和脚本语言交互的,可以被支持YAML库的不同的编程语言程序导入,比如: C/C++, Ruby, Python, Java, Perl, C#, PHP等。YML文件是以数据为核心的,比传统的xml方式更加简洁。
YML文件的扩展名可以使用.yml或者.yaml。

核心代码

#普通数据:  冒号后面必须有空格
name: 小鸭鸭
age: 15

#对象数据
person:
  name: 小飞飞
  age: 16
  gender:#数组
addr:
  - 天河九巷
  - 天河八巷
  - 天河十巷
  
#对象数组
persons:
  - name: 小野鸡
    age: 18
  - name: 小龟龟
    age: 6

小结:

1)多个yml配置文件;在spring boot中是被允许的。这些配置文件的名称必须为application-***.yml,并且这些配置文件必须要在application.yml【这个必须有】配置文件中激活之后才可以使用。

#激活配置文件;需要指定其它的配置文件名称
spring:
  profiles:
    active: prod,dev

2)如果properties和yml配置文件同时存在在spring boot项目中;那么这两类配置文件都有效。在两个配置文件中如果存在同名的配置项的话会以properties文件的为主。

2 读取配置文件内容

掌握读取配置文件的两种方法

读取配置文件的两种方法涉及到的两个注解分别是?

  1. @Value
  2. @ConfigurationProperties

核心代码

第一种方法:@Value : 基本数据类型和String

package com.itheima.controller;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

/*@Controller
@ResponseBody*/

/**
 * Controller
 * @author Johnny.Chen
 *
 */
@RestController
public class HelloController {
	
	@Value("${person.name}")
	private String n;
	
	@Value("${person.age}")
	private int a;
	
	//@RequestMapping(value="/sayHello",method=RequestMethod.GET)
	@GetMapping("/sayhello")
	public String sayHello() {
		return n+" 真的好骚啊!===>"+a;
	}

}


第二种方法:@ConfigurationProperties: 除了基本数据类型和String之外还可以注入数组

package com.itheima.controller;

import java.util.Arrays;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

/*@Controller
@ResponseBody*/

/**
 * Controller
 * @author Johnny.Chen
 *
 */
@RestController
@ConfigurationProperties(prefix="person")
public class HelloController2 {
	
	private String name;
	private int age;
	private String[] addr;
	
	public String[] getAddr() {
		return addr;
	}
	public void setAddr(String[] addr) {
		this.addr = addr;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public int getAge() {
		return age;
	}
	public void setAge(int age) {
		this.age = age;
	}


	//@RequestMapping(value="/sayHello",method=RequestMethod.GET)
	@GetMapping("/sayhello2")
	public String sayHello() {
		return name+" 真的好骚啊!===>"+age+"====>"+Arrays.toString(addr);
	}

}


3.总结

SpringBoot为我们提供了默认配置,而默认配置生效的步骤:

  • @EnableAutoConfiguration注解会去寻找META-INF/spring.factories文件,读取其中以EnableAutoConfiguration为key的所有类的名称,这些类就是提前写好的自动配置类
  • 这些类都声明了@Configuration注解,并且通过@Bean注解提前配置了我们所需要的一切实例。完成自动配置
  • 但是,这些配置不一定生效,因为有@ConditionalOn注解,满足一定条件才会生效。比如条件之一:是一些相关的类要存在
  • 类要存在,我们只需要引入了相关依赖(启动器),依赖有了条件成立,自动配置生效。
  • 如果我们自己配置了相关Bean,那么会覆盖默认的自动配置的Bean
  • 我们还可以通过配置application.yml文件,来覆盖自动配置中的属性

1)启动器

所以,我们如果不想配置,只需要引入依赖即可,而依赖版本我们也不用操心,因为只要引入了SpringBoot提供的stater(启动器),就会自动管理依赖及版本了。

因此,玩SpringBoot的第一件事情,就是找启动器,SpringBoot提供了大量的默认启动器

2)全局配置

另外,SpringBoot的默认配置,都会读取默认属性,而这些属性可以通过自定义application.properties文件来进行覆盖。这样虽然使用的还是默认配置,但是配置中的值改成了我们自定义的。

因此,玩SpringBoot的第二件事情,就是通过application.properties来覆盖默认属性值,形成自定义配置。我们需要知道SpringBoot的默认属性key,非常多,可以再idea中自动提示

5 快速构建SpringBoot项目

掌握快速构建SpringBoot项目的方法

配置步骤

1、要在一个网络环境较好的地方去创建

2、创建项目选择Spring Initializr 项目

3、勾选需要的起步依赖即可

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

如果有两个以上的SpringBoot的项目,右下角会弹出一个框:

在这里插入图片描述

点击向下箭头

在这里插入图片描述

RunDashboard界面:

在这里插入图片描述

扩展:spring的banner

只需要在resource目录下,创建banner.txt

在这里插入图片描述

${AnsiColor.BRIGHT_YELLOW}

//                          _ooOoo_                               //
//                         o8888888o                              //
//                         88" . "88                              //
//                         (| ^_^ |)                              //
//                         O\  =  /O                              //
//                      ____/`---'\____                           //
//                    .'  \\|     |//  `.                         //
//                   /  \\|||  :  |||//  \                        //
//                  /  _||||| -:- |||||-  \                       //
//                  |   | \\\  -  /// |   |                       //
//                  | \_|  ''\---/''  |   |                       //
//                  \  .-\__  `-`  ___/-. /                       //
//                ___`. .'  /--.--\  `. . ___                     //
//              ."" '<  `.___\_<|>_/___.'  >'"".                  //
//            | | :  `- \`.;`\ _ /`;.`/ - ` : | |                 //
//            \  \ `-.   \_ __\ /__ _/   .-` /  /                 //
//      ========`-.____`-.___\_____/___.-`____.-'========         //
//                           `=---='                              //
//      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^        //
//            佛祖保佑       永不宕机     永无BUG                  //

${AnsiColor.BRIGHT_GREEN}
Application Version: ${application.version}${application.formatted-version}
Spring Boot Version: ${spring-boot.version}${spring-boot.formatted-version}

小结

创建的 Spring Initializr 项目一定要联网吗?

6 SpringBoot整合 - lombok应用

我们编写pojo时,经常需要编写构造函数和gettersetter方法,属性多的时候,就非常浪费时间,使用lombok插件可以解决这个问题:

在idea中安装lombok插件:

在这里插入图片描述

需要在maven中引入依赖:

 <dependency>
     <groupId>org.projectlombok</groupId>
     <artifactId>lombok</artifactId>
     <version>1.18.6</version>
     <scope>provided</scope>
 </dependency>

然后可以在Bean上使用:

@Data :自动提供getter和setter、hashCode、equals、toString等方法

@Getter:自动提供getter方法

@Setter:自动提供setter方法

@Slf4j:自动在bean中提供log变量,其实用的是slf4j的日志功能。

@ToString:生成toString方法

@NonNull:这个注解可以用在成员方法或者构造方法的参数前面,会自动产生一个关于此参数的非空检查,如果参数为空,则抛出一个空指针异常。

例如,我们在javabean上加@Data,那么就可以getter和setter等方法的编写,lombok插件会帮我们自动生成:

package com.itheima.pojo;

import lombok.*;

@ToString
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Book {
    private Integer id;
    private String bookname;
    private Long price;
    private String pic;
    private String bookdesc;
}

7.SpringBoot整合 - Mybatis

1.Mybaties

<!--mybatis -->
<dependency>
    <groupId>org.mybatis.spring.boot</groupId>
    <artifactId>mybatis-spring-boot-starter</artifactId>
    <version>2.0.1</version>
</dependency>

配置,一些文件位置相关的,mybatis知道,需要我们来指定:

#mybatis配置
mybatis:
  type-aliases-package: com.leyou.pojo  #配置实体类的别名
  mapper-locations:
    - classpath:/mapper/*.xml  #扫描配置映射文件
  configuration:
    map-underscore-to-camel-case: true  #驼峰命名

Mapper接口的扫描有两种实现方式:

Mapper接口的位置在application.yml中并不能配置,Mapper接口的扫描有两种实现方式:

方式一

我们需要给每一个Mapper接口添加@Mapper注解,由Spring来扫描这些注解,完成Mapper的动态代理。

@Mapper
public interface UserDao {
}

方式二

在启动类上添加扫描包注解@MapperScan (推荐):

这种方式的好处是,不用给每一个Mapper都添加注解。

@SpringBootApplication
@MapperScan("cn.itcast.mapper")
public class Application {
    public static void main(String[] args) {
        // 启动代码
        SpringApplication.run(Application.class, args);
    }
}

2.通用mapper(重点)

通用Mapper的作者也为自己的插件编写了启动器,我们直接引入即可:

<!-- 通用mapper -->
<dependency>
    <groupId>tk.mybatis</groupId>
    <artifactId>mapper-spring-boot-starter</artifactId>
    <version>2.1.5</version>
</dependency>

注意一旦引入了通用Mapper的启动器,会覆盖Mybatis官方启动器的功能,因此需要移除对官方Mybatis启动器的依赖。

无需任何配置就可以使用了。如果有特殊需要,可以到通用mapper官网查看:https://github.com/abel533/Mapper/wiki/3.config

另外,我们需要把启动类上的@MapperScan注解修改为通用mapper中自带的

注意 @MapperScan是tk.mybatis.spring.annotation包下的,用于扫描Mapper接口

在这里插入图片描述

通用mapper的使用步骤

1)继承Mapper接口

继承了Mapper接口,就自动实现了增删改查的常用方法。

public interface UserDao extends Mapper<User>{
}
2)在实体类上加JPA注解:

@Table 和 **@Id都是JPA注解,@Table**用于配置表与实体类的映射关系,@Id用于标识主键属性。

@Table(name = "tb_user")// 表名
public class User{
    @Id
    @KeySql(useGeneratedKeys = true) // 开启自增主键回显功能
    private Long id;
    
  	@Column(name = "user-Name")  // 若实体类与表字段不对应 需要指定
    private String userName;
    private String password;
    private String name;
    private Integer age;
    private Integer sex;
    private Date birthday;
    private Date created;
    private Date updated;
    private String note;
}

在这里插入图片描述

对UserService的代码进行简单改造:

@Service
public class UserService {

    @Autowired
    private UserDao userDao;

    public User queryById(Long id){
        // 查询
        return userDao.selectByPrimaryKey(id);
    }

    @Transactional
    public Integer saveUser(User user){
        // 新增
        return userDao.insertSelective(user);
    }
}

8.SpringBoot整合 - SpringMVC

虽然默认配置已经可以使用SpringMVC了,不过我们有时候需要进行自定义配置。

1 日志控制

@Slf4j //加入这个注解就可以使用日志

日志级别控制:

logging:
  level:
  	root: info   #所有包的日志基本
    cn.itcast: debug
    org.springframework: debug

其中:

  • logging.level:是固定写法,说明下面是日志级别配置,日志相关其它配置也可以使用。
  • cn.itcast和org.springframework是指定包名,后面的配置仅对这个包有效。
  • debug:日志的级别

我们编写的控制器加入日志:

@RestController   
@Slf4j   //加入这个注解就可以使用日志
public class ConfigController {

    //映射
    @GetMapping("/hello1")
    public String sayHello(){
        
        //记录日志
        log.debug("debug  小鸭鸭大战冲击钻");
        log.info("info  小飞飞大战乔碧萝!");
        log.warn("warn   告警日志:弗利萨来了。。。");
        log.error("error  错误日志。。。。。。");


        return ".....";
    }
}

2.访问静态资源

现在,我们的项目是一个jar工程,那么就没有webapp,我们的静态资源该放哪里呢?

回顾我们上面看的源码,有一个叫做ResourceProperties的类,里面就定义了静态资源的默认查找路径:

在这里插入图片描述

默认的静态资源路径为:

  • classpath:/META-INF/resources/
  • classpath:/resources/
  • classpath:/static/
  • classpath:/public

只要静态资源放在这些目录中任何一个,SpringMVC都会帮我们处理。

我们习惯会把静态资源放在classpath:/static/目录下。我们创建目录,并且添加一些静态资源:

在这里插入图片描述

重启项目后测试,访问图片,如果配置了上下文路径,记得加上

在这里插入图片描述

3.添加拦截器

拦截器也是我们经常需要使用的,在SpringBoot中该如何配置呢?

拦截器不是一个普通属性,而是一个类,所以就要用到java配置方式了。在SpringBoot官方文档中有这么一段

如果你想要保持Spring Boot 的一些默认MVC特征,同时又想自定义一些MVC配置(包括:拦截器,格式化器, 视图控制器、消息转换器 等等),你应该让一个类实现WebMvcConfigurer,并且添加@Configuration注解,但是千万不要@EnableWebMvc注解。如果你想要自定义HandlerMappingHandlerAdapterExceptionResolver等组件,你可以创建一个WebMvcRegistrationsAdapter实例 来提供以上组件。

如果你想要完全自定义SpringMVC,不保留SpringBoot提供的一切特征,你可以自己定义类并且添加@Configuration注解和@EnableWebMvc注解

通过实现WebMvcConfigurer并添加@Configuration注解来实现自定义部分SpringMvc配置。

首先我们定义一个拦截器:

@Slf4j
public class LoginInterceptor implements HandlerInterceptor {

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
        log.debug("preHandle method is now running!");
        return true;
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) {
        log.debug("postHandle method is now running!");
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {
        log.debug("afterCompletion method is now running!");
    }
}

然后,我们定义配置类,注册拦截器:

@Configuration
public class MvcConfig implements WebMvcConfigurer{
    /**
     * 重写接口中的addInterceptors方法,添加自定义拦截器
     * @param registry
     */
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        // 通过registry来注册拦截器,通过addPathPatterns来添加拦截路径
        registry.addInterceptor(new LoginInterceptor()).addPathPatterns("/**");
    }
}

结构如下:

在这里插入图片描述

接下来运行并查看日志:

你会发现日志中什么都没有,因为我们记录的log级别是debug,默认是显示info以上,我们需要进行配置。

SpringBoot通过logging.level.*=debug来配置日志级别,*填写包名

# 设置com.leyou包的日志级别为debug
logging:
  level:
    com.leyou=debug

再次运行查看:

2018-05-05 17:50:01.811 DEBUG 4548 --- [p-nio-80-exec-1] com.leyou.interceptor.LoginInterceptor   : preHandle method is now running!
2018-05-05 17:50:01.854 DEBUG 4548 --- [p-nio-80-exec-1] com.leyou.interceptor.LoginInterceptor   : postHandle method is now running!
2018-05-05 17:50:01.854 DEBUG 4548 --- [p-nio-80-exec-1] com.leyou.interceptor.LoginInterceptor   : afterCompletion method is now running!

9. SpringBoot整合 - Redis

1 添加redis的起步依赖

<!-- 配置使用redis启动器 -->
<dependency>
   <groupId>org.springframework.boot</groupId>
   <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>

2 配置redis的连接信息

#Redis 配置信息
#远程
#spring.redis.host=192.168.207.50
#spring.redis.port=6379
#如果设置了需要密码,则需要添加密码
#spring.redis.password=12345678

#本地
spring.redis.host=127.0.0.1
spring.redis.port=6379

3 注入RedisTemplate测试redis操作

package com.leyou.test;

import com.leyou.pojo.Book;
import com.leyou.service.BookService;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.test.context.junit4.SpringRunner;

//替换运行器
@RunWith(SpringRunner.class)
//指定启动类
//@SpringBootTest(classes = XiaofeifeiApplication.class)
@SpringBootTest  //如果测试类在引导类的同级目录或者子目录下可以省略指定
public class Test02_redis {


    /**
     * serivce
     */
    @Autowired
    private BookService bookService;


    //redis模板
    @Autowired
    private RedisTemplate redisTemplate;

    /*
    缓存使用:
        1、先去缓存中找
            1.1 如果没有,去数据库中找,找到返回之前先存入缓存中
            1.2 如果有直接返回
     */
    @Test
    public void test(){


        //书本id
        int id = 1;

        //去缓存中找
        Book book = (Book) redisTemplate.opsForValue().get("book_"+id);
        if(book==null){
            //1.1 如果没有,去数据库中找,找到返回之前先存入缓存中
            book = bookService.queryById(1);
            //保存到缓存中
            redisTemplate.opsForValue().set("book_"+id, book);
            //返回
            System.out.println("从数据库中找:"+book);
        }else{
            System.out.println("从缓存中找:"+book);
        }

    }
}

10、SpringBoot整合 - JDBC与连接池

1.整合jdbc和事务

1 spring中的jdbc连接和事务是配置中的重要一环,在SpringBoot中该如何处理呢?

答案是不需要处理,我们只要找到SpringBoot提供的启动器即可:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>

2数据库驱动,SpringBoot并不知道我们用的什么数据库,这里我们选择MySQL:

<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>5.1.47</version>
</dependency>

3 SpringBoot中通过注解来控制。就是我们熟知的@Transactional

@Service
public class UserService {

    public User queryById(Long id){
        // 开始查询
        return new User();
    }

    @Transactional
    public void deleteById(Long id){
        // 开始删除
        System.out.println("删除了: " + id);
    }
}

2.整合连接池

其实,在刚才引入jdbc启动器的时候,SpringBoot已经自动帮我们引入了一个连接池:

在这里插入图片描述

HikariCP应该是目前速度最快的连接池了,我们看看它与c3p0的对比:

在这里插入图片描述

因此,我们只需要指定连接池参数即可:

spring:
  datasource:
    driver-class-name: com.mysql.jdbc.Driver
    url: jdbc:mysql://localhost:3306/mydb01
    username: root
    password: root

11. 公共异常处理

统一异常的处理器

为了使我们的代码更容易维护,我们创建一个类集中处理异常

import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;

@ControllerAdvice    //在controller中抛出的异常都能被该类统一解析
public class BaseExceptionHandler {

//注意:@ControllerAdvice注解,全局捕获异常类,所有的异常都会被捕获。
    @ExceptionHandler(value = Exception.class)
    @ResponseBody//返回json数据
    public Result error(Exception e) {
        e.printStackTrace();
        return new Result(false, StatusCode.ERROR, e.getMessage());
    }
}


import com.baomidou.mybatisplus.extension.api.R;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.boot.autoconfigure.AutoConfigureBefore;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
import org.springframework.boot.autoconfigure.web.ErrorProperties;
import org.springframework.boot.autoconfigure.web.ResourceProperties;
import org.springframework.boot.autoconfigure.web.ServerProperties;
import org.springframework.boot.autoconfigure.web.servlet.WebMvcAutoConfiguration;
import org.springframework.boot.autoconfigure.web.servlet.error.BasicErrorController;
import org.springframework.boot.autoconfigure.web.servlet.error.ErrorViewResolver;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.boot.web.servlet.error.ErrorAttributes;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.MissingServletRequestParameterException;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.servlet.DispatcherServlet;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.Servlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Collections;
import java.util.List;
import java.util.Map;


   /* 自定义异常处理  下面有两种方式自定义异常处理

        对于应用级别的业务异常处理,我们可以通过注解 @ControllerAdvice 或 @RestControllerAdvice
    来实现异常处理。但是上面的注解只能捕获处理应用级别的异常,

        例如 Controller 中抛出自定义的异常。却不能处理容器级别的异常,例如 Filter 中抛出的异常等。
    要想处理容器级别的异常,需要继承 BasicErrorController 类,重写 errorHtml 和 error 方法。或者实现 ErrorController 接口,
    起到和类 BasicErrorController 相似的作用。

    */


   /*     (一) 处理应用级别异常

            @RestControllerAdvice 与 @ControllerAdvice +@ResponseBody 起到的作用是一样的

     @ExceptionHandler 里面的 value 的类是我们捕获的处理异常, 此类异常会被defaultErrorHandler 方法处理.
     @ResponseStatus(HttpStatus.BAD_REQUEST) 注解, 指定了此异常返回的状态码, 因为是缺少参数, 所以返回 400 的状态码

        R 类为一个 ResultJSON 类, 把内容封装起来, 一般有 code, meg , data 三个属性. 返回一个 JSON 字符串


    下面是返回 JSON 格式的处理类*/
    @RestControllerAdvice
    public class ExpectedException {

        private static final long serialVersionUID = 1L;

       //@ExceptionHandler 里面的 value 的类是我们捕获的处理异常, 此类异常会被defaultErrorHandler 方法处理.
        @ExceptionHandler(value = MissingServletRequestParameterException.class)
        //@ResponseStatus(HttpStatus.BAD_REQUEST) 注解, 指定了此异常返回的状态码, 因为是缺少参数, 所以返回 400 的状态码
        @ResponseStatus(HttpStatus.BAD_REQUEST)
        public R defaultErrorHandler(HttpServletRequest req, Exception e) throws Exception {

            // R 类为一个 ResultJSON 类, 把内容封装起来, 一般有 code, meg , data 三个属性. 返回一个 JSON 字符串
            return new R<>(null, "缺少参数");
        }
    }




     /*      (二) 处理容器级别的异常
        @ControllerAdvice 注解的异常处理类并不能处理容器级别的异常, 我们可以通过继承 BasicErrorController 类重写 errorHtml 或 error 方法,
         以达到我们想要的返回结果。

            还可以通过实现 ErrorController 接口的方法来实现自定义异常处理,BasicErrorController 类也是实现了 ErrorController 接口,
            因此这种方式和 BasicErrorController 类有相似作用。实现起来相对麻烦,本文只讲解继承 BasicErrorController 类的方式。     */

    @Controller
    public class CustomizeErrorController extends BasicErrorController {

        public CustomizeErrorController(ErrorAttributes errorAttributes, ErrorProperties errorProperties, List<ErrorViewResolver> errorViewResolvers){
            super(errorAttributes, errorProperties, errorViewResolvers);
        }

        @RequestMapping(produces = {"text/html"})
        public ModelAndView errorHtml(HttpServletRequest request, HttpServletResponse response) {
            HttpStatus status = this.getStatus(request);
            Map<String, Object> model = Collections.unmodifiableMap(this.getErrorAttributes(request, this.isIncludeStackTrace(request, MediaType.TEXT_HTML)));
            response.setStatus(status.value());
            ModelAndView modelAndView = this.resolveErrorView(request, response, status, model);
            return modelAndView == null ? new ModelAndView("error", model) : modelAndView;
        }

        @RequestMapping
        @ResponseBody
        public ResponseEntity<Map<String, Object>> error(HttpServletRequest request) {
            Map<String, Object> body = this.getErrorAttributes(request, this.isIncludeStackTrace(request, MediaType.ALL));
            HttpStatus status = this.getStatus(request);
            
            //自定义一个类封装数据
            ApiResponseBody responseBody = new ApiResponseBody((int)body.get("status"), (String) body.get("error") + ": " + (String) body.get("message"));
            return new ResponseEntity(responseBody, status);
        }
    }



    /*  该类将会覆盖 BasicErrorController 类起到处理异常的作用。但这里要注意,如果想要保留对SpringBoot默认的对浏览器请求的异常处理
    (也就是根据异常错误状态码返回 error 文件夹下对应的错误页面),

    还需新建一个配置文件 CustomErrorConfiguration*/

    @Configuration
    @ConditionalOnWebApplication
    @ConditionalOnClass({Servlet.class, DispatcherServlet.class})
    @AutoConfigureBefore({WebMvcAutoConfiguration.class})
    @EnableConfigurationProperties({ResourceProperties.class})
    public class CustomErrorConfiguration {
        private final ServerProperties serverProperties;
        private final List<ErrorViewResolver> errorViewResolvers;

        public CustomErrorConfiguration(ServerProperties serverProperties,ObjectProvider <List<ErrorViewResolver>> errorViewResolversProvider) {
            this.serverProperties = serverProperties;
            this.errorViewResolvers = (List)errorViewResolversProvider.getIfAvailable();
        }

        @Bean
        public CustomizeErrorController customizeErrorController(ErrorAttributes errorAttributes){
            return new CustomizeErrorController(errorAttributes, this.serverProperties.getError(),errorViewResolvers);
        }
    }


12.SpringBoot项目打包部署

1. Spring Boot项目部署和打包:基于Jar

将Spring Boot项目使用maven指令打成jar包并运行测试

分析

  1. 需要添加打包组件将项目中的资源、配置、依赖包打到一个jar包中;可以使用maven的package
  2. 部署:java -jar 包名

jdk环境即可 + springboot自带的tomcat即可

步骤

  • 添加打包组件

    <build>
        <plugins>
            <!-- 打jar包时如果不配置该插件,打出来的jar包没有清单文件 -->
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>
    

    在这里插入图片描述

  • 打包 执行命令

    mvn clean package
    
  • SpringBoot 项目部署运行

    java -jar xxxx.jar
    

    在这里插入图片描述

  • 然后浏览器访问 http://ip:port/index 即可

2. Spring Boot项目部署和打包:基于war

将springboot项目以war的方式发布和部署

步骤

  • 修改pom.xml
<packaging>war</packaging>
  • 排除springboot自带的tomcat
 <dependency>
     <groupId>org.springframework.boot</groupId>
     <artifactId>spring-boot-starter-web</artifactId>
     <exclusions>
            <exclusion>
             	<groupId>org.springframework.boot</groupId>
             	<artifactId>spring-boot-starter-tomcat</artifactId>
            </exclusion>
     </exclusions>
 </dependency>

 <dependency>
     <groupId>org.springframework.boot</groupId>
     <artifactId>spring-boot-starter-tomcat</artifactId>
     <scope>provided</scope>
</dependency>


注意:把tomcat排除以后还要依赖,请注意这个时候的作用域是 provided,也就是告诉springboot在编译和打包的时候会依赖一下容器中提供的servlet和jsp环境,但是在最终的war中会自动排除在外。否则会出现打包失败的情况,因为没有servlet容器环境。

  • 启动类继承SpringBootServletInitializer
@SpringBootApplication
@MapperScan("com.itbooking.mapper")
public class ItbookingAppApplication  extends SpringBootServletInitializer {

    public static void main(String[] args) {
        SpringApplication.run(ItbookingAppApplication.class, args);
    }
    
    @Override
    protected SpringApplicationBuilder configure(SpringApplicationBuilder builder) {
        return builder.sources(ItbookingAppApplication.class);
    }
}
  • 在pom.xml修改工程的名称为ROOT
<build>
     <!--finalName 打包后的名称-->
    <finalName>ROOT</finalName>
</build>

ROOT是tomcat的默认工程名,也是唯一一个不需要加工程访问的目录,所以我们打包的时候用finalName指定的名字打包就直接生成的WAR包就是ROOT.war

  • 发布工程ROOT.war

    1:安装JDK1.8环境

    2:安装Tomcat 把 ROOT.war部署到webapps下即可

    4:启动Tomcat,bin/startup.bat 即可,会自动解压ROOT.war

    5:访问http://ip:8080/index 查看效果

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值