springboot入门

springboot

为什么需要springboot
	springboot解决了什么问题
快速入门
	创建项目
	详解
配置原理
	java配置
	属性注入
springboot的web项目配置
	拦截器
	转换器
	文件上传
	...
缓存控制
	redis整合
日志管理
常用配置
	跨域
	banner
	打包
整合mybatis

为什么需要springboot

在之前的ssm项目,会出现大量的xml配置,在这种开发的情况之下,程序员花很多的时间在xml的配置当中,如果这些配置出现了问题项目还可能会无法正常运行,影响了具体的业务代码时间

spring项目发现了上述问题,为了解决上述问题就推出了springboot框架

springboot是spring项目的一个子工程,其实也算是一个项目,官方解释:你只需要点一下run就可以很轻松构建一个独立,生产级别的spring项目

springboot把很多项目需要的东西都添加进去了,而且都进行了默认的配置,如果都是使用这些默认的配置就可以快速的创建一个零配置的项目,解决了配置复杂,依赖混乱的问题

springboot提倡的是约定大于配置

快速入门

创建项目

首先创建一个maven的普通项目

在pom.xml文件中去继承springboot项目

<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.3.12.RELEASE</version>
  </parent>

​ 添加一个springboot的web启动器依赖,需要注意的是这个依赖不需要添加版本号

因为我们是继承的父项目  父项目对于版本号已经做了约束
<dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-web</artifactId>
    </dependency>

添加一个控制器UserController

package com.controller;

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class UserController {

    @GetMapping("hello")
    public String helloWorld(){
        return "hello world";
    }
}

添加启动类

package com;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

/**
 * Hello world!
 *
 */
@SpringBootApplication
public class App 
{
    public static void main( String[] args )
    {
        SpringApplication.run(App.class,args);
    }
}

通过main方法启动后就可以访问 http://localhost:8080/hello

注解解释

@RestController 就是@Controller@ResponseBody 组合
@GetMapping 就是@RequestMapping请求方式设置为get
@SpringBootApplication 表示当前是springboot的程序 组合注解
@SpringBootConfiguration 表示springboot的配置  还是组合注解
    @Configuration 表示为配置类 在springboot中如果需要添加配置的时候可以使用这个注解
    声明当前类为配置类
	@Indexed 索引
@EnableAutoConfiguration 启动自动配置
@ComponentScan( 组件扫描 类似xml中 component-scan 标签 从当前类的包开始扫描 包含当前包及其子包
    excludeFilters = {@Filter(
    type = FilterType.CUSTOM,
    classes = {TypeExcludeFilter.class}
), @Filter(
    type = FilterType.CUSTOM,
    classes = {AutoConfigurationExcludeFilter.class}
)}
)

启动器

在springboot中添加依赖的时候发现依赖总是包含了starter这个词,这个称为启动器。启动器本质就是spring为了帮助我们完成各种自动化配置,提供了自动配置的依赖,这些依赖就是启动器。是由spring-boot-starter-parent 项目将依赖关系声明为一个或者多个启动器。这样的话我们就可以根据实际的需求将需要的启动器引入即可,比如当前是一个web项目,所以引入了一个web的启动器。

需要注意的是引用启动器的时候我们这里没有添加版本号,那是因为继承的父项目中有这个启动器并且声明版本信息,所以不需要添加版本号。但是如果引入的启动器在父项目中不存在,那就需要添加对应版本号了

配置原理

java配置

在springboot中出现的配置可以使用java配置来完成,java配置主要依赖于java的类和注解来完成,可以替换xml配置,和xml配置效果是一样的

比较常见的注解

@Configuration  一般加在类上面,表示当前类是一个配置类,这个配置类可以替换spring中的xml文件
@PropertySource("classpath:db.properties")  可以指定引入外部配置文件的地址
@Value("com.mysql.jdbc.Driver") 或者 @Value("${jdbc.driver}") 普通属性的值注入 可以使用 ${name} 方式注入配置文件中的值
@Bean 可以声明在方法上,将方法的返回值放入spring的容器中,替换了xml中的bean标签

demo 配置druid进去

添加依赖
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-legIMgpe-1681890801112)(assets/1663162661184.png)]

