SpringBoot 基础入门

SpringBoot 基础入门


Spring Boot简介

Spring Boot是由Pivotal团队提供的全新框架,其设计目的是用来简化Spring应用的创建、运行、调试、部署等。使用Spring Boot可以做到专注于Spring应用的开发,而无需过多关注XML的配置。Spring Boot遵循“ 习惯优于配置”的理念,简单来说,它提供了一堆依赖打包,并已经按照使用习惯解决了依赖问题。使用Spring Boot可以不用或者只需要很少的Spring配置就可以让企业项目快速运行起来。

Spring Boot特点:

  1. 创建独立的Spring应用程序

  2. 嵌入的Tomcat,无需部署WAR文件

  3. 简化Maven配置

  4. 自动配置Spring

  5. 提供生产就绪型功能,如指标,健康检查和外部配置

  6. 绝对没有代码生成以及对XML没有要求配置


如果使用的IntelliJ IDEA,则无需下载插件,如果是使用Eclipse开发,没有SpringBoot插件的话,还是需要下载(这里可跳过…):

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

接受后,点击Finish,然后等待下载完毕,最后重启。

新建一个Spring Boot工程:

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

自动生成的目录结构如下:

在这里插入图片描述
在com.wu.application下再次新建一个controller包,并新建一个MyController类:

package com.wu.application.controller;

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

@Controller
@RequestMapping("/boot")
public class MyController {
	
	@ResponseBody
	@RequestMapping("/sayhello")
	public String sayHello() {
		return "Hello,Spring Boot 2!";
	}
}

以上简单的几行语句就相当于SSM整合的几十甚至上百行代码,因为SSM整合需要编写许多配置文件,极其繁琐。

在这里插入图片描述
在application.properties中修改端口号和默认访问路径:

# 配置服务器的端口号
server.port=8888
# 配置服务器的默认访问路径
server.servlet.context-path=/app

在这里插入图片描述
Spring Boot不但能创建传统的war包应用,还能创建独立的不依赖于任何外部容器(比如Tomcat)的独立应用。

首先检查pom.xml文件:

<?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.4.2</version>
		<relativePath/> <!-- lookup parent from repository -->
	</parent>
	<groupId>com.wu</groupId>
	<artifactId>springboot-1</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<packaging>jar</packaging>
	<name>springboot-1</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-web</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-test</artifactId>
			<scope>test</scope>
		</dependency>
	</dependencies>

	<build>
		<plugins>
			<plugin>
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-maven-plugin</artifactId>
			</plugin>
		</plugins>
	</build>

</project>

如果要打jar包,就修改为<packaging>jar</packaging>,如果要打成war包,就修改为<packaging>war</packaging>

右击项目,点击Run As,选择Maven Clean,清除编译后的目录,默认是target目录:

[INFO] Scanning for projects...
[INFO] 
[INFO] ------------------------< com.wu:springboot-1 >-------------------------
[INFO] Building springboot-1 0.0.1-SNAPSHOT
[INFO] --------------------------------[ jar ]---------------------------------
[INFO] 
[INFO] --- maven-clean-plugin:3.1.0:clean (default-clean) @ springboot-1 ---
[INFO] Deleting E:\javaworkspace\springboot-1\target
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time:  0.820 s
[INFO] Finished at: 2021-01-29T10:12:40+08:00
[INFO] ------------------------------------------------------------------------
[WARNING] The requested profile "pom.xml" could not be activated because it does not exist.

然后再次点击Run As,选择Maven Build,对Goals框输入内容 package:

在这里插入图片描述

可以发现,在项目目录下的target文件下出现了已经打好了的jar包:

在这里插入图片描述
文件路径搜索框搜索cmd,并输入java -jar springboot-1-0.0.1-SNAPSHOT.jar 命令:

在这里插入图片描述
对浏览器输入http://localhost:8888/app/boot/sayhello:

在这里插入图片描述

总结:约定优于配置,简洁胜于复杂,当学习完了SSH或SSM感触深刻,因为那就是配置的地狱。


@Configuration注解

创建两个pojo类:

package com.wu.application.pojo;

