【实战教程】SpringBoot全面指南:快速上手到项目实战(SpringBoot)

news2024/11/24 22:45:13

文章目录

  • 【实战教程】SpringBoot全面指南:快速上手到项目实战(SpringBoot)
    • 1. SpringBoot介绍
      • 1.1 SpringBoot简介
      • 1.2系统要求
      • 1.3 SpringBoot和SpringMVC区别
      • 1.4 SpringBoot和SpringCloud区别
    • 2.快速入门
    • 3. Web开发
      • 3.1 静态资源访问
      • 3.2 渲染Web页面
      • 3.3 YML与Properties用法
      • 3.4使用Freemarker模板引擎渲染web视图
      • 3.5 使用thymeleaf渲染Web页面
    • 4.数据库访问
      • 4.1 springboot整合使用JdbcTemplate
      • 4.2 springboot整合使用mybatis
      • 4.3 springboot整合多数据源
    • 5.事务管理
      • 5.1 Springboot整合事务管理
      • 5.2 SpringBoot分布式事务管理
    • 6.整合热部署
      • 6.1 Spring Boot集成lombok让代码更简洁
      • 6.2 Spring Boot整合热部署框架
    • 7.整合配置文件
      • 7.1使用@value注解和@ConfigurationProperties注解
      • 7.2配置文件占位符
      • 7.3多环境配置和核心配置
    • 8.日志管理
      • 8.1使用logback记录日志
      • 8.2使用log4j记录日志
      • 8.3使用AOP统一处理Web请求日志
    • 9.其他内容
      • 9.1使用@Scheduled创建定时任务
      • 9.2使用@Async实现异步调用
      • 9.3全局捕获异常
      • 9.4发布打包


【实战教程】SpringBoot全面指南:快速上手到项目实战(SpringBoot)

1. SpringBoot介绍

1.1 SpringBoot简介

SpringBoot 是一个快速开发的框架, 封装了Maven常用依赖、能够快速的整合第三方框架;简化XML配置,全部采用注解形式,内置Tomcat、Jetty、Undertow,帮助开发者能够实现快速开发,SpringBoot的Web组件 默认集成的是SpringMVC框架。
SpringBoot原理介绍:

  1. 能够帮助开发者实现快速整合第三方框架 (原理:Maven依赖封装)
  2. 去除xml配置 完全采用注解化 (原理:Spring体系中内置注解方式)
  3. 无需外部Tomcat、内部实现服务器(原理:Java语言支持内嵌入Tomcat服务器)

1.2系统要求

Java1.8及以上
Spring Framework 5.0及以上
本课程采用Java1.8版本、SpringBoot2.1.8版本

1.3 SpringBoot和SpringMVC区别

SpringBoot 是一个快速开发的框架,能够快速的整合第三方框架,简化XML配置,全部采用注解形式,内置Tomcat容器,帮助开发者能够实现快速开发,SpringBoot的Web组件默认集成的是SpringMVC框架。
SpringMVC是控制层。

1.4 SpringBoot和SpringCloud区别

SpringBoot 是一个快速开发的框架,能够快速的整合第三方框架,简化XML配置,全部采用注解形式,内置Tomcat容器,帮助开发者能够实现快速开发,SpringBoot的Web组件 默认集成的是SpringMVC框架。
SpringMVC是控制层。
SpringCloud依赖与SpringBoot组件,使用SpringMVC编写Http协议接口,同时SpringCloud是一套完整的微服务解决框架。


2.快速入门

2.1创建一个Maven工程
在这里插入图片描述

2.2 pom文件引入依赖

<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.1.8.RELEASE</version>
</parent>
<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
</dependencies>

spring-boot-starter-parent作用
在pom.xml中引入spring-boot-start-parent,spring官方的解释叫什么stater poms,它可以提供dependency management,也就是说依赖管理,引入以后在申明其它dependency的时候就不需要version了,后面可以看到。
spring-boot-starter-web作用
springweb 核心组件

2.3 @RestController
@RestController 是由 @Controller(控制层注解)+@ResponBody(数据传输格式为 json 格式)组合而成的
Rest 微服务接口开发中 rest 风格的数据传输格式为 json 格式,采用HTTP协议
在上加上RestController 表示修饰该Controller所有的方法返回JSON格式,直接可以编写
Restful接口
注意该注解是(@RestController )SpringMVC提供的哦!

2.4@EnableAutoConfiguration
该注解:作用在于让 Spring Boot 根据应用所声明的依赖来对 Spring 框架进行自动配置
这个注解告诉Spring Boot根据添加的jar依赖猜测你想如何配置Spring。由于spring-boot-starter-web添加了Tomcat和Spring MVC,所以auto-configuration将假定你正在开发一个web应用并相应地对Spring进行设置。

2.5 SpringBoot的3种启动方式
方式一

package com.zhaoli.service;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@EnableAutoConfiguration
public class HelloworldService {
    @RequestMapping("/hello")
    public String hello() {
        return "Hello World!";
    }

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

可以请求本类中的 url
启动主程序,打开浏览器访问http://127.0.0.1:8080/hello,可以看到页面输出Hello World
在这里插入图片描述

方式二

package com.zhaoli.service;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.context.annotation.ComponentScan;

@ComponentScan("com.zhaoli.service")//扫包范围
@EnableAutoConfiguration
public class App {
    public static void main(String[] args) {
        SpringApplication.run(App.class, args);
    }
}
package com.zhaoli.service;

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

@RestController
public class HellowordService {
    @RequestMapping("/hello02")
    public String hello02() {
        return "Hello 赵立";
    }
}

可以启动扫包范围下的所有类中的 url

方式三(推荐使用)
在启动类上直接加上@SpringBootApplication即可
@SpringBootApplication@Configuration@EnableAutoConfiguration@ComponentScan 注解所修饰,换言之 Springboot 提供了统一的注解来替代以上三个注解
扫包范围:在启动类上加上@SpringBootApplication注解,当前包下或者子包下所有的类都可以扫到。

package com.zhaoli.service;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.ComponentScan;

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

3. Web开发

3.1 静态资源访问

在我们开发Web应用的时候,需要引用大量的jscss、图片等静态资源。
默认配置
Spring Boot默认提供静态资源目录位置需置于classpath下,目录名需符合如下规则:

/static
/public
/resources	
/META-INF/resources

举例:我们可以在src/main/resources/目录下创建static,在该位置放置一个图片文件。启动程序后,尝试访问http://localhost:8080/one.png。如能显示图片,配置成功。

微服务项目
前后端分离
前端----vue----前端工程师
后端—springboot–后端工程师

动静分离 部署cdn上
cdn 减少带宽距离传输 减少自己服务器带宽;

3.2 渲染Web页面

com.zhaoli.controller—视图层 渲染我们页面
com.zhaoli.service—业务逻辑层
com.zhaoli.dao—数据库访问层

渲染Web页面
在之前的示例中,我们都是通过@RestController来处理请求,所以返回的内容为json对象。那么如果需要渲染html页面的时候,要如何实现呢?
模板引擎 能够非常好的帮助seo搜索到该网页
在动态HTML实现上Spring Boot依然可以完美胜任,并且提供了多种模板引擎的默认配置支持,所以在推荐的模板引擎下,我们可以很快的上手开发动态网站。
Spring Boot提供了默认配置的模板引擎主要有以下几种:

  1. Thymeleaf
  2. FreeMarker
  3. Velocity
  4. Groovy
  5. Mustache
    Spring Boot建议使用这些模板引擎,避免使用JSP,若一定要使用JSP将无法实现Spring Boot的多种特性,具体可见后文:支持JSP的配置
    当你使用上述模板引擎中的任何一个,它们默认的模板配置路径为:src/main/resources/templates。当然也可以修改这个路径,具体如何修改,可在后续各模板引擎的配置属性中查询并修改。

3.3 YML与Properties用法

SpringBoot支持两种配置方式,一种是properties文件,一种是yml。(都是在resources目录下)
使用yml可以减少配置文件的重复性。
例如:application.properties配置

test.name=zhaoli
test.age=21

例如:application.yml配置

test:
  name: zhaoli
  age: 20

在企业中application.yml方式用的是比较多的;

package com.zhaoli.service;

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

@RestController
public class MayiktPropertiesService {
    @Value("${mayikt.name}")
    private String name;
    @Value("${mayikt.age}")
    private String age;