<dependency>
      <groupId>com.alibaba</groupId>
      <artifactId>druid-spring-boot-starter</artifactId>
      <version>1.2.6</version>
    </dependency>

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

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

创建配置文件 db.properties

jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql:///crm57
jdbc.username=kinglee
jdbc.password=root

创建一个配置类

package com.config;

import com.alibaba.druid.pool.DruidDataSource;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;

import javax.sql.DataSource;

@Configuration
@PropertySource("classpath:db.properties") //默认去读取指定的配置文件
public class DruidConfig {

    @Value("${jdbc.driver}")
    private String driver;
    @Value("${jdbc.url}")
    private String url;
    @Value("${jdbc.username}")
    private String username;
    @Value("${jdbc.password}")
    private String password;


    @Bean //将方法的返回值放入容器
    public DataSource dataSource(){
        DruidDataSource dataSource = new DruidDataSource();
        dataSource.setDriverClassName(driver);
        dataSource.setUrl(url);
        dataSource.setUsername(username);
        dataSource.setPassword(password);
        return dataSource;
    }
}

使用容器中的对象

package com.controller;

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

import javax.sql.DataSource;

@RestController
public class UserController {

    @Autowired
    private DataSource dataSource;

    @GetMapping("hello")
    public String helloWorld(){

        return "hello world";
    }
}

在访问的时候如果dataSource中的4个属性值有内容了,就说明刚才的配置是成功的

如果注入的属性非常多,则配置类上就会存在很多的成员变量,还是会有点麻烦的

在springboot中如果需要添加配置,可以在resources目录下去创建一个 application.properties 或者 application.yml 文件

如果两个都存在,先解析properties文件后解析yml文件 最后将解析的结果进行整合

建议大家使用 yml配置

比如我们现在创建一个application.yml 文件 内容如下

jdbc:
  driverClassName: com.mysql.jdbc.Driver
  url: jdbc:mysql:///
  username: 
  password: root

这个文件是按缩进进行等级划分的,下一级一定比上一级前面多两个空格,名称和值之间使用冒号隔开 ,冒号后面必须添加一个空格

首先创建一个类将所有的成员变量抱起来 DruidProperties类

package com.config;

import org.springframework.boot.context.properties.ConfigurationProperties;
//配置文件中的属性
@ConfigurationProperties(prefix = "jdbc") // 会自动去读取application.yml文件中的指定前缀的配置
public class DruidProperties {

    private String driverClassName;

    private String url;

    private String username;

    private String password;

    public String getDriverClassName() {
        return driverClassName;
    }

    public void setDriverClassName(String driverClassName) {
        this.driverClassName = driverClassName;
    }

    public String getUrl() {
        return url;
    }

    public void setUrl(String url) {
        this.url = url;
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }
}

在配置类中如下

package com.config;

import com.alibaba.druid.pool.DruidDataSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;

import javax.sql.DataSource;

@Configuration
//@PropertySource("classpath:db.properties") //默认去读取指定的配置文件
@EnableConfigurationProperties(DruidProperties.class)//开启配置属性的功能
public class DruidConfig {


    @Autowired
    private DruidProperties druidProperties;


    @Bean //将方法的返回值放入容器
    public DataSource dataSource(){
        DruidDataSource dataSource = new DruidDataSource();
        dataSource.setDriverClassName(druidProperties.getDriverClassName());
        dataSource.setUrl(druidProperties.getUrl());
        dataSource.setUsername(druidProperties.getUsername());
        dataSource.setPassword(druidProperties.getPassword());
        return dataSource;
    }
}

这样也可以读取到配置文件中的内容

更加优雅的注入

上面的方式实现起来还是有一些麻烦,所以springboot提供了一种更加优雅的注入方式

package com.config;

import com.alibaba.druid.pool.DruidDataSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;

import javax.sql.DataSource;

@Configuration
public class DruidConfig {


    @Bean //将方法的返回值放入容器
    @ConfigurationProperties(prefix = "jdbc") //读取配置文件中指定的前缀
    public DataSource dataSource(){
        DruidDataSource dataSource = new DruidDataSource();
        return dataSource;
    }
}

web项目配置