public class Student {
	private String name;
	private Long id;
	private Integer age;
	private Book book;
	public Student(String name,Long id,Integer age,Book book) {
		this.name = name;
		this.id = id;
		this.age = age;
		this.book = book;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public Long getId() {
		return id;
	}
	public void setId(Long id) {
		this.id = id;
	}
	public Integer getAge() {
		return age;
	}
	public void setAge(Integer age) {
		this.age = age;
	}
	public Book getBook() {
		return book;
	}
	public void setBook(Book book) {
		this.book = book;
	}
	@Override
	public String toString() {
		return "Student [name=" + name + ", id=" + id + ", age=" + age + ", book=" + book + "]";
	}
}

package com.wu.application.pojo;

public class Book {
	private String bookName;
	private Long bookId;
	public Book(String bookName,Long bookId) {
		this.bookName = bookName;
		this.bookId = bookId;
	}
	public String getBookName() {
		return bookName;
	}
	public void setBookName(String bookName) {
		this.bookName = bookName;
	}
	public Long getBookId() {
		return bookId;
	}
	public void setBookId(Long bookId) {
		this.bookId = bookId;
	}
	@Override
	public String toString() {
		return "Book [bookName=" + bookName + ", bookId=" + bookId + "]";
	}
}

创建配置类:

将实例对象交给spring容器来统一管理

package com.wu.application.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import com.wu.application.pojo.Book;
import com.wu.application.pojo.Student;

@Configuration(proxyBeanMethods = true) // 默认情况下的配置类(等价于配置文件)为单例模式 : 使用代理模式得到强化
public class MyConfig {
	@Bean("student")
	public Student getStudentBean() {
		return new Student("张三",20210129L,20,getBookBean());
	}
	@Bean("book")
	public Book getBookBean() {
		return new Book("一本书",0001L);
	}
}

应用入口类:

package com.wu.application;

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

import com.wu.application.pojo.Book;
import com.wu.application.pojo.Student;

@SpringBootApplication
public class MyApplication {

	public static void main(String[] args) {
		ApplicationContext context = SpringApplication.run(MyApplication.class, args);
		Student student = context.getBean("student",Student.class);
		Book book = context.getBean("book",Book.class);
		System.out.println("Spring容器中的bean为单例模式:"+(student.getBook() == book));	
	}
}

结果:


  .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: Spring Boot ::                (v2.4.2)

2021-01-29 17:42:33.822  INFO 1452 --- [           main] com.wu.application.MyApplication         : Starting MyApplication using Java 14.0.2 on PC-20200901HLGR with PID 1452 (E:\javaworkspace\springboot-1\target\classes started by Administrator in E:\javaworkspace\springboot-1)
2021-01-29 17:42:33.826  INFO 1452 --- [           main] com.wu.application.MyApplication         : No active profile set, falling back to default profiles: default
2021-01-29 17:42:35.089  INFO 1452 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat initialized with port(s): 8888 (http)
2021-01-29 17:42:35.102  INFO 1452 --- [           main] o.apache.catalina.core.StandardService   : Starting service [Tomcat]
2021-01-29 17:42:35.102  INFO 1452 --- [           main] org.apache.catalina.core.StandardEngine  : Starting Servlet engine: [Apache Tomcat/9.0.41]
2021-01-29 17:42:35.213  INFO 1452 --- [           main] o.a.c.c.C.[Tomcat].[localhost].[/app]    : Initializing Spring embedded WebApplicationContext
2021-01-29 17:42:35.213  INFO 1452 --- [           main] w.s.c.ServletWebServerApplicationContext : Root WebApplicationContext: initialization completed in 1315 ms
2021-01-29 17:42:35.453  INFO 1452 --- [           main] o.s.s.concurrent.ThreadPoolTaskExecutor  : Initializing ExecutorService 'applicationTaskExecutor'
2021-01-29 17:42:35.737  INFO 1452 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat started on port(s): 8888 (http) with context path '/app'
2021-01-29 17:42:35.752  INFO 1452 --- [           main] com.wu.application.MyApplication         : Started MyApplication in 2.388 seconds (JVM running for 3.517)
Spring容器中的bean为单例模式:true

如果将@Configuration中的proxyBeanMethods设置为false,则上面的结果就会变为false,所以如果组件之间形成依赖关系,则使用默认的单例模式,如果没有依赖关系的话,最好使用多例模式,因为这样的模式速度会变得更快。

@Import注解

@Import注解可以用于导入第三方包 ,虽然@Bean注解也可以,但是@Import注解快速导入的方式会显得更加便捷

package com.wu.application;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Import;

import com.wu.application.pojo.Book;
import com.wu.application.pojo.Student;


@Import({com.wu.application.pojo.Student.class,com.wu.application.pojo.Book.class})
@SpringBootApplication
public class MyApplication {

	public static void main(String[] args) {
		ApplicationContext context = SpringApplication.run(MyApplication.class, args);
		Student student = context.getBean(Student.class);
		Book book = context.getBean(Book.class);
		System.out.println("学生:"+student);
		System.out.println("书籍:"+book);
	}
}

结果:


  .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: Spring Boot ::                (v2.4.2)

2021-01-29 18:14:12.375  INFO 2428 --- [           main] com.wu.application.MyApplication         : Starting MyApplication using Java 14.0.2 on PC-20200901HLGR with PID 2428 (E:\javaworkspace\springboot-1\target\classes started by Administrator in E:\javaworkspace\springboot-1)
2021-01-29 18:14:12.379  INFO 2428 --- [           main] com.wu.application.MyApplication         : No active profile set, falling back to default profiles: default
2021-01-29 18:14:13.456  INFO 2428 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat initialized with port(s): 8888 (http)
2021-01-29 18:14:13.469  INFO 2428 --- [           main] o.apache.catalina.core.StandardService   : Starting service [Tomcat]
2021-01-29 18:14:13.470  INFO 2428 --- [           main] org.apache.catalina.core.StandardEngine  : Starting Servlet engine: [Apache Tomcat/9.0.41]
2021-01-29 18:14:13.577  INFO 2428 --- [           main] o.a.c.c.C.[Tomcat].[localhost].[/app]    : Initializing Spring embedded WebApplicationContext
2021-01-29 18:14:13.577  INFO 2428 --- [           main] w.s.c.ServletWebServerApplicationContext : Root WebApplicationContext: initialization completed in 1132 ms
2021-01-29 18:14:13.776  INFO 2428 --- [           main] o.s.s.concurrent.ThreadPoolTaskExecutor  : Initializing ExecutorService 'applicationTaskExecutor'
2021-01-29 18:14:14.024  INFO 2428 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat started on port(s): 8888 (http) with context path '/app'
2021-01-29 18:14:14.036  INFO 2428 --- [           main] com.wu.application.MyApplication         : Started MyApplication in 2.133 seconds (JVM running for 3.041)
学生:Student [name=null, id=null, age=null, book=null]
书籍:Book [bookName=null, bookId=null]

@Conditional注解

package com.wu.application.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import com.wu.application.pojo.Book;
import com.wu.application.pojo.Student;

@Configuration(proxyBeanMethods = true) // 默认情况下的配置类(等价于配置文件)为单例模式 : 使用代理模式得到强化
public class MyConfig {
	@Bean("student")
	public Student getStudentBean() {
		return new Student("张三",20210129L,20,getBookBean());
	}
//	注意这里没有使用@Bean("book")标签
	public Book getBookBean() {
		return new Book("一本书",0001L);
	}
}
package com.wu.application;

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

@SpringBootApplication
public class MyApplication {

	public static void main(String[] args) {
		ApplicationContext context = SpringApplication.run(MyApplication.class, args);
		boolean existStudent = context.containsBean("student");
		boolean existBook = context.containsBean("book");
		System.out.println("学生存在容器中:"+existStudent);
		System.out.println("书籍存在容器中:"+existBook);
	}
}

结果:

学生存在容器中:true
书籍存在容器中:false

如果使用@ConditionalOnBean:

@Configuration(proxyBeanMethods = true) // 默认情况下的配置类(等价于配置文件)为单例模式 : 使用代理模式得到强化
public class MyConfig {
	@ConditionalOnBean(name = "book")
	@Bean("student")
	public Student getStudentBean() {
		return new Student("张三",20210129L,20,getBookBean());
	}
	@Bean("book")
	public Book getBookBean() {
		return new Book("一本书",0001L);
	}
}

结果:

学生存在容器中:false
书籍存在容器中:false

之所以为以上结果,是因为使用了条件注解,只有当spring容器中已经事先存在具有name为"book"的组件,才能使得以下的组件注册成功。

相应的,还有许多其它的类似的条件注解,我们只需按照字面的英语意思理解使用即可。

在这里插入图片描述

@ImportResource

通过导入资源文件来将组件注册进入spring容器中进行统一管理。

在resource文件夹下建立bean文件夹,在其下建立spring-bean.xml:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://www.springframework.org/schema/beans
	http://www.springframework.org/schema/beans/spring-beans.xsd">
	<bean id = "student" class = "com.wu.application.pojo.Student">
		<property name="name" value = "张三"/>
		<property name="id" value = "20210129"/>
		<property name="age" value = "20"/>
		<property name="book" ref = "book" />
	</bean>
	<bean id = "book" class = "com.wu.application.pojo.Book">
		<property name="bookName" value = "一本书"/>
		<property name="bookId" value = "10001"/>
	</bean>
</beans>

配置类:

package com.wu.application.config;

import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.ImportResource;
@ImportResource(value = "classpath:/bean/spring-bean.xml")
@Configuration // 默认情况下的配置类(等价于配置文件)为单例模式 : 使用代理模式得到强化
public class MyConfig {

	}
}

MyApplication.java:

package com.wu.application;

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

import com.wu.application.pojo.Book;
import com.wu.application.pojo.Student;

@SpringBootApplication
public class MyApplication {

	public static void main(String[] args) {
		ApplicationContext context = SpringApplication.run(MyApplication.class, args);
		Student student = context.getBean("student",Student.class);
		Book book = context.getBean("book",Book.class);
		System.out.println(student);
		System.out.println(book);
	}
}

结果:

Student [name=张三, id=20210129, age=20, book=Book [bookName=一本书, bookId=10001]]
Book [bookName=一本书, bookId=10001]

@ConfigurationProperties注解