    @RequestMapping("/getProperties")
    public String getProperties(){
        return name+"---------"+age;
    }
}

3.4使用Freemarker模板引擎渲染web视图

1.Maven依赖

<!-- 引入freeMarker的依赖包. -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-freemarker</artifactId>
</dependency>

2.后端代码

package com.zhaoli.controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;

import java.util.Map;

@Controller
public class FreemarkerIndexController {
    @RequestMapping("/freemarkerIndex")
    public String freemarkerIndex(Map<String,String> result){
        //转发到页面展示数据
        result.put("name","赵立");
        return "freemarkerIndex";
    }
}

3.前端代码

src/main/resources/创建一个templates文件夹,用来存 *.ftl

<!DOCTYPE html>
<html>
<head lang="en">
    <meta charset="UTF-8"/>
    <title></title>
</head>
<body>
${name}
</body>
</html>

4.Freemarker其他用法
Freemarker配置
新建application.yml文件 (加粗提示对应的配置可以进行修改)

spring:
##Freemarker配置
  http:
    encoding:
      force: true
      ### 模版引擎编码为UTF-8
      charset: UTF-8
  freemarker:
    allow-request-override: false
    cache: false
    check-template-location: true
    charset: UTF-8
    content-type: text/html; charset=utf-8
    expose-request-attributes: false
    expose-session-attributes: false
    expose-spring-macro-helpers: false
    ## 模版文件结尾.ftl
    suffix: .ftl
    ## 模版文件目录
    template-loader-path: classpath:/templates

*.ftl 文件中使用符号替换方法

符号替换为(条件判断)
>gt 或者 <#if(x>y)>
>=gte 或者 <#if(x>=y)>
<lt 或者 <#if(x<y)>
<=lte 或者 <#if(x<=y)>

判断条件用法
com.zhaoli.controller.FreemarkerIndexController

@RequestMapping("/freemarkerIndex02")
public String freemarkerIndex02(Map<String, Object> result) {
    //转发到页面展示数据
    result.put("name", "赵立");
    //0为男 1为女
    result.put("sex", "0");
    result.put("age", 21);
    return "freemarkerIndex02";
}

freemarkerIndex02.ftl

<!DOCTYPE html>
<html>
<head lang="en">
    <meta charset="UTF-8"/>
    <title></title>
</head>
<body>
${name}
<#if sex=='0'>
    男
<#elseif sex='1'><#else >
    其他
</#if>
<#if age gt 17>
    已经成年了
<#else >
    没成年
</#if>
</body>
</html>

在这里插入图片描述

list集合
com.zhaoli.controller.FreemarkerIndexController

@RequestMapping("/freemarkerIndex03")
public String freemarkerIndex03(Map<String, Object> result) {
    //转发到页面展示数据
    List<String> userLists = new ArrayList<>();
    userLists.add("zl");
    userLists.add("fj");
    userLists.add("lfc");
    userLists.add("ywq");
    result.put("userList",userLists);
    return "freemarkerIndex03";

freemarkerIndex03.ftl

<!DOCTYPE html>
<html>
<head lang="en">
    <meta charset="UTF-8"/>
    <title></title>
</head>
<body>
<#list userList as user>
    ${user}
</#list>
</body>
</html>

3.5 使用thymeleaf渲染Web页面

1 .什么是thymeleaf
thymeleaf是一款用于渲染XML/XHTML/HTML5内容的模板引擎,类似JSPVelocityFreeMaker等,它也可以轻易的与Spring MVCWeb框架进行集成作为Web应用的模板引擎。

2.Maven依赖

<!--引入thymeleaf的依赖-->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>

3.配置文件新增
新建application.yml文件

###ThymeLeaf配置
spring:
  thymeleaf:
    #prefix:指定模板所在的目录
    prefix: classpath:/templates/
    #check-tempate-location: 检查模板路径是否存在
    check-template-location: true
    #cache: 是否缓存,开发模式下设置为false,避免改了模板还要重启服务器,线上设置为true,可以提高性能。
    cache: true
    suffix:  .html
    encoding: UTF-8
    mode: HTML5

4.案例代码
com.zhaoli.entity.UserEntity

package com.zhaoli.entity;

public class UserEntity {
    private String userName;
private Integer age;
}

com.zhaoli.controller.ThymeleafController

package com.zhaoli.controller;

import com.zhaoli.entity.UserEntity;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;

import java.util.Map;

@Controller
public class ThymeleafController {
    @RequestMapping("/thymeleaf")
    public String thymeleaf(Map<String, Object> result) {
        result.put("user", new UserEntity("赵立", 20));
        return "thymeleaf";
    }
}

src/main/resources/创建一个templates文件夹,用来存 *html

<!DOCTYPE html>
<!--需要在HTML文件中加入以下语句: -->
<html lang="en" xmlns:th="http://www.thymeleaf.org">
    <head>
        <meta charset="UTF-8">
        <title>Show User</title>
    </head>
    <body>
        <table>
            姓名:<span th:text="${user.userName}"></span>
            年龄:<span th:text="${user.age}"></span>
        </table>
    </body>
</html>

5.高级写法
循环语句:
com.zhaoli.entity.UserEntity 同上
com.zhaoli.controller.ThymeleafController

@RequestMapping("/thymeleaf02")
    public String thymeleaf02(Map<String, Object> result) {
        List<UserEntity> userLists = new ArrayList<>();
        userLists.add(new UserEntity("赵立", 21));
        userLists.add(new UserEntity("fj", 20));
        result.put("userList", userLists);
        return "thymeleaf02";
}

thymeleaf02.html

<!DOCTYPE html>
<!--需要在HTML文件中加入以下语句: -->
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>Show User</title>
</head>
<body>
<table>
    <ul th:each="user:${userList}">
        <li th:text="${user.userName}"></li>
        <li th:text="${user.age}"></li>
    </ul>
</table>
</body>
</html>

If判断:

<span th:if="${user.age>17}">已经成年啦</span>
<span th:if="${user.age<17}">未成年</span>

详细可以更多语法可以查看https://www.thymeleaf.org/documentation.html


4.数据库访问

4.1 springboot整合使用JdbcTemplate

1.pom文件引入

<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.1.8.RELEASE</version>
</parent>
<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>

    <!-- 引入freeMarker的依赖包. -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-freemarker</artifactId>
    </dependency>

    <!--引入thymeleaf的依赖-->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-thymeleaf</artifactId>
    </dependency>
    <!-- SpringBoot 整合 jdbc 模板框架-->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-jdbc</artifactId>
    </dependency>
    <!-- SpringBoot 整合 mysql 驱动类 -->
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <version>5.1.21</version>
    </dependency>
</dependencies>

2.application.yml新增配置

  ##springboot整合使用JdbcTemplate
  datasource:
    url: jdbc:mysql://localhost:3306/mayikt_springboot?serverTimezone=UTC&useSSL=false
    username: root
    password: 20020806
    driver-class-name: com.mysql.jdbc.Driver

3.数据库表结构

CREATE TABLE `users` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(32) NOT NULL COMMENT '用户名称',
  `age` int(11) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8;

4.案例代码
com.zhaoli.entity.UserEntity

public class MayiktUserEntity {
    private Integer id;
    private String userName;
private Integer age;
}

com.zhaoli.service.UserService

package com.zhaoli.service;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class UserService {
    @Autowired
    private JdbcTemplate jdbcTemplate;

    /**
     * 插入数据到 users 表
     */
    @RequestMapping("/inserUser")
    public String inserUser(String userName, Integer age) {
        int update = jdbcTemplate.update("INSERT INTO users VALUES(null,?,?);", userName, age);
        return update > 0 ? "success" : "fail";
    }
}

com.zhaoli.App App类

package com.zhaoli;

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

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

4.2 springboot整合使用mybatis

1.pom文件引入

<!-- springboot 整合mybatis -->
<dependency>
    <groupId>org.mybatis.spring.boot</groupId>
    <artifactId>mybatis-spring-boot-starter</artifactId>
    <version>1.1.1</version>
</dependency>

2.application.yml 新增配置

  ##springboot整合使用mybatis
  datasource:
    url: jdbc:mysql://localhost:3306/mayikt_springboot?serverTimezone=UTC&useSSL=false
    username: root
    password: 20020806
    driver-class-name: com.mysql.jdbc.Driver

3.案例代码
数据库表结构同上
com.zhaoli.entity.UserEntity 同上
com.zhaoli.mapper.UserMapper 接口

package com.zhaoli.mapper;

import com.zhaoli.entity.MayiktUserEntity;
import org.apache.ibatis.annotations.Insert;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select;

public interface UserMapper {
    @Insert("INSERT INTO users VALUES(null,#{userName},#{age});")
    int insertUser(@Param("userName") String userName, @Param("age")Integer age);
    @Select("SELECT id,name AS userName,age FROM users WHERE id=#{id};")
    MayiktUserEntity selectByUserId(@Param("id")Integer id);
}

com.zhaoli.service.UserService

package com.zhaoli.service;

import com.zhaoli.entity.MayiktUserEntity;
import com.zhaoli.mapper.UserMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class UserService {
    @Autowired
    private UserMapper userMapper;

    /**
     * mybatis 查询
     */
    @RequestMapping("/mybatisfinbyId")
    public MayiktUserEntity mybatisfinbyId(Integer id){
        return userMapper.selectByUserId(id);
	}
	/**
	 * mybatis 插入
	 */
	@RequestMapping("/mybatisInser")
	public String mybatisInser(String userName, Integer age) {
	    int inser = userMapper.insertUser(userName, age);
	    return inser > 0 ? "success" : "fail";
	}
}

com.zhaoli.App App类

package com.zhaoli;

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

@SpringBootApplication
@MapperScan("com.zhaoli.mapper")//将 mapper 包下的类、接口注入到ioc 容器中
public class App {
    public static void main(String[] args) {
        SpringApplication.run(App.class, args);
    }
}

在这里插入图片描述
在这里插入图片描述

4.3 springboot整合多数据源

1.Maven相关依赖

<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.1.8.RELEASE</version>
</parent>
<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <!-- springboot 整合mybatis -->
    <dependency>
        <groupId>org.mybatis.spring.boot</groupId>
        <artifactId>mybatis-spring-boot-starter</artifactId>
        <version>1.1.1</version>
    </dependency>
    <!-- SpringBoot 整合 mysql 驱动类 -->
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <version>8.0.18</version>
    </dependency>
</dependencies>

2.数据库表结构

CREATE TABLE `users` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(32) NOT NULL COMMENT '用户名称',
  `age` int(11) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8;
CREATE TABLE `order_number` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `order_name` varchar(255) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8;

3.配置文件中新增两个数据源

resources.application.yml
spring:
  datasource:
    ###会员数据库
    member:
      jdbc-url: jdbc:mysql://localhost:3306/user?serverTimezone=UTC&useSSL=false
      username: root
      password: root
      driver-class-name: com.mysql.jdbc.Driver
    ###订单数据库
    order:
      jdbc-url: jdbc:mysql://localhost:3306/order?serverTimezone=UTC&useSSL=false
      username: root
      password: root
      driver-class-name: com.mysql.jdbc.Driver

备注:如果是SpringBoot2配置多数据源 ,报如下错误:
jdbcUrl is required with driverClassName.或者Cause: java.lang.IllegalArgumentException: dataSource or dataSourceClassName or jdbcUrl is required.] with root cause
解决方案:
spring.datasource.urlspring.datasource.driverClassName,换成
spring.datasource.jdbc-urlspring.datasource.driver-class-name

4.数据库数据源相关配置
会员数据源

@Configuration
@MapperScan(basePackages = "com.zhaoli.member.mapper", sqlSessionFactoryRef = "memberSqlSessionFactory")
public class MemberDataSourceConfig {

