SpringBoot系统笔记

1. SpringBoot 基础


1.1 简介(自动装配–约定大于配置)

  1. 用途:快速搭建java EE项目,提供自动化配置方案
  2. 优势:
  • 提供一个快速的spring项目搭建渠道
  • 提供一系列通用配置,纯java配置
  • 内嵌服务器,快速部署
1.1.1 pom.xml解读
  • spring-boot-dependencies :核心依赖在父工程中
  • 引入SpringBoot依赖不需要指定版本,因为有这些版本仓库
    在这里插入图片描述
  • 启动器
<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-web</artifactId>
</dependency>

SpringBoot会将所有的功能场景,都变成一个个的启动器,要使用什么功能,就只需要找到对应的启动器。
比如spring-boot-starter-web, 他就会帮我们自动导入web环境所有的依赖
官网列出的所有启动器


1.2 手动创建SpringBoot工程(了解)

1.2.1 idea创建maven工程
1.2.2 手动构建项目
  1. 添加依赖pom.xml文件 spring-boot-starter-parent,作用:
  • Java 版本默认使用1.8 .
  • 编码格式默认使用UTF-8.
  • 提供Dependency Management 进行项目依赖的版本管理。
  • 默认的资源过滤与插件配置。
  1. 启动类
@SpringBootApplication		// 1.配置Spring和SpringMVC 2.包扫描
public class App {
    public static void main(String[] args){
	SpringApplication.run(App.class,args);
    }
}
  1. 启动项目
  • idea启动main方法(内置tomcat)
  • 引依赖spring-boot-maven-plugin, mvn clean package打包,java -jar 命令启动jar包

1.3 快速创建SpringBoot工程(常用)

new project
SpringInitializer
default--next
输入项目基本信息
选择依赖和创建路径
  • 项目的基本信息,包括组织Id 、模块名称、项目构建类型、最终生成包的类型、Java 的版本、开发语言、项目版本号、项目名称、项目描述以及项目的包。
  • Spring Boot 项目创建成功之后,几乎零配置, 开发者就可以直接使用Spring 和SpringMVC 中的功能了

1.4 @SpringBootApplication注解

1.4.1 拆成3个注解

包括:

  • @SpringBootConfiguration 表明配置类,类似于Spring
    中的aplicationContext.xml 文件

    • 一般会创建一个专门的类用来配置bean,方便管理

      @Configuration
      public class MyConfig(){
      
      }
      
  • @EnableAutoConfiguration 开启自动化配置

  • @ComponentScan 扫描当前类所在包下面内容,一般把项目启动类放在根包中

    • 会扫描@Service , @Repository 、@Component 、
      @Controller 、@RestController 和@Configuration 等注解的类
1.4.2 深入
  1. SpringBoot在启动的时候从类路径下的META-INF/spring.factories中获取@EnableAutoConfiguration指定的值在这里插入图片描述
  2. 将这些值作为自动配置类导入容器 , 自动配置类就生效 , 帮我们进行自动配置工作;
  3. 整个J2EE的整体解决方案和自动配置都在springboot-autoconfigure的jar包中;
  4. 它将所有需要导入的组件以全类名的方式返回 , 这些组件就会被添加到容器中 ;
    org.springframework.boot.autoconfigure.aop.AopAutoConfiguration
    
  5. 它会给容器中导入非常多的自动配置类 (xxxAutoConfiguration), 就是给容器中导入这个场景需要的所有组件,并配置好这些组件
  6. 有了自动配置类,免去了我们手动编写配置注入功能组件等的工作
1.4.3 SpringApplication.run分析
  1. 判断是普通项目还是web项目
  2. 查找并加载所有可用初始化器,设置到initializers属性中
  3. 找出所有的应用程序监听器,设置到listeners属性中
  4. 推断并设置main方法的定义类,找到运行的主类

1.5 web容器配置

1.5.1 tomcat配置
1.5.1.1 常规配置

spring-boot-starter-web 依赖会默认使用Tomcat 作为Web 容器,可以在application.properties 中进行进一步配置

  • server . port = 8081 端口
  • server . error . path = /error 出错跳去的路径
  • server . servlet . session.timeout = 30m session失效时间
  • server . servlet . context-path = /chapter02 访问路径
  • server . tomcat . uriencoding = utf-8
  • server . tomcat . max-threads = 500 最大线程数
  • server . tomcat .basedir = /home/sang/tmp basedir 是一个存放Tomcat 运行日志和临时文件的目录,若不配置,则默认使用系统的临时目录
1.5.1.2 https配置
  1. 通过工具生成一个https证书
 keytool -genkey -alias tomcathttps -keyalg RSA -keysize 2048 -keystore sang.p12 -validity 365