创建一个web项目

web项目配置

刚创建好的springboot项目发现启动失败了,主要的原因是因为添加了数据库的相关依赖,启动的时候就需要去连接数据库,但是没有针对连接数据库做配置

解决办法:

1.启动的时候不去初始化连接池,不去连接数据库

package com.springboot2;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;

@SpringBootApplication(exclude = DataSourceAutoConfiguration.class) // 启动的时候不去自动配置数据库连接池
public class Springboot2Application {

    public static void main(String[] args) {
        SpringApplication.run(Springboot2Application.class, args);
    }

}

2.配置数据库的连接

springboot提供了2个配置文件application.properties和application.yml去操作数据库,选择其中一个即可

建议使用application.yml来配置

server:
  port: 80 # 设置tomcat监听的端口
spring:
  datasource: # 数据库连接池  Hikari
    driver-class-name: com.mysql.jdbc.Driver
    url: jdbc:mysql:///
    username: 
    password: root

springboot中 的默认连接池是 Hikari

访问静态资源

首先因为创建项目的时候选择的打包方式是jar,那么这个项目就不存在webapp目录,所以不能像以前一样去存储静态资源了。

Resouces类中可以查看到默认的资源路径如下:
    
private static final String[] CLASSPATH_RESOURCE_LOCATIONS = new String[]{"classpath:/META-INF/resources/", "classpath:/resources/", "classpath:/static/", "classpath:/public/"};
建议使用的资源路径是  classpath:/static/ 路径
静态资源默认都放在static下 html,js,css,image等目录去存放对应的内容
    比如 static/html/test.html 访问这个html 的路径是   http://localhost/html/test.html

访问动态的页面

在springboot中默认使用thymeleaf 作为默认的模板引擎,所以显示视图是需要引入 Thymeleaf的依赖

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

模板引擎: 是专门为了动态页面显示的一种技术,他可以提供很多标签,后台将数据放入作用域,然后他可以从作用域中拿到数据并渲染

常见的模板引擎: freemarker thymeleaf volecity

在引入依赖以后可以查看 ThymeleafProperties 源码 可以看到默认的前缀和后缀

private String prefix = "classpath:/templates/";
private String suffix = ".html";

通过这个前缀和后缀可以看出默认存放在templates 目录下,后缀是html文件

当然如果不使用这个前后缀也可以通过配置文件修改

spring:
  datasource: # 数据库连接池  Hikari
    driver-class-name: com.mysql.jdbc.Driver
    url: jdbc:mysql:///
    username: kinglee
    password: root
  thymeleaf:
    prefix: classpath:/templates/  # 修改前缀
    suffix: .html #修改后缀

可以通过上述方式修改前缀和后缀

=

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <!--JBLHtmlToThymeleaf-->
</head>
<body>



</body>
</html>

=

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-GkxmoJNS-1681890698969)(assets/1663250356551.png)]

=

Thymeleaf 介绍

thymeleaf是一个模板引擎,使用起来还是比较简单的

可以通过后台获取数据,将数据放入ModelMap中,然后通过Thymeleaf来进行渲染

首先创建一个控制器 UserController

package com.springboot2.controller;

import com.springboot2.entity.User;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;

@Controller
public class UserController {

    @GetMapping("hello")
    public String hello(Model model){
        //将对象存入Model
        model.addAttribute("user",new User(1L,18,"<b>zhangsan</b>","123","张三",new Date()));
        List<User> users = new ArrayList<>();
        users.add(new User(2L,18,"<b>zhangsan1</b>","123","张三1",new Date()));
        users.add(new User(3L,19,"<b>zhangsan1</b>","123","张三1",new Date()));
        users.add(new User(4L,20,"<b>zhangsan1</b>","123","张三1",new Date()));
        users.add(new User(5L,21,"<b>zhangsan1</b>","123","张三1",new Date()));
        users.add(new User(6L,22,"<b>zhangsan1</b>","123","张三1",new Date()));
        users.add(new User(7L,23,"<b>zhangsan1</b>","123","张三1",new Date()));
        users.add(new User(8L,24,"<b>zhangsan1</b>","123","张三1",new Date()));
        model.addAttribute("users",users);
        return "show";
    }
}