    /**
     * 将会员db注册到容器中
     *
     * @return
     */
    @Bean(name = "memberDataSource")
    @ConfigurationProperties(prefix = "spring.datasource.member")
    public DataSource memberDataSource() {
        return DataSourceBuilder.create().build();
    }

    /**
     * 将会员SqlSessionFactory注册到容器中
     *
     * @param dataSource
     * @return
     * @throws Exception
     */
    @Bean(name = "memberSqlSessionFactory")
    public SqlSessionFactory memberSqlSessionFactory(@Qualifier("memberDataSource") DataSource dataSource) throws Exception {
        SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();
        sqlSessionFactoryBean.setDataSource(memberDataSource());
        return sqlSessionFactoryBean.getObject();
    }

    /**
     * 创建会员管理器
     *
     * @param dataSource
     * @return
     */
    @Bean(name = "memberTransactionManager")
    public DataSourceTransactionManager memberTransactionManager(@Qualifier("memberDataSource") DataSource dataSource) {
        return new DataSourceTransactionManager(dataSource);
    }

    /**
     * 创建订单sqlSesion模版
     *
     * @param sqlSessionFactory
     * @return
     * @throws Exception
     */
    @Bean(name = "memberSqlSessionTemplate")
    public SqlSessionTemplate menberSqlSessionTemplate(
            @Qualifier("memberSqlSessionFactory") SqlSessionFactory sqlSessionFactory) throws Exception {
        return new SqlSessionTemplate(sqlSessionFactory);
    }
}

订单数据源

@Configuration
@MapperScan(basePackages = "com.zhaoli.order.mapper", sqlSessionFactoryRef = "orderSqlSessionFactory")
public class OrderDataSourceConfig {

    /**
     * 将订单db注册到容器中
     *
     * @return
     */
    @Bean(name = "orderDataSource")
    @ConfigurationProperties(prefix = "spring.datasource.order")
    public DataSource orderDataSource() {
        return DataSourceBuilder.create().build();
    }

    /**
     * 将订单SqlSessionFactory注册到容器中
     *
     * @param dataSource
     * @return
     * @throws Exception
     */
    @Bean(name = "orderSqlSessionFactory")
    public SqlSessionFactory orderSqlSessionFactory(@Qualifier("orderDataSource") DataSource dataSource) throws Exception {
        SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();
        sqlSessionFactoryBean.setDataSource(orderDataSource());
        return sqlSessionFactoryBean.getObject();
    }

    /**
     * 创建订单管理器
     *
     * @param dataSource
     * @return
     */
    @Bean(name = "orderTransactionManager")
    public DataSourceTransactionManager orderTransactionManager(@Qualifier("orderDataSource") DataSource dataSource) {
        return new DataSourceTransactionManager(dataSource);
    }

    /**
     * 创建订单sqlSesion模版
     *
     * @param sqlSessionFactory
     * @return
     * @throws Exception
     */
    @Bean(name = "orderSqlSessionTemplate")
    public SqlSessionTemplate menberSqlSessionTemplate(
            @Qualifier("orderSqlSessionFactory") SqlSessionFactory sqlSessionFactory) throws Exception {
        return new SqlSessionTemplate(sqlSessionFactory);
    }
}

5.创建分包Mapper
会员mapper

public interface MemberMapper {
    @Insert("insert into users values(null,#{name},#{age});")
    public int addUser(@Param("name") String name, @Param("age") Integer age);
}

订单mapper

public interface OrderMapper {
    @Insert("insert into order_number values(null,#{number});")
    int inserOrder(@Param("number") String number);
}

6.启动项目

@SpringBootApplication
public class App{
    public static void main(String[] args) {
        SpringApplication.run(App.class);
    }
}

5.事务管理

5.1 Springboot整合事务管理

springboot默认集成事务,只主要在方法上加上@Transactional即可

5.2 SpringBoot分布式事务管理

使用springboot+jta+atomikos 分布式事物Transactional管理

1.多数据源分布式事务案例

@Service
public class MemberService {
    @Autowired
    private MemberMapper memberMapper;
    @Autowired
    private OrderMapper orderMapper;