在这里插入图片描述
2. 在application.properties 中配置

  • server.ssl.key-store=sang.p12
  • server.ssl.key-alias=tomcathttps
  • server.ssl.key-store-password=root123

然后就可以使用https访问了。

https://localhost:8081/chapter02/getHello

1.6 application.properties配置

对比@Value
在这里插入图片描述

1.6.1 加载&注入
  1. application.properties或application.yml可能出现的4个位置,按照顺序依次加载到Spring Environment中:
    在这里插入图片描述
  2. application.properties内容注入到bean实体类中的例子:
  • application.properties
book.name=三国演义
book.author=罗贯中
book.price=30
  • 或application.yml(多用,直接写json格式使用方便)
//yml文件还能支持对象和列表,如:book,persons
book:
  name: 水浒
  author_name: 施耐庵
  price: 30
  persons:
    - 武松
    - 宋江
    - chaogai

等同于

book: {name: 水浒传,author_name: 施耐庵,price: 30,persons: [武松,宋江,chaogai]}
  • 实体类Book
    @ConfigurationProperties(prefix = “book”)
    application.yml中的内容注入bean
    把配置文件中配置的每一个属性的值映射到这个组件中
    (直接使用 @Value 也可以赋值)
@Component
@ConfigurationProperties(prefix = "book")
public class Book {
	//@Value("楚门的世界")
	//@Value("${book.name}")
	//private String name;
	
    private String name;
    private String author;
    private Float price;
    private List<String> persons;

	public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getAuthor() {
        return author;
    }

    public void setAuthor(String author) {
        this.author = author;
    }

    public Float getPrice() {
        return price;
    }

    public void setPrice(Float price) {
        this.price = price;
    }
    
    public List<String> getPersons() {
        return persons;
    }

    public void setPersons(List<String> persons) {
        this.persons = persons;
    }
}
  • BookController
@RestController
public class BookController {

    @Autowired
    Book book;

    @GetMapping("/book")
    public Book book(){
        return book;
    }
}
  • 运行结果:
    在这里插入图片描述
    在这里插入图片描述
  1. YAML虽然方便, 但是存在缺陷,如:无法使用 @PropertySource注解加载 YAML文件
  • @PropertySource可以指定该实体类取哪个 .properties配置文件中的属性值,casey.properties就是application.yml同路径下的一个配置文件,使用@Value取属性值
@Component
//@ConfigurationProperties(prefix = "book")
@PropertySource(value = "classpath:casey.properties")
public class Book {

    @Value("${name}")
    private String name;
    private String authorName;
    private Float price;
    private List<String> persons;
    private Date time;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getAuthorName() {
        return authorName;
    }

    public void setAuthorName(String authorName) {
        this.authorName = authorName;
    }

    public Float getPrice() {
        return price;
    }

    public void setPrice(Float price) {
        this.price = price;
    }

    public List<String> getPersons() {
        return persons;
    }

    public void setPersons(List<String> persons) {
        this.persons = persons;
    }

    public Date getTime() {
        return time;
    }

    public void setTime(Date time) {
        this.time = time;
    }
}
  1. yaml文件中可以直接使用el表达式
book:
  name: 水浒${random.uuid}	#水浒96cbd308-d338-4bca-8897-17380137bc4e
  author_name: ${student.name:施耐庵}作者	#student.name不存在,取 施耐庵作者
  price: ${random.int}		#-698479567
  persons:
    - 武松
    - 宋江
    - chaogai
  1. 松散绑定
配置文件中:last-name
bean类中:lastName
  1. JSR-303校验
  • 使用 @Validated 注解,配合校验属性值
  • JSR-303
  • 最重要:正则表达式校验
@Pattern    验证 String 对象是否符合正则表达式的规则
@Component
@ConfigurationProperties(prefix = "book")
@Validated
public class Book {

    @Email(message = "邮箱格式错误")
    private String name;
    private String authorName;
    private int price;
    private List<String> persons;
    private Date time;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getAuthorName() {
        return authorName;
    }

    public void setAuthorName(String authorName) {
        this.authorName = authorName;
    }

    public int getPrice() {
        return price;
    }

    public void setPrice(int price) {
        this.price = price;
    }

    public List<String> getPersons() {
        return persons;
    }

    public void setPersons(List<String> persons) {
        this.persons = persons;
    }

    public Date getTime() {
        return time;
    }

    public void setTime(Date time) {
        this.time = time;
    }
}

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

空检查
@Null       验证对象是否为null
@NotNull    验证对象是否不为null, 无法查检长度为0的字符串
@NotBlank 检查约束字符串是不是Null还有被Trim的长度是否大于0,只对字符串,且会去掉前后空格.
@NotEmpty 检查约束元素是否为NULL或者是EMPTY.
 