模板的使用如下

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>$Title$</title>
</head>
<body>
<!--显示文本信息-->
<!--不识别标签-->
<span th:text="${user.username}"></span>
<!--识别标签-->
<span th:utext="${user.username}"></span>

<!--渲染对象到表单上-->
<form action="">
    <input type="hidden" name="uid" th:value="${user.uid}">
    <input type="text" name="username" th:value="${user.username}">
    <input type="password" name="password" th:value="${user.password}">
    <input type="text" name="nickname" th:value="${user.nickname}">
    //函数的使用  前面加#号
    <input type="text" name="birthday" th:value="${#dates.format(user.birthday,'yyyy-MM-dd')}">
</form>
<!--将对象渲染到表单-->
<form action="" th:object="${user}">
    <input type="hidden" name="uid" th:value="*{uid}">
    <input type="text" name="username" th:value="*{username}">
    <input type="password" name="password" th:value="*{password}">
    <input type="text" name="nickname" th:value="*{nickname}">
    <input type="text" name="birthday" th:value="*{#dates.format(birthday,'yyyy-MM-dd')}">
</form>

<!--判断
    lt <
    gt >
    eq ==
    le <=
    ge >=
    and or

-->

<div th:if="${user.age lt 18}">
    小于18
</div>
<div th:if="${user.age eq 18}">
    等于18
</div>
<div th:if="${user.age gt 18}">
    大于18
</div>

<!--循环


-->

<table>
    <tr th:each="u,stat:${users}">
        <td th:text="${u.uid}"></td>
        <td th:text="${u.age}"></td>
        <td th:text="${u.username}"></td>
        <td th:text="${u.password}"></td>
        <td th:utext="${u.nickname}"></td>
        <td th:utext="${#dates.format(u.birthday,'yyyy-MM-dd')}"></td>
        <!--当前循环的所有数据-->
<!--        <td th:utext="${stat}"></td>-->
    </tr>
</table>

<!--循环页码 三个参数分别是  from to step-->
<span th:each="i:${#numbers.sequence(1,10,1)}">
    <a href="#" th:utext="${i}"></a>
</span>
<!--switch case-->
<div th:switch="${user.age}">
    <div th:case="17">17</div>
    <div th:case="18">18</div>
    <div th:case="19">19</div>
</div>
</body>
</html>

文件下载

@GetMapping("download")
    public void download(HttpServletResponse response) throws IOException {
        //获取下载文件的路径
        String path = getClass().getClassLoader().getResource("static/html/test.html").getPath();
        String fileName = "test.html";
        //如果文件名包含中文需要处理一下
        fileName = URLEncoder.encode(fileName,"UTF-8");
        response.setHeader("Content-Disposition","attachment;filename=" + fileName);
        //执行下载
        FileUtils.copyFile(new File(path),response.getOutputStream());
    }

上面的文件下载使用到了commons-io包依赖如下

<!-- https://mvnrepository.com/artifact/commons-io/commons-io -->
        <dependency>
            <groupId>commons-io</groupId>
            <artifactId>commons-io</artifactId>
            <version>2.11.0</version>
        </dependency>

文件上传

文件上传和springmvc基本上是一样的,只是配置上有一些区别

springboot的web启动器中里面已经包含了文件上传的依赖和配置,所以直接使用即可

@PostMapping("upload")
    public String upload(@RequestParam("file") MultipartFile file){
        String path = "D://file3/";
        //获取文件的真实名字
        String originalFilename = file.getOriginalFilename();
        //设置文件的保存路径
        path += UUID.randomUUID().toString() + originalFilename.substring(originalFilename.lastIndexOf("."));
        //保存文件
        try {
            file.transferTo(new File(path));
        } catch (IOException e) {
            e.printStackTrace();
        }
        return "main";
    }

如果多文件上传将参数改成数组即可

默认情况下springboot允许上传的默认参数 单文件最大允许1M ,单次请求多文件最大允许10M

spring:
  servlet:
    multipart:
      max-file-size: 10MB # 单个文件最大值
      max-request-size: 100MB # 单词请求允许的最大值

如果不想使用yml来进行文件上传的配置,还可以通过java配置来进行配置