第一种:@ConfigurationProperties+@Component

配置绑定

首先在pom.xml文件中添加如下内容:

<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-configuration-processor</artifactId>
	<optional>true</optional>
</dependency>

对application.properties进行修改:

# 自定义配置
mybook.bookName=一本书
mybook.bookId=999

pojo类:

package com.wu.application.pojo;

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

@Component(value = "book")
@ConfigurationProperties(prefix = "mybook")
public class Book {
	private String bookName;
	private Long bookId;
	public Book() {}
	public Book(String bookName,Long bookId) {
		this.bookName = bookName;
		this.bookId = bookId;
	}
	public String getBookName() {
		return bookName;
	}
	public void setBookName(String bookName) {
		this.bookName = bookName;
	}
	public Long getBookId() {
		return bookId;
	}
	public void setBookId(Long bookId) {
		this.bookId = bookId;
	}
	@Override
	public String toString() {
		return "Book [bookName=" + bookName + ", bookId=" + bookId + "]";
	}
}

应用入口类:

package com.wu.application;

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

import com.wu.application.pojo.Book;

@SpringBootApplication
public class MyApplication {

	public static void main(String[] args) {
		ApplicationContext context = SpringApplication.run(MyApplication.class, args);
		Book book = context.getBean("book",Book.class);
		System.out.println(book);
	}
}

结果:

Book [bookName=张三, bookId=999]

第二种:@EnableConfigurationProperties+@ConfigurationProperties

pojo类:

package com.wu.application.pojo;

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

@ConfigurationProperties(prefix = "mybook")
public class Book {
	private String bookName;
	private Long bookId;
	public Book() {}
	public Book(String bookName,Long bookId) {
		this.bookName = bookName;
		this.bookId = bookId;
	}
	public String getBookName() {
		return bookName;
	}
	public void setBookName(String bookName) {
		this.bookName = bookName;
	}
	public Long getBookId() {
		return bookId;
	}
	public void setBookId(Long bookId) {
		this.bookId = bookId;
	}
	@Override
	public String toString() {
		return "Book [bookName=" + bookName + ", bookId=" + bookId + "]";
	}
}

配置类:

package com.wu.application.config;

import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Configuration;

import com.wu.application.pojo.Book;
@Configuration // 默认情况下的配置类(等价于配置文件)为单例模式 : 使用代理模式得到强化
@EnableConfigurationProperties(Book.class) // 1.开启属性配置功能 2.使得该组件自动注册到spring容器中
public class MyConfig {
}

应用入口类:

package com.wu.application;

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

import com.wu.application.pojo.Book;

@SpringBootApplication
public class MyApplication {

	public static void main(String[] args) {
		ApplicationContext context = SpringApplication.run(MyApplication.class, args);
		Book book = context.getBean("mybook-com.wu.application.pojo.Book",Book.class);
		System.out.println(book);
	}
}

结果:

Book [bookName=张三, bookId=999]

通过Value注解获取自定义配置

首先在application.yml中添加自定义属性语句:

student:
  name: 张三
  age: 20
  id: 2021

MyController.java:

package com.wu.springboot.controller;


import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

@Controller
@RequestMapping("/home")
public class MyController {
    @Value("${student.name}")
    String studentName;
    @Value("${student.age}")
    int studentAge;
    @Value("${student.id}")
    long studentId;

    @RequestMapping(value = "/info")
    @ResponseBody
    public String studentInfo(){
        return "学生姓名:"+studentName+",学生年龄:"+studentAge+",学生学号:"+studentId;
    }
}

结果:
在这里插入图片描述

事务处理

SpringBoot&Mybatis-Plus实现转账事务为例

在这里插入图片描述

事务实现是通过在启动类上添加注解@EnableTransactionManagement以及在相应类或者相应方法上添加@Transactional注解

package org.wu.project.controlle;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.wu.project.mapper.AccountMapper;
import org.wu.project.service.AccountService;

@RestController
public class AccountController {
    private AccountService accountService;
    @Autowired
    @Qualifier("accountServiceBean")
    public void setAccountService(AccountService accountService) {
        this.accountService = accountService;
    }

    @RequestMapping("/transfer")
    public boolean transfer(String senderId,String receiverId,Integer money){
        try {
            accountService.transfer(senderId, receiverId, money);
            return true;
        }catch(Exception e){
            e.printStackTrace();
        }
        return false;
    }
}

package org.wu.project.entity;

import lombok.Data;

@Data
public class Account {
    private String id;
    private String userName;
    private int money;
}

package org.wu.project.mapper;

import org.apache.ibatis.annotations.Param;
import org.springframework.stereotype.Repository;


@Repository("accountMapperBean")
public interface AccountMapper {
    void increaseMoney(@Param("id") String id,@Param("money") Integer money);
    void reduceMoney(@Param("id") String id,@Param("money") Integer money);
}