Booelan检查
@AssertTrue     验证 Boolean 对象是否为 true  
@AssertFalse    验证 Boolean 对象是否为 false  
 
长度检查
@Size(min=, max=) 验证对象(Array,Collection,Map,String)长度是否在给定的范围之内  
@Length(min=, max=) Validates that the annotated string is between min and max included.
 
日期检查
@Past           验证 Date 和 Calendar 对象是否在当前时间之前  
@Future     验证 Date 和 Calendar 对象是否在当前时间之后  
@Pattern    验证 String 对象是否符合正则表达式的规则
 
数值检查,建议使用在Stirng,Integer类型,不建议使用在int类型上,因为表单值为“”时无法转换为int,但可以转换为Stirng为"",Integer为null
@Min            验证 Number 和 String 对象是否大等于指定的值  
@Max            验证 Number 和 String 对象是否小等于指定的值  
@DecimalMax 被标注的值必须不大于约束中指定的最大值. 这个约束的参数是一个通过BigDecimal定义的最大值的字符串表示.小数存在精度
@DecimalMin 被标注的值必须不小于约束中指定的最小值. 这个约束的参数是一个通过BigDecimal定义的最小值的字符串表示.小数存在精度
@Digits     验证 Number 和 String 的构成是否合法  
@Digits(integer=,fraction=) 验证字符串是否是符合指定格式的数字,interger指定整数精度,fraction指定小数精度。
 
@Range(min=, max=) 检查数字是否介于min和max之间.
@Range(min=10000,max=50000,message="range.bean.wage")
private BigDecimal wage;
 
@Valid 递归的对关联对象进行校验, 如果关联对象是个集合或者数组,那么对其中的元素进行递归校验,如果是一个map,则对其中的值部分进行校验.(是否进行递归验证)
@CreditCardNumber信用卡验证
@Email  验证是否是邮件地址,如果为null,不进行验证,算通过验证。
@ScriptAssert(lang= ,script=, alias=)
@URL(protocol=,host=, port=,regexp=, flags=)

在这里插入图片描述

1.6.2 开发环境和生产环境中的配置文件区分
  1. application.yml中进行多环境配置:选择激活哪个配置环境
spring:
  profiles:
    #表示使用配置文件application-dev.yml启动项目
    active: dev
  1. 可以配置不同的端口号:8080/8081
  • 开发环境:application-dev.yml
server:
  port: 8080
  • 生产环境:application-prod.yml
server:
  port: 8081
  1. 图示
    在这里插入图片描述
  2. 也可以写到一个文件application.yml中(不推荐,不容易替换部署到服务器时)
#   tomcat配置
server:
  port: 8081
  #servlet:
  #    context-path: /chapter02
  tomcat:
    uri-encoding: utf-8

  #   https配置
  ssl:
    key-store: sang.p12
    key-alias: tomcathttps
    key-store-password: root123

#激活配置文件
spring:
  profiles:
    active: dev


---
server:
  port: 8082
spring:
  profiles: dev

---
server:
  port: 8083
spring:
  profiles: test

启动的是dev,端口是8082
在这里插入图片描述

1.7 SpringBoot 配置总结

  • springboot到底帮我们配置了什么?我们能不能进行修改?能修改哪些东西?能不能扩展?
● xxxAutoConfiguraion:向容器中自动配置组件
● xxxxProperties:自动配置类,装配配置文件中自定义的一些内容

2. SpringBoot 整合视图层

2.1 整合Thymeleaf

参考:整合Thymeleaf

2.1.1 简单实现

  1. pom
<!--thymeleaf都是基于3.x开发-->
<dependency>
    <groupId>org.thymeleaf</groupId>
    <artifactId>thymeleaf-spring5</artifactId>
</dependency>
<dependency>
    <groupId>org.thymeleaf.extras</groupId>
    <artifactId>thymeleaf-extras-java8time</artifactId>
</dependency>
  1. templates文件夹下创建html页面
  • xmlns:th=“http://www.thymeleaf.org”
    *使用th:text
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>title</title>
</head>
<body>
<!--th:text就是将div中的内容设置为它指定的值,和之前学习的Vue一样-->
	<div th:text="${msg}"></div>
</body>
</html>
  1. controller访问html页面
    @controller和@restcontroller的区别
@RequestMapping("/success")
public String success(Model model){
    //存入数据
    model.addAttribute("msg","Hello,Thymeleaf");
    //classpath:/templates/success.html
    return "success";
}

在这里插入图片描述

2.1.2 语法积累

  1. url: @{ }
