SpringBoot SpringMVC 整合
# SpringBoot 应用
SpringBoot 对 SpringMVC 的一些自动配置可以满足大部分需求,但也可以自定义配置类 并实现org.springframework.web.servlet.config.annotation.WebMvcConfigurer
接口 进行手动部分配置
接口提供方法
返回 | 方法 | 说明 |
---|---|---|
void | ==addInterceptors(InterceptorRegistry registry)== | 添加 拦截器,对请求进行拦截处理 |
void | ==addResourceHandlers(ResourceHandlerRegistry registry)== | 添加 或 修改静态资源 |
void | ==addViewControllers(ViewControllerRegistry registry)== | 无业务逻辑跳转(虚实映射重定向 |
void | ==addCorsMappings(CorsRegistry registry)== | 解决跨域问题 |
以下 SpringMVC配置问题 主要解决:
# 修改端口
在SpringBoot的 全局属性(application.properties文件) 进行以下配置端口:
# 映射端口
server.port=80
# 静态资源加载
Spring Boot 中 org.springframework.boot.autoconfigure.web.ResourceProperties
类 ,已经定义了静态资源的默认路径 :(以下路径创建对应的目录即可直接访问
private static final String[] CLASSPATH_RESOURCE_LOCATIONS = {
"classpath:/META-INF/resources/", "classpath:/resources/",
"classpath:/static/", "classpath:/public/" };
- ==classpath:/META-INF/resources/==
- ==classpath:/resources/==
- ==classpath:/static/==
- ==classpath:/public==
classpath:/
指定的目录是指 缓存中加载的类路径classes
以上目录可以在项目中直接访问到指定根目录。如果自定义的资源路径则需要指定确定路径,例如:
项目默认的路径 : 测试访问 static/1.jpg ==localhost:8080/1.jpg==
自定义静态资源路径
重写方法映射 在SpringMVC的配置类中 重写
addResourceHandlers()
方法 以下代码:@Override public void addResourceHandlers(ResourceHandlerRegistry registry) { // 类似于 SpringMVC配置 // <mvc:resources mapping="/test/**" location="/test/"/> registry.addResourceHandler("/test/**").addResourceLocations("classpath:/test/"); }
如果指定实体本机文件则: ==registry.addResourceHandler("/pic/**").addResourceLocations("file:"+"D:/uploadFiles/");==
修改配置文件 修改 application.properties更改规则
# 过滤规则 spring.mvc.static-path-pattern=/static/** # 静态资源位置 spring.web.resources.static-locations=classpath:/static/
以上是默认配置 , 可手写覆盖 , 覆盖后原有的会失效
# 文件上传
表单默认应用 enctype="application/x-www-form-urlencoded" , 需要改成 enctype="multipart/form-data" 进行上传文件
修改默认大小限制
默认每个1M , 配置修改
# 单个文件最大
spring.servlet.multipart.max-file-size=10MB
# 单次请求最大
spring.servlet.multipart.max-request-size=10M
应用
@RestController
public class FileUploadController {
@PostMapping("/upload")
public String up(String nickname, MultipartFile photo , HttpServletRequest request) throws IOException {
System.out.println("nickname = " + nickname);
// 图片信息
System.out.println("图片原始名称: "+photo.getOriginalFilename());
System.out.println("图片类型: "+photo.getContentType());
String path = request.getServletContext().getRealPath("/upload/");
System.out.println("path = " + path);
// 存储
saveFile(photo,path);
return "上传完毕";
}
// 存储
private void saveFile(MultipartFile photo, String path) throws IOException {
File dir = new File(path);
// 目录空则创建
if (!dir.exists()) {
dir.mkdir();
}
File file = new File(path + photo.getOriginalFilename());
photo.transferTo(file);
}
}
# 拦截器
拦截器需要自行配置 。 SpringMVC拦截器类配置了解 (opens new window)
Spring Boot 定义了 HandlerInterceptor接口 , 该接口实现了自定义拦截器的功能 , 可以重写以下三个过程方法进行 :
请求前 ==preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)==
参数:
handler
被拦截的控制器对象(MyController) 返回:是否允许放行,false拦截请求处理后 ==postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView)==
参数:
handler
被拦截的控制器对象 ;modelAndView
控制器方法的返回值请求最后 ==afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)== 参数:
handler
被拦截的控制器对象 ;ex
控制器方法异常
大致步骤 :
- 创建 自定义拦截器 , 继承
HandlerInterceptor
并重写以上方法 - 配置 路径 (全选 , 部分 , 排除)
- 日志配置
- 测试
创建 自定义拦截器类
自定义拦截器MyInterceptor类 展开
模拟日志形式进行输出
public class MyInterceptor implements HandlerInterceptor {
private Logger logger = LoggerFactory.getLogger(LoginInterceptor.class);
@Override
public boolean preHandle(HttpServletRequest request , HttpServletResponse response , Object handler) {
logger.debug("处理器执行前执行!");
return true;
}
@Override
public void postHandle(HttpServletRequest request , HttpServletResponse response , Object handler , ModelAndView modelAndView) throws Exception {
logger.debug("处理器执行后执行!");
}
@Override
public void afterCompletion(HttpServletRequest request , HttpServletResponse response , Object handler , Exception ex) throws Exception {
logger.debug("跳转后执行!");
}
}
注意
如果需要在自定义拦截器中食用 自动注入对象 的话 , 需要写个有参构造方法进行传递 .
在配置类中 自动注入 , 在实例化时传参进去即可
配置类 路径配置
重写 addInterceptors
方法 添加自定义拦截器 , 通过registry
对象的addInterceptor()
方法 来添加拦截器 , 拦截器的路径拦截有以下配置选项 : (分别写出应用的方法)
- 所有请求路径拦截 : 无 , 默认所有请求拦截
- 指定范围路径拦截 :
addPathPatterns()
- 排除指定路径拦截 :
excludePathPatterns()
- 指定拦截器的优先级 :
order()
@Configuration
public class SpringMVCConfig implements WebMvcConfigurer {
@Override
public void addInterceptors(InterceptorRegistry registry) {
// 通过registry来注册拦截器,通过addPathPatterns来添加拦截路径 (不加则拦截所有)
registry.addInterceptor(new MyInterceptor())
.addPathPatterns("/user/**");
}
}
日志级别打印
在 全局属性(application.properties文件) 进行添加属性(此时在控制器是看不到日志的输出)
因 记录打印 级别 : debug
,日志打印 级别 :info
# 设置 com.*包 的日志级别为debug
logging.level.com.*=debug
测试
运行项目 , 访问有效路径测试即可
# 虚实映射重定向
主要意图是把 访问的URI 转换至 自定义URI ,达到重定向效果
实现需要在 SpringMVC的配置类中 重写 addViewControllers()
方法 以下代码:
@Override
public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("/").setViewName("login.html");
registry.setOrder(Ordered.HIGHEST_PRECEDENCE);
}
首次访问重定向值登录页面,且设置最高优先级
# 跨域
CORS 是种 跨域资源共享的技术标准 , 为了更好的解决前端跨域请求 , CORS请求分为 简单请求 / 非简单请求 分别对跨域提供支持
跨域 : 当一个请求 url 的 协议/域名/端口 三者任意一个 与 当前页面url不同 称为 跨域
# 简单请求
请求方法 : GET
/ POST
/ HEAD
未自定义的请求头 : Accept
/ Accept-Language
/ Content--Language
/ Last-Event--lD
/
Content-Type
Content-Type 的值只有以下三种 : text/plain
, multipart/form-data
, application/x-www-form-urlencode
前端发出请求时 :
CORS的策略在请求头新增了个 Origin
字段(url) , 用于告诉服务器来自哪里
后端收到请求后 :
可以根据 Origin
字段 判断是否允许请求访问 , 如果允许 会在HTTP头信息添加 Access-Control-Allow-Origin
字段(应用端口)
# 非简单请求
非简单请求时 浏览器会在真实请求发出前增加一次OPTION请求 称为预检请求
预检请求将真实请求的信息 , 包括请求方法/自定义头字段/源信息 添加到HTTP头信息字段中 , 询问服务器是否允许这样的操作
前端发出请求 :
OPTIONS /test HTTP/1.1
Origin: http://www.test.com
Access-Control-Request-Method: GET
# 请求的自定义头字段
Access-Control-Request-Headers: X-Custom-Header
Host: www.test.com
后端收到请求后 :
会对 Origin
/ Access-Control-Request-Method
/ Access-Control-Request-Headers
字段进行验证 , 后端请求允许通过后会返回
# 真实请求 请求允许 来源url/方法/头信息
Access-Control-Allow-Origin: http://www.test.com
Access-Control-Allow-Methods: GET,POST,PUT,DELETE
Access-Control-Allow-Headers: X-Custom-Header
# 允许 用户 发送/处理 cookie
Access-Control-Allow-Credentials: true
# 允许 请求有效期 毫秒
Access-Control-Max-Age: 1728000
# SpringBoot解决方案
解决跨域问题需要在 SpringMVC的配置类中 重写 addCorsMappings()
方法 以下代码:
springboot 2.4.0版本前 :
@Override
public void addCorsMappings(CorsRegistry registry) {
// 允许访问的路径
registry.addMapping("/**")
// 是否发送 cookie
.allowCredentials(true)
// 允许 跨域访问的源
.allowedOrigins("*")
// 允许 接收的请求类型
.allowedMethods("POST","GET")
// 允许 头部设置
.allowedHeaders("*")
// 允许 有效期
.maxAge(1800);
}
springboot 2.4.0版本后 :
方法名更变为 : allowedOrigins
=> allowedOriginPatterns
@Override
public void addCorsMappings(CorsRegistry registry) {
// 允许访问的路径
registry.addMapping("/**")
// 是否发送 cookie
.allowCredentials(true)
// 允许 跨域访问的源
.allowedOriginPatterns("*")
// 允许 接收的请求类型
.allowedMethods("POST","GET")
// 允许 头部设置
.allowedHeaders("*")
// 允许 有效期
.maxAge(1800);
}
方案2 :
在启动器类加上注解 @CrossOrigin
. 也可实现跨域功能 (PS注意版本问题)
# url图片
@Controller
@RequestMapping(value = "/image")
public class ImageController {
@RequestMapping(value = "/get",produces = MediaType.IMAGE_JPEG_VALUE)
@ResponseBody
public byte[] getImage() throws IOException {
File file = new File("D:/test.jpg");
FileInputStream inputStream = new FileInputStream(file);
byte[] bytes = new byte[inputStream.available()];
inputStream.read(bytes, 0, inputStream.available());
return bytes;
}
}