package org.wu.project.service;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.wu.project.mapper.AccountMapper;

@Service("accountServiceBean")
public class AccountService {
    private AccountMapper accountMapper;
    @Autowired
    @Qualifier("accountMapperBean")
    public void setAccountMapper(AccountMapper accountMapper) {
        this.accountMapper = accountMapper;
    }
    @Transactional
    public void transfer(String senderId,String receiverId,Integer money){
        accountMapper.increaseMoney(receiverId,money);
        accountMapper.reduceMoney(senderId,money);
    }
}

package org.wu.project;

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

@SpringBootApplication
@EnableTransactionManagement
@MapperScan("org.wu.project.mapper")
public class ProjectApplication {
    public static void main(String[] args) {
        SpringApplication.run(ProjectApplication.class, args);
    }
}

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace = "org.wu.project.mapper.AccountMapper">
    <update id="increaseMoney">
        update account set money = #{money} + money
        where id = #{id}
    </update>
    <update id="reduceMoney">
        update account set money = money - #{money}
        where id = #{id}
    </update>
</mapper>
# 应用名称
spring.application.name=project
# 应用服务 WEB 访问端口
server.port=8888
#下面这些内容是为了让MyBatis-Plus映射
#指定Mybatis-Plus的Mapper文件
mybatis-plus.mapper-locations=classpath:mappers/*.xml
#指定Mybatis-Plus的实体目录
mybatis-plus.type-aliases-package=org.wu.project.entity
# 数据库驱动:
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
# 数据源名称
spring.datasource.name=defaultDataSource
# 数据库连接地址
spring.datasource.url=jdbc:mysql://localhost:3306/test?serverTimezone=UTC
# 数据库用户名&密码:
spring.datasource.username=root
spring.datasource.password=root

转账事务处理之前:
在这里插入图片描述
转账事务处理之后(本地局域网主机输入网址http://localhost:8888/transfer?senderId=001&receiverId=002&money=200):

在这里插入图片描述

然后模拟一个异常来使得该事务发生中断,重新输入url:

在这里插入图片描述

结果为保持以上的money:

在这里插入图片描述

进一步扩展事务有关的细节:

@Transactional相关的属性

参数名称

功能描述

readOnly

该属性用于设置当前事务是否为只读事务,设置为true表示只读,false则表示可读写,默认值为false。例如:@Transactional(readOnly=true)

rollbackFor

该属性用于设置需要进行回滚的异常类数组,当方法中抛出指定异常数组中的异常时,则进行事务回滚。例如:

指定单一异常类:@Transactional(rollbackFor=RuntimeException.class)

指定多个异常类:@Transactional(rollbackFor={RuntimeException.class, Exception.class})

rollbackForClassName

该属性用于设置需要进行回滚的异常类名称数组,当方法中抛出指定异常名称数组中的异常时,则进行事务回滚。例如:

指定单一异常类名称:@Transactional(rollbackForClassName="RuntimeException")

指定多个异常类名称:@Transactional(rollbackForClassName={"RuntimeException","Exception"})

noRollbackFor

该属性用于设置不需要进行回滚的异常类数组,当方法中抛出指定异常数组中的异常时,不进行事务回滚。例如:

指定单一异常类:@Transactional(noRollbackFor=RuntimeException.class)

指定多个异常类:@Transactional(noRollbackFor={RuntimeException.class, Exception.class})

noRollbackForClassName

该属性用于设置不需要进行回滚的异常类名称数组,当方法中抛出指定异常名称数组中的异常时,不进行事务回滚。例如:

指定单一异常类名称:@Transactional(noRollbackForClassName="RuntimeException")

指定多个异常类名称:

@Transactional(noRollbackForClassName={"RuntimeException","Exception"})

propagation

该属性用于设置事务的传播行为,具体取值可参考表6-7。

例如:@Transactional(propagation=Propagation.NOT_SUPPORTED,readOnly=true)

isolation

该属性用于设置底层数据库的事务隔离级别,事务隔离级别用于处理多事务并发的情况,通常使用数据库的默认隔离级别即可,基本不需要进行设置

timeout

该属性用于设置事务的超时秒数,默认值为-1表示永不超时

  • 脏读:并发事务A读到了并发事务B还未提交的数据
  • 不可重复读: 在一个并发事务里面读取了两次某个数据,读出来数据不一致
  • 幻读: 在一个并发事务里面的操作中实现了不符合预期的数据(另一个并发事务改变了数据数量… ),幻读出现的前提是并发的事务中发生了插入、删除操作


SpringBoot工程多环境配置

一个产品从开发到用户使用一般会涉及到以下四个环境:
  • 开发环境
  • 测试环境
  • 准生产环境
  • 生产环境

建立四个以application-作为前缀的配置文件
在这里插入图片描述

在主配置文件application.yml中添加如下语句作为环境的选择:

#以下选择为开发环境
spring.profiles.active=dev

配置文件YAML类型

简介
YAML(读音:呀们) 是 "YAML Ain't a Markup Language"(YAML 不是一种标记语言)的递归缩写。在开发的这种语言时,YAML 的意思其实是:"Yet Another Markup Language"(仍是一种标记语言)。 YAML 的语法和其他高级语言类似,并且可以简单表达清单、散列表,标量等数据形态。它使用空白符号缩进和大量依赖外观的特色,特别适合用来表达或编辑数据结构、各种配置文件、倾印调试内容、文件大纲。YAML 的配置文件后缀为 .yml.yaml
基本语法
  • 大小写敏感
  • 使用缩进表示层级关系
  • 缩进不允许使用tab,只允许空格
  • 缩进的空格数不重要,只要相同层级的元素左对齐即可
  • '#'表示注释
用法
  • 字面量意思
key: value
  • 对象
# 写法一:行内写法
key: {key1:value1,key2:value2}
# 写法二:缩进写法
key:
	key1: value1
	key2: value2
  • 数组
# 写法一:行内写法
key: [value1,value2]
# 写法二:缩进写法
key:
	- value1
	- value2

这里需要注意的地方为:单引号会将字符串中的转义字符原封不动地输出,而双引号则会解析转义字符

自定义类绑定的配置提示

在main文件夹下建立webapp文件夹,并将其设置为资源文件夹:

在这里插入图片描述

pom.xml中加入依赖:

<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-configuration-processor</artifactId>
	<optional>true</optional>
</dependency>

打包排除:

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

配置复杂属性

application.yml:

others:
  users:
    - name: 张三
      address: 中国
      contact:
        - QQ
        - 微信
    - name: 李四
      address: 日本
      contact:
        - 邮箱
        - 电话

Users.java:

package com.wu.springboot.pojo;

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

import java.util.List;


@Component
@ConfigurationProperties(prefix = "others")
public class Users {
    private List<User> users;
    public List<User> getUsers(){
        return users;
    }
    public void setUsers(List<User> users){
        this.users = users;
    }

    @Override
    public String toString() {
        return "Users{" +
                "users=" + users +
                '}';
    }
}
class User{
    private String name;
    private String address;
    private List<String> contact;

    public String getName() {
        return name;
    }
    public String getAddress(){
        return address;
    }
    public List<String> getContact(){
        return contact;
    }
    public void setName(String name){
        this.name = name;
    }
    public void setAddress(String address){
        this.address = address;
    }
    public void setContact(List<String> contact){
        this.contact = contact;
    }

    @Override
    public String toString() {
        return "User{" +
                "name='" + name + '\'' +
                ", address='" + address + '\'' +
                ", contact=" + contact +
                '}';
    }
}

MyController:

package com.wu.springboot.cotroller;

import com.wu.springboot.pojo.Book;

import com.wu.springboot.pojo.Users;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("/")
public class MyController {
    @Autowired
    Users users;
    @GetMapping("/others")
    public String others(){
        return users.toString();
    }
}

结果:

在这里插入图片描述

SpringBoot集成传统jsp页面

pom.xml:

<?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.4.2</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.wu.springboot</groupId>
    <artifactId>springboot-01</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>springboot-01</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-web</artifactId>
        </dependency>

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

        <!-- springboot内嵌Tomcat对jsp的解析依赖 -->
        <dependency>
            <groupId>org.apache.tomcat.embed</groupId>
            <artifactId>tomcat-embed-jasper</artifactId>
        </dependency>
    </dependencies>

    <build>
        <!-- 指定jsp文件编译的路径META-INF/resources -->
        <resources>
            <resource>
                <!-- 指定源文件路径 -->
                <directory>src/main/webapp</directory>
                <!-- 指定编译路径 -->
                <targetPath>META-INF/resources</targetPath>
                <includes>
                    <include>*.*</include>
                </includes>
            </resource>
            <resource>
                <directory>src/main/resources</directory>
                <includes>
                    <include>**/*.*</include>
                </includes>
            </resource>
        </resources>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <version>2.4.2</version>
            </plugin>
        </plugins>
    </build>