<link th:href="@{/css/bootstrap.min.css}" rel="stylesheet">
<form class="form-signin" th:action="@{/user/login}">
  1. 国际化: #{ }
<h1 class="h3 mb-3 font-weight-normal" th:text="#{login.tip}">Please sign in</h1>
  1. if th:if
    取反: not
    字符串为空:#strings.isEmpty( )
<!--如果msg不为空就显示-->
<p th:text="${msg}" th:if="${not #strings.isEmpty(msg)}"></p>

2.1.3 demo学习

在这里插入图片描述

2.1.4 国际化

国际化

2.2 整合FreeMarker

  • 如果使用的是目前流行的前后端分离技术, 那么在开发过程中不需要整合视图层技术,后端直接提供接口即可

3.SpringBoot 整合Web 开发

在这里插入图片描述

3.1 返回json数据

3.1.1 默认返回

由于pom.xml中添加的依赖:

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

其中默认加入了jackson-databind 作为JSON处理器,如上面例子中返回book对象就属于这种情况。在这里插入图片描述

3.1.2 自定义json处理器

  • 除了jackson-databind之外的
3.1.2.1 使用Gson
3.1.2.2 使用fastjson
  1. 首先除去jackson-databind依赖,引入fastjson依赖
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
    <exclusions>
        <exclusion>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-databind</artifactId>
        </exclusion>
    </exclusions>
</dependency>

<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>fastjson</artifactId>
</dependency>
  1. 在SpringBoot 项目中,当开发者引入spring-boot-starter-web 依赖之后,该依赖又依赖了spring-boot-autoconfigure , 在这个自动化配置中,有一个WebMvcAutoConfiguration 类提供了对SpringMVC 最基本的配置, 如果某一项自动化配置不满足开发需求,开发者可以针对该项自定义配置,只需要实现WebMvcConfigurer接口即可
  • 配置json解析过程中的一些细节
@Configuration
public class MyWebMvcConfig implements WebMvcConfigurer {
    @Override
    public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {

        FastJsonHttpMessageConverter converter = new FastJsonHttpMessageConverter();
        FastJsonConfig config = new FastJsonConfig();
        config.setDateFormat("yyyy-MM-dd hh:mm:ss");//日期格式
        config.setCharset(Charset.forName("UTF-8"));//数据编码
        config.setSerializerFeatures(
            SerializerFeature.WriteClassName,//是否在生成的JSON 中输出类名
            SerializerFeature.WriteMapNullValue,//是否输出value为null的数据
            SerializerFeature.PrettyFormat,//生成的json格式化
            SerializerFeature.WriteNullListAsEmpty,//空集合输出[]而非null
            SerializerFeature.WriteNullStringAsEmpty//空字符串输出""而非null
        );

        converter.setFastJsonConfig(config);
        converters.add(converter);
    }
}

3.2 静态资源访问

  • 源码
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
	if (!this.resourceProperties.isAddMappings()) {
		logger.debug("Default resource handling disabled");
		return;
	}
	Duration cachePeriod = this.resourceProperties.getCache().getPeriod();
	CacheControl cacheControl = this.resourceProperties.getCache().getCachecontrol().toHttpCacheControl();
	if (!registry.hasMappingForPattern("/webjars/**")) {
		customizeResourceHandlerRegistration(registry.addResourceHandler("/webjars/**")
				.addResourceLocations("classpath:/META-INF/resources/webjars/")
				.setCachePeriod(getSeconds(cachePeriod)).setCacheControl(cacheControl));
	}
	String staticPathPattern = this.mvcProperties.getStaticPathPattern();
	if (!registry.hasMappingForPattern(staticPathPattern)) {
		customizeResourceHandlerRegistration(registry.addResourceHandler(staticPathPattern)
				.addResourceLocations(getResourceLocations(this.resourceProperties.getStaticLocations()))
				.setCachePeriod(getSeconds(cachePeriod)).setCacheControl(cacheControl));
	}
}

3.2.1 默认策略

  1. 使用webjars,通过maven引入包,比如:jquery
  2. 不同位置静态资源的优先级:
  • resources/META-INF/resources
  • resources/resources
  • resources/static(默认)
  • resources/public
    在这里插入图片描述
  • IntelliJ IDEA 创建SpringBoot 项目,会默认创建出resources/static目录,一般静态资源放在此目录下即可

3.结论在这里插入图片描述

3.2.2 首页定制

  • 源码