package com.springboot2.config;

import org.springframework.boot.web.servlet.MultipartConfigFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.util.unit.DataSize;

import javax.servlet.MultipartConfigElement;

@Configuration
public class UploadConfig {

    @Bean
    public MultipartConfigElement multipartConfigElement(){
        MultipartConfigFactory multipartConfigFactory = new MultipartConfigFactory();
        multipartConfigFactory.setMaxRequestSize(DataSize.ofMegabytes(100));
        multipartConfigFactory.setMaxFileSize(DataSize.ofMegabytes(10));
        return multipartConfigFactory.createMultipartConfig();
    }
}

上述的两种配置选择一种即可

拦截器

拦截器的实现和springmvc是一样的

首先创建一个类,实现HandlerInterceptor接口,实现其中的方法即可

package com.springboot2.interceptor;

import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

@Component
@Slf4j
public class LoginInterceptor implements HandlerInterceptor {


    /**
     * 请求到达方法之前
     * @param request
     * @param response
     * @param handler
     * @return true 就放行 false 就拦截
     * @throws Exception
     */
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        log.info("pre");
        return true;
    }

    /**
     * 方法执行完毕以后 执行的方法如果抛出异常,这个方法不执行
     * @param request
     * @param response
     * @param handler
     * @param modelAndView
     * @throws Exception
     */
    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        log.info("post");
    }

    /**
     * 响应之前 执行的方法如果抛出异常这个还是会执行
     * @param request
     * @param response
     * @param handler
     * @param ex
     * @throws Exception
     */
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        log.info("afterCompletion");
    }
}

拦截器配置

package com.springboot2.config;

import com.springboot2.interceptor.LoginInterceptor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

@Configuration
public class WebConfig implements WebMvcConfigurer {

    @Autowired
    private LoginInterceptor loginInterceptor;


    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(loginInterceptor)
                .addPathPatterns("/user/*","/download") //配置需要拦截的路径 是可变参数
                .excludePathPatterns("/user/login","/user/reg");//配置不需要拦截的路径
    }
}

需要注意的是配置拦截器的时候需要实现一个接口 WebMvcConfigurer

类型转换器

package com.springboot2.convert;

import org.springframework.core.convert.converter.Converter;
import org.springframework.stereotype.Component;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;

@Component
public class DateConvert implements Converter<String, Date> {
    @Override
    public Date convert(String source) {
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

        try {
            return simpleDateFormat.parse(source);
        } catch (ParseException e) {
            e.printStackTrace();
        }
        return null;
    }
}

类型转换器的配置也是需要使用java配置

package com.springboot2.config;

import com.springboot2.convert.DateConvert;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.format.FormatterRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

@Configuration
public class WebConfig implements WebMvcConfigurer {

    @Autowired
    private DateConvert dateConvert;

    @Override
    public void addFormatters(FormatterRegistry registry) {
        registry.addConverter(dateConvert);//注册类型转换器
    }
}

异常处理

在实际的开发中,出现异常是很正常的情况,需要对这些异常进行一些处理

局部异常处理

在对应的Controller里面添加异常处理的方法即可

 @ExceptionHandler(NullPointerException.class)
    public String nullPointer(NullPointerException e){
        log.error("抛出异常",e);
        log.info("异常处理");
        return "nullPointer";
    }

全局的异常处理

单独实现一个异常处理的控制器

package com.springboot2.controller;

import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;

@ControllerAdvice // 如果返回的是页面 就用这个注解
//@RestControllerAdvice // 如果响应的是json 可以选择这个注解
@Slf4j
public class ExceptionController {

    @ExceptionHandler(NullPointerException.class)
    public String nullPointer(NullPointerException e){
        log.info("异常处理");
        return "error";
    }

    @ExceptionHandler(IndexOutOfBoundsException.class) // 要求是 @RestControllerAdvice
    public ResponseEntity  indexOutOfBoundsException(IndexOutOfBoundsException e){
        log.info("异常处理");
        return new ResponseEntity(HttpStatus.INTERNAL_SERVER_ERROR);
    }
}

自己实现一个异常处理的类,上面添加注解@ControllerAdvice 或者@RestControllerAdvice