</project>

application.yml:

spring:
  mvc:
    view:
      suffix: .jsp
      prefix: /

MyController.java:

package com.wu.springboot.controller;

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

@Controller
@RequestMapping("/home")
public class MyController {

    @RequestMapping(value = "/info")
    public String index(Model model){
        model.addAttribute("info","Hello World!");
        return "index";
    }
}

index.jsp:

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
    <h1>${info}</h1>
</body>
</html>

SpringBoot集成Thymeleaf

Thymeleaf是新一代Java模板引擎,支持HTML原型,既可以让前端工程师在浏览器中直接打开查看样式,也可以让后端工程师结合真实数据查看显示效果。使用其余的模板技术时,整合方式同Thymeleaf类似,比如FreeMarker大致也是如此,如果读者使用的是目前流行的前后端分离技术(比如Vue,React),那么在开发过程中不需要整合视图层技术,后端提供接口即可。

添加依赖:

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

application.yml:

server:
  port: 8888
# Thymeleaf选项自定义配置
spring:
  thymeleaf:
    cache: false # 缓存关闭,一般生产环境中需要关闭
    check-template: true # 检查模板是否存在
    check-template-location: true # 检查模板位置是否存在
    encoding: UTF-8 # 模板文件编码为UTF-8
    prefix: classpath:/templates/ # 模板文件位置
    suffix: .html # 模板文件后缀
    servlet:
      content-type: text/html # Content-type类型配置