    @Transactional(transactionManager = "memberTransactionManager")
    public int addUser(String userName, Integer age) {
        int result = memberMapper.addUser(userName, age);
        orderMapper.inserOrder(userName);
        int j = 1 / age;
        return result;
    }
}

2.Maven相关依赖

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

3.新增配置文件信息

spring:
  datasource:
    ###会员数据库
    member:
      url: jdbc:mysql://localhost:3306/user?serverTimezone=UTC&useSSL=false
      username: root
      password: root
      borrowConnectionTimeout: 30
      loginTimeout: 30
      maintenanceInterval: 60
      maxIdleTime: 60
      maxLifetime: 20000
      maxPoolSize: 25
      minPoolSize: 3
      uniqueResourceName: orderDatasource
    ###订单数据库
    order:
      url: jdbc:mysql://localhost:3306/order?serverTimezone=UTC&useSSL=false
      username: root
      password: root
      borrowConnectionTimeout: 30
      loginTimeout: 30
      maintenanceInterval: 60
      maxIdleTime: 60
      maxLifetime: 20000
      maxPoolSize: 25
      minPoolSize: 3
      uniqueResourceName: memberDatasource

4.读取配置文件信息

@ConfigurationProperties(prefix = "spring.datasource.member")
@Data
public class MemberConfig {
    private String url;
    private String userName;
    private String passWord;
    private int minPoolSize;
    private int maxPoolSize;
    private int maxLifetime;
    private int borrowConnectionTimeout;
    private int loginTimeout;
    private int maintenanceInterval;
    private int maxIdleTime;
    private String testQuery;

    private String uniqueResourceName;
}
@ConfigurationProperties(prefix = "spring.datasource.order")
@Data
public class OrderConfig {
    private String url;
    private String userName;
    private String passWord;
    private int minPoolSize;
    private int maxPoolSize;
    private int maxLifetime;
    private int borrowConnectionTimeout;
    private int loginTimeout;
    private int maintenanceInterval;
    private int maxIdleTime;
    private String testQuery;

    private String uniqueResourceName;
}

5.创建多数据源

@Configuration
@MapperScan(basePackages = "com.zhaoli.member.mapper", sqlSessionTemplateRef = "memberSqlSessionTemplate")
public class MemberDataSourceConfig {
    //@Configuration xml  MemberDataSourceConfig.xml

    /**
     * 创建我们的DataSource
     */
    @Bean("memberDataSource")
    public DataSource memberDataSource(MemberConfig memberConfig) throws SQLException {
        // 1.创建MysqlXADataSource
        MysqlXADataSource mysqlXaDataSource = new MysqlXADataSource();
        mysqlXaDataSource.setUrl(memberConfig.getUrl());
        mysqlXaDataSource.setPinGlobalTxToPhysicalConnection(true);
        mysqlXaDataSource.setPassword(memberConfig.getPassWord());
        mysqlXaDataSource.setUser(memberConfig.getUserName());
        mysqlXaDataSource.setPinGlobalTxToPhysicalConnection(true);

        // 2.将本地事务注册到创 Atomikos全局事务
        AtomikosDataSourceBean xaDataSource = new AtomikosDataSourceBean();
        xaDataSource.setXaDataSource(mysqlXaDataSource);
        xaDataSource.setUniqueResourceName(memberConfig.getUniqueResourceName());
        xaDataSource.setMinPoolSize(memberConfig.getMinPoolSize());
        xaDataSource.setMaxPoolSize(memberConfig.getMaxPoolSize());
        xaDataSource.setMaxLifetime(memberConfig.getMaxLifetime());
        xaDataSource.setBorrowConnectionTimeout(memberConfig.getBorrowConnectionTimeout());
        xaDataSource.setLoginTimeout(memberConfig.getLoginTimeout());
        xaDataSource.setMaintenanceInterval(memberConfig.getMaintenanceInterval());
        xaDataSource.setMaxIdleTime(memberConfig.getMaxIdleTime());
        xaDataSource.setTestQuery(memberConfig.getTestQuery());
        return xaDataSource;
    }

    /**
     * 创建我们的SqlSessionFactory
     */
    @Bean(name = "memberSqlSessionFactory")
    public SqlSessionFactory memberSqlSessionFactory(@Qualifier("memberDataSource") DataSource dataSource) throws Exception {
        SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();
        sqlSessionFactoryBean.setDataSource(dataSource);
        return sqlSessionFactoryBean.getObject();
    }

    /**
     * 创建订单sqlSesion模版
     */
    @Bean(name = "memberSqlSessionTemplate")
    public SqlSessionTemplate memberSqlSessionTemplate(
            @Qualifier("memberSqlSessionFactory") SqlSessionFactory sqlSessionFactory) throws Exception {
        return new SqlSessionTemplate(sqlSessionFactory);
    }
}
@Configuration
@MapperScan(basePackages = "com.zhaoli.order.mapper", sqlSessionTemplateRef = "orderSqlSessionTemplate")
public class OrderDataSourceConfig {
    //@Configuration xml  orderDataSourceConfig.xml

    /**
     * 创建我们的DataSource
     */
    @Bean("orderDataSource")
    public DataSource orderDataSource(OrderConfig orderConfig) throws SQLException {
        // 1.创建MysqlXADataSource
        MysqlXADataSource mysqlXaDataSource = new MysqlXADataSource();
        mysqlXaDataSource.setUrl(orderConfig.getUrl());
        mysqlXaDataSource.setPinGlobalTxToPhysicalConnection(true);
        mysqlXaDataSource.setPassword(orderConfig.getPassWord());
        mysqlXaDataSource.setUser(orderConfig.getUserName());
        mysqlXaDataSource.setPinGlobalTxToPhysicalConnection(true);

        // 2.将本地事务注册到创 Atomikos全局事务
        AtomikosDataSourceBean xaDataSource = new AtomikosDataSourceBean();
        xaDataSource.setXaDataSource(mysqlXaDataSource);
        xaDataSource.setUniqueResourceName(orderConfig.getUniqueResourceName());
        xaDataSource.setMinPoolSize(orderConfig.getMinPoolSize());
        xaDataSource.setMaxPoolSize(orderConfig.getMaxPoolSize());
        xaDataSource.setMaxLifetime(orderConfig.getMaxLifetime());
        xaDataSource.setBorrowConnectionTimeout(orderConfig.getBorrowConnectionTimeout());
        xaDataSource.setLoginTimeout(orderConfig.getLoginTimeout());
        xaDataSource.setMaintenanceInterval(orderConfig.getMaintenanceInterval());
        xaDataSource.setMaxIdleTime(orderConfig.getMaxIdleTime());
        xaDataSource.setTestQuery(orderConfig.getTestQuery());
        return xaDataSource;
    }

    /**
     * 创建我们的SqlSessionFactory
     */
    @Bean(name = "orderSqlSessionFactory")
    public SqlSessionFactory orderSqlSessionFactory(@Qualifier("orderDataSource") DataSource dataSource) throws Exception {
        SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();
        sqlSessionFactoryBean.setDataSource(dataSource);
        return sqlSessionFactoryBean.getObject();
    }
//
//    /**
//     * 创建会员管理器
//     */
//    @Bean(name = "orderTransactionManager")
//    public DataSourceTransactionManager orderTransactionManager(@Qualifier("orderDataSource") DataSource dataSource) {
//        return new DataSourceTransactionManager(dataSource);
//    }