里面添加方法 方法上添加注解@ExceptionHandler 去捕获对应的异常

缓存配置

springboot中已经有缓存的启动器,直接使用即可,主要使用的redis

redis的使用

添加redis的依赖

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

添加redis的配置

spring:
  redis:
    host: 127.0.0.1
    port: 6379
    database: 0
    password: 123456
    timeout: 5000

在springboot中操作redis主要还是使用的redisTemplate,所以要操作redis还需要先创建RedisTemplate的对象

添加一个Redis的配置类

package com.springboot2.config;

import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;

@Configuration
public class RedisConfig {

    @Bean
    public RedisTemplate redisTemplate(RedisConnectionFactory factory){
        RedisTemplate redisTemplate = new RedisTemplate();
        //设置连接工厂
        redisTemplate.setConnectionFactory(factory);

        //手动添加序列化的配置
        ObjectMapper objectMapper = new ObjectMapper();
        objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
        objectMapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
        //序列化的配置
        Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
        jackson2JsonRedisSerializer.setObjectMapper(objectMapper);
        //value序列化
        redisTemplate.setValueSerializer(jackson2JsonRedisSerializer);
        //key的序列化
        redisTemplate.setKeySerializer(new StringRedisSerializer());
        //hash的序列化
        redisTemplate.setHashKeySerializer(new StringRedisSerializer());
        redisTemplate.setHashValueSerializer(new StringRedisSerializer());
        redisTemplate.afterPropertiesSet();
        return redisTemplate;
    }
}

测试代码

package com.springboot2;

import com.springboot2.entity.User;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.redis.core.RedisTemplate;

import java.util.Date;

@SpringBootTest
class Springboot2ApplicationTests {

    @Autowired
    private RedisTemplate redisTemplate;

    @Test
    void contextLoads() {
        User user = new User(1l, 18, "zhangsan", "123456", "张三", new Date());
        redisTemplate.opsForValue().set("user",user);
    }

}

如果操作对应的类型,那么使用opsFor对应的类型即可

缓存控制

springboot中去控制缓存

添加依赖

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

给缓存取一个名字

spring:
  redis:
    host: 127.0.0.1
    port: 6379
    database: 0
    password: 123456
    timeout: 5000
    cache_name: tredis

缓存控制器

package com.springboot2.config;

import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.cache.CacheManager;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.cache.RedisCacheConfiguration;
import org.springframework.data.redis.cache.RedisCacheManager;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.RedisSerializationContext;
import org.springframework.data.redis.serializer.StringRedisSerializer;

import java.time.Duration;

@Configuration
public class RedisConfig {

    @Bean
    public CacheManager cacheManager(RedisConnectionFactory factory){
        //手动添加序列化的配置
        ObjectMapper objectMapper = new ObjectMapper();
        objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
        objectMapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
        //序列化的配置
        Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
        jackson2JsonRedisSerializer.setObjectMapper(objectMapper);
        //获取默认的配置
        RedisCacheConfiguration redisCacheConfiguration = RedisCacheConfiguration.defaultCacheConfig()
                .entryTtl(Duration.ofHours(1))
                .serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(new StringRedisSerializer()))
                .serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(jackson2JsonRedisSerializer))
                .disableCachingNullValues();
        RedisCacheManager redisCacheManager = RedisCacheManager.builder(factory).cacheDefaults(redisCacheConfiguration)
                .build();
        return redisCacheManager;
    }
}

使用的时候只需要在service的方法上添加注解@Cacheable

package com.springboot2.service.impl;

import com.springboot2.entity.User;
import com.springboot2.service.UserService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;

import java.util.Date;

@Service
@Slf4j
public class UserServiceImpl implements UserService {


    @Cacheable(value = "zltredis",key = "'uid'")
    public User selectUserByUid(Long uid){
        log.info("执行了方法{},id为{}","selectUserByUid",uid);
        User user = new User(1l, 18, "zhangsan", "123456", "张三", new Date());
        return user;
    }
}

还需要在启动类上添加注解@EnableCaching 启用缓存

package com.springboot2;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cache.annotation.EnableCaching;

@SpringBootApplication
@EnableCaching //启用缓存
public class Springboot2Application {