Book.java:

package com.wu.springboot.pojo;

public class Book {
    private String name;
    private String author;
    private Float price;

    public String getName() {
        return name;
    }

    public String getAuthor() {
        return author;
    }
    public Float getPrice(){
        return price;
    }
    public void setName(String name){
        this.name = name;
    }
    public void setAuthor(String author){
        this.author = author;
    }
    public void setPrice(Float price){
        this.price = price;
    }

    @Override
    public String toString() {
        return "Book{" +
                "name='" + name + '\'' +
                ", author='" + author + '\'' +
                ", price=" + price +
                '}';
    }
}

MyController.java:

package com.wu.springboot.cotroller;

import com.wu.springboot.pojo.Book;


import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;

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

@Controller
@RequestMapping("/")
public class MyController {
    @GetMapping("/books")
    public ModelAndView books(){
        List<Book> books = new ArrayList<Book>();
        Book book1 = new Book();
        book1.setAuthor("张三");
        book1.setName("张三传");
        book1.setPrice(new Float(100.5));
        Book book2 = new Book();
        book2.setAuthor("李四");
        book2.setName("李四记");
        book2.setPrice(new Float(150.0));
        books.add(book1);
        books.add(book2);
        ModelAndView mv = new ModelAndView();
        mv.addObject("books",books);
        mv.setViewName("books");
        return mv;
    }
}

books.html:

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>书籍信息</title>
</head>
<body>
    <div align="center">
    <table border="1">
        <tr>
            <td>书籍名称</td>
            <td>书籍作者</td>
            <td>书籍价格</td>
        </tr>
        <tr th:each="book:${books}">
            <td th:text="${book.name}"></td>
            <td th:text="${book.author}"></td>
            <td th:text="${book.price}"></td>
        </tr>
    </table>
    </div>
</body>
</html>

结果:

在这里插入图片描述


SpringBoot整合log4j2日志

日志级别
机制:当一条日志信息的级别大于等于配置文件的级别,就生成日志记录。

  • trace:追踪,就是程序推进一下,可以写个trace输出,最不常用
  • debug:调试级别,一般作为最低级别
  • info:输出重要的信息,较常用
  • warn:警告级别
  • error:错误级别
  • fatal:致命级别

输出源

  • CONSOLE(输出到控制台)
  • FILE(输出到文件)

输出格式

  • SimpleLayout:以简单的格式显示
  • HTMLLayout:以HTML表格格式显示
  • PatternLayout:自定义格式显示

PatternLayout自定义日志格式
%d{yyyy-MM-dd HH:mm:ss} : 日志生成时间格式
%-5level : 日志输出级别,-5表示左对齐并且固定输出5个字符,如果不足在右边补0
%c : 日志输出logger的名称(%logger)
%t : 日志输出当前线程名称
%p : 日志输出格式
%m : 日志内容,即 logger.info(“message”)
%n : 日志换行符
%C : 日志输出Java类名(%F)
%L : 日志输出行号
%M : 日志输出方法名
%l : 日志输出语句所在的行数, 包括类名、方法名、文件名、行数
hostName : 日志输出本地机器名
hostAddress : 日志输出本地IP地址

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
    <!-- 排除springboot默认日志配置 -->
    <exclusions>
        <exclusion>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-logging</artifactId>
        </exclusion>
    </exclusions>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-log4j2</artifactId>
    <version>2.5.1</version>
</dependency>

log4j2.xml:

<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="INFO">
    <Appenders>
        <Console name="Console" target="SYSTEM_OUT">
            <PatternLayout pattern="%d{yyyy年MM月dd日 HH时mm分ss秒} [线程:%t 方法:%M] %-5level %logger{36} - %msg%n" />
        </Console>
    </Appenders>
    <Loggers>
        <Root level="info">
            <AppenderRef ref="Console" />
        </Root>
    </Loggers>
</Configuration>

package org.wu.project.controlle;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;



@RestController
public class AccountController {
    Logger logger = LogManager.getLogger(LogManager.ROOT_LOGGER_NAME);

