第五章 SpringBoot实现Web的常用功能
学习目标
-
掌握SpringBoot中MVC功能的定制和扩展
-
掌握SpringBoot整合Servlet三大组件的实现
-
掌握SpringBoot文件上传与下载的实现
通常再Web开发中,会涉及静态资源的访问支持,视图解析器的配置,转换器和格式化器的定制,文件上传下载等功能,甚至还需要考虑到与web服务器关联的Servlet相关组件的定制。SpringBoot框架支持整合一些常用web框架,从而实现web开发,并默认支持web开发中的一些通用功能。本章将对SpringBoot实现web开发中涉及的一些常用功能进行详细讲解。
5.1 SpringMVC的整合支持
为了实现并简化web开发,SpringBoot为一些常用的web开发框架提供了整合支持,例如SpringMVC,SpringWebFlux等框架。使用SpringBoot进行web开发时,只需要再项目中引入独赢web开发框架的依赖启动器即可。那么,SpringBoot再整合一些web框架时实现了那些默认自动化配置,同时,怎样进行web功能扩展,本节就以SpringBoot整合SpringMVC框架实现web开发为例进行讲解。
5.1.1 SpringMVC自动配置介绍
再SpringBoot项目中,一旦引入了web依赖启动器spring-boot-starter-web,那么SpringBoot整合SpringMVC框架默认实现的一些xxxAutoConfiguration自动配置类就会自动生效,几乎可以在无任何额外配置的情况下进行web开发。SpringBoot为整合SpringMVC框架实现web开发,主要提供了一i西安自动化配置的功能特性:
-
内置了两个视图解析器:ContentNegotiatingViewResolver和BeanNameViewResolver。
-
支持静态资源以及WebJars。
-
自动注册了转换器和格式化器
-
支持http消息转换器
-
自动注册了消息代码解析器
-
支持静态项目首页index.html
-
支持定制应用图标favicon.ico
-
自动初始化web数据绑定器ConfigurableWebBindingInitializer
SpringBoot整合SpringMVC进行web开发时提供了很多默认配置,而且大多数时候使用默认配置即可满足开发需求。例如,SpringBoot整合SpringMVC进行web开发时,不需要额外配置视图解析器。
5.1.2 SpringMVC功能扩展实现
SpringBoot整合SpringMVC进行web开发时提供了很多的自动化配置,但在实际开发中还需要开发者对一些功能进行扩展实现。下面我们通过一个具体的案例讲解SpringBoot整合SpringMVC框架实现web开发的扩展功能。
-
项目基础环境搭建
使用SpringInitializr方式创建项目,并在依赖选择中选择web模块下的web依赖启动器和TemplateEngines模块下的Thymeleaf依赖启动器
为了更直观快速的通过页面查看整合效果,我们将上一个项目中的页面和配置信息都拷贝过来,并通过访问请求地址http://localhost:8080/toLoginPage 访问登录页面。
2.功能扩展实现
接下俩使用SpringBoot整合SpringMVC进行web开发,实现简单的页面跳转功能,这里我们将使用SpringBoot提供的WebMvcConfigurer接口编写自定义配置,并对web功能进行适当扩展。
注册视图管理器
在项目的config包中创建一个实现WebMvcConfigurer接口的配置类,用于对mvc框架功能进行扩展
package com.example.demo.config;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
/**
* 实现WebMvcConfigurer接口,扩展MVC功能
*/
@Configuration
public class MyMVCconfig implements WebMvcConfigurer {
// 添加视图管理
@Override
public void addViewControllers(ViewControllerRegistry registry) {
// 请求toLoginPage映射路径或者login.html页面都会自动映射到login.html页面
registry.addViewController("/toLoginPage").setViewName("login");
registry.addViewController("/login.html").setViewName("login");
}
}
接下来需要将控制器代码进行注释掉,再重新运行项目,可以实现通过浏览器地址访问/toLoginPage或者/login.html地址都能跳转到login.html页面
通过访问可以看到可以正常访问页面,但是页面上的年份却获取不到,那是因为年份原本是通过控制器经过参数传递给页面的,但是我们现在的请求并没有通过控制器,因此年份这个参数获取不到。因此以上这种请求方式只适合较为简单的无参数视图get方式的请求跳转,对于有参数或需要业务处理的跳转需求,最好还是采用控制器的方式处理请求。
注册自定义拦截器
WebMvcConfigurer接口提供了许多MVC开发相关方法,例如,添加拦截器方法addInterceptors(),添加格式化器方法addFormatters()等。接下来我们使用WebMvcConfigurer接口中的addInterceptors()方法注册自定义拦截器。
在项目的config包中创建一个自定义拦截器类,并编写拦截业务代码
package com.example.demo.config;
import org.springframework.lang.Nullable;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Calendar;
/**
* 自定义一个拦截器类
*/
@Component
public class MyInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response,
Object handler) throws Exception {
// 用户请求/admin开头路径时,判断用户是否登录
String uri = request.getRequestURI();
Object loginUser = request.getSession().getAttribute("loginUser");
if (uri.startsWith("/admin") && null == loginUser) {
response.sendRedirect("/toLoginPage");
return false;
}
return true;
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response,
Object handler, @Nullable ModelAndView modelAndView) throws Exception {
request.setAttribute("currentYear", Calendar.getInstance().get(Calendar.YEAR));
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse
response, Object handler, @Nullable Exception ex) throws Exception {
}
}
然后在MyMVCconfig类中重写addInterceptors()方法注册自定义的拦截器
@Autowired
private MyInterceptor myInterceptor;
// 添加拦截器管理
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(myInterceptor)
.addPathPatterns("/**") //拦截所有请求
.excludePathPatterns("/login.html"); //对于/login.html请求地址进行放行,不进行拦截
}
将项目进行重启运行,当我们访问/admin地址的时候,会被拦截器进行拦截,拦截器通过重定向修改请求地址访问/toLoginPage,并在跳转请求的同时调用了postHandle()方法,将年份参数发送给页面
当我们访问请求地址是/login.html的时候,拦截器没有拦截,而是允许访问,则会直接进入MyMVCconfig的addViewControllers方法,进行访问网页,那这时候并没有获得年份参数数据,因此这个请求页面上是不会显示年份数据信息。
5.2 SpringBoot整合Servlet三大组件
进行Servlet开发时,首先自定义Servlet、Filter、Listener三大组件,然后再文件web.xml中进行配置,而SpringBoot使用的时内嵌式Servlet容器,没有提供外部配置文件web.xml,那么SpringBoot时如何整合Servlet的相关组件呢?SpringBoot提供了组件注册和路径扫描两种方式整合Servlet三大组件,接下来我们分别对这两种整合方式进行详细讲解。
5.2.1 组件注册整合Servlet三大组件
再SpringBoot中,使用组件注册方式整合内嵌Servlet容器的Servlet、Filter、Listener三大组件时,只需将这些自定义组件通过ServletRegistrationBean,FilterRegistrationBean、ServletListenerRegistrationBean类注册到容器中即可。
-
使用组件注册方式整合Servlet
创建自定义Servlet类。在项目中创建servletComponent包,在该包下创建继承至HttpServlet的类MyServlet
package com.example.demo.servletComponent;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
/**
* 自定义Servlet类
*/
//@WebServlet("/annotationServlet")
@Component
public class MyServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
this.doPost(req, resp);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
resp.getWriter().write("hello MyServlet");
}
}
使用@Component注解将MyServlet类作为组件注入Spring容器。MyServlet类继承至HttpServlet,通过HttpServletResponse对象向页面输出“hello MyServlet”。
创建Servlet组件配置类。在项目config包下创建一个Servlet组件配置类ServletConfig,用来对Servlet相关组件进行注册。
package com.example.demo.config;
import com.example.demo.servletComponent.MyServlet;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.boot.web.servlet.ServletRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.util.Arrays;
/**
* 嵌入式Servlet容器三大组件配置
*/
@Configuration
public class ServletConfig {
// 注册Servlet组件
@Bean
public ServletRegistrationBean getServlet(MyServlet myServlet){
ServletRegistrationBean registrationBean =
new ServletRegistrationBean(myServlet,"/myServlet");
return registrationBean;
}
}
使用@Configuration注解将ServletConfig标注为配置类,ServletConfig类内部的getServlet()方法用于注册自定义的MyServlet,并返回ServletRegistrationBean对象。启动项目测试,在浏览器上访问/myServlet请求地址,浏览器上能显示MyServlet类返回的文本信息。
2.使用组件注册方式整合Filter
创建自定义Filter类,在servletComponent包下创建一个类MyFilter
package com.example.demo.servletComponent;
import org.springframework.stereotype.Component;
import javax.servlet.*;
import java.io.IOException;
/**
* 自定义Filter类
*/
//@WebFilter(value = {"/antionLogin","/antionMyFilter"})
@Component
public class MyFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse,
FilterChain filterChain) throws IOException, ServletException {
System.out.println("hello MyFilter");
filterChain.doFilter(servletRequest,servletResponse);
}
@Override
public void destroy() {
}
}
使用@Component注解将当前MyFilter类作为组件注入到Spring容器中。MyFilter类实现了Filter接口,并重写了init(),doFilter()和destroy()方法,在doFilter()方法中向控制台打印了"hello MyFilter"字符串。
向Servlet组件配置类注册自定义Filter类。打开之前创建的ServletConfig,将该自定义Filter类使用组件注册方式进行注册
// 注册Filter组件
@Bean
public FilterRegistrationBean getFilter(MyFilter filter){
FilterRegistrationBean registrationBean = new FilterRegistrationBean(filter);
registrationBean.setUrlPatterns(Arrays.asList("/toLoginPage","/myFilter"));
return registrationBean;
}
上述代码中,使用组件注册方式注册自定义的MyFilter类。在getFilter(MyFilter filter)方法中,使用setUrlPatterns(Arrays.asList("/toLoginPage","/myFilter"))方法定义了过滤的请求为/toLoginPage和/myFilter,同时使用@Bean注解将当前组装好的FilterRegistrationBean对象作为Bean组件返回。接下来可以运行项目访问以上两个请求地址,因为过滤器中并没有对以上两个请求做处理,因此浏览器上会报404错误,这里不用关注,我们只需要观察控制台是否有打印过滤器中的输出信息即可。
3.使用组件注册方式整合Listener
创建自定义Listener类,在servletComponent包下创建一个类MyListener。
package com.example.demo.servletComponent;
import org.springframework.stereotype.Component;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import javax.servlet.annotation.WebListener;
/**
* 自定义Listener类
*/
@Component
public class MyListener implements ServletContextListener {
@Override
public void contextInitialized(ServletContextEvent servletContextEvent) {
System.out.println("contextInitialized ...");
}
@Override
public void contextDestroyed(ServletContextEvent servletContextEvent) {
System.out.println("contextDestroyed ...");
}
}
使用@Component注解将MyListener类作为组件注册到Spring容器中。MyListener类实现了ServletContextListener接口,并重写了contextInitialized()和contextDestroyed()方法。需要说明的是,Servlet容器提供了很多Listener接口,我们在自定义的时候根据项目的需求实现对应的接口即可。
向Servlet组件配置类注册自定义Listener类。打开之前创建的ServletConfig,将自定义的MyListener注册。
//注册Listener组件
@Bean
public ServletListenerRegistrationBean getServletListener(MyListener myListener){
ServletListenerRegistrationBean registrationBean=new ServletListenerRegistrationBean(myListener);
return registrationBean;
}
接下来启动项目,可以在控制台中查看到监听器初始化的文字显示,"contextInitialized ...",再点击退出按钮的时候,控制台会显示contextDestroyed ...
注意,如果直接点击红色按钮停止项目服务器,则不会打印,项目直接被强制关闭了。
5.2.2 路径扫描整合Servlet三大组件
在SpringBoot中,使用路径扫描的方式整合内嵌式Servlet容器的Servlet,Filter,Listener三大组件时,首先需要在自定义组件上分别添加@WebServlet,@WebFilter和@WebListener注解进行声明,并配置相关注解属性,然后再仙姑主程序启动类上使用@ServletComponentScan注解开启组件扫描即可。
在使用注解方式注册三大组件之前,我们需要将之前创建的ServletConfig类全部注释掉,避免互相干扰。并且需要将自定义的三大组件中的@Component注解进行注释换成@WebServlet,@WebFilter和@WebListener。
package com.example.demo.servletComponent;
import org.springframework.stereotype.Component;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
/**
* 自定义Servlet类
*/
@WebServlet("/annotationServlet")
//@Component
public class MyServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
this.doPost(req, resp);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
resp.getWriter().write("hello MyServlet");
}
}
运行项目,在浏览器上请求访问"/annotationServlet"地址的时候,可以在浏览器上显示出"hello MyServlet"
package com.example.demo.servletComponent;
import org.springframework.stereotype.Component;
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import java.io.IOException;
/**
* 自定义Filter类
*/
@WebFilter(value = {"/antionLogin","/antionMyFilter"})
//@Component
public class MyFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse,
FilterChain filterChain) throws IOException, ServletException {
System.out.println("hello MyFilter");
filterChain.doFilter(servletRequest,servletResponse);
}
@Override
public void destroy() {
}
}
重新运行项目,会发现浏览器上请求访问"/antionLogin","/antionMyFilter"这两个地址的时候会被过滤器拦截,并在控制台打印出"hello MyFilter"。
package com.example.demo.servletComponent;
import org.springframework.stereotype.Component;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import javax.servlet.annotation.WebListener;
/**
* 自定义Listener类
*/
@WebListener
//@Component
public class MyListener implements ServletContextListener {
@Override
public void contextInitialized(ServletContextEvent servletContextEvent) {
System.out.println("contextInitialized ...");
}
@Override
public void contextDestroyed(ServletContextEvent servletContextEvent) {
System.out.println("contextDestroyed ...");
}
}
重新运行项目,效果和注册监听器的方式的结果是一样的。
5.3 文件上传与下载
5.3.1 文件上传
开发Web应用时,文件上传时很常见的一个需求,浏览器通过表单形式将文件以流的形式传递给服务器,服务器再对上传的数据解析处理。虾米那我通过一个案例讲解如何使用SpringBoot实现文件上传。
-
编写文件上传表单页面
在项目的templates模板引擎文件夹下创建一个用来上传文件的upload.html模板页面
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>动态添加文件上传列表</title>
<link th:href="@{/login/css/bootstrap.min.css}" rel="stylesheet">
<script th:src="@{/login/js/jquery.min.js}"></script>
</head>
<body>
<div th:if="${uploadStatus}" style="color: red" th:text="${uploadStatus}">上传成功</div>
<form th:action="@{/uploadFile}" method="post" enctype="multipart/form-data">
上传文件: <input type="button" value="添加文件" onclick="add()"/>
<div id="file" style="margin-top: 10px;" th:value="文件上传区域"> </div>
<input id="submit" type="submit" value="上传"
style="display: none;margin-top: 10px;"/>
</form>
<script type="text/javascript">
// 动态添加上传按钮
function add(){
var innerdiv = "<div>";
innerdiv += "<input type='file' name='fileUpload' required='required'>" +
"<input type='button' value='删除' onclick='remove(this)'>";
innerdiv +="</div>";
$("#file").append(innerdiv);
// 打开上传按钮
$("#submit").css("display","block");
}
// 删除当前行<div>
function remove(obj) {
$(obj).parent().remove();
if($("#file div").length ==0){
$("#submit").css("display","none");
}
}
</script>
</body>
</html>
2.在全局配置文件中添加文件上传的相关配置
在全局配置文件application.properties中添加文件上传的相关设置
# 单个上传文件大小限制(默认为1MB)
spring.servlet.multipart.max-file-size=10MB
# 总上传文件大小限制(默认为10MB)
spring.servlet.multipart.max-request-size=50MB
如果上传文件超出了限制,则会报错。
3.进行文件上传处理,实现文件上传功能
在controller包下创建一个管理上传下载的控制类FileController,用于实现文件上传功能
package com.example.demo.controller;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.multipart.MultipartFile;
import java.io.File;
import java.util.UUID;
/**
* 文件管理控制类
*/
@Controller
public class FileController {
// 向文件上传页面跳转
@GetMapping("/toUpload")
public String toUpload(){
return "upload";
}
// 文件上传管理
@PostMapping("/uploadFile")
public String uploadFile(MultipartFile[] fileUpload, Model model) {
// 默认文件上传成功,并返回状态信息
model.addAttribute("uploadStatus", "上传成功!");
for (MultipartFile file : fileUpload) {
// 获取文件名以及后缀名
String fileName = file.getOriginalFilename();
// 重新生成文件名(根据具体情况生成对应文件名)
fileName = UUID.randomUUID()+"_"+fileName;
// 指定上传文件本地存储目录,不存在需要提前创建
String dirPath = "E:/file/";
File filePath = new File(dirPath);
if(!filePath.exists()){
filePath.mkdirs();
}
try {
file.transferTo(new File(dirPath+fileName));
} catch (Exception e) {
e.printStackTrace();
// 上传失败,返回失败信息
model.addAttribute("uploadStatus","上传失败: "+e.getMessage());
}
}
// 携带上传状态信息回调到文件上传页面
return "upload";
}
}
?toUpload()方法用于处理路径为“/toUpload”的GET请求,并返回上传页面的路径。uploadFile()方法用于处理路径为“/uploadFile”的POST请求,如果文件上传成功,则会将上传的文件重命名并存储在"E:/file/"目录。如果上传失败,则会提示上传失败的相关信息。需要注意的是,uploadFile()方法的参数fileUpload的名称必须与上传页面中的input的name值一致。
4.效果测试
启动项目,项目启动成功后,在浏览器上访问“http://localhost:8080/toUpload”
单击添加文件的按钮,能够动态添加多个文件
?
成功了
添加文件进行上传
5.3.2 文件下载
下载文件能够通过IO流实现,所以多数框架并没有对文件下载进行封装处理。文件下载时涉及不同浏览器的解析处理,可能会出现中文乱码的情况。接下来我们分别针对下载英文名文件和中文名文件进行讲解。
-
英文名文件下载
添加文件下载工具依赖。再pom.xml文件中引入文件下载的一个工具依赖commons-io
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.6</version>
</dependency>
定制文件下载页面,再项目的templates文件夹下创建一个演示文件下载的download.html模板页面
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>文件下载</title>
</head>
<body>
<div style="margin-bottom: 10px">文件下载列表:</div>
<table>
<tr>
<td>bloglogo.jpg</td>
<td><a th:href="@{/download(filename='bloglogo.jpg')}">下载文件</a></td>
</tr>
<tr>
<td>Spring Boot应用级开发教程.pdf</td>
<td><a th:href="@{/download(filename='Spring Boot应用级开发教程.pdf')}">
下载文件</a></td>
</tr>
</table>
</body>
</html>
需要注意的是,在文件下载之前,需要保证在文件下载目录(本示例中的E:/file/)中存在文件bbb.jpg和计算机文化与组装.pptx(这只是两个测试文件而已,读者演示时可以自行存放,只要保持文件名统一即可)
编写文件下载处理方法,在之前创建的文件管理控制类FileController中编写文件下载的处理方法
// 向文件下载页面跳转
@GetMapping("/toDownload")
public String toDownload(){
return "download";
}
// 文件下载管理
@GetMapping("/download")
public ResponseEntity<byte[]> fileDownload(String filename){
// 指定要下载的文件根路径
String dirPath = "F:/file/";
// 创建该文件对象
File file = new File(dirPath + File.separator + filename);
// 设置响应头
HttpHeaders headers = new HttpHeaders();
// 通知浏览器以下载方式打开
headers.setContentDispositionFormData("attachment",filename);
// 定义以流的形式下载返回文件数据
headers.setContentType(MediaType.APPLICATION_OCTET_STREAM);
try {
return new ResponseEntity<>(FileUtils.readFileToByteArray(file), headers, HttpStatus.OK);
} catch (Exception e) {
e.printStackTrace();
return new ResponseEntity<byte[]>(e.getMessage().getBytes(),HttpStatus.EXPECTATION_FAILED);
}
}
上述代码中,toDownload()方法用来处理“/toDownload”的Get请求,并跳转到download.html页面,fileDownload()方法用来处理"/download"的Get请求并进行文件下载处理,下载的数据类型是ResponseEntity<byte[]>
效果测试,实现上述文件下载功能后,启动项目,项目启动成功后,在浏览器上访问(http://localhost:8080/toDownload)进入下载页面,这里先下载英文文件名的文件,点击下载文件,以IE浏览器为例
2.中文名文件下载
在上一步所示的文件下载页面中,单击第2个中文名文件“计算机文化与组装.pptx”后面的下载文件进行下载,对文件名进行下载时,虽然可以成功下载,但是下载后的文件中文名称统一变成了“_”,这显然时不理想的,因此还需要对中文名文件下载进行额外处理,在FileController类的fileDownload()方法中添加处理中文编码的代码,修改后的代码如下
// 所有类型文件下载管理
@GetMapping("/download")
public ResponseEntity<byte[]> fileDownload(HttpServletRequest request,
String filename) throws Exception{
// 指定要下载的文件根路径
String dirPath = "E:/file/";
// 创建该文件对象
File file = new File(dirPath + File.separator + filename);
// 设置响应头
HttpHeaders headers = new HttpHeaders();
// 通知浏览器以下载方式打开(下载前对文件名进行转码)
filename=getFilename(request,filename);
headers.setContentDispositionFormData("attachment",filename);
// 定义以流的形式下载返回文件数据
headers.setContentType(MediaType.APPLICATION_OCTET_STREAM);
try {
return new ResponseEntity<>(FileUtils.readFileToByteArray(file), headers, HttpStatus.OK);
} catch (Exception e) {
e.printStackTrace();
return new ResponseEntity<byte[]>(e.getMessage().getBytes(),HttpStatus.EXPECTATION_FAILED);
}
}
// 根据浏览器的不同进行编码设置,返回编码后的文件名
private String getFilename(HttpServletRequest request, String filename)
throws Exception {
// IE不同版本User-Agent中出现的关键词
String[] IEBrowserKeyWords = {"MSIE", "Trident", "Edge"};
// 获取请求头代理信息
String userAgent = request.getHeader("User-Agent");
for (String keyWord : IEBrowserKeyWords) {
if (userAgent.contains(keyWord)) {
//IE内核浏览器,统一为UTF-8编码显示,并对转换的+进行更正
return URLEncoder.encode(filename, "UTF-8").replace("+"," ");
}
}
//火狐等其它浏览器统一为ISO-8859-1编码显示
return new String(filename.getBytes("UTF-8"), "ISO-8859-1");
}
上述代码中,getFilename()方法用来根据不同浏览器对下载的中文名进行转码。其中“User-Agent”用于获取用户下载文件的浏览器内核信息,不同版本的IE浏览器内核可能不同,需要特别查看,如果内核信息时IE则转码为UTF-8,其他浏览器转码为ISO-8859-1即可。
本章小结
本章主要讲解了SpringBoot框架整合SpringMVC实现web开发过程中的一些功能,包括有MVC功能扩展和定制,Servlet三大组件定制,文件上传与下载以及SpringBoot项目的打包和部署。学习完本章后,要充分掌握SpringBoot进行web开发中主要功能的一些配置和扩展,能够完成实际开发中SpringBoot项目的开发和部署工作。
习题
一、填空题
-
SpringBoot项目中定制SpringMVC的扩展功能,需要提供实现()接口的配置类。
-
WebMvcConfigurer接口中的()方法可以定制视图管理。
-
WebMvcConfigurer接口中的()方法可以定制自定义的拦截器。
-
SpringBoot中使用路径扫描方式整合Servlet组件时,需要用()注解开启组件扫描。
-
SpringBoot整合SpringMVC实现文件上传时,默认单个文件上传大小限制为()。
二、判断题
-
SpringBoot为整合SpringMVC实现web开发提供了欢迎页index.html支持。()
-
SpringBoot中实现SpringMVC的扩展功能,要提供实现WebMvcConfigurer接口的配置类,并开启@EnableWebMvc注解。()
-
SpringBoot中整合Servlet的Listener组件时,在自定义Listener上添加@Component即可生效。()
-
SpringBoot整合SpringMVC实现中文名文件下载时,针对IE内核浏览器需要转码为UTF-8。()
-
SpringBoot提供的打包插件spring-boot-maven-plugin可以将项目打成Jar包和War包。()
三、选择题
-
SpringBoot为整合SpringMVC实现web开发,提供的功能特性不包括()
A.配置视图解析器
B.对WebJars的支持
C.对拦截器的自动配置
D.对HttpMessageConverters消息转换器的支持
-
SpringBoot整合Servlet组件涉及的注册Bean组件有()。(多选)
A.ServletRegistrationBean
B.InterceptorRegistrationBean
C.FilterRegistrationBean
D.ServletListenerRegistrationBean
-
SpringBoot中使用路径扫描的方式整合内嵌式Servlet组件时,需要使用的注解有()。(多选)
A.@WebFilter
B.@ServletComponentScan
C.@WebListener
D.@WebInterceptor
-
下列关于SpringBoot整合SpringMVC实现文件上传及下载的说法中,正确的是()
A.必须使用spring.servlet.multipart.max-file-size来设置单个上传文件的大小限制
B.处理上传文件方法中,可以使用List<MultipartFile>类型的参数来接收处理单个或多个上传文件
C.文件上传存储目录“F:/file/”需要提前创建好
D.对中文文件进行下载时,如果没有进行中文转换,下载的中文文件内容会出现乱码
-
下列关于SpringBoot项目War包方式打包部署的说法中,错误的是()
A.必须使用<packaging>标签将SpringBoot项目默认的Jar包方式修改为War
B.需要将spring-boot-starter-tomcat使用<scope>provided</scope>声明为已提供provided
C.必须让主程序启动类继承SpringBootServletInitializer类并实现cinfigure()方法
D.以War包方式部署项目进行访问,必须在访问路径上添加打包后的项目
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。 如若内容造成侵权/违法违规/事实不符,请联系我的编程经验分享网邮箱:veading@qq.com进行投诉反馈,一经查实,立即删除!