    /**
     * 创建订单sqlSesion模版
     */
    @Bean(name = "orderSqlSessionTemplate")
    public SqlSessionTemplate orderSqlSessionTemplate(
            @Qualifier("orderSqlSessionFactory") SqlSessionFactory sqlSessionFactory) throws Exception {
        return new SqlSessionTemplate(sqlSessionFactory);
    }
}

如果多数据源使用事务报错的话
cted single matching bean but found 2: memberTransactionManager,orderTransactionManager
@Transactional(transactionManager = "memberTransactionManager")
明确指定使用那个事务管理器即可

6.启动加载配置
@EnableConfigurationProperties({OrderConfig.class, MemberConfig.class})


6.整合热部署

6.1 Spring Boot集成lombok让代码更简洁

1.需要安装Idea整合 整合Lombok插件
在这里插入图片描述

2.搜索Lombok插件即可
在这里插入图片描述

3.点击install然后,安装成功之后,点击 重启idea 即可。

整合lombok注意事项

  1. 需要在idea中安装lombok插件;-----没有做
  2. 引入到lombok依赖;
    加上了注解,根本就没有生成get和set方法。

原理:
实际上在开发写代码的时候 是不需要写get和set方法,但是在编译class文件中,帮你自动生成好这样get和set方法 放入到class文件中。

4.添加lombok依赖

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

5.打印日志
//App 是类的名称,在那个类中用就写那个类
private static Logger log = Logger.getLogger(App.class);
直接在类上加上@Slf4j 就不用写上面这行代码

6.其他特性

注解描述
@Data自动生成getter/setter方法,toString()方法,equals()方法,hashCode()方法,不带参数的构造方法。
@NonNull避免NullPointerException,确保非空对象引用。
@CleanUp自动管理需要关闭的资源,无需手动在finally块中调用close()方法。
@Setter自动生成setter方法。
@Getter自动生成getter方法。
@ToString自动生成toString()方法。
@EqualsAndHashCode从对象的字段生成hashCode()equals()方法的实现。
@NoArgsConstructor自动生成无参构造方法。
@RequiredArgsConstructor根据final或@NotNull修饰的属性自动生成构造方法。
@AllArgsConstructor自动生成包含所有属性的构造方法。
@Value用于注解不可变的final类。
@Builder自动生成复杂对象的构造器API。
@SneakyThrows捕获并隐藏检查型异常,需谨慎使用。
@Synchronized将方法或代码块标记为同步的,保证线程安全。
@Getter(lazy=true)延迟加载属性值,仅适用于Java 8及以上版本。
@Log支持不同的日志框架,例如使用@Log4j注解引入Log4j日志对象。

6.2 Spring Boot整合热部署框架

1.什么是热部署
修改java类或页面或者静态文件,不需要手动重启
原理:类加载器
适合于本地开发环境

2. Maven依赖

<!--SpringBoot热部署配置 -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-devtools</artifactId>
    <scope>runtime</scope>
    <optional>true</optional>
</dependency>

3. Idea工具设置

