Name:项目名称
Location:本地存放目录
Language:编程语言肯定选择java
Type:管理工具选择Maven
Group:包的目录结构,一般形式是com.xxx,我写的是moodNotepad
Artifact:我写的项目名称moodNotepad
Package name:Group+Artifact
Project SDK:jdk版本选择1.8
Java:语言等级选择版,要与jdk版本相对应
Packaging:部署项目的形式,我选的jar
创建好的目录结构如下,删除了一些无关紧要的东西。把application.properties的后缀修改为application.yml,只是修改了文件类型而已,并不影响文件功能。
src/main路径下有两个目录,一个是java用来存放源代码,另一个是resources用来存放一些重要资源。
application.yml是项目的配置文件。
pom.xml是项目的依赖管理文件。
MoodNotepadApplication是项目的启动类,运行它就可以启动项目。
application.properties语法:
# 数据库配置信息
driver=com.mysql.jdbc.Driver
jdbcUrl=jdbc:mysql://localhost:3306/user
user=root
password=123456
application.yml语法:
# 数据库配置信息(键值对中间有一个空格)
driver: com.mysql.jdbc.Driver
jdbcUrl: jdbc:mysql://localhost:3306/user
user: root
password: 123456
person:
name: xiaoming
age: 20
friends:
# List结构
- xiaowang
- xiaohong
dog:
# Map结构
name: xiaogou
age: 2
person:
name: xiaoming
age: 20
friends: [xiaoming, xiaohong]
dog: { name: xiaogou, age: 2 }
//在变量声明上方写这一行注解
@Value("${course.id}")
private int id;
//在类的定义上方写这一行的注解,就可以以对象的形式把所有属性值注入进来
@ConfigurationProperties(prefix = "user")
除了将配置写在application.yml或application.properties文件中,还可以在resources路径下创建自定义的配置文件。
注意:为了使自定义配置生效,应该将application.yml或application.properties文件中的user相关配置删除。
user.id=1
user.userName=tracy
user.age=2
user.gender=male
package tracy.moodnotepad;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.PropertySource;
import org.springframework.stereotype.Component;
@Component
@ConfigurationProperties(prefix = "user")
@PropertySource(value= "classpath:user.properties")
public class User {
Integer id;
String userName;
String gender;
Integer age;
public void setId(Integer id) {
this.id = id;
}
public void setGender(String gender) {
this.gender = gender;
}
public void setAge(Integer age) {
this.age = age;
}
public Integer getId() {
return id;
}
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public String getGender() {
return gender;
}
public Integer getAge() {
return age;
}
@Override
public String toString() {
return "User{" +
"id=" + id +
", name='" + userName + '\'' +
", gender='" + gender + '\'' +
", age=" + age +
'}';
}
}
package tracy.moodnotepad.controller;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import tracy.moodnotepad.User;
@RestController
public class UserController {
@Autowired
private User user;
@RequestMapping(value="/user")
public String getUser(){
return user.toString();
}
}
@RestController :集合了 @Controller 注解和 @RequestBody 注解。表示该注解标识的类为一个控制器,且该类的所有方法的返回值都转换为 JSON 格式,同时将返回值写入到 Response 对象的 body 中。
@RequestMapping(“/user”) :“/user” 路径的 HTTP 请求都将映射到该方法进行处理。
默认端口是8080
浏览器地址栏输入localhost:8080/user回车,页面上就出现了自定义配置文件中的属性值。
注意:我尝试了一下,项目配置文件application.properties可以更改为yml格式,仍然能生效;但是自定义的配置文件只能是properties格式的,暂时不知道原因。
(1)基于properties配置文件
在resources目录下,创建以下三个配置文件,分别对应三种不同的环境配置。
user.id=1
user.userName=dev-tracy
user.age=2
user.gender=male
user.id=1
user.userName=test-tracy
user.age=2
user.gender=male
user.id=1
user.userName=prod-tracy
user.age=2
user.gender=male
# 激活开发环境,使用开发环境设置
spring:
profiles:
active: dev
然后运行项目:
(2)基于yml配置文件
基于yml的多环境配置比较简单,首先删除三个properties文件,然后将多环境配置内容全部写在默认的application.yml中:
# 激活开发环境,使用开发环境设置
spring:
profiles:
active: test
---
# 开发环境
user:
id: 1
userName: dev-tracy
age: 2
gender: male
spring:
config:
activate:
on-profile: dev
---
# 测试环境
user:
id: 1
userName: test-tracy
age: 2
gender: male
spring:
config:
activate:
on-profile: test
---
# 生产环境
user:
id: 1
userName: prod-tracy
age: 2
gender: male
spring:
config:
activate:
on-profile: prod
这样就可以了。可以自行运行下项目试一下效果。
(3)打包后切换环境
前面展示的都是在打包前进行多环境配置,但实际上,如果项目已经打包了,就很难再去修改配置文件了。因此,有必要学习下项目打包之后的多环境切换。
在IDEA中的terminal终端中执行命令mvn package命令,等待打包完成。
打包好的jar在target目录下,运行jar包:
java -jar target/moodNotepad-0.0.1-SNAPSHOT.jar
默认环境为test:
java -jar target/moodNotepad-0.0.1-SNAPSHOT.jar --spring.profiles.active=dev
当在 Spring Boot 中引入 Web 模块时,会自动配置 Web 相关的组件,其中 Spring MVC 便是最重要的部分。
下面分析一下spring mvc的原理。
首先,有必要了解一下Servlet是什么。关于java Servlet,这位大佬写的非常详细,请看他的博客:这里
在使用Servlet的过程中,我们需要手动安排好Servlet和URI之间的对应关系,这个过程并不高效。因此,就有了Spring MVC这样的框架,用来简化web开发工作。在了解Spring MVC框架前,我们先通过一张图片来看看什么是MVC。
组件介绍:
1. DispatcherServlet前端控制器:整个流程的控制中心,由它调用其他组件处理用户请求。
2. HandlerMapping处理器映射器:根据用户请求的 URL 找到相应的 Handler 处理器。
3. HandlerAdapter处理器适配器:根据HandlerMapping找到的 Handler的相关信息,依据特定的规则去执行相关的处理器 Handler。
4. Handler处理器:负责执行用户的请求,Controller便是处理器。
5. ModelAndView : 使用 ModelAndView类用来存储处理完后的结果数据,以及显示该数据的视图。
6. ViewResolver视图解析器:首先根据逻辑视图名解析成物理视图名即具体的页面地址,再生成 View 视图对象,最后对 View 进行渲染将处理结果通过页面展示给用户。
其中,需要开发者开发的是Handler和视图。
Spring MVC 工作流程:
1. 用户向服务器发送请求至前端控制器 DispatcherServlet。
2. DispathcherServlet 调用HandlerMapping,由此得知由哪个 Handler (Controller)来处理该请求。
3. HandlerMapping找到具体的处理器,生成处理器对象及处理器拦截器一并返回给 DispathcherServlet。
4. DispathcherServlet调用 HandlerAdapter 。
5. HandlerAdapter 经过适配调用具体的Handler,也叫做控制器(Controller)。
6. Handler 处理完请求后返回 ModelAndView 。
7. HandlerAdapter 将后端处理器的结果 ModelAndView 反馈给 DispathcherServlet。
8. DispathcherServlet 将 ModelAndView 传给 视图解析器 ViewResolver 。
9. ViewResolver 根据 ModelAndView 中的视图名称返回具体的 View 。
10. DispathcherServlet 将 ModelAndView 中的模型数据填充到视图中,渲染视图。
11. DispathcherServlet 将结果响应给用户。
通用的组件,用来标识任意类为 Spring 组件,该组件会被扫描到 IOC 容器中。当组件不好归类的时候,可以使用这个组件进行标注。
对应 Spring MVC 控制层,主要用户接受用户请求并调用 Service 层返回数据给前端页面。
对应服务层,主要涉及一些复杂的逻辑,需要用到 Dao 层。
对应持久层即 Dao 层,主要用于数据库相关操作。
用在类或者方法上,将URL与该类、该方法映射起来。
属性:
path:用来指定请求的 URL ,value 是它的别名。
method:用来指定请求的方式。值为 GET、POST、PUT、DELETE 等。
params :用于指定限制请求参数的条件。
headers:用于指定限制请求消息头的条件。
在 Spring Boot 中,针对不同的请求方式,都提供了具体的注解:
用在方法上。如果返回值是字符串,那么直接将字符串返回给前端。如果返回值是一个对象,会将对象转换为 JSON 串,然后返回给前端。
用在类上。
是 @Controller 和 @ResponseBody 的结合体。当被 @RestController 注解修饰时,表示该类是一个控制器类,且方法的返回值会写入到 Response 的 body 中。
@PathVariable 的作用为获取路径变量。
@RequestParam 的作用为获取请求参数,也能获取 HTTP 请求体中Content-Type 为 application/x-www-form-urlencoded 编码的内容格式,类似于 id=1&name=ha&age=1 这种格式的数据。
@RequestMapping("/user/addUser/{id}")
public void addUser(@PathVariable("id") int id, @RequestParam("name") String name){
...
}
接收的参数来自于 HTTP 报文的 Request Body 中,即请求体。一般用于处理非 Content-Type: application/x-www-form-urlencoded编码格式的数据,比如:application/json、application/xml 即 JSON、XML 等类型的数据。
@RequestBody和@RequestParam的区别:这里
在使用spring boot的时候,其实它已经对spring mvc进行了自动配置,但有时候也需要自定义spring mvc的配置来满足开发需求。
自定义 Spring MVC 配置有两种方式: 一种是在自动配置的基础上,进一步扩展 Spring MVC 配置;另外一种是使原有的 Spring MVC 自动配置失效,重写 Spring MVC 配置。
扩展Spring MVC配置需要定义一个配置类,并实现WebMvcConfigurer接口;重写Spring MVC配置通过定义一个继承 WebMvcConfigurationSupport 类的配置类来实现,或者在一个配置类上使用 @EnableWebMvc 注解。
在正式学习本章内容前,请先确保pom.xml中已经添加了web的依赖:
org.springframework.boot
spring-boot-starter-web
需求
下面就进入需求的实现部分。
类上添加注解@Configuration,表明这是一个配置类。
实现接口中的方法addResourceHandlers。
package tracy.moodnotepad.config;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration
public class ExtendMvcConfig implements WebMvcConfigurer {
/**
* 添加资源映射器
* @param registry
*/
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/upload/**")
.addResourceLocations("classpath:/upload/");
}
}
静态资源映射成功。
Index
this is index page
/**
* 添加视图控制器
* @param registry
*/
@Override
public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("/index").setViewName("index.html");
}
配置成功。
package tracy.moodnotepad.util;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class TestInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("前置处理完成");
return true;
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
System.out.println("后置处理完成");
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
System.out.println("最终完成");
}
}
/**
* 添加拦截器
* @param registry
*/
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new TestInterceptor()).addPathPatterns("/test");
}
配置成功。
在resources/static下创建fileupload.html文件:
Title
Spring Boot 文件上传
在com.moodnotepad.controller包下创建UploadController类:
package tracy.moodnotepad.controller;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
@RestController
public class UploadController {
//配置的文件存储绝对路径
@Value("${file.upload.path}")
String fileSavePath;
//实现的文件上传方法
@PostMapping("/upload")
public String uploadFile(@RequestParam("file") MultipartFile file){
if(file.isEmpty())return "上传失败";
String fileName = System.currentTimeMillis()+file.getOriginalFilename();//生成文件名
String filePath = fileSavePath+ File.separator+fileName;//生成绝对路径
try{
byte[] bytes = file.getBytes();
Path path= Paths.get(filePath);
Files.write(path,bytes);
}catch (IOException e){
e.printStackTrace();
}
return "文件保存路径:"+filePath;
}
}
将application.yml清空,然后添加如下配置。
注意,path的绝对路径配置一定要写正确,windows和linux操作系统的绝对路径写法是不一样的。
# -----文件上传相关配置-----
# 自定义文件上传路径
file:
upload:
path: C:\Users\14095\Desktop
# 最大支持文件大小,默认1M
spring:
http:
multipart:
maxFileSize: 10Mb
最后,启动项目,然后在浏览器中访问http://localhost:8080/fileUpload.html:
上传文件后,配置的绝对路径下出现了上传的文件,表明功能实现成功:
spring boot默认的异常处理页面是这样的:
接下来,我们来学习如何进行异常页面的配置。
在pom.xml中添加模板引擎的依赖,用来动态渲染html页面:
org.springframework.boot
spring-boot-starter-thymeleaf
然后更新maven:
在resources目录下创建模板文件目录templates,然后在templates下创建error文件夹,再在error下创建4xx.html。我们使用thymeleaf 模板引擎来设置动态的异常页面。
4xx
4xx
path
error
message
timestamp
status
4xx.html页面上获取的几个属性值均来自于 DefaultErrorAttributes 类对异常属性的封装。感兴趣的可以自行查看源码进行学习。
运行项目后在浏览器中访问一个不存在的链接:http://localhost:8080/t
一种简单好用的实现方法是:继承 DefaultErrorAttributes 类,重写 getErrorAttributes 方法。
package tracy.moodnotepad.util;
import org.springframework.boot.web.error.ErrorAttributeOptions;
import org.springframework.boot.web.servlet.error.DefaultErrorAttributes;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.WebRequest;
import java.util.Map;
@Component
public class ExtendError extends DefaultErrorAttributes {
@Override
public Map<String, Object> getErrorAttributes(WebRequest webRequest, ErrorAttributeOptions options) {
// 调用父类的方法获取包装好的异常数据
Map<String, Object> attributes = super.getErrorAttributes(webRequest, options);
if (attributes.get("status").equals(404)) {
// 添加自定义异常数据
attributes.put("author", "tracy");
}
return attributes;
}
}
4xx
4xx
path
error
message
timestamp
status
author
运行项目后在浏览器中访问一个不存在的链接:http://localhost:8080/t
成功!