@Bean
public WelcomePageHandlerMapping welcomePageHandlerMapping(ApplicationContext applicationContext,
		FormattingConversionService mvcConversionService, ResourceUrlProvider mvcResourceUrlProvider) {
	WelcomePageHandlerMapping welcomePageHandlerMapping = new WelcomePageHandlerMapping(
			new TemplateAvailabilityProviders(applicationContext), applicationContext, getWelcomePage(),
			this.mvcProperties.getStaticPathPattern());
	welcomePageHandlerMapping.setInterceptors(getInterceptors(mvcConversionService, mvcResourceUrlProvider));
	return welcomePageHandlerMapping;
}

private Optional<Resource> getWelcomePage() {
	String[] locations = getResourceLocations(this.resourceProperties.getStaticLocations());
	return Arrays.stream(locations).map(this::getIndexHtml).filter(this::isReadable).findFirst();
}

private Resource getIndexHtml(String location) {
	return this.resourceLoader.getResource(location + "index.html");
}
  • 在静态资源中添加index.html,为默认首页

3.3 文件上传

java中文件上传一般涉及两个组件:

  1. CommonsMultipartResolver:使用commons-fileupload工具包。
    文件上传的原理是IO流实现的,通过二进制流的方式向服务器传输数据,服务器再通过流读取到数据,然后解析成文件,最终保存到服务器上。
    commons-fileupload工具包里面封装了对流操作的过程,简化了实现文件上传的代码复杂度。
    参考:commons-fileupload实现文件上传
  2. StandardServletMultipartResolver

3.3.1 单文件上传

1. 在resources 目录下的static 目录中创建一个upload.html 文件,作为上传文件界面
  • 上传接口是**/upload**,请求方法是postenctypemultipart/form-data,意思是以二进制数据流的方式传输
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <form action="/upload" method="post" enctype="multipart/form-data">
        <input type="file" name="uploadFile" value="请选择文件">
        <input type="submit" value="上传">
    </form>
</body>
</html>

在这里插入图片描述

2. 创建文件上传处理接口
package com.cewell.controller;

import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletRequest;
import java.io.File;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.UUID;

/**
 * ClassName:FileUploadController
 * Package:com.cewell.controller
 * Description:文件上传
 *
 * @date:2019/11/26 18:24
 * @author:skx@cewell.com
 */
@RestController
public class FileUploadController {
    SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/dd/");

    @PostMapping("/upload")
    public String upload(MultipartFile uploadFile, HttpServletRequest req){

        //第27代码表示规划上传文件的保存路径为项目运行目录下的uploadFile 文件夹,并在文件夹中通过日期对所上传的文件归类保存。
        String realPath = req.getSession().getServletContext().getRealPath("/uploadFile/");
        String format = sdf.format(new Date());
        File folder = new File(realPath + format);
        //如果目录不存在,创建
        if (!folder.isDirectory()) {
            folder.mkdirs();
        }

        //给上传的文件重命名
        String oldName = uploadFile.getOriginalFilename();  //得到上传时的文件名
        //UUID.randomUUID().toString()  是JDK提供的一个自动生成主键的方法
        //* 截取字符串substring()方法的用法
        //  1.substring(int beginIndex);    截取开始索引beginIndex到结束
        //      "mybaby".substring(3)   returns"aby"
        //  2.substring(int beginIndex, int endIndex);    截取开始索引beginIndex到结束索引endIndex-1
        //      "hamburger".substring(3,8)  returns "burge"
        String newName = UUID.randomUUID().toString() + oldName.substring(oldName.lastIndexOf("."),oldName.length());
        //UUID + 截取的文件后缀名

        try {
            //文件保存                      地址,重命名的名字
            uploadFile.transferTo(new File(folder,newName));
            //生成上传文件的访问路径,并将访问路径返回。
            String filePath =
                    req.getScheme() + "://"                     //协议
                    + req.getServerName() + ":"                 //ip
                    + req.getServerPort() + "/uploadFile/"      //端口
                    + format + newName;
            return filePath;
        } catch (IOException e) {
            e.printStackTrace();
        }
        return "上传失败";
    }
}

  • 执行完成后,返回上传文件的访问路径
    在这里插入图片描述
  • 由访问路径访问文件内容
    在这里插入图片描述
3.还可以对上传细节进行配置
spring.servlet.multipart.enabled=true
spring.servlet.multipart.file-size-threshold=0
spring.servlet.multipart.location=E:\\temp
spring.servlet.multipart.max-file-size=1MB
spring.servlet.multipart.max-request-size=10MB
spring.servlet.multipart.resolve-lazily=false
  • 第1 行表示是否开启文件上传支持,默认为true。
  • 第2 行表示文件写入磁盘的闽值,默认为0 。
  • 第3 行表示上传文件的临时保存位直。
  • 第4 行表示上传的羊个文件的最大大小,默认为1MB
  • 第5 行表示多文件上传时文件的总大小,默认为10MB
  • 第6 行表示文件是否延迟解析,默认为false 。