    @RequestMapping("/test")
    public void test(){
        logger.info("测试信息打印");
    }

控制台输出日志信息:

2021-10-31 14:56:43,442 main INFO Log4j appears to be running in a Servlet environment, but there's no log4j-web module available. If you want better web container support, please add the log4j-web JAR to your web archive or server lib directory.
 __     _____     __ __   ___              _____ _
 \ \   / (_) \   / / \ \ / (_)            / ____| |
  \ \_/ / _ \ \_/ /__ \ V / _ _ __   __ _| |    | |__   ___ _ __
   \   / | | \   / _ \ > < | | '_ \ / _` | |    | '_ \ / _ \ '_ \
    | |  | |  | |  __// . \| | | | | (_| | |____| | | |  __/ | | |
    |_|  |_|  |_|\___/_/ \_\_|_| |_|\__, |\_____|_| |_|\___|_| |_|
                                     __/ |
                                    |___/
2021年10月31日 14时56分43秒 [线程:main 方法:logStarting] INFO  org.wu.project.ProjectApplication - Starting ProjectApplication on yiyexingchen with PID 7616 (E:\onedrive\OneDrive - laosaonan2\桌面\Java\spring-demo01\target\classes started by Localhost in E:\onedrive\OneDrive - laosaonan2\桌面\Java\spring-demo01)
2021年10月31日 14时56分43秒 [线程:main 方法:logStartupProfileInfo] INFO  org.wu.project.ProjectApplication - No active profile set, falling back to default profiles: default
2021年10月31日 14时56分44秒 [线程:main 方法:initialize] INFO  org.springframework.boot.web.embedded.tomcat.TomcatWebServer - Tomcat initialized with port(s): 8888 (http)
2021年10月31日 14时56分44秒 [线程:main 方法:log] INFO  org.apache.coyote.http11.Http11NioProtocol - Initializing ProtocolHandler ["http-nio-8888"]
2021年10月31日 14时56分44秒 [线程:main 方法:log] INFO  org.apache.catalina.core.StandardService - Starting service [Tomcat]
2021年10月31日 14时56分44秒 [线程:main 方法:log] INFO  org.apache.catalina.core.StandardEngine - Starting Servlet engine: [Apache Tomcat/9.0.41]
2021年10月31日 14时56分44秒 [线程:main 方法:log] INFO  org.apache.catalina.core.ContainerBase.[Tomcat].[localhost].[/] - Initializing Spring embedded WebApplicationContext
2021年10月31日 14时56分44秒 [线程:main 方法:prepareWebApplicationContext] INFO  org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext - Root WebApplicationContext: initialization completed in 1203 ms
 _ _   |_  _ _|_. ___ _ |    _ 
| | |\/|_)(_| | |_\  |_)||_|_\ 
     /               |         
                        3.4.2 
2021年10月31日 14时56分46秒 [线程:main 方法:initialize] INFO  org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor - Initializing ExecutorService 'applicationTaskExecutor'
2021年10月31日 14时56分46秒 [线程:main 方法:log] INFO  org.apache.coyote.http11.Http11NioProtocol - Starting ProtocolHandler ["http-nio-8888"]
2021年10月31日 14时56分46秒 [线程:main 方法:start] INFO  org.springframework.boot.web.embedded.tomcat.TomcatWebServer - Tomcat started on port(s): 8888 (http) with context path ''
2021年10月31日 14时56分46秒 [线程:main 方法:logStarted] INFO  org.wu.project.ProjectApplication - Started ProjectApplication in 3.26 seconds (JVM running for 4.83)
2021年10月31日 14时59分33秒 [线程:http-nio-8888-exec-1 方法:log] INFO  org.apache.catalina.core.ContainerBase.[Tomcat].[localhost].[/] - Initializing Spring DispatcherServlet 'dispatcherServlet'
2021年10月31日 14时59分33秒 [线程:http-nio-8888-exec-1 方法:initServletBean] INFO  org.springframework.web.servlet.DispatcherServlet - Initializing Servlet 'dispatcherServlet'
2021年10月31日 14时59分33秒 [线程:http-nio-8888-exec-1 方法:initServletBean] INFO  org.springframework.web.servlet.DispatcherServlet - Completed initialization in 8 ms
2021年10月31日 14时59分33秒 [线程:http-nio-8888-exec-1 方法:test] INFO   - 测试信息打印



自定义类绑定的配置提示依赖实例:

<dependency>
    <!-- Bean配置文件提示 -->
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-configuration-processor</artifactId>
    <optional>true</optional>
</dependency>



<configuration>
    <excludes>
        <!-- 打包排除 -->
        <exclude>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-configuration-processor</artifactId>
        </exclude>
    </excludes>
</configuration>
package org.wu.project.entity;

import lombok.Data;
import lombok.ToString;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;



@ConfigurationProperties(prefix = "test-object")
@Component
@Data
@ToString
public class TestObject {
    String testName;
    String testAge;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值