(四)Spring Boot Web 开发【返回Json数据、静态资源访问、文件上传】

一、返回 JSON 数据

1.1 默认实现

       JSON 是目前主流的前后端数据传输方式, Spring MVC 中使用消息转换器 HttpMessageConverter 对 JSON 的转换提供了很好的支持,在 Spring Boot 更进 ,对相关配置做了更进一步的简化。默认情况下,当开发者新创建一个 Spring Boot 项目后,添加 Web 依赖,代码如下:

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

这个依赖中默认加入了 jackson-databind 作为 JSON 处理器,此时不需要添加额外的 JSON 理器就能返回一段 JSON 了。 新建一个 Person 实体类

public class Person {
    private String name;
    private Integer age;
    @JsonFormat(pattern ="yyyy-MM-dd")
    private Date birthday ;
    //省略get/set方法
}

然后 PersonController 返回 Person 对象即可:

@GetMapping("/person")
public Person person() {
    Person person = new Person();
    person.setName("zhang san");
    person.setAge(24);
    person.setBirthday(new Date());
    return person;
}

此时,在浏览器中输入 http://localhost:8080/person, 即可看到返回了 JSON 数据。

       这是 Spring Booot 自带的处理方式。如果采用这种方式,那么对于字段忽略、日期格式化等常需求都可以通过注解来解决。这是通过 Spring 中默认提供的 MappingJackson2HttpMessageConert 来实现的,当然开发者在这里也可以根据实际需求自定义 JSON 转换器。

2.1 自定义转换器

常见的 JSON 处理器除了 jackson-databind 外, 还有 Gson 和 fastjson。

2.1.1 使用 Gson

Gson 是 Google 的一个开源 JSON 解析框架。使用 Gson,需要先除去默认的 jackson-databind,然后加入 Gson 依赖,代码如下:

 <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.google.code.gson</groupId>
    <artifactId>gson</artifactId>
</dependency>

由于 Spring Boot 中默认提供了 Gson 自动转换类 GsonHttpMessageConvertersConfiguration,因此 Gson 的依赖添加成功后 可以像使用 jackson-databind 那样直接使用 Gson 。但是在 Gson 进行转换时,如果想对日期数据进行格式化, 那么还需要开发者自定义 HttpMessageConverter。自定义 HttpMessageConverter 可以通过如下方式。

import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.converter.json.GsonHttpMessageConverter;

import java.lang.reflect.Modifier;

@Configuration
public class GsonConfig {
    @Bean
    GsonHttpMessageConverter gsonHttpMessageConverter() {
        GsonHttpMessageConverter converter = new GsonHttpMessageConverter();
        GsonBuilder builder = new GsonBuilder();
        builder.setDateFormat("yyyy-MM-dd");
        builder.excludeFieldsWithModifiers(Modifier.PROTECTED);
        Gson gson = builder.create();
        converter.setGson(gson);
        return converter;
    }
}

代码解释:

  • 开发者自己提供一个 GsonHttpMessageConverter 的实例
  • 设置 Gson 解析时日期的格式
  • 设置 Gson 解析时修饰符 protected 的字段被过滤掉
  • 创建 Gson 对象放入 GsonHttpMessageConverter 实例中并返回 converter

此时,将 Person 类中的 birthday 字段的修饰符改为 protected 代码如下

public class Person {
    private String name;
    private Integer age;
    @JsonFormat(pattern ="yyyy-MM-dd")
    protected Date birthday ;
    //省略get/set方法
}

此时,在浏览器中输入 http://localhost:8080/person, 即可看到返回中的 JSON 数据,其中 birthday 字段被过滤掉了。

2.1.1 使用 fastjson

       fastjson 是阿里巴巴的一个开源 JSON 框架,是目前 JSO 解析速度最快的开源框架,该框架也可以集成到 Spring Boot 中。不同于 Gson,fastjson 承完成之后并不能立马使用, 需要开发者提供相应的 HttpMessageConverter 后才能使用,集成 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>
    <version>1.2.47</version>
</dependency>

       (2)然后配置 fastjson HttpMessageConverter:

import com.alibaba.fastjson.serializer.SerializerFeature;
import com.alibaba.fastjson.support.config.FastJsonConfig;
import com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.nio.charset.Charset;


@Configuration
public class MyFastJsonConfig {
    @Bean
    FastJsonHttpMessageConverter fastJsonHttpMessageConverter() {
        FastJsonHttpMessageConverter converter = new FastJsonHttpMessageConverter();
        FastJsonConfig config = new FastJsonConfig();
        config.setDateFormat("yyyy-MM-dd");
        config.setCharset(Charset.forName("utf-8"));
        config.setSerializerFeatures(
                SerializerFeature.WriteClassName,
                SerializerFeature.WriteMapNullValue,
                SerializerFeature.PrettyFormat,
                SerializerFeature.WriteNullListAsEmpty,
                SerializerFeature.WriteNullStringAsEmpty);
        converter.setFastJsonConfig(config);
        return converter;
    }
}

       (3)MyFastJsonConfig 配置完成后,还需要配置一下响应编码,否则返回的 JSON 中文会乱码,在application. properties 添加如下配置:

spring.http.encoding.force-response=true

此时,在浏览器中输入 http://localhost:8080/person, 即可看到返回中的 JSON 数据
在这里插入图片描述
扩展:对于 FastJsonHttpMessageConverter 的配置,除了上面这种方式之外,还有另一种方式。在 Spring Boot 项目中,当开发者引入 spring-boot-starter-web 依赖之后,该依赖又依赖了spring-boot-autoconfigure 在这个自动化配置中,有一个 WebMvcAutoConfiguration 类提供了对 Spring MVC 最基本的配置, 如果某一项自动化配置不满足开发需求,开发者可以针对该项自定义配置,只需要实现 WebMvcConfigurer 接口即可(在 Spring 是通过继承 WebMvcConfigurerAdapter 类来实现的),代码如下:

import com.alibaba.fastjson.serializer.SerializerFeature;
import com.alibaba.fastjson.support.config.FastJsonConfig;
import com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

import java.nio.charset.Charset;
import java.util.List;

@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");
        config.setCharset(Charset.forName("utf-8"));
        config.setSerializerFeatures(
                SerializerFeature.WriteClassName,
                SerializerFeature.WriteMapNullValue,
                SerializerFeature.PrettyFormat,
                SerializerFeature.WriteNullListAsEmpty,
                SerializerFeature.WriteNullStringAsEmpty);
                converter.setFastJsonConfig(config);
        converters.add(converter);
    }
}

代码解释:

  • 自定义 MyWebMvcConfig 类并实现 WebMvcConfigurer 接口中的 configureMessageConverters方法
  • 将自定义的 FastJsonHttpMessageConverter 加入 converters

注意: 如果使用了 Gson ,也可以采用这种方式配置,但是不推荐。 因为当项目中没有 GsonHttpMessageConverter 时, Spring Boot 自己会提供一个GsonHttpMessageConverter ,此时重写 configureMessageConverters 方法,参数converters 中已经有 GsonHttpMessageConverter 的实例了,需要替换已有的 GsonHttpMessageConverter 实例,操作比较麻烦,所以对于 Gson,推荐直接提供 GsonHttpMessageConverter

二、静态资源访问

       在SpringMVC 中,对于静态资源都需要开发者手动配置静态资源过滤。Spring Boot 中对此也提供了自动化配置,可以简化静态资源过滤配置。

2.1 默认策略

       在Spring Boot 中对于 SpringMVC 自动化配置都在 WebMvcAutoConfiguration 类中 ,因此对于默认静态资源过滤策略可以从这个类中一探究竟。
       在WebMvcAutoConfiguration 类中有个静态内部类 WebMvcAutoConfigurationAdapter 实现了 WebMvcConfigurer 接口。 WeMvcConfigurer 接口中有个方法 addRsourceHandlers,
是用来配置静态资源过滤的。方法在 WebMvcAutoConfigurationAdapter 中得到了实现,部分核心代码如下:

public void addResourceHandlers(ResourceHandlerRegistry registry) {
	if (!registry.hasMappingForPattern(staticPathPattern)) {
			customizeResourceHandlerRegistration(
					registry.addResourceHandler(staticPathPattern)
							.addResourceLocations(getResourceLocations(
									this.resourceProperties.getStaticLocations()))
							.setCachePeriod(getSeconds(cachePeriod))
							.setCacheControl(cacheControl));
	}
}

Spring Boot 在这里进行了默认的静态资源过滤配置,其中 staticPathPattern 默认定义在
WebMvcProperties 中,定义内容如下:

private String staticPathPattern = “/**”;

this.resourceProperties.getStaticLocations()获取到的默认静态资源位置定义在ResourceProperties 中,代码如下:
在这里插入图片描述
从上面上可以看到, Spring Boot 默认会过滤所有的静态资源,开发者可以将静态资源放到这几个位置中的任意一处,注意:按照定义的顺序,资源位置的优先级依次降低 ,但是一般情况下,Spring Boot 项目不需要 webapp 目录。

在一个新创建的 Spring Boot 项目中, 添加了 spring-boot-starter-web 依赖之后,在 source 下分别创建4个目录放入资源文件,数字表示不同位置资源的优先级。
在这里插入图片描述
此时, 在浏览器中输入“ http://localhost:8080/1.jpg ”即可看 classpath:/META-INF/resources/ 目录下的 1.jpg,如果将 classpath:/META-INF/resources/ 目录下的 1.jpg 删除,就会访问到classpath:/resources/目录下的 1.jpg ,以此类推。

如果开发者使用 IntelliJ IDEA 创建 Spring Boot 项目, 就会默认创建出 classpath:/static/ 目录,静态资源一般放在这个目录下即可。

2.2 自定义策略

       如果默认静态资源过滤策略不能满足开发需求,也可以自定义静态资源过滤策略,自定义静态资源过滤策略有以下两种方式:

  1. 在自己置文件中定义
    可以 appIication. properties 直接定义过滤规则和静态资源位置 ,代码如下:
    spring.mvc.static-path-pattern=/static/**
    spring.resources.static-locations=classpath:/static/
    

       过滤规则为/static/**, 静态资源位置classpath:/static/
       重新启动项目,在浏览器中输入 http://localhost:8080/static/1.jpg ,即可看到 classpath:/static/目录下的资源。

  1. Java 编码定义
    也可以通过 Java 编码方式来定义,此时只需要实现 WebMvcConfigurer 接口即可, 然后实现该接口的 addResourceHandlers 方法,代码如下:
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 MyWebMvcConfig implements WebMvcConfigurer {
    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry){
        registry.addResourceHandler("/static/**")
                .addResourceLocations("classpath:/static/");
    }
}

       重新启动项目,在浏览器中输入 http://localhost:8080/static/1.jpg ,即可看到 classpath:/static/目录下的资源。

三、文件上传

        Spring MVC 对文件上传做了简化,在Spring Boot 中对此做了进一步简化, 文件上传更为方便。
        Java 中的文件上传共涉及两个组件,CommonsMultipartResolverStandardServletMultipartResolver,其中CommonsMultipartResolver 使用 commons-fileupload 来处理 multipart 请求,而StandardServletMultipartResolver 是基于 Servlet 3.0 来处理 multipart 请求的,若使用 StandardServletMultipartResolver ,则不需要添加额外的 jar 包。 Tomcat 7.0 开始就支持Servlet 3.0 了,而 Spring Boot 2.0.4 内嵌的 Tomcat 为 Tomcat 8.5.32 ,因此可以直接使用StandardServletMultipartResolver。而在 Spring Boot 提供的文件上传自动化配置类 MultipartAutoConfiguration 中,默认也是采用 StandardServletMultipartResolver ,部分源码如下:
在这里插入图片描述
根据这里的配置可以看出,如果开发者没有提供 MultipartResolver ,那么默认采用的MultipartResolver 就是 StandardServletMultipartResolver。因此,在 Spring Boot 中上传文件甚至可以做到零配置。下面来看具体上传过程。

3.1 单文件上传

在 resource 录下的 static 目录中创建一个 upload.html 文件,内容如下:

<!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>
  • 这是一个很简单的文件上传页面,上传接口是/upload注意请求方法是 post , enctype是multipart/form-data
  • 接着创建文件上传处理接口,代码如下:
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;


@RestController
public class FileUploadController {
    @PostMapping("/upload")
    public String upload(MultipartFile uploadFile, HttpServletRequest req) {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        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();
        String newName = UUID.randomUUID().toString() +
                oldName.substring(oldName.lastIndexOf("."), oldName.length());
        try {
            //文件保存操作
            uploadFile.transferTo(new File(folder, newName));
            //生成上传文件的访问路径, 并将访问路径返回
            String filePath = req.getScheme() + "://" + req.getServerName() + ":" + req.getServerPort()
                    + "/uploadFile/" + format + newName;
            return filePath;
        } catch (IOException e) {
            e.printStackTrace();
        }
        return "文件上传失败";
    }
}

最后在浏览器中进行测试。运行项目,在浏览器中输入 进行文件上传,如图所示。
在这里插入图片描述
单击“选择文件”按钮上传文件,文件上传成功后会返回上传文件的访问路径,如图所示。
在这里插入图片描述
当然,如果开发者需要对文件上传的细节进行配 ,也是允许的,代码如下:

# 是否开启文件上传支持,默认为 true
spring.servlet.multipart.enabled=true
# 文件写入磁盘的阈值,默认为 0
spring.servlet.multipart.file-size-threshold=0
# 上传文件的临时保存位置
spring.servlet.multipart.location=E:\\temp
# 上传的单个文件的最大大小,默认为 1MB
spring.servlet.multipart.max-file-size=1MB
# 多文件上传时文件的总大小,默认为 10MB
spring.servlet.multipart.max-request-size=10MB
# 文件是否延迟解析,默认为 false
spring.servlet.multipart.resolve-lazily=false

3.2 多文件上传

多文件上传和单文件上传基本一致,首先修改 HTML 文件,代码如下:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<form action="/uploadBatch" method="post" enctype="multipart/form-data">
    <input type="file" name="uploadFiles" value="请选择文件" multiple>
    <input type="submit" value="上传">
</form>
</body>
</html>

然后修改控制器,代码如下:

@PostMapping("/uploadBatch")
public String uploadBatch(@RequestPart("uploadFile") MultipartFile[] uploadFiles, HttpServletRequest req) {
	//遍历 uploadFiles 数组分别存储
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值