    public static void main(String[] args) {

        SpringApplication.run(Springboot2Application.class, args);
    }

}

这样的话第一次访问的时候会执行service中的方法,第二次执行就不再执行而是直接去缓存中根据key进行查询。

目前还有一个较大的问题,所有的数据都是用的同一个key,这样数据就会出现问题,所以还需要配置一个key的生成器

创建key的生成器

package com.springboot2.generator;

import org.springframework.stereotype.Component;

import java.lang.reflect.Method;

@Component
public class KeyGenerator implements org.springframework.cache.interceptor.KeyGenerator {
    /**
     * 根据信息生成一个key
     * @param target 目标对象
     * @param method 调用的方法
     * @param params 方法的参数
     * @return
     */
    @Override
    public Object generate(Object target, Method method, Object... params) {
        StringBuilder stringBuilder = new StringBuilder();
        stringBuilder.append(target.getClass().getName() );
        stringBuilder.append(":");
        stringBuilder.append(method.getName());
        stringBuilder.append(":");
        //拼接参数
        if(params != null){
            for (Object param : params) {
                stringBuilder.append(param);
                stringBuilder.append(":");
            }
        }
        return stringBuilder;
    }
}

再把key的生成器应用上去

package com.springboot2.service.impl;

import com.springboot2.entity.User;
import com.springboot2.service.UserService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;

import java.util.Date;

@Service
@Slf4j
public class UserServiceImpl implements UserService {


    @Cacheable(value = "zltredis",keyGenerator = "keyGenerator")
    public User selectUserByUid(Long uid){
        log.info("执行了方法{},id为{}","selectUserByUid",uid);
        User user = new User(uid, 18, "zhangsan", "123456", "张三", new Date());
        return user;
    }
}

这样的话只要参数不一样的时候缓存的数据的key就可以不一样

@Cacheable 根据注解中的key或者keyGenerator 去查找元素,如果有就直接返回,如果没有就调用方法,然后把方法的返回值放入缓存中
@CacheEvict 用来标注需要清除缓存的方法上,当标记在类上的时候,这个类的所有方法都会清除缓存,当标记在方法上的时候只有这个方法对应的key会清除缓存
@CachePut 对于@Cacheable 标记的方法,spring每次执行的时候都会先去查找对应的key,如果存在就不执行方法,如果不存在再去执行方法
   @CachePut 当标记在方法上后,方法执行完毕后的返回值也会放入缓存,区别是 方法执行之前不会检查key是否存在,而是每次执行方法都会将返回值放入缓存 

日志配置

springboot默认的日志依赖

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

这个日志的依赖在spring-boot-starter-web 中已经存在,可以不需要单独添加依赖

=

如果使用的是slf4j,我们可以在项目中添加lombok的依赖


        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>

可以直接在类上添加一个注解@Slf4j ,添加以后方法中就可以直接使用变量log,默认的日志等级为info

logging:
  level:
    com.springboot2.controller: debug #指定包的日志等级
    root: info #设置所有的日志的日志等级 为debug
  file:
    path: D://file3 # 设置日志的文件路径
    name: mylog.log # 设置日志保存的文件名

可以通过上述的方式去配置日志,默认情况下日志还是会输出到控制台方便调试,当设置日志文件后,日志信息可以保存到文件中去

banner制作

banner的制作有两种方式:

1.直接在resources下新建一个banner.txt 将需要显示的内容放进去即可

生成网站

1.文字转文本 https://www.bootschool.net/ascii/

2.文字转文本 http://www.network-science.de/ascii/

3.图片转文本 https://www.degraeve.com/img2txt.php

4.文字转文本 http://patorjk.com/software/taag/

2.直接将图片放在resources目录下,然后在配置文件application.yml中去配置图片的路径

spring: 
  banner:
    image:
      location: classpath:banner.png

打包问题

一般情况下打包会打包成jar文件,可以在pom.xml中简单的配置一下

<build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <configuration>
                    //指定主类
                    <mainClass>com.springboot2.Springboot2Application</mainClass>
                    <excludes>
                        <exclude>
                            <groupId>org.projectlombok</groupId>
                            <artifactId>lombok</artifactId>
                        </exclude>
                    </excludes>
                </configuration>
                <executions>
                    <execution>
                        <goals>
                            <goal>repackage</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>

