Spring boot
入门示例
配置maven依赖
<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>xm</groupId>
<artifactId>springbootTest</artifactId>
<version>1.0-SNAPSHOT</version>
<!-- 从Spring Boot继承默认值 -->
<parent>
<groupId> org.springframework.boot </groupId>
<artifactId> spring-boot-starter-parent </artifactId>
<version> 2.1.6.RELEASE </version>
</parent>
<!--添加Web应用程序的典型依赖项 -->
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
</dependencies>
</project>
springboot对多种框架提供构建支持,称为starter pom,其中对于SpringMVC的支持是
spring-boot-starter-web
包,此外还有其他Starter Pom,可以进入parent依赖中查看,也可以在官网文档中查看
创建运行程序
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 //controller里面的方法都以json格式输出
@EnableAutoConfiguration//自动配置,不需要自己写xml文件
public class Example {
@RequestMapping("/")
String home(){
return "Hello World!";
}
//程序入口
public static void main(String[] args) {
SpringApplication.run(Example.class,args);
}
}
以父子模块的方式配置maven依赖的方式
首先需要创建父工程,通过父工程点击new module
创建子工程,父工程的maven依赖如下:
<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>xm</groupId>
<artifactId>SpringBoot_Parent</artifactId>
<packaging>pom</packaging>
<version>1.0-SNAPSHOT</version>
<modules>
<module>SpringBoot_Child1</module>
</modules>
<dependencyManagement>
<dependencies>
<!-- Override Spring Data release train provided by Spring Boot -->
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-releasetrain</artifactId>
<version>Fowler-SR2</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>2.1.6.RELEASE</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
</project>
子工程需要依赖父工程,并添加自己所需要的依赖:
<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>SpringBoot_Parent</artifactId>
<groupId>xm</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>SpringBoot_Child1</artifactId>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
</dependencies>
</project>
注解
@EnableAutoConfiguration
该注解修饰的类将自动进行配置,不再需要xml配置文件,Spring-boot提供了多种自动配置的支持,可以在依赖包中的spring-boot-autoconfigure
包中查看支持的所有依赖
如果要关闭某些自动配置,可以在注解中使用exclude
属性,将不需要自动配置的类写上
//关闭Redis的自动配置
@EnableAutoConfiguration(exclude = RedisAutoConfiguration.class)
@SpringBootApplication
SpringBoot程序启动需要有一个入口,如果在每个控制器写一个入口会显得很麻烦,可以专门写一个启动类用于Spring启动,需要加上@EnableAutoConfiguration
和@ComponentScan
注解,SpringBoot提供SpringBootApplication
注解实现上面两个功能
package com.xm.app;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.ComponentScan;
//默认扫描当前包及以下的子包
//@EnableAutoConfiguration //SpringBoot自动配置
//@ComponentScan("com.xm.controller")//自动扫描
@SpringBootApplication(scanBasePackages = {"com.xm.controller"})
public class SpringApplications {
public static void main(String[] args) {
SpringApplication.run(SpringApplications.class,args);
}
}
@RestController
在控制器中,如果没有配置@ResponseBody注解,默认是进行跳转,如果一个控制器中的所有功能都是返回json,可以在类上加上@RestController
注解,这样里面的所有方法就都是返回json格式,不再需要一个一个配置注解
SpringBoot同样支持RestFul风格,方式与SpringMVC一样
全局配置文件
如果不希望使用SpringBoot默认的配置,可以自己创建配置文件,文件名必须是application,后缀名可以是properties或者yml,并将文件放置在resources目录下
server:
port: 8088
servlet:
context-path: /xm
这样重新启动时,端口号会改为8088,根目录会变成/xm
获取自定义属性的值
package com.xm.controller;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
@EnableAutoConfiguration
@Controller
public class BookController {
@Value("${book.author}")//取值
private String author;
@Value("${book.name}")
private String name;
@RequestMapping("/bookInfo")
@ResponseBody
public String showInfo(){
return author + ":" + name;
}
public static void main(String[] args) {
SpringApplication.run(BookController.class,args);
}
}
类型安全的配置
如果配置文件中有多个属性,每次取值都用value注解比较繁琐,SpringBoot提供基于类型安全的配置方式:
通过@ConfigurationProperties
指定前缀名,将文件中的属性与Bean相关联,同时Bean中的变量名要跟配置文件中的变量名一致,同时提供变量的get和set方法
package com.xm.controller;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
@EnableAutoConfiguration
@Controller
@ConfigurationProperties(prefix = "book")
public class BookController {
private String author;
private String name;
public String getAuthor() {
return author;
}
public void setAuthor(String author) {
this.author = author;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@RequestMapping("/bookInfo")
@ResponseBody
public String showInfo(){
return author + ":" + name;
}
public static void main(String[] args) {
SpringApplication.run(BookController.class,args);
}
}
Profile配置
当针对不同的环境需要使用不同的配置文件时,可以使用Profile配置,其格式为:application-*.properties
(application-prod.properties(生产环境),application-sit.properties(测试环境),application-dev.properties(开发环境))或者yml格式。然后需要在application.properties文件中通过string.profiles.active=prod/dev/..
来指定使用哪一个配置文件
# application-dev.yml
server:
port: 9999
# application.yml
book:
author: Toms
name: SpringBoots
spring:
profiles:
active: dev
SpringBoot整合测试
首先需要导入测试依赖:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-api</artifactId>
<version>5.5.0</version>
<scope>test</scope>
</dependency>
测试:
package com.xm.test;
import com.xm.controller.SpringController;
import junit.framework.TestCase;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.web.WebAppConfiguration;
@SpringBootTest(classes = SpringController.class)//测试谁
@RunWith(SpringJUnit4ClassRunner.class)//用什么测试
@WebAppConfiguration
public class TestSpringController {
@Autowired
private SpringController springController;//注入
@Test
public void test1(){
TestCase.assertEquals(this.springController.yes(),"hello");
}
}
SpringBoot日志管理
SpringBoot的日志级别有7个,从低到高分别是:
TRACE,DEBUG,INFO,WARN,ERROR,FATAL,OFF,如果设置了某个日志级别,低于该级别的日志不会输出。
SpringBoot默认配置ERROR,WARN和INFO级别的日志输出到控制台
默认情况下,SpringBoot将日志输出到控制台,不会写到日志文件。如果需要将日志写到文件中,需要在SprngBoot配置文件application.properties
中设置logging.file
或logging.path
属性
- logging.file:设置文件,绝对路径或者相对路径。如:
logging.file = log/my.log(相对)
logging.file = /log/my.log(绝对)
- logging.path:设置目录,会在该目录下创建spring.log文件,并写入日志内容
logging.path = /var/log
两者不能同时使用,如同时使用,只有logging.file生效,默认日志文件的大小达到10MB会切分一次产生新的日志文件
配置示例:
logging.level.root = WARN
logging.level.org.springframework.web = DEBUG
logging.file = 路径
logging.pattern.console = %d{yyyy/MM/dd-HH:mm:ss}
[%thread] %-5level %logger- %msg%n
[%thread] %-5level %logger- %msg&n
自定义日志配置
除了在Springboot中进行日志配置,还可以自己根据使用的日志系统写日志配置文件
文件命令建议加上-spring
,这样spring boot可以为它添加一些spring boot特有的配置项,不加的情况下需要在全局配置文件中指定自己定义的文件名:
logging.config = classpath:logging-config.xml
自定义日志系统
Spring默认使用的日志是Logback,如果要使用其他类型,需要先对Logback进行排除
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
<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>
</dependency>
配置工程为开发模式
在开发过程中,每次修改代码后需要重新启动,可以将工程设置为开发模式,代码修改不再需要重新运行,具体做法为导入以下依赖:
<dependency>
<groupId>org.springframework</groupId>
<artifactId>springloaded</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<optional>true</optional>
</dependency>
访问静态资源
在SpringBoot中访问静态资源跟普通Web项目不太一样,Spring Boot默认的路径是在resources/static
和resources/public
,也可以自己在全局配置文件中进行配置:
spring.resources.static-locations=classpath:/static/
自定义JSON转换
SpringBoot默认使用Jackson进行json解析,如果希望自定义(如使用FastJson),可以通过以下方式更改:
首先导入FastJson包
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.58</version>
</dependency>
在启动类中注入新配置:
package com.xm.app;
import com.alibaba.fastjson.serializer.SerializerFeature;
import com.alibaba.fastjson.support.config.FastJsonConfig;
import com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.http.HttpMessageConverters;
import org.springframework.context.annotation.Bean;
import org.springframework.http.converter.HttpMessageConverter;
//默认扫描当前包及以下的子包
//@EnableAutoConfiguration //SpringBoot自动配置
//@ComponentScan("com.xm.controller")//自动扫描
@SpringBootApplication(scanBasePackages = "com.xm.controller")
public class SpringApplications{
@Bean//依赖注入
public HttpMessageConverters fastJsonMessageConverter(){
//创建FastJson的消息转换器
FastJsonHttpMessageConverter converter = new FastJsonHttpMessageConverter();
//创建FastJson的配置对象
FastJsonConfig config = new FastJsonConfig();
//对json数据进行格式化
config.setSerializerFeatures(SerializerFeature.PrettyFormat);
converter.setFastJsonConfig(config);
HttpMessageConverter<?>con = converter;
return new HttpMessageConverters(con);
}
public static void main(String[] args) {
SpringApplication.run(SpringApplications.class,args);
}
}
对于中文,默认客户端接受不一定使用URTF-8编码,可以在全局配置文件加入如下配置使客户端使用UTF-8编码:
spring.http.encoding.force = true
创建实体类进行验证:
package com.xm.com.xm.pojo;
import com.alibaba.fastjson.annotation.JSONField;
import java.util.Date;
public class Person {
private Integer id;
private String name;
@JSONField(format = "yyyy-MM-dd HH:mm:ss")
private Date date;//日期格式化
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Date getDate() {
return date;
}
public void setDate(Date date) {
this.date = date;
}
}
package com.xm.controller;
import com.xm.com.xm.pojo.Person;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import java.util.Date;
@Controller
public class PersonController {
@ResponseBody
@RequestMapping("/show")
public Object show(){
Person person = new Person();
person.setId(66);
person.setName("小明");
person.setDate(new Date());
return person;
}
}
自定义拦截器
通过继承WebMvcConfigurer接口,对里面的addInterceptors
方法重写,根据自己需要实现的拦截功能进行定义:
package com.xm.interceptor;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@Configuration//声明这是一个配置
public class MyInterceptor implements WebMvcConfigurer {
@Override
public void addInterceptors(InterceptorRegistry registry) {
HandlerInterceptor interceptor = new HandlerInterceptor() {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("自定义拦截器");
return true;
}
};
registry.addInterceptor(interceptor).addPathPatterns("/**");
}
}
在启动项中扫描的包上需要加入当前包
全局异常处理器
SpringBoot使用Aop的思想进行异常处理
package com.xm.exceptionHandler;
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 GlobalExceptionHandler {
@ExceptionHandler(Exception.class)
@ResponseBody
public Map<String,Object> handleException(Exception exception){
Map<String,Object> map = new HashMap<>();
map.put("errorCode",500);
map.put("errorMag",exception.toString());
return map;
}
}
异步调用
在项目中当需要访问其他接口较慢或者做耗时工作时,如果不希望程序一直卡着而是能够并行处理,可以使用多线程来并行处理任务
SpringBoot提供了异步处理方式@Async
- 创建服务层接口及实现类
在相应需要开启子线程的方法上使用@Async
注解
package com.xm.service;
import java.util.concurrent.Future;
public interface AsyncService {
Future<String> doTask1() throws Exception;
Future<String> doTask2() throws Exception;
Future<String> doTask3() throws Exception;
}
package com.xm.service;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.AsyncResult;
import org.springframework.stereotype.Service;
import java.util.Random;
import java.util.concurrent.Future;
@Service
public class AsyncServiceImpl implements AsyncService {
private static Random random = new Random();
@Async//标示开启子进程异步调用
@Override
public Future<String> doTask1() throws Exception {
System.out.println("任务一开始执行");
long start = System.currentTimeMillis();
Thread.sleep(random.nextInt(10000));
long end = System.currentTimeMillis();
System.out.println("任务一结束,耗时:"+(end-start)+"毫秒");
return new AsyncResult<>("任务一结束");
}
@Async
@Override
public Future<String> doTask2() throws Exception {
System.out.println("任务二开始执行");
long start = System.currentTimeMillis();
Thread.sleep(random.nextInt(10000));
long end = System.currentTimeMillis();
System.out.println("任务二结束,耗时:"+(end-start)+"毫秒");
return new AsyncResult<>("任务二结束");
}
@Async
@Override
public Future<String> doTask3() throws Exception {
System.out.println("任务三开始执行");
long start = System.currentTimeMillis();
Thread.sleep(random.nextInt(10000));
long end = System.currentTimeMillis();
System.out.println("任务三结束,耗时:"+(end-start)+"毫秒");
return new AsyncResult<>("任务三结束");
}
}
- 创建控制器调用服务层
package com.xm.controller;
import com.xm.service.AsyncService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import java.util.concurrent.Future;
@Controller
public class SyncController {
@Autowired
private AsyncService asyncService;
@RequestMapping("/async")
@ResponseBody
public String asyncTest() throws Exception {
long start = System.currentTimeMillis();
Future<String> task1 = asyncService.doTask1();
Future<String> task2 = asyncService.doTask2();
Future<String> task3 = asyncService.doTask3();
while (true){
if(task1.isDone() && task2.isDone() && task3.isDone()){
break;
}
Thread.sleep(1000);
}
long end = System.currentTimeMillis();
return "全部执行完成,总耗时:"+(end-start)+"毫秒";
}
}
- 在启动类上添加
@EnableAsync
开启异步执行,同时扫描的包要加上service包
模版引擎
SpringBoot官方对于动态页面推荐使用模版引擎,动态引擎有:FreeMarker、Thymeleaf、 Mustache等
SpringBoot中整合Freemarker
- 首先导入freemarker依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-freemarker</artifactId>
</dependency>
- 创建
ftl
文件
SpringBoot默认会在resources/templates
目录下获取后缀名为.ftl
的模版引擎文件
<html>
<head> Freemarker模版引擎</head>
<body>
${name}
</body>
</html>
- 创建控制器传值
package com.xm.controller;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller
public class TemplatesController {
@RequestMapping("/index")
public String index(Model model){
model.addAttribute("name","小明");
return "show";//会自动到resources/templates目录下找
}
}
如果要改变Freemarker的默认配置,可以在全局配置文件中做自定义配置
SpringBoot整合Thymeleaf
- 导入
spring-boot-starter-thymeleaf
依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
- 创建html文件
Thymeleaf默认的页面文件是html文件,同时其有自己的语法
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Thymeleaf</title>
</head>
<body>
<h1 th:text="${name}"></h1>
</body>
</html>
剩下的跟上一种一样
SpringBoot整合QuartZ
QuartZ是一个用于任务调度的框架
- 创建定时任务:
对需要定时执行的任务使用@Scheduled
注解,同时需要将该类放入容器,使用@Component
package com.xm.job;
import org.springframework.scheduling.annotation.Scheduled;
import java.text.SimpleDateFormat;
import java.util.Date;
public class MyJob {
@Scheduled(fixedRate = 1000)//每隔多久执行一次任务,单位毫秒
public void run(){
System.out.println(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));
}
}
- 在启动类中开启任务调度:使用
@EnableScheduling
,同时扫描包要指明
数据库相关操作
SpringBoot整合JdbcTemplate
首先需要导入相关依赖:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.16</version>
</dependency>
创建相应的pojo,dao和service
package com.xm.pojo;
public class User {
private Integer id;
private String name;
private Integer age;
//省略get,set方法
}
package com.xm.dao;
import com.xm.pojo.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Repository;
@Repository
public class UserDao {
@Autowired
private JdbcTemplate jdbcTemplate;
public void addUser(User user){
jdbcTemplate.update("insert into users(name,age) values (?,?)", new Object[]{
user.getName(),
user.getAge()
});
}
}
package com.xm.service;
import com.xm.dao.UserDao;
import com.xm.pojo.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
public class UserService {
@Autowired
private UserDao userDao;
public void saveUser(User user){
userDao.addUser(user);
}
}
创建控制器:
package com.xm.controller;
import com.xm.pojo.User;
import com.xm.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
@Controller
public class UserController {
@Autowired
private UserService userService;
@RequestMapping("/savaUser")
@ResponseBody
public String save(){
User user = new User();
user.setName("潘多拉");
user.setAge(666);
userService.saveUser(user);
return "success";
}
}
在全局配置文件中设置连接数据库的相关信息:
spring.datasource.driver-class-name = com.mysql.cj.jdbc.Driver
spring.datasource.username=root
spring.datasource.password= root
spring.datasource.url = jdbc:mysql://localhost:3306/spring
SpringBoot整合Mybatis
xml文件方式
- 添加依赖:
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.16</version>
</dependency>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.0.1</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.19</version>
</dependency>
<!-- 分页插件-->
<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper-spring-boot-starter</artifactId>
<version>1.2.12</version>
</dependency>
<dependency>
<groupId>org.mybatis.generator</groupId>
<artifactId>mybatis-generator-maven-plugin</artifactId>
<version>1.3.7</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.mybatis.generator</groupId>
<artifactId>mybatis-generator-maven-plugin</artifactId>
<version>1.3.7</version>
<dependencies>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.47</version>
</dependency>
</dependencies>
</plugin>
</plugins>
</build>
- 通过逆向工程创建pojo,mapper和dao,手动添加相应的注解
- 将生成的
xxxMapper.xml
文件放到sources目录下 - 在resources目录下创建mybatis配置文件,只需写入前提配置即可
- 创建全局配置文件进行配置
spring:
datasource:
name: test
url: jdbc:mysql://localhost:3306/spring
username: root
password: root
type: com.alibaba.druid.pool.DruidDataSource
driver-class-name: com.mysql.cj.jdbc.Driver
dbcp2:
initial-size: 1
max-wait-millis: 60000
min-idle: 1
time-between-eviction-runs-millis: 60000
min-evictable-idle-time-millis: 300000
validation-query: select 'x'
test-while-idle: true
test-on-borrow: false
test-on-return: false
pool-prepared-statements: true
max-open-prepared-statements: 20
mybatis:
mapper-locations: classpath:mapper/UsersMapper.xml
config-location: classpath:mybatis/mybatis-config.xml
pagehelper:
reasonable: true
support-methods-arguments: true
params: count=countSql
helper-dialect: mysql
- 开发服务层和控制器层
package com.xm.service;
import com.github.pagehelper.PageHelper;
import com.xm.dao.UsersMapper;
import com.xm.pojo.Users;
import com.xm.pojo.UsersExample;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
@Service
public class UsersServiceImpl implements UsersService {
@Autowired
private UsersMapper usersMapper;
@Override
public void addUser(Users users) {
usersMapper.insert(users);
}
@Override
public List<Users> findUsers(int page, int rows) {
UsersExample example = new UsersExample();
PageHelper.startPage(page,rows);//相当于拦截器
List<Users> users = usersMapper.selectByExample(example);
return users;
}
}
package com.xm.controller;
import com.xm.pojo.Users;
import com.xm.service.UsersService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import java.util.List;
@Controller
public class UsersController {
@Autowired
private UsersService usersService;
@RequestMapping("/saveUser")
@ResponseBody
public String saveUsers(){
Users users = new Users();
users.setAge(12);
users.setName("阿拉斯加");
usersService.addUser(users);
return "success";
}
@RequestMapping("/findUsers/{page}/{rows}")
@ResponseBody
public List<Users> findUsers(@PathVariable int page,@PathVariable int rows){
return usersService.findUsers(page,rows);
}
}
注解方式
这种方式不需要mybatis配置文件和mapper的xml文件,主要修改的地方为映射类:
在对应的方法上使用相应的注解并自己写上sql语句,同时方法中的变量使用@Param
使其对应上
package com.xm.dao;
import com.xm.pojo.Users;
import com.xm.pojo.UsersExample;
import java.util.List;
import org.apache.ibatis.annotations.Insert;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select;
import org.springframework.stereotype.Repository;
@Repository
public interface UsersMapper {
@Select("select * from users where name=#{name}")
Users findUserByName(@Param("name") String name);
@Insert("insert into users(name,age) values(#{name},#{age})")
void addUser(@Param("name") String name,@Param("age") Integer age);
}
SpringBoot整合多数据源
在项目中通常会进行数据库拆分或者是引入其他数据库,从而需要配置多个数据源
区分多个数据源的方式:
- 通过包来区分:com.db1.mapper,com.db2.mapper
- 使用注解区分:需要使用大量注解,一般不推荐使用
整合流程:
- 在全局配置文件中配置多个数据源
#配置两个数据源
spring.datasource.db1.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.db1.username=root
spring.datasource.db1.password=root
#2.0之后的版本需要使用jdbc-url
spring.datasource.db1.jdbc-url=jdbc:mysql://localhost:3306/spring
spring.datasource.db2.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.db2.username=root
spring.datasource.db2.password=root
spring.datasource.db2.jdbc-url=jdbc:mysql://localhost:3306/sm
- 对每个数据源进行配置
DataSource1.java:
package com.xm.datasource;
import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.SqlSessionTemplate;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.jdbc.DataSourceBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import javax.sql.DataSource;
@Configuration //注册到Spring容器中
//扫描对应的mapper的包还有对应sqlSessionFactory的引用
@MapperScan(basePackages="com.xm.db1.mapper",sqlSessionFactoryRef = "db1SqlSessionFactory")
public class DataSource1 {
/**
* 配置db1数据库,生成数据源对象
* @return
*/
@Bean(name = "db1Datasource")
@ConfigurationProperties(prefix = "spring.datasource.db1")//对应全局配置文件前缀
public DataSource testDataSource(){
return DataSourceBuilder.create().build();
}
/**
* 创建SqlSessionFactory
* @param dataSource
* @return
* @throws Exception
*/
@Bean(name="db1SqlSessionFactory")
@Primary //自动装配时优先使用
public SqlSessionFactory testSqlSessionFactory(@Qualifier("db1Datasource")DataSource dataSource)
throws Exception {
SqlSessionFactoryBean bean = new SqlSessionFactoryBean();
bean.setDataSource(dataSource);
return bean.getObject();
}
/**
* 配置事务管理
* @param dataSource
* @return
*/
@Bean(name="db1TransactionManager")
public DataSourceTransactionManager testTransactionManager(
@Qualifier("db1Datasource")DataSource dataSource){
return new DataSourceTransactionManager(dataSource);
}
/**
* 整合数据库和mybatis时用于实现数据库操作
* @param sqlSessionFactory
* @return
*/
@Bean(name="db1SqlSessionTemplate")
public SqlSessionTemplate testSqlSessionTemplate(
@Qualifier("db1SqlSessionFactory") SqlSessionFactory sqlSessionFactory){
return new SqlSessionTemplate(sqlSessionFactory);
}
}
另一个数据源大致相同,只需要相应的改成2就可以了
3. 创建mapper文件,需要将两个数据源放在不用的包中
需要注意注解指定相应的数据源
package com.xm.db1.mapper;
import org.apache.ibatis.annotations.Insert;
import org.apache.ibatis.annotations.Param;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Repository;
@Qualifier("db1SqlSessionFactory")
@Repository("db1UserMapper")
public interface UsersMapper {
@Insert("insert into users(name,age) values(#{name},#{age})")
void addUser(@Param("name")String name, @Param("age")Integer age);
}
- 开发相应的service
package com.xm.db1.service;
import com.xm.db1.mapper.UsersMapper;
import com.xm.db1.pojo.Users;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
@Service("db1UsersService")
public class UsersServiceImpl implements UsersService {
@Resource(name = "db1UserMapper")
private UsersMapper usersMapper;
@Override
public void saveUser(Users users) {
usersMapper.addUser(users.getName(),users.getAge());
}
}
- 创建控制器层
import org.springframework.web.bind.annotation.ResponseBody;
import javax.annotation.Resource;
@Controller
public class IndexController {
@Resource(name = "db1UsersService")//对应不同的service
private UsersService usersService1;
@Resource(name = "db2UsersService")
private com.xm.db2.service.UsersService usersService2;
@RequestMapping("/addUser")
@ResponseBody
public String addUser(){
Users users1 = new Users();
users1.setName("哈士奇");
users1.setAge(111);
usersService1.saveUser(users1);
return "OK";
}
}
SpringBoot事务管理
在SpringBoot中推荐使用@Transactional
注解声明事务管理,只需要在需要开启事务的方法上加上即开启事务
SpringBoot整合JPA
jpa是一种数据持久化的规范,其实现最受欢迎的有Hibernate,Springboot也针对jpa做了实现:其可以根据实体类自动生成数据库表
- 导入依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
- 全局配置文件配置数据库连接和JPA
spring.datasource.driver-class-name = com.mysql.cj.jdbc.Driver
spring.datasource.username=root
spring.datasource.password= root
spring.datasource.url = jdbc:mysql://localhost:3306/spring
# 让控制器输出json字符串格式
spring.jackson.serialization.indent-output=true
spring.jpa.hibernate.ddl-auto=update
spring.jpa.show-sql=true
spring.jooq.sql-dialect=MySQL5Dialect
- 创建实体类,对实体类使用
Entity
注解表示自动生成表
生成的表的表名默认和实体类的类名相同,可以通过使用注解@Table(name="xxx"
指定表名
对于需要作为表中主键的属性,使用@Id
注解,同时对于主键上的值的生成规则做指定:
使用@GenerateValue(strategy=GenerationType.xxxx
注解
- AUTO表示自动生成
- IDENTITY表示自动增长
对于其他的属性,默认属性名跟字段名相同,可以使用@Column(name="xx")
注解指明字段名,如果字段不允许为空,可以设置@Column(nullable=false)
package com.xm.pojo;
import javax.persistence.*;
import java.util.Date;
@Entity
@Table(name="t_user")
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
private String name;
private Integer age;
private Date birthday;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
public Date getBirthday() {
return birthday;
}
public void setBirthday(Date birthday) {
this.birthday = birthday;
}
}
- 创建Dao层
只需要创建一个接口并且继承JpaRepository
,这个子类提供了增删改查的功能,它有两个范型,第一个是实体类,第二个是实体类中主键属性的类型
package com.xm.dao;
import com.xm.pojo.User;
import org.springframework.data.jpa.repository.JpaRepository;
public interface UserDao extends JpaRepository<User, Integer> {
}
- service层和controller层
package com.xm.service;
import com.xm.dao.UserDao;
import com.xm.pojo.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
public class UserServiceImpl implements UserService {
@Autowired
private UserDao userDao;
@Override
public void addUser(User user) {
userDao.save(user);
}
}
@RestController
public class UserController {
@Autowired
private UserService userService;
@RequestMapping("/saveUser")
public String saveUser(){
User user = new User();
user.setName("巴啦啦小魔仙");
user.setAge(6);
user.setBirthday(new Date());
userService.addUser(user);
return "OK";
}
}
- 启动类需要使用相应的注解扫描
package com.xm.app;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.domain.EntityScan;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
@SpringBootApplication(scanBasePackages = "com.xm")
@EntityScan("com.xm.pojo")//扫描实体类从而生成表
@EnableJpaRepositories("com.xm.dao")//扫描dao
public class SpringBootApp {
public static void main(String[] args) {
SpringApplication.run(SpringBootApp.class,args);
}
}
未解决问题:启动后出现异常:java.lang.IllegalStateException: Error processing condition on org.springframework.boot.autoconfigure.data.web.SpringDataWebAutoConfiguration.pageableCustomizer
无法正常启动
SpringBoot整合Mail
发送普通邮件
导入spring-boot-starter-mail
依赖
配置全局配置文件
spring.mail.host=smtp.qq.com
spring.mail.username=934933088@qq.com
# 授权码,在qq邮箱设置里获取
spring.mail.password=xxxxx
spring.mail.properties.mail.smtp.auth=true
spring.mail.properties.mail.smtp.starttls.enable=true
spring.mail.properties.mail.smtp.starttls.required=true
读取邮件发送者:
package com.xm.mail;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
@Component
public class EmailConfig {
@Value("${spring.mail.username}")
private String emailFrom;
public String getEmailFrom(){
return emailFrom;
}
public void setEmailFrom(String emailFrom){
this.emailFrom = emailFrom;
}
}
服务层实现:
package com.xm.mail;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.mail.SimpleMailMessage;
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.stereotype.Service;
@Service
public class EmailServiceImpl implements EmailService {
@Autowired
private EmailConfig emailConfig;
@Autowired
private JavaMailSender mailSender;
@Override
public void sendSimpleMail(String sendTo, String title, String content) {
//简单邮件的发送
SimpleMailMessage message = new SimpleMailMessage();//构造邮件实体类
message.setFrom(emailConfig.getEmailFrom());
message.setTo(sendTo);
message.setSubject(title);
message.setText(content);
mailSender.send(message);//发送邮件
}
}
带附件的邮件
@Override
public void sendAttachmentMail(String sendTo, String title, String content, File file) {
MimeMessage msg = mailSender.createMimeMessage();//将邮件封装成对象
try {
MimeMessageHelper helper = new MimeMessageHelper(msg,true);//设置为multipart格式
helper.setFrom(emailConfig.getEmailFrom());
helper.setTo(sendTo);
helper.setSubject(title);
helper.setText(content);
FileSystemResource resource = new FileSystemResource(file);
helper.addAttachment("附件",resource);
} catch (MessagingException e) {
e.printStackTrace();
}
mailSender.send(msg);
}
@RequestMapping("/sendFileMail")
@ResponseBody
public String sendAttachmentEmail(){
File file = new File("SpringBoot_Child5/src/main/resources/static/66.txt");
emailService.sendAttachmentMail("934933088@qq.com","hello","看文件",file);
return "success";
}
发送模版邮件
需要导入模版引擎,同时在resources/templates目录下创建模版
service层:
@Service
public class EmailServiceImpl implements EmailService {
@Autowired
private EmailConfig emailConfig;
@Autowired
private JavaMailSender mailSender;
@Autowired
private FreeMarkerConfigurer freeMarkerConfigurer;
@Override
public void sendTemplateMail(String sendTo, String title, String info) {
//info为模版的文件名(包含后缀)
MimeMessage message = mailSender.createMimeMessage();
try {
MimeMessageHelper helper = new MimeMessageHelper(message,true);
helper.setFrom(emailConfig.getEmailFrom());
helper.setTo(sendTo);
helper.setSubject(title);
//封装模版使用的数据
Map<String,Object> model = new HashMap<>();
model.put("username","小红");
//得到模版
Template template = freeMarkerConfigurer.getConfiguration().getTemplate(info);
String html = FreeMarkerTemplateUtils.processTemplateIntoString(template, model);
helper.setText(html,true);
} catch (Exception e) {
e.printStackTrace();
}
mailSender.send(message);
}
}
控制器:
@RequestMapping("/sendTemplateEmail")
@ResponseBody
public String sendTemplateEmail(){
emailService.sendTemplateMail("934933088@qq.com","模版邮箱","info.html");
return "success";
}
文件操作
SpringBoot实现文件上传
依赖web包之后,文件上传的包就自动依赖上了
如果需要控制上传文件的大小,可以通过全局配置文件的设置
#上传单个文件的大小
spring.servlet.multipart.max-file-size=500MB
#上传全部文件的总大小
spring.servlet.multipart.max-request-size= 500MB
- 使用模版引擎编写文件上传页面
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>文件上传</title>
</head>
<body>
<h2>文件上传</h2>
<hr/>
<form method="post" enctype="multipart/form-data" action="/upload">
<p>
文件<input type="file" name="file"/>
</p>
<p>
<input type="submit" value="上传"/>
</p>
</form>
</body>
</html>
- 实现文件上传控制器
package com.xm.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.multipart.MultipartFile;
import javax.servlet.http.HttpServletRequest;
import java.io.File;
import java.io.IOException;
import java.util.UUID;
@Controller
public class UploadController {
//页面不能直接访问,需要通过控制器跳转
@RequestMapping("/toUpload")
public String toUpload(){
return "upload";
}
@RequestMapping(value = "/upload",method = RequestMethod.POST)
@ResponseBody
public String uploadFile(MultipartFile file, HttpServletRequest request){
//创建文件在服务器端的存放路径
String dir = request.getServletContext().getRealPath("/upload");
File fileDir = new File(dir);
if(!fileDir.exists())
fileDir.mkdirs();
//生成文件在服务器端存放的名字
String fileSuffix = file.getOriginalFilename().substring(file.getOriginalFilename().lastIndexOf("."));
String fileName = UUID.randomUUID().toString()+fileSuffix;
File files = new File(fileDir+"/"+fileName);
//上传
try {
file.transferTo(files);
} catch (IOException e) {
e.printStackTrace();
return "上传失败";
}
return "success";
}
}
批量文件上传
@RequestMapping(value = "/upload/batch",method = RequestMethod.POST)
@ResponseBody
public String uploadFiles(MultipartFile[] files,HttpServletRequest request){
//创建文件在服务器端的存放路径
String dir = request.getServletContext().getRealPath("/upload");
File fileDir = new File(dir);
if(!fileDir.exists())
fileDir.mkdirs();
//遍历数组
for(int i=0;i<files.length;i++){
String fileSuffix = files[i].getOriginalFilename().substring(files[i].getOriginalFilename().lastIndexOf("."));
String fileName = UUID.randomUUID().toString()+fileSuffix;
File file = new File(fileDir+"/"+fileName);
//上传
try {
files[i].transferTo(file);
} catch (IOException e) {
e.printStackTrace();
}
}
return "success";
}