  1. `“File” -> “Settings” -> “Build,Execution,Deplyment” -> “Compiler”,选中打勾 “Build project automatically”
    在这里插入图片描述

  2. 组合键:“Shift+Ctrl+Alt+/” ,选择 “Registry” ,选中打勾 “compiler.automake.allow.when.app.running”
    在这里插入图片描述

新版本的IDEA在这里设置
在这里插入图片描述

4.效果演示
按住保存键,自动帮我实现重启项目


7.整合配置文件

1. 在springboot整合配置文件,分成两大类
application.properties
application.yml
或者是
Bootstrap.properties
Bootstrap.yml
相对于来说yml文件格式写法更加精简,减少配置文件的冗余性。

2. 加载顺序:
bootstrap.yml 先加载 application.yml后加载
bootstrap.yml 用于应用程序上下文的引导阶段。
bootstrap.yml 由父Spring ApplicationContext加载。
3.区别:
bootstrap.ymlapplication.yml 都可以用来配置参数。
bootstrap.yml 用来程序引导时执行,应用于更加早期配置信息读取。可以理解成系统级别的一些参数配置,这些参数一般是不会变动的。一旦bootStrap.yml 被加载,则内容不会被覆盖。
application.yml 可以用来定义应用级别的, 应用程序特有配置信息,可以用来配置后续各个模块中需使用的公共参数等。
分布式配置中心:

Properties在线转换yml格式网址:https://www.toyaml.com/index.html

7.1使用@value注解和@ConfigurationProperties注解

@value注解

@Value("${test.name}")//可以获取到配置文件中对应的值
private String name; 

@ConfigurationProperties注解
Maven依赖

<!--导入配置文件处理器,配置文件进行绑定就会有提示-->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-configuration-processor</artifactId>
    <optional>true</optional>
</dependency>

com.zhaoli.entity

import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;

@Component
@ConfigurationProperties(prefix = "test")
public class TestUserEntity {
    private String addres;
    private String age;
    private String name;
    //省略了get set toString
}

配置文件

test:
  addres: www.zhaoli.com
  age: 22
  name: test

com.zhaoli.service

@Autowired
private TestUserEntity userEntity;

@RequestMapping("/getNameAndAgeAddres")
public String getNameAndAgeAddres() {
    return userEntity.toString();
}

7.2配置文件占位符

SpringBoot的配置文件中,我们可以使用SpringBoot提供的的一些随机数
${random.value}${random.int}${random.long}
${random.int(10)}表示获取10以内的随机数、${random.int[1024,65536]}
-${app.name:默认值} 来制定找不到属性时的默认值

7.3多环境配置和核心配置

resources.templates.application.yml 里面指定读取文件的名称

spring:
  profiles:
    active: (dev或者test或者prd)

application-dev.yml:开发环境
application-test.yml:测试环境
application-prd.yml:生产环境

核心配置

server:
## 设定端口号
  port: 8081
  servlet:
## 设置 springboot 项目访问路径
    context-path: /mayikt
Springboot 默认的情况下整合tomcat容器

8.日志管理

8.1使用logback记录日志

Springboot 已经默认帮你整合好了logback
日志输出文件在当前项目路径log文件夹下
1.Maven依赖

<!-- 添加lombok依赖 -->
<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
</dependency>

2.在resources包下新建一个log包,在包下建 logback.xml 在里面进行配置(拷贝到里面即可)

<configuration>
    <!--本文主要输出日志为控制台日志,系统日志,sql日志,异常日志-->
    <!-- %m输出的信息,%p日志级别,%t线程名,%d日期,%c类的全名,,,, -->
    <!--控制台-->
    <appender name="console" class="ch.qos.logback.core.ConsoleAppender">
        <encoder>
            <pattern>%d %p (%file:%line\)- %m%n</pattern>
            <charset>UTF-8</charset>
        </encoder>
    </appender>

    <!--系统info级别日志-->
    <!--<File> 日志目录,没有会自动创建-->
    <!--<rollingPolicy>日志策略,每天简历一个日志文件,或者当天日志文件超过64MB时-->
    <!--encoder 日志编码及输出格式-->
    <appender name="fileLog"
              class="ch.qos.logback.core.rolling.RollingFileAppender">
        <File>log/file/fileLog.log</File>
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <fileNamePattern>log/file/fileLog.log.%d.%i</fileNamePattern>
            <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
                <!-- or whenever the file size reaches 64 MB -->
                <maxFileSize>64 MB</maxFileSize>
            </timeBasedFileNamingAndTriggeringPolicy>
        </rollingPolicy>
        <encoder>
            <pattern>
                %d %p (%file:%line\)- %m%n
            </pattern>
            <charset>UTF-8</charset>
            <!-- 此处设置字符集 -->
        </encoder>
    </appender>

    <!--sql日志-->
    <appender name="sqlFile"
              class="ch.qos.logback.core.rolling.RollingFileAppender">
        <File>log/sql/sqlFile.log</File>
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <fileNamePattern>log/sql/sqlFile.log.%d.%i</fileNamePattern>
            <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
                <!-- or whenever the file size reaches 64 MB -->
                <maxFileSize>64 MB</maxFileSize>
            </timeBasedFileNamingAndTriggeringPolicy>
        </rollingPolicy>
        <!--对记录事件进行格式化。负责两件事,一是把日志信息转换成字节数组,二是把字节数组写入到输出流。-->
        <encoder>
            <!--用来设置日志的输入格式-->
            <pattern>
                %d %p (%file:%line\)- %m%n
            </pattern>
            <charset>UTF-8</charset>
            <!-- 此处设置字符集 -->
        </encoder>
    </appender>


    <!--异常日志-->
    <appender name="errorFile"
              class="ch.qos.logback.core.rolling.RollingFileAppender">
        <File>log/error/errorFile.log</File>
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <fileNamePattern>log/error/errorFile.%d.log.%i</fileNamePattern>
            <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
                <!-- or whenever the file size reaches 64 MB -->
                <maxFileSize>64 MB</maxFileSize>
            </timeBasedFileNamingAndTriggeringPolicy>
        </rollingPolicy>
        <!--对记录事件进行格式化。负责两件事,一是把日志信息转换成字节数组,二是把字节数组写入到输出流。-->
        <encoder>
            <!--用来设置日志的输入格式-->
            <pattern>
                %d %p (%file:%line\)- %m%n
            </pattern>
            <charset>UTF-8</charset>
            <!-- 此处设置字符集 -->
        </encoder>
        <!--
            日志都在这里 过滤出 error
            使用 try {}catch (Exception e){} 的话异常无法写入日志,可以在catch里用logger.error()方法手动写入日志
            -->
        <filter class="ch.qos.logback.classic.filter.LevelFilter">
            <level>ERROR</level>
            <onMatch>ACCEPT</onMatch>
            <onMismatch>DENY</onMismatch>
        </filter>
    </appender>
    <!--  日志输出级别 -->
    <!--All\DEBUG\INFO\WARN\ERROR\FATAL\OFF-->
    <!--打印info级别日志,分别在控制台,fileLog,errorFile输出
        异常日志在上面由过滤器过滤出ERROR日志打印
    -->
    <root level="INFO">
        <appender-ref ref="fileLog" />
        <appender-ref ref="console" />
        <appender-ref ref="errorFile" />
    </root>

    <!--打印sql至sqlFile文件日志-->
    <logger name="com.dolphin.mapper" level="DEBUG" additivity="false">
        <appender-ref ref="console" />
        <appender-ref ref="sqlFile" />
    </logger>
</configuration>

3.在 resources 目录下的 application.yml 文件内新增 application 配置

###指定读取logback配置文件
logging:
  config: classpath:log/logback.xml

4.测试案例

@RestController
@Slf4j
public class MyIndexService {

    /**
     * 演示打印日志
     */
    @RequestMapping("/getNameAndAge")
    public String getNameAndAge(String name,Integer age){
        log.info("name:{},age:{}",name,age);
        return name+","+age;
	}
}

在这里插入图片描述

5.日志级别
ALL 最低等级的,用于打开所有日志记录。
TRACE designates finer-grained informational events than the DEBUG.Since:1.2.12,很低的日志级别,一般不会使用。
DEBUG 指出细粒度信息事件对调试应用程序是非常有帮助的,主要用于开发过程中打印一些运行信息。
INFO 消息在粗粒度级别上突出强调应用程序的运行过程。打印一些你感兴趣的或者重要的信息,这个可以用于生产环境中输出程序运行的一些重要信息,但是不能滥用,避免打印过多的日志。
WARN 表明会出现潜在错误的情形,有些信息不是错误信息,但是也要给程序员的一些提示
ERROR 指出虽然发生错误事件,但仍然不影响系统的继续运行。打印错误和异常信息,如果不想输出太多的日志,可以使用这个级别。
FATAL 指出每个严重的错误事件将会导致应用程序的退出。这个级别比较高了。重大错误,这种级别你可以直接停止程序了。
OFF 最高等级的,用于关闭所有日志记录。

6.日志目录
在这里插入图片描述

8.2使用log4j记录日志

日志级别描述输出源格式
TRACE追踪,程序每推进一步可以写入一个TRACE级别的日志,通常用于非常详细的执行流程跟踪。CONSOLESimpleLayout
DEBUG调试,用于记录调试信息,通常是最低级别,帮助开发者理解程序运行情况。FILEHTMLLayout
INFO重要信息,用于记录应用程序运行的关键信息,是使用较为频繁的日志级别。PatternLayout
WARN警告,记录可能需要注意的信息,这些信息虽然不是错误,但可能会导致问题或需要注意的情况。
ERROR错误,记录应用程序中的错误信息,这类信息表明应用程序中出现了问题。CONSOLE
FATAL致命错误,记录非常严重的错误信息,通常指应用程序无法继续运行下去的情况。FILE
机制:如果一条日志信息的级别大于等于配置文件的级别,则记录这条日志信息。
输出源:日志可以输出到控制台(CONSOLE)或文件(FILE)。
格式:日志输出的格式可以是简单的(SimpleLayout),HTML表格形式(HTMLLayout),或者自定义格式(PatternLayout)。

1.Maven依赖

<!-- spring boot start -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter</artifactId>
    <exclusions>
        <!-- 排除自带的logback依赖 -->
        <exclusion>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-logging</artifactId>
        </exclusion>
    </exclusions>
</dependency>

<!-- springboot-log4j -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-log4j</artifactId>
    <version>1.3.8.RELEASE</version>
</dependency>

<!-- spring boot start -->
这段代码是使用Maven构建项目时,添加spring-boot-starter依赖的一种方式,并且通过exclusions排除了其中的logback依赖。
当你使用类似的配置时,spring-boot-starter依赖会被添加到项目中,并且排除了 spring-boot-starter-logging。这样,你可以根据自己的需求选择适合的日志框架进行使用
这个排除logback依赖的操作可以用来替换其他的日志框架,或者使用自定义的日志框架进行日志的输出

2.新建log4j配置文件
resources 目录下新建文件log4j.properties
记得根据自己的项目修改里面的日志输出路径

#log4j.rootLogger=CONSOLE,info,error,DEBUG
log4j.rootLogger=DEBUG,error,CONSOLE,info
log4j.appender.CONSOLE=org.apache.log4j.ConsoleAppender     
log4j.appender.CONSOLE.layout=org.apache.log4j.PatternLayout     
log4j.appender.CONSOLE.layout.ConversionPattern=%d{yyyy-MM-dd-HH-mm} [%t] [%c] [%p] - %m%n    
   
log4j.logger.info=info
log4j.appender.info=org.apache.log4j.DailyRollingFileAppender
log4j.appender.info.layout=org.apache.log4j.PatternLayout     
log4j.appender.info.layout.ConversionPattern=%d{yyyy-MM-dd-HH-mm} [%t] [%c] [%p] - %m%n  
log4j.appender.info.datePattern='.'yyyy-MM-dd
log4j.appender.info.Threshold = info   
log4j.appender.info.append=true
log4j.appender.info.File=E:/code/log/info.log

log4j.logger.error=error  
log4j.appender.error=org.apache.log4j.DailyRollingFileAppender
log4j.appender.error.layout=org.apache.log4j.PatternLayout     
log4j.appender.error.layout.ConversionPattern=%d{yyyy-MM-dd-HH-mm} [%t] [%c] [%p] - %m%n  
log4j.appender.error.datePattern='.'yyyy-MM-dd
log4j.appender.error.Threshold = error   
log4j.appender.error.append=true
log4j.appender.error.File=E:/code/log/error.log

log4j.logger.DEBUG=DEBUG
log4j.appender.DEBUG=org.apache.log4j.DailyRollingFileAppender
log4j.appender.DEBUG.layout=org.apache.log4j.PatternLayout     
log4j.appender.DEBUG.layout.ConversionPattern=%d{yyyy-MM-dd-HH-mm} [%t] [%c] [%p] - %m%n  
log4j.appender.DEBUG.datePattern='.'yyyy-MM-dd
log4j.appender.DEBUG.Threshold = DEBUG   
log4j.appender.DEBUG.append=true
log4j.appender.DEBUG.File=E:/code/log/dubug.log

log4j代码
private static final Logger logger = LoggerFactory.getLogger(IndexController.class);

3.application

# 指定log4j.properties配置文件路径
logging:
  config: classpath:log4j.properties

在这里插入图片描述
在这里插入图片描述

8.3使用AOP统一处理Web请求日志

一般项目都是基于AOP实现 或者elk实现的
它可以在我们的方法的前后实现拦截 减少打印日志代码的冗余性的问题
1.Maven依赖

<!-- springboot-aop -->	
<dependency>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-aop</artifactId>
</dependency>

2.AOP切面相关配置(直接拷贝即可)

package com.zhaoli.aop;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.util.Enumeration;

@Aspect
@Component
@Slf4j
public class WebLogAspect {

//    private static final Logger logger = LoggerFactory.getLogger(WebLogAspect.class);

    /**
     * 切入点
     * com.zhaoli.controller.* 拦截该包下的所有类
     * com.zhaoli.controller.*.* 拦截该包下的所有类中的所有方法
     * (..)所有的方法参数
     */
    @Pointcut("execution(public * com.zhaoli.controller.*.*(..))")
    public void webLog() {
    }

    /**
     * 前置通知 请求方法之前做拦截
     */
    @Before("webLog()")
    public void doBefore(JoinPoint joinPoint) throws Throwable {
        // 接收到请求,记录请求内容
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = attributes.getRequest();
        // 记录下请求内容
        log.info("URL : " + request.getRequestURL().toString());
        log.info("HTTP_METHOD : " + request.getMethod());
        log.info("IP : " + request.getRemoteAddr());
        Enumeration<String> enu = request.getParameterNames();
        while (enu.hasMoreElements()) {
            String name = (String) enu.nextElement();
            log.info("name:{},value:{}", name, request.getParameter(name));
        }
    }

    /**
     * 目标方法请求之后 打印(响应)信息
     */
    @AfterReturning(returning = "ret", pointcut = "webLog()")
    public void doAfterReturning(Object ret) throws Throwable {
        // 处理完请求,返回内容
        log.info("RESPONSE : " + ret);
    }
}

9.其他内容

9.1使用@Scheduled创建定时任务

Spring Boot的主类(App类即启动类)中加入@EnableScheduling注解,启用定时任务的配置
package com.zhaoli.task;

import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

@Component
@Slf4j
public class ScheduledTasks {
    /**
     * 每隔三秒执行到 taskService()
     */
    @Scheduled(fixedRate = 3000)
    public void taskService(){
        log.info("<<定时任务执行>>"+System.currentTimeMillis());
    }
}

在这里插入图片描述

加粗部分一般使用@Scheduled(cron = "0/2 * * * * *") 写法:
https://www.bejson.com/othertools/cron/
可以在此网站中查找双引号中的使用规范
在这里插入图片描述

9.2使用@Async实现异步调用

在 Spring Boot 应用的主类(App类即启动类)上添加 @EnableAsync 注解,用于启用 Spring 的异步执行功能。
需要执行异步方法上加入 @Async

具体来说,@Async 注解用于告诉 Spring 框架将被注解的方法放入一个任务执行器(Task Executor)中执行,而不是使用调用线程进行同步执行。任务执行器负责管理执行异步任务的线程池或者其他执行策略。
异步应用场景
@Async实际就是多线程封装的
异步线程执行方法有可能会非常消耗cpu的资源,所以大的项目建议使用
Mq异步实现。

整合线程池
异步注解配置类
com.zhaoli.config.ThreadPoolConfig (配置线程池,可直接拷贝)

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.task.TaskExecutor;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;

import java.util.concurrent.ThreadPoolExecutor;

@Configuration
@EnableAsync
public class ThreadPoolConfig {

    /**
     * 每秒需要多少个线程处理?
     * tasks/(1/taskcost)
     */
    private int corePoolSize = 3;

    /**
     * 线程池维护线程的最大数量
     * (max(tasks)- queueCapacity)/(1/taskcost)
     */
    private int maxPoolSize = 3;

    /**
     * 缓存队列
     * (coreSizePool/taskcost)*responsetime
     */
    private int queueCapacity = 10;

    /**
     * 允许的空闲时间
     * 默认为60
     */
    private int keepAlive = 100;

    @Bean
    public TaskExecutor taskExecutor() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        // 设置核心线程数
        executor.setCorePoolSize(corePoolSize);
        // 设置最大线程数
        executor.setMaxPoolSize(maxPoolSize);
        // 设置队列容量
        executor.setQueueCapacity(queueCapacity);
        // 设置允许的空闲时间(秒)
        //executor.setKeepAliveSeconds(keepAlive);
        // 设置默认线程名称
        executor.setThreadNamePrefix("thread-");
        // 设置拒绝策略rejection-policy:当pool已经达到max size的时候,如何处理新任务
        // CALLER_RUNS:不在新线程中执行任务,而是有调用者所在的线程来执行
        executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
        // 等待所有任务结束后再关闭线程池
        executor.setWaitForTasksToCompleteOnShutdown(true);
        return executor;
    }
}

代码案例
@Async("taskExecutor") 是一个Spring框架中的注解,用于将方法标记为异步执行的方法。

import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;

@Slf4j
@Component
public class MemberServiceAsync {
    @Async("taskExecutor") //指定线程池名称
    public String smsAsync() {
        log.info(">02<");
        try {
            log.info(">正在发送短信..<");
            Thread.sleep(3000);
        } catch (Exception e) {

        }
        log.info(">03<");
        return "短信发送完成!";
    }
}

注意失效问题
注意:如果异步注解写当前自己类,有可能aop会失效,无法拦截注解,最终导致异步注解失效,需要经过代理类调用接口;
所以需要将异步的代码单独抽取成一个类调用接口。

9.3全局捕获异常

@ExceptionHandler 表示拦截异常
@ControllerAdvicecontroller 的一个辅助类,最常用的就是作为全局异常处理的切面类
@ControllerAdvice 可以指定扫描范围
@ControllerAdvice 约定了几种可行的返回值,如果是直接返回 model 类的话,需要使用 @ResponseBody 进行 json 转换

  • 返回 String,表示跳到某个 view
  • 返回 modelAndView
  • 返回 model + @ResponseBody

全局捕获异常配置类

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

import java.util.HashMap;
import java.util.Map;

@ControllerAdvice
public class MayiktExceptionHandler {

    /**
     * 拦截运行异常出现的错误~~~
     */
    @ExceptionHandler(RuntimeException.class)
    @ResponseBody
    public Map<Object, Object> exceptionHandler() {
        Map<Object, Object> map = new HashMap<>();
        map.put("error", "500");
        map.put("msg", "系统出现错误~");
        return map;
    }
}

没使用之前
在这里插入图片描述

给用户显示这个页面很不友好
使用全局捕获异常配置类之后的页面
在这里插入图片描述

9.4发布打包

使用mvn package 打包
进入到项目所在目录 输入 mvn clean package 进行打包等待打包完成
在这里插入图片描述

显示这个即打包完成
在这里插入图片描述

在项目的目录中的 target 包下生成一个java-jar
在这里插入图片描述

使用java –jar 包的全路径地址
在这里插入图片描述

如果报错没有主清单,在pom文件中新增

<!-- 设置打包主清单属性 -->
<build>
    <plugins>
        <plugin>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-maven-plugin</artifactId>
            <executions>
                <execution>
                    <goals>
                        <goal>repackage</goal>
                    </goals>
                </execution>
            </executions>
            <configuration>
                <!-- 启动类 -->
                <mainClass>com.zhaoli.App</mainClass>
                <excludes>
                    <exclude>
                        <groupId>junit</groupId>
                        <artifactId>junit</artifactId>
                    </exclude>
                    <exclude>
                        <groupId>org.springframework.boot</groupId>
                        <artifactId>spring-boot-starter-test</artifactId>
                    </exclude>
                </excludes>
            </configuration>
        </plugin>
    </plugins>
</build>

重新打包再运行
在这里插入图片描述
启动
在这里插入图片描述
在这里插入图片描述

成功运行
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2196390.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

ctf.bugku - 本地管理员

题目来源&#xff1a;本地管理员 - Bugku CTF 访问页面 页面的最后返回一个字符串&#xff1b; 结尾 应该是base64 编码&#xff1b; 解码得到 test123 同时&#xff0c;提示信息还有 IP禁止访问&#xff0c;本地管理员登陆&#xff1b; 所以&#xff0c;请求头添加&#x…

“欢迎”相关英语表达柯桥成人商务英语口语学习到蓝天广场

1.某地的欢迎标语 说到欢迎&#xff0c;小编想起了江苏的欢迎标语。 这则标语把“江苏欢迎您”&#xff0c;翻译成了“Jiangsu welcomes you”。 不少小伙伴都觉得这样翻译不对&#xff0c;“欢迎您来某某地方”&#xff0c;应该翻译成“Welcome to XX”。 但其实&#xff0c;一…

超声波气象监测站的工作原理

TH-CQX5超声波气象监测站&#xff0c;顾名思义&#xff0c;是一种通过超声波技术实现气象数据监测的设备。这种监测站的设计理念充分利用了超声波在空气中传播的特性&#xff0c;能够高效、准确地测量风速、风向、温度、湿度等气象要素。超声波气象监测站的构造简洁而高效&…

华为OD机试 - 银行插队 - 队列(Python/JS/C/C++ 2024 E卷 100分)

华为OD机试 2024E卷题库疯狂收录中&#xff0c;刷题点这里 专栏导读 本专栏收录于《华为OD机试真题&#xff08;Python/JS/C/C&#xff09;》。 刷的越多&#xff0c;抽中的概率越大&#xff0c;私信哪吒&#xff0c;备注华为OD&#xff0c;加入华为OD刷题交流群&#xff0c;…

前端vue-安装pinia,它和vuex的区别

创建一个store的目录&#xff0c;任意一个js文件&#xff0c;再导入pinia&#xff0c;再定义

想走?可以!先买票——迭代器模式

文章目录 想走&#xff1f;可以&#xff01;先买票——迭代器模式乘车买票&#xff0c;不管你是谁&#xff01;迭代器模式迭代器实现Java的迭代器实现迭代高手 想走&#xff1f;可以&#xff01;先买票——迭代器模式 乘车买票&#xff0c;不管你是谁&#xff01; 时间&#…

【2024版】最新kali linux入门及常用简单工具介绍(非常详细)零基础入门到精通,收藏这一篇就够了_kalilinux

一、介绍 kali Linux Kali Linux 是一个基于 Debian 的 Linux 发行版&#xff0c;主要用于数字取证和渗透测试。它预装了大量的安全审计和渗透测试工具&#xff0c;被广泛应用于网络安全领域。 &#xff08;一&#xff09;特点 工具丰富&#xff1a;集成了数百种用于渗透测试…

越差越好?为什么简单反而赢了,这背后究竟有什么秘诀?

你有没有发现,软件界里那些最成功的产品,往往并不是最复杂、最强大的?我们用的很多东西,看起来功能普通,甚至有些粗糙,但就是这样简陋的设计,反而成了市场上的赢家。 也许你玩过Flappy Bird这个游戏:它的设计非常简单,玩家只需要点击屏幕让小鸟飞行,避开管道障碍。游…

知名开发工具RubyMine全新发布v2024.2——增加浏览器保护的代码洞察

RubyMine 是一个为Ruby 和 Rails开发者准备的 IDE&#xff0c;其带有所有开发者必须的功能&#xff0c;并将之紧密集成于便捷的开发环境中。 立即获取RubyMine v2024.2正式版 具体更新详情如下&#xff1a; Rails 对Kamal配置文件的补全 RubyMine现在为 Kamal 配置文件提供…

代码随想录算法训练营Day28 | 39. 组合总和、40.组合总和Ⅱ、131.分割回文串

目录 39. 组合总和 40.组合总和Ⅱ 131.分割回文串 39. 组合总和 题目 39. 组合总和 - 力扣&#xff08;LeetCode&#xff09; 给你一个 无重复元素 的整数数组 candidates 和一个目标整数 target &#xff0c;找出 candidates 中可以使数字和为目标数 target 的 所有 不…

Pytorch实现CNN实验

一、实验要求 用 python 的 Pytorch模块实现卷积神经网络。网络结构为一个输入层、两个卷积层、一个全连接层、一个输出层。 二、实验目的 实现一个包含卷积层、池化层和全连接层的卷积神经网了解如何在训练数据集上使用反向传播算法和Adam优化算法训练神经网络。加深对卷积…

国外电商系统开发-运维系统文件上传-高级上传

如果您要上传文件到10台服务器中&#xff0c;有3台服务器的路径不是一样的&#xff0c;那么在这种情况下您就可以使用本功能&#xff0c;单独执行不一样的路径 点击【高级】上传

雷池+frp 批量设置proxy_protocol实现真实IP透传

需求 内网部署safeline&#xff0c;通过frp让外网访问内部web网站服务&#xff0c;让safeline记录真实外网攻击IP safeline 跟 frp都部署在同一台服务器&#xff1a;192.168.2.103 frp client 配置 frpc只需要在https上添加transport.proxyProtocolVersion "v2"即…

【星汇极客】STM32 HAL库+CubeMX开发之用户代码规范(持续更新)

前言 本人是一名嵌入式学习者&#xff0c;在大学期间也参加了不少的竞赛并获奖&#xff0c;包括&#xff1a;江苏省电子设计竞赛省一、睿抗机器人国二、中国高校智能机器人国二、嵌入式设计竞赛国三、光电设计竞赛国三、节能减排竞赛国三等。 暑假的时候参加了太多的比赛&#…

ComfyUI 实战教程:古人画像变真人

最近看到一种古画变真人的效果&#xff0c;就是将书上的古人画像重绘为真人&#xff0c;效果炸裂&#xff0c;不敢独享&#xff0c;特别分享给大家。 效果演示 废话不多说&#xff0c;还是先看效果。大家可以猜猜它们都是谁&#xff5e; 使用方法 这个方法在 Stable Diffusi…

斩获ICDAR历史地图OCR比赛冠军:我们如何处理密集旋转交叉文本?

ICDAR 比赛简介 ICDAR 比赛 https://rrc.cvc.uab.es/是国际公认的文字领域权威的比赛&#xff0c;文字领域顶会论文里的数据测评和测评指标往往都来源于ICDAR比赛的数据和指标&#xff0c;每年一般会有几个大类的赛事&#xff0c;然后每个赛事会细分3-4个比赛。ICDAR竞赛因其极…

APP未上架开通微信支付流程分享

在移动互联网时代&#xff0c;支付功能的便捷性对于APP的成功至关重要。即便APP尚未上架至应用商店&#xff0c;开发者仍可以提前开通微信支付功能&#xff0c;以便进行内部测试、预售活动或特定场景下的支付需求。本文将详细介绍APP未上架时如何开通微信支付的流程&#xff0c…

74.【C语言】文件操作(1)

目录 1.进行文件操作的原因 销毁的示例 2.文件的类型 1.操作文件的步骤 2.文件名 3.查看文件路径的方法 方法1 方法2 方法3 4.数据文件的介绍 举例 ① ASCII码的形式(即字符形式)存储 01.手动写入数据 02.用程序写入数据 ②二进制形式存储 理解"不加转换&…

技术美术百人计划 | 《5.4 水体渲染》笔记

一、水体渲染的波形模拟技术-基于物理 基于物理的波形模拟方法&#xff1a; 欧拉方法&#xff08;Eulerian approaches&#xff09;[Kass 1990]拉格朗日方法&#xff08;Lagrangian approaches&#xff09; [Stam 1995]欧拉-拉格朗日混合方法&#xff08;Hybrid approaches&a…

想有独立站但是不知道怎么建站,自助/外包建站怎么选?

绝大多数外贸人和电商人都会有一个疑问&#xff0c;那就是选择自助建站还是外包建站更好——我个人觉得吧&#xff0c;这两个选择主要取决于时间&#xff0c;技术能力&#xff0c;预算还有你的具体需求。 自助建站 比如自助建站&#xff0c;它就更适合预算有限、需求较简单且…