跨域配置

全局跨域配置

创建个跨域的配置类,配置跨域的过滤器

package com.springboot2.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import org.springframework.web.filter.CorsFilter;

@Configuration
public class CorsConfig {

    @Bean
    public CorsFilter corsFilter(){
        CorsConfiguration configuration = new CorsConfiguration();
        //设置允许的源 设置为* configuration.setAllowCredentials(true); 就不允许设置为true
//        configuration.addAllowedOrigin("*");

        //设置允许的源
        configuration.addAllowedOriginPattern("*");
        //配置是否允许携带cookie
        configuration.setAllowCredentials(true);
        //配置允许的请求头
        configuration.addAllowedHeader("*");
        //允许的请求方式 可以写* 也可以写具体的请求方式
        configuration.addAllowedMethod("GET");
        configuration.addAllowedMethod("POST");
        configuration.addAllowedMethod("PUT");
        configuration.addAllowedMethod("DELETE");
        //设置允许的响应头 客户端可以获取
        configuration.addExposedHeader("*");
        UrlBasedCorsConfigurationSource corsConfigurationSource = new UrlBasedCorsConfigurationSource();
        //配置哪些路径需要跨域
        corsConfigurationSource.registerCorsConfiguration("/**",configuration);

        return new CorsFilter(corsConfigurationSource);
    }
}

通过实现接口来进行配置

package com.springboot2.config;

import com.springboot2.convert.DateConvert;
import com.springboot2.interceptor.LoginInterceptor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.format.FormatterRegistry;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

@Configuration
public class WebConfig implements WebMvcConfigurer {


    @Override
    public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping("/**")
                .allowCredentials(true)// 允许携带cookie
                .allowedHeaders("*") // 允许的请求头
                .exposedHeaders("*") //允许的响应头
                .allowedMethods("GET","POST") //允许的请求方式
                .allowedOriginPatterns("*");//允许的源
    }
}

上面两种跨域选择一种即可

局部跨域配置

使用注解@CrossOrigin ,这个注解可以添加在类上,也可以添加在方法上

@CrossOrigin(
        originPatterns = "*",
        methods = {RequestMethod.GET,RequestMethod.POST,RequestMethod.DELETE,RequestMethod.OPTIONS},
        allowCredentials = "true",
        exposedHeaders = "*",
        allowedHeaders = "*"
)

这个注解添加在哪里,哪里就可以支持跨域

整合mybatis

创建一个项目

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.7.0</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com</groupId>
    <artifactId>bootmybatis</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>bootmybatis</name>
    <description>Demo project for Spring Boot</description>
    <properties>
        <java.version>1.8</java.version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-jdbc</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>2.2.2</version>
        </dependency>

        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <scope>runtime</scope>
            <version>5.1.38</version>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>

        <!-- https://mvnrepository.com/artifact/org.mybatis.generator/mybatis-generator-core -->
        <dependency>
            <groupId>org.mybatis.generator</groupId>
            <artifactId>mybatis-generator-core</artifactId>
            <version>1.3.7</version>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <configuration>
                    <excludes>
                        <exclude>
                            <groupId>org.projectlombok</groupId>
                            <artifactId>lombok</artifactId>
                        </exclude>
                    </excludes>
                </configuration>
            </plugin>
        </plugins>
    </build>

</project>

配置文件

server:
  port: 80
spring:
  datasource:
    driver-class-name: com.mysql.jdbc.Driver
    url: jdbc:mysql:///
    username: 
    password: root
    hikari:
      maximum-pool-size: 10
mybatis:
  mapper-locations: classpath:mapper/**.xml
logging:
  level:
    com:
      zlt:
        bootmybatis:
          dao: debug

启动类

package com.bootmybatis;

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

@SpringBootApplication
@MapperScan("com.bootmybatis.dao") // 整合mybatis后的接口扫描
public class BootmybatisApplication {

    public static void main(String[] args) {
        SpringApplication.run(BootmybatisApplication.class, args);
    }

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

程序员zhi路

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值