3.3.2 多文件上传

1. 在resources 目录下的static 目录中创建一个uploadMultiple.html 文件,作为上传文件界面(比单个的时候input标签中加一个multiple)
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <form action="/uploadMultiple" method="post" enctype="multipart/form-data">
        <input type="file" name="uploadFiles" value="请选择文件" multiple/>
        <input type="submit" value="上传"/>
    </form>
</body>
</html>

在这里插入图片描述

2. 创建文件上传处理接口
  • 传参改成数组MultipartFile[] uploadFiles
@PostMapping("/uploadMultiple")
public List<String> uploadMultiple(MultipartFile[] uploadFiles, HttpServletRequest req) {

    //定义一个list用来存放三张图片上传之后的链接
    List<String> filePathList = new ArrayList<String>();

    for (int i = 0; i < uploadFiles.length; i++) {

        //第27代码表示规划上传文件的保存路径为项目运行目录下的uploadFile 文件夹,并在文件夹中通过日期对所上传的文件归类保存。
        String realPath = req.getSession().getServletContext().getRealPath("/uploadFile/");
        String format = sdf.format(new Date());
        File folder = new File(realPath + format);
        //如果目录不存在,创建
        if (!folder.isDirectory()) {
            folder.mkdirs();
        }

        //给上传的文件重命名
        String oldName = uploadFiles[i].getOriginalFilename();  //得到上传时的文件名
        //UUID.randomUUID().toString()  是JDK提供的一个自动生成主键的方法
        //* 截取字符串substring()方法的用法
        //  1.substring(int beginIndex);    截取开始索引beginIndex到结束
        //      "mybaby".substring(3)   returns"aby"
        //  2.substring(int beginIndex, int endIndex);    截取开始索引beginIndex到结束索引endIndex-1
        //      "hamburger".substring(3,8)  returns "burge"
        String newName = UUID.randomUUID().toString() + oldName.substring(oldName.lastIndexOf("."), oldName.length());
        //UUID + 截取的文件后缀名


        try {
            //文件保存                      地址,重命名的名字
            uploadFiles[i].transferTo(new File(folder, newName));
            //生成上传文件的访问路径,并将访问路径返回。
            String filePath =
                    req.getScheme() + "://"                     //协议
                            + req.getServerName() + ":"                 //ip
                            + req.getServerPort() + "/uploadFile/"      //端口
                            + format + newName;
            filePathList.add(filePath);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    //return "上传失败";
    return filePathList;
}
  • 返回一个访问路径的list
    在这里插入图片描述
  • 然后可以由访问路径访问文件内容

3.4 @ControllerAdvice全局处理数据

3.4.1 全局异常处理

  • 如:3.3中上传文件过大会抛出MaxUploadSizeExceededException异常
  • 在系统中定义CustomExceptionHandler 类,然后添加
    @ControllerAdvice注解,系统启动时,该类被扫描到spring容器中。
  • 如果MaxUploadSizeExceededException改为Exception,表明该方法用来处理所有类型的异常
@ControllerAdvice
public class CustomExceptionHandler {

    @ExceptionHandler(MaxUploadSizeExceededException.class)
    public void uploadException(MaxUploadSizeExceededException e, HttpServletResponse resp) throws IOException {
        resp.setContentType("text/html;charset=utf-8");
        PrintWriter out = resp.getWriter(); //取一个响应客户端的流对象,用来在客户端输出
        out.write("上传文件大小超出限制"); //通过PrintWrite,以流方式输出,返回给浏览器
        out.flush();    //清空缓冲区的数据流
        out.close();    //关闭读写流
        //flush()这个函数是清空的意思,用于清空缓冲区的数据流,进行流的操作时,数据先被读到内存中,然后再用数据写到文件中,
        // 那么当你数据读完时,我们如果这时调用close()方法关闭读写流,这时就可能造成数据丢失,为什么呢,因为,读入数据完成时不代表写入数据完成,
        // 一部分数据可能会留在缓存区中,为了理解这个问题,我们举一个例子:
        //
        //比如,在农村,几乎每家都有抽水机,抽水机的作用是什么呢,就是把水井里的水抽到水缸中,这时我们就会用水管连接抽水机和水缸(水管就好比是缓冲区),
        // 当我们想把水井中的水都抽到水缸中时,我们就让抽水机工作抽水,如果我们发现水井里的水刚好抽完时,我们就会关掉抽水机的开关停止抽水,那么这时,
        // 管道里就会遗留一部分水,抽水就是读数据,水缸进水就是写数据,水管充当缓存区的角色,不知道这样是不是具象化了呢
        //
        //那么这样一来我们如果中途调用close()方法,输出区也还是有数据的,就像水缸里有水,只是在缓冲区遗留了一部分,这时如果我们先调用flush()方法,
        // 就会强制把数据输出,缓存区就清空了,最后再关闭读写流调用close()就完成了。
    }
}

在这里插入图片描述

3.4.2 添加全局数据

  • @ModelAttribute中的value属性(“info”)表示这条返回数据的key,而方法的返回值是返回数据的value
@ControllerAdvice
public class GlobalConfig {

    //注解@ModelAttribute中的value属性表示这条返回数据的key,而方法的返回值是返回数据的value
    @ModelAttribute(value = "info")
    public Map<String,String> userInfo(){
        HashMap<String,String> map = new HashMap<>();
        map.put("writer","罗贯中");
        map.put("bookName","三国演义");
        return map;
    }
}
  • 此时在任意请求的Controller 中,通过方法参数中的Model 都可以获取info 的数据。
@RestController
public class HelloController {
    @GetMapping("/helloBook")
    public String helloBook(Model model){
        Map<String,Object> map = model.asMap();
        return map.toString();  //{info={writer=罗贯中, bookName=三国演义}}
    }
}

3.4.3 请求参数预处理


3. SpringBoot 整合持久层

3.1 整合Mybatis

3.1.1 pom.xml添加相关依赖

  • 添加MyBatis依赖、数据库驱动依赖以及数据库连接池依赖
<dependency>
    <groupId>org.mybatis.spring.boot</groupId>
    <artifactId>mybatis-spring-boot-starter</artifactId>
    <version>1.3.2</version>
</dependency>
<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>druid</artifactId>
    <version>1.1.9</version>
</dependency>
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <scope>runtime</scope>
</dependency>

3.1.2 创建数据库和表

在这里插入图片描述

3.1.3 创建数据库配置

  • application.yml中配置数据库基本连接信息
#   数据库配置
spring:
  datasource:
    type: com.alibaba.druid.pool.DruidDataSource
    url: jdbc:mysql://localhost:3306/exercise?serverTimezone=GMT%2B8&useUnicode=true&characterEncoding=utf-8
    username: root
    password: root123

3.1.4 创建bean、controller、service、mapper、mapper.xml

//bean
public class Masterpiece {
    private Integer id;
    private String name;
    private String author;

    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 String getAuthor() {
        return author;
    }

    public void setAuthor(String author) {
        this.author = author;
    }
}
<?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="com.cewell.dao.MasterpieceMapper">
    <resultMap id="BaseResultMap" type="com.cewell.bean.Masterpiece">
        <id column="id" jdbcType="INTEGER" property="id"/>
        <result column="name" jdbcType="VARCHAR" property="name"/>
        <result column="author" jdbcType="VARCHAR" property="author"/>
    </resultMap>
    <select id="getMasterpiece" resultMap="BaseResultMap">
    	select * from masterpiece
    </select>
</mapper>

3.1.5 在pom.xml中配置扫描 java 目录下的xml文件

  • Maven工程中,XML 配置文件建议写在resources目录下
    Mapper.xml文件写在java包下,Maven在运行时会忽略包下的XML文件,因此需要在pom.xml文件中重新指明资源文件位置
<resources>   
	<resource>
	  <directory>src/main/java</directory>
	  <includes>
	      <include>**/*.xml</include>
	      <!--<include>**/*.properties</include>
	      <include>**/*.dic</include>
	      <include>**/*.xsd</include>-->
	  </includes>
	</resource>
	<resource>
	  <directory>src/main/resources</directory>
	  <!--<includes>
	      <include>**/*.xml</include>
	      <include>**/*.yml</include>
	      <include>**/*.ftl</include>
	  </includes>-->
	</resource>
</resources>

3.1.6 controller运行结果

在这里插入图片描述

3.2 MyBatis多数据源(暂缺)


4. SpringBoot 整合NoSQL

4.1 整合Redis

4.1.1 redis基础

1.
  • redis可以看作一个独立的hashMap,不是在JVM中运行,而是以一个独立进程的形式运行
2. Key-Value数据库
3.
  • 当作缓存使用。 因为它比数据库(mysql)快,所以常用的数据,可以考虑放在这里,这样就提高了性能
4.
redis-server.exeredis-cli.exe
服务端客户端
启动redis程序进入redis的命令界面
必须启动用jedis之类的操作redis的话就无须启动
5.
有5种数据类型	: 
  • String(字符串)
  • List(列表)
  • Hash(字典)
  • Set(集合)
  • Sorted Set(有序集合)
6. jedis:
  • 除了使用各种Redis自带客户端的命令行–方式访问Redis服务。 在实际工作中更多用Java代码访问,使用第三方jarJedis就能方便地访问Redis的各种服务了。
	import redis.clients.jedis.Jedis;
7. JedisJedisPool 连接池
	1>.Jedis直连	
		生成Jedis对象
		Jedis执行命令
		返回执行结果
		关闭Jedis连接
			Jedis jedis = new Jedis("127.0.0.1","6379");
			jedis.set("hello","world");
			String value = jedis.get("hello");
	2>.使用Jedis连接池	
			从资源池借Jedis对象
			Jedis执行命令
			返回执行结果
			归还Jedis对象给连接池
				GenericObjectPoolConfig poolConfig = new GenericObjectPoolConfig();
				JedisPool jedisPool = new JedisPool(poolConfig ,"12.0.0.1",6379);
				Jedis jedis = null ;
				try{
				   jedis = jedisPool.getResource();
				}catch(Exception e ){
				   e.printStackTrace;
				}finally{

				}
8.RedisJedisSpringDataRedisRedisTemplate关系
	(1)Redis、Jedis、SpringDataRedis及RedisTemplate关系
		1>.Redis是一个基于内存的Key-Value数据库
		2>.Jedis是Redis官方推出的面向Java的客户端Client,提供了很多接口和方法,可以让Java操作使用Redis
		3>.SDR是Spring框架集成Redis操作的一个子框架,封装了Redis的很多命令;比Jedis多了自动管理连接池的特性
		4>.RedisTemplate是SpringDataRedis中对JedisApi的高度封装

	(2)jedis : 操作redis是很简单的,通过new的方式,获取jedis对象,然后增删改查(set,get,del,exists)等,简单来说就是代码的方式来实现操作的;

	   RedisTemplate : 也可以做到操作redis缓存, 使用spring注入方式的配置

	   一个比较原生,一个经过spring托管控制;RedisTemplate只做缓存,没有队列,相对jedis功能更少;
	   单线程使用RedisTemplate缓存即可,如果有多线程,需要使用jedis

4.1.2 SpringBoot整合redis

1. pom.xml 添加相关依赖
<!--添加redis依赖-->
<dependency>
     <groupId>org.springframework.boot</groupId>
     <artifactId>spring-boot-starter-data-redis</artifactId>
     <!--从spring-boot-starter-data-redis中排除Lettuce并引入Jedis-->
     <exclusions>
         <exclusion>
             <groupId>io.lettuce</groupId>
             <artifactId>lettuce-core</artifactId>
         </exclusion>
     </exclusions>
 </dependency>
<!--引入Jedis-->
 <dependency>
     <groupId>redis.clients</groupId>
     <artifactId>jedis</artifactId>
 </dependency>
2. 创建redis配置(application.yml 中)
spring:
# 配置Redis
  redis:
    # 基本连接信息
    database: 0 #数据库索引,共16个,编号1-15
    host: 127.0.0.1
    port: 6379
    password:
    # 连接池信息
    jedis:
      pool:
        #最大连接数
        max-active: 8
        #最大空闲连接数
        max-idle: 8
        #最大阻塞等待时间(负数表示没限制)
        max-wait: -1ms
        #最小空闲
        min-idle: 0
3. 创建实体类bean
//一个类只有实现了Serializable接口,它的对象才是可序列化的
//Serializable是一个空接口,没有什么具体内容,它的目的只是简单的标识一个类的对象可以被序列化。
public class Masterpiece implements Serializable {
    private Integer id;
    private String name;
    private String author;

    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 String getAuthor() {
        return author;
    }

    public void setAuthor(String author) {
        this.author = author;
    }

    @Override
    public String toString() {
        return "name: " + this.name + " " + "author: " + this.author;
    }
}
4. 创建controller
@RestController
@RequestMapping("api")

    @GetMapping("/getMasterpieceRedis")
    public void getRedis(){
        //向redis中存一条记录,再将其读取
        ValueOperations<String,String> opsl = stringRedisTemplate.opsForValue();    //获取一个键值操作器
        opsl.set("name","三国演义");
        String name = opsl.get("name");
        System.out.println(name);

        //向redis中存一个对象,再将其读取
        ValueOperations opsl2 = redisTemplate.opsForValue();
        Masterpiece m = new Masterpiece();
        m.setId(1);
        m.setAuthor("罗贯中");
        m.setName("三国演义");
        opsl2.set("m",m);
        Masterpiece masterpiece = (Masterpiece) opsl2.get("m");
        System.out.println(masterpiece.toString());
    }
}
5. 访问后结果

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

4.1.3 SpringBoot整合redis集群(暂缺)

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值